diff --git a/HypoAlarm/src/main/AndroidManifest.xml b/HypoAlarm/src/main/AndroidManifest.xml
index 906e3b8..9c0752c 100644
--- a/HypoAlarm/src/main/AndroidManifest.xml
+++ b/HypoAlarm/src/main/AndroidManifest.xml
@@ -21,9 +21,12 @@
android:launchMode="singleInstance"
android:noHistory="true">
+
+
+
@@ -35,6 +38,11 @@
android:name=".AlarmNotify"
android:label="@string/alarm_notification" >
+
+
+
diff --git a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmReceiver.java b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmReceiver.java
index d3cf51d..0e57744 100644
--- a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmReceiver.java
+++ b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmReceiver.java
@@ -23,8 +23,8 @@ import java.util.Calendar;
*/
public class AlarmReceiver extends BroadcastReceiver {
- private static final int SNOOZE_TIME = 1000*20; //TODO 1000*60*5; // Snooze for 5 minutes if need be
- private static final int ALERT_LIFE = 1000*60; //TODO 1000*60*2; // 2 minutes
+ 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;
@@ -44,10 +44,18 @@ public class AlarmReceiver extends BroadcastReceiver {
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);
@@ -76,8 +84,9 @@ public class AlarmReceiver extends BroadcastReceiver {
startAlert(context);
// Reset for tomorrow; as of API 19, setRepeating() is inexact, so we use setExact()
- // (Calendar will automatically advance the day since today's alarmTimeStr is now in the past.)
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);
@@ -108,8 +117,8 @@ public class AlarmReceiver extends BroadcastReceiver {
alarmStatus.contentEquals(ALARM_SNOOZED)) {
return;
}
- // Stop if we're running the snooze alert
- if (alarmStatus.contentEquals(ALARM_SNOOZE_RUNNING)) {
+ // 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
diff --git a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/CancelAlarmReceiver.java b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/CancelAlarmReceiver.java
new file mode 100644
index 0000000..ea097e1
--- /dev/null
+++ b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/CancelAlarmReceiver.java
@@ -0,0 +1,48 @@
+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.preference.PreferenceManager;
+import android.util.Log;
+import android.widget.Toast;
+
+import java.util.Calendar;
+
+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);
+
+ 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");
+
+ // 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));
+
+ // Display toast
+ Toast.makeText(context, context.getString(R.string.alarmCancelToast), Toast.LENGTH_LONG).show();
+
+ // Remove notification
+ context.stopService(new Intent(context, PreAlarmNotify.class));
+
+ }
+}
\ 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 76696b8..58a7306 100644
--- a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/GraceReceiver.java
+++ b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/GraceReceiver.java
@@ -4,29 +4,64 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.os.Bundle;
import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.telephony.SmsManager;
import android.util.Log;
+import android.widget.Toast;
public class GraceReceiver extends BroadcastReceiver {
private static SharedPreferences sharedPref;
+ private static String uri;
@Override
public void onReceive(Context context, Intent intent) {
sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
Boolean alarmActive = sharedPref.getBoolean(context.getString(R.string.AlarmActivePref), true);
- // TODO get location of phone and send in the message
-
if (alarmActive) {
String phoneNumber = sharedPref.getString(context.getString(R.string.PhoneNumberPref), null);
String message = sharedPref.getString(context.getString(R.string.MessagePref), null);
+ // TODO get location of phone and send in the message
+ LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
+ LocationListener locationListener = new LocationListener() {
+ public void onLocationChanged(Location location) {
+ // Called when a new location is found by the network location provider.
+ if (location != null) {
+ double latitude = location.getLatitude();
+ double longitude = location.getLongitude();
+
+ uri = " http://maps.google.com?q=" + location.getLatitude() + "," + location.getLongitude();
+ }
+ }
+ public void onStatusChanged(String provider, int status, Bundle extras) {
+ }
+ public void onProviderEnabled(String provider) {
+ }
+ public void onProviderDisabled(String provider) {
+ }
+ };
+
+ if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
+ locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
+ } else if (locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
+ locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
+ }
+
+ message += uri;
+
SmsManager sms = SmsManager.getDefault();
// TODO uncomment this:
//sms.sendTextMessage(phoneNumber, null, message, null, null);
+ Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
Log.d("GraceReceiver", "Sending sms to " + phoneNumber);
}
}
+
+
}
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 2c25cea..0097050 100644
--- a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/MainActivity.java
+++ b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/MainActivity.java
@@ -62,7 +62,9 @@ import java.util.regex.Pattern;
public class MainActivity extends ActionBarActivity {
public static int ALARM_REQUEST = 1;
public static int GRACE_REQUEST = 2;
- public static int CANCEL_GRACE_REQUEST = 3;
+ public static int PRENOTIFY_REQUEST = 3;
+ public static int CANCEL_GRACE_REQUEST = 4;
+ public static int CANCEL_ALARM_REQUEST = 5;
private static Switch alarmActiveSwitch;
private static Button alarmTimeButton;
private static Spinner gracePeriodSpinner;
@@ -268,7 +270,7 @@ public class MainActivity extends ActionBarActivity {
public static class TimePickerFragment extends DialogFragment implements TimePickerDialog.OnTimeSetListener {
SharedPreferences sharedPref;
private AlarmManager alarmManager;
- private PendingIntent alarmPendingIntent;
+ private PendingIntent alarmPendingIntent, preNotifyPendingIntent;
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
@@ -319,6 +321,21 @@ 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
+ Calendar preNotifyCal = cal;
+ preNotifyCal.add(Calendar.MINUTE, -30);
+ Intent preNotifyIntent = new Intent(getActivity(), PreAlarmReceiver.class);
+ preNotifyPendingIntent = PendingIntent.getBroadcast(getActivity(), PRENOTIFY_REQUEST, preNotifyIntent, 0);
+ // Cancel any existing alarms
+ alarmManager.cancel(preNotifyPendingIntent);
+ // Set or reset alarm
+ if (Build.VERSION.SDK_INT >= 19) {
+ alarmManager.setExact(AlarmManager.RTC_WAKEUP, preNotifyCal.getTimeInMillis(), preNotifyPendingIntent);
+ } else {
+ alarmManager.set(AlarmManager.RTC_WAKEUP, preNotifyCal.getTimeInMillis(), preNotifyPendingIntent);
+ }
+ Log.d("MainActivity", "Setting pre-alarm for " + MainActivity.debugDate(preNotifyCal));
+
// Set boot receiver, so alarm restarts on boot
ComponentName receiver = new ComponentName(getActivity(), BootReceiver.class);
PackageManager pm = getActivity().getPackageManager();
@@ -435,10 +452,6 @@ public class MainActivity extends ActionBarActivity {
cal.set(Calendar.HOUR, dateCal.get(Calendar.HOUR));
cal.set(Calendar.MINUTE, dateCal.get(Calendar.MINUTE));
cal.set(Calendar.SECOND, 0);
- // Ensure that this date is in the future
- if (date.before(new Date())) {
- cal.add(Calendar.DAY_OF_MONTH, 1);
- }
return cal;
} catch (ParseException e) {
e.printStackTrace();
@@ -495,6 +508,4 @@ public class MainActivity extends ActionBarActivity {
}
return remMinutes + minStr;
}
-
-
}
diff --git a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/PreAlarmNotify.java b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/PreAlarmNotify.java
new file mode 100644
index 0000000..a052583
--- /dev/null
+++ b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/PreAlarmNotify.java
@@ -0,0 +1,69 @@
+package za.org.treehouse.hypoalarm;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Build;
+import android.os.IBinder;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+public class PreAlarmNotify extends Service {
+ public static final int preNotifyID = 2;
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public void onDestroy() {
+ // Remove the notification in the notification bar
+ NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+ nm.cancel(preNotifyID);
+ Log.d("AlarmNotify", "Pre-notification stopped.");
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
+
+ Log.d("PreAlarmNotify", "Pre-notification started.");
+
+ String alarmTimeStr = sharedPref.getString(getString(R.string.AlarmTimePref), null);
+
+ Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_grey);
+ final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+ if (Build.VERSION.SDK_INT >= 11) {
+ final Notification.Builder notification = new Notification.Builder(this)
+ .setContentTitle(getString(R.string.app_name))
+ .setContentText(getString(R.string.preNotificationText))
+ .setSmallIcon(R.drawable.alarm_notification)
+ .setLargeIcon(bm)
+ .setOnlyAlertOnce(true)
+ .setAutoCancel(false)
+ .setPriority(Notification.PRIORITY_HIGH);
+
+ // Set up dismiss action
+ Intent cancelAlarmIntent = new Intent(getBaseContext(), CancelAlarmReceiver.class);
+ PendingIntent cancelAlarmPendingIntent = PendingIntent.getBroadcast(getBaseContext(), MainActivity.CANCEL_ALARM_REQUEST, cancelAlarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
+
+ // Cancel the grace period if the user clears the notification
+ notification.setDeleteIntent(cancelAlarmPendingIntent);
+ // Allow the user to cancel by clicking a "Cancel" button
+ notification.addAction(android.R.drawable.ic_menu_close_clear_cancel, getString(R.string.preNotificationCancellation), cancelAlarmPendingIntent);
+ // Allow the user to cancel by selecting the ContentText or ContentTitle
+ notification.setContentIntent(cancelAlarmPendingIntent);
+
+ nm.cancel(this.preNotifyID);
+ nm.notify(this.preNotifyID, notification.build());
+ }
+ return super.onStartCommand(intent, flags, startId);
+ }
+}
diff --git a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/PreAlarmReceiver.java b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/PreAlarmReceiver.java
new file mode 100644
index 0000000..107c751
--- /dev/null
+++ b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/PreAlarmReceiver.java
@@ -0,0 +1,23 @@
+package za.org.treehouse.hypoalarm;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+
+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);
+ String alarmTimeStr = sharedPref.getString(context.getString(R.string.AlarmTimePref), null);
+
+ if (alarmActive) {
+ // Create notification
+ Intent preNotifyIntent = new Intent(context, PreAlarmNotify.class);
+ // The PreAlarmNotify service can either be stopped by calling CancelAlarmReceiver, or by waiting for AlarmReceiver to run
+ context.startService(preNotifyIntent);
+ }
+ }
+}
\ No newline at end of file
diff --git a/HypoAlarm/src/main/res/values/strings.xml b/HypoAlarm/src/main/res/values/strings.xml
index 0d38b21..aa28b33 100644
--- a/HypoAlarm/src/main/res/values/strings.xml
+++ b/HypoAlarm/src/main/res/values/strings.xml
@@ -55,6 +55,10 @@
Cancel
+ Upcoming alarm
+
+ Dismiss Now
+
All HypoAlarms cancelled