blob: 6033ed26579c2cbb8bdcf9ee8f52b37660fa8b75 [file] [log] [blame]
Fabian Kozynski8d06c712018-11-07 10:33:02 -05001/*
2 * Copyright (C) 2018 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
17package com.android.systemui.privacy
18
Fabian Kozynskib5625ac2018-11-21 08:56:55 -050019import android.app.ActivityManager
Fabian Kozynski8d06c712018-11-07 10:33:02 -050020import android.app.AppOpsManager
Fabian Kozynski81765392019-02-11 12:38:26 -050021import android.content.Context
Fabian Kozynskib5625ac2018-11-21 08:56:55 -050022import android.content.Intent
Fabian Kozynski510585d2018-12-19 13:59:17 -050023import android.content.pm.UserInfo
Fabian Kozynski8d06c712018-11-07 10:33:02 -050024import android.os.Handler
Fabian Kozynskib5625ac2018-11-21 08:56:55 -050025import android.os.UserHandle
26import android.os.UserManager
Brett Chabot84151d92019-02-27 15:37:59 -080027import androidx.test.filters.SmallTest
Fabian Kozynski8d06c712018-11-07 10:33:02 -050028import android.testing.AndroidTestingRunner
29import android.testing.TestableLooper
30import android.testing.TestableLooper.RunWithLooper
31import com.android.systemui.Dependency
Fabian Kozynski81765392019-02-11 12:38:26 -050032import com.android.systemui.Dependency.BG_HANDLER
33import com.android.systemui.Dependency.MAIN_HANDLER
Fabian Kozynski508422b2018-12-20 10:58:17 -050034import com.android.systemui.R
Fabian Kozynski8d06c712018-11-07 10:33:02 -050035import com.android.systemui.SysuiTestCase
36import com.android.systemui.appops.AppOpItem
37import com.android.systemui.appops.AppOpsController
Fabian Kozynskia6ff80b2019-02-12 11:32:44 -050038import org.hamcrest.Matchers.hasItem
39import org.hamcrest.Matchers.not
40import org.hamcrest.Matchers.nullValue
Fabian Kozynski510585d2018-12-19 13:59:17 -050041import org.junit.Assert.assertEquals
Fabian Kozynskia6ff80b2019-02-12 11:32:44 -050042import org.junit.Assert.assertThat
43import org.junit.Assert.assertTrue
Fabian Kozynski8d06c712018-11-07 10:33:02 -050044import org.junit.Before
45import org.junit.Test
46import org.junit.runner.RunWith
Fabian Kozynski510585d2018-12-19 13:59:17 -050047import org.mockito.ArgumentCaptor
Fabian Kozynski8d06c712018-11-07 10:33:02 -050048import org.mockito.ArgumentMatchers.any
49import org.mockito.ArgumentMatchers.anyInt
50import org.mockito.ArgumentMatchers.anyList
51import org.mockito.ArgumentMatchers.eq
Fabian Kozynski510585d2018-12-19 13:59:17 -050052import org.mockito.Captor
Fabian Kozynski8d06c712018-11-07 10:33:02 -050053import org.mockito.Mock
Fabian Kozynskib5625ac2018-11-21 08:56:55 -050054import org.mockito.Mockito.atLeastOnce
Fabian Kozynski8d06c712018-11-07 10:33:02 -050055import org.mockito.Mockito.doReturn
Fabian Kozynski04f83eb2019-01-22 10:38:40 -050056import org.mockito.Mockito.mock
Fabian Kozynskib5625ac2018-11-21 08:56:55 -050057import org.mockito.Mockito.never
Fabian Kozynski04f83eb2019-01-22 10:38:40 -050058import org.mockito.Mockito.reset
Fabian Kozynskib5625ac2018-11-21 08:56:55 -050059import org.mockito.Mockito.spy
Fabian Kozynski8d06c712018-11-07 10:33:02 -050060import org.mockito.Mockito.verify
Fabian Kozynski04f83eb2019-01-22 10:38:40 -050061import org.mockito.Mockito.verifyNoMoreInteractions
Fabian Kozynski8d06c712018-11-07 10:33:02 -050062import org.mockito.MockitoAnnotations
63
64@RunWith(AndroidTestingRunner::class)
65@SmallTest
66@RunWithLooper
67class PrivacyItemControllerTest : SysuiTestCase() {
68
Fabian Kozynskib5625ac2018-11-21 08:56:55 -050069 companion object {
70 val CURRENT_USER_ID = ActivityManager.getCurrentUser()
Fabian Kozynski508422b2018-12-20 10:58:17 -050071 val TEST_UID = CURRENT_USER_ID * UserHandle.PER_USER_RANGE
72 const val SYSTEM_UID = 1000
73 const val TEST_PACKAGE_NAME = "test"
74 const val DEVICE_SERVICES_STRING = "Device services"
Fabian Kozynskib5625ac2018-11-21 08:56:55 -050075 const val TAG = "PrivacyItemControllerTest"
Fabian Kozynski510585d2018-12-19 13:59:17 -050076 fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
Fabian Kozynskib5625ac2018-11-21 08:56:55 -050077 }
78
Fabian Kozynski8d06c712018-11-07 10:33:02 -050079 @Mock
80 private lateinit var appOpsController: AppOpsController
81 @Mock
82 private lateinit var callback: PrivacyItemController.Callback
Fabian Kozynskib5625ac2018-11-21 08:56:55 -050083 @Mock
84 private lateinit var userManager: UserManager
Fabian Kozynski510585d2018-12-19 13:59:17 -050085 @Captor
86 private lateinit var argCaptor: ArgumentCaptor<List<PrivacyItem>>
Fabian Kozynski04f83eb2019-01-22 10:38:40 -050087 @Captor
88 private lateinit var argCaptorCallback: ArgumentCaptor<AppOpsController.Callback>
Fabian Kozynski8d06c712018-11-07 10:33:02 -050089
90 private lateinit var testableLooper: TestableLooper
91 private lateinit var privacyItemController: PrivacyItemController
Fabian Kozynski81765392019-02-11 12:38:26 -050092 private lateinit var handler: Handler
93
94 fun PrivacyItemController(context: Context) =
95 PrivacyItemController(context, appOpsController, handler, handler)
Fabian Kozynski8d06c712018-11-07 10:33:02 -050096
97 @Before
98 fun setup() {
99 MockitoAnnotations.initMocks(this)
100 testableLooper = TestableLooper.get(this)
Fabian Kozynski81765392019-02-11 12:38:26 -0500101 handler = Handler(testableLooper.looper)
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500102
Fabian Kozynskib5625ac2018-11-21 08:56:55 -0500103 appOpsController = mDependency.injectMockDependency(AppOpsController::class.java)
Fabian Kozynski81765392019-02-11 12:38:26 -0500104 mDependency.injectTestDependency(Dependency.BG_HANDLER, handler)
105 mDependency.injectTestDependency(Dependency.MAIN_HANDLER, handler)
Fabian Kozynskib5625ac2018-11-21 08:56:55 -0500106 mContext.addMockSystemService(UserManager::class.java, userManager)
Fabian Kozynski508422b2018-12-20 10:58:17 -0500107 mContext.getOrCreateTestableResources().addOverride(R.string.device_services,
108 DEVICE_SERVICES_STRING)
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500109
Fabian Kozynski510585d2018-12-19 13:59:17 -0500110 doReturn(listOf(object : UserInfo() {
111 init {
112 id = CURRENT_USER_ID
113 }
114 })).`when`(userManager).getProfiles(anyInt())
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500115
Fabian Kozynski04f83eb2019-01-22 10:38:40 -0500116 privacyItemController = PrivacyItemController(mContext)
117 }
118
119 @Test
120 fun testSetListeningTrueByAddingCallback() {
121 privacyItemController.addCallback(callback)
122 verify(appOpsController).addCallback(eq(PrivacyItemController.OPS),
123 any(AppOpsController.Callback::class.java))
124 testableLooper.processAllMessages()
125 verify(callback).privacyChanged(anyList())
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500126 }
Fabian Kozynskib5625ac2018-11-21 08:56:55 -0500127
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500128 @Test
129 fun testSetListeningTrue() {
130 privacyItemController.setListening(true)
131 verify(appOpsController).addCallback(eq(PrivacyItemController.OPS),
132 any(AppOpsController.Callback::class.java))
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500133 }
134
135 @Test
136 fun testSetListeningFalse() {
137 privacyItemController.setListening(true)
138 privacyItemController.setListening(false)
139 verify(appOpsController).removeCallback(eq(PrivacyItemController.OPS),
Fabian Kozynskib5625ac2018-11-21 08:56:55 -0500140 any(AppOpsController.Callback::class.java))
141 }
142
143 @Test
Fabian Kozynski510585d2018-12-19 13:59:17 -0500144 fun testDistinctItems() {
Fabian Kozynski508422b2018-12-20 10:58:17 -0500145 doReturn(listOf(AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, "", 0),
146 AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, "", 1)))
Fabian Kozynski510585d2018-12-19 13:59:17 -0500147 .`when`(appOpsController).getActiveAppOpsForUser(anyInt())
148
Fabian Kozynski04f83eb2019-01-22 10:38:40 -0500149 privacyItemController.addCallback(callback)
Fabian Kozynski510585d2018-12-19 13:59:17 -0500150 testableLooper.processAllMessages()
151 verify(callback).privacyChanged(capture(argCaptor))
152 assertEquals(1, argCaptor.value.size)
153 }
154
155 @Test
Fabian Kozynski508422b2018-12-20 10:58:17 -0500156 fun testSystemApps() {
157 doReturn(listOf(AppOpItem(AppOpsManager.OP_COARSE_LOCATION, SYSTEM_UID, TEST_PACKAGE_NAME,
158 0))).`when`(appOpsController).getActiveAppOpsForUser(anyInt())
Fabian Kozynski04f83eb2019-01-22 10:38:40 -0500159 privacyItemController.addCallback(callback)
Fabian Kozynski508422b2018-12-20 10:58:17 -0500160 testableLooper.processAllMessages()
161 verify(callback).privacyChanged(capture(argCaptor))
162 assertEquals(1, argCaptor.value.size)
163 assertEquals(context.getString(R.string.device_services),
164 argCaptor.value[0].application.applicationName)
165 }
166
167 @Test
Fabian Kozynskib5625ac2018-11-21 08:56:55 -0500168 fun testRegisterReceiver_allUsers() {
169 val spiedContext = spy(mContext)
Fabian Kozynski04f83eb2019-01-22 10:38:40 -0500170 val itemController = PrivacyItemController(spiedContext)
171 itemController.setListening(true)
Fabian Kozynskib5625ac2018-11-21 08:56:55 -0500172 verify(spiedContext, atLeastOnce()).registerReceiverAsUser(
173 eq(itemController.userSwitcherReceiver), eq(UserHandle.ALL), any(), eq(null),
174 eq(null))
175 verify(spiedContext, never()).unregisterReceiver(eq(itemController.userSwitcherReceiver))
176 }
177
178 @Test
179 fun testReceiver_ACTION_USER_FOREGROUND() {
180 privacyItemController.userSwitcherReceiver.onReceive(context,
181 Intent(Intent.ACTION_USER_FOREGROUND))
182 verify(userManager).getProfiles(anyInt())
183 }
184
185 @Test
186 fun testReceiver_ACTION_MANAGED_PROFILE_ADDED() {
187 privacyItemController.userSwitcherReceiver.onReceive(context,
188 Intent(Intent.ACTION_MANAGED_PROFILE_ADDED))
189 verify(userManager).getProfiles(anyInt())
190 }
191
192 @Test
193 fun testReceiver_ACTION_MANAGED_PROFILE_REMOVED() {
194 privacyItemController.userSwitcherReceiver.onReceive(context,
195 Intent(Intent.ACTION_MANAGED_PROFILE_REMOVED))
196 verify(userManager).getProfiles(anyInt())
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500197 }
Fabian Kozynski04f83eb2019-01-22 10:38:40 -0500198
199 @Test
200 fun testAddMultipleCallbacks() {
201 val otherCallback = mock(PrivacyItemController.Callback::class.java)
202 privacyItemController.addCallback(callback)
203 testableLooper.processAllMessages()
204 verify(callback).privacyChanged(anyList())
205
206 privacyItemController.addCallback(otherCallback)
207 testableLooper.processAllMessages()
208 verify(otherCallback).privacyChanged(anyList())
209 // Adding a callback should not unnecessarily call previous ones
210 verifyNoMoreInteractions(callback)
211 }
212
213 @Test
214 fun testMultipleCallbacksAreUpdated() {
215 doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOpsForUser(anyInt())
216
217 val otherCallback = mock(PrivacyItemController.Callback::class.java)
218 privacyItemController.addCallback(callback)
219 privacyItemController.addCallback(otherCallback)
220 testableLooper.processAllMessages()
221 reset(callback)
222 reset(otherCallback)
223
224 verify(appOpsController).addCallback(any<IntArray>(), capture(argCaptorCallback))
225 argCaptorCallback.value.onActiveStateChanged(0, TEST_UID, "", true)
226 testableLooper.processAllMessages()
227 verify(callback).privacyChanged(anyList())
228 verify(otherCallback).privacyChanged(anyList())
229 }
230
231 @Test
232 fun testRemoveCallback() {
233 doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOpsForUser(anyInt())
234 val otherCallback = mock(PrivacyItemController.Callback::class.java)
235 privacyItemController.addCallback(callback)
236 privacyItemController.addCallback(otherCallback)
237 testableLooper.processAllMessages()
238 reset(callback)
239 reset(otherCallback)
240
241 verify(appOpsController).addCallback(any<IntArray>(), capture(argCaptorCallback))
242 privacyItemController.removeCallback(callback)
243 argCaptorCallback.value.onActiveStateChanged(0, TEST_UID, "", true)
244 testableLooper.processAllMessages()
245 verify(callback, never()).privacyChanged(anyList())
246 verify(otherCallback).privacyChanged(anyList())
247 }
Fabian Kozynskia6ff80b2019-02-12 11:32:44 -0500248
249 @Test
250 fun testListShouldNotHaveNull() {
251 doReturn(listOf(AppOpItem(AppOpsManager.OP_ACTIVATE_VPN, TEST_UID, "", 0),
252 AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, "", 0)))
253 .`when`(appOpsController).getActiveAppOpsForUser(anyInt())
254 privacyItemController.addCallback(callback)
255 testableLooper.processAllMessages()
256
257 verify(callback).privacyChanged(capture(argCaptor))
258 assertEquals(1, argCaptor.value.size)
259 assertThat(argCaptor.value, not(hasItem(nullValue())))
260 }
261
262 @Test
263 fun testListShouldBeCopy() {
264 val list = listOf(PrivacyItem(PrivacyType.TYPE_CAMERA,
265 PrivacyApplication("", TEST_UID, mContext)))
266 privacyItemController.privacyList = list
Fabian Kozynski72090102019-03-04 10:55:55 -0500267 val privacyList = privacyItemController.privacyList
268 assertEquals(list, privacyList)
269 assertTrue(list !== privacyList)
Fabian Kozynskia6ff80b2019-02-12 11:32:44 -0500270 }
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500271}