From 82ce1d19dec35dcfffd60b2b52d0276bd9595acf Mon Sep 17 00:00:00 2001 From: jasonwshsu Date: Mon, 14 Mar 2022 17:28:08 +0800 Subject: [PATCH 1/3] Header for hearing aids now listed in one summary Root Cause: Change design in Android T to show left-side and right-side in one summary line. Bug: 224323976 Test: manual test Change-Id: Ia43b491d571787d356240593b221d6fe8dd1453c --- .../settings/bluetooth/BluetoothDetailsHeaderController.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsHeaderController.java b/src/com/android/settings/bluetooth/BluetoothDetailsHeaderController.java index 9c7aa58cf7c..06a71f06483 100644 --- a/src/com/android/settings/bluetooth/BluetoothDetailsHeaderController.java +++ b/src/com/android/settings/bluetooth/BluetoothDetailsHeaderController.java @@ -75,10 +75,8 @@ public class BluetoothDetailsHeaderController extends BluetoothDetailsController if (TextUtils.isEmpty(summaryText)) { // If first summary is unavailable, not to show second summary. mHeaderController.setSecondSummary((CharSequence)null); - } else { - // If both the hearing aids are connected, two device status should be shown. - mHeaderController.setSecondSummary(mDeviceManager.getSubDeviceSummary(mCachedDevice)); } + mHeaderController.setLabel(mCachedDevice.getName()); mHeaderController.setIcon(pair.first); mHeaderController.setIconContentDescription(pair.second); From 82d3bb2b733f107f4c6041d0aa7571dbb4d5831b Mon Sep 17 00:00:00 2001 From: jasonwshsu Date: Tue, 22 Mar 2022 03:13:51 +0800 Subject: [PATCH 2/3] Update summary in Accessibility -> Hearing aids Bug: 225117843 Test: make RunSettingsRoboTests ROBOTEST_FILTER=AccessibilityHearingAidPreferenceControllerTest Change-Id: I19c08474349e9ae98cd3f296ba8423f920d55fcf --- ...ibilityHearingAidPreferenceController.java | 88 ++++++++++++------- ...ityHearingAidPreferenceControllerTest.java | 66 ++++++++++---- 2 files changed, 108 insertions(+), 46 deletions(-) diff --git a/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceController.java b/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceController.java index 8f0ca3e5721..2cb74262f0a 100644 --- a/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceController.java +++ b/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceController.java @@ -39,12 +39,13 @@ import com.android.settings.bluetooth.BluetoothDeviceDetailsFragment; import com.android.settings.core.BasePreferenceController; import com.android.settings.core.SubSettingLauncher; import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; +import com.android.settingslib.bluetooth.HearingAidProfile; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnStart; import com.android.settingslib.core.lifecycle.events.OnStop; -import java.util.Iterator; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; @@ -82,15 +83,13 @@ public class AccessibilityHearingAidPreferenceController extends BasePreferenceC private final LocalBluetoothManager mLocalBluetoothManager; private final BluetoothAdapter mBluetoothAdapter; - //cache value of supporting hearing aid or not - private boolean mHearingAidProfileSupported; + private FragmentManager mFragmentManager; public AccessibilityHearingAidPreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); mLocalBluetoothManager = getLocalBluetoothManager(); mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); - mHearingAidProfileSupported = isHearingAidProfileSupported(); } @Override @@ -101,29 +100,25 @@ public class AccessibilityHearingAidPreferenceController extends BasePreferenceC @Override public int getAvailabilityStatus() { - return mHearingAidProfileSupported ? AVAILABLE : UNSUPPORTED_ON_DEVICE; + return isHearingAidProfileSupported() ? AVAILABLE : UNSUPPORTED_ON_DEVICE; } @Override public void onStart() { - if (mHearingAidProfileSupported) { - IntentFilter filter = new IntentFilter(); - filter.addAction(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED); - filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); - mContext.registerReceiver(mHearingAidChangedReceiver, filter); - } + IntentFilter filter = new IntentFilter(); + filter.addAction(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED); + filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); + mContext.registerReceiver(mHearingAidChangedReceiver, filter); } @Override public void onStop() { - if (mHearingAidProfileSupported) { - mContext.unregisterReceiver(mHearingAidChangedReceiver); - } + mContext.unregisterReceiver(mHearingAidChangedReceiver); } @Override public boolean handlePreferenceTreeClick(Preference preference) { - if (TextUtils.equals(preference.getKey(), getPreferenceKey())){ + if (TextUtils.equals(preference.getKey(), getPreferenceKey())) { final CachedBluetoothDevice device = getConnectedHearingAidDevice(); if (device == null) { launchHearingAidInstructionDialog(); @@ -141,7 +136,27 @@ public class AccessibilityHearingAidPreferenceController extends BasePreferenceC if (device == null) { return mContext.getText(R.string.accessibility_hearingaid_not_connected_summary); } - return device.getName(); + + final int connectedNum = getConnectedHearingAidDeviceNum(); + final CharSequence name = device.getName(); + final int side = device.getDeviceSide(); + final CachedBluetoothDevice subDevice = device.getSubDevice(); + if (connectedNum > 1) { + return mContext.getString(R.string.accessibility_hearingaid_more_device_summary, name); + } + if (subDevice != null && subDevice.isConnected()) { + return mContext.getString( + R.string.accessibility_hearingaid_left_and_right_side_device_summary, name); + } + if (side == HearingAidProfile.DeviceSide.SIDE_INVALID) { + return mContext.getString( + R.string.accessibility_hearingaid_active_device_summary, name); + } + return (side == HearingAidProfile.DeviceSide.SIDE_LEFT) + ? mContext.getString( + R.string.accessibility_hearingaid_left_side_device_summary, name) + : mContext.getString( + R.string.accessibility_hearingaid_right_side_device_summary, name); } public void setFragmentManager(FragmentManager fragmentManager) { @@ -150,33 +165,44 @@ public class AccessibilityHearingAidPreferenceController extends BasePreferenceC @VisibleForTesting CachedBluetoothDevice getConnectedHearingAidDevice() { - if (!mHearingAidProfileSupported) { + if (!isHearingAidProfileSupported()) { return null; } - if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) { - return null; - } - final List deviceList = mLocalBluetoothManager.getProfileManager() - .getHearingAidProfile().getConnectedDevices(); - final Iterator it = deviceList.iterator(); - while (it.hasNext()) { - BluetoothDevice obj = (BluetoothDevice)it.next(); - if (!mLocalBluetoothManager.getCachedDeviceManager().isSubDevice(obj)) { - return mLocalBluetoothManager.getCachedDeviceManager().findDevice(obj); + + final CachedBluetoothDeviceManager deviceManager = + mLocalBluetoothManager.getCachedDeviceManager(); + final HearingAidProfile hearingAidProfile = + mLocalBluetoothManager.getProfileManager().getHearingAidProfile(); + final List deviceList = hearingAidProfile.getConnectedDevices(); + for (BluetoothDevice obj : deviceList) { + if (!deviceManager.isSubDevice(obj)) { + return deviceManager.findDevice(obj); } } return null; } + private int getConnectedHearingAidDeviceNum() { + if (!isHearingAidProfileSupported()) { + return 0; + } + + final CachedBluetoothDeviceManager deviceManager = + mLocalBluetoothManager.getCachedDeviceManager(); + final HearingAidProfile hearingAidProfile = + mLocalBluetoothManager.getProfileManager().getHearingAidProfile(); + final List deviceList = hearingAidProfile.getConnectedDevices(); + return (int) deviceList.stream() + .filter(device -> !deviceManager.isSubDevice(device)) + .count(); + } + private boolean isHearingAidProfileSupported() { if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) { return false; } final List supportedList = mBluetoothAdapter.getSupportedProfiles(); - if (supportedList.contains(BluetoothProfile.HEARING_AID)) { - return true; - } - return false; + return supportedList.contains(BluetoothProfile.HEARING_AID); } private LocalBluetoothManager getLocalBluetoothManager() { diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceControllerTest.java index a45564812e2..1b8c8c3b5a7 100644 --- a/tests/robotests/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceControllerTest.java @@ -18,9 +18,7 @@ package com.android.settings.accessibility; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -48,7 +46,6 @@ import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; import org.junit.After; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -63,7 +60,6 @@ import java.util.ArrayList; import java.util.List; @RunWith(RobolectricTestRunner.class) -@Ignore @Config(shadows = {ShadowBluetoothAdapter.class, ShadowBluetoothUtils.class}) public class AccessibilityHearingAidPreferenceControllerTest { private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1"; @@ -82,6 +78,8 @@ public class AccessibilityHearingAidPreferenceControllerTest { @Mock private CachedBluetoothDevice mCachedBluetoothDevice; @Mock + private CachedBluetoothDevice mCachedSubBluetoothDevice; + @Mock private CachedBluetoothDeviceManager mCachedDeviceManager; @Mock private LocalBluetoothManager mLocalBluetoothManager; @@ -111,18 +109,54 @@ public class AccessibilityHearingAidPreferenceControllerTest { } @Test - public void onHearingAidStateChanged_connected_updateHearingAidSummary() { + public void getSummary_connectedHearingAidRightSide_connectedRightSideSummary() { + when(mCachedBluetoothDevice.getDeviceSide()).thenReturn( + HearingAidProfile.DeviceSide.SIDE_RIGHT); when(mHearingAidProfile.getConnectedDevices()).thenReturn(generateHearingAidDeviceList()); mPreferenceController.onStart(); Intent intent = new Intent(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED); intent.putExtra(BluetoothHearingAid.EXTRA_STATE, BluetoothHearingAid.STATE_CONNECTED); sendIntent(intent); - assertThat(mHearingAidPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME); + assertThat(mHearingAidPreference.getSummary().toString().contentEquals( + "TEST_HEARING_AID_BT_DEVICE_NAME, right only")).isTrue(); } @Test - public void onHearingAidStateChanged_disconnected_updateHearingAidSummary() { + public void getSummary_connectedHearingAidBothSide_connectedBothSideSummary() { + when(mCachedBluetoothDevice.getDeviceSide()).thenReturn( + HearingAidProfile.DeviceSide.SIDE_LEFT); + when(mCachedSubBluetoothDevice.isConnected()).thenReturn(true); + when(mCachedBluetoothDevice.getSubDevice()).thenReturn(mCachedSubBluetoothDevice); + when(mHearingAidProfile.getConnectedDevices()).thenReturn(generateHearingAidDeviceList()); + mPreferenceController.onStart(); + Intent intent = new Intent(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED); + intent.putExtra(BluetoothHearingAid.EXTRA_STATE, BluetoothHearingAid.STATE_CONNECTED); + sendIntent(intent); + + assertThat(mHearingAidPreference.getSummary().toString().contentEquals( + "TEST_HEARING_AID_BT_DEVICE_NAME, left and right")).isTrue(); + } + + @Test + public void getSummary_connectedMultipleHearingAids_connectedBothSideSummary() { + when(mCachedBluetoothDevice.getDeviceSide()).thenReturn( + HearingAidProfile.DeviceSide.SIDE_LEFT); + when(mCachedSubBluetoothDevice.isConnected()).thenReturn(true); + when(mCachedBluetoothDevice.getSubDevice()).thenReturn(mCachedSubBluetoothDevice); + when(mHearingAidProfile.getConnectedDevices()).thenReturn( + generateMultipleHearingAidDeviceList()); + mPreferenceController.onStart(); + Intent intent = new Intent(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED); + intent.putExtra(BluetoothHearingAid.EXTRA_STATE, BluetoothHearingAid.STATE_CONNECTED); + sendIntent(intent); + + assertThat(mHearingAidPreference.getSummary().toString().contentEquals( + "TEST_HEARING_AID_BT_DEVICE_NAME +1 more")).isTrue(); + } + + @Test + public void getSummary_disconnectedHearingAid_disconnectedSummary() { mPreferenceController.onStart(); Intent intent = new Intent(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED); intent.putExtra(BluetoothHearingAid.EXTRA_STATE, BluetoothHearingAid.STATE_DISCONNECTED); @@ -133,7 +167,7 @@ public class AccessibilityHearingAidPreferenceControllerTest { } @Test - public void onBluetoothStateChanged_bluetoothOff_updateHearingAidSummary() { + public void getSummary_bluetoothOff_disconnectedSummary() { mPreferenceController.onStart(); Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); intent.putExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF); @@ -168,19 +202,14 @@ public class AccessibilityHearingAidPreferenceControllerTest { } @Test - public void onNotSupportHearingAidProfile_doNotDoReceiverOperation() { + public void onNotSupportHearingAidProfile_isNotAvailable() { //clear bluetooth supported profile mShadowBluetoothAdapter.clearSupportedProfiles(); mPreferenceController = new AccessibilityHearingAidPreferenceController(mContext, HEARING_AID_PREFERENCE); mPreferenceController.setPreference(mHearingAidPreference); - //not call registerReceiver() - mPreferenceController.onStart(); - verify(mContext, never()).registerReceiver(any(), any()); - //not call unregisterReceiver() - mPreferenceController.onStop(); - verify(mContext, never()).unregisterReceiver(any()); + assertThat(mPreferenceController.isAvailable()).isFalse(); } @Test @@ -224,4 +253,11 @@ public class AccessibilityHearingAidPreferenceControllerTest { deviceList.add(mBluetoothDevice); return deviceList; } + + private List generateMultipleHearingAidDeviceList() { + final List deviceList = new ArrayList<>(2); + deviceList.add(mBluetoothDevice); + deviceList.add(mBluetoothDevice); + return deviceList; + } } From 384200a337e308064e18cf247a47cdfaee444ba1 Mon Sep 17 00:00:00 2001 From: jasonwshsu Date: Tue, 22 Mar 2022 23:00:15 +0800 Subject: [PATCH 3/3] Add 'Live Caption' preference for hearing aids device in Device details page Bug: 225117933 Test: make RunSettingsRoboTests ROBOTEST_FILTER=BluetoothDetailsRelatedToolsControllerTest Change-Id: Ic607fa7d10aa2049ab0852a86a57dd1d5d1ac7df --- res/xml/bluetooth_device_details_fragment.xml | 12 ++++ ...luetoothDetailsRelatedToolsController.java | 72 +++++++++++++++++++ .../BluetoothDeviceDetailsFragment.java | 2 + ...oothDetailsRelatedToolsControllerTest.java | 52 ++++++++++++++ 4 files changed, 138 insertions(+) create mode 100644 src/com/android/settings/bluetooth/BluetoothDetailsRelatedToolsController.java create mode 100644 tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsRelatedToolsControllerTest.java diff --git a/res/xml/bluetooth_device_details_fragment.xml b/res/xml/bluetooth_device_details_fragment.xml index f6c0af662aa..57698b5e5d0 100644 --- a/res/xml/bluetooth_device_details_fragment.xml +++ b/res/xml/bluetooth_device_details_fragment.xml @@ -61,6 +61,18 @@ + + + +