• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.AlertDialog;
20 import android.app.TimePickerDialog;
21 import android.content.Context;
22 import android.content.DialogInterface;
23 import android.content.DialogInterface.OnCancelListener;
24 import android.content.Intent;
25 import android.os.Bundle;
26 import android.os.Handler;
27 import android.os.Vibrator;
28 import android.preference.CheckBoxPreference;
29 import android.preference.Preference;
30 import android.preference.PreferenceActivity;
31 import android.preference.PreferenceScreen;
32 import android.text.format.DateFormat;
33 import android.view.View;
34 import android.widget.Button;
35 import android.widget.EditText;
36 import android.widget.ListView;
37 import android.widget.TimePicker;
38 import android.widget.Toast;
39 
40 /**
41  * Manages each alarm
42  */
43 public class SetAlarm extends PreferenceActivity implements Preference.OnPreferenceChangeListener,
44         TimePickerDialog.OnTimeSetListener, OnCancelListener {
45     private static final String KEY_CURRENT_ALARM = "currentAlarm";
46     private static final String KEY_ORIGINAL_ALARM = "originalAlarm";
47     private static final String KEY_TIME_PICKER_BUNDLE = "timePickerBundle";
48 
49     private EditText mLabel;
50     private CheckBoxPreference mEnabledPref;
51     private Preference mTimePref;
52     private AlarmPreference mAlarmPref;
53     private CheckBoxPreference mVibratePref;
54     private RepeatPreference mRepeatPref;
55 
56     private int     mId;
57     private int     mHour;
58     private int     mMinute;
59     private TimePickerDialog mTimePickerDialog;
60     private Alarm   mOriginalAlarm;
61 
62     @Override
onCreate(Bundle icicle)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         // Attach actions to each button.
111         Button b = (Button) findViewById(R.id.alarm_save);
112         b.setOnClickListener(new View.OnClickListener() {
113                 public void onClick(View v) {
114                     long time = saveAlarm(null);
115                     if(mEnabledPref.isChecked()) {
116                         popAlarmSetToast(SetAlarm.this, time);
117                     }
118                     finish();
119                 }
120         });
121         Button revert = (Button) findViewById(R.id.alarm_revert);
122         revert.setOnClickListener(new View.OnClickListener() {
123             public void onClick(View v) {
124                 revert();
125                 finish();
126             }
127         });
128         b = (Button) findViewById(R.id.alarm_delete);
129         if (mId == -1) {
130             b.setEnabled(false);
131             b.setVisibility(View.GONE);
132         } else {
133             b.setVisibility(View.VISIBLE);
134             b.setOnClickListener(new View.OnClickListener() {
135                 public void onClick(View v) {
136                     deleteAlarm();
137                 }
138             });
139         }
140     }
141 
142     @Override
onSaveInstanceState(Bundle outState)143     protected void onSaveInstanceState(Bundle outState) {
144         super.onSaveInstanceState(outState);
145         outState.putParcelable(KEY_ORIGINAL_ALARM, mOriginalAlarm);
146         outState.putParcelable(KEY_CURRENT_ALARM, buildAlarmFromUi());
147         if (mTimePickerDialog != null) {
148             if (mTimePickerDialog.isShowing()) {
149                 outState.putParcelable(KEY_TIME_PICKER_BUNDLE, mTimePickerDialog
150                         .onSaveInstanceState());
151                 mTimePickerDialog.dismiss();
152             }
153             mTimePickerDialog = null;
154         }
155     }
156 
157     @Override
onRestoreInstanceState(Bundle state)158     protected void onRestoreInstanceState(Bundle state) {
159         super.onRestoreInstanceState(state);
160 
161         Alarm alarmFromBundle = state.getParcelable(KEY_ORIGINAL_ALARM);
162         if (alarmFromBundle != null) {
163             mOriginalAlarm = alarmFromBundle;
164         }
165 
166         alarmFromBundle = state.getParcelable(KEY_CURRENT_ALARM);
167         if (alarmFromBundle != null) {
168             updatePrefs(alarmFromBundle);
169         }
170 
171         Bundle b = state.getParcelable(KEY_TIME_PICKER_BUNDLE);
172         if (b != null) {
173             showTimePicker();
174             mTimePickerDialog.onRestoreInstanceState(b);
175         }
176     }
177 
178     // Used to post runnables asynchronously.
179     private static final Handler sHandler = new Handler();
180 
onPreferenceChange(final Preference p, Object newValue)181     public boolean onPreferenceChange(final Preference p, Object newValue) {
182         // Asynchronously save the alarm since this method is called _before_
183         // the value of the preference has changed.
184         sHandler.post(new Runnable() {
185             public void run() {
186                 // Editing any preference (except enable) enables the alarm.
187                 if (p != mEnabledPref) {
188                     mEnabledPref.setChecked(true);
189                 }
190                 saveAlarm(null);
191             }
192         });
193         return true;
194     }
195 
updatePrefs(Alarm alarm)196     private void updatePrefs(Alarm alarm) {
197         mId = alarm.id;
198         mEnabledPref.setChecked(alarm.enabled);
199         mLabel.setText(alarm.label);
200         mHour = alarm.hour;
201         mMinute = alarm.minutes;
202         mRepeatPref.setDaysOfWeek(alarm.daysOfWeek);
203         mVibratePref.setChecked(alarm.vibrate);
204         // Give the alert uri to the preference.
205         mAlarmPref.setAlert(alarm.alert);
206         updateTime();
207     }
208 
209     @Override
onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference)210     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
211             Preference preference) {
212         if (preference == mTimePref) {
213             showTimePicker();
214         }
215 
216         return super.onPreferenceTreeClick(preferenceScreen, preference);
217     }
218 
219     @Override
onBackPressed()220     public void onBackPressed() {
221         revert();
222         finish();
223     }
224 
showTimePicker()225     private void showTimePicker() {
226         if (mTimePickerDialog != null) {
227             if (mTimePickerDialog.isShowing()) {
228                 Log.e("mTimePickerDialog is already showing.");
229                 mTimePickerDialog.dismiss();
230             } else {
231                 Log.e("mTimePickerDialog is not null");
232             }
233             mTimePickerDialog.dismiss();
234         }
235 
236         mTimePickerDialog = new TimePickerDialog(this, this, mHour, mMinute,
237                 DateFormat.is24HourFormat(this));
238         mTimePickerDialog.setOnCancelListener(this);
239         mTimePickerDialog.show();
240     }
241 
onTimeSet(TimePicker view, int hourOfDay, int minute)242     public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
243         // onTimeSet is called when the user clicks "Set"
244         mTimePickerDialog = null;
245         mHour = hourOfDay;
246         mMinute = minute;
247         updateTime();
248         // If the time has been changed, enable the alarm.
249         mEnabledPref.setChecked(true);
250     }
251 
252     @Override
onCancel(DialogInterface dialog)253     public void onCancel(DialogInterface dialog) {
254         mTimePickerDialog = null;
255     }
256 
updateTime()257     private void updateTime() {
258         mTimePref.setSummary(Alarms.formatTime(this, mHour, mMinute,
259                 mRepeatPref.getDaysOfWeek()));
260     }
261 
saveAlarm(Alarm alarm)262     private long saveAlarm(Alarm alarm) {
263         if (alarm == null) {
264             alarm = buildAlarmFromUi();
265         }
266 
267         long time;
268         if (alarm.id == -1) {
269             time = Alarms.addAlarm(this, alarm);
270             // addAlarm populates the alarm with the new id. Update mId so that
271             // changes to other preferences update the new alarm.
272             mId = alarm.id;
273         } else {
274             time = Alarms.setAlarm(this, alarm);
275         }
276         return time;
277     }
278 
buildAlarmFromUi()279     private Alarm buildAlarmFromUi() {
280         Alarm alarm = new Alarm();
281         alarm.id = mId;
282         alarm.enabled = mEnabledPref.isChecked();
283         alarm.hour = mHour;
284         alarm.minutes = mMinute;
285         alarm.daysOfWeek = mRepeatPref.getDaysOfWeek();
286         alarm.vibrate = mVibratePref.isChecked();
287         alarm.label = mLabel.getText().toString();
288         alarm.alert = mAlarmPref.getAlert();
289         return alarm;
290     }
291 
deleteAlarm()292     private void deleteAlarm() {
293         new AlertDialog.Builder(this)
294                 .setTitle(getString(R.string.delete_alarm))
295                 .setMessage(getString(R.string.delete_alarm_confirm))
296                 .setPositiveButton(android.R.string.ok,
297                         new DialogInterface.OnClickListener() {
298                             public void onClick(DialogInterface d, int w) {
299                                 Alarms.deleteAlarm(SetAlarm.this, mId);
300                                 finish();
301                             }
302                         })
303                 .setNegativeButton(android.R.string.cancel, null)
304                 .show();
305     }
306 
revert()307     private void revert() {
308         int newId = mId;
309         // "Revert" on a newly created alarm should delete it.
310         if (mOriginalAlarm.id == -1) {
311             Alarms.deleteAlarm(SetAlarm.this, newId);
312         } else {
313             saveAlarm(mOriginalAlarm);
314         }
315     }
316 
317     /**
318      * Display a toast that tells the user how long until the alarm
319      * goes off.  This helps prevent "am/pm" mistakes.
320      */
popAlarmSetToast(Context context, int hour, int minute, Alarm.DaysOfWeek daysOfWeek)321     static void popAlarmSetToast(Context context, int hour, int minute,
322                                  Alarm.DaysOfWeek daysOfWeek) {
323         popAlarmSetToast(context,
324                 Alarms.calculateAlarm(hour, minute, daysOfWeek)
325                 .getTimeInMillis());
326     }
327 
popAlarmSetToast(Context context, long timeInMillis)328     static void popAlarmSetToast(Context context, long timeInMillis) {
329         String toastText = formatToast(context, timeInMillis);
330         Toast toast = Toast.makeText(context, toastText, Toast.LENGTH_LONG);
331         ToastMaster.setToast(toast);
332         toast.show();
333     }
334 
335     /**
336      * format "Alarm set for 2 days 7 hours and 53 minutes from
337      * now"
338      */
formatToast(Context context, long timeInMillis)339     static String formatToast(Context context, long timeInMillis) {
340         long delta = timeInMillis - System.currentTimeMillis();
341         long hours = delta / (1000 * 60 * 60);
342         long minutes = delta / (1000 * 60) % 60;
343         long days = hours / 24;
344         hours = hours % 24;
345 
346         String daySeq = (days == 0) ? "" :
347                 (days == 1) ? context.getString(R.string.day) :
348                 context.getString(R.string.days, Long.toString(days));
349 
350         String minSeq = (minutes == 0) ? "" :
351                 (minutes == 1) ? context.getString(R.string.minute) :
352                 context.getString(R.string.minutes, Long.toString(minutes));
353 
354         String hourSeq = (hours == 0) ? "" :
355                 (hours == 1) ? context.getString(R.string.hour) :
356                 context.getString(R.string.hours, Long.toString(hours));
357 
358         boolean dispDays = days > 0;
359         boolean dispHour = hours > 0;
360         boolean dispMinute = minutes > 0;
361 
362         int index = (dispDays ? 1 : 0) |
363                     (dispHour ? 2 : 0) |
364                     (dispMinute ? 4 : 0);
365 
366         String[] formats = context.getResources().getStringArray(R.array.alarm_set);
367         return String.format(formats[index], daySeq, hourSeq, minSeq);
368     }
369 }
370