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.deskclock;
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.content.res.Configuration;
26 import android.database.Cursor;
27 import android.net.Uri;
28 import android.os.Bundle;
29 import android.os.Handler;
30 import android.provider.Settings;
31 import android.view.ContextMenu;
32 import android.view.ContextMenu.ContextMenuInfo;
33 import android.view.LayoutInflater;
34 import android.view.Menu;
35 import android.view.MenuItem;
36 import android.view.View;
37 import android.view.View.OnClickListener;
38 import android.view.View.OnCreateContextMenuListener;
39 import android.view.ViewGroup;
40 import android.widget.AdapterView;
41 import android.widget.AdapterView.AdapterContextMenuInfo;
42 import android.widget.AdapterView.OnItemClickListener;
43 import android.widget.CursorAdapter;
44 import android.widget.ListView;
45 import android.widget.TextView;
46 import android.widget.CheckBox;
48 import java.util.Calendar;
49 import java.text.DateFormatSymbols;
52 * AlarmClock application.
54 public class AlarmClock extends Activity implements OnItemClickListener {
56 final static String PREFERENCES = "AlarmClock";
57 final static String PREF_CLOCK_FACE = "face";
58 final static String PREF_SHOW_CLOCK = "show_clock";
60 /** Cap alarm count at this number */
61 final static int MAX_ALARM_COUNT = 12;
63 /** This must be false for production. If true, turns on logging,
65 final static boolean DEBUG = false;
67 private SharedPreferences mPrefs;
68 private LayoutInflater mFactory;
69 private ViewGroup mClockLayout;
70 private View mClock = null;
71 private ListView mAlarmsList;
72 private Cursor mCursor;
74 private String mAm, mPm;
77 * Which clock face to show
79 private int mFace = -1;
82 * FIXME: it would be nice for this to live in an xml config file.
84 final static int[] CLOCKS = {
85 R.layout.clock_basic_bw,
86 R.layout.clock_googly,
87 R.layout.clock_droid2,
88 R.layout.clock_droids,
89 R.layout.digital_clock
92 private class AlarmTimeAdapter extends CursorAdapter {
93 public AlarmTimeAdapter(Context context, Cursor cursor) {
94 super(context, cursor);
97 public View newView(Context context, Cursor cursor, ViewGroup parent) {
98 View ret = mFactory.inflate(R.layout.alarm_time, parent, false);
100 ((TextView) ret.findViewById(R.id.am)).setText(mAm);
101 ((TextView) ret.findViewById(R.id.pm)).setText(mPm);
103 DigitalClock digitalClock = (DigitalClock)ret.findViewById(R.id.digitalClock);
104 digitalClock.setLive(false);
105 if (Log.LOGV) Log.v("newView " + cursor.getPosition());
109 public void bindView(View view, Context context, Cursor cursor) {
110 final Alarm alarm = new Alarm(cursor);
112 CheckBox onButton = (CheckBox)view.findViewById(R.id.alarmButton);
113 onButton.setChecked(alarm.enabled);
114 onButton.setOnClickListener(new OnClickListener() {
115 public void onClick(View v) {
116 boolean isChecked = ((CheckBox) v).isChecked();
117 Alarms.enableAlarm(AlarmClock.this, alarm.id,
120 SetAlarm.popAlarmSetToast(AlarmClock.this,
121 alarm.hour, alarm.minutes, alarm.daysOfWeek);
126 DigitalClock digitalClock =
127 (DigitalClock) view.findViewById(R.id.digitalClock);
129 // set the alarm text
130 final Calendar c = Calendar.getInstance();
131 c.set(Calendar.HOUR_OF_DAY, alarm.hour);
132 c.set(Calendar.MINUTE, alarm.minutes);
133 digitalClock.updateTime(c);
135 // Set the repeat text or leave it blank if it does not repeat.
136 TextView daysOfWeekView =
137 (TextView) digitalClock.findViewById(R.id.daysOfWeek);
138 final String daysOfWeekStr =
139 alarm.daysOfWeek.toString(AlarmClock.this, false);
140 if (daysOfWeekStr != null && daysOfWeekStr.length() != 0) {
141 daysOfWeekView.setText(daysOfWeekStr);
142 daysOfWeekView.setVisibility(View.VISIBLE);
144 daysOfWeekView.setVisibility(View.GONE);
149 (TextView) digitalClock.findViewById(R.id.label);
150 if (alarm.label != null && alarm.label.length() != 0) {
151 labelView.setText(alarm.label);
152 labelView.setVisibility(View.VISIBLE);
154 labelView.setVisibility(View.GONE);
160 public boolean onContextItemSelected(final MenuItem item) {
161 final AdapterContextMenuInfo info =
162 (AdapterContextMenuInfo) item.getMenuInfo();
163 final int id = (int) info.id;
164 switch (item.getItemId()) {
165 case R.id.delete_alarm:
166 // Confirm that the alarm will be deleted.
167 new AlertDialog.Builder(this)
168 .setTitle(getString(R.string.delete_alarm))
169 .setMessage(getString(R.string.delete_alarm_confirm))
170 .setPositiveButton(android.R.string.ok,
171 new DialogInterface.OnClickListener() {
172 public void onClick(DialogInterface d,
174 Alarms.deleteAlarm(AlarmClock.this, id);
177 .setNegativeButton(android.R.string.cancel, null)
181 case R.id.enable_alarm:
182 final Cursor c = (Cursor) mAlarmsList.getAdapter()
183 .getItem(info.position);
184 final Alarm alarm = new Alarm(c);
185 Alarms.enableAlarm(this, alarm.id, !alarm.enabled);
186 if (!alarm.enabled) {
187 SetAlarm.popAlarmSetToast(this, alarm.hour, alarm.minutes,
195 return super.onContextItemSelected(item);
199 protected void onCreate(Bundle icicle) {
200 super.onCreate(icicle);
202 String[] ampm = new DateFormatSymbols().getAmPmStrings();
206 mFactory = LayoutInflater.from(this);
207 mPrefs = getSharedPreferences(PREFERENCES, 0);
208 mCursor = Alarms.getAlarmsCursor(getContentResolver());
211 setClockVisibility(mPrefs.getBoolean(PREF_SHOW_CLOCK, true));
215 public void onConfigurationChanged(Configuration newConfig) {
216 super.onConfigurationChanged(newConfig);
221 private void updateLayout() {
222 setContentView(R.layout.alarm_clock);
223 mAlarmsList = (ListView) findViewById(R.id.alarms_list);
224 mAlarmsList.setAdapter(new AlarmTimeAdapter(this, mCursor));
225 mAlarmsList.setVerticalScrollBarEnabled(true);
226 mAlarmsList.setOnItemClickListener(this);
227 mAlarmsList.setOnCreateContextMenuListener(this);
229 mClockLayout = (ViewGroup) findViewById(R.id.clock_layout);
230 mClockLayout.setOnClickListener(new View.OnClickListener() {
231 public void onClick(View v) {
232 final Intent intent =
233 new Intent(AlarmClock.this, ClockPicker.class);
234 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
235 startActivity(intent);
241 protected void onResume() {
244 int face = mPrefs.getInt(PREF_CLOCK_FACE, 0);
246 if (face < 0 || face >= AlarmClock.CLOCKS.length) {
256 protected void onDestroy() {
258 ToastMaster.cancelToast();
259 mCursor.deactivate();
262 protected void inflateClock() {
263 if (mClock != null) {
264 mClockLayout.removeView(mClock);
267 LayoutInflater.from(this).inflate(CLOCKS[mFace], mClockLayout);
268 mClock = findViewById(R.id.clock);
270 TextView am = (TextView) findViewById(R.id.am);
271 TextView pm = (TextView) findViewById(R.id.pm);
282 public boolean onCreateOptionsMenu(Menu menu) {
284 getMenuInflater().inflate(R.menu.main_menu, menu);
286 return super.onCreateOptionsMenu(menu);
290 public void onCreateContextMenu(ContextMenu menu, View view,
291 ContextMenuInfo menuInfo) {
292 // Inflate the menu from xml.
293 getMenuInflater().inflate(R.menu.context_menu, menu);
295 // Use the current item to create a custom view for the header.
296 final AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
298 (Cursor) mAlarmsList.getAdapter().getItem((int) info.position);
299 final Alarm alarm = new Alarm(c);
301 // Construct the Calendar to compute the time.
302 final Calendar cal = Calendar.getInstance();
303 cal.set(Calendar.HOUR_OF_DAY, alarm.hour);
304 cal.set(Calendar.MINUTE, alarm.minutes);
305 final String time = Alarms.formatTime(this, cal);
307 // Inflate the custom view and set each TextView's text.
308 final View v = mFactory.inflate(R.layout.context_menu_header, null);
309 TextView textView = (TextView) v.findViewById(R.id.header_time);
310 textView.setText(time);
311 textView = (TextView) v.findViewById(R.id.header_label);
312 textView.setText(alarm.label);
314 // Set the custom view on the menu.
315 menu.setHeaderView(v);
316 // Change the text to "disable" if the alarm is already enabled.
318 menu.findItem(R.id.enable_alarm).setTitle(R.string.disable_alarm);
322 public void onItemClick(AdapterView parent, View v, int pos, long id) {
323 Intent intent = new Intent(this, SetAlarm.class);
324 intent.putExtra(Alarms.ALARM_ID, (int) id);
325 startActivity(intent);
329 * Only allow user to add a new alarm if there are fewer than
333 public boolean onPrepareOptionsMenu(Menu menu) {
334 menu.findItem(R.id.menu_add_alarm).setVisible(
335 mAlarmsList.getAdapter().getCount() < MAX_ALARM_COUNT);
336 menu.findItem(R.id.menu_toggle_clock).setTitle(
337 getClockVisibility() ? R.string.hide_clock
338 : R.string.show_clock);
339 return super.onPrepareOptionsMenu(menu);
343 public boolean onOptionsItemSelected(MenuItem item) {
344 switch (item.getItemId()) {
345 case R.id.menu_add_alarm:
346 Uri uri = Alarms.addAlarm(getContentResolver());
347 // FIXME: scroll to new item?
348 String segment = uri.getPathSegments().get(1);
349 int newId = Integer.parseInt(segment);
351 Log.v("In AlarmClock, new alarm id = " + newId);
353 Intent intent = new Intent(this, SetAlarm.class);
354 intent.putExtra(Alarms.ALARM_ID, newId);
355 startActivity(intent);
358 case R.id.menu_toggle_clock:
359 setClockVisibility(!getClockVisibility());
360 saveClockVisibility();
363 case R.id.menu_settings:
364 startActivity(new Intent(this, SettingsActivity.class));
368 return super.onOptionsItemSelected(item);
372 private boolean getClockVisibility() {
373 return mClockLayout.getVisibility() == View.VISIBLE;
376 private void setClockVisibility(boolean visible) {
377 mClockLayout.setVisibility(visible ? View.VISIBLE : View.GONE);
380 private void saveClockVisibility() {
381 mPrefs.edit().putBoolean(PREF_SHOW_CLOCK, getClockVisibility()).commit();