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