BT-HFP: Update Bluetooth headset state handler to Multi-HFP
* When multiple headset devices are connected at the same time, at most one
device can be used for SCO audio at any time. This device is called
Active Device and is indicated by either
BluetoothHeadset.getActiveDevice() or
BluetoothHeadset.ACTIVE_DEVICE_CHANGED intent. It can also be set
through BluetoothHeadset.setActiveDevice(BluetoothDevice) internal API.
* This change let AudioService to listen to ACTIVE_DEVICE_CHANGED intent
instead of CONNECTION_STATE_CHANGED intent since it is the active
device that AudioService cares about, not the list of connected
devices.
* Everytime a new active device is set, AudioService will treat the old
one (if not null) as disconnected and call disconnection methods in
audio framework and the new active device is regarded as newly
connected and connection methods will be called by AudioService.
* When disconnectHeadset() is called, active device will be set to null
Bug: 71875419
Test: compile, connect multiple HFP devices and switch active device
among them
Change-Id: I148cca079d36a2dfc6a46b8d42ba69821c9c6de3
This commit is contained in:
committed by
Pavlin Radoslavov
parent
c584d2772d
commit
8dd33941a4
@@ -136,7 +136,6 @@ import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@@ -768,7 +767,7 @@ public class AudioService extends IAudioService.Stub
|
||||
// Register for device connection intent broadcasts.
|
||||
IntentFilter intentFilter =
|
||||
new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
|
||||
intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
|
||||
intentFilter.addAction(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED);
|
||||
intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
|
||||
intentFilter.addAction(Intent.ACTION_SCREEN_ON);
|
||||
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
|
||||
@@ -2929,14 +2928,28 @@ public class AudioService extends IAudioService.Stub
|
||||
}
|
||||
|
||||
public void setBluetoothScoOnInt(boolean on, String eventSource) {
|
||||
if (DEBUG_DEVICES) {
|
||||
Log.d(TAG, "setBluetoothScoOnInt: " + on + " " + eventSource);
|
||||
}
|
||||
if (on) {
|
||||
// do not accept SCO ON if SCO audio is not connected
|
||||
synchronized(mScoClients) {
|
||||
if ((mBluetoothHeadset != null) &&
|
||||
(mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
|
||||
!= BluetoothHeadset.STATE_AUDIO_CONNECTED)) {
|
||||
mForcedUseForCommExt = AudioSystem.FORCE_BT_SCO;
|
||||
return;
|
||||
synchronized (mScoClients) {
|
||||
if (mBluetoothHeadset != null) {
|
||||
if (mBluetoothHeadsetDevice == null) {
|
||||
BluetoothDevice activeDevice = mBluetoothHeadset.getActiveDevice();
|
||||
if (activeDevice != null) {
|
||||
// setBtScoActiveDevice() might trigger resetBluetoothSco() which
|
||||
// will call setBluetoothScoOnInt(false, "resetBluetoothSco")
|
||||
setBtScoActiveDevice(activeDevice);
|
||||
}
|
||||
}
|
||||
if (mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
|
||||
!= BluetoothHeadset.STATE_AUDIO_CONNECTED) {
|
||||
mForcedUseForCommExt = AudioSystem.FORCE_BT_SCO;
|
||||
Log.w(TAG, "setBluetoothScoOnInt(true) failed because "
|
||||
+ mBluetoothHeadsetDevice + " is not in audio connected mode");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
|
||||
@@ -3324,24 +3337,23 @@ public class AudioService extends IAudioService.Stub
|
||||
}
|
||||
}
|
||||
|
||||
void setBtScoDeviceConnectionState(BluetoothDevice btDevice, int state) {
|
||||
private boolean handleBtScoActiveDeviceChange(BluetoothDevice btDevice, boolean isActive) {
|
||||
if (btDevice == null) {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
String address = btDevice.getAddress();
|
||||
BluetoothClass btClass = btDevice.getBluetoothClass();
|
||||
int outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
|
||||
int inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
|
||||
if (btClass != null) {
|
||||
switch (btClass.getDeviceClass()) {
|
||||
case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
|
||||
case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
|
||||
outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
|
||||
break;
|
||||
case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
|
||||
outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
|
||||
break;
|
||||
case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
|
||||
case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
|
||||
outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
|
||||
break;
|
||||
case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
|
||||
outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3349,34 +3361,33 @@ public class AudioService extends IAudioService.Stub
|
||||
address = "";
|
||||
}
|
||||
|
||||
boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
|
||||
|
||||
String btDeviceName = btDevice.getName();
|
||||
boolean success =
|
||||
handleDeviceConnection(connected, outDevice, address, btDeviceName) &&
|
||||
handleDeviceConnection(connected, inDevice, address, btDeviceName);
|
||||
boolean result = handleDeviceConnection(isActive, outDevice, address, btDeviceName);
|
||||
// handleDeviceConnection() && result to make sure the method get executed
|
||||
result = handleDeviceConnection(isActive, inDevice, address, btDeviceName) && result;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
return;
|
||||
void setBtScoActiveDevice(BluetoothDevice btDevice) {
|
||||
if (DEBUG_DEVICES) {
|
||||
Log.d(TAG, "setBtScoActiveDevice(" + btDevice + ")");
|
||||
}
|
||||
|
||||
/* When one BT headset is disconnected while another BT headset
|
||||
* is connected, don't mess with the headset device.
|
||||
*/
|
||||
if ((state == BluetoothProfile.STATE_DISCONNECTED ||
|
||||
state == BluetoothProfile.STATE_DISCONNECTING) &&
|
||||
mBluetoothHeadset != null &&
|
||||
mBluetoothHeadset.getAudioState(btDevice) == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
|
||||
Log.w(TAG, "SCO connected through another device, returning");
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (mScoClients) {
|
||||
if (connected) {
|
||||
final BluetoothDevice previousActiveDevice = mBluetoothHeadsetDevice;
|
||||
if (!Objects.equals(btDevice, previousActiveDevice)) {
|
||||
if (!handleBtScoActiveDeviceChange(previousActiveDevice, false)) {
|
||||
Log.w(TAG, "setBtScoActiveDevice() failed to remove previous device "
|
||||
+ previousActiveDevice);
|
||||
}
|
||||
if (!handleBtScoActiveDeviceChange(btDevice, true)) {
|
||||
Log.e(TAG, "setBtScoActiveDevice() failed to add new device " + btDevice);
|
||||
// set mBluetoothHeadsetDevice to null when failing to add new device
|
||||
btDevice = null;
|
||||
}
|
||||
mBluetoothHeadsetDevice = btDevice;
|
||||
} else {
|
||||
mBluetoothHeadsetDevice = null;
|
||||
resetBluetoothSco();
|
||||
if (mBluetoothHeadsetDevice == null) {
|
||||
resetBluetoothSco();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3431,12 +3442,7 @@ public class AudioService extends IAudioService.Stub
|
||||
// Discard timeout message
|
||||
mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
|
||||
mBluetoothHeadset = (BluetoothHeadset) proxy;
|
||||
deviceList = mBluetoothHeadset.getConnectedDevices();
|
||||
if (deviceList.size() > 0) {
|
||||
mBluetoothHeadsetDevice = deviceList.get(0);
|
||||
} else {
|
||||
mBluetoothHeadsetDevice = null;
|
||||
}
|
||||
setBtScoActiveDevice(mBluetoothHeadset.getActiveDevice());
|
||||
// Refresh SCO audio state
|
||||
checkScoAudioState();
|
||||
// Continue pending action if any
|
||||
@@ -3557,10 +3563,7 @@ public class AudioService extends IAudioService.Stub
|
||||
|
||||
void disconnectHeadset() {
|
||||
synchronized (mScoClients) {
|
||||
if (mBluetoothHeadsetDevice != null) {
|
||||
setBtScoDeviceConnectionState(mBluetoothHeadsetDevice,
|
||||
BluetoothProfile.STATE_DISCONNECTED);
|
||||
}
|
||||
setBtScoActiveDevice(null);
|
||||
mBluetoothHeadset = null;
|
||||
}
|
||||
}
|
||||
@@ -5732,11 +5735,9 @@ public class AudioService extends IAudioService.Stub
|
||||
AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
|
||||
}
|
||||
mDockState = dockState;
|
||||
} else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
|
||||
state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
|
||||
BluetoothProfile.STATE_DISCONNECTED);
|
||||
} else if (action.equals(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED)) {
|
||||
BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
|
||||
setBtScoDeviceConnectionState(btDevice, state);
|
||||
setBtScoActiveDevice(btDevice);
|
||||
} else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
|
||||
boolean broadcast = false;
|
||||
int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
|
||||
|
||||
Reference in New Issue
Block a user