OSDN Git Service

Avoid a NPE in the monkey by checking for a null alarm.
[android-x86/packages-apps-DeskClock.git] / src / com / android / alarmclock / SetAlarm.java
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.alarmclock;
18
19 import android.app.TimePickerDialog;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.media.RingtoneManager;
23 import android.net.Uri;
24 import android.os.Bundle;
25 import android.preference.CheckBoxPreference;
26 import android.preference.EditTextPreference;
27 import android.preference.Preference;
28 import android.preference.PreferenceActivity;
29 import android.preference.PreferenceScreen;
30 import android.text.format.DateFormat;
31 import android.view.LayoutInflater;
32 import android.view.Menu;
33 import android.view.MenuItem;
34 import android.view.View;
35 import android.view.ViewGroup.LayoutParams;
36 import android.widget.Button;
37 import android.widget.FrameLayout;
38 import android.widget.LinearLayout;
39 import android.widget.ListView;
40 import android.widget.TimePicker;
41 import android.widget.Toast;
42
43 /**
44  * Manages each alarm
45  */
46 public class SetAlarm extends PreferenceActivity
47         implements TimePickerDialog.OnTimeSetListener {
48
49     private EditTextPreference mLabel;
50     private Preference mTimePref;
51     private AlarmPreference mAlarmPref;
52     private CheckBoxPreference mVibratePref;
53     private RepeatPreference mRepeatPref;
54     private MenuItem mDeleteAlarmItem;
55     private MenuItem mTestAlarmItem;
56
57     private int     mId;
58     private boolean mEnabled;
59     private int     mHour;
60     private int     mMinutes;
61
62     /**
63      * Set an alarm.  Requires an Alarms.ALARM_ID to be passed in as an
64      * extra. FIXME: Pass an Alarm object like every other Activity.
65      */
66     @Override
67     protected void onCreate(Bundle icicle) {
68         super.onCreate(icicle);
69
70         addPreferencesFromResource(R.xml.alarm_prefs);
71
72         // Get each preference so we can retrieve the value later.
73         mLabel = (EditTextPreference) findPreference("label");
74         mLabel.setOnPreferenceChangeListener(
75                 new Preference.OnPreferenceChangeListener() {
76                     public boolean onPreferenceChange(Preference p,
77                             Object newValue) {
78                         // Set the summary based on the new label.
79                         p.setSummary((String) newValue);
80                         return true;
81                     }
82                 });
83         mTimePref = findPreference("time");
84         mAlarmPref = (AlarmPreference) findPreference("alarm");
85         mVibratePref = (CheckBoxPreference) findPreference("vibrate");
86         mRepeatPref = (RepeatPreference) findPreference("setRepeat");
87
88         Intent i = getIntent();
89         mId = i.getIntExtra(Alarms.ALARM_ID, -1);
90         if (Log.LOGV) {
91             Log.v("In SetAlarm, alarm id = " + mId);
92         }
93
94         /* load alarm details from database */
95         Alarm alarm = Alarms.getAlarm(getContentResolver(), mId);
96         // Bad alarm, bail to avoid a NPE.
97         if (alarm == null) {
98             finish();
99             return;
100         }
101         mEnabled = alarm.enabled;
102         mLabel.setText(alarm.label);
103         mLabel.setSummary(alarm.label);
104         mHour = alarm.hour;
105         mMinutes = alarm.minutes;
106         mRepeatPref.setDaysOfWeek(alarm.daysOfWeek);
107         mVibratePref.setChecked(alarm.vibrate);
108         // Give the alert uri to the preference.
109         mAlarmPref.setAlert(alarm.alert);
110         updateTime();
111
112         // We have to do this to get the save/cancel buttons to highlight on
113         // their own.
114         getListView().setItemsCanFocus(true);
115
116         // Grab the content view so we can modify it.
117         FrameLayout content = (FrameLayout) getWindow().getDecorView()
118                 .findViewById(com.android.internal.R.id.content);
119
120         // Get the main ListView and remove it from the content view.
121         ListView lv = getListView();
122         content.removeView(lv);
123
124         // Create the new LinearLayout that will become the content view and
125         // make it vertical.
126         LinearLayout ll = new LinearLayout(this);
127         ll.setOrientation(LinearLayout.VERTICAL);
128
129         // Have the ListView expand to fill the screen minus the save/cancel
130         // buttons.
131         LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
132                 LayoutParams.FILL_PARENT,
133                 LayoutParams.WRAP_CONTENT);
134         lp.weight = 1;
135         ll.addView(lv, lp);
136
137         // Inflate the buttons onto the LinearLayout.
138         View v = LayoutInflater.from(this).inflate(
139                 R.layout.save_cancel_alarm, ll);
140
141         // Attach actions to each button.
142         Button b = (Button) v.findViewById(R.id.alarm_save);
143         b.setOnClickListener(new View.OnClickListener() {
144                 public void onClick(View v) {
145                     // Enable the alarm when clicking "Done"
146                     mEnabled = true;
147                     saveAlarm();
148                     finish();
149                 }
150         });
151         b = (Button) v.findViewById(R.id.alarm_cancel);
152         b.setOnClickListener(new View.OnClickListener() {
153                 public void onClick(View v) {
154                     finish();
155                 }
156         });
157
158         // Replace the old content view with our new one.
159         setContentView(ll);
160     }
161
162     @Override
163     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
164             Preference preference) {
165         if (preference == mTimePref) {
166             new TimePickerDialog(this, this, mHour, mMinutes,
167                     DateFormat.is24HourFormat(this)).show();
168         }
169
170         return super.onPreferenceTreeClick(preferenceScreen, preference);
171     }
172
173     @Override
174     public void onBackPressed() {
175         saveAlarm();
176         finish();
177     }
178
179     public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
180         mHour = hourOfDay;
181         mMinutes = minute;
182         updateTime();
183         // If the time has been changed, enable the alarm.
184         mEnabled = true;
185     }
186
187     private void updateTime() {
188         if (Log.LOGV) {
189             Log.v("updateTime " + mId);
190         }
191         mTimePref.setSummary(Alarms.formatTime(this, mHour, mMinutes,
192                 mRepeatPref.getDaysOfWeek()));
193     }
194
195     private void saveAlarm() {
196         final String alert = mAlarmPref.getAlertString();
197         Alarms.setAlarm(this, mId, mEnabled, mHour, mMinutes,
198                 mRepeatPref.getDaysOfWeek(), mVibratePref.isChecked(),
199                 mLabel.getText(), alert);
200
201         if (mEnabled) {
202             popAlarmSetToast(this, mHour, mMinutes,
203                     mRepeatPref.getDaysOfWeek());
204         }
205     }
206
207     /**
208      * Write alarm out to persistent store and pops toast if alarm
209      * enabled
210      */
211     private static void saveAlarm(
212             Context context, int id, boolean enabled, int hour, int minute,
213             Alarm.DaysOfWeek daysOfWeek, boolean vibrate, String label,
214             String alert, boolean popToast) {
215         if (Log.LOGV) Log.v("** saveAlarm " + id + " " + label + " " + enabled
216                 + " " + hour + " " + minute + " vibe " + vibrate);
217
218         // Fix alert string first
219         Alarms.setAlarm(context, id, enabled, hour, minute, daysOfWeek, vibrate,
220                 label, alert);
221
222         if (enabled && popToast) {
223             popAlarmSetToast(context, hour, minute, daysOfWeek);
224         }
225     }
226
227     /**
228      * Display a toast that tells the user how long until the alarm
229      * goes off.  This helps prevent "am/pm" mistakes.
230      */
231     static void popAlarmSetToast(Context context, int hour, int minute,
232                                  Alarm.DaysOfWeek daysOfWeek) {
233
234         String toastText = formatToast(context, hour, minute, daysOfWeek);
235         Toast toast = Toast.makeText(context, toastText, Toast.LENGTH_LONG);
236         ToastMaster.setToast(toast);
237         toast.show();
238     }
239
240     /**
241      * format "Alarm set for 2 days 7 hours and 53 minutes from
242      * now"
243      */
244     static String formatToast(Context context, int hour, int minute,
245                               Alarm.DaysOfWeek daysOfWeek) {
246         long alarm = Alarms.calculateAlarm(hour, minute,
247                                            daysOfWeek).getTimeInMillis();
248         long delta = alarm - System.currentTimeMillis();;
249         long hours = delta / (1000 * 60 * 60);
250         long minutes = delta / (1000 * 60) % 60;
251         long days = hours / 24;
252         hours = hours % 24;
253
254         String daySeq = (days == 0) ? "" :
255                 (days == 1) ? context.getString(R.string.day) :
256                 context.getString(R.string.days, Long.toString(days));
257
258         String minSeq = (minutes == 0) ? "" :
259                 (minutes == 1) ? context.getString(R.string.minute) :
260                 context.getString(R.string.minutes, Long.toString(minutes));
261
262         String hourSeq = (hours == 0) ? "" :
263                 (hours == 1) ? context.getString(R.string.hour) :
264                 context.getString(R.string.hours, Long.toString(hours));
265
266         boolean dispDays = days > 0;
267         boolean dispHour = hours > 0;
268         boolean dispMinute = minutes > 0;
269
270         int index = (dispDays ? 1 : 0) |
271                     (dispHour ? 2 : 0) |
272                     (dispMinute ? 4 : 0);
273
274         String[] formats = context.getResources().getStringArray(R.array.alarm_set);
275         return String.format(formats[index], daySeq, hourSeq, minSeq);
276     }
277
278     public boolean onCreateOptionsMenu(Menu menu) {
279         super.onCreateOptionsMenu(menu);
280
281         mDeleteAlarmItem = menu.add(0, 0, 0, R.string.delete_alarm);
282         mDeleteAlarmItem.setIcon(android.R.drawable.ic_menu_delete);
283
284         if (AlarmClock.DEBUG) {
285             mTestAlarmItem = menu.add(0, 0, 0, "test alarm");
286         }
287
288         return true;
289     }
290
291     public boolean onOptionsItemSelected(MenuItem item) {
292         if (item == mDeleteAlarmItem) {
293             Alarms.deleteAlarm(this, mId);
294             finish();
295             return true;
296         }
297         if (AlarmClock.DEBUG) {
298             if (item == mTestAlarmItem) {
299                 setTestAlarm();
300                 return true;
301             }
302         }
303
304         return false;
305     }
306
307
308     /**
309      * Test code: this is disabled for production build.  Sets
310      * this alarm to go off on the next minute
311      */
312     void setTestAlarm() {
313
314         // start with now
315         java.util.Calendar c = java.util.Calendar.getInstance();
316         c.setTimeInMillis(System.currentTimeMillis());
317
318         int nowHour = c.get(java.util.Calendar.HOUR_OF_DAY);
319         int nowMinute = c.get(java.util.Calendar.MINUTE);
320
321         int minutes = (nowMinute + 1) % 60;
322         int hour = nowHour + (nowMinute == 0 ? 1 : 0);
323
324         saveAlarm(this, mId, true, hour, minutes, mRepeatPref.getDaysOfWeek(),
325                 true, mLabel.getText(), mAlarmPref.getAlertString(), true);
326     }
327
328 }