Created
November 7, 2017 21:43
-
-
Save draekko/3ae830055c708ffe73a7c6a1aecf75f8 to your computer and use it in GitHub Desktop.
Chronometer class to display timer in HH:MM:SS format based on the Android Chronometer class.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (C) 2008 The Android Open Source Project | |
* Copyright (C) 2017 Benoit Touchette (Draekko RAND) | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
package com.draekko.clock; | |
import android.content.Context; | |
import android.os.Handler; | |
import android.os.Message; | |
import android.os.SystemClock; | |
import android.util.AttributeSet; | |
import android.widget.RemoteViews.RemoteView; | |
import java.util.Locale; | |
/** | |
* Class that implements a simple timer. | |
* <p> | |
* You can give it a start time in the {@link SystemClock#elapsedRealtime} timebase, | |
* and it counts up from that, or if you don't give it a base time, it will use the | |
* time at which you call {@link #start}. The default time format is HH:MM:SS. | |
*/ | |
@RemoteView | |
public class DRChronometer extends android.support.v7.widget.AppCompatTextView { | |
private static final String TAG = "DRChronometer"; | |
private long mBase; | |
private boolean mVisible; | |
private boolean mStarted; | |
private boolean mRunning; | |
private boolean mLogged; | |
private String mDefaultFormat = "%02d:%02d:%02d"; | |
/** | |
* Initialize this Chronometer object. | |
* Sets the base to the current time. | |
*/ | |
public DRChronometer(Context context) { | |
this(context, null, 0); | |
} | |
/** | |
* Initialize with standard view layout information. | |
* Sets the base to the current time. | |
*/ | |
public DRChronometer(Context context, AttributeSet attrs) { | |
this(context, attrs, 0); | |
} | |
/** | |
* Initialize with standard view layout information and style. | |
* Sets the base to the current time. | |
*/ | |
public DRChronometer(Context context, AttributeSet attrs, int defStyle) { | |
super(context, attrs, defStyle); | |
init(); | |
} | |
private void init() { | |
mBase = SystemClock.elapsedRealtime(); | |
updateText(mBase); | |
} | |
/** | |
* Set the time that the count-up timer is in reference to. | |
* | |
* @param base Use the {@link SystemClock#elapsedRealtime} time base. | |
*/ | |
public void setBase(long base) { | |
mBase = base; | |
updateText(SystemClock.elapsedRealtime()); | |
} | |
/** | |
* Return the base time as set through {@link #setBase}. | |
*/ | |
public long getBase() { | |
return mBase; | |
} | |
/** | |
* Start counting up. This does not affect the base as set from {@link #setBase}, just | |
* the view display. | |
* | |
* Chronometer works by regularly scheduling messages to the handler, even when the | |
* Widget is not visible. To make sure resource leaks do not occur, the user should | |
* make sure that each start() call has a reciprocal call to {@link #stop}. | |
*/ | |
public void start() { | |
mStarted = true; | |
updateRunning(); | |
} | |
/** | |
* Stop counting up. This does not affect the base as set from {@link #setBase}, just | |
* the view display. | |
* | |
* This stops the messages to the handler, effectively releasing resources that would | |
* be held as the chronometer is running, via {@link #start}. | |
*/ | |
public void stop() { | |
mStarted = false; | |
updateRunning(); | |
long now = SystemClock.elapsedRealtime(); | |
setBase(now); | |
updateText(now); | |
} | |
@Override | |
protected void onDetachedFromWindow() { | |
super.onDetachedFromWindow(); | |
mVisible = false; | |
updateRunning(); | |
} | |
@Override | |
protected void onWindowVisibilityChanged(int visibility) { | |
super.onWindowVisibilityChanged(visibility); | |
mVisible = visibility == VISIBLE; | |
updateRunning(); | |
} | |
private void updateText(long now) { | |
long seconds = (now - mBase) / 1000; | |
int hh = (int)(seconds / 3600); | |
int mm = (int)((seconds % 3600) / 60); | |
int ss = (int)(seconds % 60); | |
String text = String.format(Locale.US, mDefaultFormat, hh, mm, ss); | |
setText(text); | |
} | |
private void updateRunning() { | |
boolean running = mVisible && mStarted; | |
if (running != mRunning) { | |
if (running) { | |
updateText(SystemClock.elapsedRealtime()); | |
mHandler.sendMessageDelayed(Message.obtain(), 1000); | |
} | |
mRunning = running; | |
} | |
} | |
private Handler mHandler = new Handler() { | |
public void handleMessage(Message m) { | |
if (mStarted) { | |
updateText(SystemClock.elapsedRealtime()); | |
sendMessageDelayed(Message.obtain(), 1000); | |
} | |
} | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment