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

This commit is contained in:
Sherry Zhou
2023-01-11 18:33:49 +00:00
committed by Android (Google) Code Review
4 changed files with 177 additions and 128 deletions

View File

@@ -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(squishinessFraction: Float, delay: Float, duration: Float): Float { fun calculateAlpha(
val transformStartFraction = delay / ANIMATION_BASE_DURATION squishinessFraction: Float,
val transformDurationFraction = duration / ANIMATION_BASE_DURATION startPosition: Float,
val squishinessToTime = REVERSE_BEZIER.getInterpolation(squishinessFraction) endPosition: Float
return MathUtils.constrain( ): Float {
(squishinessToTime - transformStartFraction) / transformDurationFraction, val transformFraction =
0F, MathUtils.constrain(
1F (squishinessFraction - startPosition) / (endPosition - startPosition),
) 0F,
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. */

View File

@@ -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,41 +301,108 @@ 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 ->
squishedViewState.widgetStates.get(id)?.let { state ->
state.alpha = calculateAlpha(squishFraction, MEDIACONTAINERS_DELAY, DURATION)
}
}
RecommendationViewHolder.mediaTitlesAndSubtitlesIds.forEach { id ->
squishedViewState.widgetStates.get(id)?.let { state ->
state.alpha = calculateAlpha(squishFraction, MEDIATITLES_DELAY, DURATION)
}
} }
// media player
val controlsTop =
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 return squishedViewState
} }
/**
* 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 ->
state.alpha =
calculateAlpha(
squishFraction,
startPosition / nonsquishedHeight,
endPosition / nonsquishedHeight
)
}
}
return groupTop // used for the widget group above this group
}
/** /**
* Obtain a new viewState for a given media state. This usually returns a cached state, but if * Obtain a new viewState for a given media state. This usually returns a cached state, but if
* it's not available, it will recreate one by measuring, which may be expensive. * it's not available, it will recreate one by measuring, which may be expensive.
@@ -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

View File

@@ -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")

View File

@@ -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,10 +70,11 @@ 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 =
this.height = 100 TransitionViewState().apply {
this.measureHeight = 100 this.height = 100
} this.measureHeight = 100
}
mediaHostStateHolder.expansion = 1f mediaHostStateHolder.expansion = 1f
val widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY) val widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY)
val heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY) val heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY)
@@ -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)
// media container widgets occupy [20, 300]
whenever(mediaContainerWidgetState.y).thenReturn(20F)
whenever(mediaContainerWidgetState.height).thenReturn(280)
// media title widgets occupy [320, 330]
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)
val containerSquishMiddle = // in current beizer, when the progress reach 0.38, the result will be 0.5
TRANSFORM_BEZIER.getInterpolation( mediaViewController.squishViewState(mockViewState, 307.6F / 360F)
(MEDIACONTAINERS_DELAY + DURATION / 2) / ANIMATION_BASE_DURATION
)
mediaViewController.squishViewState(mockViewState, containerSquishMiddle)
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 }
} }
} }