blob: d5934102c8569636b6b2978ab48f85698e123ca0 [file] [log] [blame]
/*
* 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 android.os;
import android.util.Log;
import com.android.internal.os.RuntimeInit;
/**
* This class gives you control of the power state of the device.
*
* <p><b>Device battery life will be significantly affected by the use of this API.</b> Do not
* acquire WakeLocks unless you really need them, use the minimum levels possible, and be sure
* to release it as soon as you can.
*
* <p>You can obtain an instance of this class by calling
* {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}.
*
* <p>The primary API you'll use is {@link #newWakeLock(int, String) newWakeLock()}. This will
* create a {@link PowerManager.WakeLock} object. You can then use methods on this object to
* control the power state of the device. In practice it's quite simple:
*
* {@samplecode
* PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
* PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "My Tag");
* wl.acquire();
* ..screen will stay on during this section..
* wl.release();
* }
*
* <p>The following flags are defined, with varying effects on system power. <i>These flags are
* mutually exclusive - you may only specify one of them.</i>
* <table border="2" width="85%" align="center" frame="hsides" rules="rows">
*
* <thead>
* <tr><th>Flag Value</th>
* <th>CPU</th> <th>Screen</th> <th>Keyboard</th></tr>
* </thead>
*
* <tbody>
* <tr><th>{@link #PARTIAL_WAKE_LOCK}</th>
* <td>On*</td> <td>Off</td> <td>Off</td>
* </tr>
*
* <tr><th>{@link #SCREEN_DIM_WAKE_LOCK}</th>
* <td>On</td> <td>Dim</td> <td>Off</td>
* </tr>
*
* <tr><th>{@link #SCREEN_BRIGHT_WAKE_LOCK}</th>
* <td>On</td> <td>Bright</td> <td>Off</td>
* </tr>
*
* <tr><th>{@link #FULL_WAKE_LOCK}</th>
* <td>On</td> <td>Bright</td> <td>Bright</td>
* </tr>
* </tbody>
* </table>
*
* <p>*<i>If you hold a partial wakelock, the CPU will continue to run, irrespective of any timers
* and even after the user presses the power button. In all other wakelocks, the CPU will run, but
* the user can still put the device to sleep using the power button.</i>
*
* <p>In addition, you can add two more flags, which affect behavior of the screen only. <i>These
* flags have no effect when combined with a {@link #PARTIAL_WAKE_LOCK}.</i>
* <table border="2" width="85%" align="center" frame="hsides" rules="rows">
*
* <thead>
* <tr><th>Flag Value</th> <th>Description</th></tr>
* </thead>
*
* <tbody>
* <tr><th>{@link #ACQUIRE_CAUSES_WAKEUP}</th>
* <td>Normal wake locks don't actually turn on the illumination. Instead, they cause
* the illumination to remain on once it turns on (e.g. from user activity). This flag
* will force the screen and/or keyboard to turn on immediately, when the WakeLock is
* acquired. A typical use would be for notifications which are important for the user to
* see immediately.</td>
* </tr>
*
* <tr><th>{@link #ON_AFTER_RELEASE}</th>
* <td>If this flag is set, the user activity timer will be reset when the WakeLock is
* released, causing the illumination to remain on a bit longer. This can be used to
* reduce flicker if you are cycling between wake lock conditions.</td>
* </tr>
* </tbody>
* </table>
*
*
*/
public class PowerManager
{
private static final String TAG = "PowerManager";
/**
* These internal values define the underlying power elements that we might
* want to control individually. Eventually we'd like to expose them.
*/
private static final int WAKE_BIT_CPU_STRONG = 1;
private static final int WAKE_BIT_CPU_WEAK = 2;
private static final int WAKE_BIT_SCREEN_DIM = 4;
private static final int WAKE_BIT_SCREEN_BRIGHT = 8;
private static final int WAKE_BIT_KEYBOARD_BRIGHT = 16;
private static final int WAKE_BIT_PROXIMITY_SCREEN_OFF = 32;
private static final int LOCK_MASK = WAKE_BIT_CPU_STRONG
| WAKE_BIT_CPU_WEAK
| WAKE_BIT_SCREEN_DIM
| WAKE_BIT_SCREEN_BRIGHT
| WAKE_BIT_KEYBOARD_BRIGHT
| WAKE_BIT_PROXIMITY_SCREEN_OFF;
/**
* Wake lock that ensures that the CPU is running. The screen might
* not be on.
*/
public static final int PARTIAL_WAKE_LOCK = WAKE_BIT_CPU_STRONG;
/**
* Wake lock that ensures that the screen and keyboard are on at
* full brightness.
*/
public static final int FULL_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_BRIGHT
| WAKE_BIT_KEYBOARD_BRIGHT;
/**
* Wake lock that ensures that the screen is on at full brightness;
* the keyboard backlight will be allowed to go off.
*/
public static final int SCREEN_BRIGHT_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_BRIGHT;
/**
* Wake lock that ensures that the screen is on (but may be dimmed);
* the keyboard backlight will be allowed to go off.
*/
public static final int SCREEN_DIM_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_DIM;
/**
* Wake lock that turns the screen off when the proximity sensor activates.
* Since not all devices have proximity sensors, use
* {@link #getSupportedWakeLockFlags() getSupportedWakeLockFlags()} to determine if
* this wake lock mode is supported.
*
* {@hide}
*/
public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = WAKE_BIT_PROXIMITY_SCREEN_OFF;
/**
* Normally wake locks don't actually wake the device, they just cause
* it to remain on once it's already on. Think of the video player
* app as the normal behavior. Notifications that pop up and want
* the device to be on are the exception; use this flag to be like them.
* <p>
* Does not work with PARTIAL_WAKE_LOCKs.
*/
public static final int ACQUIRE_CAUSES_WAKEUP = 0x10000000;
/**
* When this wake lock is released, poke the user activity timer
* so the screen stays on for a little longer.
* <p>
* Will not turn the screen on if it is not already on. See {@link #ACQUIRE_CAUSES_WAKEUP}
* if you want that.
* <p>
* Does not work with PARTIAL_WAKE_LOCKs.
*/
public static final int ON_AFTER_RELEASE = 0x20000000;
/**
* Class lets you say that you need to have the device on.
*
* <p>Call release when you are done and don't need the lock anymore.
*/
public class WakeLock
{
static final int RELEASE_WAKE_LOCK = 1;
Runnable mReleaser = new Runnable() {
public void run() {
release();
}
};
int mFlags;
String mTag;
IBinder mToken;
int mCount = 0;
boolean mRefCounted = true;
boolean mHeld = false;
WakeLock(int flags, String tag)
{
switch (flags & LOCK_MASK) {
case PARTIAL_WAKE_LOCK:
case SCREEN_DIM_WAKE_LOCK:
case SCREEN_BRIGHT_WAKE_LOCK:
case FULL_WAKE_LOCK:
case PROXIMITY_SCREEN_OFF_WAKE_LOCK:
break;
default:
throw new IllegalArgumentException();
}
mFlags = flags;
mTag = tag;
mToken = new Binder();
}
/**
* Sets whether this WakeLock is ref counted.
*
* @param value true for ref counted, false for not ref counted.
*/
public void setReferenceCounted(boolean value)
{
mRefCounted = value;
}
/**
* Makes sure the device is on at the level you asked when you created
* the wake lock.
*/
public void acquire()
{
synchronized (mToken) {
if (!mRefCounted || mCount++ == 0) {
try {
mService.acquireWakeLock(mFlags, mToken, mTag);
} catch (RemoteException e) {
}
mHeld = true;
}
}
}
/**
* Makes sure the device is on at the level you asked when you created
* the wake lock. The lock will be released after the given timeout.
*
* @param timeout Release the lock after the give timeout in milliseconds.
*/
public void acquire(long timeout) {
acquire();
mHandler.postDelayed(mReleaser, timeout);
}
/**
* Release your claim to the CPU or screen being on.
*
* <p>
* It may turn off shortly after you release it, or it may not if there
* are other wake locks held.
*/
public void release()
{
synchronized (mToken) {
if (!mRefCounted || --mCount == 0) {
try {
mService.releaseWakeLock(mToken);
} catch (RemoteException e) {
}
mHeld = false;
}
if (mCount < 0) {
throw new RuntimeException("WakeLock under-locked " + mTag);
}
}
}
public boolean isHeld()
{
synchronized (mToken) {
return mHeld;
}
}
public String toString() {
synchronized (mToken) {
return "WakeLock{"
+ Integer.toHexString(System.identityHashCode(this))
+ " held=" + mHeld + ", refCount=" + mCount + "}";
}
}
@Override
protected void finalize() throws Throwable
{
synchronized (mToken) {
if (mHeld) {
try {
mService.releaseWakeLock(mToken);
} catch (RemoteException e) {
}
RuntimeInit.crash(TAG, new Exception(
"WakeLock finalized while still held: "+mTag));
}
}
}
}
/**
* Get a wake lock at the level of the flags parameter. Call
* {@link WakeLock#acquire() acquire()} on the object to acquire the
* wake lock, and {@link WakeLock#release release()} when you are done.
*
* {@samplecode
*PowerManager pm = (PowerManager)mContext.getSystemService(
* Context.POWER_SERVICE);
*PowerManager.WakeLock wl = pm.newWakeLock(
* PowerManager.SCREEN_DIM_WAKE_LOCK
* | PowerManager.ON_AFTER_RELEASE,
* TAG);
*wl.acquire();
* // ...
*wl.release();
* }
*
* @param flags Combination of flag values defining the requested behavior of the WakeLock.
* @param tag Your class name (or other tag) for debugging purposes.
*
* @see WakeLock#acquire()
* @see WakeLock#release()
*/
public WakeLock newWakeLock(int flags, String tag)
{
return new WakeLock(flags, tag);
}
/**
* User activity happened.
* <p>
* Turns the device from whatever state it's in to full on, and resets
* the auto-off timer.
*
* @param when is used to order this correctly with the wake lock calls.
* This time should be in the {@link SystemClock#uptimeMillis
* SystemClock.uptimeMillis()} time base.
* @param noChangeLights should be true if you don't want the lights to
* turn on because of this event. This is set when the power
* key goes down. We want the device to stay on while the button
* is down, but we're about to turn off. Otherwise the lights
* flash on and then off and it looks weird.
*/
public void userActivity(long when, boolean noChangeLights)
{
try {
mService.userActivity(when, noChangeLights);
} catch (RemoteException e) {
}
}
/**
* Force the device to go to sleep. Overrides all the wake locks that are
* held.
*
* @param time is used to order this correctly with the wake lock calls.
* The time should be in the {@link SystemClock#uptimeMillis
* SystemClock.uptimeMillis()} time base.
*/
public void goToSleep(long time)
{
try {
mService.goToSleep(time);
} catch (RemoteException e) {
}
}
/**
* Returns the set of flags for {@link #newWakeLock(int, String) newWakeLock()}
* that are supported on the device.
* For example, to test to see if the {@link #PROXIMITY_SCREEN_OFF_WAKE_LOCK}
* is supported:
*
* {@samplecode
* PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
* int supportedFlags = pm.getSupportedWakeLockFlags();
* boolean proximitySupported = ((supportedFlags & PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)
* == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK);
* }
*
* @return the set of supported WakeLock flags.
*
* {@hide}
*/
public int getSupportedWakeLockFlags()
{
try {
return mService.getSupportedWakeLockFlags();
} catch (RemoteException e) {
return 0;
}
}
private PowerManager()
{
}
/**
* {@hide}
*/
public PowerManager(IPowerManager service, Handler handler)
{
mService = service;
mHandler = handler;
}
/**
* TODO: It would be nice to be able to set the poke lock here,
* but I'm not sure what would be acceptable as an interface -
* either a PokeLock object (like WakeLock) or, possibly just a
* method call to set the poke lock.
*/
IPowerManager mService;
Handler mHandler;
}