AudioService: make all BT device updates async
Make AudioManager methods to (dis)connect a BT device (hearing aid or A2DP) and handle config update run on the AudioDeviceBroker event thread to prevent concurrency issues between BtService and AudioService. Bug: 126239173 Test: have multiple A2DP devices connected, switch between them Change-Id: Iefd4b4d29e28b15cbb74e8a175ee5e6cc7918c1d
This commit is contained in:
@@ -4068,6 +4068,10 @@ public class AudioManager {
|
||||
/**
|
||||
* Indicate Hearing Aid connection state change and eventually suppress
|
||||
* the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent.
|
||||
* This operation is asynchronous but its execution will still be sequentially scheduled
|
||||
* relative to calls to {@link #setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
|
||||
* * BluetoothDevice, int, int, boolean, int)} and
|
||||
* and {@link #handleBluetoothA2dpDeviceConfigChange(BluetoothDevice)}.
|
||||
* @param device Bluetooth device connected/disconnected
|
||||
* @param state new connection state (BluetoothProfile.STATE_xxx)
|
||||
* @param musicDevice Default get system volume for the connecting device.
|
||||
@@ -4075,27 +4079,27 @@ public class AudioManager {
|
||||
* {@link android.bluetooth.BluetoothProfile.HEARING_AID})
|
||||
* @param suppressNoisyIntent if true the
|
||||
* {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent.
|
||||
* @return a delay in ms that the caller should wait before broadcasting
|
||||
* BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED intent.
|
||||
* {@hide}
|
||||
*/
|
||||
public int setBluetoothHearingAidDeviceConnectionState(
|
||||
public void setBluetoothHearingAidDeviceConnectionState(
|
||||
BluetoothDevice device, int state, boolean suppressNoisyIntent,
|
||||
int musicDevice) {
|
||||
final IAudioService service = getService();
|
||||
int delay = 0;
|
||||
try {
|
||||
delay = service.setBluetoothHearingAidDeviceConnectionState(device,
|
||||
service.setBluetoothHearingAidDeviceConnectionState(device,
|
||||
state, suppressNoisyIntent, musicDevice);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
return delay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate A2DP source or sink connection state change and eventually suppress
|
||||
* the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent.
|
||||
* This operation is asynchronous but its execution will still be sequentially scheduled
|
||||
* relative to calls to {@link #setBluetoothHearingAidDeviceConnectionState(BluetoothDevice,
|
||||
* int, boolean, int)} and
|
||||
* {@link #handleBluetoothA2dpDeviceConfigChange(BluetoothDevice)}.
|
||||
* @param device Bluetooth device connected/disconnected
|
||||
* @param state new connection state, {@link BluetoothProfile#STATE_CONNECTED}
|
||||
* or {@link BluetoothProfile#STATE_DISCONNECTED}
|
||||
@@ -4105,26 +4109,27 @@ public class AudioManager {
|
||||
* {@link android.bluetooth.BluetoothProfile.A2DP_SINK})
|
||||
* @param suppressNoisyIntent if true the
|
||||
* {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent.
|
||||
* @return a delay in ms that the caller should wait before broadcasting
|
||||
* BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED intent.
|
||||
* {@hide}
|
||||
*/
|
||||
public int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
|
||||
public void setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
|
||||
BluetoothDevice device, int state,
|
||||
int profile, boolean suppressNoisyIntent, int a2dpVolume) {
|
||||
final IAudioService service = getService();
|
||||
int delay = 0;
|
||||
try {
|
||||
delay = service.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(device,
|
||||
service.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(device,
|
||||
state, profile, suppressNoisyIntent, a2dpVolume);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
return delay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate A2DP device configuration has changed.
|
||||
* This operation is asynchronous but its execution will still be sequentially scheduled
|
||||
* relative to calls to
|
||||
* {@link #setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(BluetoothDevice, int, int,
|
||||
* boolean, int)} and
|
||||
* {@link #setBluetoothHearingAidDeviceConnectionState(BluetoothDevice, int, boolean, int)}
|
||||
* @param device Bluetooth device whose configuration has changed.
|
||||
* {@hide}
|
||||
*/
|
||||
|
||||
@@ -228,10 +228,10 @@ interface IAudioService {
|
||||
|
||||
oneway void playerHasOpPlayAudio(in int piid, in boolean hasOpPlayAudio);
|
||||
|
||||
int setBluetoothHearingAidDeviceConnectionState(in BluetoothDevice device,
|
||||
void setBluetoothHearingAidDeviceConnectionState(in BluetoothDevice device,
|
||||
int state, boolean suppressNoisyIntent, int musicDevice);
|
||||
|
||||
int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(in BluetoothDevice device,
|
||||
void setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(in BluetoothDevice device,
|
||||
int state, int profile, boolean suppressNoisyIntent, int a2dpVolume);
|
||||
|
||||
oneway void setFocusRequestResultFromExtPolicy(in AudioFocusInfo afi, int requestResult,
|
||||
|
||||
@@ -201,51 +201,72 @@ import java.util.ArrayList;
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
|
||||
private static final class BtDeviceConnectionInfo {
|
||||
final @NonNull BluetoothDevice mDevice;
|
||||
final @AudioService.BtProfileConnectionState int mState;
|
||||
final int mProfile;
|
||||
final boolean mSupprNoisy;
|
||||
final int mVolume;
|
||||
|
||||
BtDeviceConnectionInfo(@NonNull BluetoothDevice device,
|
||||
@AudioService.BtProfileConnectionState int state,
|
||||
int profile, boolean suppressNoisyIntent, int vol) {
|
||||
mDevice = device;
|
||||
mState = state;
|
||||
mProfile = profile;
|
||||
mSupprNoisy = suppressNoisyIntent;
|
||||
mVolume = vol;
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ void postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
|
||||
@NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
|
||||
int profile, boolean suppressNoisyIntent, int a2dpVolume) {
|
||||
AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
|
||||
"setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent state=" + state
|
||||
// only querying address as this is the only readily available field
|
||||
// on the device
|
||||
+ " addr=" + device.getAddress()
|
||||
+ " prof=" + profile + " supprNoisy=" + suppressNoisyIntent
|
||||
+ " vol=" + a2dpVolume)).printLog(TAG));
|
||||
synchronized (mDeviceStateLock) {
|
||||
if (mBrokerHandler.hasMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE,
|
||||
new BtHelper.BluetoothA2dpDeviceInfo(device))) {
|
||||
AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
|
||||
"A2DP connection state ignored"));
|
||||
return 0;
|
||||
}
|
||||
return mDeviceInventory.setBluetoothA2dpDeviceConnectionState(
|
||||
device, state, profile, suppressNoisyIntent,
|
||||
AudioSystem.DEVICE_NONE, a2dpVolume);
|
||||
}
|
||||
final BtDeviceConnectionInfo info = new BtDeviceConnectionInfo(device, state, profile,
|
||||
suppressNoisyIntent, a2dpVolume);
|
||||
|
||||
// TODO add a check to try to remove unprocessed messages for the same device (the old
|
||||
// check didn't work), and make sure it doesn't conflict with config change message
|
||||
sendLMsgNoDelay(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT, SENDMSG_QUEUE, info);
|
||||
}
|
||||
|
||||
/*package*/ int handleBluetoothA2dpActiveDeviceChange(
|
||||
@NonNull BluetoothDevice device,
|
||||
@AudioService.BtProfileConnectionState int state, int profile,
|
||||
boolean suppressNoisyIntent, int a2dpVolume) {
|
||||
// FIXME method was added by @a8439e2 but never used, and now conflicts with async behavior
|
||||
// of handleBluetoothA2dpDeviceConfigChange and
|
||||
// setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
|
||||
synchronized (mDeviceStateLock) {
|
||||
return mDeviceInventory.handleBluetoothA2dpActiveDeviceChange(device, state, profile,
|
||||
suppressNoisyIntent, a2dpVolume);
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ int setBluetoothHearingAidDeviceConnectionState(
|
||||
private static final class HearingAidDeviceConnectionInfo {
|
||||
final @NonNull BluetoothDevice mDevice;
|
||||
final @AudioService.BtProfileConnectionState int mState;
|
||||
final boolean mSupprNoisy;
|
||||
final int mMusicDevice;
|
||||
final @NonNull String mEventSource;
|
||||
|
||||
HearingAidDeviceConnectionInfo(@NonNull BluetoothDevice device,
|
||||
@AudioService.BtProfileConnectionState int state,
|
||||
boolean suppressNoisyIntent, int musicDevice, @NonNull String eventSource) {
|
||||
mDevice = device;
|
||||
mState = state;
|
||||
mSupprNoisy = suppressNoisyIntent;
|
||||
mMusicDevice = musicDevice;
|
||||
mEventSource = eventSource;
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ void postBluetoothHearingAidDeviceConnectionState(
|
||||
@NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
|
||||
boolean suppressNoisyIntent, int musicDevice, @NonNull String eventSource) {
|
||||
AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
|
||||
"setHearingAidDeviceConnectionState state=" + state
|
||||
+ " addr=" + device.getAddress()
|
||||
+ " supprNoisy=" + suppressNoisyIntent
|
||||
+ " src=" + eventSource)).printLog(TAG));
|
||||
synchronized (mDeviceStateLock) {
|
||||
return mDeviceInventory.setBluetoothHearingAidDeviceConnectionState(
|
||||
device, state, suppressNoisyIntent, musicDevice);
|
||||
}
|
||||
final HearingAidDeviceConnectionInfo info = new HearingAidDeviceConnectionInfo(
|
||||
device, state, suppressNoisyIntent, musicDevice, eventSource);
|
||||
sendLMsgNoDelay(MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT, SENDMSG_QUEUE, info);
|
||||
}
|
||||
|
||||
// never called by system components
|
||||
@@ -766,6 +787,35 @@ import java.util.ArrayList;
|
||||
mBtHelper.onHeadsetProfileConnected((BluetoothHeadset) msg.obj);
|
||||
}
|
||||
break;
|
||||
case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT: {
|
||||
final BtDeviceConnectionInfo info = (BtDeviceConnectionInfo) msg.obj;
|
||||
AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
|
||||
"setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent "
|
||||
+ " state=" + info.mState
|
||||
// only querying address as this is the only readily available
|
||||
// field on the device
|
||||
+ " addr=" + info.mDevice.getAddress()
|
||||
+ " prof=" + info.mProfile + " supprNoisy=" + info.mSupprNoisy
|
||||
+ " vol=" + info.mVolume)).printLog(TAG));
|
||||
synchronized (mDeviceStateLock) {
|
||||
mDeviceInventory.setBluetoothA2dpDeviceConnectionState(
|
||||
info.mDevice, info.mState, info.mProfile, info.mSupprNoisy,
|
||||
AudioSystem.DEVICE_NONE, info.mVolume);
|
||||
}
|
||||
} break;
|
||||
case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT: {
|
||||
final HearingAidDeviceConnectionInfo info =
|
||||
(HearingAidDeviceConnectionInfo) msg.obj;
|
||||
AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
|
||||
"setHearingAidDeviceConnectionState state=" + info.mState
|
||||
+ " addr=" + info.mDevice.getAddress()
|
||||
+ " supprNoisy=" + info.mSupprNoisy
|
||||
+ " src=" + info.mEventSource)).printLog(TAG));
|
||||
synchronized (mDeviceStateLock) {
|
||||
mDeviceInventory.setBluetoothHearingAidDeviceConnectionState(
|
||||
info.mDevice, info.mState, info.mSupprNoisy, info.mMusicDevice);
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
Log.wtf(TAG, "Invalid message " + msg.what);
|
||||
}
|
||||
@@ -809,6 +859,10 @@ import java.util.ArrayList;
|
||||
private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK = 24;
|
||||
private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID = 25;
|
||||
private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET = 26;
|
||||
// process external command to (dis)connect an A2DP device
|
||||
private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT = 27;
|
||||
// process external command to (dis)connect a hearing aid device
|
||||
private static final int MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT = 28;
|
||||
|
||||
|
||||
private static boolean isMessageHandledUnderWakelock(int msgId) {
|
||||
@@ -821,6 +875,8 @@ import java.util.ArrayList;
|
||||
case MSG_L_A2DP_DEVICE_CONFIG_CHANGE:
|
||||
case MSG_TOGGLE_HDMI:
|
||||
case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE:
|
||||
case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT:
|
||||
case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
||||
@@ -578,7 +578,7 @@ public final class AudioDeviceInventory {
|
||||
return mCurAudioRoutes;
|
||||
}
|
||||
|
||||
/*package*/ int setBluetoothA2dpDeviceConnectionState(
|
||||
/*package*/ void setBluetoothA2dpDeviceConnectionState(
|
||||
@NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
|
||||
int profile, boolean suppressNoisyIntent, int musicDevice, int a2dpVolume) {
|
||||
int delay;
|
||||
@@ -614,46 +614,50 @@ public final class AudioDeviceInventory {
|
||||
delay);
|
||||
}
|
||||
}
|
||||
return delay;
|
||||
}
|
||||
|
||||
/*package*/ int handleBluetoothA2dpActiveDeviceChange(
|
||||
@NonNull BluetoothDevice device,
|
||||
@AudioService.BtProfileConnectionState int state, int profile,
|
||||
boolean suppressNoisyIntent, int a2dpVolume) {
|
||||
if (state == BluetoothProfile.STATE_DISCONNECTED) {
|
||||
return setBluetoothA2dpDeviceConnectionState(device, state, profile,
|
||||
suppressNoisyIntent, AudioSystem.DEVICE_NONE, a2dpVolume);
|
||||
}
|
||||
// state == BluetoothProfile.STATE_CONNECTED
|
||||
synchronized (mConnectedDevices) {
|
||||
for (int i = 0; i < mConnectedDevices.size(); i++) {
|
||||
final DeviceInfo deviceInfo = mConnectedDevices.valueAt(i);
|
||||
if (deviceInfo.mDeviceType != AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
|
||||
continue;
|
||||
}
|
||||
// If A2DP device exists, this is either an active device change or
|
||||
// device config change
|
||||
final String existingDevicekey = mConnectedDevices.keyAt(i);
|
||||
final String deviceName = device.getName();
|
||||
final String address = device.getAddress();
|
||||
final String newDeviceKey = DeviceInfo.makeDeviceListKey(
|
||||
AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address);
|
||||
int a2dpCodec = mDeviceBroker.getA2dpCodec(device);
|
||||
// Device not equal to existing device, active device change
|
||||
if (!TextUtils.equals(existingDevicekey, newDeviceKey)) {
|
||||
mConnectedDevices.remove(existingDevicekey);
|
||||
mConnectedDevices.put(newDeviceKey, new DeviceInfo(
|
||||
AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, deviceName,
|
||||
address, a2dpCodec));
|
||||
mDeviceBroker.postA2dpActiveDeviceChange(
|
||||
new BtHelper.BluetoothA2dpDeviceInfo(
|
||||
device, a2dpVolume, a2dpCodec));
|
||||
return 0;
|
||||
} else {
|
||||
// Device config change for existing device
|
||||
mDeviceBroker.postBluetoothA2dpDeviceConfigChange(device);
|
||||
return 0;
|
||||
// method was added by QC but never used, and now conflicts with async behavior of
|
||||
// handleBluetoothA2dpDeviceConfigChange and
|
||||
// setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
|
||||
if (false) {
|
||||
if (state == BluetoothProfile.STATE_DISCONNECTED) {
|
||||
setBluetoothA2dpDeviceConnectionState(device, state, profile,
|
||||
suppressNoisyIntent, AudioSystem.DEVICE_NONE, a2dpVolume);
|
||||
}
|
||||
// state == BluetoothProfile.STATE_CONNECTED
|
||||
synchronized (mConnectedDevices) {
|
||||
for (int i = 0; i < mConnectedDevices.size(); i++) {
|
||||
final DeviceInfo deviceInfo = mConnectedDevices.valueAt(i);
|
||||
if (deviceInfo.mDeviceType != AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
|
||||
continue;
|
||||
}
|
||||
// If A2DP device exists, this is either an active device change or
|
||||
// device config change
|
||||
final String existingDevicekey = mConnectedDevices.keyAt(i);
|
||||
final String deviceName = device.getName();
|
||||
final String address = device.getAddress();
|
||||
final String newDeviceKey = DeviceInfo.makeDeviceListKey(
|
||||
AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address);
|
||||
int a2dpCodec = mDeviceBroker.getA2dpCodec(device);
|
||||
// Device not equal to existing device, active device change
|
||||
if (!TextUtils.equals(existingDevicekey, newDeviceKey)) {
|
||||
mConnectedDevices.remove(existingDevicekey);
|
||||
mConnectedDevices.put(newDeviceKey, new DeviceInfo(
|
||||
AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, deviceName,
|
||||
address, a2dpCodec));
|
||||
mDeviceBroker.postA2dpActiveDeviceChange(
|
||||
new BtHelper.BluetoothA2dpDeviceInfo(
|
||||
device, a2dpVolume, a2dpCodec));
|
||||
return 0;
|
||||
} else {
|
||||
// Device config change for existing device
|
||||
mDeviceBroker.postBluetoothA2dpDeviceConfigChange(device);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4041,7 +4041,10 @@ public class AudioService extends IAudioService.Stub
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface BtProfileConnectionState {}
|
||||
|
||||
public int setBluetoothHearingAidDeviceConnectionState(
|
||||
/**
|
||||
* See AudioManager.setBluetoothHearingAidDeviceConnectionState()
|
||||
*/
|
||||
public void setBluetoothHearingAidDeviceConnectionState(
|
||||
@NonNull BluetoothDevice device, @BtProfileConnectionState int state,
|
||||
boolean suppressNoisyIntent, int musicDevice)
|
||||
{
|
||||
@@ -4053,14 +4056,14 @@ public class AudioService extends IAudioService.Stub
|
||||
throw new IllegalArgumentException("Illegal BluetoothProfile state for device "
|
||||
+ " (dis)connection, got " + state);
|
||||
}
|
||||
return mDeviceBroker.setBluetoothHearingAidDeviceConnectionState(
|
||||
mDeviceBroker.postBluetoothHearingAidDeviceConnectionState(
|
||||
device, state, suppressNoisyIntent, musicDevice, "AudioService");
|
||||
}
|
||||
|
||||
/**
|
||||
* See AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent()
|
||||
*/
|
||||
public int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
|
||||
public void setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
|
||||
@NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
|
||||
int profile, boolean suppressNoisyIntent, int a2dpVolume) {
|
||||
if (device == null) {
|
||||
@@ -4071,7 +4074,7 @@ public class AudioService extends IAudioService.Stub
|
||||
throw new IllegalArgumentException("Illegal BluetoothProfile state for device "
|
||||
+ " (dis)connection, got " + state);
|
||||
}
|
||||
return mDeviceBroker.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(device, state,
|
||||
mDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(device, state,
|
||||
profile, suppressNoisyIntent, a2dpVolume);
|
||||
}
|
||||
|
||||
@@ -4094,6 +4097,9 @@ public class AudioService extends IAudioService.Stub
|
||||
public int handleBluetoothA2dpActiveDeviceChange(
|
||||
BluetoothDevice device, int state, int profile, boolean suppressNoisyIntent,
|
||||
int a2dpVolume) {
|
||||
// FIXME method was added by @a8439e2 but never used, and now conflicts with async behavior
|
||||
// of handleBluetoothA2dpDeviceConfigChange and
|
||||
// setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
|
||||
if (device == null) {
|
||||
throw new IllegalArgumentException("Illegal null device");
|
||||
}
|
||||
|
||||
@@ -426,7 +426,7 @@ public class BtHelper {
|
||||
final BluetoothDevice btDevice = deviceList.get(0);
|
||||
final @BluetoothProfile.BtProfileState int state =
|
||||
mHearingAid.getConnectionState(btDevice);
|
||||
mDeviceBroker.setBluetoothHearingAidDeviceConnectionState(
|
||||
mDeviceBroker.postBluetoothHearingAidDeviceConnectionState(
|
||||
btDevice, state,
|
||||
/*suppressNoisyIntent*/ false,
|
||||
/*musicDevice*/ android.media.AudioSystem.DEVICE_NONE,
|
||||
|
||||
Reference in New Issue
Block a user