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 }