Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit caa3a4b9 authored by Ze Li's avatar Ze Li
Browse files

[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
parent 38236869
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -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
+41 −0
Original line number Diff line number Diff line
@@ -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<SearchIndexableRaw> 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);
        }
    }
}
+62 −1
Original line number Diff line number Diff line
@@ -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<SearchIndexableRaw> 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<SearchIndexableRaw> searchData = new ArrayList<>();

        mConnectedDeviceGroupController.updateDynamicRawDataToIndex(searchData);

        assertThat(searchData).isNotEmpty();
        assertThat(searchData.get(0).key).contains(DEVICE_NAME);
    }
}