Use system colors for media

Instead of deriving background color from the album art, use theme colors
Also fixes layout so the output switcher touch target is not too wide

Bug: 176177555
Test: visual
Change-Id: I3de7caa6cd6870f65d50068a81af4472e0566ed7
This commit is contained in:
Beth Thibodeau
2021-02-08 13:47:04 -05:00
parent 2fa12f8ec3
commit 16ea9a6951
9 changed files with 67 additions and 83 deletions

View File

@@ -47,7 +47,7 @@
android:layout_width="wrap_content"
android:layout_height="48dp"
android:layout_marginBottom="4dp"
android:tint="@color/media_primary_text"
android:tint="?android:attr/textColorPrimary"
android:forceHasOverlappingRendering="false"
/>
</FrameLayout>

View File

@@ -48,7 +48,7 @@
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:fontFamily="@*android:string/config_bodyFontFamily"
android:textColor="@color/media_primary_text"
android:textColor="?android:attr/textColorPrimary"
android:gravity="start"
android:textSize="14sp" />
@@ -58,7 +58,7 @@
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:fontFamily="@*android:string/config_bodyFontFamily"
android:textColor="@color/media_primary_text"
android:textColor="?android:attr/textColorPrimary"
android:gravity="end"
android:textSize="14sp" />
</FrameLayout>
@@ -120,13 +120,13 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical|end"
android:gravity="center"
android:background="@drawable/qs_media_light_source"
android:forceHasOverlappingRendering="false">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:foreground="@drawable/qs_media_seamless_background"
android:background="@drawable/qs_media_light_source"
android:background="@drawable/qs_media_seamless_background"
android:orientation="horizontal"
android:padding="6dp"
android:contentDescription="@string/quick_settings_media_device_label">
@@ -135,7 +135,7 @@
android:layout_width="@dimen/qs_seamless_icon_size"
android:layout_height="@dimen/qs_seamless_icon_size"
android:layout_gravity="center"
android:tint="@color/media_primary_text"
android:tint="?android:attr/colorPrimary"
android:src="@*android:drawable/ic_media_seamless" />
<TextView
android:visibility="gone"
@@ -147,7 +147,7 @@
android:fontFamily="@*android:string/config_headlineFontFamily"
android:singleLine="true"
android:text="@*android:string/ext_media_seamless_action"
android:textColor="@color/media_primary_text"
android:textColor="?android:attr/colorPrimary"
android:textDirection="locale"
android:textSize="14sp" />
</LinearLayout>
@@ -157,7 +157,7 @@
android:id="@+id/media_seamless_fallback"
android:layout_width="@dimen/qs_seamless_icon_size"
android:layout_height="@dimen/qs_seamless_icon_size"
android:tint="@color/media_primary_text"
android:tint="?android:attr/textColorPrimary"
android:src="@drawable/ic_cast_connected"
android:forceHasOverlappingRendering="false" />
@@ -171,15 +171,15 @@
android:clickable="true"
android:maxHeight="@dimen/qs_media_enabled_seekbar_height"
android:paddingVertical="@dimen/qs_media_enabled_seekbar_vertical_padding"
android:thumbTint="@color/media_primary_text"
android:progressTint="@color/media_seekbar_progress"
android:progressBackgroundTint="@color/media_disabled"
android:thumbTint="?android:attr/textColorPrimary"
android:progressTint="?android:attr/textColorPrimary"
android:progressBackgroundTint="?android:attr/colorBackground"
android:splitTrack="false" />
<!-- App name -->
<TextView
android:id="@+id/app_name"
android:textColor="@color/media_primary_text"
android:textColor="?android:attr/textColorPrimary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:singleLine="true"
@@ -194,7 +194,7 @@
android:layout_height="wrap_content"
android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
android:singleLine="true"
android:textColor="@color/media_primary_text"
android:textColor="?android:attr/textColorPrimary"
android:textSize="16sp" />
<!-- Artist name -->
@@ -204,12 +204,12 @@
android:layout_height="wrap_content"
android:fontFamily="@*android:string/config_headlineFontFamily"
android:singleLine="true"
android:textColor="@color/media_secondary_text"
android:textColor="?android:attr/textColorSecondary"
android:textSize="14sp" />
<com.android.internal.widget.CachingIconView
android:id="@+id/icon"
android:tint="@color/media_primary_text"
android:tint="?android:attr/textColorPrimary"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_margin="6dp" />
@@ -223,7 +223,7 @@
android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
android:id="@+id/media_text"
android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
android:textColor="@color/media_primary_text"
android:textColor="?android:attr/textColorSecondary"
android:text="@string/controls_media_title"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
@@ -238,7 +238,7 @@
android:id="@+id/remove_text"
android:fontFamily="@*android:string/config_headlineFontFamily"
android:singleLine="true"
android:textColor="@color/media_primary_text"
android:textColor="?android:attr/textColorPrimary"
android:text="@string/controls_media_close_session"
app:layout_constraintTop_toBottomOf="@id/media_text"
app:layout_constraintStart_toStartOf="parent"
@@ -262,7 +262,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
android:textColor="@android:color/white"
android:textColor="?android:attr/textColorPrimary"
android:text="@string/controls_media_settings_button" />
</FrameLayout>
@@ -283,7 +283,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
android:textColor="@android:color/white"
android:textColor="?android:attr/textColorPrimary"
android:text="@string/cancel" />
</FrameLayout>
@@ -304,7 +304,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
android:textColor="@android:color/white"
android:textColor="?android:attr/textColorPrimary"
android:text="@string/controls_media_dismiss_button"
/>
</FrameLayout>

View File

@@ -240,11 +240,8 @@
<color name="magnification_switch_button_color">#7F000000</color>
<!-- media -->
<color name="media_primary_text">@android:color/white</color>
<color name="media_secondary_text">#99ffffff</color> <!-- 60% -->
<color name="media_seekbar_progress">#c0ffffff</color>
<color name="media_disabled">#80ffffff</color>
<color name="media_seamless_border">#26ffffff</color> <!-- 15% -->
<color name="media_seamless_border">?android:attr/colorAccent</color>
<color name="media_divider">#1d000000</color>
<!-- controls -->

View File

@@ -582,7 +582,7 @@
<style name="MediaPlayer.Button" parent="@android:style/Widget.Material.Button.Borderless.Small">
<item name="android:background">@drawable/qs_media_light_source</item>
<item name="android:tint">@android:color/white</item>
<item name="android:tint">?android:attr/textColorPrimary</item>
<item name="android:stateListAnimator">@anim/media_button_state_list_animator</item>
</style>

View File

@@ -36,25 +36,23 @@
app:layout_constraintTop_toTopOf="@id/icon"
app:layout_constraintBottom_toBottomOf="@id/icon"
app:layout_constraintStart_toEndOf="@id/icon"
app:layout_constraintEnd_toStartOf="@id/media_seamless"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintEnd_toStartOf="@id/center_vertical_guideline"
app:layout_constrainedWidth="true"
app:layout_constraintHorizontal_bias="0"
/>
<Constraint
android:id="@+id/media_seamless"
android:layout_width="0dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@id/app_name"
app:layout_constraintStart_toEndOf="@id/center_vertical_guideline"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintHorizontal_bias="1"
app:layout_constrainedWidth="true"
app:layout_constraintWidth_min="48dp"
app:layout_constraintHeight_min="48dp"
android:layout_marginEnd="@dimen/qs_center_guideline_padding"
android:layout_marginStart="@dimen/qs_center_guideline_padding"
/>

View File

@@ -36,25 +36,23 @@
app:layout_constraintTop_toTopOf="@id/icon"
app:layout_constraintBottom_toBottomOf="@id/icon"
app:layout_constraintStart_toEndOf="@id/icon"
app:layout_constraintEnd_toStartOf="@id/media_seamless"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintEnd_toStartOf="@id/center_vertical_guideline"
app:layout_constrainedWidth="true"
app:layout_constraintHorizontal_bias="0"
/>
<Constraint
android:id="@+id/media_seamless"
android:layout_width="0dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@id/app_name"
app:layout_constraintStart_toEndOf="@id/center_vertical_guideline"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintHorizontal_bias="1"
app:layout_constrainedWidth="true"
app:layout_constraintWidth_min="48dp"
app:layout_constraintHeight_min="48dp"
android:layout_marginEnd="@dimen/qs_center_guideline_padding"
android:layout_marginStart="@dimen/qs_center_guideline_padding"
/>

View File

@@ -1,7 +1,9 @@
package com.android.systemui.media
import android.animation.ArgbEvaluator
import android.content.Context
import android.content.Intent
import android.content.res.ColorStateList
import android.content.res.Configuration
import android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS
import android.util.Log
@@ -112,6 +114,9 @@ class MediaCarouselController @Inject constructor(
private val visualStabilityCallback: VisualStabilityManager.Callback
private var needsReordering: Boolean = false
private var keysNeedRemoval = mutableSetOf<String>()
private var bgColor = getBackgroundColor()
private var fgColor = com.android.settingslib.Utils.getColorAttr(context,
com.android.internal.R.attr.textColorPrimary).defaultColor
private var isRtl: Boolean = false
set(value) {
if (value != field) {
@@ -147,7 +152,7 @@ class MediaCarouselController @Inject constructor(
}
override fun onUiModeChanged() {
// Only settings button needs to update for dark theme
recreatePlayers()
inflateSettingsButton()
}
}
@@ -249,6 +254,11 @@ class MediaCarouselController @Inject constructor(
}
private fun addOrUpdatePlayer(key: String, oldKey: String?, data: MediaData) {
data.actions.forEach {
it.icon?.setTintList(ColorStateList.valueOf(fgColor))
}
data.appIcon?.setTintList(ColorStateList.valueOf(fgColor))
val dataCopy = data.copy(backgroundColor = bgColor)
val existingPlayer = MediaPlayerData.getMediaPlayer(key, oldKey)
if (existingPlayer == null) {
var newPlayer = mediaControlPanelFactory.get()
@@ -257,14 +267,14 @@ class MediaCarouselController @Inject constructor(
val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT)
newPlayer.view?.player?.setLayoutParams(lp)
newPlayer.bind(data, key)
newPlayer.bind(dataCopy, key)
newPlayer.setListening(currentlyExpanded)
MediaPlayerData.addMediaPlayer(key, data, newPlayer)
MediaPlayerData.addMediaPlayer(key, dataCopy, newPlayer)
updatePlayerToState(newPlayer, noAnimation = true)
reorderAllPlayers()
} else {
existingPlayer.bind(data, key)
MediaPlayerData.addMediaPlayer(key, data, existingPlayer)
existingPlayer.bind(dataCopy, key)
MediaPlayerData.addMediaPlayer(key, dataCopy, existingPlayer)
if (visualStabilityManager.isReorderingAllowed) {
reorderAllPlayers()
} else {
@@ -298,12 +308,27 @@ class MediaCarouselController @Inject constructor(
}
private fun recreatePlayers() {
bgColor = getBackgroundColor()
fgColor = com.android.settingslib.Utils.getColorAttr(context,
com.android.internal.R.attr.textColorPrimary).defaultColor
pageIndicator.tintList = ColorStateList.valueOf(fgColor)
MediaPlayerData.mediaData().forEach { (key, data) ->
removePlayer(key, dismissMediaData = false)
addOrUpdatePlayer(key = key, oldKey = null, data = data)
}
}
private fun getBackgroundColor(): Int {
val themeAccent = com.android.settingslib.Utils.getColorAttr(context,
com.android.internal.R.attr.colorAccent).defaultColor
val themeBackground = com.android.settingslib.Utils.getColorAttr(context,
com.android.internal.R.attr.colorBackground).defaultColor
// Simulate transparency - cannot be actually transparent because of lockscreen
return ArgbEvaluator().evaluate(0.25f, themeBackground, themeAccent) as Int
}
private fun updatePageIndicator() {
val numPages = mediaContent.getChildCount()
pageIndicator.setNumPages(numPages)

View File

@@ -25,7 +25,6 @@ import android.content.Intent
import android.content.IntentFilter
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.ImageDecoder
import android.graphics.drawable.Drawable
import android.graphics.drawable.Icon
@@ -38,7 +37,6 @@ import android.os.UserHandle
import android.service.notification.StatusBarNotification
import android.text.TextUtils
import android.util.Log
import com.android.internal.graphics.ColorUtils
import com.android.systemui.Dumpable
import com.android.systemui.R
import com.android.systemui.broadcast.BroadcastDispatcher
@@ -48,7 +46,6 @@ import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.NotificationMediaManager.isPlayingState
import com.android.systemui.statusbar.notification.MediaNotificationProcessor
import com.android.systemui.statusbar.notification.row.HybridGroupManager
import com.android.systemui.util.Assert
import com.android.systemui.util.Utils
@@ -68,10 +65,6 @@ private val ART_URIS = arrayOf(
private const val TAG = "MediaDataManager"
private const val DEBUG = true
private const val DEFAULT_LUMINOSITY = 0.25f
private const val LUMINOSITY_THRESHOLD = 0.05f
private const val SATURATION_MULTIPLIER = 0.8f
const val DEFAULT_COLOR = Color.DKGRAY
private val LOADING = MediaData(-1, false, 0, null, null, null, null, null,
emptyList(), emptyList(), "INVALID", null, null, null, true, null)
@@ -110,6 +103,11 @@ class MediaDataManager(
private val useQsMediaPlayer: Boolean
) : Dumpable {
private val themeText = com.android.settingslib.Utils.getColorAttr(context,
com.android.internal.R.attr.textColorPrimary).defaultColor
private val bgColor = com.android.settingslib.Utils.getColorAttr(context,
com.android.internal.R.attr.colorBackground).defaultColor
// Internal listeners are part of the internal pipeline. External listeners (those registered
// with [MediaDeviceManager.addListener]) receive events after they have propagated through
// the internal pipeline.
@@ -395,7 +393,6 @@ class MediaDataManager(
} else {
null
}
val bgColor = artworkBitmap?.let { computeBackgroundColor(it) } ?: DEFAULT_COLOR
val mediaAction = getResumeMediaAction(resumeAction)
foregroundExecutor.execute {
@@ -449,7 +446,6 @@ class MediaDataManager(
}
}
}
val bgColor = computeBackgroundColor(artworkBitmap)
// App name
val builder = Notification.Builder.recoverBuilder(context, notif)
@@ -506,7 +502,7 @@ class MediaDataManager(
Icon.createWithResource(packageContext, action.getIcon()!!.getResId())
} else {
action.getIcon()
}
}.setTint(themeText)
val mediaAction = MediaAction(
mediaActionIcon,
runnable,
@@ -589,38 +585,9 @@ class MediaDataManager(
}
}
private fun computeBackgroundColor(artworkBitmap: Bitmap?): Int {
var color = Color.WHITE
if (artworkBitmap != null && artworkBitmap.width > 1 && artworkBitmap.height > 1) {
// If we have valid art, get colors from that
val p = MediaNotificationProcessor.generateArtworkPaletteBuilder(artworkBitmap)
.generate()
val swatch = MediaNotificationProcessor.findBackgroundSwatch(p)
color = swatch.rgb
} else {
return DEFAULT_COLOR
}
// Adapt background color, so it's always subdued and text is legible
val tmpHsl = floatArrayOf(0f, 0f, 0f)
ColorUtils.colorToHSL(color, tmpHsl)
val l = tmpHsl[2]
// Colors with very low luminosity can have any saturation. This means that changing the
// luminosity can make a black become red. Let's remove the saturation of very light or
// very dark colors to avoid this issue.
if (l < LUMINOSITY_THRESHOLD || l > 1f - LUMINOSITY_THRESHOLD) {
tmpHsl[1] = 0f
}
tmpHsl[1] *= SATURATION_MULTIPLIER
tmpHsl[2] = DEFAULT_LUMINOSITY
color = ColorUtils.HSLToColor(tmpHsl)
return color
}
private fun getResumeMediaAction(action: Runnable): MediaAction {
return MediaAction(
Icon.createWithResource(context, R.drawable.lb_ic_play),
Icon.createWithResource(context, R.drawable.lb_ic_play).setTint(themeText),
action,
context.getString(R.string.controls_media_resume)
)

View File

@@ -315,10 +315,9 @@ class MediaDataManagerTest : SysuiTestCase() {
}
mediaDataManager.onNotificationAdded(KEY, notif)
// THEN it loads and uses the default background color
// THEN it still loads
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor))
assertThat(mediaDataCaptor.value!!.backgroundColor).isEqualTo(DEFAULT_COLOR)
}
}