Create an elegantly designed Reminder/Alarm clock application
DownloadKeywords: ListActivity SimpleCursorAdapter SQLiteDatabase AlarmManager NotificationManager IntentService BroadcastReceiver ToggleButton ViewSwitcher DatePicker TimePicker RadioGroup
Contents- Overview
- Create a new Eclipse Android project
- Define the Data model
- The Android Manifest file
- The Application class
- The Preferences screen
- The Alarm Service
- The Alarm Receiver
- The Alarm Setter
- The Main screen
- The Options Menu
- The Context Menu
- The Edit Dialog
- The New Reminder screen
- Date and Time Controls
6. The Preferences screen
Android provides an easy means to implement preferences screen. Create a xml file (for ex. settings.xml) under res/xml directory using predefined preferences for ex. ListPreference, CheckBoxPreference, RingtonePreference.<?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" > <PreferenceCategory android:title="Display Settings"> <ListPreference android:key="time_option" android:title="Display Time" android:summary="Actual" android:entries="@array/time_option_arr" android:entryValues="@array/val_arr" android:defaultValue="0" /> <ListPreference android:key="date_range" android:title="Date Range" android:summary="Daily" android:entries="@array/date_range_arr" android:entryValues="@array/val_arr" android:defaultValue="0" /> <ListPreference android:key="date_format" android:title="Date Format" android:summary="yyyy-M-d" android:entries="@array/date_format_arr" android:entryValues="@array/date_format_arr" android:defaultValue="yyyy-M-d" /> <CheckBoxPreference android:key="time_format" android:title="Time Format" android:summary="Use 24-hour format" android:defaultValue="true" /> </PreferenceCategory> <PreferenceCategory android:title="Notification Settings"> <CheckBoxPreference android:key="vibrate_pref" android:title="Vibrate" android:summary="Vibrate on notification" android:defaultValue="true" /> <RingtonePreference android:key="ringtone_pref" android:title="Set Ringtone" android:summary="Default" android:ringtoneType="all" android:showDefault="true" android:showSilent="false" /> </PreferenceCategory> </PreferenceScreen>Next, create a new activity and make it extend PreferenceActivity. Additionally we will implement OnSharedPreferenceChangeListener interface to do our stuff when a preference value gets changed.
public class SettingsActivity extends PreferenceActivity implements OnSharedPreferenceChangeListener { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.settings); } @Override protected void onResume(){ super.onResume(); getPreferenceScreen().getSharedPreferences() .registerOnSharedPreferenceChangeListener(this); // TODO update preferences } @Override protected void onPause() { super.onPause(); getPreferenceScreen().getSharedPreferences() .unregisterOnSharedPreferenceChangeListener(this); } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { updatePreference(key); } }We created a generic method to update the summary of a preference when its value is changed.
private void updatePreference(String key){ Preference pref = findPreference(key); if (pref instanceof ListPreference) { ListPreference listPref = (ListPreference) pref; pref.setSummary(listPref.getEntry()); return; } if (pref instanceof EditTextPreference){ EditTextPreference editPref = (EditTextPreference) pref; editPref.setSummary(editPref.getText()); return; } if (pref instanceof RingtonePreference) { Uri ringtoneUri = Uri.parse(RemindMe.getRingtone()); Ringtone ringtone = RingtoneManager.getRingtone(this, ringtoneUri); if (ringtone != null) pref.setSummary(ringtone.getTitle(this)); } }
7. The Alarm Service
It is a good practice to perform all time consuming tasks in a separate thread which is the secret behind responsive UI. Android provides an easy means to accomplish this through IntentService.So we create a class which extends IntentService and override onHandleIntent(intent) method to do our stuff. We have already declared this component using <service> tag in the manifest file.
public class AlarmService extends IntentService { public static final String CREATE = "CREATE"; public static final String CANCEL = "CANCEL"; private IntentFilter matcher; public AlarmService() { super(TAG); matcher = new IntentFilter(); matcher.addAction(CREATE); matcher.addAction(CANCEL); } @Override protected void onHandleIntent(Intent intent) { String action = intent.getAction(); String notificationId = intent.getStringExtra("notificationId"); if (matcher.matchAction(action)) { execute(action, notificationId); } } }The actual logic to create or cancel alarm is done in a separate private method.
private void execute(String action, String notificationId) { AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE); Cursor c = RemindMe.db.query(Notification.TABLE_NAME, null, "_id = ?", new String[]{notificationId}, null, null, null); if (c.moveToFirst()) { Intent i = new Intent(this, AlarmReceiver.class); i.putExtra("id", c.getLong(c.getColumnIndex(Notification.COL_ID))); i.putExtra("msg", c.getString(c.getColumnIndex(Notification.COL_MSG))); PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, PendingIntent.FLAG_UPDATE_CURRENT); long time = c.getLong(c.getColumnIndex(Notification.COL_DATETIME)); if (CREATE.equals(action)) { am.set(AlarmManager.RTC_WAKEUP, time, pi); } else if (CANCEL.equals(action)) { am.cancel(pi); } } c.close(); }
AlarmManager allows creation of repeating alarms using the method setRepeating(AlarmManager.RTC_WAKEUP, triggerAtTime, interval, operation)
We'll next implement the alarm receiver which creates notification when the alarm gets triggered. For this we use another system service provided by Android i.e. NOTIFICATION_SERVICE.