Home | History | Annotate | Download | only in alarmclock
      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 
     17 package com.android.alarmclock;
     18 
     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.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.AdapterView;
     39 import android.widget.AdapterView.AdapterContextMenuInfo;
     40 import android.widget.AdapterView.OnItemClickListener;
     41 import android.widget.CheckBox;
     42 import android.widget.CursorAdapter;
     43 import android.widget.ListView;
     44 import android.widget.TextView;
     45 
     46 import java.text.DateFormatSymbols;
     47 import java.util.Calendar;
     48 
     49 /**
     50  * AlarmClock application.
     51  */
     52 public class AlarmClock extends Activity implements OnItemClickListener {
     53 
     54     static final String PREFERENCES = "AlarmClock";
     55     static final String PREF_CLOCK_FACE = "face";
     56     static final String PREF_SHOW_CLOCK = "show_clock";
     57 
     58     /** Cap alarm count at this number */
     59     static final int MAX_ALARM_COUNT = 12;
     60 
     61     /** This must be false for production.  If true, turns on logging,
     62         test code, etc. */
     63     static final boolean DEBUG = false;
     64 
     65     private SharedPreferences mPrefs;
     66     private LayoutInflater mFactory;
     67     private ViewGroup mClockLayout;
     68     private View mClock = null;
     69     private ListView mAlarmsList;
     70     private Cursor mCursor;
     71 
     72     private String mAm, mPm;
     73 
     74     /**
     75      * Which clock face to show
     76      */
     77     private int mFace = -1;
     78 
     79     /*
     80      * TODO: it would be nice for this to live in an xml config file.
     81      */
     82     static final int[] CLOCKS = {
     83         R.layout.clock_basic_bw,
     84         R.layout.clock_googly,
     85         R.layout.clock_droid2,
     86         R.layout.clock_droids,
     87         R.layout.digital_clock
     88     };
     89 
     90     private class AlarmTimeAdapter extends CursorAdapter {
     91         public AlarmTimeAdapter(Context context, Cursor cursor) {
     92             super(context, cursor);
     93         }
     94 
     95         public View newView(Context context, Cursor cursor, ViewGroup parent) {
     96             View ret = mFactory.inflate(R.layout.alarm_time, parent, false);
     97 
     98             ((TextView) ret.findViewById(R.id.am)).setText(mAm);
     99             ((TextView) ret.findViewById(R.id.pm)).setText(mPm);
    100 
    101             DigitalClock digitalClock =
    102                     (DigitalClock) ret.findViewById(R.id.digitalClock);
    103             digitalClock.setLive(false);
    104             return ret;
    105         }
    106 
    107         public void bindView(View view, Context context, Cursor cursor) {
    108             final Alarm alarm = new Alarm(cursor);
    109 
    110             CheckBox onButton = (CheckBox) view.findViewById(R.id.alarmButton);
    111             onButton.setChecked(alarm.enabled);
    112             onButton.setOnClickListener(new OnClickListener() {
    113                     public void onClick(View v) {
    114                         boolean isChecked = ((CheckBox) v).isChecked();
    115                         Alarms.enableAlarm(AlarmClock.this, alarm.id,
    116                             isChecked);
    117                         if (isChecked) {
    118                             SetAlarm.popAlarmSetToast(AlarmClock.this,
    119                                 alarm.hour, alarm.minutes, alarm.daysOfWeek);
    120                         }
    121                     }
    122             });
    123 
    124             DigitalClock digitalClock =
    125                     (DigitalClock) view.findViewById(R.id.digitalClock);
    126 
    127             // set the alarm text
    128             final Calendar c = Calendar.getInstance();
    129             c.set(Calendar.HOUR_OF_DAY, alarm.hour);
    130             c.set(Calendar.MINUTE, alarm.minutes);
    131             digitalClock.updateTime(c);
    132 
    133             // Set the repeat text or leave it blank if it does not repeat.
    134             TextView daysOfWeekView =
    135                     (TextView) digitalClock.findViewById(R.id.daysOfWeek);
    136             final String daysOfWeekStr =
    137                     alarm.daysOfWeek.toString(AlarmClock.this, false);
    138             if (daysOfWeekStr != null && daysOfWeekStr.length() != 0) {
    139                 daysOfWeekView.setText(daysOfWeekStr);
    140                 daysOfWeekView.setVisibility(View.VISIBLE);
    141             } else {
    142                 daysOfWeekView.setVisibility(View.GONE);
    143             }
    144 
    145             // Display the label
    146             TextView labelView =
    147                     (TextView) digitalClock.findViewById(R.id.label);
    148             if (alarm.label != null && alarm.label.length() != 0) {
    149                 labelView.setText(alarm.label);
    150                 labelView.setVisibility(View.VISIBLE);
    151             } else {
    152                 labelView.setVisibility(View.GONE);
    153             }
    154         }
    155     };
    156 
    157     @Override
    158     public boolean onContextItemSelected(final MenuItem item) {
    159         final AdapterContextMenuInfo info =
    160                 (AdapterContextMenuInfo) item.getMenuInfo();
    161         final int id = (int) info.id;
    162         switch (item.getItemId()) {
    163             case R.id.delete_alarm:
    164                 // Confirm that the alarm will be deleted.
    165                 new AlertDialog.Builder(this)
    166                         .setTitle(getString(R.string.delete_alarm))
    167                         .setMessage(getString(R.string.delete_alarm_confirm))
    168                         .setPositiveButton(android.R.string.ok,
    169                                 new DialogInterface.OnClickListener() {
    170                                     public void onClick(DialogInterface d,
    171                                             int w) {
    172                                         Alarms.deleteAlarm(AlarmClock.this, id);
    173                                     }
    174                                 })
    175                         .setNegativeButton(android.R.string.cancel, null)
    176                         .show();
    177                 return true;
    178 
    179             case R.id.enable_alarm:
    180                 final Cursor c = (Cursor) mAlarmsList.getAdapter()
    181                         .getItem(info.position);
    182                 final Alarm alarm = new Alarm(c);
    183                 Alarms.enableAlarm(this, alarm.id, !alarm.enabled);
    184                 if (!alarm.enabled) {
    185                     SetAlarm.popAlarmSetToast(this, alarm.hour, alarm.minutes,
    186                             alarm.daysOfWeek);
    187                 }
    188                 return true;
    189 
    190             default:
    191                 break;
    192         }
    193         return super.onContextItemSelected(item);
    194     }
    195 
    196     @Override
    197     protected void onCreate(Bundle icicle) {
    198         super.onCreate(icicle);
    199 
    200         String[] ampm = new DateFormatSymbols().getAmPmStrings();
    201         mAm = ampm[0];
    202         mPm = ampm[1];
    203 
    204         mFactory = LayoutInflater.from(this);
    205         mPrefs = getSharedPreferences(PREFERENCES, 0);
    206         mCursor = Alarms.getAlarmsCursor(getContentResolver());
    207 
    208         updateLayout();
    209         setClockVisibility(mPrefs.getBoolean(PREF_SHOW_CLOCK, true));
    210     }
    211 
    212     private final Handler mHandler = new Handler();
    213 
    214     @Override
    215     public void onConfigurationChanged(Configuration newConfig) {
    216         super.onConfigurationChanged(newConfig);
    217         // Send a message to avoid a possible ANR.
    218         mHandler.post(new Runnable() {
    219             public void run() {
    220                 updateLayout();
    221                 inflateClock();
    222                 setClockVisibility(mPrefs.getBoolean(PREF_SHOW_CLOCK, true));
    223             }
    224         });
    225     }
    226 
    227     private void updateLayout() {
    228         setContentView(R.layout.alarm_clock);
    229         mAlarmsList = (ListView) findViewById(R.id.alarms_list);
    230         mAlarmsList.setAdapter(new AlarmTimeAdapter(this, mCursor));
    231         mAlarmsList.setVerticalScrollBarEnabled(true);
    232         mAlarmsList.setOnItemClickListener(this);
    233         mAlarmsList.setOnCreateContextMenuListener(this);
    234 
    235         mClockLayout = (ViewGroup) findViewById(R.id.clock_layout);
    236         mClockLayout.setOnClickListener(new View.OnClickListener() {
    237                 public void onClick(View v) {
    238                     final Intent intent =
    239                             new Intent(AlarmClock.this, ClockPicker.class);
    240                     intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    241                     startActivity(intent);
    242                 }
    243             });
    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             }
    257             inflateClock();
    258         }
    259     }
    260 
    261     @Override
    262     protected void onDestroy() {
    263         super.onDestroy();
    264         ToastMaster.cancelToast();
    265         mCursor.deactivate();
    266     }
    267 
    268     protected void inflateClock() {
    269         if (mClock != null) {
    270             mClockLayout.removeView(mClock);
    271         }
    272 
    273         LayoutInflater.from(this).inflate(CLOCKS[mFace], mClockLayout);
    274         mClock = findViewById(R.id.clock);
    275 
    276         TextView am = (TextView) findViewById(R.id.am);
    277         TextView pm = (TextView) findViewById(R.id.pm);
    278 
    279         if (am != null) {
    280             am.setText(mAm);
    281         }
    282         if (pm != null) {
    283             pm.setText(mPm);
    284         }
    285     }
    286 
    287     @Override
    288     public boolean onCreateOptionsMenu(Menu menu) {
    289         // Inflate our menu.
    290         getMenuInflater().inflate(R.menu.main_menu, menu);
    291 
    292         return super.onCreateOptionsMenu(menu);
    293     }
    294 
    295     @Override
    296     public void onCreateContextMenu(ContextMenu menu, View view,
    297             ContextMenuInfo menuInfo) {
    298         // Inflate the menu from xml.
    299         getMenuInflater().inflate(R.menu.context_menu, menu);
    300 
    301         // Use the current item to create a custom view for the header.
    302         final AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
    303         final Cursor c =
    304                 (Cursor) mAlarmsList.getAdapter().getItem((int) info.position);
    305         final Alarm alarm = new Alarm(c);
    306 
    307         // Construct the Calendar to compute the time.
    308         final Calendar cal = Calendar.getInstance();
    309         cal.set(Calendar.HOUR_OF_DAY, alarm.hour);
    310         cal.set(Calendar.MINUTE, alarm.minutes);
    311         final String time = Alarms.formatTime(this, cal);
    312 
    313         // Inflate the custom view and set each TextView's text.
    314         final View v = mFactory.inflate(R.layout.context_menu_header, null);
    315         TextView textView = (TextView) v.findViewById(R.id.header_time);
    316         textView.setText(time);
    317         textView = (TextView) v.findViewById(R.id.header_label);
    318         textView.setText(alarm.label);
    319 
    320         // Set the custom view on the menu.
    321         menu.setHeaderView(v);
    322         // Change the text to "disable" if the alarm is already enabled.
    323         if (alarm.enabled) {
    324             menu.findItem(R.id.enable_alarm).setTitle(R.string.disable_alarm);
    325         }
    326     }
    327 
    328     public void onItemClick(AdapterView parent, View v, int pos, long id) {
    329         Intent intent = new Intent(this, SetAlarm.class);
    330         intent.putExtra(Alarms.ALARM_ID, (int) id);
    331         startActivity(intent);
    332     }
    333 
    334     /**
    335      * Only allow user to add a new alarm if there are fewer than
    336      * MAX_ALARM_COUNT
    337      */
    338     @Override
    339     public boolean onPrepareOptionsMenu(Menu menu) {
    340         menu.findItem(R.id.menu_add_alarm).setVisible(
    341                 mAlarmsList.getAdapter().getCount() < MAX_ALARM_COUNT);
    342         menu.findItem(R.id.menu_toggle_clock).setTitle(
    343                 getClockVisibility() ? R.string.hide_clock
    344                     : R.string.show_clock);
    345         return super.onPrepareOptionsMenu(menu);
    346     }
    347 
    348     @Override
    349     public boolean onOptionsItemSelected(MenuItem item) {
    350         switch (item.getItemId()) {
    351             case R.id.menu_add_alarm:
    352                 Uri uri = Alarms.addAlarm(getContentResolver());
    353                 // TODO: Create new alarm _after_ SetAlarm so the user has the
    354                 // chance to cancel alarm creation.
    355                 String segment = uri.getPathSegments().get(1);
    356                 int newId = Integer.parseInt(segment);
    357                 if (Log.LOGV) {
    358                     Log.v("In AlarmClock, new alarm id = " + newId);
    359                 }
    360                 Intent intent = new Intent(this, SetAlarm.class);
    361                 intent.putExtra(Alarms.ALARM_ID, newId);
    362                 startActivity(intent);
    363                 return true;
    364 
    365             case R.id.menu_toggle_clock:
    366                 setClockVisibility(!getClockVisibility());
    367                 saveClockVisibility();
    368                 return true;
    369 
    370             case R.id.menu_settings:
    371                 startActivity(new Intent(this, SettingsActivity.class));
    372                 return true;
    373         }
    374 
    375         return super.onOptionsItemSelected(item);
    376     }
    377 
    378 
    379     private boolean getClockVisibility() {
    380         return mClockLayout.getVisibility() == View.VISIBLE;
    381     }
    382 
    383     private void setClockVisibility(boolean visible) {
    384         mClockLayout.setVisibility(visible ? View.VISIBLE : View.GONE);
    385     }
    386 
    387     private void saveClockVisibility() {
    388         mPrefs.edit().putBoolean(PREF_SHOW_CLOCK, getClockVisibility()).commit();
    389     }
    390 }
    391