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.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 onCreate(Bundle icicle)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 onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference)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 onBackPressed()167 public void onBackPressed() { 168 saveAlarm(); 169 finish(); 170 } 171 onTimeSet(TimePicker view, int hourOfDay, int minute)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 updateTime()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 saveAlarm()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 */ saveAlarm( Context context, int id, boolean enabled, int hour, int minute, Alarm.DaysOfWeek daysOfWeek, boolean vibrate, String label, String alert, boolean popToast)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 */ popAlarmSetToast(Context context, int hour, int minute, Alarm.DaysOfWeek daysOfWeek)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 popAlarmSetToast(Context context, long timeInMillis)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 */ formatToast(Context context, long timeInMillis)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 onCreateOptionsMenu(Menu menu)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 onOptionsItemSelected(MenuItem item)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 */ setTestAlarm()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