Android8.0 禁止系统和预装之外的应用弹出通知

最近在开发电子白板项目,系统用的是Android8.0

最近一个需求是:系统自带的应用和预装的应用可以弹出通知,其他应用不能弹出

8.0的通知使用可以查看 Android8.0中通知无法正常使用问题

要弹出通知,会使用到NotificationManagernotify方法

那就来看NotificationManager的代码吧,NotificationManager的代码位置是在(framework/base/core/java/andtoid/app/)

notify的代码如下

    public void notify(int id, Notification notification)
    {
        notify(null, id, notification);
    }

    public void notify(String tag, int id, Notification notification)
    {
        notifyAsUser(tag, id, notification, new UserHandle(UserHandle.myUserId()));
    }

这里走到notifyAsUsernotifyAsUser的代码如下

    public void notifyAsUser(String tag, int id, Notification notification, UserHandle user)
    {
        INotificationManager service = getService();
        String pkg = mContext.getPackageName();
        // Fix the notification as best we can.
        Notification.addFieldsFromContext(mContext, notification);
        if (notification.sound != null) {
            notification.sound = notification.sound.getCanonicalUri();
            if (StrictMode.vmFileUriExposureEnabled()) {
                notification.sound.checkFileUriExposed("Notification.sound");
            }
        }
        fixLegacySmallIcon(notification, pkg);
        if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {
            if (notification.getSmallIcon() == null) {
                throw new IllegalArgumentException("Invalid notification (no valid small icon): "
                        + notification);
            }
        }
        if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
        final Notification copy = Builder.maybeCloneStrippedForDelivery(notification);
        try {
            service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
                    copy, user.getIdentifier());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

这里最后调了serviceenqueueNotificationWithTag,这里的serviceNotificationManagerService

NotificationManagerService里的enqueueNotificationWithTag代码如下

        @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);
        }

这里调了 enqueueNotificationInternalenqueueNotificationInternal的代码如下

void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
            final int callingPid, final String tag, final int id, final Notification notification,
            int incomingUserId) {
        if (DBG) {
            Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
                    + " notification=" + notification);
        }
        checkCallerIsSystemOrSameApp(pkg);

        //zhongxiang.huang add begin
    	//Notification interception
        if(!isSystemApp(pkg) && !isNoticeWhiteApp(pkg)){
            Slog.i(TAG, ">>>>>>>>>>>>>>>>>>>>>>Notification interception return<<<<<<<<<<<<<<<<<");
            return;
        }
        //zhongxiang.huang add end

        final int userId = ActivityManager.handleIncomingUser(callingPid,
                callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
        final UserHandle user = new UserHandle(userId);

        if (pkg == null || notification == null) {
            throw new IllegalArgumentException("null not allowed: pkg=" + pkg
                    + " id=" + id + " notification=" + notification);
        }

        // The system can post notifications for any package, let us resolve that.
        final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);

        // Fix the notification as best we can.
        try {
            final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
                    pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
                    (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
            Notification.addFieldsFromContext(ai, notification);
        } catch (NameNotFoundException e) {
            Slog.e(TAG, "Cannot create a context for sending app", e);
            return;
        }

        mUsageStats.registerEnqueuedByApp(pkg);

        // setup local book-keeping
        String channelId = notification.getChannelId();
        if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
            channelId = (new Notification.TvExtender(notification)).getChannelId();
        }
        final NotificationChannel channel = mRankingHelper.getNotificationChannel(pkg,
                notificationUid, channelId, false /* includeDeleted */);
        if (channel == null) {
            final String noChannelStr = "No Channel found for "
                    + "pkg=" + pkg
                    + ", channelId=" + channelId
                    + ", id=" + id
                    + ", tag=" + tag
                    + ", opPkg=" + opPkg
                    + ", callingUid=" + callingUid
                    + ", userId=" + userId
                    + ", incomingUserId=" + incomingUserId
                    + ", notificationUid=" + notificationUid
                    + ", notification=" + notification;
            Log.e(TAG, noChannelStr);
            doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
                    "Failed to post notification on channel \"" + channelId + "\"\n" +
                    "See log for more details");
            return;
        }

        final StatusBarNotification n = new StatusBarNotification(
                pkg, opPkg, id, tag, notificationUid, callingPid, notification,
                user, null, System.currentTimeMillis());
        final NotificationRecord r = new NotificationRecord(getContext(), n, channel);

        if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r)) {
            return;
        }

        // Whitelist pending intents.
        if (notification.allPendingIntents != null) {
            final int intentCount = notification.allPendingIntents.size();
            if (intentCount > 0) {
                final ActivityManagerInternal am = LocalServices
                        .getService(ActivityManagerInternal.class);
                final long duration = LocalServices.getService(
                        DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
                for (int i = 0; i < intentCount; i++) {
                    PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
                    if (pendingIntent != null) {
                        am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
                                WHITELIST_TOKEN, duration);
                    }
                }
            }
        }

        mHandler.post(new EnqueueNotificationRunnable(userId, r));
    }

这里最终会走到mHandler.post(new EnqueueNotificationRunnable(userId, r)),把消息发出去

拦截通知的话在这里处理就好了,在方法里我加了如下代码

    //zhongxiang.huang add begin
    //fix bug - asc07-561(617977), Notification interception
    if(!isSystemApp(pkg) && !isNoticeWhiteApp(pkg)){
	    Slog.i(TAG, ">>>>>>>>>>>>>>>>>>>>>>Notification interception return<<<<<<<<<<<<<<<<<");
	    return;
    }
    //zhongxiang.huang add end

判断是否是系统应用,是否在我的白名单应用列表里的,两者都不是的话直接return

isSystemApp的代码如下

    private boolean isSystemApp(String pkg){
        if(null != pkg){
            try{
                PackageInfo info = mPackageManagerClient.getPackageInfo(pkg, 0);
                return (info != null)
                    &&(info.applicationInfo != null)
                    &&((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
            }catch(PackageManager.NameNotFoundException e){
                Slog.e(TAG, ">>>>isSystemApp error<<<<<<<e:"+e);
                return false;
            }
        }
        return false;
    }

isNoticeWhiteApp的代码如下

    private ArrayList<String> mNotificationAppList = new ArrayList<String>();
    private static final String XML_NOTIFICATIONAPPS_FILE = "/system/etc/notification_app.xml";
    private boolean isAppXMLLoaded = false;
    private boolean isNoticeWhiteApp(String pkgName) {
        if (!isAppXMLLoaded) {
            loadNotificationAppList();
            isAppXMLLoaded = true;
        }

        boolean isWhiteApp = false;
        if (pkgName != null && mNotificationAppList.size() > 0) {
            for (int i = 0; i < mNotificationAppList.size(); i++) {
                if (pkgName.equals(mNotificationAppList.get(i))) {
                    isWhiteApp = true;
                    break;
                }
            }
        }

        return isWhiteApp;
    }

    private void loadNotificationAppList() {
        Slog.i(TAG, "loadNotificationAppList: app white list");
        try{
            InputStream inStream = new FileInputStream(new File(XML_NOTIFICATIONAPPS_FILE));
            XmlPullParser parser = Xml.newPullParser();
            parser.setInput(inStream, "utf-8");
            int eventType = parser.getEventType();
            while (eventType != XmlPullParser.END_DOCUMENT) {
                switch (eventType) {
                    case XmlPullParser.START_TAG:
                        String name = parser.getName();
                        if (name.equalsIgnoreCase("app")) {
                            String app_name = parser.getAttributeValue(null, "name");
                            if (!app_name.isEmpty()) {
                                mNotificationAppList.add(app_name);
                            }
                        }
                    break;
                }
                eventType = parser.next();
            }
            inStream.close();
        } catch (IOException eo) {
            eo.printStackTrace();
        } catch (XmlPullParserException ex) {
            ex.printStackTrace();
        }
        Log.i(TAG, "loadNotificationAppList: app white list. app_num="+mNotificationAppList.size());
    }

loadNotificationAppList方法是读取notification_app.xml文件里的应用列表,该文件是在系统的/system/etc/目录下

源码是放在/device/hisilicon/bigfish/etc/目录下,在编译的时候把它拷贝到/system/etc/目录下

<?xml version="1.0" encoding="utf-8" ?>
<Apps_notification>
    <app name="com.android.calendar"/>
    <app name="com.android.email"/>	
    <app name="com.android.calculator2"/>
	
    ......

</Apps_notification>

/device/tpv / EBONY_V811/device_copyfile.mk添加以下代码,意思是将notification_app.xml文件从/device/hisilicon/bigfish/etc/目录拷拷贝到/system/etc/目录下

PRODUCT_COPY_FILES += \
    device/hisilicon/bigfish/etc/notification_app.xml:/system/etc/notification_app.xml

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值