Merge "Opp: close the transport if opp tx is blocked when bt turning off" into q-keystone-qcom-dev
diff --git a/src/com/android/bluetooth/a2dp/A2dpService.java b/src/com/android/bluetooth/a2dp/A2dpService.java
index 9866312..63d4181 100644
--- a/src/com/android/bluetooth/a2dp/A2dpService.java
+++ b/src/com/android/bluetooth/a2dp/A2dpService.java
@@ -56,6 +56,7 @@
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* Provides Bluetooth A2DP profile, as a service in the Bluetooth application.
@@ -75,6 +76,8 @@
private final Object mBtTwsLock = new Object();
private final Object mBtAvrcpLock = new Object();
private final Object mActiveDeviceLock = new Object();
+ private final Object mVariableLock = new Object();
+ private final ReentrantReadWriteLock mA2dpNativeInterfaceLock = new ReentrantReadWriteLock();
@VisibleForTesting
A2dpNativeInterface mA2dpNativeInterface;
@@ -129,12 +132,18 @@
switch (msg.what) {
case SET_EBMONO_CFG:
Log.d(TAG, "setparameters to Mono");
- mAudioManager.setParameters("TwsChannelConfig=mono");
+ synchronized (mVariableLock) {
+ if(mAudioManager != null)
+ mAudioManager.setParameters("TwsChannelConfig=mono");
+ }
mTwsPlusChannelMode = "mono";
break;
case SET_EBDUALMONO_CFG:
Log.d(TAG, "setparameters to Dual-Mono");
- mAudioManager.setParameters("TwsChannelConfig=dual-mono");
+ synchronized (mVariableLock) {
+ if(mAudioManager != null)
+ mAudioManager.setParameters("TwsChannelConfig=dual-mono");
+ }
mTwsPlusChannelMode = "dual-mono";
break;
default:
@@ -164,73 +173,92 @@
// Step 1: Get AdapterService, A2dpNativeInterface, AudioManager.
// None of them can be null.
- mAdapterService = Objects.requireNonNull(AdapterService.getAdapterService(),
+ synchronized (mVariableLock) {
+ mAdapterService = Objects.requireNonNull(AdapterService.getAdapterService(),
"AdapterService cannot be null when A2dpService starts");
- mA2dpNativeInterface = Objects.requireNonNull(A2dpNativeInterface.getInstance(),
+ }
+ try {
+ mA2dpNativeInterfaceLock.writeLock().lock();
+ mA2dpNativeInterface = Objects.requireNonNull(A2dpNativeInterface.getInstance(),
"A2dpNativeInterface cannot be null when A2dpService starts");
- mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
- Objects.requireNonNull(mAudioManager,
+ } finally {
+ mA2dpNativeInterfaceLock.writeLock().unlock();
+ }
+ BluetoothCodecConfig[] OffloadCodecConfig;
+ synchronized (mVariableLock) {
+ mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+ Objects.requireNonNull(mAudioManager,
"AudioManager cannot be null when A2dpService starts");
- // Step 2: Get maximum number of connected audio devices
- mMaxConnectedAudioDevices = mAdapterService.getMaxConnectedAudioDevices();
- mSetMaxConnectedAudioDevices = mMaxConnectedAudioDevices;
- Log.i(TAG, "Max connected audio devices set to " + mMaxConnectedAudioDevices);
- if (mAdapterService.isVendorIntfEnabled()) {
- String twsPlusEnabled = SystemProperties.get("persist.vendor.btstack.enable.twsplus");
- if (!twsPlusEnabled.isEmpty() && "true".equals(twsPlusEnabled)) {
- mIsTwsPlusEnabled = true;
- }
- Log.i(TAG, "mMaxConnectedAudioDevices: " + mMaxConnectedAudioDevices);
- String twsShoEnabled = SystemProperties.get("persist.vendor.btstack.enable.twsplussho");
- if (!twsShoEnabled.isEmpty() && "true".equals(twsShoEnabled) &&
- (mIsTwsPlusEnabled == true) && mMaxConnectedAudioDevices <= 2) {
- mMaxConnectedAudioDevices = 3;
- Log.i(TAG, "TWS+ SHO enabled mMaxConnectedAudioDevices changed to: " + mMaxConnectedAudioDevices);
- } else if (mIsTwsPlusEnabled && mMaxConnectedAudioDevices < 2) {
- mMaxConnectedAudioDevices = 2;
- Log.i(TAG, "TWS+ enabled mMaxConnectedAudioDevices changed to: " + mMaxConnectedAudioDevices);
- }
+ // Step 2: Get maximum number of connected audio devices
+ mMaxConnectedAudioDevices = mAdapterService.getMaxConnectedAudioDevices();
mSetMaxConnectedAudioDevices = mMaxConnectedAudioDevices;
- String twsPlusMonoEnabled = SystemProperties.get("persist.vendor.btstack.twsplus.monosupport");
- if (!twsPlusMonoEnabled.isEmpty() && "true".equals(twsPlusMonoEnabled)) {
- mIsTwsPlusMonoSupported = true;
+ Log.i(TAG, "Max connected audio devices set to " + mMaxConnectedAudioDevices);
+ if (mAdapterService != null && mAdapterService.isVendorIntfEnabled()) {
+ String twsPlusEnabled = SystemProperties.get("persist.vendor.btstack.enable.twsplus");
+ if (!twsPlusEnabled.isEmpty() && "true".equals(twsPlusEnabled)) {
+ mIsTwsPlusEnabled = true;
+ }
+ Log.i(TAG, "mMaxConnectedAudioDevices: " + mMaxConnectedAudioDevices);
+ String twsShoEnabled = SystemProperties.get("persist.vendor.btstack.enable.twsplussho");
+ if (!twsShoEnabled.isEmpty() && "true".equals(twsShoEnabled) &&
+ (mIsTwsPlusEnabled == true) && mMaxConnectedAudioDevices <= 2) {
+ mMaxConnectedAudioDevices = 3;
+ Log.i(TAG, "TWS+ SHO enabled mMaxConnectedAudioDevices changed to: " + mMaxConnectedAudioDevices);
+ } else if (mIsTwsPlusEnabled && mMaxConnectedAudioDevices < 2) {
+ mMaxConnectedAudioDevices = 2;
+ Log.i(TAG, "TWS+ enabled mMaxConnectedAudioDevices changed to: " + mMaxConnectedAudioDevices);
+ }
+ mSetMaxConnectedAudioDevices = mMaxConnectedAudioDevices;
+ String twsPlusMonoEnabled = SystemProperties.get("persist.vendor.btstack.twsplus.monosupport");
+ if (!twsPlusMonoEnabled.isEmpty() && "true".equals(twsPlusMonoEnabled)) {
+ mIsTwsPlusMonoSupported = true;
+ }
+ String TwsPlusChannelMode = SystemProperties.get("persist.vendor.btstack.twsplus.defaultchannelmode");
+ if (!TwsPlusChannelMode.isEmpty() && "mono".equals(TwsPlusChannelMode)) {
+ mTwsPlusChannelMode = "mono";
+ }
+ Log.d(TAG, "Default TwsPlus ChannelMode: " + mTwsPlusChannelMode);
}
- String TwsPlusChannelMode = SystemProperties.get("persist.vendor.btstack.twsplus.defaultchannelmode");
- if (!TwsPlusChannelMode.isEmpty() && "mono".equals(TwsPlusChannelMode)) {
- mTwsPlusChannelMode = "mono";
- }
- Log.d(TAG, "Default TwsPlus ChannelMode: " + mTwsPlusChannelMode);
+
+ // Step 3: Setup AVRCP
+ if(mAdapterService != null && mAdapterService.isVendorIntfEnabled())
+ mAvrcp_ext = Avrcp_ext.make(this, this, mMaxConnectedAudioDevices);
+ else
+ mAvrcp = Avrcp.make(this);
+
+ // Step 4: Start handler thread for state machines
+ mStateMachines.clear();
+ mStateMachinesThread = new HandlerThread("A2dpService.StateMachines");
+ mStateMachinesThread.start();
+
+ // Step 5: Setup codec config
+ mA2dpCodecConfig = new A2dpCodecConfig(this, mA2dpNativeInterface);
+
+ // Step 6: Initialize native interface
+ List<BluetoothCodecConfig> mCodecConfigOffload;
+ mCodecConfigOffload = mAudioManager.getHwOffloadEncodingFormatsSupportedForA2DP();
+ OffloadCodecConfig = new BluetoothCodecConfig[mCodecConfigOffload.size()];
+ OffloadCodecConfig = mCodecConfigOffload.toArray(OffloadCodecConfig);
}
- // Step 3: Setup AVRCP
- if(mAdapterService.isVendorIntfEnabled())
- mAvrcp_ext = Avrcp_ext.make(this, this, mMaxConnectedAudioDevices);
- else
- mAvrcp = Avrcp.make(this);
-
- // Step 4: Start handler thread for state machines
- mStateMachines.clear();
- mStateMachinesThread = new HandlerThread("A2dpService.StateMachines");
- mStateMachinesThread.start();
-
- // Step 5: Setup codec config
- mA2dpCodecConfig = new A2dpCodecConfig(this, mA2dpNativeInterface);
-
- // Step 6: Initialize native interface
- List<BluetoothCodecConfig> mCodecConfigOffload;
- mCodecConfigOffload = mAudioManager.getHwOffloadEncodingFormatsSupportedForA2DP();
- BluetoothCodecConfig[] OffloadCodecConfig = new BluetoothCodecConfig[mCodecConfigOffload.size()];
- OffloadCodecConfig = mCodecConfigOffload.toArray(OffloadCodecConfig);
- mA2dpNativeInterface.init(mMaxConnectedAudioDevices,
- mA2dpCodecConfig.codecConfigPriorities(),OffloadCodecConfig);
-
- // Step 7: Check if A2DP is in offload mode
- mA2dpOffloadEnabled = mAdapterService.isA2dpOffloadEnabled();
- if (DBG) {
- Log.d(TAG, "A2DP offload flag set to " + mA2dpOffloadEnabled);
+ try {
+ mA2dpNativeInterfaceLock.writeLock().lock();
+ if (mA2dpNativeInterface != null)
+ mA2dpNativeInterface.init(mMaxConnectedAudioDevices,
+ mA2dpCodecConfig.codecConfigPriorities(),OffloadCodecConfig);
+ } finally {
+ mA2dpNativeInterfaceLock.writeLock().unlock();
}
+ synchronized (mVariableLock) {
+
+ // Step 7: Check if A2DP is in offload mode
+ mA2dpOffloadEnabled = mAdapterService.isA2dpOffloadEnabled();
+ if (DBG) {
+ Log.d(TAG, "A2DP offload flag set to " + mA2dpOffloadEnabled);
+ }
+ }
// Step 8: Setup broadcast receivers
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
@@ -260,7 +288,6 @@
// Step 9: Clear active device and stop playing audio
removeActiveDevice(true);
-
// Step 8: Mark service as stopped
setA2dpService(null);
@@ -269,10 +296,14 @@
mConnectionStateChangedReceiver = null;
unregisterReceiver(mBondStateChangedReceiver);
mBondStateChangedReceiver = null;
-
// Step 6: Cleanup native interface
- mA2dpNativeInterface.cleanup();
- mA2dpNativeInterface = null;
+ try {
+ mA2dpNativeInterfaceLock.writeLock().lock();
+ if (mA2dpNativeInterface != null)
+ mA2dpNativeInterface.cleanup();
+ } finally {
+ mA2dpNativeInterfaceLock.writeLock().unlock();
+ }
// Step 5: Clear codec config
mA2dpCodecConfig = null;
@@ -303,21 +334,28 @@
}
// Step 2: Reset maximum number of connected audio devices
- if (mAdapterService.isVendorIntfEnabled()) {
- if (mIsTwsPlusEnabled) {
- mMaxConnectedAudioDevices = 2;
+ synchronized (mVariableLock) {
+ if (mAdapterService != null && mAdapterService.isVendorIntfEnabled()) {
+ if (mIsTwsPlusEnabled) {
+ mMaxConnectedAudioDevices = 2;
+ } else {
+ mMaxConnectedAudioDevices = 1;
+ }
} else {
- mMaxConnectedAudioDevices = 1;
- }
- } else {
- mMaxConnectedAudioDevices = 1;
+ mMaxConnectedAudioDevices = 1;
+ }
+ mSetMaxConnectedAudioDevices = 1;
+ // Step 1: Clear AdapterService, A2dpNativeInterface, AudioManager
+ mAudioManager = null;
+ mAdapterService = null;
}
- mSetMaxConnectedAudioDevices = 1;
- // Step 1: Clear AdapterService, A2dpNativeInterface, AudioManager
- mAudioManager = null;
- mA2dpNativeInterface = null;
- mAdapterService = null;
+ try {
+ mA2dpNativeInterfaceLock.writeLock().lock();
+ mA2dpNativeInterface = null;
+ } finally {
+ mA2dpNativeInterfaceLock.writeLock().unlock();
+ }
return true;
}
@@ -356,10 +394,14 @@
Log.e(TAG, "Cannot connect to " + device + " : PRIORITY_OFF");
return false;
}
- if (!BluetoothUuid.isUuidPresent(mAdapterService.getRemoteUuids(device),
- BluetoothUuid.AudioSink)) {
- Log.e(TAG, "Cannot connect to " + device + " : Remote does not have A2DP Sink UUID");
- return false;
+ synchronized (mVariableLock) {
+ if (mAdapterService == null)
+ return false;
+ if (!BluetoothUuid.isUuidPresent(mAdapterService.getRemoteUuids(device),
+ BluetoothUuid.AudioSink)) {
+ Log.e(TAG, "Cannot connect to " + device + " : Remote does not have A2DP Sink UUID");
+ return false;
+ }
}
synchronized (mBtA2dpLock) {
@@ -503,15 +545,17 @@
int tws_device = 0;
// Count devices that are in the process of connecting or already connected
synchronized (mBtA2dpLock) {
- for (A2dpStateMachine sm : mStateMachines.values()) {
+ for (A2dpStateMachine sm : mStateMachines.values()) {
switch (sm.getConnectionState()) {
case BluetoothProfile.STATE_CONNECTING:
case BluetoothProfile.STATE_CONNECTED:
if (Objects.equals(device, sm.getDevice())) {
return true; // Already connected or accounted for
}
- if (mAdapterService.isTwsPlusDevice(sm.getDevice()))
- tws_device++;
+ synchronized (mVariableLock) {
+ if (mAdapterService != null && mAdapterService.isTwsPlusDevice(sm.getDevice()))
+ tws_device++;
+ }
connected++;
break;
default:
@@ -521,11 +565,13 @@
}
Log.d(TAG,"connectionAllowedCheckMaxDevices connected = " + connected +
"tws connected = " + tws_device);
- if (mAdapterService.isVendorIntfEnabled() &&
- ((tws_device > 0) || mAdapterService.isTwsPlusDevice(device) ||
- ((tws_device > 0) && connected == mMaxConnectedAudioDevices &&
- !mAdapterService.isTwsPlusDevice(device)))) {
- return isConnectionAllowed(device, tws_device, connected);
+ synchronized (mVariableLock) {
+ if (mAdapterService != null && mAdapterService.isVendorIntfEnabled() &&
+ ((tws_device > 0) || mAdapterService.isTwsPlusDevice(device) ||
+ ((tws_device > 0) && connected == mMaxConnectedAudioDevices &&
+ !mAdapterService.isTwsPlusDevice(device)))) {
+ return isConnectionAllowed(device, tws_device, connected);
+ }
}
if (mSetMaxConnectedAudioDevices == 1 &&
connected == mSetMaxConnectedAudioDevices) {
@@ -548,9 +594,13 @@
public boolean okToConnect(BluetoothDevice device, boolean isOutgoingRequest) {
Log.i(TAG, "okToConnect: device " + device + " isOutgoingRequest: " + isOutgoingRequest);
// Check if this is an incoming connection in Quiet mode.
- if (mAdapterService.isQuietModeEnabled() && !isOutgoingRequest) {
- Log.e(TAG, "okToConnect: cannot connect to " + device + " : quiet mode enabled");
- return false;
+ synchronized (mVariableLock) {
+ if (mAdapterService == null)
+ return false;
+ if (mAdapterService.isQuietModeEnabled() && !isOutgoingRequest) {
+ Log.e(TAG, "okToConnect: cannot connect to " + device + " : quiet mode enabled");
+ return false;
+ }
}
// Check if too many devices
if (!connectionAllowedCheckMaxDevices(device)) {
@@ -562,7 +612,11 @@
// Check priority and accept or reject the connection.
// Note: Logic can be simplified, but keeping it this way for readability
int priority = getPriority(device);
- int bondState = mAdapterService.getBondState(device);
+ int bondState = BluetoothDevice.BOND_NONE;
+ synchronized (mVariableLock) {
+ if (mAdapterService != null)
+ bondState = mAdapterService.getBondState(device);
+ }
// If priority is undefined, it is likely that service discovery has not completed and peer
// initiated the connection. Allow this connection only if the device is bonded or bonding
boolean serviceDiscoveryPending = (priority == BluetoothProfile.PRIORITY_UNDEFINED)
@@ -589,15 +643,21 @@
if (states == null) {
return devices;
}
- final BluetoothDevice[] bondedDevices = mAdapterService.getBondedDevices();
+ BluetoothDevice [] bondedDevices = null;
+ synchronized (mVariableLock) {
+ if (mAdapterService != null)
+ bondedDevices = mAdapterService.getBondedDevices();
+ }
if (bondedDevices == null) {
return devices;
}
synchronized (mStateMachines) {
for (BluetoothDevice device : bondedDevices) {
- if (!BluetoothUuid.isUuidPresent(mAdapterService.getRemoteUuids(device),
+ synchronized (mVariableLock) {
+ if (mAdapterService != null && !BluetoothUuid.isUuidPresent(mAdapterService.getRemoteUuids(device),
BluetoothUuid.AudioSink)) {
- continue;
+ continue;
+ }
}
int connectionState = BluetoothProfile.STATE_DISCONNECTED;
A2dpStateMachine sm = mStateMachines.get(device);
@@ -681,16 +741,23 @@
isBAActive = (mBatService != null) && (mBatService.isBATActive());
Log.d(TAG," removeActiveDevice: BA active " + isBAActive);
// If BA streaming is ongoing, we don't want to pause music player
- if(!isBAActive) {
- mAudioManager.handleBluetoothA2dpActiveDeviceChange(
- previousActiveDevice, BluetoothProfile.STATE_DISCONNECTED,
- BluetoothProfile.A2DP, suppressNoisyIntent, -1);
- }
+ synchronized (mVariableLock ) {
+ if(!isBAActive && mAudioManager != null) {
+ mAudioManager.handleBluetoothA2dpActiveDeviceChange(
+ previousActiveDevice, BluetoothProfile.STATE_DISCONNECTED,
+ BluetoothProfile.A2DP, suppressNoisyIntent, -1);
+ }
+ }
}
// Make sure the Active device in native layer is set to null and audio is off
- if (!mA2dpNativeInterface.setActiveDevice(null)) {
- Log.w(TAG, "setActiveDevice(null): Cannot remove active device in native "
- + "layer");
+ try {
+ mA2dpNativeInterfaceLock.readLock().lock();
+ if (mA2dpNativeInterface != null && !mA2dpNativeInterface.setActiveDevice(null)) {
+ Log.w(TAG, "setActiveDevice(null): Cannot remove active device in native "
+ + "layer");
+ }
+ } finally {
+ mA2dpNativeInterfaceLock.readLock().unlock();
}
}
@@ -712,10 +779,18 @@
// Set the device as the active device if currently no active device.
setActiveDevice(device);
}
- if (!mA2dpNativeInterface.setSilenceDevice(device, silence)) {
- Log.e(TAG, "Cannot set " + device + " silence mode " + silence + " in native layer");
- return false;
+
+ try {
+ mA2dpNativeInterfaceLock.readLock().lock();
+ if (mA2dpNativeInterface != null &&
+ !mA2dpNativeInterface.setSilenceDevice(device, silence)) {
+ Log.e(TAG, "Cannot set " + device + " silence mode " + silence + " in native layer");
+ return false;
+ }
+ } finally {
+ mA2dpNativeInterfaceLock.readLock().unlock();
}
+
return true;
}
@@ -765,19 +840,21 @@
boolean tws_switch = false;
Log.w(TAG, "setActiveDevice(" + device + "): previous is " + previousActiveDevice);
+ if (device == null) {
+ // Remove active device and continue playing audio only if necessary.
+ removeActiveDevice(false);
+ synchronized(mBtAvrcpLock) {
+ if(mAvrcp_ext != null)
+ mAvrcp_ext.setActiveDevice(device);
+ }
+ return true;
+ }
+
synchronized (mBtA2dpLock) {
BATService mBatService = BATService.getBATService();
isBAActive = (mBatService != null) && (mBatService.isBATActive());
Log.d(TAG," setActiveDevice: BA active " + isBAActive);
- if (device == null) {
- // Remove active device and continue playing audio only if necessary.
- removeActiveDevice(false);
- if(mAvrcp_ext != null)
- mAvrcp_ext.setActiveDevice(device);
- return true;
- }
-
A2dpStateMachine sm = mStateMachines.get(device);
deviceChanged = !Objects.equals(device, mActiveDevice);
if (!deviceChanged) {
@@ -794,12 +871,15 @@
+ "device is not connected");
return false;
}
- if (mActiveDevice != null && mAdapterService.isTwsPlusDevice(device) &&
- mAdapterService.isTwsPlusDevice(mActiveDevice) &&
- !Objects.equals(device, mActiveDevice) &&
- getConnectionState(mActiveDevice) == BluetoothProfile.STATE_CONNECTED) {
- Log.d(TAG,"Ignore setActiveDevice request");
- return false;
+ synchronized (mVariableLock) {
+ if (mActiveDevice != null && mAdapterService != null &&
+ mAdapterService.isTwsPlusDevice(device) &&
+ mAdapterService.isTwsPlusDevice(mActiveDevice) &&
+ !Objects.equals(device, mActiveDevice) &&
+ getConnectionState(mActiveDevice) == BluetoothProfile.STATE_CONNECTED) {
+ Log.d(TAG,"Ignore setActiveDevice request");
+ return false;
+ }
}
codecStatus = sm.getCodecStatus();
@@ -816,47 +896,48 @@
Log.w(TAG, "setActiveDevice coming out of mutex lock");
}
- if (!mA2dpNativeInterface.setActiveDevice(device)) {
- Log.e(TAG, "setActiveDevice(" + device + "): Cannot set as active in native layer");
- return false;
+ try {
+ mA2dpNativeInterfaceLock.readLock().lock();
+ if (mA2dpNativeInterface != null && !mA2dpNativeInterface.setActiveDevice(device)) {
+ Log.e(TAG, "setActiveDevice(" + device + "): Cannot set as active in native layer");
+ return false;
+ }
+
+ } finally {
+ mA2dpNativeInterfaceLock.readLock().unlock();
}
+
+
updateAndBroadcastActiveDevice(device);
Log.d(TAG, "setActiveDevice(" + device + "): completed");
if (deviceChanged) {
if(mAvrcp_ext != null)
mAvrcp_ext.setActiveDevice(device);
- if (mAdapterService.isTwsPlusDevice(device) &&
- (previousActiveDevice != null && mAdapterService.isTwsPlusDevice(previousActiveDevice))) {
- Log.d(TAG,"TWS+ active device disconnected, setting other pair as active");
- tws_switch = true;
+ synchronized (mVariableLock) {
+ if (mAdapterService != null && mAdapterService.isTwsPlusDevice(device) &&
+ (previousActiveDevice != null && mAdapterService.isTwsPlusDevice(previousActiveDevice))) {
+ Log.d(TAG,"TWS+ active device disconnected, setting other pair as active");
+ tws_switch = true;
+ }
}
// Send an intent with the active device codec config
if (codecStatus != null) {
broadcastCodecConfig(mActiveDevice, codecStatus);
}
int rememberedVolume = -1;
- if (mFactory.getAvrcpTargetService() != null) {
- rememberedVolume = mFactory.getAvrcpTargetService()
- .getRememberedVolumeForDevice(mActiveDevice);
- } else if (mAdapterService.isVendorIntfEnabled()) {
- rememberedVolume = mAvrcp_ext.getVolume(device);
- Log.d(TAG,"volume = " + rememberedVolume);
- }
- // Make sure the Audio Manager knows the previous Active device is disconnected,
- // and the new Active device is connected.
- // Also, mute and unmute the output during the switch to avoid audio glitches.
- boolean wasMuted = false;
- if (previousActiveDevice != null && !tws_switch) {
- if (!mAudioManager.isStreamMute(AudioManager.STREAM_MUSIC)) {
- mAudioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,
- AudioManager.ADJUST_MUTE,
- mAudioManager.FLAG_BLUETOOTH_ABS_VOLUME);
- wasMuted = true;
+ synchronized (mVariableLock) {
+ if (mFactory.getAvrcpTargetService() != null) {
+ rememberedVolume = mFactory.getAvrcpTargetService()
+ .getRememberedVolumeForDevice(mActiveDevice);
+ } else if (mAdapterService != null && mAdapterService.isVendorIntfEnabled()) {
+ rememberedVolume = mAvrcp_ext.getVolume(device);
+ Log.d(TAG,"volume = " + rememberedVolume);
}
- }
+ // Make sure the Audio Manager knows the previous Active device is disconnected,
+ // and the new Active device is connected.
- if (!isBAActive) {
+ if (!isBAActive && mAudioManager != null) {
// Make sure the Audio Manager knows the previous
// Active device is disconnected, and the new Active
// device is connected.
@@ -864,19 +945,25 @@
// new active device so that Audio Service
// can reset accordingly the audio feeding parameters
// in the Audio HAL to the Bluetooth stack.
- mAudioManager.handleBluetoothA2dpActiveDeviceChange(
- mActiveDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP,
- true, rememberedVolume);
- }
+ mAudioManager.handleBluetoothA2dpActiveDeviceChange(
+ mActiveDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP,
+ true, rememberedVolume);
+ }
// Inform the Audio Service about the codec configuration
// change, so the Audio Service can reset accordingly the audio
// feeding parameters in the Audio HAL to the Bluetooth stack.
- if (wasMuted) {
- mAudioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,
- AudioManager.ADJUST_UNMUTE,
- mAudioManager.FLAG_BLUETOOTH_ABS_VOLUME);
+ // Split A2dp will be enabled by default
+ boolean isSplitA2dpEnabled = true;
+ AdapterService adapterService = AdapterService.getAdapterService();
+
+ if (adapterService != null){
+ isSplitA2dpEnabled = adapterService.isSplitA2dpEnabled();
+ Log.v(TAG,"isSplitA2dpEnabled: " + isSplitA2dpEnabled);
+ } else {
+ Log.e(TAG,"adapterService is null");
+ }
}
if (mAvrcp_ext != null && !tws_switch) {
mAvrcp_ext.setAbsVolumeFlag(device);
@@ -909,15 +996,23 @@
if (DBG) {
Log.d(TAG, "Saved priority " + device + " = " + priority);
}
- mAdapterService.getDatabase()
+
+ synchronized (mVariableLock) {
+ if(mAdapterService != null)
+ mAdapterService.getDatabase()
.setProfilePriority(device, BluetoothProfile.A2DP, priority);
+ }
return true;
}
public int getPriority(BluetoothDevice device) {
enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
- return mAdapterService.getDatabase()
- .getProfilePriority(device, BluetoothProfile.A2DP);
+ synchronized (mVariableLock) {
+ if(mAdapterService != null)
+ return mAdapterService.getDatabase()
+ .getProfilePriority(device, BluetoothProfile.A2DP);
+ }
+ return BluetoothProfile.PRIORITY_UNDEFINED;
}
/* Absolute volume implementation */
@@ -1124,10 +1219,12 @@
Log.e(TAG, "setCodecConfigPreference: Codec status is null");
return;
}
- if (mAdapterService.isTwsPlusDevice(device) && ( cs4 == 0 ||
- codecConfig.getCodecType() != BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_ADAPTIVE )) {
- Log.w(TAG, "Block un-supportive codec on TWS+ device: " + device);
- return;
+ synchronized (mVariableLock) {
+ if (mAdapterService != null && mAdapterService.isTwsPlusDevice(device) && ( cs4 == 0 ||
+ codecConfig.getCodecType() != BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_ADAPTIVE )) {
+ Log.w(TAG, "Block un-supportive codec on TWS+ device: " + device);
+ return;
+ }
}
mA2dpCodecConfig.setCodecConfigPreference(device, codecStatus, codecConfig);
}
@@ -1196,19 +1293,30 @@
public int getSupportsOptionalCodecs(BluetoothDevice device) {
enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
- return mAdapterService.getDatabase().getA2dpSupportsOptionalCodecs(device);
+ synchronized (mVariableLock) {
+ if(mAdapterService != null)
+ return mAdapterService.getDatabase().getA2dpSupportsOptionalCodecs(device);
+ }
+ return BluetoothA2dp.OPTIONAL_CODECS_NOT_SUPPORTED;
}
public void setSupportsOptionalCodecs(BluetoothDevice device, boolean doesSupport) {
enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
int value = doesSupport ? BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED
: BluetoothA2dp.OPTIONAL_CODECS_NOT_SUPPORTED;
- mAdapterService.getDatabase().setA2dpSupportsOptionalCodecs(device, value);
+ synchronized (mVariableLock) {
+ if(mAdapterService != null)
+ mAdapterService.getDatabase().setA2dpSupportsOptionalCodecs(device, value);
+ }
}
public int getOptionalCodecsEnabled(BluetoothDevice device) {
enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
- return mAdapterService.getDatabase().getA2dpOptionalCodecsEnabled(device);
+ synchronized (mVariableLock) {
+ if(mAdapterService != null)
+ return mAdapterService.getDatabase().getA2dpOptionalCodecsEnabled(device);
+ }
+ return BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN;
}
public void setOptionalCodecsEnabled(BluetoothDevice device, int value) {
@@ -1219,7 +1327,10 @@
Log.w(TAG, "Unexpected value passed to setOptionalCodecsEnabled:" + value);
return;
}
- mAdapterService.getDatabase().setA2dpOptionalCodecsEnabled(device, value);
+ synchronized (mVariableLock) {
+ if(mAdapterService != null)
+ mAdapterService.getDatabase().setA2dpOptionalCodecsEnabled(device, value);
+ }
}
// Handle messages from native (JNI) to Java
@@ -1233,41 +1344,57 @@
if (stackEvent.type == A2dpStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED) {
switch (stackEvent.valueInt) {
case A2dpStackEvent.CONNECTION_STATE_CONNECTED:
- case A2dpStackEvent.CONNECTION_STATE_CONNECTING:
- // Create a new state machine only when connecting to a device
- if (mAdapterService.isVendorIntfEnabled())
- mA2dpStackEvent = stackEvent.valueInt;
- if (mAdapterService.isTwsPlusDevice(device)) {
- sm = getOrCreateStateMachine(device);
- break;
+ case A2dpStackEvent.CONNECTION_STATE_CONNECTING: {
+ boolean connectionAllowed;
+ synchronized (mVariableLock) {
+ // Create a new state machine only when connecting to a device
+ if (mAdapterService != null && mAdapterService.isVendorIntfEnabled())
+ mA2dpStackEvent = stackEvent.valueInt;
+ if (mAdapterService != null && mAdapterService.isTwsPlusDevice(device)) {
+ sm = getOrCreateStateMachine(device);
+ break;
+ }
+ connectionAllowed = connectionAllowedCheckMaxDevices(device);
}
- if (!connectionAllowedCheckMaxDevices(device)) {
+ if (!connectionAllowed) {
Log.e(TAG, "Cannot connect to " + device
+ " : too many connected devices");
- mA2dpNativeInterface.disconnectA2dp(device);
- return;
+ try {
+ mA2dpNativeInterfaceLock.readLock().lock();
+ if (mA2dpNativeInterface != null) {
+ mA2dpNativeInterface.disconnectA2dp(device);
+ return;
+ }
+ } finally {
+ mA2dpNativeInterfaceLock.readLock().unlock();
+ }
}
sm = getOrCreateStateMachine(device);
break;
+ }
default:
- if (mAdapterService.isVendorIntfEnabled() &&
- mA2dpStackEvent == A2dpStackEvent.CONNECTION_STATE_CONNECTED ||
- mA2dpStackEvent == A2dpStackEvent.CONNECTION_STATE_CONNECTING) {
- Log.d(TAG,"Reset local stack event value");
- mA2dpStackEvent = EVENT_TYPE_NONE;
+ synchronized (mVariableLock) {
+ if (mAdapterService!= null && mAdapterService.isVendorIntfEnabled() &&
+ mA2dpStackEvent == A2dpStackEvent.CONNECTION_STATE_CONNECTED ||
+ mA2dpStackEvent == A2dpStackEvent.CONNECTION_STATE_CONNECTING) {
+ Log.d(TAG,"Reset local stack event value");
+ mA2dpStackEvent = EVENT_TYPE_NONE;
+ }
}
break;
}
}
} else {
- if (mAdapterService.isVendorIntfEnabled()) {
- switch (sm.getConnectionState()) {
- case BluetoothProfile.STATE_DISCONNECTED:
- mA2dpStackEvent = stackEvent.valueInt;
- break;
- default:
- mA2dpStackEvent = EVENT_TYPE_NONE;
- break;
+ synchronized (mVariableLock) {
+ if (mAdapterService != null && mAdapterService.isVendorIntfEnabled()) {
+ switch (sm.getConnectionState()) {
+ case BluetoothProfile.STATE_DISCONNECTED:
+ mA2dpStackEvent = stackEvent.valueInt;
+ break;
+ default:
+ mA2dpStackEvent = EVENT_TYPE_NONE;
+ break;
+ }
}
}
}
@@ -1295,20 +1422,24 @@
// Log codec config and capability metrics
BluetoothCodecConfig codecConfig = codecStatus.getCodecConfig();
- StatsLog.write(StatsLog.BLUETOOTH_A2DP_CODEC_CONFIG_CHANGED,
- mAdapterService.obfuscateAddress(device), codecConfig.getCodecType(),
- codecConfig.getCodecPriority(), codecConfig.getSampleRate(),
- codecConfig.getBitsPerSample(), codecConfig.getChannelMode(),
- codecConfig.getCodecSpecific1(), codecConfig.getCodecSpecific2(),
- codecConfig.getCodecSpecific3(), codecConfig.getCodecSpecific4());
- BluetoothCodecConfig[] codecCapabilities = codecStatus.getCodecsSelectableCapabilities();
- for (BluetoothCodecConfig codecCapability : codecCapabilities) {
- StatsLog.write(StatsLog.BLUETOOTH_A2DP_CODEC_CAPABILITY_CHANGED,
- mAdapterService.obfuscateAddress(device), codecCapability.getCodecType(),
- codecCapability.getCodecPriority(), codecCapability.getSampleRate(),
- codecCapability.getBitsPerSample(), codecCapability.getChannelMode(),
+ synchronized (mVariableLock) {
+ if(mAdapterService != null) {
+ StatsLog.write(StatsLog.BLUETOOTH_A2DP_CODEC_CONFIG_CHANGED,
+ mAdapterService.obfuscateAddress(device), codecConfig.getCodecType(),
+ codecConfig.getCodecPriority(), codecConfig.getSampleRate(),
+ codecConfig.getBitsPerSample(), codecConfig.getChannelMode(),
codecConfig.getCodecSpecific1(), codecConfig.getCodecSpecific2(),
codecConfig.getCodecSpecific3(), codecConfig.getCodecSpecific4());
+ BluetoothCodecConfig[] codecCapabilities = codecStatus.getCodecsSelectableCapabilities();
+ for (BluetoothCodecConfig codecCapability : codecCapabilities) {
+ StatsLog.write(StatsLog.BLUETOOTH_A2DP_CODEC_CAPABILITY_CHANGED,
+ mAdapterService.obfuscateAddress(device), codecCapability.getCodecType(),
+ codecCapability.getCodecPriority(), codecCapability.getSampleRate(),
+ codecCapability.getBitsPerSample(), codecCapability.getChannelMode(),
+ codecConfig.getCodecSpecific1(), codecConfig.getCodecSpecific2(),
+ codecConfig.getCodecSpecific3(), codecConfig.getCodecSpecific4());
+ }
+ }
}
broadcastCodecConfig(device, codecStatus);
@@ -1320,14 +1451,23 @@
if (isActiveDevice(device) && !sameAudioFeedingParameters) {
if (mAvrcp_ext != null)
rememberedVolume = mAvrcp_ext.getVolume(device);
- mAudioManager.handleBluetoothA2dpActiveDeviceChange(device,
- BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP,
- true, rememberedVolume);
+ synchronized (mVariableLock) {
+ if (mAudioManager != null) {
+ mAudioManager.handleBluetoothA2dpActiveDeviceChange(device,
+ BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP,
+ true, rememberedVolume);
+ }
+ }
}
}
+
void updateTwsChannelMode(int state, BluetoothDevice device) {
if (mIsTwsPlusMonoSupported) {
- BluetoothDevice peerTwsDevice = mAdapterService.getTwsPlusPeerDevice(device);
+ BluetoothDevice peerTwsDevice = null;
+ synchronized (mVariableLock) {
+ if (mAdapterService != null)
+ peerTwsDevice = mAdapterService.getTwsPlusPeerDevice(device);
+ }
Log.d(TAG, "TwsChannelMode: " + mTwsPlusChannelMode);
synchronized(mBtTwsLock) {
if ("mono".equals(mTwsPlusChannelMode)) {
@@ -1338,7 +1478,10 @@
mHandler.sendMessageDelayed(msg, DualMonoCfg_Timeout);
} else if (state == BluetoothA2dp.STATE_PLAYING) {
Log.d(TAG, "setparameters to Mono");
- mAudioManager.setParameters("TwsChannelConfig=mono");
+ synchronized (mVariableLock) {
+ if (mAudioManager != null)
+ mAudioManager.setParameters("TwsChannelConfig=mono");
+ }
}
if ((state == BluetoothA2dp.STATE_NOT_PLAYING) &&
isA2dpPlaying(peerTwsDevice)) {
@@ -1364,7 +1507,10 @@
if ((state == BluetoothA2dp.STATE_NOT_PLAYING)
&& isA2dpPlaying(peerTwsDevice)) {
Log.d(TAG, "setparameters to Mono");
- mAudioManager.setParameters("TwsChannelConfig=mono");
+ synchronized (mVariableLock) {
+ if (mAudioManager != null)
+ mAudioManager.setParameters("TwsChannelConfig=mono");
+ }
mTwsPlusChannelMode = "mono";
}
}
@@ -1384,7 +1530,10 @@
if(isBAActive) {
return;
}
- mAudioManager.setParameters("reconfigA2dp=true");
+ synchronized (mVariableLock) {
+ if (mAudioManager != null)
+ mAudioManager.setParameters("reconfigA2dp=true");
+ }
}
@@ -1430,8 +1579,11 @@
mActiveDevice = device;
}
- StatsLog.write(StatsLog.BLUETOOTH_ACTIVE_DEVICE_CHANGED, BluetoothProfile.A2DP,
- mAdapterService.obfuscateAddress(device));
+ synchronized (mVariableLock) {
+ if (mAdapterService != null)
+ StatsLog.write(StatsLog.BLUETOOTH_ACTIVE_DEVICE_CHANGED, BluetoothProfile.A2DP,
+ mAdapterService.obfuscateAddress(device));
+ }
Intent intent = new Intent(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
@@ -1494,6 +1646,9 @@
if (mFactory.getAvrcpTargetService() != null) {
mFactory.getAvrcpTargetService().removeStoredVolumeForDevice(device);
}
+ if (mAvrcp_ext != null) {
+ mAvrcp_ext.removeVolumeForDevice(device);
+ }
removeStateMachine(device);
}
@@ -1549,7 +1704,6 @@
Log.i(TAG, "updateOptionalCodecsSupport: Mandatory codec is not selectable.");
return;
}
-
if (previousSupport == BluetoothA2dp.OPTIONAL_CODECS_SUPPORT_UNKNOWN
|| supportsOptional != (previousSupport
== BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED)) {
@@ -1580,14 +1734,20 @@
if (toState == BluetoothProfile.STATE_CONNECTED) {
MetricsLogger.logProfileConnectionEvent(BluetoothMetricsProto.ProfileId.A2DP);
}
+ int bondState = BluetoothDevice.BOND_NONE;
// Check if the device is disconnected - if unbond, remove the state machine
if (toState == BluetoothProfile.STATE_DISCONNECTED) {
- int bondState = mAdapterService.getBondState(device);
+ synchronized (mVariableLock) {
+ if(mAdapterService != null)
+ bondState = mAdapterService.getBondState(device);
+ }
if (bondState == BluetoothDevice.BOND_NONE) {
if (mFactory.getAvrcpTargetService() != null) {
mFactory.getAvrcpTargetService().removeStoredVolumeForDevice(device);
}
-
+ if (mAvrcp_ext != null) {
+ mAvrcp_ext.removeVolumeForDevice(device);
+ }
removeStateMachine(device);
}
}
diff --git a/src/com/android/bluetooth/btservice/AdapterProperties.java b/src/com/android/bluetooth/btservice/AdapterProperties.java
index beff7c8..c7eb53c 100644
--- a/src/com/android/bluetooth/btservice/AdapterProperties.java
+++ b/src/com/android/bluetooth/btservice/AdapterProperties.java
@@ -86,7 +86,18 @@
private CopyOnWriteArrayList<BluetoothDevice> mBondedDevices =
new CopyOnWriteArrayList<BluetoothDevice>();
- private int mProfilesConnecting, mProfilesConnected, mProfilesDisconnecting;
+ private final class ProfilesConnectionState {
+ public int mProfilesConnecting, mProfilesConnected, mProfilesDisconnecting;
+
+ ProfilesConnectionState(int connecting, int connected, int disconnecting) {
+ mProfilesConnecting = connecting;
+ mProfilesConnected = connected;
+ mProfilesDisconnecting = disconnecting;
+ }
+ }
+ private final HashMap<BluetoothDevice, ProfilesConnectionState> mDevicesConnectionState =
+ new HashMap<>();
+
private final HashMap<Integer, Pair<Integer, Integer>> mProfileConnectionState =
new HashMap<>();
@@ -218,6 +229,7 @@
public void init(RemoteDevices remoteDevices) {
mProfileConnectionState.clear();
+ mDevicesConnectionState.clear();
mRemoteDevices = remoteDevices;
// Get default max connected audio devices from config.xml in frameworks/base/core
@@ -274,6 +286,7 @@
}
mService = null;
mBondedDevices.clear();
+ mDevicesConnectionState.clear();
}
@Override
@@ -787,6 +800,10 @@
debugLog("Adding bonded device:" + device);
mBondedDevices.add(device);
}
+ if (!mDevicesConnectionState.containsKey(device)) {
+ debugLog("Adding connection state:" + device);
+ mDevicesConnectionState.put(device, new ProfilesConnectionState(0, 0, 0));
+ }
} else if (state == BluetoothDevice.BOND_NONE) {
// remove device from list
if (mBondedDevices.remove(device)) {
@@ -794,6 +811,10 @@
} else {
debugLog("Failed to remove device: " + device);
}
+ if (mDevicesConnectionState.containsKey(device)) {
+ debugLog("Removing connection state:" + device);
+ mDevicesConnectionState.remove(device);
+ }
}
} catch (Exception ee) {
Log.w(TAG, "onBondStateChanged: Exception ", ee);
@@ -868,7 +889,7 @@
try {
validateConnectionState =
- updateCountersAndCheckForConnectionStateChange(state, prevState);
+ updateCountersAndCheckForConnectionStateChange(device, state, prevState);
} catch (IllegalStateException ee) {
Log.w(TAG, "ADAPTER_CONNECTION_STATE_CHANGE: unexpected transition for profile="
+ profile + ", " + prevState + " -> " + state);
@@ -932,33 +953,45 @@
}
}
- private boolean updateCountersAndCheckForConnectionStateChange(int state, int prevState) {
+ private boolean updateCountersAndCheckForConnectionStateChange(BluetoothDevice device,
+ int state, int prevState) {
+ if(!mDevicesConnectionState.containsKey(device)) {
+ Log.e(TAG, "Can't find device connection record, adding new one: " + device);
+ mDevicesConnectionState.put(device, new ProfilesConnectionState(0, 0, 0));
+ }
+ ProfilesConnectionState connstate = mDevicesConnectionState.get(device);
+
+ Log.e(TAG, "prevState=" + prevState + " -> State=" + state +
+ " mProfilesConnecting=" + connstate.mProfilesConnecting +
+ " mProfilesConnected=" + connstate.mProfilesConnected +
+ " mProfilesDisconnecting=" + connstate.mProfilesDisconnecting);
+
switch (prevState) {
case BluetoothProfile.STATE_CONNECTING:
- if (mProfilesConnecting > 0) {
- mProfilesConnecting--;
+ if (connstate.mProfilesConnecting > 0) {
+ connstate.mProfilesConnecting--;
} else {
- Log.e(TAG, "mProfilesConnecting " + mProfilesConnecting);
+ Log.e(TAG, "mProfilesConnecting " + connstate.mProfilesConnecting);
throw new IllegalStateException(
"Invalid state transition, " + prevState + " -> " + state);
}
break;
case BluetoothProfile.STATE_CONNECTED:
- if (mProfilesConnected > 0) {
- mProfilesConnected--;
+ if (connstate.mProfilesConnected > 0) {
+ connstate.mProfilesConnected--;
} else {
- Log.e(TAG, "mProfilesConnected " + mProfilesConnected);
+ Log.e(TAG, "mProfilesConnected " + connstate.mProfilesConnected);
throw new IllegalStateException(
"Invalid state transition, " + prevState + " -> " + state);
}
break;
case BluetoothProfile.STATE_DISCONNECTING:
- if (mProfilesDisconnecting > 0) {
- mProfilesDisconnecting--;
+ if (connstate.mProfilesDisconnecting > 0) {
+ connstate.mProfilesDisconnecting--;
} else {
- Log.e(TAG, "mProfilesDisconnecting " + mProfilesDisconnecting);
+ Log.e(TAG, "mProfilesDisconnecting " + connstate.mProfilesDisconnecting);
throw new IllegalStateException(
"Invalid state transition, " + prevState + " -> " + state);
}
@@ -967,19 +1000,19 @@
switch (state) {
case BluetoothProfile.STATE_CONNECTING:
- mProfilesConnecting++;
- return (mProfilesConnected == 0 && mProfilesConnecting == 1);
+ connstate.mProfilesConnecting++;
+ return (connstate.mProfilesConnected == 0 && connstate.mProfilesConnecting == 1);
case BluetoothProfile.STATE_CONNECTED:
- mProfilesConnected++;
- return (mProfilesConnected == 1);
+ connstate.mProfilesConnected++;
+ return (connstate.mProfilesConnected == 1);
case BluetoothProfile.STATE_DISCONNECTING:
- mProfilesDisconnecting++;
- return (mProfilesConnected == 0 && mProfilesDisconnecting == 1);
+ connstate.mProfilesDisconnecting++;
+ return (connstate.mProfilesConnected == 0 && connstate.mProfilesDisconnecting == 1);
case BluetoothProfile.STATE_DISCONNECTED:
- return (mProfilesConnected == 0 && mProfilesConnecting == 0);
+ return (connstate.mProfilesConnected == 0 && connstate.mProfilesConnecting == 0);
default:
return true;
@@ -1240,9 +1273,8 @@
// Reset adapter and profile connection states
setConnectionState(BluetoothAdapter.STATE_DISCONNECTED);
mProfileConnectionState.clear();
- mProfilesConnected = 0;
- mProfilesConnecting = 0;
- mProfilesDisconnecting = 0;
+ mDevicesConnectionState.clear();
+
// adapterPropertyChangedCallback has already been received. Set the scan mode.
setScanMode(AbstractionLayer.BT_SCAN_MODE_CONNECTABLE);
// This keeps NV up-to date on first-boot after flash.
diff --git a/src/com/android/bluetooth/btservice/AdapterService.java b/src/com/android/bluetooth/btservice/AdapterService.java
index 277eb8c..5bec2d0 100644
--- a/src/com/android/bluetooth/btservice/AdapterService.java
+++ b/src/com/android/bluetooth/btservice/AdapterService.java
@@ -2620,6 +2620,12 @@
return false;
}
+ if (pinCode.length != len) {
+ android.util.EventLog.writeEvent(0x534e4554, "139287605", -1,
+ "PIN code length mismatch");
+ return false;
+ }
+
StatsLog.write(StatsLog.BLUETOOTH_BOND_STATE_CHANGED,
obfuscateAddress(device), 0, device.getType(),
BluetoothDevice.BOND_BONDING,
@@ -2636,6 +2642,12 @@
return false;
}
+ if (passkey.length != len) {
+ android.util.EventLog.writeEvent(0x534e4554, "139287605", -1,
+ "Passkey length mismatch");
+ return false;
+ }
+
StatsLog.write(StatsLog.BLUETOOTH_BOND_STATE_CHANGED,
obfuscateAddress(device), 0, device.getType(),
BluetoothDevice.BOND_BONDING,
diff --git a/src/com/android/bluetooth/btservice/PhonePolicy.java b/src/com/android/bluetooth/btservice/PhonePolicy.java
index f3097fe..529decf 100644
--- a/src/com/android/bluetooth/btservice/PhonePolicy.java
+++ b/src/com/android/bluetooth/btservice/PhonePolicy.java
@@ -326,6 +326,9 @@
+ prevState + " -> " + nextState);
if ((profileId == BluetoothProfile.A2DP) || (profileId == BluetoothProfile.HEADSET)
|| profileId == BluetoothProfile.A2DP_SINK) {
+ BluetoothDevice peerTwsDevice =
+ (mAdapterService != null && mAdapterService.isTwsPlusDevice(device)) ?
+ mAdapterService.getTwsPlusPeerDevice(device):null;
if (nextState == BluetoothProfile.STATE_CONNECTED) {
debugLog("processProfileStateChanged: isTwsDevice: " + mAdapterService.isTwsPlusDevice(device));
switch (profileId) {
@@ -333,12 +336,16 @@
mA2dpRetrySet.remove(device);
if (mAdapterService.isTwsPlusDevice(device)) {
setAutoConnectForA2dpSink(device);
+ if (peerTwsDevice != null)
+ setAutoConnectForA2dpSink(peerTwsDevice);
}
break;
case BluetoothProfile.HEADSET:
mHeadsetRetrySet.remove(device);
if (mAdapterService.isTwsPlusDevice(device)) {
setAutoConnectForHeadset(device);
+ if (peerTwsDevice != null)
+ setAutoConnectForHeadset(peerTwsDevice);
}
break;
case BluetoothProfile.A2DP_SINK:
@@ -348,24 +355,45 @@
connectOtherProfile(device);
}
if (nextState == BluetoothProfile.STATE_DISCONNECTED) {
+ HeadsetService hsService = mFactory.getHeadsetService();
+ A2dpService a2dpService = mFactory.getA2dpService();
handleAllProfilesDisconnected(device);
if (prevState == BluetoothProfile.STATE_CONNECTING) {
- HeadsetService hsService = mFactory.getHeadsetService();
boolean hsDisconnected = hsService == null
|| hsService.getConnectionState(device)
== BluetoothProfile.STATE_DISCONNECTED;
- A2dpService a2dpService = mFactory.getA2dpService();
boolean a2dpDisconnected = a2dpService == null
|| a2dpService.getConnectionState(device)
== BluetoothProfile.STATE_DISCONNECTED;
+ boolean isAnyTwsPairConnected = (peerTwsDevice != null) && ((a2dpService != null) &&
+ (a2dpService.getConnectionState(peerTwsDevice) == BluetoothProfile.STATE_CONNECTED))
+ || ((hsService != null) &&
+ (hsService.getConnectionState(peerTwsDevice) == BluetoothProfile.STATE_CONNECTED));
debugLog("processProfileStateChanged, device=" + device + ", a2dpDisconnected="
- + a2dpDisconnected + ", hsDisconnected=" + hsDisconnected);
+ + a2dpDisconnected + ", hsDisconnected=" + hsDisconnected
+ + ", TwsPairConnected=" + isAnyTwsPairConnected);
if (hsDisconnected && a2dpDisconnected) {
//remove a2dp and headset retry set.
mA2dpRetrySet.remove(device);
mHeadsetRetrySet.remove(device);
- removeAutoConnectFromA2dpSink(device);
- removeAutoConnectFromHeadset(device);
+ if (!isAnyTwsPairConnected) {
+ removeAutoConnectFromA2dpSink(device);
+ removeAutoConnectFromHeadset(device);
+ }
+ }
+ } else if (prevState == BluetoothProfile.STATE_DISCONNECTING) {
+ if (peerTwsDevice != null) {
+ int autoConnect = BluetoothProfile.PRIORITY_AUTO_CONNECT;
+ if (((a2dpService.getPriority(peerTwsDevice) == autoConnect) &&
+ (hsService.getPriority(peerTwsDevice) == autoConnect)) ||
+ ((a2dpService.getPriority(device) == autoConnect) &&
+ (hsService.getPriority(device) == autoConnect))) {
+ debugLog("User triggered disconnect reset priority ON to both EBs");
+ removeAutoConnectFromA2dpSink(device);
+ removeAutoConnectFromHeadset(device);
+ removeAutoConnectFromA2dpSink(peerTwsDevice);
+ removeAutoConnectFromHeadset(peerTwsDevice);
+ }
}
}
}
@@ -394,21 +422,13 @@
setAutoConnectForA2dpSink(activeDevice);
setAutoConnectForHeadset(activeDevice);
- if (mAdapterService.isTwsPlusDevice(activeDevice)) {
- BluetoothDevice peerTwsDevice = hsService.getTwsPlusConnectedPeer(activeDevice);
+ if (mAdapterService != null && mAdapterService.isTwsPlusDevice(activeDevice)) {
+ BluetoothDevice peerTwsDevice = mAdapterService.getTwsPlusPeerDevice(activeDevice);
if (peerTwsDevice != null) {
- if (a2dpService != null &&
- a2dpService.getConnectionState(peerTwsDevice) !=
- BluetoothProfile.STATE_DISCONNECTED) {
- debugLog("A2DP: Set Autoconnect for Peer TWS+ as well");
- setAutoConnectForA2dpSink(peerTwsDevice);
- }
- if (hsService != null &&
- hsService.getConnectionState(peerTwsDevice) !=
- BluetoothProfile.STATE_DISCONNECTED) {
- debugLog("HFP: Set Autoconnect for Peer TWS+ as well");
- setAutoConnectForHeadset(peerTwsDevice);
- }
+ debugLog("A2DP: Set Autoconnect for Peer TWS+ as well");
+ setAutoConnectForA2dpSink(peerTwsDevice);
+ debugLog("HFP: Set Autoconnect for Peer TWS+ as well");
+ setAutoConnectForHeadset(peerTwsDevice);
}
}
break;
diff --git a/src/com/android/bluetooth/hfp/HeadsetService.java b/src/com/android/bluetooth/hfp/HeadsetService.java
index 0ca6734..fce6d43 100644
--- a/src/com/android/bluetooth/hfp/HeadsetService.java
+++ b/src/com/android/bluetooth/hfp/HeadsetService.java
@@ -861,13 +861,14 @@
return null;
}
- private BluetoothDevice getConnectedTwspDevice() {
- List<BluetoothDevice> connDevices = getConnectedDevices();
+ private BluetoothDevice getConnectedOrConnectingTwspDevice() {
+ List<BluetoothDevice> connDevices =
+ getAllDevicesMatchingConnectionStates(CONNECTING_CONNECTED_STATES);
int size = connDevices.size();
for(int i = 0; i < size; i++) {
BluetoothDevice ConnectedDevice = connDevices.get(i);
if (mAdapterService.isTwsPlusDevice(ConnectedDevice)) {
- logD("getConnectedTwspDevice: found" + ConnectedDevice);
+ logD("getConnectedorConnectingTwspDevice: found" + ConnectedDevice);
return ConnectedDevice;
}
}
@@ -905,12 +906,14 @@
if (connDevices.size() == 0) {
allowSecondHfConnection = true;
} else {
- BluetoothDevice connectedTwspDev = getConnectedTwspDevice();
- if (connectedTwspDev != null) {
+ BluetoothDevice connectedOrConnectingTwspDev =
+ getConnectedOrConnectingTwspDevice();
+ if (connectedOrConnectingTwspDev != null) {
// There is TWSP connected earbud
if (adapterService.isTwsPlusDevice(device)) {
if (adapterService.getTwsPlusPeerAddress
- (device).equals(connectedTwspDev.getAddress())) {
+ (device).equals(
+ connectedOrConnectingTwspDev.getAddress())) {
//Allow connection only if the outgoing
//is peer of TWS connected earbud
allowSecondHfConnection = true;
@@ -919,7 +922,8 @@
}
} else {
reservedSlotForTwspPeer = 0;
- if (getTwsPlusConnectedPeer(connectedTwspDev) == null) {
+ if (getTwsPlusConnectedPeer(
+ connectedOrConnectingTwspDev) == null) {
//Peer of Connected Tws+ device is not Connected
//yet, reserve one slot
reservedSlotForTwspPeer = 1;
@@ -965,8 +969,9 @@
"is"+ adapterService.isTwsPlusDevice(device));
Log.v(TAG, "TWS Peer Addr: " +
adapterService.getTwsPlusPeerAddress(device));
- if (connectedTwspDev != null) {
- Log.v(TAG, "Connected device" + connectedTwspDev.getAddress());
+ if (connectedOrConnectingTwspDev != null) {
+ Log.v(TAG, "Connected or Connecting device"
+ + connectedOrConnectingTwspDev.getAddress());
} else {
Log.v(TAG, "No Connected TWSP devices");
}
diff --git a/src/com/android/bluetooth/hfp/HeadsetStateMachine.java b/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
index 37c5c22..784dead 100644
--- a/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
+++ b/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
@@ -2640,8 +2640,10 @@
mNativeInterface.atResponseCode(device, HeadsetHalConstants.AT_RESPONSE_ERROR, 0);
} else if (atCommand.equals("+CGMI")) {
mNativeInterface.atResponseString(device, "+CGMI: \"" + Build.MANUFACTURER + "\"");
+ mNativeInterface.atResponseCode(device, HeadsetHalConstants.AT_RESPONSE_OK, 0);
} else if (atCommand.equals("+CGMM")) {
mNativeInterface.atResponseString(device, "+CGMM: " + Build.MODEL);
+ mNativeInterface.atResponseCode(device, HeadsetHalConstants.AT_RESPONSE_OK, 0);
} else {
processVendorSpecificAt(atCommand, device);
}