Loading android/app/src/com/android/bluetooth/avrcp/Avrcp.java +49 −42 Original line number Diff line number Diff line Loading @@ -161,9 +161,8 @@ public final class Avrcp { private static final int MSG_SET_ABSOLUTE_VOLUME = 16; private static final int MSG_ABS_VOL_TIMEOUT = 17; private static final int MSG_SET_A2DP_AUDIO_STATE = 18; private static final int MSG_AVAILABLE_PLAYERS_CHANGED_RSP = 19; private static final int MSG_NOW_PLAYING_CHANGED_RSP = 20; private static final int MSG_UPDATE_MEDIA = 21; private static final int MSG_NOW_PLAYING_CHANGED_RSP = 19; private static final int MSG_UPDATE_MEDIA = 20; private static final int CMD_TIMEOUT_DELAY = 2000; private static final int MEDIA_DWELL_TIME = 1000; Loading @@ -179,6 +178,7 @@ public final class Avrcp { /* List of Media player instances, useful for retrieving MediaPlayerList or MediaPlayerInfo */ private SortedMap<Integer, MediaPlayerInfo> mMediaPlayerInfoList; private boolean mAvailablePlayerViewChanged; /* List of media players which supports browse */ private List<BrowsePlayerInfo> mBrowsePlayerInfoList; Loading Loading @@ -304,6 +304,7 @@ public final class Avrcp { mMediaControllerCb = new MediaControllerListener(); mAvrcpMediaRsp = new AvrcpMediaRsp(); mMediaPlayerInfoList = new TreeMap<Integer, MediaPlayerInfo>(); mAvailablePlayerViewChanged = false; mBrowsePlayerInfoList = Collections.synchronizedList(new ArrayList<BrowsePlayerInfo>()); mPassthroughDispatched = 0; mPassthroughLogs = new EvictingQueue<MediaKeyLog>(PASSTHROUGH_LOG_MAX_SIZE); Loading Loading @@ -474,13 +475,6 @@ public final class Avrcp { processRegisterNotification((byte[]) msg.obj, msg.arg1, msg.arg2); break; case MSG_AVAILABLE_PLAYERS_CHANGED_RSP: if (DEBUG) Log.v(TAG, "MSG_AVAILABLE_PLAYERS_CHANGED_RSP"); removeMessages(MSG_AVAILABLE_PLAYERS_CHANGED_RSP); registerNotificationRspAvalPlayerChangedNative( AvrcpConstants.NOTIFICATION_TYPE_CHANGED); break; case MSG_NOW_PLAYING_CHANGED_RSP: if (DEBUG) Log.v(TAG, "MSG_NOW_PLAYING_CHANGED_RSP"); removeMessages(MSG_NOW_PLAYING_CHANGED_RSP); Loading Loading @@ -986,12 +980,19 @@ public final class Avrcp { } private void updateCurrentMediaState(boolean registering) { if (!registering && mAddrPlayerChangedNT == AvrcpConstants.NOTIFICATION_TYPE_INTERIM // Only do player updates when we aren't registering for track changes. if (!registering) { if (mAvailablePlayerViewChanged) { registerNotificationRspAvalPlayerChangedNative( AvrcpConstants.NOTIFICATION_TYPE_CHANGED); mAvailablePlayerViewChanged = false; } if (mAddrPlayerChangedNT == AvrcpConstants.NOTIFICATION_TYPE_INTERIM && mReportedPlayerID != mCurrAddrPlayerID) { registerNotificationRspAddrPlayerChangedNative( AvrcpConstants.NOTIFICATION_TYPE_CHANGED, mCurrAddrPlayerID, sUIDCounter); mAddrPlayerChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; // Changing player sends reject to all these, so disable them. // Changing player sends reject to anything else we would notify... mReportedPlayerID = mCurrAddrPlayerID; mPlayStatusChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; Loading @@ -1000,6 +1001,7 @@ public final class Avrcp { // so we can skip the rest of the update. return; } } MediaAttributes currentAttributes; PlaybackState newState = updatePlaybackState(); Loading Loading @@ -1580,23 +1582,17 @@ public final class Avrcp { @Override public void onActiveSessionsChanged( List<android.media.session.MediaController> newControllers) { boolean playersChanged = false; // Update the current players for (android.media.session.MediaController controller : newControllers) { addMediaPlayerController(controller); playersChanged = true; } if (playersChanged) { mHandler.sendEmptyMessage(MSG_AVAILABLE_PLAYERS_CHANGED_RSP); if (newControllers.size() > 0 && getAddressedPlayerInfo() == null) { if (DEBUG) Log.v(TAG, "No addressed player but active sessions, taking first."); Log.v(TAG, "No addressed player but active sessions, taking first."); setAddressedMediaSessionPackage(newControllers.get(0).getPackageName()); } } scheduleMediaUpdate(); } }; Loading @@ -1612,7 +1608,7 @@ public final class Avrcp { // If the player doesn't exist, we need to add it. if (getMediaPlayerInfo(packageName) == null) { addMediaPlayerPackage(packageName); mHandler.sendEmptyMessage(MSG_AVAILABLE_PLAYERS_CHANGED_RSP); scheduleMediaUpdate(); } synchronized (mMediaPlayerInfoList) { for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) { Loading Loading @@ -1758,9 +1754,8 @@ public final class Avrcp { for (android.media.session.MediaController controller : controllers) { addMediaPlayerController(controller); } if (controllers.size() > 0) { mHandler.sendEmptyMessage(MSG_AVAILABLE_PLAYERS_CHANGED_RSP); } scheduleMediaUpdate(); if (mMediaPlayerInfoList.size() > 0) { // Set the first one as the Addressed Player Loading Loading @@ -1808,10 +1803,20 @@ public final class Avrcp { private boolean addMediaPlayerInfo(MediaPlayerInfo info) { int updateId = -1; boolean updated = false; boolean currentRemoved = false; synchronized (mMediaPlayerInfoList) { for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) { if (info.getPackageName().equals(entry.getValue().getPackageName())) { updateId = entry.getKey(); MediaPlayerInfo current = entry.getValue(); int id = entry.getKey(); if (info.getPackageName().equals(current.getPackageName())) { if (!current.equalView(info)) { // If we would present a different player, make it a new player // so that controllers know whether a player is browsable or not. mMediaPlayerInfoList.remove(id); currentRemoved = (mCurrAddrPlayerID == id); break; } updateId = id; updated = true; break; } Loading @@ -1820,12 +1825,13 @@ public final class Avrcp { // New player mLastUsedPlayerID++; updateId = mLastUsedPlayerID; mAvailablePlayerViewChanged = true; } mMediaPlayerInfoList.put(updateId, info); if (DEBUG) Log.d(TAG, (updated ? "update #" : "add #") + updateId + ":" + info.toString()); if (updateId == mCurrAddrPlayerID) { updateCurrentController(mCurrAddrPlayerID, mCurrBrowsePlayerID); if (currentRemoved || updateId == mCurrAddrPlayerID) { updateCurrentController(updateId, mCurrBrowsePlayerID); } } return updated; Loading @@ -1844,6 +1850,7 @@ public final class Avrcp { if (removeKey != -1) { if (DEBUG) Log.d(TAG, "remove #" + removeKey + ":" + mMediaPlayerInfoList.get(removeKey)); mAvailablePlayerViewChanged = true; return mMediaPlayerInfoList.remove(removeKey); } Loading android/app/src/com/android/bluetooth/avrcp/AvrcpHelperClasses.java +21 −7 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.bluetooth.avrcp; import android.annotation.NonNull; import android.annotation.Nullable; import android.media.session.MediaSession; import com.android.bluetooth.Utils; Loading Loading @@ -200,17 +202,19 @@ class MediaPlayerInfo { private int subType; private byte playStatus; private short[] featureBitMask; private String packageName; private String displayableName; private MediaController mediaController; private @NonNull String packageName; private @NonNull String displayableName; private @Nullable MediaController mediaController; MediaPlayerInfo(MediaController controller, byte majorType, int subType, byte playStatus, short[] featureBitMask, String packageName, String displayableName) { MediaPlayerInfo(@Nullable MediaController controller, byte majorType, int subType, byte playStatus, short[] featureBitMask, @NonNull String packageName, @Nullable String displayableName) { this.setMajorType(majorType); this.setSubType(subType); this.playStatus = playStatus; // store a copy the FeatureBitMask array this.featureBitMask = Arrays.copyOf(featureBitMask, featureBitMask.length); Arrays.sort(this.featureBitMask); this.setPackageName(packageName); this.setDisplayableName(displayableName); this.setMediaController(controller); Loading @@ -236,7 +240,7 @@ class MediaPlayerInfo { this.mediaController = mediaController; } void setPackageName(String name) { void setPackageName(@NonNull String name) { // Controller determines package name when it is set. if (mediaController != null) return; this.packageName = name; Loading Loading @@ -271,7 +275,8 @@ class MediaPlayerInfo { return displayableName; } void setDisplayableName(String displayableName) { void setDisplayableName(@Nullable String displayableName) { if (displayableName == null) displayableName = ""; this.displayableName = displayableName; } Loading @@ -282,6 +287,7 @@ class MediaPlayerInfo { void setFeatureBitMask(short[] featureBitMask) { synchronized (this) { this.featureBitMask = Arrays.copyOf(featureBitMask, featureBitMask.length); Arrays.sort(this.featureBitMask); } } Loading @@ -295,6 +301,14 @@ class MediaPlayerInfo { return false; } /** Tests if the view of this player presented to the controller is different enough to * justify sending an Available Players Changed update */ public boolean equalView(MediaPlayerInfo other) { return (this.majorType == other.getMajorType()) && (this.subType == other.getSubType()) && Arrays.equals(this.featureBitMask, other.getFeatureBitMask()) && this.displayableName.equals(other.getDisplayableName()); } @Override public String toString() { StringBuilder sb = new StringBuilder(); Loading Loading
android/app/src/com/android/bluetooth/avrcp/Avrcp.java +49 −42 Original line number Diff line number Diff line Loading @@ -161,9 +161,8 @@ public final class Avrcp { private static final int MSG_SET_ABSOLUTE_VOLUME = 16; private static final int MSG_ABS_VOL_TIMEOUT = 17; private static final int MSG_SET_A2DP_AUDIO_STATE = 18; private static final int MSG_AVAILABLE_PLAYERS_CHANGED_RSP = 19; private static final int MSG_NOW_PLAYING_CHANGED_RSP = 20; private static final int MSG_UPDATE_MEDIA = 21; private static final int MSG_NOW_PLAYING_CHANGED_RSP = 19; private static final int MSG_UPDATE_MEDIA = 20; private static final int CMD_TIMEOUT_DELAY = 2000; private static final int MEDIA_DWELL_TIME = 1000; Loading @@ -179,6 +178,7 @@ public final class Avrcp { /* List of Media player instances, useful for retrieving MediaPlayerList or MediaPlayerInfo */ private SortedMap<Integer, MediaPlayerInfo> mMediaPlayerInfoList; private boolean mAvailablePlayerViewChanged; /* List of media players which supports browse */ private List<BrowsePlayerInfo> mBrowsePlayerInfoList; Loading Loading @@ -304,6 +304,7 @@ public final class Avrcp { mMediaControllerCb = new MediaControllerListener(); mAvrcpMediaRsp = new AvrcpMediaRsp(); mMediaPlayerInfoList = new TreeMap<Integer, MediaPlayerInfo>(); mAvailablePlayerViewChanged = false; mBrowsePlayerInfoList = Collections.synchronizedList(new ArrayList<BrowsePlayerInfo>()); mPassthroughDispatched = 0; mPassthroughLogs = new EvictingQueue<MediaKeyLog>(PASSTHROUGH_LOG_MAX_SIZE); Loading Loading @@ -474,13 +475,6 @@ public final class Avrcp { processRegisterNotification((byte[]) msg.obj, msg.arg1, msg.arg2); break; case MSG_AVAILABLE_PLAYERS_CHANGED_RSP: if (DEBUG) Log.v(TAG, "MSG_AVAILABLE_PLAYERS_CHANGED_RSP"); removeMessages(MSG_AVAILABLE_PLAYERS_CHANGED_RSP); registerNotificationRspAvalPlayerChangedNative( AvrcpConstants.NOTIFICATION_TYPE_CHANGED); break; case MSG_NOW_PLAYING_CHANGED_RSP: if (DEBUG) Log.v(TAG, "MSG_NOW_PLAYING_CHANGED_RSP"); removeMessages(MSG_NOW_PLAYING_CHANGED_RSP); Loading Loading @@ -986,12 +980,19 @@ public final class Avrcp { } private void updateCurrentMediaState(boolean registering) { if (!registering && mAddrPlayerChangedNT == AvrcpConstants.NOTIFICATION_TYPE_INTERIM // Only do player updates when we aren't registering for track changes. if (!registering) { if (mAvailablePlayerViewChanged) { registerNotificationRspAvalPlayerChangedNative( AvrcpConstants.NOTIFICATION_TYPE_CHANGED); mAvailablePlayerViewChanged = false; } if (mAddrPlayerChangedNT == AvrcpConstants.NOTIFICATION_TYPE_INTERIM && mReportedPlayerID != mCurrAddrPlayerID) { registerNotificationRspAddrPlayerChangedNative( AvrcpConstants.NOTIFICATION_TYPE_CHANGED, mCurrAddrPlayerID, sUIDCounter); mAddrPlayerChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; // Changing player sends reject to all these, so disable them. // Changing player sends reject to anything else we would notify... mReportedPlayerID = mCurrAddrPlayerID; mPlayStatusChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; Loading @@ -1000,6 +1001,7 @@ public final class Avrcp { // so we can skip the rest of the update. return; } } MediaAttributes currentAttributes; PlaybackState newState = updatePlaybackState(); Loading Loading @@ -1580,23 +1582,17 @@ public final class Avrcp { @Override public void onActiveSessionsChanged( List<android.media.session.MediaController> newControllers) { boolean playersChanged = false; // Update the current players for (android.media.session.MediaController controller : newControllers) { addMediaPlayerController(controller); playersChanged = true; } if (playersChanged) { mHandler.sendEmptyMessage(MSG_AVAILABLE_PLAYERS_CHANGED_RSP); if (newControllers.size() > 0 && getAddressedPlayerInfo() == null) { if (DEBUG) Log.v(TAG, "No addressed player but active sessions, taking first."); Log.v(TAG, "No addressed player but active sessions, taking first."); setAddressedMediaSessionPackage(newControllers.get(0).getPackageName()); } } scheduleMediaUpdate(); } }; Loading @@ -1612,7 +1608,7 @@ public final class Avrcp { // If the player doesn't exist, we need to add it. if (getMediaPlayerInfo(packageName) == null) { addMediaPlayerPackage(packageName); mHandler.sendEmptyMessage(MSG_AVAILABLE_PLAYERS_CHANGED_RSP); scheduleMediaUpdate(); } synchronized (mMediaPlayerInfoList) { for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) { Loading Loading @@ -1758,9 +1754,8 @@ public final class Avrcp { for (android.media.session.MediaController controller : controllers) { addMediaPlayerController(controller); } if (controllers.size() > 0) { mHandler.sendEmptyMessage(MSG_AVAILABLE_PLAYERS_CHANGED_RSP); } scheduleMediaUpdate(); if (mMediaPlayerInfoList.size() > 0) { // Set the first one as the Addressed Player Loading Loading @@ -1808,10 +1803,20 @@ public final class Avrcp { private boolean addMediaPlayerInfo(MediaPlayerInfo info) { int updateId = -1; boolean updated = false; boolean currentRemoved = false; synchronized (mMediaPlayerInfoList) { for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) { if (info.getPackageName().equals(entry.getValue().getPackageName())) { updateId = entry.getKey(); MediaPlayerInfo current = entry.getValue(); int id = entry.getKey(); if (info.getPackageName().equals(current.getPackageName())) { if (!current.equalView(info)) { // If we would present a different player, make it a new player // so that controllers know whether a player is browsable or not. mMediaPlayerInfoList.remove(id); currentRemoved = (mCurrAddrPlayerID == id); break; } updateId = id; updated = true; break; } Loading @@ -1820,12 +1825,13 @@ public final class Avrcp { // New player mLastUsedPlayerID++; updateId = mLastUsedPlayerID; mAvailablePlayerViewChanged = true; } mMediaPlayerInfoList.put(updateId, info); if (DEBUG) Log.d(TAG, (updated ? "update #" : "add #") + updateId + ":" + info.toString()); if (updateId == mCurrAddrPlayerID) { updateCurrentController(mCurrAddrPlayerID, mCurrBrowsePlayerID); if (currentRemoved || updateId == mCurrAddrPlayerID) { updateCurrentController(updateId, mCurrBrowsePlayerID); } } return updated; Loading @@ -1844,6 +1850,7 @@ public final class Avrcp { if (removeKey != -1) { if (DEBUG) Log.d(TAG, "remove #" + removeKey + ":" + mMediaPlayerInfoList.get(removeKey)); mAvailablePlayerViewChanged = true; return mMediaPlayerInfoList.remove(removeKey); } Loading
android/app/src/com/android/bluetooth/avrcp/AvrcpHelperClasses.java +21 −7 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.bluetooth.avrcp; import android.annotation.NonNull; import android.annotation.Nullable; import android.media.session.MediaSession; import com.android.bluetooth.Utils; Loading Loading @@ -200,17 +202,19 @@ class MediaPlayerInfo { private int subType; private byte playStatus; private short[] featureBitMask; private String packageName; private String displayableName; private MediaController mediaController; private @NonNull String packageName; private @NonNull String displayableName; private @Nullable MediaController mediaController; MediaPlayerInfo(MediaController controller, byte majorType, int subType, byte playStatus, short[] featureBitMask, String packageName, String displayableName) { MediaPlayerInfo(@Nullable MediaController controller, byte majorType, int subType, byte playStatus, short[] featureBitMask, @NonNull String packageName, @Nullable String displayableName) { this.setMajorType(majorType); this.setSubType(subType); this.playStatus = playStatus; // store a copy the FeatureBitMask array this.featureBitMask = Arrays.copyOf(featureBitMask, featureBitMask.length); Arrays.sort(this.featureBitMask); this.setPackageName(packageName); this.setDisplayableName(displayableName); this.setMediaController(controller); Loading @@ -236,7 +240,7 @@ class MediaPlayerInfo { this.mediaController = mediaController; } void setPackageName(String name) { void setPackageName(@NonNull String name) { // Controller determines package name when it is set. if (mediaController != null) return; this.packageName = name; Loading Loading @@ -271,7 +275,8 @@ class MediaPlayerInfo { return displayableName; } void setDisplayableName(String displayableName) { void setDisplayableName(@Nullable String displayableName) { if (displayableName == null) displayableName = ""; this.displayableName = displayableName; } Loading @@ -282,6 +287,7 @@ class MediaPlayerInfo { void setFeatureBitMask(short[] featureBitMask) { synchronized (this) { this.featureBitMask = Arrays.copyOf(featureBitMask, featureBitMask.length); Arrays.sort(this.featureBitMask); } } Loading @@ -295,6 +301,14 @@ class MediaPlayerInfo { return false; } /** Tests if the view of this player presented to the controller is different enough to * justify sending an Available Players Changed update */ public boolean equalView(MediaPlayerInfo other) { return (this.majorType == other.getMajorType()) && (this.subType == other.getSubType()) && Arrays.equals(this.featureBitMask, other.getFeatureBitMask()) && this.displayableName.equals(other.getDisplayableName()); } @Override public String toString() { StringBuilder sb = new StringBuilder(); Loading