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.AlertDialog;
     21 import android.content.Context;
     22 import android.content.DialogInterface;
     23 import android.content.Intent;
     24 import android.os.Bundle;
     25 import android.os.Handler;
     26 import android.os.Vibrator;
     27 import android.preference.CheckBoxPreference;
     28 import android.preference.Preference;
     29 import android.preference.PreferenceActivity;
     30 import android.preference.PreferenceScreen;
     31 import android.view.LayoutInflater;
     32 import android.view.Menu;
     33 import android.view.MenuItem;
     34 import android.view.View;
     35 import android.view.View.OnClickListener;
     36 import android.widget.Button;
     37 import android.widget.EditText;
     38 import android.widget.ListView;
     39 
     40 /**
     41  * Manages each alarm
     42  */
     43 public class SetAlarm extends PreferenceActivity implements Preference.OnPreferenceChangeListener,
     44         AlarmTimePickerDialogFragment.AlarmTimePickerDialogHandler {
     45 
     46     private static final String KEY_CURRENT_ALARM = "currentAlarm";
     47     private static final String KEY_ORIGINAL_ALARM = "originalAlarm";
     48     private static final String KEY_TIME_PICKER_BUNDLE = "timePickerBundle";
     49 
     50     private EditText mLabel;
     51     private CheckBoxPreference mEnabledPref;
     52     private Preference mTimePref;
     53     private AlarmPreference mAlarmPref;
     54     private CheckBoxPreference mVibratePref;
     55     private RepeatPreference mRepeatPref;
     56 
     57     private int     mId;
     58     private int     mHour;
     59     private int     mMinute;
     60     private Alarm   mOriginalAlarm;
     61 
     62     @Override
     63     protected void onCreate(Bundle icicle) {
     64         super.onCreate(icicle);
     65 
     66         // Override the default content view.
     67         setContentView(R.layout.set_alarm);
     68 
     69         EditText label = (EditText) getLayoutInflater().inflate(R.layout.alarm_label, null);
     70         ListView list = (ListView) findViewById(android.R.id.list);
     71         list.addFooterView(label);
     72 
     73         // TODO Stop using preferences for this view. Save on done, not after
     74         // each change.
     75         addPreferencesFromResource(R.xml.alarm_prefs);
     76 
     77         // Get each preference so we can retrieve the value later.
     78         mLabel = label;
     79         mEnabledPref = (CheckBoxPreference) findPreference("enabled");
     80         mEnabledPref.setOnPreferenceChangeListener(this);
     81         mTimePref = findPreference("time");
     82         mAlarmPref = (AlarmPreference) findPreference("alarm");
     83         mAlarmPref.setOnPreferenceChangeListener(this);
     84         mVibratePref = (CheckBoxPreference) findPreference("vibrate");
     85         mVibratePref.setOnPreferenceChangeListener(this);
     86         Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
     87         if (!v.hasVibrator()) {
     88             getPreferenceScreen().removePreference(mVibratePref);
     89         }
     90         mRepeatPref = (RepeatPreference) findPreference("setRepeat");
     91         mRepeatPref.setOnPreferenceChangeListener(this);
     92 
     93         Intent i = getIntent();
     94         Alarm alarm = i.getParcelableExtra(Alarms.ALARM_INTENT_EXTRA);
     95 
     96         if (alarm == null) {
     97             // No alarm means create a new alarm.
     98             alarm = new Alarm();
     99         }
    100         mOriginalAlarm = alarm;
    101 
    102         // Populate the prefs with the original alarm data.  updatePrefs also
    103         // sets mId so it must be called before checking mId below.
    104         updatePrefs(mOriginalAlarm);
    105 
    106         // We have to do this to get the save/cancel buttons to highlight on
    107         // their own.
    108         getListView().setItemsCanFocus(true);
    109 
    110         ActionBar actionBar = getActionBar();
    111         if (actionBar != null) {
    112             actionBar.setDisplayOptions(
    113                     0, ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_SHOW_TITLE);
    114             LayoutInflater inflater = (LayoutInflater) getSystemService
    115                     (Context.LAYOUT_INFLATER_SERVICE);
    116             View customActionBarView = inflater.inflate(R.layout.set_alarm_action_bar, null);
    117             actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
    118                     ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_SHOW_HOME |
    119                     ActionBar.DISPLAY_SHOW_TITLE);
    120             actionBar.setCustomView(customActionBarView);
    121             View saveMenuItem = customActionBarView.findViewById(R.id.save_menu_item);
    122             saveMenuItem.setOnClickListener(new OnClickListener() {
    123                 @Override
    124                 public void onClick(View v) {
    125                     saveAndExit();
    126                 }
    127             });
    128         }
    129 
    130         // Attach actions to each button.
    131         Button b = (Button) findViewById(R.id.alarm_save);
    132         if (b != null) {
    133             b.setOnClickListener(new View.OnClickListener() {
    134                     public void onClick(View v) {
    135                         long time = saveAlarm(null);
    136                         if(mEnabledPref.isChecked()) {
    137                             AlarmUtils.popAlarmSetToast(SetAlarm.this, time);
    138                         }
    139                         finish();
    140                     }
    141             });
    142         }
    143         b = (Button) findViewById(R.id.alarm_revert);
    144         if (b != null) {
    145             b.setOnClickListener(new View.OnClickListener() {
    146                 public void onClick(View v) {
    147                     revert();
    148                     finish();
    149                 }
    150             });
    151         }
    152         b = (Button) findViewById(R.id.alarm_delete);
    153         if (b != null) {
    154             if (mId == -1) {
    155                 b.setEnabled(false);
    156                 b.setVisibility(View.GONE);
    157             } else {
    158                 b.setVisibility(View.VISIBLE);
    159                 b.setOnClickListener(new View.OnClickListener() {
    160                     public void onClick(View v) {
    161                         deleteAlarm();
    162                     }
    163                 });
    164             }
    165         }
    166 }
    167 
    168     @Override
    169     public boolean onOptionsItemSelected(MenuItem item) {
    170         if (item.getItemId() == R.id.menu_delete) {
    171             deleteAlarm();
    172             return true;
    173         }
    174         return super.onOptionsItemSelected(item);
    175     }
    176 
    177     @Override
    178     public boolean onCreateOptionsMenu(Menu menu) {
    179         getMenuInflater().inflate(R.menu.set_alarm_context, menu);
    180         return true;
    181     }
    182 
    183     @Override
    184     protected void onSaveInstanceState(Bundle outState) {
    185         super.onSaveInstanceState(outState);
    186         outState.putParcelable(KEY_ORIGINAL_ALARM, mOriginalAlarm);
    187         outState.putParcelable(KEY_CURRENT_ALARM, buildAlarmFromUi());
    188     }
    189 
    190     @Override
    191     protected void onRestoreInstanceState(Bundle state) {
    192         super.onRestoreInstanceState(state);
    193 
    194         Alarm alarmFromBundle = state.getParcelable(KEY_ORIGINAL_ALARM);
    195         if (alarmFromBundle != null) {
    196             mOriginalAlarm = alarmFromBundle;
    197         }
    198 
    199         alarmFromBundle = state.getParcelable(KEY_CURRENT_ALARM);
    200         if (alarmFromBundle != null) {
    201             updatePrefs(alarmFromBundle);
    202         }
    203 
    204         Bundle b = state.getParcelable(KEY_TIME_PICKER_BUNDLE);
    205         if (b != null) {
    206             showTimePicker();
    207         }
    208     }
    209 
    210     // Used to post runnables asynchronously.
    211     private static final Handler sHandler = new Handler();
    212 
    213     public boolean onPreferenceChange(final Preference p, Object newValue) {
    214         // Asynchronously save the alarm since this method is called _before_
    215         // the value of the preference has changed.
    216         sHandler.post(new Runnable() {
    217             public void run() {
    218                 // Editing any preference (except enable) enables the alarm.
    219                 if (p != mEnabledPref) {
    220                     mEnabledPref.setChecked(true);
    221                 }
    222                 saveAlarm(null);
    223             }
    224         });
    225         return true;
    226     }
    227 
    228     private void updatePrefs(Alarm alarm) {
    229         mId = alarm.id;
    230         mEnabledPref.setChecked(alarm.enabled);
    231         mLabel.setText(alarm.label);
    232         mHour = alarm.hour;
    233         mMinute = alarm.minutes;
    234         mRepeatPref.setDaysOfWeek(alarm.daysOfWeek);
    235         mVibratePref.setChecked(alarm.vibrate);
    236         // Give the alert uri to the preference.
    237         mAlarmPref.setAlert(alarm.alert);
    238         updateTime();
    239     }
    240 
    241     @Override
    242     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
    243             Preference preference) {
    244         if (preference == mTimePref) {
    245             showTimePicker();
    246         }
    247 
    248         return super.onPreferenceTreeClick(preferenceScreen, preference);
    249     }
    250 
    251     @Override
    252     public void onBackPressed() {
    253         saveAndExit();
    254     }
    255 
    256     private void showTimePicker() {
    257         AlarmUtils.showTimeEditDialog(getFragmentManager(), null);
    258     }
    259 
    260     @Override
    261     public void onDialogTimeSet(Alarm alarm, int hourOfDay, int minute) {
    262         // onTimeSet is called when the user clicks "Set"
    263         mHour = hourOfDay;
    264         mMinute = minute;
    265         updateTime();
    266         // If the time has been changed, enable the alarm.
    267         mEnabledPref.setChecked(true);
    268         saveAlarm(null);
    269     }
    270 
    271     private void updateTime() {
    272         mTimePref.setSummary(Alarms.formatTime(this, mHour, mMinute,
    273                 mRepeatPref.getDaysOfWeek()));
    274     }
    275 
    276     private long saveAlarm(Alarm alarm) {
    277         if (alarm == null) {
    278             alarm = buildAlarmFromUi();
    279         }
    280 
    281         long time;
    282         if (alarm.id == -1) {
    283             time = Alarms.addAlarm(this, alarm);
    284             // addAlarm populates the alarm with the new id. Update mId so that
    285             // changes to other preferences update the new alarm.
    286             mId = alarm.id;
    287         } else {
    288             time = Alarms.setAlarm(this, alarm);
    289         }
    290         return time;
    291     }
    292 
    293     private Alarm buildAlarmFromUi() {
    294         Alarm alarm = new Alarm();
    295         alarm.id = mId;
    296         alarm.enabled = mEnabledPref.isChecked();
    297         alarm.hour = mHour;
    298         alarm.minutes = mMinute;
    299         alarm.daysOfWeek = mRepeatPref.getDaysOfWeek();
    300         alarm.vibrate = mVibratePref.isChecked();
    301         alarm.label = mLabel.getText().toString();
    302         alarm.alert = mAlarmPref.getAlert();
    303         return alarm;
    304     }
    305 
    306     private void deleteAlarm() {
    307         if (mId == -1) {
    308             // Unedited, newly created alarms don't require confirmation
    309             finish();
    310         } else {
    311             new AlertDialog.Builder(this)
    312                     .setTitle(getString(R.string.delete_alarm))
    313                     .setMessage(getString(R.string.delete_alarm_confirm))
    314                     .setPositiveButton(android.R.string.ok,
    315                             new DialogInterface.OnClickListener() {
    316                                 public void onClick(DialogInterface d, int w) {
    317                                     Alarms.deleteAlarm(SetAlarm.this, mId);
    318                                     finish();
    319                                 }
    320                             })
    321                     .setNegativeButton(android.R.string.cancel, null)
    322                     .show();
    323         }
    324     }
    325 
    326     private void revert() {
    327         int newId = mId;
    328         // "Revert" on a newly created alarm should delete it.
    329         if (mOriginalAlarm.id == -1) {
    330             Alarms.deleteAlarm(SetAlarm.this, newId);
    331         } else {
    332             saveAlarm(mOriginalAlarm);
    333         }
    334     }
    335 
    336     /**
    337      * Store any changes to the alarm and exit the activity.
    338      * Show a toast if the alarm is enabled with the time remaining until alarm
    339      */
    340     private void saveAndExit() {
    341         long time = saveAlarm(null);
    342         if(mEnabledPref.isChecked()) {
    343             AlarmUtils.popAlarmSetToast(SetAlarm.this, time);
    344         }
    345         finish();
    346     }
    347 
    348     /**
    349      * format "Alarm set for 2 days 7 hours and 53 minutes from
    350      * now"
    351      */
    352     static String formatToast(Context context, long timeInMillis) {
    353         long delta = timeInMillis - System.currentTimeMillis();
    354         long hours = delta / (1000 * 60 * 60);
    355         long minutes = delta / (1000 * 60) % 60;
    356         long days = hours / 24;
    357         hours = hours % 24;
    358 
    359         String daySeq = (days == 0) ? "" :
    360                 (days == 1) ? context.getString(R.string.day) :
    361                 context.getString(R.string.days, Long.toString(days));
    362 
    363         String minSeq = (minutes == 0) ? "" :
    364                 (minutes == 1) ? context.getString(R.string.minute) :
    365                 context.getString(R.string.minutes, Long.toString(minutes));
    366 
    367         String hourSeq = (hours == 0) ? "" :
    368                 (hours == 1) ? context.getString(R.string.hour) :
    369                 context.getString(R.string.hours, Long.toString(hours));
    370 
    371         boolean dispDays = days > 0;
    372         boolean dispHour = hours > 0;
    373         boolean dispMinute = minutes > 0;
    374 
    375         int index = (dispDays ? 1 : 0) |
    376                     (dispHour ? 2 : 0) |
    377                     (dispMinute ? 4 : 0);
    378 
    379         String[] formats = context.getResources().getStringArray(R.array.alarm_set);
    380         return String.format(formats[index], daySeq, hourSeq, minSeq);
    381     }
    382 }
    383