diff options
author | 2024-02-21 04:26:51 +0000 | |
---|---|---|
committer | 2024-02-27 05:56:37 +0000 | |
commit | 63413d163ee44e4222c677190f7ca3cccda35378 (patch) | |
tree | 408271f192d6b035127e2d503b0e85cca5169f77 | |
parent | 9b2ce0e931c896649fab3cef5dbf6d2a08ce0bfb (diff) |
Migrate to use the latest ModalBottomSheet
Bug: 319453757
Test: local e2e & screenshot tests
Change-Id: Id80a5365b6ebf8f864bcc58e3ece03c04f916b64
14 files changed, 131 insertions, 81 deletions
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt index d319e4cc9ef9..a7b5c36215cf 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt @@ -16,8 +16,15 @@ package com.android.credentialmanager.common.ui +import android.credentials.flags.Flags +import androidx.compose.animation.animateContentSize import androidx.compose.foundation.background -import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.rememberCoroutineScope @@ -25,6 +32,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import com.android.compose.rememberSystemUiController import com.android.compose.theme.LocalAndroidColorScheme +import androidx.compose.ui.unit.dp import com.android.credentialmanager.common.material.ModalBottomSheetLayout import com.android.credentialmanager.common.material.ModalBottomSheetValue import com.android.credentialmanager.common.material.rememberModalBottomSheetState @@ -34,40 +42,68 @@ import kotlinx.coroutines.launch /** Draws a modal bottom sheet with the same styles and effects shared by various flows. */ @Composable +@OptIn(ExperimentalMaterial3Api::class) fun ModalBottomSheet( - sheetContent: @Composable ColumnScope.() -> Unit, - onDismiss: () -> Unit, - isInitialRender: Boolean, - onInitialRenderComplete: () -> Unit, - isAutoSelectFlow: Boolean, + sheetContent: @Composable () -> Unit, + onDismiss: () -> Unit, + isInitialRender: Boolean, + onInitialRenderComplete: () -> Unit, + isAutoSelectFlow: Boolean, ) { - val scope = rememberCoroutineScope() - val state = rememberModalBottomSheetState( - initialValue = if (isAutoSelectFlow) ModalBottomSheetValue.Expanded - else ModalBottomSheetValue.Hidden, - skipHalfExpanded = true - ) - val sysUiController = rememberSystemUiController() - if (state.targetValue == ModalBottomSheetValue.Hidden || isAutoSelectFlow) { - setTransparentSystemBarsColor(sysUiController) + if (Flags.selectorUiImprovementsEnabled()) { + val state = androidx.compose.material3.rememberModalBottomSheetState( + skipPartiallyExpanded = true + ) + androidx.compose.material3.ModalBottomSheet( + onDismissRequest = onDismiss, + containerColor = LocalAndroidColorScheme.current.surfaceBright, + sheetState = state, + content = { + Box( + modifier = Modifier + .animateContentSize() + .wrapContentHeight() + .fillMaxWidth() + ) { + sheetContent() + } + }, + scrimColor = MaterialTheme.colorScheme.scrim.copy(alpha = .32f), + shape = EntryShape.TopRoundedCorner, + dragHandle = null, + // Never take over the full screen. We always want to leave some top scrim space + // for exiting and viewing the underlying app to help a user gain context. + modifier = Modifier.padding(top = 56.dp), + ) } else { - setBottomSheetSystemBarsColor(sysUiController) - } - ModalBottomSheetLayout( - sheetBackgroundColor = LocalAndroidColorScheme.current.surfaceBright, - modifier = Modifier.background(Color.Transparent), - sheetState = state, - sheetContent = sheetContent, - sheetShape = EntryShape.TopRoundedCorner, - ) {} - LaunchedEffect(state.currentValue, state.targetValue) { - if (state.currentValue == ModalBottomSheetValue.Hidden) { - if (isInitialRender) { - onInitialRenderComplete() - scope.launch { state.show() } - } else if (state.targetValue == ModalBottomSheetValue.Hidden) { - // Only dismiss ui when the motion is downwards - onDismiss() + val scope = rememberCoroutineScope() + val state = rememberModalBottomSheetState( + initialValue = if (isAutoSelectFlow) ModalBottomSheetValue.Expanded + else ModalBottomSheetValue.Hidden, + skipHalfExpanded = true + ) + val sysUiController = rememberSystemUiController() + if (state.targetValue == ModalBottomSheetValue.Hidden || isAutoSelectFlow) { + setTransparentSystemBarsColor(sysUiController) + } else { + setBottomSheetSystemBarsColor(sysUiController) + } + ModalBottomSheetLayout( + sheetBackgroundColor = LocalAndroidColorScheme.current.surfaceBright, + modifier = Modifier.background(Color.Transparent), + sheetState = state, + sheetContent = { sheetContent() }, + sheetShape = EntryShape.TopRoundedCorner, + ) {} + LaunchedEffect(state.currentValue, state.targetValue) { + if (state.currentValue == ModalBottomSheetValue.Hidden) { + if (isInitialRender) { + onInitialRenderComplete() + scope.launch { state.show() } + } else if (state.targetValue == ModalBottomSheetValue.Hidden) { + // Only dismiss ui when the motion is downwards + onDismiss() + } } } } diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt index bdfe39920d44..c68ae8b168fb 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt @@ -18,7 +18,10 @@ package com.android.credentialmanager.common.ui import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.asPaddingValues +import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.lazy.LazyColumn @@ -66,6 +69,9 @@ fun SheetContainerCard( horizontalAlignment = Alignment.CenterHorizontally, content = content, verticalArrangement = contentVerticalArrangement, + // The bottom sheet overlaps with the navigation bars but make sure the actual content + // in the bottom sheet does not. + contentPadding = WindowInsets.navigationBars.asPaddingValues(), ) } } diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt index a6253b8d4e07..8ff17e0d333a 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt @@ -29,13 +29,10 @@ import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material.icons.outlined.Lock -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.SuggestionChip import androidx.compose.material3.SuggestionChipDefaults -import androidx.compose.material3.TopAppBar -import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -278,31 +275,6 @@ fun ActionEntry( } /** - * A single row of leading icon and text describing a benefit of passkeys, used by the - * [com.android.credentialmanager.createflow.PasskeyIntroCard]. - */ -@Composable -fun PasskeyBenefitRow( - leadingIconPainter: Painter, - text: String, -) { - Row( - horizontalArrangement = Arrangement.spacedBy(16.dp), - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.fillMaxWidth() - ) { - Icon( - modifier = Modifier.size(24.dp), - painter = leadingIconPainter, - tint = LocalAndroidColorScheme.current.onSurfaceVariant, - // Decorative purpose only. - contentDescription = null, - ) - BodyMediumText(text = text) - } -} - -/** * A single row of one or two CTA buttons for continuing or cancelling the current step. */ @Composable @@ -327,40 +299,36 @@ fun CtaButtonRow( } } -@OptIn(ExperimentalMaterial3Api::class) @Composable fun MoreOptionTopAppBar( text: String, onNavigationIconClicked: () -> Unit, bottomPadding: Dp, ) { - TopAppBar( - title = { - LargeTitleText(text = text, modifier = Modifier.padding(horizontal = 4.dp)) - }, - navigationIcon = { - IconButton( + Row( + modifier = Modifier.padding(top = 12.dp, bottom = bottomPadding), + verticalAlignment = Alignment.CenterVertically, + ) { + IconButton( modifier = Modifier.padding(top = 8.dp, bottom = 8.dp, start = 4.dp).size(48.dp), onClick = onNavigationIconClicked - ) { - Box( + ) { + Box( modifier = Modifier.size(48.dp), contentAlignment = Alignment.Center, - ) { - Icon( + ) { + Icon( imageVector = Icons.Filled.ArrowBack, contentDescription = stringResource( - R.string.accessibility_back_arrow_button + R.string.accessibility_back_arrow_button ), modifier = Modifier.size(24.dp).autoMirrored(), tint = LocalAndroidColorScheme.current.onSurfaceVariant, - ) - } + ) } - }, - colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent), - modifier = Modifier.padding(top = 12.dp, bottom = bottomPadding) - ) + } + LargeTitleText(text = text, modifier = Modifier.padding(horizontal = 4.dp)) + } } private fun Modifier.autoMirrored() = composed { diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt index 4ed84b908865..72775500e7c5 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt @@ -653,4 +653,4 @@ fun EmptyAuthEntrySnackBarScreen( contentText = stringResource(R.string.no_sign_in_info_in, lastLocked.providerDisplayName), ) onLog(GetCredentialEvent.CREDMAN_GET_CRED_SCREEN_EMPTY_AUTH_SNACKBAR_SCREEN) -}
\ No newline at end of file +} diff --git a/packages/CredentialManager/tests/robotests/Android.bp b/packages/CredentialManager/tests/robotests/Android.bp index baebfeb399f2..75a0dcce0b9e 100644 --- a/packages/CredentialManager/tests/robotests/Android.bp +++ b/packages/CredentialManager/tests/robotests/Android.bp @@ -37,7 +37,7 @@ android_robolectric_test { ":CredentialManagerScreenshotTestFiles", ], - // Do not add any libraries here, instead add them to the ScreenshotTestStub + // Do not add any libraries here, instead add them to the ScreenshotTestRobo static_libs: [ "androidx.compose.runtime_runtime", "androidx.test.uiautomator_uiautomator", @@ -45,6 +45,7 @@ android_robolectric_test { "inline-mockito-robolectric-prebuilt", "platform-parametric-runner-lib", "uiautomator-helpers", + "flag-junit-base", ], libs: [ "android.test.runner", diff --git a/packages/CredentialManager/tests/robotests/customization/assets/phone/dark_landscape_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/phone/dark_landscape_singleCredentialScreen_newM3BottomSheet.png Binary files differnew file mode 100644 index 000000000000..81860e538275 --- /dev/null +++ b/packages/CredentialManager/tests/robotests/customization/assets/phone/dark_landscape_singleCredentialScreen_newM3BottomSheet.png diff --git a/packages/CredentialManager/tests/robotests/customization/assets/phone/dark_portrait_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/phone/dark_portrait_singleCredentialScreen_newM3BottomSheet.png Binary files differnew file mode 100644 index 000000000000..8c1fff7df8ab --- /dev/null +++ b/packages/CredentialManager/tests/robotests/customization/assets/phone/dark_portrait_singleCredentialScreen_newM3BottomSheet.png diff --git a/packages/CredentialManager/tests/robotests/customization/assets/phone/light_landscape_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/phone/light_landscape_singleCredentialScreen_newM3BottomSheet.png Binary files differnew file mode 100644 index 000000000000..4eb025fcd190 --- /dev/null +++ b/packages/CredentialManager/tests/robotests/customization/assets/phone/light_landscape_singleCredentialScreen_newM3BottomSheet.png diff --git a/packages/CredentialManager/tests/robotests/customization/assets/phone/light_portrait_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/phone/light_portrait_singleCredentialScreen_newM3BottomSheet.png Binary files differnew file mode 100644 index 000000000000..c709f934f78d --- /dev/null +++ b/packages/CredentialManager/tests/robotests/customization/assets/phone/light_portrait_singleCredentialScreen_newM3BottomSheet.png diff --git a/packages/CredentialManager/tests/robotests/customization/assets/tablet/dark_landscape_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/tablet/dark_landscape_singleCredentialScreen_newM3BottomSheet.png Binary files differnew file mode 100644 index 000000000000..278c13f6c7da --- /dev/null +++ b/packages/CredentialManager/tests/robotests/customization/assets/tablet/dark_landscape_singleCredentialScreen_newM3BottomSheet.png diff --git a/packages/CredentialManager/tests/robotests/customization/assets/tablet/dark_portrait_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/tablet/dark_portrait_singleCredentialScreen_newM3BottomSheet.png Binary files differnew file mode 100644 index 000000000000..cb85df350ccf --- /dev/null +++ b/packages/CredentialManager/tests/robotests/customization/assets/tablet/dark_portrait_singleCredentialScreen_newM3BottomSheet.png diff --git a/packages/CredentialManager/tests/robotests/customization/assets/tablet/light_landscape_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/tablet/light_landscape_singleCredentialScreen_newM3BottomSheet.png Binary files differnew file mode 100644 index 000000000000..2eca70741a3c --- /dev/null +++ b/packages/CredentialManager/tests/robotests/customization/assets/tablet/light_landscape_singleCredentialScreen_newM3BottomSheet.png diff --git a/packages/CredentialManager/tests/robotests/customization/assets/tablet/light_portrait_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/tablet/light_portrait_singleCredentialScreen_newM3BottomSheet.png Binary files differnew file mode 100644 index 000000000000..7ee91b3705df --- /dev/null +++ b/packages/CredentialManager/tests/robotests/customization/assets/tablet/light_portrait_singleCredentialScreen_newM3BottomSheet.png diff --git a/packages/CredentialManager/tests/robotests/screenshot/src/com/android/credentialmanager/GetCredScreenshotTest.kt b/packages/CredentialManager/tests/robotests/screenshot/src/com/android/credentialmanager/GetCredScreenshotTest.kt index a0e1fed0ac96..e609d0c5c008 100644 --- a/packages/CredentialManager/tests/robotests/screenshot/src/com/android/credentialmanager/GetCredScreenshotTest.kt +++ b/packages/CredentialManager/tests/robotests/screenshot/src/com/android/credentialmanager/GetCredScreenshotTest.kt @@ -16,7 +16,10 @@ package com.android.credentialmanager +import android.credentials.flags.Flags import android.content.Context +import android.platform.test.flag.junit.SetFlagsRule +import androidx.compose.ui.test.isPopup import com.android.credentialmanager.getflow.RequestDisplayInfo import com.android.credentialmanager.model.CredentialType import com.android.credentialmanager.model.get.ProviderInfo @@ -59,8 +62,11 @@ class GetCredScreenshotTest(emulationSpec: DeviceEmulationSpec) { CredentialManagerGoldenImagePathManager(getEmulatedDevicePathConfig(emulationSpec)) ) + @get:Rule val setFlagsRule: SetFlagsRule = SetFlagsRule() + @Test - fun singleCredentialScreen() { + fun singleCredentialScreen_M3BottomSheetDisabled() { + setFlagsRule.disableFlags(Flags.FLAG_SELECTOR_UI_IMPROVEMENTS_ENABLED) val providerInfoList = buildProviderInfoList() val providerDisplayInfo = toProviderDisplayInfo(providerInfoList) val activeEntry = toActiveEntry(providerDisplayInfo) @@ -86,6 +92,39 @@ class GetCredScreenshotTest(emulationSpec: DeviceEmulationSpec) { } } + @Test + fun singleCredentialScreen_M3BottomSheetEnabled() { + setFlagsRule.enableFlags(Flags.FLAG_SELECTOR_UI_IMPROVEMENTS_ENABLED) + val providerInfoList = buildProviderInfoList() + val providerDisplayInfo = toProviderDisplayInfo(providerInfoList) + val activeEntry = toActiveEntry(providerDisplayInfo) + screenshotRule.screenshotTest( + "singleCredentialScreen_newM3BottomSheet", + // M3's ModalBottomSheet lives in a new window, meaning we have two windows with + // a root. Hence use a different matcher `isPopup`. + viewFinder = { screenshotRule.composeRule.onNode(isPopup()) }, + ) { + ModalBottomSheet( + sheetContent = { + PrimarySelectionCard( + requestDisplayInfo = REQUEST_DISPLAY_INFO, + providerDisplayInfo = providerDisplayInfo, + providerInfoList = providerInfoList, + activeEntry = activeEntry, + onEntrySelected = {}, + onConfirm = {}, + onMoreOptionSelected = {}, + onLog = {}, + ) + }, + isInitialRender = true, + onDismiss = {}, + onInitialRenderComplete = {}, + isAutoSelectFlow = false, + ) + } + } + private fun buildProviderInfoList(): List<ProviderInfo> { val context = ApplicationProvider.getApplicationContext<Context>() val provider1 = ProviderInfo( |