203 lines
9.1 KiB
Java
203 lines
9.1 KiB
Java
package za.org.treehouse.hypoalarm;
|
|
|
|
import android.app.AlarmManager;
|
|
import android.app.PendingIntent;
|
|
import android.app.Service;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.SharedPreferences;
|
|
import android.os.Build;
|
|
import android.os.Handler;
|
|
import android.os.IBinder;
|
|
import android.preference.PreferenceManager;
|
|
import android.telephony.TelephonyManager;
|
|
import android.util.Log;
|
|
|
|
import java.util.Calendar;
|
|
|
|
public class AlarmService extends Service {
|
|
private static final int SNOOZE_TIME = 1000*60;//60*5; // Snooze for 5 minutes if need be
|
|
private static final int ALERT_LIFE = 1000*10;//60*2; // 2 minutes
|
|
private static AlarmManager alarmManager;
|
|
private static Intent alarmServiceIntent, alertActivityIntent, notifyIntent;
|
|
public static Boolean alarmStarted = false;
|
|
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 onCreate() {
|
|
alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
|
|
}
|
|
@Override
|
|
public void onDestroy() {
|
|
Log.d("AlarmService", "Destroying alarm");
|
|
if (alarmStarted) {
|
|
stopAlert(getApplicationContext());
|
|
alarmStarted = false;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
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);
|
|
|
|
if (alarmActive) {
|
|
// Cancel the pre-alarm notification, if it exists
|
|
stopService(new Intent(this, PreAlarmNotify.class));
|
|
|
|
// Set up intents for later use
|
|
notifyIntent = new Intent(this, AlarmNotify.class);
|
|
alertActivityIntent = new Intent(this, AlarmAlertActivity.class);
|
|
alertActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
|
|
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
|
|
|
|
if (alarmStarted) {
|
|
stopAlert(getApplicationContext());
|
|
stopService(notifyIntent);
|
|
}
|
|
alarmStarted = true;
|
|
|
|
// 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
|
|
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));
|
|
|
|
// Calculate when the grace period (converted from minutes to milliseconds) ends
|
|
graceEndTime = System.currentTimeMillis() + (gracePeriod * 60 * 1000);
|
|
|
|
// 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
|
|
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);
|
|
}
|
|
|
|
public static void startAlert(final Context context) {
|
|
Log.d("AlarmService", "Starting alert; 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've already run the snooze alert
|
|
} else if (alarmStatus.contentEquals(ALARM_SNOOZE_RUNNING)) {
|
|
alarmStatus = ALARM_IGNORED;
|
|
context.stopService(alarmServiceIntent);
|
|
} 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("AlarmService", "Stopping alert; status is " + alarmStatus);
|
|
if (alarmStarted) {
|
|
AlarmKlaxon.stop(context);
|
|
AlarmAlertActivity.alertActivity.finish();
|
|
if (!alarmStatus.contentEquals(ALARM_DISMISSED)) {
|
|
context.startService(notifyIntent);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void dismissAlarm(final Context context) {
|
|
Log.d("AlarmService", "Dismissing alarm");
|
|
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);
|
|
|
|
// Stop this service, along with the alert and all notifications
|
|
context.stopService(alarmServiceIntent);
|
|
}
|
|
|
|
public static void snoozeAlarm(final Context context) {
|
|
Log.d("AlarmService", "Snoozing alarm");
|
|
// 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_SNOOZE_RUNNING)) &&
|
|
(!alarmStatus.contentEquals(ALARM_SNOOZED)) &&
|
|
(!alarmStatus.contentEquals(ALARM_DISMISSED))) {
|
|
stopAlert(context);
|
|
new Handler().postDelayed(new Runnable() {
|
|
public void run() {
|
|
Log.d("AlarmService", "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;
|
|
} else {
|
|
context.stopService(alarmServiceIntent);
|
|
}
|
|
}
|
|
|
|
public static void setAlarmStatus (String status) {
|
|
Log.d("AlarmService", "Setting alarm status to " + status);
|
|
alarmStatus = status;
|
|
}
|
|
@Override
|
|
public IBinder onBind(Intent intent) {
|
|
return null;
|
|
}
|
|
}
|