Loading packages/SystemUI/compose/features/src/com/android/systemui/ambientcue/ui/compose/NavBarPill.kt +21 −7 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.systemui.ambientcue.ui.compose import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.MutableTransitionState import androidx.compose.animation.core.animateFloat import androidx.compose.animation.core.animateFloatAsState Loading Loading @@ -84,6 +85,7 @@ import com.android.systemui.ambientcue.ui.utils.FilterUtils import com.android.systemui.ambientcue.ui.viewmodel.ActionType import com.android.systemui.ambientcue.ui.viewmodel.ActionViewModel import com.android.systemui.res.R import kotlinx.coroutines.delay @Composable fun NavBarPill( Loading Loading @@ -174,6 +176,15 @@ fun NavBarPill( onAnimationStateChange = onAnimationStateChange, ) val blurRadius = remember { Animatable(4f) } LaunchedEffect(Unit) { delay(BLUR_DURATION_MILLIS) blurRadius.animateTo( targetValue = 0f, animationSpec = tween(durationMillis = BLUR_FADE_DURATION_MILLIS), ) } val config = LocalConfiguration.current val isBoldTextEnabled = config.fontWeightAdjustment > 0 val fontScale = config.fontScale Loading Loading @@ -250,11 +261,6 @@ fun NavBarPill( Modifier.clip(RoundedCornerShape(16.dp)) .widthIn(min = navBarWidth, max = maxPillWidth) .background(backgroundColor) .animatedActionBorder( strokeWidth = 1.dp, cornerRadius = 16.dp, visible = visible, ) .then( if (expanded) Modifier else Loading Loading @@ -386,8 +392,13 @@ fun NavBarPill( // Inner glow Box( Modifier.matchParentSize() .padding(1.dp) .blur(4.dp, edgeTreatment = BlurredEdgeTreatment.Unbounded) // Prevent the border from being invisible due to blur. .animatedActionBorder( strokeWidth = 1.dp, cornerRadius = 16.dp, visible = visible, ) .blur(blurRadius.value.dp, edgeTreatment = BlurredEdgeTreatment.Unbounded) .animatedActionBorder( strokeWidth = 1.dp, cornerRadius = 16.dp, Loading Loading @@ -428,3 +439,6 @@ fun NavBarPill( } } } private const val BLUR_DURATION_MILLIS = 1500L private const val BLUR_FADE_DURATION_MILLIS = 500 packages/SystemUI/compose/features/src/com/android/systemui/ambientcue/ui/compose/ShortPill.kt +54 −10 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.systemui.ambientcue.ui.compose import android.view.Surface.ROTATION_90 import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.MutableTransitionState import androidx.compose.animation.core.TweenSpec import androidx.compose.animation.core.animateFloat Loading Loading @@ -48,6 +49,7 @@ import androidx.compose.material3.IconButtonDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf Loading Loading @@ -83,6 +85,7 @@ import com.android.systemui.ambientcue.ui.utils.FilterUtils import com.android.systemui.ambientcue.ui.viewmodel.ActionType import com.android.systemui.ambientcue.ui.viewmodel.ActionViewModel import com.android.systemui.res.R import kotlinx.coroutines.delay @Composable fun ShortPill( Loading Loading @@ -148,6 +151,15 @@ fun ShortPill( if (it) 0.4f else 0f } val blurRadius = remember { Animatable(4f) } LaunchedEffect(Unit) { delay(BLUR_DURATION_MILLIS) blurRadius.animateTo( targetValue = 0f, animationSpec = tween(durationMillis = BLUR_FADE_DURATION_MILLIS), ) } AmbientCueJankMonitorComposable( visibleTargetState = visibleState.targetState, enterProgress = enterProgress, Loading Loading @@ -223,7 +235,6 @@ fun ShortPill( val pillModifier = Modifier.clip(RoundedCornerShape(16.dp)) .background(backgroundColor) .animatedActionBorder(strokeWidth = 1.dp, cornerRadius = 16.dp, visible = visible) .widthIn(0.dp, minSize * 2) .padding(4.dp) Loading Loading @@ -310,10 +321,19 @@ fun ShortPill( } } // Inner glow Box( Modifier.matchParentSize() .padding(1.dp) .blur(4.dp, edgeTreatment = BlurredEdgeTreatment.Unbounded) // Prevent the border from being invisible due to blur. .animatedActionBorder( strokeWidth = 1.dp, cornerRadius = 16.dp, visible = visible, ) .blur( blurRadius.value.dp, edgeTreatment = BlurredEdgeTreatment.Unbounded, ) .animatedActionBorder( strokeWidth = 1.dp, cornerRadius = 16.dp, Loading Loading @@ -344,6 +364,7 @@ fun ShortPill( pillContentPosition = coordinates.positionInParent() }, ) { Box { Column( verticalArrangement = Arrangement.spacedBy(-4.dp, Alignment.CenterVertically), Loading @@ -353,6 +374,27 @@ fun ShortPill( Icon(action, backgroundColor) } } // Inner glow Box( Modifier.matchParentSize() // Prevent the border from being invisible due to blur. .animatedActionBorder( strokeWidth = 1.dp, cornerRadius = 16.dp, visible = visible, ) .blur( blurRadius.value.dp, edgeTreatment = BlurredEdgeTreatment.Unbounded, ) .animatedActionBorder( strokeWidth = 1.dp, cornerRadius = 16.dp, visible = visible, ) ) } } CloseButton(onCloseClick = onCloseClick, modifier = Modifier.size(closeButtonSize)) Loading Loading @@ -437,3 +479,5 @@ private fun Icon(action: ActionViewModel, backgroundColor: Color, modifier: Modi } private val closeButtonTouchTargetSize = 36.dp private const val BLUR_DURATION_MILLIS = 1500L private const val BLUR_FADE_DURATION_MILLIS = 500 packages/SystemUI/compose/features/src/com/android/systemui/ambientcue/ui/compose/modifier/AnimatedActionBorder.kt +19 −38 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.ambientcue.ui.compose.modifier import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.repeatable import androidx.compose.animation.core.tween import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable Loading Loading @@ -48,7 +49,6 @@ fun Modifier.animatedActionBorder( visible: Boolean = true, ): Modifier { val rotationAngle = remember { Animatable(Constants.INITIAL_ROTATION_DEGREES) } val fadeProgress = remember { Animatable(0f) } // 0f = full gradient, 1f = full solid val strokeWidthPx = with(LocalDensity.current) { strokeWidth.toPx() } val halfStroke = strokeWidthPx / 2f Loading @@ -65,25 +65,14 @@ fun Modifier.animatedActionBorder( launch { rotationAngle.snapTo(Constants.INITIAL_ROTATION_DEGREES) rotationAngle.animateTo( targetValue = Constants.INITIAL_ROTATION_DEGREES + 180f, targetValue = rotationAngle.value + 360f, animationSpec = repeatable( iterations = 2, tween( durationMillis = Constants.ROTATION_DURATION_MILLIS, delayMillis = Constants.FADE_DURATION_MILLIS, easing = LinearEasing, ), ) } launch { fadeProgress.snapTo(0f) fadeProgress.animateTo( targetValue = 1f, animationSpec = tween( durationMillis = Constants.FADE_DURATION_MILLIS, delayMillis = Constants.FADE_DELAY_MILLIS, easing = LinearEasing, ), ) } Loading @@ -92,9 +81,6 @@ fun Modifier.animatedActionBorder( return drawWithContent { val currentRotationRad = Math.toRadians(rotationAngle.value.toDouble()).toFloat() val solidOutlineFadeIn = fadeProgress.value val gradientOutlineFadeOut = (1f - solidOutlineFadeIn) val cornerRadiusPx = with(density) { cornerRadius.toPx() } val gradientWidth = size.width / 2f Loading @@ -120,16 +106,13 @@ fun Modifier.animatedActionBorder( tileMode = TileMode.Clamp, ) if (gradientOutlineFadeOut > 0) { drawRoundRect( brush = gradientBrush, topLeft = topLeft, size = Size(size.width - strokeWidthPx, size.height - strokeWidthPx), cornerRadius = CornerRadius(cornerRadiusPx), alpha = gradientOutlineFadeOut, style = strokeStyle, ) } drawContent() } Loading @@ -137,10 +120,8 @@ fun Modifier.animatedActionBorder( private object Constants { const val INITIAL_ROTATION_DEGREES: Float = 45f const val GRADIENT_START_FRACTION = 0.1f const val GRADIENT_MIDDLE_FRACTION = 0.4f const val GRADIENT_END_FRACTION = 0.6f const val ROTATION_DURATION_MILLIS: Int = 1500 const val FADE_DURATION_MILLIS: Int = 500 const val FADE_DELAY_MILLIS: Int = 1500 const val GRADIENT_START_FRACTION = 0.3f const val GRADIENT_MIDDLE_FRACTION = 0.5f const val GRADIENT_END_FRACTION = 0.8f const val ROTATION_DURATION_MILLIS: Int = 3000 } Loading
packages/SystemUI/compose/features/src/com/android/systemui/ambientcue/ui/compose/NavBarPill.kt +21 −7 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.systemui.ambientcue.ui.compose import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.MutableTransitionState import androidx.compose.animation.core.animateFloat import androidx.compose.animation.core.animateFloatAsState Loading Loading @@ -84,6 +85,7 @@ import com.android.systemui.ambientcue.ui.utils.FilterUtils import com.android.systemui.ambientcue.ui.viewmodel.ActionType import com.android.systemui.ambientcue.ui.viewmodel.ActionViewModel import com.android.systemui.res.R import kotlinx.coroutines.delay @Composable fun NavBarPill( Loading Loading @@ -174,6 +176,15 @@ fun NavBarPill( onAnimationStateChange = onAnimationStateChange, ) val blurRadius = remember { Animatable(4f) } LaunchedEffect(Unit) { delay(BLUR_DURATION_MILLIS) blurRadius.animateTo( targetValue = 0f, animationSpec = tween(durationMillis = BLUR_FADE_DURATION_MILLIS), ) } val config = LocalConfiguration.current val isBoldTextEnabled = config.fontWeightAdjustment > 0 val fontScale = config.fontScale Loading Loading @@ -250,11 +261,6 @@ fun NavBarPill( Modifier.clip(RoundedCornerShape(16.dp)) .widthIn(min = navBarWidth, max = maxPillWidth) .background(backgroundColor) .animatedActionBorder( strokeWidth = 1.dp, cornerRadius = 16.dp, visible = visible, ) .then( if (expanded) Modifier else Loading Loading @@ -386,8 +392,13 @@ fun NavBarPill( // Inner glow Box( Modifier.matchParentSize() .padding(1.dp) .blur(4.dp, edgeTreatment = BlurredEdgeTreatment.Unbounded) // Prevent the border from being invisible due to blur. .animatedActionBorder( strokeWidth = 1.dp, cornerRadius = 16.dp, visible = visible, ) .blur(blurRadius.value.dp, edgeTreatment = BlurredEdgeTreatment.Unbounded) .animatedActionBorder( strokeWidth = 1.dp, cornerRadius = 16.dp, Loading Loading @@ -428,3 +439,6 @@ fun NavBarPill( } } } private const val BLUR_DURATION_MILLIS = 1500L private const val BLUR_FADE_DURATION_MILLIS = 500
packages/SystemUI/compose/features/src/com/android/systemui/ambientcue/ui/compose/ShortPill.kt +54 −10 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.systemui.ambientcue.ui.compose import android.view.Surface.ROTATION_90 import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.MutableTransitionState import androidx.compose.animation.core.TweenSpec import androidx.compose.animation.core.animateFloat Loading Loading @@ -48,6 +49,7 @@ import androidx.compose.material3.IconButtonDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf Loading Loading @@ -83,6 +85,7 @@ import com.android.systemui.ambientcue.ui.utils.FilterUtils import com.android.systemui.ambientcue.ui.viewmodel.ActionType import com.android.systemui.ambientcue.ui.viewmodel.ActionViewModel import com.android.systemui.res.R import kotlinx.coroutines.delay @Composable fun ShortPill( Loading Loading @@ -148,6 +151,15 @@ fun ShortPill( if (it) 0.4f else 0f } val blurRadius = remember { Animatable(4f) } LaunchedEffect(Unit) { delay(BLUR_DURATION_MILLIS) blurRadius.animateTo( targetValue = 0f, animationSpec = tween(durationMillis = BLUR_FADE_DURATION_MILLIS), ) } AmbientCueJankMonitorComposable( visibleTargetState = visibleState.targetState, enterProgress = enterProgress, Loading Loading @@ -223,7 +235,6 @@ fun ShortPill( val pillModifier = Modifier.clip(RoundedCornerShape(16.dp)) .background(backgroundColor) .animatedActionBorder(strokeWidth = 1.dp, cornerRadius = 16.dp, visible = visible) .widthIn(0.dp, minSize * 2) .padding(4.dp) Loading Loading @@ -310,10 +321,19 @@ fun ShortPill( } } // Inner glow Box( Modifier.matchParentSize() .padding(1.dp) .blur(4.dp, edgeTreatment = BlurredEdgeTreatment.Unbounded) // Prevent the border from being invisible due to blur. .animatedActionBorder( strokeWidth = 1.dp, cornerRadius = 16.dp, visible = visible, ) .blur( blurRadius.value.dp, edgeTreatment = BlurredEdgeTreatment.Unbounded, ) .animatedActionBorder( strokeWidth = 1.dp, cornerRadius = 16.dp, Loading Loading @@ -344,6 +364,7 @@ fun ShortPill( pillContentPosition = coordinates.positionInParent() }, ) { Box { Column( verticalArrangement = Arrangement.spacedBy(-4.dp, Alignment.CenterVertically), Loading @@ -353,6 +374,27 @@ fun ShortPill( Icon(action, backgroundColor) } } // Inner glow Box( Modifier.matchParentSize() // Prevent the border from being invisible due to blur. .animatedActionBorder( strokeWidth = 1.dp, cornerRadius = 16.dp, visible = visible, ) .blur( blurRadius.value.dp, edgeTreatment = BlurredEdgeTreatment.Unbounded, ) .animatedActionBorder( strokeWidth = 1.dp, cornerRadius = 16.dp, visible = visible, ) ) } } CloseButton(onCloseClick = onCloseClick, modifier = Modifier.size(closeButtonSize)) Loading Loading @@ -437,3 +479,5 @@ private fun Icon(action: ActionViewModel, backgroundColor: Color, modifier: Modi } private val closeButtonTouchTargetSize = 36.dp private const val BLUR_DURATION_MILLIS = 1500L private const val BLUR_FADE_DURATION_MILLIS = 500
packages/SystemUI/compose/features/src/com/android/systemui/ambientcue/ui/compose/modifier/AnimatedActionBorder.kt +19 −38 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.ambientcue.ui.compose.modifier import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.repeatable import androidx.compose.animation.core.tween import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable Loading Loading @@ -48,7 +49,6 @@ fun Modifier.animatedActionBorder( visible: Boolean = true, ): Modifier { val rotationAngle = remember { Animatable(Constants.INITIAL_ROTATION_DEGREES) } val fadeProgress = remember { Animatable(0f) } // 0f = full gradient, 1f = full solid val strokeWidthPx = with(LocalDensity.current) { strokeWidth.toPx() } val halfStroke = strokeWidthPx / 2f Loading @@ -65,25 +65,14 @@ fun Modifier.animatedActionBorder( launch { rotationAngle.snapTo(Constants.INITIAL_ROTATION_DEGREES) rotationAngle.animateTo( targetValue = Constants.INITIAL_ROTATION_DEGREES + 180f, targetValue = rotationAngle.value + 360f, animationSpec = repeatable( iterations = 2, tween( durationMillis = Constants.ROTATION_DURATION_MILLIS, delayMillis = Constants.FADE_DURATION_MILLIS, easing = LinearEasing, ), ) } launch { fadeProgress.snapTo(0f) fadeProgress.animateTo( targetValue = 1f, animationSpec = tween( durationMillis = Constants.FADE_DURATION_MILLIS, delayMillis = Constants.FADE_DELAY_MILLIS, easing = LinearEasing, ), ) } Loading @@ -92,9 +81,6 @@ fun Modifier.animatedActionBorder( return drawWithContent { val currentRotationRad = Math.toRadians(rotationAngle.value.toDouble()).toFloat() val solidOutlineFadeIn = fadeProgress.value val gradientOutlineFadeOut = (1f - solidOutlineFadeIn) val cornerRadiusPx = with(density) { cornerRadius.toPx() } val gradientWidth = size.width / 2f Loading @@ -120,16 +106,13 @@ fun Modifier.animatedActionBorder( tileMode = TileMode.Clamp, ) if (gradientOutlineFadeOut > 0) { drawRoundRect( brush = gradientBrush, topLeft = topLeft, size = Size(size.width - strokeWidthPx, size.height - strokeWidthPx), cornerRadius = CornerRadius(cornerRadiusPx), alpha = gradientOutlineFadeOut, style = strokeStyle, ) } drawContent() } Loading @@ -137,10 +120,8 @@ fun Modifier.animatedActionBorder( private object Constants { const val INITIAL_ROTATION_DEGREES: Float = 45f const val GRADIENT_START_FRACTION = 0.1f const val GRADIENT_MIDDLE_FRACTION = 0.4f const val GRADIENT_END_FRACTION = 0.6f const val ROTATION_DURATION_MILLIS: Int = 1500 const val FADE_DURATION_MILLIS: Int = 500 const val FADE_DELAY_MILLIS: Int = 1500 const val GRADIENT_START_FRACTION = 0.3f const val GRADIENT_MIDDLE_FRACTION = 0.5f const val GRADIENT_END_FRACTION = 0.8f const val ROTATION_DURATION_MILLIS: Int = 3000 }