package com.artfulbits.ui; import android.os.CountDownTimer; import com.artfulbits.utils.LogEx; import com.artfulbits.utils.ValidUtils; import java.util.WeakHashMap; import java.util.logging.Logger; /** CountDown timer that implements callback pattern. */ public final class CountDownWithCallback extends CountDownTimer { // #region Static Members /** Our own class Logger instance. */ private final static Logger _log = LogEx.getLogger(CountDownWithCallback.class); /** */ private final static long THE_END = -1; // #endregion // #region Members /** Collection of callbacks */ private final WeakHashMap<Callback, Callback> mCallbacks = new WeakHashMap<CountDownWithCallback.Callback, CountDownWithCallback.Callback>(); private long mMillisUntilFinish; private final long mTotal; private final long mInterval; // #endregion // #region Constructor public CountDownWithCallback(long total, long interval, Callback callback) { super(total, interval); mTotal = total; mInterval = interval; if (null != callback) mCallbacks.put(callback, callback); } /** * Copy constructor that reveal countdown from it last position. * * @param copy instance to copy. */ public CountDownWithCallback(final CountDownWithCallback copy) { super((THE_END == copy.mMillisUntilFinish) ? copy.mTotal : copy.mMillisUntilFinish, copy.mInterval); mInterval = copy.mInterval; mTotal = copy.mTotal; if (copy.mCallbacks.size() > 0) { for (Callback call : copy.mCallbacks.keySet()) { mCallbacks.put(call, call); } } } // #endregion // #region Public API /** * Register callback. * * @param callback instance of callback. * @return this. */ public CountDownWithCallback register(final Callback callback) { ValidUtils.isNull(callback, "Callback instance required."); synchronized (mCallbacks) { mCallbacks.put(callback, callback); } return this; } /** * Unregister callback. * * @param callback instance of callback. * @return this. */ public CountDownWithCallback unregister(final Callback callback) { ValidUtils.isNull(callback, "Callback instance required."); synchronized (mCallbacks) { mCallbacks.remove(callback); } return this; } // #endregion // #region Overrides /** {@inheritDoc} */ @Override public void onTick(long until) { mMillisUntilFinish = until; _log.finest("Countdown: " + until); for (Callback call : mCallbacks.keySet()) { try { call.onTick(until); } catch (Throwable ignored) { _log.warning("Callback throws exception. " + LogEx.dump(ignored)); } } } /** {@inheritDoc} */ @Override public void onFinish() { mMillisUntilFinish = THE_END; for (Callback call : mCallbacks.keySet()) { try { call.onFinish(); } catch (Throwable ignored) { _log.warning("Callback throws exception. " + LogEx.dump(ignored)); } } } // #endregion // #region Nested declarations /** Callback interface for count-down timer. */ public interface Callback { /** @see CountDownTimer#onTick(long) */ public void onTick(long until); /** @see CountDownTimer#onFinish() */ public void onFinish(); } // #endregion }