summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt38
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaContentPicker.kt1
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToSplitShadeTransition.kt7
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToShadeTransition.kt10
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeMediaOffsetProvider.kt79
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt49
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSImpl.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanel.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt13
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/adapter/FakeQSSceneAdapter.kt2
12 files changed, 227 insertions, 31 deletions
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt
index 26ab10b459d8..85d5d6a41965 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt
@@ -24,9 +24,11 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.approachLayout
import androidx.compose.ui.layout.layout
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.dimensionResource
+import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.viewinterop.AndroidView
import com.android.compose.animation.scene.MovableElementKey
import com.android.compose.animation.scene.SceneScope
@@ -51,6 +53,7 @@ fun SceneScope.MediaCarousel(
mediaHost: MediaHost,
modifier: Modifier = Modifier,
carouselController: MediaCarouselController,
+ offsetProvider: (() -> IntOffset)? = null,
) {
if (!isVisible) {
return
@@ -68,21 +71,38 @@ fun SceneScope.MediaCarousel(
MovableElement(
key = MediaCarousel.Elements.Content,
- modifier = modifier.height(mediaHeight).fillMaxWidth()
+ modifier = modifier.height(mediaHeight).fillMaxWidth(),
) {
content {
AndroidView(
modifier =
- Modifier.fillMaxSize().layout { measurable, constraints ->
- val placeable = measurable.measure(constraints)
+ Modifier.fillMaxSize()
+ .approachLayout(
+ isMeasurementApproachInProgress = { offsetProvider != null },
+ approachMeasure = { measurable, constraints ->
+ val placeable = measurable.measure(constraints)
+ layout(placeable.width, placeable.height) {
+ placeable.placeRelative(
+ offsetProvider?.invoke() ?: IntOffset.Zero
+ )
+ }
+ }
+ )
+ .layout { measurable, constraints ->
+ val placeable = measurable.measure(constraints)
- // Notify controller to size the carousel for the current space
- mediaHost.measurementInput =
- MeasurementInput(placeable.width, placeable.height)
- carouselController.setSceneContainerSize(placeable.width, placeable.height)
+ // Notify controller to size the carousel for the current space
+ mediaHost.measurementInput =
+ MeasurementInput(placeable.width, placeable.height)
+ carouselController.setSceneContainerSize(
+ placeable.width,
+ placeable.height
+ )
- layout(placeable.width, placeable.height) { placeable.placeRelative(0, 0) }
- },
+ layout(placeable.width, placeable.height) {
+ placeable.placeRelative(0, 0)
+ }
+ },
factory = { context ->
FrameLayout(context).apply {
layoutParams =
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaContentPicker.kt b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaContentPicker.kt
index 3f04f3728bef..70c0db1582c4 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaContentPicker.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaContentPicker.kt
@@ -27,7 +27,6 @@ import com.android.systemui.scene.shared.model.Scenes
/** [ElementContentPicker] implementation for the media carousel object. */
object MediaContentPicker : StaticElementContentPicker {
- const val SHADE_FRACTION = 0.66f
override val contents =
setOf(
Scenes.Lockscreen,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToSplitShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToSplitShadeTransition.kt
index a9da733116fc..71fa6c9e567a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToSplitShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToSplitShadeTransition.kt
@@ -25,7 +25,6 @@ import com.android.compose.animation.scene.TransitionBuilder
import com.android.compose.animation.scene.UserActionDistance
import com.android.compose.animation.scene.UserActionDistanceScope
import com.android.systemui.media.controls.ui.composable.MediaCarousel
-import com.android.systemui.media.controls.ui.composable.MediaContentPicker
import com.android.systemui.notifications.ui.composable.Notifications
import com.android.systemui.qs.ui.composable.QuickSettings
import com.android.systemui.shade.ui.composable.Shade
@@ -54,13 +53,7 @@ fun TransitionBuilder.goneToSplitShadeTransition(
fractionRange(end = .33f) { fade(Shade.Elements.BackgroundScrim) }
fractionRange(start = .33f) {
- val qsTranslation =
- ShadeHeader.Dimensions.CollapsedHeight * MediaContentPicker.SHADE_FRACTION
- val qsExpansionDiff =
- ShadeHeader.Dimensions.ExpandedHeight - ShadeHeader.Dimensions.CollapsedHeight
- translate(MediaCarousel.Elements.Content, y = -(qsExpansionDiff + qsTranslation))
fade(MediaCarousel.Elements.Content)
-
fade(ShadeHeader.Elements.Clock)
fade(ShadeHeader.Elements.CollapsedContentStart)
fade(ShadeHeader.Elements.CollapsedContentEnd)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToShadeTransition.kt
index 21dfc49cbe7b..b677dff2dcf9 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToShadeTransition.kt
@@ -26,7 +26,6 @@ import com.android.compose.animation.scene.TransitionBuilder
import com.android.compose.animation.scene.UserActionDistance
import com.android.compose.animation.scene.UserActionDistanceScope
import com.android.systemui.media.controls.ui.composable.MediaCarousel
-import com.android.systemui.media.controls.ui.composable.MediaContentPicker
import com.android.systemui.notifications.ui.composable.Notifications
import com.android.systemui.qs.ui.composable.QuickSettings
import com.android.systemui.scene.shared.model.Scenes
@@ -62,12 +61,9 @@ fun TransitionBuilder.toShadeTransition(
fade(QuickSettings.Elements.FooterActions)
}
- val qsTranslation = ShadeHeader.Dimensions.CollapsedHeight * MediaContentPicker.SHADE_FRACTION
- val qsExpansionDiff =
- ShadeHeader.Dimensions.ExpandedHeight - ShadeHeader.Dimensions.CollapsedHeight
-
- translate(QuickSettings.Elements.QuickQuickSettings, y = -qsTranslation)
- translate(MediaCarousel.Elements.Content, y = -(qsExpansionDiff + qsTranslation))
+ val qsTranslation = -ShadeHeader.Dimensions.CollapsedHeight * 0.66f
+ translate(QuickSettings.Elements.QuickQuickSettings, y = qsTranslation)
+ translate(MediaCarousel.Elements.Content, y = qsTranslation)
translate(Notifications.Elements.NotificationScrim, Edge.Top, false)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeMediaOffsetProvider.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeMediaOffsetProvider.kt
new file mode 100644
index 000000000000..e0b7909dcaa3
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeMediaOffsetProvider.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shade.ui.composable
+
+import androidx.compose.ui.unit.IntOffset
+import com.android.systemui.qs.ui.adapter.QSSceneAdapter
+
+/**
+ * Provider for the extra offset for the Media section in the shade to accommodate for the squishing
+ * qs or qqs tiles.
+ */
+interface ShadeMediaOffsetProvider {
+
+ /** Returns current offset to be applied to the Media Carousel */
+ val offset: IntOffset
+
+ /**
+ * [ShadeMediaOffsetProvider] implementation for Quick Settings.
+ *
+ * [updateLayout] should represent an access to some state to trigger Compose to relayout to
+ * track [QSSceneAdapter] internal state changes during the transition.
+ */
+ class Qs(private val updateLayout: () -> Unit, private val qsSceneAdapter: QSSceneAdapter) :
+ ShadeMediaOffsetProvider {
+
+ override val offset: IntOffset
+ get() =
+ calculateQsOffset(
+ updateLayout,
+ qsSceneAdapter.qsHeight,
+ qsSceneAdapter.squishedQsHeight
+ )
+ }
+
+ /**
+ * [ShadeMediaOffsetProvider] implementation for Quick Quick Settings.
+ *
+ * [updateLayout] should represent an access to some state to trigger Compose to relayout to
+ * track [QSSceneAdapter] internal state changes during the transition.
+ */
+ class Qqs(private val updateLayout: () -> Unit, private val qsSceneAdapter: QSSceneAdapter) :
+ ShadeMediaOffsetProvider {
+
+ override val offset: IntOffset
+ get() =
+ calculateQsOffset(
+ updateLayout,
+ qsSceneAdapter.qqsHeight,
+ qsSceneAdapter.squishedQqsHeight
+ )
+ }
+
+ companion object {
+
+ protected fun calculateQsOffset(
+ updateLayout: () -> Unit,
+ qsHeight: Int,
+ qsSquishedHeight: Int
+ ): IntOffset {
+ updateLayout()
+ val distanceFromBottomToActualBottom = qsHeight - qsSquishedHeight
+ return IntOffset(0, -distanceFromBottomToActualBottom)
+ }
+ }
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
index 0e3fcf4598af..16972bc95e57 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
@@ -118,7 +118,6 @@ import kotlinx.coroutines.flow.Flow
object Shade {
object Elements {
- val MediaCarousel = ElementKey("ShadeMediaCarousel")
val BackgroundScrim =
ElementKey("ShadeBackgroundScrim", contentPicker = LowestZIndexContentPicker)
val SplitShadeStartColumn = ElementKey("SplitShadeStartColumn")
@@ -283,6 +282,13 @@ private fun SceneScope.SingleShade(
val navBarHeight = WindowInsets.systemBars.asPaddingValues().calculateBottomPadding()
+ val mediaOffsetProvider = remember {
+ ShadeMediaOffsetProvider.Qqs(
+ { @Suppress("UNUSED_EXPRESSION") tileSquishiness },
+ viewModel.qsSceneAdapter,
+ )
+ }
+
Box(
modifier =
modifier.thenIf(shouldPunchHoleBehindScrim) {
@@ -335,12 +341,12 @@ private fun SceneScope.SingleShade(
)
}
- MediaCarousel(
+ ShadeMediaCarousel(
isVisible = isMediaVisible,
mediaHost = mediaHost,
+ mediaOffsetProvider = mediaOffsetProvider,
modifier =
- Modifier.fillMaxWidth()
- .layoutId(QSMediaMeasurePolicy.LayoutId.Media),
+ Modifier.layoutId(QSMediaMeasurePolicy.LayoutId.Media),
carouselController = mediaCarouselController,
)
}
@@ -497,6 +503,13 @@ private fun SceneScope.SplitShade(
val brightnessMirrorShowingModifier = Modifier.graphicsLayer { alpha = contentAlpha }
+ val mediaOffsetProvider = remember {
+ ShadeMediaOffsetProvider.Qs(
+ { @Suppress("UNUSED_EXPRESSION") tileSquishiness },
+ viewModel.qsSceneAdapter,
+ )
+ }
+
Box {
Box(
modifier =
@@ -570,11 +583,13 @@ private fun SceneScope.SplitShade(
squishiness = { tileSquishiness },
)
}
- MediaCarousel(
+
+ ShadeMediaCarousel(
isVisible = isMediaVisible,
mediaHost = mediaHost,
+ mediaOffsetProvider = mediaOffsetProvider,
modifier =
- Modifier.fillMaxWidth().thenIf(
+ Modifier.thenIf(
MediaContentPicker.shouldElevateMedia(layoutState)
) {
Modifier.zIndex(1f)
@@ -620,3 +635,25 @@ private fun SceneScope.SplitShade(
)
}
}
+
+@Composable
+private fun SceneScope.ShadeMediaCarousel(
+ isVisible: Boolean,
+ mediaHost: MediaHost,
+ carouselController: MediaCarouselController,
+ mediaOffsetProvider: ShadeMediaOffsetProvider,
+ modifier: Modifier = Modifier,
+) {
+ MediaCarousel(
+ modifier = modifier.fillMaxWidth(),
+ isVisible = isVisible,
+ mediaHost = mediaHost,
+ carouselController = carouselController,
+ offsetProvider =
+ if (MediaContentPicker.shouldElevateMedia(layoutState)) {
+ null
+ } else {
+ { mediaOffsetProvider.offset }
+ }
+ )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index 9939075b77d2..1511f31a3f92 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -259,6 +259,13 @@ public class QSContainerImpl extends FrameLayout implements Dumpable {
}
/**
+ * @return height with the squishiness fraction applied.
+ */
+ int getSquishedQqsHeight() {
+ return mHeader.getSquishedHeight();
+ }
+
+ /**
* Returns the size of QS (or the QSCustomizer), regardless of the measured size of this view
* @return size in pixels of QS (or QSCustomizer)
*/
@@ -267,6 +274,13 @@ public class QSContainerImpl extends FrameLayout implements Dumpable {
: mQSPanel.getMeasuredHeight();
}
+ /**
+ * @return height with the squishiness fraction applied.
+ */
+ int getSquishedQsHeight() {
+ return mQSPanel.getSquishedHeight();
+ }
+
public void setExpansion(float expansion) {
mQsExpansion = expansion;
if (mQSPanelContainer != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java
index a6fd35a9ee37..0b37b5b7be3d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java
@@ -992,11 +992,25 @@ public class QSImpl implements QS, CommandQueue.Callbacks, StatusBarStateControl
return mContainer.getQqsHeight();
}
+ /**
+ * @return height with the squishiness fraction applied.
+ */
+ public int getSquishedQqsHeight() {
+ return mContainer.getSquishedQqsHeight();
+ }
+
public int getQSHeight() {
return mContainer.getQsHeight();
}
/**
+ * @return height with the squishiness fraction applied.
+ */
+ public int getSquishedQsHeight() {
+ return mContainer.getSquishedQsHeight();
+ }
+
+ /**
* Pass the size of the navbar when it's at the bottom of the device so it can be used as
* padding
* @param padding size of the bottom nav bar in px
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 032891fa715e..d3bed27ab2ab 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -733,6 +733,30 @@ public class QSPanel extends LinearLayout implements Tunable {
mCanCollapse = canCollapse;
}
+ /**
+ * @return height with the {@link QSPanel#setSquishinessFraction(float)} applied.
+ */
+ public int getSquishedHeight() {
+ if (mFooter != null) {
+ final ViewGroup.LayoutParams footerLayoutParams = mFooter.getLayoutParams();
+ final int footerBottomMargin;
+ if (footerLayoutParams instanceof MarginLayoutParams) {
+ footerBottomMargin = ((MarginLayoutParams) footerLayoutParams).bottomMargin;
+ } else {
+ footerBottomMargin = 0;
+ }
+ // This is the distance between the top of the QSPanel and the last view in the
+ // layout (which is the effective the bottom)
+ return mFooter.getBottom() + footerBottomMargin - getTop();
+ }
+ if (mTileLayout != null) {
+ // Footer absence means that the panel is in the QQS. In this case it's just height
+ // of the tiles + paddings.
+ return mTileLayout.getTilesHeight() + getPaddingBottom() + getPaddingTop();
+ }
+ return getHeight();
+ }
+
@Nullable
@VisibleForTesting
View getMediaPlaceholder() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 5a3f1c0b7426..8fde52c910da 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -123,4 +123,11 @@ public class QuickStatusBarHeader extends FrameLayout {
lp.setMarginEnd(marginEnd);
view.setLayoutParams(lp);
}
+
+ /**
+ * @return height with the squishiness fraction applied.
+ */
+ public int getSquishedHeight() {
+ return mHeaderQsPanel.getSquishedHeight();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt
index ae2f32aae874..dfcf21628c3b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt
@@ -34,7 +34,6 @@ import com.android.systemui.plugins.qs.QSContainerController
import com.android.systemui.qs.QSContainerImpl
import com.android.systemui.qs.QSImpl
import com.android.systemui.qs.dagger.QSSceneComponent
-import com.android.systemui.qs.tiles.viewmodel.StubQSTileViewModel.state
import com.android.systemui.res.R
import com.android.systemui.settings.brightness.MirrorController
import com.android.systemui.shade.domain.interactor.ShadeInteractor
@@ -126,12 +125,18 @@ interface QSSceneAdapter {
/** The current height of QQS in the current [qsView], or 0 if there's no view. */
val qqsHeight: Int
+ /** @return height with the squishiness fraction applied. */
+ val squishedQqsHeight: Int
+
/**
* The current height of QS in the current [qsView], or 0 if there's no view. If customizing, it
* will return the height allocated to the customizer.
*/
val qsHeight: Int
+ /** @return height with the squishiness fraction applied. */
+ val squishedQsHeight: Int
+
/** Compatibility for use by LockscreenShadeTransitionController. Matches default from [QS] */
val isQsFullyCollapsed: Boolean
get() = true
@@ -273,9 +278,15 @@ constructor(
override val qqsHeight: Int
get() = qsImpl.value?.qqsHeight ?: 0
+ override val squishedQqsHeight: Int
+ get() = qsImpl.value?.squishedQqsHeight ?: 0
+
override val qsHeight: Int
get() = qsImpl.value?.qsHeight ?: 0
+ override val squishedQsHeight: Int
+ get() = qsImpl.value?.squishedQsHeight ?: 0
+
// If value is null, there's no QS and therefore it's fully collapsed.
override val isQsFullyCollapsed: Boolean
get() = qsImpl.value?.isFullyCollapsed ?: true
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/adapter/FakeQSSceneAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/adapter/FakeQSSceneAdapter.kt
index b6194e3f511d..bbe753e8c7a5 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/adapter/FakeQSSceneAdapter.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/adapter/FakeQSSceneAdapter.kt
@@ -27,7 +27,9 @@ import kotlinx.coroutines.flow.filterNotNull
class FakeQSSceneAdapter(
private val inflateDelegate: suspend (Context) -> View,
override val qqsHeight: Int = 0,
+ override val squishedQqsHeight: Int = 0,
override val qsHeight: Int = 0,
+ override val squishedQsHeight: Int = 0,
) : QSSceneAdapter {
private val _customizerState = MutableStateFlow<CustomizerState>(CustomizerState.Hidden)