More Alarm utility methods for cancelling and scheduling
This commit is contained in:
parent
5eb52ee510
commit
abdb939ada
@ -16,6 +16,7 @@ import com.philliphsu.clock2.BaseViewHolder;
|
|||||||
import com.philliphsu.clock2.DaysOfWeek;
|
import com.philliphsu.clock2.DaysOfWeek;
|
||||||
import com.philliphsu.clock2.OnListItemInteractionListener;
|
import com.philliphsu.clock2.OnListItemInteractionListener;
|
||||||
import com.philliphsu.clock2.R;
|
import com.philliphsu.clock2.R;
|
||||||
|
import com.philliphsu.clock2.model.AlarmsRepository;
|
||||||
import com.philliphsu.clock2.util.AlarmUtils;
|
import com.philliphsu.clock2.util.AlarmUtils;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@ -52,41 +53,9 @@ public class AlarmViewHolder extends BaseViewHolder<Alarm> implements AlarmCount
|
|||||||
bindTime(new Date(alarm.ringsAt()));
|
bindTime(new Date(alarm.ringsAt()));
|
||||||
bindSwitch(alarm.isEnabled());
|
bindSwitch(alarm.isEnabled());
|
||||||
bindCountdown(alarm.isEnabled(), alarm.ringsIn());
|
bindCountdown(alarm.isEnabled(), alarm.ringsIn());
|
||||||
|
bindDismissButton(alarm);
|
||||||
int hoursBeforeUpcoming = AlarmUtils.hoursBeforeUpcoming(getContext());
|
bindLabel(alarm);
|
||||||
boolean visible = alarm.isEnabled() && (alarm.ringsWithinHours(hoursBeforeUpcoming) || alarm.isSnoozed());
|
bindDays(alarm);
|
||||||
String buttonText = alarm.isSnoozed()
|
|
||||||
? getContext().getString(R.string.title_snoozing_until, formatTime(getContext(), alarm.snoozingUntil()))
|
|
||||||
: getContext().getString(R.string.dismiss_now);
|
|
||||||
// TODO: Register dynamic broadcast receiver in this class to listen for
|
|
||||||
// when this alarm crosses the upcoming threshold, so we can show this button.
|
|
||||||
bindDismissButton(visible, buttonText);
|
|
||||||
|
|
||||||
// Should also be visible even if alarm has no label so mCountdown is properly positioned next
|
|
||||||
// to mLabel. That is, mCountdown's layout position is dependent on mLabel being present.
|
|
||||||
boolean labelVisible = alarm.label().length() > 0 || mCountdown.getVisibility() == VISIBLE;
|
|
||||||
bindLabel(labelVisible, alarm.label());
|
|
||||||
|
|
||||||
int num = alarm.numRecurringDays();
|
|
||||||
String text;
|
|
||||||
if (num == NUM_DAYS) {
|
|
||||||
text = getContext().getString(R.string.every_day);
|
|
||||||
} else if (num == 0) {
|
|
||||||
text = "";
|
|
||||||
} else {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for (int i = 0 /* Ordinal days*/; i < NUM_DAYS; i++) {
|
|
||||||
// What day is at this position in the week?
|
|
||||||
int weekDay = DaysOfWeek.getInstance(getContext()).weekDayAt(i);
|
|
||||||
if (alarm.isRecurring(weekDay)) {
|
|
||||||
sb.append(DaysOfWeek.getLabel(weekDay)).append(", ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Cut off the last comma and space
|
|
||||||
sb.delete(sb.length() - 2, sb.length());
|
|
||||||
text = sb.toString();
|
|
||||||
}
|
|
||||||
bindDays(num > 0, text);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -95,14 +64,26 @@ public class AlarmViewHolder extends BaseViewHolder<Alarm> implements AlarmCount
|
|||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.dismiss)
|
@OnClick(R.id.dismiss)
|
||||||
void onClick() {
|
void dismiss() {
|
||||||
Alarm alarm = getAlarm();
|
AlarmUtils.cancelAlarm(getContext(), getAlarm());
|
||||||
AlarmUtils.cancelAlarm(getContext(), alarm);
|
|
||||||
if (alarm.isSnoozed()) {
|
|
||||||
alarm.stopSnoozing(); // TOneverDO: before cancelAlarm()
|
|
||||||
}
|
|
||||||
bindDismissButton(false, ""); // Will be set to correct text the next time we bind.
|
bindDismissButton(false, ""); // Will be set to correct text the next time we bind.
|
||||||
// TODO: Check if alarm has no recurrence, then turn it off.
|
// If cancelAlarm() modified the alarm's fields, then it will save changes for you.
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnClick(R.id.on_off_switch)
|
||||||
|
void toggle() {
|
||||||
|
Alarm alarm = getAlarm();
|
||||||
|
alarm.setEnabled(mSwitch.isChecked());
|
||||||
|
if (alarm.isEnabled()) {
|
||||||
|
AlarmUtils.scheduleAlarm(getContext(), alarm);
|
||||||
|
bindCountdown(true, alarm.ringsIn());
|
||||||
|
bindDismissButton(alarm);
|
||||||
|
} else {
|
||||||
|
AlarmUtils.cancelAlarm(getContext(), alarm); // might save repo
|
||||||
|
bindCountdown(false, -1);
|
||||||
|
bindDismissButton(false, "");
|
||||||
|
}
|
||||||
|
save(); // TODO: Problem! If cancelAlarm() saves the repo, this is a redundant call!
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bindTime(Date date) {
|
private void bindTime(Date date) {
|
||||||
@ -132,16 +113,57 @@ public class AlarmViewHolder extends BaseViewHolder<Alarm> implements AlarmCount
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void bindDismissButton(Alarm alarm) {
|
||||||
|
int hoursBeforeUpcoming = AlarmUtils.hoursBeforeUpcoming(getContext());
|
||||||
|
boolean visible = alarm.isEnabled() && (alarm.ringsWithinHours(hoursBeforeUpcoming) || alarm.isSnoozed());
|
||||||
|
String buttonText = alarm.isSnoozed()
|
||||||
|
? getContext().getString(R.string.title_snoozing_until, formatTime(getContext(), alarm.snoozingUntil()))
|
||||||
|
: getContext().getString(R.string.dismiss_now);
|
||||||
|
// TODO: Register dynamic broadcast receiver in this class to listen for
|
||||||
|
// when this alarm crosses the upcoming threshold, so we can show this button.
|
||||||
|
bindDismissButton(visible, buttonText);
|
||||||
|
}
|
||||||
|
|
||||||
private void bindDismissButton(boolean visible, String buttonText) {
|
private void bindDismissButton(boolean visible, String buttonText) {
|
||||||
setVisibility(mDismissButton, visible);
|
setVisibility(mDismissButton, visible);
|
||||||
mDismissButton.setText(buttonText);
|
mDismissButton.setText(buttonText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void bindLabel(Alarm alarm) {
|
||||||
|
// Should also be visible even if alarm has no label so mCountdown is properly positioned next
|
||||||
|
// to mLabel. That is, mCountdown's layout position is dependent on mLabel being present.
|
||||||
|
boolean labelVisible = alarm.label().length() > 0 || mCountdown.getVisibility() == VISIBLE;
|
||||||
|
bindLabel(labelVisible, alarm.label());
|
||||||
|
}
|
||||||
|
|
||||||
private void bindLabel(boolean visible, String label) {
|
private void bindLabel(boolean visible, String label) {
|
||||||
setVisibility(mLabel, visible);
|
setVisibility(mLabel, visible);
|
||||||
mLabel.setText(label);
|
mLabel.setText(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void bindDays(Alarm alarm) {
|
||||||
|
int num = alarm.numRecurringDays();
|
||||||
|
String text;
|
||||||
|
if (num == NUM_DAYS) {
|
||||||
|
text = getContext().getString(R.string.every_day);
|
||||||
|
} else if (num == 0) {
|
||||||
|
text = "";
|
||||||
|
} else {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0 /* Ordinal days*/; i < NUM_DAYS; i++) {
|
||||||
|
// What day is at this position in the week?
|
||||||
|
int weekDay = DaysOfWeek.getInstance(getContext()).weekDayAt(i);
|
||||||
|
if (alarm.isRecurring(weekDay)) {
|
||||||
|
sb.append(DaysOfWeek.getLabel(weekDay)).append(", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Cut off the last comma and space
|
||||||
|
sb.delete(sb.length() - 2, sb.length());
|
||||||
|
text = sb.toString();
|
||||||
|
}
|
||||||
|
bindDays(num > 0, text);
|
||||||
|
}
|
||||||
|
|
||||||
private void bindDays(boolean visible, String text) {
|
private void bindDays(boolean visible, String text) {
|
||||||
setVisibility(mDays, visible);
|
setVisibility(mDays, visible);
|
||||||
mDays.setText(text);
|
mDays.setText(text);
|
||||||
@ -154,4 +176,8 @@ public class AlarmViewHolder extends BaseViewHolder<Alarm> implements AlarmCount
|
|||||||
private Alarm getAlarm() {
|
private Alarm getAlarm() {
|
||||||
return getItem();
|
return getItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void save() {
|
||||||
|
AlarmsRepository.getInstance(getContext()).saveItems();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,7 +29,6 @@ import com.philliphsu.clock2.R;
|
|||||||
import com.philliphsu.clock2.SharedPreferencesHelper;
|
import com.philliphsu.clock2.SharedPreferencesHelper;
|
||||||
import com.philliphsu.clock2.model.AlarmsRepository;
|
import com.philliphsu.clock2.model.AlarmsRepository;
|
||||||
import com.philliphsu.clock2.util.AlarmUtils;
|
import com.philliphsu.clock2.util.AlarmUtils;
|
||||||
import com.philliphsu.clock2.util.DurationUtils;
|
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
@ -425,9 +424,6 @@ public class EditAlarmActivity extends BaseActivity implements AlarmNumpad.KeyLi
|
|||||||
@Override
|
@Override
|
||||||
public void scheduleAlarm(Alarm alarm) {
|
public void scheduleAlarm(Alarm alarm) {
|
||||||
AlarmUtils.scheduleAlarm(this, alarm);
|
AlarmUtils.scheduleAlarm(this, alarm);
|
||||||
String message = getString(R.string.alarm_set_for,
|
|
||||||
DurationUtils.toString(this, alarm.ringsIn(), false /*abbreviate?*/));
|
|
||||||
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -91,7 +91,9 @@ public class EditAlarmPresenter implements EditAlarmContract.Presenter {
|
|||||||
@Override
|
@Override
|
||||||
public void delete() {
|
public void delete() {
|
||||||
if (mAlarm != null) {
|
if (mAlarm != null) {
|
||||||
|
if (mAlarm.isEnabled()) {
|
||||||
mAlarmUtilsHelper.cancelAlarm(mAlarm); // (1)
|
mAlarmUtilsHelper.cancelAlarm(mAlarm); // (1)
|
||||||
|
}
|
||||||
mRepository.deleteItem(mAlarm); // TOneverDO: before (1)
|
mRepository.deleteItem(mAlarm); // TOneverDO: before (1)
|
||||||
}
|
}
|
||||||
mView.showEditorClosed();
|
mView.showEditorClosed();
|
||||||
@ -105,8 +107,12 @@ public class EditAlarmPresenter implements EditAlarmContract.Presenter {
|
|||||||
@Override
|
@Override
|
||||||
public void stopSnoozing() {
|
public void stopSnoozing() {
|
||||||
dismissNow(); // MUST be first, see AlarmUtils.notifyUpcomingAlarmIntent()
|
dismissNow(); // MUST be first, see AlarmUtils.notifyUpcomingAlarmIntent()
|
||||||
|
|
||||||
|
// AlarmUtils.cancelAlarm() does this for you if snoozed
|
||||||
|
/*
|
||||||
mAlarm.stopSnoozing(); // TOneverDO: before dismissNow()
|
mAlarm.stopSnoozing(); // TOneverDO: before dismissNow()
|
||||||
mRepository.saveItems();
|
mRepository.saveItems();
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -11,14 +11,12 @@ import android.util.Log;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import com.philliphsu.clock2.Alarm;
|
import com.philliphsu.clock2.Alarm;
|
||||||
import com.philliphsu.clock2.R;
|
import com.philliphsu.clock2.R;
|
||||||
import com.philliphsu.clock2.model.AlarmsRepository;
|
import com.philliphsu.clock2.model.AlarmsRepository;
|
||||||
import com.philliphsu.clock2.util.AlarmUtils;
|
import com.philliphsu.clock2.util.AlarmUtils;
|
||||||
|
|
||||||
import static com.philliphsu.clock2.util.DateFormatUtils.formatTime;
|
|
||||||
import static com.philliphsu.clock2.util.Preconditions.checkNotNull;
|
import static com.philliphsu.clock2.util.Preconditions.checkNotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -132,18 +130,16 @@ public class RingtoneActivity extends AppCompatActivity implements RingtoneServi
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void snooze() {
|
private void snooze() {
|
||||||
int snoozeMins = AlarmUtils.snoozeDuration(this);
|
AlarmUtils.snoozeAlarm(this, mAlarm);
|
||||||
mAlarm.snooze(snoozeMins);
|
// Can't call dismiss() because we don't want to also call cancelAlarm()! Why? For example,
|
||||||
AlarmUtils.scheduleAlarm(this, mAlarm);
|
// we don't want the alarm, if it has no recurrence, to be turned off immediately.
|
||||||
AlarmsRepository.getInstance(this).saveItems();
|
unbindService(); // don't wait for finish() to call onDestroy()
|
||||||
// Display toast
|
finish();
|
||||||
String message = getString(R.string.title_snoozing_until, formatTime(this, mAlarm.snoozingUntil()));
|
|
||||||
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
|
|
||||||
dismiss();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dismiss() {
|
private void dismiss() {
|
||||||
// TODO: Do we need to cancel the PendingIntent and the alarm in AlarmManager?
|
// TODO: Do we need to cancel the PendingIntent and the alarm in AlarmManager?
|
||||||
|
AlarmUtils.cancelAlarm(this, mAlarm);
|
||||||
unbindService(); // don't wait for finish() to call onDestroy()
|
unbindService(); // don't wait for finish() to call onDestroy()
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -77,14 +77,19 @@ public class RingtoneService extends Service { // TODO: abstract this, make subc
|
|||||||
// stopService(Intent) [or stopSelf()] is called, regardless of whether any clients are connected to it."
|
// stopService(Intent) [or stopSelf()] is called, regardless of whether any clients are connected to it."
|
||||||
// I have found the regardless part does not apply here. You MUST also unbind any clients from this service
|
// I have found the regardless part does not apply here. You MUST also unbind any clients from this service
|
||||||
// at the same time you stop this service!
|
// at the same time you stop this service!
|
||||||
|
long id = intent.getLongExtra(EXTRA_ITEM_ID, -1);
|
||||||
|
if (id < 0)
|
||||||
|
throw new IllegalStateException("No item id set");
|
||||||
|
Alarm alarm = checkNotNull(AlarmsRepository.getInstance(this).getItem(id));
|
||||||
|
|
||||||
if (ACTION_SNOOZE.equals(intent.getAction())) {
|
if (ACTION_SNOOZE.equals(intent.getAction())) {
|
||||||
long id = intent.getLongExtra(EXTRA_ITEM_ID, -1);
|
AlarmUtils.snoozeAlarm(this, alarm);
|
||||||
if (id < 0) throw new IllegalStateException("No item id set");
|
} else if (ACTION_DISMISS.equals(intent.getAction())) {
|
||||||
Alarm alarm = checkNotNull(AlarmsRepository.getInstance(this).getItem(id));
|
AlarmUtils.cancelAlarm(this, alarm);
|
||||||
alarm.snooze(AlarmUtils.snoozeDuration(this));
|
} else {
|
||||||
AlarmUtils.scheduleAlarm(this, alarm);
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
stopSelf(startId);
|
stopSelf(startId);
|
||||||
if (mRingtoneCallback != null) {
|
if (mRingtoneCallback != null) {
|
||||||
mRingtoneCallback.onServiceFinish(); // tell client to unbind from this service
|
mRingtoneCallback.onServiceFinish(); // tell client to unbind from this service
|
||||||
|
|||||||
@ -7,16 +7,19 @@ import android.content.Intent;
|
|||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.support.annotation.StringRes;
|
import android.support.annotation.StringRes;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.philliphsu.clock2.Alarm;
|
import com.philliphsu.clock2.Alarm;
|
||||||
import com.philliphsu.clock2.R;
|
import com.philliphsu.clock2.R;
|
||||||
import com.philliphsu.clock2.UpcomingAlarmReceiver;
|
import com.philliphsu.clock2.UpcomingAlarmReceiver;
|
||||||
|
import com.philliphsu.clock2.model.AlarmsRepository;
|
||||||
import com.philliphsu.clock2.ringtone.RingtoneActivity;
|
import com.philliphsu.clock2.ringtone.RingtoneActivity;
|
||||||
import com.philliphsu.clock2.ringtone.RingtoneService;
|
import com.philliphsu.clock2.ringtone.RingtoneService;
|
||||||
|
|
||||||
import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
|
import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
|
||||||
import static android.app.PendingIntent.FLAG_NO_CREATE;
|
import static android.app.PendingIntent.FLAG_NO_CREATE;
|
||||||
import static android.app.PendingIntent.getActivity;
|
import static android.app.PendingIntent.getActivity;
|
||||||
|
import static com.philliphsu.clock2.util.DateFormatUtils.formatTime;
|
||||||
import static com.philliphsu.clock2.util.Preconditions.checkNotNull;
|
import static com.philliphsu.clock2.util.Preconditions.checkNotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,6 +53,18 @@ public final class AlarmUtils {
|
|||||||
am.set(AlarmManager.RTC_WAKEUP, ringAt - hoursBeforeUpcoming(context) * 3600000,
|
am.set(AlarmManager.RTC_WAKEUP, ringAt - hoursBeforeUpcoming(context) * 3600000,
|
||||||
notifyUpcomingAlarmIntent(context, alarm, false));
|
notifyUpcomingAlarmIntent(context, alarm, false));
|
||||||
am.setExact(AlarmManager.RTC_WAKEUP, ringAt, alarmIntent(context, alarm, false));
|
am.setExact(AlarmManager.RTC_WAKEUP, ringAt, alarmIntent(context, alarm, false));
|
||||||
|
|
||||||
|
// Display toast
|
||||||
|
String message;
|
||||||
|
if (alarm.isSnoozed()) {
|
||||||
|
message = context.getString(R.string.title_snoozing_until,
|
||||||
|
formatTime(context, alarm.snoozingUntil()));
|
||||||
|
} else {
|
||||||
|
message = context.getString(R.string.alarm_set_for,
|
||||||
|
DurationUtils.toString(context, alarm.ringsIn(), false /*abbreviate?*/));
|
||||||
|
}
|
||||||
|
// TODO: Will toasts show for any Context? e.g. IntentService can't do anything on UI thread.
|
||||||
|
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void cancelAlarm(Context c, Alarm a) {
|
public static void cancelAlarm(Context c, Alarm a) {
|
||||||
@ -66,6 +81,16 @@ public final class AlarmUtils {
|
|||||||
|
|
||||||
removeUpcomingAlarmNotification(c, a);
|
removeUpcomingAlarmNotification(c, a);
|
||||||
|
|
||||||
|
if (a.isSnoozed()) {
|
||||||
|
a.stopSnoozing();
|
||||||
|
save(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!a.hasRecurrence()) {
|
||||||
|
a.setEnabled(false);
|
||||||
|
save(c);
|
||||||
|
}
|
||||||
|
|
||||||
// If service is not running, nothing happens
|
// If service is not running, nothing happens
|
||||||
// TODO: Since RingtoneService is a bound service, will this destroy the service after returning?
|
// TODO: Since RingtoneService is a bound service, will this destroy the service after returning?
|
||||||
// Note that if a stopped service still has ServiceConnection objects bound to it with the
|
// Note that if a stopped service still has ServiceConnection objects bound to it with the
|
||||||
@ -73,6 +98,12 @@ public final class AlarmUtils {
|
|||||||
c.stopService(new Intent(c, RingtoneService.class));
|
c.stopService(new Intent(c, RingtoneService.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void snoozeAlarm(Context c, Alarm a) {
|
||||||
|
a.snooze(AlarmUtils.snoozeDuration(c));
|
||||||
|
AlarmUtils.scheduleAlarm(c, a);
|
||||||
|
save(c);
|
||||||
|
}
|
||||||
|
|
||||||
public static void removeUpcomingAlarmNotification(Context c, Alarm a) {
|
public static void removeUpcomingAlarmNotification(Context c, Alarm a) {
|
||||||
Intent intent = new Intent(c, UpcomingAlarmReceiver.class)
|
Intent intent = new Intent(c, UpcomingAlarmReceiver.class)
|
||||||
.setAction(UpcomingAlarmReceiver.ACTION_CANCEL_NOTIFICATION)
|
.setAction(UpcomingAlarmReceiver.ACTION_CANCEL_NOTIFICATION)
|
||||||
@ -130,4 +161,8 @@ public final class AlarmUtils {
|
|||||||
}
|
}
|
||||||
return pi;
|
return pi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void save(Context c) {
|
||||||
|
AlarmsRepository.getInstance(c).saveItems();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user