From 20f99f2b5f1be66574e63297e75b37395757e1e6 Mon Sep 17 00:00:00 2001 From: tim Date: Thu, 17 Apr 2014 13:40:28 +0200 Subject: [PATCH] Prevent subsequent alarms from snoozing; make pre-alarm an hour earlier; correct boot receiver bug. --- HypoAlarm/HypoAlarm-HypoAlarm.iml | 40 +++--- .../hypoalarm/AlarmAlertActivity.java | 2 +- .../hypoalarm/AlarmChangeReceiver.java | 4 +- .../org/treehouse/hypoalarm/AlarmNotify.java | 2 +- .../org/treehouse/hypoalarm/AlarmService.java | 68 ++++----- .../hypoalarm/CancelAlarmReceiver.java | 29 ++-- .../hypoalarm/CancelGraceReceiver.java | 11 +- .../treehouse/hypoalarm/GraceReceiver.java | 18 ++- .../org/treehouse/hypoalarm/MainActivity.java | 134 ++++++++++++++---- .../treehouse/hypoalarm/PreAlarmNotify.java | 2 +- .../treehouse/hypoalarm/PreAlarmReceiver.java | 2 +- HypoAlarm/src/main/res/values/strings.xml | 4 +- 12 files changed, 194 insertions(+), 122 deletions(-) diff --git a/HypoAlarm/HypoAlarm-HypoAlarm.iml b/HypoAlarm/HypoAlarm-HypoAlarm.iml index 70b00c6..978d53d 100644 --- a/HypoAlarm/HypoAlarm-HypoAlarm.iml +++ b/HypoAlarm/HypoAlarm-HypoAlarm.iml @@ -8,10 +8,11 @@ - - + - - - - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmAlertActivity.java b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmAlertActivity.java index 56cafd9..b558b0f 100644 --- a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmAlertActivity.java +++ b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmAlertActivity.java @@ -11,7 +11,7 @@ import android.view.WindowManager; import net.frakbot.glowpadbackport.GlowPadView; public class AlarmAlertActivity extends Activity { - public static Activity alertActivity; + public static Activity alertActivity; @Override protected void onCreate(Bundle savedInstanceState) { diff --git a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmChangeReceiver.java b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmChangeReceiver.java index 7a9589a..9aab468 100644 --- a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmChangeReceiver.java +++ b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmChangeReceiver.java @@ -16,10 +16,10 @@ public class AlarmChangeReceiver extends BroadcastReceiver { if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED") || intent.getAction().equals("android.intent.action.TIMEZONE_CHANGED") || intent.getAction().equals("android.intent.action.TIME_SET")) { - String alarmTimeStr = sharedPref.getString(context.getString(R.string.AlarmTimePref), null); + String alarmTimeStr = sharedPref.getString(context.getString(R.string.AlarmTimePref), MainActivity.defaultTimeStr); Calendar cal = MainActivity.TimeStringToCalendar(alarmTimeStr); Log.d("AlarmChangeReceiver", intent.getAction() + ": resetting alarm for " + MainActivity.debugDate(cal)); - MainActivity.resetAlarm(context, cal); + MainActivity.setAlarm(context, cal); } } } diff --git a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmNotify.java b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmNotify.java index aed664d..e1bf047 100644 --- a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmNotify.java +++ b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmNotify.java @@ -42,7 +42,7 @@ public class AlarmNotify extends Service { Log.d("AlarmNotify", "Notification started."); //final String phoneNumber = sharedPref.getString(getString(R.string.PhoneNumberPref), null); - final int gracePeriod = sharedPref.getInt(getString(R.string.GracePeriodPref), 60); + final int gracePeriod = sharedPref.getInt(getString(R.string.GracePeriodPref), MainActivity.defaultGracePeriod); Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_grey); final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); diff --git a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmService.java b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmService.java index c6058ce..0d96458 100644 --- a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmService.java +++ b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmService.java @@ -1,5 +1,6 @@ package za.org.treehouse.hypoalarm; +import android.app.ActivityManager; import android.app.AlarmManager; import android.app.PendingIntent; import android.app.Service; @@ -18,7 +19,7 @@ import java.util.Calendar; public class AlarmService extends Service { private static final int SNOOZE_TIME = 1000*60*5; // Snooze for 5 minutes if need be - private static final int ALERT_LIFE = 1000*60*1; // 2 minutes + private static final int ALERT_LIFE = 1000*60*2; // 2 minutes private static PowerManager.WakeLock wl; private static AlarmManager alarmManager; private static Intent alarmServiceIntent, alertActivityIntent, notifyIntent; @@ -36,13 +37,15 @@ public class AlarmService extends Service { // Ensure that CPU runs while the service is running, so we don't miss an alert or snooze PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "AlarmService"); + // TODO: wake lock? //wl.acquire(); alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); + } @Override public void onDestroy() { - Log.d("AlarmService", "Destroying alarm"); + Log.d("AlarmService", "Destroying alarm (alarmStarted: " + alarmStarted + ")"); if (alarmStarted) { stopAlert(getApplicationContext()); alarmStarted = false; @@ -56,9 +59,9 @@ public class AlarmService extends Service { public int onStartCommand(Intent intent, int flags, int startId) { alarmServiceIntent = intent; SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); - final Boolean alarmActive = sharedPref.getBoolean(getString(R.string.AlarmActivePref), true); - final int gracePeriod = sharedPref.getInt(getString(R.string.GracePeriodPref), 60); - final String alarmTimeStr = sharedPref.getString(getString(R.string.AlarmTimePref), null); + final Boolean alarmActive = sharedPref.getBoolean(getString(R.string.AlarmActivePref), MainActivity.defaultActive); + final String alarmTimeStr = sharedPref.getString(getString(R.string.AlarmTimePref), MainActivity.defaultTimeStr); + final int gracePeriod = sharedPref.getInt(getString(R.string.GracePeriodPref), MainActivity.defaultGracePeriod); if (alarmActive) { // Cancel the pre-alarm notification, if it exists @@ -79,23 +82,22 @@ public class AlarmService extends Service { // if nothing else happens, assume the alert was ignored. alarmStatus = ALARM_RUNNING; - // If dialing, active in a phone call, or on hold, don't bother with the alarm, just reset it for tomorrow + // Reset for tomorrow; as of API 19, setRepeating() is inexact, so we use setExact() + Calendar cal = MainActivity.TimeStringToCalendar(alarmTimeStr); + // Advance the calendar to tomorrow (and make sure the calendar hasn't already been advanced) + if (cal.before(Calendar.getInstance())) { + cal.add(Calendar.DAY_OF_MONTH, 1); + } + + MainActivity.setAlarm(getApplicationContext(), cal); + Log.d("AlarmService", "Alarm reset for next period"); + + // If dialing, active in a phone call, or on hold, don't bother with today's alarm, just reset it for tomorrow TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); if (telephonyManager.getCallState() != TelephonyManager.CALL_STATE_OFFHOOK) { - // Set a grace period alarm to send SMS - Calendar graceCal = Calendar.getInstance(); - graceCal.set(Calendar.SECOND, 0); - graceCal.add(Calendar.MINUTE, gracePeriod); - Intent graceIntent = new Intent(this, GraceReceiver.class); - PendingIntent gracePendingIntent = PendingIntent.getBroadcast(this, MainActivity.GRACE_REQUEST, graceIntent, 0); - alarmManager.cancel(gracePendingIntent); - if (Build.VERSION.SDK_INT >= 19) { - alarmManager.setExact(AlarmManager.RTC_WAKEUP, graceCal.getTimeInMillis(), gracePendingIntent); - } else { - alarmManager.set(AlarmManager.RTC_WAKEUP, graceCal.getTimeInMillis(), gracePendingIntent); - } - Log.d("AlarmService", "Setting grace alarm for " + MainActivity.debugDate(graceCal)); + // set grace period, which sends the text message upon firing + MainActivity.setGraceAlarm(getApplicationContext()); // Calculate when the grace period (converted from minutes to milliseconds) ends graceEndTime = System.currentTimeMillis() + (gracePeriod * 60 * 1000); @@ -103,22 +105,6 @@ public class AlarmService extends Service { // Allow user to acknowledge alarm and cancel grace alarm startAlert(this); } - - // Reset for tomorrow; as of API 19, setRepeating() is inexact, so we use setExact() - Calendar cal = MainActivity.TimeStringToCalendar(alarmTimeStr); - // Advance the calendar to tomorrow if it's in the past - if (cal.before(Calendar.getInstance())) { - cal.add(Calendar.DAY_OF_MONTH, 1); - } - - PendingIntent alarmPendingIntent = PendingIntent.getBroadcast(this, MainActivity.ALARM_REQUEST, intent, 0); - alarmManager.cancel(alarmPendingIntent); - if (Build.VERSION.SDK_INT >= 19) { - alarmManager.setExact(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), alarmPendingIntent); - } else { - alarmManager.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), alarmPendingIntent); - } - Log.d("AlarmService", "Resetting alarm for " + MainActivity.debugDate(cal)); } return super.onStartCommand(intent, flags, startId); } @@ -134,12 +120,13 @@ public class AlarmService extends Service { // Turn off the alert activity after a period, and switch to a notification new Handler().postDelayed(new Runnable() { public void run() { + Log.d("AlarmService", "Closing alert activity, status is " + alarmStatus); // Close the dialogue and switch to notification // if the Activity has not been closed by the user // (that is, snoozeAlert and dismissAlert have not been called) if (alarmStatus.contentEquals(ALARM_DISMISSED) || alarmStatus.contentEquals(ALARM_SNOOZED)) { - return; + // Do nothing // Stop if we've already run the snooze alert } else if (alarmStatus.contentEquals(ALARM_SNOOZE_RUNNING)) { alarmStatus = ALARM_IGNORED; @@ -156,7 +143,9 @@ public class AlarmService extends Service { Log.d("AlarmService", "Stopping alert; status is " + alarmStatus); if (alarmStarted) { AlarmKlaxon.stop(context); - AlarmAlertActivity.alertActivity.finish(); + if (AlarmAlertActivity.alertActivity != null) { + AlarmAlertActivity.alertActivity.finish(); + } if (!alarmStatus.contentEquals(ALARM_DISMISSED)) { context.startService(notifyIntent); } @@ -168,9 +157,7 @@ public class AlarmService extends Service { alarmStatus = ALARM_DISMISSED; // Cancel the graceAlarm - Intent graceIntent = new Intent(context, GraceReceiver.class); - PendingIntent gracePendingIntent = PendingIntent.getBroadcast(context, MainActivity.GRACE_REQUEST, graceIntent, 0); - alarmManager.cancel(gracePendingIntent); + MainActivity.cancelGraceAlarm(context); // Stop this service, along with the alert and all notifications context.stopService(alarmServiceIntent); @@ -208,6 +195,7 @@ public class AlarmService extends Service { Log.d("AlarmService", "Setting alarm status to " + status); alarmStatus = status; } + @Override public IBinder onBind(Intent intent) { return null; diff --git a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/CancelAlarmReceiver.java b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/CancelAlarmReceiver.java index ea097e1..29e5793 100644 --- a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/CancelAlarmReceiver.java +++ b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/CancelAlarmReceiver.java @@ -17,30 +17,25 @@ public class CancelAlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context); - String alarmTimeStr = sharedPref.getString(context.getString(R.string.AlarmTimePref), null); + String alarmTimeStr = sharedPref.getString(context.getString(R.string.AlarmTimePref), MainActivity.defaultTimeStr); - AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - Intent alarmIntent = new Intent(context, AlarmReceiver.class); - PendingIntent alarmPendingIntent = PendingIntent.getBroadcast(context, MainActivity.ALARM_REQUEST, alarmIntent, 0); - alarmManager.cancel(alarmPendingIntent); - Log.d("CancelAlarmReceiver", "Cancelled grace alarm"); + // Cancel alarm. This isn't technically necessary, as it'll happen in setAlarm + MainActivity.cancelAlarm(context); + + // Reset for tomorrow. setAlarm will also advance the day, but + // make it explicit here. + Calendar cal = MainActivity.TimeStringToCalendar(alarmTimeStr); + cal.add(Calendar.DAY_OF_MONTH, 1); // Reset alarm for tomorrow - - // Reset for tomorrow; as of API 19, setRepeating() is inexact, so we use setExact() - Calendar cal = MainActivity.TimeStringToCalendar(alarmTimeStr); - // Set for tomorrow - cal.add(Calendar.DAY_OF_MONTH, 1); - if (Build.VERSION.SDK_INT >= 19) { - alarmManager.setExact(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), alarmPendingIntent); - } else { - alarmManager.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), alarmPendingIntent); - } - Log.d("CancelAlarmReceiver", "Resetting alarm for " + MainActivity.debugDate(cal)); + MainActivity.setAlarm(context, cal); // Display toast Toast.makeText(context, context.getString(R.string.alarmCancelToast), Toast.LENGTH_LONG).show(); + // Stop any snoozed/existing alarms that may have started + context.stopService(new Intent(context, AlarmService.class)); + // Remove notification context.stopService(new Intent(context, PreAlarmNotify.class)); diff --git a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/CancelGraceReceiver.java b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/CancelGraceReceiver.java index ba8dd13..0963b21 100644 --- a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/CancelGraceReceiver.java +++ b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/CancelGraceReceiver.java @@ -11,20 +11,13 @@ import android.widget.Toast; public class CancelGraceReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - AlarmManager graceManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - Intent graceIntent = new Intent(context, GraceReceiver.class); - PendingIntent gracePendingIntent = PendingIntent.getBroadcast(context, MainActivity.GRACE_REQUEST, graceIntent, 0); - graceManager.cancel(gracePendingIntent); - Log.d("CancelGraceReceiver", "Cancelled grace alarm"); - // Ensure that any snoozes that are pending never happen. AlarmService.setAlarmStatus(AlarmService.ALARM_DISMISSED); context.stopService(new Intent(context, AlarmService.class)); - // Remove notification - context.stopService(new Intent(context, AlarmNotify.class)); + MainActivity.cancelGraceAlarm(context); // Display toast - Toast.makeText(context, context.getString(R.string.alarmCancelToast), Toast.LENGTH_LONG).show(); + Toast.makeText(context, context.getString(R.string.graceCancelToast), Toast.LENGTH_LONG).show(); } } \ No newline at end of file diff --git a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/GraceReceiver.java b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/GraceReceiver.java index 54d83f5..69f4081 100644 --- a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/GraceReceiver.java +++ b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/GraceReceiver.java @@ -30,7 +30,7 @@ public class GraceReceiver extends BroadcastReceiver { @Override public void onReceive(final Context context, Intent intent) { SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context); - Boolean alarmActive = sharedPref.getBoolean(context.getString(R.string.AlarmActivePref), true); + Boolean alarmActive = sharedPref.getBoolean(context.getString(R.string.AlarmActivePref), MainActivity.defaultActive); phoneNumber = sharedPref.getString(context.getString(R.string.PhoneNumberPref), null); message = sharedPref.getString(context.getString(R.string.MessagePref), context.getString(R.string.defaultMessage)); @@ -70,17 +70,23 @@ public class GraceReceiver extends BroadcastReceiver { ); locationClient.connect(); } else { - Log.e("GraceReceiver", "No Google Play Services. Sending text message anyway."); + Log.e("GraceReceiver", "Google Play Services is not available. Sending text message anyway."); sendText(context); } } } private void sendText(Context context) { SmsManager sms = SmsManager.getDefault(); - if (!MainActivity.HYPOALARM_DEBUG) { - sms.sendTextMessage(phoneNumber, null, message, null, null); + if (phoneNumber == null || phoneNumber.isEmpty()) { + message = "You have not specified a phone number. No text message will be sent."; + Toast.makeText(context, message, Toast.LENGTH_LONG).show(); + Log.e("GraceReceiver", "ERROR: " + message); + } else { + if (!MainActivity.HYPOALARM_DEBUG) { + sms.sendTextMessage(phoneNumber, null, message, null, null); + } + Toast.makeText(context, message, Toast.LENGTH_LONG).show(); + Log.d("GraceReceiver", "Sending sms to " + phoneNumber + " with message: " + message); } - Toast.makeText(context, message, Toast.LENGTH_LONG).show(); - Log.d("GraceReceiver", "Sending sms to " + phoneNumber + " with message: " + message); } } diff --git a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/MainActivity.java b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/MainActivity.java index 808f6c6..c7d96d6 100644 --- a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/MainActivity.java +++ b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/MainActivity.java @@ -1,5 +1,6 @@ package za.org.treehouse.hypoalarm; +import android.app.ActivityManager; import android.app.AlarmManager; import android.app.AlertDialog; import android.app.Dialog; @@ -65,6 +66,9 @@ public class MainActivity extends ActionBarActivity { public static final int CANCEL_ALARM_REQUEST = 5; public static final int PHONE_NUMBER_REQUEST = 6; public static final int RINGTONE_REQUEST = 7; + public static final String defaultTimeStr = "09:00"; + public static final int defaultGracePeriod = 60; + public static final Boolean defaultActive = true; public static final Boolean HYPOALARM_DEBUG = false; @@ -98,7 +102,6 @@ public class MainActivity extends ActionBarActivity { super.onStart(); // Set alarm time - final String defaultTimeStr = "09:00"; String alarmTimeStr = verifyTimeString(sharedPref.getString(getString(R.string.AlarmTimePref), defaultTimeStr)); final Button alarmTimeButton = (Button) getActivity().findViewById(R.id.alarm_time); @@ -119,7 +122,7 @@ public class MainActivity extends ActionBarActivity { }); // Allow alarm to activate - Boolean alarmActive = sharedPref.getBoolean(getString(R.string.AlarmActivePref), true); + Boolean alarmActive = sharedPref.getBoolean(getString(R.string.AlarmActivePref), defaultActive); final CompoundButton alarmActiveSwitch = (CompoundButton) getActivity().findViewById(R.id.alarm_active_switch); alarmActiveSwitch.setChecked(alarmActive); alarmActiveSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @@ -130,23 +133,24 @@ public class MainActivity extends ActionBarActivity { editor.commit(); if (!active) { + // Stop any snoozed alerts, and cancel any alarms + getActivity().stopService(new Intent(getActivity(), AlarmService.class)); cancelAllAlarms(getActivity()); Toast.makeText(getActivity(), getString(R.string.alarmCancelled), Toast.LENGTH_SHORT).show(); } else { String alarmTimeStr = verifyTimeString(sharedPref.getString(getString(R.string.AlarmTimePref), defaultTimeStr)); Calendar cal = TimeStringToCalendar(alarmTimeStr); - resetAlarm(getActivity(), cal); + setAlarm(getActivity(), cal); } } }); - // Activate the time (after setting alarmActive) when starting the app. + // Activate the time (after setting alarmActive) when starting the app (but don't cancel any existing grace period alarms) Calendar cal = TimeStringToCalendar(alarmTimeStr); - resetAlarm(getActivity(), cal); + setAlarm(getActivity(), cal); // Set grace period - final int defaultGrace = 60; - int gracePeriod = sharedPref.getInt(getString(R.string.GracePeriodPref), defaultGrace); + int gracePeriod = sharedPref.getInt(getString(R.string.GracePeriodPref), defaultGracePeriod); final Spinner gracePeriodSpinner = (Spinner) getActivity().findViewById(R.id.grace_period); gracePeriodSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @@ -251,6 +255,14 @@ public class MainActivity extends ActionBarActivity { imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); } }); + + // Set time change and boot receiver, so alarm restarts on boot + ComponentName bootReceiver = new ComponentName(getActivity(), AlarmChangeReceiver.class); + PackageManager pm = getActivity().getPackageManager(); + pm.setComponentEnabledSetting(bootReceiver, + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, + PackageManager.DONT_KILL_APP); + Log.d("MainActivity", "Setting boot receiver"); } @Override @@ -276,7 +288,13 @@ public class MainActivity extends ActionBarActivity { } } - public static void cancelAllAlarms(Context context) { + /** + * Cancel main alarm, but not grace alarm. + * This should be run whenever the alarm is set. + * + * @param context + */ + public static void cancelAlarm(Context context) { AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); // Cancel any current alarm @@ -284,30 +302,63 @@ public class MainActivity extends ActionBarActivity { PendingIntent alarmPendingIntent = PendingIntent.getBroadcast(context, ALARM_REQUEST, alarmIntent, 0); alarmManager.cancel(alarmPendingIntent); - // Cancel any pre-alarm notification + // Cancel any pre-alarm notification that may fire Intent preNotifyIntent = new Intent(context, PreAlarmReceiver.class); PendingIntent preNotifyPendingIntent = PendingIntent.getBroadcast(context, PRE_NOTIFY_REQUEST, preNotifyIntent, 0); alarmManager.cancel(preNotifyPendingIntent); + // Stop any existing pre-alarm notification that has already fired + context.stopService(new Intent(context, PreAlarmNotify.class)); + + Log.d("MainActivity", "Alarm cancelled"); + } + + /** + * Cancel grace alarm and notifications + * + * @param context + */ + public static void cancelGraceAlarm(Context context) { + AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + // Cancel any grace period Intent graceIntent = new Intent(context, GraceReceiver.class); PendingIntent gracePendingIntent = PendingIntent.getBroadcast(context, GRACE_REQUEST, graceIntent, 0); alarmManager.cancel(gracePendingIntent); - // Stop any notifications + // Stop any notification of grace period expiry context.stopService(new Intent(context, AlarmNotify.class)); - context.stopService(new Intent(context, PreAlarmNotify.class)); - Log.d("MainActivity", "Alarms cancelled"); + // Stop any active/snoozed alarms + context.stopService(new Intent(context, AlarmService.class)); + + Log.d("MainActivity", "Grace alarm cancelled"); + } + /** + * Cancels main alarm and grace alarm + * This should only be run when we're disabling the alarm entirely. + * + * @param context + */ + public static void cancelAllAlarms(Context context) { + cancelAlarm(context); + cancelGraceAlarm(context); + Log.d("MainActivity", "All alarms cancelled"); } - public static void resetAlarm(Context context, Calendar cal) { + /** + * Set the alarm. + * + * @param context Context + * @param cal Time at which to fire alarm + */ + public static void setAlarm(Context context, Calendar cal) { AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); PendingIntent alarmPendingIntent, preNotifyPendingIntent; SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context); - Boolean alarmActive = sharedPref.getBoolean(context.getString(R.string.AlarmActivePref), true); + Boolean alarmActive = sharedPref.getBoolean(context.getString(R.string.AlarmActivePref), defaultActive); - cancelAllAlarms(context); + cancelAlarm(context); // Advance cal to tomorrow if setting a time earlier than now if (cal.before(Calendar.getInstance())) { @@ -318,7 +369,6 @@ public class MainActivity extends ActionBarActivity { // Initialise alarm, which displays a dialog and system alert, and // calls AlarmManager with grace_period as the delay // which in turn, sends SMS if dialog is not exited. - // Advance to tomorrow if setting a time earlier than now Intent alarmIntent = new Intent(context, AlarmReceiver.class); alarmPendingIntent = PendingIntent.getBroadcast(context, ALARM_REQUEST, alarmIntent, 0); // Set or reset alarm @@ -329,9 +379,9 @@ public class MainActivity extends ActionBarActivity { } Log.d("MainActivity", "Setting alarm for " + MainActivity.debugDate(cal)); - // Set an alarm for the pre-alarm notification, half an hour before the alarm + // Set an alarm for the pre-alarm notification, an hour before the alarm Calendar preNotifyCal = (Calendar) cal.clone(); - preNotifyCal.add(Calendar.MINUTE, -30); + preNotifyCal.add(Calendar.MINUTE, -60); Intent preNotifyIntent = new Intent(context, PreAlarmReceiver.class); preNotifyPendingIntent = PendingIntent.getBroadcast(context, PRE_NOTIFY_REQUEST, preNotifyIntent, 0); // Set or reset alarm @@ -342,14 +392,35 @@ public class MainActivity extends ActionBarActivity { } Log.d("MainActivity", "Setting pre-alarm for " + MainActivity.debugDate(preNotifyCal)); - // Set time change and boot receiver, so alarm restarts on boot - ComponentName bootReceiver = new ComponentName(context, AlarmChangeReceiver.class); - PackageManager pm = context.getPackageManager(); - pm.setComponentEnabledSetting(bootReceiver, - PackageManager.COMPONENT_ENABLED_STATE_ENABLED, - PackageManager.DONT_KILL_APP); - Log.d("MainActivity", "Setting boot receiver"); + } + } + /** + * Set the grace alarm, to fire at the end of the grace period and send a text message. + * + * @param context + */ + public static void setGraceAlarm(Context context) { + AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context); + Boolean alarmActive = sharedPref.getBoolean(context.getString(R.string.AlarmActivePref), defaultActive); + int gracePeriod = sharedPref.getInt(context.getString(R.string.GracePeriodPref), MainActivity.defaultGracePeriod); + + cancelGraceAlarm(context); + + if (alarmActive) { + // Set a grace period alarm to send SMS + Calendar graceCal = Calendar.getInstance(); + graceCal.set(Calendar.SECOND, 0); + graceCal.add(Calendar.MINUTE, gracePeriod); + Intent graceIntent = new Intent(context, GraceReceiver.class); + PendingIntent gracePendingIntent = PendingIntent.getBroadcast(context, MainActivity.GRACE_REQUEST, graceIntent, 0); + if (Build.VERSION.SDK_INT >= 19) { + alarmManager.setExact(AlarmManager.RTC_WAKEUP, graceCal.getTimeInMillis(), gracePendingIntent); + } else { + alarmManager.set(AlarmManager.RTC_WAKEUP, graceCal.getTimeInMillis(), gracePendingIntent); + } + Log.d("MainActivity", "Setting grace alarm for " + MainActivity.debugDate(graceCal)); } } @@ -388,8 +459,10 @@ public class MainActivity extends ActionBarActivity { Button alarm_time = (Button) getActivity().findViewById(R.id.alarm_time); alarm_time.setText(alarmStr); + // Cancel any snoozed alerts + getActivity().stopService(new Intent(getActivity(), AlarmService.class)); // Set actual alarm - resetAlarm(getActivity(), cal); + setAlarm(getActivity(), cal); // Display toast CharSequence text = getString(R.string.alarmSetToast) + " " + CalendarToTimeString(cal); @@ -562,6 +635,15 @@ public class MainActivity extends ActionBarActivity { return remMinutes + minStr; } + // TODO remove this function? + public static Calendar minutesAgo(int minutes) { + // Negate number to get minutes in the past. + minutes = minutes * -1; + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.MINUTE, minutes); + return cal; + } + public static String debugDate(Calendar cal) { SimpleDateFormat print = new SimpleDateFormat("dd-MM-yyyy HH:mm:ssZ"); return print.format(cal.getTime()); diff --git a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/PreAlarmNotify.java b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/PreAlarmNotify.java index afce195..267c683 100644 --- a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/PreAlarmNotify.java +++ b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/PreAlarmNotify.java @@ -40,7 +40,7 @@ public class PreAlarmNotify extends Service { Log.d("PreAlarmNotify", "Pre-notification started."); // Get alarm time, and convert it into something readable. - String alarmTimeStr = sharedPref.getString(getString(R.string.AlarmTimePref), null); + String alarmTimeStr = sharedPref.getString(getString(R.string.AlarmTimePref), MainActivity.defaultTimeStr); Calendar alarmCal = MainActivity.TimeStringToCalendar(alarmTimeStr); alarmTimeStr = MainActivity.formattedTime(getApplicationContext(), alarmCal); diff --git a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/PreAlarmReceiver.java b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/PreAlarmReceiver.java index 9befcb6..50fee9f 100644 --- a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/PreAlarmReceiver.java +++ b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/PreAlarmReceiver.java @@ -10,7 +10,7 @@ public class PreAlarmReceiver extends BroadcastReceiver { @Override public void onReceive(final Context context, Intent intent) { SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context); - Boolean alarmActive = sharedPref.getBoolean(context.getString(R.string.AlarmActivePref), true); + Boolean alarmActive = sharedPref.getBoolean(context.getString(R.string.AlarmActivePref), MainActivity.defaultActive); if (alarmActive) { // Create notification diff --git a/HypoAlarm/src/main/res/values/strings.xml b/HypoAlarm/src/main/res/values/strings.xml index b9c7869..37fabc2 100644 --- a/HypoAlarm/src/main/res/values/strings.xml +++ b/HypoAlarm/src/main/res/values/strings.xml @@ -53,7 +53,9 @@ HypoAlarm set to - HypoAlarm text message cancelled + HypoAlarm cancelled + + HypoAlarm text message cancelled Hi, I haven\'t responded to my alarm today. Please contact me to make sure I\'m awake.