携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第3天,点击查看活动详情
一、息屏显示介绍
息屏显示又叫主动显示,是指在灭屏后可以显示日期时间电量通知等内容。
息屏显示的原理主要是利用了OLED
屏幕像素点自发光的特性,功耗相比LCD
屏幕要低很多。
设置项在:设置->显示->主动显示(高级中)
总共可以有如下4中设置:
- a. 始终显示 - 只要灭屏就显示日期时间电量信息
- b. 点击两次即显示 - 灭屏后点击屏幕2次显示日期时间电量信息
- c. 拿起手机即显示 - 拿起手机后显示日期时间电量信息
- d. 收到新通知后显示 - 收到新通知后显示通知信息 其中a开启时b,c设置无效,因为总是显示了,b,c设置只有在a设置关闭时才有意义,而d设置是显示通知的,跟a,b,c设置无关。 而且这些设置项并不总是可见的,控制可见与否可查看AmbientDisplaySettings.java的onAttach方法,有各自的控制器,如下:
//始终显示
use(AmbientDisplayAlwaysOnPreferenceController.class)
.setConfig(getConfig(context))
.setCallback(this::updatePreferenceStates);
//收到新通知后显示
use(AmbientDisplayNotificationsPreferenceController.class).setConfig(getConfig(context));
//点击两次即显示
use(DoubleTapScreenPreferenceController.class).setConfig(getConfig(context));
//拿起手机即显示
use(PickupGesturePreferenceController.class).setConfig(getConfig(context));
是否显示主要看下各个Controller
的getAvailabilityStatus()
返回值,返回AVAILABLE
就可以显示了,而是否开启主要看下各个Controller
的isChecked()
方法,而这些控制都使用到了framework
下的AmbientDisplayConfiguration.java
。
二、开关控制
列举下各个的控制条件:
收到新通知后显示开关
设置项是否显示:AmbientDisplayConfiguration.java的pulseOnNotificationAvailable()
只判断frameworks/base/core/res/res/values/config.xml
中的config_dozeComponent
是否配置了值(以下所有设置均在该文件中,直接写设置名了),默认frameworks
下的config.xml
中是没有配置的,就是默认不显示,但是平台在device\qcom\common\product\overlay
下默认配置了该值如下:
<string name="config_dozeComponent">com.android.systemui/com.android.systemui.doze.DozeService</string>
所以这个设置是默认显示的
默认开关状态:AmbientDisplayConfiguration.java的pulseOnNotificationEnabled()
config_dozeComponent
配置了值 并且Settings.Secure.DOZE_ENABLED(doze_enabled)
无默认值或配置为1
,而doze_enabled
实际无默认值,所以这项是默认开启的。
总是显示开关
设置项是否显示:AmbientDisplayConfiguration.java的alwaysOnAvailableForUser()
条件比较多如下
config_dozeComponent
配置有值 - 满足,overlay
中有配置
系统属性debug.doze.aod
为true
并且是debug
版本 或者 config_dozeAlwaysOnDisplayAvailable
配置为了true
- 目前这2
项都不满足,所以总体这一项是不满足的
Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED
值没有配置或配置为了0
- 当前没有配置,满足条件
综合来说由于这项是默认不显示,如果要显示请将config_dozeAlwaysOnDisplayAvailable
配置为true
默认开关状态:AmbientDisplayConfiguration.java
的alwaysOnEnabled()
条件如下
Settings.Secure.DOZE_ALWAYS_ON
没有默认值或者值为1
- 目前没有默认值,满足
上面控制显示的部分要为ture
,也就是可以显示 - 如上可知不满足
Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED
值没有配置或配置为了0
- 当前没有配置,满足条件
综上,该项默认不显示,config_dozeAlwaysOnDisplayAvailable
配置为true
后就能显示并默认开启
点击两次即显示开关
设置项是否显示:AmbientDisplayConfiguration.java
的doubleTapSensorAvailable()
R.string.config_dozeDoubleTapSensorType
是否有配置值,framework
下config.xml
中默认是空,qcom overlay
中也没有配置,所以该项是不显示的。
另外发现google/wahoo/overlay
下有配置:
<string name="config_dozeDoubleTapSensorType" translatable="false">com.google.sensor.double_touch</string>
可以尝试配置为这个,配置后肯定是能显示的,有没有效果就不试了。
默认开关状态:AmbientDisplayConfiguration.java
的pulseOnDoubleTapEnabled()
复合条件如下
Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP
没有默认值或值为1 - 目前无默认值,满足
config_dozeDoubleTapSensorType
有配置值 - 如上不满足
config_dozeComponent
有配置值 - 如上满足
综上,这项默认不显示,如果要显示并默认开启,要配置R.string.config_dozeDoubleTapSensorType
值
拿起手机即显示开关
设置项是否显示:AmbientDisplayConfiguration.java
的dozePulsePickupSensorAvailable()
R.bool.config_dozePulsePickup
配置为true
- 目前配置为false
,不满足,如果要显示设置项,将config_dozePulsePickup
配置为true
即可。
默认开关状态:AmbientDisplayConfiguration.java
的pulseOnPickupEnabled()
Settings.Secure.DOZE_PULSE_ON_PICK_UP
没有默认值或默认为1
或者 AmbientDisplayConfiguration.java
的alwaysOnEnabled()
alwaysOnEnabled()
也是个复合判断,DOZE_PULSE_ON_PICK_UP
这一项没有默认值就直接满足了,目前alwaysOnEnabled()
是不满足的,其正好是开启总是显示的条件,其条件见上分析。
R.bool.config_dozePulsePickup
配置为true
- 如上不满足
config_dozeComponent
有配置值 - 如上满足
综上,该项默认不显示,将R.bool.config_dozePulsePickup
配置为true
,该项就能显示并且默认开启
三、息屏显示实现
DreamService
DREAM_SERVICE
初始化
息屏显示主要通过服务DREAM_SERVICE
来操作的:
IDreamManager mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
该服务的实现是在DreamManagerService.java
中,在其onStart()
方法中有如下代码:
publishBinderService(DreamService.DREAM_SERVICE, new BinderService());
publishLocalService(DreamManagerInternal.class, new LocalService());
通过调用其startDozing()
以及stopDozing()
方法可以开启和关闭打盹
startDozing()
方法会持有DreamManagerService.java
的mDozeWakeLock(PowerManager.DOZE_WAKE_LOCK)
锁。 备注:该锁可能不释放,在数据网络开启时导致不休眠。
DREAM_SERVICE
被封装到了frameworks/base/core/java/android/service/dreams/DreamService.java
中,其他应用可通过继承DreamService
来实现自己的屏保。
DozeService
DozeService
在SystemUI
中,继承自DreamService
,是一种特殊的屏保,实现息屏显示功能。下面看下DozeService
是如何启动的:
在PowerManagerService.java
的systemReady()
方法中,有如下注册
filter = new IntentFilter();
filter.addAction(Intent.ACTION_DREAMING_STARTED);
filter.addAction(Intent.ACTION_DREAMING_STOPPED);
mContext.registerReceiver(new DreamReceiver(), filter, null, mHandler);
在绑定Dream
服务时会发出ACTION_DREAMING_STARTED
,收到该消息后DreamReceiver
会调用scheduleSandmanLocked()
方法,最终会调用到DreamManagerService.java的内部类LocalService的startDream()
方法,根据config_dozeComponen
t配置最终在DreamController.java的startDream()方法中启动DozeService。
DozeTriggers
DozeTriggers
是在SystemUI
中,控制总是显示以及来通知显示息屏信息的触发,该类创建基本流程是DozeService - DozeFactory - DozeTriggers
。