blob: ac5b160670b0d362e8f422d3042619a051244770 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 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 com.android.server;
18
19import android.os.SystemClock;
20
21import android.os.ConditionVariable;
22
23/**
24 * Utility class that you can call on with a timeout, and get called back
25 * after a given time, dealing correctly with restarting the timeout.
26 *
27 * <p>For example, this class is used by the android.os.Vibrator class.
28 */
29abstract class ResettableTimeout
30{
31 /**
32 * Override this do what you need to do when it's starting
33 * This is called with the monitor on this method held, so be careful.
34 *
35 * @param alreadyOn is true if it's currently running
36 */
37 public abstract void on(boolean alreadyOn);
38
39 /**
40 * Override this to do what you need to do when it's stopping.
41 * This is called with the monitor on this method held, so be careful.
42 */
43 public abstract void off();
44
45 /**
46 * Does the following steps.
47 * <p>1. Call on()</p>
48 * <p>2. Start the timer.</p>
49 * <p>3. At the timeout, calls off()<p>
50 * <p>If you call this again, the timeout is reset to the new one</p>
51 */
52 public void go(long milliseconds)
53 {
54 synchronized (this) {
55 mOffAt = SystemClock.uptimeMillis() + milliseconds;
56
57 boolean alreadyOn;
58
59 // By starting the thread first and waiting, we ensure that if the
60 // thread to stop it can't start, we don't turn the vibrator on
61 // forever. This still isn't really sufficient, because we don't
62 // have another processor watching us. We really should have a
63 // service for this in case our process crashes.
64 if (mThread == null) {
65 alreadyOn = false;
66 mLock.close();
67 mThread = new T();
68 mThread.start();
69 mLock.block();
70 mOffCalled = false;
71 } else {
72 alreadyOn = true;
73 // poke the thread so it gets the new timeout.
74 mThread.interrupt();
75 }
76 on(alreadyOn);
77 }
78 }
79
80 /**
81 * Cancel the timeout and call off now.
82 */
83 public void cancel()
84 {
85 synchronized (this) {
86 mOffAt = 0;
87 if (mThread != null) {
88 mThread.interrupt();
89 mThread = null;
90 }
91 if (!mOffCalled) {
92 mOffCalled = true;
93 off();
94 }
95 }
96 }
97
98 private class T extends Thread
99 {
100 public void run()
101 {
102 mLock.open();
103 while (true) {
104 long diff;
105 synchronized (this) {
106 diff = mOffAt - SystemClock.uptimeMillis();
107 if (diff <= 0) {
108 mOffCalled = true;
109 off();
110 mThread = null;
111 break;
112 }
113 }
114 try {
115 sleep(diff);
116 }
117 catch (InterruptedException e) {
118 }
119 }
120 }
121 }
122
123 private ConditionVariable mLock = new ConditionVariable();
124
125 // turn it off at this time.
126 private volatile long mOffAt;
127 private volatile boolean mOffCalled;
128
129 private Thread mThread;
130
131}
132