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.View.OnCreateContextMenuListener;
38 import android.view.ViewGroup;
39 import android.widget.AdapterView;
40 import android.widget.AdapterView.AdapterContextMenuInfo;
41 import android.widget.AdapterView.OnItemClickListener;
42 import android.widget.CursorAdapter;
43 import android.widget.ListView;
44 import android.widget.TextView;
45 import android.widget.CheckBox;
47 import java.util.Calendar;
48 import java.text.DateFormatSymbols;
51 * AlarmClock application.
53 public class AlarmClock extends Activity implements OnItemClickListener {
55 final static String PREFERENCES = "AlarmClock";
56 final static String PREF_CLOCK_FACE = "face";
57 final static String PREF_SHOW_CLOCK = "show_clock";
59 /** Cap alarm count at this number */
60 final static int MAX_ALARM_COUNT = 12;
62 /** This must be false for production. If true, turns on logging,
64 final static boolean DEBUG = false;
66 private SharedPreferences mPrefs;
67 private LayoutInflater mFactory;
68 private ViewGroup mClockLayout;
69 private View mClock = null;
70 private ListView mAlarmsList;
71 private Cursor mCursor;
73 private String mAm, mPm;
76 * Which clock face to show
78 private int mFace = -1;
81 * FIXME: it would be nice for this to live in an xml config file.
83 final static int[] CLOCKS = {
84 R.layout.clock_basic_bw,
85 R.layout.clock_googly,
86 R.layout.clock_droid2,
87 R.layout.clock_droids,
88 R.layout.digital_clock
91 private class AlarmTimeAdapter extends CursorAdapter {
92 public AlarmTimeAdapter(Context context, Cursor cursor) {
93 super(context, cursor);
96 public View newView(Context context, Cursor cursor, ViewGroup parent) {
97 View ret = mFactory.inflate(R.layout.alarm_time, parent, false);
99 ((TextView) ret.findViewById(R.id.am)).setText(mAm);
100 ((TextView) ret.findViewById(R.id.pm)).setText(mPm);
102 DigitalClock digitalClock = (DigitalClock)ret.findViewById(R.id.digitalClock);
103 digitalClock.setLive(false);
104 if (Log.LOGV) Log.v("newView " + cursor.getPosition());
108 public void bindView(View view, Context context, Cursor cursor) {
109 final Alarm alarm = new Alarm(cursor);
111 CheckBox onButton = (CheckBox)view.findViewById(R.id.alarmButton);
112 onButton.setChecked(alarm.enabled);
113 onButton.setOnClickListener(new OnClickListener() {
114 public void onClick(View v) {
115 boolean isChecked = ((CheckBox) v).isChecked();
116 Alarms.enableAlarm(AlarmClock.this, alarm.id,
119 SetAlarm.popAlarmSetToast(AlarmClock.this,
120 alarm.hour, alarm.minutes, alarm.daysOfWeek);
125 DigitalClock digitalClock =
126 (DigitalClock) view.findViewById(R.id.digitalClock);
128 // set the alarm text
129 final Calendar c = Calendar.getInstance();
130 c.set(Calendar.HOUR_OF_DAY, alarm.hour);
131 c.set(Calendar.MINUTE, alarm.minutes);
132 digitalClock.updateTime(c);
134 // Set the repeat text or leave it blank if it does not repeat.
135 TextView daysOfWeekView =
136 (TextView) digitalClock.findViewById(R.id.daysOfWeek);
137 final String daysOfWeekStr =
138 alarm.daysOfWeek.toString(AlarmClock.this, false);
139 if (daysOfWeekStr != null && daysOfWeekStr.length() != 0) {
140 daysOfWeekView.setText(daysOfWeekStr);
141 daysOfWeekView.setVisibility(View.VISIBLE);
143 daysOfWeekView.setVisibility(View.GONE);
148 (TextView) digitalClock.findViewById(R.id.label);
149 if (alarm.label != null && alarm.label.length() != 0) {
150 labelView.setText(alarm.label);
151 labelView.setVisibility(View.VISIBLE);
153 labelView.setVisibility(View.GONE);
159 public boolean onContextItemSelected(final MenuItem item) {
160 final AdapterContextMenuInfo info =
161 (AdapterContextMenuInfo) item.getMenuInfo();
162 final int id = (int) info.id;
163 switch (item.getItemId()) {
164 case R.id.delete_alarm:
165 // Confirm that the alarm will be deleted.
166 new AlertDialog.Builder(this)
167 .setTitle(getString(R.string.delete_alarm))
168 .setMessage(getString(R.string.delete_alarm_confirm))
169 .setPositiveButton(android.R.string.ok,
170 new DialogInterface.OnClickListener() {
171 public void onClick(DialogInterface d,
173 Alarms.deleteAlarm(AlarmClock.this, id);
176 .setNegativeButton(android.R.string.cancel, null)
180 case R.id.enable_alarm:
181 final Cursor c = (Cursor) mAlarmsList.getAdapter()
182 .getItem(info.position);
183 final Alarm alarm = new Alarm(c);
184 Alarms.enableAlarm(this, alarm.id, !alarm.enabled);
185 if (!alarm.enabled) {
186 SetAlarm.popAlarmSetToast(this, alarm.hour, alarm.minutes,
194 return super.onContextItemSelected(item);
198 protected void onCreate(Bundle icicle) {
199 super.onCreate(icicle);
201 String[] ampm = new DateFormatSymbols().getAmPmStrings();
205 // sanity check -- no database, no clock
206 if (getContentResolver() == null) {
207 new AlertDialog.Builder(this)
208 .setTitle(getString(R.string.error))
209 .setMessage(getString(R.string.dberror))
212 new DialogInterface.OnClickListener() {
213 public void onClick(DialogInterface dialog, int which) {
217 .setOnCancelListener(
218 new DialogInterface.OnCancelListener() {
219 public void onCancel(DialogInterface dialog) {
222 .setIcon(android.R.drawable.ic_dialog_alert)
227 setContentView(R.layout.alarm_clock);
228 mFactory = LayoutInflater.from(this);
229 mPrefs = getSharedPreferences(PREFERENCES, 0);
231 mCursor = Alarms.getAlarmsCursor(getContentResolver());
232 mAlarmsList = (ListView) findViewById(R.id.alarms_list);
233 mAlarmsList.setAdapter(new AlarmTimeAdapter(this, mCursor));
234 mAlarmsList.setVerticalScrollBarEnabled(true);
235 mAlarmsList.setOnItemClickListener(this);
236 mAlarmsList.setOnCreateContextMenuListener(this);
238 mClockLayout = (ViewGroup) findViewById(R.id.clock_layout);
239 mClockLayout.setOnClickListener(new View.OnClickListener() {
240 public void onClick(View v) {
241 final Intent intent = new Intent(AlarmClock.this, ClockPicker.class);
242 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
243 startActivity(intent);
247 setClockVisibility(mPrefs.getBoolean(PREF_SHOW_CLOCK, true));
251 protected void onResume() {
254 int face = mPrefs.getInt(PREF_CLOCK_FACE, 0);
256 if (face < 0 || face >= AlarmClock.CLOCKS.length)
265 protected void onDestroy() {
267 ToastMaster.cancelToast();
268 mCursor.deactivate();
271 protected void inflateClock() {
272 if (mClock != null) {
273 mClockLayout.removeView(mClock);
276 LayoutInflater.from(this).inflate(CLOCKS[mFace], mClockLayout);
277 mClock = findViewById(R.id.clock);
279 TextView am = (TextView) findViewById(R.id.am);
280 TextView pm = (TextView) findViewById(R.id.pm);
291 public boolean onCreateOptionsMenu(Menu menu) {
293 getMenuInflater().inflate(R.menu.main_menu, menu);
295 return super.onCreateOptionsMenu(menu);
299 public void onCreateContextMenu(ContextMenu menu, View view,
300 ContextMenuInfo menuInfo) {
301 // Inflate the menu from xml.
302 getMenuInflater().inflate(R.menu.context_menu, menu);
304 // Use the current item to create a custom view for the header.
305 final AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
307 (Cursor) mAlarmsList.getAdapter().getItem((int) info.position);
308 final Alarm alarm = new Alarm(c);
310 // Construct the Calendar to compute the time.
311 final Calendar cal = Calendar.getInstance();
312 cal.set(Calendar.HOUR_OF_DAY, alarm.hour);
313 cal.set(Calendar.MINUTE, alarm.minutes);
314 final String time = Alarms.formatTime(this, cal);
316 // Inflate the custom view and set each TextView's text.
317 final View v = mFactory.inflate(R.layout.context_menu_header, null);
318 TextView textView = (TextView) v.findViewById(R.id.header_time);
319 textView.setText(time);
320 textView = (TextView) v.findViewById(R.id.header_label);
321 textView.setText(alarm.label);
323 // Set the custom view on the menu.
324 menu.setHeaderView(v);
325 // Change the text to "disable" if the alarm is already enabled.
327 menu.findItem(R.id.enable_alarm).setTitle(R.string.disable_alarm);
331 public void onItemClick(AdapterView parent, View v, int pos, long id) {
332 Intent intent = new Intent(this, SetAlarm.class);
333 intent.putExtra(Alarms.ALARM_ID, (int) id);
334 startActivity(intent);
338 * Only allow user to add a new alarm if there are fewer than
342 public boolean onPrepareOptionsMenu(Menu menu) {
343 menu.findItem(R.id.menu_add_alarm).setVisible(
344 mAlarmsList.getAdapter().getCount() < MAX_ALARM_COUNT);
345 menu.findItem(R.id.menu_toggle_clock).setTitle(
346 getClockVisibility() ? R.string.hide_clock
347 : R.string.show_clock);
348 return super.onPrepareOptionsMenu(menu);
352 public boolean onOptionsItemSelected(MenuItem item) {
353 switch (item.getItemId()) {
354 case R.id.menu_add_alarm:
355 Uri uri = Alarms.addAlarm(getContentResolver());
356 // FIXME: scroll to new item?
357 String segment = uri.getPathSegments().get(1);
358 int newId = Integer.parseInt(segment);
360 Log.v("In AlarmClock, new alarm id = " + newId);
362 Intent intent = new Intent(this, SetAlarm.class);
363 intent.putExtra(Alarms.ALARM_ID, newId);
364 startActivity(intent);
367 case R.id.menu_toggle_clock:
368 setClockVisibility(!getClockVisibility());
369 saveClockVisibility();
372 case R.id.menu_settings:
373 startActivity(new Intent(this, SettingsActivity.class));
377 return super.onOptionsItemSelected(item);
381 private boolean getClockVisibility() {
382 return mClockLayout.getVisibility() == View.VISIBLE;
385 private void setClockVisibility(boolean visible) {
386 mClockLayout.setVisibility(visible ? View.VISIBLE : View.GONE);
389 private void saveClockVisibility() {
390 mPrefs.edit().putBoolean(PREF_SHOW_CLOCK, getClockVisibility()).commit();