Prevent subsequent alarms from snoozing; make pre-alarm an hour earlier; correct boot receiver bug.

This commit is contained in:
Timothy Allen 2014-04-17 13:40:28 +02:00
parent 571df2f2c2
commit 20f99f2b5f
12 changed files with 194 additions and 122 deletions

View File

@ -8,10 +8,11 @@
</facet>
<facet type="android" name="Android">
<configuration>
<option name="SELECTED_BUILD_VARIANT" value="release" />
<option name="ASSEMBLE_TASK_NAME" value="assembleRelease" />
<option name="COMPILE_JAVA_TASK_NAME" value="compileReleaseJava" />
<option name="SOURCE_GEN_TASK_NAME" value="generateReleaseSources" />
<option name="SELECTED_BUILD_VARIANT" value="debug" />
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugJava" />
<option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugTest" />
<option name="SOURCE_GEN_TASK_NAME" value="generateDebugSources" />
<option name="ALLOW_USER_CONFIGURATION" value="false" />
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
@ -21,21 +22,26 @@
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/build/classes/release" />
<output url="file://$MODULE_DIR$/build/classes/debug" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/build/source/r/release" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/source/aidl/release" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/source/buildConfig/release" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/source/rs/release" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/res/rs/release" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/release/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/release/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/release/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/release/assets" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/release/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/release/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/release/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/build/source/r/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/source/aidl/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/source/buildConfig/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/source/rs/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/res/rs/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/source/r/test/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/source/aidl/test/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/source/buildConfig/test/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/source/rs/test/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/res/rs/test/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />

View File

@ -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);
}
}
}

View File

@ -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);

View File

@ -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);
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;

View File

@ -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));

View File

@ -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();
}
}

View File

@ -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 (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);
}
}
}

View File

@ -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());

View File

@ -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);

View File

@ -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

View File

@ -53,7 +53,9 @@
<string name="alarmSetToast">HypoAlarm set to </string>
<string name="alarmCancelToast">HypoAlarm text message cancelled</string>
<string name="alarmCancelToast">HypoAlarm cancelled</string>
<string name="graceCancelToast">HypoAlarm text message cancelled</string>
<string name="defaultMessage">Hi, I haven\'t responded to my alarm today. Please contact me to make sure I\'m awake.</string>