135 lines
3.9 KiB
Java
135 lines
3.9 KiB
Java
/*
|
|
* Copyright (C) 2007 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.android.server;
|
|
|
|
import android.compat.annotation.UnsupportedAppUsage;
|
|
import android.os.ConditionVariable;
|
|
import android.os.SystemClock;
|
|
|
|
/**
|
|
* Utility class that you can call on with a timeout, and get called back
|
|
* after a given time, dealing correctly with restarting the timeout.
|
|
*
|
|
* <p>For example, this class is used by the android.os.Vibrator class.
|
|
*/
|
|
abstract class ResettableTimeout
|
|
{
|
|
/**
|
|
* Override this do what you need to do when it's starting
|
|
* This is called with the monitor on this method held, so be careful.
|
|
*
|
|
* @param alreadyOn is true if it's currently running
|
|
*/
|
|
public abstract void on(boolean alreadyOn);
|
|
|
|
/**
|
|
* Override this to do what you need to do when it's stopping.
|
|
* This is called with the monitor on this method held, so be careful.
|
|
*/
|
|
public abstract void off();
|
|
|
|
/**
|
|
* Does the following steps.
|
|
* <p>1. Call on()</p>
|
|
* <p>2. Start the timer.</p>
|
|
* <p>3. At the timeout, calls off()<p>
|
|
* <p>If you call this again, the timeout is reset to the new one</p>
|
|
*/
|
|
public void go(long milliseconds)
|
|
{
|
|
synchronized (this) {
|
|
mOffAt = SystemClock.uptimeMillis() + milliseconds;
|
|
|
|
boolean alreadyOn;
|
|
|
|
// By starting the thread first and waiting, we ensure that if the
|
|
// thread to stop it can't start, we don't turn the vibrator on
|
|
// forever. This still isn't really sufficient, because we don't
|
|
// have another processor watching us. We really should have a
|
|
// service for this in case our process crashes.
|
|
if (mThread == null) {
|
|
alreadyOn = false;
|
|
mLock.close();
|
|
mThread = new T();
|
|
mThread.start();
|
|
mLock.block();
|
|
mOffCalled = false;
|
|
} else {
|
|
alreadyOn = true;
|
|
// poke the thread so it gets the new timeout.
|
|
mThread.interrupt();
|
|
}
|
|
on(alreadyOn);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Cancel the timeout and call off now.
|
|
*/
|
|
public void cancel()
|
|
{
|
|
synchronized (this) {
|
|
mOffAt = 0;
|
|
if (mThread != null) {
|
|
mThread.interrupt();
|
|
mThread = null;
|
|
}
|
|
if (!mOffCalled) {
|
|
mOffCalled = true;
|
|
off();
|
|
}
|
|
}
|
|
}
|
|
|
|
private class T extends Thread
|
|
{
|
|
public void run()
|
|
{
|
|
mLock.open();
|
|
while (true) {
|
|
long diff;
|
|
synchronized (this) {
|
|
diff = mOffAt - SystemClock.uptimeMillis();
|
|
if (diff <= 0) {
|
|
mOffCalled = true;
|
|
off();
|
|
mThread = null;
|
|
break;
|
|
}
|
|
}
|
|
try {
|
|
sleep(diff);
|
|
}
|
|
catch (InterruptedException e) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@UnsupportedAppUsage
|
|
private ConditionVariable mLock = new ConditionVariable();
|
|
|
|
// turn it off at this time.
|
|
@UnsupportedAppUsage
|
|
private volatile long mOffAt;
|
|
private volatile boolean mOffCalled;
|
|
|
|
private Thread mThread;
|
|
|
|
}
|
|
|