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

【SystemUI】锁屏点击通知显示的解锁界面和通知重叠

一、问题描述

基于 Android 14平台,解锁界面的背景被设置为透明时,当锁屏界面点击通知时会跳出解锁界面,此时解锁界面覆盖再通知之上造成重叠,体验不好。我们发现在锁屏界面上,上滑解锁时会折叠通知页面,此时显示的解锁界面会全面显示,没有重叠,需要将锁屏点击通知的交互修改同上。此时在锁屏界面上通知会有点击和长按事件都可以调出解锁界面,需要分 2 部分处理。

在这里插入图片描述

二、问题分析

2.1 锁屏点击通知

分析 NotificationClicker.java 代码,发现实际处理通知点击后启动应用(Activity)以及相关解锁逻辑的关键调用是 mNotificationActivityStarter.onNotificationClicked(entry, row);NotificationClicker 本身只负责接收点击事件并进行一些初步的判断(如菜单是否可见、Guts是否暴露等),而核心的启动和解锁流程被封装在了 NotificationActivityStarter 类中。

再分析 NotificationActivityStarter 的实现类 StatusBarNotificationActivityStarter.java 代码后,发现处理点击通知的核心逻辑在 onNotificationClicked 方法中。这个方法区分了两种主要情况:

  1. showOverLockscreentrue: 应用可以直接在锁屏界面之上显示。这种情况下,代码已经包含了 mShadeController.collapseShade(true); 的调用,所以行为是正确的。
  2. showOverLockscreenfalse: 这是我们需要关注的情况。当设备处于锁屏状态且应用不能直接在锁屏之上显示时,系统需要先弹出解锁界面(Bouncer)。代码通过调用 mActivityStarter.dismissKeyguardThenExecute(...) 来处理这个流程。

问题就出在这里:在调用 mActivityStarter.dismissKeyguardThenExecute(...) 之前,代码没有收起通知面板(Shade),而ActivityStarter会直接在其上显示Bouncer,导致了UI重叠。

正确的修改方案是在 onNotificationClicked 方法中,针对 showOverLockscreenfalse 的分支,在调用 mActivityStarter.dismissKeyguardThenExecute(...) 之前,手动添加一行代码来收起通知面板。

2.2 锁屏长按通知

长按通知的逻辑路径

  1. 事件监听: 对通知的长时间按压事件由 ExpandableNotificationRow.java 捕获。
  2. Guts的开启: 长按操作的目的是为了打开通知的详细设置界面,这个界面在SystemUI中被称为 “Guts”。这个过程由 NotificationGutsManager.java 类来管理。
  3. 检查锁屏状态: NotificationGutsManager 在准备显示Guts之前,会通过 KeyguardStateController 检查设备是否处于锁定状态。
  4. 触发解锁: 如果设备是锁定的,NotificationGutsManager 不能直接显示Guts(因为这可能暴露信息或提供无需验证的操作)。因此,它会调用一个方法来请求系统显示Bouncer,并在用户成功解锁后,再回来执行显示Guts的操作。
  5. 问题发生: 与之前的单击场景一样,在请求显示Bouncer时,它没有先收起通知面板,导致了Bouncer直接覆盖在当前显示的通知和Guts的开启位置之上。

openGuts 处理从通知菜单行(NotificationMenuRowPlugin.MenuItem)触发打开Guts的逻辑,这通常是用户在通知上向一侧轻微滑动后点击设置按钮(或其他自定义按钮)时触发的流程,也包括长按。

mActivityStarter.executeRunnableDismissingKeyguard(...): 它请求 ActivityStarter 组件去解除锁屏。ActivityStarter 会负责显示解锁界面(Bouncer),并在用户成功解锁后,执行传入的 Runnable r。代码在调用 executeRunnableDismissingKeyguard 以显示Bouncer之前,没有收起通知面板(Shade),从而导致了UI重叠。

解决方案与之前的场景完全一致:在请求解锁之前,先调用 mShadeController 来收起通知面板。

三、解决方案

1. 锁屏点击通知

src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java

/*** Called when a notification is clicked.** @param entry notification that was clicked* @param row row for that notification*/
@Override
public void onNotificationClicked(NotificationEntry entry, ExpandableNotificationRow row) {...if (showOverLockscreen) {mIsCollapsingToShowActivityOverLockscreen = true;postKeyguardAction.onDismiss();} else {//*/ collapse when notification click in keyguard.if (mKeyguardStateController.isShowing()) {mShadeController.collapseShade(false /* animate */);}//*/mActivityStarter.dismissKeyguardThenExecute(postKeyguardAction,null,willLaunchResolverActivity);}
}

2. 锁屏长按通知

src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java

/*** Opens guts on the given ExpandableNotificationRow {@code view}. This handles opening guts for* the normal half-swipe and long-press use cases via a circular reveal. When the blocking* helper needs to be shown on the row, this will skip the circular reveal.** @param view ExpandableNotificationRow to open guts on* @param x x coordinate of origin of circular reveal* @param y y coordinate of origin of circular reveal* @param menuItem MenuItem the guts should display* @return true if guts was opened*/
public boolean openGuts(View view,int x,int y,NotificationMenuRowPlugin.MenuItem menuItem) {...//*/ collapse when notification click in keyguard.if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {mShadeController.collapseShade(false /* animate */);}//*/Runnable r = () -> mMainHandler.post(() -> openGutsInternal(view, x, y, menuItem));// If the bouncer shows, it will block the TOUCH_UP event from reaching the notif,// so explicitly mark it as unpressed here to reset the touch animation.view.setPressed(false);mActivityStarter.executeRunnableDismissingKeyguard(r,null /* cancelAction */,false /* dismissShade */,true /* afterKeyguardGone */,true /* deferred */);return true;/*** When {@link CentralSurfaces} doesn't exist, falling through to call* {@link #openGutsInternal(View,int,int,NotificationMenuRowPlugin.MenuItem)}.*/}}return openGutsInternal(view, x, y, menuItem);
}
http://www.dtcms.com/a/351578.html

相关文章:

  • [Sync_ai_vid] 唇形同步推理流程 | Whisper架构
  • 技术分享︱国产化突破:开源MDO工具链在新一代神威超算上的安装与调试
  • DevExpress WinForms中文教程:Data Grid - Excel样式的自定义过滤器对话框
  • 在Excel和WPS表格中输入分数的两种方法
  • 自然处理语言NLP: 基于双分支 LSTM 的酒店评论情感分析模型构建与实现
  • PostgreSQL快速入门
  • 会议室预约小程序主要功能及预约审批流程
  • Java大厂面试全解析:从Spring Boot到微服务架构实战
  • Hadoop MapReduce 任务/输入数据 分片 InputSplit 解析
  • ProfiNet转CAN/CANopen网关技术详解-三格电子
  • uniapp uview吸顶u-sticky 无效怎么办?
  • 利用Certbot生成ssl证书配置到nginx
  • Android之穿山甲广告接入
  • Flutter 项目命名规范 提升开发效率
  • 深度学习(三):PyTorch 损失函数:按任务分类的实用指南
  • Swift 解法详解 LeetCode 363:矩形区域不超过 K 的最大数值和
  • Unity游戏打包——Mac基本环境杂记
  • Android Glide生命周期管理:实现原理与最佳实践
  • ubuntu2204安装搜狗拼音输入法
  • 基于spark的招聘岗位需求分析可视化系统设计与实现
  • 《相关法律、法规知识(五)》
  • 【数据结构】串——模式匹配
  • 微服务-23.网关登录校验-自定义GlobalFilter
  • yggjs_rbutton React按钮组件v1.0.0 示例和教程
  • Java全栈开发面试实录:从基础到实战的深度探索
  • JVM 学习与提升路线总结:从入门到精通的系统化指南
  • 前端-如何将前端页面输出为PDF并打包的压缩包中
  • PDF转图片、图片转PDF(免费)
  • AI+drawio生成流程图探索
  • Python 操作 PPT 文件:从新手到高手的实战指南