diff options
6 files changed, 154 insertions, 83 deletions
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 15f9b47ede09..669baeadad65 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -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} */ diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 1b82fcc48bf8..02856678879e 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -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, diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 9af57daa259b..451fd66d4327 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -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; diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index 37f0496c0db3..41a3c9859f23 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -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; + } } } } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 6bd412bcd536..91d19def1766 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -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"); } diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java index 58c1882abf6f..04073cb5f45c 100644 --- a/services/core/java/com/android/server/audio/BtHelper.java +++ b/services/core/java/com/android/server/audio/BtHelper.java @@ -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, |