Loading src/com/android/settings/panel/MediaOutputPanel.java +83 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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); } Loading @@ -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<>(); Loading src/com/android/settings/panel/PanelContent.java +5 −5 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; } /** Loading src/com/android/settings/panel/PanelFragment.java +4 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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()); } Loading tests/robotests/src/com/android/settings/panel/FakePanelContent.java +7 −5 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 Loading @@ -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) { Loading tests/robotests/src/com/android/settings/panel/MediaOutputPanelTest.java +104 −1 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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
src/com/android/settings/panel/MediaOutputPanel.java +83 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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); } Loading @@ -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<>(); Loading
src/com/android/settings/panel/PanelContent.java +5 −5 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; } /** Loading
src/com/android/settings/panel/PanelFragment.java +4 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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()); } Loading
tests/robotests/src/com/android/settings/panel/FakePanelContent.java +7 −5 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 Loading @@ -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) { Loading
tests/robotests/src/com/android/settings/panel/MediaOutputPanelTest.java +104 −1 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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)); } }