1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Licensed to the Apache Software Foundation (ASF) under one or more
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  contributor license agreements.  See the NOTICE file distributed with
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  this work for additional information regarding copyright ownership.
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  The ASF licenses this file to You under the Apache License, Version 2.0
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  (the "License"); you may not use this file except in compliance with
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  the License.  You may obtain a copy of the License at
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  See the License for the specific language governing permissions and
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  limitations under the License.
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage java.util;
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
21c38102eb6f7a01fe70094a63054337f53ab5283dJesse Wilson * Timers schedule one-shot or recurring {@link TimerTask tasks} for execution.
22c38102eb6f7a01fe70094a63054337f53ab5283dJesse Wilson * Prefer {@link java.util.concurrent.ScheduledThreadPoolExecutor
23c38102eb6f7a01fe70094a63054337f53ab5283dJesse Wilson * ScheduledThreadPoolExecutor} for new code.
24f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson *
25c38102eb6f7a01fe70094a63054337f53ab5283dJesse Wilson * <p>Each timer has one thread on which tasks are executed sequentially. When
26c38102eb6f7a01fe70094a63054337f53ab5283dJesse Wilson * this thread is busy running a task, runnable tasks may be subject to delays.
27c38102eb6f7a01fe70094a63054337f53ab5283dJesse Wilson *
28c38102eb6f7a01fe70094a63054337f53ab5283dJesse Wilson * <p>One-shot are scheduled to run at an absolute time or after a relative
29c38102eb6f7a01fe70094a63054337f53ab5283dJesse Wilson * delay.
30c38102eb6f7a01fe70094a63054337f53ab5283dJesse Wilson *
31c38102eb6f7a01fe70094a63054337f53ab5283dJesse Wilson * <p>Recurring tasks are scheduled with either a fixed period or a fixed rate:
32c38102eb6f7a01fe70094a63054337f53ab5283dJesse Wilson * <ul>
33c38102eb6f7a01fe70094a63054337f53ab5283dJesse Wilson *   <li>With the default <strong>fixed-period execution</strong>, each
34c38102eb6f7a01fe70094a63054337f53ab5283dJesse Wilson *       successive run of a task is scheduled relative to the start time of
35c38102eb6f7a01fe70094a63054337f53ab5283dJesse Wilson *       the previous run, so two runs are never fired closer together in time
36c38102eb6f7a01fe70094a63054337f53ab5283dJesse Wilson *       than the specified {@code period}.
37c38102eb6f7a01fe70094a63054337f53ab5283dJesse Wilson *   <li>With <strong>fixed-rate execution</strong>, the start time of each
38c38102eb6f7a01fe70094a63054337f53ab5283dJesse Wilson *       successive run of a task is scheduled without regard for when the
39c38102eb6f7a01fe70094a63054337f53ab5283dJesse Wilson *       previous run took place. This may result in a series of bunched-up runs
40c38102eb6f7a01fe70094a63054337f53ab5283dJesse Wilson *       (one launched immediately after another) if delays prevent the timer
41c38102eb6f7a01fe70094a63054337f53ab5283dJesse Wilson *       from starting tasks on time.
42c38102eb6f7a01fe70094a63054337f53ab5283dJesse Wilson * </ul>
43f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson *
44c38102eb6f7a01fe70094a63054337f53ab5283dJesse Wilson * <p>When a timer is no longer needed, users should call {@link #cancel}, which
45c38102eb6f7a01fe70094a63054337f53ab5283dJesse Wilson * releases the timer's thread and other resources. Timers not explicitly
46c38102eb6f7a01fe70094a63054337f53ab5283dJesse Wilson * cancelled may hold resources indefinitely.
47c38102eb6f7a01fe70094a63054337f53ab5283dJesse Wilson *
48c38102eb6f7a01fe70094a63054337f53ab5283dJesse Wilson * <p>This class does not offer guarantees about the real-time nature of task
49c38102eb6f7a01fe70094a63054337f53ab5283dJesse Wilson * scheduling. Multiple threads can share a single timer without
50c38102eb6f7a01fe70094a63054337f53ab5283dJesse Wilson * synchronization.
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic class Timer {
53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final class TimerImpl extends Thread {
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
56f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        private static final class TimerHeap {
57f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            private int DEFAULT_HEAP_SIZE = 256;
58f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
59f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            private TimerTask[] timers = new TimerTask[DEFAULT_HEAP_SIZE];
60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
61f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            private int size = 0;
62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
63f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            private int deletedCancelledNumber = 0;
64f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
65f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            public TimerTask minimum() {
66f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                return timers[0];
67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
69f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            public boolean isEmpty() {
70f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                return size == 0;
71f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
72f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
73f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            public void insert(TimerTask task) {
74f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                if (timers.length == size) {
75f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    TimerTask[] appendedTimers = new TimerTask[size * 2];
76f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    System.arraycopy(timers, 0, appendedTimers, 0, size);
77f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    timers = appendedTimers;
78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
79f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                timers[size++] = task;
80f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                upHeap();
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
83f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            public void delete(int pos) {
84f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                // posible to delete any position of the heap
85f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                if (pos >= 0 && pos < size) {
86f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    timers[pos] = timers[--size];
87f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    timers[size] = null;
88f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    downHeap(pos);
89f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                }
90f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            }
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
92f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            private void upHeap() {
93f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                int current = size - 1;
94f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                int parent = (current - 1) / 2;
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
96f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                while (timers[current].when < timers[parent].when) {
97f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    // swap the two
98f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    TimerTask tmp = timers[current];
99f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    timers[current] = timers[parent];
100f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    timers[parent] = tmp;
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
102f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    // update pos and current
103f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    current = parent;
104f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    parent = (current - 1) / 2;
105f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                }
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
108f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            private void downHeap(int pos) {
109f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                int current = pos;
110f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                int child = 2 * current + 1;
111f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
112f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                while (child < size && size > 0) {
113f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    // compare the children if they exist
114f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    if (child + 1 < size
115f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                            && timers[child + 1].when < timers[child].when) {
116f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        child++;
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
118f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
119f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    // compare selected child with parent
120f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    if (timers[current].when < timers[child].when) {
121f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        break;
122f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    }
123f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
124f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    // swap the two
125f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    TimerTask tmp = timers[current];
126f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    timers[current] = timers[child];
127f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    timers[child] = tmp;
128f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
129f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    // update pos and current
130f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    current = child;
131f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    child = 2 * current + 1;
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
135f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            public void reset() {
136f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                timers = new TimerTask[DEFAULT_HEAP_SIZE];
137f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                size = 0;
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
140f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            public void adjustMinimum() {
141f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                downHeap(0);
142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
144f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            public void deleteIfCancelled() {
145f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                for (int i = 0; i < size; i++) {
146f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    if (timers[i].cancelled) {
147f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        deletedCancelledNumber++;
148f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        delete(i);
149f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        // re-try this point
150f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        i--;
151f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    }
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
155f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            private int getTask(TimerTask task) {
156f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                for (int i = 0; i < timers.length; i++) {
157f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    if (timers[i] == task) {
158f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        return i;
159f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    }
160f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                }
161f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                return -1;
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
163f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /**
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * True if the method cancel() of the Timer was called or the !!!stop()
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * method was invoked
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        private boolean cancelled;
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /**
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * True if the Timer has become garbage
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        private boolean finished;
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /**
1782feeee4119506ed1511942f80fc2f7eb431afab7Elliott Hughes         * Contains scheduled events, sorted according to
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * {@code when} field of TaskScheduled object.
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
181f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        private TimerHeap tasks = new TimerHeap();
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /**
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Starts a new timer.
185f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes         *
186a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson         * @param name thread's name
187a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson         * @param isDaemon daemon thread or not
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        TimerImpl(String name, boolean isDaemon) {
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.setName(name);
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.setDaemon(isDaemon);
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.start();
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /**
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * This method will be launched on separate thread for each Timer
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * object.
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public void run() {
201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while (true) {
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                TimerTask task;
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                synchronized (this) {
204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // need to check cancelled inside the synchronized block
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (cancelled) {
206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        return;
207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (tasks.isEmpty()) {
209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        if (finished) {
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            return;
211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        // no tasks scheduled -- sleep until any task appear
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        try {
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            this.wait();
21555392539fea537abfb6581b474918f9d611fba27Jesse Wilson                        } catch (InterruptedException ignored) {
216adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        continue;
218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
220adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    long currentTime = System.currentTimeMillis();
221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
222f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    task = tasks.minimum();
223adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    long timeToSleep;
224adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    synchronized (task.lock) {
226adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        if (task.cancelled) {
227f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                            tasks.delete(0);
228adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            continue;
229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        // check the time to sleep for the first task scheduled
232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        timeToSleep = task.when - currentTime;
233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
234adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (timeToSleep > 0) {
236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        // sleep!
237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        try {
238adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            this.wait(timeToSleep);
23955392539fea537abfb6581b474918f9d611fba27Jesse Wilson                        } catch (InterruptedException ignored) {
240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        continue;
242adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // no sleep is necessary before launching the task
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    synchronized (task.lock) {
247f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        int pos = 0;
248f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        if (tasks.minimum().when != task.when) {
249f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                            pos = tasks.getTask(task);
250f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        }
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        if (task.cancelled) {
252f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                            tasks.delete(tasks.getTask(task));
253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            continue;
254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        // set time to schedule
257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        task.setScheduledTime(task.when);
258adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
259adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        // remove task from queue
260f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        tasks.delete(pos);
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        // set when the next task should be launched
263adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        if (task.period >= 0) {
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            // this is a repeating task,
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            if (task.fixedRate) {
266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                // task is scheduled at fixed rate
267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                task.when = task.when + task.period;
268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            } else {
269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                // task is scheduled at fixed delay
270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                task.when = System.currentTimeMillis()
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                        + task.period;
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            }
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            // insert this task into queue
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            insertTask(task);
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        } else {
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            task.when = 0;
278adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
281adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
28255392539fea537abfb6581b474918f9d611fba27Jesse Wilson                boolean taskCompletedNormally = false;
283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                try {
284adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    task.run();
28555392539fea537abfb6581b474918f9d611fba27Jesse Wilson                    taskCompletedNormally = true;
28655392539fea537abfb6581b474918f9d611fba27Jesse Wilson                } finally {
28755392539fea537abfb6581b474918f9d611fba27Jesse Wilson                    if (!taskCompletedNormally) {
28855392539fea537abfb6581b474918f9d611fba27Jesse Wilson                        synchronized (this) {
28955392539fea537abfb6581b474918f9d611fba27Jesse Wilson                            cancelled = true;
29055392539fea537abfb6581b474918f9d611fba27Jesse Wilson                        }
29155392539fea537abfb6581b474918f9d611fba27Jesse Wilson                    }
292adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
296adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        private void insertTask(TimerTask newTask) {
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // callers are synchronized
298f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            tasks.insert(newTask);
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.notify();
300adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
302adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /**
303adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Cancels timer.
304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
305adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public synchronized void cancel() {
306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            cancelled = true;
307f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            tasks.reset();
308adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.notify();
309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
310adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
311adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public int purge() {
312adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (tasks.isEmpty()) {
313adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return 0;
314adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
315adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // callers are synchronized
316adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            tasks.deletedCancelledNumber = 0;
317f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            tasks.deleteIfCancelled();
318adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return tasks.deletedCancelledNumber;
319adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
320adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
321adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
322f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
323d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes    private static final class FinalizerHelper {
324d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes        private final TimerImpl impl;
325f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
326d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes        FinalizerHelper(TimerImpl impl) {
327d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes            this.impl = impl;
328d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes        }
329f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
330e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        @Override protected void finalize() throws Throwable {
331e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            try {
332e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom                synchronized (impl) {
333e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom                    impl.finished = true;
334e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom                    impl.notify();
335e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom                }
336e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            } finally {
337e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom                super.finalize();
338d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes            }
339d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes        }
340d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes    }
341f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
342d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes    private static long timerId;
343f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
344d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes    private synchronized static long nextId() {
345d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes        return timerId++;
346d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes    }
347adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
348adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /* This object will be used in synchronization purposes */
349a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson    private final TimerImpl impl;
350adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
351adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // Used to finalize thread
352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @SuppressWarnings("unused")
353a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson    private final FinalizerHelper finalizer;
354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
355adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
356adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Creates a new named {@code Timer} which may be specified to be run as a
357adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * daemon thread.
358f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
359a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson     * @param name the name of the {@code Timer}.
360a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson     * @param isDaemon true if {@code Timer}'s thread should be a daemon thread.
361a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson     * @throws NullPointerException is {@code name} is {@code null}
362adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
363adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Timer(String name, boolean isDaemon) {
36432c2297a959b72abdb18743f0519e1d8b7c7ea88Elliott Hughes        if (name == null) {
36586acc043d3334651ee26c65467d78d6cefedd397Kenny Root            throw new NullPointerException("name == null");
366d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes        }
367a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson        this.impl = new TimerImpl(name, isDaemon);
368a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson        this.finalizer = new FinalizerHelper(impl);
369adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
370f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
371adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
372adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Creates a new named {@code Timer} which does not run as a daemon thread.
373f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
374a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson     * @param name the name of the Timer.
375a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson     * @throws NullPointerException is {@code name} is {@code null}
376adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
377adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Timer(String name) {
378a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson        this(name, false);
379a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson    }
380f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
381a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson    /**
382a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson     * Creates a new {@code Timer} which may be specified to be run as a daemon thread.
383a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson     *
384a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson     * @param isDaemon {@code true} if the {@code Timer}'s thread should be a daemon thread.
385a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson     */
386a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson    public Timer(boolean isDaemon) {
387a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson        this("Timer-" + Timer.nextId(), isDaemon);
388f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    }
389f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
390a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson    /**
391a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson     * Creates a new non-daemon {@code Timer}.
392a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson     */
393a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson    public Timer() {
394a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson        this(false);
395adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
396adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
397adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
398c38102eb6f7a01fe70094a63054337f53ab5283dJesse Wilson     * Cancels the {@code Timer} and all scheduled tasks. If there is a
399adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * currently running task it is not affected. No more tasks may be scheduled
400adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * on this {@code Timer}. Subsequent calls do nothing.
401adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
402adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void cancel() {
403adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        impl.cancel();
404adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
405adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
406adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
407adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Removes all canceled tasks from the task queue. If there are no
408f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * other references on the tasks, then after this call they are free
409adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * to be garbage collected.
410f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
411adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the number of canceled tasks that were removed from the task
412adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         queue.
413adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
414adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public int purge() {
415adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (impl) {
416adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return impl.purge();
417adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
418adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
419adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
420adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
421adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Schedule a task for single execution. If {@code when} is less than the
422adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * current time, it will be scheduled to be executed as soon as possible.
423f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
424adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param task
425adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the task to schedule.
426adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param when
427adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            time of execution.
428f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * @throws IllegalArgumentException
429adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *                if {@code when.getTime() < 0}.
430f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * @throws IllegalStateException
431adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *                if the {@code Timer} has been canceled, or if the task has been
432adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *                scheduled or canceled.
433adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
434adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void schedule(TimerTask task, Date when) {
435adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (when.getTime() < 0) {
436cff1616012dc0d56c2da9af2b9b1183e76c7e044Elliott Hughes            throw new IllegalArgumentException("when < 0: " + when.getTime());
437adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
438adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        long delay = when.getTime() - System.currentTimeMillis();
439adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        scheduleImpl(task, delay < 0 ? 0 : delay, -1, false);
440adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
441adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
442adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
443adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Schedule a task for single execution after a specified delay.
444f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
445adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param task
446adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the task to schedule.
447adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param delay
448a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson     *            amount of time in milliseconds before execution.
449f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * @throws IllegalArgumentException
450adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *                if {@code delay < 0}.
451f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * @throws IllegalStateException
452adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *                if the {@code Timer} has been canceled, or if the task has been
453adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *                scheduled or canceled.
454adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
455adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void schedule(TimerTask task, long delay) {
456adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (delay < 0) {
457cff1616012dc0d56c2da9af2b9b1183e76c7e044Elliott Hughes            throw new IllegalArgumentException("delay < 0: " + delay);
458adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
459adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        scheduleImpl(task, delay, -1, false);
460adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
461adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
462adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
463adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Schedule a task for repeated fixed-delay execution after a specific delay.
464f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
465adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param task
466adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the task to schedule.
467adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param delay
468a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson     *            amount of time in milliseconds before first execution.
469adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param period
470a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson     *            amount of time in milliseconds between subsequent executions.
471f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * @throws IllegalArgumentException
472723f75d03dd4a6c51e9e1ff67847b10fe0cb16e6Jesse Wilson     *                if {@code delay < 0} or {@code period <= 0}.
473f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * @throws IllegalStateException
474adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *                if the {@code Timer} has been canceled, or if the task has been
475adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *                scheduled or canceled.
476adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
477adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void schedule(TimerTask task, long delay, long period) {
478adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (delay < 0 || period <= 0) {
479adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException();
480adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
481adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        scheduleImpl(task, delay, period, false);
482adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
483adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
484adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
485adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Schedule a task for repeated fixed-delay execution after a specific time
486adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * has been reached.
487f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
488adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param task
489adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the task to schedule.
490adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param when
491adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            time of first execution.
492adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param period
493a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson     *            amount of time in milliseconds between subsequent executions.
494f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * @throws IllegalArgumentException
495723f75d03dd4a6c51e9e1ff67847b10fe0cb16e6Jesse Wilson     *                if {@code when.getTime() < 0} or {@code period <= 0}.
496f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * @throws IllegalStateException
497adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *                if the {@code Timer} has been canceled, or if the task has been
498adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *                scheduled or canceled.
499adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
500adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void schedule(TimerTask task, Date when, long period) {
501adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (period <= 0 || when.getTime() < 0) {
502adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException();
503adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
504adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        long delay = when.getTime() - System.currentTimeMillis();
505adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        scheduleImpl(task, delay < 0 ? 0 : delay, period, false);
506adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
507adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
508adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
509adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Schedule a task for repeated fixed-rate execution after a specific delay
510adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * has passed.
511f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
512adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param task
513adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the task to schedule.
514adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param delay
515a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson     *            amount of time in milliseconds before first execution.
516adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param period
517a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson     *            amount of time in milliseconds between subsequent executions.
518f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * @throws IllegalArgumentException
519723f75d03dd4a6c51e9e1ff67847b10fe0cb16e6Jesse Wilson     *                if {@code delay < 0} or {@code period <= 0}.
520f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * @throws IllegalStateException
521adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *                if the {@code Timer} has been canceled, or if the task has been
522adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *                scheduled or canceled.
523adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
524adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
525adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (delay < 0 || period <= 0) {
526adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException();
527adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
528adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        scheduleImpl(task, delay, period, true);
529adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
530adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
531adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
532adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Schedule a task for repeated fixed-rate execution after a specific time
533adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * has been reached.
534f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
535adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param task
536adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the task to schedule.
537adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param when
538adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            time of first execution.
539adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param period
540a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson     *            amount of time in milliseconds between subsequent executions.
541f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * @throws IllegalArgumentException
542723f75d03dd4a6c51e9e1ff67847b10fe0cb16e6Jesse Wilson     *                if {@code when.getTime() < 0} or {@code period <= 0}.
543f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * @throws IllegalStateException
544adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *                if the {@code Timer} has been canceled, or if the task has been
545adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *                scheduled or canceled.
546adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
547adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void scheduleAtFixedRate(TimerTask task, Date when, long period) {
548adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (period <= 0 || when.getTime() < 0) {
549adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException();
550adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
551adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        long delay = when.getTime() - System.currentTimeMillis();
55255392539fea537abfb6581b474918f9d611fba27Jesse Wilson        scheduleImpl(task, delay, period, true);
553adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
554adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
555f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    /*
556adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Schedule a task.
557adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
558b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes    private void scheduleImpl(TimerTask task, long delay, long period, boolean fixed) {
559adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (impl) {
560adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (impl.cancelled) {
561b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes                throw new IllegalStateException("Timer was canceled");
562adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
563adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
564adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            long when = delay + System.currentTimeMillis();
565adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
566adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (when < 0) {
567b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes                throw new IllegalArgumentException("Illegal delay to start the TimerTask: " + when);
568adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
569adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
570adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            synchronized (task.lock) {
571adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (task.isScheduled()) {
572b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes                    throw new IllegalStateException("TimerTask is scheduled already");
573adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
574adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
575adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (task.cancelled) {
576b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes                    throw new IllegalStateException("TimerTask is canceled");
577adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
578adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
579adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                task.when = when;
580adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                task.period = period;
581adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                task.fixedRate = fixed;
582adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
583adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
584adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // insert the newTask into queue
585adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            impl.insertTask(task);
586adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
587adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
588adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
589