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 }