summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> 2024-10-17 22:58:33 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2024-10-17 22:58:33 +0000
commit64bc28bd4e7bef37eacdd90244d11439c7ca7fe8 (patch)
treece343577509f71a93f5b2cc473a432214fdaaffe
parentbc83c3d0d3c6932151c3a374833a2dcc912437da (diff)
parent3e388b266f326928631818d4beab486186f36150 (diff)
Merge "[flexiglass] Fixes long-press on emergency button." into main
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt226
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractor.kt2
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()
}
},