Loading packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt +13 −0 Original line number Diff line number Diff line Loading @@ -39,10 +39,13 @@ import androidx.compose.material3.IconButtonDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.blur import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Rect import androidx.compose.ui.geometry.Size Loading Loading @@ -155,6 +158,15 @@ constructor( val contentAlphaFromBrightnessMirror by animateFloatAsState(if (showBrightnessMirror) 0f else 1f) val targetBlurRadiusPx: Float by remember(layoutState) { derivedStateOf { contentViewModel.calculateTargetBlurRadius(layoutState.transitionState) } } val animatedBlurRadiusPx: Float by animateFloatAsState(targetValue = targetBlurRadiusPx, label = "NSOverlay-blurRadius") // Set the bounds to null when the QuickSettings overlay disappears. DisposableEffectWithLifecycle(Unit) { onDispose { Loading @@ -169,6 +181,7 @@ constructor( modifier = modifier .graphicsLayer { alpha = contentAlphaFromBrightnessMirror } .blur(with(LocalDensity.current) { animatedBlurRadiusPx.toDp() }) .thenIf(showBrightnessMirror) { Modifier.gesturesDisabled() } ) { OverlayShade( Loading packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModelTest.kt +59 −0 Original line number Diff line number Diff line Loading @@ -23,12 +23,14 @@ import android.platform.test.annotations.EnableFlags import androidx.compose.ui.geometry.Rect 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.Flags.FLAG_NOTIFICATION_SHADE_BLUR import com.android.systemui.SysuiTestCase import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository import com.android.systemui.authentication.domain.interactor.AuthenticationResult import com.android.systemui.authentication.domain.interactor.authenticationInteractor import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.keyguard.ui.transitions.blurConfig import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.runCurrent Loading Loading @@ -256,6 +258,63 @@ class QuickSettingsShadeOverlayContentViewModelTest : SysuiTestCase() { assertThat(underTest.isTransparencyEnabled).isFalse() } @Test @EnableFlags(FLAG_NOTIFICATION_SHADE_BLUR) fun calculateTargetBlurRadius() = kosmos.runTest { // Only bouncer shown: no blur. fakeWindowRootViewBlurRepository.isBlurSupported.value = true assertThat( underTest.calculateTargetBlurRadius( transitionState = TransitionState.Idle( currentScene = Scenes.Lockscreen, currentOverlays = setOf(Overlays.Bouncer), ) ) ) .isEqualTo(0f) // Quick Settings shade and bouncer shown: apply blur. assertThat( underTest.calculateTargetBlurRadius( transitionState = TransitionState.Idle( currentScene = Scenes.Lockscreen, currentOverlays = setOf(Overlays.Bouncer, Overlays.QuickSettingsShade), ) ) ) .isEqualTo(blurConfig.maxBlurRadiusPx) // No bouncer shown: no blur. assertThat( underTest.calculateTargetBlurRadius( transitionState = TransitionState.Idle( currentScene = Scenes.Lockscreen, currentOverlays = setOf(Overlays.QuickSettingsShade), ) ) ) .isEqualTo(0) // Blur not supported: no blur. fakeWindowRootViewBlurRepository.isBlurSupported.value = false assertThat( underTest.calculateTargetBlurRadius( transitionState = TransitionState.Idle( currentScene = Scenes.Lockscreen, currentOverlays = setOf(Overlays.Bouncer, Overlays.QuickSettingsShade), ) ) ) .isEqualTo(0f) } private fun Kosmos.lockDevice() { val currentScene by collectLastValue(sceneInteractor.currentScene) powerInteractor.setAsleepForTest() Loading packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModel.kt +19 −0 Original line number Diff line number Diff line Loading @@ -21,11 +21,13 @@ import android.graphics.Rect import android.media.AudioManager import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import com.android.compose.animation.scene.content.state.TransitionState import com.android.settingslib.volume.shared.model.AudioStream import com.android.systemui.Flags import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.desktop.domain.interactor.DesktopInteractor import com.android.systemui.development.ui.viewmodel.BuildNumberViewModel 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.flags.QsDetailedView Loading @@ -33,6 +35,7 @@ import com.android.systemui.qs.panels.ui.viewmodel.toolbar.ToolbarViewModel import com.android.systemui.qs.tiles.dialog.AudioDetailsViewModel import com.android.systemui.res.R import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.ShadeDisplayAware import com.android.systemui.shade.domain.interactor.ShadeInteractor Loading Loading @@ -80,6 +83,7 @@ constructor( val notificationStackAppearanceInteractor: NotificationStackAppearanceInteractor, @Assisted private val volumeSliderCoroutineScope: CoroutineScope?, val toolbarViewModelFactory: ToolbarViewModel.Factory, private val blurConfig: BlurConfig, windowRootViewBlurInteractor: WindowRootViewBlurInteractor, ) : ExclusiveActivatable() { Loading Loading @@ -118,6 +122,21 @@ constructor( }, ) /** * Calculates the blur radius to apply to the overlay. * * @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 calculateTargetBlurRadius(transitionState: TransitionState): Float { return when { !isTransparencyEnabled -> 0f Overlays.QuickSettingsShade !in transitionState.currentOverlays -> 0f Overlays.Bouncer in transitionState.currentOverlays -> blurConfig.maxBlurRadiusPx else -> 0f } } private val showVolumeSlider = QsDetailedView.isEnabled && shadeContext.resources.getBoolean(R.bool.config_enableDesktopAudioTileDetailsView) Loading packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModelKosmos.kt +2 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.systemui.qs.ui.viewmodel import android.content.applicationContext import com.android.systemui.desktop.domain.interactor.desktopInteractor import com.android.systemui.development.ui.viewmodel.buildNumberViewModelFactory import com.android.systemui.keyguard.ui.transitions.blurConfig import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testDispatcher import com.android.systemui.qs.panels.ui.viewmodel.toolbar.toolbarViewModelFactory Loading Loading @@ -51,6 +52,7 @@ val Kosmos.quickSettingsShadeOverlayContentViewModelFactory: buildNumberViewModelFactory = buildNumberViewModelFactory, volumeSliderCoroutineScope = volumeSliderCoroutineScope, toolbarViewModelFactory = toolbarViewModelFactory, blurConfig = blurConfig, windowRootViewBlurInteractor = windowRootViewBlurInteractor, ) } Loading Loading
packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt +13 −0 Original line number Diff line number Diff line Loading @@ -39,10 +39,13 @@ import androidx.compose.material3.IconButtonDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.blur import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Rect import androidx.compose.ui.geometry.Size Loading Loading @@ -155,6 +158,15 @@ constructor( val contentAlphaFromBrightnessMirror by animateFloatAsState(if (showBrightnessMirror) 0f else 1f) val targetBlurRadiusPx: Float by remember(layoutState) { derivedStateOf { contentViewModel.calculateTargetBlurRadius(layoutState.transitionState) } } val animatedBlurRadiusPx: Float by animateFloatAsState(targetValue = targetBlurRadiusPx, label = "NSOverlay-blurRadius") // Set the bounds to null when the QuickSettings overlay disappears. DisposableEffectWithLifecycle(Unit) { onDispose { Loading @@ -169,6 +181,7 @@ constructor( modifier = modifier .graphicsLayer { alpha = contentAlphaFromBrightnessMirror } .blur(with(LocalDensity.current) { animatedBlurRadiusPx.toDp() }) .thenIf(showBrightnessMirror) { Modifier.gesturesDisabled() } ) { OverlayShade( Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModelTest.kt +59 −0 Original line number Diff line number Diff line Loading @@ -23,12 +23,14 @@ import android.platform.test.annotations.EnableFlags import androidx.compose.ui.geometry.Rect 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.Flags.FLAG_NOTIFICATION_SHADE_BLUR import com.android.systemui.SysuiTestCase import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository import com.android.systemui.authentication.domain.interactor.AuthenticationResult import com.android.systemui.authentication.domain.interactor.authenticationInteractor import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.keyguard.ui.transitions.blurConfig import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.runCurrent Loading Loading @@ -256,6 +258,63 @@ class QuickSettingsShadeOverlayContentViewModelTest : SysuiTestCase() { assertThat(underTest.isTransparencyEnabled).isFalse() } @Test @EnableFlags(FLAG_NOTIFICATION_SHADE_BLUR) fun calculateTargetBlurRadius() = kosmos.runTest { // Only bouncer shown: no blur. fakeWindowRootViewBlurRepository.isBlurSupported.value = true assertThat( underTest.calculateTargetBlurRadius( transitionState = TransitionState.Idle( currentScene = Scenes.Lockscreen, currentOverlays = setOf(Overlays.Bouncer), ) ) ) .isEqualTo(0f) // Quick Settings shade and bouncer shown: apply blur. assertThat( underTest.calculateTargetBlurRadius( transitionState = TransitionState.Idle( currentScene = Scenes.Lockscreen, currentOverlays = setOf(Overlays.Bouncer, Overlays.QuickSettingsShade), ) ) ) .isEqualTo(blurConfig.maxBlurRadiusPx) // No bouncer shown: no blur. assertThat( underTest.calculateTargetBlurRadius( transitionState = TransitionState.Idle( currentScene = Scenes.Lockscreen, currentOverlays = setOf(Overlays.QuickSettingsShade), ) ) ) .isEqualTo(0) // Blur not supported: no blur. fakeWindowRootViewBlurRepository.isBlurSupported.value = false assertThat( underTest.calculateTargetBlurRadius( transitionState = TransitionState.Idle( currentScene = Scenes.Lockscreen, currentOverlays = setOf(Overlays.Bouncer, Overlays.QuickSettingsShade), ) ) ) .isEqualTo(0f) } private fun Kosmos.lockDevice() { val currentScene by collectLastValue(sceneInteractor.currentScene) powerInteractor.setAsleepForTest() Loading
packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModel.kt +19 −0 Original line number Diff line number Diff line Loading @@ -21,11 +21,13 @@ import android.graphics.Rect import android.media.AudioManager import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import com.android.compose.animation.scene.content.state.TransitionState import com.android.settingslib.volume.shared.model.AudioStream import com.android.systemui.Flags import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.desktop.domain.interactor.DesktopInteractor import com.android.systemui.development.ui.viewmodel.BuildNumberViewModel 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.flags.QsDetailedView Loading @@ -33,6 +35,7 @@ import com.android.systemui.qs.panels.ui.viewmodel.toolbar.ToolbarViewModel import com.android.systemui.qs.tiles.dialog.AudioDetailsViewModel import com.android.systemui.res.R import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.ShadeDisplayAware import com.android.systemui.shade.domain.interactor.ShadeInteractor Loading Loading @@ -80,6 +83,7 @@ constructor( val notificationStackAppearanceInteractor: NotificationStackAppearanceInteractor, @Assisted private val volumeSliderCoroutineScope: CoroutineScope?, val toolbarViewModelFactory: ToolbarViewModel.Factory, private val blurConfig: BlurConfig, windowRootViewBlurInteractor: WindowRootViewBlurInteractor, ) : ExclusiveActivatable() { Loading Loading @@ -118,6 +122,21 @@ constructor( }, ) /** * Calculates the blur radius to apply to the overlay. * * @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 calculateTargetBlurRadius(transitionState: TransitionState): Float { return when { !isTransparencyEnabled -> 0f Overlays.QuickSettingsShade !in transitionState.currentOverlays -> 0f Overlays.Bouncer in transitionState.currentOverlays -> blurConfig.maxBlurRadiusPx else -> 0f } } private val showVolumeSlider = QsDetailedView.isEnabled && shadeContext.resources.getBoolean(R.bool.config_enableDesktopAudioTileDetailsView) Loading
packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModelKosmos.kt +2 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.systemui.qs.ui.viewmodel import android.content.applicationContext import com.android.systemui.desktop.domain.interactor.desktopInteractor import com.android.systemui.development.ui.viewmodel.buildNumberViewModelFactory import com.android.systemui.keyguard.ui.transitions.blurConfig import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testDispatcher import com.android.systemui.qs.panels.ui.viewmodel.toolbar.toolbarViewModelFactory Loading Loading @@ -51,6 +52,7 @@ val Kosmos.quickSettingsShadeOverlayContentViewModelFactory: buildNumberViewModelFactory = buildNumberViewModelFactory, volumeSliderCoroutineScope = volumeSliderCoroutineScope, toolbarViewModelFactory = toolbarViewModelFactory, blurConfig = blurConfig, windowRootViewBlurInteractor = windowRootViewBlurInteractor, ) } Loading