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

Commit 59e02d4d authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "API to enable apps to be opted-out of bundles" into main

parents 97b1de7f f45c7305
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -270,4 +270,6 @@ interface INotificationManager

    int[] getAllowedAdjustmentKeyTypes();
    void setAssistantAdjustmentKeyTypeState(int type, boolean enabled);
    String[] getTypeAdjustmentDeniedPackages();
    void setTypeAdjustmentForPackageState(String pkg, boolean enabled);
}
+13 −0
Original line number Diff line number Diff line
@@ -1865,6 +1865,19 @@ public class NotificationManager {
        }
    }

    /**
     * @hide
     */
    @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
    public void setTypeAdjustmentForPackageState(@NonNull String pkg, boolean enabled) {
        INotificationManager service = getService();
        try {
            service.setTypeAdjustmentForPackageState(pkg, enabled);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * @hide
     */
+77 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.AppOpsManager.OP_RECEIVE_SENSITIVE_NOTIFICATIONS;
import static android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR;
import static android.app.Flags.lifetimeExtensionRefactor;
import static android.app.Flags.notificationClassificationUi;
import static android.app.Flags.sortSectionByTime;
import static android.app.Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
import static android.app.Notification.EXTRA_BUILDER_APPLICATION_INFO;
@@ -4224,6 +4225,22 @@ public class NotificationManagerService extends SystemService {
            handleSavePolicyFile();
        }
        @Override
        @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
        public @NonNull String[] getTypeAdjustmentDeniedPackages() {
            checkCallerIsSystemOrSystemUiOrShell();
            return mAssistants.getTypeAdjustmentDeniedPackages();
        }
        @Override
        @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
        public void setTypeAdjustmentForPackageState(String pkg, boolean enabled) {
            checkCallerIsSystemOrSystemUiOrShell();
            mAssistants.setTypeAdjustmentForPackageState(pkg, enabled);
            handleSavePolicyFile();
        }
        @Override
        @FlaggedApi(android.app.Flags.FLAG_API_RICH_ONGOING)
        public boolean appCanBePromoted(String pkg, int uid) {
@@ -7006,6 +7023,10 @@ public class NotificationManagerService extends SystemService {
                if (notificationClassification() && adjustments.containsKey(KEY_TYPE)) {
                    if (!mAssistants.isAdjustmentKeyTypeAllowed(adjustments.getInt(KEY_TYPE))) {
                        toRemove.add(potentialKey);
                    } else if (notificationClassificationUi()
                            && !mAssistants.isTypeAdjustmentAllowedForPackage(
                            r.getSbn().getPackageName())) {
                        toRemove.add(potentialKey);
                    }
                }
            }
@@ -11643,6 +11664,7 @@ public class NotificationManagerService extends SystemService {
        private static final String ATT_DENIED = "denied_adjustments";
        private static final String ATT_ENABLED_TYPES = "enabled_key_types";
        private static final String ATT_NAS_UNSUPPORTED = "unsupported_adjustments";
        private static final String ATT_TYPES_DENIED_APPS = "types_denied_apps";
        private final Object mLock = new Object();
@@ -11658,6 +11680,9 @@ public class NotificationManagerService extends SystemService {
        @GuardedBy("mLock")
        private Map<Integer, HashSet<String>> mNasUnsupported = new ArrayMap<>();
        @GuardedBy("mLock")
        private Set<String> mClassificationTypeDeniedPackages = new ArraySet<>();
        protected ComponentName mDefaultFromConfig = null;
        @Override
@@ -11857,6 +11882,44 @@ public class NotificationManagerService extends SystemService {
            }
        }
        @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
        protected @NonNull boolean isTypeAdjustmentAllowedForPackage(String pkg) {
            synchronized (mLock) {
                if (notificationClassificationUi()) {
                    return !mClassificationTypeDeniedPackages.contains(pkg);
                }
            }
            return true;
        }
        @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
        protected @NonNull String[] getTypeAdjustmentDeniedPackages() {
            synchronized (mLock) {
                if (notificationClassificationUi()) {
                    return mClassificationTypeDeniedPackages.toArray(new String[0]);
                }
            }
            return new String[]{};
        }
        /**
         * Set whether a particular package can have its notification channels adjusted to have a
         * different type by NotificationAssistants.
         */
        @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
        public void setTypeAdjustmentForPackageState(String pkg, boolean enabled) {
            if (!notificationClassificationUi()) {
                return;
            }
            synchronized (mLock) {
                if (enabled) {
                    mClassificationTypeDeniedPackages.remove(pkg);
                } else {
                    mClassificationTypeDeniedPackages.add(pkg);
                }
            }
        }
        protected void onNotificationsSeenLocked(ArrayList<NotificationRecord> records) {
            for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
                ArrayList<String> keys = new ArrayList<>(records.size());
@@ -12319,6 +12382,12 @@ public class NotificationManagerService extends SystemService {
                out.attribute(null, ATT_TYPES,
                        TextUtils.join(",", mAllowedAdjustmentKeyTypes));
                out.endTag(null, ATT_ENABLED_TYPES);
                if (notificationClassificationUi()) {
                    out.startTag(null, ATT_TYPES_DENIED_APPS);
                    out.attribute(null, ATT_TYPES,
                            TextUtils.join(",", mClassificationTypeDeniedPackages));
                    out.endTag(null, ATT_TYPES_DENIED_APPS);
                }
            }
        }
@@ -12350,6 +12419,14 @@ public class NotificationManagerService extends SystemService {
                        }
                    }
                }
            } else if (notificationClassificationUi() && ATT_TYPES_DENIED_APPS.equals(tag)) {
                final String apps = XmlUtils.readStringAttribute(parser, ATT_TYPES);
                synchronized (mLock) {
                    mClassificationTypeDeniedPackages.clear();
                    if (!TextUtils.isEmpty(apps)) {
                        mClassificationTypeDeniedPackages.addAll(Arrays.asList(apps.split(",")));
                    }
                }
            }
        }
+75 −2
Original line number Diff line number Diff line
@@ -60,8 +60,6 @@ import android.testing.TestableContext;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IntArray;
import android.util.Log;
import android.util.Slog;
import android.util.Xml;

import androidx.test.runner.AndroidJUnit4;
@@ -729,4 +727,79 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
        assertThat(mAssistants.getAllowedAdjustmentKeyTypes()).asList()
                .containsExactly(TYPE_PROMOTION);
    }

    @Test
    @EnableFlags(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
    public void testSetAssistantAdjustmentKeyTypeStateForPackage_allowsAndDenies() {
        // Given that a package is allowed to have its type adjusted,
        String allowedPackage = "allowed.package";
        assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).isEmpty();
        mAssistants.setTypeAdjustmentForPackageState(allowedPackage, true);

        assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).isEmpty();
        assertTrue(mAssistants.isTypeAdjustmentAllowedForPackage(allowedPackage));

        // Set type adjustment disallowed for this package
        mAssistants.setTypeAdjustmentForPackageState(allowedPackage, false);

        // Then the package is marked as denied
        assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).asList()
                .containsExactly(allowedPackage);
        assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(allowedPackage));

        // Set type adjustment allowed again
        mAssistants.setTypeAdjustmentForPackageState(allowedPackage, true);

        // Then the package is marked as allowed again
        assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).isEmpty();
        assertTrue(mAssistants.isTypeAdjustmentAllowedForPackage(allowedPackage));
    }

    @Test
    @EnableFlags(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
    public void testSetAssistantAdjustmentKeyTypeStateForPackage_deniesMultiple() {
        // Given packages not allowed to have their type adjusted,
        String deniedPkg1 = "denied.Pkg1";
        String deniedPkg2 = "denied.Pkg2";
        String deniedPkg3 = "denied.Pkg3";
        // Set type adjustment disallowed for these packages
        mAssistants.setTypeAdjustmentForPackageState(deniedPkg1, false);
        mAssistants.setTypeAdjustmentForPackageState(deniedPkg2, false);
        mAssistants.setTypeAdjustmentForPackageState(deniedPkg3, false);

        // Then the packages are marked as denied
        assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).asList()
                .containsExactlyElementsIn(List.of(deniedPkg1, deniedPkg2, deniedPkg3));
        assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg1));
        assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg2));
        assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg3));

        // And when we re-allow one of them,
        mAssistants.setTypeAdjustmentForPackageState(deniedPkg2, true);

        // Then the rest of the original packages are still marked as denied.
        assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).asList()
                .containsExactlyElementsIn(List.of(deniedPkg1, deniedPkg3));
        assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg1));
        assertTrue(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg2));
        assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg3));
    }

    @Test
    @EnableFlags(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
    public void testSetAssistantAdjustmentKeyTypeStateForPackage_readWriteXml() throws Exception {
        mAssistants.loadDefaultsFromConfig(true);
        String deniedPkg1 = "denied.Pkg1";
        String allowedPkg2 = "allowed.Pkg2";
        String deniedPkg3 = "denied.Pkg3";
        // Set type adjustment disallowed or allowed for these packages
        mAssistants.setTypeAdjustmentForPackageState(deniedPkg1, false);
        mAssistants.setTypeAdjustmentForPackageState(allowedPkg2, true);
        mAssistants.setTypeAdjustmentForPackageState(deniedPkg3, false);

        writeXmlAndReload(USER_ALL);

        assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).asList()
                .containsExactlyElementsIn(List.of(deniedPkg1, deniedPkg3));
    }
}
 No newline at end of file
+44 −7
Original line number Diff line number Diff line
@@ -232,7 +232,6 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.LauncherApps;
import android.content.pm.ModuleInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ParceledListSlice;
@@ -337,12 +336,12 @@ import com.android.server.utils.quota.MultiRateLimiter;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
import com.google.android.collect.Lists;
import com.google.common.collect.ImmutableList;
import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@@ -361,9 +360,6 @@ import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
import platform.test.runner.parameterized.Parameters;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
@@ -378,6 +374,9 @@ import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.function.Consumer;
import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
import platform.test.runner.parameterized.Parameters;
@SmallTest
@RunWith(ParameterizedAndroidJunit4.class)
@RunWithLooper
@@ -7534,6 +7533,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
        when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
        when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
        when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true);
        // Set up notifications that will be adjusted
        final NotificationRecord r1 = spy(generateNotificationRecord(
@@ -17142,6 +17142,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
                NotificationManagerService.WorkerHandler.class);
        mService.setHandler(handler);
        when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
        when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true);
        Bundle signals = new Bundle();
        signals.putInt(KEY_TYPE, TYPE_NEWS);
@@ -17175,6 +17176,42 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertThat(r.getChannel().getId()).isEqualTo(RECS_ID);
    }
    @Test
    @EnableFlags({android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION,
            android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI})
    public void testApplyAdjustment_keyTypeForDisallowedPackage_DoesNotApply() throws Exception {
        final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
        mService.addNotification(r);
        NotificationManagerService.WorkerHandler handler = mock(
                NotificationManagerService.WorkerHandler.class);
        mService.setHandler(handler);
        when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
        when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true);
        Bundle signals = new Bundle();
        signals.putInt(KEY_TYPE, TYPE_NEWS);
        Adjustment adjustment = new Adjustment(
                r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
        when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
        mBinderService.applyAdjustmentFromAssistant(null, adjustment);
        waitForIdle();
        r.applyAdjustments();
        assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID);
        // When we block adjustments for this package
        when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(false);
        signals.putInt(KEY_TYPE, TYPE_PROMOTION);
        mBinderService.applyAdjustmentFromAssistant(null, adjustment);
        waitForIdle();
        r.applyAdjustments();
        // Then the adjustment is not applied.
        assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID);
    }
    @Test
    @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
    public void testSetCanBePromoted_granted() throws Exception {