Merge "Fix clipping during media squishing and general behavior" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
c9e3c70735
@@ -82,6 +82,13 @@ constructor(
|
|||||||
R.id.header_artist,
|
R.id.header_artist,
|
||||||
R.id.actionPlayPause,
|
R.id.actionPlayPause,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val backgroundIds =
|
||||||
|
setOf(
|
||||||
|
R.id.album_art,
|
||||||
|
R.id.turbulence_noise_view,
|
||||||
|
R.id.touch_ripple_view,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A listener when the current dimensions of the player change */
|
/** A listener when the current dimensions of the player change */
|
||||||
@@ -295,7 +302,8 @@ constructor(
|
|||||||
squishFraction: Float
|
squishFraction: Float
|
||||||
): TransitionViewState {
|
): TransitionViewState {
|
||||||
val squishedViewState = viewState.copy()
|
val squishedViewState = viewState.copy()
|
||||||
squishedViewState.height = (squishedViewState.height * squishFraction).toInt()
|
val squishedHeight = (squishedViewState.measureHeight * squishFraction).toInt()
|
||||||
|
squishedViewState.height = squishedHeight
|
||||||
controlIds.forEach { id ->
|
controlIds.forEach { id ->
|
||||||
squishedViewState.widgetStates.get(id)?.let { state ->
|
squishedViewState.widgetStates.get(id)?.let { state ->
|
||||||
state.alpha = calculateAlpha(squishFraction, CONTROLS_DELAY, DURATION)
|
state.alpha = calculateAlpha(squishFraction, CONTROLS_DELAY, DURATION)
|
||||||
@@ -308,6 +316,14 @@ constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
backgroundIds.forEach { id ->
|
||||||
|
squishedViewState.widgetStates.get(id)?.let { state ->
|
||||||
|
state.height = squishedHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RecommendationViewHolder.mediaContainersIds.forEach { id ->
|
RecommendationViewHolder.mediaContainersIds.forEach { id ->
|
||||||
squishedViewState.widgetStates.get(id)?.let { state ->
|
squishedViewState.widgetStates.get(id)?.let { state ->
|
||||||
state.alpha = calculateAlpha(squishFraction, MEDIACONTAINERS_DELAY, DURATION)
|
state.alpha = calculateAlpha(squishFraction, MEDIACONTAINERS_DELAY, DURATION)
|
||||||
@@ -421,10 +437,9 @@ constructor(
|
|||||||
fun getMeasurementsForState(hostState: MediaHostState): MeasurementOutput? =
|
fun getMeasurementsForState(hostState: MediaHostState): MeasurementOutput? =
|
||||||
traceSection("MediaViewController#getMeasurementsForState") {
|
traceSection("MediaViewController#getMeasurementsForState") {
|
||||||
// measurements should never factor in the squish fraction
|
// measurements should never factor in the squish fraction
|
||||||
val viewState =
|
val viewState = obtainViewState(hostState) ?: return null
|
||||||
obtainViewState(hostState.copy().also { it.squishFraction = 1.0f }) ?: return null
|
measurement.measuredWidth = viewState.measureWidth
|
||||||
measurement.measuredWidth = viewState.width
|
measurement.measuredHeight = viewState.measureHeight
|
||||||
measurement.measuredHeight = viewState.height
|
|
||||||
return measurement
|
return measurement
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -453,7 +468,7 @@ constructor(
|
|||||||
// The view might not be bound yet or has never been measured and in that case will be
|
// The view might not be bound yet or has never been measured and in that case will be
|
||||||
// reset once the state is fully available
|
// reset once the state is fully available
|
||||||
var endViewState = obtainViewState(endHostState) ?: return
|
var endViewState = obtainViewState(endHostState) ?: return
|
||||||
endViewState = updateViewStateToCarouselSize(endViewState, endLocation, tmpState2)!!
|
endViewState = updateViewStateSize(endViewState, endLocation, tmpState2)!!
|
||||||
layoutController.setMeasureState(endViewState)
|
layoutController.setMeasureState(endViewState)
|
||||||
|
|
||||||
// If the view isn't bound, we can drop the animation, otherwise we'll execute it
|
// If the view isn't bound, we can drop the animation, otherwise we'll execute it
|
||||||
@@ -464,7 +479,7 @@ constructor(
|
|||||||
|
|
||||||
val result: TransitionViewState
|
val result: TransitionViewState
|
||||||
var startViewState = obtainViewState(startHostState)
|
var startViewState = obtainViewState(startHostState)
|
||||||
startViewState = updateViewStateToCarouselSize(startViewState, startLocation, tmpState3)
|
startViewState = updateViewStateSize(startViewState, startLocation, tmpState3)
|
||||||
|
|
||||||
if (!endHostState.visible) {
|
if (!endHostState.visible) {
|
||||||
// Let's handle the case where the end is gone first. In this case we take the
|
// Let's handle the case where the end is gone first. In this case we take the
|
||||||
@@ -517,18 +532,38 @@ constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateViewStateToCarouselSize(
|
private fun updateViewStateSize(
|
||||||
viewState: TransitionViewState?,
|
viewState: TransitionViewState?,
|
||||||
location: Int,
|
location: Int,
|
||||||
outState: TransitionViewState
|
outState: TransitionViewState
|
||||||
): TransitionViewState? {
|
): TransitionViewState? {
|
||||||
val result = viewState?.copy(outState) ?: return null
|
var result = viewState?.copy(outState) ?: return null
|
||||||
|
val state = mediaHostStatesManager.mediaHostStates[location]
|
||||||
val overrideSize = mediaHostStatesManager.carouselSizes[location]
|
val overrideSize = mediaHostStatesManager.carouselSizes[location]
|
||||||
|
var overridden = false
|
||||||
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.
|
||||||
result.height = Math.max(it.measuredHeight, result.height)
|
if (result.measureHeight != it.measuredHeight
|
||||||
result.width = Math.max(it.measuredWidth, result.width)
|
|| result.measureWidth != it.measuredWidth) {
|
||||||
|
result.measureHeight = Math.max(it.measuredHeight, result.measureHeight)
|
||||||
|
result.measureWidth = Math.max(it.measuredWidth, result.measureWidth)
|
||||||
|
// The measureHeight and the shown height should both be set to the overridden height
|
||||||
|
result.height = result.measureHeight
|
||||||
|
result.width = result.measureWidth
|
||||||
|
// Make sure all background views are also resized such that their size is correct
|
||||||
|
backgroundIds.forEach { id ->
|
||||||
|
result.widgetStates.get(id)?.let { state ->
|
||||||
|
state.height = result.height
|
||||||
|
state.width = result.width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
overridden = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (overridden && state != null && state.squishFraction <= 1f) {
|
||||||
|
// Let's squish the media player if our size was overridden
|
||||||
|
result = squishViewState(result, state.squishFraction)
|
||||||
}
|
}
|
||||||
logger.logMediaSize("update to carousel", result.width, result.height)
|
logger.logMediaSize("update to carousel", result.width, result.height)
|
||||||
return result
|
return result
|
||||||
@@ -562,7 +597,13 @@ constructor(
|
|||||||
*/
|
*/
|
||||||
private fun obtainViewStateForLocation(@MediaLocation location: Int): TransitionViewState? {
|
private fun obtainViewStateForLocation(@MediaLocation location: Int): TransitionViewState? {
|
||||||
val mediaHostState = mediaHostStatesManager.mediaHostStates[location] ?: return null
|
val mediaHostState = mediaHostStatesManager.mediaHostStates[location] ?: return null
|
||||||
return obtainViewState(mediaHostState)
|
val viewState = obtainViewState(mediaHostState)
|
||||||
|
if (viewState != null) {
|
||||||
|
// update the size of the viewstate for the location with the override
|
||||||
|
updateViewStateSize(viewState, location, tmpState)
|
||||||
|
return tmpState
|
||||||
|
}
|
||||||
|
return viewState
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -59,8 +59,8 @@ class TransitionLayout @JvmOverloads constructor(
|
|||||||
*/
|
*/
|
||||||
var measureState: TransitionViewState = TransitionViewState()
|
var measureState: TransitionViewState = TransitionViewState()
|
||||||
set(value) {
|
set(value) {
|
||||||
val newWidth = value.width
|
val newWidth = value.measureWidth
|
||||||
val newHeight = value.height
|
val newHeight = value.measureHeight
|
||||||
if (newWidth != desiredMeasureWidth || newHeight != desiredMeasureHeight) {
|
if (newWidth != desiredMeasureWidth || newHeight != desiredMeasureHeight) {
|
||||||
desiredMeasureWidth = newWidth
|
desiredMeasureWidth = newWidth
|
||||||
desiredMeasureHeight = newHeight
|
desiredMeasureHeight = newHeight
|
||||||
@@ -318,8 +318,28 @@ class TransitionLayout @JvmOverloads constructor(
|
|||||||
|
|
||||||
class TransitionViewState {
|
class TransitionViewState {
|
||||||
var widgetStates: MutableMap<Int, WidgetState> = mutableMapOf()
|
var widgetStates: MutableMap<Int, WidgetState> = mutableMapOf()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The visible width of this ViewState. This may differ from the measuredWidth when e.g.
|
||||||
|
* squishing the view
|
||||||
|
*/
|
||||||
var width: Int = 0
|
var width: Int = 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The visible height of this ViewState. This may differ from the measuredHeight when e.g.
|
||||||
|
* squishing the view
|
||||||
|
*/
|
||||||
var height: Int = 0
|
var height: Int = 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The height that determines the measured dimensions of the view
|
||||||
|
*/
|
||||||
|
var measureHeight: Int = 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The width that determines the measured dimensions of the view
|
||||||
|
*/
|
||||||
|
var measureWidth: Int = 0
|
||||||
var alpha: Float = 1.0f
|
var alpha: Float = 1.0f
|
||||||
val translation = PointF()
|
val translation = PointF()
|
||||||
val contentTranslation = PointF()
|
val contentTranslation = PointF()
|
||||||
@@ -328,6 +348,8 @@ class TransitionViewState {
|
|||||||
val copy = reusedState ?: TransitionViewState()
|
val copy = reusedState ?: TransitionViewState()
|
||||||
copy.width = width
|
copy.width = width
|
||||||
copy.height = height
|
copy.height = height
|
||||||
|
copy.measureHeight = measureHeight
|
||||||
|
copy.measureWidth = measureWidth
|
||||||
copy.alpha = alpha
|
copy.alpha = alpha
|
||||||
copy.translation.set(translation.x, translation.y)
|
copy.translation.set(translation.x, translation.y)
|
||||||
copy.contentTranslation.set(contentTranslation.x, contentTranslation.y)
|
copy.contentTranslation.set(contentTranslation.x, contentTranslation.y)
|
||||||
@@ -348,6 +370,8 @@ class TransitionViewState {
|
|||||||
}
|
}
|
||||||
width = transitionLayout.measuredWidth
|
width = transitionLayout.measuredWidth
|
||||||
height = transitionLayout.measuredHeight
|
height = transitionLayout.measuredHeight
|
||||||
|
measureWidth = width
|
||||||
|
measureHeight = height
|
||||||
translation.set(0.0f, 0.0f)
|
translation.set(0.0f, 0.0f)
|
||||||
contentTranslation.set(0.0f, 0.0f)
|
contentTranslation.set(0.0f, 0.0f)
|
||||||
alpha = 1.0f
|
alpha = 1.0f
|
||||||
|
|||||||
@@ -234,6 +234,15 @@ open class TransitionLayoutController {
|
|||||||
progress).toInt()
|
progress).toInt()
|
||||||
height = MathUtils.lerp(startState.height.toFloat(), endState.height.toFloat(),
|
height = MathUtils.lerp(startState.height.toFloat(), endState.height.toFloat(),
|
||||||
progress).toInt()
|
progress).toInt()
|
||||||
|
// If we're at the start, let's measure with the starting dimensions, otherwise always
|
||||||
|
// with the end state
|
||||||
|
if (progress == 0.0f) {
|
||||||
|
measureWidth = startState.measureWidth
|
||||||
|
measureHeight = startState.measureHeight
|
||||||
|
} else {
|
||||||
|
measureWidth = endState.measureWidth
|
||||||
|
measureHeight = endState.measureHeight
|
||||||
|
}
|
||||||
translation.x = MathUtils.lerp(startState.translation.x, endState.translation.x,
|
translation.x = MathUtils.lerp(startState.translation.x, endState.translation.x,
|
||||||
progress)
|
progress)
|
||||||
translation.y = MathUtils.lerp(startState.translation.y, endState.translation.y,
|
translation.y = MathUtils.lerp(startState.translation.y, endState.translation.y,
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ class MediaViewControllerTest : SysuiTestCase() {
|
|||||||
@Mock private lateinit var mockCopiedState: TransitionViewState
|
@Mock private lateinit var mockCopiedState: TransitionViewState
|
||||||
@Mock private lateinit var detailWidgetState: WidgetState
|
@Mock private lateinit var detailWidgetState: WidgetState
|
||||||
@Mock private lateinit var controlWidgetState: WidgetState
|
@Mock private lateinit var controlWidgetState: WidgetState
|
||||||
|
@Mock private lateinit var bgWidgetState: WidgetState
|
||||||
@Mock private lateinit var mediaTitleWidgetState: WidgetState
|
@Mock private lateinit var mediaTitleWidgetState: WidgetState
|
||||||
@Mock private lateinit var mediaContainerWidgetState: WidgetState
|
@Mock private lateinit var mediaContainerWidgetState: WidgetState
|
||||||
|
|
||||||
@@ -75,7 +76,10 @@ 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 { this.height = 100 }
|
player.measureState = TransitionViewState().apply {
|
||||||
|
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)
|
||||||
@@ -85,10 +89,12 @@ class MediaViewControllerTest : SysuiTestCase() {
|
|||||||
// Test no squish
|
// Test no squish
|
||||||
mediaHostStateHolder.squishFraction = 1f
|
mediaHostStateHolder.squishFraction = 1f
|
||||||
assertTrue(mediaViewController.obtainViewState(mediaHostStateHolder)!!.height == 100)
|
assertTrue(mediaViewController.obtainViewState(mediaHostStateHolder)!!.height == 100)
|
||||||
|
assertTrue(mediaViewController.obtainViewState(mediaHostStateHolder)!!.measureHeight == 100)
|
||||||
|
|
||||||
// Test half squish
|
// Test half squish
|
||||||
mediaHostStateHolder.squishFraction = 0.5f
|
mediaHostStateHolder.squishFraction = 0.5f
|
||||||
assertTrue(mediaViewController.obtainViewState(mediaHostStateHolder)!!.height == 50)
|
assertTrue(mediaViewController.obtainViewState(mediaHostStateHolder)!!.height == 50)
|
||||||
|
assertTrue(mediaViewController.obtainViewState(mediaHostStateHolder)!!.measureHeight == 100)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -104,10 +110,12 @@ class MediaViewControllerTest : SysuiTestCase() {
|
|||||||
// Test no squish
|
// Test no squish
|
||||||
mediaHostStateHolder.squishFraction = 1f
|
mediaHostStateHolder.squishFraction = 1f
|
||||||
assertTrue(mediaViewController.obtainViewState(mediaHostStateHolder)!!.height == 100)
|
assertTrue(mediaViewController.obtainViewState(mediaHostStateHolder)!!.height == 100)
|
||||||
|
assertTrue(mediaViewController.obtainViewState(mediaHostStateHolder)!!.measureHeight == 100)
|
||||||
|
|
||||||
// Test half squish
|
// Test half squish
|
||||||
mediaHostStateHolder.squishFraction = 0.5f
|
mediaHostStateHolder.squishFraction = 0.5f
|
||||||
assertTrue(mediaViewController.obtainViewState(mediaHostStateHolder)!!.height == 50)
|
assertTrue(mediaViewController.obtainViewState(mediaHostStateHolder)!!.height == 50)
|
||||||
|
assertTrue(mediaViewController.obtainViewState(mediaHostStateHolder)!!.measureHeight == 100)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user