android4.4 车载灭屏 按任意键及触摸屏幕恢复亮屏
来源:互联网 发布:如何用备忘录编程 编辑:程序博客网 时间:2024/04/27 01:33
车载上的android4.4系统,基本上常亮。但最近需要一个新功能可以在launcher新增一个按钮,点击的时候。屏幕亮度为0,但实际上不等于按power键,不会睡眠。
然后可以按任意键恢复亮度,包括触屏事件。
一、PowerManagerService原先屏幕亮度流程
PowerManagerService是通过updateDisplayPowerStateLocked函数,把亮度更新到DisplayPowerController那块,然后再去调用lightsService获取背光的light,再去设置背景光的亮度。
但是这有问题,在PowerManagerService的updateDisplayPowerStateLocked函数,通常有个最低的亮度值(一般为10),如果低于这个亮度还是为这个值。
所以调用PowerManager的setBacklightBrightness,哪怕设的为0,最终亮度也为10.
private void updateDisplayPowerStateLocked(int dirty) { if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS | DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED | DIRTY_SETTINGS | DIRTY_SCREEN_ON_BLOCKER_RELEASED)) != 0) { int newScreenState = getDesiredScreenPowerStateLocked(); if (newScreenState != mDisplayPowerRequest.screenState) { if (newScreenState == DisplayPowerRequest.SCREEN_STATE_OFF && mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) { mLastScreenOffEventElapsedRealTime = SystemClock.elapsedRealtime(); } mDisplayPowerRequest.screenState = newScreenState; nativeSetPowerState( newScreenState != DisplayPowerRequest.SCREEN_STATE_OFF, newScreenState == DisplayPowerRequest.SCREEN_STATE_BRIGHT); } int screenBrightness = mScreenBrightnessSettingDefault; float screenAutoBrightnessAdjustment = 0.0f; boolean autoBrightness = (mScreenBrightnessModeSetting == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) { screenBrightness = mScreenBrightnessOverrideFromWindowManager; autoBrightness = false; } else if (isValidBrightness(mTemporaryScreenBrightnessSettingOverride)) { screenBrightness = mTemporaryScreenBrightnessSettingOverride; } else if (isValidBrightness(mScreenBrightnessSetting)) { screenBrightness = mScreenBrightnessSetting; } if (autoBrightness) { screenBrightness = mScreenBrightnessSettingDefault; if (isValidAutoBrightnessAdjustment( mTemporaryScreenAutoBrightnessAdjustmentSettingOverride)) { screenAutoBrightnessAdjustment = mTemporaryScreenAutoBrightnessAdjustmentSettingOverride; } else if (isValidAutoBrightnessAdjustment( mScreenAutoBrightnessAdjustmentSetting)) { screenAutoBrightnessAdjustment = mScreenAutoBrightnessAdjustmentSetting; } } screenBrightness = Math.max(Math.min(screenBrightness,//这个就是最小亮度的调整。 mScreenBrightnessSettingMaximum), mScreenBrightnessSettingMinimum); screenAutoBrightnessAdjustment = Math.max(Math.min( screenAutoBrightnessAdjustment, 1.0f), -1.0f); mDisplayPowerRequest.screenBrightness = screenBrightness; mDisplayPowerRequest.screenAutoBrightnessAdjustment = screenAutoBrightnessAdjustment; mDisplayPowerRequest.useAutoBrightness = autoBrightness; mDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked(); mDisplayPowerRequest.blockScreenOn = mScreenOnBlocker.isHeld(); mDisplayReady = mDisplayPowerController.requestPowerState(mDisplayPowerRequest, mRequestWaitForNegativeProximity);//最终都是设置到DisplayPowerController mRequestWaitForNegativeProximity = false;
二、PowerManagerService设置背光文件节点
因此我们的选择还是直接设置背光的文件节点,况且我们还要事先获取背光值,用来下次恢复亮度的时候,设置之前的亮度值。
代码如下我们再PowerManager中做了两个接口turnoffBacklight和turnOnBacklight来控制背光,最终通过binder调用到PowerManagerService中。
在PowerManagerService中直接通过了写节点/读节点的方式,来设置/获取背光。
@Override // Binder call public void turnOffBacklight() { int lightBrightness = getBackLightBrightness(); if (lightBrightness != 0) { mBackLightBrightness = getBackLightBrightness(); setBackLightBrightness(0); } } @Override // Binder call public boolean turnOnBacklight() { int lightBrightness = getBackLightBrightness(); if (lightBrightness == 0) { Slog.d(TAG, "turnOnBacklight setBackLightBrightness :" + mBackLightBrightness); setBackLightBrightness(mBackLightBrightness); return true; } return false; } private int getBackLightBrightness() { int level = -1; File localFile = new File("/sys/class/leds/lcd-backlight/brightness"); if (!localFile.canRead()) { Slog.w(TAG, "/sys/class/leds/lcd-backlight can not read!"); return level; } try { FileInputStream in = new FileInputStream(localFile); byte[] b = new byte[4]; in.read(b); int count = 0; for (int i = 0; i < 4; i++) { if (b[i] >= '0' && b[i] <= '9') {//非数字去除 count++; } else { break; } } String str = new String(b, 0, count); str = str.replaceAll("\\s+", "");//去除空格,换行符等 level = Integer.parseInt(str); in.close(); } catch (Exception e) { } return level; } private void setBackLightBrightness(int level) { File localFile = new File("/sys/class/leds/lcd-backlight/brightness"); if (!localFile.canWrite()) { Slog.w(TAG, "/sys/class/leds/lcd-backlight can not write!"); return; } try { FileOutputStream fos = new FileOutputStream(localFile); fos.write(String.valueOf(level).getBytes()); fos.close(); } catch (Exception e) { } }
我们再Launcher的按钮点击后调用PowerManager中的turnoffBacklight函数,灭屏。
三、恢复屏幕亮度
3.1 按键
最后我们在按键和触屏的时候恢复屏幕亮度,普通按键的流程会先到PhoneWindowManager的interceptKeyBeforeQueueing函数先处理,我们可以在这个函数中先进行背光亮度的判读, 部分代码如下:
@Override public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) { if (!mSystemBooted) { // If we have not yet booted, don't let key events do anything. return 0; } if (mPowerManager.isScreenOn()) { if (mPowerManager.turnOnBacklight()) { return 0; } }.......
逻辑无非两种情况,调用mPowerManager.isScreenOn函数
1.如果isScreenOn是返回true的。因为PowerManagerService的流程没有改变,系统还认为屏幕是亮着的。
所以我们turnOnBacklight,如果这个时候屏幕的亮度为0,代表我们之前调用过turnoffBacklight函数把背景光亮度设置为0了,我们把它恢复的亮度,而函数turnOnBacklight返回true,在interceptKeyBeforeQueueing函数中直接return了,代表这次的按键就点亮屏幕了,不会走interceptKeyBeforeQueueing的后续流程了,返回0也不会最后传给用户了。
如果这个时候有亮度,代表之前没有调用turnoffBacklight,函数turnOnBacklight返回false,继续interceptKeyBeforeQueueing的原有流程。代表如果屏幕亮着,按键处理走自己的流程。
2.如果isScreenOn返回false,代表现在灭屏了。那么这是PowerManagerService的流程了,和我们的背景光无关。
3.2 触屏
触屏的话流程会有一个不一样,因为在NativeInputManager的interceptMotionBeforeQueueing函数中,只有当isScreenOn是false的时候才会调用上层的interceptMotionBeforeQueueingWhenScreenOff函数。也就是灭屏的时候才会到PhoneWindowManager的interceptMotionBeforeQueueingWhenScreenOff函数,而我们恰恰是要在PowerManagerService亮屏的时候,进行我们的逻辑。
void NativeInputManager::interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) { // Policy: // - Ignore untrusted events and pass them along. // - No special filtering for injected events required at this time. // - Filter normal events based on screen state. // - For normal events brighten (but do not wake) the screen if currently dim. if ((policyFlags & POLICY_FLAG_TRUSTED) && !(policyFlags & POLICY_FLAG_INJECTED)) { if (isScreenOn()) { policyFlags |= POLICY_FLAG_PASS_TO_USER; if (!isScreenBright()) { policyFlags |= POLICY_FLAG_BRIGHT_HERE; } } else { JNIEnv* env = jniEnv(); jint wmActions = env->CallIntMethod(mServiceObj, gServiceClassInfo.interceptMotionBeforeQueueingWhenScreenOff, policyFlags); if (checkAndClearExceptionFromCallback(env, "interceptMotionBeforeQueueingWhenScreenOff")) { wmActions = 0; } policyFlags |= POLICY_FLAG_WOKE_HERE | POLICY_FLAG_BRIGHT_HERE; handleInterceptActions(wmActions, when, /*byref*/ policyFlags); } } else { policyFlags |= POLICY_FLAG_PASS_TO_USER; }}所以在PhoneWindowManager的interceptMotionBeforeQueueingWhenScreenOff函数处理不行,最后只能到应用进程处理,看我之前几篇分析按键的博客知道,触屏事件最终会调用到ViewRootImpl的各个InputStage中,而触屏和按键会走到ViewPostImeInputStage中去
final class ViewPostImeInputStage extends InputStage { public ViewPostImeInputStage(InputStage next) { super(next); } @Override protected int onProcess(QueuedInputEvent q) { if (q.mEvent instanceof KeyEvent) { return processKeyEvent(q); } else { // If delivering a new non-key event, make sure the window is // now allowed to start updating. handleDispatchDoneAnimating(); final int source = q.mEvent.getSource(); if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {//触屏事件 if (mPowerManager.isScreenOn()) { if (mPowerManager.turnOnBacklight()) { return FORWARD; } } return processPointerEvent(q); } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) { return processTrackballEvent(q); } else { return processGenericMotionEvent(q); } } }这里的话流程和按键那边的处理逻辑是一样的,就不分析了。
四、注意
有一点我们必须注意,手机如果要杀应用的话,输入法绝对不能杀,杀了输入法后,会导致输入法没有重启的这段时间,底层按键不能分发到上层应用。具体原因,后续分析。
- android4.4 车载灭屏 按任意键及触摸屏幕恢复亮屏
- 屏幕划线-矩形,圆,任意划线,多点触摸直线划线及角度显示
- android4.0屏幕截屏流程
- android4.4 电阻触摸校准修改说明
- 触摸屏幕
- 屏幕触摸
- 关于android4.4及以上版本无法恢复还原短信的问题记录与解决
- 关于android4.4及以上版本无法恢复还原短信的问题记录与解决
- Android4.4-Launcher源码分析系列之WorkSpace及屏幕滑动
- android 亮屏及屏幕解锁代码
- android 亮屏及屏幕解锁代码
- android 亮屏及屏幕解锁代码
- 关于ProgressDialog 触摸屏幕任意位置就消失的解决版本
- cocos2dx画连接任意两点的绳子【始终连接触摸点与屏幕中心】
- Android4.4屏幕录制命令screenrecord
- Android4.4 增加屏幕旋转功能
- Android4.4屏幕不休眠&不锁屏
- Android4.4屏幕录制命令screenrecord
- 读一读Android系统源代码 一:下载源码、编译framework模块
- Rabbit实例代码
- iScroll4 滚动到底部检测
- UISnapBehavior的简单使用
- 类的实例与实例的成员变量的销毁
- android4.4 车载灭屏 按任意键及触摸屏幕恢复亮屏
- golang语法总结(十一):判断语句if
- moveTaskToBack退后台
- keilc51编程中 发现一个中断函数和中断被调函数的重要关系。
- LDAP注入与防御剖析
- POJ1815 Friendship(求最小割点 dinic)
- Cydia Substrate是一个代码修改平台
- Neutron如何开发插件?
- group by和distinct的取舍