Home | History | Annotate | Download | only in deskclock
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.deskclock;
     18 
     19 import android.app.ActionBar;
     20 import android.app.Activity;
     21 import android.app.Fragment;
     22 import android.app.FragmentTransaction;
     23 import android.app.LoaderManager;
     24 import android.content.Context;
     25 import android.content.Intent;
     26 import android.content.Loader;
     27 import android.content.res.Resources;
     28 import android.database.Cursor;
     29 import android.graphics.Rect;
     30 import android.graphics.Typeface;
     31 import android.media.Ringtone;
     32 import android.media.RingtoneManager;
     33 import android.net.Uri;
     34 import android.os.AsyncTask;
     35 import android.os.Bundle;
     36 import android.os.Vibrator;
     37 import android.view.ActionMode;
     38 import android.view.ActionMode.Callback;
     39 import android.view.LayoutInflater;
     40 import android.view.Menu;
     41 import android.view.MenuItem;
     42 import android.view.MotionEvent;
     43 import android.view.View;
     44 import android.view.View.OnLongClickListener;
     45 import android.view.ViewGroup;
     46 import android.widget.CheckBox;
     47 import android.widget.CompoundButton;
     48 import android.widget.CursorAdapter;
     49 import android.widget.LinearLayout;
     50 import android.widget.ListView;
     51 import android.widget.Switch;
     52 import android.widget.TextView;
     53 import android.widget.ToggleButton;
     54 
     55 import com.android.deskclock.widget.ActionableToastBar;
     56 import com.android.deskclock.widget.swipeablelistview.SwipeableListView;
     57 
     58 import java.text.DateFormatSymbols;
     59 import java.util.Calendar;
     60 import java.util.HashSet;
     61 
     62 /**
     63  * AlarmClock application.
     64  */
     65 public class AlarmClock extends Activity implements LoaderManager.LoaderCallbacks<Cursor>,
     66         AlarmTimePickerDialogFragment.AlarmTimePickerDialogHandler,
     67         LabelDialogFragment.AlarmLabelDialogHandler,
     68         OnLongClickListener, Callback {
     69 
     70     private static final String KEY_EXPANDED_IDS = "expandedIds";
     71     private static final String KEY_REPEAT_CHECKED_IDS = "repeatCheckedIds";
     72     private static final String KEY_RINGTONE_TITLE_CACHE = "ringtoneTitleCache";
     73     private static final String KEY_SELECTED_ALARMS = "selectedAlarms";
     74     private static final String KEY_DELETED_ALARM = "deletedAlarm";
     75     private static final String KEY_UNDO_SHOWING = "undoShowing";
     76     private static final String KEY_PREVIOUS_DAY_MAP = "previousDayMap";
     77     private static final String KEY_SELECTED_ALARM = "selectedAlarm";
     78 
     79     private static final int REQUEST_CODE_RINGTONE = 1;
     80 
     81     private SwipeableListView mAlarmsList;
     82     private AlarmItemAdapter mAdapter;
     83     private Bundle mRingtoneTitleCache; // Key: ringtone uri, value: ringtone title
     84     private ActionableToastBar mUndoBar;
     85     private ActionMode mActionMode;
     86 
     87     private Alarm mSelectedAlarm;
     88     private int mScrollToAlarmId = -1;
     89 
     90     // This flag relies on the activity having a "standard" launchMode and a new instance of this
     91     // activity being created when launched.
     92     private boolean mFirstLoad = true;
     93 
     94     // Saved states for undo
     95     private Alarm mDeletedAlarm;
     96     private boolean mUndoShowing = false;
     97 
     98     @Override
     99     protected void onCreate(Bundle savedState) {
    100         super.onCreate(savedState);
    101         initialize(savedState);
    102         updateLayout();
    103         getLoaderManager().initLoader(0, null, this);
    104     }
    105 
    106     private void initialize(Bundle savedState) {
    107         setContentView(R.layout.alarm_clock);
    108         int[] expandedIds = null;
    109         int[] repeatCheckedIds = null;
    110         int[] selectedAlarms = null;
    111         Bundle previousDayMap = null;
    112         if (savedState != null) {
    113             expandedIds = savedState.getIntArray(KEY_EXPANDED_IDS);
    114             repeatCheckedIds = savedState.getIntArray(KEY_REPEAT_CHECKED_IDS);
    115             mRingtoneTitleCache = savedState.getBundle(KEY_RINGTONE_TITLE_CACHE);
    116             mDeletedAlarm = savedState.getParcelable(KEY_DELETED_ALARM);
    117             mUndoShowing = savedState.getBoolean(KEY_UNDO_SHOWING);
    118             selectedAlarms = savedState.getIntArray(KEY_SELECTED_ALARMS);
    119             previousDayMap = savedState.getBundle(KEY_PREVIOUS_DAY_MAP);
    120             mSelectedAlarm = savedState.getParcelable(KEY_SELECTED_ALARM);
    121         }
    122 
    123         mAlarmsList = (SwipeableListView) findViewById(R.id.alarms_list);
    124         mAdapter = new AlarmItemAdapter(
    125                 this, expandedIds, repeatCheckedIds, selectedAlarms, previousDayMap, mAlarmsList);
    126         mAdapter.setLongClickListener(this);
    127 
    128         if (mRingtoneTitleCache == null) {
    129             mRingtoneTitleCache = new Bundle();
    130         }
    131 
    132         mAlarmsList.setAdapter(mAdapter);
    133         mAlarmsList.setVerticalScrollBarEnabled(true);
    134         mAlarmsList.enableSwipe(true);
    135         mAlarmsList.setOnCreateContextMenuListener(this);
    136         mAlarmsList.setOnItemSwipeListener(new SwipeableListView.OnItemSwipeListener() {
    137             @Override
    138             public void onSwipe(View view) {
    139                 final AlarmItemAdapter.ItemHolder itemHolder =
    140                         (AlarmItemAdapter.ItemHolder) view.getTag();
    141                 mAdapter.removeSelectedId(itemHolder.alarm.id);
    142                 updateActionMode();
    143                 asyncDeleteAlarm(itemHolder.alarm);
    144             }
    145         });
    146         mAlarmsList.setOnTouchListener(new View.OnTouchListener() {
    147             @Override
    148             public boolean onTouch(View view, MotionEvent event) {
    149                 hideUndoBar(true, event);
    150                 return false;
    151             }
    152         });
    153 
    154         mUndoBar = (ActionableToastBar) findViewById(R.id.undo_bar);
    155 
    156         if (mUndoShowing) {
    157             mUndoBar.show(new ActionableToastBar.ActionClickedListener() {
    158                 @Override
    159                 public void onActionClicked() {
    160                     asyncAddAlarm(mDeletedAlarm, false);
    161                     mDeletedAlarm = null;
    162                     mUndoShowing = false;
    163                 }
    164             }, 0, getResources().getString(R.string.alarm_deleted), true, R.string.alarm_undo,
    165                     true);
    166         }
    167 
    168         // Show action mode if needed
    169         int selectedNum = mAdapter.getSelectedItemsNum();
    170         if (selectedNum > 0) {
    171             mActionMode = startActionMode(this);
    172             setActionModeTitle(selectedNum);
    173         }
    174 
    175     }
    176 
    177     private void hideUndoBar(boolean animate, MotionEvent event) {
    178         if (mUndoBar != null) {
    179             if (event != null && mUndoBar.isEventInToastBar(event)) {
    180                 // Avoid touches inside the undo bar.
    181                 return;
    182             }
    183             mUndoBar.hide(animate);
    184         }
    185         mDeletedAlarm = null;
    186         mUndoShowing = false;
    187     }
    188 
    189     @Override
    190     protected void onSaveInstanceState(Bundle outState) {
    191         super.onSaveInstanceState(outState);
    192         outState.putIntArray(KEY_EXPANDED_IDS, mAdapter.getExpandedArray());
    193         outState.putIntArray(KEY_REPEAT_CHECKED_IDS, mAdapter.getRepeatArray());
    194         outState.putIntArray(KEY_SELECTED_ALARMS, mAdapter.getSelectedAlarmsArray());
    195         outState.putBundle(KEY_RINGTONE_TITLE_CACHE, mRingtoneTitleCache);
    196         outState.putParcelable(KEY_DELETED_ALARM, mDeletedAlarm);
    197         outState.putBoolean(KEY_UNDO_SHOWING, mUndoShowing);
    198         outState.putBundle(KEY_PREVIOUS_DAY_MAP, mAdapter.getPreviousDaysOfWeekMap());
    199         outState.putParcelable(KEY_SELECTED_ALARM, mSelectedAlarm);
    200     }
    201 
    202     private void updateLayout() {
    203         final ActionBar actionBar = getActionBar();
    204         if (actionBar != null) {
    205             actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP, ActionBar.DISPLAY_HOME_AS_UP);
    206         }
    207     }
    208 
    209     @Override
    210     protected void onDestroy() {
    211         super.onDestroy();
    212         ToastMaster.cancelToast();
    213     }
    214 
    215     @Override
    216     public boolean onOptionsItemSelected(MenuItem item) {
    217         hideUndoBar(true, null);
    218         switch (item.getItemId()) {
    219             case R.id.menu_item_settings:
    220                 startActivity(new Intent(this, SettingsActivity.class));
    221                 return true;
    222             case R.id.menu_item_add_alarm:
    223                 asyncAddAlarm();
    224                 return true;
    225             case R.id.menu_item_delete_alarm:
    226                 if (mAdapter != null) {
    227                     mAdapter.deleteSelectedAlarms();
    228                 }
    229                 return true;
    230             case android.R.id.home:
    231                 Intent intent = new Intent(this, DeskClock.class);
    232                 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
    233                 startActivity(intent);
    234                 return true;
    235             default:
    236 
    237                 break;
    238         }
    239         return super.onOptionsItemSelected(item);
    240     }
    241 
    242     @Override
    243     public boolean onCreateOptionsMenu(Menu menu) {
    244         getMenuInflater().inflate(R.menu.alarm_list_menu, menu);
    245         MenuItem help = menu.findItem(R.id.menu_item_help);
    246         if (help != null) {
    247             Utils.prepareHelpMenuItem(this, help);
    248         }
    249         return super.onCreateOptionsMenu(menu);
    250     }
    251 
    252     @Override
    253     protected void onRestart() {
    254         super.onRestart();
    255         // When the user places the app in the background by pressing "home",
    256         // dismiss the toast bar. However, since there is no way to determine if
    257         // home was pressed, just dismiss any existing toast bar when restarting
    258         // the app.
    259         if (mUndoBar != null) {
    260             hideUndoBar(false, null);
    261         }
    262     }
    263 
    264     // Callback used by AlarmTimePickerDialogFragment
    265     @Override
    266     public void onDialogTimeSet(Alarm alarm, int hourOfDay, int minute) {
    267         alarm.hour = hourOfDay;
    268         alarm.minutes = minute;
    269         alarm.enabled = true;
    270         mScrollToAlarmId = alarm.id;
    271         asyncUpdateAlarm(alarm, true);
    272     }
    273 
    274     private void showLabelDialog(final Alarm alarm) {
    275         final FragmentTransaction ft = getFragmentManager().beginTransaction();
    276         final Fragment prev = getFragmentManager().findFragmentByTag("label_dialog");
    277         if (prev != null) {
    278             ft.remove(prev);
    279         }
    280         ft.addToBackStack(null);
    281 
    282         // Create and show the dialog.
    283         final LabelDialogFragment newFragment = LabelDialogFragment.newInstance(alarm, alarm.label);
    284         newFragment.show(ft, "label_dialog");
    285     }
    286 
    287     // Callback used by AlarmLabelDialogFragment.
    288     @Override
    289     public void onDialogLabelSet(Alarm alarm, String label) {
    290         alarm.label = label;
    291         asyncUpdateAlarm(alarm, false);
    292     }
    293 
    294     @Override
    295     public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    296         return Alarms.getAlarmsCursorLoader(this);
    297     }
    298 
    299     @Override
    300     public void onLoadFinished(Loader<Cursor> cursorLoader, final Cursor data) {
    301         mAdapter.swapCursor(data);
    302         gotoAlarmIfSpecified();
    303     }
    304 
    305     /** If an alarm was passed in via intent and goes to that particular alarm in the list. */
    306     private void gotoAlarmIfSpecified() {
    307         final Intent intent = getIntent();
    308         if (mFirstLoad && intent != null) {
    309             final Alarm alarm = (Alarm) intent.getParcelableExtra(Alarms.ALARM_INTENT_EXTRA);
    310             if (alarm != null) {
    311                 scrollToAlarm(alarm.id);
    312             }
    313         } else if (mScrollToAlarmId != -1) {
    314             scrollToAlarm(mScrollToAlarmId);
    315             mScrollToAlarmId = -1;
    316         }
    317         mFirstLoad = false;
    318     }
    319 
    320     /**
    321      * Scroll to alarm with given alarm id.
    322      *
    323      * @param alarmId The alarm id to scroll to.
    324      */
    325     private void scrollToAlarm(int alarmId) {
    326         for (int i = 0; i < mAdapter.getCount(); i++) {
    327             long id = mAdapter.getItemId(i);
    328             if (id == alarmId) {
    329                 mAdapter.setNewAlarm(alarmId);
    330                 mAlarmsList.smoothScrollToPositionFromTop(i, 0);
    331 
    332                 final int firstPositionId = mAlarmsList.getFirstVisiblePosition();
    333                 final int childId = i - firstPositionId;
    334 
    335                 final View view = mAlarmsList.getChildAt(childId);
    336                 mAdapter.getView(i, view, mAlarmsList);
    337                 break;
    338             }
    339         }
    340     }
    341 
    342     @Override
    343     public void onLoaderReset(Loader<Cursor> cursorLoader) {
    344         mAdapter.swapCursor(null);
    345     }
    346 
    347     private void launchRingTonePicker(Alarm alarm) {
    348         mSelectedAlarm = alarm;
    349         final Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
    350         intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, alarm.alert);
    351         intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_ALARM);
    352         intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, false);
    353         startActivityForResult(intent, REQUEST_CODE_RINGTONE);
    354     }
    355 
    356     private void saveRingtoneUri(Intent intent) {
    357         final Uri uri = intent.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
    358         mSelectedAlarm.alert = uri;
    359         // Save the last selected ringtone as the default for new alarms
    360         RingtoneManager.setActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM, uri);
    361         asyncUpdateAlarm(mSelectedAlarm, false);
    362     }
    363 
    364     @Override
    365     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    366         if (resultCode == RESULT_OK) {
    367             switch (requestCode) {
    368                 case REQUEST_CODE_RINGTONE:
    369                     saveRingtoneUri(data);
    370                     break;
    371                 default:
    372                     Log.w("Unhandled request code in onActivityResult: " + requestCode);
    373             }
    374         }
    375     }
    376 
    377     /***
    378      * On long click, mark/unmark the selected view and activate/deactivate action mode
    379      */
    380     @Override
    381     public boolean onLongClick(View v) {
    382         mAdapter.toggleSelectState(v);
    383         mAdapter.notifyDataSetChanged();
    384         updateActionMode();
    385         return false;
    386     }
    387 
    388     /***
    389      * Activate/update/close action mode according to the number of selected views.
    390      */
    391     private void updateActionMode() {
    392         int selectedNum = mAdapter.getSelectedItemsNum();
    393         if (mActionMode == null && selectedNum > 0) {
    394             // Start the action mode
    395             mActionMode = startActionMode(this);
    396             setActionModeTitle(selectedNum);
    397         } else if (mActionMode != null) {
    398             if (selectedNum > 0) {
    399                 // Update the number of selected items in the title
    400                 setActionModeTitle(selectedNum);
    401             } else {
    402                 // No selected items. close the action mode
    403                 mActionMode.finish();
    404                 mActionMode = null;
    405             }
    406         }
    407     }
    408 
    409     /***
    410      * Display the number of selected items on the action bar in action mode
    411      * @param items - number of selected items
    412      */
    413     private void setActionModeTitle(int items) {
    414         mActionMode.setTitle(String.format(getString(R.string.alarms_selected), items));
    415     }
    416 
    417     public class AlarmItemAdapter extends CursorAdapter {
    418 
    419         private final Context mContext;
    420         private final LayoutInflater mFactory;
    421         private final String[] mShortWeekDayStrings;
    422         private final String[] mLongWeekDayStrings;
    423         private final int mColorLit;
    424         private final int mColorDim;
    425         private final int mBackgroundColorSelected;
    426         private final int mBackgroundColor;
    427         private final Typeface mRobotoNormal;
    428         private final Typeface mRobotoBold;
    429         private OnLongClickListener mLongClickListener;
    430         private final ListView mList;
    431 
    432         private final HashSet<Integer> mExpanded = new HashSet<Integer>();
    433         private final HashSet<Integer> mRepeatChecked = new HashSet<Integer>();
    434         private final HashSet<Integer> mSelectedAlarms = new HashSet<Integer>();
    435         private Bundle mPreviousDaysOfWeekMap = new Bundle();
    436 
    437         private final boolean mHasVibrator;
    438 
    439         // This determines the order in which it is shown and processed in the UI.
    440         private final int[] DAY_ORDER = new int[] {
    441                 Calendar.SUNDAY,
    442                 Calendar.MONDAY,
    443                 Calendar.TUESDAY,
    444                 Calendar.WEDNESDAY,
    445                 Calendar.THURSDAY,
    446                 Calendar.FRIDAY,
    447                 Calendar.SATURDAY,
    448         };
    449 
    450         public class ItemHolder {
    451 
    452             // views for optimization
    453             LinearLayout alarmItem;
    454             DigitalClock clock;
    455             Switch onoff;
    456             TextView daysOfWeek;
    457             TextView label;
    458             View expandArea;
    459             View infoArea;
    460             TextView clickableLabel;
    461             CheckBox repeat;
    462             LinearLayout repeatDays;
    463             ViewGroup[] dayButtonParents = new ViewGroup[7];
    464             ToggleButton[] dayButtons = new ToggleButton[7];
    465             CheckBox vibrate;
    466             ViewGroup collapse;
    467             TextView ringtone;
    468 
    469             // Other states
    470             Alarm alarm;
    471         }
    472 
    473         // Used for scrolling an expanded item in the list to make sure it is fully visible.
    474         private int mScrollAlarmId = -1;
    475         private final Runnable mScrollRunnable = new Runnable() {
    476             @Override
    477             public void run() {
    478                 if (mScrollAlarmId != -1) {
    479                     View v = getViewById(mScrollAlarmId);
    480                     if (v != null) {
    481                         Rect rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
    482                         mList.requestChildRectangleOnScreen(v, rect, false);
    483                     }
    484                     mScrollAlarmId = -1;
    485                 }
    486             }
    487         };
    488 
    489         public AlarmItemAdapter(Context context, int[] expandedIds, int[] repeatCheckedIds,
    490                 int[] selectedAlarms, Bundle previousDaysOfWeekMap, ListView list) {
    491             super(context, null, 0);
    492             mContext = context;
    493             mFactory = LayoutInflater.from(context);
    494             mList = list;
    495 
    496             DateFormatSymbols dfs = new DateFormatSymbols();
    497             mShortWeekDayStrings = dfs.getShortWeekdays();
    498             mLongWeekDayStrings = dfs.getWeekdays();
    499 
    500             Resources res = mContext.getResources();
    501             mColorLit = res.getColor(R.color.clock_white);
    502             mColorDim = res.getColor(R.color.clock_gray);
    503             mBackgroundColorSelected = res.getColor(R.color.alarm_selected_color);
    504             mBackgroundColor = res.getColor(R.color.alarm_whiteish);
    505 
    506 
    507             mRobotoBold = Typeface.create("sans-serif-condensed", Typeface.BOLD);
    508             mRobotoNormal = Typeface.create("sans-serif-condensed", Typeface.NORMAL);
    509 
    510             if (expandedIds != null) {
    511                 buildHashSetFromArray(expandedIds, mExpanded);
    512             }
    513             if (repeatCheckedIds != null) {
    514                 buildHashSetFromArray(repeatCheckedIds, mRepeatChecked);
    515             }
    516             if (previousDaysOfWeekMap != null) {
    517                 mPreviousDaysOfWeekMap = previousDaysOfWeekMap;
    518             }
    519             if (selectedAlarms != null) {
    520                 buildHashSetFromArray(selectedAlarms, mSelectedAlarms);
    521             }
    522 
    523             mHasVibrator = ((Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE))
    524                     .hasVibrator();
    525         }
    526 
    527         public void removeSelectedId(int id) {
    528             mSelectedAlarms.remove(id);
    529         }
    530 
    531         public void setLongClickListener(OnLongClickListener l) {
    532             mLongClickListener = l;
    533         }
    534 
    535         @Override
    536         public View getView(int position, View convertView, ViewGroup parent) {
    537             if (!getCursor().moveToPosition(position)) {
    538                 // May happen if the last alarm was deleted and the cursor refreshed while the
    539                 // list is updated.
    540                 Log.v("couldn't move cursor to position " + position);
    541                 return null;
    542             }
    543             View v;
    544             if (convertView == null) {
    545                 v = newView(mContext, getCursor(), parent);
    546             } else {
    547                 // Do a translation check to test for animation. Change this to something more
    548                 // reliable and robust in the future.
    549                 if (convertView.getTranslationX() != 0 || convertView.getTranslationY() != 0) {
    550                     // view was animated, reset
    551                     v = newView(mContext, getCursor(), parent);
    552                 } else {
    553                     v = convertView;
    554                 }
    555             }
    556             bindView(v, mContext, getCursor());
    557             return v;
    558         }
    559 
    560         @Override
    561         public View newView(Context context, Cursor cursor, ViewGroup parent) {
    562             final View view = mFactory.inflate(R.layout.alarm_time, parent, false);
    563 
    564             // standard view holder optimization
    565             final ItemHolder holder = new ItemHolder();
    566             holder.alarmItem = (LinearLayout) view.findViewById(R.id.alarm_item);
    567             holder.clock = (DigitalClock) view.findViewById(R.id.digital_clock);
    568             holder.clock.setLive(false);
    569             holder.onoff = (Switch) view.findViewById(R.id.onoff);
    570             holder.onoff.setTypeface(mRobotoNormal);
    571             holder.daysOfWeek = (TextView) view.findViewById(R.id.daysOfWeek);
    572             holder.label = (TextView) view.findViewById(R.id.label);
    573             holder.expandArea = view.findViewById(R.id.expand_area);
    574             holder.infoArea = view.findViewById(R.id.info_area);
    575             holder.repeat = (CheckBox) view.findViewById(R.id.repeat_onoff);
    576             holder.clickableLabel = (TextView) view.findViewById(R.id.edit_label);
    577             holder.repeatDays = (LinearLayout) view.findViewById(R.id.repeat_days);
    578 
    579             // Build button for each day.
    580             for (int i = 0; i < 7; i++) {
    581                 final ViewGroup viewgroup = (ViewGroup) mFactory.inflate(R.layout.day_button,
    582                         holder.repeatDays, false);
    583                 final ToggleButton button = (ToggleButton) viewgroup.getChildAt(0);
    584                 final int dayToShowIndex = DAY_ORDER[i];
    585                 button.setText(mShortWeekDayStrings[dayToShowIndex]);
    586                 button.setTextOn(mShortWeekDayStrings[dayToShowIndex]);
    587                 button.setTextOff(mShortWeekDayStrings[dayToShowIndex]);
    588                 button.setContentDescription(mLongWeekDayStrings[dayToShowIndex]);
    589                 holder.repeatDays.addView(viewgroup);
    590                 holder.dayButtons[i] = button;
    591                 holder.dayButtonParents[i] = viewgroup;
    592             }
    593             holder.vibrate = (CheckBox) view.findViewById(R.id.vibrate_onoff);
    594             holder.collapse = (ViewGroup) view.findViewById(R.id.collapse);
    595             holder.ringtone = (TextView) view.findViewById(R.id.choose_ringtone);
    596 
    597             view.setTag(holder);
    598             return view;
    599         }
    600 
    601         @Override
    602         public void bindView(View view, Context context, final Cursor cursor) {
    603             final Alarm alarm = new Alarm(cursor);
    604             final ItemHolder itemHolder = (ItemHolder) view.getTag();
    605             itemHolder.alarm = alarm;
    606 
    607             // We must unset the listener first because this maybe a recycled view so changing the
    608             // state would affect the wrong alarm.
    609             itemHolder.onoff.setOnCheckedChangeListener(null);
    610             itemHolder.onoff.setChecked(alarm.enabled);
    611             if (mSelectedAlarms.contains(itemHolder.alarm.id)) {
    612                 itemHolder.alarmItem.setBackgroundColor(mBackgroundColorSelected);
    613                 itemHolder.alarmItem.setAlpha(1f);
    614             } else {
    615                 itemHolder.alarmItem.setBackgroundColor(mBackgroundColor);
    616                 if (itemHolder.onoff.isChecked()) {
    617                     itemHolder.alarmItem.setAlpha(1f);
    618                 } else {
    619                     itemHolder.alarmItem.setAlpha(0.5f);
    620                 }
    621             }
    622             final CompoundButton.OnCheckedChangeListener onOffListener =
    623                     new CompoundButton.OnCheckedChangeListener() {
    624                         @Override
    625                         public void onCheckedChanged(CompoundButton compoundButton,
    626                                 boolean checked) {
    627                             //When action mode is on - simulate long click
    628                             if (doLongClick(compoundButton)) {
    629                                 return;
    630                             }
    631                             if (checked != alarm.enabled) {
    632                                 if (checked) {
    633                                     itemHolder.alarmItem.setAlpha(1f);
    634                                 } else {
    635                                     itemHolder.alarmItem.setAlpha(0.5f);
    636                                 }
    637                                 alarm.enabled = checked;
    638                                 asyncUpdateAlarm(alarm, alarm.enabled);
    639                             }
    640                         }
    641                     };
    642 
    643             itemHolder.onoff.setOnCheckedChangeListener(onOffListener);
    644             itemHolder.onoff.setOnLongClickListener(mLongClickListener);
    645 
    646             itemHolder.clock.updateTime(alarm.hour, alarm.minutes);
    647             itemHolder.clock.setClickable(true);
    648             itemHolder.clock.setOnClickListener(new View.OnClickListener() {
    649                 @Override
    650                 public void onClick(View view) {
    651                     //When action mode is on - simulate long click
    652                     if (doLongClick(view)) {
    653                         return;
    654                     }
    655                     AlarmUtils.showTimeEditDialog(AlarmClock.this.getFragmentManager(), alarm);
    656                     expandAlarm(itemHolder);
    657                     itemHolder.alarmItem.post(mScrollRunnable);
    658                 }
    659             });
    660             itemHolder.clock.setOnLongClickListener(mLongClickListener);
    661 
    662             itemHolder.expandArea.setVisibility(isAlarmExpanded(alarm) ? View.VISIBLE : View.GONE);
    663             itemHolder.expandArea.setOnLongClickListener(mLongClickListener);
    664             itemHolder.infoArea.setVisibility(!isAlarmExpanded(alarm) ? View.VISIBLE : View.GONE);
    665             itemHolder.infoArea.setOnClickListener(new View.OnClickListener() {
    666                 @Override
    667                 public void onClick(View view) {
    668                     //When action mode is on - simulate long click
    669                     if (doLongClick(view)) {
    670                         return;
    671                     }
    672                     expandAlarm(itemHolder);
    673                     itemHolder.alarmItem.post(mScrollRunnable);
    674                 }
    675             });
    676             itemHolder.infoArea.setOnLongClickListener(mLongClickListener);
    677 
    678             String colons = "";
    679             // Set the repeat text or leave it blank if it does not repeat.
    680             final String daysOfWeekStr = alarm.daysOfWeek.toString(AlarmClock.this, false);
    681             if (daysOfWeekStr != null && daysOfWeekStr.length() != 0) {
    682                 itemHolder.daysOfWeek.setText(daysOfWeekStr);
    683                 itemHolder.daysOfWeek.setContentDescription(
    684                         alarm.daysOfWeek.toAccessibilityString(AlarmClock.this));
    685                 itemHolder.daysOfWeek.setVisibility(View.VISIBLE);
    686                 colons = ": ";
    687                 itemHolder.daysOfWeek.setOnClickListener(new View.OnClickListener() {
    688                     @Override
    689                     public void onClick(View view) {
    690                         //When action mode is on - simulate long click
    691                         if (doLongClick(view)) {
    692                             return;
    693                         }
    694                         expandAlarm(itemHolder);
    695                         itemHolder.alarmItem.post(mScrollRunnable);
    696                     }
    697                 });
    698                 itemHolder.daysOfWeek.setOnLongClickListener(mLongClickListener);
    699 
    700             } else {
    701                 itemHolder.daysOfWeek.setVisibility(View.GONE);
    702             }
    703 
    704             if (alarm.label != null && alarm.label.length() != 0) {
    705                 itemHolder.label.setText(alarm.label + colons);
    706                 itemHolder.label.setVisibility(View.VISIBLE);
    707                 itemHolder.label.setContentDescription(
    708                         mContext.getResources().getString(R.string.label_description) + " "
    709                         + alarm.label);
    710                 itemHolder.label.setOnClickListener(new View.OnClickListener() {
    711                     @Override
    712                     public void onClick(View view) {
    713                         //When action mode is on - simulate long click
    714                         if (doLongClick(view)) {
    715                             return;
    716                         }
    717                         expandAlarm(itemHolder);
    718                         itemHolder.alarmItem.post(mScrollRunnable);
    719                     }
    720                 });
    721                 itemHolder.label.setOnLongClickListener(mLongClickListener);
    722             } else {
    723                 itemHolder.label.setVisibility(View.GONE);
    724             }
    725 
    726             if (isAlarmExpanded(alarm)) {
    727                 expandAlarm(itemHolder);
    728             }
    729             view.setOnLongClickListener(mLongClickListener);
    730             view.setOnClickListener(new View.OnClickListener() {
    731                 @Override
    732                 public void onClick(View view) {
    733                     //When action mode is on - simulate long click
    734                     doLongClick(view);
    735                 }
    736             });
    737         }
    738 
    739         private void bindExpandArea(final ItemHolder itemHolder, final Alarm alarm) {
    740             // Views in here are not bound until the item is expanded.
    741 
    742             if (alarm.label != null && alarm.label.length() > 0) {
    743                 itemHolder.clickableLabel.setText(alarm.label);
    744                 itemHolder.clickableLabel.setTextColor(mColorLit);
    745             } else {
    746                 itemHolder.clickableLabel.setText(R.string.label);
    747                 itemHolder.clickableLabel.setTextColor(mColorDim);
    748             }
    749             itemHolder.clickableLabel.setOnClickListener(new View.OnClickListener() {
    750                 @Override
    751                 public void onClick(View view) {
    752                     //When action mode is on - simulate long click
    753                     if (doLongClick(view)) {
    754                         return;
    755                     }
    756                     showLabelDialog(alarm);
    757                 }
    758             });
    759             itemHolder.clickableLabel.setOnLongClickListener(mLongClickListener);
    760 
    761             if (mRepeatChecked.contains(alarm.id) || itemHolder.alarm.daysOfWeek.isRepeatSet()) {
    762                 itemHolder.repeat.setChecked(true);
    763                 itemHolder.repeatDays.setVisibility(View.VISIBLE);
    764                 itemHolder.repeatDays.setOnLongClickListener(mLongClickListener);
    765             } else {
    766                 itemHolder.repeat.setChecked(false);
    767                 itemHolder.repeatDays.setVisibility(View.GONE);
    768             }
    769             itemHolder.repeat.setOnClickListener(new View.OnClickListener() {
    770                 @Override
    771                 public void onClick(View view) {
    772                     //When action mode is on - simulate long click
    773                     if (doLongClick(view)) {
    774                         return;
    775                     }
    776                     final boolean checked = ((CheckBox) view).isChecked();
    777                     if (checked) {
    778                         // Show days
    779                         itemHolder.repeatDays.setVisibility(View.VISIBLE);
    780                         mRepeatChecked.add(alarm.id);
    781 
    782                         // Set all previously set days
    783                         // or
    784                         // Set all days if no previous.
    785                         final int daysOfWeekCoded = mPreviousDaysOfWeekMap.getInt("" + alarm.id);
    786                         if (daysOfWeekCoded == 0) {
    787                             for (int day : DAY_ORDER) {
    788                                 alarm.daysOfWeek.setDayOfWeek(day, true);
    789                             }
    790                         } else {
    791                             alarm.daysOfWeek.set(new Alarm.DaysOfWeek(daysOfWeekCoded));
    792                         }
    793                         updateDaysOfWeekButtons(itemHolder, alarm.daysOfWeek);
    794                     } else {
    795                         itemHolder.repeatDays.setVisibility(View.GONE);
    796                         mRepeatChecked.remove(alarm.id);
    797 
    798                         // Remember the set days in case the user wants it back.
    799                         final int daysOfWeekCoded = alarm.daysOfWeek.getCoded();
    800                         mPreviousDaysOfWeekMap.putInt("" + alarm.id, daysOfWeekCoded);
    801 
    802                         // Remove all repeat days
    803                         alarm.daysOfWeek.set(new Alarm.DaysOfWeek(0));
    804                     }
    805                     asyncUpdateAlarm(alarm, false);
    806                 }
    807             });
    808             itemHolder.repeat.setOnLongClickListener(mLongClickListener);
    809 
    810             updateDaysOfWeekButtons(itemHolder, alarm.daysOfWeek);
    811             for (int i = 0; i < 7; i++) {
    812                 final int buttonIndex = i;
    813 
    814                 itemHolder.dayButtonParents[i].setOnClickListener(new View.OnClickListener() {
    815                     @Override
    816                     public void onClick(View view) {
    817                         //When action mode is on - simulate long click
    818                         if (doLongClick(view)) {
    819                             return;
    820                         }
    821                         itemHolder.dayButtons[buttonIndex].toggle();
    822                         final boolean checked = itemHolder.dayButtons[buttonIndex].isChecked();
    823                         int day = DAY_ORDER[buttonIndex];
    824                         alarm.daysOfWeek.setDayOfWeek(day, checked);
    825                         if (checked) {
    826                             turnOnDayOfWeek(itemHolder, buttonIndex);
    827                         } else {
    828                             turnOffDayOfWeek(itemHolder, buttonIndex);
    829 
    830                             // See if this was the last day, if so, un-check the repeat box.
    831                             if (alarm.daysOfWeek.getCoded() == 0) {
    832                                 itemHolder.repeatDays.setVisibility(View.GONE);
    833                                 itemHolder.repeat.setTextColor(mColorDim);
    834                                 mRepeatChecked.remove(alarm.id);
    835 
    836                                 // Remember the set days in case the user wants it back.
    837                                 mPreviousDaysOfWeekMap.putInt("" + alarm.id, 0);
    838                             }
    839                         }
    840                         asyncUpdateAlarm(alarm, false);
    841                     }
    842                 });
    843             }
    844 
    845 
    846             if (!mHasVibrator) {
    847                 itemHolder.vibrate.setVisibility(View.INVISIBLE);
    848             } else {
    849                 itemHolder.vibrate.setVisibility(View.VISIBLE);
    850                 if (!alarm.vibrate) {
    851                     itemHolder.vibrate.setChecked(false);
    852                     itemHolder.vibrate.setTextColor(mColorDim);
    853                 } else {
    854                     itemHolder.vibrate.setChecked(true);
    855                     itemHolder.vibrate.setTextColor(mColorLit);
    856                 }
    857                 itemHolder.vibrate.setOnLongClickListener(mLongClickListener);
    858             }
    859 
    860             itemHolder.vibrate.setOnClickListener(new View.OnClickListener() {
    861                 @Override
    862                 public void onClick(View v) {
    863                     final boolean checked = ((CheckBox) v).isChecked();
    864                     //When action mode is on - simulate long click
    865                     if (doLongClick(v)) {
    866                         return;
    867                     }
    868                     if (checked) {
    869                         itemHolder.vibrate.setTextColor(mColorLit);
    870                     } else {
    871                         itemHolder.vibrate.setTextColor(mColorDim);
    872                     }
    873                     alarm.vibrate = checked;
    874                     asyncUpdateAlarm(alarm, false);
    875                 }
    876             });
    877 
    878             itemHolder.collapse.setOnClickListener(new View.OnClickListener() {
    879                 @Override
    880                 public void onClick(View v) {
    881                     //When action mode is on - simulate long click
    882                     if (doLongClick(v)) {
    883                         return;
    884                     }
    885                     itemHolder.expandArea.setVisibility(LinearLayout.GONE);
    886                     itemHolder.infoArea.setVisibility(View.VISIBLE);
    887                     collapseAlarm(alarm);
    888                 }
    889             });
    890             itemHolder.collapse.setOnLongClickListener(mLongClickListener);
    891 
    892             final String ringtone;
    893             if (alarm.alert == null) {
    894                 ringtone = mContext.getResources().getString(R.string.silent_alarm_summary);
    895             } else {
    896                 ringtone = getRingToneTitle(alarm.alert);
    897             }
    898             itemHolder.ringtone.setText(ringtone);
    899             itemHolder.ringtone.setContentDescription(
    900                     mContext.getResources().getString(R.string.ringtone_description) + " "
    901                             + ringtone);
    902             itemHolder.ringtone.setOnClickListener(new View.OnClickListener() {
    903                 @Override
    904                 public void onClick(View view) {
    905                     //When action mode is on - simulate long click
    906                     if (doLongClick(view)) {
    907                         return;
    908                     }
    909                     launchRingTonePicker(alarm);
    910                 }
    911             });
    912             itemHolder.ringtone.setOnLongClickListener(mLongClickListener);
    913         }
    914 
    915         private void updateDaysOfWeekButtons(ItemHolder holder, Alarm.DaysOfWeek daysOfWeek) {
    916             HashSet<Integer> setDays = daysOfWeek.getSetDays();
    917             for (int i = 0; i < 7; i++) {
    918                 if (setDays.contains(DAY_ORDER[i])) {
    919                     turnOnDayOfWeek(holder, i);
    920                 } else {
    921                     turnOffDayOfWeek(holder, i);
    922                 }
    923             }
    924         }
    925 
    926         /***
    927          * Simulate a long click to override clicks on view when ActionMode is on
    928          * Returns true if handled a long click, false if not
    929          */
    930         private boolean doLongClick(View v) {
    931             if (mActionMode == null) {
    932                 return false;
    933             }
    934             v = getTopParent(v);
    935             if (v != null) {
    936                 toggleSelectState(v);
    937                 notifyDataSetChanged();
    938                 updateActionMode();
    939             }
    940             return true;
    941         }
    942 
    943         public void toggleSelectState(View v) {
    944             // long press could be on the parent view or one of its childs, so find the parent view
    945             v = getTopParent(v);
    946             if (v != null) {
    947                 int id = ((ItemHolder)v.getTag()).alarm.id;
    948                 if (mSelectedAlarms.contains(id)) {
    949                     mSelectedAlarms.remove(id);
    950                 } else {
    951                     mSelectedAlarms.add(id);
    952                 }
    953             }
    954         }
    955 
    956         private View getTopParent(View v) {
    957             while (v != null && v.getId() != R.id.alarm_item) {
    958                 v = (View) v.getParent();
    959             }
    960             return v;
    961         }
    962 
    963         public int getSelectedItemsNum() {
    964             return mSelectedAlarms.size();
    965         }
    966 
    967         private void turnOffDayOfWeek(ItemHolder holder, int dayIndex) {
    968             holder.dayButtons[dayIndex].setChecked(false);
    969             holder.dayButtons[dayIndex].setTextColor(mColorDim);
    970             holder.dayButtons[dayIndex].setTypeface(mRobotoNormal);
    971         }
    972 
    973         private void turnOnDayOfWeek(ItemHolder holder, int dayIndex) {
    974             holder.dayButtons[dayIndex].setChecked(true);
    975             holder.dayButtons[dayIndex].setTextColor(mColorLit);
    976             holder.dayButtons[dayIndex].setTypeface(mRobotoBold);
    977         }
    978 
    979 
    980         /**
    981          * Does a read-through cache for ringtone titles.
    982          *
    983          * @param uri The uri of the ringtone.
    984          * @return The ringtone title. {@literal null} if no matching ringtone found.
    985          */
    986         private String getRingToneTitle(Uri uri) {
    987             // Try the cache first
    988             String title = mRingtoneTitleCache.getString(uri.toString());
    989             if (title == null) {
    990                 // This is slow because a media player is created during Ringtone object creation.
    991                 Ringtone ringTone = RingtoneManager.getRingtone(mContext, uri);
    992                 title = ringTone.getTitle(mContext);
    993                 if (title != null) {
    994                     mRingtoneTitleCache.putString(uri.toString(), title);
    995                 }
    996             }
    997             return title;
    998         }
    999 
   1000         public void setNewAlarm(int alarmId) {
   1001             mExpanded.add(alarmId);
   1002         }
   1003 
   1004         /**
   1005          * Expands the alarm for editing.
   1006          *
   1007          * @param itemHolder The item holder instance.
   1008          */
   1009         private void expandAlarm(ItemHolder itemHolder) {
   1010             itemHolder.expandArea.setVisibility(View.VISIBLE);
   1011             itemHolder.expandArea.setOnClickListener(new View.OnClickListener() {
   1012                 @Override
   1013                 public void onClick(View view) {
   1014                     //When action mode is on - simulate long click
   1015                     doLongClick(view);
   1016                 }
   1017             });
   1018             itemHolder.infoArea.setVisibility(View.GONE);
   1019 
   1020             mExpanded.add(itemHolder.alarm.id);
   1021             bindExpandArea(itemHolder, itemHolder.alarm);
   1022             // Scroll the view to make sure it is fully viewed
   1023             mScrollAlarmId = itemHolder.alarm.id;
   1024         }
   1025 
   1026         private boolean isAlarmExpanded(Alarm alarm) {
   1027             return mExpanded.contains(alarm.id);
   1028         }
   1029 
   1030         private void collapseAlarm(Alarm alarm) {
   1031             mExpanded.remove(alarm.id);
   1032         }
   1033 
   1034         @Override
   1035         public int getViewTypeCount() {
   1036             return 1;
   1037         }
   1038 
   1039         private View getViewById(int id) {
   1040             for (int i = 0; i < mList.getCount(); i++) {
   1041                 View v = mList.getChildAt(i);
   1042                 if (v != null) {
   1043                     ItemHolder h = (ItemHolder)(v.getTag());
   1044                     if (h != null && h.alarm.id == id) {
   1045                         return v;
   1046                     }
   1047                 }
   1048             }
   1049             return null;
   1050         }
   1051 
   1052         public int[] getExpandedArray() {
   1053             final int[] ids = new int[mExpanded.size()];
   1054             int index = 0;
   1055             for (int id : mExpanded) {
   1056                 ids[index] = id;
   1057                 index++;
   1058             }
   1059             return ids;
   1060         }
   1061 
   1062         public int[] getSelectedAlarmsArray() {
   1063             final int[] ids = new int[mSelectedAlarms.size()];
   1064             int index = 0;
   1065             for (int id : mSelectedAlarms) {
   1066                 ids[index] = id;
   1067                 index++;
   1068             }
   1069             return ids;
   1070         }
   1071 
   1072         public int[] getRepeatArray() {
   1073             final int[] ids = new int[mRepeatChecked.size()];
   1074             int index = 0;
   1075             for (int id : mRepeatChecked) {
   1076                 ids[index] = id;
   1077                 index++;
   1078             }
   1079             return ids;
   1080         }
   1081 
   1082         public Bundle getPreviousDaysOfWeekMap() {
   1083             return mPreviousDaysOfWeekMap;
   1084         }
   1085 
   1086         private void buildHashSetFromArray(int[] ids, HashSet<Integer> set) {
   1087             for (int id : ids) {
   1088                 set.add(id);
   1089             }
   1090         }
   1091 
   1092         public void deleteSelectedAlarms() {
   1093             Integer ids [] = new Integer[mSelectedAlarms.size()];
   1094             int index = 0;
   1095             for (int id : mSelectedAlarms) {
   1096                 ids[index] = id;
   1097                 index ++;
   1098             }
   1099             asyncDeleteAlarm(ids);
   1100             clearSelectedAlarms();
   1101         }
   1102 
   1103         public void clearSelectedAlarms() {
   1104             mSelectedAlarms.clear();
   1105             notifyDataSetChanged();
   1106         }
   1107     }
   1108 
   1109     private void asyncAddAlarm() {
   1110         Alarm a = new Alarm();
   1111         a.alert = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM);
   1112         asyncAddAlarm(a, true);
   1113     }
   1114 
   1115     private void asyncDeleteAlarm(final Integer [] alarmIds) {
   1116         final AsyncTask<Integer, Void, Void> deleteTask = new AsyncTask<Integer, Void, Void>() {
   1117             @Override
   1118             protected Void doInBackground(Integer... ids) {
   1119                 for (final int id : ids) {
   1120                     Alarms.deleteAlarm(AlarmClock.this, id);
   1121                 }
   1122                 return null;
   1123             }
   1124         };
   1125         deleteTask.execute(alarmIds);
   1126     }
   1127 
   1128     private void asyncDeleteAlarm(final Alarm alarm) {
   1129         final AsyncTask<Alarm, Void, Void> deleteTask = new AsyncTask<Alarm, Void, Void>() {
   1130 
   1131             @Override
   1132             protected Void doInBackground(Alarm... alarms) {
   1133                 for (final Alarm alarm : alarms) {
   1134                     Alarms.deleteAlarm(AlarmClock.this, alarm.id);
   1135                 }
   1136                 return null;
   1137             }
   1138         };
   1139         mDeletedAlarm = alarm;
   1140         mUndoShowing = true;
   1141         deleteTask.execute(alarm);
   1142         mUndoBar.show(new ActionableToastBar.ActionClickedListener() {
   1143             @Override
   1144             public void onActionClicked() {
   1145                 asyncAddAlarm(alarm, false);
   1146                 mDeletedAlarm = null;
   1147                 mUndoShowing = false;
   1148             }
   1149         }, 0, getResources().getString(R.string.alarm_deleted), true, R.string.alarm_undo, true);
   1150     }
   1151 
   1152     private void asyncAddAlarm(final Alarm alarm, final boolean showTimePicker) {
   1153         final AsyncTask<Void, Void, Void> updateTask = new AsyncTask<Void, Void, Void>() {
   1154             @Override
   1155             protected Void doInBackground(Void... aVoid) {
   1156                 Alarms.addAlarm(AlarmClock.this, alarm);
   1157                 return null;
   1158             }
   1159 
   1160             @Override
   1161             protected void onPostExecute(Void aVoid) {
   1162                 if (alarm.enabled) {
   1163                     popToast(alarm);
   1164                 }
   1165                 mAdapter.setNewAlarm(alarm.id);
   1166                 scrollToAlarm(alarm.id);
   1167 
   1168                 // We need to refresh the first view item because bindView may have been called
   1169                 // before setNewAlarm took effect. In that case, the newly created alarm will not be
   1170                 // expanded.
   1171                 View view = mAlarmsList.getChildAt(0);
   1172                 mAdapter.getView(0, view, mAlarmsList);
   1173                 if (showTimePicker) {
   1174                     AlarmUtils.showTimeEditDialog(AlarmClock.this.getFragmentManager(), alarm);
   1175                 }
   1176             }
   1177         };
   1178         updateTask.execute();
   1179     }
   1180 
   1181     private void asyncUpdateAlarm(final Alarm alarm, final boolean popToast) {
   1182         final AsyncTask<Alarm, Void, Void> updateTask = new AsyncTask<Alarm, Void, Void>() {
   1183             @Override
   1184             protected Void doInBackground(Alarm... alarms) {
   1185                 for (final Alarm alarm : alarms) {
   1186                     Alarms.setAlarm(AlarmClock.this, alarm);
   1187                 }
   1188                 return null;
   1189             }
   1190 
   1191             @Override
   1192             protected void onPostExecute(Void aVoid) {
   1193                 if (popToast) {
   1194                     popToast(alarm);
   1195                 }
   1196             }
   1197         };
   1198         updateTask.execute(alarm);
   1199     }
   1200 
   1201     private void popToast(Alarm alarm) {
   1202         AlarmUtils.popAlarmSetToast(this, alarm.hour, alarm.minutes, alarm.daysOfWeek);
   1203     }
   1204 
   1205     /***
   1206      * Support for action mode when the user long presses an item in the alarms list
   1207      */
   1208 
   1209     @Override
   1210     public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
   1211         switch (item.getItemId()) {
   1212             // Delete selected items and close CAB.
   1213             case R.id.menu_item_delete_alarm:
   1214                 if (mAdapter != null) {
   1215                     mAdapter.deleteSelectedAlarms();
   1216                     mode.finish();
   1217                 }
   1218                 break;
   1219             default:
   1220                 break;
   1221         }
   1222         return false;
   1223     }
   1224 
   1225     @Override
   1226     public boolean onCreateActionMode(ActionMode mode, Menu menu) {
   1227         getMenuInflater().inflate(R.menu.alarm_cab_menu, menu);
   1228         return true;
   1229     }
   1230 
   1231     @Override
   1232     public void onDestroyActionMode(ActionMode arg0) {
   1233         if(mAdapter != null) {
   1234             mAdapter.clearSelectedAlarms();
   1235         }
   1236         mActionMode = null;
   1237     }
   1238 
   1239     @Override
   1240     public boolean onPrepareActionMode(ActionMode arg0, Menu arg1) {
   1241         return false;
   1242     }
   1243 
   1244 }
   1245