From 086a183aca9152b65d34afdbf94ddeaefc5a1eb3 Mon Sep 17 00:00:00 2001 From: Evan Charlton Date: Mon, 29 Nov 2010 01:07:54 -0500 Subject: Desk Clock can launch a user-specified application. The Desk Clock can now launch an application in addition to standard alarm functionality. The user also has the ability to optionally not show the snooze/dismiss dialog and notification, but only if the alarm is silent and without vibrate enabled. Change-Id: I6bfad143d28b541ce264cf724c4ce7efb6a1ca54 --- res/values/strings.xml | 18 +++++++ res/xml/alarm_prefs.xml | 9 ++++ src/com/android/deskclock/Alarm.java | 38 +++++++++++++- src/com/android/deskclock/AlarmProvider.java | 17 ++++--- src/com/android/deskclock/AlarmReceiver.java | 18 +++++++ src/com/android/deskclock/Alarms.java | 6 +++ src/com/android/deskclock/SetAlarm.java | 74 ++++++++++++++++++++++++++++ 7 files changed, 171 insertions(+), 9 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 858e53bc4..507fa5f1e 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -55,6 +55,24 @@ Alarm + + Application + + + App to launch + + + None + + + Hide dialog + + + No snooze/dismiss dialog + + + Snooze/dismiss dialog will be shown + Set alarm diff --git a/res/xml/alarm_prefs.xml b/res/xml/alarm_prefs.xml index 3ca8ed050..a76049d3b 100644 --- a/res/xml/alarm_prefs.xml +++ b/res/xml/alarm_prefs.xml @@ -40,4 +40,13 @@ android:persistent="false" android:title="@string/label" android:dialogTitle="@string/label" /> + + diff --git a/src/com/android/deskclock/Alarm.java b/src/com/android/deskclock/Alarm.java index dedc0d848..23d4b9541 100644 --- a/src/com/android/deskclock/Alarm.java +++ b/src/com/android/deskclock/Alarm.java @@ -17,14 +17,16 @@ package com.android.deskclock; import android.content.Context; +import android.content.Intent; import android.database.Cursor; import android.media.RingtoneManager; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; import android.provider.BaseColumns; -import android.text.format.DateFormat; +import android.text.TextUtils; +import java.net.URISyntaxException; import java.text.DateFormatSymbols; import java.util.Calendar; @@ -59,6 +61,8 @@ public final class Alarm implements Parcelable { p.writeString(label); p.writeParcelable(alert, flags); p.writeInt(silent ? 1 : 0); + p.writeString(intent); + p.writeInt(noDialog ? 1 : 0); } ////////////////////////////// // end Parcelable apis @@ -123,6 +127,18 @@ public final class Alarm implements Parcelable { */ public static final String ALERT = "alert"; + /** + * Intent to fire when alarm triggers + *

Type: STRING

+ */ + public static final String INTENT = "intent"; + + /** + * Option to show dialog or not + *

Type: BOOLEAN

+ */ + public static final String NO_DIALOG = "no_dialog"; + /** * The default sort order for this table */ @@ -134,7 +150,7 @@ public final class Alarm implements Parcelable { static final String[] ALARM_QUERY_COLUMNS = { _ID, HOUR, MINUTES, DAYS_OF_WEEK, ALARM_TIME, - ENABLED, VIBRATE, MESSAGE, ALERT }; + ENABLED, VIBRATE, MESSAGE, ALERT, INTENT, NO_DIALOG }; /** * These save calls to cursor.getColumnIndexOrThrow() @@ -149,6 +165,8 @@ public final class Alarm implements Parcelable { public static final int ALARM_VIBRATE_INDEX = 6; public static final int ALARM_MESSAGE_INDEX = 7; public static final int ALARM_ALERT_INDEX = 8; + public static final int ALARM_INTENT_INDEX = 9; + public static final int ALARM_NO_DIALOG_INDEX = 10; } ////////////////////////////// // End column definitions @@ -165,6 +183,8 @@ public final class Alarm implements Parcelable { public String label; public Uri alert; public boolean silent; + public String intent; + public boolean noDialog; public Alarm(Cursor c) { id = c.getInt(Columns.ALARM_ID_INDEX); @@ -193,6 +213,18 @@ public final class Alarm implements Parcelable { RingtoneManager.TYPE_ALARM); } } + String intentString = c.getString(Columns.ALARM_INTENT_INDEX); + if (!TextUtils.isEmpty(intentString)) { + try { + // Try and parse the URI, see if it breaks. + Intent.parseUri(intentString, Intent.URI_INTENT_SCHEME); + // If it's an invalid URI, the exception will short-circuit. + intent = intentString; + } catch (URISyntaxException e) { + intent = null; + } + } + noDialog = c.getInt(Columns.ALARM_NO_DIALOG_INDEX) == 1; } public Alarm(Parcel p) { @@ -206,6 +238,8 @@ public final class Alarm implements Parcelable { label = p.readString(); alert = (Uri) p.readParcelable(null); silent = p.readInt() == 1; + intent = p.readString(); + noDialog = p.readInt() == 1; } // Creates a default alarm at the current time. diff --git a/src/com/android/deskclock/AlarmProvider.java b/src/com/android/deskclock/AlarmProvider.java index 133e79abf..34f05a4b8 100644 --- a/src/com/android/deskclock/AlarmProvider.java +++ b/src/com/android/deskclock/AlarmProvider.java @@ -44,7 +44,7 @@ public class AlarmProvider extends ContentProvider { private static class DatabaseHelper extends SQLiteOpenHelper { private static final String DATABASE_NAME = "alarms.db"; - private static final int DATABASE_VERSION = 5; + private static final int DATABASE_VERSION = 7; public DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); @@ -61,14 +61,17 @@ public class AlarmProvider extends ContentProvider { "enabled INTEGER, " + "vibrate INTEGER, " + "message TEXT, " + - "alert TEXT);"); + "alert TEXT, " + + "intent TEXT," + + "no_dialog INTEGER);"); // insert default alarms - String insertMe = "INSERT INTO alarms " + - "(hour, minutes, daysofweek, alarmtime, enabled, vibrate, message, alert) " + - "VALUES "; - db.execSQL(insertMe + "(8, 30, 31, 0, 0, 1, '', '');"); - db.execSQL(insertMe + "(9, 00, 96, 0, 0, 1, '', '');"); + String insertMe = "INSERT INTO alarms " + + "(hour, minutes, daysofweek, alarmtime, enabled, vibrate, " + + "message, alert, intent, no_dialog) " + + "VALUES "; + db.execSQL(insertMe + "(8, 30, 31, 0, 0, 1, '', '', '', 0);"); + db.execSQL(insertMe + "(9, 00, 96, 0, 0, 1, '', '', '', 0);"); } @Override diff --git a/src/com/android/deskclock/AlarmReceiver.java b/src/com/android/deskclock/AlarmReceiver.java index 242f865b5..2bacada09 100644 --- a/src/com/android/deskclock/AlarmReceiver.java +++ b/src/com/android/deskclock/AlarmReceiver.java @@ -26,6 +26,11 @@ import android.content.Intent; import android.content.BroadcastReceiver; import android.database.Cursor; import android.os.Parcel; +import android.text.TextUtils; + +import java.net.URISyntaxException; +import java.text.SimpleDateFormat; +import java.util.Date; /** * Glue class: connects AlarmAlert IntentReceiver to AlarmAlert @@ -112,6 +117,19 @@ public class AlarmReceiver extends BroadcastReceiver { c = AlarmAlertFullScreen.class; } + // If there's an intent specified, start that activity. + if (!TextUtils.isEmpty(alarm.intent)) { + try { + Intent alarmActivity = Intent.parseUri(alarm.intent, Intent.URI_INTENT_SCHEME); + alarmActivity.setFlags(alarmActivity.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(alarmActivity); + } catch (URISyntaxException e) { + // Silently fail since the intent failed to parse. + } + } else { + Log.i("Empty or null intent!"); + } + // Play the alarm alert and vibrate the device. Intent playAlarm = new Intent(Alarms.ALARM_ALERT_ACTION); playAlarm.putExtra(Alarms.ALARM_INTENT_EXTRA, alarm); diff --git a/src/com/android/deskclock/Alarms.java b/src/com/android/deskclock/Alarms.java index 63b68c96e..9a1b4b9c2 100644 --- a/src/com/android/deskclock/Alarms.java +++ b/src/com/android/deskclock/Alarms.java @@ -29,6 +29,7 @@ import android.database.Cursor; import android.net.Uri; import android.os.Parcel; import android.provider.Settings; +import android.text.TextUtils; import android.text.format.DateFormat; import java.util.Calendar; @@ -167,6 +168,11 @@ public class Alarms { values.put(Alarm.Columns.ALERT, alarm.alert == null ? ALARM_ALERT_SILENT : alarm.alert.toString()); + // A null (or blank) intent Uri indicates no app launch + values.put(Alarm.Columns.INTENT, TextUtils.isEmpty(alarm.intent) ? "" : alarm.intent); + + values.put(Alarm.Columns.NO_DIALOG, alarm.noDialog); + return values; } diff --git a/src/com/android/deskclock/SetAlarm.java b/src/com/android/deskclock/SetAlarm.java index ebe6e5054..db0ced7e7 100644 --- a/src/com/android/deskclock/SetAlarm.java +++ b/src/com/android/deskclock/SetAlarm.java @@ -16,11 +16,14 @@ package com.android.deskclock; +import java.util.ArrayList; + import android.app.AlertDialog; import android.app.TimePickerDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.content.Intent.ShortcutIconResource; import android.os.Bundle; import android.os.Handler; import android.preference.CheckBoxPreference; @@ -48,6 +51,8 @@ public class SetAlarm extends PreferenceActivity implements TimePickerDialog.OnTimeSetListener, Preference.OnPreferenceChangeListener { + private static final int CODE_PICK_APP = 1; + private EditTextPreference mLabel; private CheckBoxPreference mEnabledPref; private Preference mTimePref; @@ -55,6 +60,8 @@ public class SetAlarm extends PreferenceActivity private CheckBoxPreference mVibratePref; private RepeatPreference mRepeatPref; private MenuItem mTestAlarmItem; + private Preference mIntentPref; + private CheckBoxPreference mNoDialogPref; private int mId; private int mHour; @@ -112,6 +119,9 @@ public class SetAlarm extends PreferenceActivity mVibratePref.setOnPreferenceChangeListener(this); mRepeatPref = (RepeatPreference) findPreference("setRepeat"); mRepeatPref.setOnPreferenceChangeListener(this); + mNoDialogPref = (CheckBoxPreference) findPreference("no_dialog"); + mNoDialogPref.setOnPreferenceChangeListener(this); + mIntentPref = findPreference("intent"); Intent i = getIntent(); mId = i.getIntExtra(Alarms.ALARM_ID, -1); @@ -211,7 +221,9 @@ public class SetAlarm extends PreferenceActivity mVibratePref.setChecked(alarm.vibrate); // Give the alert uri to the preference. mAlarmPref.setAlert(alarm.alert); + mIntentPref.setSummary(alarm.intent); updateTime(); + updateNoDialog(alarm); } @Override @@ -219,6 +231,8 @@ public class SetAlarm extends PreferenceActivity Preference preference) { if (preference == mTimePref) { showTimePicker(); + } else if (preference == mIntentPref) { + showAppPicker(); } return super.onPreferenceTreeClick(preferenceScreen, preference); @@ -240,6 +254,48 @@ public class SetAlarm extends PreferenceActivity DateFormat.is24HourFormat(this)).show(); } + private void showAppPicker() { + Bundle bundle = new Bundle(); + + ArrayList shortcutNames = new ArrayList(); + shortcutNames.add(getString(R.string.application_none)); + bundle.putStringArrayList(Intent.EXTRA_SHORTCUT_NAME, shortcutNames); + + ArrayList shortcutIcons = new ArrayList(); + shortcutIcons + .add(ShortcutIconResource.fromContext(this, android.R.drawable.ic_menu_delete)); + bundle.putParcelableArrayList(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, shortcutIcons); + + Intent appIntent = new Intent(Intent.ACTION_PICK_ACTIVITY); + Intent filterIntent = new Intent(Intent.ACTION_MAIN); + filterIntent.addCategory(Intent.CATEGORY_LAUNCHER); + appIntent.putExtra(Intent.EXTRA_INTENT, filterIntent); + appIntent.putExtra(Intent.EXTRA_TITLE, getText(R.string.application_title)); + appIntent.putExtras(bundle); + startActivityForResult(appIntent, CODE_PICK_APP); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + switch (requestCode) { + case CODE_PICK_APP: + setAlarmIntent(resultCode, data); + default: + super.onActivityResult(requestCode, resultCode, data); + } + } + + private void setAlarmIntent(int resultCode, Intent data) { + if (resultCode == RESULT_CANCELED || data == null) return; + + String none = getString(R.string.application_none); + if (none.equals(data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME))) { + mIntentPref.setSummary(""); + } else { + mIntentPref.setSummary(data.toUri(Intent.URI_INTENT_SCHEME)); + } + } + public void onTimeSet(TimePicker view, int hourOfDay, int minute) { // onTimeSet is called when the user clicks "Set" mTimePickerCancelled = false; @@ -259,6 +315,20 @@ public class SetAlarm extends PreferenceActivity mTimePref.setSummary(Alarms.formatTime(this, mHour, mMinutes, mRepeatPref.getDaysOfWeek())); } + + private void updateNoDialog(Alarm alarm) { + // If the alarm has vibration or sound, the dialog must be shown. + boolean silent = alarm.silent + || (alarm.alert == null || Alarms.ALARM_ALERT_SILENT.equals(alarm.alert)); + if (!silent || alarm.vibrate) { + mNoDialogPref.setEnabled(false); + alarm.noDialog = false; + } else { + mNoDialogPref.setEnabled(true); + } + + mNoDialogPref.setChecked(alarm.noDialog); + } private long saveAlarmAndEnableRevert() { // Enable "Revert" to go back to the original Alarm. @@ -277,6 +347,10 @@ public class SetAlarm extends PreferenceActivity alarm.vibrate = mVibratePref.isChecked(); alarm.label = mLabel.getText(); alarm.alert = mAlarmPref.getAlert(); + CharSequence intent = mIntentPref.getSummary(); + alarm.intent = intent == null ? "" : intent.toString(); + alarm.noDialog = mNoDialogPref.isChecked(); + updateNoDialog(alarm); long time; if (alarm.id == -1) { -- cgit v1.2.3