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

Commit 4bcdc7b0 authored by Sherry Zhou's avatar Sherry Zhou Committed by Android (Google) Code Review
Browse files

Merge "Fix widgets in recommendation card in UMO are clipped" into tm-qpr-dev

parents f0758714 066471a3
Loading
Loading
Loading
Loading
+24 −23
Original line number Original line Diff line number Diff line
@@ -94,7 +94,7 @@ constructor(
    private var currentCarouselWidth: Int = 0
    private var currentCarouselWidth: Int = 0


    /** The current height of the carousel */
    /** The current height of the carousel */
    private var currentCarouselHeight: Int = 0
    @VisibleForTesting var currentCarouselHeight: Int = 0


    /** Are we currently showing only active players */
    /** Are we currently showing only active players */
    private var currentlyShowingOnlyActive: Boolean = false
    private var currentlyShowingOnlyActive: Boolean = false
@@ -128,14 +128,14 @@ constructor(
    /** The measured height of the carousel */
    /** The measured height of the carousel */
    private var carouselMeasureHeight: Int = 0
    private var carouselMeasureHeight: Int = 0
    private var desiredHostState: MediaHostState? = null
    private var desiredHostState: MediaHostState? = null
    private val mediaCarousel: MediaScrollView
    @VisibleForTesting var mediaCarousel: MediaScrollView
    val mediaCarouselScrollHandler: MediaCarouselScrollHandler
    val mediaCarouselScrollHandler: MediaCarouselScrollHandler
    val mediaFrame: ViewGroup
    val mediaFrame: ViewGroup
    @VisibleForTesting
    @VisibleForTesting
    lateinit var settingsButton: View
    lateinit var settingsButton: View
        private set
        private set
    private val mediaContent: ViewGroup
    private val mediaContent: ViewGroup
    @VisibleForTesting val pageIndicator: PageIndicator
    @VisibleForTesting var pageIndicator: PageIndicator
    private val visualStabilityCallback: OnReorderingAllowedListener
    private val visualStabilityCallback: OnReorderingAllowedListener
    private var needsReordering: Boolean = false
    private var needsReordering: Boolean = false
    private var keysNeedRemoval = mutableSetOf<String>()
    private var keysNeedRemoval = mutableSetOf<String>()
@@ -160,25 +160,20 @@ constructor(
        }
        }


    companion object {
    companion object {
        const val ANIMATION_BASE_DURATION = 2200f
        const val DURATION = 167f
        const val DETAILS_DELAY = 1067f
        const val CONTROLS_DELAY = 1400f
        const val PAGINATION_DELAY = 1900f
        const val MEDIATITLES_DELAY = 1000f
        const val MEDIACONTAINERS_DELAY = 967f
        val TRANSFORM_BEZIER = PathInterpolator(0.68F, 0F, 0F, 1F)
        val TRANSFORM_BEZIER = PathInterpolator(0.68F, 0F, 0F, 1F)
        val REVERSE_BEZIER = PathInterpolator(0F, 0.68F, 1F, 0F)


        fun calculateAlpha(
        fun calculateAlpha(squishinessFraction: Float, delay: Float, duration: Float): Float {
            squishinessFraction: Float,
            val transformStartFraction = delay / ANIMATION_BASE_DURATION
            startPosition: Float,
            val transformDurationFraction = duration / ANIMATION_BASE_DURATION
            endPosition: Float
            val squishinessToTime = REVERSE_BEZIER.getInterpolation(squishinessFraction)
        ): Float {
            return MathUtils.constrain(
            val transformFraction =
                (squishinessToTime - transformStartFraction) / transformDurationFraction,
                MathUtils.constrain(
                    (squishinessFraction - startPosition) / (endPosition - startPosition),
                    0F,
                    0F,
                    1F
                    1F
                )
                )
            return TRANSFORM_BEZIER.getInterpolation(transformFraction)
        }
        }
    }
    }


@@ -813,7 +808,12 @@ constructor(
        val squishFraction = hostStates[currentEndLocation]?.squishFraction ?: 1.0F
        val squishFraction = hostStates[currentEndLocation]?.squishFraction ?: 1.0F
        val endAlpha =
        val endAlpha =
            (if (endIsVisible) 1.0f else 0.0f) *
            (if (endIsVisible) 1.0f else 0.0f) *
                calculateAlpha(squishFraction, PAGINATION_DELAY, DURATION)
                calculateAlpha(
                    squishFraction,
                    (pageIndicator.translationY + pageIndicator.height) /
                        mediaCarousel.measuredHeight,
                    1F
                )
        var alpha = 1.0f
        var alpha = 1.0f
        if (!endIsVisible || !startIsVisible) {
        if (!endIsVisible || !startIsVisible) {
            var progress = currentTransitionProgress
            var progress = currentTransitionProgress
@@ -839,7 +839,8 @@ constructor(
        pageIndicator.translationX = translationX + mediaCarouselScrollHandler.contentTranslation
        pageIndicator.translationX = translationX + mediaCarouselScrollHandler.contentTranslation
        val layoutParams = pageIndicator.layoutParams as ViewGroup.MarginLayoutParams
        val layoutParams = pageIndicator.layoutParams as ViewGroup.MarginLayoutParams
        pageIndicator.translationY =
        pageIndicator.translationY =
            (currentCarouselHeight - pageIndicator.height - layoutParams.bottomMargin).toFloat()
            (mediaCarousel.measuredHeight - pageIndicator.height - layoutParams.bottomMargin)
                .toFloat()
    }
    }


    /** Update the dimension of this carousel. */
    /** Update the dimension of this carousel. */
+96 −30
Original line number Original line Diff line number Diff line
@@ -24,11 +24,6 @@ import com.android.systemui.R
import com.android.systemui.media.controls.models.GutsViewHolder
import com.android.systemui.media.controls.models.GutsViewHolder
import com.android.systemui.media.controls.models.player.MediaViewHolder
import com.android.systemui.media.controls.models.player.MediaViewHolder
import com.android.systemui.media.controls.models.recommendation.RecommendationViewHolder
import com.android.systemui.media.controls.models.recommendation.RecommendationViewHolder
import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.CONTROLS_DELAY
import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.DETAILS_DELAY
import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.DURATION
import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.MEDIACONTAINERS_DELAY
import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.MEDIATITLES_DELAY
import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.calculateAlpha
import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.calculateAlpha
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.animation.MeasurementOutput
import com.android.systemui.util.animation.MeasurementOutput
@@ -36,6 +31,8 @@ import com.android.systemui.util.animation.TransitionLayout
import com.android.systemui.util.animation.TransitionLayoutController
import com.android.systemui.util.animation.TransitionLayoutController
import com.android.systemui.util.animation.TransitionViewState
import com.android.systemui.util.animation.TransitionViewState
import com.android.systemui.util.traceSection
import com.android.systemui.util.traceSection
import java.lang.Float.max
import java.lang.Float.min
import javax.inject.Inject
import javax.inject.Inject


/**
/**
@@ -304,39 +301,106 @@ constructor(
        val squishedViewState = viewState.copy()
        val squishedViewState = viewState.copy()
        val squishedHeight = (squishedViewState.measureHeight * squishFraction).toInt()
        val squishedHeight = (squishedViewState.measureHeight * squishFraction).toInt()
        squishedViewState.height = squishedHeight
        squishedViewState.height = squishedHeight
        controlIds.forEach { id ->
            squishedViewState.widgetStates.get(id)?.let { state ->
                state.alpha = calculateAlpha(squishFraction, CONTROLS_DELAY, DURATION)
            }
        }

        detailIds.forEach { id ->
            squishedViewState.widgetStates.get(id)?.let { state ->
                state.alpha = calculateAlpha(squishFraction, DETAILS_DELAY, DURATION)
            }
        }

        // We are not overriding the squishedViewStates height but only the children to avoid
        // We are not overriding the squishedViewStates height but only the children to avoid
        // them remeasuring the whole view. Instead it just remains as the original size
        // them remeasuring the whole view. Instead it just remains as the original size
        backgroundIds.forEach { id ->
        backgroundIds.forEach { id ->
            squishedViewState.widgetStates.get(id)?.let { state ->
            squishedViewState.widgetStates.get(id)?.let { state -> state.height = squishedHeight }
                state.height = squishedHeight
            }
        }
        }


        RecommendationViewHolder.mediaContainersIds.forEach { id ->
        // media player
            squishedViewState.widgetStates.get(id)?.let { state ->
        val controlsTop =
                state.alpha = calculateAlpha(squishFraction, MEDIACONTAINERS_DELAY, DURATION)
            calculateWidgetGroupAlphaForSquishiness(
            }
                controlIds,
                squishedViewState.measureHeight.toFloat(),
                squishedViewState,
                squishFraction
            )
        calculateWidgetGroupAlphaForSquishiness(
            detailIds,
            controlsTop,
            squishedViewState,
            squishFraction
        )
        // recommendation card
        val titlesTop =
            calculateWidgetGroupAlphaForSquishiness(
                RecommendationViewHolder.mediaTitlesAndSubtitlesIds,
                squishedViewState.measureHeight.toFloat(),
                squishedViewState,
                squishFraction
            )
        calculateWidgetGroupAlphaForSquishiness(
            RecommendationViewHolder.mediaContainersIds,
            titlesTop,
            squishedViewState,
            squishFraction
        )
        return squishedViewState
    }
    }


        RecommendationViewHolder.mediaTitlesAndSubtitlesIds.forEach { id ->
    /**
     * This function is to make each widget in UMO disappear before being clipped by squished UMO
     *
     * The general rule is that widgets in UMO has been divided into several groups, and widgets in
     * one group have the same alpha during squishing It will change from alpha 0.0 when the visible
     * bottom of UMO reach the bottom of this group It will change to alpha 1.0 when the visible
     * bottom of UMO reach the top of the group below e.g.Album title, artist title and play-pause
     * button will change alpha together.
     * ```
     *     And their alpha becomes 1.0 when the visible bottom of UMO reach the top of controls,
     *     including progress bar, next button, previous button
     * ```
     * widgetGroupIds: a group of widgets have same state during UMO is squished,
     * ```
     *     e.g. Album title, artist title and play-pause button
     * ```
     * groupEndPosition: the height of UMO, when the height reaches this value,
     * ```
     *     widgets in this group should have 1.0 as alpha
     *     e.g., the group of album title, artist title and play-pause button will become fully
     *         visible when the height of UMO reaches the top of controls group
     *         (progress bar, previous button and next button)
     * ```
     * squishedViewState: hold the widgetState of each widget, which will be modified
     * squishFraction: the squishFraction of UMO
     */
    private fun calculateWidgetGroupAlphaForSquishiness(
        widgetGroupIds: Set<Int>,
        groupEndPosition: Float,
        squishedViewState: TransitionViewState,
        squishFraction: Float
    ): Float {
        val nonsquishedHeight = squishedViewState.measureHeight
        var groupTop = squishedViewState.measureHeight.toFloat()
        var groupBottom = 0F
        widgetGroupIds.forEach { id ->
            squishedViewState.widgetStates.get(id)?.let { state ->
                groupTop = min(groupTop, state.y)
                groupBottom = max(groupBottom, state.y + state.height)
            }
        }
        // startPosition means to the height of squished UMO where the widget alpha should start
        // changing from 0.0
        // generally, it equals to the bottom of widgets, so that we can meet the requirement that
        // widget should not go beyond the bounds of background
        // endPosition means to the height of squished UMO where the widget alpha should finish
        // changing alpha to 1.0
        var startPosition = groupBottom
        val endPosition = groupEndPosition
        if (startPosition == endPosition) {
            startPosition = (endPosition - 0.2 * (groupBottom - groupTop)).toFloat()
        }
        widgetGroupIds.forEach { id ->
            squishedViewState.widgetStates.get(id)?.let { state ->
            squishedViewState.widgetStates.get(id)?.let { state ->
                state.alpha = calculateAlpha(squishFraction, MEDIATITLES_DELAY, DURATION)
                state.alpha =
                    calculateAlpha(
                        squishFraction,
                        startPosition / nonsquishedHeight,
                        endPosition / nonsquishedHeight
                    )
            }
            }
        }
        }

        return groupTop // used for the widget group above this group
        return squishedViewState
    }
    }


    /**
    /**
@@ -544,11 +608,13 @@ constructor(
        overrideSize?.let {
        overrideSize?.let {
            // To be safe we're using a maximum here. The override size should always be set
            // To be safe we're using a maximum here. The override size should always be set
            // properly though.
            // properly though.
            if (result.measureHeight != it.measuredHeight
            if (
                    || result.measureWidth != it.measuredWidth) {
                result.measureHeight != it.measuredHeight || result.measureWidth != it.measuredWidth
            ) {
                result.measureHeight = Math.max(it.measuredHeight, result.measureHeight)
                result.measureHeight = Math.max(it.measuredHeight, result.measureHeight)
                result.measureWidth = Math.max(it.measuredWidth, result.measureWidth)
                result.measureWidth = Math.max(it.measuredWidth, result.measureWidth)
                // The measureHeight and the shown height should both be set to the overridden height
                // The measureHeight and the shown height should both be set to the overridden
                // height
                result.height = result.measureHeight
                result.height = result.measureHeight
                result.width = result.measureWidth
                result.width = result.measureWidth
                // Make sure all background views are also resized such that their size is correct
                // Make sure all background views are also resized such that their size is correct
+14 −16
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@ import android.app.PendingIntent
import android.content.res.Configuration
import android.content.res.Configuration
import android.testing.AndroidTestingRunner
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.testing.TestableLooper
import android.util.MathUtils.abs
import androidx.test.filters.SmallTest
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
import com.android.internal.logging.InstanceId
import com.android.systemui.SysuiTestCase
import com.android.systemui.SysuiTestCase
@@ -31,14 +32,11 @@ import com.android.systemui.media.controls.models.player.MediaData
import com.android.systemui.media.controls.models.recommendation.SmartspaceMediaData
import com.android.systemui.media.controls.models.recommendation.SmartspaceMediaData
import com.android.systemui.media.controls.pipeline.EMPTY_SMARTSPACE_MEDIA_DATA
import com.android.systemui.media.controls.pipeline.EMPTY_SMARTSPACE_MEDIA_DATA
import com.android.systemui.media.controls.pipeline.MediaDataManager
import com.android.systemui.media.controls.pipeline.MediaDataManager
import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.ANIMATION_BASE_DURATION
import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.DURATION
import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.PAGINATION_DELAY
import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.TRANSFORM_BEZIER
import com.android.systemui.media.controls.ui.MediaHierarchyManager.Companion.LOCATION_QS
import com.android.systemui.media.controls.ui.MediaHierarchyManager.Companion.LOCATION_QS
import com.android.systemui.media.controls.util.MediaUiEventLogger
import com.android.systemui.media.controls.util.MediaUiEventLogger
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.qs.PageIndicator
import com.android.systemui.statusbar.notification.collection.provider.OnReorderingAllowedListener
import com.android.systemui.statusbar.notification.collection.provider.OnReorderingAllowedListener
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.ConfigurationController
@@ -56,6 +54,7 @@ import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentCaptor
import org.mockito.Captor
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mock
import org.mockito.Mockito.floatThat
import org.mockito.Mockito.mock
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
import org.mockito.Mockito.`when` as whenever
@@ -86,6 +85,8 @@ class MediaCarouselControllerTest : SysuiTestCase() {
    @Mock lateinit var debugLogger: MediaCarouselControllerLogger
    @Mock lateinit var debugLogger: MediaCarouselControllerLogger
    @Mock lateinit var mediaViewController: MediaViewController
    @Mock lateinit var mediaViewController: MediaViewController
    @Mock lateinit var smartspaceMediaData: SmartspaceMediaData
    @Mock lateinit var smartspaceMediaData: SmartspaceMediaData
    @Mock lateinit var mediaCarousel: MediaScrollView
    @Mock lateinit var pageIndicator: PageIndicator
    @Captor lateinit var listener: ArgumentCaptor<MediaDataManager.Listener>
    @Captor lateinit var listener: ArgumentCaptor<MediaDataManager.Listener>
    @Captor
    @Captor
    lateinit var configListener: ArgumentCaptor<ConfigurationController.ConfigurationListener>
    lateinit var configListener: ArgumentCaptor<ConfigurationController.ConfigurationListener>
@@ -647,25 +648,22 @@ class MediaCarouselControllerTest : SysuiTestCase() {
    @Test
    @Test
    fun testSetCurrentState_UpdatePageIndicatorAlphaWhenSquish() {
    fun testSetCurrentState_UpdatePageIndicatorAlphaWhenSquish() {
        val delta = 0.0001F
        val delta = 0.0001F
        val paginationSquishMiddle =
        mediaCarouselController.mediaCarousel = mediaCarousel
            TRANSFORM_BEZIER.getInterpolation(
        mediaCarouselController.pageIndicator = pageIndicator
                (PAGINATION_DELAY + DURATION / 2) / ANIMATION_BASE_DURATION
        whenever(mediaCarousel.measuredHeight).thenReturn(100)
            )
        whenever(pageIndicator.translationY).thenReturn(80F)
        val paginationSquishEnd =
        whenever(pageIndicator.height).thenReturn(10)
            TRANSFORM_BEZIER.getInterpolation(
                (PAGINATION_DELAY + DURATION) / ANIMATION_BASE_DURATION
            )
        whenever(mediaHostStatesManager.mediaHostStates)
        whenever(mediaHostStatesManager.mediaHostStates)
            .thenReturn(mutableMapOf(LOCATION_QS to mediaHostState))
            .thenReturn(mutableMapOf(LOCATION_QS to mediaHostState))
        whenever(mediaHostState.visible).thenReturn(true)
        whenever(mediaHostState.visible).thenReturn(true)
        mediaCarouselController.currentEndLocation = LOCATION_QS
        mediaCarouselController.currentEndLocation = LOCATION_QS
        whenever(mediaHostState.squishFraction).thenReturn(paginationSquishMiddle)
        whenever(mediaHostState.squishFraction).thenReturn(0.938F)
        mediaCarouselController.updatePageIndicatorAlpha()
        mediaCarouselController.updatePageIndicatorAlpha()
        assertEquals(mediaCarouselController.pageIndicator.alpha, 0.5F, delta)
        verify(pageIndicator).alpha = floatThat { abs(it - 0.5F) < delta }


        whenever(mediaHostState.squishFraction).thenReturn(paginationSquishEnd)
        whenever(mediaHostState.squishFraction).thenReturn(1.0F)
        mediaCarouselController.updatePageIndicatorAlpha()
        mediaCarouselController.updatePageIndicatorAlpha()
        assertEquals(mediaCarouselController.pageIndicator.alpha, 1.0F, delta)
        verify(pageIndicator).alpha = floatThat { abs(it - 1.0F) < delta }
    }
    }


    @Ignore("b/253229241")
    @Ignore("b/253229241")
+40 −56
Original line number Original line Diff line number Diff line
@@ -22,13 +22,6 @@ import android.view.View
import androidx.test.filters.SmallTest
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.SysuiTestCase
import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.ANIMATION_BASE_DURATION
import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.CONTROLS_DELAY
import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.DETAILS_DELAY
import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.DURATION
import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.MEDIACONTAINERS_DELAY
import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.MEDIATITLES_DELAY
import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.TRANSFORM_BEZIER
import com.android.systemui.util.animation.MeasurementInput
import com.android.systemui.util.animation.MeasurementInput
import com.android.systemui.util.animation.TransitionLayout
import com.android.systemui.util.animation.TransitionLayout
import com.android.systemui.util.animation.TransitionViewState
import com.android.systemui.util.animation.TransitionViewState
@@ -60,9 +53,10 @@ class MediaViewControllerTest : SysuiTestCase() {
    @Mock private lateinit var controlWidgetState: WidgetState
    @Mock private lateinit var controlWidgetState: WidgetState
    @Mock private lateinit var bgWidgetState: WidgetState
    @Mock private lateinit var bgWidgetState: WidgetState
    @Mock private lateinit var mediaTitleWidgetState: WidgetState
    @Mock private lateinit var mediaTitleWidgetState: WidgetState
    @Mock private lateinit var mediaSubTitleWidgetState: WidgetState
    @Mock private lateinit var mediaContainerWidgetState: WidgetState
    @Mock private lateinit var mediaContainerWidgetState: WidgetState


    val delta = 0.0001F
    val delta = 0.1F


    private lateinit var mediaViewController: MediaViewController
    private lateinit var mediaViewController: MediaViewController


@@ -76,7 +70,8 @@ class MediaViewControllerTest : SysuiTestCase() {
    @Test
    @Test
    fun testObtainViewState_applySquishFraction_toPlayerTransitionViewState_height() {
    fun testObtainViewState_applySquishFraction_toPlayerTransitionViewState_height() {
        mediaViewController.attach(player, MediaViewController.TYPE.PLAYER)
        mediaViewController.attach(player, MediaViewController.TYPE.PLAYER)
        player.measureState = TransitionViewState().apply {
        player.measureState =
            TransitionViewState().apply {
                this.height = 100
                this.height = 100
                this.measureHeight = 100
                this.measureHeight = 100
            }
            }
@@ -128,29 +123,21 @@ class MediaViewControllerTest : SysuiTestCase() {
                    R.id.header_artist to detailWidgetState
                    R.id.header_artist to detailWidgetState
                )
                )
            )
            )

        whenever(mockCopiedState.measureHeight).thenReturn(200)
        val detailSquishMiddle =
        // detail widgets occupy [90, 100]
            TRANSFORM_BEZIER.getInterpolation(
        whenever(detailWidgetState.y).thenReturn(90F)
                (DETAILS_DELAY + DURATION / 2) / ANIMATION_BASE_DURATION
        whenever(detailWidgetState.height).thenReturn(10)
            )
        // control widgets occupy [150, 170]
        mediaViewController.squishViewState(mockViewState, detailSquishMiddle)
        whenever(controlWidgetState.y).thenReturn(150F)
        whenever(controlWidgetState.height).thenReturn(20)
        // in current beizer, when the progress reach 0.38, the result will be 0.5
        mediaViewController.squishViewState(mockViewState, 119F / 200F)
        verify(detailWidgetState).alpha = floatThat { kotlin.math.abs(it - 0.5F) < delta }
        verify(detailWidgetState).alpha = floatThat { kotlin.math.abs(it - 0.5F) < delta }

        mediaViewController.squishViewState(mockViewState, 150F / 200F)
        val detailSquishEnd =
            TRANSFORM_BEZIER.getInterpolation((DETAILS_DELAY + DURATION) / ANIMATION_BASE_DURATION)
        mediaViewController.squishViewState(mockViewState, detailSquishEnd)
        verify(detailWidgetState).alpha = floatThat { kotlin.math.abs(it - 1.0F) < delta }
        verify(detailWidgetState).alpha = floatThat { kotlin.math.abs(it - 1.0F) < delta }

        mediaViewController.squishViewState(mockViewState, 181.4F / 200F)
        val controlSquishMiddle =
            TRANSFORM_BEZIER.getInterpolation(
                (CONTROLS_DELAY + DURATION / 2) / ANIMATION_BASE_DURATION
            )
        mediaViewController.squishViewState(mockViewState, controlSquishMiddle)
        verify(controlWidgetState).alpha = floatThat { kotlin.math.abs(it - 0.5F) < delta }
        verify(controlWidgetState).alpha = floatThat { kotlin.math.abs(it - 0.5F) < delta }

        mediaViewController.squishViewState(mockViewState, 200F / 200F)
        val controlSquishEnd =
            TRANSFORM_BEZIER.getInterpolation((CONTROLS_DELAY + DURATION) / ANIMATION_BASE_DURATION)
        mediaViewController.squishViewState(mockViewState, controlSquishEnd)
        verify(controlWidgetState).alpha = floatThat { kotlin.math.abs(it - 1.0F) < delta }
        verify(controlWidgetState).alpha = floatThat { kotlin.math.abs(it - 1.0F) < delta }
    }
    }


@@ -161,36 +148,33 @@ class MediaViewControllerTest : SysuiTestCase() {
            .thenReturn(
            .thenReturn(
                mutableMapOf(
                mutableMapOf(
                    R.id.media_title1 to mediaTitleWidgetState,
                    R.id.media_title1 to mediaTitleWidgetState,
                    R.id.media_subtitle1 to mediaSubTitleWidgetState,
                    R.id.media_cover1_container to mediaContainerWidgetState
                    R.id.media_cover1_container to mediaContainerWidgetState
                )
                )
            )
            )

        whenever(mockCopiedState.measureHeight).thenReturn(360)
        val containerSquishMiddle =
        // media container widgets occupy [20, 300]
            TRANSFORM_BEZIER.getInterpolation(
        whenever(mediaContainerWidgetState.y).thenReturn(20F)
                (MEDIACONTAINERS_DELAY + DURATION / 2) / ANIMATION_BASE_DURATION
        whenever(mediaContainerWidgetState.height).thenReturn(280)
            )
        // media title widgets occupy [320, 330]
        mediaViewController.squishViewState(mockViewState, containerSquishMiddle)
        whenever(mediaTitleWidgetState.y).thenReturn(320F)
        whenever(mediaTitleWidgetState.height).thenReturn(10)
        // media subtitle widgets occupy [340, 350]
        whenever(mediaSubTitleWidgetState.y).thenReturn(340F)
        whenever(mediaSubTitleWidgetState.height).thenReturn(10)

        // in current beizer, when the progress reach 0.38, the result will be 0.5
        mediaViewController.squishViewState(mockViewState, 307.6F / 360F)
        verify(mediaContainerWidgetState).alpha = floatThat { kotlin.math.abs(it - 0.5F) < delta }
        verify(mediaContainerWidgetState).alpha = floatThat { kotlin.math.abs(it - 0.5F) < delta }

        mediaViewController.squishViewState(mockViewState, 320F / 360F)
        val containerSquishEnd =
            TRANSFORM_BEZIER.getInterpolation(
                (MEDIACONTAINERS_DELAY + DURATION) / ANIMATION_BASE_DURATION
            )
        mediaViewController.squishViewState(mockViewState, containerSquishEnd)
        verify(mediaContainerWidgetState).alpha = floatThat { kotlin.math.abs(it - 1.0F) < delta }
        verify(mediaContainerWidgetState).alpha = floatThat { kotlin.math.abs(it - 1.0F) < delta }

        // media title and media subtitle are in same widget group, should be calculate together and
        val titleSquishMiddle =
        // have same alpha
            TRANSFORM_BEZIER.getInterpolation(
        mediaViewController.squishViewState(mockViewState, 353.8F / 360F)
                (MEDIATITLES_DELAY + DURATION / 2) / ANIMATION_BASE_DURATION
            )
        mediaViewController.squishViewState(mockViewState, titleSquishMiddle)
        verify(mediaTitleWidgetState).alpha = floatThat { kotlin.math.abs(it - 0.5F) < delta }
        verify(mediaTitleWidgetState).alpha = floatThat { kotlin.math.abs(it - 0.5F) < delta }

        verify(mediaSubTitleWidgetState).alpha = floatThat { kotlin.math.abs(it - 0.5F) < delta }
        val titleSquishEnd =
        mediaViewController.squishViewState(mockViewState, 360F / 360F)
            TRANSFORM_BEZIER.getInterpolation(
                (MEDIATITLES_DELAY + DURATION) / ANIMATION_BASE_DURATION
            )
        mediaViewController.squishViewState(mockViewState, titleSquishEnd)
        verify(mediaTitleWidgetState).alpha = floatThat { kotlin.math.abs(it - 1.0F) < delta }
        verify(mediaTitleWidgetState).alpha = floatThat { kotlin.math.abs(it - 1.0F) < delta }
        verify(mediaSubTitleWidgetState).alpha = floatThat { kotlin.math.abs(it - 1.0F) < delta }
    }
    }
}
}