blob: c7bf0fd6ba49a5f54164037f615c2c4842221b99 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
17package android.os;
18
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080019/**
20 * Schedule a countdown until a time in the future, with
21 * regular notifications on intervals along the way.
22 *
23 * Example of showing a 30 second countdown in a text field:
24 *
25 * <pre class="prettyprint">
Michael Chancf0ca992011-10-20 14:50:09 -070026 * new CountDownTimer(30000, 1000) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027 *
28 * public void onTick(long millisUntilFinished) {
29 * mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
30 * }
31 *
32 * public void onFinish() {
33 * mTextField.setText("done!");
34 * }
35 * }.start();
36 * </pre>
37 *
38 * The calls to {@link #onTick(long)} are synchronized to this object so that
39 * one call to {@link #onTick(long)} won't ever occur before the previous
40 * callback is complete. This is only relevant when the implementation of
41 * {@link #onTick(long)} takes an amount of time to execute that is significant
42 * compared to the countdown interval.
43 */
44public abstract class CountDownTimer {
45
46 /**
47 * Millis since epoch when alarm should stop.
48 */
49 private final long mMillisInFuture;
50
51 /**
52 * The interval in millis that the user receives callbacks
53 */
54 private final long mCountdownInterval;
55
56 private long mStopTimeInFuture;
jl19903cd12a52013-08-07 17:39:22 +020057
58 /**
59 * boolean representing if the timer was cancelled
60 */
61 private boolean mCancelled = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062
63 /**
64 * @param millisInFuture The number of millis in the future from the call
65 * to {@link #start()} until the countdown is done and {@link #onFinish()}
66 * is called.
67 * @param countDownInterval The interval along the way to receive
68 * {@link #onTick(long)} callbacks.
69 */
70 public CountDownTimer(long millisInFuture, long countDownInterval) {
71 mMillisInFuture = millisInFuture;
72 mCountdownInterval = countDownInterval;
73 }
74
75 /**
76 * Cancel the countdown.
77 */
jl19903cd12a52013-08-07 17:39:22 +020078 public synchronized final void cancel() {
79 mCancelled = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080 mHandler.removeMessages(MSG);
81 }
82
83 /**
84 * Start the countdown.
85 */
86 public synchronized final CountDownTimer start() {
jl19903cd12a52013-08-07 17:39:22 +020087 mCancelled = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088 if (mMillisInFuture <= 0) {
89 onFinish();
90 return this;
91 }
92 mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture;
93 mHandler.sendMessage(mHandler.obtainMessage(MSG));
94 return this;
95 }
96
97
98 /**
99 * Callback fired on regular interval.
100 * @param millisUntilFinished The amount of time until finished.
101 */
102 public abstract void onTick(long millisUntilFinished);
103
104 /**
105 * Callback fired when the time is up.
106 */
107 public abstract void onFinish();
108
109
110 private static final int MSG = 1;
111
112
113 // handles counting down
114 private Handler mHandler = new Handler() {
115
116 @Override
117 public void handleMessage(Message msg) {
118
119 synchronized (CountDownTimer.this) {
jl19903cd12a52013-08-07 17:39:22 +0200120 if (mCancelled) {
121 return;
122 }
123
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();
125
126 if (millisLeft <= 0) {
127 onFinish();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128 } else {
129 long lastTickStart = SystemClock.elapsedRealtime();
130 onTick(millisLeft);
131
132 // take into account user's onTick taking time to execute
Hidenari Koshimae0c314912016-10-18 20:43:16 +0900133 long lastTickDuration = SystemClock.elapsedRealtime() - lastTickStart;
134 long delay;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135
Hidenari Koshimae0c314912016-10-18 20:43:16 +0900136 if (millisLeft < mCountdownInterval) {
137 // just delay until done
138 delay = millisLeft - lastTickDuration;
139
140 // special case: user's onTick took more than interval to
141 // complete, trigger onFinish without delay
142 if (delay < 0) delay = 0;
143 } else {
144 delay = mCountdownInterval - lastTickDuration;
145
146 // special case: user's onTick took more than interval to
147 // complete, skip to next interval
148 while (delay < 0) delay += mCountdownInterval;
149 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150
151 sendMessageDelayed(obtainMessage(MSG), delay);
152 }
153 }
154 }
155 };
156}