Loading packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt +72 −154 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading Loading @@ -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 Loading @@ -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) } } Loading @@ -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, Loading @@ -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, Loading @@ -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)) } }, ) Loading @@ -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( Loading @@ -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( Loading @@ -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( Loading Loading @@ -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 -> { Loading @@ -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"), ) } } Loading Loading @@ -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 Loading Loading @@ -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"), ) } }, Loading @@ -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, Loading @@ -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)) Loading @@ -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( Loading @@ -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)) } } } Loading Loading @@ -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) } } } Loading @@ -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 = Loading @@ -575,7 +513,7 @@ private fun SceneScope.FoldableScene( } else { Modifier } ), ) ) { aboveFold() } Loading @@ -590,7 +528,7 @@ private fun SceneScope.FoldableScene( } else { 1f } ), ) ) { belowFold() } Loading @@ -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) { Loading Loading @@ -634,7 +569,7 @@ private fun StatusMessage( fontSize = 14.sp, lineHeight = 20.sp, overflow = TextOverflow.Ellipsis, maxLines = 2 maxLines = 2, ) } } Loading @@ -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 } Loading Loading @@ -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) } Loading @@ -722,7 +651,7 @@ private fun ActionArea( durationMillis = 450, delayMillis = 133, easing = Easings.LegacyDecelerate, ) ), ) } LaunchedEffect(Unit) { Loading @@ -733,42 +662,38 @@ private fun ActionArea( durationMillis = 450, delayMillis = 133, easing = Easings.StandardDecelerate, ) ), ) } Box( modifier = modifier.graphicsLayer { modifier .graphicsLayer { // Translate the button up from an initially pushed-down position: translationY = (1 - appearMoveAnimatable.value) * appearAnimationInitialOffset translationY = (1 - appearMoveAnimatable.value) * appearAnimationInitialOffset // Fade the button in: alpha = appearFadeInAnimatable.value }, ) { Button( onClick = actionButtonViewModel.onClick, modifier = Modifier.height(56.dp).thenIf(actionButtonViewModel.onLongClick != null) { Modifier.combinedClickable( onClick = actionButtonViewModel.onClick, onLongClick = actionButtonViewModel.onLongClick, } .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() } }, ) }, colors = ButtonDefaults.buttonColors( containerColor = MaterialTheme.colorScheme.tertiaryContainer, contentColor = MaterialTheme.colorScheme.onTertiaryContainer, ), ) { Text( text = actionButtonViewModel.label, style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onTertiaryContainer, modifier = Modifier.align(Alignment.Center).padding(ButtonDefaults.ContentPadding), ) } } } } @Composable private fun Dialog( Loading Loading @@ -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 } Loading Loading @@ -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)), ) { Loading Loading @@ -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. Loading packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractor.kt +0 −2 Original line number Diff line number Diff line Loading @@ -123,8 +123,6 @@ constructor( onLongClick = { if (emergencyAffordanceManager.needsEmergencyAffordance()) { prepareToPerformAction() // TODO(b/369767936): Check that !longPressWasDragged before invoking. emergencyAffordanceManager.performEmergencyCall() } }, Loading Loading
packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt +72 −154 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading Loading @@ -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 Loading @@ -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) } } Loading @@ -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, Loading @@ -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, Loading @@ -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)) } }, ) Loading @@ -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( Loading @@ -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( Loading @@ -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( Loading Loading @@ -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 -> { Loading @@ -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"), ) } } Loading Loading @@ -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 Loading Loading @@ -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"), ) } }, Loading @@ -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, Loading @@ -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)) Loading @@ -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( Loading @@ -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)) } } } Loading Loading @@ -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) } } } Loading @@ -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 = Loading @@ -575,7 +513,7 @@ private fun SceneScope.FoldableScene( } else { Modifier } ), ) ) { aboveFold() } Loading @@ -590,7 +528,7 @@ private fun SceneScope.FoldableScene( } else { 1f } ), ) ) { belowFold() } Loading @@ -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) { Loading Loading @@ -634,7 +569,7 @@ private fun StatusMessage( fontSize = 14.sp, lineHeight = 20.sp, overflow = TextOverflow.Ellipsis, maxLines = 2 maxLines = 2, ) } } Loading @@ -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 } Loading Loading @@ -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) } Loading @@ -722,7 +651,7 @@ private fun ActionArea( durationMillis = 450, delayMillis = 133, easing = Easings.LegacyDecelerate, ) ), ) } LaunchedEffect(Unit) { Loading @@ -733,42 +662,38 @@ private fun ActionArea( durationMillis = 450, delayMillis = 133, easing = Easings.StandardDecelerate, ) ), ) } Box( modifier = modifier.graphicsLayer { modifier .graphicsLayer { // Translate the button up from an initially pushed-down position: translationY = (1 - appearMoveAnimatable.value) * appearAnimationInitialOffset translationY = (1 - appearMoveAnimatable.value) * appearAnimationInitialOffset // Fade the button in: alpha = appearFadeInAnimatable.value }, ) { Button( onClick = actionButtonViewModel.onClick, modifier = Modifier.height(56.dp).thenIf(actionButtonViewModel.onLongClick != null) { Modifier.combinedClickable( onClick = actionButtonViewModel.onClick, onLongClick = actionButtonViewModel.onLongClick, } .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() } }, ) }, colors = ButtonDefaults.buttonColors( containerColor = MaterialTheme.colorScheme.tertiaryContainer, contentColor = MaterialTheme.colorScheme.onTertiaryContainer, ), ) { Text( text = actionButtonViewModel.label, style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onTertiaryContainer, modifier = Modifier.align(Alignment.Center).padding(ButtonDefaults.ContentPadding), ) } } } } @Composable private fun Dialog( Loading Loading @@ -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 } Loading Loading @@ -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)), ) { Loading Loading @@ -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. Loading
packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractor.kt +0 −2 Original line number Diff line number Diff line Loading @@ -123,8 +123,6 @@ constructor( onLongClick = { if (emergencyAffordanceManager.needsEmergencyAffordance()) { prepareToPerformAction() // TODO(b/369767936): Check that !longPressWasDragged before invoking. emergencyAffordanceManager.performEmergencyCall() } }, Loading