Loading packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt +9 −1 Original line number Diff line number Diff line Loading @@ -40,12 +40,14 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass import androidx.compose.runtime.Composable import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.blur import androidx.compose.ui.graphics.CompositingStrategy import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.platform.LocalConfiguration Loading Loading @@ -194,7 +196,13 @@ private fun ContentScope.QuickSettingsScene( shadeSession: SaveableSession, jankMonitor: InteractionJankMonitor, ) { Box(modifier.fillMaxSize()) { val targetBlur by remember(layoutState) { derivedStateOf { viewModel.calculateBlur(layoutState.transitionState) } } val animatedBlurRadiusPx: Float by animateFloatAsState(targetValue = targetBlur, label = "QS-blurRadius") Box(modifier.blur(with(LocalDensity.current) { animatedBlurRadiusPx.toDp() }).fillMaxSize()) { // This is the background for the whole scene, as the elements don't necessarily provide // a background that extends to the edges. ShadePanelScrim(viewModel.isTransparencyEnabled) Loading packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneContentViewModelTest.kt +51 −0 Original line number Diff line number Diff line Loading @@ -20,9 +20,12 @@ 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 Loading @@ -45,6 +48,7 @@ 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 Loading Loading @@ -84,6 +88,7 @@ class QuickSettingsSceneContentViewModelTest : SysuiTestCase() { sceneInteractor = sceneInteractor, mainDispatcher = testDispatcher, windowRootViewBlurInteractor = windowRootViewBlurInteractor, blurConfig = blurConfig, ) underTest.activateIn(testScope) testScope.backgroundScope.launch { underTest.detectShadeModeChanges() } Loading Loading @@ -113,6 +118,52 @@ class QuickSettingsSceneContentViewModelTest : SysuiTestCase() { 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 { Loading packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneContentViewModel.kt +18 −0 Original line number Diff line number Diff line Loading @@ -19,8 +19,10 @@ package com.android.systemui.qs.ui.viewmodel import androidx.compose.runtime.getValue import androidx.lifecycle.LifecycleOwner import com.android.app.tracing.coroutines.launchTraced as launch import com.android.compose.animation.scene.content.state.TransitionState import com.android.systemui.Flags import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.ui.transitions.BlurConfig import com.android.systemui.lifecycle.ExclusiveActivatable import com.android.systemui.lifecycle.Hydrator import com.android.systemui.qs.FooterActionsController Loading Loading @@ -59,6 +61,7 @@ constructor( private val sceneInteractor: SceneInteractor, @Main private val mainDispatcher: CoroutineDispatcher, windowRootViewBlurInteractor: WindowRootViewBlurInteractor, private val blurConfig: BlurConfig, ) : ExclusiveActivatable() { val qsContainerViewModel = qsContainerViewModelFactory.create(supportsBrightnessMirroring = true) Loading @@ -82,6 +85,21 @@ constructor( private val footerActionsControllerInitialized = AtomicBoolean(false) /** * Calculates the blur radius to apply to the scene UI. * * @param transitionState The current transition state of the scene (from its `ContentScope`) * @return The blur radius to apply to the scene UI, in pixels. */ fun calculateBlur(transitionState: TransitionState): Float { return when { !isTransparencyEnabled -> 0f Scenes.QuickSettings != transitionState.currentScene -> 0f Overlays.Bouncer in transitionState.currentOverlays -> blurConfig.maxBlurRadiusPx else -> 0f } } fun getFooterActionsViewModel(lifecycleOwner: LifecycleOwner): FooterActionsViewModel { if (footerActionsControllerInitialized.compareAndSet(false, true)) { footerActionsController.init() Loading packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneContentViewModelKosmos.kt +2 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.systemui.qs.ui.viewmodel import com.android.systemui.keyguard.ui.transitions.blurConfig import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.testDispatcher Loading @@ -36,6 +37,7 @@ val Kosmos.quickSettingsSceneContentViewModel by Fixture { sceneInteractor = sceneInteractor, mainDispatcher = testDispatcher, windowRootViewBlurInteractor = windowRootViewBlurInteractor, blurConfig = blurConfig, ) } Loading Loading
packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt +9 −1 Original line number Diff line number Diff line Loading @@ -40,12 +40,14 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass import androidx.compose.runtime.Composable import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.blur import androidx.compose.ui.graphics.CompositingStrategy import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.platform.LocalConfiguration Loading Loading @@ -194,7 +196,13 @@ private fun ContentScope.QuickSettingsScene( shadeSession: SaveableSession, jankMonitor: InteractionJankMonitor, ) { Box(modifier.fillMaxSize()) { val targetBlur by remember(layoutState) { derivedStateOf { viewModel.calculateBlur(layoutState.transitionState) } } val animatedBlurRadiusPx: Float by animateFloatAsState(targetValue = targetBlur, label = "QS-blurRadius") Box(modifier.blur(with(LocalDensity.current) { animatedBlurRadiusPx.toDp() }).fillMaxSize()) { // This is the background for the whole scene, as the elements don't necessarily provide // a background that extends to the edges. ShadePanelScrim(viewModel.isTransparencyEnabled) Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneContentViewModelTest.kt +51 −0 Original line number Diff line number Diff line Loading @@ -20,9 +20,12 @@ 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 Loading @@ -45,6 +48,7 @@ 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 Loading Loading @@ -84,6 +88,7 @@ class QuickSettingsSceneContentViewModelTest : SysuiTestCase() { sceneInteractor = sceneInteractor, mainDispatcher = testDispatcher, windowRootViewBlurInteractor = windowRootViewBlurInteractor, blurConfig = blurConfig, ) underTest.activateIn(testScope) testScope.backgroundScope.launch { underTest.detectShadeModeChanges() } Loading Loading @@ -113,6 +118,52 @@ class QuickSettingsSceneContentViewModelTest : SysuiTestCase() { 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 { Loading
packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneContentViewModel.kt +18 −0 Original line number Diff line number Diff line Loading @@ -19,8 +19,10 @@ package com.android.systemui.qs.ui.viewmodel import androidx.compose.runtime.getValue import androidx.lifecycle.LifecycleOwner import com.android.app.tracing.coroutines.launchTraced as launch import com.android.compose.animation.scene.content.state.TransitionState import com.android.systemui.Flags import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.ui.transitions.BlurConfig import com.android.systemui.lifecycle.ExclusiveActivatable import com.android.systemui.lifecycle.Hydrator import com.android.systemui.qs.FooterActionsController Loading Loading @@ -59,6 +61,7 @@ constructor( private val sceneInteractor: SceneInteractor, @Main private val mainDispatcher: CoroutineDispatcher, windowRootViewBlurInteractor: WindowRootViewBlurInteractor, private val blurConfig: BlurConfig, ) : ExclusiveActivatable() { val qsContainerViewModel = qsContainerViewModelFactory.create(supportsBrightnessMirroring = true) Loading @@ -82,6 +85,21 @@ constructor( private val footerActionsControllerInitialized = AtomicBoolean(false) /** * Calculates the blur radius to apply to the scene UI. * * @param transitionState The current transition state of the scene (from its `ContentScope`) * @return The blur radius to apply to the scene UI, in pixels. */ fun calculateBlur(transitionState: TransitionState): Float { return when { !isTransparencyEnabled -> 0f Scenes.QuickSettings != transitionState.currentScene -> 0f Overlays.Bouncer in transitionState.currentOverlays -> blurConfig.maxBlurRadiusPx else -> 0f } } fun getFooterActionsViewModel(lifecycleOwner: LifecycleOwner): FooterActionsViewModel { if (footerActionsControllerInitialized.compareAndSet(false, true)) { footerActionsController.init() Loading
packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneContentViewModelKosmos.kt +2 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.systemui.qs.ui.viewmodel import com.android.systemui.keyguard.ui.transitions.blurConfig import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.testDispatcher Loading @@ -36,6 +37,7 @@ val Kosmos.quickSettingsSceneContentViewModel by Fixture { sceneInteractor = sceneInteractor, mainDispatcher = testDispatcher, windowRootViewBlurInteractor = windowRootViewBlurInteractor, blurConfig = blurConfig, ) } Loading