PowerManager.java revision d710fb500c121b3f9563ccfbe488f7c9d3ec4985
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 android.os;
18
19import android.util.Log;
20
21/**
22 * This class gives you control of the power state of the device.
23 *
24 * <p><b>Device battery life will be significantly affected by the use of this API.</b>  Do not
25 * acquire WakeLocks unless you really need them, use the minimum levels possible, and be sure
26 * to release it as soon as you can.
27 *
28 * <p>You can obtain an instance of this class by calling
29 * {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}.
30 *
31 * <p>The primary API you'll use is {@link #newWakeLock(int, String) newWakeLock()}.  This will
32 * create a {@link PowerManager.WakeLock} object.  You can then use methods on this object to
33 * control the power state of the device.  In practice it's quite simple:
34 *
35 * {@samplecode
36 * PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
37 * PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "My Tag");
38 * wl.acquire();
39 *   ..screen will stay on during this section..
40 * wl.release();
41 * }
42 *
43 * <p>The following flags are defined, with varying effects on system power.  <i>These flags are
44 * mutually exclusive - you may only specify one of them.</i>
45 * <table border="2" width="85%" align="center" frame="hsides" rules="rows">
46 *
47 *     <thead>
48 *     <tr><th>Flag Value</th>
49 *     <th>CPU</th> <th>Screen</th> <th>Keyboard</th></tr>
50 *     </thead>
51 *
52 *     <tbody>
53 *     <tr><th>{@link #PARTIAL_WAKE_LOCK}</th>
54 *         <td>On*</td> <td>Off</td> <td>Off</td>
55 *     </tr>
56 *
57 *     <tr><th>{@link #SCREEN_DIM_WAKE_LOCK}</th>
58 *         <td>On</td> <td>Dim</td> <td>Off</td>
59 *     </tr>
60 *
61 *     <tr><th>{@link #SCREEN_BRIGHT_WAKE_LOCK}</th>
62 *         <td>On</td> <td>Bright</td> <td>Off</td>
63 *     </tr>
64 *
65 *     <tr><th>{@link #FULL_WAKE_LOCK}</th>
66 *         <td>On</td> <td>Bright</td> <td>Bright</td>
67 *     </tr>
68 *     </tbody>
69 * </table>
70 *
71 * <p>*<i>If you hold a partial wakelock, the CPU will continue to run, irrespective of any timers
72 * and even after the user presses the power button.  In all other wakelocks, the CPU will run, but
73 * the user can still put the device to sleep using the power button.</i>
74 *
75 * <p>In addition, you can add two more flags, which affect behavior of the screen only.  <i>These
76 * flags have no effect when combined with a {@link #PARTIAL_WAKE_LOCK}.</i>
77 * <table border="2" width="85%" align="center" frame="hsides" rules="rows">
78 *
79 *     <thead>
80 *     <tr><th>Flag Value</th> <th>Description</th></tr>
81 *     </thead>
82 *
83 *     <tbody>
84 *     <tr><th>{@link #ACQUIRE_CAUSES_WAKEUP}</th>
85 *         <td>Normal wake locks don't actually turn on the illumination.  Instead, they cause
86 *         the illumination to remain on once it turns on (e.g. from user activity).  This flag
87 *         will force the screen and/or keyboard to turn on immediately, when the WakeLock is
88 *         acquired.  A typical use would be for notifications which are important for the user to
89 *         see immediately.</td>
90 *     </tr>
91 *
92 *     <tr><th>{@link #ON_AFTER_RELEASE}</th>
93 *         <td>If this flag is set, the user activity timer will be reset when the WakeLock is
94 *         released, causing the illumination to remain on a bit longer.  This can be used to
95 *         reduce flicker if you are cycling between wake lock conditions.</td>
96 *     </tr>
97 *     </tbody>
98 * </table>
99 *
100 * Any application using a WakeLock must request the {@code android.permission.WAKE_LOCK}
101 * permission in an {@code &lt;uses-permission&gt;} element of the application's manifest.
102 */
103public class PowerManager
104{
105    private static final String TAG = "PowerManager";
106
107    /**
108     * These internal values define the underlying power elements that we might
109     * want to control individually.  Eventually we'd like to expose them.
110     */
111    private static final int WAKE_BIT_CPU_STRONG = 1;
112    private static final int WAKE_BIT_CPU_WEAK = 2;
113    private static final int WAKE_BIT_SCREEN_DIM = 4;
114    private static final int WAKE_BIT_SCREEN_BRIGHT = 8;
115    private static final int WAKE_BIT_KEYBOARD_BRIGHT = 16;
116    private static final int WAKE_BIT_PROXIMITY_SCREEN_OFF = 32;
117
118    private static final int LOCK_MASK = WAKE_BIT_CPU_STRONG
119                                        | WAKE_BIT_CPU_WEAK
120                                        | WAKE_BIT_SCREEN_DIM
121                                        | WAKE_BIT_SCREEN_BRIGHT
122                                        | WAKE_BIT_KEYBOARD_BRIGHT
123                                        | WAKE_BIT_PROXIMITY_SCREEN_OFF;
124
125    /**
126     * Wake lock that ensures that the CPU is running.  The screen might
127     * not be on.
128     */
129    public static final int PARTIAL_WAKE_LOCK = WAKE_BIT_CPU_STRONG;
130
131    /**
132     * Wake lock that ensures that the screen and keyboard are on at
133     * full brightness.
134     */
135    public static final int FULL_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_BRIGHT
136                                            | WAKE_BIT_KEYBOARD_BRIGHT;
137
138    /**
139     * Wake lock that ensures that the screen is on at full brightness;
140     * the keyboard backlight will be allowed to go off.
141     */
142    public static final int SCREEN_BRIGHT_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_BRIGHT;
143
144    /**
145     * Wake lock that ensures that the screen is on (but may be dimmed);
146     * the keyboard backlight will be allowed to go off.
147     */
148    public static final int SCREEN_DIM_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_DIM;
149
150    /**
151     * Wake lock that turns the screen off when the proximity sensor activates.
152     * Since not all devices have proximity sensors, use
153     * {@link #getSupportedWakeLockFlags() getSupportedWakeLockFlags()} to determine if
154     * this wake lock mode is supported.
155     *
156     * {@hide}
157     */
158    public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = WAKE_BIT_PROXIMITY_SCREEN_OFF;
159
160    /**
161     * Flag for {@link WakeLock#release release(int)} to defer releasing a
162     * {@link #WAKE_BIT_PROXIMITY_SCREEN_OFF} wakelock until the proximity sensor returns
163     * a negative value.
164     *
165     * {@hide}
166     */
167    public static final int WAIT_FOR_PROXIMITY_NEGATIVE = 1;
168
169    /**
170     * Normally wake locks don't actually wake the device, they just cause
171     * it to remain on once it's already on.  Think of the video player
172     * app as the normal behavior.  Notifications that pop up and want
173     * the device to be on are the exception; use this flag to be like them.
174     * <p>
175     * Does not work with PARTIAL_WAKE_LOCKs.
176     */
177    public static final int ACQUIRE_CAUSES_WAKEUP = 0x10000000;
178
179    /**
180     * When this wake lock is released, poke the user activity timer
181     * so the screen stays on for a little longer.
182     * <p>
183     * Will not turn the screen on if it is not already on.  See {@link #ACQUIRE_CAUSES_WAKEUP}
184     * if you want that.
185     * <p>
186     * Does not work with PARTIAL_WAKE_LOCKs.
187     */
188    public static final int ON_AFTER_RELEASE = 0x20000000;
189
190    /**
191     * Class lets you say that you need to have the device on.
192     * <p>
193     * Call release when you are done and don't need the lock anymore.
194     * <p>
195     * Any application using a WakeLock must request the {@code android.permission.WAKE_LOCK}
196     * permission in an {@code &lt;uses-permission&gt;} element of the application's manifest.
197     */
198    public class WakeLock
199    {
200        static final int RELEASE_WAKE_LOCK = 1;
201
202        Runnable mReleaser = new Runnable() {
203            public void run() {
204                release();
205            }
206        };
207
208        int mFlags;
209        String mTag;
210        IBinder mToken;
211        int mCount = 0;
212        boolean mRefCounted = true;
213        boolean mHeld = false;
214        WorkSource mWorkSource;
215
216        WakeLock(int flags, String tag)
217        {
218            switch (flags & LOCK_MASK) {
219            case PARTIAL_WAKE_LOCK:
220            case SCREEN_DIM_WAKE_LOCK:
221            case SCREEN_BRIGHT_WAKE_LOCK:
222            case FULL_WAKE_LOCK:
223            case PROXIMITY_SCREEN_OFF_WAKE_LOCK:
224                break;
225            default:
226                throw new IllegalArgumentException();
227            }
228
229            mFlags = flags;
230            mTag = tag;
231            mToken = new Binder();
232        }
233
234        /**
235         * Sets whether this WakeLock is ref counted.
236         *
237         * <p>Wake locks are reference counted by default.
238         *
239         * @param value true for ref counted, false for not ref counted.
240         */
241        public void setReferenceCounted(boolean value)
242        {
243            mRefCounted = value;
244        }
245
246        /**
247         * Makes sure the device is on at the level you asked when you created
248         * the wake lock.
249         */
250        public void acquire()
251        {
252            synchronized (mToken) {
253                if (!mRefCounted || mCount++ == 0) {
254                    try {
255                        mService.acquireWakeLock(mFlags, mToken, mTag, mWorkSource);
256                    } catch (RemoteException e) {
257                    }
258                    mHeld = true;
259                }
260            }
261        }
262
263        /**
264         * Makes sure the device is on at the level you asked when you created
265         * the wake lock. The lock will be released after the given timeout.
266         *
267         * @param timeout Release the lock after the give timeout in milliseconds.
268         */
269        public void acquire(long timeout) {
270            acquire();
271            mHandler.postDelayed(mReleaser, timeout);
272        }
273
274
275        /**
276         * Release your claim to the CPU or screen being on.
277         *
278         * <p>
279         * It may turn off shortly after you release it, or it may not if there
280         * are other wake locks held.
281         */
282        public void release()
283        {
284            release(0);
285        }
286
287        /**
288         * Release your claim to the CPU or screen being on.
289         * @param flags Combination of flag values to modify the release behavior.
290         *              Currently only {@link #WAIT_FOR_PROXIMITY_NEGATIVE} is supported.
291         *
292         * <p>
293         * It may turn off shortly after you release it, or it may not if there
294         * are other wake locks held.
295         *
296         * {@hide}
297         */
298        public void release(int flags)
299        {
300            synchronized (mToken) {
301                if (!mRefCounted || --mCount == 0) {
302                    try {
303                        mService.releaseWakeLock(mToken, flags);
304                    } catch (RemoteException e) {
305                    }
306                    mHeld = false;
307                }
308                if (mCount < 0) {
309                    throw new RuntimeException("WakeLock under-locked " + mTag);
310                }
311            }
312        }
313
314        public boolean isHeld()
315        {
316            synchronized (mToken) {
317                return mHeld;
318            }
319        }
320
321        public void setWorkSource(WorkSource ws) {
322            synchronized (mToken) {
323                if (ws != null && ws.size() == 0) {
324                    ws = null;
325                }
326                boolean changed = true;
327                if (ws == null) {
328                    mWorkSource = null;
329                } else if (mWorkSource == null) {
330                    changed = mWorkSource != null;
331                    mWorkSource = new WorkSource(ws);
332                } else {
333                    changed = mWorkSource.diff(ws);
334                    if (changed) {
335                        mWorkSource.set(ws);
336                    }
337                }
338                if (changed && mHeld) {
339                    try {
340                        mService.updateWakeLockWorkSource(mToken, mWorkSource);
341                    } catch (RemoteException e) {
342                    }
343                }
344            }
345        }
346
347        public String toString() {
348            synchronized (mToken) {
349                return "WakeLock{"
350                    + Integer.toHexString(System.identityHashCode(this))
351                    + " held=" + mHeld + ", refCount=" + mCount + "}";
352            }
353        }
354
355        @Override
356        protected void finalize() throws Throwable
357        {
358            synchronized (mToken) {
359                if (mHeld) {
360                    Log.wtf(TAG, "WakeLock finalized while still held: " + mTag);
361                    try {
362                        mService.releaseWakeLock(mToken, 0);
363                    } catch (RemoteException e) {
364                    }
365                }
366            }
367        }
368    }
369
370    /**
371     * Get a wake lock at the level of the flags parameter.  Call
372     * {@link WakeLock#acquire() acquire()} on the object to acquire the
373     * wake lock, and {@link WakeLock#release release()} when you are done.
374     *
375     * {@samplecode
376     *PowerManager pm = (PowerManager)mContext.getSystemService(
377     *                                          Context.POWER_SERVICE);
378     *PowerManager.WakeLock wl = pm.newWakeLock(
379     *                                      PowerManager.SCREEN_DIM_WAKE_LOCK
380     *                                      | PowerManager.ON_AFTER_RELEASE,
381     *                                      TAG);
382     *wl.acquire();
383     * // ...
384     *wl.release();
385     * }
386     *
387     * @param flags Combination of flag values defining the requested behavior of the WakeLock.
388     * @param tag Your class name (or other tag) for debugging purposes.
389     *
390     * @see WakeLock#acquire()
391     * @see WakeLock#release()
392     */
393    public WakeLock newWakeLock(int flags, String tag)
394    {
395        if (tag == null) {
396            throw new NullPointerException("tag is null in PowerManager.newWakeLock");
397        }
398        return new WakeLock(flags, tag);
399    }
400
401    /**
402     * User activity happened.
403     * <p>
404     * Turns the device from whatever state it's in to full on, and resets
405     * the auto-off timer.
406     *
407     * @param when is used to order this correctly with the wake lock calls.
408     *          This time should be in the {@link SystemClock#uptimeMillis
409     *          SystemClock.uptimeMillis()} time base.
410     * @param noChangeLights should be true if you don't want the lights to
411     *          turn on because of this event.  This is set when the power
412     *          key goes down.  We want the device to stay on while the button
413     *          is down, but we're about to turn off.  Otherwise the lights
414     *          flash on and then off and it looks weird.
415     */
416    public void userActivity(long when, boolean noChangeLights)
417    {
418        try {
419            mService.userActivity(when, noChangeLights);
420        } catch (RemoteException e) {
421        }
422    }
423
424   /**
425     * Force the device to go to sleep. Overrides all the wake locks that are
426     * held.
427     *
428     * @param time is used to order this correctly with the wake lock calls.
429     *          The time  should be in the {@link SystemClock#uptimeMillis
430     *          SystemClock.uptimeMillis()} time base.
431     */
432    public void goToSleep(long time)
433    {
434        try {
435            mService.goToSleep(time);
436        } catch (RemoteException e) {
437        }
438    }
439
440    /**
441     * sets the brightness of the backlights (screen, keyboard, button).
442     *
443     * @param brightness value from 0 to 255
444     *
445     * {@hide}
446     */
447    public void setBacklightBrightness(int brightness)
448    {
449        try {
450            mService.setBacklightBrightness(brightness);
451        } catch (RemoteException e) {
452        }
453    }
454
455   /**
456     * Returns the set of flags for {@link #newWakeLock(int, String) newWakeLock()}
457     * that are supported on the device.
458     * For example, to test to see if the {@link #PROXIMITY_SCREEN_OFF_WAKE_LOCK}
459     * is supported:
460     *
461     * {@samplecode
462     * PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
463     * int supportedFlags = pm.getSupportedWakeLockFlags();
464     *  boolean proximitySupported = ((supportedFlags & PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)
465     *                                  == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK);
466     * }
467     *
468     * @return the set of supported WakeLock flags.
469     *
470     * {@hide}
471     */
472    public int getSupportedWakeLockFlags()
473    {
474        try {
475            return mService.getSupportedWakeLockFlags();
476        } catch (RemoteException e) {
477            return 0;
478        }
479    }
480
481    /**
482      * Returns whether the screen is currently on. The screen could be bright
483      * or dim.
484      *
485      * {@samplecode
486      * PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
487      * boolean isScreenOn = pm.isScreenOn();
488      * }
489      *
490      * @return whether the screen is on (bright or dim).
491      */
492    public boolean isScreenOn()
493    {
494        try {
495            return mService.isScreenOn();
496        } catch (RemoteException e) {
497            return false;
498        }
499    }
500
501    /**
502     * Reboot the device.  Will not return if the reboot is
503     * successful.  Requires the {@link android.Manifest.permission#REBOOT}
504     * permission.
505     *
506     * @param reason code to pass to the kernel (e.g., "recovery") to
507     *               request special boot modes, or null.
508     */
509    public void reboot(String reason)
510    {
511        try {
512            mService.reboot(reason);
513        } catch (RemoteException e) {
514        }
515    }
516
517    private PowerManager()
518    {
519    }
520
521    /**
522     * {@hide}
523     */
524    public PowerManager(IPowerManager service, Handler handler)
525    {
526        mService = service;
527        mHandler = handler;
528    }
529
530    /**
531     *  TODO: It would be nice to be able to set the poke lock here,
532     *  but I'm not sure what would be acceptable as an interface -
533     *  either a PokeLock object (like WakeLock) or, possibly just a
534     *  method call to set the poke lock.
535     */
536
537    IPowerManager mService;
538    Handler mHandler;
539}
540