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.statusbar.policy
18 
19 import android.content.ComponentName
20 import android.content.Context
21 import android.content.pm.ServiceInfo
22 import android.provider.Settings
23 
24 import androidx.test.ext.junit.runners.AndroidJUnit4
25 import androidx.test.filters.SmallTest
26 
27 import com.android.systemui.res.R
28 import com.android.systemui.SysuiTestCase
29 import com.android.systemui.controls.ControlsServiceInfo
30 import com.android.systemui.controls.dagger.ControlsComponent
31 import com.android.systemui.controls.controller.ControlsController
32 import com.android.systemui.controls.controller.SeedResponse
33 import com.android.systemui.controls.controller.StructureInfo
34 import com.android.systemui.controls.management.ControlsListingController
35 import com.android.systemui.controls.management.ControlsListingController.ControlsListingCallback
36 import com.android.systemui.settings.UserContextProvider
37 import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl.Companion.PREFS_CONTROLS_FILE
38 import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl.Companion.PREFS_CONTROLS_SEEDING_COMPLETED
39 import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl.Companion.QS_DEFAULT_POSITION
40 import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl.Companion.QS_PRIORITY_POSITION
41 import com.android.systemui.util.mockito.mock
42 import com.android.systemui.util.settings.SecureSettings
43 
44 import java.util.Optional
45 import java.util.function.Consumer
46 
47 import org.junit.Before
48 import org.junit.Test
49 import org.junit.runner.RunWith
50 
51 import org.mockito.ArgumentCaptor
52 import org.mockito.Captor
53 import org.mockito.Mock
54 import org.mockito.Mockito
55 import org.mockito.MockitoAnnotations
56 import org.mockito.Mockito.never
57 import org.mockito.Mockito.verify
58 import org.mockito.Mockito.`when`
59 import org.mockito.ArgumentMatchers.anyInt
60 import org.mockito.ArgumentMatchers.anyObject
61 
62 @SmallTest
63 @RunWith(AndroidJUnit4::class)
64 class DeviceControlsControllerImplTest : SysuiTestCase() {
65 
66     @Mock
67     private lateinit var controlsComponent: ControlsComponent
68     @Mock
69     private lateinit var controlsController: ControlsController
70     @Mock
71     private lateinit var controlsListingController: ControlsListingController
72     @Mock
73     private lateinit var callback: DeviceControlsController.Callback
74     @Captor
75     private lateinit var listingCallbackCaptor: ArgumentCaptor<ControlsListingCallback>
76     @Mock
77     private lateinit var structureInfo: StructureInfo
78     @Mock
79     private lateinit var serviceInfo: ServiceInfo
80     @Mock
81     private lateinit var userContextProvider: UserContextProvider
82     @Mock
83     private lateinit var secureSettings: SecureSettings
84     @Captor
85     private lateinit var seedCallback: ArgumentCaptor<Consumer<SeedResponse>>
86 
87     private lateinit var controlsServiceInfo: ControlsServiceInfo
88     private lateinit var controller: DeviceControlsControllerImpl
89 
90     companion object {
capturenull91         fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
92         fun <T> eq(value: T): T = Mockito.eq(value) ?: value
93         private val TEST_PKG = "test.pkg"
94         private val TEST_COMPONENT = ComponentName(TEST_PKG, "test.class")
95     }
96 
97     @Before
98     fun setUp() {
99         MockitoAnnotations.initMocks(this)
100 
101         `when`(controlsComponent.getControlsController())
102                 .thenReturn(Optional.of(controlsController))
103         `when`(controlsComponent.getControlsListingController())
104                 .thenReturn(Optional.of(controlsListingController))
105 
106         `when`(controlsComponent.isEnabled()).thenReturn(true)
107 
108         controller = DeviceControlsControllerImpl(
109             mContext,
110             controlsComponent,
111             userContextProvider,
112             secureSettings
113         )
114 
115         `when`(secureSettings.getInt(Settings.Secure.CONTROLS_ENABLED, 1)).thenReturn(1)
116 
117         `when`(serviceInfo.componentName).thenReturn(TEST_COMPONENT)
118         controlsServiceInfo = ControlsServiceInfo(mContext, serviceInfo)
119 
120         `when`(userContextProvider.userContext).thenReturn(mContext)
121         mContext.getSharedPreferences(PREFS_CONTROLS_FILE, Context.MODE_PRIVATE).edit()
122             .putStringSet(PREFS_CONTROLS_SEEDING_COMPLETED, emptySet())
123             .apply()
124     }
125 
126     @Test
testNoCallbackWhenNoServicesAvailablenull127     fun testNoCallbackWhenNoServicesAvailable() {
128         `when`(controlsController.getFavorites()).thenReturn(emptyList())
129         controller.setCallback(callback)
130 
131         verify(controlsListingController).addCallback(capture(listingCallbackCaptor))
132         listingCallbackCaptor.value.onServicesUpdated(emptyList())
133         verify(callback, never()).onControlsUpdate(anyInt())
134     }
135 
136     @Test
testCallbackWithNullValueWhenSettingIsDisablednull137     fun testCallbackWithNullValueWhenSettingIsDisabled() {
138         `when`(secureSettings.getInt(Settings.Secure.CONTROLS_ENABLED, 1)).thenReturn(0)
139         controller.setCallback(callback)
140 
141         verify(controlsListingController, never()).addCallback(anyObject())
142         verify(callback).onControlsUpdate(null)
143     }
144 
145     @Test
testSetPriorityPositionIsSetWhenFavoritesAreAvailablenull146     fun testSetPriorityPositionIsSetWhenFavoritesAreAvailable() {
147         `when`(controlsController.getFavorites()).thenReturn(listOf(structureInfo))
148         controller.setCallback(callback)
149 
150         verify(controlsListingController).addCallback(capture(listingCallbackCaptor))
151         listingCallbackCaptor.value.onServicesUpdated(listOf(controlsServiceInfo))
152         verify(callback).onControlsUpdate(QS_PRIORITY_POSITION)
153     }
154 
155     @Test
testSetDefaultPositionIsSetWhenNoFavoritesAreAvailablenull156     fun testSetDefaultPositionIsSetWhenNoFavoritesAreAvailable() {
157         `when`(controlsController.getFavorites()).thenReturn(emptyList())
158         controller.setCallback(callback)
159 
160         mContext.getOrCreateTestableResources().addOverride(
161                 R.array.config_controlsPreferredPackages,
162                 arrayOf(TEST_PKG))
163 
164         verify(controlsListingController).addCallback(capture(listingCallbackCaptor))
165         listingCallbackCaptor.value.onServicesUpdated(listOf(controlsServiceInfo))
166 
167         verify(controlsController).seedFavoritesForComponents(
168             eq(listOf(TEST_COMPONENT)),
169             capture(seedCallback)
170         )
171         seedCallback.value.accept(SeedResponse(TEST_PKG, true))
172         verify(callback).onControlsUpdate(QS_DEFAULT_POSITION)
173     }
174 
175     @Test
testControlsDisabledRemoveFromAutoTrackernull176     fun testControlsDisabledRemoveFromAutoTracker() {
177         `when`(controlsComponent.isEnabled()).thenReturn(false)
178         val callback: DeviceControlsController.Callback = mock()
179 
180         controller.setCallback(callback)
181 
182         verify(callback).removeControlsAutoTracker()
183         verify(callback, never()).onControlsUpdate(anyInt())
184     }
185 }
186