summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/compose/core/src/com/android/systemui/compose/layout/pager/Pager.kt356
-rw-r--r--packages/SystemUI/compose/core/src/com/android/systemui/compose/layout/pager/PagerState.kt348
-rw-r--r--packages/SystemUI/compose/core/src/com/android/systemui/compose/layout/pager/SnappingFlingBehavior.kt270
-rw-r--r--packages/SystemUI/compose/core/src/com/android/systemui/compose/modifiers/Padding.kt142
-rw-r--r--packages/SystemUI/compose/core/src/com/android/systemui/compose/modifiers/Size.kt247
-rw-r--r--packages/SystemUI/compose/gallery/Android.bp86
-rw-r--r--packages/SystemUI/compose/gallery/AndroidManifest.xml55
-rw-r--r--packages/SystemUI/compose/gallery/TEST_MAPPING15
-rw-r--r--packages/SystemUI/compose/gallery/app/AndroidManifest.xml39
-rw-r--r--packages/SystemUI/compose/gallery/proguard-rules.pro21
-rw-r--r--packages/SystemUI/compose/gallery/res/drawable-v24/ic_launcher_foreground.xml30
-rw-r--r--packages/SystemUI/compose/gallery/res/drawable/ic_launcher_background.xml170
-rw-r--r--packages/SystemUI/compose/gallery/res/drawable/kitten1.jpegbin4097 -> 0 bytes
-rw-r--r--packages/SystemUI/compose/gallery/res/drawable/kitten2.jpegbin4875 -> 0 bytes
-rw-r--r--packages/SystemUI/compose/gallery/res/drawable/kitten3.jpegbin6268 -> 0 bytes
-rw-r--r--packages/SystemUI/compose/gallery/res/drawable/kitten4.jpegbin5212 -> 0 bytes
-rw-r--r--packages/SystemUI/compose/gallery/res/drawable/kitten5.jpegbin5339 -> 0 bytes
-rw-r--r--packages/SystemUI/compose/gallery/res/drawable/kitten6.jpegbin6109 -> 0 bytes
-rw-r--r--packages/SystemUI/compose/gallery/res/mipmap-anydpi-v26/ic_launcher.xml5
-rw-r--r--packages/SystemUI/compose/gallery/res/mipmap-anydpi-v26/ic_launcher_round.xml5
-rw-r--r--packages/SystemUI/compose/gallery/res/mipmap-hdpi/ic_launcher.webpbin1404 -> 0 bytes
-rw-r--r--packages/SystemUI/compose/gallery/res/mipmap-hdpi/ic_launcher_round.webpbin2898 -> 0 bytes
-rw-r--r--packages/SystemUI/compose/gallery/res/mipmap-mdpi/ic_launcher.webpbin982 -> 0 bytes
-rw-r--r--packages/SystemUI/compose/gallery/res/mipmap-mdpi/ic_launcher_round.webpbin1772 -> 0 bytes
-rw-r--r--packages/SystemUI/compose/gallery/res/mipmap-xhdpi/ic_launcher.webpbin1900 -> 0 bytes
-rw-r--r--packages/SystemUI/compose/gallery/res/mipmap-xhdpi/ic_launcher_round.webpbin3918 -> 0 bytes
-rw-r--r--packages/SystemUI/compose/gallery/res/mipmap-xxhdpi/ic_launcher.webpbin2884 -> 0 bytes
-rw-r--r--packages/SystemUI/compose/gallery/res/mipmap-xxhdpi/ic_launcher_round.webpbin5914 -> 0 bytes
-rw-r--r--packages/SystemUI/compose/gallery/res/mipmap-xxxhdpi/ic_launcher.webpbin3844 -> 0 bytes
-rw-r--r--packages/SystemUI/compose/gallery/res/mipmap-xxxhdpi/ic_launcher_round.webpbin7778 -> 0 bytes
-rw-r--r--packages/SystemUI/compose/gallery/res/values/colors.xml19
-rw-r--r--packages/SystemUI/compose/gallery/res/values/strings.xml20
-rw-r--r--packages/SystemUI/compose/gallery/res/values/themes.xml30
-rw-r--r--packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ButtonsScreen.kt77
-rw-r--r--packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ColorsScreen.kt139
-rw-r--r--packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ConfigurationControls.kt210
-rw-r--r--packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ExampleFeatureScreen.kt28
-rw-r--r--packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryActivity.kt80
-rw-r--r--packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt202
-rw-r--r--packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/PeopleScreen.kt46
-rw-r--r--packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/Screen.kt126
-rw-r--r--packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/TypographyScreen.kt67
-rw-r--r--packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/UserSwitcherScreen.kt35
-rw-r--r--packages/SystemUI/compose/gallery/src/com/android/systemui/people/Fakes.kt156
-rw-r--r--packages/SystemUI/compose/gallery/src/com/android/systemui/qs/footer/Fakes.kt164
-rw-r--r--packages/SystemUI/compose/gallery/src/com/android/systemui/user/Fakes.kt116
-rw-r--r--packages/SystemUI/compose/gallery/tests/Android.bp47
-rw-r--r--packages/SystemUI/compose/gallery/tests/AndroidManifest.xml28
-rw-r--r--packages/SystemUI/compose/gallery/tests/src/com/android/systemui/compose/gallery/ScreenshotsTests.kt36
49 files changed, 1363 insertions, 2052 deletions
diff --git a/packages/SystemUI/compose/core/src/com/android/systemui/compose/layout/pager/Pager.kt b/packages/SystemUI/compose/core/src/com/android/systemui/compose/layout/pager/Pager.kt
new file mode 100644
index 000000000000..19624e605be8
--- /dev/null
+++ b/packages/SystemUI/compose/core/src/com/android/systemui/compose/layout/pager/Pager.kt
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2022 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.compose.layout.pager
+
+import androidx.compose.animation.core.AnimationSpec
+import androidx.compose.animation.core.DecayAnimationSpec
+import androidx.compose.animation.rememberSplineBasedDecay
+import androidx.compose.foundation.gestures.FlingBehavior
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.wrapContentSize
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.LazyRow
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.Stable
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.snapshotFlow
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
+import androidx.compose.ui.input.nestedscroll.NestedScrollSource
+import androidx.compose.ui.input.nestedscroll.nestedScroll
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.Velocity
+import androidx.compose.ui.unit.dp
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.flow.filter
+
+/** Library-wide switch to turn on debug logging. */
+internal const val DebugLog = false
+
+@RequiresOptIn(message = "Accompanist Pager is experimental. The API may be changed in the future.")
+@Retention(AnnotationRetention.BINARY)
+annotation class ExperimentalPagerApi
+
+/** Contains the default values used by [HorizontalPager] and [VerticalPager]. */
+@ExperimentalPagerApi
+object PagerDefaults {
+ /**
+ * Remember the default [FlingBehavior] that represents the scroll curve.
+ *
+ * @param state The [PagerState] to update.
+ * @param decayAnimationSpec The decay animation spec to use for decayed flings.
+ * @param snapAnimationSpec The animation spec to use when snapping.
+ */
+ @Composable
+ fun flingBehavior(
+ state: PagerState,
+ decayAnimationSpec: DecayAnimationSpec<Float> = rememberSplineBasedDecay(),
+ snapAnimationSpec: AnimationSpec<Float> = SnappingFlingBehaviorDefaults.snapAnimationSpec,
+ ): FlingBehavior =
+ rememberSnappingFlingBehavior(
+ lazyListState = state.lazyListState,
+ decayAnimationSpec = decayAnimationSpec,
+ snapAnimationSpec = snapAnimationSpec,
+ )
+
+ @Deprecated(
+ "Replaced with PagerDefaults.flingBehavior()",
+ ReplaceWith("PagerDefaults.flingBehavior(state, decayAnimationSpec, snapAnimationSpec)")
+ )
+ @Composable
+ fun rememberPagerFlingConfig(
+ state: PagerState,
+ decayAnimationSpec: DecayAnimationSpec<Float> = rememberSplineBasedDecay(),
+ snapAnimationSpec: AnimationSpec<Float> = SnappingFlingBehaviorDefaults.snapAnimationSpec,
+ ): FlingBehavior = flingBehavior(state, decayAnimationSpec, snapAnimationSpec)
+}
+
+/**
+ * A horizontally scrolling layout that allows users to flip between items to the left and right.
+ *
+ * @sample com.google.accompanist.sample.pager.HorizontalPagerSample
+ *
+ * @param count the number of pages.
+ * @param modifier the modifier to apply to this layout.
+ * @param state the state object to be used to control or observe the pager's state.
+ * @param reverseLayout reverse the direction of scrolling and layout, when `true` items will be
+ * composed from the end to the start and [PagerState.currentPage] == 0 will mean the first item is
+ * located at the end.
+ * @param itemSpacing horizontal spacing to add between items.
+ * @param flingBehavior logic describing fling behavior.
+ * @param key the scroll position will be maintained based on the key, which means if you add/remove
+ * items before the current visible item the item with the given key will be kept as the first
+ * visible one.
+ * @param content a block which describes the content. Inside this block you can reference
+ * [PagerScope.currentPage] and other properties in [PagerScope].
+ */
+@ExperimentalPagerApi
+@Composable
+fun HorizontalPager(
+ count: Int,
+ modifier: Modifier = Modifier,
+ state: PagerState = rememberPagerState(),
+ reverseLayout: Boolean = false,
+ itemSpacing: Dp = 0.dp,
+ flingBehavior: FlingBehavior = PagerDefaults.flingBehavior(state),
+ verticalAlignment: Alignment.Vertical = Alignment.CenterVertically,
+ key: ((page: Int) -> Any)? = null,
+ contentPadding: PaddingValues = PaddingValues(0.dp),
+ content: @Composable PagerScope.(page: Int) -> Unit,
+) {
+ Pager(
+ count = count,
+ state = state,
+ modifier = modifier,
+ isVertical = false,
+ reverseLayout = reverseLayout,
+ itemSpacing = itemSpacing,
+ verticalAlignment = verticalAlignment,
+ flingBehavior = flingBehavior,
+ key = key,
+ contentPadding = contentPadding,
+ content = content
+ )
+}
+
+/**
+ * A vertically scrolling layout that allows users to flip between items to the top and bottom.
+ *
+ * @sample com.google.accompanist.sample.pager.VerticalPagerSample
+ *
+ * @param count the number of pages.
+ * @param modifier the modifier to apply to this layout.
+ * @param state the state object to be used to control or observe the pager's state.
+ * @param reverseLayout reverse the direction of scrolling and layout, when `true` items will be
+ * composed from the bottom to the top and [PagerState.currentPage] == 0 will mean the first item is
+ * located at the bottom.
+ * @param itemSpacing vertical spacing to add between items.
+ * @param flingBehavior logic describing fling behavior.
+ * @param key the scroll position will be maintained based on the key, which means if you add/remove
+ * items before the current visible item the item with the given key will be kept as the first
+ * visible one.
+ * @param content a block which describes the content. Inside this block you can reference
+ * [PagerScope.currentPage] and other properties in [PagerScope].
+ */
+@ExperimentalPagerApi
+@Composable
+fun VerticalPager(
+ count: Int,
+ modifier: Modifier = Modifier,
+ state: PagerState = rememberPagerState(),
+ reverseLayout: Boolean = false,
+ itemSpacing: Dp = 0.dp,
+ flingBehavior: FlingBehavior = PagerDefaults.flingBehavior(state),
+ horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally,
+ key: ((page: Int) -> Any)? = null,
+ contentPadding: PaddingValues = PaddingValues(0.dp),
+ content: @Composable PagerScope.(page: Int) -> Unit,
+) {
+ Pager(
+ count = count,
+ state = state,
+ modifier = modifier,
+ isVertical = true,
+ reverseLayout = reverseLayout,
+ itemSpacing = itemSpacing,
+ horizontalAlignment = horizontalAlignment,
+ flingBehavior = flingBehavior,
+ key = key,
+ contentPadding = contentPadding,
+ content = content
+ )
+}
+
+@ExperimentalPagerApi
+@Composable
+internal fun Pager(
+ count: Int,
+ modifier: Modifier,
+ state: PagerState,
+ reverseLayout: Boolean,
+ itemSpacing: Dp,
+ isVertical: Boolean,
+ flingBehavior: FlingBehavior,
+ key: ((page: Int) -> Any)?,
+ contentPadding: PaddingValues,
+ verticalAlignment: Alignment.Vertical = Alignment.CenterVertically,
+ horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally,
+ content: @Composable PagerScope.(page: Int) -> Unit,
+) {
+ require(count >= 0) { "pageCount must be >= 0" }
+
+ // Provide our PagerState with access to the SnappingFlingBehavior animation target
+ // TODO: can this be done in a better way?
+ state.flingAnimationTarget = { (flingBehavior as? SnappingFlingBehavior)?.animationTarget }
+
+ LaunchedEffect(count) {
+ state.currentPage = minOf(count - 1, state.currentPage).coerceAtLeast(0)
+ }
+
+ // Once a fling (scroll) has finished, notify the state
+ LaunchedEffect(state) {
+ // When a 'scroll' has finished, notify the state
+ snapshotFlow { state.isScrollInProgress }
+ .filter { !it }
+ .collect { state.onScrollFinished() }
+ }
+
+ val pagerScope = remember(state) { PagerScopeImpl(state) }
+
+ // We only consume nested flings in the main-axis, allowing cross-axis flings to propagate
+ // as normal
+ val consumeFlingNestedScrollConnection =
+ ConsumeFlingNestedScrollConnection(
+ consumeHorizontal = !isVertical,
+ consumeVertical = isVertical,
+ )
+
+ if (isVertical) {
+ LazyColumn(
+ state = state.lazyListState,
+ verticalArrangement = Arrangement.spacedBy(itemSpacing, verticalAlignment),
+ horizontalAlignment = horizontalAlignment,
+ flingBehavior = flingBehavior,
+ reverseLayout = reverseLayout,
+ contentPadding = contentPadding,
+ modifier = modifier,
+ ) {
+ items(
+ count = count,
+ key = key,
+ ) { page ->
+ Box(
+ Modifier
+ // We don't any nested flings to continue in the pager, so we add a
+ // connection which consumes them.
+ // See: https://github.com/google/accompanist/issues/347
+ .nestedScroll(connection = consumeFlingNestedScrollConnection)
+ // Constraint the content to be <= than the size of the pager.
+ .fillParentMaxHeight()
+ .wrapContentSize()
+ ) { pagerScope.content(page) }
+ }
+ }
+ } else {
+ LazyRow(
+ state = state.lazyListState,
+ verticalAlignment = verticalAlignment,
+ horizontalArrangement = Arrangement.spacedBy(itemSpacing, horizontalAlignment),
+ flingBehavior = flingBehavior,
+ reverseLayout = reverseLayout,
+ contentPadding = contentPadding,
+ modifier = modifier,
+ ) {
+ items(
+ count = count,
+ key = key,
+ ) { page ->
+ Box(
+ Modifier
+ // We don't any nested flings to continue in the pager, so we add a
+ // connection which consumes them.
+ // See: https://github.com/google/accompanist/issues/347
+ .nestedScroll(connection = consumeFlingNestedScrollConnection)
+ // Constraint the content to be <= than the size of the pager.
+ .fillParentMaxWidth()
+ .wrapContentSize()
+ ) { pagerScope.content(page) }
+ }
+ }
+ }
+}
+
+private class ConsumeFlingNestedScrollConnection(
+ private val consumeHorizontal: Boolean,
+ private val consumeVertical: Boolean,
+) : NestedScrollConnection {
+ override fun onPostScroll(
+ consumed: Offset,
+ available: Offset,
+ source: NestedScrollSource
+ ): Offset =
+ when (source) {
+ // We can consume all resting fling scrolls so that they don't propagate up to the
+ // Pager
+ NestedScrollSource.Fling -> available.consume(consumeHorizontal, consumeVertical)
+ else -> Offset.Zero
+ }
+
+ override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity {
+ // We can consume all post fling velocity on the main-axis
+ // so that it doesn't propagate up to the Pager
+ return available.consume(consumeHorizontal, consumeVertical)
+ }
+}
+
+private fun Offset.consume(
+ consumeHorizontal: Boolean,
+ consumeVertical: Boolean,
+): Offset =
+ Offset(
+ x = if (consumeHorizontal) this.x else 0f,
+ y = if (consumeVertical) this.y else 0f,
+ )
+
+private fun Velocity.consume(
+ consumeHorizontal: Boolean,
+ consumeVertical: Boolean,
+): Velocity =
+ Velocity(
+ x = if (consumeHorizontal) this.x else 0f,
+ y = if (consumeVertical) this.y else 0f,
+ )
+
+/** Scope for [HorizontalPager] content. */
+@ExperimentalPagerApi
+@Stable
+interface PagerScope {
+ /** Returns the current selected page */
+ val currentPage: Int
+
+ /** The current offset from the start of [currentPage], as a ratio of the page width. */
+ val currentPageOffset: Float
+}
+
+@ExperimentalPagerApi
+private class PagerScopeImpl(
+ private val state: PagerState,
+) : PagerScope {
+ override val currentPage: Int
+ get() = state.currentPage
+ override val currentPageOffset: Float
+ get() = state.currentPageOffset
+}
+
+/**
+ * Calculate the offset for the given [page] from the current scroll position. This is useful when
+ * using the scroll position to apply effects or animations to items.
+ *
+ * The returned offset can positive or negative, depending on whether which direction the [page] is
+ * compared to the current scroll position.
+ *
+ * @sample com.google.accompanist.sample.pager.HorizontalPagerWithOffsetTransition
+ */
+@ExperimentalPagerApi
+fun PagerScope.calculateCurrentOffsetForPage(page: Int): Float {
+ return (currentPage + currentPageOffset) - page
+}
diff --git a/packages/SystemUI/compose/core/src/com/android/systemui/compose/layout/pager/PagerState.kt b/packages/SystemUI/compose/core/src/com/android/systemui/compose/layout/pager/PagerState.kt
new file mode 100644
index 000000000000..288c26eb1199
--- /dev/null
+++ b/packages/SystemUI/compose/core/src/com/android/systemui/compose/layout/pager/PagerState.kt
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2022 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.compose.layout.pager
+
+import androidx.annotation.FloatRange
+import androidx.annotation.IntRange
+import androidx.compose.animation.core.AnimationSpec
+import androidx.compose.animation.core.spring
+import androidx.compose.foundation.MutatePriority
+import androidx.compose.foundation.gestures.ScrollScope
+import androidx.compose.foundation.gestures.ScrollableState
+import androidx.compose.foundation.interaction.InteractionSource
+import androidx.compose.foundation.lazy.LazyListItemInfo
+import androidx.compose.foundation.lazy.LazyListState
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.Stable
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.saveable.Saver
+import androidx.compose.runtime.saveable.listSaver
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
+import kotlin.math.absoluteValue
+import kotlin.math.roundToInt
+
+@Deprecated(
+ "Replaced with rememberPagerState(initialPage) and count parameter on Pager composables",
+ ReplaceWith("rememberPagerState(initialPage)"),
+ level = DeprecationLevel.ERROR,
+)
+@Suppress("UNUSED_PARAMETER", "NOTHING_TO_INLINE")
+@ExperimentalPagerApi
+@Composable
+inline fun rememberPagerState(
+ @IntRange(from = 0) pageCount: Int,
+ @IntRange(from = 0) initialPage: Int = 0,
+ @FloatRange(from = 0.0, to = 1.0) initialPageOffset: Float = 0f,
+ @IntRange(from = 1) initialOffscreenLimit: Int = 1,
+ infiniteLoop: Boolean = false
+): PagerState {
+ return rememberPagerState(initialPage = initialPage)
+}
+
+/**
+ * Creates a [PagerState] that is remembered across compositions.
+ *
+ * Changes to the provided values for [initialPage] will **not** result in the state being recreated
+ * or changed in any way if it has already been created.
+ *
+ * @param initialPage the initial value for [PagerState.currentPage]
+ */
+@ExperimentalPagerApi
+@Composable
+fun rememberPagerState(
+ @IntRange(from = 0) initialPage: Int = 0,
+): PagerState =
+ rememberSaveable(saver = PagerState.Saver) {
+ PagerState(
+ currentPage = initialPage,
+ )
+ }
+
+/**
+ * A state object that can be hoisted to control and observe scrolling for [HorizontalPager].
+ *
+ * In most cases, this will be created via [rememberPagerState].
+ *
+ * @param currentPage the initial value for [PagerState.currentPage]
+ */
+@ExperimentalPagerApi
+@Stable
+class PagerState(
+ @IntRange(from = 0) currentPage: Int = 0,
+) : ScrollableState {
+ // Should this be public?
+ internal val lazyListState = LazyListState(firstVisibleItemIndex = currentPage)
+
+ private var _currentPage by mutableStateOf(currentPage)
+
+ private val currentLayoutPageInfo: LazyListItemInfo?
+ get() =
+ lazyListState.layoutInfo.visibleItemsInfo
+ .asSequence()
+ .filter { it.offset <= 0 && it.offset + it.size > 0 }
+ .lastOrNull()
+
+ private val currentLayoutPageOffset: Float
+ get() =
+ currentLayoutPageInfo?.let { current ->
+ // We coerce since itemSpacing can make the offset > 1f.
+ // We don't want to count spacing in the offset so cap it to 1f
+ (-current.offset / current.size.toFloat()).coerceIn(0f, 1f)
+ }
+ ?: 0f
+
+ /**
+ * [InteractionSource] that will be used to dispatch drag events when this list is being
+ * dragged. If you want to know whether the fling (or animated scroll) is in progress, use
+ * [isScrollInProgress].
+ */
+ val interactionSource: InteractionSource
+ get() = lazyListState.interactionSource
+
+ /** The number of pages to display. */
+ @get:IntRange(from = 0)
+ val pageCount: Int by derivedStateOf { lazyListState.layoutInfo.totalItemsCount }
+
+ /**
+ * The index of the currently selected page. This may not be the page which is currently
+ * displayed on screen.
+ *
+ * To update the scroll position, use [scrollToPage] or [animateScrollToPage].
+ */
+ @get:IntRange(from = 0)
+ var currentPage: Int
+ get() = _currentPage
+ internal set(value) {
+ if (value != _currentPage) {
+ _currentPage = value
+ }
+ }
+
+ /**
+ * The current offset from the start of [currentPage], as a ratio of the page width.
+ *
+ * To update the scroll position, use [scrollToPage] or [animateScrollToPage].
+ */
+ val currentPageOffset: Float by derivedStateOf {
+ currentLayoutPageInfo?.let {
+ // The current page offset is the current layout page delta from `currentPage`
+ // (which is only updated after a scroll/animation).
+ // We calculate this by looking at the current layout page + it's offset,
+ // then subtracting the 'current page'.
+ it.index + currentLayoutPageOffset - _currentPage
+ }
+ ?: 0f
+ }
+
+ /** The target page for any on-going animations. */
+ private var animationTargetPage: Int? by mutableStateOf(null)
+
+ internal var flingAnimationTarget: (() -> Int?)? by mutableStateOf(null)
+
+ /**
+ * The target page for any on-going animations or scrolls by the user. Returns the current page
+ * if a scroll or animation is not currently in progress.
+ */
+ val targetPage: Int
+ get() =
+ animationTargetPage
+ ?: flingAnimationTarget?.invoke()
+ ?: when {
+ // If a scroll isn't in progress, return the current page
+ !isScrollInProgress -> currentPage
+ // If the offset is 0f (or very close), return the current page
+ currentPageOffset.absoluteValue < 0.001f -> currentPage
+ // If we're offset towards the start, guess the previous page
+ currentPageOffset < -0.5f -> (currentPage - 1).coerceAtLeast(0)
+ // If we're offset towards the end, guess the next page
+ else -> (currentPage + 1).coerceAtMost(pageCount - 1)
+ }
+
+ @Deprecated(
+ "Replaced with animateScrollToPage(page, pageOffset)",
+ ReplaceWith("animateScrollToPage(page = page, pageOffset = pageOffset)")
+ )
+ @Suppress("UNUSED_PARAMETER")
+ suspend fun animateScrollToPage(
+ @IntRange(from = 0) page: Int,
+ @FloatRange(from = 0.0, to = 1.0) pageOffset: Float = 0f,
+ animationSpec: AnimationSpec<Float> = spring(),
+ initialVelocity: Float = 0f,
+ skipPages: Boolean = true,
+ ) {
+ animateScrollToPage(page = page, pageOffset = pageOffset)
+ }
+
+ /**
+ * Animate (smooth scroll) to the given page to the middle of the viewport.
+ *
+ * Cancels the currently running scroll, if any, and suspends until the cancellation is
+ * complete.
+ *
+ * @param page the page to animate to. Must be between 0 and [pageCount] (inclusive).
+ * @param pageOffset the percentage of the page width to offset, from the start of [page]. Must
+ * be in the range 0f..1f.
+ */
+ suspend fun animateScrollToPage(
+ @IntRange(from = 0) page: Int,
+ @FloatRange(from = 0.0, to = 1.0) pageOffset: Float = 0f,
+ ) {
+ requireCurrentPage(page, "page")
+ requireCurrentPageOffset(pageOffset, "pageOffset")
+ try {
+ animationTargetPage = page
+
+ if (pageOffset <= 0.005f) {
+ // If the offset is (close to) zero, just call animateScrollToItem and we're done
+ lazyListState.animateScrollToItem(index = page)
+ } else {
+ // Else we need to figure out what the offset is in pixels...
+
+ var target =
+ lazyListState.layoutInfo.visibleItemsInfo.firstOrNull { it.index == page }
+
+ if (target != null) {
+ // If we have access to the target page layout, we can calculate the pixel
+ // offset from the size
+ lazyListState.animateScrollToItem(
+ index = page,
+ scrollOffset = (target.size * pageOffset).roundToInt()
+ )
+ } else {
+ // If we don't, we use the current page size as a guide
+ val currentSize = currentLayoutPageInfo!!.size
+ lazyListState.animateScrollToItem(
+ index = page,
+ scrollOffset = (currentSize * pageOffset).roundToInt()
+ )
+
+ // The target should be visible now
+ target = lazyListState.layoutInfo.visibleItemsInfo.first { it.index == page }
+
+ if (target.size != currentSize) {
+ // If the size we used for calculating the offset differs from the actual
+ // target page size, we need to scroll again. This doesn't look great,
+ // but there's not much else we can do.
+ lazyListState.animateScrollToItem(
+ index = page,
+ scrollOffset = (target.size * pageOffset).roundToInt()
+ )
+ }
+ }
+ }
+ } finally {
+ // We need to manually call this, as the `animateScrollToItem` call above will happen
+ // in 1 frame, which is usually too fast for the LaunchedEffect in Pager to detect
+ // the change. This is especially true when running unit tests.
+ onScrollFinished()
+ }
+ }
+
+ /**
+ * Instantly brings the item at [page] to the middle of the viewport.
+ *
+ * Cancels the currently running scroll, if any, and suspends until the cancellation is
+ * complete.
+ *
+ * @param page the page to snap to. Must be between 0 and [pageCount] (inclusive).
+ */
+ suspend fun scrollToPage(
+ @IntRange(from = 0) page: Int,
+ @FloatRange(from = 0.0, to = 1.0) pageOffset: Float = 0f,
+ ) {
+ requireCurrentPage(page, "page")
+ requireCurrentPageOffset(pageOffset, "pageOffset")
+ try {
+ animationTargetPage = page
+
+ // First scroll to the given page. It will now be laid out at offset 0
+ lazyListState.scrollToItem(index = page)
+
+ // If we have a start spacing, we need to offset (scroll) by that too
+ if (pageOffset > 0.0001f) {
+ scroll { currentLayoutPageInfo?.let { scrollBy(it.size * pageOffset) } }
+ }
+ } finally {
+ // We need to manually call this, as the `scroll` call above will happen in 1 frame,
+ // which is usually too fast for the LaunchedEffect in Pager to detect the change.
+ // This is especially true when running unit tests.
+ onScrollFinished()
+ }
+ }
+
+ internal fun onScrollFinished() {
+ // Then update the current page to our layout page
+ currentPage = currentLayoutPageInfo?.index ?: 0
+ // Clear the animation target page
+ animationTargetPage = null
+ }
+
+ override suspend fun scroll(
+ scrollPriority: MutatePriority,
+ block: suspend ScrollScope.() -> Unit
+ ) = lazyListState.scroll(scrollPriority, block)
+
+ override fun dispatchRawDelta(delta: Float): Float {
+ return lazyListState.dispatchRawDelta(delta)
+ }
+
+ override val isScrollInProgress: Boolean
+ get() = lazyListState.isScrollInProgress
+
+ override fun toString(): String =
+ "PagerState(" +
+ "pageCount=$pageCount, " +
+ "currentPage=$currentPage, " +
+ "currentPageOffset=$currentPageOffset" +
+ ")"
+
+ private fun requireCurrentPage(value: Int, name: String) {
+ if (pageCount == 0) {
+ require(value == 0) { "$name must be 0 when pageCount is 0" }
+ } else {
+ require(value in 0 until pageCount) { "$name[$value] must be >= 0 and < pageCount" }
+ }
+ }
+
+ private fun requireCurrentPageOffset(value: Float, name: String) {
+ if (pageCount == 0) {
+ require(value == 0f) { "$name must be 0f when pageCount is 0" }
+ } else {
+ require(value in 0f..1f) { "$name must be >= 0 and <= 1" }
+ }
+ }
+
+ companion object {
+ /** The default [Saver] implementation for [PagerState]. */
+ val Saver: Saver<PagerState, *> =
+ listSaver(
+ save = {
+ listOf<Any>(
+ it.currentPage,
+ )
+ },
+ restore = {
+ PagerState(
+ currentPage = it[0] as Int,
+ )
+ }
+ )
+ }
+}
diff --git a/packages/SystemUI/compose/core/src/com/android/systemui/compose/layout/pager/SnappingFlingBehavior.kt b/packages/SystemUI/compose/core/src/com/android/systemui/compose/layout/pager/SnappingFlingBehavior.kt
new file mode 100644
index 000000000000..0b53f5324a7d
--- /dev/null
+++ b/packages/SystemUI/compose/core/src/com/android/systemui/compose/layout/pager/SnappingFlingBehavior.kt
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2022 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.compose.layout.pager
+
+import androidx.compose.animation.core.AnimationSpec
+import androidx.compose.animation.core.AnimationState
+import androidx.compose.animation.core.DecayAnimationSpec
+import androidx.compose.animation.core.animateDecay
+import androidx.compose.animation.core.animateTo
+import androidx.compose.animation.core.calculateTargetValue
+import androidx.compose.animation.core.spring
+import androidx.compose.animation.rememberSplineBasedDecay
+import androidx.compose.foundation.gestures.FlingBehavior
+import androidx.compose.foundation.gestures.ScrollScope
+import androidx.compose.foundation.lazy.LazyListItemInfo
+import androidx.compose.foundation.lazy.LazyListState
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import kotlin.math.abs
+
+/** Default values used for [SnappingFlingBehavior] & [rememberSnappingFlingBehavior]. */
+internal object SnappingFlingBehaviorDefaults {
+ /** TODO */
+ val snapAnimationSpec: AnimationSpec<Float> = spring(stiffness = 600f)
+}
+
+/**
+ * Create and remember a snapping [FlingBehavior] to be used with [LazyListState].
+ *
+ * TODO: move this to a new module and make it public
+ *
+ * @param lazyListState The [LazyListState] to update.
+ * @param decayAnimationSpec The decay animation spec to use for decayed flings.
+ * @param snapAnimationSpec The animation spec to use when snapping.
+ */
+@Composable
+internal fun rememberSnappingFlingBehavior(
+ lazyListState: LazyListState,
+ decayAnimationSpec: DecayAnimationSpec<Float> = rememberSplineBasedDecay(),
+ snapAnimationSpec: AnimationSpec<Float> = SnappingFlingBehaviorDefaults.snapAnimationSpec,
+): SnappingFlingBehavior =
+ remember(lazyListState, decayAnimationSpec, snapAnimationSpec) {
+ SnappingFlingBehavior(
+ lazyListState = lazyListState,
+ decayAnimationSpec = decayAnimationSpec,
+ snapAnimationSpec = snapAnimationSpec,
+ )
+ }
+
+/**
+ * A snapping [FlingBehavior] for [LazyListState]. Typically this would be created via
+ * [rememberSnappingFlingBehavior].
+ *
+ * @param lazyListState The [LazyListState] to update.
+ * @param decayAnimationSpec The decay animation spec to use for decayed flings.
+ * @param snapAnimationSpec The animation spec to use when snapping.
+ */
+internal class SnappingFlingBehavior(
+ private val lazyListState: LazyListState,
+ private val decayAnimationSpec: DecayAnimationSpec<Float>,
+ private val snapAnimationSpec: AnimationSpec<Float>,
+) : FlingBehavior {
+ /** The target item index for any on-going animations. */
+ var animationTarget: Int? by mutableStateOf(null)
+ private set
+
+ override suspend fun ScrollScope.performFling(initialVelocity: Float): Float {
+ val itemInfo = currentItemInfo ?: return initialVelocity
+
+ // If the decay fling can scroll past the current item, fling with decay
+ return if (decayAnimationSpec.canFlingPastCurrentItem(itemInfo, initialVelocity)) {
+ performDecayFling(initialVelocity, itemInfo)
+ } else {
+ // Otherwise we 'spring' to current/next item
+ performSpringFling(
+ index =
+ when {
+ // If the velocity is greater than 1 item per second (velocity is px/s),
+ // spring
+ // in the relevant direction
+ initialVelocity > itemInfo.size -> {
+ (itemInfo.index + 1).coerceAtMost(
+ lazyListState.layoutInfo.totalItemsCount - 1
+ )
+ }
+ initialVelocity < -itemInfo.size -> itemInfo.index
+ // If the velocity is 0 (or less than the size of the item), spring to
+ // whichever item is closest to the snap point
+ itemInfo.offset < -itemInfo.size / 2 -> itemInfo.index + 1
+ else -> itemInfo.index
+ },
+ initialVelocity = initialVelocity,
+ )
+ }
+ }
+
+ private suspend fun ScrollScope.performDecayFling(
+ initialVelocity: Float,
+ startItem: LazyListItemInfo,
+ ): Float {
+ val index =
+ when {
+ initialVelocity > 0 -> startItem.index + 1
+ else -> startItem.index
+ }
+ val forward = index > (currentItemInfo?.index ?: return initialVelocity)
+
+ // Update the animationTarget
+ animationTarget = index
+
+ var velocityLeft = initialVelocity
+ var lastValue = 0f
+ AnimationState(
+ initialValue = 0f,
+ initialVelocity = initialVelocity,
+ )
+ .animateDecay(decayAnimationSpec) {
+ val delta = value - lastValue
+ val consumed = scrollBy(delta)
+ lastValue = value
+ velocityLeft = this.velocity
+
+ val current = currentItemInfo
+ if (current == null) {
+ cancelAnimation()
+ return@animateDecay
+ }
+
+ if (
+ !forward &&
+ (current.index < index || current.index == index && current.offset >= 0)
+ ) {
+ // 'snap back' to the item as we may have scrolled past it
+ scrollBy(lazyListState.calculateScrollOffsetToItem(index).toFloat())
+ cancelAnimation()
+ } else if (
+ forward &&
+ (current.index > index || current.index == index && current.offset <= 0)
+ ) {
+ // 'snap back' to the item as we may have scrolled past it
+ scrollBy(lazyListState.calculateScrollOffsetToItem(index).toFloat())
+ cancelAnimation()
+ } else if (abs(delta - consumed) > 0.5f) {
+ // avoid rounding errors and stop if anything is unconsumed
+ cancelAnimation()
+ }
+ }
+ animationTarget = null
+ return velocityLeft
+ }
+
+ private suspend fun ScrollScope.performSpringFling(
+ index: Int,
+ scrollOffset: Int = 0,
+ initialVelocity: Float = 0f,
+ ): Float {
+ // If we don't have a current layout, we can't snap
+ val initialItem = currentItemInfo ?: return initialVelocity
+
+ val forward = index > initialItem.index
+ // We add 10% on to the size of the current item, to compensate for any item spacing, etc
+ val target = (if (forward) initialItem.size else -initialItem.size) * 1.1f
+
+ // Update the animationTarget
+ animationTarget = index
+
+ var velocityLeft = initialVelocity
+ var lastValue = 0f
+ AnimationState(
+ initialValue = 0f,
+ initialVelocity = initialVelocity,
+ )
+ .animateTo(
+ targetValue = target,
+ animationSpec = snapAnimationSpec,
+ ) {
+ // Springs can overshoot their target, clamp to the desired range
+ val coercedValue =
+ if (forward) {
+ value.coerceAtMost(target)
+ } else {
+ value.coerceAtLeast(target)
+ }
+ val delta = coercedValue - lastValue
+ val consumed = scrollBy(delta)
+ lastValue = coercedValue
+ velocityLeft = this.velocity
+
+ val current = currentItemInfo
+ if (current == null) {
+ cancelAnimation()
+ return@animateTo
+ }
+
+ if (scrolledPastItem(initialVelocity, current, index, scrollOffset)) {
+ // If we've scrolled to/past the item, stop the animation. We may also need to
+ // 'snap back' to the item as we may have scrolled past it
+ scrollBy(lazyListState.calculateScrollOffsetToItem(index).toFloat())
+ cancelAnimation()
+ } else if (abs(delta - consumed) > 0.5f) {
+ // avoid rounding errors and stop if anything is unconsumed
+ cancelAnimation()
+ }
+ }
+ animationTarget = null
+ return velocityLeft
+ }
+
+ private fun LazyListState.calculateScrollOffsetToItem(index: Int): Int {
+ return layoutInfo.visibleItemsInfo.firstOrNull { it.index == index }?.offset ?: 0
+ }
+
+ private val currentItemInfo: LazyListItemInfo?
+ get() =
+ lazyListState.layoutInfo.visibleItemsInfo
+ .asSequence()
+ .filter { it.offset <= 0 && it.offset + it.size > 0 }
+ .lastOrNull()
+}
+
+private fun scrolledPastItem(
+ initialVelocity: Float,
+ currentItem: LazyListItemInfo,
+ targetIndex: Int,
+ targetScrollOffset: Int = 0,
+): Boolean {
+ return if (initialVelocity > 0) {
+ // forward
+ currentItem.index > targetIndex ||
+ (currentItem.index == targetIndex && currentItem.offset <= targetScrollOffset)
+ } else {
+ // backwards
+ currentItem.index < targetIndex ||
+ (currentItem.index == targetIndex && currentItem.offset >= targetScrollOffset)
+ }
+}
+
+private fun DecayAnimationSpec<Float>.canFlingPastCurrentItem(
+ currentItem: LazyListItemInfo,
+ initialVelocity: Float,
+): Boolean {
+ val targetValue =
+ calculateTargetValue(
+ initialValue = currentItem.offset.toFloat(),
+ initialVelocity = initialVelocity,
+ )
+ return when {
+ // forward. We add 10% onto the size to cater for any item spacing
+ initialVelocity > 0 -> targetValue <= -(currentItem.size * 1.1f)
+ // backwards. We add 10% onto the size to cater for any item spacing
+ else -> targetValue >= (currentItem.size * 0.1f)
+ }
+}
diff --git a/packages/SystemUI/compose/core/src/com/android/systemui/compose/modifiers/Padding.kt b/packages/SystemUI/compose/core/src/com/android/systemui/compose/modifiers/Padding.kt
new file mode 100644
index 000000000000..3b13c0b78cbe
--- /dev/null
+++ b/packages/SystemUI/compose/core/src/com/android/systemui/compose/modifiers/Padding.kt
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2022 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.compose.modifiers
+
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.LayoutModifier
+import androidx.compose.ui.layout.Measurable
+import androidx.compose.ui.layout.MeasureResult
+import androidx.compose.ui.layout.MeasureScope
+import androidx.compose.ui.platform.InspectorInfo
+import androidx.compose.ui.platform.InspectorValueInfo
+import androidx.compose.ui.platform.debugInspectorInfo
+import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.constrainHeight
+import androidx.compose.ui.unit.constrainWidth
+import androidx.compose.ui.unit.offset
+
+// This file was mostly copy/pasted from by androidx.compose.foundation.layout.Padding.kt and
+// contains modifiers with lambda parameters to change the padding of a Composable without
+// triggering recomposition when the paddings change.
+//
+// These should be used instead of the traditional size modifiers when the size changes often, for
+// instance when it is animated.
+//
+// TODO(b/247473910): Remove these modifiers once they can be fully replaced by layout animations
+// APIs.
+
+/** @see androidx.compose.foundation.layout.padding */
+fun Modifier.padding(
+ start: Density.() -> Int = PaddingUnspecified,
+ top: Density.() -> Int = PaddingUnspecified,
+ end: Density.() -> Int = PaddingUnspecified,
+ bottom: Density.() -> Int = PaddingUnspecified,
+) =
+ this.then(
+ PaddingModifier(
+ start,
+ top,
+ end,
+ bottom,
+ rtlAware = true,
+ inspectorInfo =
+ debugInspectorInfo {
+ name = "padding"
+ properties["start"] = start
+ properties["top"] = top
+ properties["end"] = end
+ properties["bottom"] = bottom
+ }
+ )
+ )
+
+/** @see androidx.compose.foundation.layout.padding */
+fun Modifier.padding(
+ horizontal: Density.() -> Int = PaddingUnspecified,
+ vertical: Density.() -> Int = PaddingUnspecified,
+): Modifier {
+ return this.then(
+ PaddingModifier(
+ start = horizontal,
+ top = vertical,
+ end = horizontal,
+ bottom = vertical,
+ rtlAware = true,
+ inspectorInfo =
+ debugInspectorInfo {
+ name = "padding"
+ properties["horizontal"] = horizontal
+ properties["vertical"] = vertical
+ }
+ )
+ )
+}
+
+private val PaddingUnspecified: Density.() -> Int = { 0 }
+
+private class PaddingModifier(
+ val start: Density.() -> Int,
+ val top: Density.() -> Int,
+ val end: Density.() -> Int,
+ val bottom: Density.() -> Int,
+ val rtlAware: Boolean,
+ inspectorInfo: InspectorInfo.() -> Unit
+) : LayoutModifier, InspectorValueInfo(inspectorInfo) {
+ override fun MeasureScope.measure(
+ measurable: Measurable,
+ constraints: Constraints
+ ): MeasureResult {
+ val start = start()
+ val top = top()
+ val end = end()
+ val bottom = bottom()
+
+ val horizontal = start + end
+ val vertical = top + bottom
+
+ val placeable = measurable.measure(constraints.offset(-horizontal, -vertical))
+
+ val width = constraints.constrainWidth(placeable.width + horizontal)
+ val height = constraints.constrainHeight(placeable.height + vertical)
+ return layout(width, height) {
+ if (rtlAware) {
+ placeable.placeRelative(start, top)
+ } else {
+ placeable.place(start, top)
+ }
+ }
+ }
+
+ override fun hashCode(): Int {
+ var result = start.hashCode()
+ result = 31 * result + top.hashCode()
+ result = 31 * result + end.hashCode()
+ result = 31 * result + bottom.hashCode()
+ result = 31 * result + rtlAware.hashCode()
+ return result
+ }
+
+ override fun equals(other: Any?): Boolean {
+ val otherModifier = other as? PaddingModifier ?: return false
+ return start == otherModifier.start &&
+ top == otherModifier.top &&
+ end == otherModifier.end &&
+ bottom == otherModifier.bottom &&
+ rtlAware == otherModifier.rtlAware
+ }
+}
diff --git a/packages/SystemUI/compose/core/src/com/android/systemui/compose/modifiers/Size.kt b/packages/SystemUI/compose/core/src/com/android/systemui/compose/modifiers/Size.kt
new file mode 100644
index 000000000000..570d24312c80
--- /dev/null
+++ b/packages/SystemUI/compose/core/src/com/android/systemui/compose/modifiers/Size.kt
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2022 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.compose.modifiers
+
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.IntrinsicMeasurable
+import androidx.compose.ui.layout.IntrinsicMeasureScope
+import androidx.compose.ui.layout.LayoutModifier
+import androidx.compose.ui.layout.Measurable
+import androidx.compose.ui.layout.MeasureResult
+import androidx.compose.ui.layout.MeasureScope
+import androidx.compose.ui.platform.InspectorInfo
+import androidx.compose.ui.platform.InspectorValueInfo
+import androidx.compose.ui.platform.debugInspectorInfo
+import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.constrain
+import androidx.compose.ui.unit.constrainHeight
+import androidx.compose.ui.unit.constrainWidth
+
+// This file was mostly copy pasted from androidx.compose.foundation.layout.Size.kt and contains
+// modifiers with lambda parameters to change the (min/max) size of a Composable without triggering
+// recomposition when the sizes change.
+//
+// These should be used instead of the traditional size modifiers when the size changes often, for
+// instance when it is animated.
+//
+// TODO(b/247473910): Remove these modifiers once they can be fully replaced by layout animations
+// APIs.
+
+/** @see androidx.compose.foundation.layout.width */
+fun Modifier.width(width: Density.() -> Int) =
+ this.then(
+ SizeModifier(
+ minWidth = width,
+ maxWidth = width,
+ enforceIncoming = true,
+ inspectorInfo =
+ debugInspectorInfo {
+ name = "width"
+ value = width
+ }
+ )
+ )
+
+/** @see androidx.compose.foundation.layout.height */
+fun Modifier.height(height: Density.() -> Int) =
+ this.then(
+ SizeModifier(
+ minHeight = height,
+ maxHeight = height,
+ enforceIncoming = true,
+ inspectorInfo =
+ debugInspectorInfo {
+ name = "height"
+ value = height
+ }
+ )
+ )
+
+/** @see androidx.compose.foundation.layout.size */
+fun Modifier.size(width: Density.() -> Int, height: Density.() -> Int) =
+ this.then(
+ SizeModifier(
+ minWidth = width,
+ maxWidth = width,
+ minHeight = height,
+ maxHeight = height,
+ enforceIncoming = true,
+ inspectorInfo =
+ debugInspectorInfo {
+ name = "size"
+ properties["width"] = width
+ properties["height"] = height
+ }
+ )
+ )
+
+private val SizeUnspecified: Density.() -> Int = { 0 }
+
+private class SizeModifier(
+ private val minWidth: Density.() -> Int = SizeUnspecified,
+ private val minHeight: Density.() -> Int = SizeUnspecified,
+ private val maxWidth: Density.() -> Int = SizeUnspecified,
+ private val maxHeight: Density.() -> Int = SizeUnspecified,
+ private val enforceIncoming: Boolean,
+ inspectorInfo: InspectorInfo.() -> Unit
+) : LayoutModifier, InspectorValueInfo(inspectorInfo) {
+ private val Density.targetConstraints: Constraints
+ get() {
+ val maxWidth =
+ if (maxWidth != SizeUnspecified) {
+ maxWidth().coerceAtLeast(0)
+ } else {
+ Constraints.Infinity
+ }
+ val maxHeight =
+ if (maxHeight != SizeUnspecified) {
+ maxHeight().coerceAtLeast(0)
+ } else {
+ Constraints.Infinity
+ }
+ val minWidth =
+ if (minWidth != SizeUnspecified) {
+ minWidth().coerceAtMost(maxWidth).coerceAtLeast(0).let {
+ if (it != Constraints.Infinity) it else 0
+ }
+ } else {
+ 0
+ }
+ val minHeight =
+ if (minHeight != SizeUnspecified) {
+ minHeight().coerceAtMost(maxHeight).coerceAtLeast(0).let {
+ if (it != Constraints.Infinity) it else 0
+ }
+ } else {
+ 0
+ }
+ return Constraints(
+ minWidth = minWidth,
+ minHeight = minHeight,
+ maxWidth = maxWidth,
+ maxHeight = maxHeight
+ )
+ }
+
+ override fun MeasureScope.measure(
+ measurable: Measurable,
+ constraints: Constraints
+ ): MeasureResult {
+ val wrappedConstraints =
+ targetConstraints.let { targetConstraints ->
+ if (enforceIncoming) {
+ constraints.constrain(targetConstraints)
+ } else {
+ val resolvedMinWidth =
+ if (minWidth != SizeUnspecified) {
+ targetConstraints.minWidth
+ } else {
+ constraints.minWidth.coerceAtMost(targetConstraints.maxWidth)
+ }
+ val resolvedMaxWidth =
+ if (maxWidth != SizeUnspecified) {
+ targetConstraints.maxWidth
+ } else {
+ constraints.maxWidth.coerceAtLeast(targetConstraints.minWidth)
+ }
+ val resolvedMinHeight =
+ if (minHeight != SizeUnspecified) {
+ targetConstraints.minHeight
+ } else {
+ constraints.minHeight.coerceAtMost(targetConstraints.maxHeight)
+ }
+ val resolvedMaxHeight =
+ if (maxHeight != SizeUnspecified) {
+ targetConstraints.maxHeight
+ } else {
+ constraints.maxHeight.coerceAtLeast(targetConstraints.minHeight)
+ }
+ Constraints(
+ resolvedMinWidth,
+ resolvedMaxWidth,
+ resolvedMinHeight,
+ resolvedMaxHeight
+ )
+ }
+ }
+ val placeable = measurable.measure(wrappedConstraints)
+ return layout(placeable.width, placeable.height) { placeable.placeRelative(0, 0) }
+ }
+
+ override fun IntrinsicMeasureScope.minIntrinsicWidth(
+ measurable: IntrinsicMeasurable,
+ height: Int
+ ): Int {
+ val constraints = targetConstraints
+ return if (constraints.hasFixedWidth) {
+ constraints.maxWidth
+ } else {
+ constraints.constrainWidth(measurable.minIntrinsicWidth(height))
+ }
+ }
+
+ override fun IntrinsicMeasureScope.minIntrinsicHeight(
+ measurable: IntrinsicMeasurable,
+ width: Int
+ ): Int {
+ val constraints = targetConstraints
+ return if (constraints.hasFixedHeight) {
+ constraints.maxHeight
+ } else {
+ constraints.constrainHeight(measurable.minIntrinsicHeight(width))
+ }
+ }
+
+ override fun IntrinsicMeasureScope.maxIntrinsicWidth(
+ measurable: IntrinsicMeasurable,
+ height: Int
+ ): Int {
+ val constraints = targetConstraints
+ return if (constraints.hasFixedWidth) {
+ constraints.maxWidth
+ } else {
+ constraints.constrainWidth(measurable.maxIntrinsicWidth(height))
+ }
+ }
+
+ override fun IntrinsicMeasureScope.maxIntrinsicHeight(
+ measurable: IntrinsicMeasurable,
+ width: Int
+ ): Int {
+ val constraints = targetConstraints
+ return if (constraints.hasFixedHeight) {
+ constraints.maxHeight
+ } else {
+ constraints.constrainHeight(measurable.maxIntrinsicHeight(width))
+ }
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (other !is SizeModifier) return false
+ return minWidth == other.minWidth &&
+ minHeight == other.minHeight &&
+ maxWidth == other.maxWidth &&
+ maxHeight == other.maxHeight &&
+ enforceIncoming == other.enforceIncoming
+ }
+
+ override fun hashCode() =
+ (((((minWidth.hashCode() * 31 + minHeight.hashCode()) * 31) + maxWidth.hashCode()) * 31) +
+ maxHeight.hashCode()) * 31
+}
diff --git a/packages/SystemUI/compose/gallery/Android.bp b/packages/SystemUI/compose/gallery/Android.bp
deleted file mode 100644
index 5a7a1e1807a3..000000000000
--- a/packages/SystemUI/compose/gallery/Android.bp
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright (C) 2022 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 {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
-}
-
-android_library {
- name: "SystemUIComposeGalleryLib",
- manifest: "AndroidManifest.xml",
-
- srcs: [
- "src/**/*.kt",
- ":SystemUI-tests-utils",
- ],
-
- resource_dirs: [
- "res",
- ],
-
- static_libs: [
- "SystemUI-core",
- "SystemUIComposeCore",
- "SystemUIComposeFeatures",
-
- "androidx.compose.runtime_runtime",
- "androidx.compose.material3_material3",
- "androidx.compose.material_material-icons-extended",
- "androidx.activity_activity-compose",
- "androidx.navigation_navigation-compose",
-
- "androidx.appcompat_appcompat",
-
- // TODO(b/240431193): Remove the dependencies and depend on
- // SystemUI-test-utils directly.
- "androidx.test.runner",
- "mockito-target-extended-minus-junit4",
- "testables",
- "truth-prebuilt",
- "androidx.test.uiautomator",
- "kotlinx_coroutines_test",
- ],
-
- libs: [
- "android.test.mock",
- ],
-
- kotlincflags: ["-Xjvm-default=all"],
-}
-
-android_app {
- name: "SystemUIComposeGallery",
- defaults: ["platform_app_defaults"],
- manifest: "app/AndroidManifest.xml",
-
- static_libs: [
- "SystemUIComposeGalleryLib",
- ],
-
- platform_apis: true,
- system_ext_specific: true,
- certificate: "platform",
- privileged: true,
-
- optimize: {
- proguard_flags_files: ["proguard-rules.pro"],
- },
-
- dxflags: ["--multi-dex"],
-}
diff --git a/packages/SystemUI/compose/gallery/AndroidManifest.xml b/packages/SystemUI/compose/gallery/AndroidManifest.xml
deleted file mode 100644
index 2f30651a6acf..000000000000
--- a/packages/SystemUI/compose/gallery/AndroidManifest.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2022 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- package="com.android.systemui.compose.gallery">
- <!-- To emulate a display size and density. -->
- <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
-
- <application
- android:name="android.app.Application"
- android:appComponentFactory="androidx.core.app.AppComponentFactory"
- tools:replace="android:name,android:appComponentFactory">
- <!-- Disable providers from SystemUI -->
- <provider android:name="com.android.systemui.keyguard.KeyguardSliceProvider"
- android:authorities="com.android.systemui.test.keyguard.disabled"
- android:enabled="false"
- tools:replace="android:authorities"
- tools:node="remove" />
- <provider android:name="com.google.android.systemui.keyguard.KeyguardSliceProviderGoogle"
- android:authorities="com.android.systemui.test.keyguard.disabled"
- android:enabled="false"
- tools:replace="android:authorities"
- tools:node="remove" />
- <provider android:name="com.android.keyguard.clock.ClockOptionsProvider"
- android:authorities="com.android.systemui.test.keyguard.clock.disabled"
- android:enabled="false"
- tools:replace="android:authorities"
- tools:node="remove" />
- <provider android:name="com.android.systemui.people.PeopleProvider"
- android:authorities="com.android.systemui.test.people.disabled"
- android:enabled="false"
- tools:replace="android:authorities"
- tools:node="remove" />
- <provider android:name="androidx.core.content.FileProvider"
- android:authorities="com.android.systemui.test.fileprovider.disabled"
- android:enabled="false"
- tools:replace="android:authorities"
- tools:node="remove"/>
- </application>
-</manifest>
diff --git a/packages/SystemUI/compose/gallery/TEST_MAPPING b/packages/SystemUI/compose/gallery/TEST_MAPPING
deleted file mode 100644
index c7f8a9216418..000000000000
--- a/packages/SystemUI/compose/gallery/TEST_MAPPING
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "presubmit": [
- {
- "name": "SystemUIComposeGalleryTests",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
- }
- ]
-} \ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/app/AndroidManifest.xml b/packages/SystemUI/compose/gallery/app/AndroidManifest.xml
deleted file mode 100644
index 1f3fd8c312d9..000000000000
--- a/packages/SystemUI/compose/gallery/app/AndroidManifest.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2022 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- package="com.android.systemui.compose.gallery.app">
- <application
- android:allowBackup="true"
- android:icon="@mipmap/ic_launcher"
- android:label="@string/app_name"
- android:roundIcon="@mipmap/ic_launcher_round"
- android:supportsRtl="true"
- android:theme="@style/Theme.SystemUI.Gallery"
- tools:replace="android:icon,android:theme,android:label">
- <activity
- android:name="com.android.systemui.compose.gallery.GalleryActivity"
- android:exported="true"
- android:label="@string/app_name">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/packages/SystemUI/compose/gallery/proguard-rules.pro b/packages/SystemUI/compose/gallery/proguard-rules.pro
deleted file mode 100644
index 481bb4348141..000000000000
--- a/packages/SystemUI/compose/gallery/proguard-rules.pro
+++ /dev/null
@@ -1,21 +0,0 @@
-# Add project specific ProGuard rules here.
-# You can control the set of applied configuration files using the
-# proguardFiles setting in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
-
-# Uncomment this to preserve the line number information for
-# debugging stack traces.
-#-keepattributes SourceFile,LineNumberTable
-
-# If you keep the line number information, uncomment this to
-# hide the original source file name.
-#-renamesourcefileattribute SourceFile \ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/res/drawable-v24/ic_launcher_foreground.xml b/packages/SystemUI/compose/gallery/res/drawable-v24/ic_launcher_foreground.xml
deleted file mode 100644
index 966abaff2074..000000000000
--- a/packages/SystemUI/compose/gallery/res/drawable-v24/ic_launcher_foreground.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:aapt="http://schemas.android.com/aapt"
- android:width="108dp"
- android:height="108dp"
- android:viewportHeight="108"
- android:viewportWidth="108">
- <path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
- <aapt:attr name="android:fillColor">
- <gradient
- android:endX="85.84757"
- android:endY="92.4963"
- android:startX="42.9492"
- android:startY="49.59793"
- android:type="linear">
- <item
- android:color="#44000000"
- android:offset="0.0" />
- <item
- android:color="#00000000"
- android:offset="1.0" />
- </gradient>
- </aapt:attr>
- </path>
- <path
- android:fillColor="#FFFFFF"
- android:fillType="nonZero"
- android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
- android:strokeColor="#00000000"
- android:strokeWidth="1" />
-</vector> \ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/res/drawable/ic_launcher_background.xml b/packages/SystemUI/compose/gallery/res/drawable/ic_launcher_background.xml
deleted file mode 100644
index 61bb79edb709..000000000000
--- a/packages/SystemUI/compose/gallery/res/drawable/ic_launcher_background.xml
+++ /dev/null
@@ -1,170 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="108dp"
- android:height="108dp"
- android:viewportHeight="108"
- android:viewportWidth="108">
- <path
- android:fillColor="#3DDC84"
- android:pathData="M0,0h108v108h-108z" />
- <path
- android:fillColor="#00000000"
- android:pathData="M9,0L9,108"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M19,0L19,108"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M29,0L29,108"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M39,0L39,108"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M49,0L49,108"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M59,0L59,108"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M69,0L69,108"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M79,0L79,108"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M89,0L89,108"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M99,0L99,108"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M0,9L108,9"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M0,19L108,19"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M0,29L108,29"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M0,39L108,39"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M0,49L108,49"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M0,59L108,59"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M0,69L108,69"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M0,79L108,79"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M0,89L108,89"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M0,99L108,99"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M19,29L89,29"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M19,39L89,39"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M19,49L89,49"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M19,59L89,59"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M19,69L89,69"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M19,79L89,79"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M29,19L29,89"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M39,19L39,89"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M49,19L49,89"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M59,19L59,89"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M69,19L69,89"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M79,19L79,89"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
-</vector>
diff --git a/packages/SystemUI/compose/gallery/res/drawable/kitten1.jpeg b/packages/SystemUI/compose/gallery/res/drawable/kitten1.jpeg
deleted file mode 100644
index 6241b0b44bb6..000000000000
--- a/packages/SystemUI/compose/gallery/res/drawable/kitten1.jpeg
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/drawable/kitten2.jpeg b/packages/SystemUI/compose/gallery/res/drawable/kitten2.jpeg
deleted file mode 100644
index 870ef13ee2d9..000000000000
--- a/packages/SystemUI/compose/gallery/res/drawable/kitten2.jpeg
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/drawable/kitten3.jpeg b/packages/SystemUI/compose/gallery/res/drawable/kitten3.jpeg
deleted file mode 100644
index bb7261c10033..000000000000
--- a/packages/SystemUI/compose/gallery/res/drawable/kitten3.jpeg
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/drawable/kitten4.jpeg b/packages/SystemUI/compose/gallery/res/drawable/kitten4.jpeg
deleted file mode 100644
index e34b7ddf58ce..000000000000
--- a/packages/SystemUI/compose/gallery/res/drawable/kitten4.jpeg
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/drawable/kitten5.jpeg b/packages/SystemUI/compose/gallery/res/drawable/kitten5.jpeg
deleted file mode 100644
index 9cde24be59ef..000000000000
--- a/packages/SystemUI/compose/gallery/res/drawable/kitten5.jpeg
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/drawable/kitten6.jpeg b/packages/SystemUI/compose/gallery/res/drawable/kitten6.jpeg
deleted file mode 100644
index 17825b639a26..000000000000
--- a/packages/SystemUI/compose/gallery/res/drawable/kitten6.jpeg
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-anydpi-v26/ic_launcher.xml b/packages/SystemUI/compose/gallery/res/mipmap-anydpi-v26/ic_launcher.xml
deleted file mode 100644
index 03eed2533da2..000000000000
--- a/packages/SystemUI/compose/gallery/res/mipmap-anydpi-v26/ic_launcher.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
- <background android:drawable="@drawable/ic_launcher_background" />
- <foreground android:drawable="@drawable/ic_launcher_foreground" />
-</adaptive-icon> \ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-anydpi-v26/ic_launcher_round.xml b/packages/SystemUI/compose/gallery/res/mipmap-anydpi-v26/ic_launcher_round.xml
deleted file mode 100644
index 03eed2533da2..000000000000
--- a/packages/SystemUI/compose/gallery/res/mipmap-anydpi-v26/ic_launcher_round.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
- <background android:drawable="@drawable/ic_launcher_background" />
- <foreground android:drawable="@drawable/ic_launcher_foreground" />
-</adaptive-icon> \ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-hdpi/ic_launcher.webp b/packages/SystemUI/compose/gallery/res/mipmap-hdpi/ic_launcher.webp
deleted file mode 100644
index c209e78ecd37..000000000000
--- a/packages/SystemUI/compose/gallery/res/mipmap-hdpi/ic_launcher.webp
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-hdpi/ic_launcher_round.webp b/packages/SystemUI/compose/gallery/res/mipmap-hdpi/ic_launcher_round.webp
deleted file mode 100644
index b2dfe3d1ba5c..000000000000
--- a/packages/SystemUI/compose/gallery/res/mipmap-hdpi/ic_launcher_round.webp
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-mdpi/ic_launcher.webp b/packages/SystemUI/compose/gallery/res/mipmap-mdpi/ic_launcher.webp
deleted file mode 100644
index 4f0f1d64e58b..000000000000
--- a/packages/SystemUI/compose/gallery/res/mipmap-mdpi/ic_launcher.webp
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-mdpi/ic_launcher_round.webp b/packages/SystemUI/compose/gallery/res/mipmap-mdpi/ic_launcher_round.webp
deleted file mode 100644
index 62b611da0816..000000000000
--- a/packages/SystemUI/compose/gallery/res/mipmap-mdpi/ic_launcher_round.webp
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-xhdpi/ic_launcher.webp b/packages/SystemUI/compose/gallery/res/mipmap-xhdpi/ic_launcher.webp
deleted file mode 100644
index 948a3070fe34..000000000000
--- a/packages/SystemUI/compose/gallery/res/mipmap-xhdpi/ic_launcher.webp
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-xhdpi/ic_launcher_round.webp b/packages/SystemUI/compose/gallery/res/mipmap-xhdpi/ic_launcher_round.webp
deleted file mode 100644
index 1b9a6956b3ac..000000000000
--- a/packages/SystemUI/compose/gallery/res/mipmap-xhdpi/ic_launcher_round.webp
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-xxhdpi/ic_launcher.webp b/packages/SystemUI/compose/gallery/res/mipmap-xxhdpi/ic_launcher.webp
deleted file mode 100644
index 28d4b77f9f03..000000000000
--- a/packages/SystemUI/compose/gallery/res/mipmap-xxhdpi/ic_launcher.webp
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-xxhdpi/ic_launcher_round.webp b/packages/SystemUI/compose/gallery/res/mipmap-xxhdpi/ic_launcher_round.webp
deleted file mode 100644
index 9287f5083623..000000000000
--- a/packages/SystemUI/compose/gallery/res/mipmap-xxhdpi/ic_launcher_round.webp
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-xxxhdpi/ic_launcher.webp b/packages/SystemUI/compose/gallery/res/mipmap-xxxhdpi/ic_launcher.webp
deleted file mode 100644
index aa7d6427e6fa..000000000000
--- a/packages/SystemUI/compose/gallery/res/mipmap-xxxhdpi/ic_launcher.webp
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-xxxhdpi/ic_launcher_round.webp b/packages/SystemUI/compose/gallery/res/mipmap-xxxhdpi/ic_launcher_round.webp
deleted file mode 100644
index 9126ae37cbc3..000000000000
--- a/packages/SystemUI/compose/gallery/res/mipmap-xxxhdpi/ic_launcher_round.webp
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/values/colors.xml b/packages/SystemUI/compose/gallery/res/values/colors.xml
deleted file mode 100644
index a2fcbffc26c0..000000000000
--- a/packages/SystemUI/compose/gallery/res/values/colors.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2022 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.
--->
-<resources>
- <color name="ic_launcher_background">#FFFFFF</color>
-</resources> \ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/res/values/strings.xml b/packages/SystemUI/compose/gallery/res/values/strings.xml
deleted file mode 100644
index 86bdb0568837..000000000000
--- a/packages/SystemUI/compose/gallery/res/values/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2022 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.
--->
-<resources>
- <!-- Application name [CHAR LIMIT=NONE] -->
- <string name="app_name">SystemUI Gallery</string>
-</resources> \ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/res/values/themes.xml b/packages/SystemUI/compose/gallery/res/values/themes.xml
deleted file mode 100644
index 45fa1f5dfb5c..000000000000
--- a/packages/SystemUI/compose/gallery/res/values/themes.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2022 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.
--->
-<resources xmlns:tools="http://schemas.android.com/tools">
- <style name="Theme.SystemUI.Gallery">
- <item name="android:windowActionBar">false</item>
- <item name="android:windowNoTitle">true</item>
-
- <item name="android:statusBarColor" tools:targetApi="l">
- @android:color/transparent
- </item>
- <item name="android:navigationBarColor" tools:targetApi="l">
- @android:color/transparent
- </item>
- <item name="android:windowLightStatusBar">true</item>
- </style>
-</resources>
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ButtonsScreen.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ButtonsScreen.kt
deleted file mode 100644
index 881a1def113a..000000000000
--- a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ButtonsScreen.kt
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2022 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.
- *
- */
-
-@file:OptIn(ExperimentalMaterial3Api::class)
-
-package com.android.systemui.compose.gallery
-
-import androidx.compose.foundation.layout.Column
-import androidx.compose.material3.ExperimentalMaterial3Api
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import com.android.systemui.compose.SysUiButton
-import com.android.systemui.compose.SysUiOutlinedButton
-import com.android.systemui.compose.SysUiTextButton
-
-@Composable
-fun ButtonsScreen(
- modifier: Modifier = Modifier,
-) {
- Column(
- modifier = modifier,
- ) {
- SysUiButton(
- onClick = {},
- ) {
- Text("SysUiButton")
- }
-
- SysUiButton(
- onClick = {},
- enabled = false,
- ) {
- Text("SysUiButton - disabled")
- }
-
- SysUiOutlinedButton(
- onClick = {},
- ) {
- Text("SysUiOutlinedButton")
- }
-
- SysUiOutlinedButton(
- onClick = {},
- enabled = false,
- ) {
- Text("SysUiOutlinedButton - disabled")
- }
-
- SysUiTextButton(
- onClick = {},
- ) {
- Text("SysUiTextButton")
- }
-
- SysUiTextButton(
- onClick = {},
- enabled = false,
- ) {
- Text("SysUiTextButton - disabled")
- }
- }
-}
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ColorsScreen.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ColorsScreen.kt
deleted file mode 100644
index dfa1b26f464e..000000000000
--- a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ColorsScreen.kt
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2022 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.compose.gallery
-
-import androidx.compose.foundation.background
-import androidx.compose.foundation.border
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.unit.dp
-import com.android.systemui.compose.theme.LocalAndroidColorScheme
-
-/** The screen that shows all the Material 3 colors. */
-@Composable
-fun MaterialColorsScreen() {
- val colors = MaterialTheme.colorScheme
- ColorsScreen(
- listOf(
- "primary" to colors.primary,
- "onPrimary" to colors.onPrimary,
- "primaryContainer" to colors.primaryContainer,
- "onPrimaryContainer" to colors.onPrimaryContainer,
- "inversePrimary" to colors.inversePrimary,
- "secondary" to colors.secondary,
- "onSecondary" to colors.onSecondary,
- "secondaryContainer" to colors.secondaryContainer,
- "onSecondaryContainer" to colors.onSecondaryContainer,
- "tertiary" to colors.tertiary,
- "onTertiary" to colors.onTertiary,
- "tertiaryContainer" to colors.tertiaryContainer,
- "onTertiaryContainer" to colors.onTertiaryContainer,
- "background" to colors.background,
- "onBackground" to colors.onBackground,
- "surface" to colors.surface,
- "onSurface" to colors.onSurface,
- "surfaceVariant" to colors.surfaceVariant,
- "onSurfaceVariant" to colors.onSurfaceVariant,
- "inverseSurface" to colors.inverseSurface,
- "inverseOnSurface" to colors.inverseOnSurface,
- "error" to colors.error,
- "onError" to colors.onError,
- "errorContainer" to colors.errorContainer,
- "onErrorContainer" to colors.onErrorContainer,
- "outline" to colors.outline,
- )
- )
-}
-
-/** The screen that shows all the Android colors. */
-@Composable
-fun AndroidColorsScreen() {
- val colors = LocalAndroidColorScheme.current
- ColorsScreen(
- listOf(
- "colorPrimary" to colors.colorPrimary,
- "colorPrimaryDark" to colors.colorPrimaryDark,
- "colorAccent" to colors.colorAccent,
- "colorAccentPrimary" to colors.colorAccentPrimary,
- "colorAccentSecondary" to colors.colorAccentSecondary,
- "colorAccentTertiary" to colors.colorAccentTertiary,
- "colorAccentPrimaryVariant" to colors.colorAccentPrimaryVariant,
- "colorAccentSecondaryVariant" to colors.colorAccentSecondaryVariant,
- "colorAccentTertiaryVariant" to colors.colorAccentTertiaryVariant,
- "colorSurface" to colors.colorSurface,
- "colorSurfaceHighlight" to colors.colorSurfaceHighlight,
- "colorSurfaceVariant" to colors.colorSurfaceVariant,
- "colorSurfaceHeader" to colors.colorSurfaceHeader,
- "colorError" to colors.colorError,
- "colorBackground" to colors.colorBackground,
- "colorBackgroundFloating" to colors.colorBackgroundFloating,
- "panelColorBackground" to colors.panelColorBackground,
- "textColorPrimary" to colors.textColorPrimary,
- "textColorSecondary" to colors.textColorSecondary,
- "textColorTertiary" to colors.textColorTertiary,
- "textColorPrimaryInverse" to colors.textColorPrimaryInverse,
- "textColorSecondaryInverse" to colors.textColorSecondaryInverse,
- "textColorTertiaryInverse" to colors.textColorTertiaryInverse,
- "textColorOnAccent" to colors.textColorOnAccent,
- "colorForeground" to colors.colorForeground,
- "colorForegroundInverse" to colors.colorForegroundInverse,
- )
- )
-}
-
-@Composable
-private fun ColorsScreen(
- colors: List<Pair<String, Color>>,
-) {
- LazyColumn(
- Modifier.fillMaxWidth(),
- ) {
- colors.forEach { (name, color) -> item { ColorTile(color, name) } }
- }
-}
-
-@Composable
-private fun ColorTile(
- color: Color,
- name: String,
-) {
- Row(
- Modifier.padding(16.dp),
- verticalAlignment = Alignment.CenterVertically,
- ) {
- val shape = RoundedCornerShape(16.dp)
- Spacer(
- Modifier.border(1.dp, MaterialTheme.colorScheme.onBackground, shape)
- .background(color, shape)
- .size(64.dp)
- )
- Spacer(Modifier.width(16.dp))
- Text(name)
- }
-}
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ConfigurationControls.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ConfigurationControls.kt
deleted file mode 100644
index 990d060207df..000000000000
--- a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ConfigurationControls.kt
+++ /dev/null
@@ -1,210 +0,0 @@
-package com.android.systemui.compose.gallery
-
-import android.graphics.Point
-import android.os.UserHandle
-import android.view.Display
-import android.view.WindowManagerGlobal
-import androidx.compose.foundation.layout.RowScope
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.lazy.LazyRow
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.DarkMode
-import androidx.compose.material.icons.filled.FormatSize
-import androidx.compose.material.icons.filled.FormatTextdirectionLToR
-import androidx.compose.material.icons.filled.FormatTextdirectionRToL
-import androidx.compose.material.icons.filled.InvertColors
-import androidx.compose.material.icons.filled.LightMode
-import androidx.compose.material.icons.filled.Smartphone
-import androidx.compose.material.icons.filled.Tablet
-import androidx.compose.material3.Button
-import androidx.compose.material3.ButtonDefaults
-import androidx.compose.material3.Icon
-import androidx.compose.material3.Text
-import androidx.compose.material3.TextButton
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.saveable.rememberSaveable
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.vector.ImageVector
-import androidx.compose.ui.unit.LayoutDirection
-import androidx.compose.ui.unit.dp
-import kotlin.math.max
-import kotlin.math.min
-
-enum class FontScale(val scale: Float) {
- Small(0.85f),
- Normal(1f),
- Big(1.15f),
- Bigger(1.30f),
-}
-
-/** A configuration panel that allows to toggle the theme, font scale and layout direction. */
-@Composable
-fun ConfigurationControls(
- theme: Theme,
- fontScale: FontScale,
- layoutDirection: LayoutDirection,
- onChangeTheme: () -> Unit,
- onChangeLayoutDirection: () -> Unit,
- onChangeFontScale: () -> Unit,
- modifier: Modifier = Modifier,
-) {
- // The display we are emulating, if any.
- var emulatedDisplayName by rememberSaveable { mutableStateOf<String?>(null) }
- val emulatedDisplay =
- emulatedDisplayName?.let { name -> EmulatedDisplays.firstOrNull { it.name == name } }
-
- LaunchedEffect(emulatedDisplay) {
- val wm = WindowManagerGlobal.getWindowManagerService()
-
- val defaultDisplayId = Display.DEFAULT_DISPLAY
- if (emulatedDisplay == null) {
- wm.clearForcedDisplayDensityForUser(defaultDisplayId, UserHandle.myUserId())
- wm.clearForcedDisplaySize(defaultDisplayId)
- } else {
- val density = emulatedDisplay.densityDpi
-
- // Emulate the display and make sure that we use the maximum available space possible.
- val initialSize = Point()
- wm.getInitialDisplaySize(defaultDisplayId, initialSize)
- val width = emulatedDisplay.width
- val height = emulatedDisplay.height
- val minOfSize = min(width, height)
- val maxOfSize = max(width, height)
- if (initialSize.x < initialSize.y) {
- wm.setForcedDisplaySize(defaultDisplayId, minOfSize, maxOfSize)
- } else {
- wm.setForcedDisplaySize(defaultDisplayId, maxOfSize, minOfSize)
- }
- wm.setForcedDisplayDensityForUser(defaultDisplayId, density, UserHandle.myUserId())
- }
- }
-
- // TODO(b/231131244): Fork FlowRow from Accompanist and use that instead to make sure that users
- // don't miss any available configuration.
- LazyRow(modifier) {
- // Dark/light theme.
- item {
- TextButton(onChangeTheme) {
- val text: String
- val icon: ImageVector
-
- when (theme) {
- Theme.System -> {
- icon = Icons.Default.InvertColors
- text = "System"
- }
- Theme.Dark -> {
- icon = Icons.Default.DarkMode
- text = "Dark"
- }
- Theme.Light -> {
- icon = Icons.Default.LightMode
- text = "Light"
- }
- }
-
- Icon(icon, null)
- Spacer(Modifier.width(8.dp))
- Text(text)
- }
- }
-
- // Font scale.
- item {
- TextButton(onChangeFontScale) {
- Icon(Icons.Default.FormatSize, null)
- Spacer(Modifier.width(8.dp))
-
- Text(fontScale.name)
- }
- }
-
- // Layout direction.
- item {
- TextButton(onChangeLayoutDirection) {
- when (layoutDirection) {
- LayoutDirection.Ltr -> {
- Icon(Icons.Default.FormatTextdirectionLToR, null)
- Spacer(Modifier.width(8.dp))
- Text("LTR")
- }
- LayoutDirection.Rtl -> {
- Icon(Icons.Default.FormatTextdirectionRToL, null)
- Spacer(Modifier.width(8.dp))
- Text("RTL")
- }
- }
- }
- }
-
- // Display emulation.
- EmulatedDisplays.forEach { display ->
- item {
- DisplayButton(
- display,
- emulatedDisplay == display,
- { emulatedDisplayName = it?.name },
- )
- }
- }
- }
-}
-
-@Composable
-private fun DisplayButton(
- display: EmulatedDisplay,
- selected: Boolean,
- onChangeEmulatedDisplay: (EmulatedDisplay?) -> Unit,
-) {
- val onClick = {
- if (selected) {
- onChangeEmulatedDisplay(null)
- } else {
- onChangeEmulatedDisplay(display)
- }
- }
-
- val content: @Composable RowScope.() -> Unit = {
- Icon(display.icon, null)
- Spacer(Modifier.width(8.dp))
- Text(display.name)
- }
-
- if (selected) {
- Button(onClick, contentPadding = ButtonDefaults.TextButtonContentPadding, content = content)
- } else {
- TextButton(onClick, content = content)
- }
-}
-
-/** The displays that can be emulated from this Gallery app. */
-private val EmulatedDisplays =
- listOf(
- EmulatedDisplay(
- "Phone",
- Icons.Default.Smartphone,
- width = 1440,
- height = 3120,
- densityDpi = 560,
- ),
- EmulatedDisplay(
- "Tablet",
- Icons.Default.Tablet,
- width = 2560,
- height = 1600,
- densityDpi = 320,
- ),
- )
-
-private data class EmulatedDisplay(
- val name: String,
- val icon: ImageVector,
- val width: Int,
- val height: Int,
- val densityDpi: Int,
-)
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ExampleFeatureScreen.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ExampleFeatureScreen.kt
deleted file mode 100644
index 6e1721490f98..000000000000
--- a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ExampleFeatureScreen.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2022 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.compose.gallery
-
-import androidx.compose.foundation.layout.Column
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import com.android.systemui.ExampleFeature
-
-/** The screen that shows ExampleFeature. */
-@Composable
-fun ExampleFeatureScreen(modifier: Modifier = Modifier) {
- Column(modifier) { ExampleFeature("This is an example feature!") }
-}
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryActivity.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryActivity.kt
deleted file mode 100644
index bb2d2feba39f..000000000000
--- a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryActivity.kt
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2022 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.compose.gallery
-
-import android.app.UiModeManager
-import android.content.Context
-import android.os.Bundle
-import androidx.activity.ComponentActivity
-import androidx.activity.compose.setContent
-import androidx.compose.foundation.isSystemInDarkTheme
-import androidx.compose.runtime.SideEffect
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.saveable.rememberSaveable
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.graphics.Color
-import androidx.core.view.WindowCompat
-import com.android.systemui.compose.rememberSystemUiController
-
-class GalleryActivity : ComponentActivity() {
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- WindowCompat.setDecorFitsSystemWindows(window, false)
- val uiModeManager = getSystemService(Context.UI_MODE_SERVICE) as UiModeManager
-
- setContent {
- var theme by rememberSaveable { mutableStateOf(Theme.System) }
- val onChangeTheme = {
- // Change to the next theme for a toggle behavior.
- theme =
- when (theme) {
- Theme.System -> Theme.Dark
- Theme.Dark -> Theme.Light
- Theme.Light -> Theme.System
- }
- }
-
- val isSystemInDarkTheme = isSystemInDarkTheme()
- val isDark = theme == Theme.Dark || (theme == Theme.System && isSystemInDarkTheme)
- val useDarkIcons = !isDark
- val systemUiController = rememberSystemUiController()
- SideEffect {
- systemUiController.setSystemBarsColor(
- color = Color.Transparent,
- darkIcons = useDarkIcons,
- )
-
- uiModeManager.setApplicationNightMode(
- when (theme) {
- Theme.System -> UiModeManager.MODE_NIGHT_AUTO
- Theme.Dark -> UiModeManager.MODE_NIGHT_YES
- Theme.Light -> UiModeManager.MODE_NIGHT_NO
- }
- )
- }
-
- GalleryApp(theme, onChangeTheme)
- }
- }
-}
-
-enum class Theme {
- System,
- Dark,
- Light,
-}
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt
deleted file mode 100644
index 6805bf83dff4..000000000000
--- a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt
+++ /dev/null
@@ -1,202 +0,0 @@
-package com.android.systemui.compose.gallery
-
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.systemBarsPadding
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Surface
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.saveable.rememberSaveable
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.platform.LocalDensity
-import androidx.compose.ui.platform.LocalLayoutDirection
-import androidx.compose.ui.unit.Density
-import androidx.compose.ui.unit.LayoutDirection
-import androidx.compose.ui.unit.dp
-import androidx.navigation.compose.NavHost
-import androidx.navigation.compose.rememberNavController
-import com.android.systemui.compose.theme.SystemUITheme
-
-/** The gallery app screens. */
-object GalleryAppScreens {
- private val Typography = ChildScreen("typography") { TypographyScreen() }
- private val MaterialColors = ChildScreen("material_colors") { MaterialColorsScreen() }
- private val AndroidColors = ChildScreen("android_colors") { AndroidColorsScreen() }
- private val Buttons = ChildScreen("buttons") { ButtonsScreen() }
- private val ExampleFeature = ChildScreen("example_feature") { ExampleFeatureScreen() }
-
- private val PeopleEmpty =
- ChildScreen("people_empty") { navController ->
- EmptyPeopleScreen(onResult = { navController.popBackStack() })
- }
- private val PeopleFew =
- ChildScreen("people_few") { navController ->
- FewPeopleScreen(onResult = { navController.popBackStack() })
- }
- private val PeopleFull =
- ChildScreen("people_full") { navController ->
- FullPeopleScreen(onResult = { navController.popBackStack() })
- }
- private val People =
- ParentScreen(
- "people",
- mapOf(
- "Empty" to PeopleEmpty,
- "Few" to PeopleFew,
- "Full" to PeopleFull,
- )
- )
- private val UserSwitcherSingleUser =
- ChildScreen("user_switcher_single") { navController ->
- UserSwitcherScreen(
- userCount = 1,
- onFinished = navController::popBackStack,
- )
- }
- private val UserSwitcherThreeUsers =
- ChildScreen("user_switcher_three") { navController ->
- UserSwitcherScreen(
- userCount = 3,
- onFinished = navController::popBackStack,
- )
- }
- private val UserSwitcherFourUsers =
- ChildScreen("user_switcher_four") { navController ->
- UserSwitcherScreen(
- userCount = 4,
- onFinished = navController::popBackStack,
- )
- }
- private val UserSwitcherFiveUsers =
- ChildScreen("user_switcher_five") { navController ->
- UserSwitcherScreen(
- userCount = 5,
- onFinished = navController::popBackStack,
- )
- }
- private val UserSwitcherSixUsers =
- ChildScreen("user_switcher_six") { navController ->
- UserSwitcherScreen(
- userCount = 6,
- onFinished = navController::popBackStack,
- )
- }
- private val UserSwitcher =
- ParentScreen(
- "user_switcher",
- mapOf(
- "Single" to UserSwitcherSingleUser,
- "Three" to UserSwitcherThreeUsers,
- "Four" to UserSwitcherFourUsers,
- "Five" to UserSwitcherFiveUsers,
- "Six" to UserSwitcherSixUsers,
- )
- )
-
- val Home =
- ParentScreen(
- "home",
- mapOf(
- "Typography" to Typography,
- "Material colors" to MaterialColors,
- "Android colors" to AndroidColors,
- "Example feature" to ExampleFeature,
- "Buttons" to Buttons,
- "People" to People,
- "User Switcher" to UserSwitcher,
- )
- )
-}
-
-/** The main content of the app, that shows [GalleryAppScreens.Home] by default. */
-@Composable
-private fun MainContent(onControlToggleRequested: () -> Unit) {
- Box(Modifier.fillMaxSize()) {
- val navController = rememberNavController()
- NavHost(
- navController = navController,
- startDestination = GalleryAppScreens.Home.identifier,
- ) {
- screen(GalleryAppScreens.Home, navController, onControlToggleRequested)
- }
- }
-}
-
-/**
- * The top-level composable shown when starting the app. This composable always shows a
- * [ConfigurationControls] at the top of the screen, above the [MainContent].
- */
-@Composable
-fun GalleryApp(
- theme: Theme,
- onChangeTheme: () -> Unit,
-) {
- val systemFontScale = LocalDensity.current.fontScale
- var fontScale: FontScale by rememberSaveable {
- mutableStateOf(
- FontScale.values().firstOrNull { it.scale == systemFontScale } ?: FontScale.Normal
- )
- }
- val context = LocalContext.current
- val density = Density(context.resources.displayMetrics.density, fontScale.scale)
- val onChangeFontScale = {
- fontScale =
- when (fontScale) {
- FontScale.Small -> FontScale.Normal
- FontScale.Normal -> FontScale.Big
- FontScale.Big -> FontScale.Bigger
- FontScale.Bigger -> FontScale.Small
- }
- }
-
- val systemLayoutDirection = LocalLayoutDirection.current
- var layoutDirection by rememberSaveable { mutableStateOf(systemLayoutDirection) }
- val onChangeLayoutDirection = {
- layoutDirection =
- when (layoutDirection) {
- LayoutDirection.Ltr -> LayoutDirection.Rtl
- LayoutDirection.Rtl -> LayoutDirection.Ltr
- }
- }
-
- CompositionLocalProvider(
- LocalDensity provides density,
- LocalLayoutDirection provides layoutDirection,
- ) {
- SystemUITheme {
- Surface(
- Modifier.fillMaxSize(),
- color = MaterialTheme.colorScheme.background,
- ) {
- Column(Modifier.fillMaxSize().systemBarsPadding()) {
- var showControls by rememberSaveable { mutableStateOf(true) }
-
- if (showControls) {
- ConfigurationControls(
- theme,
- fontScale,
- layoutDirection,
- onChangeTheme,
- onChangeLayoutDirection,
- onChangeFontScale,
- Modifier.padding(horizontal = 16.dp),
- )
-
- Spacer(Modifier.height(4.dp))
- }
-
- MainContent(onControlToggleRequested = { showControls = !showControls })
- }
- }
- }
- }
-}
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/PeopleScreen.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/PeopleScreen.kt
deleted file mode 100644
index 2f0df7790ffd..000000000000
--- a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/PeopleScreen.kt
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2022 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.compose.gallery
-
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.platform.LocalContext
-import com.android.systemui.people.emptyPeopleSpaceViewModel
-import com.android.systemui.people.fewPeopleSpaceViewModel
-import com.android.systemui.people.fullPeopleSpaceViewModel
-import com.android.systemui.people.ui.compose.PeopleScreen
-import com.android.systemui.people.ui.viewmodel.PeopleViewModel
-
-@Composable
-fun EmptyPeopleScreen(onResult: (PeopleViewModel.Result) -> Unit) {
- val context = LocalContext.current.applicationContext
- val viewModel = emptyPeopleSpaceViewModel(context)
- PeopleScreen(viewModel, onResult)
-}
-
-@Composable
-fun FewPeopleScreen(onResult: (PeopleViewModel.Result) -> Unit) {
- val context = LocalContext.current.applicationContext
- val viewModel = fewPeopleSpaceViewModel(context)
- PeopleScreen(viewModel, onResult)
-}
-
-@Composable
-fun FullPeopleScreen(onResult: (PeopleViewModel.Result) -> Unit) {
- val context = LocalContext.current.applicationContext
- val viewModel = fullPeopleSpaceViewModel(context)
- PeopleScreen(viewModel, onResult)
-}
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/Screen.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/Screen.kt
deleted file mode 100644
index d7d0d721b01c..000000000000
--- a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/Screen.kt
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2022 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.compose.gallery
-
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Surface
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.unit.dp
-import androidx.navigation.NavController
-import androidx.navigation.NavGraphBuilder
-import androidx.navigation.compose.composable
-import androidx.navigation.compose.navigation
-
-/**
- * A screen in an app. It is either an [ParentScreen] which lists its child screens to navigate to
- * them or a [ChildScreen] which shows some content.
- */
-sealed class Screen(val identifier: String)
-
-class ParentScreen(
- identifier: String,
- val children: Map<String, Screen>,
-) : Screen(identifier)
-
-class ChildScreen(
- identifier: String,
- val content: @Composable (NavController) -> Unit,
-) : Screen(identifier)
-
-/** Create the navigation graph for [screen]. */
-fun NavGraphBuilder.screen(
- screen: Screen,
- navController: NavController,
- onControlToggleRequested: () -> Unit,
-) {
- when (screen) {
- is ChildScreen -> composable(screen.identifier) { screen.content(navController) }
- is ParentScreen -> {
- val menuRoute = "${screen.identifier}_menu"
- navigation(startDestination = menuRoute, route = screen.identifier) {
- // The menu to navigate to one of the children screens.
- composable(menuRoute) {
- ScreenMenu(screen, navController, onControlToggleRequested)
- }
-
- // The content of the child screens.
- screen.children.forEach { (_, child) ->
- screen(
- child,
- navController,
- onControlToggleRequested,
- )
- }
- }
- }
- }
-}
-
-@Composable
-private fun ScreenMenu(
- screen: ParentScreen,
- navController: NavController,
- onControlToggleRequested: () -> Unit,
-) {
- LazyColumn(
- Modifier.padding(horizontal = 16.dp),
- verticalArrangement = Arrangement.spacedBy(8.dp),
- ) {
- item {
- Surface(
- Modifier.fillMaxWidth(),
- color = MaterialTheme.colorScheme.tertiaryContainer,
- shape = CircleShape,
- ) {
- Column(
- Modifier.clickable(onClick = onControlToggleRequested).padding(16.dp),
- horizontalAlignment = Alignment.CenterHorizontally,
- ) {
- Text("Toggle controls")
- }
- }
- }
-
- screen.children.forEach { (name, child) ->
- item {
- Surface(
- Modifier.fillMaxWidth(),
- color = MaterialTheme.colorScheme.secondaryContainer,
- shape = CircleShape,
- ) {
- Column(
- Modifier.clickable { navController.navigate(child.identifier) }
- .padding(16.dp),
- horizontalAlignment = Alignment.CenterHorizontally,
- ) {
- Text(name)
- }
- }
- }
- }
- }
-}
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/TypographyScreen.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/TypographyScreen.kt
deleted file mode 100644
index 147025ed1d60..000000000000
--- a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/TypographyScreen.kt
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2022 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.compose.gallery
-
-import androidx.compose.foundation.horizontalScroll
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.rememberScrollState
-import androidx.compose.foundation.verticalScroll
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.text.TextStyle
-import androidx.compose.ui.text.style.TextOverflow
-
-/** The screen that shows the Material text styles. */
-@Composable
-fun TypographyScreen() {
- val typography = MaterialTheme.typography
-
- Column(
- Modifier.fillMaxSize()
- .horizontalScroll(rememberScrollState())
- .verticalScroll(rememberScrollState()),
- ) {
- FontLine("displayLarge", typography.displayLarge)
- FontLine("displayMedium", typography.displayMedium)
- FontLine("displaySmall", typography.displaySmall)
- FontLine("headlineLarge", typography.headlineLarge)
- FontLine("headlineMedium", typography.headlineMedium)
- FontLine("headlineSmall", typography.headlineSmall)
- FontLine("titleLarge", typography.titleLarge)
- FontLine("titleMedium", typography.titleMedium)
- FontLine("titleSmall", typography.titleSmall)
- FontLine("bodyLarge", typography.bodyLarge)
- FontLine("bodyMedium", typography.bodyMedium)
- FontLine("bodySmall", typography.bodySmall)
- FontLine("labelLarge", typography.labelLarge)
- FontLine("labelMedium", typography.labelMedium)
- FontLine("labelSmall", typography.labelSmall)
- }
-}
-
-@Composable
-private fun FontLine(name: String, style: TextStyle) {
- Text(
- "$name (${style.fontSize}/${style.lineHeight}, W${style.fontWeight?.weight})",
- style = style,
- maxLines = 1,
- overflow = TextOverflow.Visible,
- )
-}
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/UserSwitcherScreen.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/UserSwitcherScreen.kt
deleted file mode 100644
index fe9707d22684..000000000000
--- a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/UserSwitcherScreen.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2022 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.compose.gallery
-
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.platform.LocalContext
-import com.android.systemui.user.Fakes.fakeUserSwitcherViewModel
-import com.android.systemui.user.ui.compose.UserSwitcherScreen
-
-@Composable
-fun UserSwitcherScreen(
- userCount: Int,
- onFinished: () -> Unit,
-) {
- val context = LocalContext.current.applicationContext
- UserSwitcherScreen(
- viewModel = fakeUserSwitcherViewModel(context, userCount = userCount),
- onFinished = onFinished,
- )
-}
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/people/Fakes.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/people/Fakes.kt
deleted file mode 100644
index 0966c3233ad5..000000000000
--- a/packages/SystemUI/compose/gallery/src/com/android/systemui/people/Fakes.kt
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2022 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.people
-
-import android.content.Context
-import android.graphics.Bitmap
-import android.graphics.Canvas
-import android.graphics.Color
-import android.graphics.Paint
-import android.graphics.drawable.Icon
-import androidx.core.graphics.drawable.toIcon
-import com.android.systemui.R
-import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.people.data.model.PeopleTileModel
-import com.android.systemui.people.ui.viewmodel.PeopleViewModel
-import com.android.systemui.people.widget.PeopleTileKey
-
-/** A [PeopleViewModel] that does not have any conversations. */
-fun emptyPeopleSpaceViewModel(@Application context: Context): PeopleViewModel {
- return fakePeopleSpaceViewModel(context, emptyList(), emptyList())
-}
-
-/** A [PeopleViewModel] that has a few conversations. */
-fun fewPeopleSpaceViewModel(@Application context: Context): PeopleViewModel {
- return fakePeopleSpaceViewModel(
- context,
- priorityTiles =
- listOf(
- fakeTile(context, id = "0", Color.RED, "Priority"),
- fakeTile(context, id = "1", Color.BLUE, "Priority NewStory", hasNewStory = true),
- ),
- recentTiles =
- listOf(
- fakeTile(context, id = "2", Color.GREEN, "Recent Important", isImportant = true),
- fakeTile(context, id = "3", Color.CYAN, "Recent DndBlocking", isDndBlocking = true),
- ),
- )
-}
-
-/** A [PeopleViewModel] that has a lot of conversations. */
-fun fullPeopleSpaceViewModel(@Application context: Context): PeopleViewModel {
- return fakePeopleSpaceViewModel(
- context,
- priorityTiles =
- listOf(
- fakeTile(context, id = "0", Color.RED, "Priority"),
- fakeTile(context, id = "1", Color.BLUE, "Priority NewStory", hasNewStory = true),
- fakeTile(context, id = "2", Color.GREEN, "Priority Important", isImportant = true),
- fakeTile(
- context,
- id = "3",
- Color.CYAN,
- "Priority DndBlocking",
- isDndBlocking = true,
- ),
- fakeTile(
- context,
- id = "4",
- Color.MAGENTA,
- "Priority NewStory Important",
- hasNewStory = true,
- isImportant = true,
- ),
- ),
- recentTiles =
- listOf(
- fakeTile(
- context,
- id = "5",
- Color.RED,
- "Recent NewStory DndBlocking",
- hasNewStory = true,
- isDndBlocking = true,
- ),
- fakeTile(
- context,
- id = "6",
- Color.BLUE,
- "Recent Important DndBlocking",
- isImportant = true,
- isDndBlocking = true,
- ),
- fakeTile(
- context,
- id = "7",
- Color.GREEN,
- "Recent NewStory Important DndBlocking",
- hasNewStory = true,
- isImportant = true,
- isDndBlocking = true,
- ),
- fakeTile(context, id = "8", Color.CYAN, "Recent"),
- fakeTile(context, id = "9", Color.MAGENTA, "Recent"),
- ),
- )
-}
-
-private fun fakePeopleSpaceViewModel(
- @Application context: Context,
- priorityTiles: List<PeopleTileModel>,
- recentTiles: List<PeopleTileModel>,
-): PeopleViewModel {
- return PeopleViewModel(
- context,
- FakePeopleTileRepository(priorityTiles, recentTiles),
- FakePeopleWidgetRepository(),
- )
-}
-
-private fun fakeTile(
- @Application context: Context,
- id: String,
- iconColor: Int,
- username: String,
- hasNewStory: Boolean = false,
- isImportant: Boolean = false,
- isDndBlocking: Boolean = false
-): PeopleTileModel {
- return PeopleTileModel(
- PeopleTileKey(id, /* userId= */ 0, /* packageName */ ""),
- username,
- fakeUserIcon(context, iconColor),
- hasNewStory,
- isImportant,
- isDndBlocking,
- )
-}
-
-private fun fakeUserIcon(@Application context: Context, color: Int): Icon {
- val size = context.resources.getDimensionPixelSize(R.dimen.avatar_size_for_medium)
- val bitmap =
- Bitmap.createBitmap(
- size,
- size,
- Bitmap.Config.ARGB_8888,
- )
- val canvas = Canvas(bitmap)
- val paint = Paint().apply { this.color = color }
- val radius = size / 2f
- canvas.drawCircle(/* cx= */ radius, /* cy= */ radius, /* radius= */ radius, paint)
- return bitmap.toIcon()
-}
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/qs/footer/Fakes.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/qs/footer/Fakes.kt
deleted file mode 100644
index 6588e22721fb..000000000000
--- a/packages/SystemUI/compose/gallery/src/com/android/systemui/qs/footer/Fakes.kt
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2022 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.qs.footer
-
-import android.content.Context
-import android.os.UserHandle
-import android.view.View
-import com.android.internal.util.UserIcons
-import com.android.systemui.R
-import com.android.systemui.animation.Expandable
-import com.android.systemui.classifier.FalsingManagerFake
-import com.android.systemui.common.shared.model.Icon
-import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.globalactions.GlobalActionsDialogLite
-import com.android.systemui.qs.footer.data.model.UserSwitcherStatusModel
-import com.android.systemui.qs.footer.domain.interactor.FooterActionsInteractor
-import com.android.systemui.qs.footer.domain.model.SecurityButtonConfig
-import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
-import com.android.systemui.util.mockito.mock
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.flowOf
-
-/** A list of fake [FooterActionsViewModel] to be used in screenshot tests and the gallery. */
-fun fakeFooterActionsViewModels(
- @Application context: Context,
-): List<FooterActionsViewModel> {
- return listOf(
- fakeFooterActionsViewModel(context),
- fakeFooterActionsViewModel(context, showPowerButton = false, isGuestUser = true),
- fakeFooterActionsViewModel(context, showUserSwitcher = false),
- fakeFooterActionsViewModel(context, showUserSwitcher = false, foregroundServices = 4),
- fakeFooterActionsViewModel(
- context,
- foregroundServices = 4,
- hasNewForegroundServices = true,
- userId = 1,
- ),
- fakeFooterActionsViewModel(
- context,
- securityText = "Security",
- foregroundServices = 4,
- showUserSwitcher = false,
- ),
- fakeFooterActionsViewModel(
- context,
- securityText = "Security (not clickable)",
- securityClickable = false,
- foregroundServices = 4,
- hasNewForegroundServices = true,
- userId = 2,
- ),
- )
-}
-
-private fun fakeFooterActionsViewModel(
- @Application context: Context,
- securityText: String? = null,
- securityClickable: Boolean = true,
- foregroundServices: Int = 0,
- hasNewForegroundServices: Boolean = false,
- showUserSwitcher: Boolean = true,
- showPowerButton: Boolean = true,
- userId: Int = UserHandle.USER_OWNER,
- isGuestUser: Boolean = false,
-): FooterActionsViewModel {
- val interactor =
- FakeFooterActionsInteractor(
- securityButtonConfig =
- flowOf(
- securityText?.let { text ->
- SecurityButtonConfig(
- icon =
- Icon.Resource(
- R.drawable.ic_info_outline,
- contentDescription = null,
- ),
- text = text,
- isClickable = securityClickable,
- )
- }
- ),
- foregroundServicesCount = flowOf(foregroundServices),
- hasNewForegroundServices = flowOf(hasNewForegroundServices),
- userSwitcherStatus =
- flowOf(
- if (showUserSwitcher) {
- UserSwitcherStatusModel.Enabled(
- currentUserName = "foo",
- currentUserImage =
- UserIcons.getDefaultUserIcon(
- context.resources,
- userId,
- /* light= */ false,
- ),
- isGuestUser = isGuestUser,
- )
- } else {
- UserSwitcherStatusModel.Disabled
- }
- ),
- deviceMonitoringDialogRequests = flowOf(),
- )
-
- return FooterActionsViewModel(
- context,
- interactor,
- FalsingManagerFake(),
- globalActionsDialogLite = mock(),
- showPowerButton = showPowerButton,
- )
-}
-
-private class FakeFooterActionsInteractor(
- override val securityButtonConfig: Flow<SecurityButtonConfig?> = flowOf(null),
- override val foregroundServicesCount: Flow<Int> = flowOf(0),
- override val hasNewForegroundServices: Flow<Boolean> = flowOf(false),
- override val userSwitcherStatus: Flow<UserSwitcherStatusModel> =
- flowOf(UserSwitcherStatusModel.Disabled),
- override val deviceMonitoringDialogRequests: Flow<Unit> = flowOf(),
- private val onShowDeviceMonitoringDialogFromView: (View) -> Unit = {},
- private val onShowDeviceMonitoringDialog: (Context) -> Unit = {},
- private val onShowForegroundServicesDialog: (View) -> Unit = {},
- private val onShowPowerMenuDialog: (GlobalActionsDialogLite, View) -> Unit = { _, _ -> },
- private val onShowSettings: (Expandable) -> Unit = {},
- private val onShowUserSwitcher: (View) -> Unit = {},
-) : FooterActionsInteractor {
- override fun showDeviceMonitoringDialog(view: View) {
- onShowDeviceMonitoringDialogFromView(view)
- }
-
- override fun showDeviceMonitoringDialog(quickSettingsContext: Context) {
- onShowDeviceMonitoringDialog(quickSettingsContext)
- }
-
- override fun showForegroundServicesDialog(view: View) {
- onShowForegroundServicesDialog(view)
- }
-
- override fun showPowerMenuDialog(globalActionsDialogLite: GlobalActionsDialogLite, view: View) {
- onShowPowerMenuDialog(globalActionsDialogLite, view)
- }
-
- override fun showSettings(expandable: Expandable) {
- onShowSettings(expandable)
- }
-
- override fun showUserSwitcher(view: View) {
- onShowUserSwitcher(view)
- }
-}
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/user/Fakes.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/user/Fakes.kt
deleted file mode 100644
index 91a73ea16dc4..000000000000
--- a/packages/SystemUI/compose/gallery/src/com/android/systemui/user/Fakes.kt
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2022 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.user
-
-import android.content.Context
-import androidx.appcompat.content.res.AppCompatResources
-import com.android.systemui.common.shared.model.Text
-import com.android.systemui.compose.gallery.R
-import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
-import com.android.systemui.power.data.repository.FakePowerRepository
-import com.android.systemui.power.domain.interactor.PowerInteractor
-import com.android.systemui.user.data.repository.FakeUserRepository
-import com.android.systemui.user.domain.interactor.UserInteractor
-import com.android.systemui.user.shared.model.UserActionModel
-import com.android.systemui.user.shared.model.UserModel
-import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel
-import com.android.systemui.util.mockito.mock
-
-object Fakes {
- private val USER_TINT_COLORS =
- arrayOf(
- 0x000000,
- 0x0000ff,
- 0x00ff00,
- 0x00ffff,
- 0xff0000,
- 0xff00ff,
- 0xffff00,
- 0xffffff,
- )
-
- fun fakeUserSwitcherViewModel(
- context: Context,
- userCount: Int,
- ): UserSwitcherViewModel {
- return UserSwitcherViewModel.Factory(
- userInteractor =
- UserInteractor(
- repository =
- FakeUserRepository().apply {
- setUsers(
- (0 until userCount).map { index ->
- UserModel(
- id = index,
- name =
- Text.Loaded(
- when (index % 6) {
- 0 -> "Ross Geller"
- 1 -> "Phoebe Buffay"
- 2 -> "Monica Geller"
- 3 -> "Rachel Greene"
- 4 -> "Chandler Bing"
- else -> "Joey Tribbiani"
- }
- ),
- image =
- checkNotNull(
- AppCompatResources.getDrawable(
- context,
- when (index % 6) {
- 0 -> R.drawable.kitten1
- 1 -> R.drawable.kitten2
- 2 -> R.drawable.kitten3
- 3 -> R.drawable.kitten4
- 4 -> R.drawable.kitten5
- else -> R.drawable.kitten6
- },
- )
- ),
- isSelected = index == 0,
- isSelectable = true,
- )
- }
- )
- setActions(
- UserActionModel.values().mapNotNull {
- if (it == UserActionModel.NAVIGATE_TO_USER_MANAGEMENT) {
- null
- } else {
- it
- }
- }
- )
- },
- controller = mock(),
- activityStarter = mock(),
- keyguardInteractor =
- KeyguardInteractor(
- repository =
- FakeKeyguardRepository().apply { setKeyguardShowing(false) },
- ),
- ),
- powerInteractor =
- PowerInteractor(
- repository = FakePowerRepository(),
- )
- )
- .create(UserSwitcherViewModel::class.java)
- }
-}
diff --git a/packages/SystemUI/compose/gallery/tests/Android.bp b/packages/SystemUI/compose/gallery/tests/Android.bp
deleted file mode 100644
index 3e01f7d2c431..000000000000
--- a/packages/SystemUI/compose/gallery/tests/Android.bp
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (C) 2022 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 {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
-}
-
-android_test {
- name: "SystemUIComposeGalleryTests",
- manifest: "AndroidManifest.xml",
- test_suites: ["device-tests"],
- sdk_version: "current",
- certificate: "platform",
-
- srcs: [
- "src/**/*.kt",
- ],
-
- static_libs: [
- "SystemUIComposeGalleryLib",
-
- "androidx.test.runner",
- "androidx.test.ext.junit",
-
- "androidx.compose.runtime_runtime",
- "androidx.compose.ui_ui-test-junit4",
- "androidx.compose.ui_ui-test-manifest",
- ],
-
- kotlincflags: ["-Xjvm-default=enable"],
-}
diff --git a/packages/SystemUI/compose/gallery/tests/AndroidManifest.xml b/packages/SystemUI/compose/gallery/tests/AndroidManifest.xml
deleted file mode 100644
index 5eeb3ad24e5a..000000000000
--- a/packages/SystemUI/compose/gallery/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.systemui.compose.gallery.tests" >
-
- <application>
- <uses-library android:name="android.test.runner" />
- </application>
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.systemui.compose.gallery.tests"
- android:label="Tests for SystemUIComposeGallery"/>
-
-</manifest> \ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/tests/src/com/android/systemui/compose/gallery/ScreenshotsTests.kt b/packages/SystemUI/compose/gallery/tests/src/com/android/systemui/compose/gallery/ScreenshotsTests.kt
deleted file mode 100644
index 66ecc8d4fde5..000000000000
--- a/packages/SystemUI/compose/gallery/tests/src/com/android/systemui/compose/gallery/ScreenshotsTests.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2022 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.compose.gallery
-
-import androidx.compose.ui.test.junit4.createComposeRule
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.android.systemui.compose.theme.SystemUITheme
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-class ScreenshotsTests {
- @get:Rule val composeRule = createComposeRule()
-
- @Test
- fun exampleFeatureScreenshotTest() {
- // TODO(b/230832101): Wire this with the screenshot diff testing infra. We should reuse the
- // configuration of the features in the gallery app to populate the UIs.
- composeRule.setContent { SystemUITheme { ExampleFeatureScreen() } }
- }
-}