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)
+ }
}