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 /**
     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  */
    103 public 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