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
@Override
public 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() {
@Override
public 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 mNotificationList = new ArrayList<>();
final ArrayList mEnqueuedNotifications = new ArrayList<>();
final ArrayMap mNotificationsByKey = new ArrayMap<>();
接着分析 cancelAllNotificationsByListLocked()
@GuardedBy("mNotificationLock")
private void cancelAllNotificationsByListLocked(ArrayList 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 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;
}
//比较channelId
if (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 again
notificationList.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) {
//找到通知后,把该通知从通知列表中清除,并把返回值设置为true
mNotificationList.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;
}
// 处理通知lights
NotificationRecord 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 repeatedly
mNotificationLight.setFlashing(light.color, LogicalLight.LIGHT_FLASH_TIMED,
light.onMs, light.offMs);
}
}
}
至此,notificationManager.cancelAll()已分析完毕.