Friday, February 15, 2013

CountDownChronometer

While searching for a count-down chronometer in the android API, one finds that most resembles is the CountDownTimer class; but it only starts a count-down, and send an event on every predetermined time, and one event when finish, but, what if I want to pause it? I've create a CountDownChronometer class to manage this, and one interface that must implement the class which instantiates it:

CountDownChronometer

Use the constructor to set up the count-down, start() to start it or resume it after pause(), and stop() to cancel the count-down:
package reprom.blogspot.com;

import android.os.CountDownTimer;
import android.os.SystemClock;
import android.util.Log;

/**
 * @author David 'svprdga' Serrano Canales
 */
public class CountDownChronometer{
 
 // Set here the milliseconds interval for every tick.
 private long millisInterval = 500;
  
 private final static String TAG = "CountDownChronometer";
 private ICountDownChronometer handler;
 private boolean isPaused = false;
 private long initCountDownMillis;
 private long restartCountDownMillis;
 private long startCountDownMillis;
 private CountDownTimerImpl countDownTimerImpl;

 /**
  * CountDownChronometer's public constructor.
  * @param initCountDownMillis Milliseconds until the count-down ends.
  * @param handler Object which invoked this constructor, with ICountDownChronometer interface implemented.
  */
 public CountDownChronometer(long initCountDownMillis, ICountDownChronometer handler){
  this.initCountDownMillis = initCountDownMillis;
  this.handler = handler;
 }
 
 /**
  * Starts the count-down. Also used for restart after pause() call.
  */
 public void start(){
  long countDownMillis = 0;
  if (isPaused){
   countDownMillis = restartCountDownMillis;
   isPaused = false;
  } else {
   countDownMillis = initCountDownMillis;
  }
    
  countDownTimerImpl = new CountDownTimerImpl(countDownMillis);
  startCountDownMillis = SystemClock.elapsedRealtime();
  countDownTimerImpl.start();
 }
 
 /**
  * Pauses the count-down.
  */
 public void pause(){  
  isPaused = true;
  restartCountDownMillis = initCountDownMillis - (SystemClock.elapsedRealtime() - startCountDownMillis);
  initCountDownMillis = restartCountDownMillis;
  Log.d("countDown", "restartCountDownMillis: "+restartCountDownMillis);
  countDownTimerImpl.cancel();
 }
 
 /**
  * Stops and cancels the count-down.
  */
 public void stop(){
  countDownTimerImpl.cancel();
  countDownTimerImpl = null;
  isPaused = false;
  onCountDownFinish();
 }
 
 /**
  * Method which is invoked on every count-down tick.
  * @param millisUntilFinished
  */
 public void onCountDownTick(long millisUntilFinished){
  handler.onCountDownTimerTick(millisUntilFinished);
 }
 
 /**
  * Method which is invoked when the count-down finishes.
  */
 public void onCountDownFinish(){
  handler.onCountDownTimerFinish();
 }
 
 public class CountDownTimerImpl extends CountDownTimer{
  
  /**
   * CountDownTimerImpl constructor.
   * @param millisInFuture Time in milliseconds until the count-down ends.
   */
  public CountDownTimerImpl(long millisInFuture) {
   super(millisInFuture, millisInterval);
  }
  
  public void onTick(long millisUntilFinished) {
   onCountDownTick(millisUntilFinished);
  }
  
  public void onFinish() {
   onCountDownFinish();
  }

 }

}

ICountDownChronometer

This interface must be implemented for the objects that instantiates the CountDownChronometer, the implemented methos allows you to control the count-down tick events, and the finish event:
/**
 * @author David 'svprdga' Serrano Canales
 */
public interface ICountDownChronometer {
 
 /**
  * Method called on every CountDownTimer tick.
  */
 public void onCountDownTimerTick(long millisUntilFinished);
 
 /**
  * Method called when CountDownTimer finishes.
  */
 public void onCountDownTimerFinish();
}