Merge "Improve album art handling" into rvc-dev am: 9f4b4c23e7 am: feca79eac0

Change-Id: I12ae88a011e71b0c1875d453fc333f13ce7b7e14
This commit is contained in:
Beth Thibodeau
2020-04-21 20:24:39 +00:00
committed by Automerger Merge Worker
5 changed files with 100 additions and 23 deletions

View File

@@ -26,14 +26,18 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.content.res.ColorStateList; import android.content.res.ColorStateList;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.ImageDecoder;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.Icon;
import android.graphics.drawable.RippleDrawable; import android.graphics.drawable.RippleDrawable;
import android.media.MediaDescription; import android.media.MediaDescription;
import android.media.MediaMetadata; import android.media.MediaMetadata;
import android.media.ThumbnailUtils;
import android.media.session.MediaController; import android.media.session.MediaController;
import android.media.session.MediaSession; import android.media.session.MediaSession;
import android.media.session.PlaybackState; import android.media.session.PlaybackState;
import android.net.Uri;
import android.service.media.MediaBrowserService; import android.service.media.MediaBrowserService;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@@ -59,6 +63,7 @@ import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.qs.QSMediaBrowser; import com.android.systemui.qs.QSMediaBrowser;
import com.android.systemui.util.Assert; import com.android.systemui.util.Assert;
import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
@@ -99,6 +104,13 @@ public class MediaControlPanel {
com.android.internal.R.id.action4 com.android.internal.R.id.action4
}; };
// 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() { private final MediaController.Callback mSessionCallback = new MediaController.Callback() {
@Override @Override
public void onSessionDestroyed() { public void onSessionDestroyed() {
@@ -205,14 +217,16 @@ public class MediaControlPanel {
* Update the media panel view for the given media session * Update the media panel view for the given media session
* @param token * @param token
* @param iconDrawable * @param iconDrawable
* @param largeIcon
* @param iconColor * @param iconColor
* @param bgColor * @param bgColor
* @param contentIntent * @param contentIntent
* @param appNameString * @param appNameString
* @param key * @param key
*/ */
public void setMediaSession(MediaSession.Token token, Drawable iconDrawable, int iconColor, public void setMediaSession(MediaSession.Token token, Drawable iconDrawable, Icon largeIcon,
int bgColor, PendingIntent contentIntent, String appNameString, String key) { int iconColor, int bgColor, PendingIntent contentIntent, String appNameString,
String key) {
// Ensure that component names are updated if token has changed // Ensure that component names are updated if token has changed
if (mToken == null || !mToken.equals(token)) { if (mToken == null || !mToken.equals(token)) {
mToken = token; mToken = token;
@@ -303,7 +317,7 @@ public class MediaControlPanel {
ImageView albumView = mMediaNotifView.findViewById(R.id.album_art); ImageView albumView = mMediaNotifView.findViewById(R.id.album_art);
if (albumView != null) { if (albumView != null) {
// Resize art in a background thread // Resize art in a background thread
mBackgroundExecutor.execute(() -> processAlbumArt(mediaMetadata, albumView)); mBackgroundExecutor.execute(() -> processAlbumArt(mediaMetadata, largeIcon, albumView));
} }
// Song name // Song name
@@ -396,30 +410,82 @@ public class MediaControlPanel {
* @param albumView view to hold the album art * @param albumView view to hold the album art
*/ */
protected void processAlbumArt(MediaDescription description, ImageView albumView) { protected void processAlbumArt(MediaDescription description, ImageView albumView) {
Bitmap albumArt = description.getIconBitmap(); Bitmap albumArt = null;
//TODO check other fields (b/151054111, b/152067055)
// First try loading from URI
albumArt = loadBitmapFromUri(description.getIconUri());
// Then check bitmap
if (albumArt == null) {
albumArt = description.getIconBitmap();
}
processAlbumArtInternal(albumArt, albumView); processAlbumArtInternal(albumArt, albumView);
} }
/** /**
* Process album art for layout * Process album art for layout
* @param metadata media metadata * @param metadata media metadata
* @param largeIcon from notification, checked as a fallback if metadata does not have art
* @param albumView view to hold the album art * @param albumView view to hold the album art
*/ */
private void processAlbumArt(MediaMetadata metadata, ImageView albumView) { private void processAlbumArt(MediaMetadata metadata, Icon largeIcon, ImageView albumView) {
Bitmap albumArt = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART); Bitmap albumArt = null;
//TODO check other fields (b/151054111, b/152067055)
// First look in URI fields
for (String field : ART_URIS) {
String uriString = metadata.getString(field);
if (uriString != null) {
albumArt = loadBitmapFromUri(Uri.parse(uriString));
if (albumArt != null) {
Log.d(TAG, "loaded art from " + field);
break;
}
}
}
// Then check bitmap field
if (albumArt == null) {
albumArt = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
}
// Finally try the notification's largeIcon
if (albumArt == null && largeIcon != null) {
albumArt = largeIcon.getBitmap();
}
processAlbumArtInternal(albumArt, albumView); processAlbumArtInternal(albumArt, albumView);
} }
private void processAlbumArtInternal(Bitmap albumArt, ImageView albumView) { /**
float radius = mContext.getResources().getDimension(R.dimen.qs_media_corner_radius); * Load a bitmap from a URI
* @param uri
* @return bitmap, or null if couldn't be loaded
*/
private Bitmap loadBitmapFromUri(Uri uri) {
ImageDecoder.Source source = ImageDecoder.createSource(mContext.getContentResolver(), uri);
try {
return ImageDecoder.decodeBitmap(source);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
/**
* Resize and crop the image if provided and update the control view
* @param albumArt Bitmap of art to display, or null to hide view
* @param albumView View that will hold the art
*/
private void processAlbumArtInternal(@Nullable Bitmap albumArt, ImageView albumView) {
// Resize
RoundedBitmapDrawable roundedDrawable = null; RoundedBitmapDrawable roundedDrawable = null;
if (albumArt != null) { if (albumArt != null) {
float radius = mContext.getResources().getDimension(R.dimen.qs_media_corner_radius);
Bitmap original = albumArt.copy(Bitmap.Config.ARGB_8888, true); Bitmap original = albumArt.copy(Bitmap.Config.ARGB_8888, true);
int albumSize = (int) mContext.getResources().getDimension( int albumSize = (int) mContext.getResources().getDimension(
R.dimen.qs_media_album_size); R.dimen.qs_media_album_size);
Bitmap scaled = Bitmap.createScaledBitmap(original, albumSize, albumSize, false); Bitmap scaled = ThumbnailUtils.extractThumbnail(original, albumSize, albumSize);
roundedDrawable = RoundedBitmapDrawableFactory.create(mContext.getResources(), scaled); roundedDrawable = RoundedBitmapDrawableFactory.create(mContext.getResources(), scaled);
roundedDrawable.setCornerRadius(radius); roundedDrawable.setCornerRadius(radius);
} else { } else {

View File

@@ -23,6 +23,7 @@ import android.content.Context;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.res.ColorStateList; import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.media.MediaDescription; import android.media.MediaDescription;
import android.media.session.MediaController; import android.media.session.MediaController;
import android.media.session.MediaSession; import android.media.session.MediaSession;
@@ -115,8 +116,8 @@ public class QSMediaPlayer extends MediaControlPanel {
} }
// Set what we can normally // Set what we can normally
super.setMediaSession(token, icon, iconColor, bgColor, contentIntent, appName.toString(), super.setMediaSession(token, icon, null, iconColor, bgColor, contentIntent,
null); appName.toString(), null);
// Then add info from MediaDescription // Then add info from MediaDescription
ImageView albumView = mMediaNotifView.findViewById(R.id.album_art); ImageView albumView = mMediaNotifView.findViewById(R.id.album_art);
@@ -149,6 +150,7 @@ public class QSMediaPlayer extends MediaControlPanel {
* Update media panel view for the given media session * Update media panel view for the given media session
* @param token token for this media session * @param token token for this media session
* @param icon app notification icon * @param icon app notification icon
* @param largeIcon notification's largeIcon, used as a fallback for album art
* @param iconColor foreground color (for text, icons) * @param iconColor foreground color (for text, icons)
* @param bgColor background color * @param bgColor background color
* @param actionsContainer a LinearLayout containing the media action buttons * @param actionsContainer a LinearLayout containing the media action buttons
@@ -156,11 +158,12 @@ public class QSMediaPlayer extends MediaControlPanel {
* @param appName Application title * @param appName Application title
* @param key original notification's key * @param key original notification's key
*/ */
public void setMediaSession(MediaSession.Token token, Drawable icon, int iconColor, public void setMediaSession(MediaSession.Token token, Drawable icon, Icon largeIcon,
int bgColor, View actionsContainer, PendingIntent contentIntent, String appName, int iconColor, int bgColor, View actionsContainer, PendingIntent contentIntent,
String key) { String appName, String key) {
super.setMediaSession(token, icon, iconColor, bgColor, contentIntent, appName, key); super.setMediaSession(token, icon, largeIcon, iconColor, bgColor, contentIntent, appName,
key);
// Media controls // Media controls
if (actionsContainer != null) { if (actionsContainer != null) {

View File

@@ -32,6 +32,7 @@ import android.content.res.Configuration;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.media.MediaDescription; import android.media.MediaDescription;
import android.media.session.MediaSession; import android.media.session.MediaSession;
import android.metrics.LogMaker; import android.metrics.LogMaker;
@@ -225,14 +226,16 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
* Add or update a player for the associated media session * Add or update a player for the associated media session
* @param token * @param token
* @param icon * @param icon
* @param largeIcon
* @param iconColor * @param iconColor
* @param bgColor * @param bgColor
* @param actionsContainer * @param actionsContainer
* @param notif * @param notif
* @param key * @param key
*/ */
public void addMediaSession(MediaSession.Token token, Drawable icon, int iconColor, int bgColor, public void addMediaSession(MediaSession.Token token, Drawable icon, Icon largeIcon,
View actionsContainer, StatusBarNotification notif, String key) { int iconColor, int bgColor, View actionsContainer, StatusBarNotification notif,
String key) {
if (!useQsMediaPlayer(mContext)) { if (!useQsMediaPlayer(mContext)) {
// Shouldn't happen, but just in case // Shouldn't happen, but just in case
Log.e(TAG, "Tried to add media session without player!"); Log.e(TAG, "Tried to add media session without player!");
@@ -296,7 +299,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
Log.d(TAG, "setting player session"); Log.d(TAG, "setting player session");
String appName = Notification.Builder.recoverBuilder(getContext(), notif.getNotification()) String appName = Notification.Builder.recoverBuilder(getContext(), notif.getNotification())
.loadHeaderAppName(); .loadHeaderAppName();
player.setMediaSession(token, icon, iconColor, bgColor, actionsContainer, player.setMediaSession(token, icon, largeIcon, iconColor, bgColor, actionsContainer,
notif.getNotification().contentIntent, appName, key); notif.getNotification().contentIntent, appName, key);
if (mMediaPlayers.size() > 0) { if (mMediaPlayers.size() > 0) {

View File

@@ -19,6 +19,7 @@ package com.android.systemui.qs;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.media.session.MediaController; import android.media.session.MediaController;
import android.media.session.MediaSession; import android.media.session.MediaSession;
import android.view.View; import android.view.View;
@@ -58,6 +59,7 @@ public class QuickQSMediaPlayer extends MediaControlPanel {
* Update media panel view for the given media session * Update media panel view for the given media session
* @param token token for this media session * @param token token for this media session
* @param icon app notification icon * @param icon app notification icon
* @param largeIcon notification's largeIcon, used as a fallback for album art
* @param iconColor foreground color (for text, icons) * @param iconColor foreground color (for text, icons)
* @param bgColor background color * @param bgColor background color
* @param actionsContainer a LinearLayout containing the media action buttons * @param actionsContainer a LinearLayout containing the media action buttons
@@ -66,8 +68,9 @@ public class QuickQSMediaPlayer extends MediaControlPanel {
* @param contentIntent Intent to send when user taps on the view * @param contentIntent Intent to send when user taps on the view
* @param key original notification's key * @param key original notification's key
*/ */
public void setMediaSession(MediaSession.Token token, Drawable icon, int iconColor, int bgColor, public void setMediaSession(MediaSession.Token token, Drawable icon, Icon largeIcon,
View actionsContainer, int[] actionsToShow, PendingIntent contentIntent, String key) { int iconColor, int bgColor, View actionsContainer, int[] actionsToShow,
PendingIntent contentIntent, String key) {
// Only update if this is a different session and currently playing // Only update if this is a different session and currently playing
String oldPackage = ""; String oldPackage = "";
if (getController() != null) { if (getController() != null) {
@@ -82,7 +85,7 @@ public class QuickQSMediaPlayer extends MediaControlPanel {
return; return;
} }
super.setMediaSession(token, icon, iconColor, bgColor, contentIntent, null, key); super.setMediaSession(token, icon, largeIcon, iconColor, bgColor, contentIntent, null, key);
LinearLayout parentActionsLayout = (LinearLayout) actionsContainer; LinearLayout parentActionsLayout = (LinearLayout) actionsContainer;
int i = 0; int i = 0;

View File

@@ -191,6 +191,7 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi
Drawable iconDrawable = notif.getSmallIcon().loadDrawable(mContext); Drawable iconDrawable = notif.getSmallIcon().loadDrawable(mContext);
panel.getMediaPlayer().setMediaSession(token, panel.getMediaPlayer().setMediaSession(token,
iconDrawable, iconDrawable,
notif.getLargeIcon(),
tintColor, tintColor,
mBackgroundColor, mBackgroundColor,
mActions, mActions,
@@ -201,6 +202,7 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi
com.android.systemui.R.id.quick_settings_panel); com.android.systemui.R.id.quick_settings_panel);
bigPanel.addMediaSession(token, bigPanel.addMediaSession(token,
iconDrawable, iconDrawable,
notif.getLargeIcon(),
tintColor, tintColor,
mBackgroundColor, mBackgroundColor,
mActions, mActions,