Loading packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToShadeTransition.kt +1 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ fun TransitionBuilder.goneToShadeTransition( ) { spec = tween(durationMillis = DefaultDuration.times(durationScale).inWholeMilliseconds.toInt()) fractionRange(start = .58f) { fade(ShadeHeader.Elements.Clock) } fractionRange(start = .58f) { fade(ShadeHeader.Elements.CollapsedContentStart) } fractionRange(start = .58f) { fade(ShadeHeader.Elements.CollapsedContentEnd) } fractionRange(start = .58f) { fade(ShadeHeader.Elements.PrivacyChip) } Loading packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt +6 −1 Original line number Diff line number Diff line Loading @@ -18,10 +18,15 @@ fun TransitionBuilder.shadeToQuickSettingsTransition() { y = ShadeHeader.Dimensions.CollapsedHeight ) translate(ShadeHeader.Elements.CollapsedContentEnd, y = ShadeHeader.Dimensions.CollapsedHeight) translate(ShadeHeader.Elements.ExpandedContent, y = (-ShadeHeader.Dimensions.ExpandedHeight)) translate( ShadeHeader.Elements.ExpandedContent, y = -(ShadeHeader.Dimensions.ExpandedHeight - ShadeHeader.Dimensions.CollapsedHeight) ) translate(ShadeHeader.Elements.ShadeCarrierGroup, y = -ShadeHeader.Dimensions.CollapsedHeight) fractionRange(end = .14f) { fade(ShadeHeader.Elements.CollapsedContentStart) } fractionRange(end = .14f) { fade(ShadeHeader.Elements.CollapsedContentEnd) } fractionRange(start = .58f) { fade(ShadeHeader.Elements.ExpandedContent) } fractionRange(start = .58f) { fade(ShadeHeader.Elements.ShadeCarrierGroup) } } packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt +69 −38 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.systemui.shade.ui.composable import android.view.ContextThemeWrapper import android.view.ViewGroup import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column Loading Loading @@ -52,6 +53,7 @@ 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.ValueKey import com.android.compose.animation.scene.animateElementFloatAsState import com.android.compose.animation.scene.animateSceneFloatAsState import com.android.compose.windowsizeclass.LocalWindowSizeClass import com.android.settingslib.Utils Loading @@ -64,6 +66,7 @@ import com.android.systemui.res.R import com.android.systemui.scene.ui.composable.QuickSettings import com.android.systemui.scene.ui.composable.Shade as ShadeKey import com.android.systemui.shade.ui.composable.ShadeHeader.Dimensions.CollapsedHeight import com.android.systemui.shade.ui.composable.ShadeHeader.Values.ClockScale import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel import com.android.systemui.statusbar.phone.StatusBarIconController import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager Loading @@ -79,12 +82,18 @@ object ShadeHeader { val CollapsedContentStart = ElementKey("ShadeHeaderCollapsedContentStart") val CollapsedContentEnd = ElementKey("ShadeHeaderCollapsedContentEnd") val PrivacyChip = ElementKey("PrivacyChip", scenePicker = LowestZIndexScenePicker) val Clock = ElementKey("ShadeHeaderClock", scenePicker = LowestZIndexScenePicker) val ShadeCarrierGroup = ElementKey("ShadeCarrierGroup") } object Keys { val transitionProgress = ValueKey("ShadeHeaderTransitionProgress") } object Values { val ClockScale = ValueKey("ShadeHeaderClockScale") } object Dimensions { val CollapsedHeight = 48.dp val ExpandedHeight = 120.dp Loading Loading @@ -121,20 +130,18 @@ fun SceneScope.CollapsedShadeHeader( contents = listOf( { Row(modifier = Modifier.element(ShadeHeader.Elements.CollapsedContentStart)) { AndroidView( factory = { context -> Row { Clock( ContextThemeWrapper(context, R.style.TextAppearance_QS_Status), null ) }, scale = 1f, viewModel = viewModel, modifier = Modifier.align(Alignment.CenterVertically), ) Spacer(modifier = Modifier.width(5.dp)) VariableDayDate( viewModel = viewModel, modifier = Modifier.align(Alignment.CenterVertically), modifier = Modifier.element(ShadeHeader.Elements.CollapsedContentStart) .align(Alignment.CenterVertically), ) } }, Loading Loading @@ -257,40 +264,29 @@ fun SceneScope.ExpandedShadeHeader( Column( verticalArrangement = Arrangement.Bottom, modifier = Modifier.element(ShadeHeader.Elements.ExpandedContent) .fillMaxWidth() Modifier.fillMaxWidth() .defaultMinSize(minHeight = ShadeHeader.Dimensions.ExpandedHeight) ) { Row { AndroidView( factory = { context -> Clock(ContextThemeWrapper(context, R.style.TextAppearance_QS_Status), null) }, modifier = Modifier.align(Alignment.CenterVertically) // use graphicsLayer instead of Modifier.scale to anchor transform to // the (start, top) corner .graphicsLayer( scaleX = 2.57f, scaleY = 2.57f, transformOrigin = TransformOrigin( when (LocalLayoutDirection.current) { LayoutDirection.Ltr -> 0f LayoutDirection.Rtl -> 1f }, 0.5f ) ), Box(modifier = Modifier.fillMaxWidth()) { Box { Clock( scale = 2.57f, viewModel = viewModel, modifier = Modifier.align(Alignment.CenterStart), ) Spacer(modifier = Modifier.weight(1f)) } Box( modifier = Modifier.element(ShadeHeader.Elements.ShadeCarrierGroup).fillMaxWidth() ) { ShadeCarrierGroup( viewModel = viewModel, modifier = Modifier.align(Alignment.CenterVertically), modifier = Modifier.align(Alignment.CenterEnd), ) } } Spacer(modifier = Modifier.width(5.dp)) Row { Row(modifier = Modifier.element(ShadeHeader.Elements.ExpandedContent)) { VariableDayDate( viewModel = viewModel, modifier = Modifier.widthIn(max = 90.dp).align(Alignment.CenterVertically), Loading Loading @@ -318,6 +314,41 @@ fun SceneScope.ExpandedShadeHeader( } } @Composable private fun SceneScope.Clock( scale: Float, viewModel: ShadeHeaderViewModel, modifier: Modifier, ) { val layoutDirection = LocalLayoutDirection.current Element(key = ShadeHeader.Elements.Clock, modifier = modifier) { val animatedScale by animateElementFloatAsState(scale, ClockScale, canOverflow = false) AndroidView( factory = { context -> Clock(ContextThemeWrapper(context, R.style.TextAppearance_QS_Status), null) }, modifier = modifier // use graphicsLayer instead of Modifier.scale to anchor transform // to the (start, top) corner .graphicsLayer { scaleX = animatedScale scaleY = animatedScale transformOrigin = TransformOrigin( when (layoutDirection) { LayoutDirection.Ltr -> 0f LayoutDirection.Rtl -> 1f }, 0.5f ) } .clickable { viewModel.onClockClicked() } ) } } @Composable private fun BatteryIcon( createBatteryMeterViewController: (ViewGroup, StatusBarLocation) -> BatteryMeterViewController, Loading packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt +6 −2 Original line number Diff line number Diff line Loading @@ -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.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember Loading @@ -42,6 +43,7 @@ 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.compose.modifiers.thenIf import com.android.systemui.battery.BatteryMeterViewController import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application Loading Loading @@ -163,6 +165,7 @@ private fun SceneScope.ShadeScene( val maxNotifScrimTop = remember { mutableStateOf(0f) } val tileSquishiness by animateSceneFloatAsState(value = 1f, key = QuickSettings.SharedValues.TilesSquishiness) val isClickable by viewModel.isClickable.collectAsState() Box( modifier = Loading @@ -178,8 +181,9 @@ private fun SceneScope.ShadeScene( Column( horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.fillMaxWidth() .clickable(onClick = { viewModel.onContentClicked() }) Modifier.fillMaxWidth().thenIf(isClickable) { Modifier.clickable(onClick = { viewModel.onContentClicked() }) } ) { CollapsedShadeHeader( viewModel = viewModel.shadeHeaderViewModel, Loading packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt +2 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.UserAction import com.android.systemui.scene.shared.model.UserActionResult import com.android.systemui.shade.domain.interactor.privacyChipInteractor import com.android.systemui.shade.domain.interactor.shadeHeaderClockInteractor import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel import com.android.systemui.statusbar.notification.stack.ui.viewmodel.notificationsPlaceholderViewModel import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository Loading Loading @@ -97,6 +98,7 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() { mobileIconsInteractor = mobileIconsInteractor, mobileIconsViewModel = mobileIconsViewModel, privacyChipInteractor = kosmos.privacyChipInteractor, clockInteractor = kosmos.shadeHeaderClockInteractor, broadcastDispatcher = fakeBroadcastDispatcher, ) Loading Loading
packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToShadeTransition.kt +1 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ fun TransitionBuilder.goneToShadeTransition( ) { spec = tween(durationMillis = DefaultDuration.times(durationScale).inWholeMilliseconds.toInt()) fractionRange(start = .58f) { fade(ShadeHeader.Elements.Clock) } fractionRange(start = .58f) { fade(ShadeHeader.Elements.CollapsedContentStart) } fractionRange(start = .58f) { fade(ShadeHeader.Elements.CollapsedContentEnd) } fractionRange(start = .58f) { fade(ShadeHeader.Elements.PrivacyChip) } Loading
packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt +6 −1 Original line number Diff line number Diff line Loading @@ -18,10 +18,15 @@ fun TransitionBuilder.shadeToQuickSettingsTransition() { y = ShadeHeader.Dimensions.CollapsedHeight ) translate(ShadeHeader.Elements.CollapsedContentEnd, y = ShadeHeader.Dimensions.CollapsedHeight) translate(ShadeHeader.Elements.ExpandedContent, y = (-ShadeHeader.Dimensions.ExpandedHeight)) translate( ShadeHeader.Elements.ExpandedContent, y = -(ShadeHeader.Dimensions.ExpandedHeight - ShadeHeader.Dimensions.CollapsedHeight) ) translate(ShadeHeader.Elements.ShadeCarrierGroup, y = -ShadeHeader.Dimensions.CollapsedHeight) fractionRange(end = .14f) { fade(ShadeHeader.Elements.CollapsedContentStart) } fractionRange(end = .14f) { fade(ShadeHeader.Elements.CollapsedContentEnd) } fractionRange(start = .58f) { fade(ShadeHeader.Elements.ExpandedContent) } fractionRange(start = .58f) { fade(ShadeHeader.Elements.ShadeCarrierGroup) } }
packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt +69 −38 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.systemui.shade.ui.composable import android.view.ContextThemeWrapper import android.view.ViewGroup import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column Loading Loading @@ -52,6 +53,7 @@ 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.ValueKey import com.android.compose.animation.scene.animateElementFloatAsState import com.android.compose.animation.scene.animateSceneFloatAsState import com.android.compose.windowsizeclass.LocalWindowSizeClass import com.android.settingslib.Utils Loading @@ -64,6 +66,7 @@ import com.android.systemui.res.R import com.android.systemui.scene.ui.composable.QuickSettings import com.android.systemui.scene.ui.composable.Shade as ShadeKey import com.android.systemui.shade.ui.composable.ShadeHeader.Dimensions.CollapsedHeight import com.android.systemui.shade.ui.composable.ShadeHeader.Values.ClockScale import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel import com.android.systemui.statusbar.phone.StatusBarIconController import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager Loading @@ -79,12 +82,18 @@ object ShadeHeader { val CollapsedContentStart = ElementKey("ShadeHeaderCollapsedContentStart") val CollapsedContentEnd = ElementKey("ShadeHeaderCollapsedContentEnd") val PrivacyChip = ElementKey("PrivacyChip", scenePicker = LowestZIndexScenePicker) val Clock = ElementKey("ShadeHeaderClock", scenePicker = LowestZIndexScenePicker) val ShadeCarrierGroup = ElementKey("ShadeCarrierGroup") } object Keys { val transitionProgress = ValueKey("ShadeHeaderTransitionProgress") } object Values { val ClockScale = ValueKey("ShadeHeaderClockScale") } object Dimensions { val CollapsedHeight = 48.dp val ExpandedHeight = 120.dp Loading Loading @@ -121,20 +130,18 @@ fun SceneScope.CollapsedShadeHeader( contents = listOf( { Row(modifier = Modifier.element(ShadeHeader.Elements.CollapsedContentStart)) { AndroidView( factory = { context -> Row { Clock( ContextThemeWrapper(context, R.style.TextAppearance_QS_Status), null ) }, scale = 1f, viewModel = viewModel, modifier = Modifier.align(Alignment.CenterVertically), ) Spacer(modifier = Modifier.width(5.dp)) VariableDayDate( viewModel = viewModel, modifier = Modifier.align(Alignment.CenterVertically), modifier = Modifier.element(ShadeHeader.Elements.CollapsedContentStart) .align(Alignment.CenterVertically), ) } }, Loading Loading @@ -257,40 +264,29 @@ fun SceneScope.ExpandedShadeHeader( Column( verticalArrangement = Arrangement.Bottom, modifier = Modifier.element(ShadeHeader.Elements.ExpandedContent) .fillMaxWidth() Modifier.fillMaxWidth() .defaultMinSize(minHeight = ShadeHeader.Dimensions.ExpandedHeight) ) { Row { AndroidView( factory = { context -> Clock(ContextThemeWrapper(context, R.style.TextAppearance_QS_Status), null) }, modifier = Modifier.align(Alignment.CenterVertically) // use graphicsLayer instead of Modifier.scale to anchor transform to // the (start, top) corner .graphicsLayer( scaleX = 2.57f, scaleY = 2.57f, transformOrigin = TransformOrigin( when (LocalLayoutDirection.current) { LayoutDirection.Ltr -> 0f LayoutDirection.Rtl -> 1f }, 0.5f ) ), Box(modifier = Modifier.fillMaxWidth()) { Box { Clock( scale = 2.57f, viewModel = viewModel, modifier = Modifier.align(Alignment.CenterStart), ) Spacer(modifier = Modifier.weight(1f)) } Box( modifier = Modifier.element(ShadeHeader.Elements.ShadeCarrierGroup).fillMaxWidth() ) { ShadeCarrierGroup( viewModel = viewModel, modifier = Modifier.align(Alignment.CenterVertically), modifier = Modifier.align(Alignment.CenterEnd), ) } } Spacer(modifier = Modifier.width(5.dp)) Row { Row(modifier = Modifier.element(ShadeHeader.Elements.ExpandedContent)) { VariableDayDate( viewModel = viewModel, modifier = Modifier.widthIn(max = 90.dp).align(Alignment.CenterVertically), Loading Loading @@ -318,6 +314,41 @@ fun SceneScope.ExpandedShadeHeader( } } @Composable private fun SceneScope.Clock( scale: Float, viewModel: ShadeHeaderViewModel, modifier: Modifier, ) { val layoutDirection = LocalLayoutDirection.current Element(key = ShadeHeader.Elements.Clock, modifier = modifier) { val animatedScale by animateElementFloatAsState(scale, ClockScale, canOverflow = false) AndroidView( factory = { context -> Clock(ContextThemeWrapper(context, R.style.TextAppearance_QS_Status), null) }, modifier = modifier // use graphicsLayer instead of Modifier.scale to anchor transform // to the (start, top) corner .graphicsLayer { scaleX = animatedScale scaleY = animatedScale transformOrigin = TransformOrigin( when (layoutDirection) { LayoutDirection.Ltr -> 0f LayoutDirection.Rtl -> 1f }, 0.5f ) } .clickable { viewModel.onClockClicked() } ) } } @Composable private fun BatteryIcon( createBatteryMeterViewController: (ViewGroup, StatusBarLocation) -> BatteryMeterViewController, Loading
packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt +6 −2 Original line number Diff line number Diff line Loading @@ -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.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember Loading @@ -42,6 +43,7 @@ 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.compose.modifiers.thenIf import com.android.systemui.battery.BatteryMeterViewController import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application Loading Loading @@ -163,6 +165,7 @@ private fun SceneScope.ShadeScene( val maxNotifScrimTop = remember { mutableStateOf(0f) } val tileSquishiness by animateSceneFloatAsState(value = 1f, key = QuickSettings.SharedValues.TilesSquishiness) val isClickable by viewModel.isClickable.collectAsState() Box( modifier = Loading @@ -178,8 +181,9 @@ private fun SceneScope.ShadeScene( Column( horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.fillMaxWidth() .clickable(onClick = { viewModel.onContentClicked() }) Modifier.fillMaxWidth().thenIf(isClickable) { Modifier.clickable(onClick = { viewModel.onContentClicked() }) } ) { CollapsedShadeHeader( viewModel = viewModel.shadeHeaderViewModel, Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt +2 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.UserAction import com.android.systemui.scene.shared.model.UserActionResult import com.android.systemui.shade.domain.interactor.privacyChipInteractor import com.android.systemui.shade.domain.interactor.shadeHeaderClockInteractor import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel import com.android.systemui.statusbar.notification.stack.ui.viewmodel.notificationsPlaceholderViewModel import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository Loading Loading @@ -97,6 +98,7 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() { mobileIconsInteractor = mobileIconsInteractor, mobileIconsViewModel = mobileIconsViewModel, privacyChipInteractor = kosmos.privacyChipInteractor, clockInteractor = kosmos.shadeHeaderClockInteractor, broadcastDispatcher = fakeBroadcastDispatcher, ) Loading