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