diff options
Diffstat (limited to 'core/java/android/os/PowerManager.java')
-rw-r--r-- | core/java/android/os/PowerManager.java | 915 |
1 files changed, 577 insertions, 338 deletions
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 903c8b3..ae50ddb 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -16,22 +16,25 @@ package android.os; +import android.content.Context; import android.util.Log; /** - * 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 + * 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 {@link WakeLock}s unless you really need them, use the minimum levels + * possible, and be sure to release them as soon as possible. + * </p><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: - * + * </p><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 the wake lock object to control the power state of the device. + * </p><p> + * 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"); @@ -39,11 +42,11 @@ import android.util.Log; * ..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"> + * </p><p> + * The following wake lock levels are defined, with varying effects on system power. + * <i>These levels 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> @@ -67,15 +70,16 @@ import android.util.Log; * </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"> + * </p><p> + * *<i>If you hold a partial wake lock, the CPU will continue to run, regardless of any + * display timeouts or the state of the screen and even after the user presses the power button. + * In all other wake locks, the CPU will run, but the user can still put the device to sleep + * using the power button.</i> + * </p><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> @@ -96,113 +100,132 @@ import android.util.Log; * </tr> * </tbody> * </table> - * + * </p><p> * Any application using a WakeLock must request the {@code android.permission.WAKE_LOCK} * permission in an {@code <uses-permission>} element of the application's manifest. + * </p> */ -public class PowerManager -{ +public final 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. + + /* NOTE: Wake lock levels were previously defined as a bit field, except that only a few + * combinations were actually supported so the bit field was removed. This explains + * why the numbering scheme is so odd. If adding a new wake lock level, any unused + * value can be used. */ - 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. + * Wake lock level: Ensures that the CPU is running; the screen and keyboard + * backlight will be allowed to go off. + * <p> + * If the user presses the power button, then the screen will be turned off + * but the CPU will be kept on until all partial wake locks have been released. + * </p> */ - public static final int PARTIAL_WAKE_LOCK = WAKE_BIT_CPU_STRONG; + public static final int PARTIAL_WAKE_LOCK = 0x00000001; /** - * Wake lock that ensures that the screen and keyboard are on at - * full brightness. + * Wake lock level: Ensures that the screen is on (but may be dimmed); + * the keyboard backlight will be allowed to go off. + * <p> + * If the user presses the power button, then the {@link #SCREEN_DIM_WAKE_LOCK} will be + * implicitly released by the system, causing both the screen and the CPU to be turned off. + * Contrast with {@link #PARTIAL_WAKE_LOCK}. + * </p> * - * <p class="note">Most applications should strongly consider using - * {@link android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON}. - * This window flag will be correctly managed by the platform - * as the user moves between applications and doesn't require a special permission.</p> + * @deprecated Most applications should use + * {@link android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON} instead + * of this type of wake lock, as it will be correctly managed by the platform + * as the user moves between applications and doesn't require a special permission. */ - public static final int FULL_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_BRIGHT - | WAKE_BIT_KEYBOARD_BRIGHT; + @Deprecated + public static final int SCREEN_DIM_WAKE_LOCK = 0x00000006; /** + * Wake lock level: Ensures that the screen is on at full brightness; + * the keyboard backlight will be allowed to go off. + * <p> + * If the user presses the power button, then the {@link #SCREEN_BRIGHT_WAKE_LOCK} will be + * implicitly released by the system, causing both the screen and the CPU to be turned off. + * Contrast with {@link #PARTIAL_WAKE_LOCK}. + * </p> + * * @deprecated Most applications should use * {@link android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON} instead * of this type of wake lock, as it will be correctly managed by the platform * as the user moves between applications and doesn't require a special permission. - * - * Wake lock that ensures that the screen is on at full brightness; - * the keyboard backlight will be allowed to go off. */ @Deprecated - public static final int SCREEN_BRIGHT_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_BRIGHT; + public static final int SCREEN_BRIGHT_WAKE_LOCK = 0x0000000a; /** - * Wake lock that ensures that the screen is on (but may be dimmed); - * the keyboard backlight will be allowed to go off. + * Wake lock level: Ensures that the screen and keyboard backlight are on at + * full brightness. + * <p> + * If the user presses the power button, then the {@link #FULL_WAKE_LOCK} will be + * implicitly released by the system, causing both the screen and the CPU to be turned off. + * Contrast with {@link #PARTIAL_WAKE_LOCK}. + * </p> + * + * @deprecated Most applications should use + * {@link android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON} instead + * of this type of wake lock, as it will be correctly managed by the platform + * as the user moves between applications and doesn't require a special permission. */ - public static final int SCREEN_DIM_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_DIM; + @Deprecated + public static final int FULL_WAKE_LOCK = 0x0000001a; /** - * 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. + * Wake lock level: Turns the screen off when the proximity sensor activates. + * <p> + * Since not all devices have proximity sensors, use {@link #isWakeLockLevelSupported} + * to determine whether this wake lock level is supported. + * </p> * * {@hide} */ - public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = WAKE_BIT_PROXIMITY_SCREEN_OFF; + public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 0x00000020; /** - * Flag for {@link WakeLock#release release(int)} to defer releasing a - * {@link #WAKE_BIT_PROXIMITY_SCREEN_OFF} wakelock until the proximity sensor returns - * a negative value. + * Mask for the wake lock level component of a combined wake lock level and flags integer. * - * {@hide} + * @hide */ - public static final int WAIT_FOR_PROXIMITY_NEGATIVE = 1; + public static final int WAKE_LOCK_LEVEL_MASK = 0x0000ffff; /** + * Wake lock flag: Turn the screen on when the wake lock is acquired. + * <p> * 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 screen to remain on once it's already on. Think of the video player + * application 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. + * </p><p> + * Cannot be used with {@link #PARTIAL_WAKE_LOCK}. + * </p> */ public static final int ACQUIRE_CAUSES_WAKEUP = 0x10000000; /** - * When this wake lock is released, poke the user activity timer + * Wake lock flag: 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. + * Will not turn the screen on if it is not already on. + * See {@link #ACQUIRE_CAUSES_WAKEUP} if you want that. + * </p><p> + * Cannot be used with {@link #PARTIAL_WAKE_LOCK}. + * </p> */ public static final int ON_AFTER_RELEASE = 0x20000000; /** - * Brightness value to use when battery is low. - * @hide + * Flag for {@link WakeLock#release release(int)} to defer releasing a + * {@link #WAKE_BIT_PROXIMITY_SCREEN_OFF} wake lock until the proximity sensor returns + * a negative value. + * + * {@hide} */ - public static final int BRIGHTNESS_LOW_BATTERY = 10; + public static final int WAIT_FOR_PROXIMITY_NEGATIVE = 1; /** * Brightness value for fully on. @@ -211,46 +234,181 @@ public class PowerManager public static final int BRIGHTNESS_ON = 255; /** - * Brightness value for dim backlight. + * Brightness value for fully off. + * @hide + */ + public static final int BRIGHTNESS_OFF = 0; + + // Note: Be sure to update android.os.BatteryStats and PowerManager.h + // if adding or modifying user activity event constants. + + /** + * User activity event type: Unspecified event type. * @hide */ - public static final int BRIGHTNESS_DIM = 20; + public static final int USER_ACTIVITY_EVENT_OTHER = 0; /** - * Brightness value for fully off. + * User activity event type: Button or key pressed or released. * @hide */ - public static final int BRIGHTNESS_OFF = 0; + public static final int USER_ACTIVITY_EVENT_BUTTON = 1; /** - * 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. + * User activity event type: Touch down, move or up. + * @hide + */ + public static final int USER_ACTIVITY_EVENT_TOUCH = 2; + + /** + * User activity flag: Do not restart the user activity timeout or brighten + * the display in response to user activity if it is already dimmed. + * @hide + */ + public static final int USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS = 1 << 0; + + /** + * Go to sleep reason code: Going to sleep due by user request. + * @hide + */ + public static final int GO_TO_SLEEP_REASON_USER = 0; + + /** + * Go to sleep reason code: Going to sleep due by request of the + * device administration policy. + * @hide + */ + public static final int GO_TO_SLEEP_REASON_DEVICE_ADMIN = 1; + + /** + * Go to sleep reason code: Going to sleep due to a screen timeout. + * @hide + */ + public static final int GO_TO_SLEEP_REASON_TIMEOUT = 2; + + final Context mContext; + final IPowerManager mService; + final Handler mHandler; + + /** + * {@hide} + */ + public PowerManager(Context context, IPowerManager service, Handler handler) { + mContext = context; + mService = service; + mHandler = handler; + } + + /** + * Gets the minimum supported screen brightness setting. + * The screen may be allowed to become dimmer than this value but + * this is the minimum value that can be set by the user. + * @hide + */ + public int getMinimumScreenBrightnessSetting() { + return mContext.getResources().getInteger( + com.android.internal.R.integer.config_screenBrightnessSettingMinimum); + } + + /** + * Gets the maximum supported screen brightness setting. + * The screen may be allowed to become dimmer than this value but + * this is the maximum value that can be set by the user. + * @hide + */ + public int getMaximumScreenBrightnessSetting() { + return mContext.getResources().getInteger( + com.android.internal.R.integer.config_screenBrightnessSettingMaximum); + } + + /** + * Gets the default screen brightness setting. + * @hide + */ + public int getDefaultScreenBrightnessSetting() { + return mContext.getResources().getInteger( + com.android.internal.R.integer.config_screenBrightnessSettingDefault); + } + + /** + * Returns true if the screen auto-brightness adjustment setting should + * be available in the UI. This setting is experimental and disabled by default. + * @hide + */ + public static boolean useScreenAutoBrightnessAdjustmentFeature() { + return SystemProperties.getBoolean("persist.power.useautobrightadj", false); + } + + /** + * Returns true if the twilight service should be used to adjust screen brightness + * policy. This setting is experimental and disabled by default. + * @hide + */ + public static boolean useTwilightAdjustmentFeature() { + return SystemProperties.getBoolean("persist.power.usetwilightadj", false); + } + + /** + * Creates a new wake lock with the specified level and flags. * <p> - * Any application using a WakeLock must request the {@code android.permission.WAKE_LOCK} - * permission in an {@code <uses-permission>} element of the application's manifest. + * The {@code levelAndFlags} parameter specifies a wake lock level and optional flags + * combined using the logical OR operator. + * </p><p> + * The wake lock levels are: {@link #PARTIAL_WAKE_LOCK}, + * {@link #FULL_WAKE_LOCK}, {@link #SCREEN_DIM_WAKE_LOCK} + * and {@link #SCREEN_BRIGHT_WAKE_LOCK}. Exactly one wake lock level must be + * specified as part of the {@code levelAndFlags} parameter. + * </p><p> + * The wake lock flags are: {@link #ACQUIRE_CAUSES_WAKEUP} + * and {@link #ON_AFTER_RELEASE}. Multiple flags can be combined as part of the + * {@code levelAndFlags} parameters. + * </p><p> + * Call {@link WakeLock#acquire() acquire()} on the object to acquire the + * wake lock, and {@link WakeLock#release release()} when you are done. + * </p><p> + * {@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(); + * // ... do work... + * wl.release(); + * } + * </p><p> + * Although a wake lock can be created without special permissions, + * the {@link android.Manifest.permission#WAKE_LOCK} permission is + * required to actually acquire or release the wake lock that is returned. + * </p><p class="note"> + * If using this to keep the screen on, you should strongly consider using + * {@link android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON} instead. + * This window flag will be correctly managed by the platform + * as the user moves between applications and doesn't require a special permission. + * </p> + * + * @param levelAndFlags Combination of wake lock level and 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() + * @see #PARTIAL_WAKE_LOCK + * @see #FULL_WAKE_LOCK + * @see #SCREEN_DIM_WAKE_LOCK + * @see #SCREEN_BRIGHT_WAKE_LOCK + * @see #ACQUIRE_CAUSES_WAKEUP + * @see #ON_AFTER_RELEASE */ - public class WakeLock - { - static final int RELEASE_WAKE_LOCK = 1; + public WakeLock newWakeLock(int levelAndFlags, String tag) { + validateWakeLockParameters(levelAndFlags, tag); + return new WakeLock(levelAndFlags, tag); + } - Runnable mReleaser = new Runnable() { - public void run() { - release(); - } - }; - - int mFlags; - String mTag; - IBinder mToken; - int mCount = 0; - boolean mRefCounted = true; - boolean mHeld = false; - WorkSource mWorkSource; - - WakeLock(int flags, String tag) - { - switch (flags & LOCK_MASK) { + /** @hide */ + public static void validateWakeLockParameters(int levelAndFlags, String tag) { + switch (levelAndFlags & WAKE_LOCK_LEVEL_MASK) { case PARTIAL_WAKE_LOCK: case SCREEN_DIM_WAKE_LOCK: case SCREEN_BRIGHT_WAKE_LOCK: @@ -258,42 +416,282 @@ public class PowerManager case PROXIMITY_SCREEN_OFF_WAKE_LOCK: break; default: - throw new IllegalArgumentException(); + throw new IllegalArgumentException("Must specify a valid wake lock level."); + } + if (tag == null) { + throw new IllegalArgumentException("The tag must not be null."); + } + } + + /** + * Notifies the power manager that user activity happened. + * <p> + * Resets the auto-off timer and brightens the screen if the device + * is not asleep. This is what happens normally when a key or the touch + * screen is pressed or when some other user activity occurs. + * This method does not wake up the device if it has been put to sleep. + * </p><p> + * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission. + * </p> + * + * @param when The time of the user activity, in the {@link SystemClock#uptimeMillis()} + * time base. This timestamp is used to correctly order the user activity request with + * other power management functions. It should be set + * to the timestamp of the input event that caused the user activity. + * @param noChangeLights If true, does not cause the keyboard backlight to turn on + * because of this event. This is set when the power key is pressed. + * We want the device to stay on while the button is down, but we're about + * to turn off the screen so we don't want the keyboard backlight to turn on again. + * Otherwise the lights flash on and then off and it looks weird. + * + * @see #wakeUp + * @see #goToSleep + */ + public void userActivity(long when, boolean noChangeLights) { + try { + mService.userActivity(when, USER_ACTIVITY_EVENT_OTHER, + noChangeLights ? USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS : 0); + } catch (RemoteException e) { + } + } + + /** + * Forces the device to go to sleep. + * <p> + * Overrides all the wake locks that are held. + * This is what happens when the power key is pressed to turn off the screen. + * </p><p> + * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission. + * </p> + * + * @param time The time when the request to go to sleep was issued, in the + * {@link SystemClock#uptimeMillis()} time base. This timestamp is used to correctly + * order the go to sleep request with other power management functions. It should be set + * to the timestamp of the input event that caused the request to go to sleep. + * + * @see #userActivity + * @see #wakeUp + */ + public void goToSleep(long time) { + try { + mService.goToSleep(time, GO_TO_SLEEP_REASON_USER); + } catch (RemoteException e) { + } + } + + /** + * Forces the device to wake up from sleep. + * <p> + * If the device is currently asleep, wakes it up, otherwise does nothing. + * This is what happens when the power key is pressed to turn on the screen. + * </p><p> + * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission. + * </p> + * + * @param time The time when the request to wake up was issued, in the + * {@link SystemClock#uptimeMillis()} time base. This timestamp is used to correctly + * order the wake up request with other power management functions. It should be set + * to the timestamp of the input event that caused the request to wake up. + * + * @see #userActivity + * @see #goToSleep + */ + public void wakeUp(long time) { + try { + mService.wakeUp(time); + } catch (RemoteException e) { + } + } + + /** + * Forces the device to start napping. + * <p> + * If the device is currently awake, starts dreaming, otherwise does nothing. + * When the dream ends or if the dream cannot be started, the device will + * either wake up or go to sleep depending on whether there has been recent + * user activity. + * </p><p> + * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission. + * </p> + * + * @param time The time when the request to nap was issued, in the + * {@link SystemClock#uptimeMillis()} time base. This timestamp is used to correctly + * order the nap request with other power management functions. It should be set + * to the timestamp of the input event that caused the request to nap. + * + * @see #wakeUp + * @see #goToSleep + * + * @hide + */ + public void nap(long time) { + try { + mService.nap(time); + } catch (RemoteException e) { + } + } + + /** + * Sets the brightness of the backlights (screen, keyboard, button). + * <p> + * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission. + * </p> + * + * @param brightness The brightness value from 0 to 255. + * + * {@hide} + */ + public void setBacklightBrightness(int brightness) { + try { + mService.setTemporaryScreenBrightnessSettingOverride(brightness); + } catch (RemoteException e) { + } + } + + /** + * Returns true if the specified wake lock level is supported. + * + * @param level The wake lock level to check. + * @return True if the specified wake lock level is supported. + * + * {@hide} + */ + public boolean isWakeLockLevelSupported(int level) { + try { + return mService.isWakeLockLevelSupported(level); + } catch (RemoteException e) { + return false; + } + } + + /** + * Returns whether the screen is currently on. + * <p> + * Only indicates whether the screen is on. The screen could be either bright or dim. + * </p><p> + * {@samplecode + * PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); + * boolean isScreenOn = pm.isScreenOn(); + * } + * </p> + * + * @return whether the screen is on (bright or dim). + */ + public boolean isScreenOn() { + try { + return mService.isScreenOn(); + } catch (RemoteException e) { + return false; + } + } + + /** + * Reboot the device. Will not return if the reboot is successful. + * <p> + * Requires the {@link android.Manifest.permission#REBOOT} permission. + * </p> + * + * @param reason code to pass to the kernel (e.g., "recovery") to + * request special boot modes, or null. + */ + public void reboot(String reason) { + try { + mService.reboot(reason); + } catch (RemoteException e) { + } + } + + /** + * A wake lock is a mechanism to indicate that your application needs + * to have the device stay on. + * <p> + * Any application using a WakeLock must request the {@code android.permission.WAKE_LOCK} + * permission in an {@code <uses-permission>} element of the application's manifest. + * Obtain a wake lock by calling {@link PowerManager#newWakeLock(int, String)}. + * </p><p> + * Call {@link #acquire()} to acquire the wake lock and force the device to stay + * on at the level that was requested when the wake lock was created. + * </p><p> + * Call {@link #release()} when you are done and don't need the lock anymore. + * It is very important to do this as soon as possible to avoid running down the + * device's battery excessively. + * </p> + */ + public final class WakeLock { + private final int mFlags; + private final String mTag; + private final IBinder mToken; + private int mCount; + private boolean mRefCounted = true; + private boolean mHeld; + private WorkSource mWorkSource; + + private final Runnable mReleaser = new Runnable() { + public void run() { + release(); } + }; + WakeLock(int flags, String tag) { mFlags = flags; mTag = tag; mToken = new Binder(); } + @Override + protected void finalize() throws Throwable { + synchronized (mToken) { + if (mHeld) { + Log.wtf(TAG, "WakeLock finalized while still held: " + mTag); + try { + mService.releaseWakeLock(mToken, 0); + } catch (RemoteException e) { + } + } + } + } + /** - * Sets whether this WakeLock is ref counted. - * - * <p>Wake locks are reference counted by default. + * Sets whether this WakeLock is reference counted. + * <p> + * Wake locks are reference counted by default. If a wake lock is + * reference counted, then each call to {@link #acquire()} must be + * balanced by an equal number of calls to {@link #release()}. If a wake + * lock is not reference counted, then one call to {@link #release()} is + * sufficient to undo the effect of all previous calls to {@link #acquire()}. + * </p> * - * @param value true for ref counted, false for not ref counted. + * @param value True to make the wake lock reference counted, false to + * make the wake lock non-reference counted. */ - public void setReferenceCounted(boolean value) - { - mRefCounted = value; + public void setReferenceCounted(boolean value) { + synchronized (mToken) { + mRefCounted = value; + } } /** - * Makes sure the device is on at the level you asked when you created - * the wake lock. + * Acquires the wake lock. + * <p> + * Ensures that the device is on at the level requested when + * the wake lock was created. + * </p> */ - public void acquire() - { + public void acquire() { synchronized (mToken) { acquireLocked(); } } /** - * 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. + * Acquires the wake lock with a timeout. + * <p> + * Ensures that the device is on at the level requested when + * the wake lock was created. The lock will be released after the given timeout + * expires. + * </p> + * + * @param timeout The timeout after which to release the wake lock, in milliseconds. */ public void acquire(long timeout) { synchronized (mToken) { @@ -301,12 +699,18 @@ public class PowerManager mHandler.postDelayed(mReleaser, timeout); } } - + private void acquireLocked() { if (!mRefCounted || mCount++ == 0) { + // Do this even if the wake lock is already thought to be held (mHeld == true) + // because non-reference counted wake locks are not always properly released. + // For example, the keyguard's wake lock might be forcibly released by the + // power manager without the keyguard knowing. A subsequent call to acquire + // should immediately acquire the wake lock once again despite never having + // been explicitly released by the keyguard. mHandler.removeCallbacks(mReleaser); try { - mService.acquireWakeLock(mFlags, mToken, mTag, mWorkSource); + mService.acquireWakeLock(mToken, mFlags, mTag, mWorkSource); } catch (RemoteException e) { } mHeld = true; @@ -314,24 +718,27 @@ public class PowerManager } /** - * Release your claim to the CPU or screen being on. - * + * Releases the wake lock. * <p> - * It may turn off shortly after you release it, or it may not if there - * are other wake locks held. + * This method releases your claim to the CPU or screen being on. + * The screen may turn off shortly after you release the wake lock, or it may + * not if there are other wake locks still held. + * </p> */ public void release() { release(0); } /** - * Release your claim to the CPU or screen being on. - * @param flags Combination of flag values to modify the release behavior. - * Currently only {@link #WAIT_FOR_PROXIMITY_NEGATIVE} is supported. - * + * Releases the wake lock with flags to modify the release behavior. * <p> - * It may turn off shortly after you release it, or it may not if there - * are other wake locks held. + * This method releases your claim to the CPU or screen being on. + * The screen may turn off shortly after you release the wake lock, or it may + * not if there are other wake locks still held. + * </p> + * + * @param flags Combination of flag values to modify the release behavior. + * Currently only {@link #WAIT_FOR_PROXIMITY_NEGATIVE} is supported. * * {@hide} */ @@ -339,11 +746,13 @@ public class PowerManager synchronized (mToken) { if (!mRefCounted || --mCount == 0) { mHandler.removeCallbacks(mReleaser); - try { - mService.releaseWakeLock(mToken, flags); - } catch (RemoteException e) { + if (mHeld) { + try { + mService.releaseWakeLock(mToken, flags); + } catch (RemoteException e) { + } + mHeld = false; } - mHeld = false; } if (mCount < 0) { throw new RuntimeException("WakeLock under-locked " + mTag); @@ -351,23 +760,40 @@ public class PowerManager } } - public boolean isHeld() - { + /** + * Returns true if the wake lock has been acquired but not yet released. + * + * @return True if the wake lock is held. + */ + public boolean isHeld() { synchronized (mToken) { return mHeld; } } + /** + * Sets the work source associated with the wake lock. + * <p> + * The work source is used to determine on behalf of which application + * the wake lock is being held. This is useful in the case where a + * service is performing work on behalf of an application so that the + * cost of that work can be accounted to the application. + * </p> + * + * @param ws The work source, or null if none. + */ public void setWorkSource(WorkSource ws) { synchronized (mToken) { if (ws != null && ws.size() == 0) { ws = null; } - boolean changed = true; + + final boolean changed; if (ws == null) { + changed = mWorkSource != null; mWorkSource = null; } else if (mWorkSource == null) { - changed = mWorkSource != null; + changed = true; mWorkSource = new WorkSource(ws); } else { changed = mWorkSource.diff(ws); @@ -375,6 +801,7 @@ public class PowerManager mWorkSource.set(ws); } } + if (changed && mHeld) { try { mService.updateWakeLockWorkSource(mToken, mWorkSource); @@ -384,6 +811,7 @@ public class PowerManager } } + @Override public String toString() { synchronized (mToken) { return "WakeLock{" @@ -391,194 +819,5 @@ public class PowerManager + " held=" + mHeld + ", refCount=" + mCount + "}"; } } - - @Override - protected void finalize() throws Throwable - { - synchronized (mToken) { - if (mHeld) { - Log.wtf(TAG, "WakeLock finalized while still held: " + mTag); - try { - mService.releaseWakeLock(mToken, 0); - } catch (RemoteException e) { - } - } - } - } } - - /** - * 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(); - * } - * - * <p class="note">If using this to keep the screen on, you should strongly consider using - * {@link android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON} instead. - * This window flag will be correctly managed by the platform - * as the user moves between applications and doesn't require a special permission.</p> - * - * @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) - { - if (tag == null) { - throw new NullPointerException("tag is null in PowerManager.newWakeLock"); - } - 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) { - } - } - - /** - * sets the brightness of the backlights (screen, keyboard, button). - * - * @param brightness value from 0 to 255 - * - * {@hide} - */ - public void setBacklightBrightness(int brightness) - { - try { - mService.setBacklightBrightness(brightness); - } 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; - } - } - - /** - * Returns whether the screen is currently on. The screen could be bright - * or dim. - * - * {@samplecode - * PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); - * boolean isScreenOn = pm.isScreenOn(); - * } - * - * @return whether the screen is on (bright or dim). - */ - public boolean isScreenOn() - { - try { - return mService.isScreenOn(); - } catch (RemoteException e) { - return false; - } - } - - /** - * Reboot the device. Will not return if the reboot is - * successful. Requires the {@link android.Manifest.permission#REBOOT} - * permission. - * - * @param reason code to pass to the kernel (e.g., "recovery") to - * request special boot modes, or null. - */ - public void reboot(String reason) - { - try { - mService.reboot(reason); - } catch (RemoteException e) { - } - } - - 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; } |