diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 44a5356..947f3a1 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -20,9 +20,9 @@
@@ -47,7 +47,6 @@
android:name="android.support.PARENT_ACTIVITY"
android:value="com.philliphsu.clock2.MainActivity"/>
-
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/philliphsu/clock2/PendingAlarmScheduler.java b/app/src/main/java/com/philliphsu/clock2/PendingAlarmScheduler.java
new file mode 100644
index 0000000..b441467
--- /dev/null
+++ b/app/src/main/java/com/philliphsu/clock2/PendingAlarmScheduler.java
@@ -0,0 +1,32 @@
+package com.philliphsu.clock2;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+import com.philliphsu.clock2.model.AlarmsRepository;
+import com.philliphsu.clock2.util.AlarmUtils;
+
+import static com.philliphsu.clock2.util.Preconditions.checkNotNull;
+
+/**
+ * Used to reschedule recurring alarms that were dismissed in their upcoming state, so {@link Alarm#ringsAt()}
+ * still refers to the time it rings today. This class receives
+ * your intent at the Alarm instance's normal ring time, so by the time you make a subsequent call
+ * to {@link Alarm#ringsAt()}, the value returned refers to the next time the alarm will recur.
+ */
+public class PendingAlarmScheduler extends BroadcastReceiver {
+ // We include the class name in the string to distinguish this constant from the one defined
+ // in UpcomingAlarmReceiver.
+ public static final String EXTRA_ALARM_ID = "com.philliphsu.clock2.PendingAlarmScheduler.extra.ALARM_ID";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ long id = intent.getLongExtra(EXTRA_ALARM_ID, -1);
+ if (id < 0) {
+ throw new IllegalStateException("No alarm id received");
+ }
+ Alarm alarm = checkNotNull(AlarmsRepository.getInstance(context).getItem(id));
+ AlarmUtils.scheduleAlarm(context, alarm, false);
+ }
+}
diff --git a/app/src/main/java/com/philliphsu/clock2/UpcomingAlarmReceiver.java b/app/src/main/java/com/philliphsu/clock2/UpcomingAlarmReceiver.java
index d1bc9e5..bfeea5c 100644
--- a/app/src/main/java/com/philliphsu/clock2/UpcomingAlarmReceiver.java
+++ b/app/src/main/java/com/philliphsu/clock2/UpcomingAlarmReceiver.java
@@ -37,7 +37,7 @@ public class UpcomingAlarmReceiver extends BroadcastReceiver {
} else {
Alarm alarm = checkNotNull(AlarmsRepository.getInstance(context).getItem(id));
if (ACTION_DISMISS_NOW.equals(intent.getAction())) {
- AlarmUtils.cancelAlarm(context, alarm, true);
+ AlarmUtils.cancelAlarm(context, alarm, true); // TODO: Cancel only, do not reschedule.
} else {
// Prepare notification
String title;
diff --git a/app/src/main/java/com/philliphsu/clock2/editalarm/EditAlarmActivity.java b/app/src/main/java/com/philliphsu/clock2/editalarm/EditAlarmActivity.java
index 7142208..9b03bfe 100644
--- a/app/src/main/java/com/philliphsu/clock2/editalarm/EditAlarmActivity.java
+++ b/app/src/main/java/com/philliphsu/clock2/editalarm/EditAlarmActivity.java
@@ -433,7 +433,7 @@ public class EditAlarmActivity extends BaseActivity implements AlarmNumpad.KeyLi
@Override
public void cancelAlarm(Alarm alarm, boolean showToast) {
- AlarmUtils.cancelAlarm(this, alarm, showToast);
+ AlarmUtils.cancelAlarm(this, alarm, showToast); // TODO: Cancel only?
if (RingtoneActivity.isAlive()) {
Intent intent = new Intent(this, RingtoneActivity.class)
.setAction(RingtoneActivity.ACTION_UNBIND);
diff --git a/app/src/main/java/com/philliphsu/clock2/ringtone/RingtoneActivity.java b/app/src/main/java/com/philliphsu/clock2/ringtone/RingtoneActivity.java
index 26dc55c..a26dde1 100644
--- a/app/src/main/java/com/philliphsu/clock2/ringtone/RingtoneActivity.java
+++ b/app/src/main/java/com/philliphsu/clock2/ringtone/RingtoneActivity.java
@@ -158,12 +158,6 @@ public class RingtoneActivity extends AppCompatActivity implements RingtoneServi
private void dismiss() {
AlarmUtils.cancelAlarm(this, mAlarm, false);
- // As of API 19, alarms scheduled with AlarmManager.setRepeating() are inexact. The recommended
- // workaround is to schedule one-time exact alarms, and reschedule each time after handling
- // an alarm delivery.
- if (mAlarm.hasRecurrence()) {
- AlarmUtils.scheduleAlarm(this, mAlarm, false /*show toast?*/);
- }
unbindAndFinish();
}
diff --git a/app/src/main/java/com/philliphsu/clock2/util/AlarmUtils.java b/app/src/main/java/com/philliphsu/clock2/util/AlarmUtils.java
index 451c7e7..2a157c6 100644
--- a/app/src/main/java/com/philliphsu/clock2/util/AlarmUtils.java
+++ b/app/src/main/java/com/philliphsu/clock2/util/AlarmUtils.java
@@ -10,6 +10,7 @@ import android.util.Log;
import android.widget.Toast;
import com.philliphsu.clock2.Alarm;
+import com.philliphsu.clock2.PendingAlarmScheduler;
import com.philliphsu.clock2.R;
import com.philliphsu.clock2.UpcomingAlarmReceiver;
import com.philliphsu.clock2.model.AlarmsRepository;
@@ -84,7 +85,7 @@ public final class AlarmUtils {
removeUpcomingAlarmNotification(c, a);
// TOneverDO: Place block after making value changes to the alarm.
- if (showToast && (a.ringsIn() <= HOURS.toMillis(hoursBeforeUpcoming(c)) || a.isSnoozed())) {
+ if (showToast && (a.ringsWithinHours(hoursBeforeUpcoming(c)) || a.isSnoozed())) {
String time = formatTime(c, a.isSnoozed() ? a.snoozingUntil() : a.ringsAt());
String text = c.getString(R.string.upcoming_alarm_dismissed, time);
Toast.makeText(c, text, Toast.LENGTH_LONG).show();
@@ -96,6 +97,19 @@ public final class AlarmUtils {
if (!a.hasRecurrence()) {
a.setEnabled(false);
+ } else {
+ if (a.isEnabled()) {
+ if (a.ringsWithinHours(hoursBeforeUpcoming(c))) {
+ // Still upcoming today, so wait until the normal ring time passes before
+ // rescheduling the alarm.
+ Intent intent = new Intent(c, PendingAlarmScheduler.class)
+ .putExtra(PendingAlarmScheduler.EXTRA_ALARM_ID, a.id());
+ pi = PendingIntent.getBroadcast(c, a.intId(), intent, PendingIntent.FLAG_ONE_SHOT);
+ am.set(AlarmManager.RTC_WAKEUP, a.ringsAt(), pi);
+ } else {
+ scheduleAlarm(c, a, false);
+ }
+ }
}
save(c); // Save any changes
@@ -108,8 +122,8 @@ public final class AlarmUtils {
}
public static void snoozeAlarm(Context c, Alarm a) {
- a.snooze(AlarmUtils.snoozeDuration(c));
- AlarmUtils.scheduleAlarm(c, a, true);
+ a.snooze(snoozeDuration(c));
+ scheduleAlarm(c, a, true);
save(c);
}