/* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.qs.ui.viewmodel import android.testing.TestableLooper.RunWithLooper import androidx.lifecycle.LifecycleOwner import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.compose.animation.scene.content.state.TransitionState import com.android.systemui.SysuiTestCase import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.keyguard.ui.transitions.blurConfig import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.runCurrent import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.lifecycle.activateIn import com.android.systemui.qs.FooterActionsController import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.domain.startable.sceneContainerStartable import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.domain.interactor.disableDualShade import com.android.systemui.shade.domain.interactor.enableDualShade import com.android.systemui.shade.domain.interactor.enableSingleShade import com.android.systemui.shade.domain.interactor.enableSplitShade import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.shade.domain.interactor.shadeModeInteractor import com.android.systemui.shade.ui.viewmodel.shadeHeaderViewModelFactory import com.android.systemui.testKosmos import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.android.systemui.window.data.repository.fakeWindowRootViewBlurRepository import com.android.systemui.window.domain.interactor.windowRootViewBlurInteractor import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.launch import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.times import org.mockito.Mockito.verify @SmallTest @RunWith(AndroidJUnit4::class) @RunWithLooper @EnableSceneContainer class QuickSettingsSceneContentViewModelTest : SysuiTestCase() { private val kosmos = testKosmos().useUnconfinedTestDispatcher() private val footerActionsViewModel = mock() private val footerActionsController = mock() private lateinit var underTest: QuickSettingsSceneContentViewModel @Before fun setUp() { with(kosmos) { sceneContainerStartable.start() val footerActionsViewModelFactory = mock { whenever(create(any())).thenReturn(footerActionsViewModel) } underTest = QuickSettingsSceneContentViewModel( shadeHeaderViewModelFactory = shadeHeaderViewModelFactory, qsContainerViewModelFactory = kosmos.quickSettingsContainerViewModelFactory, footerActionsViewModelFactory = footerActionsViewModelFactory, footerActionsController = footerActionsController, shadeModeInteractor = shadeModeInteractor, sceneInteractor = sceneInteractor, mainDispatcher = testDispatcher, windowRootViewBlurInteractor = windowRootViewBlurInteractor, blurConfig = blurConfig, ) underTest.activateIn(testScope) testScope.backgroundScope.launch { underTest.detectShadeModeChanges() } disableDualShade() } } @Test fun gettingViewModelInitializesControllerOnlyOnce() { underTest.getFooterActionsViewModel(mock()) underTest.getFooterActionsViewModel(mock()) verify(footerActionsController, times(1)).init() } @Test fun shadeModeChange_split_switchToShadeScene() = kosmos.runTest { val scene by collectLastValue(sceneInteractor.currentScene) enableSingleShade() shadeInteractor.expandQuickSettingsShade("test") assertThat(scene).isEqualTo(Scenes.QuickSettings) enableSplitShade() assertThat(scene).isEqualTo(Scenes.Shade) } @Test fun isBlurred_whenBouncerOverlayShowingOverQuickSettingsAndBlurSupported_isTrue() = kosmos.runTest { assertThat( underTest.calculateBlur( transitionState = TransitionState.Idle( currentScene = Scenes.Lockscreen, currentOverlays = setOf(Overlays.Bouncer), ) ) ) .isEqualTo(0f) kosmos.fakeWindowRootViewBlurRepository.isBlurSupported.value = true runCurrent() assertThat( underTest.calculateBlur( transitionState = TransitionState.Idle( currentScene = Scenes.Lockscreen, currentOverlays = setOf(Overlays.Bouncer), ) ) ) .isEqualTo(0f) assertThat( underTest.calculateBlur( transitionState = TransitionState.Idle( currentScene = Scenes.QuickSettings, currentOverlays = setOf(Overlays.Bouncer), ) ) ) .isEqualTo(blurConfig.maxBlurRadiusPx) assertThat( underTest.calculateBlur( transitionState = TransitionState.Idle(currentScene = Scenes.QuickSettings) ) ) .isEqualTo(0) } @Test fun shadeModeChange_dual_switchToOverlay() = kosmos.runTest { val scene by collectLastValue(sceneInteractor.currentScene) val overlays by collectLastValue(sceneInteractor.currentOverlays) enableSingleShade() shadeInteractor.expandQuickSettingsShade("test") assertThat(scene).isEqualTo(Scenes.QuickSettings) assertThat(overlays).isEmpty() enableDualShade() assertThat(scene).isEqualTo(Scenes.Lockscreen) assertThat(overlays).containsExactly(Overlays.QuickSettingsShade) } }