diff options
| author | 2024-10-17 22:58:33 +0000 | |
|---|---|---|
| committer | 2024-10-17 22:58:33 +0000 | |
| commit | 64bc28bd4e7bef37eacdd90244d11439c7ca7fe8 (patch) | |
| tree | ce343577509f71a93f5b2cc473a432214fdaaffe | |
| parent | bc83c3d0d3c6932151c3a374833a2dcc912437da (diff) | |
| parent | 3e388b266f326928631818d4beab486186f36150 (diff) | |
Merge "[flexiglass] Fixes long-press on emergency button." into main
2 files changed, 72 insertions, 156 deletions
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt index 7dc2901273b2..c1c3b1fb6c5a 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt @@ -28,6 +28,7 @@ import androidx.compose.animation.core.snap import androidx.compose.animation.core.tween import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image +import androidx.compose.foundation.background import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.layout.Arrangement @@ -46,7 +47,6 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.KeyboardArrowDown -import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem @@ -64,6 +64,7 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.input.key.onKeyEvent @@ -72,6 +73,9 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.platform.testTag +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.semantics.role +import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.DpOffset @@ -88,7 +92,6 @@ import com.android.compose.animation.scene.SceneKey import com.android.compose.animation.scene.SceneScope import com.android.compose.animation.scene.SceneTransitionLayout import com.android.compose.animation.scene.transitions -import com.android.compose.modifiers.thenIf import com.android.compose.windowsizeclass.LocalWindowSizeClass import com.android.systemui.bouncer.shared.model.BouncerActionButtonModel import com.android.systemui.bouncer.ui.BouncerDialogFactory @@ -131,7 +134,7 @@ fun BouncerContent( layout: BouncerSceneLayout, viewModel: BouncerSceneContentViewModel, dialogFactory: BouncerDialogFactory, - modifier: Modifier + modifier: Modifier, ) { Box( // Allows the content within each of the layouts to react to the appearance and @@ -140,31 +143,17 @@ fun BouncerContent( // Despite the keyboard only being part of the password bouncer, adding it at this level is // both necessary to properly handle the keyboard in all layouts and harmless in cases when // the keyboard isn't used (like the PIN or pattern auth methods). - modifier = modifier.imePadding().onKeyEvent(viewModel::onKeyEvent), + modifier = modifier.imePadding().onKeyEvent(viewModel::onKeyEvent) ) { when (layout) { - BouncerSceneLayout.STANDARD_BOUNCER -> - StandardLayout( - viewModel = viewModel, - ) + BouncerSceneLayout.STANDARD_BOUNCER -> StandardLayout(viewModel = viewModel) BouncerSceneLayout.BESIDE_USER_SWITCHER -> - BesideUserSwitcherLayout( - viewModel = viewModel, - ) - BouncerSceneLayout.BELOW_USER_SWITCHER -> - BelowUserSwitcherLayout( - viewModel = viewModel, - ) - BouncerSceneLayout.SPLIT_BOUNCER -> - SplitLayout( - viewModel = viewModel, - ) + BesideUserSwitcherLayout(viewModel = viewModel) + BouncerSceneLayout.BELOW_USER_SWITCHER -> BelowUserSwitcherLayout(viewModel = viewModel) + BouncerSceneLayout.SPLIT_BOUNCER -> SplitLayout(viewModel = viewModel) } - Dialog( - bouncerViewModel = viewModel, - dialogFactory = dialogFactory, - ) + Dialog(bouncerViewModel = viewModel, dialogFactory = dialogFactory) } } @@ -173,31 +162,19 @@ fun BouncerContent( * authentication attempt, including all messaging UI (directives, reasoning, errors, etc.). */ @Composable -private fun StandardLayout( - viewModel: BouncerSceneContentViewModel, - modifier: Modifier = Modifier, -) { +private fun StandardLayout(viewModel: BouncerSceneContentViewModel, modifier: Modifier = Modifier) { val isHeightExpanded = LocalWindowSizeClass.current.heightSizeClass == WindowHeightSizeClass.Expanded FoldAware( - modifier = - modifier.padding( - start = 32.dp, - top = 92.dp, - end = 32.dp, - bottom = 48.dp, - ), + modifier = modifier.padding(start = 32.dp, top = 92.dp, end = 32.dp, bottom = 48.dp), viewModel = viewModel, aboveFold = { Column( horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.fillMaxWidth(), ) { - StatusMessage( - viewModel = viewModel.message, - modifier = Modifier, - ) + StatusMessage(viewModel = viewModel.message, modifier = Modifier) OutputArea( viewModel = viewModel, @@ -210,9 +187,7 @@ private fun StandardLayout( horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.fillMaxWidth(), ) { - Box( - modifier = Modifier.weight(1f), - ) { + Box(modifier = Modifier.weight(1f)) { InputArea( viewModel = viewModel, pinButtonRowVerticalSpacing = 12.dp, @@ -221,10 +196,7 @@ private fun StandardLayout( ) } - ActionArea( - viewModel = viewModel, - modifier = Modifier.padding(top = 48.dp), - ) + ActionArea(viewModel = viewModel, modifier = Modifier.padding(top = 48.dp)) } }, ) @@ -235,10 +207,7 @@ private fun StandardLayout( * by double-tapping on the side. */ @Composable -private fun SplitLayout( - viewModel: BouncerSceneContentViewModel, - modifier: Modifier = Modifier, -) { +private fun SplitLayout(viewModel: BouncerSceneContentViewModel, modifier: Modifier = Modifier) { val authMethod by viewModel.authMethodViewModel.collectAsStateWithLifecycle() Row( @@ -248,12 +217,10 @@ private fun SplitLayout( .padding( horizontal = 24.dp, vertical = if (authMethod is PasswordBouncerViewModel) 24.dp else 48.dp, - ), + ) ) { // Left side (in left-to-right locales). - Box( - modifier = Modifier.fillMaxHeight().weight(1f), - ) { + Box(modifier = Modifier.fillMaxHeight().weight(1f)) { when (authMethod) { is PinBouncerViewModel -> { StatusMessage( @@ -263,7 +230,7 @@ private fun SplitLayout( OutputArea( viewModel = viewModel, modifier = - Modifier.align(Alignment.Center).sysuiResTag("bouncer_text_entry") + Modifier.align(Alignment.Center).sysuiResTag("bouncer_text_entry"), ) ActionArea( @@ -293,9 +260,7 @@ private fun SplitLayout( } // Right side (in right-to-left locales). - Box( - modifier = Modifier.fillMaxHeight().weight(1f), - ) { + Box(modifier = Modifier.fillMaxHeight().weight(1f)) { when (authMethod) { is PinBouncerViewModel, is PatternBouncerViewModel -> { @@ -311,13 +276,11 @@ private fun SplitLayout( horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.fillMaxWidth().align(Alignment.Center), ) { - StatusMessage( - viewModel = viewModel.message, - ) + StatusMessage(viewModel = viewModel.message) OutputArea( viewModel = viewModel, modifier = - Modifier.padding(top = 24.dp).sysuiResTag("bouncer_text_entry") + Modifier.padding(top = 24.dp).sysuiResTag("bouncer_text_entry"), ) } } @@ -365,7 +328,7 @@ private fun BesideUserSwitcherLayout( .padding( top = if (isHeightExpanded) 128.dp else 96.dp, bottom = if (isHeightExpanded) 128.dp else 48.dp, - ), + ) ) { LaunchedEffect(isSwapped) { swapAnimationEnd = false } val animatedOffset by @@ -419,14 +382,12 @@ private fun BesideUserSwitcherLayout( aboveFold = { Column( horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier.fillMaxWidth() + modifier = Modifier.fillMaxWidth(), ) { - StatusMessage( - viewModel = viewModel.message, - ) + StatusMessage(viewModel = viewModel.message) OutputArea( viewModel = viewModel, - modifier = Modifier.padding(top = 24.dp).sysuiResTag("bouncer_text_entry") + modifier = Modifier.padding(top = 24.dp).sysuiResTag("bouncer_text_entry"), ) } }, @@ -444,7 +405,7 @@ private fun BesideUserSwitcherLayout( Box( modifier = Modifier.weight(1f) - .padding(top = (if (addSpacingBetweenOutputAndInput) 24 else 0).dp), + .padding(top = (if (addSpacingBetweenOutputAndInput) 24 else 0).dp) ) { InputArea( viewModel = viewModel, @@ -470,16 +431,8 @@ private fun BelowUserSwitcherLayout( viewModel: BouncerSceneContentViewModel, modifier: Modifier = Modifier, ) { - Column( - modifier = - modifier.padding( - vertical = 128.dp, - ) - ) { - UserSwitcher( - viewModel = viewModel, - modifier = Modifier.fillMaxWidth(), - ) + Column(modifier = modifier.padding(vertical = 128.dp)) { + UserSwitcher(viewModel = viewModel, modifier = Modifier.fillMaxWidth()) Spacer(Modifier.weight(1f)) @@ -488,9 +441,7 @@ private fun BelowUserSwitcherLayout( horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.fillMaxWidth(), ) { - StatusMessage( - viewModel = viewModel.message, - ) + StatusMessage(viewModel = viewModel.message) OutputArea(viewModel = viewModel, modifier = Modifier.padding(top = 24.dp)) InputArea( @@ -500,10 +451,7 @@ private fun BelowUserSwitcherLayout( modifier = Modifier.padding(top = 128.dp), ) - ActionArea( - viewModel = viewModel, - modifier = Modifier.padding(top = 48.dp), - ) + ActionArea(viewModel = viewModel, modifier = Modifier.padding(top = 48.dp)) } } } @@ -533,19 +481,11 @@ private fun FoldAware( SceneTransitionLayout(state, modifier = modifier) { scene(SceneKeys.ContiguousSceneKey) { - FoldableScene( - aboveFold = aboveFold, - belowFold = belowFold, - isSplit = false, - ) + FoldableScene(aboveFold = aboveFold, belowFold = belowFold, isSplit = false) } scene(SceneKeys.SplitSceneKey) { - FoldableScene( - aboveFold = aboveFold, - belowFold = belowFold, - isSplit = true, - ) + FoldableScene(aboveFold = aboveFold, belowFold = belowFold, isSplit = true) } } } @@ -562,9 +502,7 @@ private fun SceneScope.FoldableScene( R.dimen.motion_layout_half_fold_bouncer_height_ratio ) - Column( - modifier = modifier.fillMaxHeight(), - ) { + Column(modifier = modifier.fillMaxHeight()) { // Content above the fold, when split on a foldable device in a "table top" posture: Box( modifier = @@ -575,7 +513,7 @@ private fun SceneScope.FoldableScene( } else { Modifier } - ), + ) ) { aboveFold() } @@ -590,7 +528,7 @@ private fun SceneScope.FoldableScene( } else { 1f } - ), + ) ) { belowFold() } @@ -598,10 +536,7 @@ private fun SceneScope.FoldableScene( } @Composable -private fun StatusMessage( - viewModel: BouncerMessageViewModel, - modifier: Modifier = Modifier, -) { +private fun StatusMessage(viewModel: BouncerMessageViewModel, modifier: Modifier = Modifier) { val message: MessageViewModel? by viewModel.message.collectAsStateWithLifecycle() DisposableEffect(Unit) { @@ -634,7 +569,7 @@ private fun StatusMessage( fontSize = 14.sp, lineHeight = 20.sp, overflow = TextOverflow.Ellipsis, - maxLines = 2 + maxLines = 2, ) } } @@ -647,22 +582,19 @@ private fun StatusMessage( * For example, this can be the PIN shapes or password text field. */ @Composable -private fun OutputArea( - viewModel: BouncerSceneContentViewModel, - modifier: Modifier = Modifier, -) { +private fun OutputArea(viewModel: BouncerSceneContentViewModel, modifier: Modifier = Modifier) { val authMethodViewModel: AuthMethodBouncerViewModel? by viewModel.authMethodViewModel.collectAsStateWithLifecycle() when (val nonNullViewModel = authMethodViewModel) { is PinBouncerViewModel -> PinInputDisplay( viewModel = nonNullViewModel, - modifier = modifier.sysuiResTag("bouncer_text_entry") + modifier = modifier.sysuiResTag("bouncer_text_entry"), ) is PasswordBouncerViewModel -> PasswordBouncer( viewModel = nonNullViewModel, - modifier = modifier.sysuiResTag("bouncer_text_entry") + modifier = modifier.sysuiResTag("bouncer_text_entry"), ) else -> Unit } @@ -703,10 +635,7 @@ private fun InputArea( } @Composable -private fun ActionArea( - viewModel: BouncerSceneContentViewModel, - modifier: Modifier = Modifier, -) { +private fun ActionArea(viewModel: BouncerSceneContentViewModel, modifier: Modifier = Modifier) { val actionButton: BouncerActionButtonModel? by viewModel.actionButton.collectAsStateWithLifecycle() val appearFadeInAnimatable = remember { Animatable(0f) } @@ -722,7 +651,7 @@ private fun ActionArea( durationMillis = 450, delayMillis = 133, easing = Easings.LegacyDecelerate, - ) + ), ) } LaunchedEffect(Unit) { @@ -733,39 +662,35 @@ private fun ActionArea( durationMillis = 450, delayMillis = 133, easing = Easings.StandardDecelerate, - ) + ), ) } Box( modifier = - modifier.graphicsLayer { - // Translate the button up from an initially pushed-down position: - translationY = (1 - appearMoveAnimatable.value) * appearAnimationInitialOffset - // Fade the button in: - alpha = appearFadeInAnimatable.value - }, + modifier + .graphicsLayer { + // Translate the button up from an initially pushed-down position: + translationY = + (1 - appearMoveAnimatable.value) * appearAnimationInitialOffset + // Fade the button in: + alpha = appearFadeInAnimatable.value + } + .height(56.dp) + .clip(ButtonDefaults.shape) + .background(color = MaterialTheme.colorScheme.tertiaryContainer) + .semantics { role = Role.Button } + .combinedClickable( + onClick = { actionButtonViewModel.onClick() }, + onLongClick = actionButtonViewModel.onLongClick?.let { { it.invoke() } }, + ) ) { - Button( - onClick = actionButtonViewModel.onClick, - modifier = - Modifier.height(56.dp).thenIf(actionButtonViewModel.onLongClick != null) { - Modifier.combinedClickable( - onClick = actionButtonViewModel.onClick, - onLongClick = actionButtonViewModel.onLongClick, - ) - }, - colors = - ButtonDefaults.buttonColors( - containerColor = MaterialTheme.colorScheme.tertiaryContainer, - contentColor = MaterialTheme.colorScheme.onTertiaryContainer, - ), - ) { - Text( - text = actionButtonViewModel.label, - style = MaterialTheme.typography.bodyMedium, - ) - } + Text( + text = actionButtonViewModel.label, + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onTertiaryContainer, + modifier = Modifier.align(Alignment.Center).padding(ButtonDefaults.ContentPadding), + ) } } } @@ -800,15 +725,10 @@ private fun Dialog( /** Renders the UI of the user switcher that's displayed on large screens next to the bouncer UI. */ @Composable -private fun UserSwitcher( - viewModel: BouncerSceneContentViewModel, - modifier: Modifier = Modifier, -) { +private fun UserSwitcher(viewModel: BouncerSceneContentViewModel, modifier: Modifier = Modifier) { if (!viewModel.isUserSwitcherVisible) { // Take up the same space as the user switcher normally would, but with nothing inside it. - Box( - modifier = modifier, - ) + Box(modifier = modifier) return } @@ -891,7 +811,7 @@ private fun UserSwitcherDropdownMenu( MaterialTheme( colorScheme = MaterialTheme.colorScheme.copy( - surface = MaterialTheme.colorScheme.surfaceContainerHighest, + surface = MaterialTheme.colorScheme.surfaceContainerHighest ), shapes = MaterialTheme.shapes.copy(extraSmall = RoundedCornerShape(28.dp)), ) { @@ -932,9 +852,7 @@ private fun UserSwitcherDropdownMenu( * Calculates an alpha for the user switcher and bouncer such that it's at `1` when the offset of * the two reaches a stopping point but `0` in the middle of the transition. */ -private fun animatedAlpha( - offset: Float, -): Float { +private fun animatedAlpha(offset: Float): Float { // Describes a curve that is made of two parabolic U-shaped curves mirrored horizontally around // the y-axis. The U on the left runs between x = -1 and x = 0 while the U on the right runs // between x = 0 and x = 1. diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractor.kt index 7337e5af51a1..da01c583db0a 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractor.kt @@ -123,8 +123,6 @@ constructor( onLongClick = { if (emergencyAffordanceManager.needsEmergencyAffordance()) { prepareToPerformAction() - - // TODO(b/369767936): Check that !longPressWasDragged before invoking. emergencyAffordanceManager.performEmergencyCall() } }, |