Merge "A2DP: Add support for multicast in config store" into bt.lnx.5.0
diff --git a/packages_apps_bluetooth_ext/src/avrcp/AddressedMediaPlayer_ext.java b/packages_apps_bluetooth_ext/src/avrcp/AddressedMediaPlayer_ext.java
index a650069..4dd8e2e 100644
--- a/packages_apps_bluetooth_ext/src/avrcp/AddressedMediaPlayer_ext.java
+++ b/packages_apps_bluetooth_ext/src/avrcp/AddressedMediaPlayer_ext.java
@@ -506,10 +506,11 @@
                     break;
 
                 case AvrcpConstants_ext.ATTRID_COVER_ART:
-                    if (mAvrcp != null) {
+                    if (mAvrcp != null && mAvrcp.isCoverArtFeatureSupported(bdaddr)) {
                         attrValue = mAvrcp.getImgHandleFromTitle(bdaddr,
                                 desc.getTitle().toString());
                     } else {
+                        attrValue = null;
                         if (DEBUG) Log.d(TAG, " mAvrcp null ");
                     }
                     break;
diff --git a/packages_apps_bluetooth_ext/src/avrcp/Avrcp_ext.java b/packages_apps_bluetooth_ext/src/avrcp/Avrcp_ext.java
index 0517c05..9381d4c 100644
--- a/packages_apps_bluetooth_ext/src/avrcp/Avrcp_ext.java
+++ b/packages_apps_bluetooth_ext/src/avrcp/Avrcp_ext.java
@@ -198,7 +198,8 @@
     public static final int BTRC_FEAT_METADATA = 0x01;
     public static final int BTRC_FEAT_ABSOLUTE_VOLUME = 0x02;
     public static final int BTRC_FEAT_BROWSE = 0x04;
-    public static final int BTRC_FEAT_AVRC_UI_UPDATE = 0x08;
+    public static final int BTRC_FEAT_COVER_ART = 0x08;
+    public static final int BTRC_FEAT_AVRC_UI_UPDATE = 0x10;
 
     /* AVRC response codes, from avrc_defs */
     private static final int AVRC_RSP_NOT_IMPL = 8;
@@ -239,6 +240,7 @@
     private final static int MESSAGE_UPDATE_ABS_VOLUME_STATUS = 31;
     private static final int MSG_PLAY_STATUS_CMD_TIMEOUT = 33;
     private final static int MESSAGE_START_SHO = 34;
+    private static final int MSG_SET_ACTIVE_DEVICE = 35;
 
     private static final int STACK_CLEANUP = 0;
     private static final int APP_CLEANUP = 1;
@@ -693,6 +695,30 @@
         Log.d(TAG, "Exit cleanup()");
     }
 
+    public boolean isCoverArtFeatureSupported(byte[] bdaddr) {
+        Log.w(TAG, "isCoverArtFeatureSupported");
+        String address = Utils.getAddressStringFromByte((byte[]) bdaddr);
+        BluetoothDevice device = mAdapter.getRemoteDevice(address);
+        if (device == null)
+            return false;
+        MediaPlayerInfo_ext player = mMediaPlayerInfoList.getOrDefault(mCurrAddrPlayerID, null);
+        int index = getIndexForDevice(device);
+        if ((index == INVALID_DEVICE_INDEX) || (player == null))
+            return false;
+
+        short[] featureBits = player.getFeatureBitMask();
+        boolean playerSupportsCA = false;
+        for (int i = 0; i < featureBits.length; i++) {
+            if (featureBits[i] == AvrcpConstants_ext.AVRC_PF_COVER_ART_BIT_NO) {
+                playerSupportsCA = true;
+                break;
+            }
+        }
+        boolean peerSupprtsCA = ((deviceFeatures[index].mFeatures & BTRC_FEAT_COVER_ART) != 0);
+        Log.w(TAG, "playersupportCA " + playerSupportsCA + " peersupportCA " + peerSupprtsCA);
+        return (peerSupprtsCA && playerSupportsCA);
+    }
+
     private class AudioManagerPlaybackListener extends AudioManager.AudioPlaybackCallback {
         @Override
         public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {
@@ -1612,6 +1638,114 @@
                 }
                 break;
 
+            case MSG_SET_ACTIVE_DEVICE:
+                boolean tws_switch = false;
+                Log.d(TAG, "MSG_SET_ACTIVE_DEVICE");
+                BluetoothDevice bt_device = (BluetoothDevice) msg.obj;
+                if (bt_device == null) {
+                    for (int i = 0; i < maxAvrcpConnections; i++) {
+                        deviceFeatures[i].isActiveDevice = false;
+                    }
+                    break;
+                }
+                if (bt_device != null && bt_device.isTwsPlusDevice()) {
+                    for (int i = 0; i < maxAvrcpConnections; i++) {
+                        if (deviceFeatures[i].mCurrentDevice != null &&
+                                deviceFeatures[i].isActiveDevice &&
+                                deviceFeatures[i].mCurrentDevice.isTwsPlusDevice()) {
+                            tws_switch = true;
+                        }
+                    }
+                }
+                deviceIndex = getIndexForDevice(bt_device);
+                if (deviceIndex == INVALID_DEVICE_INDEX) {
+                    Log.e(TAG,"Invalid device index for setActiveDevice");
+                    for (int i = 0; i < maxAvrcpConnections; i++) {
+                        deviceFeatures[i].isActiveDevice = false;
+                    }
+                    break;
+                }
+                deviceFeatures[deviceIndex].isActiveDevice = true;
+
+                Log.w(TAG, "Active device Calling SetBrowsePackage for " + mCachedBrowsePlayer);
+                if (mCachedBrowsePlayer != null && is_player_updated_for_browse == false) {
+                    SetBrowsePackage(mCachedBrowsePlayer);
+                }
+
+                if (deviceFeatures[deviceIndex].mCurrentDevice.isTwsPlusDevice() &&
+                        updateAbsVolume == true) {
+                    Log.d(TAG,"setting absVolume flag for TWS+ device");
+                    mAudioManager.avrcpSupportsAbsoluteVolume(bt_device.getAddress(),true);
+                    AdapterService mAdapterService = AdapterService.getAdapterService();
+                    BluetoothDevice peer_device = mAdapterService.
+                            getTwsPlusPeerDevice(deviceFeatures[deviceIndex].mCurrentDevice);
+                    if (peer_device != null &&
+                            getIndexForDevice(peer_device) == INVALID_DEVICE_INDEX) {
+                        Log.d(TAG,"Other TWS+ earbud not connected, reset updateAbsVolume flag");
+                        updateAbsVolume = false;
+                    }
+                }
+                if (bt_device.isTwsPlusDevice() && !tws_switch) {
+                    Log.d(TAG,"Restting mTwsPairDisconnected at index " + deviceIndex);
+                    deviceFeatures[deviceIndex].mTwsPairDisconnected = false;
+                }
+                if (maxAvrcpConnections > 1) {
+                    for (int i = 0; i < maxAvrcpConnections; i++) {
+                        if (deviceIndex != i && deviceFeatures[i].mCurrentDevice != null &&
+                                deviceFeatures[i].mCurrentDevice.isTwsPlusDevice() &&
+                                isTwsPlusPair(deviceFeatures[i].mCurrentDevice, bt_device)) {
+                            Log.d(TAG,"TWS+ pair connected, keep both devices active");
+                            deviceFeatures[i].isActiveDevice = true;
+                            if (updateAbsVolume == true) {
+                                Log.d(TAG,"Setting absVolume flag to TWS+ pair");
+                                mAudioManager.avrcpSupportsAbsoluteVolume(
+                                        bt_device.getAddress(), true);
+                                updateAbsVolume = false;
+                            }
+                        } else {
+                            if (deviceIndex != i)
+                                deviceFeatures[i].isActiveDevice = false;
+                        }
+                    }
+                }
+                Log.e(TAG, "AVRCP isActive device index " + deviceIndex + " setActive addr " +
+                            deviceFeatures[deviceIndex].mCurrentDevice.getAddress());
+
+                //to keep volume copy for setting volume
+                deviceFeatures[deviceIndex].mLocalVolume = getVolume(bt_device);
+                if((maxAvrcpConnections > 1) && (deviceFeatures[deviceIndex].mCurrentDevice != null)
+                        && (deviceFeatures[deviceIndex].mReportedPlayerID != mCurrAddrPlayerID)) {
+                    Log.d(TAG,"Update cache browsing event to last active device, deviceFeatures[" +
+                            deviceIndex + "].mReportedPlayerID: " +
+                            deviceFeatures[deviceIndex].mReportedPlayerID +
+                            ", mCurrAddrPlayerID: " + mCurrAddrPlayerID);
+                    if (deviceFeatures[deviceIndex].mAvailablePlayersChangedNT ==
+                            AvrcpConstants.NOTIFICATION_TYPE_INTERIM) {
+                        registerNotificationRspAvalPlayerChangedNative(
+                                AvrcpConstants.NOTIFICATION_TYPE_CHANGED,
+                                getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
+                        mAvailablePlayerViewChanged = false;
+                        deviceFeatures[deviceIndex].mAvailablePlayersChangedNT =
+                                AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
+                    }
+                    if (deviceFeatures[deviceIndex].mAddrPlayerChangedNT ==
+                            AvrcpConstants.NOTIFICATION_TYPE_INTERIM) {
+                        registerNotificationRspAddrPlayerChangedNative(
+                                AvrcpConstants.NOTIFICATION_TYPE_CHANGED,
+                                mCurrAddrPlayerID, sUIDCounter,
+                                getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
+                        deviceFeatures[deviceIndex].mAddrPlayerChangedNT =
+                                AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
+                        // send track change event becasue some carkits will refresh metadata
+                        // while receive addressed player change event. Track change event to
+                        // make remote get metadata correctly.
+                        sendTrackChangedRsp(false, deviceFeatures[deviceIndex].mCurrentDevice);
+                    }
+
+                    deviceFeatures[deviceIndex].mReportedPlayerID = mCurrAddrPlayerID;
+                    break;
+                }
+
             default:
                 Log.e(TAG, "unknown message! msg.what=" + msg.what);
                 break;
@@ -4581,7 +4715,7 @@
             if (connList.containsKey(bdaddrStr)) {
                 mediaPlayer = connList.get(bdaddrStr);
             } else {
-                mediaPlayer = new BrowsedMediaPlayer_ext(bdaddr, mContext, mMediaInterface);
+                mediaPlayer = new BrowsedMediaPlayer_ext(bdaddr, mContext, mMediaInterface, mAvrcp);
                 connList.put(bdaddrStr, mediaPlayer);
             }
             return mediaPlayer;
@@ -5037,106 +5171,9 @@
     }
 
     public void setActiveDevice(BluetoothDevice device) {
-        boolean tws_switch = false;
-        if (device == null) {
-          for (int i = 0; i < maxAvrcpConnections; i++) {
-              deviceFeatures[i].isActiveDevice = false;
-          }
-          return;
-        }
-        if (device != null && device.isTwsPlusDevice()) {
-            for (int i = 0; i < maxAvrcpConnections; i++) {
-                if (deviceFeatures[i].mCurrentDevice != null &&
-                    deviceFeatures[i].isActiveDevice &&
-                    deviceFeatures[i].mCurrentDevice.isTwsPlusDevice()) {
-                    tws_switch = true;
-                }
-            }
-        }
-        int deviceIndex = getIndexForDevice(device);
-        if (deviceIndex == INVALID_DEVICE_INDEX) {
-            Log.e(TAG,"Invalid device index for setActiveDevice");
-            for (int i = 0; i < maxAvrcpConnections; i++) {
-                deviceFeatures[i].isActiveDevice = false;
-            }
-            return;
-        }
-        deviceFeatures[deviceIndex].isActiveDevice = true;
-
-        Log.w(TAG, "Active device Calling SetBrowsePackage for " + mCachedBrowsePlayer);
-        if (mCachedBrowsePlayer != null && is_player_updated_for_browse == false) {
-            SetBrowsePackage(mCachedBrowsePlayer);
-        }
-
-        if (updateAbsVolume == true && deviceFeatures[deviceIndex].mCurrentDevice.isTwsPlusDevice()) {
-            Log.d(TAG,"setting absVolume flag for TWS+ device");
-            mAudioManager.avrcpSupportsAbsoluteVolume(device.getAddress(),true);
-            AdapterService mAdapterService = AdapterService.getAdapterService();
-            BluetoothDevice peer_device =
-                 mAdapterService.getTwsPlusPeerDevice(deviceFeatures[deviceIndex].mCurrentDevice);
-            if (peer_device != null &&
-                getIndexForDevice(peer_device) == INVALID_DEVICE_INDEX) {
-                Log.d(TAG,"Other TWS+ earbud not connected, reset updateAbsVolume flag");
-                updateAbsVolume = false;
-            }
-        }
-        if (device.isTwsPlusDevice() && !tws_switch) {
-            Log.d(TAG,"Restting mTwsPairDisconnected at index " + deviceIndex);
-            deviceFeatures[deviceIndex].mTwsPairDisconnected = false;
-        }
-        if (maxAvrcpConnections > 1) {
-            for (int i = 0; i < maxAvrcpConnections; i++) {
-                if (deviceIndex != i && deviceFeatures[i].mCurrentDevice != null &&
-                    deviceFeatures[i].mCurrentDevice.isTwsPlusDevice() &&
-                    isTwsPlusPair(deviceFeatures[i].mCurrentDevice, device)) {
-                    Log.d(TAG,"TWS+ pair connected, keep both devices active");
-                    deviceFeatures[i].isActiveDevice = true;
-                    if (updateAbsVolume == true) {
-                        Log.d(TAG,"Setting absVolume flag to TWS+ pair");
-                        mAudioManager.avrcpSupportsAbsoluteVolume(device.getAddress(),true);
-                        updateAbsVolume = false;
-                    }
-                } else {
-                    if(deviceIndex != i)
-                        deviceFeatures[i].isActiveDevice = false;
-                }
-            }
-        }
-        Log.e(TAG,"AVRCP setActive  addr " + deviceFeatures[deviceIndex].mCurrentDevice.getAddress() +
-                    " isActive device index " + deviceIndex);
-
-        //to keep volume copy for setting volume
-        deviceFeatures[deviceIndex].mLocalVolume = getVolume(device);
-        if ((maxAvrcpConnections > 1) && (deviceFeatures[deviceIndex].mCurrentDevice != null) &&
-                (deviceFeatures[deviceIndex].mReportedPlayerID != mCurrAddrPlayerID)) {
-            Log.d(TAG,"Update cached browsing events to latest active device, deviceFeatures[" +
-                    deviceIndex + "].mReportedPlayerID: " +
-                    deviceFeatures[deviceIndex].mReportedPlayerID +
-                    ", mCurrAddrPlayerID: " + mCurrAddrPlayerID);
-            if (deviceFeatures[deviceIndex].mAvailablePlayersChangedNT ==
-                    AvrcpConstants_ext.NOTIFICATION_TYPE_INTERIM) {
-                registerNotificationRspAvalPlayerChangedNative(
-                        AvrcpConstants_ext.NOTIFICATION_TYPE_CHANGED,
-                        getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
-                mAvailablePlayerViewChanged = false;
-                deviceFeatures[deviceIndex].mAvailablePlayersChangedNT =
-                        AvrcpConstants_ext.NOTIFICATION_TYPE_CHANGED;
-            }
-            if (deviceFeatures[deviceIndex].mAddrPlayerChangedNT ==
-                    AvrcpConstants_ext.NOTIFICATION_TYPE_INTERIM) {
-                registerNotificationRspAddrPlayerChangedNative(
-                        AvrcpConstants_ext.NOTIFICATION_TYPE_CHANGED, mCurrAddrPlayerID,
-                        sUIDCounter, getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
-                deviceFeatures[deviceIndex].mAddrPlayerChangedNT =
-                        AvrcpConstants_ext.NOTIFICATION_TYPE_CHANGED;
-                // send track change event becasue some carkits will refresh metadata
-                // while receive addressed player change event. Track change event to
-                // make remote get metadata correctly.
-                sendTrackChangedRsp(false, deviceFeatures[deviceIndex].mCurrentDevice);
-            }
-
-            deviceFeatures[deviceIndex].mReportedPlayerID = mCurrAddrPlayerID;
-        }
+        Log.w(TAG, "setActiveDevice call for device " + device);
+        Message msg = mHandler.obtainMessage(MSG_SET_ACTIVE_DEVICE, 0, 0, device);
+        mHandler.sendMessage(msg);
     }
 
     private SharedPreferences getVolumeMap() {
diff --git a/packages_apps_bluetooth_ext/src/avrcp/BrowsedMediaPlayer_ext.java b/packages_apps_bluetooth_ext/src/avrcp/BrowsedMediaPlayer_ext.java
index 8f1801d..f8290f5 100644
--- a/packages_apps_bluetooth_ext/src/avrcp/BrowsedMediaPlayer_ext.java
+++ b/packages_apps_bluetooth_ext/src/avrcp/BrowsedMediaPlayer_ext.java
@@ -59,6 +59,7 @@
     private Context mContext;
     private AvrcpMediaRspInterface_ext mMediaInterface;
     private byte[] mBDAddr;
+    private Avrcp_ext mAvrcp = null;
 
     private String mCurrentBrowsePackage;
     private String mCurrentBrowseClass;
@@ -281,10 +282,11 @@
 
     /* Constructor */
     BrowsedMediaPlayer_ext(byte[] address, Context context,
-            AvrcpMediaRspInterface_ext mAvrcpMediaRspInterface) {
+            AvrcpMediaRspInterface_ext mAvrcpMediaRspInterface, Avrcp_ext mAvrcp_ext) {
         mContext = context;
         mMediaInterface = mAvrcpMediaRspInterface;
         mBDAddr = address;
+        mAvrcp = mAvrcp_ext;
     }
 
     /* initialize mediacontroller in order to communicate with media player. */
@@ -852,7 +854,7 @@
         mMediaInterface.folderItemsRsp(bdaddr, AvrcpConstants_ext.RSP_NO_ERROR, rspObj);
     }
 
-    public String getAttrValue(byte []bdaddr, int attr, MediaBrowser.MediaItem item) {
+    public String getAttrValue(byte[] bdaddr, int attr, MediaBrowser.MediaItem item) {
         String attrValue = null;
         try {
             MediaDescription desc = item.getDescription();
@@ -888,8 +890,12 @@
                     break;
 
                 case AvrcpConstants_ext.ATTRID_COVER_ART:
-                    attrValue = Avrcp_ext.getImgHandleFromTitle(bdaddr,
-                            desc.getTitle().toString());
+                    if (mAvrcp != null && mAvrcp.isCoverArtFeatureSupported(bdaddr)) {
+                        attrValue = Avrcp_ext.getImgHandleFromTitle(bdaddr,
+                                desc.getTitle().toString());
+                    } else {
+                        attrValue = null;
+                    }
                     break;
 
                 default:
diff --git a/system_bt_ext/conf/interop_database.conf b/system_bt_ext/conf/interop_database.conf
index dc1f5ff..cf6348f 100644
--- a/system_bt_ext/conf/interop_database.conf
+++ b/system_bt_ext/conf/interop_database.conf
@@ -401,7 +401,7 @@
 [INTEROP_DISABLE_PLAYER_APPLICATION_SETTING_CMDS]
 00:09:93 = Address_Based
 74:6f:f7 = Address_Based
-A0:56:B2 = Address_Based
+A0:56:B2:4F = Address_Based
 00:54:AF = Address_Based
 
 [INTEROP_DISABLE_CONNECTION_AFTER_COLLISION]