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