HypoAlarm/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmReceiver.java

184 lines
8.5 KiB
Java

package za.org.treehouse.hypoalarm;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.util.Log;
import android.widget.Toast;
import java.util.Calendar;
/**
* TODO change alarm state if a phone call comes in
*
* TODO display notification if alarm is about to go off (and allow user to cancel it before alarm goes off)
*
*/
public class AlarmReceiver extends BroadcastReceiver {
private static final int SNOOZE_TIME = 0; //1000*60*5; // Snooze for 5 minutes if need be
private static final int ALERT_LIFE = 1000*10; //TODO 1000*60*2; // 2 minutes
private static SharedPreferences sharedPref;
private static AlarmManager alarmManager, graceManager;
private static PendingIntent alarmPendingIntent, gracePendingIntent;
private static Intent alertActivityIntent, notifyIntent;
public static volatile String alarmStatus; // Register ALARM_DISMISSED and its brethren here
public static final String ALARM_RUNNING = "ALARM_RUNNING";
public static final String ALARM_DISMISSED = "ALARM_DISMISSED";
public static final String ALARM_IGNORED = "ALARM_IGNORED";
public static final String ALARM_SNOOZED = "ALARM_SNOOZED";
public static final String ALARM_SNOOZE_RUNNING = "ALARM_SNOOZE_RUNNING";
public static long graceEndTime;
@Override
public void onReceive(final Context context, Intent intent) {
sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
Boolean alarmActive = sharedPref.getBoolean(context.getString(R.string.AlarmActivePref), true);
int gracePeriod = sharedPref.getInt(context.getString(R.string.GracePeriodPref), 60);
String alarmTimeStr = sharedPref.getString(context.getString(R.string.AlarmTimePref), null);
// TODO remove
if (MainActivity.HYPOALARM_DEBUG) {
gracePeriod = 1;
}
if (alarmActive) {
// if nothing else happens, assume the alert was ignored.
alarmStatus = ALARM_RUNNING;
// Cancel the pre-alarm notification, if it exists
context.stopService(new Intent(context, PreAlarmNotify.class));
// Set a grace period alarm to send SMS
Calendar graceCal = Calendar.getInstance();
graceCal.set(Calendar.SECOND, 0);
graceCal.add(Calendar.MINUTE, gracePeriod);
graceManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent graceIntent = new Intent(context, GraceReceiver.class);
gracePendingIntent = PendingIntent.getBroadcast(context, MainActivity.GRACE_REQUEST, graceIntent, 0);
graceManager.cancel(gracePendingIntent);
if (Build.VERSION.SDK_INT >= 19) {
graceManager.setExact(AlarmManager.RTC_WAKEUP, graceCal.getTimeInMillis(), gracePendingIntent);
} else {
graceManager.set(AlarmManager.RTC_WAKEUP, graceCal.getTimeInMillis(), gracePendingIntent);
}
Log.d("AlarmReceiver", "Setting grace alarm for " + MainActivity.debugDate(graceCal));
// Calculate when the grace period ends
graceEndTime = System.currentTimeMillis() + (gracePeriod * 60 * 1000);
// Set up intents for later use
notifyIntent = new Intent(context, AlarmNotify.class);
alertActivityIntent = new Intent(context, AlarmAlertActivity.class);
alertActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
// Allow user to acknowledge alarm and cancel grace alarm
startAlert(context);
// Reset for tomorrow; as of API 19, setRepeating() is inexact, so we use setExact()
Calendar cal = MainActivity.TimeStringToCalendar(alarmTimeStr);
// Advance the calendar to tomorrow
cal.add(Calendar.DAY_OF_MONTH, 1);
alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmPendingIntent = PendingIntent.getBroadcast(context, 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("AlarmReceiver", "Resetting alarm for " + MainActivity.debugDate(cal));
}
}
public static void startAlert(final Context context) {
Log.d("AlarmReceiver", "Starting alarm; status is " + alarmStatus);
// Turn off any notifications first
context.stopService(notifyIntent);
context.startActivity(alertActivityIntent);
AlarmKlaxon.start(context);
// Turn off the alert activity after a period, and switch to a notification
new Handler().postDelayed(new Runnable() {
public void run() {
// 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;
}
// Stop if we're running the snooze alert, or the snooze time is less than 10 seconds
if (alarmStatus.contentEquals(ALARM_SNOOZE_RUNNING) || SNOOZE_TIME < 10000) {
stopAlert(context);
} else {
alarmStatus = ALARM_IGNORED; // This is true, although we are about to switch to ALARM_SNOOZED
snoozeAlarm(context);
}
}
}, ALERT_LIFE);
}
public static void stopAlert(final Context context) {
Log.d("AlarmReceiver", "Stopping alarm; status is " + alarmStatus);
AlarmKlaxon.stop(context);
AlarmAlertActivity.alertActivity.finish();
// Display a notification if the alarm hasn't been dismissed
if (!alarmStatus.contentEquals(ALARM_DISMISSED)) {
context.startService(notifyIntent);
}
}
public static void dismissAlarm(final Context context) {
Log.d("AlarmReceiver", "Dismissing alarm");
alarmStatus = ALARM_DISMISSED;
// Close the alert and all notifications
stopAlert(context);
// Cancel the graceAlarm
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);
}
// TODO should the snooze reset the time at which the grace period alarm fires?
public static void snoozeAlarm(final Context context) {
Log.d("AlarmReceiver", "Snoozing alarm");
stopAlert(context);
// Close the alert, stop the klaxon, and start the notification,
// but only if there's time left before the gracePeriod triggers,
// and we haven't snoozed before
if (((System.currentTimeMillis() + SNOOZE_TIME) < graceEndTime) &&
(!alarmStatus.contentEquals(ALARM_SNOOZED)) &&
(!alarmStatus.contentEquals(ALARM_DISMISSED))) {
new Handler().postDelayed(new Runnable() {
public void run() {
Log.d("AlarmReceiver", "Resuming after snooze; status is " + alarmStatus);
// Don't run if the alarm was dismissed before the timer ran out
// (because a notification was acknowledged)
if (!alarmStatus.contentEquals(ALARM_DISMISSED)) {
alarmStatus = ALARM_SNOOZE_RUNNING;
startAlert(context);
}
}
}, SNOOZE_TIME);
// Change alarm status from ignored to snoozed
alarmStatus = ALARM_SNOOZED;
}
}
public static void setAlarmStatus (String status) {
Log.d("AlarmReceiver", "Setting alarm status to " + status);
alarmStatus = status;
}
}