Loading packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt +68 −32 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -34,13 +42,40 @@ 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, sheetContent: @Composable () -> Unit, onDismiss: () -> Unit, isInitialRender: Boolean, onInitialRenderComplete: () -> Unit, isAutoSelectFlow: Boolean, ) { 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 { val scope = rememberCoroutineScope() val state = rememberModalBottomSheetState( initialValue = if (isAutoSelectFlow) ModalBottomSheetValue.Expanded Loading @@ -57,7 +92,7 @@ fun ModalBottomSheet( sheetBackgroundColor = LocalAndroidColorScheme.current.surfaceBright, modifier = Modifier.background(Color.Transparent), sheetState = state, sheetContent = sheetContent, sheetContent = { sheetContent() }, sheetShape = EntryShape.TopRoundedCorner, ) {} LaunchedEffect(state.currentValue, state.targetValue) { Loading @@ -72,3 +107,4 @@ fun ModalBottomSheet( } } } } packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt +6 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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(), ) } } Loading packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt +14 −46 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -277,31 +274,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. */ Loading @@ -327,18 +299,16 @@ 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 = { 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 Loading @@ -357,10 +327,8 @@ fun MoreOptionTopAppBar( ) } } }, 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 { Loading packages/CredentialManager/tests/robotests/Android.bp +2 −1 Original line number Diff line number Diff line Loading @@ -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", Loading @@ -45,6 +45,7 @@ android_robolectric_test { "inline-mockito-robolectric-prebuilt", "platform-parametric-runner-lib", "uiautomator-helpers", "flag-junit-base", ], libs: [ "android.test.runner", Loading packages/CredentialManager/tests/robotests/customization/assets/phone/dark_landscape_singleCredentialScreen_newM3BottomSheet.png 0 → 100644 +77.7 KiB Loading image diff... Loading
packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt +68 −32 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -34,13 +42,40 @@ 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, sheetContent: @Composable () -> Unit, onDismiss: () -> Unit, isInitialRender: Boolean, onInitialRenderComplete: () -> Unit, isAutoSelectFlow: Boolean, ) { 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 { val scope = rememberCoroutineScope() val state = rememberModalBottomSheetState( initialValue = if (isAutoSelectFlow) ModalBottomSheetValue.Expanded Loading @@ -57,7 +92,7 @@ fun ModalBottomSheet( sheetBackgroundColor = LocalAndroidColorScheme.current.surfaceBright, modifier = Modifier.background(Color.Transparent), sheetState = state, sheetContent = sheetContent, sheetContent = { sheetContent() }, sheetShape = EntryShape.TopRoundedCorner, ) {} LaunchedEffect(state.currentValue, state.targetValue) { Loading @@ -72,3 +107,4 @@ fun ModalBottomSheet( } } } }
packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt +6 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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(), ) } } Loading
packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt +14 −46 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -277,31 +274,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. */ Loading @@ -327,18 +299,16 @@ 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 = { 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 Loading @@ -357,10 +327,8 @@ fun MoreOptionTopAppBar( ) } } }, 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 { Loading
packages/CredentialManager/tests/robotests/Android.bp +2 −1 Original line number Diff line number Diff line Loading @@ -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", Loading @@ -45,6 +45,7 @@ android_robolectric_test { "inline-mockito-robolectric-prebuilt", "platform-parametric-runner-lib", "uiautomator-helpers", "flag-junit-base", ], libs: [ "android.test.runner", Loading
packages/CredentialManager/tests/robotests/customization/assets/phone/dark_landscape_singleCredentialScreen_newM3BottomSheet.png 0 → 100644 +77.7 KiB Loading image diff...