From 1f24f521c266b3f2eac0601ac4b0237752cf3334 Mon Sep 17 00:00:00 2001 From: timhypeng Date: Fri, 25 May 2018 14:23:44 +0800 Subject: [PATCH 1/4] Add isConnectedHearingAidDevice function to check if it supports Hearing Aid profile Bug: 116317072 Bug: 116044083 Bug: 79553082 Test: make -j50 RunSettingsLibRoboTests Change-Id: I2950f63c4a95d692b77cfffeacc9d1d319243e0d Merged-In: I2950f63c4a95d692b77cfffeacc9d1d319243e0d (cherry picked from commit c509a65541bf0140b5da92ea1b1358f843ba0b89) --- .../bluetooth/CachedBluetoothDevice.java | 8 ++++++++ .../bluetooth/CachedBluetoothDeviceTest.java | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index bb8fbe2da9c99..2fc6038088509 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -1200,4 +1200,12 @@ public class CachedBluetoothDevice implements Comparable return mProfileManager.getHeadsetProfile().getConnectionStatus(mDevice) == BluetoothProfile.STATE_CONNECTED; } + + /** + * @return {@code true} if {@code cachedBluetoothDevice} is Hearing Aid device + */ + public boolean isConnectedHearingAidDevice() { + return mProfileManager.getHearingAidProfile().getConnectionStatus(mDevice) == + BluetoothProfile.STATE_CONNECTED; + } } 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 927a94f6b0179..9bc47eb210c19 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 @@ -572,4 +572,22 @@ public class CachedBluetoothDeviceTest { assertThat(mCachedDevice.isHfpDevice()).isFalse(); } + + @Test + public void isConnectedHearingAidDevice_connected_returnTrue() { + when(mProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile); + when(mHearingAidProfile.getConnectionStatus(mDevice)). + thenReturn(BluetoothProfile.STATE_CONNECTED); + + assertThat(mCachedDevice.isConnectedHearingAidDevice()).isTrue(); + } + + @Test + public void isConnectedHearingAidDevice_disconnected_returnFalse() { + when(mProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile); + when(mHearingAidProfile.getConnectionStatus(mDevice)). + thenReturn(BluetoothProfile.STATE_DISCONNECTED); + + assertThat(mCachedDevice.isConnectedHearingAidDevice()).isFalse(); + } } From c3ea0d3f799ec1ce7b42b159b80a5f5022bd9b07 Mon Sep 17 00:00:00 2001 From: Hansong Zhang Date: Wed, 13 Jun 2018 11:30:59 -0700 Subject: [PATCH 2/4] Prevent NPE when profile is null When CachedBluetoothDevice is checking whether it's a connected A2DP/HFP/HearingAid device, check profile != null Bug: 116317072 Bug: 116044083 Bug: 110153306 Test: robolectric Change-Id: I094d065d29ccbfc76bad00b4a307be8f1b88ec9b Merged-In: I094d065d29ccbfc76bad00b4a307be8f1b88ec9b (cherry picked from commit 28963cdd45505832ce79a8afe5b01990528289d2) --- .../bluetooth/CachedBluetoothDevice.java | 9 +++++--- .../bluetooth/CachedBluetoothDeviceTest.java | 21 +++++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index 2fc6038088509..0370f204f0867 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -1189,7 +1189,8 @@ public class CachedBluetoothDevice implements Comparable * @return {@code true} if {@code cachedBluetoothDevice} is a2dp device */ public boolean isA2dpDevice() { - return mProfileManager.getA2dpProfile().getConnectionStatus(mDevice) == + A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile(); + return a2dpProfile != null && a2dpProfile.getConnectionStatus(mDevice) == BluetoothProfile.STATE_CONNECTED; } @@ -1197,7 +1198,8 @@ public class CachedBluetoothDevice implements Comparable * @return {@code true} if {@code cachedBluetoothDevice} is HFP device */ public boolean isHfpDevice() { - return mProfileManager.getHeadsetProfile().getConnectionStatus(mDevice) == + HeadsetProfile headsetProfile = mProfileManager.getHeadsetProfile(); + return headsetProfile != null && headsetProfile.getConnectionStatus(mDevice) == BluetoothProfile.STATE_CONNECTED; } @@ -1205,7 +1207,8 @@ public class CachedBluetoothDevice implements Comparable * @return {@code true} if {@code cachedBluetoothDevice} is Hearing Aid device */ public boolean isConnectedHearingAidDevice() { - return mProfileManager.getHearingAidProfile().getConnectionStatus(mDevice) == + HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile(); + return hearingAidProfile != null && hearingAidProfile.getConnectionStatus(mDevice) == BluetoothProfile.STATE_CONNECTED; } } 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 9bc47eb210c19..c39fb85428fa3 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 @@ -590,4 +590,25 @@ public class CachedBluetoothDeviceTest { assertThat(mCachedDevice.isConnectedHearingAidDevice()).isFalse(); } + + @Test + public void isConnectedHfpDevice_profileIsNull_returnFalse() { + when(mProfileManager.getHeadsetProfile()).thenReturn(null); + + assertThat(mCachedDevice.isHfpDevice()).isFalse(); + } + + @Test + public void isConnectedA2dpDevice_profileIsNull_returnFalse() { + when(mProfileManager.getA2dpProfile()).thenReturn(null); + + assertThat(mCachedDevice.isA2dpDevice()).isFalse(); + } + + @Test + public void isConnectedHearingAidDevice_profileIsNull_returnFalse() { + when(mProfileManager.getHearingAidProfile()).thenReturn(null); + + assertThat(mCachedDevice.isConnectedHearingAidDevice()).isFalse(); + } } From 172efa1ed8dafc7270448a5aeb3155a9dee06e3f Mon Sep 17 00:00:00 2001 From: Stanley Tng Date: Tue, 19 Jun 2018 08:48:10 -0700 Subject: [PATCH 3/4] Add Feature Flag for Hearing Aid Profile Using the Settings App-Developer Options-Feature Flag, allow the user to enable or disable the Hearing Aid Profile. Bug: 116317072 Bug: 116044083 Test: Manual testing using Settings App Change-Id: I58a9d339941e235242c443c85b6f4194b5a296c9 Merged-In: I58a9d339941e235242c443c85b6f4194b5a296c9 (cherry picked from commit fe8c8337edc5e9d6b61d0942873538912d523db7) --- core/java/android/util/FeatureFlagUtils.java | 3 +++ .../com/android/server/BluetoothManagerService.java | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index c861499073232..01e2db2e39395 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -33,6 +33,8 @@ public class FeatureFlagUtils { public static final String FFLAG_PREFIX = "sys.fflag."; public static final String FFLAG_OVERRIDE_PREFIX = FFLAG_PREFIX + "override."; + public static final String PERSIST_PREFIX = "persist." + FFLAG_OVERRIDE_PREFIX; + public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid"; private static final Map DEFAULT_FLAGS; static { @@ -44,6 +46,7 @@ public class FeatureFlagUtils { DEFAULT_FLAGS.put("settings_data_usage_v2", "true"); DEFAULT_FLAGS.put("settings_audio_switcher", "true"); DEFAULT_FLAGS.put("settings_systemui_theme", "true"); + DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "true"); } /** diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index aa426d3cd31f5..78b738500a97f 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -53,12 +53,16 @@ import android.os.Process; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.SystemClock; +import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.os.UserManagerInternal; import android.os.UserManagerInternal.UserRestrictionsListener; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; +import android.text.TextUtils; +import android.util.FeatureFlagUtils; +import android.util.Log; import android.util.Slog; import android.util.StatsLog; @@ -386,6 +390,15 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mCallbacks = new RemoteCallbackList(); mStateChangeCallbacks = new RemoteCallbackList(); + // TODO: We need a more generic way to initialize the persist keys of FeatureFlagUtils + boolean isHearingAidEnabled; + String value = SystemProperties.get(FeatureFlagUtils.PERSIST_PREFIX + FeatureFlagUtils.HEARING_AID_SETTINGS); + if (!TextUtils.isEmpty(value)) { + isHearingAidEnabled = Boolean.parseBoolean(value); + Log.v(TAG, "set feature flag HEARING_AID_SETTINGS to " + isHearingAidEnabled); + FeatureFlagUtils.setEnabled(context, FeatureFlagUtils.HEARING_AID_SETTINGS, isHearingAidEnabled); + } + IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED); filter.addAction(BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED); From c6f5643d966850a023ff9cae8af38b395898839b Mon Sep 17 00:00:00 2001 From: Stanley Tng Date: Tue, 25 Sep 2018 18:07:41 -0700 Subject: [PATCH 4/4] Fix missing connection state changes intent for Hearing Aids In some corner cases, the intent receiver for hearing aids CONNECTION_STATE_CHANGED is not registered. This fixes this problem. We need to check hearing aid profile before updateLocalProfile(). Note: This has been totally fixed in master in refactoring code. Bug: 116317072 Bug: 116044083 Bug: 116643085 Test: Manual tests with one Hearing Aid device and in Settings-Device details page. Change-Id: I20bf6b9fe929cd8753a20b8112e66467e560f6df Merged-In: Id2dc364dfa815e72db91b92bcee9745e6c40d34a --- .../bluetooth/LocalBluetoothProfileManager.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java index 62f8724870e3c..29f21908f20df 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java @@ -123,6 +123,14 @@ public class LocalBluetoothProfileManager { ParcelUuid[] uuids = adapter.getUuids(); + List supportedList = mLocalAdapter.getSupportedProfiles(); + if (supportedList.contains(BluetoothProfile.HEARING_AID)) { + mHearingAidProfile = new HearingAidProfile(mContext, mLocalAdapter, mDeviceManager, + this); + addProfile(mHearingAidProfile, HearingAidProfile.NAME, + BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED); + } + // uuids may be null if Bluetooth is turned off if (uuids != null) { updateLocalProfiles(uuids); @@ -159,13 +167,6 @@ public class LocalBluetoothProfileManager { addProfile(mPbapProfile, PbapServerProfile.NAME, BluetoothPbap.ACTION_CONNECTION_STATE_CHANGED); - List supportedList = mLocalAdapter.getSupportedProfiles(); - if (supportedList.contains(BluetoothProfile.HEARING_AID)) { - mHearingAidProfile = new HearingAidProfile(mContext, mLocalAdapter, mDeviceManager, - this); - addProfile(mHearingAidProfile, HearingAidProfile.NAME, - BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED); - } if (DEBUG) Log.d(TAG, "LocalBluetoothProfileManager construction complete"); }