package com.android.systemui.qs import android.content.res.Configuration import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import android.testing.TestableResources import android.view.ContextThemeWrapper import com.android.internal.logging.MetricsLogger import com.android.internal.logging.UiEventLogger import com.android.systemui.SysuiTestCase import com.android.systemui.dump.DumpManager import com.android.systemui.haptics.qs.QSLongPressEffect import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor import com.android.systemui.media.controls.ui.view.MediaHost import com.android.systemui.media.controls.ui.view.MediaHostState import com.android.systemui.plugins.FalsingManager import com.android.systemui.plugins.qs.QSTile import com.android.systemui.qs.customize.QSCustomizerController import com.android.systemui.qs.logging.QSLogger import com.android.systemui.res.R import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.settings.brightness.BrightnessController import com.android.systemui.settings.brightness.BrightnessSliderController import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController import com.android.systemui.tuner.TunerService import com.google.common.truth.Truth.assertThat import javax.inject.Provider import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.anyBoolean import org.mockito.Mock import org.mockito.Mockito import org.mockito.Mockito.any import org.mockito.Mockito.never import org.mockito.Mockito.reset import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations import org.mockito.Mockito.`when` as whenever @SmallTest @RunWith(AndroidJUnit4::class) class QSPanelControllerTest : SysuiTestCase() { @Mock private lateinit var qsPanel: QSPanel @Mock private lateinit var tunerService: TunerService @Mock private lateinit var qsHost: QSHost @Mock private lateinit var qsCustomizerController: QSCustomizerController @Mock private lateinit var qsTileRevealControllerFactory: QSTileRevealController.Factory @Mock private lateinit var dumpManager: DumpManager @Mock private lateinit var metricsLogger: MetricsLogger @Mock private lateinit var uiEventLogger: UiEventLogger @Mock private lateinit var qsLogger: QSLogger @Mock private lateinit var brightnessControllerFactory: BrightnessController.Factory @Mock private lateinit var brightnessController: BrightnessController @Mock private lateinit var brightnessSlider: BrightnessSliderController @Mock private lateinit var brightnessSliderFactory: BrightnessSliderController.Factory @Mock private lateinit var falsingManager: FalsingManager @Mock private lateinit var mediaHost: MediaHost @Mock private lateinit var tile: QSTile @Mock private lateinit var otherTile: QSTile @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager @Mock private lateinit var configuration: Configuration @Mock private lateinit var pagedTileLayout: PagedTileLayout @Mock private lateinit var longPressEffectProvider: Provider @Mock private lateinit var mediaCarouselInteractor: MediaCarouselInteractor private val usingMediaPlayer: Boolean by lazy { !SceneContainerFlag.isEnabled } private lateinit var controller: QSPanelController private val testableResources: TestableResources = mContext.orCreateTestableResources @Before fun setUp() { MockitoAnnotations.initMocks(this) whenever(brightnessSliderFactory.create(any(), any())).thenReturn(brightnessSlider) whenever(brightnessControllerFactory.create(any())).thenReturn(brightnessController) setShouldUseSplitShade(false) whenever(qsPanel.resources).thenReturn(testableResources.resources) whenever(qsPanel.context) .thenReturn( ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings)) whenever(qsPanel.getOrCreateTileLayout()).thenReturn(pagedTileLayout) whenever(statusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(false) whenever(qsPanel.setListening(anyBoolean())).then { whenever(qsPanel.isListening).thenReturn(it.getArgument(0)) } controller = QSPanelController( qsPanel, tunerService, qsHost, qsCustomizerController, /* usingMediaPlayer= */ usingMediaPlayer, mediaHost, qsTileRevealControllerFactory, dumpManager, metricsLogger, uiEventLogger, qsLogger, brightnessControllerFactory, brightnessSliderFactory, falsingManager, statusBarKeyguardViewManager, ResourcesSplitShadeStateController(), longPressEffectProvider, mediaCarouselInteractor, ) } @After fun tearDown() { reset(mediaHost) } @Test fun onInit_setsMediaAsExpanded() { controller.onInit() verify(mediaHost).expansion = MediaHostState.EXPANDED } @Test fun testSetListeningDoesntRefreshListeningTiles() { whenever(qsHost.getTiles()).thenReturn(listOf(tile, otherTile)) controller.setTiles() whenever(tile.isListening()).thenReturn(false) whenever(otherTile.isListening()).thenReturn(true) controller.setListening(true, true) verify(tile).refreshState() verify(otherTile, Mockito.never()).refreshState() } @Test fun testIsBouncerInTransit() { whenever(statusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(true) assertThat(controller.isBouncerInTransit()).isEqualTo(true) whenever(statusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(false) assertThat(controller.isBouncerInTransit()).isEqualTo(false) } @Test fun configurationChange_onlySplitShadeConfigChanges_tileAreRedistributed() { setShouldUseSplitShade(false) controller.mOnConfigurationChangedListener.onConfigurationChange(configuration) verify(pagedTileLayout, never()).forceTilesRedistribution(any()) setShouldUseSplitShade(true) controller.mOnConfigurationChangedListener.onConfigurationChange(configuration) verify(pagedTileLayout).forceTilesRedistribution("Split shade state changed") } @Test fun configurationChange_onlySplitShadeConfigChanges_qsPanelCanBeCollapsed() { setShouldUseSplitShade(false) controller.mOnConfigurationChangedListener.onConfigurationChange(configuration) verify(qsPanel, never()).setCanCollapse(anyBoolean()) setShouldUseSplitShade(true) controller.mOnConfigurationChangedListener.onConfigurationChange(configuration) verify(qsPanel).setCanCollapse(false) setShouldUseSplitShade(false) controller.mOnConfigurationChangedListener.onConfigurationChange(configuration) verify(qsPanel).setCanCollapse(true) } @Test fun multipleListeningOnlyCallsBrightnessControllerOnce() { controller.setListening(true, true) controller.setListening(true, false) controller.setListening(true, true) verify(brightnessController).registerCallbacks() controller.setListening(false, true) controller.setListening(false, false) controller.setListening(false, true) verify(brightnessController).unregisterCallbacks() } private fun setShouldUseSplitShade(shouldUse: Boolean) { testableResources.addOverride(R.bool.config_use_split_notification_shade, shouldUse) } }