Android 12.0 中 清除通知 , 系统源码分析(二)

Android 提供了标准的api供第三方应用去清除通知,如下:

NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);notificationManager.cancel(id);//删除指定id的通知
notificationManager.cancelAll();//删除全部通知


针对的使用场景: 只能删除从该App中发出的通知,不能删除别的应用或者是系统的通知. 

特别提示:notificationManager.cancelAll() 是删除由该APP发出的所有通知,即 "App的包名"对应下的所有通知.

其中 "删除全部通知" 的源码分析如下: 

(1)源码路径: frameworks/base/core/java/android/app/NotificationManager.java

  /*** 取消所有先前显示的通知. */public void cancelAll(){INotificationManager service = getService();//通过context获取应用的包名,即定义NotificationManager的应用的包名String pkg = mContext.getPackageName();if (localLOGV) Log.v(TAG, pkg + ": cancelAll()");try {//跨进程通信调用NotificationManagerService中的方法service.cancelAllNotifications(pkg, mContext.getUserId());} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}

(2) 源码路径: frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java

 @Overridepublic void cancelAllNotifications(String pkg, int userId) {checkCallerIsSystemOrSameApp(pkg);userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);//不允许清除前提服务的通知,接着继续清除通知,cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),pkg, null, 0, FLAG_FOREGROUND_SERVICE, true, userId,REASON_APP_CANCEL_ALL, null);}//------------------------------------------------------/*** 清除给定包名的所有通知*/void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,ManagedServiceInfo listener) {mHandler.post(new Runnable() {@Overridepublic void run() {String listenerName = listener == null ? null : listener.component.toShortString();EventLogTags.writeNotificationCancelAll(callingUid, callingPid,pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,listenerName);// 设置退出参数if (!doit) {return;}synchronized (mNotificationLock) {FlagChecker flagChecker = (int flags) -> {if ((flags & mustHaveFlags) != mustHaveFlags) {return false;}if ((flags & mustNotHaveFlags) != 0) {return false;}return true;};//清除mNotificationList列表里保存的通知,看分析(3)cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,listenerName, true /* wasPosted */);//清除mEnqueuedNotifications列表里保存的通知,看分析(3)cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,flagChecker, false /*includeCurrentProfiles*/, userId,false /*sendDelete*/, reason, listenerName, false /* wasPosted */);mSnoozeHelper.cancel(userId, pkg);}}});}

(3) 上面 注释的  清除mNotificationList 和清除 mEnqueuedNotifications 其实都时调用同一个方法,即cancelAllNotificationsByListLocked().区别在于传入的list不同,其中mNotificationList 保存了所有的通知, 而 mEnqueuedNotifications  则是保存了所有发送的到系统的通知,它们的定义如下:

 final ArrayList<NotificationRecord> mNotificationList = new ArrayList<>();final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();final ArrayMap<String, NotificationRecord> mNotificationsByKey = new ArrayMap<>();

接着分析 cancelAllNotificationsByListLocked()

 @GuardedBy("mNotificationLock")private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,boolean sendDelete, int reason, String listenerName, boolean wasPosted) {Set<String> childNotifications = null;//遍历notificationList,并根据给定的条件筛选for (int i = notificationList.size() - 1; i >= 0; --i) {NotificationRecord r = notificationList.get(i);if (includeCurrentProfiles) {if (!notificationMatchesCurrentProfiles(r, userId)) {continue;}} else if (!notificationMatchesUserId(r, userId)) {continue;}// 如果没有指定包名称,不能删除所有通知if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {continue;}if (!flagChecker.apply(r.getFlags())) {continue;}//比较包名if (pkg != null && !r.getSbn().getPackageName().equals(pkg)) {continue;}//比较channelIdif (channelId != null && !channelId.equals(r.getChannel().getId())) {continue;}if (r.getSbn().isGroup() && r.getNotification().isGroupChild()) {if (childNotifications == null) {childNotifications = new HashSet<>();}childNotifications.add(r.getKey());continue;}//从notificationList中清除通知notificationList.remove(i);//从mNotificationsByKey中清除通知, mNotificationsByKey是保存了通知Key和通知的对应关系,mNotificationsByKey.remove(r.getKey());r.recordDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_NEUTRAL);//把通知从列表中清除后,还需要对通知的资源进行回收处理,分析(4)cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);}if (childNotifications != null) {final int M = notificationList.size();for (int i = M - 1; i >= 0; i--) {NotificationRecord r = notificationList.get(i);if (childNotifications.contains(r.getKey())) {// dismiss conditions were checked in the first loop and so don't need to be// checked againnotificationList.remove(i);mNotificationsByKey.remove(r.getKey());r.recordDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_NEUTRAL);cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);}}//更新通知设定的LED,分析(5)updateLightsLocked();}}

(4)继续分析 removeFromNotificationListsLocked() ,通知的资源释放

 @GuardedBy("mNotificationLock")private boolean removeFromNotificationListsLocked(NotificationRecord r) {// 从两个列表中删除,任一列表都可以有一个单独的记录,实际上是相同的通知。boolean wasPosted = false;//NotificationRecord在NotificationManagerService中代表一个通知,NotificationRecord recordInList = null;//根据指定的通知的key,在通知列表中查询是否有符合的通知if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))!= null) {//找到通知后,把该通知从通知列表中清除,并把返回值设置为truemNotificationList.remove(recordInList);mNotificationsByKey.remove(recordInList.getSbn().getKey());wasPosted = true;}while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))!= null) {//mEnqueuedNotifications 是一个list,里面保存了所有发送的通知,如果在该list中也存在需要删除的通知,则把该通知也从list中清除mEnqueuedNotifications.remove(recordInList);}return wasPosted;}

(5) 最后 处理通知的LED, updateLightsLocked()

  @GuardedBy("mNotificationLock")void updateLightsLocked(){if (mNotificationLight == null) {return;}// 处理通知lightsNotificationRecord ledNotification = null;while (ledNotification == null && !mLights.isEmpty()) {final String owner = mLights.get(mLights.size() - 1);ledNotification = mNotificationsByKey.get(owner);if (ledNotification == null) {Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);mLights.remove(owner);}}// 通话或屏幕打开时不要闪烁if (ledNotification == null || isInCall() || mScreenOn) {mNotificationLight.turnOff();} else {NotificationRecord.Light light = ledNotification.getLight();if (light != null && mNotificationPulseEnabled) {// pulse repeatedlymNotificationLight.setFlashing(light.color, LogicalLight.LIGHT_FLASH_TIMED,light.onMs, light.offMs);}}}

至此,notificationManager.cancelAll()已分析完毕.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/142630.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pycharm pro v2023.2.4(Python编辑开发)

PyCharm2023是一款集成开发环境&#xff08;IDE&#xff09;&#xff0c;专门为Python编程语言设计。以下是PyCharm2023的一些主要功能和特点&#xff1a; 代码编辑器&#xff1a;PyCharm2023提供了一个功能强大的代码编辑器&#xff0c;支持语法高亮、自动补全、代码调试、版…

AI歌姬,C位出道,基于PaddleHub/Diffsinger实现音频歌声合成操作(Python3.10)

懂乐理的音乐专业人士可以通过写乐谱并通过乐器演奏来展示他们的音乐创意和构思&#xff0c;但不识谱的素人如果也想跨界玩儿音乐&#xff0c;那么门槛儿就有点高了。但随着人工智能技术的快速迭代&#xff0c;现在任何一个人都可以成为“创作型歌手”&#xff0c;即自主创作并…

《数据结构、算法与应用C++语言描述》-队列的应用-工厂仿真

工厂仿真 完整可编译运行代码见&#xff1a;Github::Data-Structures-Algorithms-and-Applications/_19Factory simulation/ 问题描述 一个工厂有m台机器。工厂的每项任务都需要若干道工序才能完成。每台机器都执行一道工序&#xff0c;不同的机器执行不同的工序。一台机器一…

Python数据结构:集合(set)详解

1.集合的概念 在Python中&#xff0c;集合&#xff08;Set&#xff09;是一种无序、不重复的数据类型&#xff0c;它的实现基于哈希表&#xff0c;是由唯一元素组成的。集合中不允许有重复的元素&#xff0c;即相同元素只能出现一次。Python中的集合类似于数学中的集合&#xf…

Double DQN算法

Double DQN算法 问题 DQN 算法通过贪婪法直接获得目标 Q 值&#xff0c;贪婪法通过最大化方式使 Q 值快速向可能的优化目标收敛&#xff0c;但易导致过估计Q 值的问题&#xff0c;使模型具有较大的偏差。 即&#xff1a; 对于DQN模型, 损失函数使用的 Q(state) reward Q(ne…

Java14新增特性

前言 前面的文章&#xff0c;我们对Java9、Java10、Java11、Java12 、Java13的特性进行了介绍&#xff0c;对应的文章如下 Java9新增特性 Java10新增特性 Java11新增特性 Java12新增特性 Java13新增特性 今天我们来一起看一下Java14这个版本的一些重要信息 版本介绍 Java 14…

线程相关问题

多线程 计算机在同一时间可以执行多个线程 并行 多个事情在同一时间点内发生&#xff0c;并行的发生是不会抢占资源的 并发 多个事情在一段时间内同时发生&#xff0c;并发的产生会抢占资源 多线程的好处 如果为单线程计算机一次只能处理一个线程&#xff0c;那么当处理的线程需…

JNDI注入

1、什么是 JNDI JNDI(Java Naming and Directory Interface, Java命名和目录接口)&#xff0c;JNDI API 映射为特定的命名&#xff08;Name&#xff09;和目录服务&#xff08;Directory&#xff09;系统&#xff0c;使得Java应用程序可以和这些命名&#xff08;Name&#xff…

【Shell脚本11】Shell 函数

Shell 函数 linux shell 可以用户定义函数&#xff0c;然后在shell脚本中可以随便调用。 shell中函数的定义格式如下&#xff1a; [ function ] funname [()]{action;[return int;]}说明&#xff1a; 1、可以带function fun() 定义&#xff0c;也可以直接fun() 定义,不带任何…

SQL基础理论篇(一):什么是SQL

文章目录 什么是SQLSQL的四大部分常用的SQL标准参考文献 什么是SQL SQL的全称是Structured Query Language&#xff0c;即结构化查询语句。 其最早诞生于1974年&#xff0c;IBM研究员发布的一篇论文"SEQUEL&#xff1a;一门结构化的英语查询语言"。这几十年里&…

旺店通·企业版对接打通金蝶云星空查询调拨单接口与分布式调入单新增接口

旺店通企业版对接打通金蝶云星空查询调拨单接口与分布式调入单新增接口 源系统:旺店通企业版 旺店通是北京掌上先机网络科技有限公司旗下品牌&#xff0c;国内的零售云服务提供商&#xff0c;基于云计算SaaS服务模式&#xff0c;以体系化解决方案&#xff0c;助力零售企业数字化…

Android framework添加自定义的Product项目,lunch目标项目

文章目录 Android framework添加自定义的Product项目1.什么是Product&#xff1f;2.定义自己的Product玩一玩 Android framework添加自定义的Product项目 1.什么是Product&#xff1f; 源码目录下输入lunch命令之后&#xff0c;简单理解下面这些列表就是product。用于把系统编…

OpenCV+特征检测

检测 函数cv.cornerHarris()。其参数为&#xff1a; img 输入图像&#xff0c;应为灰度和float32类型blockSize是拐角检测考虑的邻域大小ksize 使用的Sobel导数的光圈参数k 等式中的哈里斯检测器自由参数 import numpy as np import cv2 as cv filename chessboard.png img…

如何显示标注的纯黑mask图

文章目录 前言一、二分类mask显示二、多分类mask显示 前言 通常情况下&#xff0c;使用标注软件标注的标签图看起来都是纯黑的&#xff0c;因为mask图为单通道的灰度图&#xff0c;而灰度图一般要像素值大于128后&#xff0c;才会逐渐显白&#xff0c;255为白色。而标注的时候…

sass 生成辅助色

背景 一个按钮往往有 4 个状态。 默认状态hover鼠标按下禁用状态 为了表示这 4 个状态&#xff0c;需要设置 4 个颜色来提示用户。 按钮类型一般有 5 个&#xff1a; 以 primary 类型按钮为例&#xff0c;设置它不同状态下的颜色&#xff1a; <button class"btn…

IP-guard Webserver view 远程命令执行漏洞【2023最新漏洞】

IP-guard Webserver view 远程命令执行漏洞【2023最新漏洞】 一、漏洞描述二、漏洞影响三、漏洞危害四、FOFA语句五、漏洞复现1、手动复现yaml pocburp发包 2、自动化复现小龙POC检测工具下载地址 免责声明&#xff1a;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传…

R程序 示例4.3.2版本包 在centos进行编译部署

为了在CentOS上下载和编译R语言4.3.2包&#xff0c;可以按照以下步骤进行操作&#xff1a; 1.首先&#xff0c;需要安装一些必要的依赖项。可以使用以下命令安装它们&#xff1a; sudo yum install -y epel-release sudo yum install -y gcc gcc-c gcc-gfortran readline-dev…

Linux 使用随记

Linux 使用随记 shell 命令行模式登录后所取得的程序被成为shell&#xff0c;这是因为这个程序负责最外层的跟用户&#xff08;我们&#xff09;通信工作&#xff0c;所以才被戏称为shell。 命令 1、命令格式 command [-options] parameter1 parameter2 … 1、一行命令中第…

UML建模语言

UML建模语言 类的关系 依赖关系 类的方法中使用形参、局部变量或者静态方法的方式调用其他类&#xff0c;表示当前类依赖其他类。 public class Main {public void eat(Person person) {person.play();// 方法参数Student student new Student();student.study();// 局部变…

4 条件判断和循环

文章目录 一、条件判断和循环1.1 if语句1.2 if-else1.3 if-elif-else1.4 for循环1.5 while循环1.6 break退出循环1.7 continue继续循环1.8 多重循环 二、练习题小结 一、条件判断和循环 1.1 if语句 输入用户年龄&#xff0c;根据年龄打印不同的内容&#xff0c;在Python程序中…