Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b68135e6 authored by Fabian Kozynski's avatar Fabian Kozynski Committed by Android (Google) Code Review
Browse files

Merge "Add extra animation params for media" into main

parents e6a2f840 ec23101e
Loading
Loading
Loading
Loading
+108 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.systemui.qs.composefragment.viewmodel

import android.app.StatusBarManager
import android.content.testableContext
import android.graphics.Rect
import android.testing.TestableLooper.RunWithLooper
import androidx.compose.runtime.snapshots.Snapshot
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -43,6 +44,7 @@ import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
import com.android.systemui.statusbar.sysuiStatusBarStateController
import com.android.systemui.util.animation.DisappearParameters
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
@@ -375,6 +377,92 @@ class QSFragmentComposeViewModelTest : AbstractQSFragmentComposeViewModelTest()
            }
        }

    @Test
    fun applyQsScrollPositionForClipping() =
        with(kosmos) {
            testScope.testWithinLifecycle {
                val left = 1f
                val top = 3f
                val right = 5f
                val bottom = 7f

                underTest.applyNewQsScrollerBounds(left, top, right, bottom)

                assertThat(qsMediaHost.currentClipping)
                    .isEqualTo(Rect(left.toInt(), top.toInt(), right.toInt(), bottom.toInt()))
            }
        }

    @Test
    fun shouldUpdateMediaSquishiness_inSplitShadeFalse_mediaSquishinessSet() =
        with(kosmos) {
            testScope.testWithinLifecycle {
                underTest.isInSplitShade = false
                underTest.squishinessFraction = 0.3f

                underTest.shouldUpdateSquishinessOnMedia = true
                Snapshot.sendApplyNotifications()
                runCurrent()

                assertThat(underTest.qsMediaHost.squishFraction).isWithin(0.01f).of(0.3f)

                underTest.shouldUpdateSquishinessOnMedia = false
                Snapshot.sendApplyNotifications()
                runCurrent()
                assertThat(underTest.qsMediaHost.squishFraction).isWithin(0.01f).of(1f)
            }
        }

    @Test
    fun inSplitShade_differentStatusBarState_mediaSquishinessSet() =
        with(kosmos) {
            testScope.testWithinLifecycle {
                underTest.isInSplitShade = true
                underTest.squishinessFraction = 0.3f

                sysuiStatusBarStateController.setState(StatusBarState.SHADE)
                Snapshot.sendApplyNotifications()
                runCurrent()
                assertThat(underTest.qsMediaHost.squishFraction).isWithin(epsilon).of(0.3f)

                sysuiStatusBarStateController.setState(StatusBarState.KEYGUARD)
                runCurrent()
                Snapshot.sendApplyNotifications()
                runCurrent()
                assertThat(underTest.qsMediaHost.squishFraction).isWithin(epsilon).of(1f)

                sysuiStatusBarStateController.setState(StatusBarState.SHADE_LOCKED)
                runCurrent()
                Snapshot.sendApplyNotifications()
                runCurrent()
                assertThat(underTest.qsMediaHost.squishFraction).isWithin(epsilon).of(1f)
            }
        }

    @Test
    fun disappearParams() =
        with(kosmos) {
            testScope.testWithinLifecycle {
                setMediaState(ACTIVE_MEDIA)

                setConfigurationForMediaInRow(false)
                Snapshot.sendApplyNotifications()
                runCurrent()

                assertThat(underTest.qqsMediaHost.disappearParameters)
                    .isEqualTo(disappearParamsColumn)
                assertThat(underTest.qsMediaHost.disappearParameters)
                    .isEqualTo(disappearParamsColumn)

                setConfigurationForMediaInRow(true)
                Snapshot.sendApplyNotifications()
                runCurrent()

                assertThat(underTest.qqsMediaHost.disappearParameters).isEqualTo(disappearParamsRow)
                assertThat(underTest.qsMediaHost.disappearParameters).isEqualTo(disappearParamsRow)
            }
        }

    private fun TestScope.setMediaState(state: MediaState) {
        with(kosmos) {
            val activeMedia = state == ACTIVE_MEDIA
@@ -404,6 +492,26 @@ class QSFragmentComposeViewModelTest : AbstractQSFragmentComposeViewModelTest()
        }

        private const val epsilon = 0.001f

        private val disappearParamsColumn =
            DisappearParameters().apply {
                fadeStartPosition = 0.95f
                disappearStart = 0f
                disappearEnd = 0.95f
                disappearSize.set(1f, 0f)
                gonePivot.set(0f, 0f)
                contentTranslationFraction.set(0f, 1f)
            }

        private val disappearParamsRow =
            DisappearParameters().apply {
                fadeStartPosition = 0.95f
                disappearStart = 0f
                disappearEnd = 0.6f
                disappearSize.set(0f, 0.4f)
                gonePivot.set(1f, 0f)
                contentTranslationFraction.set(0.25f, 1f)
            }
    }
}

+27 −5
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@ import androidx.compose.ui.layout.approachLayout
import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.layout.positionInRoot
import androidx.compose.ui.layout.positionOnScreen
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.stringResource
@@ -124,6 +125,7 @@ import com.android.systemui.qs.ui.composable.QuickSettingsShade
import com.android.systemui.qs.ui.composable.QuickSettingsTheme
import com.android.systemui.res.R
import com.android.systemui.util.LifecycleFragment
import com.android.systemui.util.animation.UniqueObjectHostView
import com.android.systemui.util.asIndenting
import com.android.systemui.util.printSection
import com.android.systemui.util.println
@@ -447,8 +449,7 @@ constructor(
    }

    override fun setShouldUpdateSquishinessOnMedia(shouldUpdate: Boolean) {
        super.setShouldUpdateSquishinessOnMedia(shouldUpdate)
        // TODO (b/353253280)
        viewModel.shouldUpdateSquishinessOnMedia = shouldUpdate
    }

    override fun setInSplitShade(isInSplitShade: Boolean) {
@@ -660,7 +661,20 @@ constructor(

                    Column(
                        modifier =
                            Modifier.offset {
                            Modifier.onPlaced { coordinates ->
                                    val positionOnScreen = coordinates.positionOnScreen()
                                    val left = positionOnScreen.x
                                    val right = left + coordinates.size.width
                                    val top = positionOnScreen.y
                                    val bottom = top + coordinates.size.height
                                    viewModel.applyNewQsScrollerBounds(
                                        left = left,
                                        top = top,
                                        right = right,
                                        bottom = bottom,
                                    )
                                }
                                .offset {
                                    IntOffset(
                                        x = 0,
                                        y = viewModel.qsScrollTranslationY.fastRoundToInt(),
@@ -704,7 +718,10 @@ constructor(
                        val Media =
                            @Composable {
                                if (viewModel.qsMediaVisible) {
                                    MediaObject(mediaHost = viewModel.qsMediaHost)
                                    MediaObject(
                                        mediaHost = viewModel.qsMediaHost,
                                        update = { translationY = viewModel.qsMediaTranslationY },
                                    )
                                }
                            }
                        Box(
@@ -987,7 +1004,11 @@ private fun Modifier.gesturesDisabled(disabled: Boolean) =
    }

@Composable
private fun MediaObject(mediaHost: MediaHost, modifier: Modifier = Modifier) {
private fun MediaObject(
    mediaHost: MediaHost,
    modifier: Modifier = Modifier,
    update: UniqueObjectHostView.() -> Unit = {},
) {
    Box {
        AndroidView(
            modifier = modifier,
@@ -1000,6 +1021,7 @@ private fun MediaObject(mediaHost: MediaHost, modifier: Modifier = Modifier) {
                        )
                }
            },
            update = { view -> view.update() },
            onReset = {},
        )
    }
+83 −3
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.lifecycle.LifecycleCoroutineScope
import com.android.app.animation.Interpolators
import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.keyguard.BouncerPanelExpansionCalculator
import com.android.systemui.Dumpable
@@ -270,6 +271,23 @@ constructor(
    val qsMediaInRow: Boolean
        get() = qsMediaInRowViewModel.shouldMediaShowInRow

    var shouldUpdateSquishinessOnMedia by mutableStateOf(false)

    val qsMediaTranslationY by derivedStateOf {
        if (
            qsExpansion > 0f &&
                !isKeyguardState &&
                !qqsMediaVisible &&
                !qsMediaInRow &&
                !isInSplitShade
        ) {
            val interpolation = Interpolators.ACCELERATE.getInterpolation(1f - qsExpansion)
            -qsMediaHost.hostView.height * 1.3f * interpolation
        } else {
            0f
        }
    }

    val animateTilesExpansion: Boolean
        get() = inFirstPage && !mediaSuddenlyAppearingInLandscape

@@ -297,6 +315,18 @@ constructor(
                MediaHostState.EXPANDED
            }

    private val shouldApplySquishinessToMedia by derivedStateOf {
        shouldUpdateSquishinessOnMedia || (isInSplitShade && statusBarState == StatusBarState.SHADE)
    }

    private val mediaSquishiness by derivedStateOf {
        if (shouldApplySquishinessToMedia) {
            squishinessFraction
        } else {
            1f
        }
    }

    private var qsBounds by mutableStateOf(Rect())

    private val constrainedSquishinessFraction: Float
@@ -355,8 +385,6 @@ constructor(
    private val isOverscrolling: Boolean
        get() = overScrollAmount != 0

    private var shouldUpdateMediaSquishiness by mutableStateOf(false)

    private val forceQs by derivedStateOf {
        (isQsExpanded || isStackScrollerOverscrolling) &&
            (isKeyguardState && !showCollapsedOnKeyguard)
@@ -394,11 +422,26 @@ constructor(
                ),
        )

    fun applyNewQsScrollerBounds(left: Float, top: Float, right: Float, bottom: Float) {
        if (usingMedia) {
            qsMediaHost.currentClipping.set(
                left.toInt(),
                top.toInt(),
                right.toInt(),
                bottom.toInt(),
            )
        }
    }

    override suspend fun onActivated(): Nothing {
        initMediaHosts() // init regardless of using media (same as current QS).
        coroutineScope {
            launch { hydrateSquishinessInteractor() }
            if (usingMedia) {
                launch { hydrateQqsMediaExpansion() }
                launch { hydrateMediaSquishiness() }
                launch { hydrateMediaDisappearParameters() }
            }
            launch { hydrator.activate() }
            launch { containerViewModel.activate() }
            launch { qqsMediaInRowViewModel.activate() }
@@ -429,6 +472,21 @@ constructor(
        snapshotFlow { qqsMediaExpansion }.collect { qqsMediaHost.expansion = it }
    }

    private suspend fun hydrateMediaSquishiness() {
        snapshotFlow { mediaSquishiness }.collect { qsMediaHost.squishFraction = it }
    }

    private suspend fun hydrateMediaDisappearParameters() {
        coroutineScope {
            launch {
                snapshotFlow { qqsMediaInRow }.collect { qqsMediaHost.applyDisappearParameters(it) }
            }
            launch {
                snapshotFlow { qsMediaInRow }.collect { qsMediaHost.applyDisappearParameters(it) }
            }
        }
    }

    override fun dump(pw: PrintWriter, args: Array<out String>) {
        pw.asIndenting().run {
            printSection("Quick Settings state") {
@@ -474,6 +532,9 @@ constructor(
                println("qsMediaInRow", qsMediaInRow)
                println("collapsedLandscapeMedia", collapsedLandscapeMedia)
                println("qqsMediaExpansion", qqsMediaExpansion)
                println("shouldUpdateSquishinessOnMedia", shouldUpdateSquishinessOnMedia)
                println("mediaSquishiness", mediaSquishiness)
                println("qsMediaTranslationY", qsMediaTranslationY)
            }
        }
    }
@@ -510,3 +571,22 @@ private fun mediaHostVisible(mediaHost: MediaHost): Flow<Boolean> {
        // lazily.
        .onStart { emit(mediaHost.visible) }
}

// Taken from QSPanelControllerBase
private fun MediaHost.applyDisappearParameters(inRow: Boolean) {
    disappearParameters.apply {
        fadeStartPosition = 0.95f
        disappearStart = 0f
        if (inRow) {
            disappearSize.set(0f, 0.4f)
            gonePivot.set(1f, 0f)
            contentTranslationFraction.set(0.25f, 1f)
            disappearEnd = 0.6f
        } else {
            disappearSize.set(1f, 0f)
            gonePivot.set(0f, 0f)
            contentTranslationFraction.set(0f, 1f)
            disappearEnd = 0.95f
        }
    }
}