1 package com.android.systemui.qs
2 
3 import android.content.res.Configuration
4 import android.test.suitebuilder.annotation.SmallTest
5 import android.testing.AndroidTestingRunner
6 import android.testing.TestableResources
7 import com.android.internal.logging.MetricsLogger
8 import com.android.internal.logging.UiEventLogger
9 import com.android.systemui.R
10 import com.android.systemui.SysuiTestCase
11 import com.android.systemui.dump.DumpManager
12 import com.android.systemui.media.controls.ui.MediaHost
13 import com.android.systemui.media.controls.ui.MediaHostState
14 import com.android.systemui.plugins.FalsingManager
15 import com.android.systemui.plugins.qs.QSTile
16 import com.android.systemui.qs.customize.QSCustomizerController
17 import com.android.systemui.qs.logging.QSLogger
18 import com.android.systemui.settings.brightness.BrightnessController
19 import com.android.systemui.settings.brightness.BrightnessSliderController
20 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
21 import com.android.systemui.tuner.TunerService
22 import com.google.common.truth.Truth.assertThat
23 import org.junit.After
24 import org.junit.Before
25 import org.junit.Test
26 import org.junit.runner.RunWith
27 import org.mockito.ArgumentMatchers.anyBoolean
28 import org.mockito.Mock
29 import org.mockito.Mockito
30 import org.mockito.Mockito.any
31 import org.mockito.Mockito.never
32 import org.mockito.Mockito.reset
33 import org.mockito.Mockito.verify
34 import org.mockito.MockitoAnnotations
35 import org.mockito.Mockito.`when` as whenever
36 
37 @SmallTest
38 @RunWith(AndroidTestingRunner::class)
39 class QSPanelControllerTest : SysuiTestCase() {
40 
41     @Mock private lateinit var qsPanel: QSPanel
42     @Mock private lateinit var tunerService: TunerService
43     @Mock private lateinit var qsHost: QSHost
44     @Mock private lateinit var qsCustomizerController: QSCustomizerController
45     @Mock private lateinit var qsTileRevealControllerFactory: QSTileRevealController.Factory
46     @Mock private lateinit var dumpManager: DumpManager
47     @Mock private lateinit var metricsLogger: MetricsLogger
48     @Mock private lateinit var uiEventLogger: UiEventLogger
49     @Mock private lateinit var qsLogger: QSLogger
50     @Mock private lateinit var brightnessControllerFactory: BrightnessController.Factory
51     @Mock private lateinit var brightnessController: BrightnessController
52     @Mock private lateinit var brightnessSlider: BrightnessSliderController
53     @Mock private lateinit var brightnessSliderFactory: BrightnessSliderController.Factory
54     @Mock private lateinit var falsingManager: FalsingManager
55     @Mock private lateinit var mediaHost: MediaHost
56     @Mock private lateinit var tile: QSTile
57     @Mock private lateinit var otherTile: QSTile
58     @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
59     @Mock private lateinit var configuration: Configuration
60     @Mock private lateinit var pagedTileLayout: PagedTileLayout
61 
62     private lateinit var controller: QSPanelController
63     private val testableResources: TestableResources = mContext.orCreateTestableResources
64 
65     @Before
66     fun setUp() {
67         MockitoAnnotations.initMocks(this)
68 
69         whenever(brightnessSliderFactory.create(any(), any())).thenReturn(brightnessSlider)
70         whenever(brightnessControllerFactory.create(any())).thenReturn(brightnessController)
71         setShouldUseSplitShade(false)
72         whenever(qsPanel.resources).thenReturn(testableResources.resources)
73         whenever(qsPanel.getOrCreateTileLayout()).thenReturn(pagedTileLayout)
74         whenever(statusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(false)
75         whenever(qsPanel.setListening(anyBoolean())).then {
76             whenever(qsPanel.isListening).thenReturn(it.getArgument(0))
77         }
78 
79         controller = QSPanelController(
80             qsPanel,
81             tunerService,
82             qsHost,
83             qsCustomizerController,
84             /* usingMediaPlayer= */ true,
85             mediaHost,
86             qsTileRevealControllerFactory,
87             dumpManager,
88             metricsLogger,
89             uiEventLogger,
90             qsLogger,
91             brightnessControllerFactory,
92             brightnessSliderFactory,
93             falsingManager,
94             statusBarKeyguardViewManager
95         )
96     }
97 
98     @After
99     fun tearDown() {
100         reset(mediaHost)
101     }
102 
103     @Test
104     fun onInit_setsMediaAsExpanded() {
105         controller.onInit()
106 
107         verify(mediaHost).expansion = MediaHostState.EXPANDED
108     }
109 
110     @Test
111     fun testSetListeningDoesntRefreshListeningTiles() {
112         whenever(qsHost.getTiles()).thenReturn(listOf(tile, otherTile))
113         controller.setTiles()
114         whenever(tile.isListening()).thenReturn(false)
115         whenever(otherTile.isListening()).thenReturn(true)
116 
117         controller.setListening(true, true)
118 
119         verify(tile).refreshState()
120         verify(otherTile, Mockito.never()).refreshState()
121     }
122 
123     @Test
124     fun testIsBouncerInTransit() {
125         whenever(statusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(true)
126         assertThat(controller.isBouncerInTransit()).isEqualTo(true)
127         whenever(statusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(false)
128         assertThat(controller.isBouncerInTransit()).isEqualTo(false)
129     }
130 
131     @Test
132     fun configurationChange_onlySplitShadeConfigChanges_tileAreRedistributed() {
133         setShouldUseSplitShade(false)
134         controller.mOnConfigurationChangedListener.onConfigurationChange(configuration)
135         verify(pagedTileLayout, never()).forceTilesRedistribution(any())
136 
137         setShouldUseSplitShade(true)
138         controller.mOnConfigurationChangedListener.onConfigurationChange(configuration)
139         verify(pagedTileLayout).forceTilesRedistribution("Split shade state changed")
140     }
141 
142     @Test
143     fun configurationChange_onlySplitShadeConfigChanges_qsPanelCanBeCollapsed() {
144         setShouldUseSplitShade(false)
145         controller.mOnConfigurationChangedListener.onConfigurationChange(configuration)
146         verify(qsPanel, never()).setCanCollapse(anyBoolean())
147 
148         setShouldUseSplitShade(true)
149         controller.mOnConfigurationChangedListener.onConfigurationChange(configuration)
150         verify(qsPanel).setCanCollapse(false)
151 
152         setShouldUseSplitShade(false)
153         controller.mOnConfigurationChangedListener.onConfigurationChange(configuration)
154         verify(qsPanel).setCanCollapse(true)
155     }
156 
157     @Test
158     fun multipleListeningOnlyCallsBrightnessControllerOnce() {
159         controller.setListening(true, true)
160         controller.setListening(true, false)
161         controller.setListening(true, true)
162 
163         verify(brightnessController).registerCallbacks()
164 
165         controller.setListening(false, true)
166         controller.setListening(false, false)
167         controller.setListening(false, true)
168 
169         verify(brightnessController).unregisterCallbacks()
170     }
171 
172     private fun setShouldUseSplitShade(shouldUse: Boolean) {
173         testableResources.addOverride(R.bool.config_use_split_notification_shade, shouldUse)
174     }
175 }
176