PowerManager.java revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
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
21import com.android.internal.os.RuntimeInit;
22
23/**
24 * This class gives you control of the power state of the device.
25 *
26 * <p><b>Device battery life will be significantly affected by the use of this API.</b>  Do not
27 * acquire WakeLocks unless you really need them, use the minimum levels possible, and be sure
28 * to release it as soon as you can.
29 *
30 * <p>You can obtain an instance of this class by calling
31 * {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}.
32 *
33 * <p>The primary API you'll use is {@link #newWakeLock(int, String) newWakeLock()}.  This will
34 * create a {@link PowerManager.WakeLock} object.  You can then use methods on this object to
35 * control the power state of the device.  In practice it's quite simple:
36 *
37 * {@samplecode
38 * PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
39 * PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "My Tag");
40 * wl.acquire();
41 *   ..screen will stay on during this section..
42 * wl.release();
43 * }
44 *
45 * <p>The following flags are defined, with varying effects on system power.  <i>These flags are
46 * mutually exclusive - you may only specify one of them.</i>
47 * <table border="2" width="85%" align="center" frame="hsides" rules="rows">
48 *
49 *     <thead>
50 *     <tr><th>Flag Value</th>
51 *     <th>CPU</th> <th>Screen</th> <th>Keyboard</th></tr>
52 *     </thead>
53 *
54 *     <tbody>
55 *     <tr><th>{@link #PARTIAL_WAKE_LOCK}</th>
56 *         <td>On*</td> <td>Off</td> <td>Off</td>
57 *     </tr>
58 *
59 *     <tr><th>{@link #SCREEN_DIM_WAKE_LOCK}</th>
60 *         <td>On</td> <td>Dim</td> <td>Off</td>
61 *     </tr>
62 *
63 *     <tr><th>{@link #SCREEN_BRIGHT_WAKE_LOCK}</th>
64 *         <td>On</td> <td>Bright</td> <td>Off</td>
65 *     </tr>
66 *
67 *     <tr><th>{@link #FULL_WAKE_LOCK}</th>
68 *         <td>On</td> <td>Bright</td> <td>Bright</td>
69 *     </tr>
70 *     </tbody>
71 * </table>
72 *
73 * <p>*<i>If you hold a partial wakelock, the CPU will continue to run, irrespective of any timers
74 * and even after the user presses the power button.  In all other wakelocks, the CPU will run, but
75 * the user can still put the device to sleep using the power button.</i>
76 *
77 * <p>In addition, you can add two more flags, which affect behavior of the screen only.  <i>These
78 * flags have no effect when combined with a {@link #PARTIAL_WAKE_LOCK}.</i>
79 * <table border="2" width="85%" align="center" frame="hsides" rules="rows">
80 *
81 *     <thead>
82 *     <tr><th>Flag Value</th> <th>Description</th></tr>
83 *     </thead>
84 *
85 *     <tbody>
86 *     <tr><th>{@link #ACQUIRE_CAUSES_WAKEUP}</th>
87 *         <td>Normal wake locks don't actually turn on the illumination.  Instead, they cause
88 *         the illumination to remain on once it turns on (e.g. from user activity).  This flag
89 *         will force the screen and/or keyboard to turn on immediately, when the WakeLock is
90 *         acquired.  A typical use would be for notifications which are important for the user to
91 *         see immediately.</td>
92 *     </tr>
93 *
94 *     <tr><th>{@link #ON_AFTER_RELEASE}</th>
95 *         <td>If this flag is set, the user activity timer will be reset when the WakeLock is
96 *         released, causing the illumination to remain on a bit longer.  This can be used to
97 *         reduce flicker if you are cycling between wake lock conditions.</td>
98 *     </tr>
99 *     </tbody>
100 * </table>
101 *
102 *
103 */
104public class PowerManager
105{
106    private static final String TAG = "PowerManager";
107
108    /**
109     * These internal values define the underlying power elements that we might
110     * want to control individually.  Eventually we'd like to expose them.
111     */
112    private static final int WAKE_BIT_CPU_STRONG = 1;
113    private static final int WAKE_BIT_CPU_WEAK = 2;
114    private static final int WAKE_BIT_SCREEN_DIM = 4;
115    private static final int WAKE_BIT_SCREEN_BRIGHT = 8;
116    private static final int WAKE_BIT_KEYBOARD_BRIGHT = 16;
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
124    /**
125     * Wake lock that ensures that the CPU is running.  The screen might
126     * not be on.
127     */
128    public static final int PARTIAL_WAKE_LOCK = WAKE_BIT_CPU_STRONG;
129
130    /**
131     * Wake lock that ensures that the screen and keyboard are on at
132     * full brightness.
133     */
134    public static final int FULL_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_BRIGHT
135                                            | WAKE_BIT_KEYBOARD_BRIGHT;
136
137    /**
138     * Wake lock that ensures that the screen is on at full brightness;
139     * the keyboard backlight will be allowed to go off.
140     */
141    public static final int SCREEN_BRIGHT_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_BRIGHT;
142
143    /**
144     * Wake lock that ensures that the screen is on (but may be dimmed);
145     * the keyboard backlight will be allowed to go off.
146     */
147    public static final int SCREEN_DIM_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_DIM;
148
149    /**
150     * Normally wake locks don't actually wake the device, they just cause
151     * it to remain on once it's already on.  Think of the video player
152     * app as the normal behavior.  Notifications that pop up and want
153     * the device to be on are the exception; use this flag to be like them.
154     * <p>
155     * Does not work with PARTIAL_WAKE_LOCKs.
156     */
157    public static final int ACQUIRE_CAUSES_WAKEUP = 0x10000000;
158
159    /**
160     * When this wake lock is released, poke the user activity timer
161     * so the screen stays on for a little longer.
162     * <p>
163     * Will not turn the screen on if it is not already on.  See {@link #ACQUIRE_CAUSES_WAKEUP}
164     * if you want that.
165     * <p>
166     * Does not work with PARTIAL_WAKE_LOCKs.
167     */
168    public static final int ON_AFTER_RELEASE = 0x20000000;
169
170    /**
171     * Class lets you say that you need to have the device on.
172     *
173     * <p>Call release when you are done and don't need the lock anymore.
174     */
175    public class WakeLock
176    {
177        static final int RELEASE_WAKE_LOCK = 1;
178
179        Runnable mReleaser = new Runnable() {
180            public void run() {
181                release();
182            }
183        };
184
185        int mFlags;
186        String mTag;
187        IBinder mToken;
188        int mCount = 0;
189        boolean mRefCounted = true;
190        boolean mHeld = false;
191
192        WakeLock(int flags, String tag)
193        {
194            switch (flags & LOCK_MASK) {
195            case PARTIAL_WAKE_LOCK:
196            case SCREEN_DIM_WAKE_LOCK:
197            case SCREEN_BRIGHT_WAKE_LOCK:
198            case FULL_WAKE_LOCK:
199                break;
200            default:
201                throw new IllegalArgumentException();
202            }
203
204            mFlags = flags;
205            mTag = tag;
206            mToken = new Binder();
207        }
208
209        /**
210         * Sets whether this WakeLock is ref counted.
211         *
212         * @param value true for ref counted, false for not ref counted.
213         */
214        public void setReferenceCounted(boolean value)
215        {
216            mRefCounted = value;
217        }
218
219        /**
220         * Makes sure the device is on at the level you asked when you created
221         * the wake lock.
222         */
223        public void acquire()
224        {
225            synchronized (mToken) {
226                if (!mRefCounted || mCount++ == 0) {
227                    try {
228                        mService.acquireWakeLock(mFlags, mToken, mTag);
229                    } catch (RemoteException e) {
230                    }
231                    mHeld = true;
232                }
233            }
234        }
235
236        /**
237         * Makes sure the device is on at the level you asked when you created
238         * the wake lock. The lock will be released after the given timeout.
239         *
240         * @param timeout Release the lock after the give timeout in milliseconds.
241         */
242        public void acquire(long timeout) {
243            acquire();
244            mHandler.postDelayed(mReleaser, timeout);
245        }
246
247
248        /**
249         * Release your claim to the CPU or screen being on.
250         *
251         * <p>
252         * It may turn off shortly after you release it, or it may not if there
253         * are other wake locks held.
254         */
255        public void release()
256        {
257            synchronized (mToken) {
258                if (!mRefCounted || --mCount == 0) {
259                    try {
260                        mService.releaseWakeLock(mToken);
261                    } catch (RemoteException e) {
262                    }
263                    mHeld = false;
264                }
265                if (mCount < 0) {
266                    throw new RuntimeException("WakeLock under-locked " + mTag);
267                }
268            }
269        }
270
271        public boolean isHeld()
272        {
273            synchronized (mToken) {
274                return mHeld;
275            }
276        }
277
278        public String toString() {
279            synchronized (mToken) {
280                return "WakeLock{"
281                    + Integer.toHexString(System.identityHashCode(this))
282                    + " held=" + mHeld + ", refCount=" + mCount + "}";
283            }
284        }
285
286        @Override
287        protected void finalize() throws Throwable
288        {
289            synchronized (mToken) {
290                if (mHeld) {
291                    try {
292                        mService.releaseWakeLock(mToken);
293                    } catch (RemoteException e) {
294                    }
295                    RuntimeInit.crash(TAG, new Exception(
296                                "WakeLock finalized while still held: "+mTag));
297                }
298            }
299        }
300    }
301
302    /**
303     * Get a wake lock at the level of the flags parameter.  Call
304     * {@link WakeLock#acquire() acquire()} on the object to acquire the
305     * wake lock, and {@link WakeLock#release release()} when you are done.
306     *
307     * {@samplecode
308     *PowerManager pm = (PowerManager)mContext.getSystemService(
309     *                                          Context.POWER_SERVICE);
310     *PowerManager.WakeLock wl = pm.newWakeLock(
311     *                                      PowerManager.SCREEN_DIM_WAKE_LOCK
312     *                                      | PowerManager.ON_AFTER_RELEASE,
313     *                                      TAG);
314     *wl.acquire();
315     * // ...
316     *wl.release();
317     * }
318     *
319     * @param flags Combination of flag values defining the requested behavior of the WakeLock.
320     * @param tag Your class name (or other tag) for debugging purposes.
321     *
322     * @see WakeLock#acquire()
323     * @see WakeLock#release()
324     */
325    public WakeLock newWakeLock(int flags, String tag)
326    {
327        return new WakeLock(flags, tag);
328    }
329
330    /**
331     * User activity happened.
332     * <p>
333     * Turns the device from whatever state it's in to full on, and resets
334     * the auto-off timer.
335     *
336     * @param when is used to order this correctly with the wake lock calls.
337     *          This time should be in the {@link SystemClock#uptimeMillis
338     *          SystemClock.uptimeMillis()} time base.
339     * @param noChangeLights should be true if you don't want the lights to
340     *          turn on because of this event.  This is set when the power
341     *          key goes down.  We want the device to stay on while the button
342     *          is down, but we're about to turn off.  Otherwise the lights
343     *          flash on and then off and it looks weird.
344     */
345    public void userActivity(long when, boolean noChangeLights)
346    {
347        try {
348            mService.userActivity(when, noChangeLights);
349        } catch (RemoteException e) {
350        }
351    }
352
353   /**
354     * Force the device to go to sleep. Overrides all the wake locks that are
355     * held.
356     *
357     * @param time is used to order this correctly with the wake lock calls.
358     *          The time  should be in the {@link SystemClock#uptimeMillis
359     *          SystemClock.uptimeMillis()} time base.
360     */
361    public void goToSleep(long time)
362    {
363        try {
364            mService.goToSleep(time);
365        } catch (RemoteException e) {
366        }
367    }
368
369    private PowerManager()
370    {
371    }
372
373    /**
374     * {@hide}
375     */
376    public PowerManager(IPowerManager service, Handler handler)
377    {
378        mService = service;
379        mHandler = handler;
380    }
381
382    /**
383     *  TODO: It would be nice to be able to set the poke lock here,
384     *  but I'm not sure what would be acceptable as an interface -
385     *  either a PokeLock object (like WakeLock) or, possibly just a
386     *  method call to set the poke lock.
387     */
388
389    IPowerManager mService;
390    Handler mHandler;
391}
392
393