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:
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 -->
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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"
|
||||
/>
|
||||
|
||||
|
||||
@@ -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"
|
||||
/>
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user