Loading android/app/jni/com_android_bluetooth_avrcp_controller.cpp +17 −1 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ static jmethodID method_createFromNativePlayerItem; static jmethodID method_handleChangeFolderRsp; static jmethodID method_handleSetBrowsedPlayerRsp; static jmethodID method_handleSetAddressedPlayerRsp; static jmethodID method_handleAddressedPlayerChanged; static jclass class_MediaBrowser_MediaItem; static jclass class_AvrcpPlayer; Loading Loading @@ -579,6 +580,17 @@ static void btavrcp_set_addressed_player_callback(const RawAddress& bd_addr, sCallbacksObj, method_handleSetAddressedPlayerRsp, (jint)status); } static void btavrcp_addressed_player_changed_callback(const RawAddress& bd_addr, uint16_t id) { ALOGI("%s status %d", __func__, id); CallbackEnv sCallbackEnv(__func__); if (!sCallbackEnv.valid()) return; sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleAddressedPlayerChanged, (jint)id); } static btrc_ctrl_callbacks_t sBluetoothAvrcpCallbacks = { sizeof(sBluetoothAvrcpCallbacks), btavrcp_passthrough_response_callback, Loading @@ -596,7 +608,8 @@ static btrc_ctrl_callbacks_t sBluetoothAvrcpCallbacks = { btavrcp_get_folder_items_callback, btavrcp_change_path_callback, btavrcp_set_browsed_player_callback, btavrcp_set_addressed_player_callback}; btavrcp_set_addressed_player_callback, btavrcp_addressed_player_changed_callback}; static void classInitNative(JNIEnv* env, jclass clazz) { method_handlePassthroughRsp = Loading Loading @@ -658,6 +671,9 @@ static void classInitNative(JNIEnv* env, jclass clazz) { env->GetMethodID(clazz, "handleSetBrowsedPlayerRsp", "(II)V"); method_handleSetAddressedPlayerRsp = env->GetMethodID(clazz, "handleSetAddressedPlayerRsp", "(I)V"); method_handleAddressedPlayerChanged = env->GetMethodID(clazz, "handleAddressedPlayerChanged", "(I)V"); ALOGI("%s: succeeds", __func__); } Loading android/app/src/com/android/bluetooth/a2dpsink/mbs/A2dpMediaBrowserService.java +19 −11 Original line number Diff line number Diff line Loading @@ -106,13 +106,11 @@ public class A2dpMediaBrowserService extends MediaBrowserService { private A2dpSinkService mA2dpSinkService = null; private Handler mAvrcpCommandQueue; private final Map<String, Result<List<MediaItem>>> mParentIdToRequestMap = new HashMap<>(); private int mCurrentlyHeldKey = 0; // Browsing related structures. private List<MediaItem> mNowPlayingList = null; private long mTransportControlFlags = PlaybackState.ACTION_PAUSE | PlaybackState.ACTION_PLAY | PlaybackState.ACTION_SKIP_TO_NEXT | PlaybackState.ACTION_SKIP_TO_PREVIOUS; private static final class AvrcpCommandQueueHandler extends Handler { WeakReference<A2dpMediaBrowserService> mInst; Loading Loading @@ -408,10 +406,6 @@ public class A2dpMediaBrowserService extends MediaBrowserService { mA2dpSinkService = A2dpSinkService.getA2dpSinkService(); PlaybackState playbackState = mAvrcpCtrlSrvc.getPlaybackState(mA2dpDevice); // Add actions required for playback and rebuild the object. PlaybackState.Builder pbb = new PlaybackState.Builder(playbackState); playbackState = pbb.setActions(mTransportControlFlags).build(); MediaMetadata mediaMetadata = mAvrcpCtrlSrvc.getMetaData(mA2dpDevice); if (VDBG) { Log.d(TAG, "Media metadata " + mediaMetadata + " playback state " + playbackState); Loading @@ -435,7 +429,6 @@ public class A2dpMediaBrowserService extends MediaBrowserService { PlaybackState.Builder pbb = new PlaybackState.Builder(); pbb = pbb.setState(PlaybackState.STATE_ERROR, PlaybackState.PLAYBACK_POSITION_UNKNOWN, PLAYBACK_SPEED) .setActions(mTransportControlFlags) .setErrorMessage(getString(R.string.bluetooth_disconnected)); mSession.setPlaybackState(pbb.build()); Loading Loading @@ -470,8 +463,6 @@ public class A2dpMediaBrowserService extends MediaBrowserService { if (pb != null) { if (DBG) Log.d(TAG, "msgTrack() playbackstate " + pb); PlaybackState.Builder pbb = new PlaybackState.Builder(pb); pb = pbb.setActions(mTransportControlFlags).build(); mSession.setPlaybackState(pb); // If we are now playing then we should start pushing updates via MediaSession so that Loading @@ -482,6 +473,11 @@ public class A2dpMediaBrowserService extends MediaBrowserService { } } private boolean isHoldableKey(int cmd) { return (cmd == AvrcpControllerService.PASS_THRU_CMD_ID_REWIND) || (cmd == AvrcpControllerService.PASS_THRU_CMD_ID_FF); } private synchronized void msgPassThru(int cmd) { if (DBG) Log.d(TAG, "msgPassThru " + cmd); if (mA2dpDevice == null) { Loading @@ -489,13 +485,25 @@ public class A2dpMediaBrowserService extends MediaBrowserService { Log.w(TAG, "Already disconnected ignoring."); return; } // Some keys should be held until the next event. if (mCurrentlyHeldKey != 0) { mAvrcpCtrlSrvc.sendPassThroughCmd(mA2dpDevice, mCurrentlyHeldKey, AvrcpControllerService.KEY_STATE_RELEASED); mCurrentlyHeldKey = 0; } // Send the pass through. mAvrcpCtrlSrvc.sendPassThroughCmd(mA2dpDevice, cmd, AvrcpControllerService.KEY_STATE_PRESSED); if (isHoldableKey(cmd)) { // Release cmd next time a command is sent. mCurrentlyHeldKey = cmd; } else { mAvrcpCtrlSrvc.sendPassThroughCmd(mA2dpDevice, cmd, AvrcpControllerService.KEY_STATE_RELEASED); } } private synchronized void msgGetPlayStatusNative() { if (DBG) Log.d(TAG, "msgGetPlayStatusNative"); Loading android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java +10 −1 Original line number Diff line number Diff line Loading @@ -1031,7 +1031,7 @@ public class AvrcpControllerService extends ProfileService { "createFromNativePlayerItem name: " + name + " transportFlags " + transportFlags + " play status " + playStatus + " player type " + playerType); } AvrcpPlayer player = new AvrcpPlayer(id, name, 0, playStatus, playerType); AvrcpPlayer player = new AvrcpPlayer(id, name, transportFlags, playStatus, playerType); return player; } Loading Loading @@ -1063,6 +1063,15 @@ public class AvrcpControllerService extends ProfileService { mAvrcpCtSm.sendMessage(msg); } private void handleAddressedPlayerChanged(int id) { if (DBG) { Log.d(TAG, "handleAddressedPlayerChanged id: " + id); } Message msg = mAvrcpCtSm.obtainMessage( AvrcpControllerStateMachine.MESSAGE_PROCESS_ADDRESSED_PLAYER_CHANGED, id); mAvrcpCtSm.sendMessage(msg); } @Override public void dump(StringBuilder sb) { super.dump(sb); Loading android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java +25 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import android.media.session.PlaybackState; import android.os.Bundle; import android.os.Message; import android.util.Log; import android.util.SparseArray; import com.android.bluetooth.BluetoothMetricsProto; import com.android.bluetooth.Utils; Loading Loading @@ -73,6 +74,7 @@ class AvrcpControllerStateMachine extends StateMachine { static final int MESSAGE_PROCESS_FOLDER_PATH = 112; static final int MESSAGE_PROCESS_SET_BROWSED_PLAYER = 113; static final int MESSAGE_PROCESS_SET_ADDRESSED_PLAYER = 114; static final int MESSAGE_PROCESS_ADDRESSED_PLAYER_CHANGED = 115; // commands from A2DP sink static final int MESSAGE_STOP_METADATA_BROADCASTS = 201; Loading Loading @@ -136,6 +138,8 @@ class AvrcpControllerStateMachine extends StateMachine { // Only accessed from State Machine processMessage private int mVolumeChangedNotificationsToIgnore = 0; private int mPreviousPercentageVol = -1; private int mAddressedPlayerID = -1; private SparseArray<AvrcpPlayer> mAvailablePlayerList = new SparseArray<AvrcpPlayer>(); // Depth from root of current browsing. This can be used to move to root directly. private int mBrowseDepth = 0; Loading Loading @@ -458,6 +462,17 @@ class AvrcpControllerStateMachine extends StateMachine { } break; case MESSAGE_PROCESS_ADDRESSED_PLAYER_CHANGED: mAddressedPlayerID = msg.arg1; if (DBG) Log.d(TAG, "AddressedPlayer = " + mAddressedPlayerID); AvrcpPlayer updatedPlayer = mAvailablePlayerList.get(mAddressedPlayerID); if (updatedPlayer != null) { mAddressedPlayer = updatedPlayer; if (DBG) Log.d(TAG, "AddressedPlayer = " + mAddressedPlayer.getName()); } sendMessage(MESSAGE_PROCESS_SET_ADDRESSED_PLAYER); break; default: return false; } Loading Loading @@ -729,12 +744,22 @@ class AvrcpControllerStateMachine extends StateMachine { switch (msg.what) { case MESSAGE_PROCESS_GET_PLAYER_ITEMS: List<AvrcpPlayer> playerList = (List<AvrcpPlayer>) msg.obj; mAvailablePlayerList.clear(); for (AvrcpPlayer player : playerList) { mAvailablePlayerList.put(player.getId(), player); } mBrowseTree.refreshChildren(BrowseTree.ROOT, playerList); ArrayList<MediaItem> mediaItemList = new ArrayList<>(); for (BrowseTree.BrowseNode c : mBrowseTree.findBrowseNodeByID(BrowseTree.ROOT) .getChildren()) { mediaItemList.add(c.getMediaItem()); } if (DBG) Log.d(TAG, "AddressedPlayer List Updated"); AvrcpPlayer updatedPlayer = mAvailablePlayerList.get(mAddressedPlayerID); if (updatedPlayer != null) { mAddressedPlayer = updatedPlayer; if (DBG) Log.d(TAG, "AddressedPlayer = " + mAddressedPlayer.getName()); } broadcastFolderList(BrowseTree.ROOT, mediaItemList); mBrowseTree.setCurrentBrowsedFolder(BrowseTree.ROOT); transitionTo(mConnected); Loading android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpPlayer.java +57 −2 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package com.android.bluetooth.avrcpcontroller; import android.media.session.PlaybackState; import android.util.Log; import java.util.Arrays; /* * Contains information about remote player */ Loading @@ -28,21 +30,38 @@ class AvrcpPlayer { public static final int INVALID_ID = -1; public static final int FEATURE_PLAY = 40; public static final int FEATURE_STOP = 41; public static final int FEATURE_PAUSE = 42; public static final int FEATURE_REWIND = 44; public static final int FEATURE_FAST_FORWARD = 45; public static final int FEATURE_FORWARD = 47; public static final int FEATURE_PREVIOUS = 48; public static final int FEATURE_BROWSING = 59; private int mPlayStatus = PlaybackState.STATE_NONE; private long mPlayTime = PlaybackState.PLAYBACK_POSITION_UNKNOWN; private int mId; private String mName = ""; private int mPlayerType; private byte[] mPlayerFeatures; private long mAvailableActions; private TrackInfo mCurrentTrack = new TrackInfo(); AvrcpPlayer() { mId = INVALID_ID; //Set Default Actions in case Player data isn't available. mAvailableActions = PlaybackState.ACTION_PAUSE | PlaybackState.ACTION_PLAY | PlaybackState.ACTION_SKIP_TO_NEXT | PlaybackState.ACTION_SKIP_TO_PREVIOUS; } AvrcpPlayer(int id, String name, int transportFlags, int playStatus, int playerType) { AvrcpPlayer(int id, String name, byte[] playerFeatures, int playStatus, int playerType) { mId = id; mName = name; mPlayStatus = playStatus; mPlayerType = playerType; mPlayerFeatures = Arrays.copyOf(playerFeatures, playerFeatures.length); updateAvailableActions(); } public int getId() { Loading @@ -65,6 +84,16 @@ class AvrcpPlayer { mPlayStatus = playStatus; } public int getPlayStatus() { return mPlayStatus; } public boolean supportsFeature(int featureId) { int byteNumber = featureId / 8; byte bitMask = (byte) (1 << (featureId % 8)); return (mPlayerFeatures[byteNumber] & bitMask) == bitMask; } public PlaybackState getPlaybackState() { if (DBG) { Log.d(TAG, "getPlayBackState state " + mPlayStatus + " time " + mPlayTime); Loading @@ -87,7 +116,8 @@ class AvrcpPlayer { speed = -3; break; } return new PlaybackState.Builder().setState(mPlayStatus, position, speed).build(); return new PlaybackState.Builder().setState(mPlayStatus, position, speed) .setActions(mAvailableActions).build(); } public synchronized void updateCurrentTrack(TrackInfo update) { Loading @@ -97,4 +127,29 @@ class AvrcpPlayer { public synchronized TrackInfo getCurrentTrack() { return mCurrentTrack; } private void updateAvailableActions() { if (supportsFeature(FEATURE_PLAY)) { mAvailableActions = mAvailableActions | PlaybackState.ACTION_PLAY; } if (supportsFeature(FEATURE_STOP)) { mAvailableActions = mAvailableActions | PlaybackState.ACTION_STOP; } if (supportsFeature(FEATURE_PAUSE)) { mAvailableActions = mAvailableActions | PlaybackState.ACTION_PAUSE; } if (supportsFeature(FEATURE_REWIND)) { mAvailableActions = mAvailableActions | PlaybackState.ACTION_REWIND; } if (supportsFeature(FEATURE_FAST_FORWARD)) { mAvailableActions = mAvailableActions | PlaybackState.ACTION_FAST_FORWARD; } if (supportsFeature(FEATURE_FORWARD)) { mAvailableActions = mAvailableActions | PlaybackState.ACTION_SKIP_TO_NEXT; } if (supportsFeature(FEATURE_PREVIOUS)) { mAvailableActions = mAvailableActions | PlaybackState.ACTION_SKIP_TO_PREVIOUS; } if (DBG) Log.d(TAG, "Supported Actions = " + mAvailableActions); } } Loading
android/app/jni/com_android_bluetooth_avrcp_controller.cpp +17 −1 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ static jmethodID method_createFromNativePlayerItem; static jmethodID method_handleChangeFolderRsp; static jmethodID method_handleSetBrowsedPlayerRsp; static jmethodID method_handleSetAddressedPlayerRsp; static jmethodID method_handleAddressedPlayerChanged; static jclass class_MediaBrowser_MediaItem; static jclass class_AvrcpPlayer; Loading Loading @@ -579,6 +580,17 @@ static void btavrcp_set_addressed_player_callback(const RawAddress& bd_addr, sCallbacksObj, method_handleSetAddressedPlayerRsp, (jint)status); } static void btavrcp_addressed_player_changed_callback(const RawAddress& bd_addr, uint16_t id) { ALOGI("%s status %d", __func__, id); CallbackEnv sCallbackEnv(__func__); if (!sCallbackEnv.valid()) return; sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleAddressedPlayerChanged, (jint)id); } static btrc_ctrl_callbacks_t sBluetoothAvrcpCallbacks = { sizeof(sBluetoothAvrcpCallbacks), btavrcp_passthrough_response_callback, Loading @@ -596,7 +608,8 @@ static btrc_ctrl_callbacks_t sBluetoothAvrcpCallbacks = { btavrcp_get_folder_items_callback, btavrcp_change_path_callback, btavrcp_set_browsed_player_callback, btavrcp_set_addressed_player_callback}; btavrcp_set_addressed_player_callback, btavrcp_addressed_player_changed_callback}; static void classInitNative(JNIEnv* env, jclass clazz) { method_handlePassthroughRsp = Loading Loading @@ -658,6 +671,9 @@ static void classInitNative(JNIEnv* env, jclass clazz) { env->GetMethodID(clazz, "handleSetBrowsedPlayerRsp", "(II)V"); method_handleSetAddressedPlayerRsp = env->GetMethodID(clazz, "handleSetAddressedPlayerRsp", "(I)V"); method_handleAddressedPlayerChanged = env->GetMethodID(clazz, "handleAddressedPlayerChanged", "(I)V"); ALOGI("%s: succeeds", __func__); } Loading
android/app/src/com/android/bluetooth/a2dpsink/mbs/A2dpMediaBrowserService.java +19 −11 Original line number Diff line number Diff line Loading @@ -106,13 +106,11 @@ public class A2dpMediaBrowserService extends MediaBrowserService { private A2dpSinkService mA2dpSinkService = null; private Handler mAvrcpCommandQueue; private final Map<String, Result<List<MediaItem>>> mParentIdToRequestMap = new HashMap<>(); private int mCurrentlyHeldKey = 0; // Browsing related structures. private List<MediaItem> mNowPlayingList = null; private long mTransportControlFlags = PlaybackState.ACTION_PAUSE | PlaybackState.ACTION_PLAY | PlaybackState.ACTION_SKIP_TO_NEXT | PlaybackState.ACTION_SKIP_TO_PREVIOUS; private static final class AvrcpCommandQueueHandler extends Handler { WeakReference<A2dpMediaBrowserService> mInst; Loading Loading @@ -408,10 +406,6 @@ public class A2dpMediaBrowserService extends MediaBrowserService { mA2dpSinkService = A2dpSinkService.getA2dpSinkService(); PlaybackState playbackState = mAvrcpCtrlSrvc.getPlaybackState(mA2dpDevice); // Add actions required for playback and rebuild the object. PlaybackState.Builder pbb = new PlaybackState.Builder(playbackState); playbackState = pbb.setActions(mTransportControlFlags).build(); MediaMetadata mediaMetadata = mAvrcpCtrlSrvc.getMetaData(mA2dpDevice); if (VDBG) { Log.d(TAG, "Media metadata " + mediaMetadata + " playback state " + playbackState); Loading @@ -435,7 +429,6 @@ public class A2dpMediaBrowserService extends MediaBrowserService { PlaybackState.Builder pbb = new PlaybackState.Builder(); pbb = pbb.setState(PlaybackState.STATE_ERROR, PlaybackState.PLAYBACK_POSITION_UNKNOWN, PLAYBACK_SPEED) .setActions(mTransportControlFlags) .setErrorMessage(getString(R.string.bluetooth_disconnected)); mSession.setPlaybackState(pbb.build()); Loading Loading @@ -470,8 +463,6 @@ public class A2dpMediaBrowserService extends MediaBrowserService { if (pb != null) { if (DBG) Log.d(TAG, "msgTrack() playbackstate " + pb); PlaybackState.Builder pbb = new PlaybackState.Builder(pb); pb = pbb.setActions(mTransportControlFlags).build(); mSession.setPlaybackState(pb); // If we are now playing then we should start pushing updates via MediaSession so that Loading @@ -482,6 +473,11 @@ public class A2dpMediaBrowserService extends MediaBrowserService { } } private boolean isHoldableKey(int cmd) { return (cmd == AvrcpControllerService.PASS_THRU_CMD_ID_REWIND) || (cmd == AvrcpControllerService.PASS_THRU_CMD_ID_FF); } private synchronized void msgPassThru(int cmd) { if (DBG) Log.d(TAG, "msgPassThru " + cmd); if (mA2dpDevice == null) { Loading @@ -489,13 +485,25 @@ public class A2dpMediaBrowserService extends MediaBrowserService { Log.w(TAG, "Already disconnected ignoring."); return; } // Some keys should be held until the next event. if (mCurrentlyHeldKey != 0) { mAvrcpCtrlSrvc.sendPassThroughCmd(mA2dpDevice, mCurrentlyHeldKey, AvrcpControllerService.KEY_STATE_RELEASED); mCurrentlyHeldKey = 0; } // Send the pass through. mAvrcpCtrlSrvc.sendPassThroughCmd(mA2dpDevice, cmd, AvrcpControllerService.KEY_STATE_PRESSED); if (isHoldableKey(cmd)) { // Release cmd next time a command is sent. mCurrentlyHeldKey = cmd; } else { mAvrcpCtrlSrvc.sendPassThroughCmd(mA2dpDevice, cmd, AvrcpControllerService.KEY_STATE_RELEASED); } } private synchronized void msgGetPlayStatusNative() { if (DBG) Log.d(TAG, "msgGetPlayStatusNative"); Loading
android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java +10 −1 Original line number Diff line number Diff line Loading @@ -1031,7 +1031,7 @@ public class AvrcpControllerService extends ProfileService { "createFromNativePlayerItem name: " + name + " transportFlags " + transportFlags + " play status " + playStatus + " player type " + playerType); } AvrcpPlayer player = new AvrcpPlayer(id, name, 0, playStatus, playerType); AvrcpPlayer player = new AvrcpPlayer(id, name, transportFlags, playStatus, playerType); return player; } Loading Loading @@ -1063,6 +1063,15 @@ public class AvrcpControllerService extends ProfileService { mAvrcpCtSm.sendMessage(msg); } private void handleAddressedPlayerChanged(int id) { if (DBG) { Log.d(TAG, "handleAddressedPlayerChanged id: " + id); } Message msg = mAvrcpCtSm.obtainMessage( AvrcpControllerStateMachine.MESSAGE_PROCESS_ADDRESSED_PLAYER_CHANGED, id); mAvrcpCtSm.sendMessage(msg); } @Override public void dump(StringBuilder sb) { super.dump(sb); Loading
android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java +25 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import android.media.session.PlaybackState; import android.os.Bundle; import android.os.Message; import android.util.Log; import android.util.SparseArray; import com.android.bluetooth.BluetoothMetricsProto; import com.android.bluetooth.Utils; Loading Loading @@ -73,6 +74,7 @@ class AvrcpControllerStateMachine extends StateMachine { static final int MESSAGE_PROCESS_FOLDER_PATH = 112; static final int MESSAGE_PROCESS_SET_BROWSED_PLAYER = 113; static final int MESSAGE_PROCESS_SET_ADDRESSED_PLAYER = 114; static final int MESSAGE_PROCESS_ADDRESSED_PLAYER_CHANGED = 115; // commands from A2DP sink static final int MESSAGE_STOP_METADATA_BROADCASTS = 201; Loading Loading @@ -136,6 +138,8 @@ class AvrcpControllerStateMachine extends StateMachine { // Only accessed from State Machine processMessage private int mVolumeChangedNotificationsToIgnore = 0; private int mPreviousPercentageVol = -1; private int mAddressedPlayerID = -1; private SparseArray<AvrcpPlayer> mAvailablePlayerList = new SparseArray<AvrcpPlayer>(); // Depth from root of current browsing. This can be used to move to root directly. private int mBrowseDepth = 0; Loading Loading @@ -458,6 +462,17 @@ class AvrcpControllerStateMachine extends StateMachine { } break; case MESSAGE_PROCESS_ADDRESSED_PLAYER_CHANGED: mAddressedPlayerID = msg.arg1; if (DBG) Log.d(TAG, "AddressedPlayer = " + mAddressedPlayerID); AvrcpPlayer updatedPlayer = mAvailablePlayerList.get(mAddressedPlayerID); if (updatedPlayer != null) { mAddressedPlayer = updatedPlayer; if (DBG) Log.d(TAG, "AddressedPlayer = " + mAddressedPlayer.getName()); } sendMessage(MESSAGE_PROCESS_SET_ADDRESSED_PLAYER); break; default: return false; } Loading Loading @@ -729,12 +744,22 @@ class AvrcpControllerStateMachine extends StateMachine { switch (msg.what) { case MESSAGE_PROCESS_GET_PLAYER_ITEMS: List<AvrcpPlayer> playerList = (List<AvrcpPlayer>) msg.obj; mAvailablePlayerList.clear(); for (AvrcpPlayer player : playerList) { mAvailablePlayerList.put(player.getId(), player); } mBrowseTree.refreshChildren(BrowseTree.ROOT, playerList); ArrayList<MediaItem> mediaItemList = new ArrayList<>(); for (BrowseTree.BrowseNode c : mBrowseTree.findBrowseNodeByID(BrowseTree.ROOT) .getChildren()) { mediaItemList.add(c.getMediaItem()); } if (DBG) Log.d(TAG, "AddressedPlayer List Updated"); AvrcpPlayer updatedPlayer = mAvailablePlayerList.get(mAddressedPlayerID); if (updatedPlayer != null) { mAddressedPlayer = updatedPlayer; if (DBG) Log.d(TAG, "AddressedPlayer = " + mAddressedPlayer.getName()); } broadcastFolderList(BrowseTree.ROOT, mediaItemList); mBrowseTree.setCurrentBrowsedFolder(BrowseTree.ROOT); transitionTo(mConnected); Loading
android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpPlayer.java +57 −2 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package com.android.bluetooth.avrcpcontroller; import android.media.session.PlaybackState; import android.util.Log; import java.util.Arrays; /* * Contains information about remote player */ Loading @@ -28,21 +30,38 @@ class AvrcpPlayer { public static final int INVALID_ID = -1; public static final int FEATURE_PLAY = 40; public static final int FEATURE_STOP = 41; public static final int FEATURE_PAUSE = 42; public static final int FEATURE_REWIND = 44; public static final int FEATURE_FAST_FORWARD = 45; public static final int FEATURE_FORWARD = 47; public static final int FEATURE_PREVIOUS = 48; public static final int FEATURE_BROWSING = 59; private int mPlayStatus = PlaybackState.STATE_NONE; private long mPlayTime = PlaybackState.PLAYBACK_POSITION_UNKNOWN; private int mId; private String mName = ""; private int mPlayerType; private byte[] mPlayerFeatures; private long mAvailableActions; private TrackInfo mCurrentTrack = new TrackInfo(); AvrcpPlayer() { mId = INVALID_ID; //Set Default Actions in case Player data isn't available. mAvailableActions = PlaybackState.ACTION_PAUSE | PlaybackState.ACTION_PLAY | PlaybackState.ACTION_SKIP_TO_NEXT | PlaybackState.ACTION_SKIP_TO_PREVIOUS; } AvrcpPlayer(int id, String name, int transportFlags, int playStatus, int playerType) { AvrcpPlayer(int id, String name, byte[] playerFeatures, int playStatus, int playerType) { mId = id; mName = name; mPlayStatus = playStatus; mPlayerType = playerType; mPlayerFeatures = Arrays.copyOf(playerFeatures, playerFeatures.length); updateAvailableActions(); } public int getId() { Loading @@ -65,6 +84,16 @@ class AvrcpPlayer { mPlayStatus = playStatus; } public int getPlayStatus() { return mPlayStatus; } public boolean supportsFeature(int featureId) { int byteNumber = featureId / 8; byte bitMask = (byte) (1 << (featureId % 8)); return (mPlayerFeatures[byteNumber] & bitMask) == bitMask; } public PlaybackState getPlaybackState() { if (DBG) { Log.d(TAG, "getPlayBackState state " + mPlayStatus + " time " + mPlayTime); Loading @@ -87,7 +116,8 @@ class AvrcpPlayer { speed = -3; break; } return new PlaybackState.Builder().setState(mPlayStatus, position, speed).build(); return new PlaybackState.Builder().setState(mPlayStatus, position, speed) .setActions(mAvailableActions).build(); } public synchronized void updateCurrentTrack(TrackInfo update) { Loading @@ -97,4 +127,29 @@ class AvrcpPlayer { public synchronized TrackInfo getCurrentTrack() { return mCurrentTrack; } private void updateAvailableActions() { if (supportsFeature(FEATURE_PLAY)) { mAvailableActions = mAvailableActions | PlaybackState.ACTION_PLAY; } if (supportsFeature(FEATURE_STOP)) { mAvailableActions = mAvailableActions | PlaybackState.ACTION_STOP; } if (supportsFeature(FEATURE_PAUSE)) { mAvailableActions = mAvailableActions | PlaybackState.ACTION_PAUSE; } if (supportsFeature(FEATURE_REWIND)) { mAvailableActions = mAvailableActions | PlaybackState.ACTION_REWIND; } if (supportsFeature(FEATURE_FAST_FORWARD)) { mAvailableActions = mAvailableActions | PlaybackState.ACTION_FAST_FORWARD; } if (supportsFeature(FEATURE_FORWARD)) { mAvailableActions = mAvailableActions | PlaybackState.ACTION_SKIP_TO_NEXT; } if (supportsFeature(FEATURE_PREVIOUS)) { mAvailableActions = mAvailableActions | PlaybackState.ACTION_SKIP_TO_PREVIOUS; } if (DBG) Log.d(TAG, "Supported Actions = " + mAvailableActions); } }