Move UserRestrictionInstallTest to a separate test suite.

UserRestrictionInstallTest requires that the device is unrooted. Other
package installer tests may/may not need root. To prevent side effects
of enforcing no-root, move it to a separate suite.

Bug: 335455719
Bug: 321157732
Test: atest CtsUserRestrictionTestCases
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:68ec70762b0cb0ed50484cf79cf3147b1e8b88c7)

Change-Id: Ib90785ea1a0b4d75a951f089dada2f86bda87d77
Merged-In: Ifeae22ce34ff6d77fc6be6a9694e606e8ff34350
diff --git a/tests/tests/packageinstaller/TEST_MAPPING b/tests/tests/packageinstaller/TEST_MAPPING
index a17298a..205945a 100644
--- a/tests/tests/packageinstaller/TEST_MAPPING
+++ b/tests/tests/packageinstaller/TEST_MAPPING
@@ -1,4 +1,9 @@
 {
+  "postsubmit": [
+    {
+      "name": "CtsUserRestrictionTestCases"
+    }
+  ],
   "presubmit": [
     {
       "name": "CtsAdminPackageInstallerTestCases"
diff --git a/tests/tests/packageinstaller/userrestriction/Android.bp b/tests/tests/packageinstaller/userrestriction/Android.bp
new file mode 100644
index 0000000..df09a1e
--- /dev/null
+++ b/tests/tests/packageinstaller/userrestriction/Android.bp
@@ -0,0 +1,43 @@
+// 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+    name: "CtsUserRestrictionTestCases",
+    srcs: ["src/**/*.kt"],
+    static_libs: [
+        "androidx.core_core",
+        "androidx.test.ext.junit",
+        "androidx.test.rules",
+        "androidx.test.runner",
+        "androidx.test.uiautomator_uiautomator",
+        "junit",
+        "kotlin-test",
+        "truth",
+        "Nene",
+        "Harrier",
+        "platform-test-annotations",
+    ],
+    platform_apis: true,
+    test_suites: [
+        "cts",
+        "general-tests",
+    ],
+    data: [
+        ":CtsEmptyTestApp",
+    ],
+}
diff --git a/tests/tests/packageinstaller/userrestriction/AndroidManifest.xml b/tests/tests/packageinstaller/userrestriction/AndroidManifest.xml
new file mode 100644
index 0000000..1f0fada
--- /dev/null
+++ b/tests/tests/packageinstaller/userrestriction/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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="android.packageinstaller.userrestriction.cts" >
+
+    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
+
+    <application android:label="Cts User Restriction Install Tests">
+        <uses-library android:name="android.test.runner" />
+
+        <activity android:name="com.android.compatibility.common.util.FutureResultActivity" />
+
+        <provider android:authorities="android.packageinstaller.userrestriction.cts.fileprovider"
+            android:name="androidx.core.content.FileProvider"
+            android:grantUriPermissions="true">
+            <meta-data
+                android:name="android.support.FILE_PROVIDER_PATHS"
+                android:resource="@xml/file_paths" />
+        </provider>
+    </application>
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:functionalTest="true"
+                     android:targetPackage="android.packageinstaller.userrestriction.cts"
+                     android:label="Install with User Restriction Tests"/>
+
+</manifest>
diff --git a/tests/tests/packageinstaller/userrestriction/AndroidTest.xml b/tests/tests/packageinstaller/userrestriction/AndroidTest.xml
new file mode 100644
index 0000000..1f41356
--- /dev/null
+++ b/tests/tests/packageinstaller/userrestriction/AndroidTest.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+
+<configuration description="Config for CTS Packageinstaller UserRestriction test cases">
+    <option name="test-suite-tag" value="cts" />
+    <option name="config-descriptor:metadata" key="component" value="packagemanager" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+    <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
+    <option name="config-descriptor:metadata" key="parameter" value="multiuser" />
+
+    <!-- disable GPP UI -->
+    <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+        <option name="force-skip-system-props" value="true" />
+        <option name="set-global-setting" key="verifier_engprod" value="1" />
+        <option name="set-global-setting" key="verifier_verify_adb_installs" value="0" />
+        <option name="restore-settings" value="true" />
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsUserRestrictionTestCases.apk" />
+    </target_preparer>
+
+    <target_preparer
+        class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <option name="cleanup" value="true" />
+        <option name="push" value="CtsEmptyTestApp.apk->/data/local/tmp/cts/packageinstaller/CtsEmptyTestApp.apk" />
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="appops set android.packageinstaller.userrestriction.cts REQUEST_INSTALL_PACKAGES allow" />
+        <option name="teardown-command" value="appops set android.packageinstaller.userrestriction.cts REQUEST_INSTALL_PACKAGES default" />
+        <!-- Ensure the UI is ready and in an idle state before running tests -->
+        <option name="run-command" value="input keyevent KEYCODE_WAKEUP" />
+        <option name="run-command" value="wm dismiss-keyguard" />
+        <!-- Collapse notifications -->
+        <option name="run-command" value="cmd statusbar collapse" />
+        <!-- dismiss all system dialogs before launch test -->
+        <option name="run-command" value="am broadcast -a android.intent.action.CLOSE_SYSTEM_DIALOGS" />
+    </target_preparer>
+
+    <!-- Do not remove this (b/277987631) -->
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+        <option name="force-root" value="false" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.packageinstaller.userrestriction.cts" />
+        <option name="runtime-hint" value="1m" />
+        <option name="exclude-annotation" value="com.android.bedstead.harrier.annotations.RequireRunOnWorkProfile" />
+        <option name="exclude-annotation" value="com.android.bedstead.harrier.annotations.RequireRunOnSecondaryUser" />
+    </test>
+
+</configuration>
diff --git a/tests/tests/packageinstaller/userrestriction/res/xml/file_paths.xml b/tests/tests/packageinstaller/userrestriction/res/xml/file_paths.xml
new file mode 100644
index 0000000..80b7e2d
--- /dev/null
+++ b/tests/tests/packageinstaller/userrestriction/res/xml/file_paths.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 Google Inc.
+
+     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.
+-->
+
+<paths xmlns:android="http://schemas.android.com/apk/res/android">
+    <files-path name="apk" path="/" />
+</paths>
\ No newline at end of file
diff --git a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/UserRestrictionInstallTest.kt b/tests/tests/packageinstaller/userrestriction/src/android/packageinstaller/userrestriction/cts/UserRestrictionInstallTest.kt
similarity index 61%
rename from tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/UserRestrictionInstallTest.kt
rename to tests/tests/packageinstaller/userrestriction/src/android/packageinstaller/userrestriction/cts/UserRestrictionInstallTest.kt
index 7eb7a6f..e6641ef 100644
--- a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/UserRestrictionInstallTest.kt
+++ b/tests/tests/packageinstaller/userrestriction/src/android/packageinstaller/userrestriction/cts/UserRestrictionInstallTest.kt
@@ -1,11 +1,11 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2024 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
+ *      https://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,
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
-package android.packageinstaller.install.cts
+package android.packageinstaller.userrestriction.cts
 
 import android.app.Activity
 import android.app.PendingIntent
+import android.content.Context
 import android.content.Intent
 import android.content.pm.PackageInstaller.EXTRA_STATUS
 import android.content.pm.PackageInstaller.STATUS_FAILURE_INVALID
@@ -25,9 +26,17 @@
 import android.content.pm.PackageInstaller.Session
 import android.content.pm.PackageInstaller.SessionParams
 import android.platform.test.annotations.AppModeFull
+import android.util.Log
 import androidx.core.content.FileProvider
+import androidx.test.InstrumentationRegistry
+import androidx.test.rule.ActivityTestRule
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.BySelector
+import androidx.test.uiautomator.UiDevice
 import androidx.test.uiautomator.UiObject
+import androidx.test.uiautomator.UiObject2
 import androidx.test.uiautomator.UiSelector
+import androidx.test.uiautomator.Until
 import com.android.bedstead.harrier.BedsteadJUnit4
 import com.android.bedstead.harrier.DeviceState
 import com.android.bedstead.harrier.UserType
@@ -39,7 +48,7 @@
 import com.android.bedstead.harrier.annotations.RequireRunOnWorkProfile
 import com.android.bedstead.harrier.annotations.enterprise.DevicePolicyRelevant
 import com.android.bedstead.nene.TestApis
-import com.android.bedstead.nene.appops.CommonAppOps.OPSTR_REQUEST_INSTALL_PACKAGES
+import android.app.AppOpsManager.OPSTR_REQUEST_INSTALL_PACKAGES
 import com.android.bedstead.nene.exceptions.AdbException
 import com.android.bedstead.nene.permissions.CommonPermissions.INTERACT_ACROSS_USERS_FULL
 import com.android.bedstead.nene.userrestrictions.CommonUserRestrictions.DISALLOW_DEBUGGING_FEATURES
@@ -48,11 +57,15 @@
 import com.android.bedstead.nene.utils.ShellCommand
 import com.android.compatibility.common.util.ApiTest
 import com.android.compatibility.common.util.BlockingBroadcastReceiver
+import com.android.compatibility.common.util.FutureResultActivity
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
 import java.io.File
+import java.util.concurrent.CompletableFuture
 import java.util.concurrent.TimeUnit
+import java.util.regex.Pattern
 import kotlin.test.assertFailsWith
+import org.junit.Assert
 import org.junit.Assert.fail
 import org.junit.Before
 import org.junit.ClassRule
@@ -62,17 +75,39 @@
 
 @RunWith(BedsteadJUnit4::class)
 @AppModeFull(reason = "DEVICE_POLICY_SERVICE is null in instant mode")
-class UserRestrictionInstallTest : PackageInstallerTestBase() {
-    private val APP_INSTALL_ACTION =
-            "android.packageinstaller.install.cts.UserRestrictionInstallTest.action"
+class UserRestrictionInstallTest {
 
     companion object {
+        const val INSTALL_BUTTON_ID = "button1"
+        const val CANCEL_BUTTON_ID = "button2"
+
+        const val PACKAGE_INSTALLER_PACKAGE_NAME = "com.android.packageinstaller"
+        const val SYSTEM_PACKAGE_NAME = "android"
+
+        const val TEST_APK_NAME = "CtsEmptyTestApp.apk"
+        const val TEST_APK_PACKAGE_NAME = "android.packageinstaller.emptytestapp.cts"
+        const val TEST_APK_LOCATION = "/data/local/tmp/cts/packageinstaller"
+
+        const val CONTENT_AUTHORITY = "android.packageinstaller.userrestriction.cts.fileprovider"
+        const val APP_INSTALL_ACTION = "android.packageinstaller.userrestriction.cts.action"
+
+        const val TIMEOUT = 60000L
+
         @JvmField
         @ClassRule
         @Rule
         val sDeviceState = DeviceState()
     }
 
+    val TAG = UserRestrictionInstallTest::class.java.simpleName
+
+    @get:Rule
+    val installDialogStarter = ActivityTestRule(FutureResultActivity::class.java)
+
+    val context: Context = InstrumentationRegistry.getTargetContext()
+    val apkFile = File(context.filesDir, TEST_APK_NAME)
+    val uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
+
     @Before
     fun uninstallTestApp() {
         val cmd = ShellCommand.builder("pm uninstall")
@@ -84,6 +119,11 @@
         }
     }
 
+    @Before
+    fun copyTestApk() {
+        File(TEST_APK_LOCATION, TEST_APK_NAME).copyTo(target = apkFile, overwrite = true)
+    }
+
     @Test
     @ApiTest(apis = ["android.os.UserManager#DISALLOW_DEBUGGING_FEATURES"])
     @DevicePolicyRelevant
@@ -97,13 +137,15 @@
         installPackageViaAdb(apkPath = "$TEST_APK_LOCATION/$TEST_APK_NAME")
 
         assertWithMessage("Test app should be installed in initial user")
-                .that(TestApis.packages().find(TEST_APK_PACKAGE_NAME).installedOnUser(initialUser))
-                .isTrue()
+            .that(TestApis.packages().find(TEST_APK_PACKAGE_NAME).installedOnUser(initialUser))
+            .isTrue()
 
-        assertWithMessage("Test app shouldn't be installed in a work profile with " +
-                "$DISALLOW_DEBUGGING_FEATURES set")
-                .that(TestApis.packages().find(TEST_APK_PACKAGE_NAME).installedOnUser(workProfile))
-                .isFalse()
+        assertWithMessage(
+            "Test app shouldn't be installed in a work profile with " +
+                "$DISALLOW_DEBUGGING_FEATURES set"
+        )
+            .that(TestApis.packages().find(TEST_APK_PACKAGE_NAME).installedOnUser(workProfile))
+            .isFalse()
     }
 
     @Test
@@ -117,10 +159,12 @@
 
         installPackageViaAdb(apkPath = "$TEST_APK_LOCATION/$TEST_APK_NAME", user = workProfile)
 
-        assertWithMessage("Test app shouldn't be installed in a work profile with " +
-                "$DISALLOW_DEBUGGING_FEATURES set")
-                .that(TestApis.packages().find(TEST_APK_PACKAGE_NAME).installedOnUser(workProfile))
-                .isFalse()
+        assertWithMessage(
+            "Test app shouldn't be installed in a work profile with " +
+                "$DISALLOW_DEBUGGING_FEATURES set"
+        )
+            .that(TestApis.packages().find(TEST_APK_PACKAGE_NAME).installedOnUser(workProfile))
+            .isFalse()
     }
 
     @Test
@@ -138,7 +182,7 @@
             val result: Intent? = commitSessionAsUser(workProfile, session)
             assertThat(result).isNotNull()
             assertThat(result!!.getIntExtra(EXTRA_STATUS, STATUS_FAILURE_INVALID))
-                    .isEqualTo(STATUS_PENDING_USER_ACTION)
+                .isEqualTo(STATUS_PENDING_USER_ACTION)
         } finally {
             session.abandon()
         }
@@ -153,7 +197,7 @@
     @RequireRunOnWorkProfile
     fun disallowDebuggingFeatures_intentInstallOnWorkProfile_installationSucceeds() {
         val context = TestApis.context().instrumentedContext()
-        val apkFile = File(context.filesDir, TEST_APK_NAME)
+        // val apkFile = File(context.filesDir, TEST_APK_NAME)
         val appInstallIntent = getAppInstallationIntent(apkFile)
 
         val installation = startInstallationViaIntent(appInstallIntent)
@@ -168,8 +212,10 @@
     @DevicePolicyRelevant
     @EnsureHasWorkProfile
     @EnsureHasUserRestriction(value = DISALLOW_INSTALL_APPS, onUser = UserType.WORK_PROFILE)
-    @EnsureDoesNotHaveUserRestriction(value = DISALLOW_DEBUGGING_FEATURES,
-            onUser = UserType.WORK_PROFILE)
+    @EnsureDoesNotHaveUserRestriction(
+        value = DISALLOW_DEBUGGING_FEATURES,
+        onUser = UserType.WORK_PROFILE
+    )
     fun disallowInstallApps_adbInstallOnAllUsers_installedOnUnrestrictedUser() {
         val initialUser = sDeviceState.initialUser()
         val workProfile = sDeviceState.workProfile()
@@ -180,14 +226,17 @@
             it.packageName().equals(TEST_APK_PACKAGE_NAME)
         }
         assertWithMessage("Test app should be installed in initial user")
-                .that(targetPackage.size).isNotEqualTo(0)
+            .that(targetPackage.size)
+            .isNotEqualTo(0)
 
         targetPackage = TestApis.packages().installedForUser(workProfile).filter {
             it.packageName().equals(TEST_APK_PACKAGE_NAME)
         }
-        assertWithMessage("Test app shouldn't be installed in a work profile with " +
-                "$DISALLOW_INSTALL_APPS set")
-                .that(targetPackage.size).isEqualTo(0)
+        assertWithMessage(
+            "Test app shouldn't be installed in a work profile with $DISALLOW_INSTALL_APPS set"
+        )
+            .that(targetPackage.size)
+            .isEqualTo(0)
     }
 
     @Test
@@ -195,21 +244,27 @@
     @DevicePolicyRelevant
     @EnsureHasWorkProfile
     @EnsureHasUserRestriction(value = DISALLOW_INSTALL_APPS, onUser = UserType.WORK_PROFILE)
-    @EnsureDoesNotHaveUserRestriction(value = DISALLOW_DEBUGGING_FEATURES,
-            onUser = UserType.WORK_PROFILE)
+    @EnsureDoesNotHaveUserRestriction(
+        value = DISALLOW_DEBUGGING_FEATURES,
+        onUser = UserType.WORK_PROFILE
+    )
     fun disallowInstallApps_adbInstallOnWorkProfile_fails() {
         val workProfile = sDeviceState.workProfile()
-        assertThat(TestApis.devicePolicy().userRestrictions(workProfile)
-                .isSet(DISALLOW_INSTALL_APPS)).isTrue()
+        assertThat(
+            TestApis.devicePolicy().userRestrictions(workProfile).isSet(DISALLOW_INSTALL_APPS)
+        ).isTrue()
 
         installPackageViaAdb(apkPath = "$TEST_APK_LOCATION/$TEST_APK_NAME", user = workProfile)
 
         val targetPackage = TestApis.packages().installedForUser(workProfile).filter {
             it.packageName().equals(TEST_APK_PACKAGE_NAME)
         }
-        assertWithMessage("Test app shouldn't be installed in a work profile with " +
-                "$DISALLOW_DEBUGGING_FEATURES set")
-                .that(targetPackage.size).isEqualTo(0)
+        assertWithMessage(
+            "Test app shouldn't be installed in a work profile with " +
+                "$DISALLOW_DEBUGGING_FEATURES set"
+        )
+            .that(targetPackage.size)
+            .isEqualTo(0)
     }
 
     @Test
@@ -217,8 +272,10 @@
     @DevicePolicyRelevant
     @EnsureHasWorkProfile
     @EnsureHasUserRestriction(value = DISALLOW_INSTALL_APPS, onUser = UserType.WORK_PROFILE)
-    @EnsureDoesNotHaveUserRestriction(value = DISALLOW_DEBUGGING_FEATURES,
-            onUser = UserType.WORK_PROFILE)
+    @EnsureDoesNotHaveUserRestriction(
+        value = DISALLOW_DEBUGGING_FEATURES,
+        onUser = UserType.WORK_PROFILE
+    )
     @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL)
     fun disallowInstallApps_sessionInstallOnWorkProfile_throwsException() {
         val workProfile = sDeviceState.workProfile()
@@ -231,13 +288,15 @@
     @ApiTest(apis = ["android.os.UserManager#DISALLOW_INSTALL_APPS"])
     @DevicePolicyRelevant
     @EnsureHasUserRestriction(value = DISALLOW_INSTALL_APPS, onUser = UserType.WORK_PROFILE)
-    @EnsureDoesNotHaveUserRestriction(value = DISALLOW_DEBUGGING_FEATURES,
-            onUser = UserType.WORK_PROFILE)
+    @EnsureDoesNotHaveUserRestriction(
+        value = DISALLOW_DEBUGGING_FEATURES,
+        onUser = UserType.WORK_PROFILE
+    )
     @EnsureHasAppOp(OPSTR_REQUEST_INSTALL_PACKAGES)
     @RequireRunOnWorkProfile
     fun disallowInstallApps_intentInstallOnWorkProfile_installationFails() {
         val context = TestApis.context().instrumentedContext()
-        val apkFile = File(context.filesDir, TEST_APK_NAME)
+        // val apkFile = File(context.filesDir, TEST_APK_NAME)
         val appInstallIntent = getAppInstallationIntent(apkFile)
 
         val installation = startInstallationViaIntent(appInstallIntent)
@@ -249,24 +308,30 @@
 
         // Install should have failed
         assertThat(installation.get(TIMEOUT, TimeUnit.MILLISECONDS))
-                .isEqualTo(Activity.RESULT_CANCELED)
+            .isEqualTo(Activity.RESULT_CANCELED)
     }
 
     @Test
-    @ApiTest(apis = ["android.os.UserManager#DISALLOW_DEBUGGING_FEATURES",
-        "android.os.UserManager#DISALLOW_INSTALL_APPS"])
+    @ApiTest(
+        apis = ["android.os.UserManager#DISALLOW_DEBUGGING_FEATURES",
+        "android.os.UserManager#DISALLOW_INSTALL_APPS"]
+    )
     @DevicePolicyRelevant
     @EnsureHasWorkProfile
-    @EnsureDoesNotHaveUserRestriction(value = DISALLOW_DEBUGGING_FEATURES,
-            onUser = UserType.WORK_PROFILE)
+    @EnsureDoesNotHaveUserRestriction(
+        value = DISALLOW_DEBUGGING_FEATURES,
+        onUser = UserType.WORK_PROFILE
+    )
     @EnsureDoesNotHaveUserRestriction(value = DISALLOW_INSTALL_APPS, onUser = UserType.WORK_PROFILE)
     fun unrestrictedWorkProfile_adbInstallOnAllUsers_installedOnAllUsers() {
         val initialUser = sDeviceState.initialUser()
         val workProfile = sDeviceState.workProfile()
-        assertThat(TestApis.devicePolicy().userRestrictions(workProfile)
-                .isSet(DISALLOW_DEBUGGING_FEATURES)).isFalse()
-        assertThat(TestApis.devicePolicy().userRestrictions(workProfile)
-                .isSet(DISALLOW_INSTALL_APPS)).isFalse()
+        assertThat(
+            TestApis.devicePolicy().userRestrictions(workProfile).isSet(DISALLOW_DEBUGGING_FEATURES)
+        ).isFalse()
+        assertThat(
+            TestApis.devicePolicy().userRestrictions(workProfile).isSet(DISALLOW_INSTALL_APPS)
+        ).isFalse()
 
         installPackageViaAdb(apkPath = "$TEST_APK_LOCATION/$TEST_APK_NAME")
 
@@ -274,13 +339,22 @@
             it.packageName().equals(TEST_APK_PACKAGE_NAME)
         }
         assertWithMessage("Test app should be installed in initial user")
-                .that(targetPackage.size).isNotEqualTo(0)
+            .that(targetPackage.size)
+            .isNotEqualTo(0)
 
         targetPackage = TestApis.packages().installedForUser(workProfile).filter {
             it.packageName().equals(TEST_APK_PACKAGE_NAME)
         }
         assertWithMessage("Test app should be installed in work profile")
-                .that(targetPackage.size).isNotEqualTo(0)
+            .that(targetPackage.size)
+            .isNotEqualTo(0)
+    }
+
+    /**
+     * Start an installation via an Intent
+     */
+    private fun startInstallationViaIntent(intent: Intent): CompletableFuture<Int> {
+        return installDialogStarter.activity.startActivityForResult(intent)
     }
 
     private fun installPackageViaAdb(apkPath: String, user: UserReference? = null): String? {
@@ -310,11 +384,11 @@
     }
 
     private fun writeSessionAsUser(
-            user: UserReference = sDeviceState.initialUser(),
-            session: Session
+        user: UserReference = sDeviceState.initialUser(),
+        session: Session
     ) {
         val context = TestApis.context().androidContextAsUser(user)
-        val apkFile = File(context.filesDir, TEST_APK_NAME)
+        // val apkFile = File(context.filesDir, TEST_APK_NAME)
         // Write data to session
         apkFile.inputStream().use { fileOnDisk ->
             session.openWrite(TEST_APK_NAME, 0, -1).use { sessionFile ->
@@ -324,8 +398,8 @@
     }
 
     private fun commitSessionAsUser(
-            user: UserReference = sDeviceState.initialUser(),
-            session: Session
+        user: UserReference = sDeviceState.initialUser(),
+        session: Session
     ): Intent? {
         val context = TestApis.context().androidContextAsUser(user)
         val receiver: BlockingBroadcastReceiver =
@@ -335,8 +409,11 @@
         val intent = Intent(APP_INSTALL_ACTION).setPackage(context.packageName)
                 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
         val pendingIntent = PendingIntent.getBroadcast(
-                context, 0 /* requestCode */, intent,
-                PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE)
+            context,
+            0 /* requestCode */,
+            intent,
+            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
+        )
 
         session.commit(pendingIntent.intentSender)
 
@@ -351,4 +428,65 @@
         intent.putExtra(Intent.EXTRA_RETURN_RESULT, true)
         return intent
     }
+
+    /**
+     * Click a button in the UI of the installer app
+     *
+     * @param resId The resource ID of the button to click
+     */
+    fun clickInstallerUIButton(resId: String) {
+        clickInstallerUIButton(getBySelector(resId))
+    }
+
+    fun getBySelector(id: String): BySelector {
+        // Normally, we wouldn't need to look for buttons from 2 different packages.
+        // However, to fix b/297132020, AlertController was replaced with AlertDialog and shared
+        // to selective partners, leading to fragmentation in which button surfaces in an OEM's
+        // installer app.
+        return By.res(
+            Pattern.compile(
+                String.format(
+                    "(?:^%s|^%s):id/%s", PACKAGE_INSTALLER_PACKAGE_NAME, SYSTEM_PACKAGE_NAME, id
+                )
+            )
+        )
+    }
+
+    /**
+     * Click a button in the UI of the installer app
+     *
+     * @param bySelector The bySelector of the button to click
+     */
+    fun clickInstallerUIButton(bySelector: BySelector) {
+        var button: UiObject2? = null
+        val startTime = System.currentTimeMillis()
+        while (startTime + TIMEOUT > System.currentTimeMillis()) {
+            try {
+                button = uiDevice.wait(Until.findObject(bySelector), 1000)
+                if (button != null) {
+                    Log.d(
+                        TAG,
+                        "Found bounds: ${button.getVisibleBounds()} of button $bySelector," +
+                        " text: ${button.getText()}," +
+                        " package: ${button.getApplicationPackage()}"
+                    )
+                    button.click()
+                    return
+                } else {
+                    // Maybe the screen is small. Swipe down and attempt to click
+                    swipeDown()
+                }
+            } catch (ignore: Throwable) {
+            }
+        }
+        Assert.fail("Failed to click the button: $bySelector")
+    }
+
+    private fun swipeDown() {
+        // Perform a swipe from the center of the screen to the top of the screen.
+        // Higher the "steps" value, slower is the swipe
+        val centerX = uiDevice.displayWidth / 2
+        val centerY = uiDevice.displayHeight / 2
+        uiDevice.swipe(centerX, centerY, centerX, 0, 10)
+    }
 }