Merge "A2dp: Support A2dp Source and A2dpSink profiles concurrency." into q-keystone-qcom-dev
diff --git a/src/com/android/bluetooth/a2dp/A2dpService.java b/src/com/android/bluetooth/a2dp/A2dpService.java
old mode 100644
new mode 100755
index 6b1678e..521b00c
--- a/src/com/android/bluetooth/a2dp/A2dpService.java
+++ b/src/com/android/bluetooth/a2dp/A2dpService.java
@@ -23,6 +23,7 @@
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.bluetooth.IBluetoothA2dp;
+import com.android.bluetooth.a2dpsink.A2dpSinkService;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -65,8 +66,12 @@
public class A2dpService extends ProfileService {
private static final boolean DBG = true;
private static final String TAG = "A2dpService";
+ private static final String A2DP_CONCURRENCY_SUPPORTED_PROPERTY =
+ "persist.vendor.service.bt.a2dp_concurrency";
private static A2dpService sA2dpService;
+ private static A2dpSinkService sA2dpSinkService;
+ private static boolean mA2dpSrcSnkConcurrency;
private AdapterService mAdapterService;
private HandlerThread mStateMachinesThread;
@@ -275,6 +280,11 @@
// Step 10: Clear active device
setActiveDevice(null);
+ // Step 11: Check if A2DP is in concurrency mode
+ mA2dpSrcSnkConcurrency = SystemProperties.getBoolean(A2DP_CONCURRENCY_SUPPORTED_PROPERTY, false);
+ if (DBG) {
+ Log.d(TAG, "A2DP concurrency mode set to " + mA2dpSrcSnkConcurrency);
+ }
return true;
}
@@ -440,12 +450,20 @@
Log.e(TAG, "Cannot connect to " + device + " : no state machine");
return false;
}
+ if (mA2dpSrcSnkConcurrency) {
+ sA2dpSinkService = A2dpSinkService.getA2dpSinkService();
+ List<BluetoothDevice> srcDevs = sA2dpSinkService.getConnectedDevices();
+ for ( BluetoothDevice src : srcDevs ) {
+ Log.d(TAG, "calling sink disconnect to " + src);
+ sA2dpSinkService.disconnect(src);
+ }
+ }
smConnect.sendMessage(A2dpStateMachine.CONNECT);
return true;
}
}
- boolean disconnect(BluetoothDevice device) {
+ public boolean disconnect(BluetoothDevice device) {
enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
if (DBG) {
Log.d(TAG, "disconnect(): " + device);
@@ -1406,6 +1424,16 @@
Log.e(TAG, "Cannot process stack event: no state machine: " + stackEvent);
return;
}
+ if (mA2dpSrcSnkConcurrency &&
+ (A2dpStackEvent.CONNECTION_STATE_CONNECTING == stackEvent.valueInt ||
+ A2dpStackEvent.CONNECTION_STATE_CONNECTED == stackEvent.valueInt )) {
+ sA2dpSinkService = A2dpSinkService.getA2dpSinkService();
+ List<BluetoothDevice> srcDevs = sA2dpSinkService.getConnectedDevices();
+ for ( BluetoothDevice src : srcDevs ) {
+ Log.d(TAG, "calling sink disconnect to " + src);
+ sA2dpSinkService.disconnect(src);
+ }
+ }
sm.sendMessage(A2dpStateMachine.STACK_EVENT, stackEvent);
}
}
diff --git a/src/com/android/bluetooth/a2dpsink/A2dpSinkService.java b/src/com/android/bluetooth/a2dpsink/A2dpSinkService.java
old mode 100644
new mode 100755
index b51ffea..3bac062
--- a/src/com/android/bluetooth/a2dpsink/A2dpSinkService.java
+++ b/src/com/android/bluetooth/a2dpsink/A2dpSinkService.java
@@ -26,6 +26,8 @@
import com.android.bluetooth.Utils;
import com.android.bluetooth.btservice.AdapterService;
+import com.android.bluetooth.a2dp.A2dpService;
+import com.android.bluetooth.hfp.HeadsetService;
import com.android.bluetooth.btservice.ProfileService;
import com.android.internal.annotations.VisibleForTesting;
import com.android.bluetooth.avrcpcontroller.AvrcpControllerService;
@@ -54,6 +56,9 @@
private static final Object mBtA2dpLock = new Object();
private static A2dpSinkStreamHandler mA2dpSinkStreamHandler;
private static A2dpSinkService sService;
+ private static A2dpService sA2dpService;
+ private static HeadsetService sHeadsetService;
+ private static boolean mA2dpSrcSnkConcurrency;
protected static BluetoothDevice mStreamingDevice;
private static int mMaxA2dpSinkConnections = 1;
@@ -70,6 +75,11 @@
mMaxA2dpSinkConnections = Math.min(
SystemProperties.getInt("persist.vendor.bt.a2dp.sink_conn", 1),
MAX_ALLOWED_SINK_CONNECTIONS);
+ mA2dpSrcSnkConcurrency= SystemProperties.getBoolean(
+ "persist.vendor.service.bt.a2dp_concurrency", false);
+ if (DBG) {
+ Log.d(TAG, "A2DP concurrency set to " + mA2dpSrcSnkConcurrency);
+ }
return true;
}
@@ -250,6 +260,22 @@
}
A2dpSinkStateMachine stateMachine = getOrCreateStateMachine(device);
if (stateMachine != null) {
+ if (mA2dpSrcSnkConcurrency) {
+ //in A2dp Concurrency mode, it need to disconnect all sink devices and headset clients
+ //before connecting to A2dp Source device.
+ sA2dpService = A2dpService.getA2dpService();
+ List<BluetoothDevice> snkDevs = sA2dpService.getConnectedDevices();
+ for( BluetoothDevice snk : snkDevs ) {
+ Log.d(TAG, "calling src disconnect to " + snk);
+ sA2dpService.disconnect(snk);
+ }
+ sHeadsetService = HeadsetService.getHeadsetService();
+ List<BluetoothDevice> hsDevs = sHeadsetService.getConnectedDevices();
+ for ( BluetoothDevice hs : hsDevs ) {
+ Log.d(TAG, "calling headset disconnect to " + hs);
+ sHeadsetService.disconnect(hs);
+ }
+ }
stateMachine.connect();
return true;
} else {
@@ -532,14 +558,20 @@
mStreamingDevice = null;
}
- // Intiate Handoff operations when state has been connectiond
- if (state == BluetoothProfile.STATE_CONNECTED) {
- if (mStreamingDevice != null && !mStreamingDevice.equals(device)) {
- Log.d(TAG, "current connected device: " + device + "is different from previous device");
- initiateHandoffOperations(device);
- mStreamingDevice = device;
- } else if (device != null) {
- mStreamingDevice = device;
+ if (mA2dpSrcSnkConcurrency &&
+ (state == BluetoothProfile.STATE_CONNECTING ||
+ state == BluetoothProfile.STATE_CONNECTED)) {
+ sA2dpService = A2dpService.getA2dpService();
+ List<BluetoothDevice> snkDevs = sA2dpService.getConnectedDevices();
+ for ( BluetoothDevice snk : snkDevs ) {
+ Log.d(TAG, "calling src disconnect to " + snk);
+ sA2dpService.disconnect(snk);
+ }
+ sHeadsetService = HeadsetService.getHeadsetService();
+ List<BluetoothDevice> hsDevs = sHeadsetService.getConnectedDevices();
+ for ( BluetoothDevice hs : hsDevs ) {
+ Log.d(TAG, "calling headset disconnect to " + hs);
+ sHeadsetService.disconnect(hs);
}
}
stateMachine.sendMessage(A2dpSinkStateMachine.STACK_EVENT, event);
diff --git a/src/com/android/bluetooth/btservice/Config.java b/src/com/android/bluetooth/btservice/Config.java
old mode 100644
new mode 100755
index 0e170b1..c906317
--- a/src/com/android/bluetooth/btservice/Config.java
+++ b/src/com/android/bluetooth/btservice/Config.java
@@ -171,14 +171,24 @@
private static synchronized boolean addAudioProfiles(String serviceName) {
Log.d(TAG," addAudioProfiles profile" + serviceName);
- boolean isA2dpSink = SystemProperties.getBoolean(
- "persist.vendor.service.bt.a2dp.sink", false);
- Log.i(TAG, "addAudioProfiles isA2dpSink :" + isA2dpSink);
- /* If property not enabled and request is for A2DPSinkService, don't add */
- if ((serviceName.equals("A2dpSinkService")) && (!isA2dpSink))
- return false;
- if ((serviceName.equals("A2dpService")) && (isA2dpSink))
- return false;
+ boolean isA2dpConcurrency= SystemProperties.getBoolean(
+ "persist.vendor.service.bt.a2dp_concurrency", false);
+ Log.i(TAG, "addAudioProfiles isA2dpConcurrency:" + isA2dpConcurrency);
+
+ if(isA2dpConcurrency) {
+ if ((serviceName.equals("A2dpSinkService")) || (serviceName.equals("A2dpService"))) {
+ return true;
+ }
+ } else {
+ boolean isA2dpSink = SystemProperties.getBoolean(
+ "persist.vendor.service.bt.a2dp.sink", false);
+ Log.i(TAG, "addAudioProfiles isA2dpSink :" + isA2dpSink);
+ /* If property not enabled and request is for A2DPSinkService, don't add */
+ if ((serviceName.equals("A2dpSinkService")) && (!isA2dpSink))
+ return false;
+ if ((serviceName.equals("A2dpService")) && (isA2dpSink))
+ return false;
+ }
boolean isBAEnabled = SystemProperties.getBoolean("persist.vendor.service.bt.bca", false);
diff --git a/src/com/android/bluetooth/hfp/HeadsetService.java b/src/com/android/bluetooth/hfp/HeadsetService.java
old mode 100644
new mode 100755
index d9cadd9..8fefdba
--- a/src/com/android/bluetooth/hfp/HeadsetService.java
+++ b/src/com/android/bluetooth/hfp/HeadsetService.java
@@ -1049,7 +1049,7 @@
return true;
}
- boolean disconnect(BluetoothDevice device) {
+ public boolean disconnect(BluetoothDevice device) {
enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
Log.i(TAG, "disconnect: device=" + device + ", " + Utils.getUidPidString());
synchronized (mStateMachines) {