HypoAlarm/HypoAlarm/src/main/java/za/org/treehouse/HypoAlarm/AlarmService.java

195 lines
8.4 KiB
Java

package za.org.treehouse.HypoAlarm;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Handler;
import android.os.IBinder;
import android.os.PowerManager;
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*5; // Snooze for 5 minutes if need be
private static final int ALERT_LIFE = 1000*60*2; // 2 minutes
private static PowerManager.WakeLock wl;
private static Intent alarmServiceIntent, alertActivityIntent, notifyIntent;
private static Boolean alarmStarted = false;
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 volatile String alarmStatus = ALARM_DISMISSED; // Register ALARM_DISMISSED and its brethren here
public static long graceEndTime;
@Override
public void onCreate() {
// Ensure that CPU runs while the service is running, so we don't miss an alert after snoozing
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "AlarmService");
wl.acquire();
}
@Override
public void onDestroy() {
Log.d("AlarmService", "Destroying alarm (alarmStarted: " + alarmStarted + ")");
if (alarmStarted) {
stopAlert(getApplicationContext());
alarmStarted = false;
}
if (wl.isHeld()) {
wl.release();
}
}
@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), 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
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) {
stopService(notifyIntent);
}
alarmStarted = true;
// if nothing else happens, assume the alert was ignored.
alarmStatus = ALARM_RUNNING;
// 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 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);
// Allow user to acknowledge alarm and cancel grace alarm
startAlert(this);
}
}
return super.onStartCommand(intent, flags, startId);
}
private 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() {
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)) {
// Do nothing
// 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);
}
private static void stopAlert(final Context context) {
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);
}
}
}
public static void dismissAlarm(final Context context) {
Log.d("AlarmService", "Dismissing alarm");
alarmStatus = ALARM_DISMISSED;
// Cancel the graceAlarm
MainActivity.cancelGraceAlarm(context);
// 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 {
Log.d("AlarmService", "Actually, not snoozing!");
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;
}
}