Removed unnecessary classes. Implement handling start/pause action in StopwatchNotificationService.
This commit is contained in:
parent
d6eeac1db1
commit
81e8e0b1ad
@ -135,7 +135,7 @@ public abstract class ChronometerNotificationService extends Service {
|
|||||||
// Display any notification updates associated with the current state
|
// Display any notification updates associated with the current state
|
||||||
// of the chronometer. If we relied on the HandlerThread to do this for us,
|
// of the chronometer. If we relied on the HandlerThread to do this for us,
|
||||||
// the message delivery would be delayed.
|
// the message delivery would be delayed.
|
||||||
mThread.updateNotification();
|
mThread.updateNotification(false/*updateText*/);
|
||||||
// If the chronometer has been set to not run, the effect is obvious.
|
// If the chronometer has been set to not run, the effect is obvious.
|
||||||
// Otherwise, we're preparing for the start of a new thread.
|
// Otherwise, we're preparing for the start of a new thread.
|
||||||
quitThread();
|
quitThread();
|
||||||
@ -214,8 +214,8 @@ public abstract class ChronometerNotificationService extends Service {
|
|||||||
return mDelegate.getBase();
|
return mDelegate.getBase();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final void updateNotification() {
|
protected final void updateNotification(boolean updateText) {
|
||||||
mThread.updateNotification();
|
mThread.updateNotification(updateText);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final void setContentTitle(CharSequence title) {
|
protected final void setContentTitle(CharSequence title) {
|
||||||
|
|||||||
@ -75,7 +75,7 @@ public class ChronometerNotificationThread extends HandlerThread {
|
|||||||
mHandler = new Handler() {
|
mHandler = new Handler() {
|
||||||
@Override
|
@Override
|
||||||
public void handleMessage(Message m) {
|
public void handleMessage(Message m) {
|
||||||
updateNotification();
|
updateNotification(true);
|
||||||
sendMessageDelayed(Message.obtain(this, MSG_WHAT), 1000);
|
sendMessageDelayed(Message.obtain(this, MSG_WHAT), 1000);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -83,9 +83,16 @@ public class ChronometerNotificationThread extends HandlerThread {
|
|||||||
mHandler.sendMessageDelayed(Message.obtain(mHandler, MSG_WHAT), 1000);
|
mHandler.sendMessageDelayed(Message.obtain(mHandler, MSG_WHAT), 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateNotification() {
|
/**
|
||||||
CharSequence text = mDelegate.formatElapsedTime(SystemClock.elapsedRealtime(), mResources);
|
* @param updateText whether the new notification should update its chronometer.
|
||||||
mNoteBuilder.setContentText(text);
|
* Use {@code false} if you are updating everything else about the notification,
|
||||||
|
* e.g. you just want to refresh the actions due to a start/pause state change.
|
||||||
|
*/
|
||||||
|
public void updateNotification(boolean updateText) {
|
||||||
|
if (updateText) {
|
||||||
|
CharSequence text = mDelegate.formatElapsedTime(SystemClock.elapsedRealtime(), mResources);
|
||||||
|
mNoteBuilder.setContentText(text);
|
||||||
|
}
|
||||||
mNotificationManager.notify(mNoteTag, mNoteId, mNoteBuilder.build());
|
mNotificationManager.notify(mNoteTag, mNoteId, mNoteBuilder.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,92 +0,0 @@
|
|||||||
package com.philliphsu.clock2.stopwatch;
|
|
||||||
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by Phillip Hsu on 9/11/2016.
|
|
||||||
*/
|
|
||||||
public abstract class BaseStopwatchController { // TODO: Extend this for use in StopwatchFragment and StopwatchNotificationSErvice
|
|
||||||
// TODO: EIther expose these to subclasses or write an API for them to call
|
|
||||||
// to write to prefs.
|
|
||||||
private static final String KEY_START_TIME = "start_time";
|
|
||||||
private static final String KEY_PAUSE_TIME = "pause_time";
|
|
||||||
private static final String KEY_RUNNING = "running";
|
|
||||||
|
|
||||||
private final AsyncLapsTableUpdateHandler mUpdateHandler;
|
|
||||||
private final SharedPreferences mPrefs;
|
|
||||||
|
|
||||||
private Stopwatch mStopwatch;
|
|
||||||
private Lap mCurrentLap;
|
|
||||||
private Lap mPreviousLap;
|
|
||||||
|
|
||||||
public BaseStopwatchController(@NonNull AsyncLapsTableUpdateHandler updateHandler,
|
|
||||||
@NonNull SharedPreferences prefs) {
|
|
||||||
mUpdateHandler = updateHandler;
|
|
||||||
mPrefs = prefs;
|
|
||||||
long startTime = mPrefs.getLong(KEY_START_TIME, 0);
|
|
||||||
long pauseTime = mPrefs.getLong(KEY_PAUSE_TIME, 0);
|
|
||||||
mStopwatch = new Stopwatch(startTime, pauseTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void run() {
|
|
||||||
if (!mStopwatch.hasStarted()) {
|
|
||||||
// addNewLap() won't call through unless chronometer is running, which
|
|
||||||
// we can't start until we compute mStartTime
|
|
||||||
mCurrentLap = new Lap();
|
|
||||||
mUpdateHandler.asyncInsert(mCurrentLap);
|
|
||||||
}
|
|
||||||
mStopwatch.run();
|
|
||||||
if (!mCurrentLap.isRunning()) {
|
|
||||||
mCurrentLap.resume();
|
|
||||||
mUpdateHandler.asyncUpdate(mCurrentLap.getId(), mCurrentLap);
|
|
||||||
}
|
|
||||||
savePrefs();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void pause() {
|
|
||||||
mStopwatch.pause();
|
|
||||||
mCurrentLap.pause();
|
|
||||||
mUpdateHandler.asyncUpdate(mCurrentLap.getId(), mCurrentLap);
|
|
||||||
savePrefs();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stop() {
|
|
||||||
mStopwatch.stop();
|
|
||||||
mCurrentLap = null;
|
|
||||||
mPreviousLap = null;
|
|
||||||
mUpdateHandler.asyncClear(); // Clear laps
|
|
||||||
savePrefs();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addNewLap(String currentLapTotalText) {
|
|
||||||
if (mCurrentLap != null) {
|
|
||||||
mCurrentLap.end(currentLapTotalText);
|
|
||||||
}
|
|
||||||
mPreviousLap = mCurrentLap;
|
|
||||||
mCurrentLap = new Lap();
|
|
||||||
if (mPreviousLap != null) {
|
|
||||||
// if (getAdapter().getItemCount() == 0) {
|
|
||||||
// mUpdateHandler.asyncInsert(mPreviousLap);
|
|
||||||
// } else {
|
|
||||||
mUpdateHandler.asyncUpdate(mPreviousLap.getId(), mPreviousLap);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
mUpdateHandler.asyncInsert(mCurrentLap);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final Stopwatch getStopwatch() {
|
|
||||||
return mStopwatch;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isStopwatchRunning() {
|
|
||||||
return mPrefs.getBoolean(KEY_RUNNING, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void savePrefs() {
|
|
||||||
mPrefs.edit().putLong(KEY_START_TIME, mStopwatch.getStartTime())
|
|
||||||
.putLong(KEY_PAUSE_TIME, mStopwatch.getPauseTime())
|
|
||||||
.putBoolean(KEY_RUNNING, mStopwatch.isRunning())
|
|
||||||
.apply();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,55 +0,0 @@
|
|||||||
package com.philliphsu.clock2.stopwatch;
|
|
||||||
|
|
||||||
import android.os.SystemClock;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by Phillip Hsu on 9/11/2016.
|
|
||||||
*/
|
|
||||||
public final class Stopwatch {
|
|
||||||
private static final String TAG = "Stopwatch";
|
|
||||||
|
|
||||||
private long mStartTime;
|
|
||||||
private long mPauseTime;
|
|
||||||
|
|
||||||
public Stopwatch(long startTime, long pauseTime) {
|
|
||||||
mStartTime = startTime;
|
|
||||||
mPauseTime = pauseTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void pause() {
|
|
||||||
if (!isRunning())
|
|
||||||
throw new IllegalStateException("This stopwatch cannot be paused because it is not running");
|
|
||||||
if (mPauseTime > 0)
|
|
||||||
throw new IllegalStateException("This stopwatch is already paused");
|
|
||||||
mPauseTime = SystemClock.elapsedRealtime();
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void run() {
|
|
||||||
if (isRunning())
|
|
||||||
throw new IllegalStateException("This stopwatch is already running");
|
|
||||||
mStartTime += SystemClock.elapsedRealtime() - mPauseTime;
|
|
||||||
mPauseTime = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void stop() {
|
|
||||||
mStartTime = 0;
|
|
||||||
mPauseTime = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getStartTime() {
|
|
||||||
return mStartTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getPauseTime() {
|
|
||||||
return mPauseTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRunning() {
|
|
||||||
return hasStarted() && mPauseTime == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasStarted() {
|
|
||||||
// Not required to be presently running to have been started
|
|
||||||
return mStartTime > 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -6,6 +6,7 @@ import android.content.Intent;
|
|||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.SystemClock;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.design.widget.FloatingActionButton;
|
import android.support.design.widget.FloatingActionButton;
|
||||||
@ -36,17 +37,22 @@ public class StopwatchFragment extends RecyclerViewFragment<
|
|||||||
LapsAdapter> {
|
LapsAdapter> {
|
||||||
private static final String TAG = "StopwatchFragment";
|
private static final String TAG = "StopwatchFragment";
|
||||||
|
|
||||||
|
// Exposed for StopwatchNotificationService
|
||||||
|
static final String KEY_START_TIME = "start_time";
|
||||||
|
static final String KEY_PAUSE_TIME = "pause_time";
|
||||||
|
static final String KEY_CHRONOMETER_RUNNING = "chronometer_running";
|
||||||
|
|
||||||
|
private long mStartTime;
|
||||||
|
private long mPauseTime;
|
||||||
|
private Lap mCurrentLap;
|
||||||
|
private Lap mPreviousLap;
|
||||||
|
|
||||||
|
private AsyncLapsTableUpdateHandler mUpdateHandler;
|
||||||
private ObjectAnimator mProgressAnimator;
|
private ObjectAnimator mProgressAnimator;
|
||||||
|
private SharedPreferences mPrefs;
|
||||||
private WeakReference<FloatingActionButton> mActivityFab;
|
private WeakReference<FloatingActionButton> mActivityFab;
|
||||||
private Drawable mStartDrawable;
|
private Drawable mStartDrawable;
|
||||||
private Drawable mPauseDrawable;
|
private Drawable mPauseDrawable;
|
||||||
// TODO: Actual subclass
|
|
||||||
private BaseStopwatchController mController;
|
|
||||||
|
|
||||||
// For read-only purposes within this Fragment.
|
|
||||||
// Actual changes are persisted by the controller.
|
|
||||||
private Lap mCurrentLap;
|
|
||||||
private Lap mPreviousLap;
|
|
||||||
|
|
||||||
@Bind(R.id.chronometer) ChronometerWithMillis mChronometer;
|
@Bind(R.id.chronometer) ChronometerWithMillis mChronometer;
|
||||||
@Bind(R.id.new_lap) FloatingActionButton mNewLapButton;
|
@Bind(R.id.new_lap) FloatingActionButton mNewLapButton;
|
||||||
@ -61,6 +67,12 @@ public class StopwatchFragment extends RecyclerViewFragment<
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
mUpdateHandler = new AsyncLapsTableUpdateHandler(getActivity(), null/*we shouldn't need a scroll handler*/);
|
||||||
|
mPrefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
||||||
|
mStartTime = mPrefs.getLong(KEY_START_TIME, 0);
|
||||||
|
mPauseTime = mPrefs.getLong(KEY_PAUSE_TIME, 0);
|
||||||
|
Log.d(TAG, "mStartTime = " + mStartTime
|
||||||
|
+ ", mPauseTime = " + mPauseTime);
|
||||||
// TODO: Will these be kept alive after onDestroyView()? If not, we should move these to
|
// TODO: Will these be kept alive after onDestroyView()? If not, we should move these to
|
||||||
// onCreateView() or any other callback that is guaranteed to be called.
|
// onCreateView() or any other callback that is guaranteed to be called.
|
||||||
mStartDrawable = ContextCompat.getDrawable(getActivity(), R.drawable.ic_start_24dp);
|
mStartDrawable = ContextCompat.getDrawable(getActivity(), R.drawable.ic_start_24dp);
|
||||||
@ -73,13 +85,21 @@ public class StopwatchFragment extends RecyclerViewFragment<
|
|||||||
Log.d(TAG, "onCreateView()");
|
Log.d(TAG, "onCreateView()");
|
||||||
View view = super.onCreateView(inflater, container, savedInstanceState);
|
View view = super.onCreateView(inflater, container, savedInstanceState);
|
||||||
|
|
||||||
AsyncLapsTableUpdateHandler updateHandler = new AsyncLapsTableUpdateHandler(
|
mChronometer.setShowCentiseconds(true, true);
|
||||||
getActivity(), null/*we shouldn't need a scroll handler*/);
|
if (mStartTime > 0) {
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
long base = mStartTime;
|
||||||
// This can't be initialized until the layout is inflated, because we need the
|
if (mPauseTime > 0) {
|
||||||
// mChronometer reference for the controller.
|
base += SystemClock.elapsedRealtime() - mPauseTime;
|
||||||
mController = new StopwatchViewController(updateHandler, prefs, mChronometer);
|
// We're not done pausing yet, so don't reset mPauseTime.
|
||||||
|
}
|
||||||
|
mChronometer.setBase(base);
|
||||||
|
}
|
||||||
|
if (isStopwatchRunning()) {
|
||||||
|
mChronometer.start();
|
||||||
|
// Note: mChronometer.isRunning() will return false at this point and
|
||||||
|
// in other upcoming lifecycle methods because it is not yet visible
|
||||||
|
// (i.e. mVisible == false).
|
||||||
|
}
|
||||||
// The primary reason we call this is to show the mini FABs after rotate,
|
// The primary reason we call this is to show the mini FABs after rotate,
|
||||||
// if the stopwatch is running. If the stopwatch is stopped, then this
|
// if the stopwatch is running. If the stopwatch is stopped, then this
|
||||||
// would have hidden the mini FABs, if not for us already setting its
|
// would have hidden the mini FABs, if not for us already setting its
|
||||||
@ -138,6 +158,9 @@ public class StopwatchFragment extends RecyclerViewFragment<
|
|||||||
if (mProgressAnimator != null) {
|
if (mProgressAnimator != null) {
|
||||||
mProgressAnimator.removeAllListeners();
|
mProgressAnimator.removeAllListeners();
|
||||||
}
|
}
|
||||||
|
Log.d(TAG, "onDestroyView()");
|
||||||
|
Log.d(TAG, "mStartTime = " + mStartTime
|
||||||
|
+ ", mPauseTime = " + mPauseTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -180,8 +203,7 @@ public class StopwatchFragment extends RecyclerViewFragment<
|
|||||||
//
|
//
|
||||||
// NOTE: If we just recreated ourselves due to rotation, mChronometer.isRunning() == false,
|
// NOTE: If we just recreated ourselves due to rotation, mChronometer.isRunning() == false,
|
||||||
// because it is not yet visible (i.e. mVisible == false).
|
// because it is not yet visible (i.e. mVisible == false).
|
||||||
if (mController.isStopwatchRunning()) {
|
if (isStopwatchRunning()) {
|
||||||
// TODO: I think we should just pass in the two laps as local params
|
|
||||||
startNewProgressBarAnimator();
|
startNewProgressBarAnimator();
|
||||||
} else {
|
} else {
|
||||||
// I verified the bar was visible already without this, so we probably don't need this,
|
// I verified the bar was visible already without this, so we probably don't need this,
|
||||||
@ -198,7 +220,10 @@ public class StopwatchFragment extends RecyclerViewFragment<
|
|||||||
@Override
|
@Override
|
||||||
public void onFabClick() {
|
public void onFabClick() {
|
||||||
if (mChronometer.isRunning()) {
|
if (mChronometer.isRunning()) {
|
||||||
mController.pause();
|
mPauseTime = SystemClock.elapsedRealtime();
|
||||||
|
mChronometer.stop();
|
||||||
|
mCurrentLap.pause();
|
||||||
|
mUpdateHandler.asyncUpdate(mCurrentLap.getId(), mCurrentLap);
|
||||||
// No issues controlling the animator here, because onLoadFinished() can't
|
// No issues controlling the animator here, because onLoadFinished() can't
|
||||||
// call through to startNewProgressBarAnimator(), because by that point
|
// call through to startNewProgressBarAnimator(), because by that point
|
||||||
// the chronometer won't be running.
|
// the chronometer won't be running.
|
||||||
@ -209,7 +234,20 @@ public class StopwatchFragment extends RecyclerViewFragment<
|
|||||||
mProgressAnimator.cancel();
|
mProgressAnimator.cancel();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mController.run();
|
if (mStartTime == 0) {
|
||||||
|
// addNewLap() won't call through unless chronometer is running, which
|
||||||
|
// we can't start until we compute mStartTime
|
||||||
|
mCurrentLap = new Lap();
|
||||||
|
mUpdateHandler.asyncInsert(mCurrentLap);
|
||||||
|
}
|
||||||
|
mStartTime += SystemClock.elapsedRealtime() - mPauseTime;
|
||||||
|
mPauseTime = 0;
|
||||||
|
mChronometer.setBase(mStartTime);
|
||||||
|
mChronometer.start();
|
||||||
|
if (!mCurrentLap.isRunning()) {
|
||||||
|
mCurrentLap.resume();
|
||||||
|
mUpdateHandler.asyncUpdate(mCurrentLap.getId(), mCurrentLap);
|
||||||
|
}
|
||||||
// This animator instance will end up having end() called on it. When
|
// This animator instance will end up having end() called on it. When
|
||||||
// the table update prompts us to requery, onLoadFinished will be called as a result.
|
// the table update prompts us to requery, onLoadFinished will be called as a result.
|
||||||
// There, it calls startNewProgressAnimator() to end this animation and starts an
|
// There, it calls startNewProgressAnimator() to end this animation and starts an
|
||||||
@ -219,6 +257,7 @@ public class StopwatchFragment extends RecyclerViewFragment<
|
|||||||
// }
|
// }
|
||||||
getActivity().startService(new Intent(getActivity(), StopwatchNotificationService.class));
|
getActivity().startService(new Intent(getActivity(), StopwatchNotificationService.class));
|
||||||
}
|
}
|
||||||
|
savePrefs();
|
||||||
// TOneverDO: Precede savePrefs(), or else we don't save false to KEY_CHRONOMETER_RUNNING
|
// TOneverDO: Precede savePrefs(), or else we don't save false to KEY_CHRONOMETER_RUNNING
|
||||||
/// and updateFab will update the wrong icon.
|
/// and updateFab will update the wrong icon.
|
||||||
updateAllFabs();
|
updateAllFabs();
|
||||||
@ -241,7 +280,23 @@ public class StopwatchFragment extends RecyclerViewFragment<
|
|||||||
|
|
||||||
@OnClick(R.id.new_lap)
|
@OnClick(R.id.new_lap)
|
||||||
void addNewLap() {
|
void addNewLap() {
|
||||||
mController.addNewLap(mChronometer.getText().toString());
|
if (!mChronometer.isRunning()) {
|
||||||
|
Log.d(TAG, "Cannot add new lap");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mCurrentLap != null) {
|
||||||
|
mCurrentLap.end(mChronometer.getText().toString());
|
||||||
|
}
|
||||||
|
mPreviousLap = mCurrentLap;
|
||||||
|
mCurrentLap = new Lap();
|
||||||
|
if (mPreviousLap != null) {
|
||||||
|
// if (getAdapter().getItemCount() == 0) {
|
||||||
|
// mUpdateHandler.asyncInsert(mPreviousLap);
|
||||||
|
// } else {
|
||||||
|
mUpdateHandler.asyncUpdate(mPreviousLap.getId(), mPreviousLap);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
mUpdateHandler.asyncInsert(mCurrentLap);
|
||||||
// This would end up being called twice: here, and in onLoadFinished(), because the
|
// This would end up being called twice: here, and in onLoadFinished(), because the
|
||||||
// table updates will prompt us to requery.
|
// table updates will prompt us to requery.
|
||||||
// startNewProgressBarAnimator();
|
// startNewProgressBarAnimator();
|
||||||
@ -249,13 +304,17 @@ public class StopwatchFragment extends RecyclerViewFragment<
|
|||||||
|
|
||||||
@OnClick(R.id.stop)
|
@OnClick(R.id.stop)
|
||||||
void stop() {
|
void stop() {
|
||||||
|
mChronometer.stop();
|
||||||
|
mChronometer.setBase(SystemClock.elapsedRealtime());
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
// TOneverDO: Precede these with mProgressAnimator.end(), otherwise our
|
// TOneverDO: Precede these with mProgressAnimator.end(), otherwise our
|
||||||
// Animator.onAnimationEnd() callback won't hide SeekBar in time.
|
// Animator.onAnimationEnd() callback won't hide SeekBar in time.
|
||||||
mController.stop();
|
mStartTime = 0;
|
||||||
|
mPauseTime = 0;
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
mCurrentLap = null;
|
mCurrentLap = null;
|
||||||
mPreviousLap = null;
|
mPreviousLap = null;
|
||||||
|
mUpdateHandler.asyncClear(); // Clear laps
|
||||||
// No issues controlling the animator here, because onLoadFinished() can't
|
// No issues controlling the animator here, because onLoadFinished() can't
|
||||||
// call through to startNewProgressBarAnimator(), because by that point
|
// call through to startNewProgressBarAnimator(), because by that point
|
||||||
// the chronometer won't be running.
|
// the chronometer won't be running.
|
||||||
@ -263,6 +322,7 @@ public class StopwatchFragment extends RecyclerViewFragment<
|
|||||||
mProgressAnimator.end();
|
mProgressAnimator.end();
|
||||||
}
|
}
|
||||||
mProgressAnimator = null;
|
mProgressAnimator = null;
|
||||||
|
savePrefs();
|
||||||
// TOneverDO: Precede savePrefs(), or else we don't save false to KEY_CHRONOMETER_RUNNING
|
// TOneverDO: Precede savePrefs(), or else we don't save false to KEY_CHRONOMETER_RUNNING
|
||||||
/// and updateFab will update the wrong icon.
|
/// and updateFab will update the wrong icon.
|
||||||
updateAllFabs();
|
updateAllFabs();
|
||||||
@ -282,14 +342,14 @@ public class StopwatchFragment extends RecyclerViewFragment<
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateMiniFabs() {
|
private void updateMiniFabs() {
|
||||||
boolean started = mController.getStopwatch().hasStarted();
|
boolean started = mStartTime > 0;
|
||||||
int vis = started ? View.VISIBLE : View.INVISIBLE;
|
int vis = started ? View.VISIBLE : View.INVISIBLE;
|
||||||
mNewLapButton.setVisibility(vis);
|
mNewLapButton.setVisibility(vis);
|
||||||
mStopButton.setVisibility(vis);
|
mStopButton.setVisibility(vis);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateFab() {
|
private void updateFab() {
|
||||||
mActivityFab.get().setImageDrawable(mController.isStopwatchRunning() ? mPauseDrawable : mStartDrawable);
|
mActivityFab.get().setImageDrawable(isStopwatchRunning() ? mPauseDrawable : mStartDrawable);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startNewProgressBarAnimator() {
|
private void startNewProgressBarAnimator() {
|
||||||
@ -354,6 +414,21 @@ public class StopwatchFragment extends RecyclerViewFragment<
|
|||||||
return mPreviousLap.elapsed() - mCurrentLap.elapsed();
|
return mPreviousLap.elapsed() - mCurrentLap.elapsed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void savePrefs() {
|
||||||
|
mPrefs.edit().putLong(KEY_START_TIME, mStartTime)
|
||||||
|
.putLong(KEY_PAUSE_TIME, mPauseTime)
|
||||||
|
.putBoolean(KEY_CHRONOMETER_RUNNING, mChronometer.isRunning())
|
||||||
|
.apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the state of the stopwatch when we're in a resumed and visible state,
|
||||||
|
* or when we're going through a rotation
|
||||||
|
*/
|
||||||
|
private boolean isStopwatchRunning() {
|
||||||
|
return mChronometer.isRunning() || mPrefs.getBoolean(KEY_CHRONOMETER_RUNNING, false);
|
||||||
|
}
|
||||||
|
|
||||||
// ======================= DO NOT IMPLEMENT ============================
|
// ======================= DO NOT IMPLEMENT ============================
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -68,18 +68,20 @@ public class StopwatchNotificationService extends ChronometerNotificationService
|
|||||||
@Override
|
@Override
|
||||||
protected void handleStartPauseAction(Intent intent, int flags, long startId) {
|
protected void handleStartPauseAction(Intent intent, int flags, long startId) {
|
||||||
// TODO: Tell StopwatchFragment to start/pause itself.. perhaps with an Intent?
|
// TODO: Tell StopwatchFragment to start/pause itself.. perhaps with an Intent?
|
||||||
boolean running = mPrefs.getBoolean("KEY_RUNNING", false);
|
boolean running = mPrefs.getBoolean(StopwatchFragment.KEY_CHRONOMETER_RUNNING, false);
|
||||||
syncNotificationWithStopwatchState(!running);
|
|
||||||
SharedPreferences.Editor editor = mPrefs.edit();
|
SharedPreferences.Editor editor = mPrefs.edit();
|
||||||
editor.putBoolean("KEY_RUNNING", !running);
|
editor.putBoolean(StopwatchFragment.KEY_CHRONOMETER_RUNNING, !running);
|
||||||
if (running) {
|
if (running) {
|
||||||
editor.putLong("key_pause_time", SystemClock.elapsedRealtime());
|
editor.putLong(StopwatchFragment.KEY_PAUSE_TIME, SystemClock.elapsedRealtime());
|
||||||
} else {
|
} else {
|
||||||
long startTime = mPrefs.getLong("key_start_time", 0);
|
long startTime = mPrefs.getLong(StopwatchFragment.KEY_START_TIME, 0);
|
||||||
long pauseTime = mPrefs.getLong("key_pause_time", 0);
|
long pauseTime = mPrefs.getLong(StopwatchFragment.KEY_PAUSE_TIME, 0);
|
||||||
editor.putLong("key_start_time", startTime + SystemClock.elapsedRealtime() - pauseTime);
|
startTime += SystemClock.elapsedRealtime() - pauseTime;
|
||||||
|
editor.putLong(StopwatchFragment.KEY_START_TIME, startTime);
|
||||||
|
editor.putLong(StopwatchFragment.KEY_PAUSE_TIME, 0);
|
||||||
}
|
}
|
||||||
editor.apply();
|
editor.apply();
|
||||||
|
syncNotificationWithStopwatchState(!running);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -110,8 +112,8 @@ public class StopwatchNotificationService extends ChronometerNotificationService
|
|||||||
|
|
||||||
quitCurrentThread();
|
quitCurrentThread();
|
||||||
if (running) {
|
if (running) {
|
||||||
// TODO: Read the stopwatch's start time in shared prefs.
|
long startTime = mPrefs.getLong(StopwatchFragment.KEY_START_TIME, SystemClock.elapsedRealtime());
|
||||||
startNewThread(0, SystemClock.elapsedRealtime());
|
startNewThread(0, startTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,78 +0,0 @@
|
|||||||
package com.philliphsu.clock2.stopwatch;
|
|
||||||
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.os.SystemClock;
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by Phillip Hsu on 9/11/2016.
|
|
||||||
*/
|
|
||||||
public final class StopwatchViewController extends BaseStopwatchController {
|
|
||||||
private static final String TAG = "StopwatchViewController";
|
|
||||||
|
|
||||||
private final ChronometerWithMillis mChronometer;
|
|
||||||
|
|
||||||
public StopwatchViewController(@NonNull AsyncLapsTableUpdateHandler updateHandler,
|
|
||||||
@NonNull SharedPreferences prefs,
|
|
||||||
@NonNull ChronometerWithMillis chronometer) {
|
|
||||||
super(updateHandler, prefs);
|
|
||||||
mChronometer = chronometer;
|
|
||||||
|
|
||||||
mChronometer.setShowCentiseconds(true, true);
|
|
||||||
final Stopwatch sw = getStopwatch();
|
|
||||||
if (sw.getStartTime() > 0) {
|
|
||||||
long base = sw.getStartTime();
|
|
||||||
if (sw.getPauseTime() > 0) {
|
|
||||||
base += SystemClock.elapsedRealtime() - sw.getPauseTime();
|
|
||||||
// We're not done pausing yet, so don't reset mPauseTime.
|
|
||||||
}
|
|
||||||
chronometer.setBase(base);
|
|
||||||
}
|
|
||||||
if (isStopwatchRunning()) {
|
|
||||||
chronometer.start();
|
|
||||||
// Note: mChronometer.isRunning() will return false at this point and
|
|
||||||
// in other upcoming lifecycle methods because it is not yet visible
|
|
||||||
// (i.e. mVisible == false).
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
super.run();
|
|
||||||
mChronometer.setBase(getStopwatch().getStartTime());
|
|
||||||
mChronometer.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void pause() {
|
|
||||||
// Keep this call and the call to Stopwatch.pause() close together to minimize the time delta.
|
|
||||||
mChronometer.stop();
|
|
||||||
super.pause();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void stop() {
|
|
||||||
mChronometer.stop();
|
|
||||||
mChronometer.setBase(SystemClock.elapsedRealtime());
|
|
||||||
super.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addNewLap(String currentLapTotalText) {
|
|
||||||
if (!mChronometer.isRunning()) {
|
|
||||||
Log.d(TAG, "Cannot add new lap");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
super.addNewLap(currentLapTotalText);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the state of the stopwatch when we're in a resumed and visible state,
|
|
||||||
* or when we're going through a rotation
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean isStopwatchRunning() {
|
|
||||||
return mChronometer.isRunning() || super.isStopwatchRunning();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -136,7 +136,7 @@ public class TimerNotificationService extends ChronometerNotificationService {
|
|||||||
// there is a noticeable delay before the minute gets added on.
|
// there is a noticeable delay before the minute gets added on.
|
||||||
// Update the text immediately, because there's no harm in doing so.
|
// Update the text immediately, because there's no harm in doing so.
|
||||||
setBase(getBase() + 60000);
|
setBase(getBase() + 60000);
|
||||||
updateNotification();
|
updateNotification(true);
|
||||||
mController.addOneMinute();
|
mController.addOneMinute();
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("TimerNotificationService cannot handle action " + action);
|
throw new IllegalArgumentException("TimerNotificationService cannot handle action " + action);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user