/*
* Copyright (C) 2013 The Android Open Source Project
*
* 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.google.android.glass.sample.stopwatch;
import android.content.Context;
import android.os.Handler;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.FrameLayout;
import android.widget.TextView;
import java.util.concurrent.TimeUnit;
/**
* View used to display draw a running Chronometer.
*
* This code is greatly inspired by the Android's Chronometer widget.
*/
public class ChronometerView extends FrameLayout {
/**
* Interface to listen for changes on the view layout.
*/
public interface ChangeListener {
/** Notified of a change in the view. */
public void onChange();
}
// About 24 FPS.
private static final long DELAY_MILLIS = 41;
private final TextView mMinuteView;
private final TextView mSecondView;
private final TextView mCentiSecondView;
private boolean mStarted;
private boolean mForceStart;
private boolean mVisible;
private boolean mRunning;
private long mBaseMillis;
private ChangeListener mChangeListener;
public ChronometerView(Context context) {
this(context, null, 0);
}
public ChronometerView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ChronometerView(Context context, AttributeSet attrs, int style) {
super(context, attrs, style);
LayoutInflater.from(context).inflate(R.layout.card_chronometer, this);
mMinuteView = (TextView) findViewById(R.id.minute);
mSecondView = (TextView) findViewById(R.id.second);
mCentiSecondView = (TextView) findViewById(R.id.centi_second);
setBaseMillis(SystemClock.elapsedRealtime());
}
/**
* Set the base value of the chronometer in milliseconds.
*/
public void setBaseMillis(long baseMillis) {
mBaseMillis = baseMillis;
updateText();
}
/**
* Get the base value of the chronometer in milliseconds.
*/
public long getBaseMillis() {
return mBaseMillis;
}
/**
* Set a {@link ChangeListener}.
*/
public void setListener(ChangeListener listener) {
mChangeListener = listener;
}
/**
* Set whether or not to force the start of the chronometer when a window has not been attached
* to the view.
*/
public void setForceStart(boolean forceStart) {
mForceStart = forceStart;
updateRunning();
}
/**
* Start the chronometer.
*/
public void start() {
mStarted = true;
updateRunning();
}
/**
* Stop the chronometer.
*/
public void stop() {
mStarted = false;
updateRunning();
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mVisible = false;
updateRunning();
}
@Override
protected void onWindowVisibilityChanged(int visibility) {
super.onWindowVisibilityChanged(visibility);
mVisible = (visibility == VISIBLE);
updateRunning();
}
private final Handler mHandler = new Handler();
private final Runnable mUpdateTextRunnable = new Runnable() {
@Override
public void run() {
if (mRunning) {
updateText();
mHandler.postDelayed(mUpdateTextRunnable, DELAY_MILLIS);
}
}
};
/**
* Update the running state of the chronometer.
*/
private void updateRunning() {
boolean running = (mVisible || mForceStart) && mStarted;
if (running != mRunning) {
if (running) {
mHandler.post(mUpdateTextRunnable);
} else {
mHandler.removeCallbacks(mUpdateTextRunnable);
}
mRunning = running;
}
}
/**
* Update the value of the chronometer.
*/
private void updateText() {
long millis = SystemClock.elapsedRealtime() - mBaseMillis;
// Cap chronometer to one hour.
millis %= TimeUnit.HOURS.toMillis(1);
mMinuteView.setText(String.format("%02d", TimeUnit.MILLISECONDS.toMinutes(millis)));
millis %= TimeUnit.MINUTES.toMillis(1);
mSecondView.setText(String.format("%02d", TimeUnit.MILLISECONDS.toSeconds(millis)));
millis = (millis % TimeUnit.SECONDS.toMillis(1)) / 10;
mCentiSecondView.setText(String.format("%02d", millis));
if (mChangeListener != null) {
mChangeListener.onChange();
}
}
}