当前位置:网站首页>systemui屏蔽通知栏

systemui屏蔽通知栏

2022-08-10 14:29:00 纵容_伊人倩影

背景描述

客户说要屏蔽掉某个应用里的通知,但是不全部屏蔽,只屏蔽指定应用的部分通知。
很奇怪,这个东西要系统来做,应用不发通知不就好了嘛?
但是没办法,甲方爸爸的需求,唉(:

需求实现

方案1 ------ systemui中屏蔽通知

vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java的shouldFilterOut方法中添加过滤

	/** * "packageName/channelId" * 表示 包名中此channelID的通知可以显示,其它全部屏蔽,判断逻辑见{@link notificationHide} * */
    private static void initNotificationFilterList(){
    
        notificationFilterList.add("com.aaa.bbb/background_download");
        notificationFilterList.add("com.aaaa.ccc/background__upgrade");
    }
	/** * @return true/false 标时指定同时是否需要隐藏 * @param key 指定应用的包名 * @param channelId 显示指定的通知,其它通知全部过滤 * */
    public static boolean notificationHide(String key,String channelId){
    
        if (notificationFilterList.size() == 0){
    
            initNotificationFilterList();
        }
        if (key != null && key.length() > 0 && channelId != null && channelId.length() > 0){
    
            for (int i=0;i < notificationFilterList.size();i++){
    
                String index = notificationFilterList.get(i);
                String packageName ;
                String cId ;
                if (index != null && index.length() > 0){
    
                    String[] dex = index.split("/");
                    if (dex !=null && dex.length == 2){
    
                        packageName = dex[0];
                        cId = dex[1];
                        if (key.contains(packageName)
                                && !channelId.equals(cId)) {
    
                            return true;
                        }
                    }
                }

            }
        }
        return false;
    }
	/** * @return true if the provided notification should NOT be shown right now. */
    public boolean shouldFilterOut(NotificationEntry entry) {
    
        final StatusBarNotification sbn = entry.getSbn();
        ...
		if (sbn != null){
    
            if (notificationHide(sbn.getKey(),sbn.getNotification().getChannelId())){
    
            	//屏蔽应用通知
                return true;
            }
        }
		...
        return false;
    }

vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java的onNotificationPosted中

@Override
    public void onNotificationPosted(final StatusBarNotification sbn,
            final RankingMap rankingMap) {
    
        if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
        if (sbn != null){
    
            //屏蔽应用通知
            if (NotificationFilter.notificationHide(sbn.getKey(),sbn.getNotification().getChannelId())){
    
                return ;
            }
        }
        if (sbn != null && !onPluginNotificationPosted(sbn, rankingMap)) {
    
            mMainHandler.post(() -> {
    
                processForRemoteInput(sbn.getNotification(), mContext);

                for (NotificationHandler handler : mNotificationHandlers) {
    
                    handler.onNotificationPosted(sbn, rankingMap);
                }
            });
        }
    }

上述方法可以屏蔽systemui下面的通知,实现指定应用只显示指定通知,其它通知全部隐藏的需求。
but
这个效果只是不显示通知,通知本身还是在的。
1、比如launcher的通知小圆点,长按桌面图标的通知显示等问题。
frameworks/base/core/java/android/service/notification/NotificationListenerService.java
的getActiveNotifications方法获取通知。
2、其它应用可以通过
frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java的getNotificationRecord、getActiveNotificationsFromListener或者其他方法获取通知内容。
换个思路重新触发
我们应该从根本上删除那些要屏蔽的通知,或者从一开始就不让它add到NotificationManagerService中去。

方案2 ------ framework中屏蔽

frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java中
通知的获取主要在

@GuardedBy("mNotificationLock")
final ArrayList<NotificationRecord> mNotificationList = new ArrayList<>();
@GuardedBy("mNotificationLock")
final ArrayMap<String, NotificationRecord> mNotificationsByKey = new ArrayMap<>();

这两个列表和map中存储。我们要实现阻断添加,实现屏蔽特定通知。
1、跟踪上面2个add和put数据的地方
2、PostNotificationRunnable的run方法中进行add和put通知数据
3、EnqueueNotificationRunnable中启动的PostNotificationRunnable
4、enqueueNotificationInternal方法中启动EnqueueNotificationRunnable,但是后续发现还有其他地方也启用了EnqueueNotificationRunnable。
所以我们在enqueueNotificationInternal和EnqueueNotificationRunnable 2个地方都加了一些屏蔽处理。

void enqueueNotificationInternal(...){
    
	...
	if (notificationHide(pkg,channelId)){
    //过滤通知
    	return;
	}
	if (channel == null) {
    
    	final String noChannelStr = "No Channel found for "
	}
	...
}

内部类EnqueueNotificationRunnable的run方法中

public void run() {
    
	...
	if (contextId != null) {
    
		(new SnoozeNotificationRunnable(r.getSbn().getKey(),
				0, contextId)).snoozeLocked(r);
		return;
	}
	//屏蔽通知
	if(r != null && r.getSbn() !=null && r.getSbn().getNotification() !=null){
    
		String key = r.getSbn().getKey();
		String channelId = r.getSbn().getNotification().getChannelId();
		if (notificationHide(key,channelId)){
    
			return;
		}
	}
	mEnqueuedNotifications.add(r);
	...
}

这样修改之后,就可以完全屏蔽,通知不会添加到列表中了。

结尾

上述流程只是notification通知流程中的一小部分
完整的通知发送----framework添加通知----systemui显示通知。等流程没有完全跟踪。
如果有理解不到位的地方,欢迎留言~

补充

通知的使用:https://blog.csdn.net/jppipai/article/details/122864465
1、应用发送通知------framework中service管理通知数据
NotificationManager.notify------NotificationManagerService.enqueueNotificationWithTag------NotificationManagerService.enqueueNotificationInternal
这里就和上面service屏蔽通知的地方呼应上了。

//manager作为给上层的接口,最终还是会掉到service管理通知数据
frameworks/base/core/java/android/app/NotificationManager.java
    public void notify(int id, Notification notification)
    {
    
        notify(null, id, notification);
    }
    public void notify(String tag, int id, Notification notification)
    {
    
        notifyAsUser(tag, id, notification, mContext.getUser());
    }
    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();
        }
    }
//service管理通知数据
frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java
@Override
public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
        Notification notification, int userId) throws RemoteException {
    
    enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
            Binder.getCallingPid(), tag, id, notification, userId);
} 
原网站

版权声明
本文为[纵容_伊人倩影]所创,转载请带上原文链接,感谢
https://blog.csdn.net/a396604593/article/details/125376789