1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.permissioncontroller.permissionui.ui.handheld 18 19 import android.Manifest.permission.ACCESS_COARSE_LOCATION 20 import android.content.Intent 21 import android.content.pm.PackageManager 22 import android.permission.cts.PermissionUtils.grantPermission 23 import android.permission.cts.PermissionUtils.install 24 import android.permission.cts.PermissionUtils.revokePermission 25 import android.permission.cts.PermissionUtils.uninstallApp 26 import android.platform.test.annotations.RequiresFlagsEnabled 27 import android.platform.test.flag.junit.DeviceFlagsValueProvider 28 import android.util.Log 29 import androidx.test.ext.junit.runners.AndroidJUnit4 30 import androidx.test.uiautomator.By 31 import com.android.compatibility.common.util.SystemUtil.eventually 32 import com.android.compatibility.common.util.SystemUtil.getEventually 33 import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity 34 import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObjectOrNull 35 import com.android.permission.flags.Flags 36 import com.android.permissioncontroller.permissionui.getUsageCountsFromUi 37 import com.android.permissioncontroller.permissionui.wakeUpScreen 38 import com.google.common.truth.Truth.assertThat 39 import org.junit.After 40 import org.junit.Assert.assertNull 41 import org.junit.Before 42 import org.junit.Rule 43 import org.junit.Test 44 import org.junit.runner.RunWith 45 46 /** Simple tests for {@link ManageStandardPermissionsFragment} */ 47 @RunWith(AndroidJUnit4::class) 48 class ManageStandardPermissionsFragmentTest : BaseHandheldPermissionUiTest() { 49 50 @JvmField @Rule val checkFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() 51 52 @Before setupnull53 fun setup() { 54 wakeUpScreen() 55 56 runWithShellPermissionIdentity { 57 removePackageIfInstalled() 58 instrumentationContext.startActivity( 59 Intent(Intent.ACTION_MANAGE_PERMISSIONS).apply { 60 addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) 61 } 62 ) 63 } 64 } 65 66 @After tearDownnull67 fun tearDown() { 68 uninstallApp(LOCATION_USER_PKG) 69 uninstallApp(ADDITIONAL_DEFINER_PKG) 70 uninstallApp(ADDITIONAL_USER_PKG) 71 uiDevice.pressBack() 72 } 73 74 /** 75 * The test packages are not expected to be installed already, remove them if they are already 76 * installed (i.e. leftover from another test) when a test starts. 77 */ removePackageIfInstallednull78 private fun removePackageIfInstalled() { 79 val packageNames = listOf(LOCATION_USER_PKG, ADDITIONAL_DEFINER_PKG, ADDITIONAL_USER_PKG) 80 for (packageName in packageNames) { 81 try { 82 val packageInfo = 83 instrumentationContext.packageManager.getPackageInfo(packageName, 0) 84 if (packageInfo != null) { 85 Log.w(LOG_TAG, "package $packageName not expected to be installed.") 86 uninstallApp(packageName) 87 Thread.sleep(1000) 88 } 89 } catch (e: PackageManager.NameNotFoundException) { 90 // ignore 91 } 92 } 93 } 94 95 /** 96 * Read the number of additional permissions from the Ui. 97 * 98 * @return number of additional permissions 99 */ getAdditionalPermissionCountnull100 private fun getAdditionalPermissionCount(): Int { 101 waitFindObjectOrNull(By.textContains(ADDITIONAL_PERMISSIONS_LABEL)) ?: return 0 102 // Sometimes the entire preference disappears while it's searching for the app count 103 // (during uninstalling). Hence also return the count as 0 if count doesn't exist 104 val additionalPermissionsSummary = 105 waitFindObjectOrNull(By.textContains(ADDITIONAL_PERMISSIONS_SUMMARY)) ?: return 0 106 val additionalPermissionsSummaryText = additionalPermissionsSummary.getText() 107 108 // Matches a single number out of the summary line, i.e. "...3..." -> "3" 109 return getEventually { 110 Regex("^[^\\d]*(\\d+)[^\\d]*\$") 111 .find(additionalPermissionsSummaryText)!! 112 .groupValues[1] 113 .toInt() 114 } 115 } 116 117 @Test groupSummaryGetsUpdatedWhenAppGetsInstallednull118 fun groupSummaryGetsUpdatedWhenAppGetsInstalled() { 119 val original = getUsageCountsFromUi(LOCATION_GROUP_LABEL) 120 121 install(LOCATION_USER_APK) 122 eventually( 123 { 124 val afterInstall = getUsageCountsFromUi(LOCATION_GROUP_LABEL) 125 assertThat(afterInstall.granted).isEqualTo(original.granted) 126 assertThat(afterInstall.total).isEqualTo(original.total + 1) 127 }, 128 TIMEOUT, 129 ) 130 } 131 132 @Test groupSummaryGetsUpdatedWhenAppGetsUninstallednull133 fun groupSummaryGetsUpdatedWhenAppGetsUninstalled() { 134 val original = getUsageCountsFromUi(LOCATION_GROUP_LABEL) 135 install(LOCATION_USER_APK) 136 eventually( 137 { assertThat(getUsageCountsFromUi(LOCATION_GROUP_LABEL)).isNotEqualTo(original) }, 138 TIMEOUT, 139 ) 140 141 uninstallApp(LOCATION_USER_PKG) 142 eventually( 143 { assertThat(getUsageCountsFromUi(LOCATION_GROUP_LABEL)).isEqualTo(original) }, 144 TIMEOUT, 145 ) 146 } 147 148 @Test groupSummaryGetsUpdatedWhenPermissionGetsGrantednull149 fun groupSummaryGetsUpdatedWhenPermissionGetsGranted() { 150 val original = getUsageCountsFromUi(LOCATION_GROUP_LABEL) 151 152 install(LOCATION_USER_APK) 153 eventually( 154 { 155 assertThat(getUsageCountsFromUi(LOCATION_GROUP_LABEL).total) 156 .isEqualTo(original.total + 1) 157 }, 158 TIMEOUT, 159 ) 160 161 grantPermission(LOCATION_USER_PKG, ACCESS_COARSE_LOCATION) 162 eventually { 163 assertThat(getUsageCountsFromUi(LOCATION_GROUP_LABEL).granted) 164 .isEqualTo(original.granted + 1) 165 } 166 } 167 168 @Test groupSummaryGetsUpdatedWhenPermissionGetsRevokednull169 fun groupSummaryGetsUpdatedWhenPermissionGetsRevoked() { 170 val original = getUsageCountsFromUi(LOCATION_GROUP_LABEL) 171 172 install(LOCATION_USER_APK) 173 grantPermission(LOCATION_USER_PKG, ACCESS_COARSE_LOCATION) 174 eventually( 175 { 176 assertThat(getUsageCountsFromUi(LOCATION_GROUP_LABEL).total) 177 .isNotEqualTo(original.total) 178 assertThat(getUsageCountsFromUi(LOCATION_GROUP_LABEL).granted) 179 .isNotEqualTo(original.granted) 180 }, 181 TIMEOUT, 182 ) 183 184 revokePermission(LOCATION_USER_PKG, ACCESS_COARSE_LOCATION) 185 eventually { 186 assertThat(getUsageCountsFromUi(LOCATION_GROUP_LABEL).granted) 187 .isEqualTo(original.granted) 188 } 189 } 190 191 @Test additionalPermissionSummaryGetUpdateWhenAppGetsInstallednull192 fun additionalPermissionSummaryGetUpdateWhenAppGetsInstalled() { 193 val additionalPermissionBefore = getAdditionalPermissionCount() 194 195 install(ADDITIONAL_DEFINER_APK) 196 install(ADDITIONAL_USER_APK) 197 eventually( 198 { 199 assertThat(getAdditionalPermissionCount()).isEqualTo(additionalPermissionBefore + 1) 200 }, 201 TIMEOUT, 202 ) 203 } 204 205 @Test additionalPermissionSummaryGetUpdateWhenUserGetsUninstallednull206 fun additionalPermissionSummaryGetUpdateWhenUserGetsUninstalled() { 207 val additionalPermissionBefore = getAdditionalPermissionCount() 208 209 install(ADDITIONAL_DEFINER_APK) 210 install(ADDITIONAL_USER_APK) 211 eventually( 212 { assertThat(getAdditionalPermissionCount()).isNotEqualTo(additionalPermissionBefore) }, 213 TIMEOUT, 214 ) 215 216 uninstallApp(ADDITIONAL_USER_PKG) 217 eventually( 218 { assertThat(getAdditionalPermissionCount()).isEqualTo(additionalPermissionBefore) }, 219 TIMEOUT, 220 ) 221 } 222 223 @Test additionalPermissionSummaryGetUpdateWhenDefinerGetsUninstallednull224 fun additionalPermissionSummaryGetUpdateWhenDefinerGetsUninstalled() { 225 val additionalPermissionBefore = getAdditionalPermissionCount() 226 227 install(ADDITIONAL_DEFINER_APK) 228 install(ADDITIONAL_USER_APK) 229 eventually( 230 { assertThat(getAdditionalPermissionCount()).isNotEqualTo(additionalPermissionBefore) }, 231 TIMEOUT, 232 ) 233 234 uninstallApp(ADDITIONAL_DEFINER_PKG) 235 eventually( 236 { assertThat(getAdditionalPermissionCount()).isEqualTo(additionalPermissionBefore) }, 237 TIMEOUT, 238 ) 239 } 240 241 @Test 242 @RequiresFlagsEnabled(Flags.FLAG_DECLUTTERED_PERMISSION_MANAGER_ENABLED) noUnusedPermissionGroupDisplayedInTheMainPagenull243 fun noUnusedPermissionGroupDisplayedInTheMainPage() { 244 eventually { assertNull(waitFindObjectOrNull(By.hasChild(By.textStartsWith("0 of 0")))) } 245 eventually { assertNull(waitFindObjectOrNull(By.hasChild(By.textStartsWith("0/0")))) } 246 } 247 248 companion object { 249 private val LOG_TAG = ManageStandardPermissionsFragmentTest::class.java.simpleName 250 251 private const val LOCATION_USER_APK = 252 "/data/local/tmp/pc-permissionui/AppThatRequestsLocation.apk" 253 private const val ADDITIONAL_DEFINER_APK = 254 "/data/local/tmp/pc-permissionui/" + "PermissionUiDefineAdditionalPermissionApp.apk" 255 private const val ADDITIONAL_USER_APK = 256 "/data/local/tmp/pc-permissionui/" + "PermissionUiUseAdditionalPermissionApp.apk" 257 private const val LOCATION_USER_PKG = "android.permission.cts.appthatrequestpermission" 258 private const val ADDITIONAL_DEFINER_PKG = 259 "com.android.permissioncontroller.tests.appthatdefinespermission" 260 private const val ADDITIONAL_USER_PKG = 261 "com.android.permissioncontroller.tests.appthatrequestpermission" 262 private const val ADDITIONAL_PERMISSIONS_LABEL = "Additional permissions" 263 private const val ADDITIONAL_PERMISSIONS_SUMMARY = "more" 264 private const val LOCATION_GROUP_LABEL = "Location" 265 266 // Package Added/Removed broadcast are pretty slow on cf devices, we may want to increase 267 // this in future if the test still fails. 268 private const val TIMEOUT = 30000L 269 } 270 } 271