package com.firstbuild.androidapp.opal; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.util.SparseArrayCompat; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; import com.firstbuild.androidapp.OpalValues; import com.firstbuild.androidapp.R; import com.firstbuild.androidapp.productmanager.OpalInfo; import com.firstbuild.androidapp.productmanager.ProductManager; import com.firstbuild.commonframework.blemanager.BleManager; import com.firstbuild.tools.MathTools; import com.firstbuild.viewutil.OpalScheduleGridLayout; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Calendar; import java.util.HashSet; /** * Created by hans on 16. 7. 13.. */ public class OpalScheduleFragment extends Fragment { private static final String TAG_HELP_TUTORIAL = "tag_help_tutorial"; private String TAG = OpalScheduleFragment.class.getSimpleName(); private OpalScheduleGridLayout timeSlotContainer; private ViewGroup weekdaysContainer; private Button applyAllDay; private View currentSelectedWeekDay; // Key : weekday view Id , value : selected timeslot view id private SparseArrayCompat<HashSet<Integer>> timeSlotTracker = new SparseArrayCompat<>(); private int[] weekdayTvIds = new int[]{ R.id.sunday, R.id.monday, R.id.tuesday, R.id.wednesday, R.id.thursday, R.id.friday, R.id.saturday }; private ArrayList<Integer> timeSlotTvIds = new ArrayList<>(); private OpalInfo currentOpal; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_opal_schedule, container, false); timeSlotContainer = (OpalScheduleGridLayout)view.findViewById(R.id.time_slot_item_container); weekdaysContainer = (ViewGroup)view.findViewById(R.id.weekdays_header); applyAllDay = (Button)view.findViewById(R.id.apply_all_day_btn); // init Time Slot View id array list for(int i=0; i <timeSlotContainer.getChildCount(); i++) { timeSlotTvIds.add(i, timeSlotContainer.getChildAt(i).getId()); } // Apply All btn applyAllDay.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(v.isSelected() == false) { onHandleApplyAllClicked(v); } } }); timeSlotContainer.setDiagonalDragDetector(new OpalScheduleGridLayout.GridDiagonalDragDector() { @Override public void onDiagonalDragDetected(View start, View end) { int startIndex = timeSlotContainer.indexOfChild(start); int endIndex = timeSlotContainer.indexOfChild(end); HashSet<Integer> set = timeSlotTracker.get(currentSelectedWeekDay.getId()); Boolean childSelectChanged = false; for(int i = startIndex; i < endIndex + 1; i++) { View child = timeSlotContainer.getChildAt(i); if(child.isSelected() == false) { child.setSelected(true); childSelectChanged = true; } set.add(child.getId()); } if(childSelectChanged == true) { onTimeSlotSelectionChanged(); } } }); // update schedule data read from the Opal Device into timeSlotTracker initTimeSlotTrackerFromScheduleData(); // Select the current day of week initTodayWeekdayHeader(weekdaysContainer); setHasOptionsMenu(true); return view; } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.menu_schedule, menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { if(item.getItemId() == R.id.action_help) { showHelpTutorial(); return true; } return super.onOptionsItemSelected(item); } private void showHelpTutorial() { FragmentManager fm = getFragmentManager(); if(fm != null && fm.findFragmentByTag(TAG_HELP_TUTORIAL) != null) { // skip showing dialog as it is already shown return; } OpalHelpTutorialFragment helpFragment = OpalHelpTutorialFragment.getInstance(); helpFragment.show(fm, TAG_HELP_TUTORIAL); } /** * initialize internal data structure based on the value read from the Opal Device */ private void initTimeSlotTrackerFromScheduleData() { currentOpal = (OpalInfo) ProductManager.getInstance().getCurrent(); byte[] schedule = currentOpal.getScheduleValue(); HashSet<Integer> item; for(int i=0 ; i < weekdayTvIds.length ; i++) { int key = weekdayTvIds[i]; // get schedule time slot info from each day of week if(timeSlotTracker.get(key) == null) { item = new HashSet<>(); } else { item = timeSlotTracker.get(key); item.clear(); } byte hourTimeSlot; boolean isSet; // starts at 12:00 am and 1 hour increment per each loop for(int j=0; j<schedule.length; j++) { hourTimeSlot = schedule[j]; isSet = (( hourTimeSlot >> i ) & 1) == 1; if(isSet == true) { Log.d(TAG, "[HANS] Time set : " + i + " bit" + " at " + j + " byte" ); TextView tv = (TextView)(timeSlotContainer.findViewById(timeSlotTvIds.get(j))); Log.d(TAG, "[HANS] Time set : store view id where text is : " + tv.getText() ); item.add(timeSlotTvIds.get(j)); } } timeSlotTracker.put(key, item); } } private void sendTimeSlotInfoToOpal() { ByteBuffer valueBuffer = ByteBuffer.allocate(24); boolean[][] scheduleTable = new boolean[24][8]; for(int i = 0; i < timeSlotTracker.size(); i++) { int key = timeSlotTracker.keyAt(i); HashSet<Integer> value = timeSlotTracker.get(key); TextView weekday = (TextView)weekdaysContainer.findViewById(key); // View id for (Integer integer : value) { int index = timeSlotTvIds.indexOf(integer); TextView tv = (TextView)(timeSlotContainer.findViewById(integer)); Log.d(TAG, "[HANS] \"On\" detected over : " + weekday.getText() + " : " + tv.getText() ); scheduleTable[index][i] = true; } } for(int i=0; i<24; i++) { boolean[] row = scheduleTable[i]; byte b = (byte)((row[0] ? 1 : 0) + (row[1] ? 1<<1 : 0) + (row[2] ? 1<<2 : 0) + (row[3] ? 1<<3 : 0) + (row[4] ? 1<<4 : 0) + (row[5] ? 1<<5 : 0) + (row[6] ? 1<<6 : 0) + (row[7] ? 1<<7 : 0)); valueBuffer.put(b); } Log.d(TAG, "[HANS] sendTimeSlotInfoToOpal : " + MathTools.byteArrayToHex(valueBuffer.array())); BleManager.getInstance().writeCharacteristics(currentOpal.bluetoothDevice, OpalValues.OPAL_SET_SCHEDULE_UUID, valueBuffer.array()); } private void onHandleApplyAllClicked(View v) { // Update the UI v.setSelected(true); applyAllDay.setText(R.string.schedule_applied_all); // Copy current timeSlot selection status to other weekdays HashSet<Integer> selectedTimeSlots = timeSlotTracker.get(currentSelectedWeekDay.getId()); for(int i = 0; i < weekdaysContainer.getChildCount(); i++) { View child = weekdaysContainer.getChildAt(i); if(child instanceof TextView && child.getId() != currentSelectedWeekDay.getId()) { timeSlotTracker.put(child.getId(), (HashSet<Integer>)selectedTimeSlots.clone()); } if(child instanceof ImageView && i != weekdaysContainer.indexOfChild(currentSelectedWeekDay) + 7) { child.setVisibility(View.VISIBLE); } } } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); } @Override public void onPause() { super.onPause(); Log.d(TAG, "onPause() IN"); sendTimeSlotInfoToOpal(); Log.d(TAG, "sendTimeSlotInfoToOpal in onPause() !!!"); } private void initTodayWeekdayHeader(View weekDayHeader) { Calendar calendar = Calendar.getInstance(); int day = calendar.get(Calendar.DAY_OF_WEEK); View today; switch (day) { case Calendar.SUNDAY: today = weekDayHeader.findViewById(R.id.sunday); break; case Calendar.MONDAY: today = weekDayHeader.findViewById(R.id.monday); break; case Calendar.TUESDAY: today = weekDayHeader.findViewById(R.id.tuesday); break; case Calendar.WEDNESDAY: today = weekDayHeader.findViewById(R.id.wednesday); break; case Calendar.THURSDAY: today = weekDayHeader.findViewById(R.id.thursday); break; case Calendar.FRIDAY: today = weekDayHeader.findViewById(R.id.friday); break; case Calendar.SATURDAY: today = weekDayHeader.findViewById(R.id.saturday); break; default : today = null; break; } onHandleWeekdaysClicked(today); } public void onHandleTimeSlotClicked(View v) { // Toggle selection state v.setSelected(!v.isSelected()); // update selection state when time slot selection status changes HashSet<Integer> selectedTimeSlotSet = timeSlotTracker.get(currentSelectedWeekDay.getId()); if(v.isSelected()) { selectedTimeSlotSet.add(Integer.valueOf(v.getId())); } else { selectedTimeSlotSet.remove(Integer.valueOf(v.getId())); } // Check if applied all days mode is on, if so, cancel applied mode onTimeSlotSelectionChanged(); } private void onTimeSlotSelectionChanged() { if(applyAllDay.isSelected() == true) { for(int i = 0; i < weekdaysContainer.getChildCount(); i++) { View child = weekdaysContainer.getChildAt(i); if(child instanceof ImageView) { child.setVisibility(View.GONE); } } applyAllDay.setSelected(false); applyAllDay.setText(R.string.schedule_apply_all_days); } } public void onHandleWeekdaysClicked(View v) { // if current weekday is selected again, then skip handling ! if(v == null || currentSelectedWeekDay != null && currentSelectedWeekDay.getId() == v.getId()) { return; } // Update previous week day selection status to false if(currentSelectedWeekDay != null && currentSelectedWeekDay.getId() != v.getId() ) { currentSelectedWeekDay.setSelected(false); } v.setSelected(true); currentSelectedWeekDay = v; // If there is no data structure for current selected weekday, create it lazily if(timeSlotTracker.get(currentSelectedWeekDay.getId()) == null) { timeSlotTracker.put(currentSelectedWeekDay.getId(), new HashSet<Integer>()); } // update the current time slot UI using stored information HashSet<Integer> selectedTimeSlotSet = timeSlotTracker.get(currentSelectedWeekDay.getId()); // If there is any slected status stored, then update the UI for(int i=0; i < timeSlotContainer.getChildCount(); i++) { View child = timeSlotContainer.getChildAt(i); if(selectedTimeSlotSet.contains(Integer.valueOf(child.getId())) == true) { child.setSelected(true); } else { child.setSelected(false); } } } }