1/*
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
133