1 /* 2 * Copyright (C) 2021 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.systemui.privacy 18 19 import android.app.ActivityManager 20 import android.content.Context 21 import android.content.Intent 22 import android.content.pm.ActivityInfo 23 import android.content.pm.ApplicationInfo 24 import android.content.pm.PackageManager 25 import android.content.pm.PackageManager.ResolveInfoFlags 26 import android.content.pm.ResolveInfo 27 import android.content.pm.UserInfo 28 import android.os.Process.SYSTEM_UID 29 import android.os.UserHandle 30 import android.permission.PermissionGroupUsage 31 import android.permission.PermissionManager 32 import android.testing.AndroidTestingRunner 33 import androidx.test.filters.SmallTest 34 import com.android.internal.logging.UiEventLogger 35 import com.android.systemui.SysuiTestCase 36 import com.android.systemui.appops.AppOpsController 37 import com.android.systemui.plugins.ActivityStarter 38 import com.android.systemui.privacy.logging.PrivacyLogger 39 import com.android.systemui.settings.UserTracker 40 import com.android.systemui.statusbar.policy.KeyguardStateController 41 import com.android.systemui.util.concurrency.FakeExecutor 42 import com.android.systemui.util.mockito.capture 43 import com.android.systemui.util.mockito.eq 44 import com.android.systemui.util.time.FakeSystemClock 45 import com.google.common.truth.Truth.assertThat 46 import org.junit.After 47 import org.junit.Before 48 import org.junit.Test 49 import org.junit.runner.RunWith 50 import org.mockito.ArgumentCaptor 51 import org.mockito.ArgumentMatchers.any 52 import org.mockito.ArgumentMatchers.anyBoolean 53 import org.mockito.ArgumentMatchers.anyInt 54 import org.mockito.ArgumentMatchers.anyString 55 import org.mockito.Captor 56 import org.mockito.Mock 57 import org.mockito.Mockito.`when` 58 import org.mockito.Mockito.atLeastOnce 59 import org.mockito.Mockito.mock 60 import org.mockito.Mockito.never 61 import org.mockito.Mockito.times 62 import org.mockito.Mockito.verify 63 import org.mockito.MockitoAnnotations 64 65 @SmallTest 66 @RunWith(AndroidTestingRunner::class) 67 class PrivacyDialogControllerTest : SysuiTestCase() { 68 69 companion object { 70 private const val USER_ID = 0 71 private const val ENT_USER_ID = 10 72 73 private const val TEST_PACKAGE_NAME = "test package name" 74 private const val TEST_ATTRIBUTION_TAG = "test attribution tag" 75 private const val TEST_PROXY_LABEL = "test proxy label" 76 77 private const val PERM_CAMERA = android.Manifest.permission_group.CAMERA 78 private const val PERM_MICROPHONE = android.Manifest.permission_group.MICROPHONE 79 private const val PERM_LOCATION = android.Manifest.permission_group.LOCATION 80 } 81 82 @Mock 83 private lateinit var dialog: PrivacyDialog 84 @Mock 85 private lateinit var permissionManager: PermissionManager 86 @Mock 87 private lateinit var packageManager: PackageManager 88 @Mock 89 private lateinit var privacyItemController: PrivacyItemController 90 @Mock 91 private lateinit var userTracker: UserTracker 92 @Mock 93 private lateinit var activityStarter: ActivityStarter 94 @Mock 95 private lateinit var privacyLogger: PrivacyLogger 96 @Mock 97 private lateinit var keyguardStateController: KeyguardStateController 98 @Mock 99 private lateinit var appOpsController: AppOpsController 100 @Captor 101 private lateinit var dialogDismissedCaptor: ArgumentCaptor<PrivacyDialog.OnDialogDismissed> 102 @Captor 103 private lateinit var activityStartedCaptor: ArgumentCaptor<ActivityStarter.Callback> 104 @Captor 105 private lateinit var intentCaptor: ArgumentCaptor<Intent> 106 @Mock 107 private lateinit var uiEventLogger: UiEventLogger 108 109 private val backgroundExecutor = FakeExecutor(FakeSystemClock()) 110 private val uiExecutor = FakeExecutor(FakeSystemClock()) 111 private lateinit var controller: PrivacyDialogController 112 private var nextUid: Int = 0 113 114 private val dialogProvider = object : PrivacyDialogController.DialogProvider { 115 var list: List<PrivacyDialog.PrivacyElement>? = null 116 var starter: ((String, Int, CharSequence?, Intent?) -> Unit)? = null 117 118 override fun makeDialog( 119 context: Context, 120 list: List<PrivacyDialog.PrivacyElement>, 121 starter: (String, Int, CharSequence?, Intent?) -> Unit 122 ): PrivacyDialog { 123 this.list = list 124 this.starter = starter 125 return dialog 126 } 127 } 128 129 @Before 130 fun setUp() { 131 MockitoAnnotations.initMocks(this) 132 nextUid = 0 133 setUpDefaultMockResponses() 134 135 controller = PrivacyDialogController( 136 permissionManager, 137 packageManager, 138 privacyItemController, 139 userTracker, 140 activityStarter, 141 backgroundExecutor, 142 uiExecutor, 143 privacyLogger, 144 keyguardStateController, 145 appOpsController, 146 uiEventLogger, 147 dialogProvider 148 ) 149 } 150 151 @After 152 fun tearDown() { 153 FakeExecutor.exhaustExecutors(uiExecutor, backgroundExecutor) 154 dialogProvider.list = null 155 dialogProvider.starter = null 156 } 157 158 @Test 159 fun testMicMutedParameter() { 160 `when`(appOpsController.isMicMuted).thenReturn(true) 161 controller.showDialog(context) 162 backgroundExecutor.runAllReady() 163 164 verify(permissionManager).getIndicatorAppOpUsageData(true) 165 } 166 167 @Test 168 fun testPermissionManagerOnlyCalledInBackgroundThread() { 169 controller.showDialog(context) 170 verify(permissionManager, never()).getIndicatorAppOpUsageData(anyBoolean()) 171 backgroundExecutor.runAllReady() 172 verify(permissionManager).getIndicatorAppOpUsageData(anyBoolean()) 173 } 174 175 @Test 176 fun testPackageManagerOnlyCalledInBackgroundThread() { 177 val usage = createMockPermGroupUsage() 178 `when`(usage.isPhoneCall).thenReturn(false) 179 `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) 180 181 controller.showDialog(context) 182 verify(packageManager, never()).getApplicationInfoAsUser(anyString(), anyInt(), anyInt()) 183 backgroundExecutor.runAllReady() 184 verify(packageManager, atLeastOnce()) 185 .getApplicationInfoAsUser(anyString(), anyInt(), anyInt()) 186 } 187 188 @Test 189 fun testShowDialogShowsDialog() { 190 val usage = createMockPermGroupUsage() 191 `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) 192 193 controller.showDialog(context) 194 exhaustExecutors() 195 196 verify(dialog).show() 197 } 198 199 @Test 200 fun testDontShowEmptyDialog() { 201 controller.showDialog(context) 202 exhaustExecutors() 203 204 verify(dialog, never()).show() 205 } 206 207 @Test 208 fun testHideDialogDismissesDialogIfShown() { 209 val usage = createMockPermGroupUsage() 210 `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) 211 controller.showDialog(context) 212 exhaustExecutors() 213 214 controller.dismissDialog() 215 verify(dialog).dismiss() 216 } 217 218 @Test 219 fun testHideDialogNoopIfNotShown() { 220 controller.dismissDialog() 221 verify(dialog, never()).dismiss() 222 } 223 224 @Test 225 fun testHideDialogNoopAfterDismissed() { 226 val usage = createMockPermGroupUsage() 227 `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) 228 controller.showDialog(context) 229 exhaustExecutors() 230 231 verify(dialog).addOnDismissListener(capture(dialogDismissedCaptor)) 232 233 dialogDismissedCaptor.value.onDialogDismissed() 234 controller.dismissDialog() 235 verify(dialog, never()).dismiss() 236 } 237 238 @Test 239 fun testShowForAllUsers() { 240 val usage = createMockPermGroupUsage() 241 `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) 242 controller.showDialog(context) 243 244 exhaustExecutors() 245 verify(dialog).setShowForAllUsers(true) 246 } 247 248 @Test 249 fun testSingleElementInList() { 250 val usage = createMockPermGroupUsage( 251 packageName = TEST_PACKAGE_NAME, 252 uid = generateUidForUser(USER_ID), 253 permissionGroupName = PERM_CAMERA, 254 lastAccessTimeMillis = 5L, 255 isActive = true, 256 isPhoneCall = false, 257 attributionTag = null, 258 proxyLabel = TEST_PROXY_LABEL 259 ) 260 `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) 261 262 controller.showDialog(context) 263 exhaustExecutors() 264 265 dialogProvider.list?.let { list -> 266 assertThat(list.get(0).type).isEqualTo(PrivacyType.TYPE_CAMERA) 267 assertThat(list.get(0).packageName).isEqualTo(TEST_PACKAGE_NAME) 268 assertThat(list.get(0).userId).isEqualTo(USER_ID) 269 assertThat(list.get(0).applicationName).isEqualTo(TEST_PACKAGE_NAME) 270 assertThat(list.get(0).attributionTag).isNull() 271 assertThat(list.get(0).attributionLabel).isNull() 272 assertThat(list.get(0).proxyLabel).isEqualTo(TEST_PROXY_LABEL) 273 assertThat(list.get(0).lastActiveTimestamp).isEqualTo(5L) 274 assertThat(list.get(0).active).isTrue() 275 assertThat(list.get(0).phoneCall).isFalse() 276 assertThat(list.get(0).enterprise).isFalse() 277 assertThat(list.get(0).permGroupName).isEqualTo(PERM_CAMERA) 278 assertThat(isIntentEqual(list.get(0).navigationIntent!!, 279 controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID))) 280 .isTrue() 281 } 282 } 283 284 private fun isIntentEqual(actual: Intent, expected: Intent): Boolean { 285 return actual.action == expected.action && 286 actual.getStringExtra(Intent.EXTRA_PACKAGE_NAME) == 287 expected.getStringExtra(Intent.EXTRA_PACKAGE_NAME) && 288 actual.getParcelableExtra(Intent.EXTRA_USER) as? UserHandle == 289 expected.getParcelableExtra(Intent.EXTRA_USER) as? UserHandle 290 } 291 292 @Test 293 fun testTwoElementsDifferentType_sorted() { 294 val usage_camera = createMockPermGroupUsage( 295 packageName = "${TEST_PACKAGE_NAME}_camera", 296 permissionGroupName = PERM_CAMERA 297 ) 298 val usage_microphone = createMockPermGroupUsage( 299 packageName = "${TEST_PACKAGE_NAME}_microphone", 300 permissionGroupName = PERM_MICROPHONE 301 ) 302 `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn( 303 listOf(usage_microphone, usage_camera) 304 ) 305 306 controller.showDialog(context) 307 exhaustExecutors() 308 309 dialogProvider.list?.let { list -> 310 assertThat(list).hasSize(2) 311 assertThat(list.get(0).type.compareTo(list.get(1).type)).isLessThan(0) 312 } 313 } 314 315 @Test 316 fun testTwoElementsSameType_oneActive() { 317 val usage_active = createMockPermGroupUsage( 318 packageName = "${TEST_PACKAGE_NAME}_active", 319 isActive = true 320 ) 321 val usage_recent = createMockPermGroupUsage( 322 packageName = "${TEST_PACKAGE_NAME}_recent", 323 isActive = false 324 ) 325 `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn( 326 listOf(usage_recent, usage_active) 327 ) 328 329 controller.showDialog(context) 330 exhaustExecutors() 331 332 assertThat(dialogProvider.list).hasSize(1) 333 assertThat(dialogProvider.list?.get(0)?.active).isTrue() 334 } 335 336 @Test 337 fun testTwoElementsSameType_twoActive() { 338 val usage_active = createMockPermGroupUsage( 339 packageName = "${TEST_PACKAGE_NAME}_active", 340 isActive = true, 341 lastAccessTimeMillis = 0L 342 ) 343 val usage_active_moreRecent = createMockPermGroupUsage( 344 packageName = "${TEST_PACKAGE_NAME}_active_recent", 345 isActive = true, 346 lastAccessTimeMillis = 1L 347 ) 348 `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn( 349 listOf(usage_active, usage_active_moreRecent) 350 ) 351 controller.showDialog(context) 352 exhaustExecutors() 353 assertThat(dialogProvider.list).hasSize(2) 354 assertThat(dialogProvider.list?.get(0)?.lastActiveTimestamp).isEqualTo(1L) 355 assertThat(dialogProvider.list?.get(1)?.lastActiveTimestamp).isEqualTo(0L) 356 } 357 358 @Test 359 fun testManyElementsSameType_bothRecent() { 360 val usage_recent = createMockPermGroupUsage( 361 packageName = "${TEST_PACKAGE_NAME}_recent", 362 isActive = false, 363 lastAccessTimeMillis = 0L 364 ) 365 val usage_moreRecent = createMockPermGroupUsage( 366 packageName = "${TEST_PACKAGE_NAME}_moreRecent", 367 isActive = false, 368 lastAccessTimeMillis = 1L 369 ) 370 val usage_mostRecent = createMockPermGroupUsage( 371 packageName = "${TEST_PACKAGE_NAME}_mostRecent", 372 isActive = false, 373 lastAccessTimeMillis = 2L 374 ) 375 `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn( 376 listOf(usage_recent, usage_mostRecent, usage_moreRecent) 377 ) 378 379 controller.showDialog(context) 380 exhaustExecutors() 381 382 assertThat(dialogProvider.list).hasSize(1) 383 assertThat(dialogProvider.list?.get(0)?.lastActiveTimestamp).isEqualTo(2L) 384 } 385 386 @Test 387 fun testMicAndCameraDisabled() { 388 val usage_camera = createMockPermGroupUsage( 389 permissionGroupName = PERM_CAMERA 390 ) 391 val usage_microphone = createMockPermGroupUsage( 392 permissionGroupName = PERM_MICROPHONE 393 ) 394 val usage_location = createMockPermGroupUsage( 395 permissionGroupName = PERM_LOCATION 396 ) 397 398 `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn( 399 listOf(usage_camera, usage_location, usage_microphone) 400 ) 401 `when`(privacyItemController.micCameraAvailable).thenReturn(false) 402 403 controller.showDialog(context) 404 exhaustExecutors() 405 406 assertThat(dialogProvider.list).hasSize(1) 407 assertThat(dialogProvider.list?.get(0)?.type).isEqualTo(PrivacyType.TYPE_LOCATION) 408 } 409 410 @Test 411 fun testLocationDisabled() { 412 val usage_camera = createMockPermGroupUsage( 413 permissionGroupName = PERM_CAMERA 414 ) 415 val usage_microphone = createMockPermGroupUsage( 416 permissionGroupName = PERM_MICROPHONE 417 ) 418 val usage_location = createMockPermGroupUsage( 419 permissionGroupName = PERM_LOCATION 420 ) 421 422 `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn( 423 listOf(usage_camera, usage_location, usage_microphone) 424 ) 425 `when`(privacyItemController.locationAvailable).thenReturn(false) 426 427 controller.showDialog(context) 428 exhaustExecutors() 429 430 assertThat(dialogProvider.list).hasSize(2) 431 dialogProvider.list?.forEach { 432 assertThat(it.type).isNotEqualTo(PrivacyType.TYPE_LOCATION) 433 } 434 } 435 436 @Test 437 fun testAllIndicatorsAvailable() { 438 val usage_camera = createMockPermGroupUsage( 439 permissionGroupName = PERM_CAMERA 440 ) 441 val usage_microphone = createMockPermGroupUsage( 442 permissionGroupName = PERM_MICROPHONE 443 ) 444 val usage_location = createMockPermGroupUsage( 445 permissionGroupName = PERM_LOCATION 446 ) 447 448 `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn( 449 listOf(usage_camera, usage_location, usage_microphone) 450 ) 451 `when`(privacyItemController.micCameraAvailable).thenReturn(true) 452 `when`(privacyItemController.locationAvailable).thenReturn(true) 453 454 controller.showDialog(context) 455 exhaustExecutors() 456 457 assertThat(dialogProvider.list).hasSize(3) 458 } 459 460 @Test 461 fun testNoIndicatorsAvailable() { 462 val usage_camera = createMockPermGroupUsage( 463 permissionGroupName = PERM_CAMERA 464 ) 465 val usage_microphone = createMockPermGroupUsage( 466 permissionGroupName = PERM_MICROPHONE 467 ) 468 val usage_location = createMockPermGroupUsage( 469 permissionGroupName = PERM_LOCATION 470 ) 471 472 `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn( 473 listOf(usage_camera, usage_location, usage_microphone) 474 ) 475 `when`(privacyItemController.micCameraAvailable).thenReturn(false) 476 `when`(privacyItemController.locationAvailable).thenReturn(false) 477 478 controller.showDialog(context) 479 exhaustExecutors() 480 481 verify(dialog, never()).show() 482 } 483 484 @Test 485 fun testEnterpriseUser() { 486 val usage_enterprise = createMockPermGroupUsage( 487 uid = generateUidForUser(ENT_USER_ID) 488 ) 489 `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())) 490 .thenReturn(listOf(usage_enterprise)) 491 492 controller.showDialog(context) 493 exhaustExecutors() 494 495 assertThat(dialogProvider.list?.single()?.enterprise).isTrue() 496 } 497 498 @Test 499 fun testNotCurrentUser() { 500 val usage_other = createMockPermGroupUsage( 501 uid = generateUidForUser(ENT_USER_ID + 1) 502 ) 503 `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())) 504 .thenReturn(listOf(usage_other)) 505 506 controller.showDialog(context) 507 exhaustExecutors() 508 509 verify(dialog, never()).show() 510 } 511 512 @Test 513 fun testStartActivityCorrectIntent() { 514 val usage = createMockPermGroupUsage() 515 `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) 516 controller.showDialog(context) 517 exhaustExecutors() 518 519 dialogProvider.starter?.invoke(TEST_PACKAGE_NAME, USER_ID, null, null) 520 verify(activityStarter) 521 .startActivity(capture(intentCaptor), eq(true), any<ActivityStarter.Callback>()) 522 523 assertThat(intentCaptor.value.action).isEqualTo(Intent.ACTION_MANAGE_APP_PERMISSIONS) 524 assertThat(intentCaptor.value.getStringExtra(Intent.EXTRA_PACKAGE_NAME)) 525 .isEqualTo(TEST_PACKAGE_NAME) 526 assertThat(intentCaptor.value.getParcelableExtra(Intent.EXTRA_USER) as? UserHandle) 527 .isEqualTo(UserHandle.of(USER_ID)) 528 } 529 530 @Test 531 fun testStartActivityCorrectIntent_enterpriseUser() { 532 val usage = createMockPermGroupUsage() 533 `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) 534 controller.showDialog(context) 535 exhaustExecutors() 536 537 dialogProvider.starter?.invoke(TEST_PACKAGE_NAME, ENT_USER_ID, null, null) 538 verify(activityStarter) 539 .startActivity(capture(intentCaptor), eq(true), any<ActivityStarter.Callback>()) 540 541 assertThat(intentCaptor.value.getParcelableExtra(Intent.EXTRA_USER) as? UserHandle) 542 .isEqualTo(UserHandle.of(ENT_USER_ID)) 543 } 544 545 @Test 546 fun testStartActivitySuccess() { 547 val usage = createMockPermGroupUsage() 548 `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) 549 controller.showDialog(context) 550 exhaustExecutors() 551 552 dialogProvider.starter?.invoke(TEST_PACKAGE_NAME, USER_ID, null, null) 553 verify(activityStarter).startActivity(any(), eq(true), capture(activityStartedCaptor)) 554 555 activityStartedCaptor.value.onActivityStarted(ActivityManager.START_DELIVERED_TO_TOP) 556 557 verify(dialog).dismiss() 558 } 559 560 @Test 561 fun testStartActivityFailure() { 562 val usage = createMockPermGroupUsage() 563 `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) 564 controller.showDialog(context) 565 exhaustExecutors() 566 567 dialogProvider.starter?.invoke(TEST_PACKAGE_NAME, USER_ID, null, null) 568 verify(activityStarter).startActivity(any(), eq(true), capture(activityStartedCaptor)) 569 570 activityStartedCaptor.value.onActivityStarted(ActivityManager.START_ABORTED) 571 572 verify(dialog, never()).dismiss() 573 } 574 575 @Test 576 fun testCallOnSecondaryUser() { 577 // Calls happen in 578 val usage = createMockPermGroupUsage(uid = SYSTEM_UID, isPhoneCall = true) 579 `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) 580 `when`(userTracker.userProfiles).thenReturn(listOf( 581 UserInfo(ENT_USER_ID, "", 0) 582 )) 583 584 controller.showDialog(context) 585 exhaustExecutors() 586 587 verify(dialog).show() 588 } 589 590 @Test 591 fun testStartActivityLogs() { 592 val usage = createMockPermGroupUsage() 593 `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) 594 controller.showDialog(context) 595 exhaustExecutors() 596 597 dialogProvider.starter?.invoke(TEST_PACKAGE_NAME, USER_ID, null, null) 598 verify(uiEventLogger).log(PrivacyDialogEvent.PRIVACY_DIALOG_ITEM_CLICKED_TO_APP_SETTINGS, 599 USER_ID, TEST_PACKAGE_NAME) 600 } 601 602 @Test 603 fun testDismissedDialogLogs() { 604 val usage = createMockPermGroupUsage() 605 `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) 606 controller.showDialog(context) 607 exhaustExecutors() 608 609 verify(dialog).addOnDismissListener(capture(dialogDismissedCaptor)) 610 611 dialogDismissedCaptor.value.onDialogDismissed() 612 613 controller.dismissDialog() 614 615 verify(uiEventLogger, times(1)).log(PrivacyDialogEvent.PRIVACY_DIALOG_DISMISSED) 616 } 617 618 @Test 619 fun testInvalidAttributionTag() { 620 val usage = createMockPermGroupUsage( 621 packageName = TEST_PACKAGE_NAME, 622 uid = generateUidForUser(USER_ID), 623 permissionGroupName = PERM_CAMERA, 624 lastAccessTimeMillis = 5L, 625 isActive = true, 626 isPhoneCall = false, 627 attributionTag = "INVALID_ATTRIBUTION_TAG", 628 proxyLabel = TEST_PROXY_LABEL 629 ) 630 `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) 631 632 controller.showDialog(context) 633 exhaustExecutors() 634 635 dialogProvider.list?.let { list -> 636 assertThat(list.get(0).type).isEqualTo(PrivacyType.TYPE_CAMERA) 637 assertThat(list.get(0).packageName).isEqualTo(TEST_PACKAGE_NAME) 638 assertThat(list.get(0).userId).isEqualTo(USER_ID) 639 assertThat(list.get(0).applicationName).isEqualTo(TEST_PACKAGE_NAME) 640 assertThat(list.get(0).attributionTag).isEqualTo("INVALID_ATTRIBUTION_TAG") 641 assertThat(list.get(0).attributionLabel).isNull() 642 assertThat(list.get(0).proxyLabel).isEqualTo(TEST_PROXY_LABEL) 643 assertThat(list.get(0).lastActiveTimestamp).isEqualTo(5L) 644 assertThat(list.get(0).active).isTrue() 645 assertThat(list.get(0).phoneCall).isFalse() 646 assertThat(list.get(0).enterprise).isFalse() 647 assertThat(list.get(0).permGroupName).isEqualTo(PERM_CAMERA) 648 assertThat(isIntentEqual(list.get(0).navigationIntent!!, 649 controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID))) 650 .isTrue() 651 } 652 } 653 654 @Test 655 fun testCorrectIntentSubAttribution() { 656 val usage = createMockPermGroupUsage( 657 attributionTag = TEST_ATTRIBUTION_TAG, 658 attributionLabel = "TEST_LABEL" 659 ) 660 661 val activityInfo = createMockActivityInfo() 662 val resolveInfo = createMockResolveInfo(activityInfo) 663 `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) 664 `when`(packageManager.resolveActivity(any(), any<ResolveInfoFlags>())) 665 .thenAnswer { resolveInfo } 666 controller.showDialog(context) 667 exhaustExecutors() 668 669 dialogProvider.list?.let { list -> 670 val navigationIntent = list.get(0).navigationIntent!! 671 assertThat(navigationIntent.action).isEqualTo(Intent.ACTION_MANAGE_PERMISSION_USAGE) 672 assertThat(navigationIntent.getStringExtra(Intent.EXTRA_PERMISSION_GROUP_NAME)) 673 .isEqualTo(PERM_CAMERA) 674 assertThat(navigationIntent.getStringArrayExtra(Intent.EXTRA_ATTRIBUTION_TAGS)) 675 .isEqualTo(arrayOf(TEST_ATTRIBUTION_TAG.toString())) 676 assertThat(navigationIntent.getBooleanExtra(Intent.EXTRA_SHOWING_ATTRIBUTION, false)) 677 .isTrue() 678 } 679 } 680 681 @Test 682 fun testDefaultIntentOnMissingAttributionLabel() { 683 val usage = createMockPermGroupUsage( 684 attributionTag = TEST_ATTRIBUTION_TAG 685 ) 686 687 val activityInfo = createMockActivityInfo() 688 val resolveInfo = createMockResolveInfo(activityInfo) 689 `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) 690 `when`(packageManager.resolveActivity(any(), any<ResolveInfoFlags>())) 691 .thenAnswer { resolveInfo } 692 controller.showDialog(context) 693 exhaustExecutors() 694 695 dialogProvider.list?.let { list -> 696 assertThat(isIntentEqual(list.get(0).navigationIntent!!, 697 controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID))) 698 .isTrue() 699 } 700 } 701 702 @Test 703 fun testDefaultIntentOnIncorrectPermission() { 704 val usage = createMockPermGroupUsage( 705 attributionTag = TEST_ATTRIBUTION_TAG 706 ) 707 708 val activityInfo = createMockActivityInfo( 709 permission = "INCORRECT_PERMISSION" 710 ) 711 val resolveInfo = createMockResolveInfo(activityInfo) 712 `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) 713 `when`(packageManager.resolveActivity(any(), any<ResolveInfoFlags>())) 714 .thenAnswer { resolveInfo } 715 controller.showDialog(context) 716 exhaustExecutors() 717 718 dialogProvider.list?.let { list -> 719 assertThat(isIntentEqual(list.get(0).navigationIntent!!, 720 controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID))) 721 .isTrue() 722 } 723 } 724 725 private fun exhaustExecutors() { 726 FakeExecutor.exhaustExecutors(backgroundExecutor, uiExecutor) 727 } 728 729 private fun setUpDefaultMockResponses() { 730 `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(emptyList()) 731 `when`(appOpsController.isMicMuted).thenReturn(false) 732 733 `when`(packageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) 734 .thenAnswer { FakeApplicationInfo(it.getArgument(0)) } 735 736 `when`(privacyItemController.locationAvailable).thenReturn(true) 737 `when`(privacyItemController.micCameraAvailable).thenReturn(true) 738 739 `when`(userTracker.userProfiles).thenReturn(listOf( 740 UserInfo(USER_ID, "", 0), 741 UserInfo(ENT_USER_ID, "", UserInfo.FLAG_MANAGED_PROFILE) 742 )) 743 744 `when`(keyguardStateController.isUnlocked).thenReturn(true) 745 } 746 747 private class FakeApplicationInfo(val label: CharSequence) : ApplicationInfo() { 748 override fun loadLabel(pm: PackageManager): CharSequence { 749 return label 750 } 751 } 752 753 private fun generateUidForUser(user: Int): Int { 754 return user * UserHandle.PER_USER_RANGE + nextUid++ 755 } 756 757 private fun createMockResolveInfo( 758 activityInfo: ActivityInfo? = null 759 ): ResolveInfo { 760 val resolveInfo = mock(ResolveInfo::class.java) 761 resolveInfo.activityInfo = activityInfo 762 return resolveInfo 763 } 764 765 private fun createMockActivityInfo( 766 permission: String = android.Manifest.permission.START_VIEW_PERMISSION_USAGE, 767 className: String = "TEST_CLASS_NAME" 768 ): ActivityInfo { 769 val activityInfo = mock(ActivityInfo::class.java) 770 activityInfo.permission = permission 771 activityInfo.name = className 772 return activityInfo 773 } 774 775 private fun createMockPermGroupUsage( 776 packageName: String = TEST_PACKAGE_NAME, 777 uid: Int = generateUidForUser(USER_ID), 778 permissionGroupName: String = PERM_CAMERA, 779 lastAccessTimeMillis: Long = 0L, 780 isActive: Boolean = false, 781 isPhoneCall: Boolean = false, 782 attributionTag: CharSequence? = null, 783 attributionLabel: CharSequence? = null, 784 proxyLabel: CharSequence? = null 785 ): PermissionGroupUsage { 786 val usage = mock(PermissionGroupUsage::class.java) 787 `when`(usage.packageName).thenReturn(packageName) 788 `when`(usage.uid).thenReturn(uid) 789 `when`(usage.permissionGroupName).thenReturn(permissionGroupName) 790 `when`(usage.lastAccessTimeMillis).thenReturn(lastAccessTimeMillis) 791 `when`(usage.isActive).thenReturn(isActive) 792 `when`(usage.isPhoneCall).thenReturn(isPhoneCall) 793 `when`(usage.attributionTag).thenReturn(attributionTag) 794 `when`(usage.attributionLabel).thenReturn(attributionLabel) 795 `when`(usage.proxyLabel).thenReturn(proxyLabel) 796 return usage 797 } 798 }