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