From 8ae5134aefa26e0f5669416750f74dd4f7aaa158 Mon Sep 17 00:00:00 2001 From: Angela Wang Date: Tue, 11 Oct 2022 08:51:36 +0000 Subject: [PATCH 1/2] Shows LE audio hearing aid device in a11y settings page (1/3) Handles HAP profile in LocalBluetoothProfileManager Bug: 249235823 Test: build pass Change-Id: Ieb31a1bade5ab43fb229a9e75cc782544d99d0dd --- .../bluetooth/LocalBluetoothProfileManager.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java index fb861da0a7f0e..4e9073ce5a61e 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java @@ -21,6 +21,7 @@ import android.bluetooth.BluetoothA2dpSink; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothCsipSetCoordinator; import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothHapClient; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothHeadsetClient; import android.bluetooth.BluetoothHearingAid; @@ -103,6 +104,7 @@ public class LocalBluetoothProfileManager { private PbapClientProfile mPbapClientProfile; private PbapServerProfile mPbapProfile; private HearingAidProfile mHearingAidProfile; + private HapClientProfile mHapClientProfile; private CsipSetCoordinatorProfile mCsipSetCoordinatorProfile; private LeAudioProfile mLeAudioProfile; private LocalBluetoothLeBroadcast mLeAudioBroadcast; @@ -189,6 +191,12 @@ public class LocalBluetoothProfileManager { addProfile(mHearingAidProfile, HearingAidProfile.NAME, BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED); } + if (mHapClientProfile == null && supportedList.contains(BluetoothProfile.HAP_CLIENT)) { + if (DEBUG) Log.d(TAG, "Adding local HAP_CLIENT profile"); + mHapClientProfile = new HapClientProfile(mContext, mDeviceManager, this); + addProfile(mHapClientProfile, HapClientProfile.NAME, + BluetoothHapClient.ACTION_HAP_CONNECTION_STATE_CHANGED); + } if (mHidProfile == null && supportedList.contains(BluetoothProfile.HID_HOST)) { if (DEBUG) Log.d(TAG, "Adding local HID_HOST profile"); mHidProfile = new HidProfile(mContext, mDeviceManager, this); @@ -524,6 +532,10 @@ public class LocalBluetoothProfileManager { return mHearingAidProfile; } + public HapClientProfile getHapClientProfile() { + return mHapClientProfile; + } + public LeAudioProfile getLeAudioProfile() { return mLeAudioProfile; } @@ -675,6 +687,11 @@ public class LocalBluetoothProfileManager { removedProfiles.remove(mHearingAidProfile); } + if (mHapClientProfile != null && ArrayUtils.contains(uuids, BluetoothUuid.HAS)) { + profiles.add(mHapClientProfile); + removedProfiles.remove(mHapClientProfile); + } + if (mSapProfile != null && ArrayUtils.contains(uuids, BluetoothUuid.SAP)) { profiles.add(mSapProfile); removedProfiles.remove(mSapProfile); From 3176b4d15b78dbf666a070f90464488fd8c7cd68 Mon Sep 17 00:00:00 2001 From: Angela Wang Date: Tue, 11 Oct 2022 08:52:39 +0000 Subject: [PATCH 2/2] Shows LE audio hearing aid device in a11y settings page (2/3) Handles LE audio hearing aid in CachedBluetoothDevice. Previously isHearingAidDevice() will only consider ASHA hearing aid, and now it takes LE audio hearing aid into consideration as well. Bug: 249235823 Test: make RunSettingsLibRoboTests ROBOTEST_FILTER=CachedBluetoothDeviceTest Change-Id: I9c50a7b759b7fbcd80f1f5706909ce0a6ddc5959 --- .../bluetooth/CachedBluetoothDevice.java | 38 ++++++++++--- .../settingslib/media/MediaDeviceUtils.java | 5 +- .../bluetooth/CachedBluetoothDeviceTest.java | 55 ++++++++++++++++--- 3 files changed, 80 insertions(+), 18 deletions(-) diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index 950ee21ae7b56..978e5926033e3 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -161,6 +161,8 @@ public class CachedBluetoothDevice implements Comparable mDevice = device; fillData(); mHiSyncId = BluetoothHearingAid.HI_SYNC_ID_INVALID; + mDeviceSide = HearingAidProfile.DeviceSide.SIDE_INVALID; + mDeviceMode = HearingAidProfile.DeviceMode.MODE_INVALID; mGroupId = BluetoothCsipSetCoordinator.GROUP_ID_INVALID; initDrawableCache(); mUnpairing = false; @@ -363,10 +365,6 @@ public class CachedBluetoothDevice implements Comparable mHiSyncId = id; } - public boolean isHearingAidDevice() { - return mHiSyncId != BluetoothHearingAid.HI_SYNC_ID_INVALID; - } - /** * Mark the discovered device as member of coordinated set. * @@ -778,8 +776,6 @@ public class CachedBluetoothDevice implements Comparable ParcelUuid[] localUuids = new ParcelUuid[uuidsList.size()]; uuidsList.toArray(localUuids); - if (localUuids == null) return false; - /* * Now we know if the device supports PBAP, update permissions... */ @@ -1365,14 +1361,40 @@ public class CachedBluetoothDevice implements Comparable } /** - * @return {@code true} if {@code cachedBluetoothDevice} is Hearing Aid device + * @return {@code true} if {@code cachedBluetoothDevice} is ASHA hearing aid device */ - public boolean isConnectedHearingAidDevice() { + public boolean isConnectedAshaHearingAidDevice() { HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile(); return hearingAidProfile != null && hearingAidProfile.getConnectionStatus(mDevice) == BluetoothProfile.STATE_CONNECTED; } + /** + * @return {@code true} if {@code cachedBluetoothDevice} is HAP device + */ + public boolean isConnectedHapClientDevice() { + HapClientProfile hapClientProfile = mProfileManager.getHapClientProfile(); + return hapClientProfile != null && hapClientProfile.getConnectionStatus(mDevice) + == BluetoothProfile.STATE_CONNECTED; + } + + /** + * @return {@code true} if {@code cachedBluetoothDevice} is LeAudio hearing aid device + */ + public boolean isConnectedLeAudioHearingAidDevice() { + return isConnectedHapClientDevice() && isConnectedLeAudioDevice(); + } + + /** + * @return {@code true} if {@code cachedBluetoothDevice} is hearing aid device + * + * The device may be an ASHA hearing aid that supports {@link HearingAidProfile} or a LeAudio + * hearing aid that supports {@link HapClientProfile} and {@link LeAudioProfile}. + */ + public boolean isHearingAidDevice() { + return isConnectedAshaHearingAidDevice() || isConnectedLeAudioHearingAidDevice(); + } + /** * @return {@code true} if {@code cachedBluetoothDevice} is LeAudio device */ diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDeviceUtils.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDeviceUtils.java index df6929e114eea..b3a52b9ec7884 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDeviceUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDeviceUtils.java @@ -16,6 +16,7 @@ package com.android.settingslib.media; import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothHearingAid; import android.media.MediaRoute2Info; import com.android.settingslib.bluetooth.CachedBluetoothDevice; @@ -32,7 +33,9 @@ public class MediaDeviceUtils { */ public static String getId(CachedBluetoothDevice cachedDevice) { if (cachedDevice.isHearingAidDevice()) { - return Long.toString(cachedDevice.getHiSyncId()); + if (cachedDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID) { + return Long.toString(cachedDevice.getHiSyncId()); + } } return cachedDevice.getAddress(); } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java index 79e99387b2fa0..864725ba600c8 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java @@ -74,6 +74,10 @@ public class CachedBluetoothDeviceTest { @Mock private HearingAidProfile mHearingAidProfile; @Mock + private HapClientProfile mHapClientProfile; + @Mock + private LeAudioProfile mLeAudioProfile; + @Mock private BluetoothDevice mDevice; @Mock private BluetoothDevice mSubDevice; @@ -859,21 +863,21 @@ public class CachedBluetoothDeviceTest { } @Test - public void isConnectedHearingAidDevice_connected_returnTrue() { + public void isConnectedAshaHearingAidDevice_connected_returnTrue() { when(mProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile); when(mHearingAidProfile.getConnectionStatus(mDevice)). thenReturn(BluetoothProfile.STATE_CONNECTED); - assertThat(mCachedDevice.isConnectedHearingAidDevice()).isTrue(); + assertThat(mCachedDevice.isConnectedAshaHearingAidDevice()).isTrue(); } @Test - public void isConnectedHearingAidDevice_disconnected_returnFalse() { + public void isConnectedAshaHearingAidDevice_disconnected_returnFalse() { when(mProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile); when(mHearingAidProfile.getConnectionStatus(mDevice)). thenReturn(BluetoothProfile.STATE_DISCONNECTED); - assertThat(mCachedDevice.isConnectedHearingAidDevice()).isFalse(); + assertThat(mCachedDevice.isConnectedAshaHearingAidDevice()).isFalse(); } @Test @@ -891,10 +895,10 @@ public class CachedBluetoothDeviceTest { } @Test - public void isConnectedHearingAidDevice_profileIsNull_returnFalse() { + public void isConnectedAshaHearingAidDevice_profileIsNull_returnFalse() { when(mProfileManager.getHearingAidProfile()).thenReturn(null); - assertThat(mCachedDevice.isConnectedHearingAidDevice()).isFalse(); + assertThat(mCachedDevice.isConnectedAshaHearingAidDevice()).isFalse(); } @Test @@ -987,11 +991,11 @@ public class CachedBluetoothDeviceTest { @Test public void getConnectionSummary_profileConnectedFail_showErrorMessage() { - final A2dpProfile profle = mock(A2dpProfile.class); - mCachedDevice.onProfileStateChanged(profle, BluetoothProfile.STATE_CONNECTED); + final A2dpProfile profile = mock(A2dpProfile.class); + mCachedDevice.onProfileStateChanged(profile, BluetoothProfile.STATE_CONNECTED); mCachedDevice.setProfileConnectedStatus(BluetoothProfile.A2DP, true); - when(profle.getConnectionStatus(mDevice)).thenReturn(BluetoothProfile.STATE_CONNECTED); + when(profile.getConnectionStatus(mDevice)).thenReturn(BluetoothProfile.STATE_CONNECTED); assertThat(mCachedDevice.getConnectionSummary()).isEqualTo( mContext.getString(R.string.profile_connect_timeout_subtext)); @@ -1069,4 +1073,37 @@ public class CachedBluetoothDeviceTest { assertThat(mSubCachedDevice.mDevice).isEqualTo(mDevice); assertThat(mCachedDevice.getMemberDevice().contains(mSubCachedDevice)).isTrue(); } + + @Test + public void isConnectedHearingAidDevice_isConnectedAshaHearingAidDevice_returnTrue() { + when(mProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile); + + updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); + + assertThat(mCachedDevice.isHearingAidDevice()).isTrue(); + } + + @Test + public void isConnectedHearingAidDevice_isConnectedLeAudioHearingAidDevice_returnTrue() { + when(mProfileManager.getHapClientProfile()).thenReturn(mHapClientProfile); + when(mProfileManager.getLeAudioProfile()).thenReturn(mLeAudioProfile); + + updateProfileStatus(mHapClientProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mLeAudioProfile, BluetoothProfile.STATE_CONNECTED); + + assertThat(mCachedDevice.isHearingAidDevice()).isTrue(); + } + + @Test + public void isConnectedHearingAidDevice_isNotAnyConnectedHearingAidDevice_returnFalse() { + when(mProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile); + when(mProfileManager.getHapClientProfile()).thenReturn(mHapClientProfile); + when(mProfileManager.getLeAudioProfile()).thenReturn(mLeAudioProfile); + + updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mHapClientProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mLeAudioProfile, BluetoothProfile.STATE_DISCONNECTED); + + assertThat(mCachedDevice.isHearingAidDevice()).isFalse(); + } }