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.testing.AndroidTestingRunner
20 import android.testing.TestableLooper
21 import android.view.View
22 import android.view.ViewGroup
23 import android.widget.TextView
24 import androidx.test.filters.SmallTest
25 import com.android.systemui.R
26 import com.android.systemui.SysuiTestCase
27 import com.google.common.truth.Truth.assertThat
28 import org.junit.After
29 import org.junit.Before
30 import org.junit.Test
31 import org.junit.runner.RunWith
32 import org.mockito.Mock
33 import org.mockito.Mockito.mock
34 import org.mockito.Mockito.never
35 import org.mockito.Mockito.verify
36 import org.mockito.MockitoAnnotations
37 import android.content.Intent
38 import android.text.TextUtils
39 
40 @SmallTest
41 @RunWith(AndroidTestingRunner::class)
42 @TestableLooper.RunWithLooper(setAsMainLooper = true)
43 class PrivacyDialogTest : SysuiTestCase() {
44 
45     companion object {
46         private const val TEST_PACKAGE_NAME = "test_pkg"
47         private const val TEST_USER_ID = 0
48         private const val TEST_PERM_GROUP = "test_perm_group"
49     }
50 
51     @Mock
52     private lateinit var starter: (String, Int, CharSequence?, Intent?) -> Unit
53     private lateinit var dialog: PrivacyDialog
54 
55     @Before
56     fun setUp() {
57         MockitoAnnotations.initMocks(this)
58     }
59 
60     @After
61     fun teardown() {
62         if (this::dialog.isInitialized) {
63             dialog.dismiss()
64         }
65     }
66 
67     @Test
68     fun testStarterCalledWithCorrectParams() {
69         val list = listOf(
70                 PrivacyDialog.PrivacyElement(
71                         PrivacyType.TYPE_MICROPHONE,
72                         TEST_PACKAGE_NAME,
73                         TEST_USER_ID,
74                         "App",
75                         null,
76                         null,
77                         null,
78                         0L,
79                         false,
80                         false,
81                         false,
82                         TEST_PERM_GROUP,
83                         null
84                 )
85         )
86         dialog = PrivacyDialog(context, list, starter)
87         dialog.show()
88         dialog.requireViewById<View>(R.id.privacy_item).callOnClick()
89         verify(starter).invoke(TEST_PACKAGE_NAME, TEST_USER_ID, null, null)
90     }
91 
92     @Test
93     fun testDismissListenerCalledOnDismiss() {
94         dialog = PrivacyDialog(context, emptyList(), starter)
95         val dismissListener = mock(PrivacyDialog.OnDialogDismissed::class.java)
96         dialog.addOnDismissListener(dismissListener)
97         dialog.show()
98 
99         verify(dismissListener, never()).onDialogDismissed()
100         dialog.dismiss()
101         verify(dismissListener).onDialogDismissed()
102     }
103 
104     @Test
105     fun testDismissListenerCalledImmediatelyIfDialogAlreadyDismissed() {
106         dialog = PrivacyDialog(context, emptyList(), starter)
107         val dismissListener = mock(PrivacyDialog.OnDialogDismissed::class.java)
108         dialog.show()
109         dialog.dismiss()
110 
111         dialog.addOnDismissListener(dismissListener)
112         verify(dismissListener).onDialogDismissed()
113     }
114 
115     @Test
116     fun testCorrectNumElements() {
117         val list = listOf(
118                 PrivacyDialog.PrivacyElement(
119                         PrivacyType.TYPE_CAMERA,
120                         TEST_PACKAGE_NAME,
121                         TEST_USER_ID,
122                         "App",
123                         null,
124                         null,
125                         null,
126                         0L,
127                         true,
128                         false,
129                         false,
130                         TEST_PERM_GROUP,
131                         null
132                 ),
133                 PrivacyDialog.PrivacyElement(
134                         PrivacyType.TYPE_MICROPHONE,
135                         TEST_PACKAGE_NAME,
136                         TEST_USER_ID,
137                         "App",
138                         null,
139                         null,
140                         null,
141                         0L,
142                         false,
143                         false,
144                         false,
145                         TEST_PERM_GROUP,
146                         null
147                 )
148         )
149         dialog = PrivacyDialog(context, list, starter)
150         dialog.show()
151         assertThat(dialog.requireViewById<ViewGroup>(R.id.root).childCount).isEqualTo(2)
152     }
153 
154     @Test
155     fun testUsingText() {
156         val element = PrivacyDialog.PrivacyElement(
157                 PrivacyType.TYPE_CAMERA,
158                 TEST_PACKAGE_NAME,
159                 TEST_USER_ID,
160                 "App",
161                 null,
162                 null,
163                 null,
164                 0L,
165                 true,
166                 false,
167                 false,
168                 TEST_PERM_GROUP,
169                 null
170         )
171 
172         val list = listOf(element)
173         dialog = PrivacyDialog(context, list, starter)
174         dialog.show()
175         assertThat(dialog.requireViewById<TextView>(R.id.text).text).isEqualTo(
176                 context.getString(
177                         R.string.ongoing_privacy_dialog_using_op,
178                         element.applicationName,
179                         element.type.getName(context)
180                 )
181         )
182     }
183 
184     @Test
185     fun testRecentText() {
186         val element = PrivacyDialog.PrivacyElement(
187                 PrivacyType.TYPE_MICROPHONE,
188                 TEST_PACKAGE_NAME,
189                 TEST_USER_ID,
190                 "App",
191                 null,
192                 null,
193                 null,
194                 0L,
195                 false,
196                 false,
197                 false,
198                 TEST_PERM_GROUP,
199                 null
200         )
201 
202         val list = listOf(element)
203         dialog = PrivacyDialog(context, list, starter)
204         dialog.show()
205         assertThat(dialog.requireViewById<TextView>(R.id.text).text).isEqualTo(
206                 context.getString(
207                         R.string.ongoing_privacy_dialog_recent_op,
208                         element.applicationName,
209                         element.type.getName(context)
210                 )
211         )
212     }
213 
214     @Test
215     fun testEnterprise() {
216         val element = PrivacyDialog.PrivacyElement(
217                 PrivacyType.TYPE_MICROPHONE,
218                 TEST_PACKAGE_NAME,
219                 TEST_USER_ID,
220                 "App",
221                 null,
222                 null,
223                 null,
224                 0L,
225                 false,
226                 true,
227                 false,
228                 TEST_PERM_GROUP,
229                 null
230         )
231 
232         val list = listOf(element)
233         dialog = PrivacyDialog(context, list, starter)
234         dialog.show()
235         assertThat(dialog.requireViewById<TextView>(R.id.text).text.toString()).contains(
236                 context.getString(R.string.ongoing_privacy_dialog_enterprise)
237         )
238     }
239 
240     @Test
241     fun testPhoneCall() {
242         val element = PrivacyDialog.PrivacyElement(
243                 PrivacyType.TYPE_MICROPHONE,
244                 TEST_PACKAGE_NAME,
245                 TEST_USER_ID,
246                 "App",
247                 null,
248                 null,
249                 null,
250                 0L,
251                 false,
252                 false,
253                 true,
254                 TEST_PERM_GROUP,
255                 null
256         )
257 
258         val list = listOf(element)
259         dialog = PrivacyDialog(context, list, starter)
260         dialog.show()
261         assertThat(dialog.requireViewById<TextView>(R.id.text).text.toString()).contains(
262                 context.getString(R.string.ongoing_privacy_dialog_phonecall)
263         )
264     }
265 
266     @Test
267     fun testPhoneCallNotClickable() {
268         val element = PrivacyDialog.PrivacyElement(
269                 PrivacyType.TYPE_MICROPHONE,
270                 TEST_PACKAGE_NAME,
271                 TEST_USER_ID,
272                 "App",
273                 null,
274                 null,
275                 null,
276                 0L,
277                 false,
278                 false,
279                 true,
280                 TEST_PERM_GROUP,
281                 null
282         )
283 
284         val list = listOf(element)
285         dialog = PrivacyDialog(context, list, starter)
286         dialog.show()
287         assertThat(dialog.requireViewById<View>(R.id.privacy_item).isClickable).isFalse()
288         assertThat(dialog.requireViewById<View>(R.id.chevron).visibility).isEqualTo(View.GONE)
289     }
290 
291     @Test
292     fun testProxyLabel() {
293         val element = PrivacyDialog.PrivacyElement(
294                 PrivacyType.TYPE_MICROPHONE,
295                 TEST_PACKAGE_NAME,
296                 TEST_USER_ID,
297                 "App",
298                 null,
299                 null,
300                 "proxyLabel",
301                 0L,
302                 false,
303                 false,
304                 true,
305                 TEST_PERM_GROUP,
306                 null
307         )
308 
309         val list = listOf(element)
310         dialog = PrivacyDialog(context, list, starter)
311         dialog.show()
312         assertThat(dialog.requireViewById<TextView>(R.id.text).text.toString()).contains(
313                 context.getString(
314                         R.string.ongoing_privacy_dialog_attribution_text,
315                         element.proxyLabel
316                 )
317         )
318     }
319 
320     @Test
321     fun testSubattribution() {
322         val element = PrivacyDialog.PrivacyElement(
323                 PrivacyType.TYPE_MICROPHONE,
324                 TEST_PACKAGE_NAME,
325                 TEST_USER_ID,
326                 "App",
327                 null,
328                 "For subattribution",
329                 null,
330                 0L,
331                 true,
332                 false,
333                 false,
334                 TEST_PERM_GROUP,
335                 null
336         )
337 
338         val list = listOf(element)
339         dialog = PrivacyDialog(context, list, starter)
340         dialog.show()
341         assertThat(dialog.requireViewById<TextView>(R.id.text).text.toString()).contains(
342                 context.getString(
343                         R.string.ongoing_privacy_dialog_attribution_label,
344                         element.attributionLabel
345                 )
346         )
347     }
348 
349     @Test
350     fun testSubattributionAndProxyLabel() {
351         val element = PrivacyDialog.PrivacyElement(
352                 PrivacyType.TYPE_MICROPHONE,
353                 TEST_PACKAGE_NAME,
354                 TEST_USER_ID,
355                 "App",
356                 null,
357                 "For subattribution",
358                 "proxy label",
359                 0L,
360                 true,
361                 false,
362                 false,
363                 TEST_PERM_GROUP,
364                 null
365         )
366 
367         val list = listOf(element)
368         dialog = PrivacyDialog(context, list, starter)
369         dialog.show()
370         assertThat(dialog.requireViewById<TextView>(R.id.text).text.toString()).contains(
371                 context.getString(
372                         R.string.ongoing_privacy_dialog_attribution_proxy_label,
373                         element.attributionLabel, element.proxyLabel
374                 )
375         )
376     }
377 
378     @Test
379     fun testDialogHasTitle() {
380         // Dialog must have a non-empty title for a11y purposes.
381 
382         val list = listOf(
383             PrivacyDialog.PrivacyElement(
384                 PrivacyType.TYPE_MICROPHONE,
385                 TEST_PACKAGE_NAME,
386                 TEST_USER_ID,
387                 "App",
388                 null,
389                 null,
390                 null,
391                 0L,
392                 false,
393                 false,
394                 false,
395                 TEST_PERM_GROUP,
396                 null
397             )
398         )
399         dialog = PrivacyDialog(context, list, starter)
400         dialog.show()
401 
402         assertThat(TextUtils.isEmpty(dialog.window?.attributes?.title)).isFalse()
403     }
404 }