AlarmClock.java revision 57c4e8b2ef600f89caafb0520b44b06fc73ab845
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.alarmclock; 18 19import android.app.Activity; 20import android.app.AlertDialog; 21import android.content.Context; 22import android.content.DialogInterface; 23import android.content.Intent; 24import android.content.SharedPreferences; 25import android.database.Cursor; 26import android.net.Uri; 27import android.os.Bundle; 28import android.os.Handler; 29import android.provider.Settings; 30import android.view.ContextMenu; 31import android.view.ContextMenu.ContextMenuInfo; 32import android.view.LayoutInflater; 33import android.view.Menu; 34import android.view.MenuItem; 35import android.view.View; 36import android.view.View.OnClickListener; 37import android.view.ViewGroup; 38import android.widget.CursorAdapter; 39import android.widget.ListView; 40import android.widget.TextView; 41import android.widget.CheckBox; 42 43import java.util.Calendar; 44 45/** 46 * AlarmClock application. 47 */ 48public class AlarmClock extends Activity { 49 50 final static String PREFERENCES = "AlarmClock"; 51 final static int SET_ALARM = 1; 52 final static String PREF_CLOCK_FACE = "face"; 53 final static String PREF_SHOW_CLOCK = "show_clock"; 54 55 /** Cap alarm count at this number */ 56 final static int MAX_ALARM_COUNT = 12; 57 58 /** This must be false for production. If true, turns on logging, 59 test code, etc. */ 60 final static boolean DEBUG = false; 61 62 private SharedPreferences mPrefs; 63 private LayoutInflater mFactory; 64 private ViewGroup mClockLayout; 65 private View mClock = null; 66 private MenuItem mAddAlarmItem; 67 private MenuItem mToggleClockItem; 68 private ListView mAlarmsList; 69 private Cursor mCursor; 70 71 /** 72 * Which clock face to show 73 */ 74 private int mFace = -1; 75 76 /* 77 * FIXME: it would be nice for this to live in an xml config file. 78 */ 79 final static int[] CLOCKS = { 80 R.layout.clock_basic_bw, 81 R.layout.clock_googly, 82 R.layout.clock_droid2, 83 R.layout.clock_droids, 84 R.layout.digital_clock 85 }; 86 87 private class AlarmTimeAdapter extends CursorAdapter { 88 public AlarmTimeAdapter(Context context, Cursor cursor) { 89 super(context, cursor); 90 } 91 92 public View newView(Context context, Cursor cursor, ViewGroup parent) { 93 View ret = mFactory.inflate(R.layout.alarm_time, parent, false); 94 DigitalClock digitalClock = (DigitalClock)ret.findViewById(R.id.digitalClock); 95 digitalClock.setLive(false); 96 if (Log.LOGV) Log.v("newView " + cursor.getPosition()); 97 return ret; 98 } 99 100 public void bindView(View view, Context context, Cursor cursor) { 101 final int id = cursor.getInt(Alarms.AlarmColumns.ALARM_ID_INDEX); 102 final int hour = cursor.getInt(Alarms.AlarmColumns.ALARM_HOUR_INDEX); 103 final int minutes = cursor.getInt(Alarms.AlarmColumns.ALARM_MINUTES_INDEX); 104 final Alarms.DaysOfWeek daysOfWeek = new Alarms.DaysOfWeek( 105 cursor.getInt(Alarms.AlarmColumns.ALARM_DAYS_OF_WEEK_INDEX)); 106 final boolean enabled = cursor.getInt(Alarms.AlarmColumns.ALARM_ENABLED_INDEX) == 1; 107 final String label = 108 cursor.getString(Alarms.AlarmColumns.ALARM_MESSAGE_INDEX); 109 110 CheckBox onButton = (CheckBox)view.findViewById(R.id.alarmButton); 111 onButton.setChecked(enabled); 112 onButton.setOnClickListener(new OnClickListener() { 113 public void onClick(View v) { 114 boolean isChecked = ((CheckBox) v).isChecked(); 115 Alarms.enableAlarm(AlarmClock.this, id, isChecked); 116 if (isChecked) { 117 SetAlarm.popAlarmSetToast( 118 AlarmClock.this, hour, minutes, daysOfWeek); 119 } 120 } 121 }); 122 123 DigitalClock digitalClock = (DigitalClock)view.findViewById(R.id.digitalClock); 124 if (Log.LOGV) Log.v("bindView " + cursor.getPosition() + " " + id + " " + hour + 125 ":" + minutes + " " + daysOfWeek.toString(context, true) + " dc " + digitalClock); 126 127 digitalClock.setOnClickListener(new OnClickListener() { 128 public void onClick(View v) { 129 if (true) { 130 Intent intent = new Intent(AlarmClock.this, SetAlarm.class); 131 intent.putExtra(Alarms.ID, id); 132 startActivityForResult(intent, SET_ALARM); 133 } else { 134 // TESTING: immediately pop alarm 135 Intent fireAlarm = new Intent(AlarmClock.this, AlarmAlert.class); 136 fireAlarm.putExtra(Alarms.ID, id); 137 fireAlarm.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 138 startActivity(fireAlarm); 139 } 140 } 141 }); 142 143 // set the alarm text 144 final Calendar c = Calendar.getInstance(); 145 c.set(Calendar.HOUR_OF_DAY, hour); 146 c.set(Calendar.MINUTE, minutes); 147 digitalClock.updateTime(c); 148 149 // Set the repeat text or leave it blank if it does not repeat. 150 TextView daysOfWeekView = (TextView) digitalClock.findViewById(R.id.daysOfWeek); 151 final String daysOfWeekStr = 152 daysOfWeek.toString(AlarmClock.this, false); 153 if (daysOfWeekStr != null && daysOfWeekStr.length() != 0) { 154 daysOfWeekView.setText(daysOfWeekStr); 155 daysOfWeekView.setVisibility(View.VISIBLE); 156 } else { 157 daysOfWeekView.setVisibility(View.GONE); 158 } 159 160 // Display the label 161 TextView labelView = 162 (TextView) digitalClock.findViewById(R.id.label); 163 if (label != null && label.length() != 0) { 164 labelView.setText(label); 165 } else { 166 labelView.setText(R.string.default_label); 167 } 168 169 // Build context menu 170 digitalClock.setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() { 171 public void onCreateContextMenu(ContextMenu menu, View view, 172 ContextMenuInfo menuInfo) { 173 menu.setHeaderTitle(Alarms.formatTime(AlarmClock.this, c)); 174 MenuItem deleteAlarmItem = menu.add(0, id, 0, R.string.delete_alarm); 175 } 176 }); 177 } 178 }; 179 180 @Override 181 public boolean onContextItemSelected(final MenuItem item) { 182 // Confirm that the alarm will be deleted. 183 new AlertDialog.Builder(this) 184 .setTitle(getString(R.string.delete_alarm)) 185 .setMessage(getString(R.string.delete_alarm_confirm)) 186 .setPositiveButton(android.R.string.ok, 187 new DialogInterface.OnClickListener() { 188 public void onClick(DialogInterface d, int w) { 189 Alarms.deleteAlarm(AlarmClock.this, 190 item.getItemId()); 191 } 192 }) 193 .setNegativeButton(android.R.string.cancel, null) 194 .show(); 195 return true; 196 } 197 198 @Override 199 protected void onCreate(Bundle icicle) { 200 super.onCreate(icicle); 201 202 // sanity check -- no database, no clock 203 if (getContentResolver() == null) { 204 new AlertDialog.Builder(this) 205 .setTitle(getString(R.string.error)) 206 .setMessage(getString(R.string.dberror)) 207 .setPositiveButton( 208 android.R.string.ok, 209 new DialogInterface.OnClickListener() { 210 public void onClick(DialogInterface dialog, int which) { 211 finish(); 212 } 213 }) 214 .setOnCancelListener( 215 new DialogInterface.OnCancelListener() { 216 public void onCancel(DialogInterface dialog) { 217 finish(); 218 }}) 219 .setIcon(android.R.drawable.ic_dialog_alert) 220 .create().show(); 221 return; 222 } 223 224 setContentView(R.layout.alarm_clock); 225 mFactory = LayoutInflater.from(this); 226 mPrefs = getSharedPreferences(PREFERENCES, 0); 227 228 mCursor = Alarms.getAlarmsCursor(getContentResolver()); 229 mAlarmsList = (ListView) findViewById(R.id.alarms_list); 230 mAlarmsList.setAdapter(new AlarmTimeAdapter(this, mCursor)); 231 mAlarmsList.setVerticalScrollBarEnabled(true); 232 mAlarmsList.setItemsCanFocus(true); 233 234 mClockLayout = (ViewGroup) findViewById(R.id.clock_layout); 235 mClockLayout.setOnClickListener(new View.OnClickListener() { 236 public void onClick(View v) { 237 final Intent intent = new Intent(AlarmClock.this, ClockPicker.class); 238 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 239 startActivity(intent); 240 } 241 }); 242 243 setClockVisibility(mPrefs.getBoolean(PREF_SHOW_CLOCK, true)); 244 } 245 246 @Override 247 protected void onResume() { 248 super.onResume(); 249 250 int face = mPrefs.getInt(PREF_CLOCK_FACE, 0); 251 if (mFace != face) { 252 if (face < 0 || face >= AlarmClock.CLOCKS.length) 253 mFace = 0; 254 else 255 mFace = face; 256 inflateClock(); 257 } 258 } 259 260 @Override 261 protected void onDestroy() { 262 super.onDestroy(); 263 ToastMaster.cancelToast(); 264 mCursor.deactivate(); 265 } 266 267 protected void inflateClock() { 268 if (mClock != null) { 269 mClockLayout.removeView(mClock); 270 } 271 mClock = mFactory.inflate(CLOCKS[mFace], null); 272 mClockLayout.addView(mClock, 0); 273 } 274 275 @Override 276 public boolean onCreateOptionsMenu(Menu menu) { 277 super.onCreateOptionsMenu(menu); 278 279 mAddAlarmItem = menu.add(0, 0, 0, R.string.add_alarm); 280 mAddAlarmItem.setIcon(android.R.drawable.ic_menu_add); 281 282 mToggleClockItem = menu.add(0, 0, 0, R.string.hide_clock); 283 mToggleClockItem.setIcon(R.drawable.ic_menu_clock_face); 284 285 MenuItem settingsItem = menu.add(0, 0, 0, R.string.settings); 286 settingsItem.setIcon(android.R.drawable.ic_menu_preferences); 287 settingsItem.setIntent(new Intent(this, SettingsActivity.class)); 288 289 return true; 290 } 291 292 /** 293 * Only allow user to add a new alarm if there are fewer than 294 * MAX_ALARM_COUNT 295 */ 296 @Override 297 public boolean onPrepareOptionsMenu(Menu menu) { 298 super.onPrepareOptionsMenu(menu); 299 mAddAlarmItem.setVisible(mAlarmsList.getChildCount() < MAX_ALARM_COUNT); 300 mToggleClockItem.setTitle(getClockVisibility() ? R.string.hide_clock : 301 R.string.show_clock); 302 return true; 303 } 304 305 @Override 306 public boolean onOptionsItemSelected(MenuItem item) { 307 if (item == mAddAlarmItem) { 308 Uri uri = Alarms.addAlarm(getContentResolver()); 309 // FIXME: scroll to new item. mAlarmsList.requestChildRectangleOnScreen() ? 310 String segment = uri.getPathSegments().get(1); 311 int newId = Integer.parseInt(segment); 312 if (Log.LOGV) Log.v("In AlarmClock, new alarm id = " + newId); 313 Intent intent = new Intent(AlarmClock.this, SetAlarm.class); 314 intent.putExtra(Alarms.ID, newId); 315 startActivityForResult(intent, SET_ALARM); 316 return true; 317 } else if (item == mToggleClockItem) { 318 setClockVisibility(!getClockVisibility()); 319 saveClockVisibility(); 320 return true; 321 } 322 323 return false; 324 } 325 326 327 private boolean getClockVisibility() { 328 return mClockLayout.getVisibility() == View.VISIBLE; 329 } 330 331 private void setClockVisibility(boolean visible) { 332 mClockLayout.setVisibility(visible ? View.VISIBLE : View.GONE); 333 } 334 335 private void saveClockVisibility() { 336 mPrefs.edit().putBoolean(PREF_SHOW_CLOCK, getClockVisibility()).commit(); 337 } 338} 339