Work back in media uri loading that was changed in the refactor
Rebuilt ag/11180565 and fixed a few cases while doing so. This also includes the fixes from ag/11270945 Test: play music from spotify Bug: 154137987 Change-Id: Ib912df716d754f451b68b289920a2e138977b9bd
This commit is contained in:
@@ -26,10 +26,13 @@ import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.graphics.drawable.RippleDrawable;
|
||||
import android.media.MediaMetadata;
|
||||
import android.media.session.MediaController;
|
||||
import android.media.session.MediaController.PlaybackInfo;
|
||||
import android.media.session.MediaSession;
|
||||
@@ -52,7 +55,10 @@ import androidx.constraintlayout.motion.widget.KeyAttributes;
|
||||
import androidx.constraintlayout.motion.widget.KeyFrames;
|
||||
import androidx.constraintlayout.motion.widget.MotionLayout;
|
||||
import androidx.constraintlayout.widget.ConstraintSet;
|
||||
import androidx.core.graphics.drawable.RoundedBitmapDrawable;
|
||||
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
|
||||
|
||||
import com.android.settingslib.Utils;
|
||||
import com.android.settingslib.media.LocalMediaManager;
|
||||
import com.android.settingslib.media.MediaDevice;
|
||||
import com.android.settingslib.media.MediaOutputSliceConstants;
|
||||
@@ -104,6 +110,8 @@ public class MediaControlPanel {
|
||||
private boolean mIsRegistered = false;
|
||||
private final List<KeyFrames> mKeyFrames;
|
||||
private String mKey;
|
||||
private int mAlbumArtSize;
|
||||
private int mAlbumArtRadius;
|
||||
|
||||
public static final String MEDIA_PREFERENCES = "media_control_prefs";
|
||||
public static final String MEDIA_PREFERENCE_KEY = "browser_components";
|
||||
@@ -112,13 +120,6 @@ public class MediaControlPanel {
|
||||
private boolean mIsRemotePlayback;
|
||||
private QSMediaBrowser mQSMediaBrowser;
|
||||
|
||||
// URI fields to try loading album art from
|
||||
private static final String[] ART_URIS = {
|
||||
MediaMetadata.METADATA_KEY_ALBUM_ART_URI,
|
||||
MediaMetadata.METADATA_KEY_ART_URI,
|
||||
MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI
|
||||
};
|
||||
|
||||
private final MediaController.Callback mSessionCallback = new MediaController.Callback() {
|
||||
@Override
|
||||
public void onSessionDestroyed() {
|
||||
@@ -210,6 +211,13 @@ public class MediaControlPanel {
|
||||
SeekBar bar = getView().findViewById(R.id.media_progress_bar);
|
||||
bar.setOnSeekBarChangeListener(mSeekBarViewModel.getSeekBarListener());
|
||||
bar.setOnTouchListener(mSeekBarViewModel.getSeekBarTouchListener());
|
||||
loadDimens();
|
||||
}
|
||||
|
||||
private void loadDimens() {
|
||||
mAlbumArtRadius = mContext.getResources().getDimensionPixelSize(
|
||||
Utils.getThemeAttr(mContext, android.R.attr.dialogCornerRadius));
|
||||
mAlbumArtSize = mContext.getResources().getDimensionPixelSize(R.dimen.qs_media_album_size);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -296,7 +304,10 @@ public class MediaControlPanel {
|
||||
}
|
||||
|
||||
ImageView albumView = mMediaNotifView.findViewById(R.id.album_art);
|
||||
albumView.setImageDrawable(data.getArtwork());
|
||||
// TODO: migrate this to a view with rounded corners instead of baking the rounding
|
||||
// into the bitmap
|
||||
Drawable artwork = createRoundedBitmap(data.getArtwork());
|
||||
albumView.setImageDrawable(artwork);
|
||||
|
||||
// App icon
|
||||
ImageView appIcon = mMediaNotifView.requireViewById(R.id.icon);
|
||||
@@ -400,6 +411,37 @@ public class MediaControlPanel {
|
||||
makeActive();
|
||||
}
|
||||
|
||||
private Drawable createRoundedBitmap(Icon icon) {
|
||||
if (icon == null) {
|
||||
return null;
|
||||
}
|
||||
// Let's scale down the View, such that the content always nicely fills the view.
|
||||
// ThumbnailUtils actually scales it down such that it may not be filled for odd aspect
|
||||
// ratios
|
||||
Drawable drawable = icon.loadDrawable(mContext);
|
||||
float aspectRatio = drawable.getIntrinsicHeight() / (float) drawable.getIntrinsicWidth();
|
||||
Rect bounds;
|
||||
if (aspectRatio > 1.0f) {
|
||||
bounds = new Rect(0, 0, mAlbumArtSize, (int) (mAlbumArtSize * aspectRatio));
|
||||
} else {
|
||||
bounds = new Rect(0, 0, (int) (mAlbumArtSize / aspectRatio), mAlbumArtSize);
|
||||
}
|
||||
if (bounds.width() > mAlbumArtSize || bounds.height() > mAlbumArtSize) {
|
||||
float offsetX = (bounds.width() - mAlbumArtSize) / 2.0f;
|
||||
float offsetY = (bounds.height() - mAlbumArtSize) / 2.0f;
|
||||
bounds.offset((int) -offsetX,(int) -offsetY);
|
||||
}
|
||||
drawable.setBounds(bounds);
|
||||
Bitmap scaled = Bitmap.createBitmap(mAlbumArtSize, mAlbumArtSize,
|
||||
Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(scaled);
|
||||
drawable.draw(canvas);
|
||||
RoundedBitmapDrawable artwork = RoundedBitmapDrawableFactory.create(
|
||||
mContext.getResources(), scaled);
|
||||
artwork.setCornerRadius(mAlbumArtRadius);
|
||||
return artwork;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the keyframe visibility such that only views that are not visible actually go
|
||||
* through a transition and fade in.
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.systemui.media
|
||||
|
||||
import android.app.PendingIntent
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.Icon
|
||||
import android.media.session.MediaSession
|
||||
|
||||
/** State of a media view. */
|
||||
@@ -27,9 +28,9 @@ data class MediaData(
|
||||
val backgroundColor: Int,
|
||||
val app: String?,
|
||||
val appIcon: Drawable?,
|
||||
val artist: String?,
|
||||
val song: String?,
|
||||
val artwork: Drawable?,
|
||||
val artist: CharSequence?,
|
||||
val song: CharSequence?,
|
||||
val artwork: Icon?,
|
||||
val actions: List<MediaAction>,
|
||||
val actionsToShowInCompact: List<Int>,
|
||||
val packageName: String?,
|
||||
|
||||
@@ -17,29 +17,45 @@
|
||||
package com.android.systemui.media
|
||||
|
||||
import android.app.Notification
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.ImageDecoder
|
||||
import android.graphics.Rect
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.Icon
|
||||
import android.media.MediaMetadata
|
||||
import android.media.session.MediaSession
|
||||
import android.media.session.PlaybackState
|
||||
import android.net.Uri
|
||||
import android.provider.Settings
|
||||
import android.service.notification.StatusBarNotification
|
||||
import androidx.core.graphics.drawable.RoundedBitmapDrawable
|
||||
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
|
||||
import android.text.TextUtils
|
||||
import android.util.Log
|
||||
import com.android.internal.util.ContrastColorUtil
|
||||
import com.android.settingslib.Utils
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.dagger.qualifiers.Background
|
||||
import com.android.systemui.dagger.qualifiers.Main
|
||||
import com.android.systemui.statusbar.NotificationMediaManager
|
||||
import com.android.systemui.statusbar.notification.MediaNotificationProcessor
|
||||
import com.android.systemui.statusbar.notification.row.HybridGroupManager
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
import java.util.concurrent.Executor
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import kotlin.collections.LinkedHashMap
|
||||
|
||||
// URI fields to try loading album art from
|
||||
private val ART_URIS = arrayOf(
|
||||
MediaMetadata.METADATA_KEY_ALBUM_ART_URI,
|
||||
MediaMetadata.METADATA_KEY_ART_URI,
|
||||
MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI
|
||||
)
|
||||
|
||||
private const val TAG = "MediaDataManager"
|
||||
|
||||
private val LOADING = MediaData(false, 0, 0, null, null, null, null, null,
|
||||
emptyList(), emptyList(), null, null, null)
|
||||
|
||||
/**
|
||||
* A class that facilitates management and loading of Media Data, ready for binding.
|
||||
*/
|
||||
@@ -52,20 +68,8 @@ class MediaDataManager @Inject constructor(
|
||||
) {
|
||||
|
||||
private val listeners: MutableSet<Listener> = mutableSetOf()
|
||||
private var albumArtSize: Int = 0
|
||||
private var albumArtRadius: Int = 0
|
||||
private val mediaEntries: LinkedHashMap<String, MediaData> = LinkedHashMap()
|
||||
|
||||
init {
|
||||
loadDimens()
|
||||
}
|
||||
|
||||
private fun loadDimens() {
|
||||
albumArtRadius = context.resources.getDimensionPixelSize(
|
||||
Utils.getThemeAttr(context, android.R.attr.dialogCornerRadius))
|
||||
albumArtSize = context.resources.getDimensionPixelSize(R.dimen.qs_media_album_size)
|
||||
}
|
||||
|
||||
fun onNotificationAdded(key: String, sbn: StatusBarNotification) {
|
||||
if (isMediaNotification(sbn)) {
|
||||
if (!mediaEntries.containsKey(key)) {
|
||||
@@ -111,9 +115,31 @@ class MediaDataManager @Inject constructor(
|
||||
if (artworkBitmap == null) {
|
||||
artworkBitmap = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART)
|
||||
}
|
||||
// TODO: load media data from uri
|
||||
if (artworkBitmap != null) {
|
||||
if (artworkBitmap == null) {
|
||||
artworkBitmap = loadBitmapFromUri(metadata)
|
||||
}
|
||||
val artWorkIcon = if (artworkBitmap == null) {
|
||||
notif.getLargeIcon()
|
||||
} else {
|
||||
Icon.createWithBitmap(artworkBitmap)
|
||||
}
|
||||
if (artWorkIcon != null) {
|
||||
// If we have art, get colors from that
|
||||
if (artworkBitmap == null) {
|
||||
if (artWorkIcon.type == Icon.TYPE_BITMAP
|
||||
|| artWorkIcon.type == Icon.TYPE_ADAPTIVE_BITMAP) {
|
||||
artworkBitmap = artWorkIcon.bitmap
|
||||
} else {
|
||||
val drawable: Drawable = artWorkIcon.loadDrawable(context)
|
||||
artworkBitmap = Bitmap.createBitmap(
|
||||
drawable.intrinsicWidth,
|
||||
drawable.intrinsicHeight,
|
||||
Bitmap.Config.ARGB_8888)
|
||||
val canvas = Canvas(artworkBitmap)
|
||||
drawable.setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight)
|
||||
drawable.draw(canvas)
|
||||
}
|
||||
}
|
||||
val p = MediaNotificationProcessor.generateArtworkPaletteBuilder(artworkBitmap)
|
||||
.generate()
|
||||
val swatch = MediaNotificationProcessor.findBackgroundSwatch(p)
|
||||
@@ -126,16 +152,6 @@ class MediaDataManager @Inject constructor(
|
||||
isDark)
|
||||
fgColor = ContrastColorUtil.ensureTextContrast(fgColor, bgColor, isDark)
|
||||
|
||||
// Album art
|
||||
var artwork: RoundedBitmapDrawable? = null
|
||||
if (artworkBitmap != null) {
|
||||
val original = artworkBitmap.copy(Bitmap.Config.ARGB_8888, true)
|
||||
val scaled = Bitmap.createScaledBitmap(original, albumArtSize, albumArtSize,
|
||||
false)
|
||||
artwork = RoundedBitmapDrawableFactory.create(context.resources, scaled)
|
||||
artwork.cornerRadius = albumArtRadius.toFloat()
|
||||
}
|
||||
|
||||
// App name
|
||||
val builder = Notification.Builder.recoverBuilder(context, notif)
|
||||
val app = builder.loadHeaderAppName()
|
||||
@@ -144,10 +160,19 @@ class MediaDataManager @Inject constructor(
|
||||
val smallIconDrawable: Drawable = sbn.notification.smallIcon.loadDrawable(context)
|
||||
|
||||
// Song name
|
||||
val song: String = metadata.getString(MediaMetadata.METADATA_KEY_TITLE)
|
||||
var song: CharSequence? = metadata.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE)
|
||||
if (song == null) {
|
||||
song = metadata.getString(MediaMetadata.METADATA_KEY_TITLE)
|
||||
}
|
||||
if (song == null) {
|
||||
song = HybridGroupManager.resolveTitle(notif)
|
||||
}
|
||||
|
||||
// Artist name
|
||||
val artist: String = metadata.getString(MediaMetadata.METADATA_KEY_ARTIST)
|
||||
var artist: CharSequence? = metadata.getString(MediaMetadata.METADATA_KEY_ARTIST)
|
||||
if (artist == null) {
|
||||
artist = HybridGroupManager.resolveText(notif)
|
||||
}
|
||||
|
||||
// Control buttons
|
||||
val actionIcons: MutableList<MediaAction> = ArrayList()
|
||||
@@ -167,12 +192,55 @@ class MediaDataManager @Inject constructor(
|
||||
|
||||
foregroundExcecutor.execute {
|
||||
onMediaDataLoaded(key, MediaData(true, fgColor, bgColor, app, smallIconDrawable, artist,
|
||||
song, artwork, actionIcons, actionsToShowCollapsed, sbn.packageName, token,
|
||||
song, artWorkIcon, actionIcons, actionsToShowCollapsed, sbn.packageName, token,
|
||||
notif.contentIntent))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a bitmap from the various Art metadata URIs
|
||||
*/
|
||||
private fun loadBitmapFromUri(metadata: MediaMetadata): Bitmap? {
|
||||
for (uri in ART_URIS) {
|
||||
val uriString = metadata.getString(uri)
|
||||
if (!TextUtils.isEmpty(uriString)) {
|
||||
val albumArt = loadBitmapFromUri(Uri.parse(uriString))
|
||||
if (albumArt != null) {
|
||||
Log.d(TAG, "loaded art from $uri")
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a bitmap from a URI
|
||||
* @param uri the uri to load
|
||||
* @return bitmap, or null if couldn't be loaded
|
||||
*/
|
||||
private fun loadBitmapFromUri(uri: Uri): Bitmap? {
|
||||
// ImageDecoder requires a scheme of the following types
|
||||
if (uri.getScheme() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)
|
||||
&& !uri.getScheme().equals(ContentResolver.SCHEME_ANDROID_RESOURCE)
|
||||
&& !uri.getScheme().equals(ContentResolver.SCHEME_FILE)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
val source = ImageDecoder.createSource(context.getContentResolver(), uri)
|
||||
return try {
|
||||
ImageDecoder.decodeBitmap(source)
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun onMediaDataLoaded(key: String, data: MediaData) {
|
||||
if (mediaEntries.containsKey(key)) {
|
||||
// Otherwise this was removed already
|
||||
@@ -236,6 +304,3 @@ class MediaDataManager @Inject constructor(
|
||||
fun onMediaDataRemoved(key: String) {}
|
||||
}
|
||||
}
|
||||
|
||||
private val LOADING = MediaData(false, 0, 0, null, null, null, null, null,
|
||||
emptyList(), emptyList(), null, null, null)
|
||||
|
||||
@@ -109,7 +109,7 @@ public class HybridGroupManager {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private CharSequence resolveText(Notification notification) {
|
||||
public static CharSequence resolveText(Notification notification) {
|
||||
CharSequence contentText = notification.extras.getCharSequence(Notification.EXTRA_TEXT);
|
||||
if (contentText == null) {
|
||||
contentText = notification.extras.getCharSequence(Notification.EXTRA_BIG_TEXT);
|
||||
@@ -118,7 +118,7 @@ public class HybridGroupManager {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private CharSequence resolveTitle(Notification notification) {
|
||||
public static CharSequence resolveTitle(Notification notification) {
|
||||
CharSequence titleText = notification.extras.getCharSequence(Notification.EXTRA_TITLE);
|
||||
if (titleText == null) {
|
||||
titleText = notification.extras.getCharSequence(Notification.EXTRA_TITLE_BIG);
|
||||
|
||||
Reference in New Issue
Block a user