Show alarm set icon in status bar
This commit is contained in:
parent
d171ac9536
commit
c6cfe57e5d
@ -267,7 +267,7 @@ public class MainActivity extends BaseActivity {
|
|||||||
public Fragment getItem(int position) {
|
public Fragment getItem(int position) {
|
||||||
switch (position) {
|
switch (position) {
|
||||||
case PAGE_ALARMS:
|
case PAGE_ALARMS:
|
||||||
return AlarmsFragment.newInstance(1);
|
return new AlarmsFragment();
|
||||||
case PAGE_TIMERS:
|
case PAGE_TIMERS:
|
||||||
return new TimersFragment();
|
return new TimersFragment();
|
||||||
case PAGE_STOPWATCH:
|
case PAGE_STOPWATCH:
|
||||||
|
|||||||
@ -4,12 +4,15 @@ import android.app.AlarmManager;
|
|||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.os.Build;
|
||||||
import android.support.design.widget.Snackbar;
|
import android.support.design.widget.Snackbar;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
|
import com.philliphsu.clock2.MainActivity;
|
||||||
import com.philliphsu.clock2.R;
|
import com.philliphsu.clock2.R;
|
||||||
import com.philliphsu.clock2.alarms.Alarm;
|
import com.philliphsu.clock2.alarms.Alarm;
|
||||||
|
import com.philliphsu.clock2.alarms.ui.AlarmsFragment;
|
||||||
import com.philliphsu.clock2.ringtone.AlarmActivity;
|
import com.philliphsu.clock2.ringtone.AlarmActivity;
|
||||||
import com.philliphsu.clock2.ringtone.playback.AlarmRingtoneService;
|
import com.philliphsu.clock2.ringtone.playback.AlarmRingtoneService;
|
||||||
import com.philliphsu.clock2.alarms.background.PendingAlarmScheduler;
|
import com.philliphsu.clock2.alarms.background.PendingAlarmScheduler;
|
||||||
@ -53,46 +56,56 @@ public final class AlarmController {
|
|||||||
* Schedules the alarm with the {@link AlarmManager}.
|
* Schedules the alarm with the {@link AlarmManager}.
|
||||||
* If {@code alarm.}{@link Alarm#isEnabled() isEnabled()}
|
* If {@code alarm.}{@link Alarm#isEnabled() isEnabled()}
|
||||||
* returns false, this does nothing and returns immediately.
|
* returns false, this does nothing and returns immediately.
|
||||||
|
*
|
||||||
|
* If there is already an alarm for this Intent scheduled (with the equality of two
|
||||||
|
* intents being defined by filterEquals(Intent)), then it will be removed and replaced
|
||||||
|
* by this one. For most of our uses, the relevant criteria for equality will be the
|
||||||
|
* action, the data, and the class (component). Although not documented, the request code
|
||||||
|
* of a PendingIntent is also considered to determine equality of two intents.
|
||||||
*/
|
*/
|
||||||
public void scheduleAlarm(Alarm alarm, boolean showSnackbar) {
|
public void scheduleAlarm(Alarm alarm, boolean showSnackbar) {
|
||||||
if (!alarm.isEnabled()) {
|
if (!alarm.isEnabled()) {
|
||||||
Log.i(TAG, "Skipped scheduling an alarm because it was not enabled");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Does nothing if it's not posted. This is primarily here for when alarms
|
// Does nothing if it's not posted. This is primarily here for when alarms
|
||||||
// are updated, instead of newly created, so that we don't leave behind
|
// are updated, instead of newly created, so that we don't leave behind
|
||||||
// stray upcoming alarm notifications. This occurs e.g. when a single-use
|
// stray upcoming alarm notifications. This occurs e.g. when a single-use
|
||||||
// alarm is updated to recur on a weekday later than the current day.
|
// alarm is updated to recur on a weekday later than the current day.
|
||||||
removeUpcomingAlarmNotification(alarm);
|
removeUpcomingAlarmNotification(alarm);
|
||||||
|
|
||||||
Log.d(TAG, "Scheduling alarm " + alarm);
|
|
||||||
AlarmManager am = (AlarmManager) mAppContext.getSystemService(Context.ALARM_SERVICE);
|
AlarmManager am = (AlarmManager) mAppContext.getSystemService(Context.ALARM_SERVICE);
|
||||||
// If there is already an alarm for this Intent scheduled (with the equality of two
|
|
||||||
// intents being defined by filterEquals(Intent)), then it will be removed and replaced
|
|
||||||
// by this one. For most of our uses, the relevant criteria for equality will be the
|
|
||||||
// action, the data, and the class (component). Although not documented, the request code
|
|
||||||
// of a PendingIntent is also considered to determine equality of two intents.
|
|
||||||
|
|
||||||
// WAKEUP alarm types wake the CPU up, but NOT the screen. If that is what you want, you need
|
|
||||||
// to handle that yourself by using a wakelock, etc..
|
|
||||||
// We use a WAKEUP alarm to send the upcoming alarm notification so it goes off even if the
|
|
||||||
// device is asleep. Otherwise, it will not go off until the device is turned back on.
|
|
||||||
final long ringAt = alarm.isSnoozed() ? alarm.snoozingUntil() : alarm.ringsAt();
|
final long ringAt = alarm.isSnoozed() ? alarm.snoozingUntil() : alarm.ringsAt();
|
||||||
am.setExact(AlarmManager.RTC_WAKEUP, ringAt, alarmIntent(alarm, false));
|
final PendingIntent alarmIntent = alarmIntent(alarm, false);
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
Intent viewAlarm = new Intent(mAppContext, MainActivity.class);
|
||||||
|
viewAlarm.putExtra(AlarmsFragment.EXTRA_SCROLL_TO_ALARM_ID, alarm.getId());
|
||||||
|
PendingIntent showIntent = PendingIntent.getActivity(mAppContext,
|
||||||
|
alarm.getIntId(), viewAlarm, FLAG_CANCEL_CURRENT);
|
||||||
|
AlarmManager.AlarmClockInfo info = new AlarmManager.AlarmClockInfo(ringAt, showIntent);
|
||||||
|
am.setAlarmClock(info, alarmIntent);
|
||||||
|
} else {
|
||||||
|
// WAKEUP alarm types wake the CPU up, but NOT the screen;
|
||||||
|
// you would handle that yourself by using a wakelock, etc..
|
||||||
|
am.setExact(AlarmManager.RTC_WAKEUP, ringAt, alarmIntent);
|
||||||
|
// Show alarm in the status bar
|
||||||
|
Intent alarmChanged = new Intent("android.intent.action.ALARM_CHANGED");
|
||||||
|
alarmChanged.putExtra("alarmSet", true/*enabled*/);
|
||||||
|
mAppContext.sendBroadcast(alarmChanged);
|
||||||
|
}
|
||||||
|
|
||||||
final int hoursToNotifyInAdvance = AlarmPreferences.hoursBeforeUpcoming(mAppContext);
|
final int hoursToNotifyInAdvance = AlarmPreferences.hoursBeforeUpcoming(mAppContext);
|
||||||
if (hoursToNotifyInAdvance > 0 || alarm.isSnoozed()) {
|
if (hoursToNotifyInAdvance > 0 || alarm.isSnoozed()) {
|
||||||
// If snoozed, upcoming note posted immediately.
|
// If snoozed, upcoming note posted immediately.
|
||||||
long upcomingAt = ringAt - HOURS.toMillis(hoursToNotifyInAdvance);
|
long upcomingAt = ringAt - HOURS.toMillis(hoursToNotifyInAdvance);
|
||||||
|
// We use a WAKEUP alarm to send the upcoming alarm notification so it goes off even if the
|
||||||
|
// device is asleep. Otherwise, it will not go off until the device is turned back on.
|
||||||
am.set(AlarmManager.RTC_WAKEUP, upcomingAt, notifyUpcomingAlarmIntent(alarm, false));
|
am.set(AlarmManager.RTC_WAKEUP, upcomingAt, notifyUpcomingAlarmIntent(alarm, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showSnackbar) {
|
if (showSnackbar) {
|
||||||
String message = mAppContext.getString(R.string.alarm_set_for,
|
String message = mAppContext.getString(R.string.alarm_set_for,
|
||||||
DurationUtils.toString(mAppContext, alarm.ringsIn(), false /*abbreviate?*/));
|
DurationUtils.toString(mAppContext, alarm.ringsIn(), false/*abbreviate*/));
|
||||||
// TODO: Consider adding delay to allow the alarm item animation
|
|
||||||
// to finish first before we show the snackbar. Inbox app does this.
|
|
||||||
showSnackbar(message);
|
showSnackbar(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -104,7 +117,6 @@ public final class AlarmController {
|
|||||||
* and is enabled.
|
* and is enabled.
|
||||||
*/
|
*/
|
||||||
public void cancelAlarm(Alarm alarm, boolean showSnackbar, boolean rescheduleIfRecurring) {
|
public void cancelAlarm(Alarm alarm, boolean showSnackbar, boolean rescheduleIfRecurring) {
|
||||||
// TODO: Consider doing this in a new thread.
|
|
||||||
Log.d(TAG, "Cancelling alarm " + alarm);
|
Log.d(TAG, "Cancelling alarm " + alarm);
|
||||||
AlarmManager am = (AlarmManager) mAppContext.getSystemService(Context.ALARM_SERVICE);
|
AlarmManager am = (AlarmManager) mAppContext.getSystemService(Context.ALARM_SERVICE);
|
||||||
|
|
||||||
@ -112,6 +124,12 @@ public final class AlarmController {
|
|||||||
if (pi != null) {
|
if (pi != null) {
|
||||||
am.cancel(pi);
|
am.cancel(pi);
|
||||||
pi.cancel();
|
pi.cancel();
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
// Remove alarm in the status bar
|
||||||
|
Intent alarmChanged = new Intent("android.intent.action.ALARM_CHANGED");
|
||||||
|
alarmChanged.putExtra("alarmSet", false/*enabled*/);
|
||||||
|
mAppContext.sendBroadcast(alarmChanged);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pi = notifyUpcomingAlarmIntent(alarm, true);
|
pi = notifyUpcomingAlarmIntent(alarm, true);
|
||||||
@ -124,6 +142,7 @@ public final class AlarmController {
|
|||||||
removeUpcomingAlarmNotification(alarm);
|
removeUpcomingAlarmNotification(alarm);
|
||||||
|
|
||||||
final int hoursToNotifyInAdvance = AlarmPreferences.hoursBeforeUpcoming(mAppContext);
|
final int hoursToNotifyInAdvance = AlarmPreferences.hoursBeforeUpcoming(mAppContext);
|
||||||
|
// ------------------------------------------------------------------------------------
|
||||||
// TOneverDO: Place block after making value changes to the alarm.
|
// TOneverDO: Place block after making value changes to the alarm.
|
||||||
if ((hoursToNotifyInAdvance > 0 && showSnackbar
|
if ((hoursToNotifyInAdvance > 0 && showSnackbar
|
||||||
// TODO: Consider showing the snackbar for non-upcoming alarms too;
|
// TODO: Consider showing the snackbar for non-upcoming alarms too;
|
||||||
@ -134,6 +153,7 @@ public final class AlarmController {
|
|||||||
formatTime(mAppContext, time));
|
formatTime(mAppContext, time));
|
||||||
showSnackbar(msg);
|
showSnackbar(msg);
|
||||||
}
|
}
|
||||||
|
// ------------------------------------------------------------------------------------
|
||||||
|
|
||||||
if (alarm.isSnoozed()) {
|
if (alarm.isSnoozed()) {
|
||||||
alarm.stopSnoozing();
|
alarm.stopSnoozing();
|
||||||
@ -195,40 +215,24 @@ public final class AlarmController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private PendingIntent alarmIntent(Alarm alarm, boolean retrievePrevious) {
|
private PendingIntent alarmIntent(Alarm alarm, boolean retrievePrevious) {
|
||||||
// TODO: Use appropriate subclass instead
|
|
||||||
Intent intent = new Intent(mAppContext, AlarmActivity.class)
|
Intent intent = new Intent(mAppContext, AlarmActivity.class)
|
||||||
.putExtra(AlarmActivity.EXTRA_RINGING_OBJECT, alarm);
|
.putExtra(AlarmActivity.EXTRA_RINGING_OBJECT, alarm);
|
||||||
int flag = retrievePrevious ? FLAG_NO_CREATE : FLAG_CANCEL_CURRENT;
|
int flag = retrievePrevious ? FLAG_NO_CREATE : FLAG_CANCEL_CURRENT;
|
||||||
PendingIntent pi = getActivity(mAppContext, alarm.getIntId(), intent, flag);
|
|
||||||
// Even when we try to retrieve a previous instance that actually did exist,
|
// Even when we try to retrieve a previous instance that actually did exist,
|
||||||
// null can be returned for some reason.
|
// null can be returned for some reason. Thus, we don't checkNotNull().
|
||||||
/*
|
return getActivity(mAppContext, alarm.getIntId(), intent, flag);
|
||||||
if (retrievePrevious) {
|
|
||||||
checkNotNull(pi);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return pi;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private PendingIntent notifyUpcomingAlarmIntent(Alarm alarm, boolean retrievePrevious) {
|
private PendingIntent notifyUpcomingAlarmIntent(Alarm alarm, boolean retrievePrevious) {
|
||||||
Intent intent = new Intent(mAppContext, UpcomingAlarmReceiver.class)
|
Intent intent = new Intent(mAppContext, UpcomingAlarmReceiver.class)
|
||||||
.putExtra(UpcomingAlarmReceiver.EXTRA_ALARM, alarm);
|
.putExtra(UpcomingAlarmReceiver.EXTRA_ALARM, alarm);
|
||||||
if (alarm.isSnoozed()) {
|
if (alarm.isSnoozed()) {
|
||||||
// TODO: Will this affect retrieving a previous instance? Say if the previous instance
|
|
||||||
// didn't have this action set initially, but at a later time we made a new instance
|
|
||||||
// with it set.
|
|
||||||
intent.setAction(UpcomingAlarmReceiver.ACTION_SHOW_SNOOZING);
|
intent.setAction(UpcomingAlarmReceiver.ACTION_SHOW_SNOOZING);
|
||||||
}
|
}
|
||||||
int flag = retrievePrevious ? FLAG_NO_CREATE : FLAG_CANCEL_CURRENT;
|
int flag = retrievePrevious ? FLAG_NO_CREATE : FLAG_CANCEL_CURRENT;
|
||||||
PendingIntent pi = PendingIntent.getBroadcast(mAppContext, alarm.getIntId(), intent, flag);
|
|
||||||
// Even when we try to retrieve a previous instance that actually did exist,
|
// Even when we try to retrieve a previous instance that actually did exist,
|
||||||
// null can be returned for some reason.
|
// null can be returned for some reason. Thus, we don't checkNotNull().
|
||||||
/*
|
return PendingIntent.getBroadcast(mAppContext, alarm.getIntId(), intent, flag);
|
||||||
if (retrievePrevious) {
|
|
||||||
checkNotNull(pi);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return pi;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showSnackbar(final String message) {
|
private void showSnackbar(final String message) {
|
||||||
|
|||||||
@ -1,28 +1,22 @@
|
|||||||
package com.philliphsu.clock2.alarms.ui;
|
package com.philliphsu.clock2.alarms.ui;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.media.RingtoneManager;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.content.Loader;
|
import android.support.v4.content.Loader;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.util.Log;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import com.philliphsu.clock2.R;
|
import com.philliphsu.clock2.R;
|
||||||
import com.philliphsu.clock2.list.RecyclerViewFragment;
|
|
||||||
import com.philliphsu.clock2.dialogs.TimePickerDialogController;
|
|
||||||
import com.philliphsu.clock2.alarms.Alarm;
|
import com.philliphsu.clock2.alarms.Alarm;
|
||||||
|
import com.philliphsu.clock2.alarms.data.AlarmCursor;
|
||||||
import com.philliphsu.clock2.alarms.data.AlarmsListCursorLoader;
|
import com.philliphsu.clock2.alarms.data.AlarmsListCursorLoader;
|
||||||
import com.philliphsu.clock2.alarms.data.AsyncAlarmsTableUpdateHandler;
|
import com.philliphsu.clock2.alarms.data.AsyncAlarmsTableUpdateHandler;
|
||||||
import com.philliphsu.clock2.alarms.misc.AlarmController;
|
import com.philliphsu.clock2.alarms.misc.AlarmController;
|
||||||
|
import com.philliphsu.clock2.dialogs.TimePickerDialogController;
|
||||||
|
import com.philliphsu.clock2.list.RecyclerViewFragment;
|
||||||
import com.philliphsu.clock2.timepickers.BaseTimePickerDialog;
|
import com.philliphsu.clock2.timepickers.BaseTimePickerDialog;
|
||||||
import com.philliphsu.clock2.alarms.data.AlarmCursor;
|
|
||||||
import com.philliphsu.clock2.util.DelayedSnackbarHandler;
|
import com.philliphsu.clock2.util.DelayedSnackbarHandler;
|
||||||
|
|
||||||
import static com.philliphsu.clock2.util.FragmentTagUtils.makeTag;
|
import static com.philliphsu.clock2.util.FragmentTagUtils.makeTag;
|
||||||
@ -30,54 +24,19 @@ import static com.philliphsu.clock2.util.FragmentTagUtils.makeTag;
|
|||||||
public class AlarmsFragment extends RecyclerViewFragment<Alarm, BaseAlarmViewHolder, AlarmCursor,
|
public class AlarmsFragment extends RecyclerViewFragment<Alarm, BaseAlarmViewHolder, AlarmCursor,
|
||||||
AlarmsCursorAdapter> implements BaseTimePickerDialog.OnTimeSetListener {
|
AlarmsCursorAdapter> implements BaseTimePickerDialog.OnTimeSetListener {
|
||||||
private static final String TAG = "AlarmsFragment";
|
private static final String TAG = "AlarmsFragment";
|
||||||
|
|
||||||
private static final String KEY_EXPANDED_POSITION = "expanded_position";
|
private static final String KEY_EXPANDED_POSITION = "expanded_position";
|
||||||
|
|
||||||
// TODO: Delete these constants. We no longer use EditAlarmActivity.
|
|
||||||
// @Deprecated
|
|
||||||
// private static final int REQUEST_EDIT_ALARM = 0;
|
|
||||||
// // Public because MainActivity needs to use it.
|
|
||||||
// // TODO: private because we handle fab clicks in the fragment now
|
|
||||||
// @Deprecated
|
|
||||||
// public static final int REQUEST_CREATE_ALARM = 1;
|
|
||||||
|
|
||||||
// TODO: Delete this. We no longer use the system's ringtone picker.
|
|
||||||
public static final int REQUEST_PICK_RINGTONE = 1;
|
|
||||||
public static final String EXTRA_SCROLL_TO_ALARM_ID = "com.philliphsu.clock2.alarms.extra.SCROLL_TO_ALARM_ID";
|
public static final String EXTRA_SCROLL_TO_ALARM_ID = "com.philliphsu.clock2.alarms.extra.SCROLL_TO_ALARM_ID";
|
||||||
|
|
||||||
private AsyncAlarmsTableUpdateHandler mAsyncUpdateHandler;
|
private AsyncAlarmsTableUpdateHandler mAsyncUpdateHandler;
|
||||||
private AlarmController mAlarmController;
|
private AlarmController mAlarmController;
|
||||||
// TODO: Delete this. If I recall correctly, this was just used for delaying item animations.
|
|
||||||
private Handler mHandler = new Handler();
|
|
||||||
private View mSnackbarAnchor;
|
private View mSnackbarAnchor;
|
||||||
private TimePickerDialogController mTimePickerDialogController;
|
private TimePickerDialogController mTimePickerDialogController;
|
||||||
|
|
||||||
private int mExpandedPosition = RecyclerView.NO_POSITION;
|
private int mExpandedPosition = RecyclerView.NO_POSITION;
|
||||||
|
|
||||||
/**
|
|
||||||
* Mandatory empty constructor for the fragment manager to instantiate the
|
|
||||||
* fragment (e.g. upon screen orientation changes).
|
|
||||||
*/
|
|
||||||
public AlarmsFragment() {}
|
|
||||||
|
|
||||||
// TODO: Customize parameter initialization
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public static AlarmsFragment newInstance(int columnCount) {
|
|
||||||
AlarmsFragment fragment = new AlarmsFragment();
|
|
||||||
Bundle args = new Bundle();
|
|
||||||
// TODO Put any arguments in bundle
|
|
||||||
fragment.setArguments(args);
|
|
||||||
return fragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
if (getArguments() != null) {
|
|
||||||
// TODO Read arguments
|
|
||||||
}
|
|
||||||
|
|
||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
// Restore the value of the last expanded position here.
|
// Restore the value of the last expanded position here.
|
||||||
// We cannot tell the adapter to expand this item until onLoadFinished()
|
// We cannot tell the adapter to expand this item until onLoadFinished()
|
||||||
@ -144,61 +103,8 @@ public class AlarmsFragment extends RecyclerViewFragment<Alarm, BaseAlarmViewHol
|
|||||||
return R.string.empty_alarms_container;
|
return R.string.empty_alarms_container;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: We're not using EditAlarmActivity anymore, so move this logic somewhere else.
|
|
||||||
// We also don't need to delay the change to get animations working.
|
|
||||||
@Override
|
|
||||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
||||||
Log.d(TAG, "onActivityResult()");
|
|
||||||
if (resultCode != Activity.RESULT_OK || data == null)
|
|
||||||
return;
|
|
||||||
if (requestCode == REQUEST_PICK_RINGTONE) {
|
|
||||||
Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
|
|
||||||
Log.d(TAG, "Retrieved ringtone URI: " + uri);
|
|
||||||
// TODO: We'll have to create a new Alarm instance with this ringtone value
|
|
||||||
// because we don't have a setter method. Alternatively, write an independent
|
|
||||||
// SQL update statement updating COLUMN_RINGTONE.
|
|
||||||
}
|
|
||||||
|
|
||||||
// final Alarm alarm = data.getParcelableExtra(EditAlarmActivity.EXTRA_MODIFIED_ALARM);
|
|
||||||
// if (alarm == null)
|
|
||||||
// return;
|
|
||||||
//
|
|
||||||
// // http://stackoverflow.com/a/27055512/5055032
|
|
||||||
// // "RecyclerView does not run animations in the first layout
|
|
||||||
// // pass after being attached." A workaround is to postpone
|
|
||||||
// // the CRUD operation to the next frame. A delay of 300ms is
|
|
||||||
// // short enough to not be noticeable, and long enough to
|
|
||||||
// // give us the animation *most of the time*.
|
|
||||||
// switch (requestCode) {
|
|
||||||
// case REQUEST_CREATE_ALARM:
|
|
||||||
// mHandler.postDelayed(
|
|
||||||
// new AsyncAddItemRunnable(mAsyncUpdateHandler, alarm),
|
|
||||||
// 300);
|
|
||||||
// break;
|
|
||||||
// case REQUEST_EDIT_ALARM:
|
|
||||||
// if (data.getBooleanExtra(EditAlarmActivity.EXTRA_IS_DELETING, false)) {
|
|
||||||
// // TODO: Should we delay this too? It seems animations run
|
|
||||||
// // some of the time.
|
|
||||||
// mAsyncUpdateHandler.asyncDelete(alarm);
|
|
||||||
// } else {
|
|
||||||
// // TODO: Increase the delay, because update animation is
|
|
||||||
// // more elusive than insert.
|
|
||||||
// mHandler.postDelayed(
|
|
||||||
// new AsyncUpdateItemRunnable(mAsyncUpdateHandler, alarm),
|
|
||||||
// 300);
|
|
||||||
// }
|
|
||||||
// break;
|
|
||||||
// default:
|
|
||||||
// Log.i(TAG, "Could not handle request code " + requestCode);
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onListItemClick(Alarm item, int position) {
|
public void onListItemClick(Alarm item, int position) {
|
||||||
// Intent intent = new Intent(getActivity(), EditAlarmActivity.class);
|
|
||||||
// intent.putExtra(EditAlarmActivity.EXTRA_ALARM_ID, item.id());
|
|
||||||
// startActivityForResult(intent, REQUEST_EDIT_ALARM);
|
|
||||||
boolean expanded = getAdapter().expand(position);
|
boolean expanded = getAdapter().expand(position);
|
||||||
if (!expanded) {
|
if (!expanded) {
|
||||||
getAdapter().collapse(position);
|
getAdapter().collapse(position);
|
||||||
@ -210,7 +116,6 @@ public class AlarmsFragment extends RecyclerViewFragment<Alarm, BaseAlarmViewHol
|
|||||||
// to the AlarmsCursorAdapter and call these on the save and delete button click bindings.
|
// to the AlarmsCursorAdapter and call these on the save and delete button click bindings.
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
// TODO: Rename to onListItem***Delete*** because the item hasn't been deleted from our db yet
|
|
||||||
public void onListItemDeleted(final Alarm item) {
|
public void onListItemDeleted(final Alarm item) {
|
||||||
// The corresponding VH will be automatically removed from view following
|
// The corresponding VH will be automatically removed from view following
|
||||||
// the requery, so we don't have to do anything to it.
|
// the requery, so we don't have to do anything to it.
|
||||||
@ -223,9 +128,6 @@ public class AlarmsFragment extends RecyclerViewFragment<Alarm, BaseAlarmViewHol
|
|||||||
// be in view. While the requery will probably update the values displayed
|
// be in view. While the requery will probably update the values displayed
|
||||||
// by the VH, the VH remains in its expanded state from before we were
|
// by the VH, the VH remains in its expanded state from before we were
|
||||||
// called. Tell the adapter reset its expanded position.
|
// called. Tell the adapter reset its expanded position.
|
||||||
// TODO: Implement editing in the expanded VH. Then verify that changes
|
|
||||||
// while in that VH are saved and updated after the requery.
|
|
||||||
// getAdapter().collapse(position);
|
|
||||||
mAsyncUpdateHandler.asyncUpdate(item.getId(), item);
|
mAsyncUpdateHandler.asyncUpdate(item.getId(), item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,8 +135,6 @@ public class AlarmsFragment extends RecyclerViewFragment<Alarm, BaseAlarmViewHol
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onScrolledToStableId(long id, int position) {
|
protected void onScrolledToStableId(long id, int position) {
|
||||||
// We were called because of a requery. If it was due to an insertion,
|
|
||||||
// expand the newly added alarm.
|
|
||||||
boolean expanded = getAdapter().expand(position);
|
boolean expanded = getAdapter().expand(position);
|
||||||
if (!expanded) {
|
if (!expanded) {
|
||||||
// Otherwise, it was due to an item update. The VH is expanded
|
// Otherwise, it was due to an item update. The VH is expanded
|
||||||
@ -300,65 +200,4 @@ public class AlarmsFragment extends RecyclerViewFragment<Alarm, BaseAlarmViewHol
|
|||||||
private static String makeTimePickerDialogTag() {
|
private static String makeTimePickerDialogTag() {
|
||||||
return makeTag(AlarmsFragment.class, R.id.fab);
|
return makeTag(AlarmsFragment.class, R.id.fab);
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// TODO: We won't need these anymore, since we won't handle the db
|
|
||||||
// update in onActivityResult() anymore.
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
private static abstract class BaseAsyncItemChangeRunnable {
|
|
||||||
// TODO: Will holding onto this cause a memory leak?
|
|
||||||
private final AsyncAlarmsTableUpdateHandler mAsyncAlarmsTableUpdateHandler;
|
|
||||||
private final Alarm mAlarm;
|
|
||||||
|
|
||||||
BaseAsyncItemChangeRunnable(AsyncAlarmsTableUpdateHandler asyncAlarmsTableUpdateHandler, Alarm alarm) {
|
|
||||||
mAsyncAlarmsTableUpdateHandler = asyncAlarmsTableUpdateHandler;
|
|
||||||
mAlarm = alarm;
|
|
||||||
}
|
|
||||||
|
|
||||||
void asyncAddAlarm() {
|
|
||||||
mAsyncAlarmsTableUpdateHandler.asyncInsert(mAlarm);
|
|
||||||
}
|
|
||||||
|
|
||||||
void asyncUpdateAlarm() {
|
|
||||||
mAsyncAlarmsTableUpdateHandler.asyncUpdate(mAlarm.getId(), mAlarm);
|
|
||||||
}
|
|
||||||
|
|
||||||
void asyncRemoveAlarm() {
|
|
||||||
mAsyncAlarmsTableUpdateHandler.asyncDelete(mAlarm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class AsyncAddItemRunnable extends BaseAsyncItemChangeRunnable implements Runnable {
|
|
||||||
AsyncAddItemRunnable(AsyncAlarmsTableUpdateHandler asyncAlarmsTableUpdateHandler, Alarm alarm) {
|
|
||||||
super(asyncAlarmsTableUpdateHandler, alarm);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
asyncAddAlarm();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class AsyncUpdateItemRunnable extends BaseAsyncItemChangeRunnable implements Runnable {
|
|
||||||
AsyncUpdateItemRunnable(AsyncAlarmsTableUpdateHandler asyncAlarmsTableUpdateHandler, Alarm alarm) {
|
|
||||||
super(asyncAlarmsTableUpdateHandler, alarm);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
asyncUpdateAlarm();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class AsyncRemoveItemRunnable extends BaseAsyncItemChangeRunnable implements Runnable {
|
|
||||||
AsyncRemoveItemRunnable(AsyncAlarmsTableUpdateHandler asyncAlarmsTableUpdateHandler, Alarm alarm) {
|
|
||||||
super(asyncAlarmsTableUpdateHandler, alarm);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
asyncRemoveAlarm();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -140,7 +140,8 @@ public abstract class RecyclerViewFragment<
|
|||||||
}
|
}
|
||||||
// This may have been a requery due to content change. If the change
|
// This may have been a requery due to content change. If the change
|
||||||
// was an insertion, scroll to the last modified alarm.
|
// was an insertion, scroll to the last modified alarm.
|
||||||
performScrollToStableId();
|
performScrollToStableId(mScrollToStableId);
|
||||||
|
mScrollToStableId = RecyclerView.NO_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -167,21 +168,19 @@ public abstract class RecyclerViewFragment<
|
|||||||
mList.smoothScrollToPosition(position);
|
mList.smoothScrollToPosition(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void performScrollToStableId() {
|
protected final void performScrollToStableId(long stableId) {
|
||||||
if (mScrollToStableId != RecyclerView.NO_ID) {
|
if (stableId != RecyclerView.NO_ID) {
|
||||||
int position = -1;
|
int position = -1;
|
||||||
for (int i = 0; i < mAdapter.getItemCount(); i++) {
|
for (int i = 0; i < mAdapter.getItemCount(); i++) {
|
||||||
if (mAdapter.getItemId(i) == mScrollToStableId) {
|
if (mAdapter.getItemId(i) == stableId) {
|
||||||
position = i;
|
position = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (position >= 0) {
|
if (position >= 0) {
|
||||||
scrollToPosition(position);
|
scrollToPosition(position);
|
||||||
onScrolledToStableId(mScrollToStableId, position);
|
onScrolledToStableId(stableId, position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Reset
|
|
||||||
mScrollToStableId = RecyclerView.NO_ID;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user