Loading packages/SystemUI/aconfig/desktop_users_and_accounts.aconfig +7 −0 Original line number Original line Diff line number Diff line Loading @@ -10,6 +10,13 @@ flag { bug: "416223998" bug: "416223998" } } flag { name: "disable_user_switcher_dropdown_on_bouncer" namespace: "desktop_users_and_accounts" description: "Show pill with current user's name instead of user switcher dropdown" bug: "425357051" } flag { flag { name: "sign_out_button_on_keyguard_status_bar" name: "sign_out_button_on_keyguard_status_bar" namespace: "desktop_users_and_accounts" namespace: "desktop_users_and_accounts" Loading packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt +80 −40 Original line number Original line Diff line number Diff line Loading @@ -48,6 +48,7 @@ import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.KeyboardArrowDown import androidx.compose.material.icons.filled.KeyboardArrowDown Loading Loading @@ -104,6 +105,7 @@ import com.android.compose.animation.scene.rememberMutableSceneTransitionLayoutS import com.android.compose.animation.scene.transitions import com.android.compose.animation.scene.transitions import com.android.compose.modifiers.thenIf import com.android.compose.modifiers.thenIf import com.android.compose.windowsizeclass.LocalWindowSizeClass import com.android.compose.windowsizeclass.LocalWindowSizeClass import com.android.systemui.Flags import com.android.systemui.bouncer.shared.model.BouncerActionButtonModel import com.android.systemui.bouncer.shared.model.BouncerActionButtonModel import com.android.systemui.bouncer.ui.BouncerDialogFactory import com.android.systemui.bouncer.ui.BouncerDialogFactory import com.android.systemui.bouncer.ui.viewmodel.AuthMethodBouncerViewModel import com.android.systemui.bouncer.ui.viewmodel.AuthMethodBouncerViewModel Loading Loading @@ -898,6 +900,7 @@ private fun Dialog( @Composable @Composable private fun UserSwitcher(viewModel: BouncerOverlayContentViewModel, modifier: Modifier = Modifier) { private fun UserSwitcher(viewModel: BouncerOverlayContentViewModel, modifier: Modifier = Modifier) { val isUserSwitcherVisible by viewModel.isUserSwitcherVisible.collectAsStateWithLifecycle() val isUserSwitcherVisible by viewModel.isUserSwitcherVisible.collectAsStateWithLifecycle() val dropdownItems by viewModel.userSwitcherDropdown.collectAsStateWithLifecycle(emptyList()) if (!isUserSwitcherVisible) { if (!isUserSwitcherVisible) { // Take up the same space as the user switcher normally would, but with nothing inside it. // Take up the same space as the user switcher normally would, but with nothing inside it. Box(modifier = modifier) Box(modifier = modifier) Loading @@ -905,10 +908,8 @@ private fun UserSwitcher(viewModel: BouncerOverlayContentViewModel, modifier: Mo } } val selectedUserImage by viewModel.selectedUserImage.collectAsStateWithLifecycle(null) val selectedUserImage by viewModel.selectedUserImage.collectAsStateWithLifecycle(null) val dropdownItems by viewModel.userSwitcherDropdown.collectAsStateWithLifecycle(emptyList()) val userSwitcherIconSize = dimensionResource(R.dimen.bouncer_user_switcher_icon_size) val userSwitcherIconSize = dimensionResource(R.dimen.bouncer_user_switcher_icon_size) val dropDownWidth = userSwitcherIconSize + UserSwitcherDropdownExtraWidth val maxUserSwitcherWidth = userSwitcherIconSize + UserSwitcherDropdownExtraWidth Column( Column( horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, verticalArrangement = Arrangement.Center, Loading @@ -921,19 +922,59 @@ private fun UserSwitcher(viewModel: BouncerOverlayContentViewModel, modifier: Mo modifier = Modifier.size(userSwitcherIconSize).sysuiResTag("user_icon"), modifier = Modifier.size(userSwitcherIconSize).sysuiResTag("user_icon"), ) ) } } if (Flags.disableUserSwitcherDropdownOnBouncer() && dropdownItems.size <= 1) { Spacer(modifier = Modifier.height(24.dp)) UserNamePill(viewModel = viewModel, maxWidth = maxUserSwitcherWidth) } else { Spacer(modifier = Modifier.height(40.dp)) UserSwitcherDropdown(viewModel = viewModel, width = maxUserSwitcherWidth) } } } /** * Displays the current user's name in a stylized pill shape. This is used when the user switcher * dropdown is disabled. */ @Composable private fun UserNamePill(viewModel: BouncerOverlayContentViewModel, maxWidth: Dp) { val selectedUserName by viewModel.selectedUserName.collectAsStateWithLifecycle() val context = LocalContext.current selectedUserName.loadText(context)?.let { userName -> Text( text = userName, style = MaterialTheme.typography.titleMedium, color = MaterialTheme.colorScheme.onSurface, maxLines = 1, overflow = TextOverflow.Ellipsis, modifier = Modifier.widthIn(max = maxWidth) .background( color = MaterialTheme.colorScheme.surfaceContainer, shape = RoundedCornerShape(percent = 50), ) .padding(horizontal = 24.dp, vertical = 16.dp), ) } } /** * Displays the current user's name and an arrow, which can be clicked to expand a dropdown menu for * switching users. */ @Composable private fun UserSwitcherDropdown(viewModel: BouncerOverlayContentViewModel, width: Dp) { val dropdownItems by viewModel.userSwitcherDropdown.collectAsStateWithLifecycle(emptyList()) val (isDropdownExpanded, setDropdownExpanded) = remember { mutableStateOf(false) } val (isDropdownExpanded, setDropdownExpanded) = remember { mutableStateOf(false) } dropdownItems.firstOrNull()?.let { firstDropdownItem -> dropdownItems.firstOrNull()?.let { firstDropdownItem -> Spacer(modifier = Modifier.height(40.dp)) Box { Box { PlatformButton( PlatformButton( modifier = modifier = Modifier Modifier // Remove the built-in padding applied inside PlatformButton: // Remove the built-in padding applied inside PlatformButton: .padding(vertical = 0.dp) .padding(vertical = 0.dp) .width(dropDownWidth) .width(width) .height(UserSwitcherDropdownHeight), .height(UserSwitcherDropdownHeight), colors = colors = ButtonDefaults.buttonColors( ButtonDefaults.buttonColors( Loading @@ -945,7 +986,7 @@ private fun UserSwitcher(viewModel: BouncerOverlayContentViewModel, modifier: Mo val context = LocalContext.current val context = LocalContext.current Text( Text( text = checkNotNull(firstDropdownItem.text.loadText(context)), text = checkNotNull(firstDropdownItem.text.loadText(context)), style = MaterialTheme.typography.labelMedium, style = MaterialTheme.typography.headlineSmall, maxLines = 1, maxLines = 1, overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis, ) ) Loading @@ -962,13 +1003,12 @@ private fun UserSwitcher(viewModel: BouncerOverlayContentViewModel, modifier: Mo UserSwitcherDropdownMenu( UserSwitcherDropdownMenu( isExpanded = isDropdownExpanded, isExpanded = isDropdownExpanded, items = dropdownItems, items = dropdownItems, dropDownWidth = dropDownWidth, dropDownWidth = width, onDismissed = { setDropdownExpanded(false) }, onDismissed = { setDropdownExpanded(false) }, ) ) } } } } } } } /** /** * Renders the dropdown menu that displays the actual users and/or user actions that can be * Renders the dropdown menu that displays the actual users and/or user actions that can be Loading packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerOverlayContentViewModel.kt +7 −0 Original line number Original line Diff line number Diff line Loading @@ -84,6 +84,9 @@ constructor( private val _selectedUserImage = MutableStateFlow<Bitmap?>(null) private val _selectedUserImage = MutableStateFlow<Bitmap?>(null) val selectedUserImage: StateFlow<Bitmap?> = _selectedUserImage.asStateFlow() val selectedUserImage: StateFlow<Bitmap?> = _selectedUserImage.asStateFlow() private val _selectedUserName = MutableStateFlow<Text?>(null) val selectedUserName: StateFlow<Text?> = _selectedUserName.asStateFlow() val message: BouncerMessageViewModel by lazy { bouncerMessageViewModelFactory.create() } val message: BouncerMessageViewModel by lazy { bouncerMessageViewModelFactory.create() } private val _userSwitcherDropdown = private val _userSwitcherDropdown = Loading Loading @@ -212,6 +215,10 @@ constructor( .collect { _selectedUserImage.value = it } .collect { _selectedUserImage.value = it } } } launch { userSwitcher.selectedUser.map { it.name }.collect { _selectedUserName.value = it } } launch { launch { combine(userSwitcher.users, userSwitcher.menu) { users, actions -> combine(userSwitcher.users, userSwitcher.menu) { users, actions -> users.map { user -> users.map { user -> Loading Loading
packages/SystemUI/aconfig/desktop_users_and_accounts.aconfig +7 −0 Original line number Original line Diff line number Diff line Loading @@ -10,6 +10,13 @@ flag { bug: "416223998" bug: "416223998" } } flag { name: "disable_user_switcher_dropdown_on_bouncer" namespace: "desktop_users_and_accounts" description: "Show pill with current user's name instead of user switcher dropdown" bug: "425357051" } flag { flag { name: "sign_out_button_on_keyguard_status_bar" name: "sign_out_button_on_keyguard_status_bar" namespace: "desktop_users_and_accounts" namespace: "desktop_users_and_accounts" Loading
packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt +80 −40 Original line number Original line Diff line number Diff line Loading @@ -48,6 +48,7 @@ import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.KeyboardArrowDown import androidx.compose.material.icons.filled.KeyboardArrowDown Loading Loading @@ -104,6 +105,7 @@ import com.android.compose.animation.scene.rememberMutableSceneTransitionLayoutS import com.android.compose.animation.scene.transitions import com.android.compose.animation.scene.transitions import com.android.compose.modifiers.thenIf import com.android.compose.modifiers.thenIf import com.android.compose.windowsizeclass.LocalWindowSizeClass import com.android.compose.windowsizeclass.LocalWindowSizeClass import com.android.systemui.Flags import com.android.systemui.bouncer.shared.model.BouncerActionButtonModel import com.android.systemui.bouncer.shared.model.BouncerActionButtonModel import com.android.systemui.bouncer.ui.BouncerDialogFactory import com.android.systemui.bouncer.ui.BouncerDialogFactory import com.android.systemui.bouncer.ui.viewmodel.AuthMethodBouncerViewModel import com.android.systemui.bouncer.ui.viewmodel.AuthMethodBouncerViewModel Loading Loading @@ -898,6 +900,7 @@ private fun Dialog( @Composable @Composable private fun UserSwitcher(viewModel: BouncerOverlayContentViewModel, modifier: Modifier = Modifier) { private fun UserSwitcher(viewModel: BouncerOverlayContentViewModel, modifier: Modifier = Modifier) { val isUserSwitcherVisible by viewModel.isUserSwitcherVisible.collectAsStateWithLifecycle() val isUserSwitcherVisible by viewModel.isUserSwitcherVisible.collectAsStateWithLifecycle() val dropdownItems by viewModel.userSwitcherDropdown.collectAsStateWithLifecycle(emptyList()) if (!isUserSwitcherVisible) { if (!isUserSwitcherVisible) { // Take up the same space as the user switcher normally would, but with nothing inside it. // Take up the same space as the user switcher normally would, but with nothing inside it. Box(modifier = modifier) Box(modifier = modifier) Loading @@ -905,10 +908,8 @@ private fun UserSwitcher(viewModel: BouncerOverlayContentViewModel, modifier: Mo } } val selectedUserImage by viewModel.selectedUserImage.collectAsStateWithLifecycle(null) val selectedUserImage by viewModel.selectedUserImage.collectAsStateWithLifecycle(null) val dropdownItems by viewModel.userSwitcherDropdown.collectAsStateWithLifecycle(emptyList()) val userSwitcherIconSize = dimensionResource(R.dimen.bouncer_user_switcher_icon_size) val userSwitcherIconSize = dimensionResource(R.dimen.bouncer_user_switcher_icon_size) val dropDownWidth = userSwitcherIconSize + UserSwitcherDropdownExtraWidth val maxUserSwitcherWidth = userSwitcherIconSize + UserSwitcherDropdownExtraWidth Column( Column( horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, verticalArrangement = Arrangement.Center, Loading @@ -921,19 +922,59 @@ private fun UserSwitcher(viewModel: BouncerOverlayContentViewModel, modifier: Mo modifier = Modifier.size(userSwitcherIconSize).sysuiResTag("user_icon"), modifier = Modifier.size(userSwitcherIconSize).sysuiResTag("user_icon"), ) ) } } if (Flags.disableUserSwitcherDropdownOnBouncer() && dropdownItems.size <= 1) { Spacer(modifier = Modifier.height(24.dp)) UserNamePill(viewModel = viewModel, maxWidth = maxUserSwitcherWidth) } else { Spacer(modifier = Modifier.height(40.dp)) UserSwitcherDropdown(viewModel = viewModel, width = maxUserSwitcherWidth) } } } /** * Displays the current user's name in a stylized pill shape. This is used when the user switcher * dropdown is disabled. */ @Composable private fun UserNamePill(viewModel: BouncerOverlayContentViewModel, maxWidth: Dp) { val selectedUserName by viewModel.selectedUserName.collectAsStateWithLifecycle() val context = LocalContext.current selectedUserName.loadText(context)?.let { userName -> Text( text = userName, style = MaterialTheme.typography.titleMedium, color = MaterialTheme.colorScheme.onSurface, maxLines = 1, overflow = TextOverflow.Ellipsis, modifier = Modifier.widthIn(max = maxWidth) .background( color = MaterialTheme.colorScheme.surfaceContainer, shape = RoundedCornerShape(percent = 50), ) .padding(horizontal = 24.dp, vertical = 16.dp), ) } } /** * Displays the current user's name and an arrow, which can be clicked to expand a dropdown menu for * switching users. */ @Composable private fun UserSwitcherDropdown(viewModel: BouncerOverlayContentViewModel, width: Dp) { val dropdownItems by viewModel.userSwitcherDropdown.collectAsStateWithLifecycle(emptyList()) val (isDropdownExpanded, setDropdownExpanded) = remember { mutableStateOf(false) } val (isDropdownExpanded, setDropdownExpanded) = remember { mutableStateOf(false) } dropdownItems.firstOrNull()?.let { firstDropdownItem -> dropdownItems.firstOrNull()?.let { firstDropdownItem -> Spacer(modifier = Modifier.height(40.dp)) Box { Box { PlatformButton( PlatformButton( modifier = modifier = Modifier Modifier // Remove the built-in padding applied inside PlatformButton: // Remove the built-in padding applied inside PlatformButton: .padding(vertical = 0.dp) .padding(vertical = 0.dp) .width(dropDownWidth) .width(width) .height(UserSwitcherDropdownHeight), .height(UserSwitcherDropdownHeight), colors = colors = ButtonDefaults.buttonColors( ButtonDefaults.buttonColors( Loading @@ -945,7 +986,7 @@ private fun UserSwitcher(viewModel: BouncerOverlayContentViewModel, modifier: Mo val context = LocalContext.current val context = LocalContext.current Text( Text( text = checkNotNull(firstDropdownItem.text.loadText(context)), text = checkNotNull(firstDropdownItem.text.loadText(context)), style = MaterialTheme.typography.labelMedium, style = MaterialTheme.typography.headlineSmall, maxLines = 1, maxLines = 1, overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis, ) ) Loading @@ -962,13 +1003,12 @@ private fun UserSwitcher(viewModel: BouncerOverlayContentViewModel, modifier: Mo UserSwitcherDropdownMenu( UserSwitcherDropdownMenu( isExpanded = isDropdownExpanded, isExpanded = isDropdownExpanded, items = dropdownItems, items = dropdownItems, dropDownWidth = dropDownWidth, dropDownWidth = width, onDismissed = { setDropdownExpanded(false) }, onDismissed = { setDropdownExpanded(false) }, ) ) } } } } } } } /** /** * Renders the dropdown menu that displays the actual users and/or user actions that can be * Renders the dropdown menu that displays the actual users and/or user actions that can be Loading
packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerOverlayContentViewModel.kt +7 −0 Original line number Original line Diff line number Diff line Loading @@ -84,6 +84,9 @@ constructor( private val _selectedUserImage = MutableStateFlow<Bitmap?>(null) private val _selectedUserImage = MutableStateFlow<Bitmap?>(null) val selectedUserImage: StateFlow<Bitmap?> = _selectedUserImage.asStateFlow() val selectedUserImage: StateFlow<Bitmap?> = _selectedUserImage.asStateFlow() private val _selectedUserName = MutableStateFlow<Text?>(null) val selectedUserName: StateFlow<Text?> = _selectedUserName.asStateFlow() val message: BouncerMessageViewModel by lazy { bouncerMessageViewModelFactory.create() } val message: BouncerMessageViewModel by lazy { bouncerMessageViewModelFactory.create() } private val _userSwitcherDropdown = private val _userSwitcherDropdown = Loading Loading @@ -212,6 +215,10 @@ constructor( .collect { _selectedUserImage.value = it } .collect { _selectedUserImage.value = it } } } launch { userSwitcher.selectedUser.map { it.name }.collect { _selectedUserName.value = it } } launch { launch { combine(userSwitcher.users, userSwitcher.menu) { users, actions -> combine(userSwitcher.users, userSwitcher.menu) { users, actions -> users.map { user -> users.map { user -> Loading