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

 @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()已分析完毕.

你可能感兴趣的:(android)