Merge "Fix widgets in recommendation card in UMO are clipped" into tm-qpr-dev am: 4bcdc7b0d8
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20798530 Change-Id: I1fbb1e390f5004cb3f27dfe851adfa43cc3247f0 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -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. */
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
@@ -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 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user