From caa3a4b9fd7afd64999363c917e10f3766f248b7 Mon Sep 17 00:00:00 2001 From: Ze Li Date: Tue, 4 Jun 2024 18:43:09 +0800 Subject: [PATCH] [ConnectedDevicePage] Make bonded bluetooth devices can be found by Settings search Bonded bluetooth devices can be found by Settings search using device name and jump to connected device page. Test: atest ConnectedDeviceGroupControllerTest Bug: 319056077 Change-Id: I738d7bd400e41647666966e6b39cd7bff01fc551 Flag: com.android.settings.flags.Flags.enableBondedBluetoothDeviceSearchable --- ..._connecteddevice_flag_declarations.aconfig | 11 ++++ .../ConnectedDeviceGroupController.java | 41 ++++++++++++ .../ConnectedDeviceGroupControllerTest.java | 63 ++++++++++++++++++- 3 files changed, 114 insertions(+), 1 deletion(-) diff --git a/aconfig/settings_connecteddevice_flag_declarations.aconfig b/aconfig/settings_connecteddevice_flag_declarations.aconfig index 2d66c30446a..7942ccd1416 100644 --- a/aconfig/settings_connecteddevice_flag_declarations.aconfig +++ b/aconfig/settings_connecteddevice_flag_declarations.aconfig @@ -14,3 +14,14 @@ flag { description: "Gates whether to require an auth challenge for changing USB preferences" bug: "317367746" } + + +flag { + name: "enable_bonded_bluetooth_device_searchable" + namespace: "pixel_cross_device_control" + description: "Set bonded bluetooth devices under connected devices page to be searchable by Settings search." + bug: "319056077" + metadata { + purpose: PURPOSE_BUGFIX + } +} \ No newline at end of file diff --git a/src/com/android/settings/connecteddevice/ConnectedDeviceGroupController.java b/src/com/android/settings/connecteddevice/ConnectedDeviceGroupController.java index 5be761efc79..56a3005f6dd 100644 --- a/src/com/android/settings/connecteddevice/ConnectedDeviceGroupController.java +++ b/src/com/android/settings/connecteddevice/ConnectedDeviceGroupController.java @@ -19,6 +19,7 @@ import android.content.Context; import android.content.pm.PackageManager; import android.hardware.input.InputManager; import android.util.FeatureFlagUtils; +import android.util.Log; import android.view.InputDevice; import androidx.annotation.VisibleForTesting; @@ -26,19 +27,29 @@ import androidx.preference.Preference; import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceScreen; +import com.android.settings.R; import com.android.settings.bluetooth.BluetoothDeviceUpdater; import com.android.settings.bluetooth.ConnectedBluetoothDeviceUpdater; +import com.android.settings.bluetooth.Utils; import com.android.settings.connecteddevice.dock.DockUpdater; import com.android.settings.connecteddevice.stylus.StylusDeviceUpdater; import com.android.settings.connecteddevice.usb.ConnectedUsbDeviceUpdater; import com.android.settings.core.BasePreferenceController; import com.android.settings.core.PreferenceControllerMixin; import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.flags.Flags; import com.android.settings.overlay.DockUpdaterFeatureProvider; import com.android.settings.overlay.FeatureFactory; +import com.android.settingslib.bluetooth.BluetoothDeviceFilter; +import com.android.settingslib.bluetooth.BluetoothUtils; +import com.android.settingslib.bluetooth.CachedBluetoothDevice; +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 com.android.settingslib.search.SearchIndexableRaw; + +import java.util.List; /** * Controller to maintain the {@link androidx.preference.PreferenceGroup} for all @@ -49,6 +60,7 @@ public class ConnectedDeviceGroupController extends BasePreferenceController DevicePreferenceCallback { private static final String KEY = "connected_device_list"; + private static final String TAG = "ConnectedDeviceGroupController"; @VisibleForTesting PreferenceGroup mPreferenceGroup; @@ -58,11 +70,13 @@ public class ConnectedDeviceGroupController extends BasePreferenceController private StylusDeviceUpdater mStylusDeviceUpdater; private final PackageManager mPackageManager; private final InputManager mInputManager; + private final LocalBluetoothManager mLocalBluetoothManager; public ConnectedDeviceGroupController(Context context) { super(context, KEY); mPackageManager = context.getPackageManager(); mInputManager = context.getSystemService(InputManager.class); + mLocalBluetoothManager = Utils.getLocalBluetoothManager(context); } @Override @@ -221,4 +235,31 @@ public class ConnectedDeviceGroupController extends BasePreferenceController } return false; } + + @Override + public void updateDynamicRawDataToIndex(List rawData) { + if (!Flags.enableBondedBluetoothDeviceSearchable()) { + return; + } + if (mLocalBluetoothManager == null) { + Log.d(TAG, "Bluetooth is not supported"); + return; + } + for (CachedBluetoothDevice cachedDevice : + mLocalBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy()) { + if (!BluetoothDeviceFilter.BONDED_DEVICE_FILTER.matches(cachedDevice.getDevice())) { + continue; + } + if (BluetoothUtils.isExclusivelyManagedBluetoothDevice(mContext, + cachedDevice.getDevice())) { + continue; + } + SearchIndexableRaw data = new SearchIndexableRaw(mContext); + // Include the identity address as well to ensure the key is unique. + data.key = cachedDevice.getName() + cachedDevice.getIdentityAddress(); + data.title = cachedDevice.getName(); + data.summaryOn = mContext.getString(R.string.connected_devices_dashboard_title); + rawData.add(data); + } + } } diff --git a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceGroupControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceGroupControllerTest.java index a35ef45f518..d28ab3b928b 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceGroupControllerTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceGroupControllerTest.java @@ -27,9 +27,12 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.bluetooth.BluetoothDevice; import android.content.Context; import android.content.pm.PackageManager; import android.hardware.input.InputManager; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import android.util.FeatureFlagUtils; import android.view.InputDevice; @@ -39,13 +42,23 @@ import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; import com.android.settings.bluetooth.ConnectedBluetoothDeviceUpdater; +import com.android.settings.bluetooth.Utils; import com.android.settings.connecteddevice.dock.DockUpdater; import com.android.settings.connecteddevice.stylus.StylusDeviceUpdater; import com.android.settings.connecteddevice.usb.ConnectedUsbDeviceUpdater; import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.flags.Flags; import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; +import com.android.settings.testutils.shadow.ShadowBluetoothUtils; +import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; +import com.android.settingslib.bluetooth.LocalBluetoothManager; +import com.android.settingslib.search.SearchIndexableRaw; + +import com.google.common.collect.ImmutableList; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; @@ -57,11 +70,16 @@ import org.robolectric.Shadows; import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowApplicationPackageManager; +import java.util.ArrayList; +import java.util.List; + @RunWith(RobolectricTestRunner.class) -@Config(shadows = {ShadowApplicationPackageManager.class, ShadowBluetoothAdapter.class}) +@Config(shadows = {ShadowApplicationPackageManager.class, ShadowBluetoothUtils.class, + ShadowBluetoothAdapter.class}) public class ConnectedDeviceGroupControllerTest { private static final String PREFERENCE_KEY_1 = "pref_key_1"; + private static final String DEVICE_NAME = "device"; @Mock private DashboardFragment mDashboardFragment; @@ -79,6 +97,14 @@ public class ConnectedDeviceGroupControllerTest { private PreferenceManager mPreferenceManager; @Mock private InputManager mInputManager; + @Mock + private CachedBluetoothDeviceManager mCachedDeviceManager; + @Mock + private LocalBluetoothManager mLocalBluetoothManager; + @Mock + private CachedBluetoothDevice mCachedDevice; + @Mock + private BluetoothDevice mDevice; private ShadowApplicationPackageManager mPackageManager; private PreferenceGroup mPreferenceGroup; @@ -86,6 +112,9 @@ public class ConnectedDeviceGroupControllerTest { private Preference mPreference; private ConnectedDeviceGroupController mConnectedDeviceGroupController; + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + @Before public void setUp() { MockitoAnnotations.initMocks(this); @@ -102,11 +131,20 @@ public class ConnectedDeviceGroupControllerTest { when(mContext.getSystemService(InputManager.class)).thenReturn(mInputManager); when(mInputManager.getInputDeviceIds()).thenReturn(new int[]{}); + ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager; + mLocalBluetoothManager = Utils.getLocalBtManager(mContext); + when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager); + mConnectedDeviceGroupController = new ConnectedDeviceGroupController(mContext); mConnectedDeviceGroupController.init(mConnectedBluetoothDeviceUpdater, mConnectedUsbDeviceUpdater, mConnectedDockUpdater, mStylusDeviceUpdater); mConnectedDeviceGroupController.mPreferenceGroup = mPreferenceGroup; + when(mCachedDevice.getName()).thenReturn(DEVICE_NAME); + when(mCachedDevice.getDevice()).thenReturn(mDevice); + when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn( + ImmutableList.of(mCachedDevice)); + FeatureFlagUtils.setEnabled(mContext, FeatureFlagUtils.SETTINGS_SHOW_STYLUS_PREFERENCES, true); } @@ -267,4 +305,27 @@ public class ConnectedDeviceGroupControllerTest { mConnectedDeviceGroupController.onStart(); mConnectedDeviceGroupController.onStop(); } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_BONDED_BLUETOOTH_DEVICE_SEARCHABLE) + public void updateDynamicRawDataToIndex_deviceNotBonded_deviceIsNotSearchable() { + when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_NONE); + List searchData = new ArrayList<>(); + + mConnectedDeviceGroupController.updateDynamicRawDataToIndex(searchData); + + assertThat(searchData).isEmpty(); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_BONDED_BLUETOOTH_DEVICE_SEARCHABLE) + public void updateDynamicRawDataToIndex_deviceBonded_deviceIsSearchable() { + when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); + List searchData = new ArrayList<>(); + + mConnectedDeviceGroupController.updateDynamicRawDataToIndex(searchData); + + assertThat(searchData).isNotEmpty(); + assertThat(searchData.get(0).key).contains(DEVICE_NAME); + } }