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

Commit 133a1004 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 am: 791e7c85

Change-Id: I426bc90faaef4e32390f034821b1b8a0ccd7b735
parents 176cb272 791e7c85
Loading
Loading
Loading
Loading
+77 −11
Original line number Original line Diff line number Diff line
@@ -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 {
+9 −6
Original line number Original line Diff line number Diff line
@@ -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) {
+6 −3
Original line number Original line Diff line number Diff line
@@ -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) {
+6 −3
Original line number Original line Diff line number Diff line
@@ -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;
+2 −0
Original line number Original line Diff line number Diff line
@@ -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,