Anroid 11 关于NotificationManager && NotificationManagerService

僵小七 / 2024-07-20 / 原文

NotificationManager && NotificationManagerService

frameworks/base/core/java/android/app/NotificationManager.java
几个比较重要的函数:

//移除mContext.getUser发送的通知
public void cancel(@Nullable String tag, int id)
    {
        cancelAsUser(tag, id, mContext.getUser());
    }
//移除所有通知 
public void cancelAll()
    {
        INotificationManager service = getService();
        String pkg = mContext.getPackageName();
        if (localLOGV) Log.v(TAG, pkg + ": cancelAll()");
        try {
            service.cancelAllNotifications(pkg, mContext.getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

//发送通知,这里可以做判断屏蔽不发送通知
public void notify(int id, Notification notification)
public void notify(String tag, int id, Notification notification)
public void notifyAsUser(String tag, int id, Notification notification, UserHandle user)
    {
        INotificationManager service = getService();
        String pkg = mContext.getPackageName();

        try {
            if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
            service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
                    fixNotification(notification), user.getIdentifier());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java

enqueueNotificationInternal(...)
{
      ...
     if (notificationUid == INVALID_UID) {
            throw new SecurityException("Caller " + opPkg + ":" + callingUid
                    + " trying to post for invalid pkg " + pkg + " in user " + incomingUserId);
        }
    
     //检查通知是否属于仅限于系统使用的类别类型
     checkRestrictedCategories(pkg, notification);
    ...
    //Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
    //检查是否可以发送通知。检查速率限制器、贪睡助手和阻塞。
    if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
                r.getSbn().getOverrideGroupKey() != null)) {
            return;
      }
    ...
    mHandler.post(new EnqueueNotificationRunnable(userId, r, isAppForeground));
}
-> postPostNotificationRunnableMaybeDelayedLocked(r, new PostNotificationRunnable(r.getKey()));
->class PostNotificationRunnable implements Runnable 
{   
        @Override
        public void run() {
            //通知放在通知队列中,按照顺序处理
            synchronized (mNotificationLock) {
                try {
                    NotificationRecord r = null;
                    int N = mEnqueuedNotifications.size();
                    for (int i = 0; i < N; i++) {
                        final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
                        if (Objects.equals(key, enqueued.getKey())) {
                            r = enqueued;
                            break;
                        }
                    }
                    if (r == null) {
                        Slog.i(TAG, "Cannot find enqueued record for key: " + key);
                        return;
                    }

                    if (isBlocked(r)) {
                        Slog.i(TAG, "notification blocked by assistant request");
                        return;
                    }
}


//负责处理通知声音的函数.
//判断通知是否应尝试发出噪音、振动或闪烁LED,
//@return buzzBeepBlink - bitfield (buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)

int buzzBeepBlinkLocked(NotificationRecord record) {
    if (mIsAutomotive && !mNotificationEffectsEnabledForAutomotive) {
            return 0;
        }
        boolean buzz = false;
        boolean beep = false;
        boolean blink = false;
    ...
        if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
                    if (!sentAccessibilityEvent) {
                        sendAccessibilityEvent(record);
                        sentAccessibilityEvent = true;
                    }
                    if (DBG) Slog.v(TAG, "Interrupting!");
                    if (hasValidSound) {
                        if (isInCall()) {
                            playInCallNotification();//电话铃声?
                            beep = true;
                        } else {
                            beep = playSound(record, soundUri);//播放通知的声音函数,soundUri.getPath()通知声音文件路径
                        }
                        if(beep) {
                            mSoundNotificationKey = key;
                        }
                    }

                    final boolean ringerModeSilent =
                            mAudioManager.getRingerModeInternal()
                                    == AudioManager.RINGER_MODE_SILENT;
                    if (!isInCall() && hasValidVibrate && !ringerModeSilent) {
                        buzz = playVibration(record, vibration, hasValidSound);
                        if(buzz) {
                            mVibrateNotificationKey = key;
                        }
                    }
                } else if ((record.getFlags() & Notification.FLAG_INSISTENT) != 0) {
                    hasValidSound = false;
                }
            }
            ...
}

Notification的setNotificationsEnabledForPackage接口的使用:屏蔽特定应用的通知提示

Notification的setNotificationsEnabledForPackage接口详解