Loading packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt +13 −0 Original line number Original line Diff line number Diff line Loading @@ -39,10 +39,13 @@ import androidx.compose.material3.IconButtonDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier import androidx.compose.ui.draw.blur import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Rect import androidx.compose.ui.geometry.Rect import androidx.compose.ui.geometry.Size import androidx.compose.ui.geometry.Size Loading Loading @@ -155,6 +158,15 @@ constructor( val contentAlphaFromBrightnessMirror by val contentAlphaFromBrightnessMirror by animateFloatAsState(if (showBrightnessMirror) 0f else 1f) 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. // Set the bounds to null when the QuickSettings overlay disappears. DisposableEffectWithLifecycle(Unit) { DisposableEffectWithLifecycle(Unit) { onDispose { onDispose { Loading @@ -169,6 +181,7 @@ constructor( modifier = modifier = modifier modifier .graphicsLayer { alpha = contentAlphaFromBrightnessMirror } .graphicsLayer { alpha = contentAlphaFromBrightnessMirror } .blur(with(LocalDensity.current) { animatedBlurRadiusPx.toDp() }) .thenIf(showBrightnessMirror) { Modifier.gesturesDisabled() } .thenIf(showBrightnessMirror) { Modifier.gesturesDisabled() } ) { ) { OverlayShade( OverlayShade( Loading packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModelTest.kt +59 −0 Original line number Original line Diff line number Diff line Loading @@ -23,12 +23,14 @@ import android.platform.test.annotations.EnableFlags import androidx.compose.ui.geometry.Rect import androidx.compose.ui.geometry.Rect import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest 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.Flags.FLAG_NOTIFICATION_SHADE_BLUR import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository import com.android.systemui.authentication.domain.interactor.AuthenticationResult import com.android.systemui.authentication.domain.interactor.AuthenticationResult import com.android.systemui.authentication.domain.interactor.authenticationInteractor import com.android.systemui.authentication.domain.interactor.authenticationInteractor import com.android.systemui.flags.EnableSceneContainer 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.Kosmos import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.runCurrent import com.android.systemui.kosmos.runCurrent Loading Loading @@ -256,6 +258,63 @@ class QuickSettingsShadeOverlayContentViewModelTest : SysuiTestCase() { assertThat(underTest.isTransparencyEnabled).isFalse() 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() { private fun Kosmos.lockDevice() { val currentScene by collectLastValue(sceneInteractor.currentScene) val currentScene by collectLastValue(sceneInteractor.currentScene) powerInteractor.setAsleepForTest() powerInteractor.setAsleepForTest() Loading packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModel.kt +19 −0 Original line number Original line Diff line number Diff line Loading @@ -21,11 +21,13 @@ import android.graphics.Rect import android.media.AudioManager import android.media.AudioManager import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf 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.settingslib.volume.shared.model.AudioStream import com.android.systemui.Flags import com.android.systemui.Flags import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.desktop.domain.interactor.DesktopInteractor import com.android.systemui.desktop.domain.interactor.DesktopInteractor import com.android.systemui.development.ui.viewmodel.BuildNumberViewModel 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.ExclusiveActivatable import com.android.systemui.lifecycle.Hydrator import com.android.systemui.lifecycle.Hydrator import com.android.systemui.qs.flags.QsDetailedView 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.qs.tiles.dialog.AudioDetailsViewModel import com.android.systemui.res.R import com.android.systemui.res.R import com.android.systemui.scene.domain.interactor.SceneInteractor 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.scene.shared.model.Scenes import com.android.systemui.shade.ShadeDisplayAware import com.android.systemui.shade.ShadeDisplayAware import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.shade.domain.interactor.ShadeInteractor Loading Loading @@ -80,6 +83,7 @@ constructor( val notificationStackAppearanceInteractor: NotificationStackAppearanceInteractor, val notificationStackAppearanceInteractor: NotificationStackAppearanceInteractor, @Assisted private val volumeSliderCoroutineScope: CoroutineScope?, @Assisted private val volumeSliderCoroutineScope: CoroutineScope?, val toolbarViewModelFactory: ToolbarViewModel.Factory, val toolbarViewModelFactory: ToolbarViewModel.Factory, private val blurConfig: BlurConfig, windowRootViewBlurInteractor: WindowRootViewBlurInteractor, windowRootViewBlurInteractor: WindowRootViewBlurInteractor, ) : ExclusiveActivatable() { ) : 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 = private val showVolumeSlider = QsDetailedView.isEnabled && QsDetailedView.isEnabled && shadeContext.resources.getBoolean(R.bool.config_enableDesktopAudioTileDetailsView) 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 Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.systemui.qs.ui.viewmodel import android.content.applicationContext import android.content.applicationContext import com.android.systemui.desktop.domain.interactor.desktopInteractor import com.android.systemui.desktop.domain.interactor.desktopInteractor import com.android.systemui.development.ui.viewmodel.buildNumberViewModelFactory 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.Kosmos import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testDispatcher import com.android.systemui.qs.panels.ui.viewmodel.toolbar.toolbarViewModelFactory import com.android.systemui.qs.panels.ui.viewmodel.toolbar.toolbarViewModelFactory Loading Loading @@ -51,6 +52,7 @@ val Kosmos.quickSettingsShadeOverlayContentViewModelFactory: buildNumberViewModelFactory = buildNumberViewModelFactory, buildNumberViewModelFactory = buildNumberViewModelFactory, volumeSliderCoroutineScope = volumeSliderCoroutineScope, volumeSliderCoroutineScope = volumeSliderCoroutineScope, toolbarViewModelFactory = toolbarViewModelFactory, toolbarViewModelFactory = toolbarViewModelFactory, blurConfig = blurConfig, windowRootViewBlurInteractor = windowRootViewBlurInteractor, windowRootViewBlurInteractor = windowRootViewBlurInteractor, ) ) } } Loading Loading
packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt +13 −0 Original line number Original line Diff line number Diff line Loading @@ -39,10 +39,13 @@ import androidx.compose.material3.IconButtonDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier import androidx.compose.ui.draw.blur import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Rect import androidx.compose.ui.geometry.Rect import androidx.compose.ui.geometry.Size import androidx.compose.ui.geometry.Size Loading Loading @@ -155,6 +158,15 @@ constructor( val contentAlphaFromBrightnessMirror by val contentAlphaFromBrightnessMirror by animateFloatAsState(if (showBrightnessMirror) 0f else 1f) 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. // Set the bounds to null when the QuickSettings overlay disappears. DisposableEffectWithLifecycle(Unit) { DisposableEffectWithLifecycle(Unit) { onDispose { onDispose { Loading @@ -169,6 +181,7 @@ constructor( modifier = modifier = modifier modifier .graphicsLayer { alpha = contentAlphaFromBrightnessMirror } .graphicsLayer { alpha = contentAlphaFromBrightnessMirror } .blur(with(LocalDensity.current) { animatedBlurRadiusPx.toDp() }) .thenIf(showBrightnessMirror) { Modifier.gesturesDisabled() } .thenIf(showBrightnessMirror) { Modifier.gesturesDisabled() } ) { ) { OverlayShade( OverlayShade( Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModelTest.kt +59 −0 Original line number Original line Diff line number Diff line Loading @@ -23,12 +23,14 @@ import android.platform.test.annotations.EnableFlags import androidx.compose.ui.geometry.Rect import androidx.compose.ui.geometry.Rect import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest 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.Flags.FLAG_NOTIFICATION_SHADE_BLUR import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository import com.android.systemui.authentication.domain.interactor.AuthenticationResult import com.android.systemui.authentication.domain.interactor.AuthenticationResult import com.android.systemui.authentication.domain.interactor.authenticationInteractor import com.android.systemui.authentication.domain.interactor.authenticationInteractor import com.android.systemui.flags.EnableSceneContainer 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.Kosmos import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.runCurrent import com.android.systemui.kosmos.runCurrent Loading Loading @@ -256,6 +258,63 @@ class QuickSettingsShadeOverlayContentViewModelTest : SysuiTestCase() { assertThat(underTest.isTransparencyEnabled).isFalse() 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() { private fun Kosmos.lockDevice() { val currentScene by collectLastValue(sceneInteractor.currentScene) val currentScene by collectLastValue(sceneInteractor.currentScene) powerInteractor.setAsleepForTest() powerInteractor.setAsleepForTest() Loading
packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModel.kt +19 −0 Original line number Original line Diff line number Diff line Loading @@ -21,11 +21,13 @@ import android.graphics.Rect import android.media.AudioManager import android.media.AudioManager import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf 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.settingslib.volume.shared.model.AudioStream import com.android.systemui.Flags import com.android.systemui.Flags import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.desktop.domain.interactor.DesktopInteractor import com.android.systemui.desktop.domain.interactor.DesktopInteractor import com.android.systemui.development.ui.viewmodel.BuildNumberViewModel 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.ExclusiveActivatable import com.android.systemui.lifecycle.Hydrator import com.android.systemui.lifecycle.Hydrator import com.android.systemui.qs.flags.QsDetailedView 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.qs.tiles.dialog.AudioDetailsViewModel import com.android.systemui.res.R import com.android.systemui.res.R import com.android.systemui.scene.domain.interactor.SceneInteractor 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.scene.shared.model.Scenes import com.android.systemui.shade.ShadeDisplayAware import com.android.systemui.shade.ShadeDisplayAware import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.shade.domain.interactor.ShadeInteractor Loading Loading @@ -80,6 +83,7 @@ constructor( val notificationStackAppearanceInteractor: NotificationStackAppearanceInteractor, val notificationStackAppearanceInteractor: NotificationStackAppearanceInteractor, @Assisted private val volumeSliderCoroutineScope: CoroutineScope?, @Assisted private val volumeSliderCoroutineScope: CoroutineScope?, val toolbarViewModelFactory: ToolbarViewModel.Factory, val toolbarViewModelFactory: ToolbarViewModel.Factory, private val blurConfig: BlurConfig, windowRootViewBlurInteractor: WindowRootViewBlurInteractor, windowRootViewBlurInteractor: WindowRootViewBlurInteractor, ) : ExclusiveActivatable() { ) : 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 = private val showVolumeSlider = QsDetailedView.isEnabled && QsDetailedView.isEnabled && shadeContext.resources.getBoolean(R.bool.config_enableDesktopAudioTileDetailsView) 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 Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.systemui.qs.ui.viewmodel import android.content.applicationContext import android.content.applicationContext import com.android.systemui.desktop.domain.interactor.desktopInteractor import com.android.systemui.desktop.domain.interactor.desktopInteractor import com.android.systemui.development.ui.viewmodel.buildNumberViewModelFactory 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.Kosmos import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testDispatcher import com.android.systemui.qs.panels.ui.viewmodel.toolbar.toolbarViewModelFactory import com.android.systemui.qs.panels.ui.viewmodel.toolbar.toolbarViewModelFactory Loading Loading @@ -51,6 +52,7 @@ val Kosmos.quickSettingsShadeOverlayContentViewModelFactory: buildNumberViewModelFactory = buildNumberViewModelFactory, buildNumberViewModelFactory = buildNumberViewModelFactory, volumeSliderCoroutineScope = volumeSliderCoroutineScope, volumeSliderCoroutineScope = volumeSliderCoroutineScope, toolbarViewModelFactory = toolbarViewModelFactory, toolbarViewModelFactory = toolbarViewModelFactory, blurConfig = blurConfig, windowRootViewBlurInteractor = windowRootViewBlurInteractor, windowRootViewBlurInteractor = windowRootViewBlurInteractor, ) ) } } Loading