PowerManager.java revision b5962e73e841455b8e2a4e2d5c0ef0a19d62a803
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     * <p class="note">Most applications should strongly consider using
136     * {@link android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON}.
137     * This window flag will be correctly managed by the platform
138     * as the user moves between applications and doesn't require a special permission.</p>
139     */
140    public static final int FULL_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_BRIGHT
141                                            | WAKE_BIT_KEYBOARD_BRIGHT;
142
143    /**
144     * @deprecated Most applications should use
145     * {@link android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON} instead
146     * of this type of wake lock, as it will be correctly managed by the platform
147     * as the user moves between applications and doesn't require a special permission.
148     *
149     * Wake lock that ensures that the screen is on at full brightness;
150     * the keyboard backlight will be allowed to go off.
151     */
152    @Deprecated
153    public static final int SCREEN_BRIGHT_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_BRIGHT;
154
155    /**
156     * Wake lock that ensures that the screen is on (but may be dimmed);
157     * the keyboard backlight will be allowed to go off.
158     */
159    public static final int SCREEN_DIM_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_DIM;
160
161    /**
162     * Wake lock that turns the screen off when the proximity sensor activates.
163     * Since not all devices have proximity sensors, use
164     * {@link #getSupportedWakeLockFlags() getSupportedWakeLockFlags()} to determine if
165     * this wake lock mode is supported.
166     *
167     * {@hide}
168     */
169    public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = WAKE_BIT_PROXIMITY_SCREEN_OFF;
170
171    /**
172     * Flag for {@link WakeLock#release release(int)} to defer releasing a
173     * {@link #WAKE_BIT_PROXIMITY_SCREEN_OFF} wakelock until the proximity sensor returns
174     * a negative value.
175     *
176     * {@hide}
177     */
178    public static final int WAIT_FOR_PROXIMITY_NEGATIVE = 1;
179
180    /**
181     * Normally wake locks don't actually wake the device, they just cause
182     * it to remain on once it's already on.  Think of the video player
183     * app as the normal behavior.  Notifications that pop up and want
184     * the device to be on are the exception; use this flag to be like them.
185     * <p>
186     * Does not work with PARTIAL_WAKE_LOCKs.
187     */
188    public static final int ACQUIRE_CAUSES_WAKEUP = 0x10000000;
189
190    /**
191     * When this wake lock is released, poke the user activity timer
192     * so the screen stays on for a little longer.
193     * <p>
194     * Will not turn the screen on if it is not already on.  See {@link #ACQUIRE_CAUSES_WAKEUP}
195     * if you want that.
196     * <p>
197     * Does not work with PARTIAL_WAKE_LOCKs.
198     */
199    public static final int ON_AFTER_RELEASE = 0x20000000;
200
201    /**
202     * Class lets you say that you need to have the device on.
203     * <p>
204     * Call release when you are done and don't need the lock anymore.
205     * <p>
206     * Any application using a WakeLock must request the {@code android.permission.WAKE_LOCK}
207     * permission in an {@code &lt;uses-permission&gt;} element of the application's manifest.
208     */
209    public class WakeLock
210    {
211        static final int RELEASE_WAKE_LOCK = 1;
212
213        Runnable mReleaser = new Runnable() {
214            public void run() {
215                release();
216            }
217        };
218
219        int mFlags;
220        String mTag;
221        IBinder mToken;
222        int mCount = 0;
223        boolean mRefCounted = true;
224        boolean mHeld = false;
225        WorkSource mWorkSource;
226
227        WakeLock(int flags, String tag)
228        {
229            switch (flags & LOCK_MASK) {
230            case PARTIAL_WAKE_LOCK:
231            case SCREEN_DIM_WAKE_LOCK:
232            case SCREEN_BRIGHT_WAKE_LOCK:
233            case FULL_WAKE_LOCK:
234            case PROXIMITY_SCREEN_OFF_WAKE_LOCK:
235                break;
236            default:
237                throw new IllegalArgumentException();
238            }
239
240            mFlags = flags;
241            mTag = tag;
242            mToken = new Binder();
243        }
244
245        /**
246         * Sets whether this WakeLock is ref counted.
247         *
248         * <p>Wake locks are reference counted by default.
249         *
250         * @param value true for ref counted, false for not ref counted.
251         */
252        public void setReferenceCounted(boolean value)
253        {
254            mRefCounted = value;
255        }
256
257        /**
258         * Makes sure the device is on at the level you asked when you created
259         * the wake lock.
260         */
261        public void acquire()
262        {
263            synchronized (mToken) {
264                acquireLocked();
265            }
266        }
267
268        /**
269         * Makes sure the device is on at the level you asked when you created
270         * the wake lock. The lock will be released after the given timeout.
271         *
272         * @param timeout Release the lock after the give timeout in milliseconds.
273         */
274        public void acquire(long timeout) {
275            synchronized (mToken) {
276                acquireLocked();
277                mHandler.postDelayed(mReleaser, timeout);
278            }
279        }
280
281        private void acquireLocked() {
282            if (!mRefCounted || mCount++ == 0) {
283                mHandler.removeCallbacks(mReleaser);
284                try {
285                    mService.acquireWakeLock(mFlags, mToken, mTag, mWorkSource);
286                } catch (RemoteException e) {
287                }
288                mHeld = true;
289            }
290        }
291
292        /**
293         * Release your claim to the CPU or screen being on.
294         *
295         * <p>
296         * It may turn off shortly after you release it, or it may not if there
297         * are other wake locks held.
298         */
299        public void release() {
300            release(0);
301        }
302
303        /**
304         * Release your claim to the CPU or screen being on.
305         * @param flags Combination of flag values to modify the release behavior.
306         *              Currently only {@link #WAIT_FOR_PROXIMITY_NEGATIVE} is supported.
307         *
308         * <p>
309         * It may turn off shortly after you release it, or it may not if there
310         * are other wake locks held.
311         *
312         * {@hide}
313         */
314        public void release(int flags) {
315            synchronized (mToken) {
316                if (!mRefCounted || --mCount == 0) {
317                    mHandler.removeCallbacks(mReleaser);
318                    try {
319                        mService.releaseWakeLock(mToken, flags);
320                    } catch (RemoteException e) {
321                    }
322                    mHeld = false;
323                }
324                if (mCount < 0) {
325                    throw new RuntimeException("WakeLock under-locked " + mTag);
326                }
327            }
328        }
329
330        public boolean isHeld()
331        {
332            synchronized (mToken) {
333                return mHeld;
334            }
335        }
336
337        public void setWorkSource(WorkSource ws) {
338            synchronized (mToken) {
339                if (ws != null && ws.size() == 0) {
340                    ws = null;
341                }
342                boolean changed = true;
343                if (ws == null) {
344                    mWorkSource = null;
345                } else if (mWorkSource == null) {
346                    changed = mWorkSource != null;
347                    mWorkSource = new WorkSource(ws);
348                } else {
349                    changed = mWorkSource.diff(ws);
350                    if (changed) {
351                        mWorkSource.set(ws);
352                    }
353                }
354                if (changed && mHeld) {
355                    try {
356                        mService.updateWakeLockWorkSource(mToken, mWorkSource);
357                    } catch (RemoteException e) {
358                    }
359                }
360            }
361        }
362
363        public String toString() {
364            synchronized (mToken) {
365                return "WakeLock{"
366                    + Integer.toHexString(System.identityHashCode(this))
367                    + " held=" + mHeld + ", refCount=" + mCount + "}";
368            }
369        }
370
371        @Override
372        protected void finalize() throws Throwable
373        {
374            synchronized (mToken) {
375                if (mHeld) {
376                    Log.wtf(TAG, "WakeLock finalized while still held: " + mTag);
377                    try {
378                        mService.releaseWakeLock(mToken, 0);
379                    } catch (RemoteException e) {
380                    }
381                }
382            }
383        }
384    }
385
386    /**
387     * Get a wake lock at the level of the flags parameter.  Call
388     * {@link WakeLock#acquire() acquire()} on the object to acquire the
389     * wake lock, and {@link WakeLock#release release()} when you are done.
390     *
391     * {@samplecode
392     *PowerManager pm = (PowerManager)mContext.getSystemService(
393     *                                          Context.POWER_SERVICE);
394     *PowerManager.WakeLock wl = pm.newWakeLock(
395     *                                      PowerManager.SCREEN_DIM_WAKE_LOCK
396     *                                      | PowerManager.ON_AFTER_RELEASE,
397     *                                      TAG);
398     *wl.acquire();
399     * // ...
400     *wl.release();
401     * }
402     *
403     * <p class="note">If using this to keep the screen on, you should strongly consider using
404     * {@link android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON} instead.
405     * This window flag will be correctly managed by the platform
406     * as the user moves between applications and doesn't require a special permission.</p>
407     *
408     * @param flags Combination of flag values defining the requested behavior of the WakeLock.
409     * @param tag Your class name (or other tag) for debugging purposes.
410     *
411     * @see WakeLock#acquire()
412     * @see WakeLock#release()
413     */
414    public WakeLock newWakeLock(int flags, String tag)
415    {
416        if (tag == null) {
417            throw new NullPointerException("tag is null in PowerManager.newWakeLock");
418        }
419        return new WakeLock(flags, tag);
420    }
421
422    /**
423     * User activity happened.
424     * <p>
425     * Turns the device from whatever state it's in to full on, and resets
426     * the auto-off timer.
427     *
428     * @param when is used to order this correctly with the wake lock calls.
429     *          This time should be in the {@link SystemClock#uptimeMillis
430     *          SystemClock.uptimeMillis()} time base.
431     * @param noChangeLights should be true if you don't want the lights to
432     *          turn on because of this event.  This is set when the power
433     *          key goes down.  We want the device to stay on while the button
434     *          is down, but we're about to turn off.  Otherwise the lights
435     *          flash on and then off and it looks weird.
436     */
437    public void userActivity(long when, boolean noChangeLights)
438    {
439        try {
440            mService.userActivity(when, noChangeLights);
441        } catch (RemoteException e) {
442        }
443    }
444
445   /**
446     * Force the device to go to sleep. Overrides all the wake locks that are
447     * held.
448     *
449     * @param time is used to order this correctly with the wake lock calls.
450     *          The time  should be in the {@link SystemClock#uptimeMillis
451     *          SystemClock.uptimeMillis()} time base.
452     */
453    public void goToSleep(long time)
454    {
455        try {
456            mService.goToSleep(time);
457        } catch (RemoteException e) {
458        }
459    }
460
461    /**
462     * sets the brightness of the backlights (screen, keyboard, button).
463     *
464     * @param brightness value from 0 to 255
465     *
466     * {@hide}
467     */
468    public void setBacklightBrightness(int brightness)
469    {
470        try {
471            mService.setBacklightBrightness(brightness);
472        } catch (RemoteException e) {
473        }
474    }
475
476   /**
477     * Returns the set of flags for {@link #newWakeLock(int, String) newWakeLock()}
478     * that are supported on the device.
479     * For example, to test to see if the {@link #PROXIMITY_SCREEN_OFF_WAKE_LOCK}
480     * is supported:
481     *
482     * {@samplecode
483     * PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
484     * int supportedFlags = pm.getSupportedWakeLockFlags();
485     *  boolean proximitySupported = ((supportedFlags & PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)
486     *                                  == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK);
487     * }
488     *
489     * @return the set of supported WakeLock flags.
490     *
491     * {@hide}
492     */
493    public int getSupportedWakeLockFlags()
494    {
495        try {
496            return mService.getSupportedWakeLockFlags();
497        } catch (RemoteException e) {
498            return 0;
499        }
500    }
501
502    /**
503      * Returns whether the screen is currently on. The screen could be bright
504      * or dim.
505      *
506      * {@samplecode
507      * PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
508      * boolean isScreenOn = pm.isScreenOn();
509      * }
510      *
511      * @return whether the screen is on (bright or dim).
512      */
513    public boolean isScreenOn()
514    {
515        try {
516            return mService.isScreenOn();
517        } catch (RemoteException e) {
518            return false;
519        }
520    }
521
522    /**
523     * Reboot the device.  Will not return if the reboot is
524     * successful.  Requires the {@link android.Manifest.permission#REBOOT}
525     * permission.
526     *
527     * @param reason code to pass to the kernel (e.g., "recovery") to
528     *               request special boot modes, or null.
529     */
530    public void reboot(String reason)
531    {
532        try {
533            mService.reboot(reason);
534        } catch (RemoteException e) {
535        }
536    }
537
538    private PowerManager()
539    {
540    }
541
542    /**
543     * {@hide}
544     */
545    public PowerManager(IPowerManager service, Handler handler)
546    {
547        mService = service;
548        mHandler = handler;
549    }
550
551    /**
552     *  TODO: It would be nice to be able to set the poke lock here,
553     *  but I'm not sure what would be acceptable as an interface -
554     *  either a PokeLock object (like WakeLock) or, possibly just a
555     *  method call to set the poke lock.
556     */
557
558    IPowerManager mService;
559    Handler mHandler;
560}
561