Restore current lap when StopwatchNotificationService is restarted. Change add lap icon fillColor to white.

This commit is contained in:
Phillip Hsu 2016-09-16 02:26:43 -07:00
parent 698892419b
commit 90bdbf2505
7 changed files with 52 additions and 28 deletions

View File

@ -31,7 +31,7 @@ public final class AsyncAlarmsTableUpdateHandler extends AsyncDatabaseTableUpdat
} }
@Override @Override
protected AlarmsTableManager getTableManager(Context context) { protected AlarmsTableManager onCreateTableManager(Context context) {
return new AlarmsTableManager(context); return new AlarmsTableManager(context);
} }

View File

@ -25,7 +25,7 @@ public abstract class AsyncDatabaseTableUpdateHandler<
public AsyncDatabaseTableUpdateHandler(Context context, ScrollHandler scrollHandler) { public AsyncDatabaseTableUpdateHandler(Context context, ScrollHandler scrollHandler) {
mAppContext = context.getApplicationContext(); // to prevent memory leaks mAppContext = context.getApplicationContext(); // to prevent memory leaks
mScrollHandler = scrollHandler; mScrollHandler = scrollHandler;
mTableManager = getTableManager(context); mTableManager = onCreateTableManager(context);
} }
public final void asyncInsert(final T item) { public final void asyncInsert(final T item) {
@ -63,14 +63,15 @@ public abstract class AsyncDatabaseTableUpdateHandler<
}.execute(); }.execute();
} }
public final TM getTableManager() {
return mTableManager;
}
protected final Context getContext() { protected final Context getContext() {
return mAppContext; return mAppContext;
} }
// TODO: Consider giving a base impl that returns our mTableManager field. protected abstract TM onCreateTableManager(Context context);
// Subclasses will check if this base impl is null before creating and returning
// a new instance of the TableManager.
protected abstract TM getTableManager(Context context);
protected abstract void onPostAsyncDelete(Integer result, T item); protected abstract void onPostAsyncDelete(Integer result, T item);

View File

@ -23,7 +23,7 @@ public final class AsyncTimersTableUpdateHandler extends AsyncDatabaseTableUpdat
} }
@Override @Override
protected TimersTableManager getTableManager(Context context) { protected TimersTableManager onCreateTableManager(Context context) {
return new TimersTableManager(context); return new TimersTableManager(context);
} }

View File

@ -16,7 +16,7 @@ public class AsyncLapsTableUpdateHandler extends AsyncDatabaseTableUpdateHandler
} }
@Override @Override
protected LapsTableManager getTableManager(Context context) { protected LapsTableManager onCreateTableManager(Context context) {
return new LapsTableManager(context); return new LapsTableManager(context);
} }

View File

@ -43,6 +43,16 @@ public class LapsTableManager extends DatabaseTableManager<Lap> {
// return cursor; // return cursor;
// } // }
public LapCursor queryCurrentLap() {
// The default sort order for the laps table is ID descending.
// Normally, not specifying a where clause would return all rows.
// Here, we limit the result to 1.
// This has the effect of retrieving the row with the highest ID value.
LapCursor c = queryItems(null, "1");
c.moveToFirst();
return c;
}
@Override @Override
protected String getTableName() { protected String getTableName() {
return LapsTable.TABLE_LAPS; return LapsTable.TABLE_LAPS;

View File

@ -32,10 +32,9 @@ public class StopwatchNotificationService extends ChronometerNotificationService
super.onCreate(); super.onCreate();
mUpdateHandler = new AsyncLapsTableUpdateHandler(this, null); mUpdateHandler = new AsyncLapsTableUpdateHandler(this, null);
mPrefs = PreferenceManager.getDefaultSharedPreferences(this); mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
// TODO: I'm afraid the base time here will be off by a considerable amount from the base time
// set in StopwatchFragment.
mDelegate.init(); mDelegate.init();
mDelegate.setShowCentiseconds(true, false); mDelegate.setShowCentiseconds(true, false);
setContentTitle(getString(R.string.stopwatch));
// TODO: I think we can make this a foreground service so even // TODO: I think we can make this a foreground service so even
// if the process is killed, this service remains alive. // if the process is killed, this service remains alive.
} }
@ -46,10 +45,28 @@ public class StopwatchNotificationService extends ChronometerNotificationService
// signifies that the service is being recreated after its process // signifies that the service is being recreated after its process
// had ended previously. // had ended previously.
if (intent == null) { if (intent == null) {
// Start the ticking again, leaving everything else in the notification
// as it was.
Log.d(TAG, "Recreated service, starting chronometer again."); Log.d(TAG, "Recreated service, starting chronometer again.");
startChronometer(); // Restore the current lap
new Thread(new Runnable() {
@Override
public void run() {
// If the service is being restarted, there is AT LEAST one lap in the table.
// This is the first lap that was inserted when the service was first started.
// The Cursor has already been moved to its first row.
mCurrentLap = mUpdateHandler.getTableManager().queryCurrentLap().getItem();
Log.d(TAG, "Restored current lap " + mCurrentLap);
}
}).start();
// Start the ticking again from where we left off.
// The default actions will be set on the Builder.
//
// For simplicity, even if there were laps
// in this stopwatch before the process was destroyed, we won't be restoring
// the lap number in the title. If the user is leaving this service in the background
// long enough that the system can kill its process, they probably aren't
// recording laps. As such, a solution for this is a waste of time.
boolean running = mPrefs.getBoolean(StopwatchFragment.KEY_CHRONOMETER_RUNNING, false);
syncNotificationWithStopwatchState(running);
} }
// If this service is being recreated and the above if-block called through, // If this service is being recreated and the above if-block called through,
// then the call to super won't run any commands, because it will see // then the call to super won't run any commands, because it will see
@ -93,8 +110,6 @@ public class StopwatchNotificationService extends ChronometerNotificationService
mCurrentLap = new Lap(); mCurrentLap = new Lap();
mUpdateHandler.asyncInsert(mCurrentLap); mUpdateHandler.asyncInsert(mCurrentLap);
} }
// TODO: String resource [Stopwatch: Lap %1$s]. If no laps, just [Stopwatch]
setContentTitle(getString(R.string.stopwatch));
syncNotificationWithStopwatchState(true/*always true*/); syncNotificationWithStopwatchState(true/*always true*/);
// We don't need to write anything to SharedPrefs because if we're here, StopwatchFragment // We don't need to write anything to SharedPrefs because if we're here, StopwatchFragment
// will start this service again with ACTION_START_PAUSE, which will do the writing. // will start this service again with ACTION_START_PAUSE, which will do the writing.
@ -175,10 +190,6 @@ public class StopwatchNotificationService extends ChronometerNotificationService
private void syncNotificationWithStopwatchState(boolean running) { private void syncNotificationWithStopwatchState(boolean running) {
clearActions(); clearActions();
// TODO: Change fillColor to white, to accommodate API < 21.
// Apparently, notifications on 21+ are automatically
// tinted to gray to contrast against the native notification background color.
//
// No request code needed, so use 0. // No request code needed, so use 0.
addAction(ACTION_ADD_LAP, R.drawable.ic_add_lap_24dp, getString(R.string.lap), 0); addAction(ACTION_ADD_LAP, R.drawable.ic_add_lap_24dp, getString(R.string.lap), 0);
addStartPauseAction(running, 0); addStartPauseAction(running, 0);
@ -186,15 +197,17 @@ public class StopwatchNotificationService extends ChronometerNotificationService
quitCurrentThread(); quitCurrentThread();
if (running) { if (running) {
startChronometer(); // startChronometer();
long startTime = mPrefs.getLong(StopwatchFragment.KEY_START_TIME, SystemClock.elapsedRealtime());
startNewThread(0, startTime);
} }
} }
/** // /**
* Reads the value of KEY_START_TIME and passes it to {@link #startNewThread(int, long)} for you. // * Reads the value of KEY_START_TIME and passes it to {@link #startNewThread(int, long)} for you.
*/ // */
private void startChronometer() { // private void startChronometer() {
long startTime = mPrefs.getLong(StopwatchFragment.KEY_START_TIME, SystemClock.elapsedRealtime()); // long startTime = mPrefs.getLong(StopwatchFragment.KEY_START_TIME, SystemClock.elapsedRealtime());
startNewThread(0, startTime); // startNewThread(0, startTime);
} // }
} }

View File

@ -5,5 +5,5 @@
android:width="24dp" android:width="24dp"
android:viewportWidth="24" android:viewportWidth="24"
android:viewportHeight="24"> android:viewportHeight="24">
<path android:fillColor="#FF000000" android:pathData="M6,3A1,1 0 0,1 7,4V4.88C8.06,4.44 9.5,4 11,4C14,4 14,6 16,6C19,6 20,4 20,4V12C20,12 19,14 16,14C13,14 13,12 11,12C8,12 7,14 7,14V21H5V4A1,1 0 0,1 6,3Z" /> <path android:fillColor="#FFFFFF" android:pathData="M6,3A1,1 0 0,1 7,4V4.88C8.06,4.44 9.5,4 11,4C14,4 14,6 16,6C19,6 20,4 20,4V12C20,12 19,14 16,14C13,14 13,12 11,12C8,12 7,14 7,14V21H5V4A1,1 0 0,1 6,3Z" />
</vector> </vector>