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