diff options
Diffstat (limited to 'packages/SystemUI/src')
3 files changed, 121 insertions, 130 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt index 4bf552e0f1e3..93cd1cf487b0 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt @@ -36,6 +36,7 @@ import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.FlowRowScope import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -71,8 +72,6 @@ import androidx.compose.material3.SearchBarDefaults import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults -import androidx.compose.material3.windowsizeclass.WindowHeightSizeClass -import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -116,7 +115,6 @@ import androidx.compose.ui.util.fastForEach import androidx.compose.ui.util.fastForEachIndexed import androidx.compose.ui.zIndex import com.android.compose.ui.graphics.painter.rememberDrawablePainter -import com.android.compose.windowsizeclass.LocalWindowSizeClass import com.android.systemui.keyboard.shortcut.shared.model.Shortcut import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType @@ -188,10 +186,7 @@ private fun ActiveShortcutHelper( } } -@Composable -private fun shouldUseSinglePane() = - LocalWindowSizeClass.current.widthSizeClass == WindowWidthSizeClass.Compact || - LocalWindowSizeClass.current.heightSizeClass == WindowHeightSizeClass.Compact +@Composable private fun shouldUseSinglePane() = hasCompactWindowSize() @Composable private fun ShortcutHelperSinglePane( @@ -425,7 +420,7 @@ private fun ShortcutHelperTwoPane( onKeyboardSettingsClicked: () -> Unit, ) { val selectedCategory = categories.fastFirstOrNull { it.type == selectedCategoryType } - Column(modifier = modifier.fillMaxSize().padding(start = 24.dp, end = 24.dp, top = 26.dp)) { + Column(modifier = modifier.fillMaxSize().padding(horizontal = 24.dp)) { TitleBar() Spacer(modifier = Modifier.height(12.dp)) Row(Modifier.fillMaxWidth()) { @@ -801,6 +796,8 @@ private fun TitleBar() { style = MaterialTheme.typography.headlineSmall, ) }, + windowInsets = WindowInsets(top = 0.dp, bottom = 0.dp, left = 0.dp, right = 0.dp), + expandedHeight = 64.dp, ) } @@ -835,6 +832,7 @@ private fun ShortcutsSearchBar(onQueryChange: (String) -> Unit) { onSearch = {}, leadingIcon = { Icon(Icons.Default.Search, contentDescription = null) }, placeholder = { Text(text = stringResource(R.string.shortcut_helper_search_placeholder)) }, + windowInsets = WindowInsets(top = 0.dp, bottom = 0.dp, left = 0.dp, right = 0.dp), content = {}, ) } @@ -847,9 +845,7 @@ private fun KeyboardSettings(horizontalPadding: Dp, verticalPadding: Dp, onClick shape = RoundedCornerShape(24.dp), color = Color.Transparent, modifier = - Modifier.semantics { role = Role.Button } - .fillMaxWidth() - .padding(horizontal = 12.dp), + Modifier.semantics { role = Role.Button }.fillMaxWidth().padding(horizontal = 12.dp), interactionSource = interactionSource, interactionsConfig = InteractionsConfig( diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelperUtils.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelperUtils.kt new file mode 100644 index 000000000000..1f0d696eebd6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelperUtils.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyboard.shortcut.ui.composable + +import androidx.compose.material3.windowsizeclass.WindowHeightSizeClass +import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass +import androidx.compose.runtime.Composable +import com.android.compose.windowsizeclass.LocalWindowSizeClass + +/** + * returns true if either size of the window is compact. This represents majority of phone windows + * portrait + */ +@Composable +fun hasCompactWindowSize() = + LocalWindowSizeClass.current.widthSizeClass == WindowWidthSizeClass.Compact || + LocalWindowSizeClass.current.heightSizeClass == WindowHeightSizeClass.Compact diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/view/ShortcutHelperActivity.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/view/ShortcutHelperActivity.kt index 799999aff29b..b9a16c402e59 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/view/ShortcutHelperActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/view/ShortcutHelperActivity.kt @@ -18,31 +18,43 @@ package com.android.systemui.keyboard.shortcut.ui.view import android.content.ActivityNotFoundException import android.content.Intent -import android.graphics.Insets +import android.content.res.Configuration import android.os.Bundle import android.provider.Settings -import android.view.View -import android.view.WindowInsets -import androidx.activity.BackEventCompat import androidx.activity.ComponentActivity -import androidx.activity.OnBackPressedCallback +import androidx.activity.compose.setContent +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.Surface +import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.getValue -import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.Modifier +import androidx.compose.ui.input.key.Key +import androidx.compose.ui.input.key.key +import androidx.compose.ui.input.key.onKeyEvent +import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext -import androidx.core.view.updatePadding +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.flowWithLifecycle import androidx.lifecycle.lifecycleScope import com.android.compose.theme.PlatformTheme import com.android.systemui.keyboard.shortcut.ui.composable.ShortcutHelper +import com.android.systemui.keyboard.shortcut.ui.composable.hasCompactWindowSize import com.android.systemui.keyboard.shortcut.ui.viewmodel.ShortcutHelperViewModel import com.android.systemui.res.R import com.android.systemui.settings.UserTracker -import com.android.systemui.util.dpToPx -import com.google.android.material.bottomsheet.BottomSheetBehavior -import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback -import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_HIDDEN import javax.inject.Inject import kotlinx.coroutines.launch @@ -55,52 +67,58 @@ class ShortcutHelperActivity constructor(private val userTracker: UserTracker, private val viewModel: ShortcutHelperViewModel) : ComponentActivity() { - private val bottomSheetContainer - get() = requireViewById<View>(R.id.shortcut_helper_sheet_container) - - private val bottomSheet - get() = requireViewById<View>(R.id.shortcut_helper_sheet) - - private val bottomSheetBehavior - get() = BottomSheetBehavior.from(bottomSheet) - override fun onCreate(savedInstanceState: Bundle?) { setupEdgeToEdge() super.onCreate(savedInstanceState) - setContentView(R.layout.activity_keyboard_shortcut_helper) - setUpWidth() - expandBottomSheet() - setUpInsets() - setUpPredictiveBack() - setUpSheetDismissListener() - setUpDismissOnTouchOutside() - setUpComposeView() + setContent { Content() } observeFinishRequired() viewModel.onViewOpened() } - private fun setUpWidth() { - // we override this because when maxWidth isn't specified, material imposes a max width - // constraint on bottom sheets on larger screens which is smaller than our desired width. - bottomSheetBehavior.maxWidth = - resources.getDimension(R.dimen.shortcut_helper_width).dpToPx(resources).toInt() + @Composable + private fun Content() { + CompositionLocalProvider(LocalContext provides userTracker.userContext) { + PlatformTheme { BottomSheet { finish() } } + } } - private fun setUpComposeView() { - requireViewById<ComposeView>(R.id.shortcut_helper_compose_container).apply { - setContent { - CompositionLocalProvider(LocalContext provides userTracker.userContext) { - PlatformTheme { - val shortcutsUiState by - viewModel.shortcutsUiState.collectAsStateWithLifecycle() - ShortcutHelper( - shortcutsUiState = shortcutsUiState, - onKeyboardSettingsClicked = ::onKeyboardSettingsClicked, - onSearchQueryChanged = { viewModel.onSearchQueryChanged(it) }, - ) - } - } - } + @OptIn(ExperimentalMaterial3Api::class) + @Composable + private fun BottomSheet(onDismiss: () -> Unit) { + ModalBottomSheet( + onDismissRequest = { onDismiss() }, + modifier = + Modifier.width(getWidth()).padding(top = getTopPadding()).onKeyEvent { + if (it.key == Key.Escape) { + onDismiss() + true + } else false + }, + sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true), + dragHandle = { DragHandle() }, + ) { + val shortcutsUiState by viewModel.shortcutsUiState.collectAsStateWithLifecycle() + ShortcutHelper( + shortcutsUiState = shortcutsUiState, + onKeyboardSettingsClicked = ::onKeyboardSettingsClicked, + onSearchQueryChanged = { viewModel.onSearchQueryChanged(it) }, + ) + } + } + + @Composable + fun DragHandle() { + val dragHandleContentDescription = + stringResource(id = R.string.shortcut_helper_content_description_drag_handle) + Surface( + modifier = + Modifier.padding(top = 16.dp, bottom = 6.dp).semantics { + contentDescription = dragHandleContentDescription + }, + color = MaterialTheme.colorScheme.outlineVariant, + shape = MaterialTheme.shapes.extraLarge, + ) { + Box(Modifier.size(width = 32.dp, height = 4.dp)) } } @@ -139,81 +157,27 @@ constructor(private val userTracker: UserTracker, private val viewModel: Shortcu window.setDecorFitsSystemWindows(false) } - private fun setUpInsets() { - bottomSheetContainer.setOnApplyWindowInsetsListener { _, insets -> - val safeDrawingInsets = insets.safeDrawing - // Make sure the bottom sheet is not covered by the status bar. - bottomSheetBehavior.maxHeight = - windowManager.maximumWindowMetrics.bounds.height() - safeDrawingInsets.top - // Make sure the contents inside of the bottom sheet are not hidden by system bars, or - // cutouts. - bottomSheet.updatePadding( - left = safeDrawingInsets.left, - right = safeDrawingInsets.right, - bottom = safeDrawingInsets.bottom, - ) - // The bottom sheet has to be expanded only after setting up insets, otherwise there is - // a bug and it will not use full height. - expandBottomSheet() - - // Return CONSUMED if you don't want want the window insets to keep passing - // down to descendant views. - WindowInsets.CONSUMED - } - } - - private fun expandBottomSheet() { - bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED - bottomSheetBehavior.skipCollapsed = true + @Composable + private fun getTopPadding(): Dp { + return if (hasCompactWindowSize()) DefaultTopPadding else LargeScreenTopPadding } - private fun setUpPredictiveBack() { - val onBackPressedCallback = - object : OnBackPressedCallback(/* enabled= */ true) { - override fun handleOnBackStarted(backEvent: BackEventCompat) { - bottomSheetBehavior.startBackProgress(backEvent) - } - - override fun handleOnBackProgressed(backEvent: BackEventCompat) { - bottomSheetBehavior.updateBackProgress(backEvent) - } - - override fun handleOnBackPressed() { - bottomSheetBehavior.handleBackInvoked() - } - - override fun handleOnBackCancelled() { - bottomSheetBehavior.cancelBackProgress() - } + @Composable + private fun getWidth(): Dp { + return if (hasCompactWindowSize()) { + DefaultWidth + } else + when (LocalConfiguration.current.orientation) { + Configuration.ORIENTATION_LANDSCAPE -> LargeScreenWidthLandscape + else -> LargeScreenWidthPortrait } - onBackPressedDispatcher.addCallback( - owner = this, - onBackPressedCallback = onBackPressedCallback, - ) } - private fun setUpSheetDismissListener() { - bottomSheetBehavior.addBottomSheetCallback( - object : BottomSheetCallback() { - override fun onStateChanged(bottomSheet: View, newState: Int) { - if (newState == STATE_HIDDEN) { - finish() - } - } - - override fun onSlide(bottomSheet: View, slideOffset: Float) {} - } - ) - } - - private fun setUpDismissOnTouchOutside() { - bottomSheetContainer.setOnClickListener { finish() } + companion object { + private val DefaultTopPadding = 64.dp + private val LargeScreenTopPadding = 72.dp + private val DefaultWidth = 412.dp + private val LargeScreenWidthPortrait = 704.dp + private val LargeScreenWidthLandscape = 864.dp } } - -private val WindowInsets.safeDrawing - get() = - getInsets(WindowInsets.Type.systemBars()) - .union(getInsets(WindowInsets.Type.displayCutout())) - -private fun Insets.union(insets: Insets): Insets = Insets.max(this, insets) |