Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c7c7f876 authored by Yuri Lin's avatar Yuri Lin
Browse files

Default managed profiles to off on KEY_TYPE adjustments only

Because KEY_TYPE (classification) is the only adjustment (for now) for which we want the work profile to default to off if the user hasn't explicitly turned it on, store a list of users whose preferences for that adjustment have ever changed. Then if the relevant user is a managed profile, we include KEY_TYPE in the denied adjustments if it wasn't explicitly set one way or another by the user.

Also add some more test setup in NotificationAssistantsTest so we don't get different results about what user is a profile user depending on which mock (NMS, UserManager, UserManagerInternal...) we ask.

Fixes: 415768865
Test: NotificationAssistantsTest, manual via behavior + checking policy xml
Flag: android.app.notification_classification_ui
Change-Id: Ie2e27503cc42a451d954eb66703b01628130a213
parent 27cd29d0
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
@@ -280,6 +280,10 @@ abstract public class ManagedServices {
        }
    }

    UserProfiles getUserProfiles() {
        return mUserProfiles;
    }

    /**
     * When resetting a package, we need to enable default components that belong to that packages
     * we also need to disable components that are not default to return the managed service state
@@ -2340,6 +2344,30 @@ abstract public class ManagedServices {
            }
        }

        boolean isManagedProfileUser(int userId) {
            synchronized (mCurrentProfiles) {
                UserInfo user = mCurrentProfiles.get(userId);
                if (user == null) {
                    return false;
                }
                return user.isManagedProfile();
            }
        }

        int getProfileParentId(int userId, Context context) {
            final long identity = Binder.clearCallingIdentity();
            try {
                UserManager um = context.getSystemService(UserManager.class);
                UserInfo parent = um.getProfileParent(userId);
                if (parent != null) {
                    return parent.id;
                }
                return userId;  // if no parent, return itself
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }

        boolean hasParent(UserInfo profile, Context context) {
            final long identity = Binder.clearCallingIdentity();
            try {
+58 −14
Original line number Diff line number Diff line
@@ -12145,6 +12145,9 @@ public class NotificationManagerService extends SystemService {
        private static final String TAG_ENABLED_TYPES = "enabled_classification_types";
        private static final String ATT_NAS_UNSUPPORTED = "unsupported_adjustments";
        private static final String ATT_USER_ID = "user";
        // for classification only, but named a bit more generally in case this ever gets expanded
        private static final String TAG_SET_BY_USERS = "adjustment_pref_set_by_users";
        private static final String ATT_USER_LIST = "users";
        private final Object mLock = new Object();
@@ -12162,6 +12165,12 @@ public class NotificationManagerService extends SystemService {
        @GuardedBy("mLock")
        private Map<Integer, HashSet<String>> mNasUnsupported = new ArrayMap<>();
        // Set of user IDs for which the classification setting was ever explicitly changed (in
        // other words, the current setting -- allowed or disallowed -- is not default). Used for
        // handling default behavior for profiles until the user sets a preference.
        @GuardedBy("mLock")
        private Set<Integer> mClassificationPrefSetByUsers = new ArraySet<>();
        // Map of user ID -> the disallowed packages for each adjustment key.
        // Inner map key: Adjustment key. value - list of pkgs that we shouldn't apply
        // adjustments with that key to
@@ -12334,18 +12343,28 @@ public class NotificationManagerService extends SystemService {
        // be effectively denied for that user. In particular:
        // - if an adjustment is denied for that profile user's parent, then it is also effectively
        //   denied for that profile regardless of what the profile's current setting is.
        // - for classification (KEY_TYPE) only, if a user hasn't explicitly enabled the adjustment
        //   for their managed/work profile, default the setting to off.
        @GuardedBy("mLock")
        private @NonNull Set<String> deniedAdjustmentsForUser(@UserIdInt int userId) {
            Set<String> denied = new HashSet<>();
            if (mDeniedAdjustments.containsKey(userId)) {
                denied.addAll(mDeniedAdjustments.get(userId));
            }
            final @UserIdInt int parentId = mUmInternal.getProfileParentId(userId);
            if ((parentId != userId) && mDeniedAdjustments.containsKey(parentId)) {
            if (getUserProfiles().isProfileUser(userId, mContext)) {
                final @UserIdInt int parentId = getUserProfiles().getProfileParentId(userId,
                        mContext);
                if (mDeniedAdjustments.containsKey(parentId)) {
                    denied.addAll(mDeniedAdjustments.get(parentId));
                }
            // TODO: b/415768865 - add any cases where a (work/managed) profile should default to
            //                     off unless explicitly turned on
                // Managed profiles only: if the setting hasn't been explicitly set for this
                // profile, then also consider KEY_TYPE (classification) denied.
                if (getUserProfiles().isManagedProfileUser(userId)
                        && !mClassificationPrefSetByUsers.contains(userId)) {
                    denied.add(KEY_TYPE);
                }
            }
            return denied;
        }
@@ -12849,7 +12868,7 @@ public class NotificationManagerService extends SystemService {
            return Log.isLoggable("notification_assistant", Log.VERBOSE);
        }
        @GuardedBy("mNotificationLock")
        @GuardedBy("mLock")
        private void addDefaultClassificationTypes(int userId) {
            // Add the default classification types if the list is empty or not present.
            // Will do so for the profile's parent if the user ID is a profile user.
@@ -12868,16 +12887,19 @@ public class NotificationManagerService extends SystemService {
            if (!android.service.notification.Flags.notificationClassification()) {
                return;
            }
            synchronized (mLock) {
                if (mDeniedAdjustments.containsKey(userId)) {
                    mDeniedAdjustments.get(userId).remove(key);
                }
            for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
                mHandler.post(() -> notifyCapabilitiesChanged(info));
            }
                if (KEY_TYPE.equals(key)) {
                    mClassificationPrefSetByUsers.add(userId);
                    addDefaultClassificationTypes(userId);
                }
            }
            for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
                mHandler.post(() -> notifyCapabilitiesChanged(info));
            }
        }
        @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
        @GuardedBy("mNotificationLock")
@@ -12885,8 +12907,13 @@ public class NotificationManagerService extends SystemService {
            if (!android.service.notification.Flags.notificationClassification()) {
                return;
            }
            synchronized (mLock) {
                mDeniedAdjustments.putIfAbsent(userId, new ArraySet<>());
                mDeniedAdjustments.get(userId).add(key);
                if (KEY_TYPE.equals(key)) {
                    mClassificationPrefSetByUsers.add(userId);
                }
            }
            for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
                mHandler.post(() -> notifyCapabilitiesChanged(info));
            }
@@ -12999,6 +13026,11 @@ public class NotificationManagerService extends SystemService {
                            TextUtils.join(",", mAllowedClassificationTypes.get(user)));
                    out.endTag(null, TAG_ENABLED_TYPES);
                }
                out.startTag(null, TAG_SET_BY_USERS);
                out.attribute(null, ATT_USER_LIST,
                        TextUtils.join(",", mClassificationPrefSetByUsers));
                out.endTag(null, TAG_SET_BY_USERS);
            }
        }
@@ -13035,7 +13067,7 @@ public class NotificationManagerService extends SystemService {
                            try {
                                userAllowedTypes.add(Integer.parseInt(type));
                            } catch (NumberFormatException e) {
                                Slog.wtf(TAG, "Bad type specified", e);
                                Slog.wtf(TAG, "Bad integer specified", e);
                            }
                        }
                        mAllowedClassificationTypes.put(user, userAllowedTypes);
@@ -13053,6 +13085,18 @@ public class NotificationManagerService extends SystemService {
                    userDeniedPackages.put(key, new ArraySet<>(pkgList));
                    mAdjustmentKeyDeniedPackages.put(user, userDeniedPackages);
                }
            } else if (TAG_SET_BY_USERS.equals(tag)) {
                final String users = XmlUtils.readStringAttribute(parser, ATT_USER_LIST);
                if (!TextUtils.isEmpty(users)) {
                    for (String userIdString : Arrays.asList(users.split(","))) {
                        try {
                            mClassificationPrefSetByUsers.add(
                                    Integer.parseInt(userIdString));
                        } catch (NumberFormatException e) {
                            Slog.wtf(TAG, "Bad type specified", e);
                        }
                    }
                }
            }
        }
+53 −4
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
package com.android.server.notification;

import static android.os.UserHandle.USER_ALL;
import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED;
import static android.service.notification.Adjustment.KEY_IMPORTANCE;
import static android.service.notification.Adjustment.KEY_SUMMARIZATION;
import static android.service.notification.Adjustment.KEY_TYPE;
@@ -131,9 +132,8 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
    private TestableContext mContext = spy(getContext());
    Object mLock = new Object();


    UserInfo mZero = new UserInfo(0, "zero", 0);
    UserInfo mTen = new UserInfo(10, "ten", 0);
    UserInfo mTen = new UserInfo(10, "ten", UserInfo.FLAG_PROFILE);

    ComponentName mCn = new ComponentName("a", "b");

@@ -199,11 +199,19 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
        List<UserInfo> users = new ArrayList<>();
        users.add(mZero);
        users.add(mTen);
        users.add(new UserInfo(11, "11", 0));
        users.add(new UserInfo(12, "12", 0));
        users.add(new UserInfo(11, "11", null, UserInfo.FLAG_PROFILE, USER_TYPE_PROFILE_MANAGED));
        users.add(new UserInfo(12, "12", UserInfo.FLAG_PROFILE));
        users.add(new UserInfo(13, "13", 0));
        for (UserInfo user : users) {
            when(mUm.getUserInfo(eq(user.id))).thenReturn(user);
            if (user.isProfile()) {
                when(mNm.hasParent(user)).thenReturn(true);
                when(mNm.isProfileUser(user)).thenReturn(true);
                when(mUserProfiles.isProfileUser(eq(user.id), any())).thenReturn(true);
                if (user.isManagedProfile()) {
                    when(mUserProfiles.isManagedProfileUser(user.id)).thenReturn(true);
                }
            }
        }
        when(mUm.getUsers()).thenReturn(users);
        when(mUm.getAliveUsers()).thenReturn(users);
@@ -213,8 +221,10 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
        profileIds.add(10);
        profileIds.add(12);
        when(mUmInternal.getProfileParentId(13)).thenReturn(13);  // 13 is a full user
        when(mUserProfiles.getProfileParentId(eq(13), any())).thenReturn(13);
        when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds);
        when(mUmInternal.getProfileParentId(11)).thenReturn(mZero.id);
        when(mUserProfiles.getProfileParentId(eq(11), any())).thenReturn(mZero.id);
        when(mNm.isNASMigrationDone(anyInt())).thenReturn(true);
        when(mNm.canUseManagedServices(any(), anyInt(), any())).thenReturn(true);
        mRegistry = ExtensionRegistryLite.newInstance();
@@ -704,11 +714,13 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
        // if the profile's parent has that adjustment disabled.
        // User 11 is set up as a profile user of mZero in setup; user 13 is not
        mAssistants.allowAdjustmentType(11, Adjustment.KEY_TYPE);
        mAssistants.allowAdjustmentType(13, Adjustment.KEY_TYPE);
        mAssistants.disallowAdjustmentType(mZero.id, Adjustment.KEY_TYPE);

        assertThat(mAssistants.getAllowedAssistantAdjustments(11)).doesNotContain(
                Adjustment.KEY_TYPE);
        assertThat(mAssistants.isAdjustmentAllowed(11, Adjustment.KEY_TYPE)).isFalse();
        assertThat(mAssistants.isAdjustmentAllowed(13, Adjustment.KEY_TYPE)).isTrue();

        // Now turn it back on for the parent; it should be considered allowed for the profile
        // (for which it was already on).
@@ -717,6 +729,21 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
        assertThat(mAssistants.isAdjustmentAllowed(11, Adjustment.KEY_TYPE)).isTrue();
    }

    @Test
    public void testClassificationAdjustment_managedProfileDefaultsOff() {
        // Turn on KEY_TYPE classification for mZero (parent) but not 11 (managed profile)
        mAssistants.allowAdjustmentType(mZero.id, Adjustment.KEY_TYPE);
        assertThat(mAssistants.isAdjustmentAllowed(11, Adjustment.KEY_TYPE)).isFalse();

        // Check this doesn't apply to other adjustments if they default to allowed
        mAssistants.allowAdjustmentType(mZero.id, Adjustment.KEY_SUMMARIZATION);
        assertThat(mAssistants.isAdjustmentAllowed(11, Adjustment.KEY_SUMMARIZATION)).isTrue();

        // now turn on classification for the profile user directly
        mAssistants.allowAdjustmentType(11, Adjustment.KEY_TYPE);
        assertThat(mAssistants.isAdjustmentAllowed(11, Adjustment.KEY_TYPE)).isTrue();
    }

    @Test
    @EnableFlags(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
    public void testAllowAdjustmentType_classifListEmpty_resetDefaultClassificationTypes() {
@@ -747,6 +774,28 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
            .containsExactly(TYPE_NEWS);
    }

    @Test
    @EnableFlags(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
    public void testClassificationAdjustments_readWriteXml_userSetStateMaintained()
            throws Exception {
        // Turn on KEY_TYPE classification for mZero (parent) but not 11 (managed profile)
        mAssistants.allowAdjustmentType(mZero.id, Adjustment.KEY_TYPE);
        assertThat(mAssistants.isAdjustmentAllowed(11, Adjustment.KEY_TYPE)).isFalse();

        // reload from XML; default state should persist
        writeXmlAndReload(USER_ALL);

        assertThat(mAssistants.isAdjustmentAllowed(mZero.id, Adjustment.KEY_TYPE)).isTrue();
        assertThat(mAssistants.isAdjustmentAllowed(11, Adjustment.KEY_TYPE)).isFalse();

        mAssistants.allowAdjustmentType(11, Adjustment.KEY_TYPE);
        assertThat(mAssistants.isAdjustmentAllowed(11, Adjustment.KEY_TYPE)).isTrue();

        // now that it's been set, we should still retain this information after XML reload
        writeXmlAndReload(USER_ALL);
        assertThat(mAssistants.isAdjustmentAllowed(11, Adjustment.KEY_TYPE)).isTrue();
    }

    @Test
    @EnableFlags(Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
    public void testDisallowAdjustmentType_readWriteXml_entries() throws Exception {