• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.os;
18 
19 import android.util.Log;
20 
21 /**
22  * Schedule a countdown until a time in the future, with
23  * regular notifications on intervals along the way.
24  *
25  * Example of showing a 30 second countdown in a text field:
26  *
27  * <pre class="prettyprint">
28  * new CountDownTimer(30000, 1000) {
29  *
30  *     public void onTick(long millisUntilFinished) {
31  *         mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
32  *     }
33  *
34  *     public void onFinish() {
35  *         mTextField.setText("done!");
36  *     }
37  *  }.start();
38  * </pre>
39  *
40  * The calls to {@link #onTick(long)} are synchronized to this object so that
41  * one call to {@link #onTick(long)} won't ever occur before the previous
42  * callback is complete.  This is only relevant when the implementation of
43  * {@link #onTick(long)} takes an amount of time to execute that is significant
44  * compared to the countdown interval.
45  */
46 public abstract class CountDownTimer {
47 
48     /**
49      * Millis since epoch when alarm should stop.
50      */
51     private final long mMillisInFuture;
52 
53     /**
54      * The interval in millis that the user receives callbacks
55      */
56     private final long mCountdownInterval;
57 
58     private long mStopTimeInFuture;
59 
60     /**
61      * @param millisInFuture The number of millis in the future from the call
62      *   to {@link #start()} until the countdown is done and {@link #onFinish()}
63      *   is called.
64      * @param countDownInterval The interval along the way to receive
65      *   {@link #onTick(long)} callbacks.
66      */
CountDownTimer(long millisInFuture, long countDownInterval)67     public CountDownTimer(long millisInFuture, long countDownInterval) {
68         mMillisInFuture = millisInFuture;
69         mCountdownInterval = countDownInterval;
70     }
71 
72     /**
73      * Cancel the countdown.
74      */
cancel()75     public final void cancel() {
76         mHandler.removeMessages(MSG);
77     }
78 
79     /**
80      * Start the countdown.
81      */
start()82     public synchronized final CountDownTimer start() {
83         if (mMillisInFuture <= 0) {
84             onFinish();
85             return this;
86         }
87         mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture;
88         mHandler.sendMessage(mHandler.obtainMessage(MSG));
89         return this;
90     }
91 
92 
93     /**
94      * Callback fired on regular interval.
95      * @param millisUntilFinished The amount of time until finished.
96      */
onTick(long millisUntilFinished)97     public abstract void onTick(long millisUntilFinished);
98 
99     /**
100      * Callback fired when the time is up.
101      */
onFinish()102     public abstract void onFinish();
103 
104 
105     private static final int MSG = 1;
106 
107 
108     // handles counting down
109     private Handler mHandler = new Handler() {
110 
111         @Override
112         public void handleMessage(Message msg) {
113 
114             synchronized (CountDownTimer.this) {
115                 final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();
116 
117                 if (millisLeft <= 0) {
118                     onFinish();
119                 } else if (millisLeft < mCountdownInterval) {
120                     // no tick, just delay until done
121                     sendMessageDelayed(obtainMessage(MSG), millisLeft);
122                 } else {
123                     long lastTickStart = SystemClock.elapsedRealtime();
124                     onTick(millisLeft);
125 
126                     // take into account user's onTick taking time to execute
127                     long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime();
128 
129                     // special case: user's onTick took more than interval to
130                     // complete, skip to next interval
131                     while (delay < 0) delay += mCountdownInterval;
132 
133                     sendMessageDelayed(obtainMessage(MSG), delay);
134                 }
135             }
136         }
137     };
138 }
139