systemui屏蔽通知栏

背景描述

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

需求实现
方案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);
} 
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Android中,如果想要自定义下拉通知的颜色,可以通过修改SystemUI的相关设置来实现。 首先,为了修改SystemUI的颜色,需要获取相应的权限。我们可以在AndroidManifest.xml文件中添加如下代码: ```xml <uses-permission android:name="android.permission.STATUS_BAR"/> ``` 接下来,在我们的项目中创建一个名为values的文件夹,并在其中创建一个名为colors.xml的文件。在这个文件中,我们可以定义我们想要使用的颜色。例如,我们可以定义一个名为notification_background的颜色,用于设置下拉通知的背景颜色。代码如下: ```xml <resources> <color name="notification_background">#FF0000</color> </resources> ``` 然后,我们需要修改SystemUI的源代码,以更新背景颜色。具体来说,我们需要找到StatusBar类中的updateResources方法,并在该方法中添加以下代码: ```java Context context = mContext.createPackageContext("com.example.notificationtest", Context.CONTEXT_IGNORE_SECURITY); // 替换为自己的包名 int color = context.getResources().getColor(R.color.notification_background); mBackgroundView.setBackgroundColor(color); ``` 最后,我们需要重新编译并安装我们的应用程序。一旦安装完成,我们就可以看到下拉通知的背景颜色已经根据我们在colors.xml中定义的颜色进行了自定义。 以上是通过修改SystemUI的方式来自定义下拉通知的颜色。请注意,这种方式需要具备系统级权限,因此只适用于特定的Android设备。在实际开发中,请确保在使用这种方式之前了解并遵守相关的法规和政策,以避免违规行为。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值