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 }