diff options
11 files changed, 183 insertions, 46 deletions
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt index 7b21d091d451..dd043dbebaa6 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt @@ -18,11 +18,14 @@ package com.android.systemui.keyguard.ui.composable import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import com.android.compose.animation.scene.SceneScope +import com.android.compose.animation.scene.animateSceneFloatAsState import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.keyguard.ui.viewmodel.LockscreenSceneViewModel +import com.android.systemui.qs.ui.composable.QuickSettings import com.android.systemui.scene.shared.model.Direction import com.android.systemui.scene.shared.model.Edge import com.android.systemui.scene.shared.model.SceneKey @@ -87,10 +90,15 @@ constructor( } @Composable -private fun LockscreenScene( +private fun SceneScope.LockscreenScene( lockscreenContent: Lazy<LockscreenContent>, modifier: Modifier = Modifier, ) { + animateSceneFloatAsState( + value = QuickSettings.SharedValues.SquishinessValues.LockscreenSceneStarting, + key = QuickSettings.SharedValues.TilesSquishiness, + ) + lockscreenContent .get() .Content( diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt index de8f2ec6e941..5d0b9ba2c736 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt @@ -16,7 +16,6 @@ package com.android.systemui.qs.ui.composable -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth @@ -32,14 +31,12 @@ import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.MovableElementScenePicker import com.android.compose.animation.scene.SceneScope import com.android.compose.animation.scene.TransitionState +import com.android.compose.animation.scene.ValueKey import com.android.compose.modifiers.thenIf -import com.android.compose.theme.colorAttr import com.android.systemui.qs.ui.adapter.QSSceneAdapter import com.android.systemui.qs.ui.adapter.QSSceneAdapter.State.Companion.Collapsing import com.android.systemui.qs.ui.adapter.QSSceneAdapter.State.Expanding -import com.android.systemui.res.R -import com.android.systemui.scene.ui.composable.Gone -import com.android.systemui.scene.ui.composable.Lockscreen +import com.android.systemui.qs.ui.adapter.QSSceneAdapter.State.Unsquishing import com.android.systemui.scene.ui.composable.QuickSettings as QuickSettingsSceneKey import com.android.systemui.scene.ui.composable.Shade @@ -51,15 +48,24 @@ object QuickSettings { ) object Elements { - // TODO RENAME val Content = ElementKey("QuickSettingsContent", scenePicker = MovableElementScenePicker(SCENES)) - val CollapsedGrid = ElementKey("QuickSettingsCollapsedGrid") val FooterActions = ElementKey("QuickSettingsFooterActions") } + + object SharedValues { + val TilesSquishiness = ValueKey("QuickSettingsTileSquishiness") + object SquishinessValues { + val Default = 1f + val LockscreenSceneStarting = 0f + val GoneSceneStarting = 0.3f + } + } } -private fun SceneScope.stateForQuickSettingsContent(): QSSceneAdapter.State { +private fun SceneScope.stateForQuickSettingsContent( + squishiness: Float = QuickSettings.SharedValues.SquishinessValues.Default +): QSSceneAdapter.State { return when (val transitionState = layoutState.transitionState) { is TransitionState.Idle -> { when (transitionState.currentScene) { @@ -73,10 +79,10 @@ private fun SceneScope.stateForQuickSettingsContent(): QSSceneAdapter.State { when { fromScene == Shade && toScene == QuickSettingsSceneKey -> Expanding(progress) fromScene == QuickSettingsSceneKey && toScene == Shade -> Collapsing(progress) - toScene == Shade -> QSSceneAdapter.State.QQS - toScene == QuickSettingsSceneKey -> QSSceneAdapter.State.QS - toScene == Gone -> QSSceneAdapter.State.CLOSED - toScene == Lockscreen -> QSSceneAdapter.State.CLOSED + fromScene == Shade || toScene == Shade -> Unsquishing(squishiness) + fromScene == QuickSettingsSceneKey || toScene == QuickSettingsSceneKey -> { + QSSceneAdapter.State.QS + } else -> error( "Bad transition for QuickSettings: fromScene=$fromScene," + @@ -90,14 +96,24 @@ private fun SceneScope.stateForQuickSettingsContent(): QSSceneAdapter.State { /** * This composable will show QuickSettingsContent in the correct state (as determined by its * [SceneScope]). + * + * If adding to scenes not in: + * * QuickSettingsScene + * * ShadeScene + * + * amend: + * * [stateForQuickSettingsContent], + * * [QuickSettings.SCENES], + * * this doc. */ @Composable fun SceneScope.QuickSettings( qsSceneAdapter: QSSceneAdapter, heightProvider: () -> Int, modifier: Modifier = Modifier, + squishiness: Float = QuickSettings.SharedValues.SquishinessValues.Default, ) { - val contentState = stateForQuickSettingsContent() + val contentState = stateForQuickSettingsContent(squishiness) MovableElement( key = QuickSettings.Elements.Content, @@ -136,7 +152,7 @@ private fun QuickSettingsContent( modifier.fillMaxWidth().thenIf(isCustomizing) { Modifier.fillMaxHeight() } ) { AndroidView( - modifier = Modifier.fillMaxWidth().background(colorAttr(R.attr.underSurface)), + modifier = Modifier.fillMaxWidth(), factory = { _ -> qsSceneAdapter.setState(state) view diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt index d36345a310d3..66cef86fb773 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt @@ -54,6 +54,7 @@ import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.unit.dp import com.android.compose.animation.scene.SceneScope import com.android.compose.animation.scene.TransitionState +import com.android.compose.animation.scene.animateSceneFloatAsState import com.android.compose.windowsizeclass.LocalWindowSizeClass import com.android.systemui.battery.BatteryMeterViewController import com.android.systemui.compose.modifiers.sysuiResTag @@ -128,6 +129,7 @@ private fun SceneScope.QuickSettingsScene( remember(lifecycleOwner, viewModel) { viewModel.getFooterActionsViewModel(lifecycleOwner) } + animateSceneFloatAsState(value = 1f, key = QuickSettings.SharedValues.TilesSquishiness) // ############## SCROLLING ################ diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt index f90f29d8b9dd..9ca751e81eed 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt @@ -19,9 +19,12 @@ package com.android.systemui.scene.ui.composable import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import com.android.compose.animation.scene.SceneScope +import com.android.compose.animation.scene.animateSceneFloatAsState import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.qs.ui.composable.QuickSettings import com.android.systemui.scene.shared.model.Direction import com.android.systemui.scene.shared.model.Edge import com.android.systemui.scene.shared.model.SceneKey @@ -63,6 +66,10 @@ constructor( override fun SceneScope.Content( modifier: Modifier, ) { + animateSceneFloatAsState( + value = QuickSettings.SharedValues.SquishinessValues.GoneSceneStarting, + key = QuickSettings.SharedValues.TilesSquishiness, + ) Spacer(modifier.fillMaxSize()) } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToShadeTransition.kt index e71f99669df2..48ab68a6f097 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToShadeTransition.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToShadeTransition.kt @@ -1,11 +1,11 @@ package com.android.systemui.scene.ui.composable.transitions import androidx.compose.animation.core.tween -import com.android.compose.animation.scene.Edge import com.android.compose.animation.scene.TransitionBuilder import com.android.systemui.notifications.ui.composable.Notifications import com.android.systemui.qs.ui.composable.QuickSettings import com.android.systemui.shade.ui.composable.Shade +import com.android.systemui.shade.ui.composable.ShadeHeader import kotlin.time.Duration.Companion.milliseconds fun TransitionBuilder.lockscreenToShadeTransition( @@ -13,15 +13,12 @@ fun TransitionBuilder.lockscreenToShadeTransition( ) { spec = tween(durationMillis = DefaultDuration.times(durationScale).inWholeMilliseconds.toInt()) - fractionRange(end = 0.5f) { - fade(Shade.Elements.BackgroundScrim) - translate( - QuickSettings.Elements.CollapsedGrid, - Edge.Top, - startsOutsideLayoutBounds = false, - ) + fractionRange(end = 0.5f) { fade(Shade.Elements.BackgroundScrim) } + translate(QuickSettings.Elements.Content, y = -ShadeHeader.Dimensions.CollapsedHeight * .66f) + fractionRange(start = 0.5f) { + fade(QuickSettings.Elements.Content) + fade(Notifications.Elements.NotificationScrim) } - fractionRange(start = 0.5f) { fade(Notifications.Elements.NotificationScrim) } } private val DefaultDuration = 500.milliseconds diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt index 25df3e49b618..8c6bf618454c 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt @@ -28,6 +28,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment @@ -40,6 +41,7 @@ import androidx.compose.ui.unit.dp import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.LowestZIndexScenePicker import com.android.compose.animation.scene.SceneScope +import com.android.compose.animation.scene.animateSceneFloatAsState import com.android.systemui.battery.BatteryMeterViewController import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application @@ -73,7 +75,6 @@ import kotlinx.coroutines.flow.stateIn object Shade { object Elements { - val QuickSettings = ElementKey("ShadeQuickSettings") val MediaCarousel = ElementKey("ShadeMediaCarousel") val BackgroundScrim = ElementKey("ShadeBackgroundScrim", scenePicker = LowestZIndexScenePicker) @@ -160,6 +161,8 @@ private fun SceneScope.ShadeScene( val density = LocalDensity.current val layoutWidth = remember { mutableStateOf(0) } val maxNotifScrimTop = remember { mutableStateOf(0f) } + val tileSquishiness by + animateSceneFloatAsState(value = 1f, key = QuickSettings.SharedValues.TilesSquishiness) Box( modifier = @@ -190,7 +193,11 @@ private fun SceneScope.ShadeScene( ) QuickSettings( viewModel.qsSceneAdapter, - { viewModel.qsSceneAdapter.qqsHeight }, + { + (viewModel.qsSceneAdapter.qqsHeight * tileSquishiness) + .roundToInt() + }, + squishiness = tileSquishiness, ) if (viewModel.isMediaVisible()) { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterImplTest.kt index f8573cc280c4..3c0ab240cbba 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterImplTest.kt @@ -259,6 +259,37 @@ class QSSceneAdapterImplTest : SysuiTestCase() { } @Test + fun state_unsquishing() = + testScope.runTest { + val qsImpl by collectLastValue(underTest.qsImpl) + val squishiness = 0.342f + + underTest.inflate(context) + runCurrent() + clearInvocations(qsImpl!!) + + underTest.setState(QSSceneAdapter.State.Unsquishing(squishiness)) + with(qsImpl!!) { + verify(this).setQsVisible(true) + verify(this) + .setQsExpansion( + /* expansion= */ 0f, + /* panelExpansionFraction= */ 1f, + /* proposedTranslation= */ 0f, + /* squishinessFraction= */ squishiness, + ) + verify(this).setListening(true) + verify(this).setExpanded(true) + verify(this) + .setTransitionToFullShadeProgress( + /* isTransitioningToFullShade= */ false, + /* qsTransitionFraction= */ 1f, + /* qsSquishinessFraction = */ squishiness, + ) + } + } + + @Test fun customizing_QS() = testScope.runTest { val customizing by collectLastValue(underTest.isCustomizing) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterTest.kt index d1bc686385a1..e281383e6250 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterTest.kt @@ -29,6 +29,12 @@ import org.junit.runner.RunWith @EnabledOnRavenwood @RunWith(AndroidJUnit4::class) class QSSceneAdapterTest : SysuiTestCase() { + + @Test + fun expanding_squishiness1() { + assertThat(QSSceneAdapter.State.Expanding(0.3f).squishiness).isEqualTo(1f) + } + @Test fun expandingSpecialValues() { assertThat(QSSceneAdapter.State.QQS).isEqualTo(QSSceneAdapter.State.Expanding(0f)) @@ -41,4 +47,11 @@ class QSSceneAdapterTest : SysuiTestCase() { assertThat(Collapsing(collapsingProgress)) .isEqualTo(QSSceneAdapter.State.Expanding(1 - collapsingProgress)) } + + @Test + fun unsquishing_expansionSameAsQQS() { + val squishiness = 0.6f + assertThat(QSSceneAdapter.State.Unsquishing(squishiness).expansion) + .isEqualTo(QSSceneAdapter.State.QQS.expansion) + } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java index 8ff0e365f2ce..e5d970d3b40a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java @@ -207,6 +207,9 @@ public class QSImpl implements QS, CommandQueue.Callbacks, StatusBarStateControl mFooterActionsViewBinder = footerActionsViewBinder; mListeningAndVisibilityLifecycleOwner = new ListeningAndVisibilityLifecycleOwner(); mSceneContainerFlags = sceneContainerFlags; + if (mSceneContainerFlags.isEnabled()) { + mStatusBarState = StatusBarState.SHADE; + } } /** @@ -506,10 +509,20 @@ public class QSImpl implements QS, CommandQueue.Callbacks, StatusBarStateControl } } - private boolean isKeyguardState() { - // We want the freshest state here since otherwise we'll have some weirdness if earlier - // listeners trigger updates - return mStatusBarStateController.getCurrentOrUpcomingState() == KEYGUARD; + @VisibleForTesting + boolean isKeyguardState() { + if (mSceneContainerFlags.isEnabled()) { + return false; + } else { + // We want the freshest state here since otherwise we'll have some weirdness if earlier + // listeners trigger updates + return mStatusBarStateController.getCurrentOrUpcomingState() == KEYGUARD; + } + } + + @VisibleForTesting + int getStatusBarState() { + return mStatusBarState; } private void updateShowCollapsedOnKeyguard() { @@ -562,15 +575,17 @@ public class QSImpl implements QS, CommandQueue.Callbacks, StatusBarStateControl } private void setKeyguardShowing(boolean keyguardShowing) { - if (DEBUG) Log.d(TAG, "setKeyguardShowing " + keyguardShowing); - mLastQSExpansion = -1; + if (!mSceneContainerFlags.isEnabled()) { + if (DEBUG) Log.d(TAG, "setKeyguardShowing " + keyguardShowing); + mLastQSExpansion = -1; - if (mQSAnimator != null) { - mQSAnimator.setOnKeyguard(keyguardShowing); - } + if (mQSAnimator != null) { + mQSAnimator.setOnKeyguard(keyguardShowing); + } - mFooter.setKeyguardShowing(keyguardShowing); - updateQsState(); + mFooter.setKeyguardShowing(keyguardShowing); + updateQsState(); + } } @Override @@ -971,7 +986,7 @@ public class QSImpl implements QS, CommandQueue.Callbacks, StatusBarStateControl @Override public void onStateChanged(int newState) { - if (newState == mStatusBarState) { + if (mSceneContainerFlags.isEnabled() || newState == mStatusBarState) { return; } mStatusBarState = newState; diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt index 6e4f72daaf9c..72a5c468ea94 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt @@ -84,18 +84,36 @@ interface QSSceneAdapter { */ val qsHeight: Int - sealed class State( - val isVisible: Boolean, - val expansion: Float, - ) { - data object CLOSED : State(false, 0f) - data class Expanding(val progress: Float) : State(true, progress) + sealed interface State { + + val isVisible: Boolean + val expansion: Float + val squishiness: Float + + data object CLOSED : State { + override val isVisible = false + override val expansion = 0f + override val squishiness = 1f + } + + /** State for expanding between QQS and QS */ + data class Expanding(override val expansion: Float) : State { + override val isVisible = true + override val squishiness = 1f + } + + /** State for appearing QQS from Lockscreen or Gone */ + data class Unsquishing(override val squishiness: Float) : State { + override val isVisible = true + override val expansion = 0f + } companion object { // These are special cases of the expansion. val QQS = Expanding(0f) val QS = Expanding(1f) + /** Collapsing from QS to QQS. [progress] is 0f in QS and 1f in QQS. */ fun Collapsing(progress: Float) = Expanding(1f - progress) } } @@ -232,7 +250,7 @@ constructor( setQsVisible(state.isVisible) setExpanded(state.isVisible) setListening(state.isVisible) - setQsExpansion(state.expansion, 1f, 0f, 1f) - setTransitionToFullShadeProgress(false, 1f, 1f) + setQsExpansion(state.expansion, 1f, 0f, state.squishiness) + setTransitionToFullShadeProgress(false, 1f, state.squishiness) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSImplTest.java index 563a3fe9fc7f..8e72d0636459 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSImplTest.java @@ -20,6 +20,7 @@ import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS; import static com.android.systemui.statusbar.StatusBarState.KEYGUARD; import static com.android.systemui.statusbar.StatusBarState.SHADE; +import static com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED; import static com.google.common.truth.Truth.assertThat; @@ -511,6 +512,28 @@ public class QSImplTest extends SysuiTestCase { ); } + @Test + public void testSceneContainerFlagsEnabled_statusBarStateIsShade() { + when(mSceneContainerFlags.isEnabled()).thenReturn(true); + + mUnderTest.onStateChanged(KEYGUARD); + assertThat(mUnderTest.getStatusBarState()).isEqualTo(SHADE); + + mUnderTest.onStateChanged(SHADE_LOCKED); + assertThat(mUnderTest.getStatusBarState()).isEqualTo(SHADE); + } + + @Test + public void testSceneContainerFlagsEnabled_isKeyguardState_alwaysFalse() { + when(mSceneContainerFlags.isEnabled()).thenReturn(true); + + mUnderTest.onStateChanged(KEYGUARD); + assertThat(mUnderTest.isKeyguardState()).isFalse(); + + when(mStatusBarStateController.getCurrentOrUpcomingState()).thenReturn(KEYGUARD); + assertThat(mUnderTest.isKeyguardState()).isFalse(); + } + private QSImpl instantiate() { setupQsComponent(); setUpViews(); |