当前位置: 代码迷 >> Android >> Android 中护持屏幕唤醒的方法
  详细解决方案

Android 中护持屏幕唤醒的方法

热度:35   发布时间:2016-05-01 15:12:54.0
Android 中保持屏幕唤醒的方法

最近在解一个 bug 时,用到了这个知识点。在这里总结一下:

bug 是这样描述的:

在 Camera 切换到摄像时,摄像过程大概持续2,3分钟,就自动进锁屏了

有时也会持续很长时间进锁屏。

这是一个概率性的问题(即随机出现)。

 

从原理上分析上来看,肯定是屏幕被锁住了。

log上分析会看到下面的信息:


07-01 13:56:24.144 284 315 I ActivityManager: goingToSleep
07-01 13:56:24.154 100 201 I SurfaceTexture: [SurfaceView] [virtual android::status_t android::SurfaceTexture::convertToAuxSlot(bool)] create dst buffer and image
07-01 13:56:24.168 100 201 I MDP : [MDP INFO](201): mHalMdp_RegisterLoopMemory(): client id:0 VA:0x48ACC000 size:0x384000 color:4 size:(1280x720) roi:(0 0 1280 720) rotate:0
07-01 13:56:24.168 100 201 I MDP : [MDP INFO](201): mHalMdp_RegisterLoopMemory():MVA Obj Create:client id:0 0x48ACC000(VA) 0x00000000(MVA) 0x00000001(M4U flag) 0x00000001(alloc MVA flag)
07-01 13:56:24.168 100 201 I SurfaceTexture: register MVA success, type:1, srcImgYAddr:0x48acc000, SFTexCnt:6
07-01 13:56:24.207 284 315 D ActivityManager: ACT-AM_PAUSE_ACTIVITY ActivityRecord{41b2ba28 com.android.camera/.VideoCamera}
07-01 13:56:24.208 4187 4187 I videocamera: onPause


和在摄像界面按锁屏键进锁屏的log是一样的。but 我什么都没按。

要不是我自己碰到了我还真不相信会有这个bug,从log 上看我一直认为是测试人员误按了锁屏键导致此问题的。

 

再来了解一下VideoCamera 是怎么保持屏幕唤醒的呢?

与下面几个函数有关。

    private void resetScreenOn() {        mHandler.removeMessages(CLEAR_SCREEN_DELAY);        getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);    }    private void keepScreenOnAwhile() {        Log.d(TAG, TAG + "\t call keepScreenOnAwhile() !");        mHandler.removeMessages(CLEAR_SCREEN_DELAY);        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);        mHandler.sendEmptyMessageDelayed(CLEAR_SCREEN_DELAY, SCREEN_DELAY);    }    private void keepScreenOn() {        Log.d(TAG, TAG + "\t call keepScreenOn() !");        mHandler.removeMessages(CLEAR_SCREEN_DELAY);        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);    }
                 case CLEAR_SCREEN_DELAY: {                    Log.i(TAG, "received CLEAR_SCREEN_DELAY");                    getWindow().clearFlags(                            WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);                    break;

 

在开始录像的函数 startVideoRecording 中调用 keepScreenOn() 来保持屏幕唤醒状态。

在停止录像的函数 stopVideoRecording 中调用 keepScreenOnAwhile() 来继续保持屏幕唤醒2分钟。2分钟后清除掉 FLAG_KEEP_SCREEN_ON ,使屏幕进入正常锁屏流程。

在videocamera activity 的 onPause 函数中调用 resetScreenOn() 来清除掉 FLAG_KEEP_SCREEN_ON ,使屏幕可以进入正常锁屏流程。

我们知道 onPause 函数一般是当该 Activity 在切换到后台的时候执行的。检查代码,发现在流程上并没有问题。后来了解到是系统维护的这个 FLAG_KEEP_SCREEN_ON 有问题才导致这种现象产生的。

为了解决问题,我了解到,还有一种保持屏幕唤醒的方法,即电源管理的 wakeLock 锁。了解到其用法如下:

[email protected]  PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);  PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "My Tag");  wl.acquire();    ..screen will stay on during this section..  wl.release();  }


先产生一个 PowerManager 对象,再获取一个 wakelock 锁。在需要保持屏幕唤醒的地方加上该锁,恢复的时候释放该锁即可。需要注意一下的是 pm.newWakeLock 的第一个参数。从代码注释上可以看到

 * <p>The following flags are defined, with varying effects on system power.  <i>These flags are * mutually exclusive - you may only specify one of them.</i> * <table border="2" width="85%" align="center" frame="hsides" rules="rows"> * *     <thead> *     <tr><th>Flag Value</th>  *     <th>CPU</th> <th>Screen</th> <th>Keyboard</th></tr> *     </thead> * *     <tbody> *     <tr><th>[email protected] #PARTIAL_WAKE_LOCK}</th> *         <td>On*</td> <td>Off</td> <td>Off</td>  *     </tr> *      *     <tr><th>[email protected] #SCREEN_DIM_WAKE_LOCK}</th> *         <td>On</td> <td>Dim</td> <td>Off</td>  *     </tr> * *     <tr><th>[email protected] #SCREEN_BRIGHT_WAKE_LOCK}</th> *         <td>On</td> <td>Bright</td> <td>Off</td>  *     </tr> *      *     <tr><th>[email protected] #FULL_WAKE_LOCK}</th> *         <td>On</td> <td>Bright</td> <td>Bright</td>  *     </tr> *     </tbody> * </table> 

 
 其中 Dim 是表示暗淡,即半亮的意思,这时我们选择 SCREEN_BRIGHT_WAKE_LOCK ,即 CPU  开 和 SCREEN 全亮 Keyboard 关

 来自 Google 开发者的提醒: 
 Device battery life will be significantly affected by the use of this API.
 Do not acquire WakeLocks unless you really need them, use the minimum levels possible,
 and be sure to release it as soon as you can.
 
 在 resetScreenOn(), keepScreenOn(), keepScreenOnAwhile() 及 case CLEAR_SCREEN_DELAY 下面的代码中,
 将 addFlags 处改为wl.acquire(),clearFlags 处改为wl.release() 即可最终这个问题就这样通过换锁解决了。
 
 亦可参考:http://android6.blog.51cto.com/2035380/382792

  相关解决方案