Add support for Multi-A2DP state machines per device

* Update usage of A2dpService API calls that take BluetoothDevice
  as an additional argument
* Update the description for BluetoothA2dp.connect()

Exempt-From-Owner-Approval: De-facto owner of the relevant changes is
the Bluetooth team.
Bug: 69269748
Test: Manual
Change-Id: I190ed48ef65bbc8b88b45f84ebd6ab3d21cf0b4e
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 35a21a4..b255a43 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -300,11 +300,7 @@
     }
 
     /**
-     * Initiate connection to a profile of the remote bluetooth device.
-     *
-     * <p> Currently, the system supports only 1 connection to the
-     * A2DP profile. The API will automatically disconnect connected
-     * devices before connecting.
+     * Initiate connection to a profile of the remote Bluetooth device.
      *
      * <p> This API returns false in scenarios like the profile on the
      * device is already connected or Bluetooth is not turned on.
@@ -699,15 +695,17 @@
     /**
      * Gets the current codec status (configuration and capability).
      *
+     * @param device the remote Bluetooth device. If null, use the current
+     * active A2DP Bluetooth device.
      * @return the current codec status
      * @hide
      */
-    public BluetoothCodecStatus getCodecStatus() {
-        if (DBG) Log.d(TAG, "getCodecStatus");
+    public BluetoothCodecStatus getCodecStatus(BluetoothDevice device) {
+        if (DBG) Log.d(TAG, "getCodecStatus(" + device + ")");
         try {
             mServiceLock.readLock().lock();
             if (mService != null && isEnabled()) {
-                return mService.getCodecStatus();
+                return mService.getCodecStatus(device);
             }
             if (mService == null) {
                 Log.w(TAG, "Proxy not attached to service");
@@ -724,15 +722,18 @@
     /**
      * Sets the codec configuration preference.
      *
+     * @param device the remote Bluetooth device. If null, use the current
+     * active A2DP Bluetooth device.
      * @param codecConfig the codec configuration preference
      * @hide
      */
-    public void setCodecConfigPreference(BluetoothCodecConfig codecConfig) {
-        if (DBG) Log.d(TAG, "setCodecConfigPreference");
+    public void setCodecConfigPreference(BluetoothDevice device,
+                                         BluetoothCodecConfig codecConfig) {
+        if (DBG) Log.d(TAG, "setCodecConfigPreference(" + device + ")");
         try {
             mServiceLock.readLock().lock();
             if (mService != null && isEnabled()) {
-                mService.setCodecConfigPreference(codecConfig);
+                mService.setCodecConfigPreference(device, codecConfig);
             }
             if (mService == null) Log.w(TAG, "Proxy not attached to service");
             return;
@@ -747,36 +748,42 @@
     /**
      * Enables the optional codecs.
      *
+     * @param device the remote Bluetooth device. If null, use the currect
+     * active A2DP Bluetooth device.
      * @hide
      */
-    public void enableOptionalCodecs() {
-        if (DBG) Log.d(TAG, "enableOptionalCodecs");
-        enableDisableOptionalCodecs(true);
+    public void enableOptionalCodecs(BluetoothDevice device) {
+        if (DBG) Log.d(TAG, "enableOptionalCodecs(" + device + ")");
+        enableDisableOptionalCodecs(device, true);
     }
 
     /**
      * Disables the optional codecs.
      *
+     * @param device the remote Bluetooth device. If null, use the currect
+     * active A2DP Bluetooth device.
      * @hide
      */
-    public void disableOptionalCodecs() {
-        if (DBG) Log.d(TAG, "disableOptionalCodecs");
-        enableDisableOptionalCodecs(false);
+    public void disableOptionalCodecs(BluetoothDevice device) {
+        if (DBG) Log.d(TAG, "disableOptionalCodecs(" + device + ")");
+        enableDisableOptionalCodecs(device, false);
     }
 
     /**
      * Enables or disables the optional codecs.
      *
+     * @param device the remote Bluetooth device. If null, use the currect
+     * active A2DP Bluetooth device.
      * @param enable if true, enable the optional codecs, other disable them
      */
-    private void enableDisableOptionalCodecs(boolean enable) {
+    private void enableDisableOptionalCodecs(BluetoothDevice device, boolean enable) {
         try {
             mServiceLock.readLock().lock();
             if (mService != null && isEnabled()) {
                 if (enable) {
-                    mService.enableOptionalCodecs();
+                    mService.enableOptionalCodecs(device);
                 } else {
-                    mService.disableOptionalCodecs();
+                    mService.disableOptionalCodecs(device);
                 }
             }
             if (mService == null) Log.w(TAG, "Proxy not attached to service");
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index 9b69304..6b99024 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -219,8 +219,8 @@
             return true;
         }
         BluetoothCodecConfig codecConfig = null;
-        if (mServiceWrapper.getCodecStatus() != null) {
-            codecConfig = mServiceWrapper.getCodecStatus().getCodecConfig();
+        if (mServiceWrapper.getCodecStatus(device) != null) {
+            codecConfig = mServiceWrapper.getCodecStatus(device).getCodecConfig();
         }
         if (codecConfig != null)  {
             return !codecConfig.isMandatoryCodec();
@@ -238,9 +238,9 @@
             return;
         }
         if (enabled) {
-            mService.enableOptionalCodecs();
+            mService.enableOptionalCodecs(device);
         } else {
-            mService.disableOptionalCodecs();
+            mService.disableOptionalCodecs(device);
         }
     }
 
@@ -253,8 +253,8 @@
         // We want to get the highest priority codec, since that's the one that will be used with
         // this device, and see if it is high-quality (ie non-mandatory).
         BluetoothCodecConfig[] selectable = null;
-        if (mServiceWrapper.getCodecStatus() != null) {
-            selectable = mServiceWrapper.getCodecStatus().getCodecsSelectableCapabilities();
+        if (mServiceWrapper.getCodecStatus(device) != null) {
+            selectable = mServiceWrapper.getCodecStatus(device).getCodecsSelectableCapabilities();
             // To get the highest priority, we sort in reverse.
             Arrays.sort(selectable,
                     (a, b) -> {
diff --git a/packages/SettingsLib/src/com/android/settingslib/wrapper/BluetoothA2dpWrapper.java b/packages/SettingsLib/src/com/android/settingslib/wrapper/BluetoothA2dpWrapper.java
index 4c52a9f..17e3401 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wrapper/BluetoothA2dpWrapper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wrapper/BluetoothA2dpWrapper.java
@@ -43,8 +43,8 @@
     /**
      * Wraps {@code BluetoothA2dp.getCodecStatus}
      */
-    public BluetoothCodecStatus getCodecStatus() {
-        return mService.getCodecStatus();
+    public BluetoothCodecStatus getCodecStatus(BluetoothDevice device) {
+        return mService.getCodecStatus(device);
     }
 
     /**
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
index ece0d51..590bc90 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
@@ -123,7 +123,7 @@
         when(mBluetoothA2dp.getConnectionState(any())).thenReturn(
                 BluetoothProfile.STATE_CONNECTED);
         BluetoothCodecStatus status = mock(BluetoothCodecStatus.class);
-        when(mBluetoothA2dpWrapper.getCodecStatus()).thenReturn(status);
+        when(mBluetoothA2dpWrapper.getCodecStatus(mDevice)).thenReturn(status);
         BluetoothCodecConfig config = mock(BluetoothCodecConfig.class);
         when(status.getCodecConfig()).thenReturn(config);
         when(config.isMandatoryCodec()).thenReturn(false);
@@ -186,7 +186,7 @@
         BluetoothCodecStatus status = mock(BluetoothCodecStatus.class);
         BluetoothCodecConfig config = mock(BluetoothCodecConfig.class);
         BluetoothCodecConfig[] configs = {config};
-        when(mBluetoothA2dpWrapper.getCodecStatus()).thenReturn(status);
+        when(mBluetoothA2dpWrapper.getCodecStatus(mDevice)).thenReturn(status);
         when(status.getCodecsSelectableCapabilities()).thenReturn(configs);
 
         when(config.isMandatoryCodec()).thenReturn(true);
@@ -201,7 +201,7 @@
         BluetoothCodecStatus status = mock(BluetoothCodecStatus.class);
         BluetoothCodecConfig config = mock(BluetoothCodecConfig.class);
         BluetoothCodecConfig[] configs = {config};
-        when(mBluetoothA2dpWrapper.getCodecStatus()).thenReturn(status);
+        when(mBluetoothA2dpWrapper.getCodecStatus(mDevice)).thenReturn(status);
         when(status.getCodecsSelectableCapabilities()).thenReturn(configs);
 
         when(config.isMandatoryCodec()).thenReturn(false);