Android息屏显示介绍

2,348 阅读5分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 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));

是否显示主要看下各个ControllergetAvailabilityStatus()返回值,返回AVAILABLE就可以显示了,而是否开启主要看下各个ControllerisChecked()方法,而这些控制都使用到了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.aodtrue并且是debug版本 或者 config_dozeAlwaysOnDisplayAvailable配置为了true - 目前这2项都不满足,所以总体这一项是不满足的 Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED 值没有配置或配置为了0 - 当前没有配置,满足条件 综合来说由于这项是默认不显示,如果要显示请将config_dozeAlwaysOnDisplayAvailable配置为true 默认开关状态:AmbientDisplayConfiguration.javaalwaysOnEnabled() 条件如下

Settings.Secure.DOZE_ALWAYS_ON没有默认值或者值为1 - 目前没有默认值,满足 上面控制显示的部分要为ture,也就是可以显示 - 如上可知不满足 Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED 值没有配置或配置为了0 - 当前没有配置,满足条件 综上,该项默认不显示,config_dozeAlwaysOnDisplayAvailable配置为true后就能显示并默认开启

点击两次即显示开关

设置项是否显示:AmbientDisplayConfiguration.javadoubleTapSensorAvailable() R.string.config_dozeDoubleTapSensorType是否有配置值,frameworkconfig.xml中默认是空,qcom overlay中也没有配置,所以该项是不显示的。 另外发现google/wahoo/overlay下有配置:

<string name="config_dozeDoubleTapSensorType" translatable="false">com.google.sensor.double_touch</string>

可以尝试配置为这个,配置后肯定是能显示的,有没有效果就不试了。 默认开关状态:AmbientDisplayConfiguration.javapulseOnDoubleTapEnabled() 复合条件如下

Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP没有默认值或值为1 - 目前无默认值,满足 config_dozeDoubleTapSensorType有配置值 - 如上不满足 config_dozeComponent有配置值 - 如上满足 综上,这项默认不显示,如果要显示并默认开启,要配置R.string.config_dozeDoubleTapSensorType

拿起手机即显示开关

设置项是否显示:AmbientDisplayConfiguration.javadozePulsePickupSensorAvailable() R.bool.config_dozePulsePickup配置为true - 目前配置为false,不满足,如果要显示设置项,将config_dozePulsePickup配置为true即可。 默认开关状态:AmbientDisplayConfiguration.javapulseOnPickupEnabled()

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.javamDozeWakeLock(PowerManager.DOZE_WAKE_LOCK)锁。 备注:该锁可能不释放,在数据网络开启时导致不休眠。 DREAM_SERVICE被封装到了frameworks/base/core/java/android/service/dreams/DreamService.java中,其他应用可通过继承DreamService来实现自己的屏保。 DozeService DozeServiceSystemUI中,继承自DreamService,是一种特殊的屏保,实现息屏显示功能。下面看下DozeService是如何启动的: 在PowerManagerService.javasystemReady()方法中,有如下注册

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_dozeComponent配置最终在DreamController.java的startDream()方法中启动DozeService。

DozeTriggers DozeTriggers是在SystemUI中,控制总是显示以及来通知显示息屏信息的触发,该类创建基本流程是DozeService - DozeFactory - DozeTriggers