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.content.Intent 20 import android.testing.TestableLooper 21 import android.view.View 22 import android.view.ViewGroup 23 import android.view.ViewGroup.LayoutParams.MATCH_PARENT 24 import android.widget.TextView 25 import androidx.test.ext.junit.runners.AndroidJUnit4 26 import androidx.test.filters.SmallTest 27 import com.android.systemui.res.R 28 import com.android.systemui.SysuiTestCase 29 import com.google.common.truth.Truth.assertThat 30 import org.junit.After 31 import org.junit.Before 32 import org.junit.Test 33 import org.junit.runner.RunWith 34 import org.mockito.Mock 35 import org.mockito.Mockito.mock 36 import org.mockito.Mockito.never 37 import org.mockito.Mockito.verify 38 import org.mockito.MockitoAnnotations 39 40 @SmallTest 41 @RunWith(AndroidJUnit4::class) 42 @TestableLooper.RunWithLooper(setAsMainLooper = true) 43 class PrivacyDialogV2Test : 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 private val TEST_INTENT = Intent("test_intent_action") 51 createPrivacyElementnull52 private fun createPrivacyElement( 53 type: PrivacyType = PrivacyType.TYPE_MICROPHONE, 54 packageName: String = TEST_PACKAGE_NAME, 55 userId: Int = TEST_USER_ID, 56 applicationName: CharSequence = "App", 57 attributionTag: CharSequence? = null, 58 attributionLabel: CharSequence? = null, 59 proxyLabel: CharSequence? = null, 60 lastActiveTimestamp: Long = 0L, 61 isActive: Boolean = false, 62 isPhoneCall: Boolean = false, 63 isService: Boolean = false, 64 permGroupName: String = TEST_PERM_GROUP, 65 navigationIntent: Intent = TEST_INTENT 66 ) = 67 PrivacyDialogV2.PrivacyElement( 68 type, 69 packageName, 70 userId, 71 applicationName, 72 attributionTag, 73 attributionLabel, 74 proxyLabel, 75 lastActiveTimestamp, 76 isActive, 77 isPhoneCall, 78 isService, 79 permGroupName, 80 navigationIntent 81 ) 82 } 83 84 @Mock private lateinit var manageApp: (String, Int, Intent) -> Unit 85 @Mock private lateinit var closeApp: (String, Int) -> Unit 86 @Mock private lateinit var openPrivacyDashboard: () -> Unit 87 private lateinit var dialog: PrivacyDialogV2 88 89 @Before 90 fun setUp() { 91 MockitoAnnotations.initMocks(this) 92 } 93 94 @After teardownnull95 fun teardown() { 96 if (this::dialog.isInitialized) { 97 dialog.dismiss() 98 } 99 } 100 101 @Test testManageAppCalledWithCorrectParamsnull102 fun testManageAppCalledWithCorrectParams() { 103 val list = listOf(createPrivacyElement()) 104 dialog = PrivacyDialogV2(context, list, manageApp, closeApp, openPrivacyDashboard) 105 dialog.show() 106 107 dialog.requireViewById<View>(R.id.privacy_dialog_manage_app_button).callOnClick() 108 109 verify(manageApp).invoke(TEST_PACKAGE_NAME, TEST_USER_ID, TEST_INTENT) 110 } 111 112 @Test testCloseAppCalledWithCorrectParamsnull113 fun testCloseAppCalledWithCorrectParams() { 114 val list = listOf(createPrivacyElement(isActive = true)) 115 dialog = PrivacyDialogV2(context, list, manageApp, closeApp, openPrivacyDashboard) 116 dialog.show() 117 118 dialog.requireViewById<View>(R.id.privacy_dialog_close_app_button).callOnClick() 119 120 verify(closeApp).invoke(TEST_PACKAGE_NAME, TEST_USER_ID) 121 } 122 123 @Test testCloseAppMissingForServicenull124 fun testCloseAppMissingForService() { 125 val list = listOf(createPrivacyElement(isActive = true, isService = true)) 126 dialog = PrivacyDialogV2(context, list, manageApp, closeApp, openPrivacyDashboard) 127 128 dialog.show() 129 130 assertThat(dialog.findViewById<View>(R.id.privacy_dialog_manage_app_button)).isNotNull() 131 assertThat(dialog.findViewById<View>(R.id.privacy_dialog_close_app_button)).isNull() 132 } 133 134 @Test testMoreButtonnull135 fun testMoreButton() { 136 dialog = PrivacyDialogV2(context, emptyList(), manageApp, closeApp, openPrivacyDashboard) 137 dialog.show() 138 139 dialog.requireViewById<View>(R.id.privacy_dialog_more_button).callOnClick() 140 141 verify(openPrivacyDashboard).invoke() 142 } 143 144 @Test testCloseButtonnull145 fun testCloseButton() { 146 dialog = PrivacyDialogV2(context, emptyList(), manageApp, closeApp, openPrivacyDashboard) 147 val dismissListener = mock(PrivacyDialogV2.OnDialogDismissed::class.java) 148 dialog.addOnDismissListener(dismissListener) 149 dialog.show() 150 verify(dismissListener, never()).onDialogDismissed() 151 152 dialog.requireViewById<View>(R.id.privacy_dialog_close_button).callOnClick() 153 154 verify(dismissListener).onDialogDismissed() 155 } 156 157 @Test testDismissListenerCalledOnDismissnull158 fun testDismissListenerCalledOnDismiss() { 159 dialog = PrivacyDialogV2(context, emptyList(), manageApp, closeApp, openPrivacyDashboard) 160 val dismissListener = mock(PrivacyDialogV2.OnDialogDismissed::class.java) 161 dialog.addOnDismissListener(dismissListener) 162 dialog.show() 163 verify(dismissListener, never()).onDialogDismissed() 164 165 dialog.dismiss() 166 167 verify(dismissListener).onDialogDismissed() 168 } 169 170 @Test testDismissListenerCalledImmediatelyIfDialogAlreadyDismissednull171 fun testDismissListenerCalledImmediatelyIfDialogAlreadyDismissed() { 172 dialog = PrivacyDialogV2(context, emptyList(), manageApp, closeApp, openPrivacyDashboard) 173 val dismissListener = mock(PrivacyDialogV2.OnDialogDismissed::class.java) 174 dialog.show() 175 dialog.dismiss() 176 177 dialog.addOnDismissListener(dismissListener) 178 179 verify(dismissListener).onDialogDismissed() 180 } 181 182 @Test testCorrectNumElementsnull183 fun testCorrectNumElements() { 184 val list = 185 listOf( 186 createPrivacyElement(type = PrivacyType.TYPE_CAMERA, isActive = true), 187 createPrivacyElement() 188 ) 189 dialog = PrivacyDialogV2(context, list, manageApp, closeApp, openPrivacyDashboard) 190 191 dialog.show() 192 193 assertThat( 194 dialog.requireViewById<ViewGroup>(R.id.privacy_dialog_items_container).childCount 195 ) 196 .isEqualTo(2) 197 } 198 199 @Test testHeaderTextnull200 fun testHeaderText() { 201 val list = listOf(createPrivacyElement()) 202 dialog = PrivacyDialogV2(context, list, manageApp, closeApp, openPrivacyDashboard) 203 204 dialog.show() 205 206 assertThat(dialog.requireViewById<TextView>(R.id.privacy_dialog_item_header_title).text) 207 .isEqualTo(TEST_PERM_GROUP) 208 } 209 210 @Test testUsingTextnull211 fun testUsingText() { 212 val list = listOf(createPrivacyElement(type = PrivacyType.TYPE_CAMERA, isActive = true)) 213 dialog = PrivacyDialogV2(context, list, manageApp, closeApp, openPrivacyDashboard) 214 215 dialog.show() 216 217 assertThat(dialog.requireViewById<TextView>(R.id.privacy_dialog_item_header_summary).text) 218 .isEqualTo("In use by App") 219 } 220 221 @Test testRecentTextnull222 fun testRecentText() { 223 val list = listOf(createPrivacyElement()) 224 dialog = PrivacyDialogV2(context, list, manageApp, closeApp, openPrivacyDashboard) 225 226 dialog.show() 227 228 assertThat(dialog.requireViewById<TextView>(R.id.privacy_dialog_item_header_summary).text) 229 .isEqualTo("Recently used by App") 230 } 231 232 @Test testPhoneCallnull233 fun testPhoneCall() { 234 val list = listOf(createPrivacyElement(isPhoneCall = true)) 235 dialog = PrivacyDialogV2(context, list, manageApp, closeApp, openPrivacyDashboard) 236 237 dialog.show() 238 239 assertThat(dialog.requireViewById<TextView>(R.id.privacy_dialog_item_header_summary).text) 240 .isEqualTo("Recently used in phone call") 241 } 242 243 @Test testPhoneCallNotClickablenull244 fun testPhoneCallNotClickable() { 245 val list = listOf(createPrivacyElement(isPhoneCall = true)) 246 dialog = PrivacyDialogV2(context, list, manageApp, closeApp, openPrivacyDashboard) 247 248 dialog.show() 249 250 assertThat(dialog.requireViewById<View>(R.id.privacy_dialog_item_card).isClickable) 251 .isFalse() 252 assertThat( 253 dialog 254 .requireViewById<View>(R.id.privacy_dialog_item_header_expand_toggle) 255 .visibility 256 ) 257 .isEqualTo(View.GONE) 258 } 259 260 @Test testProxyLabelnull261 fun testProxyLabel() { 262 val list = listOf(createPrivacyElement(proxyLabel = "proxy label")) 263 dialog = PrivacyDialogV2(context, list, manageApp, closeApp, openPrivacyDashboard) 264 265 dialog.show() 266 267 assertThat(dialog.requireViewById<TextView>(R.id.privacy_dialog_item_header_summary).text) 268 .isEqualTo("Recently used by App (proxy label)") 269 } 270 271 @Test testSubattributionnull272 fun testSubattribution() { 273 val list = 274 listOf( 275 createPrivacyElement( 276 attributionLabel = "For subattribution", 277 isActive = true, 278 isService = true 279 ) 280 ) 281 dialog = PrivacyDialogV2(context, list, manageApp, closeApp, openPrivacyDashboard) 282 283 dialog.show() 284 285 assertThat(dialog.requireViewById<TextView>(R.id.privacy_dialog_item_header_summary).text) 286 .isEqualTo("In use by App (For subattribution)") 287 } 288 289 @Test testSubattributionAndProxyLabelnull290 fun testSubattributionAndProxyLabel() { 291 val list = 292 listOf( 293 createPrivacyElement( 294 attributionLabel = "For subattribution", 295 proxyLabel = "proxy label", 296 isActive = true 297 ) 298 ) 299 dialog = PrivacyDialogV2(context, list, manageApp, closeApp, openPrivacyDashboard) 300 dialog.show() 301 assertThat(dialog.requireViewById<TextView>(R.id.privacy_dialog_item_header_summary).text) 302 .isEqualTo("In use by App (For subattribution \u2022 proxy label)") 303 } 304 305 @Test testDialogHasTitlenull306 fun testDialogHasTitle() { 307 val list = listOf(createPrivacyElement()) 308 dialog = PrivacyDialogV2(context, list, manageApp, closeApp, openPrivacyDashboard) 309 dialog.show() 310 311 assertThat(dialog.window?.attributes?.title).isEqualTo("Microphone & Camera") 312 } 313 314 @Test testDialogIsFullscreennull315 fun testDialogIsFullscreen() { 316 dialog = PrivacyDialogV2(context, emptyList(), manageApp, closeApp, openPrivacyDashboard) 317 dialog.show() 318 319 assertThat(dialog.window?.attributes?.width).isEqualTo(MATCH_PARENT) 320 assertThat(dialog.window?.attributes?.height).isEqualTo(MATCH_PARENT) 321 } 322 } 323