diff --git a/packages/SystemUI/res/layout/media_view.xml b/packages/SystemUI/res/layout/media_view.xml
index 5b864924f4a25..07bbb8f40eb8c 100644
--- a/packages/SystemUI/res/layout/media_view.xml
+++ b/packages/SystemUI/res/layout/media_view.xml
@@ -26,6 +26,7 @@
android:gravity="center_horizontal|fill_vertical"
android:background="@drawable/qs_media_background">
+
+
+
+
+
+
@@ -119,6 +143,7 @@
android:singleLine="true"
android:text="@*android:string/ext_media_seamless_action"
android:textColor="@color/media_primary_text"
+ android:textDirection="locale"
android:textSize="14sp" />
@@ -140,6 +165,7 @@
/>
+
@@ -172,6 +199,7 @@
android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
android:singleLine="true"
android:textColor="@color/media_primary_text"
+ android:textDirection="locale"
android:textSize="16sp" />
@@ -182,6 +210,7 @@
android:fontFamily="@*android:string/config_headlineFontFamily"
android:singleLine="true"
android:textColor="@color/media_secondary_text"
+ android:textDirection="locale"
android:textSize="14sp" />
@@ -97,7 +97,7 @@
android:layout_marginBottom="24dp"
app:layout_constraintTop_toBottomOf="@id/header_title"
app:layout_constraintStart_toStartOf="@id/header_title"
- app:layout_constraintEnd_toStartOf="@id/action0"
+ app:layout_constraintEnd_toStartOf="@id/media_action_barrier"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0"/>
@@ -127,16 +127,38 @@
android:visibility="gone"
/>
+
+
+
+
@@ -188,9 +210,10 @@
android:layout_marginEnd="4dp"
android:visibility="gone"
android:layout_marginTop="18dp"
+ app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintTop_toBottomOf="@id/app_name"
app:layout_constraintLeft_toRightOf="@id/action3"
- app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintRight_toRightOf="@id/media_action_guidebox"
>
diff --git a/packages/SystemUI/res/xml/media_expanded.xml b/packages/SystemUI/res/xml/media_expanded.xml
index 9b4caa430185a..8432abcc16cbb 100644
--- a/packages/SystemUI/res/xml/media_expanded.xml
+++ b/packages/SystemUI/res/xml/media_expanded.xml
@@ -182,6 +182,7 @@
android:layout_marginStart="4dp"
android:layout_marginEnd="4dp"
android:layout_marginBottom="@dimen/qs_media_panel_outer_padding"
+ app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toRightOf="@id/action3"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/action0"
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
index 90961dbb014ae..fc22c026974ac 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
@@ -17,9 +17,11 @@
package com.android.systemui.media
import android.content.Context
+import android.content.res.Configuration
import android.graphics.PointF
import androidx.constraintlayout.widget.ConstraintSet
import com.android.systemui.R
+import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.animation.MeasurementOutput
import com.android.systemui.util.animation.TransitionLayout
import com.android.systemui.util.animation.TransitionLayoutController
@@ -32,6 +34,7 @@ import javax.inject.Inject
*/
class MediaViewController @Inject constructor(
context: Context,
+ private val configurationController: ConfigurationController,
private val mediaHostStatesManager: MediaHostStatesManager
) {
@@ -56,12 +59,14 @@ class MediaViewController @Inject constructor(
* The ending location of the view where it ends when all animations and transitions have
* finished
*/
+ @MediaLocation
private var currentEndLocation: Int = -1
/**
* The ending location of the view where it ends when all animations and transitions have
* finished
*/
+ @MediaLocation
private var currentStartLocation: Int = -1
/**
@@ -90,11 +95,32 @@ class MediaViewController @Inject constructor(
*/
var currentHeight: Int = 0
+ /**
+ * A callback for RTL config changes
+ */
+ private val configurationListener = object : ConfigurationController.ConfigurationListener {
+ override fun onConfigChanged(newConfig: Configuration?) {
+ // Because the TransitionLayout is not always attached (and calculates/caches layout
+ // results regardless of attach state), we have to force the layoutDirection of the view
+ // to the correct value for the user's current locale to ensure correct recalculation
+ // when/after calling refreshState()
+ newConfig?.apply {
+ if (transitionLayout?.rawLayoutDirection != layoutDirection) {
+ transitionLayout?.layoutDirection = layoutDirection
+ refreshState()
+ }
+ }
+ }
+ }
+
/**
* A callback for media state changes
*/
val stateCallback = object : MediaHostStatesManager.Callback {
- override fun onHostStateChanged(location: Int, mediaHostState: MediaHostState) {
+ override fun onHostStateChanged(
+ @MediaLocation location: Int,
+ mediaHostState: MediaHostState
+ ) {
if (location == currentEndLocation || location == currentStartLocation) {
setCurrentState(currentStartLocation,
currentEndLocation,
@@ -125,6 +151,7 @@ class MediaViewController @Inject constructor(
currentHeight = height
sizeChangedListener.invoke()
}
+ configurationController.addCallback(configurationListener)
}
/**
@@ -132,6 +159,7 @@ class MediaViewController @Inject constructor(
*/
fun onDestroy() {
mediaHostStatesManager.removeController(this)
+ configurationController.removeCallback(configurationListener)
}
private fun ensureAllMeasurements() {
@@ -346,7 +374,7 @@ class MediaViewController @Inject constructor(
// Let's clear all of our measurements and recreate them!
viewStates.clear()
setCurrentState(currentStartLocation, currentEndLocation, currentTransitionProgress,
- applyImmediately = false)
+ applyImmediately = true)
}
firstRefresh = false
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
index 9ede083fa9ac1..600fdc27ef89b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
@@ -48,6 +48,7 @@ class PlayerViewHolder private constructor(itemView: View) {
// Seek bar
val seekBar = itemView.requireViewById(R.id.media_progress_bar)
+ val progressTimes = itemView.requireViewById(R.id.notification_media_progress_time)
val elapsedTimeView = itemView.requireViewById(R.id.media_elapsed_time)
val totalTimeView = itemView.requireViewById(R.id.media_total_time)
@@ -93,8 +94,16 @@ class PlayerViewHolder private constructor(itemView: View) {
* @param parent Parent of inflated view.
*/
@JvmStatic fun create(inflater: LayoutInflater, parent: ViewGroup): PlayerViewHolder {
- val v = inflater.inflate(R.layout.media_view, parent, false)
- return PlayerViewHolder(v)
+ val mediaView = inflater.inflate(R.layout.media_view, parent, false)
+ // Because this media view (a TransitionLayout) is used to measure and layout the views
+ // in various states before being attached to its parent, we can't depend on the default
+ // LAYOUT_DIRECTION_INHERIT to correctly resolve the ltr direction.
+ mediaView.layoutDirection = View.LAYOUT_DIRECTION_LOCALE
+ return PlayerViewHolder(mediaView).apply {
+ // Media playback is in the direction of tape, not time, so it stays LTR
+ seekBar.layoutDirection = View.LAYOUT_DIRECTION_LTR
+ progressTimes.layoutDirection = View.LAYOUT_DIRECTION_LTR
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/UniqueObjectHostView.kt b/packages/SystemUI/src/com/android/systemui/util/animation/UniqueObjectHostView.kt
index 5b6444d8feaf2..d6e7a8b28f0cd 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/UniqueObjectHostView.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/UniqueObjectHostView.kt
@@ -70,7 +70,10 @@ class UniqueObjectHostView(
}
override fun addView(child: View?, index: Int, params: ViewGroup.LayoutParams?) {
- if (child?.measuredWidth == 0 || measuredWidth == 0 || child?.requiresRemeasuring == true) {
+ if (child == null) {
+ throw IllegalArgumentException("child must be non-null")
+ }
+ if (child.measuredWidth == 0 || measuredWidth == 0 || child.requiresRemeasuring == true) {
super.addView(child, index, params)
return
}
@@ -78,11 +81,13 @@ class UniqueObjectHostView(
// right size when being attached to this view
invalidate()
addViewInLayout(child, index, params, true /* preventRequestLayout */)
+ // RTL properties are normally resolved in onMeasure(), which we are intentionally skipping
+ child.resolveRtlPropertiesIfNeeded()
val left = paddingLeft
val top = paddingTop
val paddingHorizontal = paddingStart + paddingEnd
val paddingVertical = paddingTop + paddingBottom
- child!!.layout(left,
+ child.layout(left,
top,
left + measuredWidth - paddingHorizontal,
top + measuredHeight - paddingVertical)