/**
* CurrentTimeTicker.java
*
* Copyright (c) 2009 codeswimmer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Created on Nov 26, 2009
*/
package com.codeswimmer.android.apps.alarm.engine;
import java.util.Timer;
import java.util.TimerTask;
import android.util.Log;
/**
* This class is responsible for broadcasting periodic notifications of the current time. Clients must implements the
* {@link OnCurrentTimeTickListener} interface in order to receive update notifications.
*
* @author codeswimmer
*/
public class CurrentTimeTicker {
private static final String LOG_TAG = CurrentTimeTicker.class.getName();
/**
* The name of this timer task.
*/
private static final String TIMER_NAME = "CurrentTimeTicker"; //$NON-NLS-1$
/**
* A default notification interval period.
*/
public static final long DEFAULT_PERIOD = 1000;
/**
* Only one {@link OnCurrentTimeTickListener} at a time allowed.
*/
private OnCurrentTimeTickListener listener;
/**
* Where we get our periodic updates from.
*/
private Timer ticker;
/**
* <code>true</code> indicates the ticker is currently firing notifications to its listener.
*/
private boolean running;
/**
* Creates a new instance
*/
public CurrentTimeTicker() {
}
/**
* Starts notification of the current time.
* <p>
* Note:
* <ul>
* <li>
* If a negative value for <code>period</code> is given, it will automatically be converted into the
* {@link #DEFAULT_PERIOD} of {@value #DEFAULT_PERIOD}; a WARNING level log statement will be issued if this occurs.
* </li>
* <li>
* If the {@link CurrentTimeTicker} is already running it will be stopped. A new {@link #ticker} will then be
* created.</li>
* </ul>
*
* @param listener
* The client who will be receiving update notifications. Must be non-<code>null</code>.
* @param period
* How often, in milliseconds, the ticker is triggered.
* @throws IllegalArgumentException
* If <code>listener</code> is <code>null</code>.
*/
public void start(OnCurrentTimeTickListener listener, long ... period) throws IllegalArgumentException {
if (listener == null) {
throw new IllegalArgumentException("listener cannot be null"); //$NON-NLS-1$
}
this.listener = listener;
// Use the given interval period; if it wasn't provided use the default.
long interval = period.length > 0 ? period[0] : DEFAULT_PERIOD;
// Ensure we don't end up with a negative value for the interval
if (interval < 0) {
Log.w(LOG_TAG, "negative value of period coerced to default"); //$NON-NLS-1$
interval = DEFAULT_PERIOD;
}
Log.d(LOG_TAG, String.format("creating timer with interval of %d ms", interval)); //$NON-NLS-1$
// If we're already running, stop the existing ticker before creating a new one.
if (running) {
Log.d(LOG_TAG, "ticker is currently running; stopping before creating new one"); //$NON-NLS-1$
stop();
}
// We want the timer to run as a daemon
ticker = new Timer(TIMER_NAME, true);
ticker.schedule(new TickTimerTask(), 0, interval);
running = true;
}
/**
* Stops notification of the current time.
*/
public void stop() {
Log.d(LOG_TAG, String.format("stopping; ticker != null: %s", (ticker != null))); //$NON-NLS-1$
if (ticker != null) {
ticker.purge();
ticker.cancel();
running = false;
}
}
/**
* If we have a listener, fire notification of the current time. If not, no need in continuing.
*/
private void fireOnCurrentTimeTick() {
if (listener != null) {
listener.onCurrentTimeTick(System.currentTimeMillis());
}
}
/**
* @return The current value of {@link #running}.
*/
public boolean isRunning() {
return running;
}
/**
* This interface is used for communicating notifications from the {@link CurrentTimeTicker} to its interested
* listener.
*/
public static interface OnCurrentTimeTickListener {
/**
* Notification that the current time has been updated.
*
* @param currentTime
* The current date and time as the number of milliseconds since January 1, 1970, midnight GMT.
*/
public void onCurrentTimeTick(long currentTime);
}
/**
* This class receives notifications from the {@link Timer} when the timer has triggered.
*/
private class TickTimerTask extends TimerTask {
/** {@inheritDoc} */
@Override
public void run() {
fireOnCurrentTimeTick();
}
}
}
|