AlarmViewHolder hides dismiss button if recurring and upcoming alarm dismissed via notification
This commit is contained in:
parent
9380f8f579
commit
20b5ff2d8a
@ -11,6 +11,7 @@ import org.json.JSONObject;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.philliphsu.clock2.DaysOfWeek.NUM_DAYS;
|
||||
import static com.philliphsu.clock2.DaysOfWeek.SATURDAY;
|
||||
@ -28,6 +29,7 @@ public abstract class Alarm implements JsonSerializable, Parcelable {
|
||||
private long snoozingUntilMillis;
|
||||
private boolean enabled;
|
||||
private final boolean[] recurringDays = new boolean[NUM_DAYS];
|
||||
private boolean ignoreUpcomingRingTime;
|
||||
// ====================================================
|
||||
|
||||
public abstract int hour();
|
||||
@ -116,6 +118,14 @@ public abstract class Alarm implements JsonSerializable, Parcelable {
|
||||
return count;
|
||||
}
|
||||
|
||||
public void ignoreUpcomingRingTime(boolean ignore) {
|
||||
ignoreUpcomingRingTime = ignore;
|
||||
}
|
||||
|
||||
public boolean isIgnoringUpcomingRingTime() {
|
||||
return ignoreUpcomingRingTime;
|
||||
}
|
||||
|
||||
public long ringsAt() {
|
||||
// Always with respect to the current date and time
|
||||
Calendar calendar = new GregorianCalendar();
|
||||
@ -124,22 +134,26 @@ public abstract class Alarm implements JsonSerializable, Parcelable {
|
||||
calendar.set(Calendar.SECOND, 0);
|
||||
calendar.set(Calendar.MILLISECOND, 0);
|
||||
|
||||
long baseRingTime = calendar.getTimeInMillis();
|
||||
|
||||
if (!hasRecurrence()) {
|
||||
if (calendar.getTimeInMillis() <= System.currentTimeMillis()) {
|
||||
if (baseRingTime <= System.currentTimeMillis()) {
|
||||
// The specified time has passed for today
|
||||
calendar.add(Calendar.HOUR_OF_DAY, 24);
|
||||
baseRingTime += TimeUnit.DAYS.toMillis(1);
|
||||
}
|
||||
return baseRingTime;
|
||||
} else {
|
||||
// Compute the ring time just for the next closest recurring day.
|
||||
// Remember that day constants defined in the Calendar class are not zero-based like ours, so we have to
|
||||
// compensate with an offset of magnitude one, with the appropriate sign based on the situation.
|
||||
// Remember that day constants defined in the Calendar class are
|
||||
// not zero-based like ours, so we have to compensate with an offset
|
||||
// of magnitude one, with the appropriate sign based on the situation.
|
||||
int weekdayToday = calendar.get(Calendar.DAY_OF_WEEK);
|
||||
int numDaysFromToday = -1;
|
||||
|
||||
for (int i = weekdayToday; i <= Calendar.SATURDAY; i++) {
|
||||
if (isRecurring(i - 1 /*match up with our day constant*/)) {
|
||||
if (i == weekdayToday) {
|
||||
if (calendar.getTimeInMillis() > System.currentTimeMillis()) {
|
||||
if (baseRingTime > System.currentTimeMillis()) {
|
||||
// The normal ring time has not passed yet
|
||||
numDaysFromToday = 0;
|
||||
break;
|
||||
@ -164,26 +178,29 @@ public abstract class Alarm implements JsonSerializable, Parcelable {
|
||||
// Still not computed yet. The only recurring day is weekdayToday,
|
||||
// and its normal ring time has already passed.
|
||||
if (numDaysFromToday < 0 && isRecurring(weekdayToday - 1)
|
||||
&& calendar.getTimeInMillis() <= System.currentTimeMillis()) {
|
||||
&& baseRingTime <= System.currentTimeMillis()) {
|
||||
numDaysFromToday = 7;
|
||||
}
|
||||
|
||||
if (numDaysFromToday < 0)
|
||||
throw new IllegalStateException("How did we get here?");
|
||||
|
||||
calendar.add(Calendar.HOUR_OF_DAY, 24 * numDaysFromToday);
|
||||
return baseRingTime + TimeUnit.DAYS.toMillis(numDaysFromToday);
|
||||
}
|
||||
|
||||
return calendar.getTimeInMillis();
|
||||
}
|
||||
|
||||
public long ringsIn() {
|
||||
return ringsAt() - System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/** @return true if this Alarm will ring in the next {@code hours} hours */
|
||||
/**
|
||||
* Returns whether this Alarm is upcoming in the next {@code hours} hours.
|
||||
* To return true, this Alarm must not have its {@link #ignoreUpcomingRingTime}
|
||||
* member field set to true.
|
||||
* @see #ignoreUpcomingRingTime(boolean)
|
||||
*/
|
||||
public boolean ringsWithinHours(int hours) {
|
||||
return ringsIn() <= hours * 3600000;
|
||||
return !ignoreUpcomingRingTime && ringsIn() <= TimeUnit.HOURS.toMillis(hours);
|
||||
}
|
||||
|
||||
public int intId() {
|
||||
@ -233,6 +250,7 @@ public abstract class Alarm implements JsonSerializable, Parcelable {
|
||||
dest.writeLong(snoozingUntilMillis);
|
||||
dest.writeInt(enabled ? 1 : 0);
|
||||
dest.writeBooleanArray(recurringDays);
|
||||
dest.writeInt(ignoreUpcomingRingTime ? 1 : 0);
|
||||
}
|
||||
|
||||
private static Alarm create(Parcel in) {
|
||||
@ -247,6 +265,7 @@ public abstract class Alarm implements JsonSerializable, Parcelable {
|
||||
alarm.snoozingUntilMillis = in.readLong();
|
||||
alarm.enabled = in.readInt() != 0;
|
||||
in.readBooleanArray(alarm.recurringDays);
|
||||
alarm.ignoreUpcomingRingTime = in.readInt() != 0;
|
||||
return alarm;
|
||||
}
|
||||
|
||||
|
||||
@ -46,10 +46,13 @@ public class PendingAlarmScheduler extends BroadcastReceiver {
|
||||
if (!alarm.isEnabled()) {
|
||||
throw new IllegalStateException("Alarm must be enabled!");
|
||||
}
|
||||
alarm.ignoreUpcomingRingTime(false); // allow #ringsWithinHours() to behave normally
|
||||
// Because showToast = false, we don't do any UI work.
|
||||
// TODO: Since we're in a worker thread, verify that the
|
||||
// UI related code within will not cause us to crash.
|
||||
AlarmUtils.scheduleAlarm(context, alarm, false);
|
||||
// Update the db
|
||||
AlarmUtils.save(context, alarm);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
@ -72,7 +72,7 @@ public class UpcomingAlarmReceiver extends BroadcastReceiver {
|
||||
}
|
||||
}
|
||||
|
||||
Intent in = new Intent(context, getClass())
|
||||
Intent in = new Intent(context, UpcomingAlarmReceiver.class)
|
||||
.putExtra(EXTRA_ALARM_ID, id) // TOneverDO: cast to int
|
||||
.setAction(ACTION_DISMISS_NOW);
|
||||
PendingIntent pi = PendingIntent.getBroadcast(context, (int) id, in, FLAG_ONE_SHOT);
|
||||
|
||||
@ -68,6 +68,8 @@ public class AlarmViewHolder extends BaseViewHolder<Alarm> implements AlarmCount
|
||||
|
||||
@OnClick(R.id.dismiss)
|
||||
void dismiss() {
|
||||
// TODO: This is NOT correct for all alarms! This may be correct for single
|
||||
// use alarms, but not so for recurring alarms!
|
||||
mSwitch.setPressed(true); // needed so the OnCheckedChange event calls through
|
||||
bindSwitch(false); // fires OnCheckedChange to do the binding for you
|
||||
// TOneverDO: AlarmUtils.cancelAlarm() otherwise it will be called twice
|
||||
@ -120,10 +122,15 @@ public class AlarmViewHolder extends BaseViewHolder<Alarm> implements AlarmCount
|
||||
if (alarm.isEnabled()) {
|
||||
// TODO: On Moto X, upcoming notification doesn't post immediately
|
||||
AlarmUtils.scheduleAlarm(getContext(), alarm, true);
|
||||
// TODO: We don't have to manually bind these if we update the alarm via the db,
|
||||
// because that would trigger the loader to reload the dataset and hence the
|
||||
// corresponding VH is rebound.
|
||||
bindCountdown(true, alarm.ringsIn());
|
||||
bindDismissButton(alarm);
|
||||
} else {
|
||||
AlarmUtils.cancelAlarm(getContext(), alarm, true); // saves repo
|
||||
// TODO: Remove these, cancelAlarm will prompt update call to the db, so all VHs will
|
||||
// be rebound.
|
||||
bindCountdown(false, -1);
|
||||
bindDismissButton(false, "");
|
||||
}
|
||||
@ -164,7 +171,6 @@ public class AlarmViewHolder extends BaseViewHolder<Alarm> implements AlarmCount
|
||||
String buttonText = alarm.isSnoozed()
|
||||
? getContext().getString(R.string.title_snoozing_until, formatTime(getContext(), alarm.snoozingUntil()))
|
||||
: getContext().getString(R.string.dismiss_now);
|
||||
// when this alarm crosses the upcoming threshold, so we can show this button.
|
||||
bindDismissButton(visible, buttonText);
|
||||
}
|
||||
|
||||
|
||||
@ -52,6 +52,7 @@ public class AlarmDatabaseHelper extends SQLiteOpenHelper {
|
||||
private static final String COLUMN_THURSDAY = "thursday";
|
||||
private static final String COLUMN_FRIDAY = "friday";
|
||||
private static final String COLUMN_SATURDAY = "saturday";
|
||||
private static final String COLUMN_IGNORE_UPCOMING_RING_TIME = "ignore_upcoming_ring_time";
|
||||
|
||||
// https://www.sqlite.org/lang_select.html#orderby
|
||||
// Rows are first sorted based on the results of evaluating the left-most expression in the
|
||||
@ -98,7 +99,8 @@ public class AlarmDatabaseHelper extends SQLiteOpenHelper {
|
||||
+ COLUMN_WEDNESDAY + " INTEGER NOT NULL DEFAULT 0, "
|
||||
+ COLUMN_THURSDAY + " INTEGER NOT NULL DEFAULT 0, "
|
||||
+ COLUMN_FRIDAY + " INTEGER NOT NULL DEFAULT 0, "
|
||||
+ COLUMN_SATURDAY + " INTEGER NOT NULL DEFAULT 0);");
|
||||
+ COLUMN_SATURDAY + " INTEGER NOT NULL DEFAULT 0, "
|
||||
+ COLUMN_IGNORE_UPCOMING_RING_TIME + " INTEGER NOT NULL);");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -168,7 +170,7 @@ public class AlarmDatabaseHelper extends SQLiteOpenHelper {
|
||||
}
|
||||
|
||||
public AlarmCursor queryEnabledAlarms() {
|
||||
return queryAlarms(COLUMN_ENABLED + " = " + 1);
|
||||
return queryAlarms(COLUMN_ENABLED + " = 1");
|
||||
}
|
||||
|
||||
private AlarmCursor queryAlarms(String where) {
|
||||
@ -194,6 +196,7 @@ public class AlarmDatabaseHelper extends SQLiteOpenHelper {
|
||||
values.put(COLUMN_THURSDAY, alarm.isRecurring(THURSDAY));
|
||||
values.put(COLUMN_FRIDAY, alarm.isRecurring(FRIDAY));
|
||||
values.put(COLUMN_SATURDAY, alarm.isRecurring(SATURDAY));
|
||||
values.put(COLUMN_IGNORE_UPCOMING_RING_TIME, alarm.isIgnoringUpcomingRingTime());
|
||||
return values;
|
||||
}
|
||||
|
||||
@ -241,6 +244,7 @@ public class AlarmDatabaseHelper extends SQLiteOpenHelper {
|
||||
alarm.setRecurring(THURSDAY, isTrue(COLUMN_THURSDAY));
|
||||
alarm.setRecurring(FRIDAY, isTrue(COLUMN_FRIDAY));
|
||||
alarm.setRecurring(SATURDAY, isTrue(COLUMN_SATURDAY));
|
||||
alarm.ignoreUpcomingRingTime(isTrue(COLUMN_IGNORE_UPCOMING_RING_TIME));
|
||||
return alarm;
|
||||
}
|
||||
|
||||
|
||||
@ -10,10 +10,10 @@ import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.philliphsu.clock2.Alarm;
|
||||
import com.philliphsu.clock2.AsyncItemChangeHandler;
|
||||
import com.philliphsu.clock2.PendingAlarmScheduler;
|
||||
import com.philliphsu.clock2.R;
|
||||
import com.philliphsu.clock2.UpcomingAlarmReceiver;
|
||||
import com.philliphsu.clock2.model.DatabaseManager;
|
||||
import com.philliphsu.clock2.ringtone.RingtoneActivity;
|
||||
import com.philliphsu.clock2.ringtone.RingtoneService;
|
||||
|
||||
@ -119,8 +119,9 @@ public final class AlarmUtils {
|
||||
} else {
|
||||
if (a.isEnabled()) {
|
||||
if (a.ringsWithinHours(hoursBeforeUpcoming(c))) {
|
||||
// Still upcoming today, so wait until the normal ring time passes before
|
||||
// rescheduling the alarm.
|
||||
// Still upcoming today, so wait until the normal ring time
|
||||
// passes before rescheduling the alarm.
|
||||
a.ignoreUpcomingRingTime(true); // Useful only for VH binding
|
||||
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);
|
||||
@ -209,7 +210,13 @@ public final class AlarmUtils {
|
||||
return pi;
|
||||
}
|
||||
|
||||
private static void save(Context c, Alarm alarm) {
|
||||
new AsyncItemChangeHandler(c, null, null).asyncUpdateAlarm(alarm);
|
||||
public static void save(final Context c, final Alarm alarm) {
|
||||
// TODO: Will using the Runnable like this cause a memory leak?
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
DatabaseManager.getInstance(c).updateAlarm(alarm.id(), alarm);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,4 +9,5 @@
|
||||
android:layout_height="match_parent"
|
||||
app:layoutManager="LinearLayoutManager"
|
||||
tools:context="com.philliphsu.clock2.alarms.AlarmsFragment"
|
||||
tools:listitem="@layout/item_alarm"/>
|
||||
tools:listitem="@layout/item_alarm"
|
||||
android:scrollbars="vertical"/>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user