Loading android/app/src/com/android/bluetooth/avrcp/AddressedMediaPlayer.java +32 −58 Original line number Diff line number Diff line Loading @@ -49,24 +49,22 @@ public class AddressedMediaPlayer { static private final String UNKNOWN_TITLE = "(unknown)"; private AvrcpMediaRspInterface mMediaInterface; private List<MediaSession.QueueItem> mNowPlayingList; private @NonNull List<MediaSession.QueueItem> mNowPlayingList; private final List<MediaSession.QueueItem> mUnknownNowPlayingList; private final List<MediaSession.QueueItem> mEmptyNowPlayingList; private long mLastTrackIdSent; public AddressedMediaPlayer(AvrcpMediaRspInterface mediaInterface) { mNowPlayingList = null; mEmptyNowPlayingList = new ArrayList<MediaSession.QueueItem>(); mNowPlayingList = mEmptyNowPlayingList; mMediaInterface = mediaInterface; mLastTrackIdSent = MediaSession.QueueItem.UNKNOWN_ID; List<MediaSession.QueueItem> unknown = new ArrayList<MediaSession.QueueItem>(); unknown.add(getCurrentQueueItem(null, SINGLE_QID)); mUnknownNowPlayingList = unknown; } void cleanup() { if (DEBUG) Log.v(TAG, "cleanup"); mNowPlayingList = null; mNowPlayingList = mEmptyNowPlayingList; mMediaInterface = null; mLastTrackIdSent = MediaSession.QueueItem.UNKNOWN_ID; } Loading @@ -93,8 +91,8 @@ public class AddressedMediaPlayer { long mediaId = ByteBuffer.wrap(itemAttr.mUid).getLong(); List<MediaSession.QueueItem> items = getNowPlayingList(mediaController); /* checking if item attributes has been asked for now playing item or * some other item with specific media id */ // NOTE: this is out-of-spec (AVRCP 1.6.1 sec 6.10.4.3, p90) but we answer it anyway // because some CTs ask for it. if (Arrays.equals(itemAttr.mUid, AvrcpConstants.TRACK_IS_SELECTED)) { if (DEBUG) Log.d(TAG, "getItemAttr: Remote requests for now playing contents:"); Loading @@ -118,14 +116,14 @@ public class AddressedMediaPlayer { /* Refresh and get the queue of now playing. */ private List<MediaSession.QueueItem> getNowPlayingList( private @NonNull List<MediaSession.QueueItem> getNowPlayingList( @Nullable MediaController mediaController) { if (mediaController == null) return mUnknownNowPlayingList; if (mNowPlayingList != null) return mNowPlayingList; if (mediaController == null) return mEmptyNowPlayingList; List<MediaSession.QueueItem> items = mediaController.getQueue(); if (items == mNowPlayingList) return mNowPlayingList; if (items == null) { Log.i(TAG, "null queue from " + mediaController.getPackageName() + ", constructing current-item list"); + ", constructing single-item list"); MediaMetadata metadata = mediaController.getMetadata(); // Because we are database-unaware, we can just number the item here whatever we want // because they have to re-poll it every time. Loading @@ -134,6 +132,8 @@ public class AddressedMediaPlayer { items.add(current); } mNowPlayingList = items; // TODO (jamuraa): test to see if the single-item queue is the same and don't send mMediaInterface.nowPlayingChangedRsp(AvrcpConstants.NOTIFICATION_TYPE_CHANGED); return items; } Loading Loading @@ -193,14 +193,14 @@ public class AddressedMediaPlayer { return bundle; } void updateNowPlayingList(List<MediaSession.QueueItem> queue){ mNowPlayingList = queue; void updateNowPlayingList(@Nullable MediaController mediaController) { getNowPlayingList(mediaController); } /* Instructs media player to play particular media item */ void playItem(byte[] bdaddr, byte[] uid, @Nullable MediaController mediaController) { long qid = ByteBuffer.wrap(uid).getLong(); List<MediaSession.QueueItem> items = mNowPlayingList; List<MediaSession.QueueItem> items = getNowPlayingList(mediaController); if (mediaController == null) { Log.e(TAG, "No mediaController when PlayItem " + qid + " requested"); Loading Loading @@ -231,30 +231,8 @@ public class AddressedMediaPlayer { } void getTotalNumOfItems(byte[] bdaddr, @Nullable MediaController mediaController) { if (DEBUG) Log.d(TAG, "getTotalNumOfItems"); List<MediaSession.QueueItem> items = mNowPlayingList; if (items != null) { // We already have the cached list, send the response to remote mMediaInterface.getTotalNumOfItemsRsp( bdaddr, AvrcpConstants.RSP_NO_ERROR, 0, items.size()); return; } if (mediaController == null) { Log.e(TAG, "getTotalNumOfItems with no mediaController, sending no items"); mMediaInterface.getTotalNumOfItemsRsp(bdaddr, AvrcpConstants.RSP_NO_ERROR, 0, 0); return; } // We don't have the cached list, fetch it from Media Controller items = mediaController.getQueue(); if (items == null) { // We may be presenting a queue with only 1 item (the current one) int count = mediaController.getMetadata() != null ? 1 : 0; mMediaInterface.getTotalNumOfItemsRsp(bdaddr, AvrcpConstants.RSP_NO_ERROR, 0, count); } // Cache the response for later mNowPlayingList = items; List<MediaSession.QueueItem> items = getNowPlayingList(mediaController); if (DEBUG) Log.d(TAG, "getTotalNumOfItems: " + items.size() + " items."); mMediaInterface.getTotalNumOfItemsRsp(bdaddr, AvrcpConstants.RSP_NO_ERROR, 0, items.size()); } Loading @@ -268,6 +246,8 @@ public class AddressedMediaPlayer { if (requesting) trackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_INTERIM; mMediaInterface.trackChangedRsp(trackChangedNT, track); mLastTrackIdSent = qid; // The nowPlaying might have changed. updateNowPlayingList(mediaController); return (trackChangedNT == AvrcpConstants.NOTIFICATION_TYPE_CHANGED); } Loading @@ -275,8 +255,8 @@ public class AddressedMediaPlayer { * helper method to check if startItem and endItem index is with range of * MediaItem list. (Resultset containing all items in current path) */ private List<MediaSession.QueueItem> checkIndexOutofBounds( byte[] bdaddr, List<MediaSession.QueueItem> items, long startItem, long endItem) { private @Nullable List<MediaSession.QueueItem> getQueueSubset( @NonNull List<MediaSession.QueueItem> items, long startItem, long endItem) { if (endItem > items.size()) endItem = items.size() - 1; if (startItem > Integer.MAX_VALUE) startItem = Integer.MAX_VALUE; try { Loading @@ -300,23 +280,15 @@ public class AddressedMediaPlayer { * response */ private void getFolderItemsFilterAttr(byte[] bdaddr, AvrcpCmd.FolderItemsCmd folderItemsReqObj, List<MediaSession.QueueItem> items, byte scope, long startItem, long endItem, @NonNull List<MediaSession.QueueItem> items, byte scope, long startItem, long endItem, @NonNull MediaController mediaController) { if (DEBUG) Log.d(TAG, "getFolderItemsFilterAttr: startItem =" + startItem + ", endItem = " + endItem); List<MediaSession.QueueItem> result_items = new ArrayList<MediaSession.QueueItem>(); if (items == null) { Log.e(TAG, "items is null in getFolderItemsFilterAttr"); mMediaInterface.folderItemsRsp(bdaddr, AvrcpConstants.RSP_INV_RANGE, null); return; } result_items = checkIndexOutofBounds(bdaddr, items, startItem, endItem); List<MediaSession.QueueItem> result_items = getQueueSubset(items, startItem, endItem); /* check for index out of bound errors */ if (result_items == null) { Log.w(TAG, "result_items is null."); Log.w(TAG, "getFolderItemsFilterAttr: result_items is empty"); mMediaInterface.folderItemsRsp(bdaddr, AvrcpConstants.RSP_INV_RANGE, null); return; } Loading Loading @@ -530,17 +502,19 @@ public class AddressedMediaPlayer { if (controller == null) return MediaSession.QueueItem.UNKNOWN_ID; PlaybackState state = controller.getPlaybackState(); if (state == null) return MediaSession.QueueItem.UNKNOWN_ID; return state.getActiveQueueItemId(); long qid = state.getActiveQueueItemId(); if (qid != MediaSession.QueueItem.UNKNOWN_ID) return qid; // Check if we're presenting a "one item queue" if (controller.getMetadata() != null) return SINGLE_QID; return MediaSession.QueueItem.UNKNOWN_ID; } public void dump(StringBuilder sb, @Nullable MediaController mediaController) { ProfileService.println(sb, "AddressedPlayer info:"); ProfileService.println(sb, "mLastTrackIdSent: " + mLastTrackIdSent); ProfileService.println(sb, "mNowPlayingList: " + mNowPlayingList); List<MediaSession.QueueItem> queue = getNowPlayingList(mediaController); ProfileService.println(sb, "Current Queue: " + queue.size() + " elements"); ProfileService.println(sb, "mNowPlayingList: " + mNowPlayingList.size() + " elements"); long currentQueueId = getActiveQueueItemId(mediaController); for (MediaSession.QueueItem item : queue) { for (MediaSession.QueueItem item : mNowPlayingList) { long itemId = item.getQueueId(); ProfileService.println(sb, (itemId == currentQueueId ? "*" : " ") + item.toString()); } Loading android/app/src/com/android/bluetooth/avrcp/Avrcp.java +2 −4 Original line number Diff line number Diff line Loading @@ -393,7 +393,6 @@ public final class Avrcp { } Log.v(TAG, "onQueueChanged: NowPlaying list changed, Queue Size = "+ queue.size()); mAddressedMediaPlayer.updateNowPlayingList(queue); mHandler.sendEmptyMessage(MSG_NOW_PLAYING_CHANGED_RSP); } } Loading Loading @@ -474,8 +473,7 @@ public final class Avrcp { case MSG_NOW_PLAYING_CHANGED_RSP: if (DEBUG) Log.v(TAG, "MSG_NOW_PLAYING_CHANGED_RSP"); removeMessages(MSG_NOW_PLAYING_CHANGED_RSP); registerNotificationRspNowPlayingChangedNative( AvrcpConstants.NOTIFICATION_TYPE_CHANGED); mAddressedMediaPlayer.updateNowPlayingList(mMediaController); break; case MSG_ADDRESSED_PLAYER_CHANGED_RSP: Loading Loading @@ -2116,7 +2114,7 @@ public final class Avrcp { mMediaController = newController; if (mMediaController != null) { mMediaController.registerCallback(mMediaControllerCb, mHandler); mAddressedMediaPlayer.updateNowPlayingList(mMediaController.getQueue()); mAddressedMediaPlayer.updateNowPlayingList(mMediaController); } else { mAddressedMediaPlayer.updateNowPlayingList(null); registerRsp = false; Loading android/app/src/com/android/bluetooth/avrcp/mockable/MediaController.java +6 −2 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ import android.content.pm.ParceledListSlice; import android.media.AudioAttributes; import android.media.AudioManager; import android.media.MediaMetadata; import android.media.MediaDescription; import android.media.Rating; import android.media.VolumeProvider; import android.media.session.PlaybackState; Loading @@ -29,7 +30,7 @@ import java.util.ArrayList; import java.util.List; public class MediaController { public android.media.session.MediaController mDelegate; public @NonNull android.media.session.MediaController mDelegate; public android.media.session.MediaController.TransportControls mTransportDelegate; public TransportControls mTransportControls; Loading Loading @@ -152,7 +153,10 @@ public class MediaController { @Override public String toString() { return super.toString() + "(wraps " + mDelegate + ")"; MediaMetadata data = getMetadata(); MediaDescription desc = (data == null) ? null : data.getDescription(); return "MediaController (" + getPackageName() + "@" + Integer.toHexString(mDelegate.hashCode()) + ") " + desc; } public static abstract class Callback extends android.media.session.MediaController.Callback { } Loading Loading
android/app/src/com/android/bluetooth/avrcp/AddressedMediaPlayer.java +32 −58 Original line number Diff line number Diff line Loading @@ -49,24 +49,22 @@ public class AddressedMediaPlayer { static private final String UNKNOWN_TITLE = "(unknown)"; private AvrcpMediaRspInterface mMediaInterface; private List<MediaSession.QueueItem> mNowPlayingList; private @NonNull List<MediaSession.QueueItem> mNowPlayingList; private final List<MediaSession.QueueItem> mUnknownNowPlayingList; private final List<MediaSession.QueueItem> mEmptyNowPlayingList; private long mLastTrackIdSent; public AddressedMediaPlayer(AvrcpMediaRspInterface mediaInterface) { mNowPlayingList = null; mEmptyNowPlayingList = new ArrayList<MediaSession.QueueItem>(); mNowPlayingList = mEmptyNowPlayingList; mMediaInterface = mediaInterface; mLastTrackIdSent = MediaSession.QueueItem.UNKNOWN_ID; List<MediaSession.QueueItem> unknown = new ArrayList<MediaSession.QueueItem>(); unknown.add(getCurrentQueueItem(null, SINGLE_QID)); mUnknownNowPlayingList = unknown; } void cleanup() { if (DEBUG) Log.v(TAG, "cleanup"); mNowPlayingList = null; mNowPlayingList = mEmptyNowPlayingList; mMediaInterface = null; mLastTrackIdSent = MediaSession.QueueItem.UNKNOWN_ID; } Loading @@ -93,8 +91,8 @@ public class AddressedMediaPlayer { long mediaId = ByteBuffer.wrap(itemAttr.mUid).getLong(); List<MediaSession.QueueItem> items = getNowPlayingList(mediaController); /* checking if item attributes has been asked for now playing item or * some other item with specific media id */ // NOTE: this is out-of-spec (AVRCP 1.6.1 sec 6.10.4.3, p90) but we answer it anyway // because some CTs ask for it. if (Arrays.equals(itemAttr.mUid, AvrcpConstants.TRACK_IS_SELECTED)) { if (DEBUG) Log.d(TAG, "getItemAttr: Remote requests for now playing contents:"); Loading @@ -118,14 +116,14 @@ public class AddressedMediaPlayer { /* Refresh and get the queue of now playing. */ private List<MediaSession.QueueItem> getNowPlayingList( private @NonNull List<MediaSession.QueueItem> getNowPlayingList( @Nullable MediaController mediaController) { if (mediaController == null) return mUnknownNowPlayingList; if (mNowPlayingList != null) return mNowPlayingList; if (mediaController == null) return mEmptyNowPlayingList; List<MediaSession.QueueItem> items = mediaController.getQueue(); if (items == mNowPlayingList) return mNowPlayingList; if (items == null) { Log.i(TAG, "null queue from " + mediaController.getPackageName() + ", constructing current-item list"); + ", constructing single-item list"); MediaMetadata metadata = mediaController.getMetadata(); // Because we are database-unaware, we can just number the item here whatever we want // because they have to re-poll it every time. Loading @@ -134,6 +132,8 @@ public class AddressedMediaPlayer { items.add(current); } mNowPlayingList = items; // TODO (jamuraa): test to see if the single-item queue is the same and don't send mMediaInterface.nowPlayingChangedRsp(AvrcpConstants.NOTIFICATION_TYPE_CHANGED); return items; } Loading Loading @@ -193,14 +193,14 @@ public class AddressedMediaPlayer { return bundle; } void updateNowPlayingList(List<MediaSession.QueueItem> queue){ mNowPlayingList = queue; void updateNowPlayingList(@Nullable MediaController mediaController) { getNowPlayingList(mediaController); } /* Instructs media player to play particular media item */ void playItem(byte[] bdaddr, byte[] uid, @Nullable MediaController mediaController) { long qid = ByteBuffer.wrap(uid).getLong(); List<MediaSession.QueueItem> items = mNowPlayingList; List<MediaSession.QueueItem> items = getNowPlayingList(mediaController); if (mediaController == null) { Log.e(TAG, "No mediaController when PlayItem " + qid + " requested"); Loading Loading @@ -231,30 +231,8 @@ public class AddressedMediaPlayer { } void getTotalNumOfItems(byte[] bdaddr, @Nullable MediaController mediaController) { if (DEBUG) Log.d(TAG, "getTotalNumOfItems"); List<MediaSession.QueueItem> items = mNowPlayingList; if (items != null) { // We already have the cached list, send the response to remote mMediaInterface.getTotalNumOfItemsRsp( bdaddr, AvrcpConstants.RSP_NO_ERROR, 0, items.size()); return; } if (mediaController == null) { Log.e(TAG, "getTotalNumOfItems with no mediaController, sending no items"); mMediaInterface.getTotalNumOfItemsRsp(bdaddr, AvrcpConstants.RSP_NO_ERROR, 0, 0); return; } // We don't have the cached list, fetch it from Media Controller items = mediaController.getQueue(); if (items == null) { // We may be presenting a queue with only 1 item (the current one) int count = mediaController.getMetadata() != null ? 1 : 0; mMediaInterface.getTotalNumOfItemsRsp(bdaddr, AvrcpConstants.RSP_NO_ERROR, 0, count); } // Cache the response for later mNowPlayingList = items; List<MediaSession.QueueItem> items = getNowPlayingList(mediaController); if (DEBUG) Log.d(TAG, "getTotalNumOfItems: " + items.size() + " items."); mMediaInterface.getTotalNumOfItemsRsp(bdaddr, AvrcpConstants.RSP_NO_ERROR, 0, items.size()); } Loading @@ -268,6 +246,8 @@ public class AddressedMediaPlayer { if (requesting) trackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_INTERIM; mMediaInterface.trackChangedRsp(trackChangedNT, track); mLastTrackIdSent = qid; // The nowPlaying might have changed. updateNowPlayingList(mediaController); return (trackChangedNT == AvrcpConstants.NOTIFICATION_TYPE_CHANGED); } Loading @@ -275,8 +255,8 @@ public class AddressedMediaPlayer { * helper method to check if startItem and endItem index is with range of * MediaItem list. (Resultset containing all items in current path) */ private List<MediaSession.QueueItem> checkIndexOutofBounds( byte[] bdaddr, List<MediaSession.QueueItem> items, long startItem, long endItem) { private @Nullable List<MediaSession.QueueItem> getQueueSubset( @NonNull List<MediaSession.QueueItem> items, long startItem, long endItem) { if (endItem > items.size()) endItem = items.size() - 1; if (startItem > Integer.MAX_VALUE) startItem = Integer.MAX_VALUE; try { Loading @@ -300,23 +280,15 @@ public class AddressedMediaPlayer { * response */ private void getFolderItemsFilterAttr(byte[] bdaddr, AvrcpCmd.FolderItemsCmd folderItemsReqObj, List<MediaSession.QueueItem> items, byte scope, long startItem, long endItem, @NonNull List<MediaSession.QueueItem> items, byte scope, long startItem, long endItem, @NonNull MediaController mediaController) { if (DEBUG) Log.d(TAG, "getFolderItemsFilterAttr: startItem =" + startItem + ", endItem = " + endItem); List<MediaSession.QueueItem> result_items = new ArrayList<MediaSession.QueueItem>(); if (items == null) { Log.e(TAG, "items is null in getFolderItemsFilterAttr"); mMediaInterface.folderItemsRsp(bdaddr, AvrcpConstants.RSP_INV_RANGE, null); return; } result_items = checkIndexOutofBounds(bdaddr, items, startItem, endItem); List<MediaSession.QueueItem> result_items = getQueueSubset(items, startItem, endItem); /* check for index out of bound errors */ if (result_items == null) { Log.w(TAG, "result_items is null."); Log.w(TAG, "getFolderItemsFilterAttr: result_items is empty"); mMediaInterface.folderItemsRsp(bdaddr, AvrcpConstants.RSP_INV_RANGE, null); return; } Loading Loading @@ -530,17 +502,19 @@ public class AddressedMediaPlayer { if (controller == null) return MediaSession.QueueItem.UNKNOWN_ID; PlaybackState state = controller.getPlaybackState(); if (state == null) return MediaSession.QueueItem.UNKNOWN_ID; return state.getActiveQueueItemId(); long qid = state.getActiveQueueItemId(); if (qid != MediaSession.QueueItem.UNKNOWN_ID) return qid; // Check if we're presenting a "one item queue" if (controller.getMetadata() != null) return SINGLE_QID; return MediaSession.QueueItem.UNKNOWN_ID; } public void dump(StringBuilder sb, @Nullable MediaController mediaController) { ProfileService.println(sb, "AddressedPlayer info:"); ProfileService.println(sb, "mLastTrackIdSent: " + mLastTrackIdSent); ProfileService.println(sb, "mNowPlayingList: " + mNowPlayingList); List<MediaSession.QueueItem> queue = getNowPlayingList(mediaController); ProfileService.println(sb, "Current Queue: " + queue.size() + " elements"); ProfileService.println(sb, "mNowPlayingList: " + mNowPlayingList.size() + " elements"); long currentQueueId = getActiveQueueItemId(mediaController); for (MediaSession.QueueItem item : queue) { for (MediaSession.QueueItem item : mNowPlayingList) { long itemId = item.getQueueId(); ProfileService.println(sb, (itemId == currentQueueId ? "*" : " ") + item.toString()); } Loading
android/app/src/com/android/bluetooth/avrcp/Avrcp.java +2 −4 Original line number Diff line number Diff line Loading @@ -393,7 +393,6 @@ public final class Avrcp { } Log.v(TAG, "onQueueChanged: NowPlaying list changed, Queue Size = "+ queue.size()); mAddressedMediaPlayer.updateNowPlayingList(queue); mHandler.sendEmptyMessage(MSG_NOW_PLAYING_CHANGED_RSP); } } Loading Loading @@ -474,8 +473,7 @@ public final class Avrcp { case MSG_NOW_PLAYING_CHANGED_RSP: if (DEBUG) Log.v(TAG, "MSG_NOW_PLAYING_CHANGED_RSP"); removeMessages(MSG_NOW_PLAYING_CHANGED_RSP); registerNotificationRspNowPlayingChangedNative( AvrcpConstants.NOTIFICATION_TYPE_CHANGED); mAddressedMediaPlayer.updateNowPlayingList(mMediaController); break; case MSG_ADDRESSED_PLAYER_CHANGED_RSP: Loading Loading @@ -2116,7 +2114,7 @@ public final class Avrcp { mMediaController = newController; if (mMediaController != null) { mMediaController.registerCallback(mMediaControllerCb, mHandler); mAddressedMediaPlayer.updateNowPlayingList(mMediaController.getQueue()); mAddressedMediaPlayer.updateNowPlayingList(mMediaController); } else { mAddressedMediaPlayer.updateNowPlayingList(null); registerRsp = false; Loading
android/app/src/com/android/bluetooth/avrcp/mockable/MediaController.java +6 −2 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ import android.content.pm.ParceledListSlice; import android.media.AudioAttributes; import android.media.AudioManager; import android.media.MediaMetadata; import android.media.MediaDescription; import android.media.Rating; import android.media.VolumeProvider; import android.media.session.PlaybackState; Loading @@ -29,7 +30,7 @@ import java.util.ArrayList; import java.util.List; public class MediaController { public android.media.session.MediaController mDelegate; public @NonNull android.media.session.MediaController mDelegate; public android.media.session.MediaController.TransportControls mTransportDelegate; public TransportControls mTransportControls; Loading Loading @@ -152,7 +153,10 @@ public class MediaController { @Override public String toString() { return super.toString() + "(wraps " + mDelegate + ")"; MediaMetadata data = getMetadata(); MediaDescription desc = (data == null) ? null : data.getDescription(); return "MediaController (" + getPackageName() + "@" + Integer.toHexString(mDelegate.hashCode()) + ") " + desc; } public static abstract class Callback extends android.media.session.MediaController.Callback { } Loading