Loading packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt +24 −23 Original line number Original line Diff line number Diff line Loading @@ -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 Loading Loading @@ -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>() Loading @@ -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) } } } } Loading Loading @@ -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 Loading @@ -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. */ Loading packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt +96 −30 Original line number Original line Diff line number Diff line Loading @@ -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 Loading @@ -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 /** /** Loading Loading @@ -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 } } /** /** Loading Loading @@ -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 Loading packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt +14 −16 Original line number Original line Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading Loading @@ -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> Loading Loading @@ -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") Loading packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt +40 −56 Original line number Original line Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading @@ -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 } } Loading Loading @@ -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 } } } Loading @@ -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 } } } } } Loading
packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt +24 −23 Original line number Original line Diff line number Diff line Loading @@ -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 Loading Loading @@ -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>() Loading @@ -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) } } } } Loading Loading @@ -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 Loading @@ -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. */ Loading
packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt +96 −30 Original line number Original line Diff line number Diff line Loading @@ -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 Loading @@ -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 /** /** Loading Loading @@ -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 } } /** /** Loading Loading @@ -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 Loading
packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt +14 −16 Original line number Original line Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading Loading @@ -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> Loading Loading @@ -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") Loading
packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt +40 −56 Original line number Original line Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading @@ -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 } } Loading Loading @@ -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 } } } Loading @@ -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 } } } } }