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