当前位置: 首页 > news >正文

【SystemUI】锁屏来通知默认亮屏Wake模式

一、问题描述

基于 Android 14平台,锁屏状态下来通知时默认是进入Doze模式,此时屏幕不能点击只能查看通知信息且很快灭屏,用户体验不是很好,要求修改为通知直接亮屏。

在这里插入图片描述

二、问题分析

梳理锁屏状态下(特指设备息屏或处于Doze/AOD状态)接收到新通知的完整流程,可以更清晰地理解代码的脉络,这个流程横跨了Android Framework的核心服务和SystemUI。

流程概览:一个App发送通知 -> NotificationManagerService (系统服务) -> SystemUI (UI进程) -> 通知中断判断 -> Doze/亮屏决策 -> 执行动作 (Pulse或WakeUp)

1. 通知的发送与接收

  • 应用层 -> 系统服务层

App: 调用 NotificationManager.notify() 方法发送一个通知。
Framework (NotificationManagerService.java): 这是Android系统中负责管理所有通知的核心服务。enqueueNotificationInternal() 接收来自App的通知请求,进行处理、权限检查、分组、排序(Ranking)等一系列操作,然后将通知“排入队列”准备分发。

  • 系统服务层 -> SystemUI进程

SystemUI (NotificationListener.java): SystemUI中有一个服务会继承 NotificationListenerService,用于监听系统中所有的通知事件。当NotificationManagerService处理完一个新通知后,会回调这个方法 void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap),这是通知进入SystemUI的第一个入口

2. SystemUI的内部处理与中断判断

  • 通知信息收集与分发

SystemUI (NotifCollection.java) & (NotificationEntryManager.java): NotificationListener 在收到通知后,会将其传递给这些管理器。它们负责将StatusBarNotification对象包装成NotificationEntry对象,这个新对象包含了通知的所有信息和其在UI中的状态。然后,它们会将“有新通知”这个事件分发给各个监听者。

  • 决定是否“打扰”用户

SystemUI (NotificationInterruptStateProvider.java): 这个类是决定一个新通知是否应该发出声音、振动或点亮屏幕(Pulse)的核心。 shouldHeadsUp() 它会根据通知的渠道、重要性(Importance)、用户设置(是否开启勿扰模式DND)、设备当前状态等一系列复杂的规则,来判断这个通知是否应该以“抬头通知”(Heads-Up Notification)的形式出现,或者是否应该触发一次Doze Pulse。

3. 从“打扰”到“亮屏”的决策传递

  • 触发Doze Host回调

SystemUI (StatusBarNotificationPresenter.java) & (DozeService.java): 当NotificationInterruptStateProvider判断一个通知应该触发Pulse时,它会通过一系列调用,最终通知到DozeHost
接口: DozeHost.Callback
方法: onNotificationAlerted(Runnable onPulseSuppressedListener)
作用: 这是一个回调方法,字面意思就是“被通知提醒了”。它标志着“有一个通知需要唤醒屏幕”这个信号正式传递到了Doze管理体系中。

  • DozeTriggers接收信号(您正在修改的地方)

SystemUI (DozeTriggers.java): 这个类实现了DozeHost.Callback接口,是各种Doze触发器(传感器、通知、充电等)的集中处理地。
成员: mHostCallback (一个DozeHost.Callback的实例)
方法: onNotification(Runnable onPulseSuppressedListener)
作用: mHostCallback在被调用时,会直接执行这个onNotification方法。这就是整个流程的汇合点,也是您进行修改的最佳位置。之前所有的判断和流程,最终都会走到这里,请求一次屏幕状态的改变。

4. 执行最终动作(Pulse或WakeUp)

DozeTriggers.onNotification() 内部 requestPulse(...), 这个方法会请求Doze状态机执行一次“脉冲”。它内部会进一步调用proximityCheckThenCall来检查近距离传感器,如果检查通过,最终会调用mMachine.requestPulse(reason),这个方法会请求Doze状态机直接“唤醒”。

SystemUI (DozeMachine.java): 这是一个状态机,负责管理设备在INITIALIZED, DOZE, DOZE_AOD, DOZE_PULSING, FINISH等各种Doze状态之间的转换。
方法: requestPulse(int reason)
效果: 将状态切换到 DOZE_PULSING。这会触发DozeService在屏幕上绘制AOD通知界面,短暂亮起后熄灭。
方法: wakeUp(int reason)
效果: 将状态切换到 FINISH。这会退出整个Doze流程,并最终通过PowerManager
完全点亮屏幕**,显示锁屏界面(Keyguard)。

三、解决方案

DozeTriggers.requestPulse() -> DozeMachine.requestPulse() -> 屏幕进入Pulse状态
DozeTriggers.mMachine.wakeUp() -> DozeMachine.wakeUp() -> 屏幕被完全唤醒

src/com/android/systemui/doze/DozeTriggers.java

private void onNotification(Runnable onPulseSuppressedListener) {// Bug #2190530 [Android14][AR.599.001744.006101.016207][SystemUI] Dimension Log Configuration for SystemUIif (UniSystemuiComponentFactory.getInstance().getDebugConfigs("DozeMachine")) {Log.d(TAG, "requestNotificationPulse");}if (!sWakeDisplaySensorState) {Log.d(TAG, "Wake display false. Pulse denied.");runIfNotNull(onPulseSuppressedListener);mDozeLog.tracePulseDropped("wakeDisplaySensor");return;}mNotificationPulseTime = SystemClock.elapsedRealtime();if (!mConfig.pulseOnNotificationEnabled(mUserTracker.getUserId())) {runIfNotNull(onPulseSuppressedListener);mDozeLog.tracePulseDropped("pulseOnNotificationsDisabled");return;}if (mDozeHost.isAlwaysOnSuppressed()) {runIfNotNull(onPulseSuppressedListener);mDozeLog.tracePulseDropped("dozeSuppressed");return;}- requestPulse(DozeLog.PULSE_REASON_NOTIFICATION, false /* performedProxCheck */,-         onPulseSuppressedListener);+ mMachine.wakeUp(DozeLog.PULSE_REASON_NOTIFICATION);mDozeLog.traceNotificationPulse();
}
http://www.xdnf.cn/news/1367029.html

相关文章:

  • 32.Ansible平台搭建
  • 1424. 对角线遍历 II
  • 2024年Engineering SCI2区,面向工程管理的无人机巡检路径与调度,深度解析+性能实测
  • 计算机毕业设计 java 药店药品信息管理系统 基于 Java 的药店药品管理平台Java 开发的药品信息系统
  • 设计模式:原型模式(Prototype Pattern)
  • 如何通过虚函数实现多态?
  • 实现自己的AI视频监控系统-第二章-AI分析模块2
  • 【git使用场景】本地仓库与远程仓库存在独立历史
  • ​Visual Studio + UE5 进行游戏开发的常见故障问题解决
  • 系统开发 Day4
  • 音视频学习(五十六):单RTP包模式和FU-A分片模式
  • Linux驱动开发笔记(七)——并发与竞争(上)——原子操作
  • 深度学习-----《PyTorch深度学习核心应用解析:从环境搭建到模型优化的完整实践指南》
  • 链表OJ习题(2)
  • 操作系统中,进程与线程的定义与区别
  • 似然函数对数似然函数负对数似然函数
  • Ant Design for UI 选择下拉框
  • BIO、NIO 和 AIO
  • 2025.8.25回溯算法-集合
  • Typora + PicList + Gitee 图床完整配置教程
  • 【ElasticSearch】json查询语法和可用的客户端
  • ESP32开发WSL_VSCODE环境搭建
  • Mysql系列--8、索引
  • Java延迟任务实现方案详解:从DelayQueue到实际应用
  • 2.3零基础玩转uni-app轮播图:从入门到精通 (咸虾米总结)
  • 【Docker基础】Docker-compose进阶配置:健康检查与服务就绪
  • K8s Pod驱逐机制详解与实战
  • C++ extern 关键字面试深度解析
  • 开源 C++ QT Widget 开发(六)通讯--TCP调试
  • 安全合规:AC(上网行为安全)--下