Home | History | Annotate | Download | only in server
      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 
     17 package com.android.server;
     18 
     19 import android.os.SystemClock;
     20 
     21 import 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  */
     29 abstract 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