Loading packages/SystemUI/res/drawable/ic_qs_dual_target_arrow.xml 0 → 100644 +26 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?><!-- ~ Copyright (C) 2025 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. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:tint="?attr/colorControlNormal" android:viewportHeight="960" android:viewportWidth="960"> <path android:fillColor="@android:color/white" android:pathData="M480,604.5Q471.04,604.5 462.85,601.4Q454.65,598.3 447.93,591.59L264.17,407.83Q251.5,395.15 251.5,376Q251.5,356.85 264.17,344.17Q276.85,331.5 296,331.5Q315.15,331.5 327.83,344.17L480,496.35L632.17,344.17Q644.85,331.5 664,331.5Q683.15,331.5 695.83,344.17Q708.5,356.85 708.5,376Q708.5,395.15 695.83,407.83L512.07,591.59Q505.35,598.3 497.15,601.4Q488.96,604.5 480,604.5Z" /> </vector> No newline at end of file packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt +36 −2 Original line number Diff line number Diff line Loading @@ -35,11 +35,14 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicText import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect Loading @@ -65,6 +68,7 @@ import androidx.compose.ui.graphics.ColorProducer import androidx.compose.ui.graphics.CompositingStrategy import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.clearAndSetSemantics Loading @@ -84,11 +88,15 @@ import com.android.systemui.common.shared.model.Icon import com.android.systemui.common.ui.compose.Icon import com.android.systemui.common.ui.compose.load import com.android.systemui.compose.modifiers.sysuiResTag import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.ChevronSize import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.SideIconHeight import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.SideIconWidth import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TILE_INITIAL_DELAY_MILLIS import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TILE_MARQUEE_ITERATIONS import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TileDualTargetEndPadding import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TileEndPadding import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TileLabelBlurWidth import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TileStartPadding import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.longPressLabel import com.android.systemui.qs.panels.ui.viewmodel.AccessibilityUiState import com.android.systemui.qs.ui.compose.borderOnFocus Loading @@ -96,6 +104,7 @@ import com.android.systemui.res.R private const val TEST_TAG_TOGGLE = "qs_tile_toggle_target" @OptIn(ExperimentalMaterial3Api::class) @Composable fun LargeTileContent( label: String, Loading @@ -104,15 +113,18 @@ fun LargeTileContent( sideDrawable: Drawable?, colors: TileColors, squishiness: () -> Float, modifier: Modifier = Modifier, isVisible: () -> Boolean = { true }, accessibilityUiState: AccessibilityUiState? = null, iconShape: RoundedCornerShape = RoundedCornerShape(CommonTileDefaults.InactiveCornerRadius), toggleClick: (() -> Unit)? = null, onLongClick: (() -> Unit)? = null, ) { val isDualTarget = toggleClick != null Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = tileHorizontalArrangement(), modifier = modifier, ) { // Icon val longPressLabel = longPressLabel().takeIf { onLongClick != null } Loading @@ -125,7 +137,7 @@ fun LargeTileContent( .clip(iconShape) .verticalSquish(squishiness) .drawBehind { drawRect(animatedBackgroundColor) } .thenIf(toggleClick != null) { .thenIf(isDualTarget) { Modifier.borderOnFocus(color = focusBorderColor, iconShape.topEnd) .combinedClickable( onClick = toggleClick!!, Loading Loading @@ -171,6 +183,13 @@ fun LargeTileContent( contentDescription = null, modifier = Modifier.width(SideIconWidth).height(SideIconHeight), ) } else if (isDualTarget) { Icon( painterResource(R.drawable.ic_qs_dual_target_arrow), contentDescription = null, tint = { colors.label }, modifier = Modifier.size(ChevronSize), ) } } } Loading Loading @@ -331,15 +350,30 @@ private fun TileLabel( ) } /** * Apply the correct padding for large tiles * * Large tiles have a different end padding based on the content, such as if it's a dual target tile * or if it has a side drawable. */ fun Modifier.largeTilePadding(isDualTarget: Boolean = false): Modifier { return padding( start = TileStartPadding, end = if (isDualTarget) TileDualTargetEndPadding else TileEndPadding, ) } object CommonTileDefaults { val IconSize = 32.dp val LargeTileIconSize = 28.dp val SideIconWidth = 32.dp val SideIconHeight = 20.dp val ChevronSize = 16.dp val ToggleTargetSize = 56.dp val TileHeight = 72.dp val TileStartPadding = 8.dp val TileEndPadding = 16.dp val TileEndPadding = 12.dp val TileDualTargetEndPadding = 8.dp val TileArrangementPadding = 6.dp val InactiveCornerRadius = 50.dp val TileLabelBlurWidth = 32.dp Loading packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt +3 −9 Original line number Diff line number Diff line Loading @@ -37,7 +37,6 @@ import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyGridScope import androidx.compose.foundation.lazy.grid.LazyGridState Loading Loading @@ -89,9 +88,7 @@ import com.android.systemui.lifecycle.rememberViewModel import com.android.systemui.qs.flags.QsDetailedView import com.android.systemui.qs.panels.ui.compose.BounceableInfo import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.InactiveCornerRadius import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TileEndPadding import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TileHeight import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TileStartPadding import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.longPressLabel import com.android.systemui.qs.panels.ui.viewmodel.AccessibilityUiState import com.android.systemui.qs.panels.ui.viewmodel.DetailsViewModel Loading Loading @@ -256,6 +253,8 @@ fun Tile( accessibilityUiState = uiState.accessibilityUiState, squishiness = squishiness, isVisible = isVisible, modifier = Modifier.largeTilePadding(isDualTarget = uiState.handlesLongClick), ) } } Loading Loading @@ -299,8 +298,7 @@ fun TileContainer( accessibilityUiState = accessibilityUiState, iconOnly = iconOnly, ) .sysuiResTag(if (iconOnly) TEST_TAG_SMALL else TEST_TAG_LARGE) .thenIf(!iconOnly) { Modifier.largeTilePadding() }, // Icon tiles are center aligned .sysuiResTag(if (iconOnly) TEST_TAG_SMALL else TEST_TAG_LARGE), content = content, ) } Loading Loading @@ -345,10 +343,6 @@ fun tileHorizontalArrangement(): Arrangement.Horizontal { return spacedBy(space = CommonTileDefaults.TileArrangementPadding, alignment = Alignment.Start) } fun Modifier.largeTilePadding(): Modifier { return padding(start = TileStartPadding, end = TileEndPadding) } @Composable fun Modifier.tileCombinedClickable( onClick: () -> Unit, Loading Loading
packages/SystemUI/res/drawable/ic_qs_dual_target_arrow.xml 0 → 100644 +26 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?><!-- ~ Copyright (C) 2025 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. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:tint="?attr/colorControlNormal" android:viewportHeight="960" android:viewportWidth="960"> <path android:fillColor="@android:color/white" android:pathData="M480,604.5Q471.04,604.5 462.85,601.4Q454.65,598.3 447.93,591.59L264.17,407.83Q251.5,395.15 251.5,376Q251.5,356.85 264.17,344.17Q276.85,331.5 296,331.5Q315.15,331.5 327.83,344.17L480,496.35L632.17,344.17Q644.85,331.5 664,331.5Q683.15,331.5 695.83,344.17Q708.5,356.85 708.5,376Q708.5,395.15 695.83,407.83L512.07,591.59Q505.35,598.3 497.15,601.4Q488.96,604.5 480,604.5Z" /> </vector> No newline at end of file
packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt +36 −2 Original line number Diff line number Diff line Loading @@ -35,11 +35,14 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicText import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect Loading @@ -65,6 +68,7 @@ import androidx.compose.ui.graphics.ColorProducer import androidx.compose.ui.graphics.CompositingStrategy import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.clearAndSetSemantics Loading @@ -84,11 +88,15 @@ import com.android.systemui.common.shared.model.Icon import com.android.systemui.common.ui.compose.Icon import com.android.systemui.common.ui.compose.load import com.android.systemui.compose.modifiers.sysuiResTag import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.ChevronSize import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.SideIconHeight import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.SideIconWidth import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TILE_INITIAL_DELAY_MILLIS import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TILE_MARQUEE_ITERATIONS import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TileDualTargetEndPadding import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TileEndPadding import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TileLabelBlurWidth import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TileStartPadding import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.longPressLabel import com.android.systemui.qs.panels.ui.viewmodel.AccessibilityUiState import com.android.systemui.qs.ui.compose.borderOnFocus Loading @@ -96,6 +104,7 @@ import com.android.systemui.res.R private const val TEST_TAG_TOGGLE = "qs_tile_toggle_target" @OptIn(ExperimentalMaterial3Api::class) @Composable fun LargeTileContent( label: String, Loading @@ -104,15 +113,18 @@ fun LargeTileContent( sideDrawable: Drawable?, colors: TileColors, squishiness: () -> Float, modifier: Modifier = Modifier, isVisible: () -> Boolean = { true }, accessibilityUiState: AccessibilityUiState? = null, iconShape: RoundedCornerShape = RoundedCornerShape(CommonTileDefaults.InactiveCornerRadius), toggleClick: (() -> Unit)? = null, onLongClick: (() -> Unit)? = null, ) { val isDualTarget = toggleClick != null Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = tileHorizontalArrangement(), modifier = modifier, ) { // Icon val longPressLabel = longPressLabel().takeIf { onLongClick != null } Loading @@ -125,7 +137,7 @@ fun LargeTileContent( .clip(iconShape) .verticalSquish(squishiness) .drawBehind { drawRect(animatedBackgroundColor) } .thenIf(toggleClick != null) { .thenIf(isDualTarget) { Modifier.borderOnFocus(color = focusBorderColor, iconShape.topEnd) .combinedClickable( onClick = toggleClick!!, Loading Loading @@ -171,6 +183,13 @@ fun LargeTileContent( contentDescription = null, modifier = Modifier.width(SideIconWidth).height(SideIconHeight), ) } else if (isDualTarget) { Icon( painterResource(R.drawable.ic_qs_dual_target_arrow), contentDescription = null, tint = { colors.label }, modifier = Modifier.size(ChevronSize), ) } } } Loading Loading @@ -331,15 +350,30 @@ private fun TileLabel( ) } /** * Apply the correct padding for large tiles * * Large tiles have a different end padding based on the content, such as if it's a dual target tile * or if it has a side drawable. */ fun Modifier.largeTilePadding(isDualTarget: Boolean = false): Modifier { return padding( start = TileStartPadding, end = if (isDualTarget) TileDualTargetEndPadding else TileEndPadding, ) } object CommonTileDefaults { val IconSize = 32.dp val LargeTileIconSize = 28.dp val SideIconWidth = 32.dp val SideIconHeight = 20.dp val ChevronSize = 16.dp val ToggleTargetSize = 56.dp val TileHeight = 72.dp val TileStartPadding = 8.dp val TileEndPadding = 16.dp val TileEndPadding = 12.dp val TileDualTargetEndPadding = 8.dp val TileArrangementPadding = 6.dp val InactiveCornerRadius = 50.dp val TileLabelBlurWidth = 32.dp Loading
packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt +3 −9 Original line number Diff line number Diff line Loading @@ -37,7 +37,6 @@ import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyGridScope import androidx.compose.foundation.lazy.grid.LazyGridState Loading Loading @@ -89,9 +88,7 @@ import com.android.systemui.lifecycle.rememberViewModel import com.android.systemui.qs.flags.QsDetailedView import com.android.systemui.qs.panels.ui.compose.BounceableInfo import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.InactiveCornerRadius import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TileEndPadding import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TileHeight import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TileStartPadding import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.longPressLabel import com.android.systemui.qs.panels.ui.viewmodel.AccessibilityUiState import com.android.systemui.qs.panels.ui.viewmodel.DetailsViewModel Loading Loading @@ -256,6 +253,8 @@ fun Tile( accessibilityUiState = uiState.accessibilityUiState, squishiness = squishiness, isVisible = isVisible, modifier = Modifier.largeTilePadding(isDualTarget = uiState.handlesLongClick), ) } } Loading Loading @@ -299,8 +298,7 @@ fun TileContainer( accessibilityUiState = accessibilityUiState, iconOnly = iconOnly, ) .sysuiResTag(if (iconOnly) TEST_TAG_SMALL else TEST_TAG_LARGE) .thenIf(!iconOnly) { Modifier.largeTilePadding() }, // Icon tiles are center aligned .sysuiResTag(if (iconOnly) TEST_TAG_SMALL else TEST_TAG_LARGE), content = content, ) } Loading Loading @@ -345,10 +343,6 @@ fun tileHorizontalArrangement(): Arrangement.Horizontal { return spacedBy(space = CommonTileDefaults.TileArrangementPadding, alignment = Alignment.Start) } fun Modifier.largeTilePadding(): Modifier { return padding(start = TileStartPadding, end = TileEndPadding) } @Composable fun Modifier.tileCombinedClickable( onClick: () -> Unit, Loading