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

Commit 54163423 authored by Yanting Yang's avatar Yanting Yang
Browse files

Support Bluetooth activation in BluetoothDevicesSlice

- Show available media devices only.
- Support activation for available media devices.

Bug: 114807655
Test: visual, robotest
Change-Id: Ie3058598a103a0fedc451a0e4d7f91603dcee0fc
parent 0ade53c9
Loading
Loading
Loading
Loading
+43 −24
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.slices.CustomSliceRegistry;
import com.android.settings.slices.CustomSliceable;
import com.android.settings.slices.SliceBroadcastReceiver;
import com.android.settings.slices.SliceBuilderUtils;
import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -59,10 +60,12 @@ import java.util.stream.Collectors;

public class BluetoothDevicesSlice implements CustomSliceable {

    @VisibleForTesting
    static final String BLUETOOTH_DEVICE_HASH_CODE = "bluetooth_device_hash_code";

    /**
     * TODO(b/114807655): Contextual Home Page - Connected Device
     * Re-design sorting for new rule:
     * Sorting rule: Audio Streaming > Last connected > Recently connected.
     * Refer {@link com.android.settings.bluetooth.BluetoothDevicePreference#compareTo} to sort the
     * Bluetooth devices by {@link CachedBluetoothDevice}.
     */
    private static final Comparator<CachedBluetoothDevice> COMPARATOR
            = Comparator.naturalOrder();
@@ -109,12 +112,11 @@ public class BluetoothDevicesSlice implements CustomSliceable {
        final SliceAction primarySliceAction = SliceAction.createDeeplink(primaryActionIntent, icon,
                ListBuilder.ICON_IMAGE, title);
        final ListBuilder listBuilder =
                new ListBuilder(mContext, CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI,
                        ListBuilder.INFINITY)
                new ListBuilder(mContext, getUri(), ListBuilder.INFINITY)
                        .setAccentColor(Utils.getColorAccentDefaultColor(mContext));

        // Get row builders by Bluetooth devices.
        final List<ListBuilder.RowBuilder> rows = getBluetoothRowBuilder(primarySliceAction);
        final List<ListBuilder.RowBuilder> rows = getBluetoothRowBuilder();

        // Return a header with IsError flag, if no Bluetooth devices.
        if (rows.isEmpty()) {
@@ -131,7 +133,7 @@ public class BluetoothDevicesSlice implements CustomSliceable {
                .setSubtitle(getSubTitle(rows.size()))
                .setPrimaryAction(primarySliceAction));

        // Add bluetooth device rows.
        // Add Bluetooth device rows.
        for (ListBuilder.RowBuilder rowBuilder : rows) {
            listBuilder.addRow(rowBuilder);
        }
@@ -154,11 +156,19 @@ public class BluetoothDevicesSlice implements CustomSliceable {
                screenTitle,
                MetricsProto.MetricsEvent.SLICE)
                .setClassName(mContext.getPackageName(), SubSettings.class.getName())
                .setData(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI);
                .setData(getUri());
    }

    @Override
    public void onNotifyChange(Intent intent) {
        // Activate available media device.
        final int bluetoothDeviceHashCode = intent.getIntExtra(BLUETOOTH_DEVICE_HASH_CODE, -1);
        for (CachedBluetoothDevice cachedBluetoothDevice : getConnectedBluetoothDevices()) {
            if (cachedBluetoothDevice.hashCode() == bluetoothDeviceHashCode) {
                cachedBluetoothDevice.setActive();
                return;
            }
        }
    }

    @Override
@@ -167,10 +177,10 @@ public class BluetoothDevicesSlice implements CustomSliceable {
    }

    @VisibleForTesting
    List<CachedBluetoothDevice> getBluetoothDevices() {
    List<CachedBluetoothDevice> getConnectedBluetoothDevices() {
        final List<CachedBluetoothDevice> bluetoothDeviceList = new ArrayList<>();

        // If Bluetooth is disable, skip to get the bluetooth devices.
        // If Bluetooth is disable, skip to get the Bluetooth devices.
        if (!BluetoothAdapter.getDefaultAdapter().isEnabled()) {
            Log.i(TAG, "Cannot get Bluetooth devices, Bluetooth is disabled.");
            return bluetoothDeviceList;
@@ -188,12 +198,13 @@ public class BluetoothDevicesSlice implements CustomSliceable {

        /**
         * TODO(b/114807655): Contextual Home Page - Connected Device
         * Re-design to get all Bluetooth devices and sort them by new rule:
         * Sorting rule: Audio Streaming > Last connected > Recently connected.
         * It's under discussion for including available media devices and currently connected
         * devices from Bluetooth. Will update the devices list or remove TODO later.
         */
        // Get connected Bluetooth devices and sort them.
        return cachedDevices.stream().filter(device -> device.isConnected()).sorted(
                COMPARATOR).collect(Collectors.toList());
        // Get available media device list and sort them.
        return cachedDevices.stream()
                .filter(device -> device.isConnected() && device.isConnectedA2dpDevice())
                .sorted(COMPARATOR).collect(Collectors.toList());
    }

    @VisibleForTesting
@@ -226,27 +237,35 @@ public class BluetoothDevicesSlice implements CustomSliceable {
        }
    }

    private List<ListBuilder.RowBuilder> getBluetoothRowBuilder(SliceAction primarySliceAction) {
    private List<ListBuilder.RowBuilder> getBluetoothRowBuilder() {
        // According Bluetooth devices to create row builders.
        final List<ListBuilder.RowBuilder> bluetoothRows = new ArrayList<>();

        /**
         * TODO(b/114807655): Contextual Home Page - Connected Device
         * Re-design to do action "activating" in primary action.
         */
        // According Bluetooth device to create row builders.
        final List<CachedBluetoothDevice> bluetoothDevices = getBluetoothDevices();
        final List<CachedBluetoothDevice> bluetoothDevices = getConnectedBluetoothDevices();
        for (CachedBluetoothDevice bluetoothDevice : bluetoothDevices) {
            bluetoothRows.add(new ListBuilder.RowBuilder()
                    .setTitleItem(getBluetoothDeviceIcon(bluetoothDevice), ListBuilder.ICON_IMAGE)
                    .setTitle(bluetoothDevice.getName())
                    .setSubtitle(bluetoothDevice.getConnectionSummary())
                    .setPrimaryAction(primarySliceAction)
                    .setPrimaryAction(buildBluetoothDeviceAction(bluetoothDevice))
                    .addEndItem(buildBluetoothDetailDeepLinkAction(bluetoothDevice)));
        }

        return bluetoothRows;
    }

    private SliceAction buildBluetoothDeviceAction(CachedBluetoothDevice bluetoothDevice) {
        // Send broadcast to activate available media device.
        final Intent intent = new Intent(getUri().toString())
                .setClass(mContext, SliceBroadcastReceiver.class)
                .putExtra(BLUETOOTH_DEVICE_HASH_CODE, bluetoothDevice.hashCode());

        return SliceAction.create(
                PendingIntent.getBroadcast(mContext, bluetoothDevice.hashCode(), intent, 0),
                getBluetoothDeviceIcon(bluetoothDevice),
                ListBuilder.ICON_IMAGE,
                bluetoothDevice.getName());
    }

    private SliceAction buildBluetoothDetailDeepLinkAction(CachedBluetoothDevice bluetoothDevice) {
        return SliceAction.createDeeplink(
                getBluetoothDetailIntent(bluetoothDevice),
+22 −5
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.app.PendingIntent;
@@ -54,6 +55,7 @@ import java.util.List;
@RunWith(RobolectricTestRunner.class)
public class BluetoothDevicesSliceTest {

    private static final String BLUETOOTH_MOCK_ADDRESS = "00:11:00:11:00:11";
    private static final String BLUETOOTH_MOCK_SUMMARY = "BluetoothSummary";
    private static final String BLUETOOTH_MOCK_TITLE = "BluetoothTitle";

@@ -96,7 +98,7 @@ public class BluetoothDevicesSliceTest {
    @Test
    public void getSlice_hasBluetoothDevices_shouldHaveBluetoothDevicesTitle() {
        mockBluetoothDeviceList();
        doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getBluetoothDevices();
        doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getConnectedBluetoothDevices();

        final Slice slice = mBluetoothDevicesSlice.getSlice();

@@ -107,7 +109,7 @@ public class BluetoothDevicesSliceTest {
    @Test
    public void getSlice_hasBluetoothDevices_shouldMatchBluetoothMockTitle() {
        mockBluetoothDeviceList();
        doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getBluetoothDevices();
        doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getConnectedBluetoothDevices();

        final Slice slice = mBluetoothDevicesSlice.getSlice();

@@ -118,7 +120,7 @@ public class BluetoothDevicesSliceTest {
    @Test
    public void getSlice_hasBluetoothDevices_shouldHavePairNewDevice() {
        mockBluetoothDeviceList();
        doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getBluetoothDevices();
        doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getConnectedBluetoothDevices();

        final Slice slice = mBluetoothDevicesSlice.getSlice();

@@ -129,7 +131,7 @@ public class BluetoothDevicesSliceTest {

    @Test
    public void getSlice_noBluetoothDevices_shouldHaveNoBluetoothDevicesTitle() {
        doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getBluetoothDevices();
        doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getConnectedBluetoothDevices();

        final Slice slice = mBluetoothDevicesSlice.getSlice();

@@ -139,7 +141,7 @@ public class BluetoothDevicesSliceTest {

    @Test
    public void getSlice_noBluetoothDevices_shouldNotHavePairNewDevice() {
        doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getBluetoothDevices();
        doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getConnectedBluetoothDevices();

        final Slice slice = mBluetoothDevicesSlice.getSlice();

@@ -148,9 +150,24 @@ public class BluetoothDevicesSliceTest {
                mContext.getString(R.string.bluetooth_pairing_pref_title))).isFalse();
    }

    @Test
    public void onNotifyChange_mediaDevice_shouldActivateDevice() {
        mockBluetoothDeviceList();
        doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getConnectedBluetoothDevices();
        final Intent intent = new Intent().putExtra(
                BluetoothDevicesSlice.BLUETOOTH_DEVICE_HASH_CODE,
                mCachedBluetoothDevice.hashCode());

        mBluetoothDevicesSlice.onNotifyChange(intent);

        verify(mCachedBluetoothDevice).setActive();
    }

    private void mockBluetoothDeviceList() {
        doReturn(BLUETOOTH_MOCK_TITLE).when(mCachedBluetoothDevice).getName();
        doReturn(BLUETOOTH_MOCK_SUMMARY).when(mCachedBluetoothDevice).getConnectionSummary();
        doReturn(BLUETOOTH_MOCK_ADDRESS).when(mCachedBluetoothDevice).getAddress();
        doReturn(true).when(mCachedBluetoothDevice).isConnectedA2dpDevice();
        mBluetoothDeviceList.add(mCachedBluetoothDevice);
    }