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.OnListItemInteractionListener;
|
||||
import com.philliphsu.clock2.R;
|
||||
import com.philliphsu.clock2.model.AlarmsRepository;
|
||||
import com.philliphsu.clock2.util.AlarmUtils;
|
||||
|
||||
import java.util.Date;
|
||||
@ -52,41 +53,9 @@ public class AlarmViewHolder extends BaseViewHolder<Alarm> implements AlarmCount
|
||||
bindTime(new Date(alarm.ringsAt()));
|
||||
bindSwitch(alarm.isEnabled());
|
||||
bindCountdown(alarm.isEnabled(), alarm.ringsIn());
|
||||
|
||||
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);
|
||||
|
||||
// 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);
|
||||
bindDismissButton(alarm);
|
||||
bindLabel(alarm);
|
||||
bindDays(alarm);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -95,14 +64,26 @@ public class AlarmViewHolder extends BaseViewHolder<Alarm> implements AlarmCount
|
||||
}
|
||||
|
||||
@OnClick(R.id.dismiss)
|
||||
void onClick() {
|
||||
Alarm alarm = getAlarm();
|
||||
AlarmUtils.cancelAlarm(getContext(), alarm);
|
||||
if (alarm.isSnoozed()) {
|
||||
alarm.stopSnoozing(); // TOneverDO: before cancelAlarm()
|
||||
}
|
||||
void dismiss() {
|
||||
AlarmUtils.cancelAlarm(getContext(), getAlarm());
|
||||
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) {
|
||||
@ -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) {
|
||||
setVisibility(mDismissButton, visible);
|
||||
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) {
|
||||
setVisibility(mLabel, visible);
|
||||
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) {
|
||||
setVisibility(mDays, visible);
|
||||
mDays.setText(text);
|
||||
@ -154,4 +176,8 @@ public class AlarmViewHolder extends BaseViewHolder<Alarm> implements AlarmCount
|
||||
private Alarm getAlarm() {
|
||||
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.model.AlarmsRepository;
|
||||
import com.philliphsu.clock2.util.AlarmUtils;
|
||||
import com.philliphsu.clock2.util.DurationUtils;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@ -425,9 +424,6 @@ public class EditAlarmActivity extends BaseActivity implements AlarmNumpad.KeyLi
|
||||
@Override
|
||||
public void scheduleAlarm(Alarm 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
|
||||
|
||||
@ -91,7 +91,9 @@ public class EditAlarmPresenter implements EditAlarmContract.Presenter {
|
||||
@Override
|
||||
public void delete() {
|
||||
if (mAlarm != null) {
|
||||
mAlarmUtilsHelper.cancelAlarm(mAlarm); // (1)
|
||||
if (mAlarm.isEnabled()) {
|
||||
mAlarmUtilsHelper.cancelAlarm(mAlarm); // (1)
|
||||
}
|
||||
mRepository.deleteItem(mAlarm); // TOneverDO: before (1)
|
||||
}
|
||||
mView.showEditorClosed();
|
||||
@ -105,8 +107,12 @@ public class EditAlarmPresenter implements EditAlarmContract.Presenter {
|
||||
@Override
|
||||
public void stopSnoozing() {
|
||||
dismissNow(); // MUST be first, see AlarmUtils.notifyUpcomingAlarmIntent()
|
||||
|
||||
// AlarmUtils.cancelAlarm() does this for you if snoozed
|
||||
/*
|
||||
mAlarm.stopSnoozing(); // TOneverDO: before dismissNow()
|
||||
mRepository.saveItems();
|
||||
*/
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -11,14 +11,12 @@ import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Button;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.philliphsu.clock2.Alarm;
|
||||
import com.philliphsu.clock2.R;
|
||||
import com.philliphsu.clock2.model.AlarmsRepository;
|
||||
import com.philliphsu.clock2.util.AlarmUtils;
|
||||
|
||||
import static com.philliphsu.clock2.util.DateFormatUtils.formatTime;
|
||||
import static com.philliphsu.clock2.util.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
@ -132,18 +130,16 @@ public class RingtoneActivity extends AppCompatActivity implements RingtoneServi
|
||||
}
|
||||
|
||||
private void snooze() {
|
||||
int snoozeMins = AlarmUtils.snoozeDuration(this);
|
||||
mAlarm.snooze(snoozeMins);
|
||||
AlarmUtils.scheduleAlarm(this, mAlarm);
|
||||
AlarmsRepository.getInstance(this).saveItems();
|
||||
// Display toast
|
||||
String message = getString(R.string.title_snoozing_until, formatTime(this, mAlarm.snoozingUntil()));
|
||||
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
|
||||
dismiss();
|
||||
AlarmUtils.snoozeAlarm(this, mAlarm);
|
||||
// Can't call dismiss() because we don't want to also call cancelAlarm()! Why? For example,
|
||||
// we don't want the alarm, if it has no recurrence, to be turned off immediately.
|
||||
unbindService(); // don't wait for finish() to call onDestroy()
|
||||
finish();
|
||||
}
|
||||
|
||||
private void dismiss() {
|
||||
// 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()
|
||||
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."
|
||||
// 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!
|
||||
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())) {
|
||||
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));
|
||||
alarm.snooze(AlarmUtils.snoozeDuration(this));
|
||||
AlarmUtils.scheduleAlarm(this, alarm);
|
||||
AlarmUtils.snoozeAlarm(this, alarm);
|
||||
} else if (ACTION_DISMISS.equals(intent.getAction())) {
|
||||
AlarmUtils.cancelAlarm(this, alarm);
|
||||
} else {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
stopSelf(startId);
|
||||
if (mRingtoneCallback != null) {
|
||||
mRingtoneCallback.onServiceFinish(); // tell client to unbind from this service
|
||||
|
||||
@ -7,16 +7,19 @@ import android.content.Intent;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.philliphsu.clock2.Alarm;
|
||||
import com.philliphsu.clock2.R;
|
||||
import com.philliphsu.clock2.UpcomingAlarmReceiver;
|
||||
import com.philliphsu.clock2.model.AlarmsRepository;
|
||||
import com.philliphsu.clock2.ringtone.RingtoneActivity;
|
||||
import com.philliphsu.clock2.ringtone.RingtoneService;
|
||||
|
||||
import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
|
||||
import static android.app.PendingIntent.FLAG_NO_CREATE;
|
||||
import static android.app.PendingIntent.getActivity;
|
||||
import static com.philliphsu.clock2.util.DateFormatUtils.formatTime;
|
||||
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,
|
||||
notifyUpcomingAlarmIntent(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) {
|
||||
@ -66,6 +81,16 @@ public final class AlarmUtils {
|
||||
|
||||
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
|
||||
// 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
|
||||
@ -73,6 +98,12 @@ public final class AlarmUtils {
|
||||
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) {
|
||||
Intent intent = new Intent(c, UpcomingAlarmReceiver.class)
|
||||
.setAction(UpcomingAlarmReceiver.ACTION_CANCEL_NOTIFICATION)
|
||||
@ -130,4 +161,8 @@ public final class AlarmUtils {
|
||||
}
|
||||
return pi;
|
||||
}
|
||||
|
||||
private static void save(Context c) {
|
||||
AlarmsRepository.getInstance(c).saveItems();
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user