2 * Copyright (C) 2007 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.alarmclock;
19 import android.app.Activity;
20 import android.app.AlertDialog;
21 import android.content.Context;
22 import android.content.DialogInterface;
23 import android.content.Intent;
24 import android.content.SharedPreferences;
25 import android.database.Cursor;
26 import android.net.Uri;
27 import android.os.Bundle;
28 import android.os.Handler;
29 import android.provider.Settings;
30 import android.view.ContextMenu;
31 import android.view.ContextMenu.ContextMenuInfo;
32 import android.view.LayoutInflater;
33 import android.view.Menu;
34 import android.view.MenuItem;
35 import android.view.View;
36 import android.view.View.OnClickListener;
37 import android.view.ViewGroup;
38 import android.widget.CursorAdapter;
39 import android.widget.ListView;
40 import android.widget.TextView;
41 import android.widget.CheckBox;
43 import java.util.Calendar;
46 * AlarmClock application.
48 public class AlarmClock extends Activity {
50 final static String PREFERENCES = "AlarmClock";
51 final static String PREF_CLOCK_FACE = "face";
52 final static String PREF_SHOW_CLOCK = "show_clock";
54 /** Cap alarm count at this number */
55 final static int MAX_ALARM_COUNT = 12;
57 /** This must be false for production. If true, turns on logging,
59 final static boolean DEBUG = false;
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;
71 * Which clock face to show
73 private int mFace = -1;
76 * FIXME: it would be nice for this to live in an xml config file.
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
86 private class AlarmTimeAdapter extends CursorAdapter {
87 public AlarmTimeAdapter(Context context, Cursor cursor) {
88 super(context, cursor);
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());
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;
107 cursor.getString(Alarms.AlarmColumns.ALARM_MESSAGE_INDEX);
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);
116 SetAlarm.popAlarmSetToast(
117 AlarmClock.this, hour, minutes, daysOfWeek);
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);
126 digitalClock.setOnClickListener(new OnClickListener() {
127 public void onClick(View v) {
129 Intent intent = new Intent(AlarmClock.this, SetAlarm.class);
130 intent.putExtra(Alarms.ID, id);
131 startActivity(intent);
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);
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);
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);
156 daysOfWeekView.setVisibility(View.GONE);
161 (TextView) digitalClock.findViewById(R.id.label);
162 if (label != null && label.length() != 0) {
163 labelView.setText(label);
164 labelView.setVisibility(View.VISIBLE);
166 labelView.setVisibility(View.GONE);
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);
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,
193 .setNegativeButton(android.R.string.cancel, null)
199 protected void onCreate(Bundle icicle) {
200 super.onCreate(icicle);
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))
209 new DialogInterface.OnClickListener() {
210 public void onClick(DialogInterface dialog, int which) {
214 .setOnCancelListener(
215 new DialogInterface.OnCancelListener() {
216 public void onCancel(DialogInterface dialog) {
219 .setIcon(android.R.drawable.ic_dialog_alert)
224 setContentView(R.layout.alarm_clock);
225 mFactory = LayoutInflater.from(this);
226 mPrefs = getSharedPreferences(PREFERENCES, 0);
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);
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);
243 setClockVisibility(mPrefs.getBoolean(PREF_SHOW_CLOCK, true));
247 protected void onResume() {
250 int face = mPrefs.getInt(PREF_CLOCK_FACE, 0);
252 if (face < 0 || face >= AlarmClock.CLOCKS.length)
261 protected void onDestroy() {
263 ToastMaster.cancelToast();
264 mCursor.deactivate();
267 protected void inflateClock() {
268 if (mClock != null) {
269 mClockLayout.removeView(mClock);
271 mClock = mFactory.inflate(CLOCKS[mFace], null);
272 mClockLayout.addView(mClock, 0);
276 public boolean onCreateOptionsMenu(Menu menu) {
278 getMenuInflater().inflate(R.menu.main_menu, menu);
280 return super.onCreateOptionsMenu(menu);
284 * Only allow user to add a new alarm if there are fewer than
288 public boolean onPrepareOptionsMenu(Menu menu) {
289 menu.findItem(R.id.menu_add_alarm).setVisible(
290 mAlarmsList.getAdapter().getCount() < MAX_ALARM_COUNT);
291 menu.findItem(R.id.menu_toggle_clock).setTitle(
292 getClockVisibility() ? R.string.hide_clock
293 : R.string.show_clock);
294 return super.onPrepareOptionsMenu(menu);
298 public boolean onOptionsItemSelected(MenuItem item) {
299 switch (item.getItemId()) {
300 case R.id.menu_add_alarm:
301 Uri uri = Alarms.addAlarm(getContentResolver());
302 // FIXME: scroll to new item?
303 String segment = uri.getPathSegments().get(1);
304 int newId = Integer.parseInt(segment);
306 Log.v("In AlarmClock, new alarm id = " + newId);
308 Intent intent = new Intent(this, SetAlarm.class);
309 intent.putExtra(Alarms.ID, newId);
310 startActivity(intent);
313 case R.id.menu_toggle_clock:
314 setClockVisibility(!getClockVisibility());
315 saveClockVisibility();
318 case R.id.menu_settings:
319 startActivity(new Intent(this, SettingsActivity.class));
323 return super.onOptionsItemSelected(item);
327 private boolean getClockVisibility() {
328 return mClockLayout.getVisibility() == View.VISIBLE;
331 private void setClockVisibility(boolean visible) {
332 mClockLayout.setVisibility(visible ? View.VISIBLE : View.GONE);
335 private void saveClockVisibility() {
336 mPrefs.edit().putBoolean(PREF_SHOW_CLOCK, getClockVisibility()).commit();