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

Commit 5610db5a authored by tim peng's avatar tim peng Committed by Android (Google) Code Review
Browse files

Merge "Add title and icon in output switcher panel header"

parents 1aa958f5 0c4db317
Loading
Loading
Loading
Loading
+83 −0
Original line number Diff line number Diff line
@@ -22,9 +22,22 @@ import static com.android.settings.slices.CustomSliceRegistry.MEDIA_OUTPUT_SLICE
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.media.MediaMetadata;
import android.media.session.MediaController;
import android.media.session.MediaSessionManager;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;

import androidx.core.graphics.drawable.IconCompat;

import com.android.settings.R;
import com.android.settings.Utils;

import java.util.ArrayList;
import java.util.List;
@@ -38,9 +51,14 @@ import java.util.List;
 */
public class MediaOutputPanel implements PanelContent {

    private static final String TAG = "MediaOutputPanel";

    private final Context mContext;
    private final String mPackageName;

    private MediaSessionManager mMediaSessionManager;
    private MediaController mMediaController;

    public static MediaOutputPanel create(Context context, String packageName) {
        return new MediaOutputPanel(context, packageName);
    }
@@ -48,13 +66,78 @@ public class MediaOutputPanel implements PanelContent {
    private MediaOutputPanel(Context context, String packageName) {
        mContext = context.getApplicationContext();
        mPackageName = packageName;
        if (mPackageName != null) {
            mMediaSessionManager = mContext.getSystemService(MediaSessionManager.class);
            for (MediaController controller : mMediaSessionManager.getActiveSessions(null)) {
                if (TextUtils.equals(controller.getPackageName(), mPackageName)) {
                    mMediaController = controller;
                    break;
                }
            }
        }
        if (mMediaController == null) {
            Log.e(TAG, "Unable to find " + mPackageName + " media controller");
        }
    }

    @Override
    public CharSequence getTitle() {
        if (mMediaController != null) {
            final MediaMetadata metadata = mMediaController.getMetadata();
            if (metadata != null) {
                return metadata.getString(MediaMetadata.METADATA_KEY_ARTIST);
            }
        }
        return mContext.getText(R.string.media_volume_title);
    }

    @Override
    public CharSequence getSubTitle() {
        if (mMediaController != null) {
            final MediaMetadata metadata = mMediaController.getMetadata();
            if (metadata != null) {
                return metadata.getString(MediaMetadata.METADATA_KEY_ALBUM);
            }
        }
        return mContext.getText(R.string.media_output_panel_title);
    }

    @Override
    public IconCompat getIcon() {
        if (mMediaController == null) {
            return IconCompat.createWithResource(mContext, R.drawable.ic_media_stream).setTint(
                    Utils.getColorAccentDefaultColor(mContext));
        }
        final MediaMetadata metadata = mMediaController.getMetadata();
        if (metadata != null) {
            final Bitmap bitmap = metadata.getDescription().getIconBitmap();
            if (bitmap != null) {
                return IconCompat.createWithBitmap(bitmap);
            }
        }
        Log.d(TAG, "Media meta data does not contain icon information");
        return getPackageIcon();
    }

    private IconCompat getPackageIcon() {
        try {
            final Drawable drawable = mContext.getPackageManager().getApplicationIcon(mPackageName);
            if (drawable instanceof BitmapDrawable) {
                return IconCompat.createWithBitmap(((BitmapDrawable) drawable).getBitmap());
            }
            final Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
                    drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
            final Canvas canvas = new Canvas(bitmap);
            drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
            drawable.draw(canvas);

            return IconCompat.createWithBitmap(bitmap);
        } catch (PackageManager.NameNotFoundException e) {
            Log.e(TAG, "Package is not found. Unable to get package icon.");
        }
        return null;
    }

    @Override
    public List<Uri> getSlices() {
        final List<Uri> uris = new ArrayList<>();
+5 −5
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ package com.android.settings.panel;
import android.content.Intent;
import android.net.Uri;

import androidx.core.graphics.drawable.IconCompat;

import com.android.settingslib.core.instrumentation.Instrumentable;

import java.util.List;
@@ -28,13 +30,11 @@ import java.util.List;
 */
public interface PanelContent extends Instrumentable {

    int ICON_UNAVAILABLE = -1;

    /**
     * @return a icon resource for the title of the Panel.
     * @return a icon for the title of the Panel.
     */
    default int getIcon() {
        return ICON_UNAVAILABLE;
    default IconCompat getIcon() {
        return null;
    }

    /**
+4 −4
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.graphics.drawable.IconCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.LiveData;
@@ -185,20 +186,19 @@ public class PanelFragment extends Fragment {
        mMetricsProvider = FeatureFactory.getFactory(activity).getMetricsFeatureProvider();

        mPanelSlices.setLayoutManager(new LinearLayoutManager((activity)));

        // Add predraw listener to remove the animation and while we wait for Slices to load.
        mLayoutView.getViewTreeObserver().addOnPreDrawListener(mOnPreDrawListener);

        // Start loading Slices. When finished, the Panel will animate in.
        loadAllSlices();

        final int iconRes = mPanel.getIcon();
        if (iconRes == PanelContent.ICON_UNAVAILABLE) {
        final IconCompat icon = mPanel.getIcon();
        if (icon == null) {
            mTitleView.setText(mPanel.getTitle());
        } else {
            mTitleView.setVisibility(View.GONE);
            mPanelHeader.setVisibility(View.VISIBLE);
            mTitleIcon.setImageResource(iconRes);
            mTitleIcon.setImageIcon(icon.toIcon(getContext()));
            mHeaderTitle.setText(mPanel.getTitle());
            mHeaderSubtitle.setText(mPanel.getSubTitle());
        }
+7 −5
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@ import android.app.settings.SettingsEnums;
import android.content.Intent;
import android.net.Uri;

import androidx.core.graphics.drawable.IconCompat;

import java.util.Arrays;
import java.util.List;

@@ -41,11 +43,11 @@ public class FakePanelContent implements PanelContent {
    public static final Intent INTENT = new Intent();

    private CharSequence mSubTitle;
    private int mIconRes = -1;
    private IconCompat mIcon;

    @Override
    public int getIcon() {
        return mIconRes;
    public IconCompat getIcon() {
        return mIcon;
    }

    @Override
@@ -53,8 +55,8 @@ public class FakePanelContent implements PanelContent {
        return mSubTitle;
    }

    public void setIcon(int iconRes) {
        mIconRes = iconRes;
    public void setIcon(IconCompat icon) {
        mIcon = icon;
    }

    public void setSubTitle(CharSequence subTitle) {
+104 −1
Original line number Diff line number Diff line
@@ -20,28 +20,59 @@ import static com.android.settings.media.MediaOutputSlice.MEDIA_PACKAGE_NAME;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;

import android.content.Context;
import android.media.MediaMetadata;
import android.media.session.MediaController;
import android.media.session.MediaSessionManager;
import android.net.Uri;

import com.android.settings.R;
import com.android.settings.slices.CustomSliceRegistry;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;

import java.util.ArrayList;
import java.util.List;

@RunWith(RobolectricTestRunner.class)
public class MediaOutputPanelTest {

    private static final String TEST_PACKAGENAME = "com.test.packagename";
    private static final String TEST_ARTIST = "test_artist";
    private static final String TEST_ALBUM = "test_album";

    @Mock
    private MediaSessionManager mMediaSessionManager;
    @Mock
    private MediaController mMediaController;
    @Mock
    private MediaMetadata mMediaMetadata;

    private MediaOutputPanel mPanel;
    private Context mContext;
    private List<MediaController> mMediaControllers = new ArrayList<>();

    @Before
    public void setUp() {
        mPanel = MediaOutputPanel.create(RuntimeEnvironment.application, TEST_PACKAGENAME);
        MockitoAnnotations.initMocks(this);

        mContext = spy(RuntimeEnvironment.application);
        mMediaControllers.add(mMediaController);
        when(mMediaController.getPackageName()).thenReturn(TEST_PACKAGENAME);
        when(mMediaSessionManager.getActiveSessions(any())).thenReturn(mMediaControllers);
        when(mContext.getApplicationContext()).thenReturn(mContext);
        when(mContext.getSystemService(MediaSessionManager.class)).thenReturn(mMediaSessionManager);
        mPanel = MediaOutputPanel.create(mContext, TEST_PACKAGENAME);
    }

    @Test
@@ -62,4 +93,76 @@ public class MediaOutputPanelTest {
    public void getSeeMoreIntent_isNull() {
        assertThat(mPanel.getSeeMoreIntent()).isNull();
    }

    @Test
    public void getTitle_withMetadata_returnArtistName() {
        when(mMediaMetadata.getString(MediaMetadata.METADATA_KEY_ARTIST)).thenReturn(TEST_ARTIST);
        when(mMediaController.getMetadata()).thenReturn(mMediaMetadata);

        assertThat(mPanel.getTitle()).isEqualTo(TEST_ARTIST);
    }

    @Test
    public void getTitle_noMetadata_returnDefaultString() {
        when(mMediaController.getMetadata()).thenReturn(null);

        assertThat(mPanel.getTitle()).isEqualTo(mContext.getText(R.string.media_volume_title));
    }

    @Test
    public void getTitle_noPackageName_returnDefaultString() {
        mPanel = MediaOutputPanel.create(mContext, null);
        when(mMediaMetadata.getString(MediaMetadata.METADATA_KEY_ARTIST)).thenReturn(TEST_ARTIST);
        when(mMediaController.getMetadata()).thenReturn(mMediaMetadata);

        assertThat(mPanel.getTitle()).isEqualTo(mContext.getText(R.string.media_volume_title));
    }

    @Test
    public void getTitle_noController_defaultString() {
        mMediaControllers.clear();
        when(mMediaMetadata.getString(MediaMetadata.METADATA_KEY_ARTIST)).thenReturn(TEST_ARTIST);
        when(mMediaController.getMetadata()).thenReturn(mMediaMetadata);
        mPanel = MediaOutputPanel.create(mContext, TEST_PACKAGENAME);

        assertThat(mPanel.getTitle()).isEqualTo(mContext.getText(R.string.media_volume_title));
    }

    @Test
    public void getSubTitle_withMetadata_returnAlbumName() {
        when(mMediaMetadata.getString(MediaMetadata.METADATA_KEY_ALBUM)).thenReturn(TEST_ALBUM);
        when(mMediaController.getMetadata()).thenReturn(mMediaMetadata);

        assertThat(mPanel.getSubTitle()).isEqualTo(TEST_ALBUM);
    }

    @Test
    public void getSubTitle_noMetadata_returnDefaultString() {
        when(mMediaController.getPackageName()).thenReturn(TEST_PACKAGENAME);
        when(mMediaController.getMetadata()).thenReturn(null);

        assertThat(mPanel.getSubTitle()).isEqualTo(mContext.getText(
                R.string.media_output_panel_title));
    }

    @Test
    public void getSubTitle_noPackageName_returnDefaultString() {
        mPanel = MediaOutputPanel.create(mContext, null);
        when(mMediaMetadata.getString(MediaMetadata.METADATA_KEY_ARTIST)).thenReturn(TEST_ARTIST);
        when(mMediaController.getMetadata()).thenReturn(mMediaMetadata);

        assertThat(mPanel.getSubTitle()).isEqualTo(mContext.getText(
                R.string.media_output_panel_title));
    }

    @Test
    public void getSubTitle_noController_returnDefaultString() {
        mMediaControllers.clear();
        mPanel = MediaOutputPanel.create(mContext, TEST_PACKAGENAME);
        when(mMediaMetadata.getString(MediaMetadata.METADATA_KEY_ALBUM)).thenReturn(TEST_ALBUM);
        when(mMediaController.getMetadata()).thenReturn(mMediaMetadata);

        assertThat(mPanel.getSubTitle()).isEqualTo(mContext.getText(
                R.string.media_output_panel_title));
    }
}
Loading