Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 791e7c85 authored by Beth Thibodeau's avatar Beth Thibodeau Committed by Automerger Merge Worker
Browse files

Merge "Improve album art handling" into rvc-dev am: 9f4b4c23 am: feca79ea

Change-Id: I12ae88a011e71b0c1875d453fc333f13ce7b7e14
parents 1cf8d67b feca79ea
Loading
Loading
Loading
Loading
+77 −11
Original line number Diff line number Diff line
@@ -26,14 +26,18 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.ImageDecoder;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.Icon;
import android.graphics.drawable.RippleDrawable;
import android.media.MediaDescription;
import android.media.MediaMetadata;
import android.media.ThumbnailUtils;
import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.media.session.PlaybackState;
import android.net.Uri;
import android.service.media.MediaBrowserService;
import android.util.Log;
import android.view.LayoutInflater;
@@ -59,6 +63,7 @@ import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.qs.QSMediaBrowser;
import com.android.systemui.util.Assert;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.Executor;

@@ -99,6 +104,13 @@ public class MediaControlPanel {
            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() {
        @Override
        public void onSessionDestroyed() {
@@ -205,14 +217,16 @@ public class MediaControlPanel {
     * Update the media panel view for the given media session
     * @param token
     * @param iconDrawable
     * @param largeIcon
     * @param iconColor
     * @param bgColor
     * @param contentIntent
     * @param appNameString
     * @param key
     */
    public void setMediaSession(MediaSession.Token token, Drawable iconDrawable, int iconColor,
            int bgColor, PendingIntent contentIntent, String appNameString, String key) {
    public void setMediaSession(MediaSession.Token token, Drawable iconDrawable, Icon largeIcon,
            int iconColor, int bgColor, PendingIntent contentIntent, String appNameString,
            String key) {
        // Ensure that component names are updated if token has changed
        if (mToken == null || !mToken.equals(token)) {
            mToken = token;
@@ -303,7 +317,7 @@ public class MediaControlPanel {
        ImageView albumView = mMediaNotifView.findViewById(R.id.album_art);
        if (albumView != null) {
            // Resize art in a background thread
            mBackgroundExecutor.execute(() -> processAlbumArt(mediaMetadata, albumView));
            mBackgroundExecutor.execute(() -> processAlbumArt(mediaMetadata, largeIcon, albumView));
        }

        // Song name
@@ -396,30 +410,82 @@ public class MediaControlPanel {
     * @param albumView view to hold the album art
     */
    protected void processAlbumArt(MediaDescription description, ImageView albumView) {
        Bitmap albumArt = description.getIconBitmap();
        //TODO check other fields (b/151054111, b/152067055)
        Bitmap albumArt = null;

        // First try loading from URI
        albumArt = loadBitmapFromUri(description.getIconUri());

        // Then check bitmap
        if (albumArt == null) {
            albumArt = description.getIconBitmap();
        }

        processAlbumArtInternal(albumArt, albumView);
    }

    /**
     * Process album art for layout
     * @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
     */
    private void processAlbumArt(MediaMetadata metadata, ImageView albumView) {
        Bitmap albumArt = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
        //TODO check other fields (b/151054111, b/152067055)
    private void processAlbumArt(MediaMetadata metadata, Icon largeIcon, ImageView albumView) {
        Bitmap albumArt = null;

        // 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);
    }

    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;
        if (albumArt != null) {
            float radius = mContext.getResources().getDimension(R.dimen.qs_media_corner_radius);
            Bitmap original = albumArt.copy(Bitmap.Config.ARGB_8888, true);
            int albumSize = (int) mContext.getResources().getDimension(
                    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.setCornerRadius(radius);
        } else {
+9 −6
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.media.MediaDescription;
import android.media.session.MediaController;
import android.media.session.MediaSession;
@@ -115,8 +116,8 @@ public class QSMediaPlayer extends MediaControlPanel {
        }

        // Set what we can normally
        super.setMediaSession(token, icon, iconColor, bgColor, contentIntent, appName.toString(),
                null);
        super.setMediaSession(token, icon, null, iconColor, bgColor, contentIntent,
                appName.toString(), null);

        // Then add info from MediaDescription
        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
     * @param token token for this media session
     * @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 bgColor background color
     * @param actionsContainer a LinearLayout containing the media action buttons
@@ -156,11 +158,12 @@ public class QSMediaPlayer extends MediaControlPanel {
     * @param appName Application title
     * @param key original notification's key
     */
    public void setMediaSession(MediaSession.Token token, Drawable icon, int iconColor,
            int bgColor, View actionsContainer, PendingIntent contentIntent, String appName,
            String key) {
    public void setMediaSession(MediaSession.Token token, Drawable icon, Icon largeIcon,
            int iconColor, int bgColor, View actionsContainer, PendingIntent contentIntent,
            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
        if (actionsContainer != null) {
+6 −3
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.media.MediaDescription;
import android.media.session.MediaSession;
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
     * @param token
     * @param icon
     * @param largeIcon
     * @param iconColor
     * @param bgColor
     * @param actionsContainer
     * @param notif
     * @param key
     */
    public void addMediaSession(MediaSession.Token token, Drawable icon, int iconColor, int bgColor,
            View actionsContainer, StatusBarNotification notif, String key) {
    public void addMediaSession(MediaSession.Token token, Drawable icon, Icon largeIcon,
            int iconColor, int bgColor, View actionsContainer, StatusBarNotification notif,
            String key) {
        if (!useQsMediaPlayer(mContext)) {
            // Shouldn't happen, but just in case
            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");
        String appName = Notification.Builder.recoverBuilder(getContext(), notif.getNotification())
                .loadHeaderAppName();
        player.setMediaSession(token, icon, iconColor, bgColor, actionsContainer,
        player.setMediaSession(token, icon, largeIcon, iconColor, bgColor, actionsContainer,
                notif.getNotification().contentIntent, appName, key);

        if (mMediaPlayers.size() > 0) {
+6 −3
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.systemui.qs;
import android.app.PendingIntent;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.view.View;
@@ -58,6 +59,7 @@ public class QuickQSMediaPlayer extends MediaControlPanel {
     * Update media panel view for the given media session
     * @param token token for this media session
     * @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 bgColor background color
     * @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 key original notification's key
     */
    public void setMediaSession(MediaSession.Token token, Drawable icon, int iconColor, int bgColor,
            View actionsContainer, int[] actionsToShow, PendingIntent contentIntent, String key) {
    public void setMediaSession(MediaSession.Token token, Drawable icon, Icon largeIcon,
            int iconColor, int bgColor, View actionsContainer, int[] actionsToShow,
            PendingIntent contentIntent, String key) {
        // Only update if this is a different session and currently playing
        String oldPackage = "";
        if (getController() != null) {
@@ -82,7 +85,7 @@ public class QuickQSMediaPlayer extends MediaControlPanel {
            return;
        }

        super.setMediaSession(token, icon, iconColor, bgColor, contentIntent, null, key);
        super.setMediaSession(token, icon, largeIcon, iconColor, bgColor, contentIntent, null, key);

        LinearLayout parentActionsLayout = (LinearLayout) actionsContainer;
        int i = 0;
+2 −0
Original line number Diff line number Diff line
@@ -191,6 +191,7 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi
            Drawable iconDrawable = notif.getSmallIcon().loadDrawable(mContext);
            panel.getMediaPlayer().setMediaSession(token,
                    iconDrawable,
                    notif.getLargeIcon(),
                    tintColor,
                    mBackgroundColor,
                    mActions,
@@ -201,6 +202,7 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi
                    com.android.systemui.R.id.quick_settings_panel);
            bigPanel.addMediaSession(token,
                    iconDrawable,
                    notif.getLargeIcon(),
                    tintColor,
                    mBackgroundColor,
                    mActions,