From 90bdbf250539f26f3c8931be324a2278e184af3c Mon Sep 17 00:00:00 2001 From: Phillip Hsu Date: Fri, 16 Sep 2016 02:26:43 -0700 Subject: [PATCH] Restore current lap when StopwatchNotificationService is restarted. Change add lap icon fillColor to white. --- .../clock2/AsyncAlarmsTableUpdateHandler.java | 2 +- .../AsyncDatabaseTableUpdateHandler.java | 11 ++-- .../clock2/AsyncTimersTableUpdateHandler.java | 2 +- .../AsyncLapsTableUpdateHandler.java | 2 +- .../clock2/stopwatch/LapsTableManager.java | 10 ++++ .../StopwatchNotificationService.java | 51 ++++++++++++------- app/src/main/res/drawable/ic_add_lap_24dp.xml | 2 +- 7 files changed, 52 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/com/philliphsu/clock2/AsyncAlarmsTableUpdateHandler.java b/app/src/main/java/com/philliphsu/clock2/AsyncAlarmsTableUpdateHandler.java index 15dcee4..e4c2333 100644 --- a/app/src/main/java/com/philliphsu/clock2/AsyncAlarmsTableUpdateHandler.java +++ b/app/src/main/java/com/philliphsu/clock2/AsyncAlarmsTableUpdateHandler.java @@ -31,7 +31,7 @@ public final class AsyncAlarmsTableUpdateHandler extends AsyncDatabaseTableUpdat } @Override - protected AlarmsTableManager getTableManager(Context context) { + protected AlarmsTableManager onCreateTableManager(Context context) { return new AlarmsTableManager(context); } diff --git a/app/src/main/java/com/philliphsu/clock2/AsyncDatabaseTableUpdateHandler.java b/app/src/main/java/com/philliphsu/clock2/AsyncDatabaseTableUpdateHandler.java index b24f924..56e9cf3 100644 --- a/app/src/main/java/com/philliphsu/clock2/AsyncDatabaseTableUpdateHandler.java +++ b/app/src/main/java/com/philliphsu/clock2/AsyncDatabaseTableUpdateHandler.java @@ -25,7 +25,7 @@ public abstract class AsyncDatabaseTableUpdateHandler< public AsyncDatabaseTableUpdateHandler(Context context, ScrollHandler scrollHandler) { mAppContext = context.getApplicationContext(); // to prevent memory leaks mScrollHandler = scrollHandler; - mTableManager = getTableManager(context); + mTableManager = onCreateTableManager(context); } public final void asyncInsert(final T item) { @@ -63,14 +63,15 @@ public abstract class AsyncDatabaseTableUpdateHandler< }.execute(); } + public final TM getTableManager() { + return mTableManager; + } + protected final Context getContext() { return mAppContext; } - // TODO: Consider giving a base impl that returns our mTableManager field. - // 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 TM onCreateTableManager(Context context); protected abstract void onPostAsyncDelete(Integer result, T item); diff --git a/app/src/main/java/com/philliphsu/clock2/AsyncTimersTableUpdateHandler.java b/app/src/main/java/com/philliphsu/clock2/AsyncTimersTableUpdateHandler.java index 0f034fa..8ef2a12 100644 --- a/app/src/main/java/com/philliphsu/clock2/AsyncTimersTableUpdateHandler.java +++ b/app/src/main/java/com/philliphsu/clock2/AsyncTimersTableUpdateHandler.java @@ -23,7 +23,7 @@ public final class AsyncTimersTableUpdateHandler extends AsyncDatabaseTableUpdat } @Override - protected TimersTableManager getTableManager(Context context) { + protected TimersTableManager onCreateTableManager(Context context) { return new TimersTableManager(context); } diff --git a/app/src/main/java/com/philliphsu/clock2/stopwatch/AsyncLapsTableUpdateHandler.java b/app/src/main/java/com/philliphsu/clock2/stopwatch/AsyncLapsTableUpdateHandler.java index fed3edd..c1ccf27 100644 --- a/app/src/main/java/com/philliphsu/clock2/stopwatch/AsyncLapsTableUpdateHandler.java +++ b/app/src/main/java/com/philliphsu/clock2/stopwatch/AsyncLapsTableUpdateHandler.java @@ -16,7 +16,7 @@ public class AsyncLapsTableUpdateHandler extends AsyncDatabaseTableUpdateHandler } @Override - protected LapsTableManager getTableManager(Context context) { + protected LapsTableManager onCreateTableManager(Context context) { return new LapsTableManager(context); } diff --git a/app/src/main/java/com/philliphsu/clock2/stopwatch/LapsTableManager.java b/app/src/main/java/com/philliphsu/clock2/stopwatch/LapsTableManager.java index dd988be..6836a64 100644 --- a/app/src/main/java/com/philliphsu/clock2/stopwatch/LapsTableManager.java +++ b/app/src/main/java/com/philliphsu/clock2/stopwatch/LapsTableManager.java @@ -43,6 +43,16 @@ public class LapsTableManager extends DatabaseTableManager { // 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 protected String getTableName() { return LapsTable.TABLE_LAPS; diff --git a/app/src/main/java/com/philliphsu/clock2/stopwatch/StopwatchNotificationService.java b/app/src/main/java/com/philliphsu/clock2/stopwatch/StopwatchNotificationService.java index 7b97ea1..5ee0046 100644 --- a/app/src/main/java/com/philliphsu/clock2/stopwatch/StopwatchNotificationService.java +++ b/app/src/main/java/com/philliphsu/clock2/stopwatch/StopwatchNotificationService.java @@ -32,10 +32,9 @@ public class StopwatchNotificationService extends ChronometerNotificationService super.onCreate(); mUpdateHandler = new AsyncLapsTableUpdateHandler(this, null); 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.setShowCentiseconds(true, false); + setContentTitle(getString(R.string.stopwatch)); // TODO: I think we can make this a foreground service so even // 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 // had ended previously. if (intent == null) { - // Start the ticking again, leaving everything else in the notification - // as it was. 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, // 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(); mUpdateHandler.asyncInsert(mCurrentLap); } - // TODO: String resource [Stopwatch: Lap %1$s]. If no laps, just [Stopwatch] - setContentTitle(getString(R.string.stopwatch)); syncNotificationWithStopwatchState(true/*always true*/); // 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. @@ -175,10 +190,6 @@ public class StopwatchNotificationService extends ChronometerNotificationService private void syncNotificationWithStopwatchState(boolean running) { 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. addAction(ACTION_ADD_LAP, R.drawable.ic_add_lap_24dp, getString(R.string.lap), 0); addStartPauseAction(running, 0); @@ -186,15 +197,17 @@ public class StopwatchNotificationService extends ChronometerNotificationService quitCurrentThread(); 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. - */ - private void 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. +// */ +// private void startChronometer() { +// long startTime = mPrefs.getLong(StopwatchFragment.KEY_START_TIME, SystemClock.elapsedRealtime()); +// startNewThread(0, startTime); +// } } diff --git a/app/src/main/res/drawable/ic_add_lap_24dp.xml b/app/src/main/res/drawable/ic_add_lap_24dp.xml index d13ac4e..d4a2324 100644 --- a/app/src/main/res/drawable/ic_add_lap_24dp.xml +++ b/app/src/main/res/drawable/ic_add_lap_24dp.xml @@ -5,5 +5,5 @@ android:width="24dp" android:viewportWidth="24" android:viewportHeight="24"> - + \ No newline at end of file