summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--android/app/res/values/config.xml3
-rw-r--r--android/app/src/com/android/bluetooth/audio_util/MediaPlayerList.java4
-rw-r--r--android/app/src/com/android/bluetooth/audio_util/helpers/Image.java4
-rw-r--r--android/app/src/com/android/bluetooth/audio_util/helpers/Metadata.java17
-rw-r--r--android/app/src/com/android/bluetooth/audio_util/helpers/Util.java17
-rw-r--r--android/app/src/com/android/bluetooth/avrcp/AvrcpCoverArtService.java5
-rw-r--r--android/app/src/com/android/bluetooth/avrcp/AvrcpTargetService.java37
-rw-r--r--android/app/src/com/android/bluetooth/avrcp/helpers/CoverArt.java30
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/audio_util/BrowserPlayerWrapperTest.java6
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/audio_util/ImageTest.java18
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/audio_util/MediaPlayerWrapperTest.java14
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/audio_util/MetadataTest.java14
-rw-r--r--android/pandora/mmi2grpc/mmi2grpc/avrcp.py17
-rw-r--r--android/pandora/server/configs/pts_bot_tests_config.json3
-rw-r--r--android/pandora/server/src/MediaPlayer.kt7
-rw-r--r--android/pandora/server/src/MediaPlayerBrowserService.kt10
-rw-r--r--pandora/interfaces/pandora_experimental/mediaplayer.proto1
17 files changed, 126 insertions, 81 deletions
diff --git a/android/app/res/values/config.xml b/android/app/res/values/config.xml
index 5668a41199..0bb72b5ca8 100644
--- a/android/app/res/values/config.xml
+++ b/android/app/res/values/config.xml
@@ -138,9 +138,6 @@
<integer name="a2dp_source_codec_priority_lc3">6001</integer>
<integer name="a2dp_source_codec_priority_opus">7001</integer>
- <!-- Enable support for URI based images. Off by default due to increased memory usage -->
- <bool name="avrcp_target_cover_art_uri_images">false</bool>
-
<!-- Package that is responsible for user interaction on pairing request,
success or cancel.
Receives:
diff --git a/android/app/src/com/android/bluetooth/audio_util/MediaPlayerList.java b/android/app/src/com/android/bluetooth/audio_util/MediaPlayerList.java
index b04f684f34..b98d9e6be8 100644
--- a/android/app/src/com/android/bluetooth/audio_util/MediaPlayerList.java
+++ b/android/app/src/com/android/bluetooth/audio_util/MediaPlayerList.java
@@ -784,6 +784,10 @@ public class MediaPlayerList {
}
}
+ public boolean isVfsCoverArtEnabled() {
+ return Util.areUriImagesSupported();
+ }
+
/**
* Adds a {@link MediaController} to the {@link #mMediaPlayers} map and returns its ID.
*
diff --git a/android/app/src/com/android/bluetooth/audio_util/helpers/Image.java b/android/app/src/com/android/bluetooth/audio_util/helpers/Image.java
index fc106e9a95..d89a6afddf 100644
--- a/android/app/src/com/android/bluetooth/audio_util/helpers/Image.java
+++ b/android/app/src/com/android/bluetooth/audio_util/helpers/Image.java
@@ -60,7 +60,7 @@ public class Image {
Bitmap bmp_album_art = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
Bitmap bmp_icon = metadata.getBitmap(MediaMetadata.METADATA_KEY_DISPLAY_ICON);
- if (mContext != null && Util.areUriImagesSupported(mContext)) {
+ if (Util.areUriImagesSupported()) {
uri_art = metadata.getString(MediaMetadata.METADATA_KEY_ART_URI);
uri_album_art = metadata.getString(MediaMetadata.METADATA_KEY_ALBUM_ART_URI);
uri_icon = metadata.getString(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI);
@@ -92,7 +92,7 @@ public class Image {
Bitmap bmp_album_art = bundle.getParcelable(MediaMetadata.METADATA_KEY_ALBUM_ART);
Bitmap bmp_icon = bundle.getParcelable(MediaMetadata.METADATA_KEY_DISPLAY_ICON);
- if (mContext != null && Util.areUriImagesSupported(mContext)) {
+ if (Util.areUriImagesSupported()) {
uri_art = bundle.getString(MediaMetadata.METADATA_KEY_ART_URI);
uri_album_art = bundle.getString(MediaMetadata.METADATA_KEY_ALBUM_ART_URI);
uri_icon = bundle.getString(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI);
diff --git a/android/app/src/com/android/bluetooth/audio_util/helpers/Metadata.java b/android/app/src/com/android/bluetooth/audio_util/helpers/Metadata.java
index 02ca4fbd5c..63791acb29 100644
--- a/android/app/src/com/android/bluetooth/audio_util/helpers/Metadata.java
+++ b/android/app/src/com/android/bluetooth/audio_util/helpers/Metadata.java
@@ -23,8 +23,6 @@ import android.media.browse.MediaBrowser.MediaItem;
import android.media.session.MediaSession;
import android.os.Bundle;
-import com.android.bluetooth.R;
-
import java.util.Objects;
public class Metadata implements Cloneable {
@@ -201,7 +199,7 @@ public class Metadata implements Cloneable {
mMetadata.duration = "" + data.getLong(MediaMetadata.METADATA_KEY_DURATION);
}
if ((mContext != null
- && Util.areUriImagesSupported(mContext)
+ && Util.areUriImagesSupported()
&& (data.containsKey(MediaMetadata.METADATA_KEY_ART_URI)
|| data.containsKey(MediaMetadata.METADATA_KEY_ALBUM_ART_URI)
|| data.containsKey(
@@ -233,7 +231,7 @@ public class Metadata implements Cloneable {
if (desc.getIconBitmap() != null) {
mMetadata.image = new Image(mContext, desc.getIconBitmap());
} else if (mContext != null
- && Util.areUriImagesSupported(mContext)
+ && Util.areUriImagesSupported()
&& desc.getIconUri() != null) {
mMetadata.image = new Image(mContext, desc.getIconUri());
}
@@ -281,7 +279,7 @@ public class Metadata implements Cloneable {
mMetadata.duration = "" + bundle.getLong(MediaMetadata.METADATA_KEY_DURATION);
}
if ((mContext != null
- && Util.areUriImagesSupported(mContext)
+ && Util.areUriImagesSupported()
&& (bundle.containsKey(MediaMetadata.METADATA_KEY_ART_URI)
|| bundle.containsKey(MediaMetadata.METADATA_KEY_ALBUM_ART_URI)
|| bundle.containsKey(
@@ -296,13 +294,8 @@ public class Metadata implements Cloneable {
/** Elect to use default values in the Metadata in place of any missing values */
public Builder useDefaults() {
- if (mMetadata.mediaId == null) {
- mMetadata.mediaId = EMPTY_MEDIA_ID;
- }
- if (mMetadata.title == null) {
- mMetadata.title =
- mContext != null ? mContext.getString(R.string.not_provided) : EMPTY_TITLE;
- }
+ if (mMetadata.mediaId == null) mMetadata.mediaId = EMPTY_MEDIA_ID;
+ if (mMetadata.title == null) mMetadata.title = EMPTY_TITLE;
if (mMetadata.artist == null) mMetadata.artist = EMPTY_ARTIST;
if (mMetadata.album == null) mMetadata.album = EMPTY_ALBUM;
if (mMetadata.trackNum == null) mMetadata.trackNum = EMPTY_TRACK_NUM;
diff --git a/android/app/src/com/android/bluetooth/audio_util/helpers/Util.java b/android/app/src/com/android/bluetooth/audio_util/helpers/Util.java
index 32597edc75..877a315c88 100644
--- a/android/app/src/com/android/bluetooth/audio_util/helpers/Util.java
+++ b/android/app/src/com/android/bluetooth/audio_util/helpers/Util.java
@@ -21,9 +21,10 @@ import android.content.pm.PackageManager;
import android.media.MediaMetadata;
import android.media.browse.MediaBrowser.MediaItem;
import android.media.session.MediaSession;
+import android.os.SystemProperties;
import android.util.Log;
-import com.android.bluetooth.R;
+import androidx.annotation.VisibleForTesting;
import java.util.ArrayList;
import java.util.List;
@@ -31,6 +32,13 @@ import java.util.List;
class Util {
public static String TAG = "audio_util.Util";
+ private static final String VFS_COVER_ART_ENABLED_PROPERTY =
+ "bluetooth.profile.avrcp.target.vfs_coverart.enabled";
+
+ @VisibleForTesting
+ static Boolean sUriImagesSupport =
+ SystemProperties.getBoolean(VFS_COVER_ART_ENABLED_PROPERTY, false);
+
// TODO (apanicke): Remove this prefix later, for now it makes debugging easier.
public static final String NOW_PLAYING_PREFIX = "NowPlayingId";
@@ -49,13 +57,12 @@ class Util {
}
/**
- * Get whether or not Bluetooth is configured to support URI images or not.
+ * Get whether or not Bluetooth is configured to support URI images.
*
* <p>Note that creating URI images will dramatically increase memory usage.
*/
- public static boolean areUriImagesSupported(Context context) {
- if (context == null) return false;
- return context.getResources().getBoolean(R.bool.avrcp_target_cover_art_uri_images);
+ public static boolean areUriImagesSupported() {
+ return sUriImagesSupport.booleanValue();
}
/** Translate a MediaItem to audio_util's Metadata */
diff --git a/android/app/src/com/android/bluetooth/avrcp/AvrcpCoverArtService.java b/android/app/src/com/android/bluetooth/avrcp/AvrcpCoverArtService.java
index 26d7d3e48d..46805f404c 100644
--- a/android/app/src/com/android/bluetooth/avrcp/AvrcpCoverArtService.java
+++ b/android/app/src/com/android/bluetooth/avrcp/AvrcpCoverArtService.java
@@ -62,8 +62,9 @@ public class AvrcpCoverArtService {
// Native interface
private AvrcpNativeInterface mNativeInterface;
- public AvrcpCoverArtService() {
- mNativeInterface = AvrcpNativeInterface.getInstance();
+ // The native interface must be a parameter here in order to be able to mock AvrcpTargetService
+ public AvrcpCoverArtService(AvrcpNativeInterface nativeInterface) {
+ mNativeInterface = nativeInterface;
mAcceptThread = new SocketAcceptor();
mStorage = new AvrcpCoverArtStorage(COVER_ART_STORAGE_MAX_ITEMS);
}
diff --git a/android/app/src/com/android/bluetooth/avrcp/AvrcpTargetService.java b/android/app/src/com/android/bluetooth/avrcp/AvrcpTargetService.java
index d0d6b89c60..068db0f024 100644
--- a/android/app/src/com/android/bluetooth/avrcp/AvrcpTargetService.java
+++ b/android/app/src/com/android/bluetooth/avrcp/AvrcpTargetService.java
@@ -37,6 +37,7 @@ import android.view.KeyEvent;
import com.android.bluetooth.BluetoothEventLogger;
import com.android.bluetooth.BluetoothMetricsProto;
import com.android.bluetooth.a2dp.A2dpService;
+import com.android.bluetooth.audio_util.ListItem;
import com.android.bluetooth.audio_util.MediaData;
import com.android.bluetooth.audio_util.MediaPlayerList;
import com.android.bluetooth.audio_util.MediaPlayerWrapper;
@@ -97,6 +98,8 @@ public class AvrcpTargetService extends ProfileService {
private static AvrcpTargetService sInstance = null;
+ private final boolean mIsVfsCoverArtEnabled;
+
public AvrcpTargetService(AdapterService adapterService) {
this(
requireNonNull(adapterService),
@@ -145,7 +148,7 @@ public class AvrcpTargetService extends ProfileService {
Log.e(TAG, "Please use AVRCP version 1.6 to enable cover art");
mAvrcpCoverArtService = null;
} else {
- AvrcpCoverArtService coverArtService = new AvrcpCoverArtService();
+ AvrcpCoverArtService coverArtService = new AvrcpCoverArtService(mNativeInterface);
if (coverArtService.start()) {
mAvrcpCoverArtService = coverArtService;
} else {
@@ -154,6 +157,8 @@ public class AvrcpTargetService extends ProfileService {
}
}
+ mIsVfsCoverArtEnabled = mMediaPlayerList.isVfsCoverArtEnabled();
+
mReceiver = new AvrcpBroadcastReceiver();
IntentFilter filter = new IntentFilter();
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
@@ -396,8 +401,7 @@ public class AvrcpTargetService extends ProfileService {
Metadata getCurrentSongInfo() {
Metadata metadata = mMediaPlayerList.getCurrentSongInfo();
if (mAvrcpCoverArtService != null && metadata.image != null) {
- String imageHandle = mAvrcpCoverArtService.storeImage(metadata.image);
- if (imageHandle != null) metadata.image.setImageHandle(imageHandle);
+ metadata.image.setImageHandle(mAvrcpCoverArtService.storeImage(metadata.image));
}
return metadata;
}
@@ -430,26 +434,20 @@ public class AvrcpTargetService extends ProfileService {
List<Metadata> getNowPlayingList() {
String currentMediaId = getCurrentMediaId();
Metadata currentTrack = null;
- String imageHandle = null;
List<Metadata> nowPlayingList = mMediaPlayerList.getNowPlayingList();
if (mAvrcpCoverArtService != null) {
for (Metadata metadata : nowPlayingList) {
if (TextUtils.equals(metadata.mediaId, currentMediaId)) {
currentTrack = metadata;
} else if (metadata.image != null) {
- imageHandle = mAvrcpCoverArtService.storeImage(metadata.image);
- if (imageHandle != null) {
- metadata.image.setImageHandle(imageHandle);
- }
+ metadata.image.setImageHandle(mAvrcpCoverArtService.storeImage(metadata.image));
}
}
// Always store the current item from the queue last so we know the image is in storage
if (currentTrack != null) {
- imageHandle = mAvrcpCoverArtService.storeImage(currentTrack.image);
- if (imageHandle != null) {
- currentTrack.image.setImageHandle(imageHandle);
- }
+ currentTrack.image.setImageHandle(
+ mAvrcpCoverArtService.storeImage(currentTrack.image));
}
}
return nowPlayingList;
@@ -488,7 +486,20 @@ public class AvrcpTargetService extends ProfileService {
/** See {@link MediaPlayerList#getFolderItems}. */
void getFolderItems(int playerId, String mediaId, MediaPlayerList.GetFolderItemsCallback cb) {
- mMediaPlayerList.getFolderItems(playerId, mediaId, cb);
+ mMediaPlayerList.getFolderItems(
+ playerId,
+ mediaId,
+ (id, results) -> {
+ if (mIsVfsCoverArtEnabled && mAvrcpCoverArtService != null) {
+ for (ListItem item : results) {
+ if (item != null && item.song != null && item.song.image != null) {
+ item.song.image.setImageHandle(
+ mAvrcpCoverArtService.storeImage(item.song.image));
+ }
+ }
+ }
+ cb.run(id, results);
+ });
}
/** See {@link MediaPlayerList#playItem}. */
diff --git a/android/app/src/com/android/bluetooth/avrcp/helpers/CoverArt.java b/android/app/src/com/android/bluetooth/avrcp/helpers/CoverArt.java
index 95388baf78..dd720077a0 100644
--- a/android/app/src/com/android/bluetooth/avrcp/helpers/CoverArt.java
+++ b/android/app/src/com/android/bluetooth/avrcp/helpers/CoverArt.java
@@ -40,7 +40,12 @@ import java.security.NoSuchAlgorithmException;
*/
public class CoverArt {
private static final String TAG = CoverArt.class.getSimpleName();
- private static final BipPixel PIXEL_THUMBNAIL = BipPixel.createFixed(200, 200);
+
+ // The size in pixels of the thumbnail sides.
+ private static final int THUMBNAIL_SIZE = 200;
+
+ private static final BipPixel PIXEL_THUMBNAIL =
+ BipPixel.createFixed(THUMBNAIL_SIZE, THUMBNAIL_SIZE);
private String mImageHandle = null;
private Bitmap mImage = null;
@@ -50,7 +55,7 @@ public class CoverArt {
// Create a scaled version of the image for now, as consumers don't need
// anything larger than this at the moment. Also makes each image gathered
// the same dimensions for hashing purposes.
- mImage = Bitmap.createScaledBitmap(image.getImage(), 200, 200, false);
+ mImage = Bitmap.createScaledBitmap(image.getImage(), THUMBNAIL_SIZE, THUMBNAIL_SIZE, false);
}
/**
@@ -133,13 +138,15 @@ public class CoverArt {
BipEncoding encoding = descriptor.getEncoding();
BipPixel pixel = descriptor.getPixel();
- if (encoding.getType() == BipEncoding.JPEG && PIXEL_THUMBNAIL.equals(pixel)) {
+ int encodingType = encoding.getType();
+ if ((encodingType == BipEncoding.JPEG || encodingType == BipEncoding.PNG)
+ && PIXEL_THUMBNAIL.equals(pixel)) {
return true;
}
return false;
}
- /** Get the cover artwork image bytes as a 200 x 200 JPEG thumbnail */
+ /** Get the cover artwork image bytes as a THUMBNAIL_SIZE x THUMBNAIL_SIZE JPEG thumbnail */
public byte[] getThumbnail() {
debug("GetImageThumbnail()");
if (mImage == null) return null;
@@ -160,12 +167,19 @@ public class CoverArt {
return null;
}
BipImageProperties.Builder builder = new BipImageProperties.Builder();
- BipEncoding encoding = new BipEncoding(BipEncoding.JPEG);
- BipPixel pixel = BipPixel.createFixed(200, 200);
- BipImageFormat format = BipImageFormat.createNative(encoding, pixel, -1);
+
+ BipEncoding jpgEncoding = new BipEncoding(BipEncoding.JPEG);
+ BipEncoding pngEncoding = new BipEncoding(BipEncoding.PNG);
+ BipPixel jpgPixel = BipPixel.createFixed(THUMBNAIL_SIZE, THUMBNAIL_SIZE);
+ BipPixel pngPixel = BipPixel.createFixed(THUMBNAIL_SIZE, THUMBNAIL_SIZE);
+
+ BipImageFormat jpgNativeFormat = BipImageFormat.createNative(jpgEncoding, jpgPixel, -1);
+ BipImageFormat pngVariantFormat =
+ BipImageFormat.createVariant(pngEncoding, pngPixel, THUMBNAIL_SIZE, null);
builder.setImageHandle(mImageHandle);
- builder.addNativeFormat(format);
+ builder.addNativeFormat(jpgNativeFormat);
+ builder.addVariantFormat(pngVariantFormat);
BipImageProperties properties = builder.build();
return properties;
diff --git a/android/app/tests/unit/src/com/android/bluetooth/audio_util/BrowserPlayerWrapperTest.java b/android/app/tests/unit/src/com/android/bluetooth/audio_util/BrowserPlayerWrapperTest.java
index cd9ad4dd9a..b3d61e33af 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/audio_util/BrowserPlayerWrapperTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/audio_util/BrowserPlayerWrapperTest.java
@@ -40,7 +40,6 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.bluetooth.R;
import com.android.bluetooth.TestUtils;
import org.junit.After;
@@ -75,7 +74,6 @@ public class BrowserPlayerWrapperTest {
private HandlerThread mThread;
@Mock Context mMockContext;
- @Mock Resources mMockResources;
private Context mTargetContext;
private Resources mTestResources;
private MockContentResolver mTestContentResolver;
@@ -116,8 +114,7 @@ public class BrowserPlayerWrapperTest {
});
when(mMockContext.getContentResolver()).thenReturn(mTestContentResolver);
- when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)).thenReturn(true);
- when(mMockContext.getResources()).thenReturn(mMockResources);
+ Util.sUriImagesSupport = true;
// Set up Looper thread for the timeout handler
mThread = new HandlerThread("MediaPlayerWrapperTestThread");
@@ -138,6 +135,7 @@ public class BrowserPlayerWrapperTest {
mTestBitmap = null;
mTestResources = null;
mTargetContext = null;
+ Util.sUriImagesSupport = false;
}
private Bitmap loadImage(int resId) {
diff --git a/android/app/tests/unit/src/com/android/bluetooth/audio_util/ImageTest.java b/android/app/tests/unit/src/com/android/bluetooth/audio_util/ImageTest.java
index 60ca5a5aef..6c6e6e78fc 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/audio_util/ImageTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/audio_util/ImageTest.java
@@ -36,7 +36,6 @@ import android.test.mock.MockContentResolver;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
-import com.android.bluetooth.R;
import com.android.bluetooth.TestUtils;
import org.junit.After;
@@ -57,7 +56,6 @@ public class ImageTest {
@Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
private @Mock Context mMockContext;
- private @Mock Resources mMockResources;
private Resources mTestResources;
private MockContentResolver mTestContentResolver;
@@ -108,8 +106,7 @@ public class ImageTest {
});
when(mMockContext.getContentResolver()).thenReturn(mTestContentResolver);
- when(mMockContext.getResources()).thenReturn(mMockResources);
- when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)).thenReturn(true);
+ Util.sUriImagesSupport = true;
}
@After
@@ -119,6 +116,7 @@ public class ImageTest {
mTestResources = null;
mTargetContext = null;
mMockContext = null;
+ Util.sUriImagesSupport = false;
}
private Bitmap loadImage(int resId) {
@@ -287,7 +285,7 @@ public class ImageTest {
*/
@Test
public void testCreateImageFromMediaMetadataWithArtUriDisabled() {
- when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)).thenReturn(false);
+ Util.sUriImagesSupport = false;
MediaMetadata metadata =
getMediaMetadataWithUri(MediaMetadata.METADATA_KEY_ART_URI, IMAGE_STRING_1);
Image artwork = new Image(mMockContext, metadata);
@@ -302,7 +300,7 @@ public class ImageTest {
*/
@Test
public void testCreateImageFromMediaMetadataWithAlbumArtUriDisabled() {
- when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)).thenReturn(false);
+ Util.sUriImagesSupport = false;
MediaMetadata metadata =
getMediaMetadataWithUri(MediaMetadata.METADATA_KEY_ALBUM_ART_URI, IMAGE_STRING_1);
Image artwork = new Image(mMockContext, metadata);
@@ -317,7 +315,7 @@ public class ImageTest {
*/
@Test
public void testCreateImageFromMediaMetadataWithDisplayIconUriDisabled() {
- when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)).thenReturn(false);
+ Util.sUriImagesSupport = false;
MediaMetadata metadata =
getMediaMetadataWithUri(
MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI, IMAGE_STRING_1);
@@ -459,7 +457,7 @@ public class ImageTest {
*/
@Test
public void testCreateImageFromBundleWithArtUriDisabled() {
- when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)).thenReturn(false);
+ Util.sUriImagesSupport = false;
Bundle bundle = getBundleWithUri(MediaMetadata.METADATA_KEY_ART_URI, IMAGE_STRING_1);
Image artwork = new Image(mMockContext, bundle);
assertThat(artwork.getImage()).isNull();
@@ -473,7 +471,7 @@ public class ImageTest {
*/
@Test
public void testCreateImageFromBundleWithAlbumArtUriDisabled() {
- when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)).thenReturn(false);
+ Util.sUriImagesSupport = false;
Bundle bundle = getBundleWithUri(MediaMetadata.METADATA_KEY_ALBUM_ART_URI, IMAGE_STRING_1);
Image artwork = new Image(mMockContext, bundle);
assertThat(artwork.getImage()).isNull();
@@ -487,7 +485,7 @@ public class ImageTest {
*/
@Test
public void testCreateImageFromBundleWithDisplayIconUriDisabled() {
- when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)).thenReturn(false);
+ Util.sUriImagesSupport = false;
Bundle bundle =
getBundleWithUri(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI, IMAGE_STRING_1);
Image artwork = new Image(mMockContext, bundle);
diff --git a/android/app/tests/unit/src/com/android/bluetooth/audio_util/MediaPlayerWrapperTest.java b/android/app/tests/unit/src/com/android/bluetooth/audio_util/MediaPlayerWrapperTest.java
index 2b323d9810..794a1200b3 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/audio_util/MediaPlayerWrapperTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/audio_util/MediaPlayerWrapperTest.java
@@ -36,9 +36,9 @@ import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
-import com.android.bluetooth.R;
import com.android.bluetooth.TestUtils;
+import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -75,7 +75,6 @@ public class MediaPlayerWrapperTest {
@Mock MediaController mMockController;
@Mock MediaPlayerWrapper.Callback mTestCbs;
@Mock Context mMockContext;
- @Mock Resources mMockResources;
List<MediaSession.QueueItem> getQueueFromDescriptions(
List<MediaDescription.Builder> descriptions) {
@@ -98,8 +97,7 @@ public class MediaPlayerWrapperTest {
InstrumentationRegistry.getInstrumentation().getTargetContext());
mTestBitmap = loadImage(com.android.bluetooth.tests.R.raw.image_200_200);
- when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)).thenReturn(true);
- when(mMockContext.getResources()).thenReturn(mMockResources);
+ Util.sUriImagesSupport = true;
// Set failure handler to capture Log.wtf messages
Log.setWtfHandler(mFailHandler);
@@ -160,6 +158,14 @@ public class MediaPlayerWrapperTest {
MediaPlayerWrapper.sTesting = true;
}
+ @After
+ public void tearDown() {
+ if (mThread != null) {
+ mThread.quitSafely();
+ }
+ Util.sUriImagesSupport = false;
+ }
+
private Bitmap loadImage(int resId) {
InputStream imageInputStream = mTestResources.openRawResource(resId);
return BitmapFactory.decodeStream(imageInputStream);
diff --git a/android/app/tests/unit/src/com/android/bluetooth/audio_util/MetadataTest.java b/android/app/tests/unit/src/com/android/bluetooth/audio_util/MetadataTest.java
index 5ba6e0f4e5..4cc12f763d 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/audio_util/MetadataTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/audio_util/MetadataTest.java
@@ -38,7 +38,6 @@ import android.test.mock.MockContentResolver;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
-import com.android.bluetooth.R;
import com.android.bluetooth.TestUtils;
import org.junit.After;
@@ -59,7 +58,6 @@ public class MetadataTest {
@Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
private @Mock Context mMockContext;
- private @Mock Resources mMockResources;
private Resources mTestResources;
private MockContentResolver mTestContentResolver;
@@ -111,8 +109,7 @@ public class MetadataTest {
});
when(mMockContext.getContentResolver()).thenReturn(mTestContentResolver);
- when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)).thenReturn(true);
- when(mMockContext.getResources()).thenReturn(mMockResources);
+ Util.sUriImagesSupport = true;
mSongImage = new Image(mMockContext, mTestBitmap);
}
@@ -125,6 +122,7 @@ public class MetadataTest {
mTestResources = null;
mTargetContext = null;
mMockContext = null;
+ Util.sUriImagesSupport = false;
}
private Bitmap loadImage(int resId) {
@@ -427,7 +425,7 @@ public class MetadataTest {
*/
@Test
public void testBuildMetadataFromMediaMetadataWithUriAndUrisDisabled() {
- when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)).thenReturn(false);
+ Util.sUriImagesSupport = false;
MediaMetadata m = getMediaMetadataWithUri(MediaMetadata.METADATA_KEY_ART_URI, IMAGE_URI_1);
Metadata metadata =
new Metadata.Builder().useContext(mMockContext).fromMediaMetadata(m).build();
@@ -737,7 +735,7 @@ public class MetadataTest {
*/
@Test
public void testBuildMetadataFromBundleWithUriAndUrisDisabled() {
- when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)).thenReturn(false);
+ Util.sUriImagesSupport = false;
Bundle bundle = getBundleWithUri(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI, IMAGE_URI_1);
Metadata metadata =
new Metadata.Builder().useContext(mMockContext).fromBundle(bundle).build();
@@ -852,7 +850,7 @@ public class MetadataTest {
*/
@Test
public void testBuildMetadataFromMediaItemWithIconUriAndUrisDisabled() {
- when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)).thenReturn(false);
+ Util.sUriImagesSupport = false;
MediaDescription description = getMediaDescription(null, IMAGE_URI_1, null);
MediaItem item = getMediaItem(description);
Metadata metadata =
@@ -980,7 +978,7 @@ public class MetadataTest {
*/
@Test
public void testBuildMetadataFromQueueItemWithIconUriandUrisDisabled() {
- when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)).thenReturn(false);
+ Util.sUriImagesSupport = false;
MediaDescription description = getMediaDescription(null, IMAGE_URI_1, null);
QueueItem queueItem = getQueueItem(description);
Metadata metadata =
diff --git a/android/pandora/mmi2grpc/mmi2grpc/avrcp.py b/android/pandora/mmi2grpc/mmi2grpc/avrcp.py
index 2c4d1ed58d..c64eb2113f 100644
--- a/android/pandora/mmi2grpc/mmi2grpc/avrcp.py
+++ b/android/pandora/mmi2grpc/mmi2grpc/avrcp.py
@@ -117,6 +117,7 @@ class AVRCPProxy(ProfileProxy):
Action: Make sure the IUT is in a connectable state.
"""
+ self.mediaplayer.ResetQueue()
return "OK"
@assert_description
@@ -1086,7 +1087,7 @@ class AVRCPProxy(ProfileProxy):
"""
Please accept the l2cap channel connection for an OBEX connection.
"""
-
+
return "OK"
@assert_description
@@ -1094,7 +1095,7 @@ class AVRCPProxy(ProfileProxy):
"""
Please accept the OBEX CONNECT REQ.
"""
-
+
return "OK"
@@ -1105,7 +1106,7 @@ class AVRCPProxy(ProfileProxy):
ready.
"""
self.mediaplayer.Play()
-
+
return "OK"
@assert_description
@@ -1113,7 +1114,7 @@ class AVRCPProxy(ProfileProxy):
"""
Take action to reject the invalid 'get-img' request sent by the tester.
"""
-
+
return "OK"
@assert_description
@@ -1121,7 +1122,7 @@ class AVRCPProxy(ProfileProxy):
"""
Take action to accept the GetImgProperties operation from the tester.
"""
-
+
return "OK"
@assert_description
@@ -1129,7 +1130,7 @@ class AVRCPProxy(ProfileProxy):
"""
Take action to accept the GetImg operation from the tester.
"""
-
+
return "OK"
@assert_description
@@ -1137,7 +1138,7 @@ class AVRCPProxy(ProfileProxy):
"""
Was the currently displayed file or folder sent by the IUT?
"""
-
+
return "OK"
@assert_description
@@ -1148,5 +1149,5 @@ class AVRCPProxy(ProfileProxy):
"""
self.mediaplayer.UpdateQueue()
self.mediaplayer.PlayUpdated()
-
+
return "OK"
diff --git a/android/pandora/server/configs/pts_bot_tests_config.json b/android/pandora/server/configs/pts_bot_tests_config.json
index 717f76a612..93c26119ec 100644
--- a/android/pandora/server/configs/pts_bot_tests_config.json
+++ b/android/pandora/server/configs/pts_bot_tests_config.json
@@ -133,7 +133,6 @@
"AVRCP/TG/CA/BI-05-C",
"AVRCP/TG/CA/BI-07-C",
"AVRCP/TG/CA/BI-10-C",
- "AVRCP/TG/CA/BV-06-C",
"AVRCP/TG/CA/BV-16-C",
"AVRCP/CT/CEC/BV-02-I",
"AVRCP/CT/CRC/BV-02-I",
@@ -785,6 +784,7 @@
"AVRCP/TG/CA/BV-02-I",
"AVRCP/TG/CA/BV-03-I",
"AVRCP/TG/CA/BV-04-C",
+ "AVRCP/TG/CA/BV-06-C",
"AVRCP/TG/CA/BV-08-C",
"AVRCP/TG/CA/BV-10-C",
"AVRCP/TG/CA/BV-12-C",
@@ -3246,7 +3246,6 @@
"AVRCP/TG/CA/BI-05-C",
"AVRCP/TG/CA/BI-07-C",
"AVRCP/TG/CA/BI-10-C",
- "AVRCP/TG/CA/BV-06-C",
"AVRCP/TG/CA/BV-16-C"
]
},
diff --git a/android/pandora/server/src/MediaPlayer.kt b/android/pandora/server/src/MediaPlayer.kt
index d0cdb6d7fb..a2c981f881 100644
--- a/android/pandora/server/src/MediaPlayer.kt
+++ b/android/pandora/server/src/MediaPlayer.kt
@@ -118,6 +118,13 @@ class MediaPlayer(val context: Context) : MediaPlayerImplBase(), Closeable {
}
}
+ override fun resetQueue(request: Empty, responseObserver: StreamObserver<Empty>) {
+ grpcUnary<Empty>(scope, responseObserver) {
+ MediaPlayerBrowserService.instance.resetQueue()
+ Empty.getDefaultInstance()
+ }
+ }
+
override fun getShuffleMode(
request: Empty,
responseObserver: StreamObserver<GetShuffleModeResponse>
diff --git a/android/pandora/server/src/MediaPlayerBrowserService.kt b/android/pandora/server/src/MediaPlayerBrowserService.kt
index 0e32617de4..eaab8a9bbe 100644
--- a/android/pandora/server/src/MediaPlayerBrowserService.kt
+++ b/android/pandora/server/src/MediaPlayerBrowserService.kt
@@ -185,6 +185,16 @@ class MediaPlayerBrowserService : MediaBrowserServiceCompat() {
mediaSession.setQueue(queue)
}
+ fun resetQueue() {
+ if (metadataItems.contains("" + NEW_QUEUE_ITEM_INDEX)) {
+ metadataItems.remove("" + NEW_QUEUE_ITEM_INDEX)
+ queue.removeLast()
+ mediaSession.setQueue(queue)
+ stop()
+ currentTrack = QUEUE_START_INDEX
+ }
+ }
+
fun getShuffleMode(): Int {
val controller = mediaSession.getController()
return controller.getShuffleMode()
diff --git a/pandora/interfaces/pandora_experimental/mediaplayer.proto b/pandora/interfaces/pandora_experimental/mediaplayer.proto
index 06519f4130..69ead553d8 100644
--- a/pandora/interfaces/pandora_experimental/mediaplayer.proto
+++ b/pandora/interfaces/pandora_experimental/mediaplayer.proto
@@ -18,6 +18,7 @@ service MediaPlayer {
rpc Backward(google.protobuf.Empty) returns (google.protobuf.Empty);
rpc SetLargeMetadata(google.protobuf.Empty) returns (google.protobuf.Empty);
rpc UpdateQueue(google.protobuf.Empty) returns (google.protobuf.Empty);
+ rpc ResetQueue(google.protobuf.Empty) returns (google.protobuf.Empty);
rpc GetShuffleMode(google.protobuf.Empty) returns (GetShuffleModeResponse);
rpc SetShuffleMode(SetShuffleModeRequest) returns (google.protobuf.Empty);
rpc StartTestPlayback(google.protobuf.Empty) returns (google.protobuf.Empty);