// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
package com.google.appinventor.components.runtime.util;
import com.google.appinventor.components.runtime.AlarmHandler;
import android.os.Handler;
/**
* Helper class for components containing timers, such as Timer and Sprite.
*
*/
public final class TimerInternal implements Runnable {
// Android message handler used as a timer
private Handler handler;
// Indicates whether the timer is running or not
private boolean enabled; // set in constructor
// Interval between timer events in ms
private int interval; // set in constructor
// Component that should be called by timer
private AlarmHandler component;
/**
* Timer constructor
*
* @param component the component whose {@link AlarmHandler#alarm()} method
* should be called on timer intervals
* @param enabled whether it is initially enabled
* @param interval time in ms
*/
public TimerInternal(AlarmHandler component, boolean enabled, int interval) {
this(component, enabled, interval, new Handler());
}
/**
* Timer constructor allowing injection of a mock Handler for test purposes
*
* @param component the component whose {@link AlarmHandler#alarm()} method
* should be called on timer intervals
* @param enabled whether it is initially enabled
* @param interval time in ms
* @param handler the handler whose {@link
* android.os.Handler#postDelayed(Runnable, long)}
* method is called to request calls of this after the delay
* specified via {@link #Interval(int)}
*/
public TimerInternal(AlarmHandler component, boolean enabled, int interval, Handler handler) {
this.handler = handler;
this.component = component;
// Set properties to default values specified by caller.
this.enabled = enabled;
this.interval = interval;
if (enabled) {
handler.postDelayed(this, interval);
}
}
/**
* Interval getter.
*
* @return timer interval in ms
*/
public int Interval() {
return interval;
}
/**
* Interval property setter method: sets the interval between timer events.
*
* @param interval timer interval in ms
*/
public void Interval(int interval) {
this.interval = interval;
if (enabled) {
handler.removeCallbacks(this);
handler.postDelayed(this, interval);
}
}
/**
* Enabled property getter method.
*
* @return {@code true} indicates a running timer, {@code false} a stopped
* timer
*/
public boolean Enabled() {
return enabled;
}
/**
* Enabled property setter method: starts or stops the timer.
*
* @param enabled {@code true} starts the timer, {@code false} stops it
*/
public void Enabled(boolean enabled) {
if (this.enabled) {
handler.removeCallbacks(this);
}
this.enabled = enabled;
if (enabled) {
handler.postDelayed(this, interval);
}
}
// Runnable implementation
public void run() {
if (enabled) {
component.alarm();
// During the call to component.alarm, the enabled field may have changed.
// We need to make sure that enabled is still true before we call handler.postDelayed.
if (enabled) {
handler.postDelayed(this, interval);
}
}
}
}