Merge "Skip attestation test for first_api_level <=26" into sc-v2-dev
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
index 505ace2..7ee0ed13 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
@@ -206,7 +206,7 @@
             mAm = getSystemService(ActivityManager.class);
             mAdmin = DeviceAdminTestReceiver.getReceiverComponentName();
             final String command = intent.getStringExtra(EXTRA_COMMAND);
-            Log.i(TAG, "Command: " + command);
+            Log.i(TAG, "Command: " + command + " forDeviceOwner: " + forDeviceOwner);
             switch (command) {
                 case COMMAND_SET_USER_RESTRICTION: {
                     String restrictionKey = intent.getStringExtra(EXTRA_USER_RESTRICTION);
@@ -380,6 +380,7 @@
                     uninstallHelperPackage();
                 } break;
                 case COMMAND_SET_PERMISSION_GRANT_STATE: {
+                    Log.d(TAG, "Granting permission using " + mDpm);
                     mDpm.setPermissionGrantState(mAdmin, getPackageName(),
                             intent.getStringExtra(EXTRA_PERMISSION),
                             intent.getIntExtra(EXTRA_GRANT_STATE,
@@ -483,16 +484,22 @@
                     mDpm.setMaximumFailedPasswordsForWipe(mAdmin, 0);
                 } break;
                 case COMMAND_SET_DEFAULT_IME: {
-                    if (!mDpm.isDeviceOwnerApp(getPackageName())) {
+                    if (!mDpm.isDeviceOwnerApp(getPackageName())
+                            && !UserManager.isHeadlessSystemUserMode()) {
                         return;
                     }
+                    Log.d(TAG, "Setting " + Settings.Secure.DEFAULT_INPUT_METHOD + " using "
+                            + mDpm);
                     mDpm.setSecureSetting(mAdmin, Settings.Secure.DEFAULT_INPUT_METHOD,
                             getPackageName());
                 } break;
                 case COMMAND_CLEAR_DEFAULT_IME: {
-                    if (!mDpm.isDeviceOwnerApp(getPackageName())) {
+                    if (!mDpm.isDeviceOwnerApp(getPackageName())
+                            && !UserManager.isHeadlessSystemUserMode()) {
                         return;
                     }
+                    Log.d(TAG, "Clearing " + Settings.Secure.DEFAULT_INPUT_METHOD + " using "
+                            + mDpm);
                     mDpm.setSecureSetting(mAdmin, Settings.Secure.DEFAULT_INPUT_METHOD, null);
                 } break;
                 case COMMAND_CREATE_MANAGED_USER:{
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java
index 5e8a92f..577a6c8 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java
@@ -16,11 +16,11 @@
 
 package com.android.cts.verifier.managedprovisioning;
 
+import static com.android.cts.verifier.managedprovisioning.Utils.createInteractiveTestItem;
+
 import android.Manifest;
 import android.app.admin.DevicePolicyManager;
-import android.content.ComponentName;
 import android.content.Intent;
-import android.content.pm.PackageManager;
 import android.database.DataSetObserver;
 import android.os.Bundle;
 import android.provider.Settings;
@@ -31,8 +31,6 @@
 import com.android.cts.verifier.R;
 import com.android.cts.verifier.TestListAdapter.TestListItem;
 
-import static com.android.cts.verifier.managedprovisioning.Utils.createInteractiveTestItem;
-
 /**
  * Test class to verify privacy information is shown for devices managed by a Device Owner.
  */
@@ -92,6 +90,12 @@
                 .putExtra(CommandReceiverActivity.EXTRA_COMMAND, command);
     }
 
+    private Intent buildCommandIntentForCurrentUser(String command) {
+        return buildCommandIntent(command)
+                .putExtra(CommandReceiverActivity.EXTRA_USE_CURRENT_USER_DPM, true);
+    }
+
+
     private TestListItem buildCommandTest(String id, int titleRes, int infoRes,
             int commandButtonRes, String command) {
         return createInteractiveTestItem(this, id, titleRes, infoRes,
@@ -105,12 +109,14 @@
             String permission) {
         return createInteractiveTestItem(this, id, titleRes, infoRes,
                 new ButtonInfo[] {
-                        new ButtonInfo(R.string.enterprise_privacy_reset, buildCommandIntent(
+                        new ButtonInfo(R.string.enterprise_privacy_reset,
+                                buildCommandIntentForCurrentUser(
                                 CommandReceiverActivity.COMMAND_SET_PERMISSION_GRANT_STATE)
                                 .putExtra(CommandReceiverActivity.EXTRA_PERMISSION, permission)
                                 .putExtra(CommandReceiverActivity.EXTRA_GRANT_STATE,
                                         DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT)),
-                        new ButtonInfo(R.string.enterprise_privacy_grant, buildCommandIntent(
+                        new ButtonInfo(R.string.enterprise_privacy_grant,
+                                buildCommandIntentForCurrentUser(
                                 CommandReceiverActivity.COMMAND_SET_PERMISSION_GRANT_STATE)
                                 .putExtra(CommandReceiverActivity.EXTRA_PERMISSION, permission)
                                 .putExtra(CommandReceiverActivity.EXTRA_GRANT_STATE,
@@ -182,11 +188,12 @@
                         new ButtonInfo(R.string.enterprise_privacy_open_settings,
                                 new Intent(Settings.ACTION_ENTERPRISE_PRIVACY_SETTINGS)),
                         new ButtonInfo(R.string.enterprise_privacy_set_keyboard,
-                                buildCommandIntent(CommandReceiverActivity
-                                        .COMMAND_SET_DEFAULT_IME)),
+                                buildCommandIntentForCurrentUser(
+                                        CommandReceiverActivity.COMMAND_SET_DEFAULT_IME)),
                         new ButtonInfo(R.string.enterprise_privacy_finish,
-                                buildCommandIntent(CommandReceiverActivity
-                                        .COMMAND_CLEAR_DEFAULT_IME))}));
+                                buildCommandIntentForCurrentUser(
+                                        CommandReceiverActivity.COMMAND_CLEAR_DEFAULT_IME))
+                }));
         adapter.add(createInteractiveTestItem(this, ENTERPRISE_PRIVACY_ALWAYS_ON_VPN,
                 R.string.enterprise_privacy_always_on_vpn,
                 R.string.enterprise_privacy_always_on_vpn_info,
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/BedsteadJUnit4.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/BedsteadJUnit4.java
index 6d43808..7ffabbe 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/BedsteadJUnit4.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/BedsteadJUnit4.java
@@ -16,7 +16,10 @@
 
 package com.android.bedstead.harrier;
 
+import android.os.Bundle;
+
 import androidx.annotation.Nullable;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.bedstead.harrier.annotations.AnnotationRunPrecedence;
 import com.android.bedstead.harrier.annotations.enterprise.CanSetPolicyTest;
@@ -72,18 +75,23 @@
         return getAnnotationWeight(a) - getAnnotationWeight(b);
     }
 
-    private static int getAnnotationWeight(Annotation a) {
-        if (!a.annotationType().getPackage().getName().startsWith(BEDSTEAD_PACKAGE_NAME)) {
+    private static int getAnnotationWeight(Annotation annotation) {
+        if (annotation instanceof DynamicParameterizedAnnotation) {
+            // Special case, not important
+            return AnnotationRunPrecedence.PRECEDENCE_NOT_IMPORTANT;
+        }
+
+        if (!annotation.annotationType().getPackage().getName().startsWith(BEDSTEAD_PACKAGE_NAME)) {
             return AnnotationRunPrecedence.FIRST;
         }
 
         try {
-            return (int) a.annotationType().getMethod("weight").invoke(a);
+            return (int) annotation.annotationType().getMethod("weight").invoke(annotation);
         } catch (NoSuchMethodException e) {
             // Default to PRECEDENCE_NOT_IMPORTANT if no weight is found on the annotation.
             return AnnotationRunPrecedence.PRECEDENCE_NOT_IMPORTANT;
         } catch (IllegalAccessException | InvocationTargetException e) {
-            throw new NeneException("Failed to invoke weight on this annotation: " + a, e);
+            throw new NeneException("Failed to invoke weight on this annotation: " + annotation, e);
         }
     }
 
@@ -92,7 +100,7 @@
      */
     public static final class BedsteadFrameworkMethod extends FrameworkMethod {
 
-        private final Class<? extends Annotation> mParameterizedAnnotation;
+        private final Annotation mParameterizedAnnotation;
         private final Map<Class<? extends Annotation>, Annotation> mAnnotationsMap =
                 new HashMap<>();
         private Annotation[] mAnnotations;
@@ -103,8 +111,7 @@
 
         public BedsteadFrameworkMethod(Method method, Annotation parameterizedAnnotation) {
             super(method);
-            this.mParameterizedAnnotation = (parameterizedAnnotation == null) ? null
-                    : parameterizedAnnotation.annotationType();
+            mParameterizedAnnotation = parameterizedAnnotation;
 
             calculateAnnotations();
         }
@@ -124,6 +131,9 @@
 
             this.mAnnotations = annotations.toArray(new Annotation[0]);
             for (Annotation annotation : annotations) {
+                if (annotation instanceof DynamicParameterizedAnnotation) {
+                    continue; // don't return this
+                }
                 mAnnotationsMap.put(annotation.annotationType(), annotation);
             }
         }
@@ -133,7 +143,7 @@
             if (mParameterizedAnnotation == null) {
                 return super.getName();
             }
-            return super.getName() + "[" + mParameterizedAnnotation.getSimpleName() + "]";
+            return super.getName() + "[" + getParameterName(mParameterizedAnnotation) + "]";
         }
 
         @Override
@@ -162,13 +172,20 @@
         }
     }
 
+    private static String getParameterName(Annotation annotation) {
+        if (annotation instanceof DynamicParameterizedAnnotation) {
+            return ((DynamicParameterizedAnnotation) annotation).name();
+        }
+        return annotation.annotationType().getSimpleName();
+    }
+
     /**
      * Resolve annotations recursively.
      *
      * @param parameterizedAnnotation The class of the parameterized annotation to expand, if any
      */
     public static void resolveRecursiveAnnotations(List<Annotation> annotations,
-            @Nullable Class<? extends Annotation> parameterizedAnnotation) {
+            @Nullable Annotation parameterizedAnnotation) {
         int index = 0;
         while (index < annotations.size()) {
             Annotation annotation = annotations.get(index);
@@ -181,11 +198,34 @@
         }
     }
 
+    private static boolean isParameterizedAnnotation(Annotation annotation) {
+        if (annotation instanceof DynamicParameterizedAnnotation) {
+            return true;
+        }
+
+        return annotation.annotationType().getAnnotation(ParameterizedAnnotation.class) != null;
+    }
+
+    private static Annotation[] getIndirectAnnotations(Annotation annotation) {
+        if (annotation instanceof DynamicParameterizedAnnotation) {
+            return ((DynamicParameterizedAnnotation) annotation).annotations();
+        }
+        return annotation.annotationType().getAnnotations();
+    }
+
+    private static boolean isRepeatingAnnotation(Annotation annotation) {
+        if (annotation instanceof DynamicParameterizedAnnotation) {
+            return false;
+        }
+
+        return annotation.annotationType().getAnnotation(RepeatingAnnotation.class) != null;
+    }
+
     private static List<Annotation> getReplacementAnnotations(Annotation annotation,
-            @Nullable Class<? extends Annotation> parameterizedAnnotation) {
+            @Nullable Annotation parameterizedAnnotation) {
         List<Annotation> replacementAnnotations = new ArrayList<>();
 
-        if (annotation.annotationType().getAnnotation(RepeatingAnnotation.class) != null) {
+        if (isRepeatingAnnotation(annotation)) {
             try {
                 Annotation[] annotations =
                         (Annotation[]) annotation.annotationType()
@@ -197,14 +237,12 @@
             }
         }
 
-        if (annotation.annotationType().getAnnotation(ParameterizedAnnotation.class) != null
-                && !annotation.annotationType().equals(parameterizedAnnotation)) {
+        if (isParameterizedAnnotation(annotation) && !annotation.equals(parameterizedAnnotation)) {
             return replacementAnnotations;
         }
 
-        for (Annotation indirectAnnotation : annotation.annotationType().getAnnotations()) {
-            String annotationPackage = indirectAnnotation.annotationType().getPackage().getName();
-            if (shouldSkipAnnotation(annotationPackage)) {
+        for (Annotation indirectAnnotation : getIndirectAnnotations(annotation)) {
+            if (shouldSkipAnnotation(annotation)) {
                 continue;
             }
 
@@ -212,12 +250,21 @@
                     indirectAnnotation, parameterizedAnnotation));
         }
 
-        replacementAnnotations.add(annotation);
+        if (!(annotation instanceof DynamicParameterizedAnnotation)) {
+            // We drop the fake annotation once it's replaced
+            replacementAnnotations.add(annotation);
+        }
 
         return replacementAnnotations;
     }
 
-    private static boolean shouldSkipAnnotation(String annotationPackage) {
+    private static boolean shouldSkipAnnotation(Annotation annotation) {
+        if (annotation instanceof DynamicParameterizedAnnotation) {
+            return false;
+        }
+
+        String annotationPackage = annotation.annotationType().getPackage().getName();
+
         for (String ignoredPackage : sIgnoredAnnotationPackages) {
             if (ignoredPackage.endsWith(".*")) {
                 if (annotationPackage.startsWith(
@@ -236,6 +283,14 @@
         super(testClass);
     }
 
+    private boolean annotationShouldBeSkipped(Annotation annotation) {
+        if (annotation instanceof DynamicParameterizedAnnotation) {
+            return false;
+        }
+
+        return annotation.annotationType().equals(IncludeNone.class);
+    }
+
     @Override
     protected List<FrameworkMethod> computeTestMethods() {
         TestClass testClass = getTestClass();
@@ -252,7 +307,7 @@
             }
 
             for (Annotation annotation : parameterizedAnnotations) {
-                if (annotation.annotationType().equals(IncludeNone.class)) {
+                if (annotationShouldBeSkipped(annotation)) {
                     // Special case - does not generate a run
                     continue;
                 }
@@ -328,7 +383,7 @@
         parseEnterpriseAnnotations(annotations);
 
         for (Annotation annotation : annotations) {
-            if (annotation.annotationType().getAnnotation(ParameterizedAnnotation.class) != null) {
+            if (isParameterizedAnnotation(annotation)) {
                 parameterizedAnnotations.add(annotation);
             }
         }
@@ -376,7 +431,7 @@
                 EnterprisePolicy enterprisePolicy =
                         policy.getAnnotation(EnterprisePolicy.class);
                 List<Annotation> replacementAnnotations =
-                        Policy.cannotSetPolicyStates(policy.getName(), enterprisePolicy);
+                        Policy.cannotSetPolicyStates(policy.getName(), enterprisePolicy, ((CannotSetPolicyTest) annotation).includeDeviceAdminStates(), ((CannotSetPolicyTest) annotation).includeNonDeviceAdminStates());
                 replacementAnnotations.sort(BedsteadJUnit4::annotationSorter);
 
                 annotations.addAll(index, replacementAnnotations);
@@ -418,4 +473,17 @@
 
         return rules;
     }
+
+    /**
+     * True if the test is running in debug mode.
+     *
+     * <p>This will result in additional debugging information being added which would otherwise
+     * be dropped to improve test performance.
+     *
+     * <p>To enable this, pass the "bedstead-debug" instrumentation arg as "true"
+     */
+    public static boolean isDebug() {
+        Bundle arguments = InstrumentationRegistry.getArguments();
+        return Boolean.parseBoolean(arguments.getString("bedstead-debug", "false"));
+    }
 }
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java
index 9bfec32..bb0783c 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java
@@ -60,6 +60,7 @@
 import com.android.bedstead.harrier.annotations.RequireSdkVersion;
 import com.android.bedstead.harrier.annotations.RequireUserSupported;
 import com.android.bedstead.harrier.annotations.TestTag;
+import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDelegate;
 import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner;
 import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDeviceOwner;
 import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoProfileOwner;
@@ -85,7 +86,11 @@
 import com.android.bedstead.nene.utils.ShellCommand;
 import com.android.bedstead.nene.utils.Tags;
 import com.android.bedstead.nene.utils.Versions;
+import com.android.bedstead.remotedpc.RemoteDelegate;
 import com.android.bedstead.remotedpc.RemoteDpc;
+import com.android.bedstead.remotedpc.RemotePolicyManager;
+import com.android.bedstead.testapp.TestApp;
+import com.android.bedstead.testapp.TestAppInstance;
 import com.android.compatibility.common.util.BlockingBroadcastReceiver;
 import com.android.eventlib.EventLogs;
 
@@ -346,6 +351,17 @@
                 continue;
             }
 
+            if (annotation instanceof EnsureHasDelegate) {
+                EnsureHasDelegate ensureHasDelegateAnnotation =
+                        (EnsureHasDelegate) annotation;
+                ensureHasDelegate(
+                        ensureHasDelegateAnnotation.admin(),
+                        Arrays.asList(ensureHasDelegateAnnotation.scopes()),
+                        ensureHasDelegateAnnotation.isPrimary());
+                continue;
+            }
+
+
             if (annotation instanceof EnsureHasDeviceOwner) {
                 EnsureHasDeviceOwner ensureHasDeviceOwnerAnnotation =
                         (EnsureHasDeviceOwner) annotation;
@@ -878,7 +894,7 @@
             mProfiles = new HashMap<>();
     private DevicePolicyController mDeviceOwner;
     private Map<UserReference, DevicePolicyController> mProfileOwners = new HashMap<>();
-    private DevicePolicyController mPrimaryDpc;
+    private RemotePolicyManager mPrimaryPolicyManager;
 
     private final List<UserReference> mCreatedUsers = new ArrayList<>();
     private final List<UserBuilder> mRemovedUsers = new ArrayList<>();
@@ -1291,9 +1307,11 @@
             broadcastReceiver.unregisterQuietly();
         }
         mRegisteredBroadcastReceivers.clear();
-        mPrimaryDpc = null;
+        mPrimaryPolicyManager = null;
     }
 
+    private Set<TestAppInstance> mInstalledTestApps = new HashSet<>();
+
     private void teardownShareableState() {
         if (mOriginalSwitchedUser != null) {
             if (!mOriginalSwitchedUser.exists()) {
@@ -1353,6 +1371,11 @@
         }
 
         mRemovedUsers.clear();
+
+        for (TestAppInstance installedTestApp : mInstalledTestApps) {
+            installedTestApp.uninstall();
+        }
+        mInstalledTestApps.clear();
     }
 
     private UserReference createProfile(
@@ -1394,16 +1417,64 @@
         }
     }
 
+    private void ensureHasDelegate(
+            EnsureHasDelegate.AdminType adminType, List<String> scopes, boolean isPrimary) {
+        RemotePolicyManager dpc = getDeviceAdmin(adminType);
+
+
+        boolean specifiesAdminType = adminType != EnsureHasDelegate.AdminType.PRIMARY;
+        boolean currentPrimaryPolicyManagerIsNotDelegator = mPrimaryPolicyManager != dpc;
+
+        if (isPrimary && mPrimaryPolicyManager != null
+                && (specifiesAdminType || currentPrimaryPolicyManagerIsNotDelegator)) {
+            throw new IllegalStateException(
+                    "Only one DPC can be marked as primary per test (current primary is "
+                            + mPrimaryPolicyManager + ")");
+        }
+
+        if (!dpc.user().equals(TestApis.users().instrumented())) {
+            // INTERACT_ACROSS_USERS_FULL is required for RemoteDPC
+            ensureCanGetPermission(INTERACT_ACROSS_USERS_FULL);
+        }
+
+        ensureTestAppInstalled(RemoteDelegate.sTestApp, dpc.user());
+        RemoteDelegate delegate = new RemoteDelegate(RemoteDelegate.sTestApp, dpc().user());
+        dpc.devicePolicyManager().setDelegatedScopes(
+                dpc.componentName(), delegate.packageName(), scopes);
+
+        if (isPrimary) {
+            mPrimaryPolicyManager = delegate;
+        }
+    }
+
+    private RemotePolicyManager getDeviceAdmin(EnsureHasDelegate.AdminType adminType) {
+        switch (adminType) {
+            case DEVICE_OWNER:
+                return deviceOwner();
+            case PROFILE_OWNER:
+                return profileOwner();
+            case PRIMARY:
+                return dpc();
+            default:
+                throw new IllegalStateException("Unknown device admin type " + adminType);
+        }
+    }
+
+    private void ensureTestAppInstalled(TestApp testApp, UserReference user) {
+        mInstalledTestApps.add(testApp.install(user));
+    }
+
     private void ensureHasDeviceOwner(FailureMode failureMode, boolean isPrimary,
             Set<String> affiliationIds) {
         // TODO(scottjonathan): Should support non-remotedpc device owner (default to remotedpc)
 
         UserReference userReference = TestApis.users().system();
 
-        if (isPrimary && mPrimaryDpc != null && !userReference.equals(mPrimaryDpc.user())) {
+        if (isPrimary && mPrimaryPolicyManager != null && !userReference.equals(
+                mPrimaryPolicyManager.user())) {
             throw new IllegalStateException(
                     "Only one DPC can be marked as primary per test (current primary is "
-                            + mPrimaryDpc + ")");
+                            + mPrimaryPolicyManager + ")");
         }
         if (!userReference.equals(TestApis.users().instrumented())) {
             // INTERACT_ACROSS_USERS_FULL is required for RemoteDPC
@@ -1455,7 +1526,7 @@
         }
 
         if (isPrimary) {
-            mPrimaryDpc = mDeviceOwner;
+            mPrimaryPolicyManager = RemoteDpc.forDevicePolicyController(mDeviceOwner);
         }
         
         RemoteDpc.forDevicePolicyController(mDeviceOwner)
@@ -1471,7 +1542,8 @@
 
     private void ensureHasProfileOwner(
             UserReference user, boolean isPrimary, Set<String> affiliationIds) {
-        if (isPrimary && mPrimaryDpc != null && !user.equals(mPrimaryDpc.user())) {
+        if (isPrimary && mPrimaryPolicyManager != null
+                && !user.equals(mPrimaryPolicyManager.user())) {
             throw new IllegalStateException("Only one DPC can be marked as primary per test");
         }
 
@@ -1501,7 +1573,7 @@
         }
 
         if (isPrimary) {
-            mPrimaryDpc = mProfileOwners.get(user);
+            mPrimaryPolicyManager = RemoteDpc.forDevicePolicyController(mProfileOwners.get(user));
         }
 
         if (affiliationIds != null) {
@@ -1670,20 +1742,22 @@
     }
 
     /**
-     * Get the most appropriate {@link RemoteDpc} instance for the device state.
+     * Get the most appropriate {@link RemotePolicyManager} instance for the device state.
      *
      * <p>This method should only be used by tests which are annotated with {@link PolicyTest}.
      *
-     * <p>If no DPC is set as the "primary" DPC for the device state, then this method will first
+     * <p>This may be a DPC, a delegate, or a normal app with or without given permissions.
+     *
+     * <p>If no policy manager is set as "primary" for the device state, then this method will first
      * check for a profile owner in the current user, or else check for a device owner.
      *
      * <p>If no Harrier-managed profile owner or device owner exists, an exception will be thrown.
      *
      * <p>If the profile owner or device owner is not a RemoteDPC then an exception will be thrown.
      */
-    public RemoteDpc dpc() {
-        if (mPrimaryDpc != null) {
-            return RemoteDpc.forDevicePolicyController(mPrimaryDpc);
+    public RemotePolicyManager dpc() {
+        if (mPrimaryPolicyManager != null) {
+            return mPrimaryPolicyManager;
         }
 
         if (mProfileOwners.containsKey(TestApis.users().instrumented())) {
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DynamicParameterizedAnnotation.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DynamicParameterizedAnnotation.java
new file mode 100644
index 0000000..15afb2b
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DynamicParameterizedAnnotation.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bedstead.harrier;
+
+import java.lang.annotation.Annotation;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * A fake annotation used inside {@link Policy} and {@link BedsteadJUnit4} to inject
+ * new parameterizations.
+ */
+public final class DynamicParameterizedAnnotation implements Annotation {
+    private final String mName;
+    private final Annotation[] mAnnotations;
+
+    DynamicParameterizedAnnotation(String name, Annotation[] annotations) {
+        mName = name;
+        mAnnotations = annotations;
+    }
+
+    /** Get the parameterization name. */
+    public String name() {
+        return mName;
+    }
+
+    /** Get the annotations applied to the parameterization. */
+    public Annotation[] annotations() {
+        return mAnnotations;
+    }
+
+    @Override
+    public Class<? extends Annotation> annotationType() {
+        // This is special cased in BedsteadJUnit4 so will never be called
+        return null;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof DynamicParameterizedAnnotation)) return false;
+        DynamicParameterizedAnnotation that = (DynamicParameterizedAnnotation) o;
+        return Objects.equals(mName, that.mName) && Arrays.equals(mAnnotations,
+                that.mAnnotations);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = Objects.hash(mName);
+        result = 31 * result + Arrays.hashCode(mAnnotations);
+        return result;
+    }
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/Policy.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/Policy.java
index c588ace..e01c8f1 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/Policy.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/Policy.java
@@ -16,6 +16,18 @@
 
 package com.android.bedstead.harrier;
 
+import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
+import static android.app.admin.DevicePolicyManager.DELEGATION_BLOCK_UNINSTALL;
+import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL;
+import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_SELECTION;
+import static android.app.admin.DevicePolicyManager.DELEGATION_ENABLE_SYSTEM_APP;
+import static android.app.admin.DevicePolicyManager.DELEGATION_INSTALL_EXISTING_PACKAGE;
+import static android.app.admin.DevicePolicyManager.DELEGATION_KEEP_UNINSTALLED_PACKAGES;
+import static android.app.admin.DevicePolicyManager.DELEGATION_NETWORK_LOGGING;
+import static android.app.admin.DevicePolicyManager.DELEGATION_PACKAGE_ACCESS;
+import static android.app.admin.DevicePolicyManager.DELEGATION_PERMISSION_GRANT;
+import static android.app.admin.DevicePolicyManager.DELEGATION_SECURITY_LOGGING;
+
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_AFFILIATED_PROFILE_OWNER;
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_AFFILIATED_PROFILE_OWNER_PROFILE;
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_AFFILIATED_PROFILE_OWNER_USER;
@@ -28,9 +40,11 @@
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_PARENT;
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_UNAFFILIATED_OTHER_USERS;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.CAN_BE_DELEGATED;
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.DO_NOT_APPLY_TO_NEGATIVE_TESTS;
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.NO;
 
+import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDelegate;
 import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy;
 import com.android.bedstead.harrier.annotations.parameterized.IncludeNone;
 import com.android.bedstead.harrier.annotations.parameterized.IncludeRunOnAffiliatedDeviceOwnerSecondaryUser;
@@ -47,21 +61,94 @@
 
 import com.google.auto.value.AutoAnnotation;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 
 import java.lang.annotation.Annotation;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 /**
  * Utility class for enterprise policy tests.
  */
 public final class Policy {
 
+    // Delegate scopes to be used for a "CannotSet" state. All delegate scopes except the ones which
+    // should allow use of the API will be granted
+    private static final ImmutableSet<String> ALL_DELEGATE_SCOPES = ImmutableSet.of(
+            DELEGATION_CERT_INSTALL,
+            DELEGATION_APP_RESTRICTIONS,
+            DELEGATION_BLOCK_UNINSTALL,
+            DELEGATION_PERMISSION_GRANT,
+            DELEGATION_PACKAGE_ACCESS,
+            DELEGATION_ENABLE_SYSTEM_APP,
+            DELEGATION_INSTALL_EXISTING_PACKAGE,
+            DELEGATION_KEEP_UNINSTALLED_PACKAGES,
+            DELEGATION_NETWORK_LOGGING,
+            DELEGATION_CERT_SELECTION,
+            DELEGATION_SECURITY_LOGGING
+    );
+
+    // This is a map containing all Include* annotations and the flags which lead to them
+    // This is not validated - every state must have a single APPLIED_BY annotation
+    private static final ImmutableMap<Integer, Function<EnterprisePolicy, Set<Annotation>>>
+            STATE_ANNOTATIONS =
+            ImmutableMap.<Integer, Function<EnterprisePolicy, Set<Annotation>>>builder()
+                    .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER, singleAnnotation(includeRunOnDeviceOwnerUser()))
+                    .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnDeviceOwnerUser(), /* isPrimary= */ true))
+                    .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIES_IN_BACKGROUND, singleAnnotation(includeRunOnBackgroundDeviceOwnerUser()))
+                    .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIES_IN_BACKGROUND | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnBackgroundDeviceOwnerUser(), /* isPrimary= */ true))
+
+                    .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_UNAFFILIATED_OTHER_USERS, singleAnnotation(includeRunOnNonAffiliatedDeviceOwnerSecondaryUser()))
+                    .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_UNAFFILIATED_OTHER_USERS | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnNonAffiliatedDeviceOwnerSecondaryUser(), /* isPrimary= */ true))
+                    .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_AFFILIATED_OTHER_USERS, singleAnnotation(includeRunOnAffiliatedDeviceOwnerSecondaryUser()))
+                    .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_AFFILIATED_OTHER_USERS | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnAffiliatedDeviceOwnerSecondaryUser(), /* isPrimary= */ true))
+
+                    .put(APPLIED_BY_AFFILIATED_PROFILE_OWNER_USER | APPLIES_TO_OWN_USER, singleAnnotation(includeRunOnAffiliatedProfileOwnerSecondaryUser()))
+                    .put(APPLIED_BY_AFFILIATED_PROFILE_OWNER_USER | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnAffiliatedProfileOwnerSecondaryUser(), /* isPrimary= */ true))
+                    .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER | APPLIES_TO_OWN_USER, singleAnnotation(includeRunOnUnaffiliatedProfileOwnerSecondaryUser()))
+                    .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnUnaffiliatedProfileOwnerSecondaryUser(), /* isPrimary= */ true))
+                    .put(APPLIED_BY_PROFILE_OWNER_USER_WITH_NO_DO | APPLIES_TO_OWN_USER, singleAnnotation(includeRunOnProfileOwnerPrimaryUser()))
+                    .put(APPLIED_BY_PROFILE_OWNER_USER_WITH_NO_DO | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnProfileOwnerPrimaryUser(), /* isPrimary= */ true))
+
+                    .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_OWN_USER, singleAnnotation(includeRunOnProfileOwnerProfileWithNoDeviceOwner()))
+                    .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnProfileOwnerProfileWithNoDeviceOwner(), /* isPrimary= */ true))
+                    .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_PARENT, singleAnnotation(includeRunOnParentOfProfileOwnerWithNoDeviceOwner()))
+                    .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_PARENT | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnParentOfProfileOwnerWithNoDeviceOwner(), /* isPrimary= */ true))
+
+                    .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_UNAFFILIATED_OTHER_USERS, singleAnnotation(includeRunOnSecondaryUserInDifferentProfileGroupToProfileOwnerProfile()))
+                    .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_UNAFFILIATED_OTHER_USERS | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnSecondaryUserInDifferentProfileGroupToProfileOwnerProfile(), /* isPrimary= */ true))
+                    .build();
+    // This must contain one key for every APPLIED_BY that is being used, and maps to the
+    // "default" for testing that DPC type
+    // in general this will be a state which runs on the same user as the dpc.
+    private static final ImmutableMap<Integer, Function<EnterprisePolicy, Set<Annotation>>>
+            DPC_STATE_ANNOTATIONS_BASE =
+            ImmutableMap.<Integer, Function<EnterprisePolicy, Set<Annotation>>>builder()
+                    .put(APPLIED_BY_DEVICE_OWNER, (flags) -> hasFlag(flags.dpc(), APPLIED_BY_DEVICE_OWNER | APPLIES_IN_BACKGROUND) ? ImmutableSet.of(includeRunOnBackgroundDeviceOwnerUser()) : ImmutableSet.of(includeRunOnDeviceOwnerUser()))
+                    .put(APPLIED_BY_AFFILIATED_PROFILE_OWNER, singleAnnotation(includeRunOnAffiliatedProfileOwnerSecondaryUser()))
+                    .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER, singleAnnotation(includeRunOnProfileOwnerPrimaryUser()))
+                    .put(APPLIED_BY_PROFILE_OWNER_USER_WITH_NO_DO, singleAnnotation(includeRunOnProfileOwnerPrimaryUser()))
+                    .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE, singleAnnotation(includeRunOnProfileOwnerProfileWithNoDeviceOwner()))
+                    .build();
+    private static final Map<Integer, Function<EnterprisePolicy, Set<Annotation>>>
+            DPC_STATE_ANNOTATIONS = DPC_STATE_ANNOTATIONS_BASE.entrySet().stream()
+            .collect(Collectors.toMap(Map.Entry::getKey, Policy::addGeneratedStates));
+    private static final int APPLIED_BY_FLAGS =
+            APPLIED_BY_DEVICE_OWNER | APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE
+                    | APPLIED_BY_AFFILIATED_PROFILE_OWNER_PROFILE
+                    | APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER
+                    | APPLIED_BY_AFFILIATED_PROFILE_OWNER_USER;
+    private static final Map<Function<EnterprisePolicy, Set<Annotation>>, Set<Integer>>
+            ANNOTATIONS_MAP = calculateAnnotationsMap(STATE_ANNOTATIONS);
+
     private Policy() {
 
     }
@@ -126,49 +213,42 @@
         return new AutoAnnotation_Policy_includeRunOnBackgroundDeviceOwnerUser();
     }
 
-    // This is a map containing all Include* annotations and the flags which lead to them
-    // This is not validated - every state must have a single APPLIED_BY annotation
-    private static final ImmutableMap<Integer, Annotation> STATE_ANNOTATIONS = ImmutableMap.<Integer, Annotation>builder()
-            .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER, includeRunOnDeviceOwnerUser())
-            .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIES_IN_BACKGROUND, includeRunOnBackgroundDeviceOwnerUser())
+    @AutoAnnotation
+    private static EnsureHasDelegate ensureHasDelegate(EnsureHasDelegate.AdminType admin,
+            String[] scopes, boolean isPrimary) {
+        return new AutoAnnotation_Policy_ensureHasDelegate(admin, scopes, isPrimary);
+    }
 
-            .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_UNAFFILIATED_OTHER_USERS, includeRunOnNonAffiliatedDeviceOwnerSecondaryUser())
-            .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_AFFILIATED_OTHER_USERS, includeRunOnAffiliatedDeviceOwnerSecondaryUser())
+    private static Function<EnterprisePolicy, Set<Annotation>> singleAnnotation(
+            Annotation annotation) {
+        return (i) -> ImmutableSet.of(annotation);
+    }
 
-            .put(APPLIED_BY_AFFILIATED_PROFILE_OWNER_USER | APPLIES_TO_OWN_USER, includeRunOnAffiliatedProfileOwnerSecondaryUser())
-            .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER | APPLIES_TO_OWN_USER, includeRunOnUnaffiliatedProfileOwnerSecondaryUser())
-            .put(APPLIED_BY_PROFILE_OWNER_USER_WITH_NO_DO | APPLIES_TO_OWN_USER, includeRunOnProfileOwnerPrimaryUser())
+    private static Function<EnterprisePolicy, Set<Annotation>> generateDelegateAnnotation(
+            Annotation annotation, boolean isPrimary) {
+        return (policy) -> {
+            Annotation[] existingAnnotations = annotation.annotationType().getAnnotations();
+            return Arrays.stream(policy.delegatedScopes())
+                    .map(scope -> {
+                        Annotation[] newAnnotations = Arrays.copyOf(existingAnnotations,
+                                existingAnnotations.length + 1);
+                        newAnnotations[newAnnotations.length - 1] = ensureHasDelegate(
+                                EnsureHasDelegate.AdminType.PRIMARY, new String[]{scope},
+                                isPrimary);
 
-            .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_OWN_USER, includeRunOnProfileOwnerProfileWithNoDeviceOwner())
-            .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_PARENT, includeRunOnParentOfProfileOwnerWithNoDeviceOwner())
+                        return new DynamicParameterizedAnnotation(
+                                annotation.annotationType().getSimpleName() + "Delegate:" + scope,
+                                newAnnotations);
+                    }).collect(Collectors.toSet());
+        };
+    }
 
-            .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_UNAFFILIATED_OTHER_USERS, includeRunOnSecondaryUserInDifferentProfileGroupToProfileOwnerProfile())
-            .build();
+    private static Map<Function<EnterprisePolicy, Set<Annotation>>, Set<Integer>> calculateAnnotationsMap(
+            Map<Integer, Function<EnterprisePolicy, Set<Annotation>>> annotations) {
+        Map<Function<EnterprisePolicy, Set<Annotation>>, Set<Integer>> b = new HashMap<>();
 
-    // This must contain one key for every APPLIED_BY that is being used, and maps to the "default" for testing that DPC type
-    // in general this will be a state which runs on the same user as the dpc.
-    private static final ImmutableMap<Integer, Annotation> DPC_STATE_ANNOTATIONS = ImmutableMap.<Integer, Annotation>builder()
-            .put(APPLIED_BY_DEVICE_OWNER, includeRunOnDeviceOwnerUser())
-            .put(APPLIED_BY_AFFILIATED_PROFILE_OWNER, includeRunOnAffiliatedProfileOwnerSecondaryUser())
-            .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER, includeRunOnProfileOwnerPrimaryUser())
-            .put(APPLIED_BY_PROFILE_OWNER_USER_WITH_NO_DO, includeRunOnProfileOwnerPrimaryUser())
-            .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE, includeRunOnProfileOwnerProfileWithNoDeviceOwner())
-            .build();
-
-    private static final int APPLIED_BY_FLAGS =
-            APPLIED_BY_DEVICE_OWNER | APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE
-                    | APPLIED_BY_AFFILIATED_PROFILE_OWNER_PROFILE
-                    | APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER
-                    | APPLIED_BY_AFFILIATED_PROFILE_OWNER_USER;
-
-
-    private static final Map<Annotation, Set<Integer>> ANNOTATIONS_MAP = calculateAnnotationsMap(STATE_ANNOTATIONS);
-
-    private static Map<Annotation, Set<Integer>> calculateAnnotationsMap(
-            Map<Integer, Annotation> annotations) {
-        Map<Annotation, Set<Integer>> b = new HashMap<>();
-
-        for (Map.Entry<Integer, Annotation> i : annotations.entrySet()) {
+        for (Map.Entry<Integer, Function<EnterprisePolicy, Set<Annotation>>> i :
+                annotations.entrySet()) {
             if (!b.containsKey(i.getValue())) {
                 b.put(i.getValue(), new HashSet<>());
             }
@@ -179,20 +259,39 @@
         return b;
     }
 
+    private static Function<EnterprisePolicy, Set<Annotation>> addGeneratedStates(
+            ImmutableMap.Entry<Integer, Function<EnterprisePolicy, Set<Annotation>>> entry) {
+        return (policy) -> {
+            if (hasFlag(policy.dpc(), entry.getKey() | CAN_BE_DELEGATED)) {
+                Set<Annotation> results = new HashSet<>(entry.getValue().apply(policy));
+                results.addAll(results.stream().flatMap(
+                        t -> generateDelegateAnnotation(t, /* isPrimary= */ true).apply(
+                                policy).stream())
+                        .collect(Collectors.toSet()));
+
+                return results;
+            }
+
+            return entry.getValue().apply(policy);
+        };
+    }
+
 
     /**
-     * Get positive state annotations for the given policy.
+     * Get parameterized test runs for the given policy.
      *
      * <p>These are states which should be run where the policy is able to be applied.
      */
-    public static List<Annotation> positiveStates(String policyName, EnterprisePolicy enterprisePolicy) {
+    public static List<Annotation> positiveStates(String policyName,
+            EnterprisePolicy enterprisePolicy) {
         Set<Annotation> annotations = new HashSet<>();
 
         validateFlags(policyName, enterprisePolicy.dpc());
 
-        for (Map.Entry<Annotation, Set<Integer>> annotation : ANNOTATIONS_MAP.entrySet()) {
+        for (Map.Entry<Function<EnterprisePolicy, Set<Annotation>>, Set<Integer>> annotation :
+                ANNOTATIONS_MAP.entrySet()) {
             if (isPositive(enterprisePolicy.dpc(), annotation.getValue())) {
-                annotations.add(annotation.getKey());
+                annotations.addAll(annotation.getKey().apply(enterprisePolicy));
             }
         }
 
@@ -215,13 +314,15 @@
 
     private static boolean isNegative(int[] policyFlags, Set<Integer> annotationFlags) {
         for (int annotationFlag : annotationFlags) {
-            if (hasFlag(annotationFlag, DO_NOT_APPLY_TO_NEGATIVE_TESTS, /* nonMatchingFlag= */ NO)) {
+            if (hasFlag(annotationFlag, DO_NOT_APPLY_TO_NEGATIVE_TESTS, /* nonMatchingFlag= */
+                    NO)) {
                 return false; // We don't support using this annotation for negative tests
             }
 
             int appliedByFlag = APPLIED_BY_FLAGS & annotationFlag;
             int otherFlags = annotationFlag ^ appliedByFlag; // remove the appliedByFlag
-            if (hasFlag(policyFlags, /* matchingFlag= */ appliedByFlag, /* nonMatchingFlag= */ otherFlags)) {
+            if (hasFlag(policyFlags, /* matchingFlag= */ appliedByFlag, /* nonMatchingFlag= */
+                    otherFlags)) {
                 return true;
             }
         }
@@ -230,18 +331,20 @@
     }
 
     /**
-     * Get negative state annotations for the given policy.
+     * Get negative parameterized test runs for the given policy.
      *
      * <p>These are states which should be run where the policy is not able to be applied.
      */
-    public static List<Annotation> negativeStates(String policyName, EnterprisePolicy enterprisePolicy) {
+    public static List<Annotation> negativeStates(String policyName,
+            EnterprisePolicy enterprisePolicy) {
         Set<Annotation> annotations = new HashSet<>();
 
         validateFlags(policyName, enterprisePolicy.dpc());
 
-        for (Map.Entry<Annotation, Set<Integer>> annotation : ANNOTATIONS_MAP.entrySet()) {
+        for (Map.Entry<Function<EnterprisePolicy, Set<Annotation>>, Set<Integer>> annotation :
+                ANNOTATIONS_MAP.entrySet()) {
             if (isNegative(enterprisePolicy.dpc(), annotation.getValue())) {
-                annotations.add(annotation.getKey());
+                annotations.addAll(annotation.getKey().apply(enterprisePolicy));
             }
         }
 
@@ -254,23 +357,60 @@
     }
 
     /**
-     * Get state annotations where the policy cannot be set for the given policy.
+     * Get parameterized test runs where the policy cannot be set for the given policy.
      */
-    public static List<Annotation> cannotSetPolicyStates(String policyName, EnterprisePolicy enterprisePolicy) {
+    public static List<Annotation> cannotSetPolicyStates(String policyName,
+            EnterprisePolicy enterprisePolicy, boolean includeDeviceAdminStates,
+            boolean includeNonDeviceAdminStates) {
         Set<Annotation> annotations = new HashSet<>();
 
         validateFlags(policyName, enterprisePolicy.dpc());
 
-        // TODO(scottjonathan): Always include a state without a dpc
+        if (includeDeviceAdminStates) {
+            int allFlags = 0;
+            for (int p : enterprisePolicy.dpc()) {
+                allFlags = allFlags | p;
+            }
 
-        int allFlags = 0;
-        for (int p : enterprisePolicy.dpc()) {
-            allFlags = allFlags | p;
+            for (Map.Entry<Integer, Function<EnterprisePolicy, Set<Annotation>>> appliedByFlag :
+                    DPC_STATE_ANNOTATIONS.entrySet()) {
+                if ((appliedByFlag.getKey() & allFlags) == 0) {
+                    annotations.addAll(appliedByFlag.getValue().apply(enterprisePolicy));
+                }
+            }
         }
 
-        for (Map.Entry<Integer, Annotation> appliedByFlag : DPC_STATE_ANNOTATIONS.entrySet()) {
-            if ((appliedByFlag.getKey() & allFlags) == 0) {
-                annotations.add(appliedByFlag.getValue());
+        if (includeNonDeviceAdminStates) {
+            Set<String> validScopes = ImmutableSet.copyOf(enterprisePolicy.delegatedScopes());
+            String[] scopes = ALL_DELEGATE_SCOPES.stream()
+                    .filter(i -> !validScopes.contains(i))
+                    .toArray(String[]::new);
+            Annotation[] existingAnnotations = IncludeRunOnDeviceOwnerUser.class.getAnnotations();
+
+            if (BedsteadJUnit4.isDebug()) {
+                // Add a non-DPC with no delegate scopes
+                Annotation[] newAnnotations = Arrays.copyOf(existingAnnotations,
+                        existingAnnotations.length + 1);
+                newAnnotations[newAnnotations.length - 1] = ensureHasDelegate(
+                        EnsureHasDelegate.AdminType.PRIMARY, new String[]{}, /* isPrimary= */ true);
+                annotations.add(
+                        new DynamicParameterizedAnnotation("DelegateWithNoScopes", newAnnotations));
+
+                for (String scope : scopes) {
+                    newAnnotations = Arrays.copyOf(existingAnnotations,
+                            existingAnnotations.length + 1);
+                    newAnnotations[newAnnotations.length - 1] = ensureHasDelegate(
+                            EnsureHasDelegate.AdminType.PRIMARY, new String[]{scope}, /* isPrimary= */ true);
+                    annotations.add(
+                            new DynamicParameterizedAnnotation("DelegateWithScope:" + scope, newAnnotations));
+                }
+            } else {
+                Annotation[] newAnnotations = Arrays.copyOf(existingAnnotations,
+                        existingAnnotations.length + 1);
+                newAnnotations[newAnnotations.length - 1] = ensureHasDelegate(
+                        EnsureHasDelegate.AdminType.PRIMARY, scopes, /* isPrimary= */ true);
+                annotations.add(
+                        new DynamicParameterizedAnnotation("DelegateWithoutValidScope", newAnnotations));
             }
         }
 
@@ -296,9 +436,10 @@
             allFlags = allFlags | p;
         }
 
-        for (Map.Entry<Integer, Annotation> appliedByFlag : DPC_STATE_ANNOTATIONS.entrySet()) {
+        for (Map.Entry<Integer, Function<EnterprisePolicy, Set<Annotation>>> appliedByFlag :
+                DPC_STATE_ANNOTATIONS.entrySet()) {
             if ((appliedByFlag.getKey() & allFlags) == appliedByFlag.getKey()) {
-                annotations.add(appliedByFlag.getValue());
+                annotations.addAll(appliedByFlag.getValue().apply(enterprisePolicy));
             }
         }
 
@@ -311,8 +452,14 @@
 
         if (singleTestOnly) {
             // We select one annotation in an arbitrary but deterministic way
-            annotationList.sort(Comparator.comparing(a -> a.annotationType().getName()));
-            Annotation firstAnnotation = annotationList.get(0);
+            annotationList.sort(Comparator.comparing(
+                    a -> a instanceof DynamicParameterizedAnnotation
+                            ? "DynamicParameterizedAnnotation" : a.annotationType().getName()));
+
+            // We don't want a delegate to be the representative test
+            Annotation firstAnnotation = annotationList.stream()
+                    .filter(i -> !(i instanceof  DynamicParameterizedAnnotation))
+                    .findFirst().get();
             annotationList.clear();
             annotationList.add(firstAnnotation);
         }
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/SlowApiTest.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/SlowApiTest.java
new file mode 100644
index 0000000..9521e88
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/SlowApiTest.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bedstead.harrier.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to indicate that a test can take a long time to run.
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface SlowApiTest {
+    String reason();
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/CannotSetPolicyTest.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/CannotSetPolicyTest.java
index 9315103..d0f1985 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/CannotSetPolicyTest.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/CannotSetPolicyTest.java
@@ -45,6 +45,17 @@
     Class<?> policy();
 
     /**
+     * If true, then this will run in states where the app is a device admin but is not one which is
+     * allowed to make the call.
+     */
+    boolean includeDeviceAdminStates() default true;
+
+    /**
+     * If true, then this will run in states where the app is not a device admin.
+     */
+    boolean includeNonDeviceAdminStates() default true;
+
+    /**
      * Weight sets the order that annotations will be resolved.
      *
      * <p>Annotations with a lower weight will be resolved before annotations with a higher weight.
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasDelegate.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasDelegate.java
new file mode 100644
index 0000000..73c1da7
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasDelegate.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bedstead.harrier.annotations.enterprise;
+
+import static com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner.DO_PO_WEIGHT;
+
+import com.android.bedstead.harrier.DeviceState;
+import com.android.bedstead.harrier.annotations.AnnotationRunPrecedence;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Mark that a test requires that the given admin delegates the given scope to a test app.
+ *
+ * <p>You should use {@link DeviceState} to ensure that the device enters
+ * the correct state for the method. You can use {@link DeviceState#delegate()} to interact with
+ * the delegate.
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface EnsureHasDelegate {
+
+    enum AdminType {
+        DEVICE_OWNER,
+        PROFILE_OWNER,
+        PRIMARY
+    }
+
+    /**
+     * The admin that should delegate this scope.
+     *
+     * <p>If this is set to {@link AdminType#PRIMARY} and {@link #isPrimary()} is true, then the
+     * delegate will replace the primary dpc as primary without error.
+     */
+    AdminType admin();
+
+    /** The scope being delegated. */
+    String[] scopes();
+
+    /**
+     * Whether this delegate should be returned by calls to {@link DeviceState#policyManager()}.
+     *
+     * <p>Only one policy manager per test should be marked as primary.
+     */
+    boolean isPrimary() default false;
+
+    /**
+     * Weight sets the order that annotations will be resolved.
+     *
+     * <p>Annotations with a lower weight will be resolved before annotations with a higher weight.
+     *
+     * <p>If there is an order requirement between annotations, ensure that the weight of the
+     * annotation which must be resolved first is lower than the one which must be resolved later.
+     *
+     * <p>Weight can be set to a {@link AnnotationRunPrecedence} constant, or to any {@link int}.
+     */
+    int weight() default DO_PO_WEIGHT + 1; // Should run after setting DO/PO
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasDeviceOwner.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasDeviceOwner.java
index 483a73e..2fdfc9d 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasDeviceOwner.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasDeviceOwner.java
@@ -49,13 +49,17 @@
 @Retention(RetentionPolicy.RUNTIME)
 @RequireFeature(FEATURE_DEVICE_ADMIN)
 public @interface EnsureHasDeviceOwner {
+
+    int DO_PO_WEIGHT = MIDDLE;
+
      /** Behaviour if the device owner cannot be set. */
     FailureMode failureMode() default FailureMode.FAIL;
 
     /**
-     * Whether this DPC should be returned by calls to {@link DeviceState#dpc()}.
+     * Whether this DPC should be returned by calls to {@link DeviceState#dpc()} or
+     * {@link DeviceState#policyManager()}}.
      *
-     * <p>Only one device policy controller per test should be marked as primary.
+     * <p>Only one policy manager per test should be marked as primary.
      */
     boolean isPrimary() default false;
 
@@ -74,5 +78,5 @@
      *
      * <p>Weight can be set to a {@link AnnotationRunPrecedence} constant, or to any {@link int}.
      */
-    int weight() default MIDDLE;
+    int weight() default DO_PO_WEIGHT;
 }
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDeviceOwner.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDeviceOwner.java
index 197a5fb..307b554 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDeviceOwner.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDeviceOwner.java
@@ -16,7 +16,7 @@
 
 package com.android.bedstead.harrier.annotations.enterprise;
 
-import static com.android.bedstead.harrier.annotations.AnnotationRunPrecedence.MIDDLE;
+import static com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner.DO_PO_WEIGHT;
 
 import com.android.bedstead.harrier.DeviceState;
 import com.android.bedstead.harrier.annotations.AnnotationRunPrecedence;
@@ -47,5 +47,5 @@
      *
      * <p>Weight can be set to a {@link AnnotationRunPrecedence} constant, or to any {@link int}.
      */
-    int weight() default MIDDLE;
+    int weight() default DO_PO_WEIGHT;
 }
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDpc.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDpc.java
index 72881ba..c97fd7f 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDpc.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDpc.java
@@ -16,7 +16,7 @@
 
 package com.android.bedstead.harrier.annotations.enterprise;
 
-import static com.android.bedstead.harrier.annotations.AnnotationRunPrecedence.MIDDLE;
+import static com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner.DO_PO_WEIGHT;
 
 import com.android.bedstead.harrier.DeviceState;
 import com.android.bedstead.harrier.annotations.AnnotationRunPrecedence;
@@ -53,5 +53,5 @@
      *
      * <p>Weight can be set to a {@link AnnotationRunPrecedence} constant, or to any {@link int}.
      */
-    int weight() default MIDDLE;
+    int weight() default DO_PO_WEIGHT;
 }
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoProfileOwner.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoProfileOwner.java
index 2d24990..561da3c 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoProfileOwner.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoProfileOwner.java
@@ -17,7 +17,7 @@
 package com.android.bedstead.harrier.annotations.enterprise;
 
 import static com.android.bedstead.harrier.DeviceState.UserType.CURRENT_USER;
-import static com.android.bedstead.harrier.annotations.AnnotationRunPrecedence.MIDDLE;
+import static com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner.DO_PO_WEIGHT;
 
 import com.android.bedstead.harrier.DeviceState;
 import com.android.bedstead.harrier.annotations.AnnotationRunPrecedence;
@@ -49,5 +49,5 @@
      *
      * <p>Weight can be set to a {@link AnnotationRunPrecedence} constant, or to any {@link int}.
      */
-    int weight() default MIDDLE;
+    int weight() default DO_PO_WEIGHT;
 }
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasProfileOwner.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasProfileOwner.java
index eb5c9e6..a408a4d 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasProfileOwner.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasProfileOwner.java
@@ -19,7 +19,7 @@
 import static android.content.pm.PackageManager.FEATURE_DEVICE_ADMIN;
 
 import static com.android.bedstead.harrier.DeviceState.UserType.CURRENT_USER;
-import static com.android.bedstead.harrier.annotations.AnnotationRunPrecedence.MIDDLE;
+import static com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner.DO_PO_WEIGHT;
 
 import com.android.bedstead.harrier.DeviceState;
 import com.android.bedstead.harrier.annotations.AnnotationRunPrecedence;
@@ -45,9 +45,10 @@
     DeviceState.UserType onUser() default CURRENT_USER;
 
     /**
-     * Whether this DPC should be returned by calls to {@link DeviceState#dpc()}.
+     * Whether this DPC should be returned by calls to {@link DeviceState#dpc()} or
+     * {@link DeviceState#policyManager()}}.
      *
-     * <p>Only one device policy controller per test should be marked as primary.
+     * <p>Only one policy manager per test should be marked as primary.
      */
     boolean isPrimary() default false;
 
@@ -66,5 +67,5 @@
      *
      * <p>Weight can be set to a {@link AnnotationRunPrecedence} constant, or to any {@link int}.
      */
-    int weight() default MIDDLE;
+    int weight() default DO_PO_WEIGHT;
 }
\ No newline at end of file
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnterprisePolicy.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnterprisePolicy.java
index f7f346d..9b3c16a 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnterprisePolicy.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnterprisePolicy.java
@@ -166,6 +166,14 @@
      * {@link APPLIES_IN_BACKGROUND}. */
     int DOES_NOT_APPLY_IN_BACKGROUND = 1 << 18;
 
+
+    /**
+     * A policy which can be applied by a delegate.
+     *
+     * See {@link #delegatedScopes()} for the scopes which enable this.
+     */
+    int CAN_BE_DELEGATED = 1 << 19;
+
     /** Flags indicating DPC states which can set the policy. */
     int[] dpc() default {};
 
@@ -186,7 +194,7 @@
     /**
      * {@link DelegatedScope} indicating which delegated scopes can control the policy.
      *
-     * <p>Note that this currently does not generate any additional tests but may do in future.
+     * <p>This applies to {@link #dpc()} entries with the {@link #CAN_BE_DELEGATED} flag.
      */
-    DelegatedScope[] delegatedScopes() default {};
+    String[] delegatedScopes() default {};
 }
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictions.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictions.java
index 5944757..9e30dad 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictions.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictions.java
@@ -16,10 +16,13 @@
 
 package com.android.bedstead.harrier.policies;
 
+import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
+
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER;
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_IN_BACKGROUND;
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.CAN_BE_DELEGATED;
 
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
@@ -34,8 +37,11 @@
  * {@link DevicePolicyManager#setApplicationRestrictions(ComponentName, String, Bundle)} and
  * {@link DevicePolicyManager#getApplicationRestrictions(ComponentName, String)}.
  */
-@EnterprisePolicy(dpc = {
-        APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIES_IN_BACKGROUND,
-        APPLIED_BY_PROFILE_OWNER | APPLIES_TO_OWN_USER})
+@EnterprisePolicy(
+        dpc = {
+            APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIES_IN_BACKGROUND | CAN_BE_DELEGATED,
+            APPLIED_BY_PROFILE_OWNER | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED},
+        delegatedScopes = DELEGATION_APP_RESTRICTIONS
+        )
 public final class ApplicationRestrictions {
 }
\ No newline at end of file
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictionsManagingPackage.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictionsManagingPackage.java
new file mode 100644
index 0000000..379b071
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictionsManagingPackage.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bedstead.harrier.policies;
+
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_IN_BACKGROUND;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.os.Bundle;
+
+import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy;
+
+/**
+ * Policy for application restrictions.
+ *
+ * <p>This is used by the method
+ * {@link DevicePolicyManager#setApplicationRestrictionsManagingPackage(ComponentName, String, Bundle)}
+ */
+@EnterprisePolicy(
+        dpc = {
+                APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIES_IN_BACKGROUND,
+                APPLIED_BY_PROFILE_OWNER | APPLIES_TO_OWN_USER})
+public final class ApplicationRestrictionsManagingPackage {
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetPermissionGrantState.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetPermissionGrantState.java
index 12bb005..bc3861a 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetPermissionGrantState.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetPermissionGrantState.java
@@ -21,12 +21,12 @@
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER;
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.CAN_BE_DELEGATED;
 
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
 
 import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy;
-import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.DelegatedScope;
 
 /**
  * Policies around setting the grant state of a basic permission.
@@ -36,8 +36,7 @@
  * granting permissions not covered by other policies.
  */
 @EnterprisePolicy(
-        dpc = APPLIED_BY_DEVICE_OWNER | APPLIED_BY_PROFILE_OWNER | APPLIES_TO_OWN_USER,
-        delegatedScopes = @DelegatedScope(
-                scope = DELEGATION_PERMISSION_GRANT, appliesTo = APPLIES_TO_OWN_USER))
+        dpc = APPLIED_BY_DEVICE_OWNER | APPLIED_BY_PROFILE_OWNER | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED,
+        delegatedScopes = DELEGATION_PERMISSION_GRANT)
 public final class SetPermissionGrantState {
 }
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetSmsPermissionGranted.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetSmsPermissionGranted.java
index 67f5615..fac7dcd 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetSmsPermissionGranted.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetSmsPermissionGranted.java
@@ -16,9 +16,12 @@
 
 package com.android.bedstead.harrier.policies;
 
+import static android.app.admin.DevicePolicyManager.DELEGATION_PERMISSION_GRANT;
+
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER_USER;
 import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.CAN_BE_DELEGATED;
 
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
@@ -34,6 +37,7 @@
  */
 // TODO(198311372): Check if APPLIED_BY_PROFILE_OWNER_USER is expected
 @EnterprisePolicy(
-        dpc = APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIED_BY_PROFILE_OWNER_USER)
+        dpc = APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIED_BY_PROFILE_OWNER_USER | CAN_BE_DELEGATED,
+        delegatedScopes = DELEGATION_PERMISSION_GRANT)
 public final class SetSmsPermissionGranted {
 }
diff --git a/common/device-side/bedstead/harrier/src/test/java/com/android/bedstead/harrier/DeviceStateTest.java b/common/device-side/bedstead/harrier/src/test/java/com/android/bedstead/harrier/DeviceStateTest.java
index 34a738a..c0290fe 100644
--- a/common/device-side/bedstead/harrier/src/test/java/com/android/bedstead/harrier/DeviceStateTest.java
+++ b/common/device-side/bedstead/harrier/src/test/java/com/android/bedstead/harrier/DeviceStateTest.java
@@ -18,6 +18,8 @@
 
 import static android.Manifest.permission.INTERACT_ACROSS_PROFILES;
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
+import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL;
 import static android.content.pm.PackageManager.PERMISSION_DENIED;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
@@ -27,6 +29,8 @@
 import static com.android.bedstead.harrier.OptionalBoolean.TRUE;
 import static com.android.bedstead.harrier.annotations.RequireAospBuild.GMS_CORE_PACKAGE;
 import static com.android.bedstead.harrier.annotations.RequireCnGmsBuild.CHINA_GOOGLE_SERVICES_FEATURE;
+import static com.android.bedstead.harrier.annotations.enterprise.EnsureHasDelegate.AdminType.DEVICE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnsureHasDelegate.AdminType.PRIMARY;
 import static com.android.bedstead.nene.users.UserType.MANAGED_PROFILE_TYPE_NAME;
 import static com.android.bedstead.nene.users.UserType.SECONDARY_USER_TYPE_NAME;
 import static com.android.bedstead.nene.users.UserType.SYSTEM_USER_TYPE_NAME;
@@ -38,6 +42,7 @@
 import android.app.ActivityManager;
 import android.os.Build;
 import android.platform.test.annotations.AppModeFull;
+import android.os.Bundle;
 
 import com.android.bedstead.harrier.annotations.EnsureDoesNotHavePermission;
 import com.android.bedstead.harrier.annotations.EnsureHasNoSecondaryUser;
@@ -67,6 +72,7 @@
 import com.android.bedstead.harrier.annotations.RequireSdkVersion;
 import com.android.bedstead.harrier.annotations.RequireUserSupported;
 import com.android.bedstead.harrier.annotations.TestTag;
+import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDelegate;
 import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner;
 import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDeviceOwner;
 import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDpc;
@@ -82,6 +88,8 @@
 import com.android.bedstead.nene.packages.Package;
 import com.android.bedstead.nene.users.UserReference;
 import com.android.bedstead.nene.utils.Tags;
+import com.android.bedstead.remotedpc.RemoteDelegate;
+import com.android.bedstead.remotedpc.RemoteDpc;
 
 import org.junit.ClassRule;
 import org.junit.Ignore;
@@ -628,7 +636,7 @@
     @IncludeRunOnBackgroundDeviceOwnerUser
     public void includeRunOnBackgroundDeviceOwnerUserAnnotation_isRunningOnDeviceOwnerUser() {
         assertThat(TestApis.users().instrumented())
-                .isEqualTo(sDeviceState.dpc().devicePolicyController().user());
+                .isEqualTo(sDeviceState.dpc().user());
     }
 
     @Test
@@ -706,4 +714,51 @@
     public void testTagAnnoation_testTagIsSet() {
         assertThat(Tags.hasTag("TestTag")).isTrue();
     }
+
+    @Test
+    @EnsureHasDeviceOwner
+    @EnsureHasDelegate(admin = DEVICE_OWNER, scopes = DELEGATION_CERT_INSTALL, isPrimary = true)
+    public void ensureHasPrimaryDelegateAnnotation_dpcReturnsDelegate() {
+        assertThat(sDeviceState.dpc()).isInstanceOf(RemoteDelegate.class);
+    }
+
+    @Test
+    @EnsureHasDeviceOwner
+    @EnsureHasDelegate(admin = DEVICE_OWNER, scopes = DELEGATION_CERT_INSTALL, isPrimary = false)
+    public void ensureHasNonPrimaryDelegateAnnotation_dpcReturnsDpc() {
+        assertThat(sDeviceState.dpc()).isInstanceOf(RemoteDpc.class);
+    }
+
+    @Test
+    @EnsureHasDeviceOwner
+    @EnsureHasDelegate(admin = DEVICE_OWNER, scopes = DELEGATION_CERT_INSTALL, isPrimary = true)
+    public void ensureHasDelegateAnnotation_dpcCanUseDelegatedFunctionality() {
+        assertThat(sDeviceState.dpc().devicePolicyManager().getEnrollmentSpecificId()).isNotNull();
+    }
+
+    @Test
+    @EnsureHasDeviceOwner
+    @EnsureHasDelegate(admin = DEVICE_OWNER,
+            scopes = {DELEGATION_CERT_INSTALL, DELEGATION_APP_RESTRICTIONS}, isPrimary = true)
+    public void ensureHasDelegateAnnotation_multipleScopes_dpcCanUseAllDelegatedFunctionality() {
+        assertThat(sDeviceState.dpc().devicePolicyManager().getEnrollmentSpecificId()).isNotNull();
+        sDeviceState.dpc().devicePolicyManager()
+                .setApplicationRestrictions(
+                        sDeviceState.dpc().componentName(),
+                        sDeviceState.dpc().packageName(), new Bundle());
+    }
+
+    @Test
+    @EnsureHasDeviceOwner(isPrimary = true)
+    @EnsureHasDelegate(admin = PRIMARY, scopes = {})
+    public void ensureHasDelegateAnnotation_primaryAdminWithoutReplace_dpcReturnsDpc() {
+        assertThat(sDeviceState.dpc()).isInstanceOf(RemoteDpc.class);
+    }
+
+    @Test
+    @EnsureHasDeviceOwner(isPrimary = true)
+    @EnsureHasDelegate(admin = PRIMARY, scopes = {}, isPrimary = true)
+    public void ensureHasDelegateAnnotation_primaryAdminAndReplace_dpcReturnsDelegate() {
+        assertThat(sDeviceState.dpc()).isInstanceOf(RemoteDelegate.class);
+    }
 }
diff --git a/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemoteDelegate.java b/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemoteDelegate.java
new file mode 100644
index 0000000..714208f
--- /dev/null
+++ b/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemoteDelegate.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bedstead.remotedpc;
+
+import android.content.ComponentName;
+
+import androidx.annotation.Nullable;
+
+import com.android.bedstead.nene.users.UserReference;
+import com.android.bedstead.testapp.TestApp;
+import com.android.bedstead.testapp.TestAppProvider;
+
+/**
+ * {@link RemotePolicyManager} subclass representing an app which has been delegated to.
+ */
+public final class RemoteDelegate extends RemotePolicyManager {
+
+    private static final TestAppProvider sTestAppProvider = new TestAppProvider();
+    public static final TestApp sTestApp = sTestAppProvider.query()
+            .wherePackageName().isEqualTo("com.android.Delegate")
+            .get();
+
+    public RemoteDelegate(TestApp testApp, UserReference user) {
+        super(testApp, user);
+    }
+
+    @Nullable
+    @Override
+    public ComponentName componentName() {
+        return null;
+    }
+}
diff --git a/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemoteDpc.java b/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemoteDpc.java
index ea230b2..01519a0 100644
--- a/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemoteDpc.java
+++ b/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemoteDpc.java
@@ -19,7 +19,6 @@
 import static android.os.UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES;
 
 import android.content.ComponentName;
-import android.content.Context;
 import android.os.Build;
 import android.os.UserHandle;
 
@@ -33,14 +32,10 @@
 import com.android.bedstead.nene.users.UserReference;
 import com.android.bedstead.nene.utils.Versions;
 import com.android.bedstead.testapp.TestApp;
-import com.android.bedstead.testapp.TestAppInstance;
 import com.android.bedstead.testapp.TestAppProvider;
 
 /** Entry point to RemoteDPC. */
-public final class RemoteDpc extends TestAppInstance {
-
-    // This must be instrumentation not instrumented to access the resources
-    private static final Context sContext = TestApis.context().instrumentationContext();
+public final class RemoteDpc extends RemotePolicyManager {
 
     public static final ComponentName DPC_COMPONENT_NAME = new ComponentName(
             "com.android.RemoteDPC",
@@ -258,16 +253,9 @@
     }
 
     /**
-     * Get the {@link TestAppInstance} for the DPC.
-     *
-     */
-    public TestAppInstance app() {
-        return sTestApp.instance(mDevicePolicyController.user());
-    }
-
-    /**
      * Get the {@link ComponentName} of the DPC.
      */
+    @Override
     public ComponentName componentName() {
         return DPC_COMPONENT_NAME;
     }
diff --git a/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemotePolicyManager.java b/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemotePolicyManager.java
new file mode 100644
index 0000000..8532ef3
--- /dev/null
+++ b/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemotePolicyManager.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bedstead.remotedpc;
+
+import android.content.ComponentName;
+
+import androidx.annotation.Nullable;
+
+import com.android.bedstead.nene.users.UserReference;
+import com.android.bedstead.testapp.TestApp;
+import com.android.bedstead.testapp.TestAppInstance;
+
+/** A Remote app which can change device policy */
+public abstract class RemotePolicyManager extends TestAppInstance {
+
+    RemotePolicyManager(TestApp testApp, UserReference user) {
+        super(testApp, user);
+    }
+
+    /**
+     * Get the {@link ComponentName} of the device admin for the policy manager.
+     *
+     * <p>Null if there is no device admin
+     */
+    @Nullable
+    public abstract ComponentName componentName();
+}
diff --git a/common/device-side/bedstead/testapp/Android.bp b/common/device-side/bedstead/testapp/Android.bp
index 410f94b..bf92e97 100644
--- a/common/device-side/bedstead/testapp/Android.bp
+++ b/common/device-side/bedstead/testapp/Android.bp
@@ -99,7 +99,7 @@
 
 java_genrule {
     name: "TestApp_Apps",
-    srcs: [":EmptyTestApp", ":EmptyTestApp2", ":DeviceAdminTestApp", ":LockTaskApp", ":RemoteDPCTestApp", ":SmsApp", ":AccountManagementApp"],
+    srcs: [":EmptyTestApp", ":EmptyTestApp2", ":DeviceAdminTestApp", ":LockTaskApp", ":DelegateTestApp", ":RemoteDPCTestApp", ":SmsApp", ":AccountManagementApp"],
     out: ["TestApp_Apps.res.zip"],
     tools: ["soong_zip", "index_testapps", "aapt2"],
     cmd: "mkdir -p $(genDir)/res/raw"
@@ -107,6 +107,7 @@
          + " && cp $(location :EmptyTestApp2) $(genDir)/res/raw"
          + " && cp $(location :DeviceAdminTestApp) $(genDir)/res/raw"
          + " && cp $(location :LockTaskApp) $(genDir)/res/raw"
+         + " && cp $(location :DelegateTestApp) $(genDir)/res/raw"
          + " && cp $(location :RemoteDPCTestApp) $(genDir)/res/raw"
          + " && cp $(location :SmsApp) $(genDir)/res/raw"
          + " && cp $(location :AccountManagementApp) $(genDir)/res/raw"
@@ -152,6 +153,15 @@
 }
 
 android_test_helper_app {
+    name: "DelegateTestApp",
+    static_libs: [
+        "TestApp_TestApps"
+    ],
+    manifest: "manifests/DelegateManifest.xml",
+    min_sdk_version: "28"
+}
+
+android_test_helper_app {
     name: "RemoteDPCTestApp",
     static_libs: [
         "TestApp_TestApps",
diff --git a/common/device-side/bedstead/testapp/manifests/DelegateManifest.xml b/common/device-side/bedstead/testapp/manifests/DelegateManifest.xml
new file mode 100644
index 0000000..5bd3772
--- /dev/null
+++ b/common/device-side/bedstead/testapp/manifests/DelegateManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.Delegate" android:targetSandboxVersion="2">
+
+    <application
+        android:appComponentFactory="com.android.bedstead.testapp.TestAppAppComponentFactory">
+
+        <!-- Don't allow this test app to be returned by queries unless filtered by package name -->
+        <meta-data android:name="testapp-package-query-only" android:value="true" />
+
+    </application>
+    <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28"/>
+</manifest>
\ No newline at end of file
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivities.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivities.java
index ce5023f..d95def6 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivities.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivities.java
@@ -53,7 +53,7 @@
         PackageManager p = TestApis.context().instrumentedContext().getPackageManager();
         try {
             PackageInfo packageInfo = p.getPackageInfo(
-                    mInstance.testApp().packageName(), /* flags= */ PackageManager.GET_ACTIVITIES);
+                    mInstance.packageName(), /* flags= */ PackageManager.GET_ACTIVITIES);
             for (android.content.pm.ActivityInfo activityInfo : packageInfo.activities) {
                 if (activityInfo.name.startsWith("androidx")) {
                     // Special case: androidx adds non-logging activities
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivitiesQueryBuilder.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivitiesQueryBuilder.java
index 3eb3633..761dec6 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivitiesQueryBuilder.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivitiesQueryBuilder.java
@@ -55,7 +55,7 @@
                 return new UnresolvedTestAppActivity(mTestAppActivities.mInstance,
                         TestApis.packages().component(
                                 new ComponentName(
-                                        mTestAppActivities.mInstance.testApp().packageName(),
+                                        mTestAppActivities.mInstance.packageName(),
                                         activity.className())));
             }
         }
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppBinder.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppBinder.java
index 4a4b5c8..282b68d 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppBinder.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppBinder.java
@@ -52,7 +52,7 @@
 
         Intent bindIntent = new Intent();
         bindIntent.setComponent(new ComponentName(
-                mTestAppInstance.testApp().packageName(),
+                mTestAppInstance.packageName(),
                 bindToService.getClassName()));
 
         Log.i(LOG_TAG, "Attempting to bind to " + bindIntent);
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppEvents.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppEvents.java
index a0db3b4..2a925dd 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppEvents.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppEvents.java
@@ -73,238 +73,238 @@
     @Override
     public ActivityCreatedEvent.ActivityCreatedEventQuery activityCreated() {
         return ActivityCreatedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public ActivityDestroyedEvent.ActivityDestroyedEventQuery activityDestroyed() {
         return ActivityDestroyedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public ActivityPausedEvent.ActivityPausedEventQuery activityPaused() {
         return ActivityPausedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public ActivityRestartedEvent.ActivityRestartedEventQuery activityRestarted() {
         return ActivityRestartedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public ActivityResumedEvent.ActivityResumedEventQuery activityResumed() {
         return ActivityResumedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public ActivityStartedEvent.ActivityStartedEventQuery activityStarted() {
         return ActivityStartedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public ActivityStoppedEvent.ActivityStoppedEventQuery activityStopped() {
         return ActivityStoppedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public BroadcastReceivedEvent.BroadcastReceivedEventQuery broadcastReceived() {
         return BroadcastReceivedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminBugreportFailedEvent.DeviceAdminBugreportFailedEventQuery bugReportFailed() {
         return DeviceAdminBugreportFailedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminBugreportSharedEvent.DeviceAdminBugreportSharedEventQuery bugReportShared() {
         return DeviceAdminBugreportSharedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminBugreportSharingDeclinedEvent.DeviceAdminBugreportSharingDeclinedEventQuery bugReportSharingDeclined() {
         return DeviceAdminBugreportSharingDeclinedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminChoosePrivateKeyAliasEvent.DeviceAdminChoosePrivateKeyAliasEventQuery choosePrivateKeyAlias() {
         return DeviceAdminChoosePrivateKeyAliasEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminDisabledEvent.DeviceAdminDisabledEventQuery deviceAdminDisabled() {
         return DeviceAdminDisabledEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminDisableRequestedEvent.DeviceAdminDisableRequestedEventQuery deviceAdminDisableRequested() {
         return DeviceAdminDisableRequestedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminEnabledEvent.DeviceAdminEnabledEventQuery deviceAdminEnabled() {
         return DeviceAdminEnabledEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminLockTaskModeEnteringEvent.DeviceAdminLockTaskModeEnteringEventQuery lockTaskModeEntering() {
         return DeviceAdminLockTaskModeEnteringEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminLockTaskModeExitingEvent.DeviceAdminLockTaskModeExitingEventQuery lockTaskModeExiting() {
         return DeviceAdminLockTaskModeExitingEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminNetworkLogsAvailableEvent.DeviceAdminNetworkLogsAvailableEventQuery networkLogsAvailable() {
         return DeviceAdminNetworkLogsAvailableEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminOperationSafetyStateChangedEvent.DeviceAdminOperationSafetyStateChangedEventQuery operationSafetyStateChanged() {
         return DeviceAdminOperationSafetyStateChangedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminPasswordChangedEvent.DeviceAdminPasswordChangedEventQuery passwordChanged() {
         return DeviceAdminPasswordChangedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminPasswordExpiringEvent.DeviceAdminPasswordExpiringEventQuery passwordExpiring() {
         return DeviceAdminPasswordExpiringEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminPasswordFailedEvent.DeviceAdminPasswordFailedEventQuery passwordFailed() {
         return DeviceAdminPasswordFailedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminPasswordSucceededEvent.DeviceAdminPasswordSucceededEventQuery passwordSucceeded() {
         return DeviceAdminPasswordSucceededEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminProfileProvisioningCompleteEvent.DeviceAdminProfileProvisioningCompleteEventQuery profileProvisioningComplete() {
         return DeviceAdminProfileProvisioningCompleteEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminReadyForUserInitializationEvent.DeviceAdminReadyForUserInitializationEventQuery readyForUserInitialization() {
         return DeviceAdminReadyForUserInitializationEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminSecurityLogsAvailableEvent.DeviceAdminSecurityLogsAvailableEventQuery securityLogsAvailable() {
         return DeviceAdminSecurityLogsAvailableEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminSystemUpdatePendingEvent.DeviceAdminSystemUpdatePendingEventQuery systemUpdatePending() {
         return DeviceAdminSystemUpdatePendingEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminTransferAffiliatedProfileOwnershipCompleteEvent.DeviceAdminTransferAffiliatedProfileOwnershipCompleteEventQuery transferAffiliatedProfileOwnershipComplete() {
         return DeviceAdminTransferAffiliatedProfileOwnershipCompleteEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminTransferOwnershipCompleteEvent.DeviceAdminTransferOwnershipCompleteEventQuery transferOwnershipComplete() {
         return DeviceAdminTransferOwnershipCompleteEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminUserAddedEvent.DeviceAdminUserAddedEventQuery userAdded() {
         return DeviceAdminUserAddedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminUserRemovedEvent.DeviceAdminUserRemovedEventQuery userRemoved() {
         return DeviceAdminUserRemovedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminUserStartedEvent.DeviceAdminUserStartedEventQuery userStarted() {
         return DeviceAdminUserStartedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminUserStoppedEvent.DeviceAdminUserStoppedEventQuery userStopped() {
         return DeviceAdminUserStoppedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 
     @Override
     public DeviceAdminUserSwitchedEvent.DeviceAdminUserSwitchedEventQuery userSwitched() {
         return DeviceAdminUserSwitchedEvent.queryPackage(
-                mTestApp.testApp().packageName())
+                mTestApp.packageName())
                 .onUser(mTestApp.user());
     }
 }
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppInstance.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppInstance.java
index 56e0443..cea69a3 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppInstance.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppInstance.java
@@ -115,6 +115,13 @@
     }
 
     /**
+     * See {@link TestApp#packageName()}.
+     */
+    public String packageName() {
+       return testApp().packageName();
+    }
+
+    /**
      * The {@link UserReference} this instance refers to.
      */
     public UserReference user() {
diff --git a/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/Processor.java b/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/Processor.java
index 287c085..03fbceb 100644
--- a/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/Processor.java
+++ b/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/Processor.java
@@ -336,7 +336,14 @@
 
             methodBuilder.nextControlFlow(
                     "catch ($T e)", PROFILE_RUNTIME_EXCEPTION_CLASSNAME)
-                    .addStatement("throw ($T) e.getCause()", RuntimeException.class)
+                    .addStatement("throw ($T) e.getCause()", RuntimeException.class);
+
+            for (TypeMirror m : method.getThrownTypes()) {
+                methodBuilder.nextControlFlow("catch ($T e)", m)
+                        .addStatement("throw e");
+            }
+
+            methodBuilder
                     .nextControlFlow("catch ($T e)", Throwable.class)
                     .addStatement(
                             "throw new $T($S, e)",
@@ -437,6 +444,11 @@
                 methodBuilder.addStatement("return $L", runLogic);
             }
 
+            for (TypeMirror m : method.getThrownTypes()) {
+                methodBuilder.nextControlFlow("catch ($T e)", m)
+                        .addStatement("throw e");
+            }
+
             methodBuilder.nextControlFlow(
                     "catch ($T e)", PROFILE_RUNTIME_EXCEPTION_CLASSNAME)
                     .addStatement("throw ($T) e.getCause()", RuntimeException.class)
@@ -536,6 +548,10 @@
                             .addModifiers(Modifier.PUBLIC)
                             .addAnnotation(Override.class);
 
+            for (TypeMirror m : method.getThrownTypes()) {
+                methodBuilder.addException(ClassName.get(m));
+            }
+
             methodBuilder.addParameter(
                     ParameterSpec.builder(String.class, "activityClassName").build());
 
@@ -580,7 +596,14 @@
 
             methodBuilder.nextControlFlow(
                     "catch ($T e)", PROFILE_RUNTIME_EXCEPTION_CLASSNAME)
-                    .addStatement("throw ($T) e.getCause()", RuntimeException.class)
+                    .addStatement("throw ($T) e.getCause()", RuntimeException.class);
+
+            for (TypeMirror m : method.getThrownTypes()) {
+                methodBuilder.nextControlFlow("catch ($T e)", m)
+                        .addStatement("throw e");
+            }
+
+            methodBuilder
                     .nextControlFlow("catch ($T e)", Throwable.class)
                     .addStatement(
                             "throw new $T($S, e)",
diff --git a/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/AppRestrictionsDelegateTest.java b/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/AppRestrictionsDelegateTest.java
deleted file mode 100644
index 9c73feb..0000000
--- a/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/AppRestrictionsDelegateTest.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.delegate;
-
-import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
-
-import static com.android.cts.delegate.DelegateTestUtils.assertExpectException;
-
-import android.app.admin.DevicePolicyManager;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.os.Process;
-import android.util.Log;
-
-import androidx.test.InstrumentationRegistry;
-
-import java.util.List;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Test that an app given the {@link DevicePolicyManager#DELEGATION_APP_RESTRICTIONS} scope via
- * {@link DevicePolicyManager#setDelegatedScopes} can manage app restrictions.
- */
-public class AppRestrictionsDelegateTest extends BaseJUnit3TestCase  {
-
-    private static final String TAG = AppRestrictionsDelegateTest.class.getSimpleName();
-
-    private static final String APP_RESTRICTIONS_TARGET_PKG =
-            "com.android.cts.apprestrictions.targetapp";
-    private static final String APP_RESTRICTIONS_ACTIVITY_NAME =
-            APP_RESTRICTIONS_TARGET_PKG + ".ApplicationRestrictionsActivity";
-    private static final String ACTION_RESTRICTIONS_VALUE =
-            "com.android.cts.apprestrictions.targetapp.RESTRICTIONS_VALUE";
-
-    private static final Bundle BUNDLE_0 = createBundle0();
-    private static final Bundle BUNDLE_1 = createBundle1();
-
-    private static final long TIMEOUT_SECONDS = 10;
-
-    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            Log.d(TAG, "onReceive(): intent " + action + " on uid " + Process.myUid());
-            if (ACTION_RESTRICTIONS_VALUE.equals(action)) {
-                mReceivedRestrictions = intent.getBundleExtra("value");
-                mOnRestrictionsSemaphore.release();
-            }
-        }
-    };
-
-    private final Semaphore mOnRestrictionsSemaphore = new Semaphore(0);
-    private Bundle mReceivedRestrictions;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_RESTRICTIONS_VALUE));
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        mContext.unregisterReceiver(mReceiver);
-        super.tearDown();
-    }
-
-    public void testCannotAccessApis() {
-        assertFalse("DelegateApp should not be an app restrictions delegate",
-                amIAppRestrictionsDelegate());
-
-        assertExpectException(SecurityException.class,
-                "Calling identity is not authorized", () -> {
-                    mDpm.setApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG, null);
-                });
-
-        assertExpectException(SecurityException.class,
-                "Calling identity is not authorized", () -> {
-                    mDpm.getApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG);
-                });
-    }
-
-    public void testCanAccessApis() throws InterruptedException {
-        assertTrue("DelegateApp is not an app restrictions delegate", amIAppRestrictionsDelegate());
-        try {
-            mDpm.setApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG, BUNDLE_0);
-            assertBundle0(mDpm.getApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG));
-
-            // Check that the target app can retrieve the same restrictions.
-            assertBundle0(waitForChangedRestriction());
-
-            // Test overwriting
-            mDpm.setApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG, BUNDLE_1);
-            assertBundle1(mDpm.getApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG));
-            assertBundle1(waitForChangedRestriction());
-        } finally {
-            mDpm.setApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG, new Bundle());
-            assertTrue(
-                mDpm.getApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG).isEmpty());
-        }
-    }
-
-    // Should be consistent with assertBundle0
-    private static Bundle createBundle0() {
-        Bundle result = new Bundle();
-        result.putString("placeholderString", "value");
-        return result;
-    }
-
-    // Should be consistent with createBundle0
-    private void assertBundle0(Bundle bundle) {
-        assertEquals(1, bundle.size());
-        assertEquals("value", bundle.getString("placeholderString"));
-    }
-
-    // Should be consistent with assertBundle1
-    private static Bundle createBundle1() {
-        Bundle result = new Bundle();
-        result.putInt("placeholderInt", 1);
-        return result;
-    }
-
-    // Should be consistent with createBundle1
-    private void assertBundle1(Bundle bundle) {
-        assertEquals(1, bundle.size());
-        assertEquals(1, bundle.getInt("placeholderInt"));
-    }
-
-    private void startTestActivity() {
-        ComponentName component = new ComponentName(
-                APP_RESTRICTIONS_TARGET_PKG, APP_RESTRICTIONS_ACTIVITY_NAME);
-        Log.d(TAG, "Starting activity " + component.flattenToShortString() + " on user "
-                + Process.myUserHandle());
-        mContext.startActivity(new Intent()
-                .setComponent(component)
-                .putExtra("admin_type",
-                        InstrumentationRegistry.getArguments().getString("admin_type"))
-                .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK));
-    }
-
-    private Bundle waitForChangedRestriction() throws InterruptedException {
-        startTestActivity();
-        assertTrue("App restrictions target app did not respond in time",
-                mOnRestrictionsSemaphore.tryAcquire(TIMEOUT_SECONDS, TimeUnit.SECONDS));
-        return mReceivedRestrictions;
-    }
-
-    private boolean amIAppRestrictionsDelegate() {
-        final List<String> scopes = mDpm.getDelegatedScopes(null, mContext.getPackageName());
-        return scopes.contains(DELEGATION_APP_RESTRICTIONS);
-    }
-}
diff --git a/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/GeneralDelegateTest.java b/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/GeneralDelegateTest.java
index 869ff7c..b93b884 100644
--- a/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/GeneralDelegateTest.java
+++ b/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/GeneralDelegateTest.java
@@ -16,7 +16,6 @@
 package com.android.cts.delegate;
 
 import android.app.admin.DevicePolicyManager;
-import android.content.ComponentName;
 import android.os.Bundle;
 import android.test.MoreAsserts;
 import android.util.Log;
@@ -58,17 +57,4 @@
                     expected.getMessage());
         }
     }
-
-    public void testSettingAdminComponentNameThrowsException() {
-        final String myPackageName = getInstrumentation().getContext().getPackageName();
-        final ComponentName myComponentName = new ComponentName(myPackageName,
-                GeneralDelegateTest.class.getName());
-
-        try {
-            mDpm.setUninstallBlocked(myComponentName, myPackageName, true);
-            fail("Expected SecurityException not thrown");
-        } catch (SecurityException expected) {
-            MoreAsserts.assertContainsRegex("No active admin", expected.getMessage());
-        }
-    }
 }
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ApplicationRestrictionsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ApplicationRestrictionsTest.java
deleted file mode 100644
index 201aeed..0000000
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ApplicationRestrictionsTest.java
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.deviceandprofileowner;
-
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.Bundle;
-import android.os.Parcelable;
-import android.os.UserManager;
-import android.test.MoreAsserts;
-
-import androidx.test.InstrumentationRegistry;
-
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Functionality tests for application restrictions APIs.
- *
- * <p>APIs are executed locally to assert that what you set can later be retrieved via the getter.
- * It also fires up an external activity to observe an application's view of its restrictions.
- *
- * <p>Finally, it checks that the {@link Intent#ACTION_APPLICATION_RESTRICTIONS_CHANGED} broadcast
- * is sent whenever app restrictions are modified for a given package.
- */
-public class ApplicationRestrictionsTest extends BaseDeviceAdminTest {
-
-    private static final String APP_RESTRICTIONS_TARGET_PKG =
-            "com.android.cts.apprestrictions.targetapp";
-    private static final String APP_RESTRICTIONS_ACTIVITY_NAME =
-            APP_RESTRICTIONS_TARGET_PKG + ".ApplicationRestrictionsActivity";
-    private static final String ACTION_RESTRICTIONS_VALUE =
-            "com.android.cts.apprestrictions.targetapp.RESTRICTIONS_VALUE";
-
-    private static final String OTHER_PACKAGE = APP_RESTRICTIONS_TARGET_PKG + "placeholder";
-
-    private static final String[] TEST_STRINGS = new String[] {
-            "<bad/>",
-            ">worse!\"£$%^&*()'<",
-            "<JSON>\"{ \\\"One\\\": { \\\"OneOne\\\": \\\"11\\\", \\\""
-                    + "OneTwo\\\": \\\"12\\\" }, \\\"Two\\\": \\\"2\\\" } <JSON/>\""
-    };
-
-    private static final Bundle BUNDLE_0 = createBundle0();
-    private static final Bundle BUNDLE_1 = createBundle1();
-
-    private static final long RESTRICTIONS_TIMEOUT_SECONDS = 10;
-
-    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (ACTION_RESTRICTIONS_VALUE.equals(action)) {
-                mReceivedRestrictions = intent.getBundleExtra("value");
-                mOnRestrictionsReceivedFromAppSemaphore.release();
-            } else if (Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED.equals(action)) {
-                mOnAppRestrictionsChangedSemahore.release();
-            }
-        }
-    };
-
-    private final Semaphore mOnAppRestrictionsChangedSemahore = new Semaphore(0);
-    private final Semaphore mOnRestrictionsReceivedFromAppSemaphore = new Semaphore(0);
-    private Bundle mReceivedRestrictions;
-    private UserManager mUserManager;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(ACTION_RESTRICTIONS_VALUE);
-        filter.addAction(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);
-        mContext.registerReceiver(mReceiver, filter);
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        mContext.unregisterReceiver(mReceiver);
-
-        mDevicePolicyManager.setApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG, new Bundle());
-        mDevicePolicyManager.setApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, OTHER_PACKAGE, new Bundle());
-        mDevicePolicyManager.setApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, mContext.getPackageName(), new Bundle());
-
-        super.tearDown();
-    }
-
-    public void testNullComponentThrowsException() {
-        try {
-            mDevicePolicyManager.setApplicationRestrictions(
-                    null, APP_RESTRICTIONS_TARGET_PKG, null);
-            fail("Expected SecurityException not thrown");
-        } catch (SecurityException expected) {
-            MoreAsserts.assertContainsRegex(
-                    "Calling identity is not authorized",
-                    expected.getMessage());
-        }
-        try {
-            mDevicePolicyManager.getApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG);
-            fail("Expected SecurityException not thrown");
-        } catch (SecurityException expected) {
-            MoreAsserts.assertContainsRegex(
-                    "Calling identity is not authorized",
-                    expected.getMessage());
-        }
-    }
-
-    public void testSetApplicationRestrictions() {
-        // Test setting restrictions
-        mDevicePolicyManager.setApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG, BUNDLE_0);
-        mDevicePolicyManager.setApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, OTHER_PACKAGE, BUNDLE_1);
-
-        // Retrieve restrictions locally and make sure they are what we put in.
-        assertBundle0(mDevicePolicyManager.getApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG));
-        assertBundle1(mDevicePolicyManager.getApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, OTHER_PACKAGE));
-
-        // Check that the target app can retrieve the same restrictions.
-        assertBundle0(waitForRestrictionsValueFromTestActivity());
-
-        // Test overwriting
-        mDevicePolicyManager.setApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG, BUNDLE_1);
-        assertBundle1(mDevicePolicyManager.getApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG));
-        assertBundle1(waitForRestrictionsValueFromTestActivity());
-
-        mDevicePolicyManager.setApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG, new Bundle());
-        assertTrue(mDevicePolicyManager.getApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG).isEmpty());
-        assertTrue(waitForRestrictionsValueFromTestActivity().isEmpty());
-
-        mDevicePolicyManager.setApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, OTHER_PACKAGE, null);
-        assertTrue(mDevicePolicyManager.getApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, OTHER_PACKAGE).isEmpty());
-    }
-
-    public void testCanRetrieveOwnRestrictionsViaUserManager() {
-        final String packageName = mContext.getPackageName();
-
-        mDevicePolicyManager.setApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, packageName, BUNDLE_0);
-        assertBundle0(mDevicePolicyManager.getApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, packageName));
-
-        // Check that we got the restrictions changed callback.
-        assertBundle0(waitForRestrictionsChangedBroadcast());
-
-        mDevicePolicyManager.setApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, packageName, BUNDLE_1);
-        assertBundle1(mDevicePolicyManager.getApplicationRestrictions(
-                ADMIN_RECEIVER_COMPONENT, packageName));
-        assertBundle1(waitForRestrictionsChangedBroadcast());
-    }
-
-    public void testCannotRetrieveOtherPackageRestrictionsViaUserManager() {
-        try {
-            mUserManager.getApplicationRestrictions(OTHER_PACKAGE);
-            fail("Expected SecurityException not thrown");
-        } catch (SecurityException expected) {
-        }
-    }
-
-    public void testSetApplicationRestrictionsManagingPackage() throws NameNotFoundException {
-        final String previousValue = mDevicePolicyManager.getApplicationRestrictionsManagingPackage(
-                ADMIN_RECEIVER_COMPONENT);
-        try {
-            mDevicePolicyManager.setApplicationRestrictionsManagingPackage(
-                    ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG);
-            assertEquals(APP_RESTRICTIONS_TARGET_PKG,
-                    mDevicePolicyManager.getApplicationRestrictionsManagingPackage(
-                            ADMIN_RECEIVER_COMPONENT));
-            mDevicePolicyManager.setApplicationRestrictionsManagingPackage(
-                    ADMIN_RECEIVER_COMPONENT, null);
-            assertNull(mDevicePolicyManager.getApplicationRestrictionsManagingPackage(
-                    ADMIN_RECEIVER_COMPONENT));
-        } finally {
-            mDevicePolicyManager.setApplicationRestrictionsManagingPackage(
-                    ADMIN_RECEIVER_COMPONENT, previousValue);
-            assertEquals(previousValue,
-                    mDevicePolicyManager.getApplicationRestrictionsManagingPackage(
-                            ADMIN_RECEIVER_COMPONENT));
-        }
-    }
-
-    public void testSetApplicationRestrictionsManagingPackageForNotInstalledPackage()
-            throws NameNotFoundException {
-        try {
-            mDevicePolicyManager.setApplicationRestrictionsManagingPackage(ADMIN_RECEIVER_COMPONENT,
-                    OTHER_PACKAGE);
-            fail("Not throwing exception for not installed package name");
-        } catch (NameNotFoundException expected) {
-            MoreAsserts.assertContainsRegex(OTHER_PACKAGE, expected.getMessage());
-        } finally {
-            mDevicePolicyManager.setApplicationRestrictionsManagingPackage(ADMIN_RECEIVER_COMPONENT,
-                    null);
-            assertNull(mDevicePolicyManager.getApplicationRestrictionsManagingPackage(
-                    ADMIN_RECEIVER_COMPONENT));
-        }
-    }
-
-    // Should be consistent with assertBundle0
-    private static Bundle createBundle0() {
-        Bundle result = new Bundle();
-        // Tests for 6 allowed types: Integer, Boolean, String, String[], Bundle and Parcelable[]
-        // Also test for string escaping handling
-        result.putBoolean("boolean_0", false);
-        result.putBoolean("boolean_1", true);
-        result.putInt("integer", 0x7fffffff);
-        // If a null is stored, "" will be read back
-        result.putString("empty", "");
-        result.putString("string", "text");
-        result.putStringArray("string[]", TEST_STRINGS);
-
-        // Adding a bundle, which contain 2 nested restrictions - bundle_string and bundle_int
-        Bundle bundle = new Bundle();
-        bundle.putString("bundle_string", "bundle_string");
-        bundle.putInt("bundle_int", 1);
-        result.putBundle("bundle", bundle);
-
-        // Adding an array of 2 bundles
-        Bundle[] bundleArray = new Bundle[2];
-        bundleArray[0] = new Bundle();
-        bundleArray[0].putString("bundle_array_string", "bundle_array_string");
-        // Put bundle inside bundle
-        bundleArray[0].putBundle("bundle_array_bundle", bundle);
-        bundleArray[1] = new Bundle();
-        bundleArray[1].putString("bundle_array_string2", "bundle_array_string2");
-        result.putParcelableArray("bundle_array", bundleArray);
-        return result;
-    }
-
-    // Should be consistent with createBundle0
-    private void assertBundle0(Bundle bundle) {
-        assertEquals(8, bundle.size());
-        assertEquals(false, bundle.getBoolean("boolean_0"));
-        assertEquals(true, bundle.getBoolean("boolean_1"));
-        assertEquals(0x7fffffff, bundle.getInt("integer"));
-        assertEquals("", bundle.getString("empty"));
-        assertEquals("text", bundle.getString("string"));
-
-        String[] strings = bundle.getStringArray("string[]");
-        assertTrue(strings != null && strings.length == TEST_STRINGS.length);
-        for (int i = 0; i < strings.length; i++) {
-            assertEquals(strings[i], TEST_STRINGS[i]);
-        }
-
-        Bundle childBundle = bundle.getBundle("bundle");
-        assertEquals("bundle_string", childBundle.getString("bundle_string"));
-        assertEquals(1, childBundle.getInt("bundle_int"));
-
-        Parcelable[] bundleArray = bundle.getParcelableArray("bundle_array");
-        assertEquals(2, bundleArray.length);
-        // Verifying bundle_array[0]
-        Bundle bundle1 = (Bundle) bundleArray[0];
-        assertEquals("bundle_array_string", bundle1.getString("bundle_array_string"));
-        Bundle bundle1ChildBundle = bundle1.getBundle("bundle_array_bundle");
-        assertNotNull(bundle1ChildBundle);
-        assertEquals("bundle_string", bundle1ChildBundle.getString("bundle_string"));
-        assertEquals(1, bundle1ChildBundle.getInt("bundle_int"));
-        // Verifying bundle_array[1]
-        Bundle bundle2 = (Bundle) bundleArray[1];
-        assertEquals("bundle_array_string2", bundle2.getString("bundle_array_string2"));
-    }
-
-    // Should be consistent with assertBundle1
-    private static Bundle createBundle1() {
-        Bundle result = new Bundle();
-        result.putInt("placeholder", 1);
-        return result;
-    }
-
-    // Should be consistent with createBundle1
-    private void assertBundle1(Bundle bundle) {
-        assertEquals(1, bundle.size());
-        assertEquals(1, bundle.getInt("placeholder"));
-    }
-
-    private void startTestActivity() {
-        mContext.startActivity(new Intent()
-                .setComponent(new ComponentName(
-                        APP_RESTRICTIONS_TARGET_PKG, APP_RESTRICTIONS_ACTIVITY_NAME))
-                .putExtra("admin_type",
-                        InstrumentationRegistry.getArguments().getString("admin_type"))
-                .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK));
-    }
-
-    private Bundle waitForRestrictionsValueFromTestActivity() {
-        startTestActivity();
-
-        try {
-            assertTrue(mOnRestrictionsReceivedFromAppSemaphore.tryAcquire(
-                    RESTRICTIONS_TIMEOUT_SECONDS, TimeUnit.SECONDS));
-        } catch (InterruptedException e) {
-            fail("waitForRestrictionsValueFromTestActivity() interrupted");
-        }
-
-        return mReceivedRestrictions;
-    }
-
-    private Bundle waitForRestrictionsChangedBroadcast() {
-        try {
-            assertTrue(mOnAppRestrictionsChangedSemahore.tryAcquire(
-                    RESTRICTIONS_TIMEOUT_SECONDS, TimeUnit.SECONDS));
-        } catch (InterruptedException e) {
-            fail("waitForRestrictionsChangedBroadcast() interrupted");
-        }
-
-        return mUserManager.getApplicationRestrictions(mContext.getPackageName());
-    }
-}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index e228828..bd1cb47 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -234,53 +234,6 @@
             "testAssertCallerIsApplicationRestrictionsManagingPackage", mUserId);
     }
 
-    @Test
-    public void testApplicationRestrictions() throws Exception {
-        installAppAsUser(DELEGATE_APP_APK, mUserId);
-        installAppAsUser(APP_RESTRICTIONS_TARGET_APP_APK, mUserId);
-
-        try {
-            // Only the DPC can manage app restrictions by default.
-            executeDeviceTestClass(".ApplicationRestrictionsTest");
-            executeAppRestrictionsManagingPackageTest("testCannotAccessApis");
-
-            // Letting the DELEGATE_APP_PKG manage app restrictions too.
-            changeApplicationRestrictionsManagingPackage(DELEGATE_APP_PKG);
-            executeAppRestrictionsManagingPackageTest("testCanAccessApis");
-            runDeviceTestsAsUser(DELEGATE_APP_PKG, ".GeneralDelegateTest",
-                    "testSettingAdminComponentNameThrowsException", mUserId);
-
-            // The DPC should still be able to manage app restrictions normally.
-            executeDeviceTestClass(".ApplicationRestrictionsTest");
-
-            // The app shouldn't be able to manage app restrictions for other users.
-            int parentUserId = getPrimaryUser();
-            if (parentUserId != mUserId) {
-                installAppAsUser(DELEGATE_APP_APK, parentUserId);
-                installAppAsUser(APP_RESTRICTIONS_TARGET_APP_APK, parentUserId);
-                runDeviceTestsAsUser(DELEGATE_APP_PKG, ".AppRestrictionsDelegateTest",
-                        "testCannotAccessApis", parentUserId);
-            }
-
-            // Revoking the permission for DELEGATE_APP_PKG to manage restrictions.
-            changeApplicationRestrictionsManagingPackage(null);
-            executeAppRestrictionsManagingPackageTest("testCannotAccessApis");
-
-            // The DPC should still be able to manage app restrictions normally.
-            executeDeviceTestClass(".ApplicationRestrictionsTest");
-
-            assertMetricsLogged(getDevice(), () -> {
-                executeDeviceTestMethod(".ApplicationRestrictionsTest",
-                        "testSetApplicationRestrictions");
-            }, new DevicePolicyEventWrapper.Builder(EventId.SET_APPLICATION_RESTRICTIONS_VALUE)
-                    .setAdminPackageName(DEVICE_ADMIN_PKG)
-                    .setStrings(APP_RESTRICTIONS_TARGET_APP_PKG)
-                    .build());
-        } finally {
-            changeApplicationRestrictionsManagingPackage(null);
-        }
-    }
-
     /**
      * Returns a list of delegation tests that should run. Add delegations tests applicable to both
      * device owner and profile owners to this method directly. DO or PO specific tests should be
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java
index 6d21042..75af1c8 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java
@@ -142,14 +142,6 @@
 
     @Override
     @Test
-    @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "189268544",
-            reason = "Will be migrated to new test infra")
-    public void testApplicationRestrictions() throws Exception {
-        super.testApplicationRestrictions();
-    }
-
-    @Override
-    @Test
     @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "197909577",
             reason = "Will be migrated to new test infra")
     public void testAccountManagement_userRestrictionAddAccount() throws Exception {
diff --git a/hostsidetests/packagemanager/domainverification/device/multiuser/src/com/android/cts/packagemanager/verify/domain/device/multiuser/DomainVerificationWorkUtils.kt b/hostsidetests/packagemanager/domainverification/device/multiuser/src/com/android/cts/packagemanager/verify/domain/device/multiuser/DomainVerificationWorkUtils.kt
index 3038849..955a078 100644
--- a/hostsidetests/packagemanager/domainverification/device/multiuser/src/com/android/cts/packagemanager/verify/domain/device/multiuser/DomainVerificationWorkUtils.kt
+++ b/hostsidetests/packagemanager/domainverification/device/multiuser/src/com/android/cts/packagemanager/verify/domain/device/multiuser/DomainVerificationWorkUtils.kt
@@ -38,7 +38,7 @@
 
 internal fun DeviceState.getWorkDevicePolicyManager() =
     profileOwner(workProfile(DeviceState.UserType.PRIMARY_USER))!!
-            .app().devicePolicyManager()
+            .devicePolicyManager()
 
 internal fun <T> withUserContext(user: UserReference, block: (context: Context) -> T) =
     TestApis.permissions()
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/AccountManagementTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/AccountManagementTest.java
index 3ed02e8..b567e77 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/AccountManagementTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/AccountManagementTest.java
@@ -42,7 +42,7 @@
 import com.android.bedstead.harrier.policies.AccountManagement;
 import com.android.bedstead.nene.TestApis;
 import com.android.bedstead.nene.utils.Poll;
-import com.android.bedstead.remotedpc.RemoteDpc;
+import com.android.bedstead.remotedpc.RemotePolicyManager;
 import com.android.bedstead.testapp.TestApp;
 import com.android.bedstead.testapp.TestAppInstance;
 import com.android.bedstead.testapp.TestAppProvider;
@@ -85,8 +85,8 @@
 
     @Before
     public void setUp() {
-        RemoteDpc dpc = sDeviceState.dpc();
-        mAdmin = dpc.devicePolicyController().componentName();
+        RemotePolicyManager dpc = sDeviceState.dpc();
+        mAdmin = dpc.componentName();
         mDpm = dpc.devicePolicyManager();
         mAccountManager = sContext.getSystemService(AccountManager.class);
     }
@@ -100,7 +100,8 @@
 
     @Test
     @Postsubmit(reason = "new test")
-    @CannotSetPolicyTest(policy = AccountManagement.class)
+    // We don't include non device admin states as passing a null admin is a NullPointerException
+    @CannotSetPolicyTest(policy = AccountManagement.class, includeNonDeviceAdminStates = false)
     public void setAccountTypesWithManagementDisabled_invalidAdmin_throwsException() {
         assertThrows(OperationCanceledException.class, () ->
                 mDpm.setAccountManagementDisabled(
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/ApplicationRestrictionsTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/ApplicationRestrictionsTest.java
index da08a5c..0c054e3 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/ApplicationRestrictionsTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/ApplicationRestrictionsTest.java
@@ -15,12 +15,21 @@
  */
 package android.devicepolicy.cts;
 
+import static android.content.Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED;
+
+import static com.android.bedstead.metricsrecorder.truth.MetricQueryBuilderSubject.assertThat;
+import static com.android.eventlib.truth.EventLogsSubject.assertThat;
+
+import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.testng.Assert.assertThrows;
 
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.os.Parcelable;
+import android.stats.devicepolicy.EventId;
 import android.util.Log;
 
 import com.android.bedstead.harrier.BedsteadJUnit4;
@@ -31,6 +40,8 @@
 import com.android.bedstead.harrier.annotations.enterprise.NegativePolicyTest;
 import com.android.bedstead.harrier.annotations.enterprise.PositivePolicyTest;
 import com.android.bedstead.harrier.policies.ApplicationRestrictions;
+import com.android.bedstead.harrier.policies.ApplicationRestrictionsManagingPackage;
+import com.android.bedstead.metricsrecorder.EnterpriseMetricsRecorder;
 import com.android.bedstead.testapp.TestApp;
 import com.android.bedstead.testapp.TestAppInstance;
 import com.android.bedstead.testapp.TestAppProvider;
@@ -45,170 +56,32 @@
 @RunWith(BedsteadJUnit4.class)
 public final class ApplicationRestrictionsTest {
 
+    @ClassRule
+    @Rule
+    public static final DeviceState sDeviceState = new DeviceState();
     private static final String TAG = ApplicationRestrictionsTest.class.getSimpleName();
-
-    private static final String[] TEST_STRINGS = new String[] {
+    private static final String[] TEST_STRINGS = new String[]{
             "<bad/>",
             ">worse!\"£$%^&*()'<",
             "<JSON>\"{ \\\"One\\\": { \\\"OneOne\\\": \\\"11\\\", \\\""
                     + "OneTwo\\\": \\\"12\\\" }, \\\"Two\\\": \\\"2\\\" } <JSON/>\""
     };
-
-    private static final Bundle BUNDLE = createBundle();
-
-    @ClassRule
-    @Rule
-    public static final DeviceState sDeviceState = new DeviceState();
-
     private static final TestAppProvider sTestAppProvider = new TestAppProvider();
 
     private static final TestApp sTestApp = sTestAppProvider.any();
     private static final TestApp sDifferentTestApp = sTestAppProvider.any();
 
-    @Test
-    @Postsubmit(reason = "New test")
-    @PositivePolicyTest(policy = ApplicationRestrictions.class)
-    public void setApplicationRestrictions_applicationRestrictionsAreSet() {
-        Bundle originalApplicationRestrictions =
-                sDeviceState.dpc().devicePolicyManager()
-                        .getApplicationRestrictions(
-                                sDeviceState.dpc().componentName(), sTestApp.packageName());
-
-        try (TestAppInstance testApp = sTestApp.install()) {
-            sDeviceState.dpc().devicePolicyManager()
-                    .setApplicationRestrictions(
-                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
-                            BUNDLE);
-
-            assertEqualToBundle(
-                    testApp.userManager().getApplicationRestrictions(sTestApp.packageName()));
-        } finally {
-            sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
-                    sDeviceState.dpc().componentName(),
-                    sTestApp.packageName(), originalApplicationRestrictions);
-        }
-    }
-
-    @Test
-    @Postsubmit(reason = "New test")
-    @CanSetPolicyTest(policy = ApplicationRestrictions.class)
-    public void getApplicationRestrictions_applicationRestrictionsAreSet_returnsApplicationRestrictions() {
-        Bundle originalApplicationRestrictions =
-                sDeviceState.dpc().devicePolicyManager()
-                        .getApplicationRestrictions(
-                                sDeviceState.dpc().componentName(), sTestApp.packageName());
-
-        try {
-            sDeviceState.dpc().devicePolicyManager()
-                    .setApplicationRestrictions(
-                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
-                            BUNDLE);
-
-            assertEqualToBundle(
-                    sDeviceState.dpc().devicePolicyManager().getApplicationRestrictions(
-                            sDeviceState.dpc().componentName(), sTestApp.packageName()));
-        } finally {
-            sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
-                    sDeviceState.dpc().componentName(),
-                    sTestApp.packageName(), originalApplicationRestrictions);
-        }
-    }
-
-    @Test
-    @Postsubmit(reason = "New test")
-    @CanSetPolicyTest(policy = ApplicationRestrictions.class)
-    public void getApplicationRestrictions_differentPackage_throwsException() {
-        Bundle originalApplicationRestrictions =
-                sDeviceState.dpc().devicePolicyManager()
-                        .getApplicationRestrictions(
-                                sDeviceState.dpc().componentName(), sTestApp.packageName());
-
-        try (TestAppInstance differentTestApp = sDifferentTestApp.install()) {
-            sDeviceState.dpc().devicePolicyManager()
-                    .setApplicationRestrictions(
-                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
-                            BUNDLE);
-
-            assertThrows(SecurityException.class,
-                    () -> differentTestApp.userManager().getApplicationRestrictions(
-                            sTestApp.packageName()));
-        } finally {
-            sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
-                    sDeviceState.dpc().componentName(),
-                    sTestApp.packageName(), originalApplicationRestrictions);
-        }
-    }
-
-    @Test
-    @Postsubmit(reason = "New test")
-    @CanSetPolicyTest(policy = ApplicationRestrictions.class)
-    public void getApplicationRestrictions_setForOtherPackage_returnsNull() {
-        Bundle originalApplicationRestrictions =
-                sDeviceState.dpc().devicePolicyManager()
-                        .getApplicationRestrictions(
-                                sDeviceState.dpc().componentName(), sTestApp.packageName());
-
-        try (TestAppInstance differentTestApp = sDifferentTestApp.install()) {
-            sDeviceState.dpc().devicePolicyManager()
-                    .setApplicationRestrictions(
-                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
-                            BUNDLE);
-
-            assertNotEqualToBundle(differentTestApp.userManager().getApplicationRestrictions(
-                            sDifferentTestApp.packageName()));
-        } finally {
-            sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
-                    sDeviceState.dpc().componentName(),
-                    sTestApp.packageName(), originalApplicationRestrictions);
-        }
-    }
-
-    @Test
-    @Postsubmit(reason = "New test")
-    @NegativePolicyTest(policy = ApplicationRestrictions.class)
-    public void setApplicationRestrictions_policyDoesNotApply_applicationRestrictionsAreNotSet() {
-        Bundle originalApplicationRestrictions =
-                sDeviceState.dpc().devicePolicyManager().getApplicationRestrictions(
-                        sDeviceState.dpc().componentName(), sTestApp.packageName());
-
-        try (TestAppInstance testApp = sTestApp.install()) {
-            sDeviceState.dpc().devicePolicyManager()
-                    .setApplicationRestrictions(
-                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
-                            BUNDLE);
-
-            assertNotEqualToBundle(testApp.userManager().getApplicationRestrictions(
-                    sTestApp.packageName()));
-        } finally {
-            sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
-                    sDeviceState.dpc().componentName(),
-                    sTestApp.packageName(), originalApplicationRestrictions);
-        }
-    }
-
-    @Test
-    @Postsubmit(reason = "New test")
-    @CannotSetPolicyTest(policy = ApplicationRestrictions.class)
-    public void setApplicationRestrictions_cannotSetPolicy_throwsException() {
-        assertThrows(SecurityException.class, () -> {
-            sDeviceState.dpc().devicePolicyManager()
-                    .setApplicationRestrictions(
-                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
-                            BUNDLE);
-        });
-    }
-
-    // Should be consistent with assertBundle0
-    private static Bundle createBundle() {
+    // Should be consistent with assertEqualToBundle
+    private static Bundle createBundle(String id) {
         Bundle result = new Bundle();
         // Tests for 6 allowed types: Integer, Boolean, String, String[], Bundle and Parcelable[]
         // Also test for string escaping handling
         result.putBoolean("boolean_0", false);
         result.putBoolean("boolean_1", true);
-        result.putInt("integer", 0x7fffffff);
+        result.putInt("integer", 0xfffff);
         // If a null is stored, "" will be read back
         result.putString("empty", "");
-        result.putString("string", "text");
+        result.putString("string", id);
         result.putStringArray("string[]", TEST_STRINGS);
 
         // Adding a bundle, which contain 2 nested restrictions - bundle_string and bundle_int
@@ -229,15 +102,298 @@
         return result;
     }
 
-    // Should be consistent with createBundle0
-    private void assertEqualToBundle(Bundle bundle) {
+    @Test
+    @Postsubmit(reason = "New test")
+    @PositivePolicyTest(policy = ApplicationRestrictions.class)
+    public void setApplicationRestrictions_applicationRestrictionsAreSet() {
+        Bundle originalApplicationRestrictions =
+                sDeviceState.dpc().devicePolicyManager()
+                        .getApplicationRestrictions(
+                                sDeviceState.dpc().componentName(), sTestApp.packageName());
+        Bundle bundle = createBundle("setApplicationRestrictions_applicationRestrictionsAreSet");
+
+        try (TestAppInstance testApp = sTestApp.install()) {
+            sDeviceState.dpc().devicePolicyManager()
+                    .setApplicationRestrictions(
+                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
+                            bundle);
+
+            assertEqualToBundle("setApplicationRestrictions_applicationRestrictionsAreSet",
+                    testApp.userManager().getApplicationRestrictions(sTestApp.packageName()));
+        } finally {
+            sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+                    sDeviceState.dpc().componentName(),
+                    sTestApp.packageName(), originalApplicationRestrictions);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "New test")
+    @PositivePolicyTest(policy = ApplicationRestrictions.class)
+    public void setApplicationRestrictions_applicationRestrictionsAlreadySet_setsNewRestrictions() {
+        Bundle originalApplicationRestrictions =
+                sDeviceState.dpc().devicePolicyManager()
+                        .getApplicationRestrictions(
+                                sDeviceState.dpc().componentName(), sTestApp.packageName());
+        Bundle bundle = createBundle("setApplicationRestrictions_applicationRestrictionsAlreadySet_setsNewRestrictions");
+
+        try (TestAppInstance testApp = sTestApp.install()) {
+            sDeviceState.dpc().devicePolicyManager()
+                    .setApplicationRestrictions(
+                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
+                            new Bundle());
+            sDeviceState.dpc().devicePolicyManager()
+                    .setApplicationRestrictions(
+                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
+                            bundle);
+
+            assertEqualToBundle("setApplicationRestrictions_applicationRestrictionsAlreadySet_setsNewRestrictions",
+                    testApp.userManager().getApplicationRestrictions(sTestApp.packageName()));
+        } finally {
+            sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+                    sDeviceState.dpc().componentName(),
+                    sTestApp.packageName(), originalApplicationRestrictions);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "New test")
+    @CanSetPolicyTest(policy = ApplicationRestrictions.class)
+    public void getApplicationRestrictions_applicationRestrictionsAreSet_returnsApplicationRestrictions() {
+        Bundle originalApplicationRestrictions =
+                sDeviceState.dpc().devicePolicyManager()
+                        .getApplicationRestrictions(
+                                sDeviceState.dpc().componentName(), sTestApp.packageName());
+        Bundle bundle = createBundle("getApplicationRestrictions_applicationRestrictionsAreSet_returnsApplicationRestrictions");
+
+        try {
+            sDeviceState.dpc().devicePolicyManager()
+                    .setApplicationRestrictions(
+                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
+                            bundle);
+
+            assertEqualToBundle("getApplicationRestrictions_applicationRestrictionsAreSet_returnsApplicationRestrictions",
+                    sDeviceState.dpc().devicePolicyManager().getApplicationRestrictions(
+                            sDeviceState.dpc().componentName(), sTestApp.packageName()));
+        } finally {
+            sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+                    sDeviceState.dpc().componentName(),
+                    sTestApp.packageName(), originalApplicationRestrictions);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "New test")
+    @CanSetPolicyTest(policy = ApplicationRestrictions.class)
+    public void getApplicationRestrictions_differentPackage_throwsException() {
+        Bundle originalApplicationRestrictions =
+                sDeviceState.dpc().devicePolicyManager()
+                        .getApplicationRestrictions(
+                                sDeviceState.dpc().componentName(), sTestApp.packageName());
+        Bundle bundle = createBundle("getApplicationRestrictions_differentPackage_throwsException");
+
+        try (TestAppInstance differentTestApp = sDifferentTestApp.install()) {
+            sDeviceState.dpc().devicePolicyManager()
+                    .setApplicationRestrictions(
+                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
+                            bundle);
+
+            assertThrows(SecurityException.class,
+                    () -> differentTestApp.userManager().getApplicationRestrictions(
+                            sTestApp.packageName()));
+        } finally {
+            sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+                    sDeviceState.dpc().componentName(),
+                    sTestApp.packageName(), originalApplicationRestrictions);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "New test")
+    @CanSetPolicyTest(policy = ApplicationRestrictions.class)
+    public void getApplicationRestrictions_setForOtherPackage_returnsNull() {
+        Bundle originalApplicationRestrictions =
+                sDeviceState.dpc().devicePolicyManager()
+                        .getApplicationRestrictions(
+                                sDeviceState.dpc().componentName(), sTestApp.packageName());
+        Bundle bundle = createBundle("getApplicationRestrictions_setForOtherPackage_returnsNull");
+
+        try (TestAppInstance differentTestApp = sDifferentTestApp.install()) {
+            sDeviceState.dpc().devicePolicyManager()
+                    .setApplicationRestrictions(
+                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
+                            bundle);
+
+            assertNotEqualToBundle("getApplicationRestrictions_setForOtherPackage_returnsNull",
+                    differentTestApp.userManager().getApplicationRestrictions(
+                    sDifferentTestApp.packageName()));
+        } finally {
+            sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+                    sDeviceState.dpc().componentName(),
+                    sTestApp.packageName(), originalApplicationRestrictions);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "New test")
+    @NegativePolicyTest(policy = ApplicationRestrictions.class)
+    public void setApplicationRestrictions_policyDoesNotApply_applicationRestrictionsAreNotSet() {
+        Bundle originalApplicationRestrictions =
+                sDeviceState.dpc().devicePolicyManager().getApplicationRestrictions(
+                        sDeviceState.dpc().componentName(), sTestApp.packageName());
+        Bundle bundle = createBundle("setApplicationRestrictions_policyDoesNotApply_applicationRestrictionsAreNotSet");
+
+        try (TestAppInstance testApp = sTestApp.install()) {
+            sDeviceState.dpc().devicePolicyManager()
+                    .setApplicationRestrictions(
+                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
+                            bundle);
+
+            assertNotEqualToBundle("setApplicationRestrictions_policyDoesNotApply_applicationRestrictionsAreNotSet",
+                    testApp.userManager().getApplicationRestrictions(sTestApp.packageName()));
+        } finally {
+            sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+                    sDeviceState.dpc().componentName(),
+                    sTestApp.packageName(), originalApplicationRestrictions);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "New test")
+    @CannotSetPolicyTest(policy = ApplicationRestrictions.class)
+    public void setApplicationRestrictions_cannotSetPolicy_throwsException() {
+        Bundle bundle = createBundle("setApplicationRestrictions_cannotSetPolicy_throwsException");
+        assertThrows(SecurityException.class, () -> {
+            sDeviceState.dpc().devicePolicyManager()
+                    .setApplicationRestrictions(
+                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
+                            bundle);
+        });
+    }
+
+    @Test
+    @Postsubmit(reason = "New test")
+    @CannotSetPolicyTest(policy = ApplicationRestrictions.class)
+    public void getApplicationRestrictions_cannotSetPolicy_throwsException() {
+        assertThrows(SecurityException.class, () -> {
+            sDeviceState.dpc().devicePolicyManager()
+                    .getApplicationRestrictions(
+                            sDeviceState.dpc().componentName(), sTestApp.packageName());
+        });
+    }
+
+    @Test
+    @Postsubmit(reason = "New test")
+    @CanSetPolicyTest(policy = ApplicationRestrictions.class, singleTestOnly = true)
+    public void setApplicationRestrictions_nullComponent_throwsException() {
+        Bundle bundle = createBundle("setApplicationRestrictions_nullComponent_throwsException");
+        assertThrows(SecurityException.class,
+                () -> sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(null,
+                        sTestApp.packageName(), bundle));
+    }
+
+    @Test
+    @Postsubmit(reason = "New test")
+    @PositivePolicyTest(policy = ApplicationRestrictions.class)
+    public void setApplicationRestrictions_restrictionsChangedBroadcastIsReceived() {
+        Bundle originalApplicationRestrictions =
+                sDeviceState.dpc().devicePolicyManager()
+                        .getApplicationRestrictions(
+                                sDeviceState.dpc().componentName(), sTestApp.packageName());
+        Bundle bundle = createBundle("setApplicationRestrictions_restrictionsChangedBroadcastIsReceived");
+
+        try (TestAppInstance testApp = sTestApp.install()) {
+            testApp.registerReceiver(new IntentFilter(ACTION_APPLICATION_RESTRICTIONS_CHANGED));
+
+            sDeviceState.dpc().devicePolicyManager()
+                    .setApplicationRestrictions(
+                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
+                            bundle);
+
+            assertThat(testApp.events().broadcastReceived().whereIntent().action().isEqualTo(
+                    ACTION_APPLICATION_RESTRICTIONS_CHANGED)).eventOccurred();
+        } finally {
+            sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+                    sDeviceState.dpc().componentName(),
+                    sTestApp.packageName(), originalApplicationRestrictions);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "New test")
+    @CanSetPolicyTest(policy = ApplicationRestrictionsManagingPackage.class)
+    public void setApplicationRestrictionsManagingPackage_applicationRestrictionsManagingPackageIsSet()
+            throws Exception {
+        final String originalApplicationRestrictionsManagingPackage =
+                sDeviceState.dpc().devicePolicyManager().getApplicationRestrictionsManagingPackage(
+                        sDeviceState.dpc().componentName());
+        try (TestAppInstance testApp = sTestApp.install()) {
+            sDeviceState.dpc().devicePolicyManager().setApplicationRestrictionsManagingPackage(
+                    sDeviceState.dpc().componentName(), sTestApp.packageName());
+
+            assertThat(sDeviceState.dpc().devicePolicyManager()
+                    .getApplicationRestrictionsManagingPackage(sDeviceState.dpc().componentName()))
+                    .isEqualTo(sTestApp.packageName());
+        } finally {
+            sDeviceState.dpc().devicePolicyManager().setApplicationRestrictionsManagingPackage(
+                    sDeviceState.dpc().componentName(),
+                    originalApplicationRestrictionsManagingPackage);
+        }
+    }
+
+    @Test
+    @Postsubmit(reason = "New test")
+    @CanSetPolicyTest(policy = ApplicationRestrictionsManagingPackage.class)
+    public void setApplicationRestrictionsManagingPackage_appNotInstalled_throwsException() {
+        sDifferentTestApp.uninstall();
+
+        assertThrows(PackageManager.NameNotFoundException.class,
+                () -> sDeviceState.dpc().devicePolicyManager()
+                        .setApplicationRestrictionsManagingPackage(
+                                sDeviceState.dpc().componentName(),
+                                sDifferentTestApp.packageName()));
+    }
+
+    @Test
+    @Postsubmit(reason = "New test")
+    @PositivePolicyTest(policy = ApplicationRestrictions.class)
+    public void setApplicationRestrictions_logged() {
+        Bundle originalApplicationRestrictions =
+                sDeviceState.dpc().devicePolicyManager()
+                        .getApplicationRestrictions(
+                                sDeviceState.dpc().componentName(), sTestApp.packageName());
+        Bundle bundle = createBundle("setApplicationRestrictions_logged");
+
+        try (EnterpriseMetricsRecorder metrics = EnterpriseMetricsRecorder.create();
+             TestAppInstance testApp = sTestApp.install()) {
+            sDeviceState.dpc().devicePolicyManager()
+                    .setApplicationRestrictions(
+                            sDeviceState.dpc().componentName(), sTestApp.packageName(),
+                            bundle);
+
+            assertThat(metrics.query()
+                    .whereType().isEqualTo(EventId.SET_APPLICATION_RESTRICTIONS_VALUE)
+                    .whereAdminPackageName().isEqualTo(
+                            sDeviceState.dpc().packageName())
+                    .whereStrings().contains(sTestApp.packageName())
+                    .whereStrings().size().isEqualTo(1))
+                    .wasLogged();
+        } finally {
+            sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+                    sDeviceState.dpc().componentName(),
+                    sTestApp.packageName(), originalApplicationRestrictions);
+        }
+    }
+
+    // Should be consistent with createBundle
+    private void assertEqualToBundle(String id, Bundle bundle) {
         assertWithMessage("bundle0 size")
                 .that(bundle.size()).isEqualTo(8);
         assertBooleanKey(bundle, "boolean_0", false);
         assertBooleanKey(bundle, "boolean_1", true);
-        assertIntKey(bundle, "integer", 0x7fffffff);
+        assertIntKey(bundle, "integer", 0xfffff);
         assertStringKey(bundle, "empty", "");
-        assertStringKey(bundle, "string", "text");
+        assertStringKey(bundle, "string", id);
         assertStringsKey(bundle, "string[]", TEST_STRINGS);
 
         Bundle childBundle = bundle.getBundle("bundle");
@@ -300,9 +456,9 @@
         return value;
     }
 
-    private void assertNotEqualToBundle(Bundle value) {
+    private void assertNotEqualToBundle(String id, Bundle value) {
         // This uses an arbitrary value from the test bundle
         assertWithMessage("Bundle should not be equal to test bundle")
-                .that(value.getInt("integer")).isNotEqualTo(0x7fffffff);
+                .that(value.getString("string")).isNotEqualTo(id);
     }
 }
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/CredentialManagementAppTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/CredentialManagementAppTest.java
index baabdc7..c6f550f 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/CredentialManagementAppTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/CredentialManagementAppTest.java
@@ -42,6 +42,7 @@
 import com.android.bedstead.harrier.BedsteadJUnit4;
 import com.android.bedstead.harrier.DeviceState;
 import com.android.bedstead.harrier.annotations.Postsubmit;
+import com.android.bedstead.harrier.annotations.SlowApiTest;
 import com.android.bedstead.nene.TestApis;
 import com.android.bedstead.nene.permissions.PermissionContext;
 import com.android.compatibility.common.util.BlockingCallback;
@@ -66,6 +67,7 @@
 import java.security.spec.PKCS8EncodedKeySpec;
 import java.util.Arrays;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 @RunWith(BedsteadJUnit4.class)
 public class CredentialManagementAppTest {
@@ -74,6 +76,7 @@
     @Rule
     public static final DeviceState sDeviceState = new DeviceState();
 
+    private static final int KEYCHAIN_CALLBACK_TIMEOUT_SECONDS = 600;
     private static final PrivateKey PRIVATE_KEY =
             getPrivateKey(FakeKeys.FAKE_RSA_1.privateKey, "RSA");
     private static final Certificate CERTIFICATE =
@@ -277,6 +280,8 @@
 
     @Test
     @Postsubmit(reason = "b/181993922 automatically marked flaky")
+    @SlowApiTest(reason = "The KeyChain.choosePrivateKeyAlias API sometimes "
+            + "takes a long time to callback")
     public void choosePrivateKeyAlias_isCredentialManagementApp_aliasSelected() throws Exception {
         setCredentialManagementApp();
 
@@ -291,7 +296,8 @@
                             /* keyTypes= */ null, /* issuers= */ null, URI, /* alias = */ null)
             );
 
-            assertThat(callback.await()).isEqualTo(ALIAS);
+            assertThat(callback.await(KEYCHAIN_CALLBACK_TIMEOUT_SECONDS, TimeUnit.SECONDS))
+                    .isEqualTo(ALIAS);
         } finally {
             // Remove keypair as credential management app
             sDevicePolicyManager.removeKeyPair(/* admin = */ null, ALIAS);
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java
index 473c60e..ddd7eeb 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java
@@ -37,7 +37,7 @@
 import com.android.bedstead.harrier.annotations.enterprise.PositivePolicyTest;
 import com.android.bedstead.harrier.policies.DefaultSmsApplication;
 import com.android.bedstead.nene.TestApis;
-import com.android.bedstead.remotedpc.RemoteDpc;
+import com.android.bedstead.remotedpc.RemotePolicyManager;
 import com.android.bedstead.testapp.TestApp;
 import com.android.bedstead.testapp.TestAppInstance;
 import com.android.bedstead.testapp.TestAppProvider;
@@ -71,8 +71,8 @@
 
     @Before
     public void setUp() {
-        RemoteDpc dpc = sDeviceState.dpc();
-        mAdmin = dpc.devicePolicyController().componentName();
+        RemotePolicyManager dpc = sDeviceState.dpc();
+        mAdmin = dpc.componentName();
         mDpm = dpc.devicePolicyManager();
         mTelephonyManager = sContext.getSystemService(TelephonyManager.class);
     }
@@ -85,9 +85,9 @@
         assumeTrue(mTelephonyManager.isSmsCapable());
         String previousSmsAppName = getDefaultSmsPackage();
         try (TestAppInstance smsApp = sSmsApp.install()) {
-            mDpm.setDefaultSmsApplication(mAdmin, smsApp.testApp().packageName());
+            mDpm.setDefaultSmsApplication(mAdmin, smsApp.packageName());
 
-            assertThat(getDefaultSmsPackage()).isEqualTo(smsApp.testApp().packageName());
+            assertThat(getDefaultSmsPackage()).isEqualTo(smsApp.packageName());
         } finally {
             mDpm.setDefaultSmsApplication(mAdmin, previousSmsAppName);
         }
@@ -101,7 +101,7 @@
         assumeTrue(mTelephonyManager.isSmsCapable());
         String previousSmsAppName = getDefaultSmsPackage();
         try (TestAppInstance smsApp = sSmsApp.install()) {
-            mDpm.setDefaultSmsApplication(mAdmin, smsApp.testApp().packageName());
+            mDpm.setDefaultSmsApplication(mAdmin, smsApp.packageName());
 
             assertThat(getDefaultSmsPackage()).isEqualTo(previousSmsAppName);
         } finally {
@@ -134,7 +134,7 @@
 
             assertThrows(NullPointerException.class, () ->
                     mDpm.setDefaultSmsApplication(
-                            /* admin= */ null, smsApp.testApp().packageName()));
+                            /* admin= */ null, smsApp.packageName()));
         }
     }
 
@@ -146,7 +146,7 @@
         assumeTrue(!mTelephonyManager.isSmsCapable());
         String previousSmsAppName = getDefaultSmsPackage();
         try (TestAppInstance smsApp = sSmsApp.install()) {
-            mDpm.setDefaultSmsApplication(mAdmin, smsApp.testApp().packageName());
+            mDpm.setDefaultSmsApplication(mAdmin, smsApp.packageName());
 
             assertThat(getDefaultSmsPackage()).isEqualTo(previousSmsAppName);
         } finally {
@@ -156,12 +156,13 @@
 
     @Test
     @Postsubmit(reason = "new test")
-    @CannotSetPolicyTest(policy = DefaultSmsApplication.class)
+    // We don't include non device admin states as passing a null admin is a NullPointerException
+    @CannotSetPolicyTest(policy = DefaultSmsApplication.class, includeNonDeviceAdminStates = false)
     public void setDefaultSmsApplication_invalidAdmin_throwsException() {
         try (TestAppInstance smsApp = sSmsApp.install()) {
 
             assertThrows(SecurityException.class, () ->
-                    mDpm.setDefaultSmsApplication(mAdmin, smsApp.testApp().packageName()));
+                    mDpm.setDefaultSmsApplication(mAdmin, smsApp.packageName()));
         }
     }
 
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DeprecatedPasswordAPIsTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DeprecatedPasswordAPIsTest.java
index 2579f14..fa0ebb8 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/DeprecatedPasswordAPIsTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DeprecatedPasswordAPIsTest.java
@@ -32,7 +32,7 @@
 import com.android.bedstead.harrier.annotations.enterprise.PositivePolicyTest;
 import com.android.bedstead.harrier.policies.DeprecatedPasswordAPIs;
 import com.android.bedstead.nene.TestApis;
-import com.android.bedstead.remotedpc.RemoteDpc;
+import com.android.bedstead.remotedpc.RemotePolicyManager;
 
 import org.junit.Before;
 import org.junit.ClassRule;
@@ -57,8 +57,8 @@
 
     @Before
     public void setUp() {
-        RemoteDpc dpc = sDeviceState.dpc();
-        mAdmin = dpc.devicePolicyController().componentName();
+        RemotePolicyManager dpc = sDeviceState.dpc();
+        mAdmin = dpc.componentName();
         mDpm = dpc.devicePolicyManager();
     }
 
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/KeyManagementTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/KeyManagementTest.java
index 0b65080..fbca7dd 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/KeyManagementTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/KeyManagementTest.java
@@ -34,6 +34,7 @@
 import com.android.bedstead.harrier.BedsteadJUnit4;
 import com.android.bedstead.harrier.DeviceState;
 import com.android.bedstead.harrier.annotations.Postsubmit;
+import com.android.bedstead.harrier.annotations.SlowApiTest;
 import com.android.bedstead.harrier.annotations.enterprise.CanSetPolicyTest;
 import com.android.bedstead.harrier.annotations.enterprise.PositivePolicyTest;
 import com.android.bedstead.harrier.policies.KeyManagement;
@@ -62,6 +63,7 @@
 import java.security.spec.InvalidKeySpecException;
 import java.security.spec.PKCS8EncodedKeySpec;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Test that a DPC can manage keys and certificate on a device by installing, generating and
@@ -74,6 +76,7 @@
     @ClassRule
     @Rule
     public static final DeviceState sDeviceState = new DeviceState();
+    private static final int KEYCHAIN_CALLBACK_TIMEOUT_SECONDS = 600;
     private static final String RSA = "RSA";
     private static final String RSA_ALIAS = "com.android.test.valid-rsa-key-1";
     private static final PrivateKey PRIVATE_KEY =
@@ -270,6 +273,8 @@
     @Test
     @Postsubmit(reason = "new test")
     @PositivePolicyTest(policy = KeyManagement.class)
+    @SlowApiTest(reason = "The KeyChain.choosePrivateKeyAlias API sometimes "
+            + "takes a long time to callback")
     public void choosePrivateKeyAlias_aliasIsSelectedByAdmin_returnAlias() throws Exception {
         try {
             // Install keypair
@@ -279,7 +284,8 @@
 
             choosePrivateKeyAlias(callback, RSA_ALIAS);
 
-            assertThat(callback.await()).isEqualTo(RSA_ALIAS);
+            assertThat(callback.await(KEYCHAIN_CALLBACK_TIMEOUT_SECONDS, TimeUnit.SECONDS))
+                    .isEqualTo(RSA_ALIAS);
         } finally {
             // Remove keypair
             sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
@@ -289,6 +295,8 @@
     @Test
     @Postsubmit(reason = "new test")
     @PositivePolicyTest(policy = KeyManagement.class)
+    @SlowApiTest(reason = "The KeyChain.choosePrivateKeyAlias API sometimes "
+            + "takes a long time to callback")
     public void choosePrivateKeyAlias_nonUserSelectedAliasIsSelectedByAdmin_returnAlias()
             throws Exception {
         try {
@@ -299,7 +307,8 @@
 
             choosePrivateKeyAlias(callback, RSA_ALIAS);
 
-            assertThat(callback.await()).isEqualTo(RSA_ALIAS);
+            assertThat(callback.await(KEYCHAIN_CALLBACK_TIMEOUT_SECONDS, TimeUnit.SECONDS))
+                    .isEqualTo(RSA_ALIAS);
         } finally {
             // Remove keypair
             sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
@@ -309,6 +318,8 @@
     @Test
     @Postsubmit(reason = "new test")
     @PositivePolicyTest(policy = KeyManagement.class)
+    @SlowApiTest(reason = "The KeyChain.choosePrivateKeyAlias API sometimes "
+            + "takes a long time to callback")
     public void getPrivateKey_aliasIsGranted_returnPrivateKey() throws Exception {
         try {
             // Install keypair
@@ -317,7 +328,7 @@
             // Grant alias via {@code KeyChain.choosePrivateKeyAlias}
             KeyChainAliasCallback callback = new KeyChainAliasCallback();
             choosePrivateKeyAlias(callback, RSA_ALIAS);
-            callback.await();
+            callback.await(KEYCHAIN_CALLBACK_TIMEOUT_SECONDS, TimeUnit.SECONDS);
 
             // Get private key for the granted alias
             final PrivateKey privateKey =
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/PermissionGrantTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/PermissionGrantTest.java
index a56b9ac..5f4bacb 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/PermissionGrantTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/PermissionGrantTest.java
@@ -34,6 +34,8 @@
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.testng.Assert.assertThrows;
+
 import com.android.bedstead.harrier.BedsteadJUnit4;
 import com.android.bedstead.harrier.DeviceState;
 import com.android.bedstead.harrier.annotations.AfterClass;
@@ -557,7 +559,7 @@
     }
 
     @Test
-    @CannotSetPolicyTest(policy = SetSmsPermissionGranted.class)
+    @CannotSetPolicyTest(policy = SetSmsPermissionGranted.class, includeNonDeviceAdminStates = false)
     public void grantSmsPermission_cannotBeApplied_returnsTrueButDoesNotSetGrantState() {
         int existingGrantState = sDeviceState.dpc().devicePolicyManager()
                 .getPermissionGrantState(sDeviceState.dpc().componentName(),
@@ -583,6 +585,15 @@
     }
 
     @Test
+    @CannotSetPolicyTest(policy = SetSmsPermissionGranted.class, includeNonDeviceAdminStates = false)
+    public void grantSmsPermission_nonDeviceAdmin_throwsException() {
+        assertThrows(SecurityException.class,
+                () -> sDeviceState.dpc().devicePolicyManager().setPermissionGrantState(
+                        sDeviceState.dpc().componentName(), sTestApp.packageName(),
+                        READ_SMS, PERMISSION_GRANT_STATE_GRANTED));
+    }
+
+    @Test
     @CannotSetPolicyTest(policy = SetSensorPermissionGranted.class)
     public void grantSensorPermission_cannotBeApplied_returnsTrueButDoesNotSetGrantState() {
         // TODO(b/188893663): Replace with parameterization
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/SupportMessageTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/SupportMessageTest.java
index f3873bb..3610ac4 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/SupportMessageTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/SupportMessageTest.java
@@ -31,7 +31,7 @@
 import com.android.bedstead.harrier.annotations.enterprise.PositivePolicyTest;
 import com.android.bedstead.harrier.policies.SupportMessage;
 import com.android.bedstead.metricsrecorder.EnterpriseMetricsRecorder;
-import com.android.bedstead.remotedpc.RemoteDpc;
+import com.android.bedstead.remotedpc.RemotePolicyManager;
 
 import org.junit.After;
 import org.junit.Before;
@@ -67,8 +67,8 @@
 
     @Before
     public void setUp() {
-        RemoteDpc dpc = sDeviceState.dpc();
-        mAdmin = dpc.devicePolicyController().componentName();
+        RemotePolicyManager dpc = sDeviceState.dpc();
+        mAdmin = dpc.componentName();
         mDevicePolicyManager = dpc.devicePolicyManager();
     }
 
@@ -195,7 +195,8 @@
     }
 
     @Test
-    @CannotSetPolicyTest(policy = SupportMessage.class)
+    // We don't include non device admin states as passing a null admin is a NullPointerException
+    @CannotSetPolicyTest(policy = SupportMessage.class, includeNonDeviceAdminStates = false)
     @Postsubmit(reason = "new test")
     public void getLongSupportMessage_invalidAdmin_fails() {
         assertThrows(SecurityException.class, () ->
@@ -203,7 +204,8 @@
     }
 
     @Test
-    @CannotSetPolicyTest(policy = SupportMessage.class)
+    // We don't include non device admin states as passing a null admin is a NullPointerException
+    @CannotSetPolicyTest(policy = SupportMessage.class, includeNonDeviceAdminStates = false)
     @Postsubmit(reason = "new test")
     public void setLongSupportMessage_invalidAdmin_fails() {
         assertThrows(SecurityException.class, () ->
@@ -211,7 +213,8 @@
     }
 
     @Test
-    @CannotSetPolicyTest(policy = SupportMessage.class)
+    // We don't include non device admin states as passing a null admin is a NullPointerException
+    @CannotSetPolicyTest(policy = SupportMessage.class, includeNonDeviceAdminStates = false)
     @Postsubmit(reason = "new test")
     public void getShortSupportMessage_invalidAdmin_fails() {
         assertThrows(SecurityException.class, () ->
@@ -219,7 +222,8 @@
     }
 
     @Test
-    @CannotSetPolicyTest(policy = SupportMessage.class)
+    // We don't include non device admin states as passing a null admin is a NullPointerException
+    @CannotSetPolicyTest(policy = SupportMessage.class, includeNonDeviceAdminStates = false)
     @Postsubmit(reason = "new test")
     public void setShortSupportMessage_invalidAdmin_fails() {
         assertThrows(SecurityException.class, () ->
diff --git a/tests/framework/base/windowmanager/AndroidManifest.xml b/tests/framework/base/windowmanager/AndroidManifest.xml
index 35f50d9..14856b3 100644
--- a/tests/framework/base/windowmanager/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/AndroidManifest.xml
@@ -518,6 +518,18 @@
                   android:exported="true"
                   android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density|touchscreen"
                   android:theme="@android:style/Theme.Translucent.NoTitleBar" />
+
+        <activity android:name="android.server.wm.HostActivity"
+                  android:exported="true">
+               <intent-filter>
+                 <action android:name="android.server.wm.app.HostActivity"/>
+               </intent-filter>
+               <intent-filter>
+                 <action android:name="android.intent.action.MAIN"/>
+                 <category android:name="android.intent.category.LAUNCHER"/>
+               </intent-filter>
+        </activity>
+
     </application>
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/framework/base/windowmanager/app/AndroidManifest.xml b/tests/framework/base/windowmanager/app/AndroidManifest.xml
index 36909cc..fbbbbca 100755
--- a/tests/framework/base/windowmanager/app/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/app/AndroidManifest.xml
@@ -573,14 +573,9 @@
            </intent-filter>
         </service>
 
-        <activity android:name=".HostActivity"
-             android:exported="true">
-            <intent-filter>
-                <action android:name="android.server.wm.app.HostActivity"/>
-            </intent-filter>
-        </activity>
         <service android:name=".RenderService"
-             android:process=".render_process"/>
+             android:process=".render_process"
+             android:exported="true"/>
         <activity android:name=".ClickableToastActivity"
              android:exported="true"/>
         <activity android:name=".MinimalPostProcessingActivity"
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java b/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java
index 1dfb795..79499f7 100644
--- a/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java
+++ b/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java
@@ -579,6 +579,12 @@
 
     public static class RenderService {
         public static final String PROCESS_NAME = ".render_process";
+        public static final String EXTRAS_BUNDLE = "EXTRAS_BUNDLE";
+        public static final String EXTRAS_DISPLAY_ID = "EXTRAS_DISPLAY_ID";
+        public static final String EXTRAS_HOST_TOKEN = "EXTRAS_HOST_TOKEN";
+        public static final String BROADCAST_EMBED_CONTENT =
+                "android.server.wm.app.RenderService.EMBED_CONTENT";
+        public static final String EXTRAS_SURFACE_PACKAGE = "surfacePackage";
     }
 
     /**
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/RenderService.java b/tests/framework/base/windowmanager/app/src/android/server/wm/app/RenderService.java
index f781d2e..9c611ea 100644
--- a/tests/framework/base/windowmanager/app/src/android/server/wm/app/RenderService.java
+++ b/tests/framework/base/windowmanager/app/src/android/server/wm/app/RenderService.java
@@ -16,13 +16,16 @@
 
 package android.server.wm.app;
 
+import static android.server.wm.app.Components.RenderService.BROADCAST_EMBED_CONTENT;
+import static android.server.wm.app.Components.RenderService.EXTRAS_BUNDLE;
+import static android.server.wm.app.Components.RenderService.EXTRAS_DISPLAY_ID;
+import static android.server.wm.app.Components.RenderService.EXTRAS_HOST_TOKEN;
+import static android.server.wm.app.Components.RenderService.EXTRAS_SURFACE_PACKAGE;
 import static android.server.wm.app.Components.UnresponsiveActivity.EXTRA_ON_MOTIONEVENT_DELAY_MS;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 
 import android.app.Service;
 import android.content.Context;
 import android.content.Intent;
-import android.graphics.PixelFormat;
 import android.hardware.display.DisplayManager;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -32,18 +35,13 @@
 import android.view.MotionEvent;
 import android.view.SurfaceControlViewHost;
 import android.view.View;
-import android.view.WindowManager;
 import android.widget.Button;
 
-public class RenderService extends Service {
-    static final String EXTRAS_BUNDLE = "INTENT_BUNDLE";
-    static final String EXTRAS_DISPLAY_ID = "hostDisplayId";
-    static final String EXTRAS_HOST_TOKEN = "hostInputToken";
-    static final String BROADCAST_EMBED_CONTENT
-            = "android.server.wm.app.RenderService.EMBED_CONTENT";
-    static final String EXTRAS_SURFACE_PACKAGE = "surfacePackage";
+import java.util.concurrent.CountDownLatch;
 
+public class RenderService extends Service {
     private int mOnMotionEventDelayMs;
+    CountDownLatch mViewDrawnCallbackLatch = new CountDownLatch(1);
 
     private boolean onTouch(View v, MotionEvent event) {
         SystemClock.sleep(mOnMotionEventDelayMs);
@@ -60,7 +58,7 @@
 
         SurfaceControlViewHost surfaceControlViewHost = getSurfaceControlViewHost(hostToken,
                 hostDisplayId);
-        sendSurfacePackage(surfaceControlViewHost.getSurfacePackage());
+        new Thread(()-> sendSurfacePackage(surfaceControlViewHost.getSurfacePackage())).start();
         return null;
     }
 
@@ -71,6 +69,8 @@
 
         View embeddedView = new Button(this);
         embeddedView.setOnTouchListener(this::onTouch);
+        embeddedView.getViewTreeObserver().registerFrameCommitCallback(
+                mViewDrawnCallbackLatch::countDown);
         DisplayMetrics metrics = new DisplayMetrics();
         displayContext.getDisplay().getMetrics(metrics);
         surfaceControlViewHost.setView(embeddedView, metrics.widthPixels, metrics.heightPixels);
@@ -84,8 +84,12 @@
     }
 
     private void sendSurfacePackage(SurfaceControlViewHost.SurfacePackage surfacePackage) {
-        Intent broadcast = new Intent();
-        broadcast.setAction(BROADCAST_EMBED_CONTENT);
+        try {
+            // wait until we commit a frame from the embedded viewrootimpl
+            mViewDrawnCallbackLatch.await();
+        } catch (InterruptedException ignored) {
+        }
+        Intent broadcast = new Intent(BROADCAST_EMBED_CONTENT);
         broadcast.putExtra(EXTRAS_SURFACE_PACKAGE, surfacePackage);
         sendBroadcast(broadcast);
     }
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/AnrTests.java b/tests/framework/base/windowmanager/src/android/server/wm/AnrTests.java
index 312fb4c..91b42dc 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/AnrTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/AnrTests.java
@@ -23,17 +23,15 @@
 import static android.server.wm.app.Components.UnresponsiveActivity.EXTRA_ON_CREATE_DELAY_MS;
 import static android.server.wm.app.Components.UnresponsiveActivity.EXTRA_ON_KEYDOWN_DELAY_MS;
 import static android.server.wm.app.Components.UnresponsiveActivity.EXTRA_ON_MOTIONEVENT_DELAY_MS;
-import static android.view.Display.DEFAULT_DISPLAY;
 
 import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeTrue;
 
-import android.app.ActivityTaskManager;
 import android.content.ComponentName;
 import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
-import android.server.wm.app.Components.RenderService;
 import android.provider.Settings;
+import android.server.wm.app.Components.RenderService;
 import android.server.wm.settings.SettingsSession;
 import android.support.test.uiautomator.By;
 import android.support.test.uiautomator.UiDevice;
@@ -43,14 +41,16 @@
 import android.util.Log;
 import android.view.KeyEvent;
 
+import androidx.test.core.app.ActivityScenario;
+import androidx.test.filters.FlakyTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
 import java.util.List;
-
-import androidx.test.filters.FlakyTest;
-import androidx.test.platform.app.InstrumentationRegistry;
+import java.util.concurrent.CountDownLatch;
 
 /**
  * Test scenarios that lead to ANR dialog being shown.
@@ -123,15 +123,11 @@
         startUnresponsiveActivity(EXTRA_ON_MOTIONEVENT_DELAY_MS, true /* waitForCompletion */,
                 UNRESPONSIVE_ACTIVITY);
 
-        // TODO(b/143566069) investigate why we need multiple taps on display to trigger anr.
         mWmState.computeState();
         // Tap on the UnresponsiveActivity
         final WindowManagerState.Task unresponsiveActivityTask =
                 mWmState.getTaskByActivity(UNRESPONSIVE_ACTIVITY);
-        tapOnTaskCenter(unresponsiveActivityTask);
-        SystemClock.sleep(1000);
-        tapOnTaskCenter(unresponsiveActivityTask);
-
+        mTouchHelper.tapOnTaskCenterAsync(unresponsiveActivityTask);
         clickCloseAppOnAnrDialog();
         assertEventLogsContainsAnr(UnresponsiveActivity.PROCESS_NAME);
     }
@@ -141,19 +137,19 @@
      */
     @Test
     public void embeddedWindowTriggersAnr() {
-        startUnresponsiveActivity(EXTRA_ON_MOTIONEVENT_DELAY_MS, true  /* waitForCompletion */,
-                HOST_ACTIVITY);
-
-        // TODO(b/143566069) investigate why we need multiple taps on display to trigger anr.
-        mWmState.computeState();
-        // Tap on the HostActivity
-        final WindowManagerState.Task hostActivityTask =
-                mWmState.getTaskByActivity(HOST_ACTIVITY);
-        tapOnTaskCenter(hostActivityTask);
-        SystemClock.sleep(1000);
-        tapOnTaskCenter(hostActivityTask);
-
-        clickCloseAppOnAnrDialog();
+        try (ActivityScenario<HostActivity> scenario =
+                     ActivityScenario.launch(HostActivity.class)) {
+            CountDownLatch[] latch = new CountDownLatch[1];
+            scenario.onActivity(activity -> latch[0] = activity.mEmbeddedViewAttachedLatch);
+            latch[0].await();
+            mWmState.computeState();
+            final WindowManagerState.Task hostActivityTask =
+                    mWmState.getTaskByActivity(new ComponentName("android.server.wm.cts",
+                            "android.server.wm.HostActivity"));
+            mTouchHelper.tapOnTaskCenterAsync(hostActivityTask);
+            clickCloseAppOnAnrDialog();
+        } catch (InterruptedException ignored) {
+        }
         assertEventLogsContainsAnr(RenderService.PROCESS_NAME);
     }
 
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java b/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java
index e948001..ad1d0e3 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java
@@ -45,7 +45,6 @@
 import android.util.Size;
 
 import androidx.annotation.Nullable;
-import androidx.test.filters.FlakyTest;
 
 import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
 import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/HostActivity.java b/tests/framework/base/windowmanager/src/android/server/wm/HostActivity.java
similarity index 65%
rename from tests/framework/base/windowmanager/app/src/android/server/wm/app/HostActivity.java
rename to tests/framework/base/windowmanager/src/android/server/wm/HostActivity.java
index 4a365a3..318e1e6 100644
--- a/tests/framework/base/windowmanager/app/src/android/server/wm/app/HostActivity.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/HostActivity.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-package android.server.wm.app;
+package android.server.wm;
 
+import static android.server.wm.app.Components.RenderService.BROADCAST_EMBED_CONTENT;
+import static android.server.wm.app.Components.RenderService.EXTRAS_BUNDLE;
+import static android.server.wm.app.Components.RenderService.EXTRAS_DISPLAY_ID;
+import static android.server.wm.app.Components.RenderService.EXTRAS_HOST_TOKEN;
+import static android.server.wm.app.Components.RenderService.EXTRAS_SURFACE_PACKAGE;
 import static android.server.wm.app.Components.UnresponsiveActivity.EXTRA_ON_MOTIONEVENT_DELAY_MS;
-import static android.server.wm.app.RenderService.BROADCAST_EMBED_CONTENT;
-import static android.server.wm.app.RenderService.EXTRAS_BUNDLE;
-import static android.server.wm.app.RenderService.EXTRAS_DISPLAY_ID;
-import static android.server.wm.app.RenderService.EXTRAS_HOST_TOKEN;
-import static android.server.wm.app.RenderService.EXTRAS_SURFACE_PACKAGE;
 
 import android.app.Activity;
 import android.content.BroadcastReceiver;
@@ -32,15 +32,18 @@
 import android.content.ServiceConnection;
 import android.os.Bundle;
 import android.os.IBinder;
-import android.view.SurfaceControlViewHost.SurfacePackage;
+import android.view.SurfaceControlViewHost;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 import android.view.ViewGroup;
 import android.widget.RelativeLayout;
 
+import java.util.concurrent.CountDownLatch;
+
+
 public class HostActivity extends Activity implements SurfaceHolder.Callback{
     private SurfaceView mSurfaceView;
-
+    public CountDownLatch mEmbeddedViewAttachedLatch =  new CountDownLatch(1);
     private ServiceConnection mConnection = new ServiceConnection() {
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {}
@@ -49,13 +52,14 @@
         public void onServiceDisconnected(ComponentName className) {}
     };
 
-    private BroadcastReceiver receiver = new BroadcastReceiver() {
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            SurfacePackage surfacePackage =
+            SurfaceControlViewHost.SurfacePackage surfacePackage =
                     intent.getParcelableExtra(EXTRAS_SURFACE_PACKAGE);
             if (surfacePackage != null) {
                 mSurfaceView.setChildSurfacePackage(surfacePackage);
+                mEmbeddedViewAttachedLatch.countDown();
             }
         }
     };
@@ -64,9 +68,8 @@
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(BROADCAST_EMBED_CONTENT);
-        registerReceiver(receiver, filter);
+        IntentFilter filter = new IntentFilter(BROADCAST_EMBED_CONTENT);
+        registerReceiver(mReceiver, filter);
 
         final RelativeLayout content = new RelativeLayout(this);
         mSurfaceView = new SurfaceView(this);
@@ -81,20 +84,21 @@
 
     @Override
     protected void onPause() {
-        unregisterReceiver(receiver);
+        unregisterReceiver(mReceiver);
         super.onPause();
     }
 
     @Override
     public void surfaceCreated(SurfaceHolder holder) {
-        Intent mIntent =  new Intent(this, RenderService.class);
-        Bundle b = new Bundle();
-        b.putBinder(EXTRAS_HOST_TOKEN, mSurfaceView.getHostToken());
-        b.putInt(EXTRAS_DISPLAY_ID, getDisplay().getDisplayId());
-        b.putInt(EXTRA_ON_MOTIONEVENT_DELAY_MS,
-                getIntent().getIntExtra(EXTRA_ON_MOTIONEVENT_DELAY_MS, 2000));
-        mIntent.putExtra(EXTRAS_BUNDLE, b);
-        bindService(mIntent, mConnection, Context.BIND_AUTO_CREATE|Context.BIND_IMPORTANT);
+        Intent mIntent = new Intent();
+        mIntent.setComponent(new ComponentName(
+                "android.server.wm.app", "android.server.wm.app.RenderService"));
+        Bundle bundle = new Bundle();
+        bundle.putBinder(EXTRAS_HOST_TOKEN, mSurfaceView.getHostToken());
+        bundle.putInt(EXTRAS_DISPLAY_ID, getDisplay().getDisplayId());
+        bundle.putInt(EXTRA_ON_MOTIONEVENT_DELAY_MS, 10000);
+        mIntent.putExtra(EXTRAS_BUNDLE, bundle);
+        bindService(mIntent, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT);
     }
 
     @Override
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/PrivacyIndicatorBoundsTests.java b/tests/framework/base/windowmanager/src/android/server/wm/PrivacyIndicatorBoundsTests.java
index 3d6d97c..49d2dba 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/PrivacyIndicatorBoundsTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/PrivacyIndicatorBoundsTests.java
@@ -21,6 +21,7 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
 import static android.server.wm.RoundedCornerTests.TestActivity.EXTRA_ORIENTATION;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
@@ -31,9 +32,11 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
 
 import android.app.Activity;
 import android.app.AppOpsManager;
+import android.content.Context;
 import android.content.Intent;
 import android.graphics.Rect;
 import android.os.Bundle;
@@ -56,7 +59,7 @@
 
 @Presubmit
 @RunWith(Parameterized.class)
-public class PrivacyIndicatorBoundsTests {
+public class PrivacyIndicatorBoundsTests extends ActivityManagerTestBase {
 
     private static final String TAG = PrivacyIndicatorBoundsTests.class.getSimpleName();
     private static final long TIMEOUT_MS = 1000;
@@ -85,6 +88,10 @@
 
     @Test
     public void testStaticBoundsAreNotNull() {
+        // TODO(b/187757919): Allow Automotive to skip this test until privacy chip is implemented
+        // in immersive mode
+        assumeFalse(isCar());
+
         final PrivacyIndicatorBoundsTests.TestActivity activity = mTestActivity.launchActivity(
                 new Intent().putExtra(EXTRA_ORIENTATION, orientation));
         getInstrumentation().runOnMainSync(() -> {
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTestBase.java b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTestBase.java
index 8a68de1..34a16a5 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTestBase.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTestBase.java
@@ -30,7 +30,6 @@
 import android.os.IBinder;
 import android.server.wm.WindowManagerState.WindowContainer;
 import android.util.ArrayMap;
-import android.window.TaskFragmentAppearedInfo;
 import android.window.TaskFragmentCreationParams;
 import android.window.TaskFragmentInfo;
 import android.window.TaskFragmentOrganizer;
@@ -259,11 +258,9 @@
         }
 
         @Override
-        public void onTaskFragmentAppeared(
-                @NonNull TaskFragmentAppearedInfo taskFragmentAppearedInfo) {
-            super.onTaskFragmentAppeared(taskFragmentAppearedInfo);
-            final TaskFragmentInfo info = taskFragmentAppearedInfo.getTaskFragmentInfo();
-            mInfos.put(info.getFragmentToken(), info);
+        public void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo) {
+            super.onTaskFragmentAppeared(taskFragmentInfo);
+            mInfos.put(taskFragmentInfo.getFragmentToken(), taskFragmentInfo);
             mAppearedLatch.countDown();
         }
 
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
index 2b133f4..054da4c 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
@@ -607,8 +607,10 @@
 
     @Test
     public void testInsetsDispatch() throws Exception {
-        // Start an activity which hides system bars.
-        final TestHideOnCreateActivity activity = startActivity(TestHideOnCreateActivity.class);
+        // Start an activity which hides system bars in fullscreen mode,
+        // otherwise, it might not be able to hide system bars in other windowing modes.
+        final TestHideOnCreateActivity activity = startActivityInWindowingModeFullScreen(
+                TestHideOnCreateActivity.class);
         final View rootView = activity.getWindow().getDecorView();
         ANIMATION_CALLBACK.waitForFinishing();
         PollingCheck.waitFor(TIMEOUT,
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
index e37f284..1c2fdf9 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
@@ -1308,7 +1308,7 @@
      */
     protected static class DisableScreenDozeRule implements TestRule {
 
-        /** Copied from android.provider.Settings.Secure since these keys are hiden. */
+        /** Copied from android.provider.Settings.Secure since these keys are hidden. */
         private static final String[] DOZE_SETTINGS = {
                 "doze_enabled",
                 "doze_always_on",
@@ -1317,7 +1317,8 @@
                 "doze_pulse_on_double_tap",
                 "doze_wake_screen_gesture",
                 "doze_wake_display_gesture",
-                "doze_tap_gesture"
+                "doze_tap_gesture",
+                "doze_quick_pickup_gesture"
         };
 
         private String get(String key) {
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/TouchHelper.java b/tests/framework/base/windowmanager/util/src/android/server/wm/TouchHelper.java
index 39afb54..54c9b3e 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/TouchHelper.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/TouchHelper.java
@@ -163,4 +163,11 @@
                 KeyEvent.ACTION_UP, keyCode, 0 /* repeatCount */);
         getInstrumentation().getUiAutomation().injectInputEvent(upEvent, sync);
     }
+
+    public void tapOnTaskCenterAsync(WindowManagerState.Task task) {
+        final Rect bounds = task.getBounds();
+        final int x = bounds.left + bounds.width() / 2;
+        final int y = bounds.top + bounds.height() / 2;
+        tapOnDisplay(x, y, task.mDisplayId, false /* sync*/);
+    }
 }
diff --git a/tests/inputmethod/AndroidManifest.xml b/tests/inputmethod/AndroidManifest.xml
index 8ce099b..18c6ebf 100644
--- a/tests/inputmethod/AndroidManifest.xml
+++ b/tests/inputmethod/AndroidManifest.xml
@@ -29,7 +29,7 @@
         <activity android:name="android.view.inputmethod.cts.util.TestActivity"
              android:theme="@style/no_starting_window"
              android:label="TestActivity"
-             android:configChanges="fontScale"
+             android:configChanges="fontScale|smallestScreenSize|screenSize|screenLayout"
              android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackTest.java b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
index d179c5a..8065633 100755
--- a/tests/tests/media/src/android/media/cts/AudioTrackTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
@@ -3367,6 +3367,122 @@
         }
     }
 
+    /**
+     * Test AudioTrack Builder error handling.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testAudioTrackBuilderError() throws Exception {
+        if (!hasAudioOutput()) {
+            return;
+        }
+
+        final AudioTrack[] audioTrack = new AudioTrack[1]; // pointer to audio track.
+        final int BIGNUM = Integer.MAX_VALUE; // large value that should be invalid.
+        final int INVALID_SESSION_ID = 1024;  // can never occur (wrong type in 3 lsbs)
+        final int INVALID_CHANNEL_MASK = -1;
+
+        try {
+            // NOTE:
+            // Tuner Configuration builder error tested in testTunerConfiguration (same file).
+            // AudioAttributes tested in AudioAttributesTest#testAudioAttributesBuilderError.
+            // AudioFormat tested in AudioFormatTest#testAudioFormatBuilderError.
+
+            // We must be able to create the AudioTrack.
+            audioTrack[0] = new AudioTrack.Builder().build();
+            audioTrack[0].release();
+
+            // Out of bounds buffer size.  A large size will fail in AudioTrack creation.
+            assertThrows(UnsupportedOperationException.class, () -> {
+                audioTrack[0] = new AudioTrack.Builder()
+                        .setBufferSizeInBytes(BIGNUM)
+                        .build();
+            });
+
+            // 0 and negative buffer size throw IllegalArgumentException
+            for (int bufferSize : new int[] {-BIGNUM, -1, 0}) {
+                assertThrows(IllegalArgumentException.class, () -> {
+                    audioTrack[0] = new AudioTrack.Builder()
+                            .setBufferSizeInBytes(bufferSize)
+                            .build();
+                });
+            }
+
+            assertThrows(IllegalArgumentException.class, () -> {
+                audioTrack[0] = new AudioTrack.Builder()
+                        .setEncapsulationMode(BIGNUM)
+                        .build();
+            });
+
+            assertThrows(IllegalArgumentException.class, () -> {
+                audioTrack[0] = new AudioTrack.Builder()
+                        .setPerformanceMode(BIGNUM)
+                        .build();
+            });
+
+            // Invalid session id that is positive.
+            // (logcat error message vague)
+            assertThrows(UnsupportedOperationException.class, () -> {
+                audioTrack[0] = new AudioTrack.Builder()
+                        .setSessionId(INVALID_SESSION_ID)
+                        .build();
+            });
+
+            assertThrows(IllegalArgumentException.class, () -> {
+                audioTrack[0] = new AudioTrack.Builder()
+                        .setTransferMode(BIGNUM)
+                        .build();
+            });
+
+            // Specialty AudioTrack build errors.
+
+            // Bad audio encoding DRA expected unsupported.
+            try {
+                audioTrack[0] = new AudioTrack.Builder()
+                        .setAudioFormat(new AudioFormat.Builder()
+                                .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
+                                .setEncoding(AudioFormat.ENCODING_DRA)
+                                .build())
+                        .build();
+                // Don't throw an exception, maybe it is supported somehow, but warn.
+                // Note: often specialty audio formats are offloaded (see setOffloadedPlayback).
+                // AudioTrackSurroundTest and AudioTrackOffloadedTest can be used as examples.
+                Log.w(TAG, "ENCODING_DRA is expected to be unsupported");
+                audioTrack[0].release();
+                audioTrack[0] = null;
+            } catch (UnsupportedOperationException e) {
+                ; // OK expected
+            }
+
+            // Sample rate out of bounds.
+            // System levels caught on AudioFormat.
+            assertThrows(IllegalArgumentException.class, () -> {
+                audioTrack[0] = new AudioTrack.Builder()
+                        .setAudioFormat(new AudioFormat.Builder()
+                                .setSampleRate(BIGNUM)
+                                .build())
+                        .build();
+            });
+
+            // Invalid channel mask - caught here on use.
+            assertThrows(IllegalArgumentException.class, () -> {
+                audioTrack[0] = new AudioTrack.Builder()
+                        .setAudioFormat(new AudioFormat.Builder()
+                                .setChannelMask(INVALID_CHANNEL_MASK)
+                                .build())
+                        .build();
+            });
+        } finally {
+            // Did we successfully complete for some reason but did not
+            // release?
+            if (audioTrack[0] != null) {
+                audioTrack[0].release();
+                audioTrack[0] = null;
+            }
+        }
+    }
+
 /* Do not run in JB-MR1. will be re-opened in the next platform release.
     public void testResourceLeakage() throws Exception {
         final int BUFFER_SIZE = 600 * 1024;
diff --git a/tests/tests/settings/Android.bp b/tests/tests/settings/Android.bp
index 246e3fd..b1a443e 100644
--- a/tests/tests/settings/Android.bp
+++ b/tests/tests/settings/Android.bp
@@ -17,12 +17,20 @@
     static_libs: [
         "androidx.slice_slice-core",
         "androidx.slice_slice-view",
+        "androidx.test.core",
         "ctstestrunner-axt",
         "junit",
+        "kotlin-stdlib",
         "truth-prebuilt",
+        "ctsWindowExtLib",
     ],
 
     srcs: ["src/**/*.java"],
 
     sdk_version: "test_current",
 }
+
+android_library_import {
+    name: "ctsWindowExtLib",
+    aars: ["libs/cts_window_ext_lib.aar"],
+}
diff --git a/tests/tests/settings/AndroidManifest.xml b/tests/tests/settings/AndroidManifest.xml
index 9225b6a..007b36d 100644
--- a/tests/tests/settings/AndroidManifest.xml
+++ b/tests/tests/settings/AndroidManifest.xml
@@ -20,9 +20,20 @@
 
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
     <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+    <uses-permission android:name="android.permission.LAUNCH_MULTI_PANE_SETTINGS_DEEP_LINK"/>
 
     <application>
         <uses-library android:name="android.test.runner"/>
+        <uses-library android:name="androidx.window.extensions" android:required="false"/>
+        <uses-library android:name="androidx.window.sidecar" android:required="false"/>
+
+        <activity android:name=".RightPaneActivity"
+                android:exported="true">
+            <intent-filter>
+                <action android:name="android.settings.cts.LAUNCH_RIGHT_PANE"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+        </activity>
     </application>
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/settings/libs/cts_window_ext_lib.aar b/tests/tests/settings/libs/cts_window_ext_lib.aar
new file mode 100644
index 0000000..ca58b36
--- /dev/null
+++ b/tests/tests/settings/libs/cts_window_ext_lib.aar
Binary files differ
diff --git a/tests/tests/settings/src/android/settings/cts/RightPaneActivity.java b/tests/tests/settings/src/android/settings/cts/RightPaneActivity.java
new file mode 100644
index 0000000..86391e7
--- /dev/null
+++ b/tests/tests/settings/src/android/settings/cts/RightPaneActivity.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.settings.cts;
+
+import android.app.Activity;
+import android.provider.Settings;
+
+/**
+ * For SettingsMultiPaneDeepLinkTest to test if
+ * {@link Settings#ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY}
+ */
+public class RightPaneActivity extends Activity {
+}
diff --git a/tests/tests/settings/src/android/settings/cts/SettingsMultiPaneDeepLinkTest.java b/tests/tests/settings/src/android/settings/cts/SettingsMultiPaneDeepLinkTest.java
new file mode 100644
index 0000000..b6103c8
--- /dev/null
+++ b/tests/tests/settings/src/android/settings/cts/SettingsMultiPaneDeepLinkTest.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.settings.cts;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.app.Instrumentation.ActivityMonitor;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.provider.Settings;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+import androidx.window.embedding.SplitController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests to ensure the Activity to handle
+ * {@link Settings#ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY}
+ */
+@RunWith(AndroidJUnit4.class)
+public class SettingsMultiPaneDeepLinkTest {
+
+    private static final String DEEP_LINK_PERMISSION =
+            "android.permission.LAUNCH_MULTI_PANE_SETTINGS_DEEP_LINK";
+
+    boolean mIsSplitSupported;
+    ResolveInfo mDeepLinkIntentResolveInfo;
+
+    @Before
+    public void setUp() throws Exception {
+        // runOnMainSync or SplitController#isSplitSupported will return wrong value for large
+        // screen devices.
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mIsSplitSupported = SplitController.getInstance().isSplitSupported();
+            }
+        });
+        mDeepLinkIntentResolveInfo = InstrumentationRegistry.getInstrumentation().getContext()
+                .getPackageManager().resolveActivity(
+                new Intent(Settings.ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY),
+                /* flags= */ PackageManager.MATCH_DEFAULT_ONLY);
+
+        assumeFalse("Skipping test: The device does not support Activity embedding",
+                !mIsSplitSupported && mDeepLinkIntentResolveInfo == null);
+    }
+
+    @Test
+    public void deepLinkHomeActivity_protectedWithPermission() throws Exception {
+        assertTrue("The Activity to handle the Intent ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY must"
+                + " be protected by " + DEEP_LINK_PERMISSION,
+                DEEP_LINK_PERMISSION.equals(mDeepLinkIntentResolveInfo.activityInfo.permission));
+    }
+
+    @Test
+    public void deepLinkHomeActivity_splitSupported_deepLinkHomeEnabled() throws Exception {
+        assumeTrue(mIsSplitSupported);
+
+        assertTrue("The Activity to handle the Intent ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY must"
+                + " be enabled when the device supports Activity embedding",
+                mDeepLinkIntentResolveInfo != null);
+    }
+
+    @Test
+    public void deepLinkHomeActivity_splitNotSupported_deepLinkHomeDisabled() throws Exception {
+        assumeFalse(mIsSplitSupported);
+
+        assertTrue("The Activity to handle the Intent ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY must"
+                + " be disabled when the device does NOT support Activity embedding",
+                mDeepLinkIntentResolveInfo == null);
+    }
+
+    @Test
+    public void deepLinkHomeActivity_receiveMultiPaneDeepLinkIntent_shouldStartActivity()
+                throws Exception {
+        Intent intent = new Intent(Settings.ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY);
+        intent.putExtra(Settings.EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI,
+                new Intent("android.settings.cts.LAUNCH_RIGHT_PANE")
+                .toUri(Intent.URI_INTENT_SCHEME));
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        ActivityMonitor am = instrumentation.addMonitor(RightPaneActivity.class.getName(),
+                /* result */ null, /* block */ false);
+
+        // Take the Shell UID permission identity because Shell app has the permission
+        // android.permission.LAUNCH_MULTI_PANE_SETTINGS_DEEP_LINK.
+        instrumentation.getUiAutomation().adoptShellPermissionIdentity();
+        try {
+            instrumentation.getContext()
+                    .startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+        } finally {
+            // Drop the Shell UID permission identity.
+            instrumentation.getUiAutomation().dropShellPermissionIdentity();
+        }
+
+        Activity rightPaneActivity = am.waitForActivityWithTimeout(5000);
+        assertNotNull("The Activity to handle the Intent ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY"
+                + " must start Activity for EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI",
+                rightPaneActivity);
+        rightPaneActivity.finish();
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
index a594afa..722cdae 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -3333,6 +3333,19 @@
                 TelephonyManager.SIM_STATE_NOT_READY,
                 TelephonyManager.SIM_STATE_PERM_DISABLED,
                 TelephonyManager.SIM_STATE_LOADED).contains(simApplicationState));
+
+        for (int i = 0; i <= mTelephonyManager.getPhoneCount(); i++) {
+            final int slotId = i;
+            simApplicationState = ShellIdentityUtils.invokeMethodWithShellPermissions(
+                    mTelephonyManager, (tm) -> tm.getSimApplicationState(slotId));
+            assertTrue(Arrays.asList(TelephonyManager.SIM_STATE_UNKNOWN,
+                    TelephonyManager.SIM_STATE_PIN_REQUIRED,
+                    TelephonyManager.SIM_STATE_PUK_REQUIRED,
+                    TelephonyManager.SIM_STATE_NETWORK_LOCKED,
+                    TelephonyManager.SIM_STATE_NOT_READY,
+                    TelephonyManager.SIM_STATE_PERM_DISABLED,
+                    TelephonyManager.SIM_STATE_LOADED).contains(simApplicationState));
+        }
     }
 
     @Test
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsUceAdapterTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsUceAdapterTest.java
index 4863f5b..d4386ff 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsUceAdapterTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsUceAdapterTest.java
@@ -818,6 +818,8 @@
             } finally {
                 errorQueue.clear();
                 retryAfterQueue.clear();
+                removeTestContactFromEab();
+                removeUceRequestDisallowedStatus();
             }
 
             requestAvailability(uceAdapter, sTestNumberUri, callback);
@@ -831,6 +833,8 @@
             } finally {
                 errorQueue.clear();
                 retryAfterQueue.clear();
+                removeTestContactFromEab();
+                removeUceRequestDisallowedStatus();
             }
 
             /*
@@ -854,6 +858,8 @@
             } finally {
                 errorQueue.clear();
                 retryAfterQueue.clear();
+                removeTestContactFromEab();
+                removeUceRequestDisallowedStatus();
             }
 
             requestAvailability(uceAdapter, sTestNumberUri, callback);
@@ -867,6 +873,8 @@
             } finally {
                 errorQueue.clear();
                 retryAfterQueue.clear();
+                removeTestContactFromEab();
+                removeUceRequestDisallowedStatus();
             }
         });
 
@@ -888,6 +896,8 @@
         } finally {
             errorQueue.clear();
             retryAfterQueue.clear();
+            removeTestContactFromEab();
+            removeUceRequestDisallowedStatus();
         }
 
         requestCapabilities(uceAdapter, numbers, callback);
@@ -902,6 +912,8 @@
         } finally {
             errorQueue.clear();
             retryAfterQueue.clear();
+            removeTestContactFromEab();
+            removeUceRequestDisallowedStatus();
         }
 
         overrideCarrierConfig(null);
@@ -975,22 +987,38 @@
         });
 
         requestCapabilities(uceAdapter, contacts, callback);
+        List<RcsContactUceCapability> resultCapList = new ArrayList<>();
 
         // Verify that all the three contact's capabilities are received
         RcsContactUceCapability capability = waitForResult(capabilityQueue);
-        assertNotNull("Capabilities were not received for contact: " + contact1, capability);
-        verifyCapabilityResult(capability, contact1, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
-                true, true);
+        assertNotNull("Capabilities were not received for contact", capability);
+        resultCapList.add(capability);
 
         capability = waitForResult(capabilityQueue);
-        assertNotNull("Capabilities were not received for contact: " + contact2, capability);
-        verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
-                true, false);
+        assertNotNull("Capabilities were not received for contact", capability);
+        resultCapList.add(capability);
 
         capability = waitForResult(capabilityQueue);
-        assertNotNull("Capabilities were not received for contact: " + contact3, capability);
-        verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
-                false, false);
+        assertNotNull("Capabilities were not received for contact", capability);
+        resultCapList.add(capability);
+
+        // Verify the first contact capabilities from the received capabilities list
+        RcsContactUceCapability resultCapability = getContactCapability(resultCapList, contact1);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact1, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_FOUND, true, true);
+
+        // Verify the second contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact2);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact2, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_FOUND, true, false);
+
+        // Verify the second contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact3);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact3, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_FOUND, false, false);
 
         // Verify the onCompleted is called
         waitForResult(completeQueue);
@@ -999,6 +1027,7 @@
         errorRetryQueue.clear();
         completeQueue.clear();
         capabilityQueue.clear();
+        resultCapList.clear();
         removeTestContactFromEab();
 
         // Setup the callback that some of the contacts are terminated.
@@ -1010,16 +1039,34 @@
 
         // Verify the contacts are not found.
         capability = waitForResult(capabilityQueue);
-        verifyCapabilityResult(capability, contact1, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
-                false, false);
+        assertNotNull("Capabilities were not received", capability);
+        resultCapList.add(capability);
 
         capability = waitForResult(capabilityQueue);
-        verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
-                false, false);
+        assertNotNull("Capabilities were not received", capability);
+        resultCapList.add(capability);
 
         capability = waitForResult(capabilityQueue);
-        verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
-                false, false);
+        assertNotNull("Capabilities were not received", capability);
+        resultCapList.add(capability);
+
+        // Verify the first contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact1);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact1, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_NOT_FOUND, false, false);
+
+        // Verify the second contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact2);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact2, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_NOT_FOUND, false, false);
+
+        // Verify the second contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact3);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact3, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_NOT_FOUND, false, false);
 
         // Verify the onCompleted is called
         waitForResult(completeQueue);
@@ -1028,6 +1075,7 @@
         errorRetryQueue.clear();
         completeQueue.clear();
         capabilityQueue.clear();
+        resultCapList.clear();
         removeTestContactFromEab();
 
         // Setup the callback that some of the contacts are terminated.
@@ -1051,17 +1099,35 @@
 
         // Verify the first contact is found.
         capability = waitForResult(capabilityQueue);
-        verifyCapabilityResult(capability, contact1, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
-                true, true);
+        assertNotNull("Capabilities were not received", capability);
+        resultCapList.add(capability);
 
         // Verify the reset contacts are not found.
         capability = waitForResult(capabilityQueue);
-        verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
-                true, false);
+        assertNotNull("Capabilities were not received", capability);
+        resultCapList.add(capability);
 
         capability = waitForResult(capabilityQueue);
-        verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
-                false, false);
+        assertNotNull("Capabilities were not received", capability);
+        resultCapList.add(capability);
+
+        // Verify the first contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact1);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact1, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_FOUND, true, true);
+
+        // Verify the second contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact2);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact2, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_NOT_FOUND, false, false);
+
+        // Verify the second contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact3);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact3, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_NOT_FOUND, false, false);
 
         // Verify the onCompleted is called
         waitForResult(completeQueue);
@@ -1962,60 +2028,17 @@
                 } else if (sipCode == sipCodeBadEvent) {
                     assertTrue(retryAfterMillis > 0L);
                 }
-
-                // Verify the ImsService received the capabilities request.
-                assertEquals(1, subscribeRequestCount.get());
             } catch (Exception e) {
                 fail("testForbiddenResponseToCapabilitiesRequest with command error failed: " + e);
             } finally {
                 errorQueue.clear();
                 retryAfterQueue.clear();
+                capabilityQueue.clear();
+                completeQueue.clear();
                 subscribeRequestCount.set(0);
+                removeTestContactFromEab();
+                removeUceRequestDisallowedStatus();
             }
-
-            // Override the network response with the sip code 503 Service Unavailable
-            capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
-                subscribeRequestCount.incrementAndGet();
-                cb.onNetworkResponse(503, "Service Unavailable");
-            });
-
-            try {
-                // Request contact uce capabilities again.
-                requestCapabilities(uceAdapter, contacts, callback);
-
-                if (sipCode == sipCodeForbidden) {
-                    // Verify that device can still send the subscribe request. The callback
-                    // "onError" is called with the Server Unavailable error.
-                    assertEquals(RcsUceAdapter.ERROR_SERVER_UNAVAILABLE,
-                            waitForIntResult(errorQueue));
-                    // Verify the retryAfter value
-                    assertEquals(0L, waitForLongResult(retryAfterQueue));
-                    // Verify that the capabilities is not forbidden. The ImsService received the
-                    // request from the framework.
-                    assertEquals(1, subscribeRequestCount.get());
-                } else if (sipCode == sipCodeBadEvent) {
-                    // When carrier config Bad Event flag is enabled and the device has received
-                    // the sip code 489 (bad event) before, the uce request will be forbidden.
-
-                    // Verify that the callback "onError" is called with the error code FORBIDDEN
-                    assertEquals(RcsUceAdapter.ERROR_FORBIDDEN, waitForIntResult(errorQueue));
-                    // Verify the retryAfter value
-                    long retryAfterMillis = waitForLongResult(retryAfterQueue);
-                    assertTrue(retryAfterMillis > 0L);
-                    // Verify that the capabilities won't be send to the ImsService because the
-                    // uce request is forbidden.
-                    assertEquals(0, subscribeRequestCount.get());
-                }
-            } catch (Exception e) {
-                fail("testForbiddenResponseToCapabilitiesRequest with command error failed: " + e);
-            } finally {
-                errorQueue.clear();
-                retryAfterQueue.clear();
-                subscribeRequestCount.set(0);
-            }
-
-            // Reset the device status
-            removeUceRequestDisallowedStatus();
         });
 
         overrideCarrierConfig(null);
@@ -2284,6 +2307,7 @@
             completeQueue.clear();
             capabilityQueue.clear();
             removeTestContactFromEab();
+            removeUceRequestDisallowedStatus();
             setCapabilitiesRequestTimeout(-1L);
         }
 
@@ -2309,12 +2333,115 @@
             completeQueue.clear();
             capabilityQueue.clear();
             removeTestContactFromEab();
+            removeUceRequestDisallowedStatus();
             setCapabilitiesRequestTimeout(-1L);
         }
 
         overrideCarrierConfig(null);
     }
 
+    @Test
+    public void testRequestTimeoutWithPresenceMechanism() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+        RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(sTestSub).getUceAdapter();
+        assertNotNull("UCE adapter should not be null!", uceAdapter);
+
+        // Remove the test contact capabilities
+        removeTestContactFromEab();
+
+        // Connect to the ImsService
+        setupTestImsService(uceAdapter, true, true /* presence cap */, false /* OPTIONS */);
+
+        TestRcsCapabilityExchangeImpl capabilityExchangeImpl = sServiceConnector
+                .getCarrierService().getRcsFeature().getRcsCapabilityExchangeImpl();
+
+        BlockingQueue<Integer> errorQueue = new LinkedBlockingQueue<>();
+        BlockingQueue<Long> errorRetryQueue = new LinkedBlockingQueue<>();
+        BlockingQueue<Boolean> completeQueue = new LinkedBlockingQueue<>();
+        BlockingQueue<RcsContactUceCapability> capabilityQueue = new LinkedBlockingQueue<>();
+        RcsUceAdapter.CapabilitiesCallback callback = new RcsUceAdapter.CapabilitiesCallback() {
+            @Override
+            public void onCapabilitiesReceived(List<RcsContactUceCapability> capabilities) {
+                capabilities.forEach(c -> capabilityQueue.offer(c));
+            }
+            @Override
+            public void onComplete() {
+                completeQueue.offer(true);
+            }
+            @Override
+            public void onError(int errorCode, long retryAfterMilliseconds) {
+                errorQueue.offer(errorCode);
+                errorRetryQueue.offer(retryAfterMilliseconds);
+            }
+        };
+
+        // Prepare the test contact
+        Collection<Uri> contacts = new ArrayList<>();
+        contacts.add(sTestNumberUri);
+
+        // Setup the ImsService doesn't trigger any callbacks.
+        AtomicInteger subscribeRequestCount = new AtomicInteger(0);
+        capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+            subscribeRequestCount.incrementAndGet();
+            // It won't trigger any callbacks to the framework.
+        });
+
+        // Set the timeout for 3 seconds
+        setCapabilitiesRequestTimeout(3000L);
+
+        // Request capabilities
+        requestCapabilities(uceAdapter, contacts, callback);
+
+        try {
+            // Verify the error code REQUEST_TIMEOUT is received
+            assertEquals(RcsUceAdapter.ERROR_REQUEST_TIMEOUT, waitForIntResult(errorQueue));
+            assertEquals(0L, waitForLongResult(errorRetryQueue));
+
+            // Verify the capabilities can still be received.
+            RcsContactUceCapability capability = waitForResult(capabilityQueue);
+            assertNotNull("Capabilities were not received", capability);
+            verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_NETWORK,
+                    REQUEST_RESULT_NOT_FOUND, false, false);
+        } finally {
+            errorQueue.clear();
+            errorRetryQueue.clear();
+            completeQueue.clear();
+            capabilityQueue.clear();
+            subscribeRequestCount.set(0);
+        }
+
+        // Request the capabilities with the same contact again.
+        requestCapabilities(uceAdapter, contacts, callback);
+
+        try {
+            // Verify that the caller can received the capabilities callback.
+            RcsContactUceCapability capability = waitForResult(capabilityQueue);
+            assertNotNull("Capabilities were not received", capability);
+            verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_NETWORK,
+                    REQUEST_RESULT_NOT_FOUND, false, false);
+
+            // Verify the complete callback will be called.
+            waitForResult(completeQueue);
+
+            // Verify that the ImsService didn't received the request because the capabilities
+            // should be retrieved from the cache.
+            assertEquals(0, subscribeRequestCount.get());
+        } finally {
+            errorQueue.clear();
+            errorRetryQueue.clear();
+            completeQueue.clear();
+            capabilityQueue.clear();
+            removeTestContactFromEab();
+            removeUceRequestDisallowedStatus();
+            subscribeRequestCount.set(0);
+            setCapabilitiesRequestTimeout(-1L);
+        }
+
+        overrideCarrierConfig(null);
+    }
 
     @Test
     public void testTimeoutToRequestCapabilitiesWithOptionsMechanism() throws Exception {
@@ -2457,22 +2584,40 @@
 
         requestCapabilities(uceAdapter, contacts, callback);
 
+        List<RcsContactUceCapability> resultCapList = new ArrayList<>();
+
         // Verify that all the three contact's capabilities are received
         RcsContactUceCapability capability = waitForResult(capabilityQueue);
-        assertNotNull("Capabilities were not received for contact: " + contact1SipScheme,
-                capability);
-        verifyCapabilityResult(capability, contact1SipScheme, SOURCE_TYPE_NETWORK,
+        assertNotNull("Capabilities were not received for contact", capability);
+        resultCapList.add(capability);
+
+        capability = waitForResult(capabilityQueue);
+        assertNotNull("Capabilities were not received for contact", capability);
+        resultCapList.add(capability);
+
+        capability = waitForResult(capabilityQueue);
+        assertNotNull("Capabilities were not received for contact", capability);
+        resultCapList.add(capability);
+
+
+        // Verify the first contact capabilities from the received capabilities list
+        RcsContactUceCapability resultCapability =
+                getContactCapability(resultCapList, contact1SipScheme);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact1SipScheme, SOURCE_TYPE_NETWORK,
                 REQUEST_RESULT_FOUND, true, true);
 
-        capability = waitForResult(capabilityQueue);
-        assertNotNull("Capabilities were not received for contact: " + contact2, capability);
-        verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
-                true, false);
+        // Verify the second contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact2);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact2, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_FOUND, true, false);
 
-        capability = waitForResult(capabilityQueue);
-        assertNotNull("Capabilities were not received for contact: " + contact3, capability);
-        verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
-                false, false);
+        // Verify the third contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact3);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact3, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_FOUND, false, false);
 
         // Verify the onCompleted is called
         waitForResult(completeQueue);
@@ -2481,6 +2626,7 @@
         errorRetryQueue.clear();
         completeQueue.clear();
         capabilityQueue.clear();
+        resultCapList.clear();
         removeTestContactFromEab();
 
         // Setup the callback that some of the contacts are terminated.
@@ -2492,16 +2638,34 @@
 
         // Verify the contacts are not found.
         capability = waitForResult(capabilityQueue);
-        verifyCapabilityResult(capability, contact1TelScheme, SOURCE_TYPE_NETWORK,
+        assertNotNull("Capabilities were not received", capability);
+        resultCapList.add(capability);
+
+        capability = waitForResult(capabilityQueue);
+        assertNotNull("Capabilities were not received", capability);
+        resultCapList.add(capability);
+
+        capability = waitForResult(capabilityQueue);
+        assertNotNull("Capabilities were not received", capability);
+        resultCapList.add(capability);
+
+        // Verify the first contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact1TelScheme);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact1TelScheme, SOURCE_TYPE_NETWORK,
                 REQUEST_RESULT_NOT_FOUND, false, false);
 
-        capability = waitForResult(capabilityQueue);
-        verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
-                false, false);
+        // Verify the second contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact2);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact2, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_NOT_FOUND, false, false);
 
-        capability = waitForResult(capabilityQueue);
-        verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
-                false, false);
+        // Verify the second contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact3);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact3, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_NOT_FOUND, false, false);
 
         // Verify the onCompleted is called
         waitForResult(completeQueue);
@@ -2510,6 +2674,7 @@
         errorRetryQueue.clear();
         completeQueue.clear();
         capabilityQueue.clear();
+        resultCapList.clear();
         removeTestContactFromEab();
 
         // Setup the callback that some of the contacts are terminated.
@@ -2533,17 +2698,35 @@
 
         // Verify the first contact is found.
         capability = waitForResult(capabilityQueue);
-        verifyCapabilityResult(capability, contact1SipScheme, SOURCE_TYPE_NETWORK,
-                REQUEST_RESULT_FOUND, true, true);
+        assertNotNull("Capabilities were not received", capability);
+        resultCapList.add(capability);
 
         // Verify the reset contacts are not found.
         capability = waitForResult(capabilityQueue);
-        verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
-                true, false);
+        assertNotNull("Capabilities were not received", capability);
+        resultCapList.add(capability);
 
         capability = waitForResult(capabilityQueue);
-        verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
-                false, false);
+        assertNotNull("Capabilities were not received", capability);
+        resultCapList.add(capability);
+
+        // Verify the first contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact1SipScheme);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact1SipScheme, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_FOUND, true, true);
+
+        // Verify the second contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact2);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact2, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_NOT_FOUND, true, false);
+
+        // Verify the second contact capabilities from the received capabilities list
+        resultCapability = getContactCapability(resultCapList, contact3);
+        assertNotNull("Cannot find the contact", resultCapability);
+        verifyCapabilityResult(resultCapability, contact3, SOURCE_TYPE_NETWORK,
+                REQUEST_RESULT_NOT_FOUND, false, false);
 
         // Verify the onCompleted is called
         waitForResult(completeQueue);
@@ -2678,6 +2861,352 @@
         overrideCarrierConfig(null);
     }
 
+    @Test
+    public void testContactInThrottlingState() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+        RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(sTestSub).getUceAdapter();
+        assertNotNull("UCE adapter should not be null!", uceAdapter);
+
+        // Remove the test contact capabilities
+        removeTestContactFromEab();
+        // Reset the UCE device state.
+        removeUceRequestDisallowedStatus();
+
+        // Connect to the ImsService
+        setupTestImsService(uceAdapter, true, true /* presence cap */, false /* options */);
+
+        TestRcsCapabilityExchangeImpl capabilityExchangeImpl = sServiceConnector
+                .getCarrierService().getRcsFeature().getRcsCapabilityExchangeImpl();
+
+        BlockingQueue<Integer> errorQueue = new LinkedBlockingQueue<>();
+        BlockingQueue<Long> errorRetryQueue = new LinkedBlockingQueue<>();
+        BlockingQueue<Boolean> completeQueue = new LinkedBlockingQueue<>();
+        BlockingQueue<RcsContactUceCapability> capabilityQueue = new LinkedBlockingQueue<>();
+        RcsUceAdapter.CapabilitiesCallback callback = new RcsUceAdapter.CapabilitiesCallback() {
+            @Override
+            public void onCapabilitiesReceived(List<RcsContactUceCapability> capabilities) {
+                capabilities.forEach(c -> capabilityQueue.offer(c));
+            }
+            @Override
+            public void onComplete() {
+                completeQueue.offer(true);
+            }
+            @Override
+            public void onError(int errorCode, long retryAfterMilliseconds) {
+                errorQueue.offer(errorCode);
+                errorRetryQueue.offer(retryAfterMilliseconds);
+            }
+        };
+
+        // Prepare the test contact
+        Collection<Uri> numbers = new ArrayList<>(1);
+        numbers.add(sTestNumberUri);
+
+        // Setup the network response is 408 Request Timeout.
+        int networkRespCode = 408;
+        String networkRespReason = "Request Timeout";
+        AtomicInteger subscribeRequestCount = new AtomicInteger(0);
+        capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+            subscribeRequestCount.incrementAndGet();
+            cb.onNetworkResponse(networkRespCode, networkRespReason);
+        });
+
+        // Request contact capabilities
+        requestCapabilities(uceAdapter, numbers, callback);
+
+        // Verify that the callback "onError" is called with the expected error code.
+        try {
+            assertEquals(RcsUceAdapter.ERROR_REQUEST_TIMEOUT, waitForIntResult(errorQueue));
+            assertEquals(0L, waitForLongResult(errorRetryQueue));
+            // Verify the caller can received the capabilities callback.
+            RcsContactUceCapability capability = waitForResult(capabilityQueue);
+            assertNotNull("Capabilities were not received", capability);
+            verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_NETWORK,
+                    REQUEST_RESULT_NOT_FOUND, false, false);
+            // Verity the ImsService received the request.
+            assertTrue(subscribeRequestCount.get() > 0);
+        } catch (Exception e) {
+            fail("testContactsInThrottlingState with command error failed: " + e);
+        } finally {
+            errorQueue.clear();
+            errorRetryQueue.clear();
+            capabilityQueue.clear();
+            completeQueue.clear();
+            subscribeRequestCount.set(0);
+        }
+
+        // Request the capabilities again with the same contact.
+        requestCapabilities(uceAdapter, numbers, callback);
+
+        // Verify that the result.
+        try {
+            // Verify that the caller can received the capabilities callback.
+            RcsContactUceCapability capability = waitForResult(capabilityQueue);
+            assertNotNull("Capabilities were not received", capability);
+            verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_CACHED,
+                    REQUEST_RESULT_NOT_FOUND, false, false);
+            // Verify the complete callback will be called.
+            waitForResult(completeQueue);
+            // Verify that the ImsService didn't received the request because the capabilities
+            // should be retrieved from the cache.
+            assertEquals(0, subscribeRequestCount.get());
+        } catch (Exception e) {
+            fail("testContactsInThrottlingState with command error failed: " + e);
+        } finally {
+            errorQueue.clear();
+            errorRetryQueue.clear();
+            subscribeRequestCount.set(0);
+            // reset the cache and throttling list
+            removeTestContactFromEab();
+            removeUceRequestDisallowedStatus();
+        }
+
+        // Request availability.
+        requestAvailability(uceAdapter, sTestNumberUri, callback);
+
+        // Verify that the callback "onError" is called with the expected error code.
+        try {
+            assertEquals(RcsUceAdapter.ERROR_REQUEST_TIMEOUT, waitForIntResult(errorQueue));
+            assertEquals(0L, waitForLongResult(errorRetryQueue));
+            // Verify the caller can received the capabilities callback.
+            RcsContactUceCapability capability = waitForResult(capabilityQueue);
+            assertNotNull("Capabilities were not received", capability);
+            verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_NETWORK,
+                    REQUEST_RESULT_NOT_FOUND, false, false);
+            // Verity the ImsService received the request.
+            assertTrue(subscribeRequestCount.get() > 0);
+        } catch (Exception e) {
+            fail("requestAvailability with command error failed: " + e);
+        } finally {
+            errorQueue.clear();
+            errorRetryQueue.clear();
+            capabilityQueue.clear();
+            completeQueue.clear();
+            subscribeRequestCount.set(0);
+        }
+
+        // Request availability again with the same contact.
+        requestAvailability(uceAdapter, sTestNumberUri, callback);
+
+        // Verify that the callback "onError" is called with the expected error code.
+        try {
+            // Verify that the caller can received the capabilities callback.
+            RcsContactUceCapability capability = waitForResult(capabilityQueue);
+            assertNotNull("Capabilities were not received", capability);
+            verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_CACHED,
+                    REQUEST_RESULT_NOT_FOUND, false, false);
+            // Verify the complete callback will be called.
+            waitForResult(completeQueue);
+            // Verify that the ImsService didn't received the request because the capabilities
+            // should be retrieved from the cache.
+            assertEquals(0, subscribeRequestCount.get());
+        } catch (Exception e) {
+            fail("testContactsInThrottlingState with command error failed: " + e);
+        } finally {
+            errorQueue.clear();
+            errorRetryQueue.clear();
+            subscribeRequestCount.set(0);
+            removeTestContactFromEab();
+            removeUceRequestDisallowedStatus();
+        }
+
+        overrideCarrierConfig(null);
+    }
+
+    @Test
+    public void testRequestResultInconclusive() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+        ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+        RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(sTestSub).getUceAdapter();
+        assertNotNull("UCE adapter should not be null!", uceAdapter);
+
+        // Remove the test contact capabilities
+        removeTestContactFromEab();
+        // Reset the UCE device state.
+        removeUceRequestDisallowedStatus();
+
+        // Connect to the ImsService
+        setupTestImsService(uceAdapter, true, true /* presence cap */, false /* options */);
+
+        TestRcsCapabilityExchangeImpl capabilityExchangeImpl = sServiceConnector
+                .getCarrierService().getRcsFeature().getRcsCapabilityExchangeImpl();
+
+        BlockingQueue<Integer> errorQueue = new LinkedBlockingQueue<>();
+        BlockingQueue<Long> errorRetryQueue = new LinkedBlockingQueue<>();
+        BlockingQueue<Boolean> completeQueue = new LinkedBlockingQueue<>();
+        BlockingQueue<RcsContactUceCapability> capabilityQueue = new LinkedBlockingQueue<>();
+        RcsUceAdapter.CapabilitiesCallback callback = new RcsUceAdapter.CapabilitiesCallback() {
+            @Override
+            public void onCapabilitiesReceived(List<RcsContactUceCapability> capabilities) {
+                capabilities.forEach(c -> capabilityQueue.offer(c));
+            }
+
+            @Override
+            public void onComplete() {
+                completeQueue.offer(true);
+            }
+
+            @Override
+            public void onError(int errorCode, long retryAfterMilliseconds) {
+                errorQueue.offer(errorCode);
+                errorRetryQueue.offer(retryAfterMilliseconds);
+            }
+        };
+
+        // In the first round, prepare the test account
+        Collection<Uri> numbers = new ArrayList<>();
+        numbers.add(sTestNumberUri);
+
+        ArrayList<String> pidfXmlList = new ArrayList<>();
+        pidfXmlList.add(getPidfXmlData(sTestNumberUri, true, true));
+
+        // Setup the network response is 200 OK for the first request
+        final int networkRespCode200 = 200;
+        final String networkRespReasonOK = "OK";
+        capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+            cb.onNetworkResponse(networkRespCode200, networkRespReasonOK);
+            cb.onNotifyCapabilitiesUpdate(pidfXmlList);
+            cb.onTerminated("", 0L);
+        });
+
+        // Request contact capabilities
+        requestCapabilities(uceAdapter, numbers, callback);
+
+        // Verify that the contact capability is received and the onCompleted is called.
+        try {
+            RcsContactUceCapability capability = waitForResult(capabilityQueue);
+            assertNotNull("Capabilities were not received", capability);
+            verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_NETWORK,
+                    REQUEST_RESULT_FOUND, true, true);
+            waitForResult(completeQueue);
+        } catch (Exception e) {
+            fail("testRequestResultInconclusive with command error failed: " + e);
+        } finally {
+            errorQueue.clear();
+            errorRetryQueue.clear();
+            capabilityQueue.clear();
+            completeQueue.clear();
+            numbers.clear();
+            pidfXmlList.clear();
+        }
+
+        // Request the second contacts and this time, the network respons is 408 Request Timeout
+        numbers.add(sTestContact2Uri);
+
+        final int networkRespCode408 = 408;
+        final String networkRespReasonTimeout = "Request Timeout";
+        AtomicInteger subscribeRequestCount = new AtomicInteger(0);
+        capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+            subscribeRequestCount.incrementAndGet();
+            cb.onNetworkResponse(networkRespCode408, networkRespReasonTimeout);
+        });
+
+        // Request contact capabilities again with different contact
+        requestCapabilities(uceAdapter, numbers, callback);
+
+        // Verify that the callback "onError" is called with the expected error code.
+        try {
+            assertEquals(RcsUceAdapter.ERROR_REQUEST_TIMEOUT, waitForIntResult(errorQueue));
+            assertEquals(0L, waitForLongResult(errorRetryQueue));
+            RcsContactUceCapability capability = waitForResult(capabilityQueue);
+            assertNotNull("Capabilities were not received", capability);
+            verifyCapabilityResult(capability, sTestContact2Uri, SOURCE_TYPE_NETWORK,
+                    REQUEST_RESULT_NOT_FOUND, false, false);
+            assertTrue(subscribeRequestCount.get() > 0);
+        } catch (Exception e) {
+            fail("testRequestResultInconclusive with command error failed: " + e);
+        } finally {
+            errorQueue.clear();
+            errorRetryQueue.clear();
+            capabilityQueue.clear();
+            completeQueue.clear();
+            numbers.clear();
+            pidfXmlList.clear();
+            subscribeRequestCount.set(0);
+        }
+
+        // Request three contacts at a time in the third round.
+        numbers.add(sTestNumberUri);
+        numbers.add(sTestContact2Uri);
+        numbers.add(sTestContact3Uri);
+
+        // The first two contact capabilities can be retrieved from the cache. However, the third
+        // contact capabilities will be provided by the ImsService
+        pidfXmlList.add(getPidfXmlData(sTestContact3Uri, true, true));
+
+        capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+            subscribeRequestCount.incrementAndGet();
+            assertNotNull("The uris of capabilities request cannot be null", uris);
+            List<Uri> uriList = new ArrayList(uris);
+            // Verify that only uri need to be queried from the network
+            assertEquals(1, uriList.size());
+            assertEquals(sTestContact3Uri, uriList.get(0));
+            cb.onNetworkResponse(networkRespCode200, networkRespReasonOK);
+            cb.onNotifyCapabilitiesUpdate(pidfXmlList);
+            cb.onTerminated("", 0L);
+        });
+
+        requestCapabilities(uceAdapter, numbers, callback);
+
+        List<RcsContactUceCapability> resultCapList = new ArrayList<>();
+
+        // Verify that the contact capability is received and the onCompleted is called.
+        try {
+            RcsContactUceCapability capability1 = waitForResult(capabilityQueue);
+            assertNotNull("Capabilities were not received", capability1);
+            resultCapList.add(capability1);
+
+            RcsContactUceCapability capability2 = waitForResult(capabilityQueue);
+            assertNotNull("Capabilities were not received", capability2);
+            resultCapList.add(capability2);
+
+            RcsContactUceCapability capability3 = waitForResult(capabilityQueue);
+            assertNotNull("Capabilities were not received", capability3);
+            resultCapList.add(capability3);
+
+            // Verify contact1's capabilities from the received capabilities list
+            RcsContactUceCapability resultCapability =
+                    getContactCapability(resultCapList, sTestNumberUri);
+            assertNotNull("Cannot find the contact", resultCapability);
+            verifyCapabilityResult(resultCapability, sTestNumberUri, SOURCE_TYPE_CACHED,
+                    REQUEST_RESULT_FOUND, true, true);
+
+            // Verify contact2's capabilities from the received capabilities list
+            resultCapability = getContactCapability(resultCapList, sTestContact2Uri);
+            assertNotNull("Cannot find the contact", resultCapability);
+            verifyCapabilityResult(resultCapability, sTestContact2Uri, SOURCE_TYPE_CACHED,
+                    REQUEST_RESULT_NOT_FOUND, false, false);
+
+            // Verify contact3's capabilities from the received capabilities list
+            resultCapability = getContactCapability(resultCapList, sTestContact3Uri);
+            assertNotNull("Cannot find the contact", sTestContact3Uri);
+            verifyCapabilityResult(resultCapability, sTestContact3Uri, SOURCE_TYPE_NETWORK,
+                    REQUEST_RESULT_FOUND, true, true);
+
+            // Verify the onCompleted is called
+            waitForResult(completeQueue);
+
+        } catch (Exception e) {
+            fail("testRequestResultInconclusive with command error failed: " + e);
+        } finally {
+            errorQueue.clear();
+            errorRetryQueue.clear();
+            capabilityQueue.clear();
+            completeQueue.clear();
+            numbers.clear();
+            pidfXmlList.clear();
+            removeTestContactFromEab();
+            removeUceRequestDisallowedStatus();
+        }
+
+        overrideCarrierConfig(null);
+    }
+
     private void setupTestImsService(RcsUceAdapter uceAdapter, boolean presencePublishEnabled,
             boolean presenceCapExchangeEnabled, boolean sipOptionsEnabled) throws Exception {
         // Trigger carrier config changed
diff --git a/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java b/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java
index ecff1a2..2fa4399 100644
--- a/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java
+++ b/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java
@@ -249,14 +249,7 @@
         }
         Log.i(TAG, "Retrieved dialog description " + dialogDescription);
 
-        if (isCar()) {
-            // Make sure Voice recognizer's app label is present in dialog.
-            assertWithMessage(
-                    "Voice recognition service can blame the calling app name " + APP_LABEL
-                            + ", but does not find it.")
-                    .that(dialogDescription)
-                    .contains(APP_LABEL);
-        } else if (trustVoiceService) {
+        if (trustVoiceService) {
             // Check trust recognizer can blame calling apmic permission
             assertWithMessage(
                     "Trusted voice recognition service can blame the calling app name " + APP_LABEL
diff --git a/tests/tests/widget/src/android/widget/cts/RemoteViewsFixedCollectionAdapterTest.java b/tests/tests/widget/src/android/widget/cts/RemoteViewsFixedCollectionAdapterTest.java
index 4c45564..ec76300 100644
--- a/tests/tests/widget/src/android/widget/cts/RemoteViewsFixedCollectionAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RemoteViewsFixedCollectionAdapterTest.java
@@ -70,6 +70,7 @@
 
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Function;
@@ -179,11 +180,15 @@
 
     @Test
     public void testParcelingAndUnparceling_multiplePackages() {
+        Optional<String> otherPackageName = getAnotherPackageName();
+        if (!otherPackageName.isPresent()) return;
         RemoteCollectionItems items = new RemoteCollectionItems.Builder()
                 .setHasStableIds(true)
                 .setViewTypeCount(10)
                 .addItem(3 /* id */, new RemoteViews(PACKAGE_NAME, R.layout.textview_singleline))
-                .addItem(5 /* id */, new RemoteViews(getOtherPackage(), R.layout.textview_gravity))
+                .addItem(
+                    5 /* id */,
+                    new RemoteViews(otherPackageName.get(), R.layout.textview_gravity))
                 .build();
 
         RemoteViews parent = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
@@ -200,7 +205,7 @@
         assertNotNull(unparceled.getItemView(0).mApplication);
         assertNotNull(unparceled.getItemView(1).mApplication);
         assertEquals(PACKAGE_NAME, unparceled.getItemView(0).mApplication.packageName);
-        assertEquals(getOtherPackage(), unparceled.getItemView(1).mApplication.packageName);
+        assertEquals(otherPackageName.get(), unparceled.getItemView(1).mApplication.packageName);
     }
 
     @Test
@@ -316,8 +321,10 @@
 
     @Test
     public void testSerializationSize_largeCollection_multiPackage() {
+        Optional<String> otherPackageName = getAnotherPackageName();
+        if (!otherPackageName.isPresent()) return;
         RemoteCollectionItems items =
-                createSampleMultiPackageCollectionItems(/* size= */ 100, getOtherPackage());
+                createSampleMultiPackageCollectionItems(/* size= */ 100, otherPackageName.get());
 
         int dataSize = parcelAndRun(items, Parcel::dataSize);
 
@@ -356,15 +363,16 @@
 
     @Test
     public void testSerializationSize_largeCollectionInLandPortRemoteViews_multiPackage() {
-        String otherPackage = getOtherPackage();
+        Optional<String> otherPackage = getAnotherPackageName();
+        if (!otherPackage.isPresent()) return;
         RemoteViews landscape = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
         landscape.setRemoteAdapter(
                 R.id.listview_default,
-                createSampleMultiPackageCollectionItems(/* size= */ 100, otherPackage));
+                createSampleMultiPackageCollectionItems(/* size= */ 100, otherPackage.get()));
         RemoteViews portrait = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
         landscape.setRemoteAdapter(
                 R.id.listview_default,
-                createSampleMultiPackageCollectionItems(/* size= */ 100, otherPackage));
+                createSampleMultiPackageCollectionItems(/* size= */ 100, otherPackage.get()));
 
         RemoteViews joinedRemoteViews = new RemoteViews(landscape, portrait);
 
@@ -399,7 +407,8 @@
 
     @Test
     public void testSerializationSize_largeCollectionInSizedRemoteViews_multiPackage() {
-        String otherPackage = getOtherPackage();
+        Optional<String> otherPackage = getAnotherPackageName();
+        if (!otherPackage.isPresent()) return;
         List<SizeF> sizes =
                 Lists.newArrayList(
                         new SizeF(50, 50),
@@ -409,7 +418,8 @@
         Map<SizeF, RemoteViews> sizeToRemoteViews =
                 sizes.stream().collect(Collectors.toMap(Function.identity(), ignored -> {
                     RemoteCollectionItems items =
-                            createSampleMultiPackageCollectionItems(/* size= */ 100, otherPackage);
+                            createSampleMultiPackageCollectionItems(
+                                    /* size= */ 100, otherPackage.get());
                     RemoteViews views = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
                     views.setRemoteAdapter(R.id.listview_default, items);
                     return views;
@@ -899,15 +909,12 @@
      * Returns a different package on the device that can be used for testing multi-package
      * collections.
      */
-    private String getOtherPackage() {
+    private Optional<String> getAnotherPackageName() {
         return mActivity.getPackageManager()
                 .getInstalledApplications(/* flags= */ 0)
                 .stream()
                 .filter(info -> !PACKAGE_NAME.equals(info.packageName))
                 .findFirst()
-                .map(info -> info.packageName)
-                .orElseThrow(
-                        () -> new AssertionError("Could not find any other applications to test "
-                                + "with"));
+                .map(info -> info.packageName);
     }
 }