diff options
author | 2021-11-15 00:08:39 +0000 | |
---|---|---|
committer | 2021-11-15 00:08:39 +0000 | |
commit | 5f91507b2b13c0132ad198d22db75c2b51a9a663 (patch) | |
tree | 1a28498c46c70f0671f7025c5f4b384efdd03bec | |
parent | a8c0faa12041eddf2c99e3f8e2bee7056a9af1a8 (diff) | |
parent | 3fe5af489010664de23c9df515e6e2140835be90 (diff) |
Merge "A2DP switch device refactor"
10 files changed, 607 insertions, 966 deletions
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index 9af6c1b340b6..3a35f249d177 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -113,6 +113,7 @@ package android.media { public class AudioManager { method public void adjustStreamVolumeForUid(int, int, int, @NonNull String, int, int, int); method public void adjustSuggestedStreamVolumeForUid(int, int, int, @NonNull String, int, int, int); + method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void handleBluetoothActiveDeviceChanged(@Nullable android.bluetooth.BluetoothDevice, @Nullable android.bluetooth.BluetoothDevice, @NonNull android.media.BtProfileConnectionInfo); method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setA2dpSuspended(boolean); method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setBluetoothHeadsetProperties(@NonNull String, boolean, boolean); method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setHfpEnabled(boolean); @@ -122,6 +123,19 @@ package android.media { field public static final int FLAG_FROM_KEY = 4096; // 0x1000 } + public final class BtProfileConnectionInfo implements android.os.Parcelable { + method @NonNull public static android.media.BtProfileConnectionInfo a2dpInfo(boolean, int); + method public int describeContents(); + method public boolean getIsLeOutput(); + method public int getProfile(); + method public boolean getSuppressNoisyIntent(); + method public int getVolume(); + method @NonNull public static android.media.BtProfileConnectionInfo hearingAidInfo(boolean); + method @NonNull public static android.media.BtProfileConnectionInfo leAudio(boolean, boolean); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.media.BtProfileConnectionInfo> CREATOR; + } + public class MediaMetadataRetriever implements java.lang.AutoCloseable { field public static final int METADATA_KEY_VIDEO_CODEC_MIME_TYPE = 40; // 0x28 } diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index cf7039b9ed5c..c7f56961e498 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -32,7 +32,6 @@ import android.app.NotificationManager; import android.app.PendingIntent; import android.bluetooth.BluetoothCodecConfig; import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothProfile; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; @@ -5796,112 +5795,25 @@ 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. - * (either {@link android.bluetooth.BluetoothProfile.hearingaid} or - * {@link android.bluetooth.BluetoothProfile.HEARING_AID}) - * @param suppressNoisyIntent if true the - * {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent. - * {@hide} - */ - public void setBluetoothHearingAidDeviceConnectionState( - BluetoothDevice device, int state, boolean suppressNoisyIntent, - int musicDevice) { - final IAudioService service = getService(); - try { - service.setBluetoothHearingAidDeviceConnectionState(device, - state, suppressNoisyIntent, musicDevice); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - /** - * Indicate Le Audio output device connection state change and eventually suppress - * the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent. - * @param device Bluetooth device connected/disconnected - * @param state new connection state (BluetoothProfile.STATE_xxx) - * @param suppressNoisyIntent if true the - * {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent. - * {@hide} - */ - public void setBluetoothLeAudioOutDeviceConnectionState(BluetoothDevice device, int state, - boolean suppressNoisyIntent) { - final IAudioService service = getService(); - try { - service.setBluetoothLeAudioOutDeviceConnectionState(device, state, suppressNoisyIntent); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Indicate Le Audio input connection state change. - * @param device Bluetooth device connected/disconnected - * @param state new connection state (BluetoothProfile.STATE_xxx) - * {@hide} - */ - public void setBluetoothLeAudioInDeviceConnectionState(BluetoothDevice device, int state) { - final IAudioService service = getService(); - try { - service.setBluetoothLeAudioInDeviceConnectionState(device, state); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * 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} - * @param profile profile for the A2DP device - * @param a2dpVolume New volume for the connecting device. Does nothing if disconnecting. - * (either {@link android.bluetooth.BluetoothProfile.A2DP} or - * {@link android.bluetooth.BluetoothProfile.A2DP_SINK}) - * @param suppressNoisyIntent if true the - * {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent. - * {@hide} - */ - public void setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( - BluetoothDevice device, int state, - int profile, boolean suppressNoisyIntent, int a2dpVolume) { - final IAudioService service = getService(); - try { - service.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(device, - state, profile, suppressNoisyIntent, a2dpVolume); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * 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. + * Indicate Bluetooth profile connection state change. + * Configuration changes for A2DP are indicated by having the same <code>newDevice</code> and + * <code>previousDevice</code> + * This operation is asynchronous. + * + * @param newDevice Bluetooth device connected or null if there is no new devices + * @param previousDevice Bluetooth device disconnected or null if there is no disconnected + * devices + * @param info contain all info related to the device. {@link BtProfileConnectionInfo} * {@hide} */ - public void handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device) { + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) + public void handleBluetoothActiveDeviceChanged(@Nullable BluetoothDevice newDevice, + @Nullable BluetoothDevice previousDevice, @NonNull BtProfileConnectionInfo info) { final IAudioService service = getService(); try { - service.handleBluetoothA2dpDeviceConfigChange(device); + service.handleBluetoothActiveDeviceChanged(newDevice, previousDevice, info); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/media/java/android/media/BtProfileConnectionInfo.aidl b/media/java/android/media/BtProfileConnectionInfo.aidl new file mode 100644 index 000000000000..047f06be0964 --- /dev/null +++ b/media/java/android/media/BtProfileConnectionInfo.aidl @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +parcelable BtProfileConnectionInfo; + diff --git a/media/java/android/media/BtProfileConnectionInfo.java b/media/java/android/media/BtProfileConnectionInfo.java new file mode 100644 index 000000000000..19ea2de6a434 --- /dev/null +++ b/media/java/android/media/BtProfileConnectionInfo.java @@ -0,0 +1,163 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.media; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.bluetooth.BluetoothProfile; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Contains information about Bluetooth profile connection state changed + * {@hide} + */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public final class BtProfileConnectionInfo implements Parcelable { + /** @hide */ + @IntDef({ + BluetoothProfile.A2DP, + BluetoothProfile.A2DP_SINK, // Can only be set by BtHelper + BluetoothProfile.HEADSET, // Can only be set by BtHelper + BluetoothProfile.HEARING_AID, + BluetoothProfile.LE_AUDIO, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface BtProfile {} + + private final @BtProfile int mProfile; + private final boolean mSupprNoisy; + private final int mVolume; + private final boolean mIsLeOutput; + + private BtProfileConnectionInfo(@BtProfile int profile, boolean suppressNoisyIntent, int volume, + boolean isLeOutput) { + mProfile = profile; + mSupprNoisy = suppressNoisyIntent; + mVolume = volume; + mIsLeOutput = isLeOutput; + } + + /** + * Constructor used by BtHelper when a profile is connected + * {@hide} + */ + public BtProfileConnectionInfo(@BtProfile int profile) { + this(profile, false, -1, false); + } + + public static final @NonNull Parcelable.Creator<BtProfileConnectionInfo> CREATOR = + new Parcelable.Creator<BtProfileConnectionInfo>() { + @Override + public BtProfileConnectionInfo createFromParcel(Parcel source) { + return new BtProfileConnectionInfo(source.readInt(), source.readBoolean(), + source.readInt(), source.readBoolean()); + } + + @Override + public BtProfileConnectionInfo[] newArray(int size) { + return new BtProfileConnectionInfo[size]; + } + }; + + @Override + public void writeToParcel(@NonNull Parcel dest, @WriteFlags int flags) { + dest.writeInt(mProfile); + dest.writeBoolean(mSupprNoisy); + dest.writeInt(mVolume); + dest.writeBoolean(mIsLeOutput); + } + + @Override + public int describeContents() { + return 0; + } + + /** + * Constructor for A2dp info + * + * @param suppressNoisyIntent if true the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} + * intent will not be sent. + * + * @param volume of device -1 to ignore value + */ + public static @NonNull BtProfileConnectionInfo a2dpInfo(boolean suppressNoisyIntent, + int volume) { + return new BtProfileConnectionInfo(BluetoothProfile.A2DP, suppressNoisyIntent, volume, + false); + } + + /** + * Constructor for hearing aid info + * + * @param suppressNoisyIntent if true the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} + * intent will not be sent. + */ + public static @NonNull BtProfileConnectionInfo hearingAidInfo(boolean suppressNoisyIntent) { + return new BtProfileConnectionInfo(BluetoothProfile.HEARING_AID, suppressNoisyIntent, -1, + false); + } + + /** + * constructor for le audio info + * + * @param suppressNoisyIntent if true the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} + * intent will not be sent. + * + * @param isLeOutput if true mean the device is an output device, if false it's an input device + */ + public static @NonNull BtProfileConnectionInfo leAudio(boolean suppressNoisyIntent, + boolean isLeOutput) { + return new BtProfileConnectionInfo(BluetoothProfile.LE_AUDIO, suppressNoisyIntent, -1, + isLeOutput); + } + + /** + * @return The profile connection + */ + public @BtProfile int getProfile() { + return mProfile; + } + + /** + * @return {@code true} if {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be + * sent + */ + public boolean getSuppressNoisyIntent() { + return mSupprNoisy; + } + + /** + * Only for {@link BluetoothProfile.A2DP} profile + * @return the volume of the connection or -1 if the value is ignored + */ + public int getVolume() { + return mVolume; + } + + /** + * Only for {@link BluetoothProfile.LE_AUDIO} profile + * @return {@code true} is the LE device is an output device, {@code false} if it's an input + * device + */ + public boolean getIsLeOutput() { + return mIsLeOutput; + } +} diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index dd44fdf1e8c4..5ff56f9c680d 100755 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -24,6 +24,7 @@ import android.media.AudioFocusInfo; import android.media.AudioPlaybackConfiguration; import android.media.AudioRecordingConfiguration; import android.media.AudioRoutesInfo; +import android.media.BtProfileConnectionInfo; import android.media.IAudioFocusDispatcher; import android.media.IAudioModeDispatcher; import android.media.IAudioRoutesObserver; @@ -207,8 +208,6 @@ interface IAudioService { void setWiredDeviceConnectionState(int type, int state, String address, String name, String caller); - void handleBluetoothA2dpDeviceConfigChange(in BluetoothDevice device); - @UnsupportedAppUsage AudioRoutesInfo startWatchingRoutes(in IAudioRoutesObserver observer); @@ -268,16 +267,8 @@ interface IAudioService { oneway void playerHasOpPlayAudio(in int piid, in boolean hasOpPlayAudio); - void setBluetoothHearingAidDeviceConnectionState(in BluetoothDevice device, - int state, boolean suppressNoisyIntent, int musicDevice); - - void setBluetoothLeAudioOutDeviceConnectionState(in BluetoothDevice device, int state, - boolean suppressNoisyIntent); - - void setBluetoothLeAudioInDeviceConnectionState(in BluetoothDevice device, int state); - - void setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(in BluetoothDevice device, - int state, int profile, boolean suppressNoisyIntent, int a2dpVolume); + void handleBluetoothActiveDeviceChanged(in BluetoothDevice newDevice, + in BluetoothDevice previousDevice, in BtProfileConnectionInfo info); oneway void setFocusRequestResultFromExtPolicy(in AudioFocusInfo afi, int requestResult, in IAudioPolicyCallback pcb); diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index c383f5120407..0b2311bc563a 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -17,12 +17,9 @@ package com.android.server.audio; import android.annotation.NonNull; import android.annotation.Nullable; -import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadset; -import android.bluetooth.BluetoothHearingAid; import android.bluetooth.BluetoothProfile; -import android.bluetooth.BluetoothLeAudio; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; @@ -32,6 +29,7 @@ import android.media.AudioDeviceInfo; import android.media.AudioManager; import android.media.AudioRoutesInfo; import android.media.AudioSystem; +import android.media.BtProfileConnectionInfo; import android.media.IAudioRoutesObserver; import android.media.ICapturePresetDevicesRoleDispatcher; import android.media.ICommunicationDeviceDispatcher; @@ -516,29 +514,82 @@ import java.util.concurrent.atomic.AtomicBoolean; } }; - /*package*/ static final class BtDeviceConnectionInfo { + /*package*/ static final class BtDeviceChangedData { + final @Nullable BluetoothDevice mNewDevice; + final @Nullable BluetoothDevice mPreviousDevice; + final @NonNull BtProfileConnectionInfo mInfo; + final @NonNull String mEventSource; + + BtDeviceChangedData(@Nullable BluetoothDevice newDevice, + @Nullable BluetoothDevice previousDevice, + @NonNull BtProfileConnectionInfo info, @NonNull String eventSource) { + mNewDevice = newDevice; + mPreviousDevice = previousDevice; + mInfo = info; + mEventSource = eventSource; + } + + @Override + public String toString() { + return "BtDeviceChangedData profile=" + BluetoothProfile.getProfileName( + mInfo.getProfile()) + + ", switch device: [" + mPreviousDevice + "] -> [" + mNewDevice + "]"; + } + } + + /*package*/ static final class BtDeviceInfo { final @NonNull BluetoothDevice mDevice; final @AudioService.BtProfileConnectionState int mState; - final int mProfile; + final @AudioService.BtProfile int mProfile; final boolean mSupprNoisy; final int mVolume; + final boolean mIsLeOutput; + final @NonNull String mEventSource; + final @AudioSystem.AudioFormatNativeEnumForBtCodec int mCodec; + final int mAudioSystemDevice; + final int mMusicDevice; - BtDeviceConnectionInfo(@NonNull BluetoothDevice device, - @AudioService.BtProfileConnectionState int state, - int profile, boolean suppressNoisyIntent, int vol) { + BtDeviceInfo(@NonNull BtDeviceChangedData d, @NonNull BluetoothDevice device, int state, + int audioDevice, @AudioSystem.AudioFormatNativeEnumForBtCodec int codec) { mDevice = device; mState = state; + mProfile = d.mInfo.getProfile(); + mSupprNoisy = d.mInfo.getSuppressNoisyIntent(); + mVolume = d.mInfo.getVolume(); + mIsLeOutput = d.mInfo.getIsLeOutput(); + mEventSource = d.mEventSource; + mAudioSystemDevice = audioDevice; + mMusicDevice = AudioSystem.DEVICE_NONE; + mCodec = codec; + } + + // constructor used by AudioDeviceBroker to search similar message + BtDeviceInfo(@NonNull BluetoothDevice device, int profile) { + mDevice = device; mProfile = profile; - mSupprNoisy = suppressNoisyIntent; - mVolume = vol; - } - - BtDeviceConnectionInfo(@NonNull BtDeviceConnectionInfo info) { - mDevice = info.mDevice; - mState = info.mState; - mProfile = info.mProfile; - mSupprNoisy = info.mSupprNoisy; - mVolume = info.mVolume; + mEventSource = ""; + mMusicDevice = AudioSystem.DEVICE_NONE; + mCodec = AudioSystem.AUDIO_FORMAT_DEFAULT; + mAudioSystemDevice = 0; + mState = 0; + mSupprNoisy = false; + mVolume = -1; + mIsLeOutput = false; + } + + // constructor used by AudioDeviceInventory when config change failed + BtDeviceInfo(@NonNull BluetoothDevice device, int profile, int state, int musicDevice, + int audioSystemDevice) { + mDevice = device; + mProfile = profile; + mEventSource = ""; + mMusicDevice = musicDevice; + mCodec = AudioSystem.AUDIO_FORMAT_DEFAULT; + mAudioSystemDevice = audioSystemDevice; + mState = state; + mSupprNoisy = false; + mVolume = -1; + mIsLeOutput = false; } // redefine equality op so we can match messages intended for this device @@ -550,16 +601,52 @@ import java.util.concurrent.atomic.AtomicBoolean; if (this == o) { return true; } - if (o instanceof BtDeviceConnectionInfo) { - return mDevice.equals(((BtDeviceConnectionInfo) o).mDevice); + if (o instanceof BtDeviceInfo) { + return mProfile == ((BtDeviceInfo) o).mProfile + && mDevice.equals(((BtDeviceInfo) o).mDevice); } return false; } + } - @Override - public String toString() { - return "BtDeviceConnectionInfo dev=" + mDevice.toString(); + BtDeviceInfo createBtDeviceInfo(@NonNull BtDeviceChangedData d, @NonNull BluetoothDevice device, + int state) { + int audioDevice; + int codec = AudioSystem.AUDIO_FORMAT_DEFAULT; + switch (d.mInfo.getProfile()) { + case BluetoothProfile.A2DP_SINK: + audioDevice = AudioSystem.DEVICE_IN_BLUETOOTH_A2DP; + break; + case BluetoothProfile.A2DP: + audioDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP; + synchronized (mDeviceStateLock) { + codec = mBtHelper.getA2dpCodec(device); + } + break; + case BluetoothProfile.HEARING_AID: + audioDevice = AudioSystem.DEVICE_OUT_HEARING_AID; + break; + case BluetoothProfile.LE_AUDIO: + if (d.mInfo.getIsLeOutput()) { + audioDevice = AudioSystem.DEVICE_OUT_BLE_HEADSET; + } else { + audioDevice = AudioSystem.DEVICE_IN_BLE_HEADSET; + } + break; + default: throw new IllegalArgumentException("Invalid profile " + d.mInfo.getProfile()); } + return new BtDeviceInfo(d, device, state, audioDevice, codec); + } + + private void btMediaMetricRecord(@NonNull BluetoothDevice device, String state, + @NonNull BtDeviceChangedData data) { + final String name = TextUtils.emptyIfNull(device.getName()); + new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE + MediaMetrics.SEPARATOR + + "queueOnBluetoothActiveDeviceChanged") + .set(MediaMetrics.Property.STATE, state) + .set(MediaMetrics.Property.STATUS, data.mInfo.getProfile()) + .set(MediaMetrics.Property.NAME, name) + .record(); } /** @@ -567,116 +654,37 @@ import java.util.concurrent.atomic.AtomicBoolean; * not just a simple message post * @param info struct with the (dis)connection information */ - /*package*/ void queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( - @NonNull BtDeviceConnectionInfo info) { - final String name = TextUtils.emptyIfNull(info.mDevice.getName()); - new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE + MediaMetrics.SEPARATOR - + "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent") - .set(MediaMetrics.Property.STATE, info.mState == BluetoothProfile.STATE_CONNECTED - ? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED) - .set(MediaMetrics.Property.INDEX, info.mVolume) - .set(MediaMetrics.Property.NAME, name) - .record(); - - // operations of removing and posting messages related to A2DP device state change must be - // mutually exclusive - synchronized (mDeviceStateLock) { - // when receiving a request to change the connection state of a device, this last - // request is the source of truth, so cancel all previous requests that are already in - // the handler - removeScheduledA2dpEvents(info.mDevice); - - sendLMsgNoDelay( - info.mState == BluetoothProfile.STATE_CONNECTED - ? MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION - : MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION, - SENDMSG_QUEUE, info); - } - } - - /** remove all previously scheduled connection and state change events for the given device */ - @GuardedBy("mDeviceStateLock") - private void removeScheduledA2dpEvents(@NonNull BluetoothDevice device) { - mBrokerHandler.removeEqualMessages(MSG_L_A2DP_DEVICE_CONFIG_CHANGE, device); - - final BtDeviceConnectionInfo connectionInfoToRemove = new BtDeviceConnectionInfo(device, - // the next parameters of the constructor will be ignored when finding the message - // to remove as the equality of the message's object is tested on the device itself - // (see BtDeviceConnectionInfo.equals() method override) - BluetoothProfile.STATE_CONNECTED, 0, false, -1); - mBrokerHandler.removeEqualMessages(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION, - connectionInfoToRemove); - mBrokerHandler.removeEqualMessages(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION, - connectionInfoToRemove); - - final BtHelper.BluetoothA2dpDeviceInfo devInfoToRemove = - new BtHelper.BluetoothA2dpDeviceInfo(device); - mBrokerHandler.removeEqualMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED, - devInfoToRemove); - mBrokerHandler.removeEqualMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED, - devInfoToRemove); - mBrokerHandler.removeEqualMessages(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE, - devInfoToRemove); - } - - 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) { - final HearingAidDeviceConnectionInfo info = new HearingAidDeviceConnectionInfo( - device, state, suppressNoisyIntent, musicDevice, eventSource); - sendLMsgNoDelay(MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT, SENDMSG_QUEUE, info); - } - - private static final class LeAudioDeviceConnectionInfo { - final @NonNull BluetoothDevice mDevice; - final @AudioService.BtProfileConnectionState int mState; - final boolean mSupprNoisy; - final @NonNull String mEventSource; - - LeAudioDeviceConnectionInfo(@NonNull BluetoothDevice device, - @AudioService.BtProfileConnectionState int state, - boolean suppressNoisyIntent, @NonNull String eventSource) { - mDevice = device; - mState = state; - mSupprNoisy = suppressNoisyIntent; - mEventSource = eventSource; + /*package*/ void queueOnBluetoothActiveDeviceChanged(@NonNull BtDeviceChangedData data) { + if (data.mInfo.getProfile() == BluetoothProfile.A2DP && data.mPreviousDevice != null + && data.mPreviousDevice.equals(data.mNewDevice)) { + final String name = TextUtils.emptyIfNull(data.mNewDevice.getName()); + new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE + MediaMetrics.SEPARATOR + + "queueOnBluetoothActiveDeviceChanged_update") + .set(MediaMetrics.Property.NAME, name) + .set(MediaMetrics.Property.STATUS, data.mInfo.getProfile()) + .record(); + synchronized (mDeviceStateLock) { + postBluetoothA2dpDeviceConfigChange(data.mNewDevice); + } + } else { + synchronized (mDeviceStateLock) { + if (data.mPreviousDevice != null) { + btMediaMetricRecord(data.mPreviousDevice, MediaMetrics.Value.DISCONNECTED, + data); + sendLMsgNoDelay(MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT, SENDMSG_QUEUE, + createBtDeviceInfo(data, data.mPreviousDevice, + BluetoothProfile.STATE_DISCONNECTED)); + } + if (data.mNewDevice != null) { + btMediaMetricRecord(data.mNewDevice, MediaMetrics.Value.CONNECTED, data); + sendLMsgNoDelay(MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT, SENDMSG_QUEUE, + createBtDeviceInfo(data, data.mNewDevice, + BluetoothProfile.STATE_CONNECTED)); + } + } } } - /*package*/ void postBluetoothLeAudioOutDeviceConnectionState( - @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, - boolean suppressNoisyIntent, @NonNull String eventSource) { - final LeAudioDeviceConnectionInfo info = new LeAudioDeviceConnectionInfo( - device, state, suppressNoisyIntent, eventSource); - sendLMsgNoDelay(MSG_L_LE_AUDIO_DEVICE_OUT_CONNECTION_CHANGE_EXT, SENDMSG_QUEUE, info); - } - - /*package*/ void postBluetoothLeAudioInDeviceConnectionState( - @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, - @NonNull String eventSource) { - final LeAudioDeviceConnectionInfo info = new LeAudioDeviceConnectionInfo( - device, state, false, eventSource); - sendLMsgNoDelay(MSG_L_LE_AUDIO_DEVICE_IN_CONNECTION_CHANGE_EXT, SENDMSG_QUEUE, info); - } - /** * Current Bluetooth SCO audio active state indicated by BtHelper via setBluetoothScoOn(). */ @@ -926,19 +934,8 @@ import java.util.concurrent.atomic.AtomicBoolean; } @GuardedBy("mDeviceStateLock") - /*package*/ void postA2dpSinkConnection(@AudioService.BtProfileConnectionState int state, - @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay) { - sendILMsg(state == BluetoothA2dp.STATE_CONNECTED - ? MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED - : MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED, - SENDMSG_QUEUE, - state, btDeviceInfo, delay); - } - - /*package*/ void postA2dpSourceConnection(@AudioService.BtProfileConnectionState int state, - @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay) { - sendILMsg(MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE, SENDMSG_QUEUE, - state, btDeviceInfo, delay); + /*package*/ void postBluetoothActiveDevice(BtDeviceInfo info, int delay) { + sendLMsg(MSG_L_SET_BT_ACTIVE_DEVICE, SENDMSG_QUEUE, info, delay); } /*package*/ void postSetWiredDeviceConnectionState( @@ -946,72 +943,12 @@ import java.util.concurrent.atomic.AtomicBoolean; sendLMsg(MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE, SENDMSG_QUEUE, connectionState, delay); } - /*package*/ void postSetHearingAidConnectionState( - @AudioService.BtProfileConnectionState int state, - @NonNull BluetoothDevice device, int delay) { - sendILMsg(MSG_IL_SET_HEARING_AID_CONNECTION_STATE, SENDMSG_QUEUE, - state, - device, - delay); - } - - /*package*/ void postSetLeAudioOutConnectionState( - @AudioService.BtProfileConnectionState int state, - @NonNull BluetoothDevice device, int delay) { - sendILMsg(MSG_IL_SET_LE_AUDIO_OUT_CONNECTION_STATE, SENDMSG_QUEUE, - state, - device, - delay); - } - - /*package*/ void postSetLeAudioInConnectionState( - @AudioService.BtProfileConnectionState int state, - @NonNull BluetoothDevice device) { - sendILMsgNoDelay(MSG_IL_SET_LE_AUDIO_IN_CONNECTION_STATE, SENDMSG_QUEUE, - state, - device); - } - - /*package*/ void postDisconnectA2dp() { - sendMsgNoDelay(MSG_DISCONNECT_A2DP, SENDMSG_QUEUE); - } - - /*package*/ void postDisconnectA2dpSink() { - sendMsgNoDelay(MSG_DISCONNECT_A2DP_SINK, SENDMSG_QUEUE); - } - - /*package*/ void postDisconnectHearingAid() { - sendMsgNoDelay(MSG_DISCONNECT_BT_HEARING_AID, SENDMSG_QUEUE); - } - - /*package*/ void postDisconnectLeAudio() { - sendMsgNoDelay(MSG_DISCONNECT_BT_LE_AUDIO, SENDMSG_QUEUE); - } - - /*package*/ void postDisconnectHeadset() { - sendMsgNoDelay(MSG_DISCONNECT_BT_HEADSET, SENDMSG_QUEUE); - } - - /*package*/ void postBtA2dpProfileConnected(BluetoothA2dp a2dpProfile) { - sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP, SENDMSG_QUEUE, a2dpProfile); - } - - /*package*/ void postBtA2dpSinkProfileConnected(BluetoothProfile profile) { - sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK, SENDMSG_QUEUE, profile); - } - - /*package*/ void postBtHeasetProfileConnected(BluetoothHeadset headsetProfile) { - sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET, SENDMSG_QUEUE, headsetProfile); - } - - /*package*/ void postBtHearingAidProfileConnected(BluetoothHearingAid hearingAidProfile) { - sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID, SENDMSG_QUEUE, - hearingAidProfile); + /*package*/ void postBtProfileDisconnected(int profile) { + sendIMsgNoDelay(MSG_I_BT_SERVICE_DISCONNECTED_PROFILE, SENDMSG_QUEUE, profile); } - /*package*/ void postBtLeAudioProfileConnected(BluetoothLeAudio leAudioProfile) { - sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_LE_AUDIO, SENDMSG_QUEUE, - leAudioProfile); + /*package*/ void postBtProfileConnected(int profile, BluetoothProfile proxy) { + sendILMsgNoDelay(MSG_IL_BT_SERVICE_CONNECTED_PROFILE, SENDMSG_QUEUE, profile, proxy); } /*package*/ void postCommunicationRouteClientDied(CommunicationRouteClient client) { @@ -1069,13 +1006,6 @@ import java.util.concurrent.atomic.AtomicBoolean; } } - /*package*/ void postSetA2dpSourceConnectionState(@BluetoothProfile.BtProfileState int state, - @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) { - final int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0; - sendILMsgNoDelay(MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE, SENDMSG_QUEUE, state, - btDeviceInfo); - } - /*package*/ void handleFailureToConnectToBtHeadsetService(int delay) { sendMsg(MSG_BT_HEADSET_CNCT_FAILED, SENDMSG_REPLACE, delay); } @@ -1088,19 +1018,10 @@ import java.util.concurrent.atomic.AtomicBoolean; sendMsgNoDelay(fromA2dp ? MSG_REPORT_NEW_ROUTES_A2DP : MSG_REPORT_NEW_ROUTES, SENDMSG_NOOP); } - /*package*/ void postA2dpActiveDeviceChange( - @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) { - sendLMsgNoDelay(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE, SENDMSG_QUEUE, btDeviceInfo); - } - // must be called synchronized on mConnectedDevices - /*package*/ boolean hasScheduledA2dpSinkConnectionState(BluetoothDevice btDevice) { - final BtHelper.BluetoothA2dpDeviceInfo devInfoToCheck = - new BtHelper.BluetoothA2dpDeviceInfo(btDevice); - return (mBrokerHandler.hasEqualMessages( - MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED, devInfoToCheck) - || mBrokerHandler.hasEqualMessages( - MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED, devInfoToCheck)); + /*package*/ boolean hasScheduledA2dpConnection(BluetoothDevice btDevice) { + final BtDeviceInfo devInfoToCheck = new BtDeviceInfo(btDevice, BluetoothProfile.A2DP); + return mBrokerHandler.hasEqualMessages(MSG_L_SET_BT_ACTIVE_DEVICE, devInfoToCheck); } /*package*/ void setA2dpTimeout(String address, int a2dpCodec, int delayMs) { @@ -1124,12 +1045,6 @@ import java.util.concurrent.atomic.AtomicBoolean; } } - /*package*/ int getA2dpCodec(@NonNull BluetoothDevice device) { - synchronized (mDeviceStateLock) { - return mBtHelper.getA2dpCodec(device); - } - } - /*package*/ void broadcastStickyIntentToCurrentProfileGroup(Intent intent) { mSystemServer.broadcastStickyIntentToCurrentProfileGroup(intent); } @@ -1285,39 +1200,11 @@ import java.util.concurrent.atomic.AtomicBoolean; mDeviceInventory.onReportNewRoutes(); } break; - case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED: - case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED: - synchronized (mDeviceStateLock) { - mDeviceInventory.onSetA2dpSinkConnectionState( - (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1); - } - break; - case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE: - synchronized (mDeviceStateLock) { - mDeviceInventory.onSetA2dpSourceConnectionState( - (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1); - } - break; - case MSG_IL_SET_HEARING_AID_CONNECTION_STATE: + case MSG_L_SET_BT_ACTIVE_DEVICE: synchronized (mDeviceStateLock) { - mDeviceInventory.onSetHearingAidConnectionState( - (BluetoothDevice) msg.obj, msg.arg1, + mDeviceInventory.onSetBtActiveDevice((BtDeviceInfo) msg.obj, mAudioService.getBluetoothContextualVolumeStream()); } - break; - case MSG_IL_SET_LE_AUDIO_OUT_CONNECTION_STATE: - synchronized (mDeviceStateLock) { - mDeviceInventory.onSetLeAudioOutConnectionState( - (BluetoothDevice) msg.obj, msg.arg1, - mAudioService.getBluetoothContextualVolumeStream()); - } - break; - case MSG_IL_SET_LE_AUDIO_IN_CONNECTION_STATE: - synchronized (mDeviceStateLock) { - mDeviceInventory.onSetLeAudioInConnectionState( - (BluetoothDevice) msg.obj, msg.arg1); - } - break; case MSG_BT_HEADSET_CNCT_FAILED: synchronized (mSetModeLock) { synchronized (mDeviceStateLock) { @@ -1332,14 +1219,10 @@ import java.util.concurrent.atomic.AtomicBoolean; } break; case MSG_L_A2DP_DEVICE_CONFIG_CHANGE: - final int a2dpCodec; final BluetoothDevice btDevice = (BluetoothDevice) msg.obj; synchronized (mDeviceStateLock) { - a2dpCodec = mBtHelper.getA2dpCodec(btDevice); - // TODO: name of method being called on AudioDeviceInventory is currently - // misleading (config change vs active device change), to be - // reconciliated once the BT side has been updated. - mDeviceInventory.onBluetoothA2dpActiveDeviceChange( + final int a2dpCodec = mBtHelper.getA2dpCodec(btDevice); + mDeviceInventory.onBluetoothA2dpDeviceConfigChange( new BtHelper.BluetoothA2dpDeviceInfo(btDevice, -1, a2dpCodec), BtHelper.EVENT_DEVICE_CONFIG_CHANGE); } @@ -1392,96 +1275,47 @@ import java.util.concurrent.atomic.AtomicBoolean; mDeviceInventory.onToggleHdmi(); } break; - case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE: - synchronized (mDeviceStateLock) { - mDeviceInventory.onBluetoothA2dpActiveDeviceChange( - (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, - BtHelper.EVENT_ACTIVE_DEVICE_CHANGE); - } - break; - case MSG_DISCONNECT_A2DP: - synchronized (mDeviceStateLock) { - mDeviceInventory.disconnectA2dp(); - } - break; - case MSG_DISCONNECT_A2DP_SINK: - synchronized (mDeviceStateLock) { - mDeviceInventory.disconnectA2dpSink(); - } - break; - case MSG_DISCONNECT_BT_HEARING_AID: - synchronized (mDeviceStateLock) { - mDeviceInventory.disconnectHearingAid(); - } - break; - case MSG_DISCONNECT_BT_HEADSET: - synchronized (mSetModeLock) { + case MSG_I_BT_SERVICE_DISCONNECTED_PROFILE: + if (msg.arg1 != BluetoothProfile.HEADSET) { synchronized (mDeviceStateLock) { - mBtHelper.disconnectHeadset(); + mDeviceInventory.onBtProfileDisconnected(msg.arg1); + } + } else { + synchronized (mSetModeLock) { + synchronized (mDeviceStateLock) { + mBtHelper.disconnectHeadset(); + } } } break; - case MSG_DISCONNECT_BT_LE_AUDIO: - synchronized(mDeviceStateLock) { - mDeviceInventory.disconnectLeAudio(); - } - break; - case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP: - synchronized (mDeviceStateLock) { - mBtHelper.onA2dpProfileConnected((BluetoothA2dp) msg.obj); - } - break; - case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK: - synchronized (mDeviceStateLock) { - mBtHelper.onA2dpSinkProfileConnected((BluetoothProfile) msg.obj); - } - break; - case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID: - synchronized (mDeviceStateLock) { - mBtHelper.onHearingAidProfileConnected((BluetoothHearingAid) msg.obj); - } - break; - - case MSG_L_BT_SERVICE_CONNECTED_PROFILE_LE_AUDIO: - synchronized(mDeviceStateLock) { - mBtHelper.onLeAudioProfileConnected((BluetoothLeAudio) msg.obj); - } - break; - case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET: - synchronized (mSetModeLock) { + case MSG_IL_BT_SERVICE_CONNECTED_PROFILE: + if (msg.arg1 != BluetoothProfile.HEADSET) { synchronized (mDeviceStateLock) { - mBtHelper.onHeadsetProfileConnected((BluetoothHeadset) msg.obj); + mBtHelper.onBtProfileConnected(msg.arg1, (BluetoothProfile) msg.obj); + } + } else { + synchronized (mSetModeLock) { + synchronized (mDeviceStateLock) { + mBtHelper.onHeadsetProfileConnected((BluetoothHeadset) msg.obj); + } } } break; - case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION: - case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION: { - final BtDeviceConnectionInfo info = (BtDeviceConnectionInfo) msg.obj; + case MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT: { + final BtDeviceInfo info = (BtDeviceInfo) msg.obj; + if (info.mDevice == null) break; AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent( - "msg: setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent " + "msg: onBluetoothActiveDeviceChange " + " 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( - "msg: setHearingAidDeviceConnectionState state=" + info.mState - + " addr=" + info.mDevice.getAddress() + + " prof=" + info.mProfile + " supprNoisy=" + info.mSupprNoisy - + " src=" + info.mEventSource)).printLog(TAG)); + + " src=" + info.mEventSource + )).printLog(TAG)); synchronized (mDeviceStateLock) { - mDeviceInventory.setBluetoothHearingAidDeviceConnectionState( - info.mDevice, info.mState, info.mSupprNoisy, info.mMusicDevice); + mDeviceInventory.setBluetoothActiveDevice(info); } } break; case MSG_IL_SAVE_PREF_DEVICES_FOR_STRATEGY: { @@ -1524,31 +1358,6 @@ import java.util.concurrent.atomic.AtomicBoolean; final int capturePreset = msg.arg1; mDeviceInventory.onSaveClearPreferredDevicesForCapturePreset(capturePreset); } break; - case MSG_L_LE_AUDIO_DEVICE_OUT_CONNECTION_CHANGE_EXT: { - final LeAudioDeviceConnectionInfo info = - (LeAudioDeviceConnectionInfo) msg.obj; - AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent( - "setLeAudioDeviceOutConnectionState state=" + info.mState - + " addr=" + info.mDevice.getAddress() - + " supprNoisy=" + info.mSupprNoisy - + " src=" + info.mEventSource)).printLog(TAG)); - synchronized (mDeviceStateLock) { - mDeviceInventory.setBluetoothLeAudioOutDeviceConnectionState( - info.mDevice, info.mState, info.mSupprNoisy); - } - } break; - case MSG_L_LE_AUDIO_DEVICE_IN_CONNECTION_CHANGE_EXT: { - final LeAudioDeviceConnectionInfo info = - (LeAudioDeviceConnectionInfo) msg.obj; - AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent( - "setLeAudioDeviceInConnectionState state=" + info.mState - + " addr=" + info.mDevice.getAddress() - + " src=" + info.mEventSource)).printLog(TAG)); - synchronized (mDeviceStateLock) { - mDeviceInventory.setBluetoothLeAudioInDeviceConnectionState(info.mDevice, - info.mState); - } - } break; default: Log.wtf(TAG, "Invalid message " + msg.what); } @@ -1579,8 +1388,7 @@ import java.util.concurrent.atomic.AtomicBoolean; private static final int MSG_IIL_SET_FORCE_USE = 4; private static final int MSG_IIL_SET_FORCE_BT_A2DP_USE = 5; private static final int MSG_TOGGLE_HDMI = 6; - private static final int MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE = 7; - private static final int MSG_IL_SET_HEARING_AID_CONNECTION_STATE = 8; + private static final int MSG_L_SET_BT_ACTIVE_DEVICE = 7; private static final int MSG_BT_HEADSET_CNCT_FAILED = 9; private static final int MSG_IL_BTA2DP_TIMEOUT = 10; @@ -1593,25 +1401,11 @@ import java.util.concurrent.atomic.AtomicBoolean; private static final int MSG_I_SET_AVRCP_ABSOLUTE_VOLUME = 15; private static final int MSG_I_SET_MODE_OWNER_PID = 16; - // process active A2DP device change, obj is BtHelper.BluetoothA2dpDeviceInfo - private static final int MSG_L_A2DP_ACTIVE_DEVICE_CHANGE = 18; - - private static final int MSG_DISCONNECT_A2DP = 19; - private static final int MSG_DISCONNECT_A2DP_SINK = 20; - private static final int MSG_DISCONNECT_BT_HEARING_AID = 21; - private static final int MSG_DISCONNECT_BT_HEADSET = 22; - private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP = 23; - 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 change of state, obj is BtHelper.BluetoothA2dpDeviceInfo - private static final int MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED = 27; - private static final int MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED = 28; + private static final int MSG_I_BT_SERVICE_DISCONNECTED_PROFILE = 22; + private static final int MSG_IL_BT_SERVICE_CONNECTED_PROFILE = 23; // process external command to (dis)connect an A2DP device, obj is BtDeviceConnectionInfo - private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION = 29; - private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION = 30; + private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT = 29; // process external command to (dis)connect a hearing aid device private static final int MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT = 31; @@ -1630,33 +1424,21 @@ import java.util.concurrent.atomic.AtomicBoolean; private static final int MSG_IL_SET_PREF_DEVICES_FOR_STRATEGY = 40; private static final int MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY = 41; - private static final int MSG_IL_SET_LE_AUDIO_OUT_CONNECTION_STATE = 42; - private static final int MSG_IL_SET_LE_AUDIO_IN_CONNECTION_STATE = 43; - private static final int MSG_L_LE_AUDIO_DEVICE_OUT_CONNECTION_CHANGE_EXT = 44; - private static final int MSG_L_LE_AUDIO_DEVICE_IN_CONNECTION_CHANGE_EXT = 45; + private static final int MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT = 45; + // // process set volume for Le Audio, obj is BleVolumeInfo private static final int MSG_II_SET_LE_AUDIO_OUT_VOLUME = 46; - private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_LE_AUDIO = 47; - private static final int MSG_DISCONNECT_BT_LE_AUDIO = 48; - private static boolean isMessageHandledUnderWakelock(int msgId) { switch(msgId) { case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE: - case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED: - case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED: - case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE: - case MSG_IL_SET_HEARING_AID_CONNECTION_STATE: + case MSG_L_SET_BT_ACTIVE_DEVICE: case MSG_IL_BTA2DP_TIMEOUT: 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_CONNECTION: - case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION: + case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT: case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT: case MSG_CHECK_MUTE_MUSIC: - case MSG_L_LE_AUDIO_DEVICE_OUT_CONNECTION_CHANGE_EXT: - case MSG_L_LE_AUDIO_DEVICE_IN_CONNECTION_CHANGE_EXT: return true; default: return false; @@ -1739,14 +1521,10 @@ import java.util.concurrent.atomic.AtomicBoolean; long time = SystemClock.uptimeMillis() + delay; switch (msg) { - case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE: - case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED: - case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED: - case MSG_IL_SET_HEARING_AID_CONNECTION_STATE: + case MSG_L_SET_BT_ACTIVE_DEVICE: case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE: case MSG_IL_BTA2DP_TIMEOUT: case MSG_L_A2DP_DEVICE_CONFIG_CHANGE: - case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE: if (sLastDeviceConnectMsgTime >= time) { // add a little delay to make sure messages are ordered as expected time = sLastDeviceConnectMsgTime + 30; @@ -1765,14 +1543,9 @@ import java.util.concurrent.atomic.AtomicBoolean; private static final Set<Integer> MESSAGES_MUTE_MUSIC; static { MESSAGES_MUTE_MUSIC = new HashSet<>(); - MESSAGES_MUTE_MUSIC.add(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED); - MESSAGES_MUTE_MUSIC.add(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED); - MESSAGES_MUTE_MUSIC.add(MSG_IL_SET_LE_AUDIO_OUT_CONNECTION_STATE); + MESSAGES_MUTE_MUSIC.add(MSG_L_SET_BT_ACTIVE_DEVICE); MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONFIG_CHANGE); - MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE); - MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION); - MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION); - MESSAGES_MUTE_MUSIC.add(MSG_L_LE_AUDIO_DEVICE_OUT_CONNECTION_CHANGE_EXT); + MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT); MESSAGES_MUTE_MUSIC.add(MSG_IIL_SET_FORCE_BT_A2DP_USE); MESSAGES_MUTE_MUSIC.add(MSG_REPORT_NEW_ROUTES_A2DP); } diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index 6c3c736aeb93..0a114b924063 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -16,11 +16,8 @@ package com.android.server.audio; import android.annotation.NonNull; -import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothHearingAid; -import android.bluetooth.BluetoothLeAudio; import android.bluetooth.BluetoothProfile; import android.content.Intent; import android.media.AudioDeviceAttributes; @@ -286,186 +283,102 @@ public class AudioDeviceInventory { } } - // only public for mocking/spying @GuardedBy("AudioDeviceBroker.mDeviceStateLock") - @VisibleForTesting - public void onSetA2dpSinkConnectionState(@NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo, - @AudioService.BtProfileConnectionState int state) { - final BluetoothDevice btDevice = btInfo.getBtDevice(); - int a2dpVolume = btInfo.getVolume(); - if (AudioService.DEBUG_DEVICES) { - Log.d(TAG, "onSetA2dpSinkConnectionState btDevice=" + btDevice + " state=" - + state + " vol=" + a2dpVolume); - } - String address = btDevice.getAddress(); - if (address == null) { - address = ""; - } - if (!BluetoothAdapter.checkBluetoothAddress(address)) { - address = ""; - } - - final @AudioSystem.AudioFormatNativeEnumForBtCodec int a2dpCodec = btInfo.getCodec(); - - AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent( - "A2DP sink connected: device addr=" + address + " state=" + state - + " codec=" + AudioSystem.audioFormatToString(a2dpCodec) - + " vol=" + a2dpVolume)); - - new MediaMetrics.Item(mMetricsId + "a2dp") - .set(MediaMetrics.Property.ADDRESS, address) - .set(MediaMetrics.Property.ENCODING, AudioSystem.audioFormatToString(a2dpCodec)) - .set(MediaMetrics.Property.EVENT, "onSetA2dpSinkConnectionState") - .set(MediaMetrics.Property.INDEX, a2dpVolume) - .set(MediaMetrics.Property.STATE, - state == BluetoothProfile.STATE_CONNECTED - ? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED) - .record(); - - synchronized (mDevicesLock) { - final String key = DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, - btDevice.getAddress()); - final DeviceInfo di = mConnectedDevices.get(key); - boolean isConnected = di != null; - - if (isConnected) { - if (state == BluetoothProfile.STATE_CONNECTED) { - // device is already connected, but we are receiving a connection again, - // it could be for a codec change - if (a2dpCodec != di.mDeviceCodecFormat) { - mDeviceBroker.postBluetoothA2dpDeviceConfigChange(btDevice); - } - } else { - makeA2dpDeviceUnavailableNow(address, di.mDeviceCodecFormat); - } - } else if (state == BluetoothProfile.STATE_CONNECTED) { - // device is not already connected - if (a2dpVolume != -1) { - mDeviceBroker.postSetVolumeIndexOnDevice(AudioSystem.STREAM_MUSIC, - // convert index to internal representation in VolumeStreamState - a2dpVolume * 10, - AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, "onSetA2dpSinkConnectionState"); - } - makeA2dpDeviceAvailable(address, BtHelper.getName(btDevice), - "onSetA2dpSinkConnectionState", a2dpCodec); - } - } - } - - /*package*/ void onSetA2dpSourceConnectionState( - @NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo, int state) { - final BluetoothDevice btDevice = btInfo.getBtDevice(); + void onSetBtActiveDevice(@NonNull AudioDeviceBroker.BtDeviceInfo btInfo, int streamType) { if (AudioService.DEBUG_DEVICES) { - Log.d(TAG, "onSetA2dpSourceConnectionState btDevice=" + btDevice + " state=" - + state); + Log.d(TAG, "onSetBtActiveDevice" + + " btDevice=" + btInfo.mDevice + + " profile=" + BluetoothProfile.getProfileName(btInfo.mProfile) + + " state=" + BluetoothProfile.getConnectionStateName(btInfo.mState)); } - String address = btDevice.getAddress(); + String address = btInfo.mDevice.getAddress(); if (!BluetoothAdapter.checkBluetoothAddress(address)) { address = ""; } - synchronized (mDevicesLock) { - final String key = DeviceInfo.makeDeviceListKey( - AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address); - final DeviceInfo di = mConnectedDevices.get(key); - boolean isConnected = di != null; - - new MediaMetrics.Item(mMetricsId + "onSetA2dpSourceConnectionState") - .set(MediaMetrics.Property.ADDRESS, address) - .set(MediaMetrics.Property.DEVICE, - AudioSystem.getDeviceName(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP)) - .set(MediaMetrics.Property.STATE, - state == BluetoothProfile.STATE_CONNECTED - ? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED) - .record(); - - if (isConnected && state != BluetoothProfile.STATE_CONNECTED) { - makeA2dpSrcUnavailable(address); - } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) { - makeA2dpSrcAvailable(address); - } - } - } - - /*package*/ void onSetHearingAidConnectionState(BluetoothDevice btDevice, - @AudioService.BtProfileConnectionState int state, int streamType) { - String address = btDevice.getAddress(); - if (!BluetoothAdapter.checkBluetoothAddress(address)) { - address = ""; - } - AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent( - "onSetHearingAidConnectionState addr=" + address)); + AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent("BT connected:" + + " addr=" + address + + " profile=" + btInfo.mProfile + + " state=" + btInfo.mState + + " codec=" + AudioSystem.audioFormatToString(btInfo.mCodec))); - new MediaMetrics.Item(mMetricsId + "onSetHearingAidConnectionState") - .set(MediaMetrics.Property.ADDRESS, address) + new MediaMetrics.Item(mMetricsId + "onSetBtActiveDevice") + .set(MediaMetrics.Property.STATUS, btInfo.mProfile) .set(MediaMetrics.Property.DEVICE, - AudioSystem.getDeviceName(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP)) - .set(MediaMetrics.Property.STATE, - state == BluetoothProfile.STATE_CONNECTED - ? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED) + AudioSystem.getDeviceName(btInfo.mAudioSystemDevice)) + .set(MediaMetrics.Property.ADDRESS, address) + .set(MediaMetrics.Property.ENCODING, + AudioSystem.audioFormatToString(btInfo.mCodec)) + .set(MediaMetrics.Property.EVENT, "onSetBtActiveDevice") .set(MediaMetrics.Property.STREAM_TYPE, AudioSystem.streamToString(streamType)) + .set(MediaMetrics.Property.STATE, + btInfo.mState == BluetoothProfile.STATE_CONNECTED + ? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED) .record(); synchronized (mDevicesLock) { - final String key = DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, - btDevice.getAddress()); + final String key = DeviceInfo.makeDeviceListKey(btInfo.mAudioSystemDevice, address); final DeviceInfo di = mConnectedDevices.get(key); - boolean isConnected = di != null; - if (isConnected && state != BluetoothProfile.STATE_CONNECTED) { - makeHearingAidDeviceUnavailable(address); - } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) { - makeHearingAidDeviceAvailable(address, BtHelper.getName(btDevice), streamType, - "onSetHearingAidConnectionState"); - } - } - } + final boolean isConnected = di != null; - /*package*/ void onSetLeAudioConnectionState(BluetoothDevice btDevice, - @AudioService.BtProfileConnectionState int state, int streamType, int device) { - String address = btDevice.getAddress(); - if (!BluetoothAdapter.checkBluetoothAddress(address)) { - address = ""; - } - AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent( - "onSetLeAudioConnectionState addr=" + address)); + final boolean switchToUnavailable = isConnected + && btInfo.mState != BluetoothProfile.STATE_CONNECTED; + final boolean switchToAvailable = !isConnected + && btInfo.mState == BluetoothProfile.STATE_CONNECTED; - synchronized (mDevicesLock) { - DeviceInfo di = null; - boolean isConnected = false; - - String key = DeviceInfo.makeDeviceListKey(device, btDevice.getAddress()); - di = mConnectedDevices.get(key); - isConnected = di != null; - - if (isConnected && state != BluetoothProfile.STATE_CONNECTED) { - makeLeAudioDeviceUnavailable(address, device); - } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) { - makeLeAudioDeviceAvailable(address, BtHelper.getName(btDevice), streamType, - device, "onSetLeAudioConnectionState"); + switch (btInfo.mProfile) { + case BluetoothProfile.A2DP_SINK: + if (switchToUnavailable) { + makeA2dpSrcUnavailable(address); + } else if (switchToAvailable) { + makeA2dpSrcAvailable(address); + } + break; + case BluetoothProfile.A2DP: + if (switchToUnavailable) { + makeA2dpDeviceUnavailableNow(address, di.mDeviceCodecFormat); + } else if (switchToAvailable) { + // device is not already connected + if (btInfo.mVolume != -1) { + mDeviceBroker.postSetVolumeIndexOnDevice(AudioSystem.STREAM_MUSIC, + // convert index to internal representation in VolumeStreamState + btInfo.mVolume * 10, btInfo.mAudioSystemDevice, + "onSetBtActiveDevice"); + } + makeA2dpDeviceAvailable(address, BtHelper.getName(btInfo.mDevice), + "onSetBtActiveDevice", btInfo.mCodec); + } + break; + case BluetoothProfile.HEARING_AID: + if (switchToUnavailable) { + makeHearingAidDeviceUnavailable(address); + } else if (switchToAvailable) { + makeHearingAidDeviceAvailable(address, BtHelper.getName(btInfo.mDevice), + streamType, "onSetBtActiveDevice"); + } + break; + case BluetoothProfile.LE_AUDIO: + if (switchToUnavailable) { + makeLeAudioDeviceUnavailable(address, btInfo.mAudioSystemDevice); + } else if (switchToAvailable) { + makeLeAudioDeviceAvailable(address, BtHelper.getName(btInfo.mDevice), + streamType, btInfo.mAudioSystemDevice, "onSetBtActiveDevice"); + } + break; + default: throw new IllegalArgumentException("Invalid profile " + + BluetoothProfile.getProfileName(btInfo.mProfile)); } } } - /*package*/ void onSetLeAudioOutConnectionState(BluetoothDevice btDevice, - @AudioService.BtProfileConnectionState int state, int streamType) { - // TODO: b/198610537 clarify DEVICE_OUT_BLE_HEADSET vs DEVICE_OUT_BLE_SPEAKER criteria - onSetLeAudioConnectionState(btDevice, state, streamType, - AudioSystem.DEVICE_OUT_BLE_HEADSET); - } - - /*package*/ void onSetLeAudioInConnectionState(BluetoothDevice btDevice, - @AudioService.BtProfileConnectionState int state) { - onSetLeAudioConnectionState(btDevice, state, AudioSystem.STREAM_DEFAULT, - AudioSystem.DEVICE_IN_BLE_HEADSET); - } @GuardedBy("AudioDeviceBroker.mDeviceStateLock") - /*package*/ void onBluetoothA2dpActiveDeviceChange( + /*package*/ void onBluetoothA2dpDeviceConfigChange( @NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo, int event) { MediaMetrics.Item mmi = new MediaMetrics.Item(mMetricsId - + "onBluetoothA2dpActiveDeviceChange") + + "onBluetoothA2dpDeviceConfigChange") .set(MediaMetrics.Property.EVENT, BtHelper.a2dpDeviceEventToString(event)); final BluetoothDevice btDevice = btInfo.getBtDevice(); @@ -474,7 +387,7 @@ public class AudioDeviceInventory { return; } if (AudioService.DEBUG_DEVICES) { - Log.d(TAG, "onBluetoothA2dpActiveDeviceChange btDevice=" + btDevice); + Log.d(TAG, "onBluetoothA2dpDeviceConfigChange btDevice=" + btDevice); } int a2dpVolume = btInfo.getVolume(); @AudioSystem.AudioFormatNativeEnumForBtCodec final int a2dpCodec = btInfo.getCodec(); @@ -484,11 +397,11 @@ public class AudioDeviceInventory { address = ""; } AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent( - "onBluetoothA2dpActiveDeviceChange addr=" + address + "onBluetoothA2dpDeviceConfigChange addr=" + address + " event=" + BtHelper.a2dpDeviceEventToString(event))); synchronized (mDevicesLock) { - if (mDeviceBroker.hasScheduledA2dpSinkConnectionState(btDevice)) { + if (mDeviceBroker.hasScheduledA2dpConnection(btDevice)) { AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent( "A2dp config change ignored (scheduled connection change)") .printLog(TAG)); @@ -500,7 +413,7 @@ public class AudioDeviceInventory { AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address); final DeviceInfo di = mConnectedDevices.get(key); if (di == null) { - Log.e(TAG, "invalid null DeviceInfo in onBluetoothA2dpActiveDeviceChange"); + Log.e(TAG, "invalid null DeviceInfo in onBluetoothA2dpDeviceConfigChange"); mmi.set(MediaMetrics.Property.EARLY_RETURN, "null DeviceInfo").record(); return; } @@ -518,7 +431,7 @@ public class AudioDeviceInventory { // convert index to internal representation in VolumeStreamState a2dpVolume * 10, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, - "onBluetoothA2dpActiveDeviceChange"); + "onBluetoothA2dpDeviceConfigChange"); } } else if (event == BtHelper.EVENT_DEVICE_CONFIG_CHANGE) { if (di.mDeviceCodecFormat != a2dpCodec) { @@ -539,10 +452,9 @@ public class AudioDeviceInventory { int musicDevice = mDeviceBroker.getDeviceForStream(AudioSystem.STREAM_MUSIC); // force A2DP device disconnection in case of error so that AudioService state is // consistent with audio policy manager state - setBluetoothA2dpDeviceConnectionState( - btDevice, BluetoothA2dp.STATE_DISCONNECTED, BluetoothProfile.A2DP, - false /* suppressNoisyIntent */, musicDevice, - -1 /* a2dpVolume */); + setBluetoothActiveDevice(new AudioDeviceBroker.BtDeviceInfo(btDevice, + BluetoothProfile.A2DP, BluetoothProfile.STATE_DISCONNECTED, + musicDevice, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)); } else { AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent( "APM handleDeviceConfigChange success for A2DP device addr=" + address @@ -828,7 +740,7 @@ public class AudioDeviceInventory { } - /*package*/ void disconnectA2dp() { + private void disconnectA2dp() { synchronized (mDevicesLock) { final ArraySet<String> toRemove = new ArraySet<>(); // Disconnect ALL DEVICE_OUT_BLUETOOTH_A2DP devices @@ -850,7 +762,7 @@ public class AudioDeviceInventory { } } - /*package*/ void disconnectA2dpSink() { + private void disconnectA2dpSink() { synchronized (mDevicesLock) { final ArraySet<String> toRemove = new ArraySet<>(); // Disconnect ALL DEVICE_IN_BLUETOOTH_A2DP devices @@ -865,7 +777,7 @@ public class AudioDeviceInventory { } } - /*package*/ void disconnectHearingAid() { + private void disconnectHearingAid() { synchronized (mDevicesLock) { final ArraySet<String> toRemove = new ArraySet<>(); // Disconnect ALL DEVICE_OUT_HEARING_AID devices @@ -887,6 +799,28 @@ public class AudioDeviceInventory { } } + /*package*/ synchronized void onBtProfileDisconnected(int profile) { + switch (profile) { + case BluetoothProfile.A2DP: + disconnectA2dp(); + break; + case BluetoothProfile.A2DP_SINK: + disconnectA2dpSink(); + break; + case BluetoothProfile.HEARING_AID: + disconnectHearingAid(); + break; + case BluetoothProfile.LE_AUDIO: + disconnectLeAudio(); + break; + default: + // Not a valid profile to disconnect + Log.e(TAG, "onBtProfileDisconnected: Not a valid profile to disconnect " + + BluetoothProfile.getProfileName(profile)); + break; + } + } + /*package*/ void disconnectLeAudio() { synchronized (mDevicesLock) { final ArraySet<String> toRemove = new ArraySet<>(); @@ -934,46 +868,39 @@ public class AudioDeviceInventory { // only public for mocking/spying @GuardedBy("AudioDeviceBroker.mDeviceStateLock") @VisibleForTesting - public void setBluetoothA2dpDeviceConnectionState( - @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, - int profile, boolean suppressNoisyIntent, int musicDevice, int a2dpVolume) { + public int setBluetoothActiveDevice(@NonNull AudioDeviceBroker.BtDeviceInfo info) { int delay; - if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) { - throw new IllegalArgumentException("invalid profile " + profile); - } synchronized (mDevicesLock) { - if (profile == BluetoothProfile.A2DP && !suppressNoisyIntent) { + if (!info.mSupprNoisy + && ((info.mProfile == BluetoothProfile.LE_AUDIO && info.mIsLeOutput) + || info.mProfile == BluetoothProfile.HEARING_AID + || info.mProfile == BluetoothProfile.A2DP)) { @AudioService.ConnectionState int asState = - (state == BluetoothA2dp.STATE_CONNECTED) + (info.mState == BluetoothProfile.STATE_CONNECTED) ? AudioService.CONNECTION_STATE_CONNECTED : AudioService.CONNECTION_STATE_DISCONNECTED; - delay = checkSendBecomingNoisyIntentInt(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, - asState, musicDevice); + delay = checkSendBecomingNoisyIntentInt(info.mAudioSystemDevice, asState, + info.mMusicDevice); } else { delay = 0; } - final int a2dpCodec = mDeviceBroker.getA2dpCodec(device); - if (AudioService.DEBUG_DEVICES) { - Log.i(TAG, "setBluetoothA2dpDeviceConnectionState device: " + device - + " state: " + state + " delay(ms): " + delay - + " codec:" + Integer.toHexString(a2dpCodec) - + " suppressNoisyIntent: " + suppressNoisyIntent); + Log.i(TAG, "setBluetoothActiveDevice device: " + info.mDevice + + " profile: " + BluetoothProfile.getProfileName(info.mProfile) + + " state: " + BluetoothProfile.getConnectionStateName(info.mState) + + " delay(ms): " + delay + + " codec:" + Integer.toHexString(info.mCodec) + + " suppressNoisyIntent: " + info.mSupprNoisy); } - - final BtHelper.BluetoothA2dpDeviceInfo a2dpDeviceInfo = - new BtHelper.BluetoothA2dpDeviceInfo(device, a2dpVolume, a2dpCodec); - if (profile == BluetoothProfile.A2DP) { - mDeviceBroker.postA2dpSinkConnection(state, - a2dpDeviceInfo, - delay); - } else { //profile == BluetoothProfile.A2DP_SINK - mDeviceBroker.postA2dpSourceConnection(state, - a2dpDeviceInfo, - delay); + mDeviceBroker.postBluetoothActiveDevice(info, delay); + if (info.mProfile == BluetoothProfile.HEARING_AID + && info.mState == BluetoothProfile.STATE_CONNECTED) { + mDeviceBroker.setForceUse_Async(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_NONE, + "HEARING_AID set to CONNECTED"); } } + return delay; } /*package*/ int setWiredDeviceConnectionState(int type, @AudioService.ConnectionState int state, @@ -987,50 +914,6 @@ public class AudioDeviceInventory { } } - /*package*/ int setBluetoothHearingAidDeviceConnectionState( - @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, - boolean suppressNoisyIntent, int musicDevice) { - int delay; - synchronized (mDevicesLock) { - if (!suppressNoisyIntent) { - int intState = (state == BluetoothHearingAid.STATE_CONNECTED) ? 1 : 0; - delay = checkSendBecomingNoisyIntentInt(AudioSystem.DEVICE_OUT_HEARING_AID, - intState, musicDevice); - } else { - delay = 0; - } - mDeviceBroker.postSetHearingAidConnectionState(state, device, delay); - if (state == BluetoothHearingAid.STATE_CONNECTED) { - mDeviceBroker.setForceUse_Async(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_NONE, - "HEARING_AID set to CONNECTED"); - } - return delay; - } - } - - /*package*/ int setBluetoothLeAudioOutDeviceConnectionState( - @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, - boolean suppressNoisyIntent) { - synchronized (mDevicesLock) { - /* Active device become null and it's previous device is not connected anymore */ - int delay = 0; - if (!suppressNoisyIntent) { - int intState = (state == BluetoothLeAudio.STATE_CONNECTED) ? 1 : 0; - delay = checkSendBecomingNoisyIntentInt(AudioSystem.DEVICE_OUT_BLE_HEADSET, - intState, AudioSystem.DEVICE_NONE); - } - mDeviceBroker.postSetLeAudioOutConnectionState(state, device, delay); - return delay; - } - } - - /*package*/ void setBluetoothLeAudioInDeviceConnectionState( - @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state) { - synchronized (mDevicesLock) { - mDeviceBroker.postSetLeAudioInConnectionState(state, device); - } - } - //------------------------------------------------------------------- // Internal utilities diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index d75f21c4ef85..51784bbce2e0 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -83,6 +83,7 @@ import android.media.AudioPlaybackConfiguration; import android.media.AudioRecordingConfiguration; import android.media.AudioRoutesInfo; import android.media.AudioSystem; +import android.media.BtProfileConnectionInfo; import android.media.IAudioFocusDispatcher; import android.media.IAudioModeDispatcher; import android.media.IAudioRoutesObserver; @@ -309,8 +310,8 @@ public class AudioService extends IAudioService.Stub private static final int MSG_UPDATE_A11Y_SERVICE_UIDS = 35; private static final int MSG_UPDATE_AUDIO_MODE = 36; private static final int MSG_RECORDING_CONFIG_CHANGE = 37; - private static final int MSG_SET_A2DP_DEV_CONNECTION_STATE = 38; - private static final int MSG_A2DP_DEV_CONFIG_CHANGE = 39; + private static final int MSG_BT_DEV_CHANGED = 38; + private static final int MSG_DISPATCH_AUDIO_MODE = 40; // start of messages handled under wakelock @@ -6266,77 +6267,44 @@ public class AudioService extends IAudioService.Stub public @interface BtProfileConnectionState {} /** - * See AudioManager.setBluetoothHearingAidDeviceConnectionState() - */ - public void setBluetoothHearingAidDeviceConnectionState( - @NonNull BluetoothDevice device, @BtProfileConnectionState int state, - boolean suppressNoisyIntent, int musicDevice) - { - if (device == null) { - throw new IllegalArgumentException("Illegal null device"); - } - if (state != BluetoothProfile.STATE_CONNECTED - && state != BluetoothProfile.STATE_DISCONNECTED) { - throw new IllegalArgumentException("Illegal BluetoothProfile state for device " - + " (dis)connection, got " + state); - } - mDeviceBroker.postBluetoothHearingAidDeviceConnectionState( - device, state, suppressNoisyIntent, musicDevice, "AudioService"); - } - - private void setBluetoothLeAudioDeviceConnectionState(@NonNull BluetoothDevice device, - @BtProfileConnectionState int state) { - if (device == null) { - throw new IllegalArgumentException("Illegal null device"); - } - if (state != BluetoothProfile.STATE_CONNECTED - && state != BluetoothProfile.STATE_DISCONNECTED) { - throw new IllegalArgumentException("Illegal BluetoothProfile state for device " - + " (dis)connection, got " + state); - } - } - - /** - * See AudioManager.setBluetoothLeAudioOutDeviceConnectionState() + * @hide + * The profiles that can be used with AudioService.handleBluetoothActiveDeviceChanged() */ - public void setBluetoothLeAudioOutDeviceConnectionState( - @NonNull BluetoothDevice device, @BtProfileConnectionState int state, - boolean suppressNoisyIntent) { - setBluetoothLeAudioDeviceConnectionState(device, state); - mDeviceBroker.postBluetoothLeAudioOutDeviceConnectionState(device, state, - suppressNoisyIntent, "AudioService"); - } + @IntDef({ + BluetoothProfile.HEARING_AID, + BluetoothProfile.A2DP, + BluetoothProfile.A2DP_SINK, + BluetoothProfile.LE_AUDIO, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface BtProfile {} - /** - * See AudioManager.setBluetoothLeAudioInDeviceConnectionState() - */ - public void setBluetoothLeAudioInDeviceConnectionState( - @NonNull BluetoothDevice device, @BtProfileConnectionState int state) { - setBluetoothLeAudioDeviceConnectionState(device, state); - mDeviceBroker.postBluetoothLeAudioInDeviceConnectionState(device, state, "AudioService"); - } /** - * See AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent() + * See AudioManager.handleBluetoothActiveDeviceChanged(...) */ - public void setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( - @NonNull BluetoothDevice device, @BtProfileConnectionState int state, - int profile, boolean suppressNoisyIntent, int a2dpVolume) { - if (device == null) { - throw new IllegalArgumentException("Illegal null device"); + public void handleBluetoothActiveDeviceChanged(BluetoothDevice newDevice, + BluetoothDevice previousDevice, @NonNull BtProfileConnectionInfo info) { + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.BLUETOOTH_STACK) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Bluetooth is the only caller allowed"); } - if (state != BluetoothProfile.STATE_CONNECTED - && state != BluetoothProfile.STATE_DISCONNECTED) { - throw new IllegalArgumentException("Illegal BluetoothProfile state for device " - + " (dis)connection, got " + state); + if (info == null) { + throw new IllegalArgumentException("Illegal null BtProfileConnectionInfo for device " + + previousDevice + " -> " + newDevice); } - - AudioDeviceBroker.BtDeviceConnectionInfo info = - new AudioDeviceBroker.BtDeviceConnectionInfo(device, state, - profile, suppressNoisyIntent, a2dpVolume); - sendMsg(mAudioHandler, MSG_SET_A2DP_DEV_CONNECTION_STATE, SENDMSG_QUEUE, - 0 /*arg1*/, 0 /*arg2*/, - /*obj*/ info, 0 /*delay*/); + final int profile = info.getProfile(); + if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK + && profile != BluetoothProfile.LE_AUDIO + && profile != BluetoothProfile.HEARING_AID) { + throw new IllegalArgumentException("Illegal BluetoothProfile profile for device " + + previousDevice + " -> " + newDevice + ". Got: " + profile); + } + AudioDeviceBroker.BtDeviceChangedData data = + new AudioDeviceBroker.BtDeviceChangedData(newDevice, previousDevice, info, + "AudioService"); + sendMsg(mAudioHandler, MSG_BT_DEV_CHANGED, SENDMSG_QUEUE, 0, 0, + /*obj*/ data, /*delay*/ 0); } /** only public for mocking/spying, do not call outside of AudioService */ @@ -6345,19 +6313,6 @@ public class AudioService extends IAudioService.Stub mStreamStates[AudioSystem.STREAM_MUSIC].muteInternally(mute); } - /** - * See AudioManager.handleBluetoothA2dpDeviceConfigChange() - * @param device - */ - public void handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device) - { - if (device == null) { - throw new IllegalArgumentException("Illegal null device"); - } - sendMsg(mAudioHandler, MSG_A2DP_DEV_CONFIG_CHANGE, SENDMSG_QUEUE, 0, 0, - /*obj*/ device, /*delay*/ 0); - } - private static final Set<Integer> DEVICE_MEDIA_UNMUTED_ON_PLUG_SET; static { DEVICE_MEDIA_UNMUTED_ON_PLUG_SET = new HashSet<>(); @@ -7709,13 +7664,9 @@ public class AudioService extends IAudioService.Stub } break; - case MSG_SET_A2DP_DEV_CONNECTION_STATE: - mDeviceBroker.queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( - (AudioDeviceBroker.BtDeviceConnectionInfo) msg.obj); - break; - - case MSG_A2DP_DEV_CONFIG_CHANGE: - mDeviceBroker.postBluetoothA2dpDeviceConfigChange((BluetoothDevice) msg.obj); + case MSG_BT_DEV_CHANGED: + mDeviceBroker.queueOnBluetoothActiveDeviceChanged( + (AudioDeviceBroker.BtDeviceChangedData) msg.obj); break; case MSG_DISPATCH_AUDIO_MODE: diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java index c924fde23f9d..9273a5d5cf9c 100644 --- a/services/core/java/com/android/server/audio/BtHelper.java +++ b/services/core/java/com/android/server/audio/BtHelper.java @@ -31,6 +31,7 @@ import android.content.Intent; import android.media.AudioDeviceAttributes; import android.media.AudioManager; import android.media.AudioSystem; +import android.media.BtProfileConnectionInfo; import android.os.Binder; import android.os.UserHandle; import android.provider.Settings; @@ -451,11 +452,11 @@ public class BtHelper { } /*package*/ synchronized void disconnectAllBluetoothProfiles() { - mDeviceBroker.postDisconnectA2dp(); - mDeviceBroker.postDisconnectA2dpSink(); - mDeviceBroker.postDisconnectHeadset(); - mDeviceBroker.postDisconnectHearingAid(); - mDeviceBroker.postDisconnectLeAudio(); + mDeviceBroker.postBtProfileDisconnected(BluetoothProfile.A2DP); + mDeviceBroker.postBtProfileDisconnected(BluetoothProfile.A2DP_SINK); + mDeviceBroker.postBtProfileDisconnected(BluetoothProfile.HEADSET); + mDeviceBroker.postBtProfileDisconnected(BluetoothProfile.HEARING_AID); + mDeviceBroker.postBtProfileDisconnected(BluetoothProfile.LE_AUDIO); } // @GuardedBy("AudioDeviceBroker.mSetModeLock") @@ -474,63 +475,32 @@ public class BtHelper { mBluetoothHeadset = null; } - /*package*/ synchronized void onA2dpProfileConnected(BluetoothA2dp a2dp) { - mA2dp = a2dp; - final List<BluetoothDevice> deviceList = mA2dp.getConnectedDevices(); - if (deviceList.isEmpty()) { + /*package*/ synchronized void onBtProfileConnected(int profile, BluetoothProfile proxy) { + if (profile == BluetoothProfile.HEADSET) { + onHeadsetProfileConnected((BluetoothHeadset) proxy); return; } - final BluetoothDevice btDevice = deviceList.get(0); - // the device is guaranteed CONNECTED - mDeviceBroker.queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( - new AudioDeviceBroker.BtDeviceConnectionInfo(btDevice, - BluetoothA2dp.STATE_CONNECTED, BluetoothProfile.A2DP_SINK, - true, -1)); - } - - /*package*/ synchronized void onA2dpSinkProfileConnected(BluetoothProfile profile) { - final List<BluetoothDevice> deviceList = profile.getConnectedDevices(); - if (deviceList.isEmpty()) { - return; + if (profile == BluetoothProfile.A2DP) { + mA2dp = (BluetoothA2dp) proxy; + } else if (profile == BluetoothProfile.LE_AUDIO) { + mLeAudio = (BluetoothLeAudio) proxy; } - final BluetoothDevice btDevice = deviceList.get(0); - final @BluetoothProfile.BtProfileState int state = - profile.getConnectionState(btDevice); - mDeviceBroker.postSetA2dpSourceConnectionState( - state, new BluetoothA2dpDeviceInfo(btDevice)); - } - - /*package*/ synchronized void onHearingAidProfileConnected(BluetoothHearingAid hearingAid) { - mHearingAid = hearingAid; - final List<BluetoothDevice> deviceList = mHearingAid.getConnectedDevices(); + final List<BluetoothDevice> deviceList = proxy.getConnectedDevices(); if (deviceList.isEmpty()) { return; } final BluetoothDevice btDevice = deviceList.get(0); final @BluetoothProfile.BtProfileState int state = - mHearingAid.getConnectionState(btDevice); - mDeviceBroker.postBluetoothHearingAidDeviceConnectionState( - btDevice, state, - /*suppressNoisyIntent*/ false, - /*musicDevice*/ android.media.AudioSystem.DEVICE_NONE, - /*eventSource*/ "mBluetoothProfileServiceListener"); - } - - /*package*/ synchronized void onLeAudioProfileConnected(BluetoothLeAudio leAudio) { - mLeAudio = leAudio; - final List<BluetoothDevice> deviceList = mLeAudio.getConnectedDevices(); - if (deviceList.isEmpty()) { - return; + proxy.getConnectionState(btDevice); + if (state == BluetoothProfile.STATE_CONNECTED) { + mDeviceBroker.queueOnBluetoothActiveDeviceChanged( + new AudioDeviceBroker.BtDeviceChangedData(btDevice, null, + new BtProfileConnectionInfo(profile), "mBluetoothProfileServiceListener")); + } else { + mDeviceBroker.queueOnBluetoothActiveDeviceChanged( + new AudioDeviceBroker.BtDeviceChangedData(null, btDevice, + new BtProfileConnectionInfo(profile), "mBluetoothProfileServiceListener")); } - - final BluetoothDevice btDevice = deviceList.get(0); - final @BluetoothProfile.BtProfileState int state = - mLeAudio.getConnectionState(btDevice); - mDeviceBroker.postBluetoothLeAudioOutDeviceConnectionState( - btDevice, state, - /*suppressNoisyIntent*/ false, - /*musicDevice android.media.AudioSystem.DEVICE_NONE,*/ - /*eventSource*/ "mBluetoothProfileServiceListener"); } // @GuardedBy("AudioDeviceBroker.mSetModeLock") @@ -677,36 +647,16 @@ public class BtHelper { public void onServiceConnected(int profile, BluetoothProfile proxy) { switch(profile) { case BluetoothProfile.A2DP: - AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent( - "BT profile service: connecting A2DP profile")); - mDeviceBroker.postBtA2dpProfileConnected((BluetoothA2dp) proxy); - break; - case BluetoothProfile.A2DP_SINK: - AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent( - "BT profile service: connecting A2DP_SINK profile")); - mDeviceBroker.postBtA2dpSinkProfileConnected(proxy); - break; - case BluetoothProfile.HEADSET: - AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent( - "BT profile service: connecting HEADSET profile")); - mDeviceBroker.postBtHeasetProfileConnected((BluetoothHeadset) proxy); - break; - case BluetoothProfile.HEARING_AID: - AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent( - "BT profile service: connecting HEARING_AID profile")); - mDeviceBroker.postBtHearingAidProfileConnected( - (BluetoothHearingAid) proxy); - break; - case BluetoothProfile.LE_AUDIO: AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent( - "BT profile service: connecting LE_AUDIO profile")); - mDeviceBroker.postBtLeAudioProfileConnected( - (BluetoothLeAudio) proxy); + "BT profile service: connecting " + + BluetoothProfile.getProfileName(profile) + " profile")); + mDeviceBroker.postBtProfileConnected(profile, proxy); break; + default: break; } @@ -715,22 +665,11 @@ public class BtHelper { switch (profile) { case BluetoothProfile.A2DP: - mDeviceBroker.postDisconnectA2dp(); - break; - case BluetoothProfile.A2DP_SINK: - mDeviceBroker.postDisconnectA2dpSink(); - break; - case BluetoothProfile.HEADSET: - mDeviceBroker.postDisconnectHeadset(); - break; - case BluetoothProfile.HEARING_AID: - mDeviceBroker.postDisconnectHearingAid(); - break; case BluetoothProfile.LE_AUDIO: - mDeviceBroker.postDisconnectLeAudio(); + mDeviceBroker.postBtProfileDisconnected(profile); break; default: diff --git a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java index 5c53d43fa1df..9e1445cf589d 100644 --- a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java +++ b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java @@ -26,11 +26,11 @@ import static org.mockito.Mockito.when; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothProfile; import android.content.Context; import android.content.Intent; import android.media.AudioManager; import android.media.AudioSystem; +import android.media.BtProfileConnectionInfo; import android.util.Log; import androidx.test.InstrumentationRegistry; @@ -98,16 +98,12 @@ public class AudioDeviceBrokerTest { Log.i(TAG, "starting testPostA2dpDeviceConnectionChange"); Assert.assertNotNull("invalid null BT device", mFakeBtDevice); - mAudioDeviceBroker.queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( - new AudioDeviceBroker.BtDeviceConnectionInfo(mFakeBtDevice, - BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 1)); + mAudioDeviceBroker.queueOnBluetoothActiveDeviceChanged( + new AudioDeviceBroker.BtDeviceChangedData(mFakeBtDevice, null, + BtProfileConnectionInfo.a2dpInfo(true, 1), "testSource")); Thread.sleep(2 * MAX_MESSAGE_HANDLING_DELAY_MS); - verify(mSpyDevInventory, times(1)).setBluetoothA2dpDeviceConnectionState( - any(BluetoothDevice.class), - ArgumentMatchers.eq(BluetoothProfile.STATE_CONNECTED) /*state*/, - ArgumentMatchers.eq(BluetoothProfile.A2DP) /*profile*/, - ArgumentMatchers.eq(true) /*suppressNoisyIntent*/, anyInt() /*musicDevice*/, - ArgumentMatchers.eq(1) /*a2dpVolume*/ + verify(mSpyDevInventory, times(1)).setBluetoothActiveDevice( + any(AudioDeviceBroker.BtDeviceInfo.class) ); // verify the connection was reported to AudioSystem @@ -210,30 +206,29 @@ public class AudioDeviceBrokerTest { ((NoOpAudioSystemAdapter) mSpyAudioSystem).configureIsStreamActive(mockMediaPlayback); // first connection: ensure the device is connected as a starting condition for the test - mAudioDeviceBroker.queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( - new AudioDeviceBroker.BtDeviceConnectionInfo(mFakeBtDevice, - BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 1)); + mAudioDeviceBroker.queueOnBluetoothActiveDeviceChanged( + new AudioDeviceBroker.BtDeviceChangedData(mFakeBtDevice, null, + BtProfileConnectionInfo.a2dpInfo(true, 1), "testSource")); Thread.sleep(MAX_MESSAGE_HANDLING_DELAY_MS); // disconnection - mAudioDeviceBroker.queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( - new AudioDeviceBroker.BtDeviceConnectionInfo(mFakeBtDevice, - BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.A2DP, false, -1)); + mAudioDeviceBroker.queueOnBluetoothActiveDeviceChanged( + new AudioDeviceBroker.BtDeviceChangedData(null, mFakeBtDevice, + BtProfileConnectionInfo.a2dpInfo(false, -1), "testSource")); if (delayAfterDisconnection > 0) { Thread.sleep(delayAfterDisconnection); } // reconnection - mAudioDeviceBroker.queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( - new AudioDeviceBroker.BtDeviceConnectionInfo(mFakeBtDevice, - BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 2)); + mAudioDeviceBroker.queueOnBluetoothActiveDeviceChanged( + new AudioDeviceBroker.BtDeviceChangedData(mFakeBtDevice, null, + BtProfileConnectionInfo.a2dpInfo(true, 2), "testSource")); Thread.sleep(AudioService.BECOMING_NOISY_DELAY_MS + MAX_MESSAGE_HANDLING_DELAY_MS); // Verify disconnection has been cancelled and we're seeing two connections attempts, // with the device connected at the end of the test - verify(mSpyDevInventory, times(2)).onSetA2dpSinkConnectionState( - any(BtHelper.BluetoothA2dpDeviceInfo.class), - ArgumentMatchers.eq(BluetoothProfile.STATE_CONNECTED)); + verify(mSpyDevInventory, times(2)).onSetBtActiveDevice( + any(AudioDeviceBroker.BtDeviceInfo.class), anyInt()); Assert.assertTrue("Mock device not connected", mSpyDevInventory.isA2dpDeviceConnected(mFakeBtDevice)); |