车载上的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);//最终都是设置到DisplayPowerControllermRequestWaitForNegativeProximity = false;

二、PowerManagerService设置背光文件节点

因此我们的选择还是直接设置背光的文件节点,况且我们还要事先获取背光值,用来下次恢复亮度的时候,设置之前的亮度值。

代码如下我们再PowerManager中做了两个接口turnoffBacklight和turnOnBacklight来控制背光,最终通过binder调用到PowerManagerService中。

在PowerManagerService中直接通过了写节点/读节点的方式,来设置/获取背光。

    @Override // Binder callpublic void turnOffBacklight() {int lightBrightness = getBackLightBrightness();if (lightBrightness != 0) {mBackLightBrightness = getBackLightBrightness();setBackLightBrightness(0);}}@Override // Binder callpublic 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函数先处理,我们可以在这个函数中先进行背光亮度的判读, 部分代码如下:

    @Overridepublic 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);}@Overrideprotected 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 车载灭屏 按任意键及触摸屏幕恢复亮屏相关推荐

  1. javaFx实现截屏——鼠标拖动选择截屏区域进行截屏,任意界面按下快捷键截屏,截屏完成后显示截屏图片

    系列文章专栏:javafx图形绘制.桌面录屏录音源码合集 目录 一.实现的效果 二.实现思路 三.代码实现 <

  2. android流程点击开机键熄屏,一种基于android系统的灭屏状态下指纹解锁加速亮屏方法与流程...

    本发明涉及android系统解锁显示方法,尤其涉及一种基于android系统的灭屏状态下指纹解锁加速亮屏方法. 背景技术: 目前,随着指纹技术越来越普及,很多android系统设备都带有指纹外设,特别 ...

  3. android 11.0 12.0控制屏幕亮屏和灭屏操作

    在11.0 12.0的产品开发中, 需要提供亮屏和灭屏的接口在8.0以后系统对于屏幕亮灭屏做了限制,直接调用亮屏和灭屏的方法就调不到了, 接下来就来看PowerManage.java类 这个是一个电源 ...

  4. 电脑录屏按哪个键?您可以这样操作!

    案例:电脑按哪3个键,可以录屏? [我平常喜欢使用快捷键在电脑上快速完成一些操作.最近接触到了电脑录屏,感觉使用它一系列的操作比较麻烦.想在这里问问小伙伴们,有没有使用快捷键成功操作过的朋友!] 电脑 ...

  5. 单击屏幕亮屏流程分析

    一. kernel部分 1.看TP驱动有没有事件上报  cat /dev/input/evnet1  或者看kernel log [ 4036.282237] bt541_ts_device 5-00 ...

  6. Android 亮屏流程分析

    https://blog.csdn.net/FightFightFight/article/details/79808100 相关文章: [Android Framework] 8.1 PowerMa ...

  7. Android 8.1 PowerManagerService分析(四)——亮屏流程分析

    欢迎大家关注我的掘金帐号 我会在那里定期更新最新版本的Android Framework源码分析! 相关文章: [Android Framework] 8.1 PowerManagerService分 ...

  8. android亮屏、暗屏、解锁、关闭系统对话的监听事件

    protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentVie ...

  9. Android手机亮屏流程分析

    极力推荐Android 开发大总结文章:欢迎收藏程序员Android 力荐 ,Android 开发者需要的必备技能 注:文章转于网络,点击查看原文 PowerManagerService 之前系列文章 ...

最新文章

  1. 20211126 为什么转动惯量矩阵是正定的?
  2. 宏BOOST_TEST_TRAIT_TRUE的用法
  3. operator new,new operator,placement new的区别
  4. opencv图像处理9-图像金字塔
  5. LeetCode 1829. 每个查询的最大异或值(前缀异或 + 位运算)
  6. iText简介(转)
  7. Zend Studio使用
  8. 手把手带你阅读Mybatis源码(二)执行篇
  9. 全球首家机器人酒店“大裁员”!别了,人工智障
  10. Spark on Yarn遇到的几个问题
  11. JSOI2007 文本生成器
  12. SCI 投稿Cover letter模板大全
  13. 【论文笔记】基于深度学习的视觉检测及抓取方法
  14. 元宇宙漫游指南-区块链构建元宇宙基础设施,一文搞清楚元宇宙和区块链
  15. 工科生的Java Hello World 透视投影动画 二-----和我一起熟悉Java的数组,列表,类型,和JFrame GUI初步
  16. 收款凭证 付款凭证 记账凭证的区别
  17. 什么是Hadoop?大数据与Hadoop简介
  18. 教你一招:安全打开U盘的方法
  19. 数据结构—绪论(基本知识点第一章)
  20. 三星手机通讯录导出 .spb格式转.vcf

热门文章

  1. 【iOS】UITextField中关于粘贴Paste操作的一些小发现
  2. 【死磕NIO】— 阻塞、非阻塞、同步、异步,傻傻分不清楚
  3. 云梦四时歌服务器维护,云梦四时歌国服今日发布停运公告,停运时间安排以及补偿方案分享[多图]...
  4. fluent算例及利用c语言程序算法,第01章 fluent简单算例17
  5. 1024 程序员节岳麓对话、技术英雄会再奏时代新曲
  6. 鹿晗是如何成功表白关晓彤的?
  7. 国产厂商硬件防火墙对比解析综述
  8. ggiohokbih
  9. 企业微信 上传临时素材 JAVA
  10. 兰博基尼仪表显示服务器,兰博基尼仪表灯图解仪表灯诊断 兰博基尼仪表灯图解大全 兰博仪表盘故障灯图解大全故障维修 Lamborghini故障灯维修检查故障灯图解大全...