android13#settings#enhanced notifications

93 阅读6分钟

1.简介

这个功能默认是打开的,如何默认关闭?

  • settings >> notifications >> 最底部

image.png

  • 参考2.3.2,首次开机的时候本地配置文件是没有的,会走catch,里边会加载默认的,并且把默认的加入allow
  • 如果默认不要打开的话,那么在2.3.2里的catch代码里,注释掉allowDefaultApprovedServices调用
  • 关于enhanced notifications

1.1.ConfigureNotificationSettings

>1.configure_notification_settings.xml

根据字符串搜索到xml如下

        <com.android.settingslib.PrimarySwitchPreference
            android:key="notification_assistant"
            android:order="24"
            android:title="@string/notification_assistant_title"
            android:summary="@string/notification_assistant_summary"
            settings:controller="com.android.settings.notification.NotificationAssistantPreferenceController"/>

1.2.NotificationAssistantPreferenceController

    protected NotificationBackend mNotificationBackend;

>1.isChecked

是否选中需要现编2个组件都不为空

    public boolean isChecked() {
        ComponentName acn = mNotificationBackend.getAllowedNotificationAssistant();
        ComponentName dcn = mNotificationBackend.getDefaultNotificationAssistant();
        return (acn != null && acn.equals(dcn));
    }

>2.setChecked

    public boolean setChecked(boolean isChecked) {
        ComponentName cn = isChecked
                ? mNotificationBackend.getDefaultNotificationAssistant() : null;
        if (isChecked) {
//打开开关会弹框提示,ok后最终调用的也是补充3,设置上边的 cn
            showDialog(cn);
            return false;
        } else {
            setNotificationAssistantGranted(null);//补充3,使默认组件不可用
            return true;
        }
    }

>3.setNotificationAssistantGranted

设置通知助手是否可用

    protected void setNotificationAssistantGranted(ComponentName cn) {
    //读取的值是1,不知道干啥的
        if (Settings.Secure.getIntForUser(mContext.getContentResolver(),
                Settings.Secure.NAS_SETTINGS_UPDATED, 0, mUserId) == 0) {
            mNotificationBackend.setNASMigrationDoneAndResetDefault(mUserId, cn != null);
        }
        mNotificationBackend.setNotificationAssistantGranted(cn);//1.3.3
    }

1.3.NotificationBackend

//最终调用的NotificationManagerService里的代码
    static INotificationManager sINM = INotificationManager.Stub.asInterface(
            ServiceManager.getService(Context.NOTIFICATION_SERVICE));

>1.getAllowedNotificationAssistant

    public ComponentName getAllowedNotificationAssistant() {
        try {
            return sINM.getAllowedNotificationAssistant();
        } catch (Exception e) {
            return null;
        }
    }

>2.getDefaultNotificationAssistant

    public ComponentName getDefaultNotificationAssistant() {
        try {
            return sINM.getDefaultNotificationAssistant();
        } catch (Exception e) {
            return null;
        }
    }

>3.setNotificationAssistantGranted

    public boolean setNotificationAssistantGranted(ComponentName cn) {
        try {
            sINM.setNotificationAssistantAccessGranted(cn, true);
            //设置完以后判断设置的是否和获取的一样
            if (cn == null) {
                return sINM.getAllowedNotificationAssistant() == null;
            } else {
                return cn.equals(sINM.getAllowedNotificationAssistant());
            }
        } catch (Exception e) {
            return false;
        }
    }

>4.setNASMigrationDoneAndResetDefault

    public void setNASMigrationDoneAndResetDefault(int userId, boolean loadFromConfig) {
        try {
            sINM.setNASMigrationDoneAndResetDefault(userId, loadFromConfig);
        }
    }

2.NotificationManagerService.java

    private NotificationListeners mListeners;
    private NotificationAssistants mAssistants;

2.1.mService

    final IBinder mService = new INotificationManager.Stub() {

>1.getAllowedNotificationAssistantForUser

        public ComponentName getAllowedNotificationAssistantForUser(int userId) {
            checkCallerIsSystemOrSystemUiOrShell();
            //参考4.3
            List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId);
            if (allowedComponents.size() > 1) {
            //只允许有一个
                throw new IllegalStateException(
                        "At most one NotificationAssistant: " + allowedComponents.size());
            }
            return CollectionUtils.firstOrNull(allowedComponents);
        }

>2.getDefaultNotificationAssistant

        public ComponentName getDefaultNotificationAssistant() {
            checkCallerIsSystem();
            return mAssistants.getDefaultFromConfig();
        }

>3.setNotificationAssistantAccessGrantedForUser

        public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
                int userId, boolean granted) {
            try {//参考2.2
                setNotificationAssistantAccessGrantedForUserInternal(assistant, userId, granted,
                        true);
            }
        }

2.2.setNotificationAssistantAccessGrantedForUserInternal

    protected void setNotificationAssistantAccessGrantedForUserInternal(
            ComponentName assistant, int baseUserId, boolean granted, boolean userSet) {
        List<UserInfo> users = mUm.getEnabledProfiles(baseUserId);
        if (users != null) {
            for (UserInfo user : users) {
                int userId = user.id;
                if (assistant == null) {
                //组件为空,说明是要关闭这个功能,那么找到已经allow的,设置granted为false
                    ComponentName allowedAssistant = CollectionUtils.firstOrNull(
                            mAssistants.getAllowedComponents(userId));
                    if (allowedAssistant != null) {
                    //把allowed改为不允许
                        setNotificationAssistantAccessGrantedForUserInternal(
                                allowedAssistant, userId, false, userSet);
                    }
                    continue;
                }
                if (!granted || mAllowedManagedServicePackages.test(assistant.getPackageName(),
                        userId, mAssistants.getRequiredPermission())) {
                    mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
                            userId, false, granted);
                            //参考4.5
                    mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
                            userId, true, granted, userSet);

                    getContext().sendBroadcastAsUser(
                            new Intent(ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
                                    .setPackage(assistant.getPackageName())
                                    .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
                            UserHandle.of(userId), null);
//保存到本地文件
                    handleSavePolicyFile();
                }
            }
        }
    }

2.3.init

    void init(WorkerHandler handler, RankingHandler rankingHandler,
    //..

        // Needs to be set before loadPolicyFile
        mAllowedManagedServicePackages = this::canUseManagedServices;//补充1

        mPolicyFile = policyFile;
        //这个就是读取本地保存的策略了,通知相关的基本都在这里,补充2
        loadPolicyFile();

>1.canUseManagedServices

如果有权限需求的话则验证对应的权限。

    boolean canUseManagedServices(String pkg, Integer userId, String requiredPermission) {
        boolean canUseManagedServices = true;
        if (requiredPermission != null) {
            try {
                if (mPackageManager.checkPermission(requiredPermission, pkg, userId)
                        != PackageManager.PERMISSION_GRANTED) {
                    canUseManagedServices = false;
                }
            }
        }
        return canUseManagedServices;
    }

>2.loadPolicyFile

  • 保存的文件路径 /data/system/notification_policy.xml
    protected void loadPolicyFile() {
        synchronized (mPolicyFile) {
            InputStream infile = null;
            try {
                infile = mPolicyFile.openRead();
                readPolicyXml(infile, false /*forRestore*/, UserHandle.USER_ALL);
            } catch (FileNotFoundException e) {
                //第一次的话文件应该是不存在的,加载默认的数据
                loadDefaultApprovedServices(USER_SYSTEM);
                //默认的加入到allow集合里
                allowDefaultApprovedServices(USER_SYSTEM);
            } 
        }
    }

>3.loadDefaultApprovedServices

    void loadDefaultApprovedServices(int userId) {
        mListeners.loadDefaultsFromConfig();
        mConditionProviders.loadDefaultsFromConfig();
        mAssistants.loadDefaultsFromConfig();
    }

2.4.setDefaultAssistantForUser

  • 小节2.5会调用,以及重置的时候会调用
//    public static final String NAS_DEFAULT_SERVICE = "nas_default_service";
//    public static final String NAMESPACE_SYSTEMUI = "systemui";

    protected void setDefaultAssistantForUser(int userId) {
    //补充1
        String overrideDefaultAssistantString = DeviceConfig.getProperty(
                DeviceConfig.NAMESPACE_SYSTEMUI,
                SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE);
        if (overrideDefaultAssistantString != null) {
            ArraySet<ComponentName> approved = mAssistants.queryPackageForServices(
                    overrideDefaultAssistantString,
                    MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
                    userId);
            for (int i = 0; i < approved.size(); i++) {
            //有覆写的默认助手,并且添加到allow集合成功
                if (allowAssistant(userId, approved.valueAt(i))) return;
            }
        }
        ArraySet<ComponentName> defaults = mAssistants.getDefaultComponents();
//把默认的组件加入allow集合
        for (int i = 0; i < defaults.size(); i++) {
            ComponentName cn = defaults.valueAt(i);
            if (allowAssistant(userId, cn)) return;
        }
    }

>1.getProperty

  • 根据namespace从Settings.Config里读取map数据,然后从根据name从map里拿到value
    public static String getProperty(@NonNull String namespace, @NonNull String name) {

        return getProperties(namespace, name).getString(name, null);
    }
    public static Properties getProperties(@NonNull String namespace, @NonNull String ... names) {
        ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
        return new Properties(namespace,
                Settings.Config.getStrings(contentResolver, namespace, Arrays.asList(names)));
    }

2.5.allowDefaultApprovedServices

添加默认允许的服务到allow集合

  • 监听新用户的add会调用
  • 加载默认的配置失败的话会调用
    protected void allowDefaultApprovedServices(int userId) {
        ArraySet<ComponentName> defaultListeners = mListeners.getDefaultComponents();
        for (int i = 0; i < defaultListeners.size(); i++) {
            ComponentName cn = defaultListeners.valueAt(i);
            allowNotificationListener(userId, cn);
        }

        ArraySet<String> defaultDnds = mConditionProviders.getDefaultPackages();
        for (int i = 0; i < defaultDnds.size(); i++) {
            allowDndPackage(userId, defaultDnds.valueAt(i));
        }
//参考2.4
        setDefaultAssistantForUser(userId);
    }

3.NotificationAssistants

    public class NotificationAssistants extends ManagedServices {

3.1.loadDefaultsFromConfig

先看下默认的配置哪里来的

        protected void loadDefaultsFromConfig() {
            loadDefaultsFromConfig(true);
        }

        protected void loadDefaultsFromConfig(boolean addToDefault) {
            ArraySet<String> assistants = new ArraySet<>();
            assistants.addAll(Arrays.asList(mContext.getResources().getString(
                    com.android.internal.R.string.config_defaultAssistantAccessComponent)
                    .split(ManagedServices.ENABLED_SERVICES_SEPARATOR)));
            for (int i = 0; i < assistants.size(); i++) {
                ComponentName assistantCn = ComponentName
                        .unflattenFromString(assistants.valueAt(i));
                String packageName = assistants.valueAt(i);
                if (assistantCn != null) {
                    packageName = assistantCn.getPackageName();
                }
                if (TextUtils.isEmpty(packageName)) {
                    continue;
                }
                //参考4.1,查找有对应action和权限的服务,配置参考3.2
                ArraySet<ComponentName> approved = queryPackageForServices(packageName,
                        MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, USER_SYSTEM);
                if (approved.contains(assistantCn)) {
                    if (addToDefault) {
                        //加入默认的组件里
                        addDefaultComponentOrPackage(assistantCn.flattenToString());
                    } else {
                        //
                        mDefaultFromConfig = assistantCn;
                    }
                }
            }
        }

>1.config_defaultAssistantAccessComponent

我们集成了谷歌应用,所以被覆写了,默认的不是这个

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <!-- Component name that should be granted Notification Assistant access -->
    <string name="config_defaultAssistantAccessComponent" translatable="false">com.google.android.ext.services/android.ext.services.notification.Assistant</string>
    <!-- Package name of the required service extension package. -->
    <string name="config_servicesExtensionPackage" translatable="false">com.google.android.ext.services</string>
</resources>

3.2.getConfig

        protected Config getConfig() {
            Config c = new Config();
            c.caption = "notification assistant";
            c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
            c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS;
            c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
            c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
            c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
            c.clientLabel = R.string.notification_ranker_binding_label;
            return c;
        }

3.3.getDefaultFromConfig

        ComponentName getDefaultFromConfig() {
            if (mDefaultFromConfig == null) {
                loadDefaultsFromConfig(false);
            }
            return mDefaultFromConfig;
        }

4.ManagedServices.java

    public ManagedServices(Context context, Object mutex, UserProfiles userProfiles,
            IPackageManager pm) {
        mContext = context;
        mMutex = mutex;
        mUserProfiles = userProfiles;
        mPm = pm;
        mConfig = getConfig();//子类实现,参考3.2
        mApprovalLevel = APPROVAL_BY_COMPONENT;//默认是enable/disable 服务组件的
        mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
    }

4.1.queryPackageForServices

  • 查找包下所有满足action的服务,action的配置参考3.2
    protected ArraySet<ComponentName> queryPackageForServices(String packageName, int extraFlags,
            int userId) {
        ArraySet<ComponentName> installed = new ArraySet<>();
        final PackageManager pm = mContext.getPackageManager();
        Intent queryIntent = new Intent(mConfig.serviceInterface);
        if (!TextUtils.isEmpty(packageName)) {
            queryIntent.setPackage(packageName);
        }
        List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
                queryIntent,
                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA | extraFlags,
                userId);

        if (installedServices != null) {
            for (int i = 0, count = installedServices.size(); i < count; i++) {
                ResolveInfo resolveInfo = installedServices.get(i);
                ServiceInfo info = resolveInfo.serviceInfo;

                ComponentName component = new ComponentName(info.packageName, info.name);
                if (!mConfig.bindPermission.equals(info.permission)) {
                //判断是否有对应的bind权限,见3.2
                    continue;
                }
                installed.add(component);
            }
        }
        return installed;
    }

4.2.addDefaultComponentOrPackage

  • 根据mApprovalLevel是包还是组件,加入不同的集合里
    protected void addDefaultComponentOrPackage(String packageOrComponent) {
        if (!TextUtils.isEmpty(packageOrComponent)) {
            synchronized (mDefaultsLock) {
                if (mApprovalLevel == APPROVAL_BY_PACKAGE) {
                    mDefaultPackages.add(packageOrComponent);
                    return;
                }
                ComponentName cn = ComponentName.unflattenFromString(packageOrComponent);
                if (cn != null  && mApprovalLevel == APPROVAL_BY_COMPONENT) {
                    mDefaultPackages.add(cn.getPackageName());
                    mDefaultComponents.add(cn);
                    return;
                }
            }
        }
    }

4.3.getAllowedComponents

还是得看mApproved里的数据哪里来的,参考4.4,4.5

    protected List<ComponentName> getAllowedComponents(int userId) {
        final List<ComponentName> allowedComponents = new ArrayList<>();
        synchronized (mApproved) {
            final ArrayMap<Boolean, ArraySet<String>> allowedByType =
                    mApproved.getOrDefault(userId, new ArrayMap<>());
            for (int i = 0; i < allowedByType.size(); i++) {
                final ArraySet<String> allowed = allowedByType.valueAt(i);
                for (int j = 0; j < allowed.size(); j++) {
                    ComponentName cn = ComponentName.unflattenFromString(allowed.valueAt(j));
                    if (cn != null) {
                        allowedComponents.add(cn);
                    }
                }
            }
        }
        return allowedComponents;
    }

4.4.addApprovedList

    protected void addApprovedList(String approved, int userId, boolean isPrimary, String userSet) {
        if (TextUtils.isEmpty(approved)) {
            approved = "";
        }
        if (userSet == null) {
            userSet = approved;
        }
        synchronized (mApproved) {
            ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
            if (approvedByType == null) {
                approvedByType = new ArrayMap<>();
                mApproved.put(userId, approvedByType);
            }

            ArraySet<String> approvedList = approvedByType.get(isPrimary);
            if (approvedList == null) {
                approvedList = new ArraySet<>();
                approvedByType.put(isPrimary, approvedList);
            }

            String[] approvedArray = approved.split(ENABLED_SERVICES_SEPARATOR);
            for (String pkgOrComponent : approvedArray) {
                String approvedItem = getApprovedValue(pkgOrComponent);
                if (approvedItem != null) {
                    approvedList.add(approvedItem);
                }
            }

            ArraySet<String> userSetList = mUserSetServices.get(userId);
            if (userSetList == null) {
                userSetList = new ArraySet<>();
                mUserSetServices.put(userId, userSetList);
            }
            String[] userSetArray = userSet.split(ENABLED_SERVICES_SEPARATOR);
            for (String pkgOrComponent : userSetArray) {
                String approvedItem = getApprovedValue(pkgOrComponent);
                if (approvedItem != null) {
                    userSetList.add(approvedItem);
                }
            }
        }
    }

调用的地方:一种是从settings里迁移过来的(不看了),一种是读取本地存储的(补充1),NMS里调用的

>1.readXml

  • allowedManagedServicePackages数据参考2.3.1
    public void readXml(
            TypedXmlPullParser parser,
            TriPredicate<String, Integer, String> allowedManagedServicePackages,
            boolean forRestore,
            int userId)
//..
            if (type == XmlPullParser.START_TAG) {
                if (TAG_MANAGED_SERVICES.equals(tag)) {
                    final String approved = XmlUtils.readStringAttribute(parser, ATT_APPROVED_LIST);
//..
                    readExtraAttributes(tag, parser, resolvedUserId);
                    if (allowedManagedServicePackages == null || allowedManagedServicePackages.test(
                            getPackageName(approved), resolvedUserId, getRequiredPermission())
                            || approved.isEmpty()) {
                        if (mUm.getUserInfo(resolvedUserId) != null) {
                        //这里
                            addApprovedList(approved, resolvedUserId, isPrimary, userSetComponent);
                        }
                        mUseXml = true;
                    }

>2.writeXml

也是NMS里调用的,保存数据

    public void writeXml(TypedXmlSerializer out, boolean forBackup, int userId) throws IOException {
        out.startTag(null, getConfig().xmlTag);

        out.attributeInt(null, ATT_VERSION, Integer.parseInt(DB_VERSION));

        writeDefaults(out);

4.5.setPackageOrComponentEnabled

eanbled为true的话加入集合里,为false的话移除

    protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId,
            boolean isPrimary, boolean enabled, boolean userSet) {
        synchronized (mApproved) {
            ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.get(userId);
            if (allowedByType == null) {
                allowedByType = new ArrayMap<>();
                mApproved.put(userId, allowedByType);
            }
            ArraySet<String> approved = allowedByType.get(isPrimary);
            if (approved == null) {
                approved = new ArraySet<>();
                allowedByType.put(isPrimary, approved);
            }
            String approvedItem = getApprovedValue(pkgOrComponent);

            if (approvedItem != null) {
                if (enabled) {
                    approved.add(approvedItem);
                } else {
                    approved.remove(approvedItem);
                }
            }
            ArraySet<String> userSetServices = mUserSetServices.get(userId);
            if (userSetServices == null) {
                userSetServices = new ArraySet<>();
                mUserSetServices.put(userId, userSetServices);
            }
            if (userSet) {
                userSetServices.add(pkgOrComponent);
            } else {
                userSetServices.remove(pkgOrComponent);
            }
        }
//最终重新bind或者unbind服务
        rebindServices(false, userId);
    }

>1.getApprovedValue

根据mApprovalLevel返回包或者组件

    private String getApprovedValue(String pkgOrComponent) {
        if (mApprovalLevel == APPROVAL_BY_COMPONENT) {
            if(ComponentName.unflattenFromString(pkgOrComponent) != null) {
                return pkgOrComponent;
            }
            return null;
        } else {
            return getPackageName(pkgOrComponent);
        }
    }

>2.getPackageName

    protected String getPackageName(String packageOrComponent) {
        final ComponentName component = ComponentName.unflattenFromString(packageOrComponent);
        if (component != null) {
            return component.getPackageName();
        } else {
            return packageOrComponent;
        }
    }

5.NotificationAssistantService

public abstract class NotificationAssistantService extends NotificationListenerService {

5.1.常量

>1.SERVICE_INTERFACE

    public static final String SERVICE_INTERFACE
            = "android.service.notification.NotificationAssistantService";

6.ConditionProviders.java

同样继承的小节4

public class ConditionProviders extends ManagedServices {

6.1.构造方法

    public ConditionProviders(Context context, UserProfiles userProfiles, IPackageManager pm) {
        super(context, new Object(), userProfiles, pm);
        //获取系统属性的值,以逗号隔开解析为数组,如果没有的话用默认的数组
        mSystemConditionProviderNames = safeSet(PropConfig.getStringArray(mContext,
                "system.condition.providers",
                R.array.config_system_condition_providers));
        mApprovalLevel = APPROVAL_BY_PACKAGE;//这里的级别是包
    }

>1.config_system_condition_providers

默认值

    <!-- Enabled built-in zen mode condition providers -->
    <string-array translatable="false" name="config_system_condition_providers">
        <item>countdown</item>
        <item>schedule</item>
        <item>event</item>
    </string-array>