Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrote Chronometer view so that timer is in a service #1

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 24 additions & 23 deletions AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.psrivastava.stopwatch"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk android:minSdkVersion="14" />

<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@android:style/Theme.Holo.Light.DarkActionBar" >
<activity
android:name=".StopwatchActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.psrivastava.stopwatch"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk android:minSdkVersion="14" />

<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@android:style/Theme.Holo.Light.DarkActionBar" >
<activity
android:name=".StopwatchActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".ChronometerService" />
</application>

</manifest>
324 changes: 169 additions & 155 deletions src/com/psrivastava/stopwatch/Chronometer.java
Original file line number Diff line number Diff line change
@@ -1,156 +1,170 @@
package com.psrivastava.stopwatch;

import java.text.DecimalFormat;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.widget.TextView;

/* Customized version of Chronometer class
* Original source from Antonis Balasas
* https://github.com/antoniom/Millisecond-Chronometer
*/
public class Chronometer extends TextView {
private static final String TAG = "Chronometer";

public interface OnChronometerTickListener {

void onChronometerTick(Chronometer chronometer);
}

private long mBase;
private boolean mVisible;
private boolean mStarted;
private boolean mRunning;
private OnChronometerTickListener mOnChronometerTickListener;

private static final int TICK_WHAT = 2;

public Chronometer(Context context) {
this(context, null, 0);
}

public Chronometer(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public Chronometer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);

init();
}

private void init() {
mBase = SystemClock.elapsedRealtime();
updateText(mBase);
}

public void setBase(long base) {
mBase = base;
dispatchChronometerTick();
updateText(SystemClock.elapsedRealtime());
}

public long getBase() {
return mBase;
}

public void setOnChronometerTickListener(OnChronometerTickListener listener) {
mOnChronometerTickListener = listener;
}

public OnChronometerTickListener getOnChronometerTickListener() {
return mOnChronometerTickListener;
}

public void start() {
mStarted = true;
updateRunning();
}

public boolean isStarted() {
return mStarted;
}

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 synchronized void updateText(long now) {
long timeElapsed = now - mBase;

DecimalFormat df = new DecimalFormat("00");

int hours = (int) (timeElapsed / (3600 * 1000));
int remaining = (int) (timeElapsed % (3600 * 1000));

int minutes = (int) (remaining / (60 * 1000));
remaining = (int) (remaining % (60 * 1000));

int seconds = (int) (remaining / 1000);
remaining = (int) (remaining % (1000));

int milliseconds = (int) (((int) timeElapsed % 1000) / 100);

String text = "";

if (hours > 0) {
text += df.format(hours) + ":";
}

text += df.format(minutes) + ":";
text += df.format(seconds) + ".";
text += Integer.toString(milliseconds);

setText(text);
}

private void updateRunning() {
boolean running = mVisible && mStarted;
if (running != mRunning) {
if (running) {
updateText(SystemClock.elapsedRealtime());
dispatchChronometerTick();
mHandler.sendMessageDelayed(
Message.obtain(mHandler, TICK_WHAT), 100);
} else {
mHandler.removeMessages(TICK_WHAT);
}
mRunning = running;
}
}

private Handler mHandler = new Handler() {
public void handleMessage(Message m) {
if (mRunning) {
updateText(SystemClock.elapsedRealtime());
dispatchChronometerTick();
sendMessageDelayed(Message.obtain(this, TICK_WHAT), 100);
}
}
};

void dispatchChronometerTick() {
if (mOnChronometerTickListener != null) {
mOnChronometerTickListener.onChronometerTick(this);
}
}
package com.psrivastava.stopwatch;

import java.text.DecimalFormat;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;

/* Gets time from service and displays it.
* Original source from Antonis Balasas
* https://github.com/antoniom/Millisecond-Chronometer
*/
public class Chronometer extends TextView {
private static final String TAG = "Chronometer";

private boolean mRunning;

private static final int TICK_WHAT = 2;

IChronometerService mService;

private ServiceConnection mConnection = new ServiceConnection() {

public void onServiceDisconnected(ComponentName name) {
stopDisplay();
}

public void onServiceConnected(ComponentName name, IBinder service) {
mService = IChronometerService.Stub.asInterface(service);
Log.v(TAG, "Service Connected");
updateText();
startDisplay();
}
};

public Chronometer(Context context) {
this(context, null, 0);
}

public Chronometer(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public Chronometer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
context.getApplicationContext().bindService(new Intent(context, ChronometerService.class), mConnection, Context.BIND_AUTO_CREATE);
}

public void start() {
try {
mService.start();
} catch (RemoteException e) {
Log.e(TAG, "Connection to service failed.", e);
}
startDisplay();
}

public void pause() {
try {
mService.pause();
} catch (RemoteException e) {
Log.e(TAG, "Connection to service failed.", e);
}
stopDisplay();
updateText();
}

public void resume() {
try {
mService.resume();
} catch (RemoteException e) {
Log.e(TAG, "Connection to service failed.", e);
}
startDisplay();
}

public void stop() {
try {
mService.stop();
} catch (RemoteException e) {
Log.e(TAG, "Connection to service failed.", e);
}
stopDisplay();
updateText();
}

@Override
protected void onDetachedFromWindow() {
stopDisplay();
}

@Override
protected void onWindowVisibilityChanged(int visibility) {
if (visibility == VISIBLE) {
startDisplay();
}
else {
stopDisplay();
}
}

/**
* Display elapsed time.
*/
private synchronized void updateText() {

try {
long timeElapsed;
timeElapsed = mService.getTime();

DecimalFormat df = new DecimalFormat("00");

int hours = (int) (timeElapsed / (3600 * 1000));
int remaining = (int) (timeElapsed % (3600 * 1000));

int minutes = (int) (remaining / (60 * 1000));
remaining = (int) (remaining % (60 * 1000));

int seconds = (int) (remaining / 1000);
remaining = (int) (remaining % (1000));

int milliseconds = (int) (((int) timeElapsed % 1000) / 100);

String text = "";

if (hours > 0) {
text += df.format(hours) + ":";
}

text += df.format(minutes) + ":";
text += df.format(seconds) + ".";
text += Integer.toString(milliseconds);

setText(text);
} catch (RemoteException e) {
Log.e(TAG, "Connection to service failed.", e);
}
}

private void startDisplay() {
try {
if (!mRunning && mService != null && mService.isRunning()) {
mHandler.dispatchMessage(Message.obtain(mHandler, TICK_WHAT));
mRunning = true;
}
} catch (RemoteException e) {
Log.e(TAG, "Connection to service failed.", e);
}
}

private void stopDisplay() {
mHandler.removeMessages(TICK_WHAT);
mRunning = false;
}

private Handler mHandler = new Handler() {
public void handleMessage(Message m) {
sendMessageDelayed(Message.obtain(this, TICK_WHAT), 100);
updateText();
}
};
}
Loading