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

Commit 31901c03 authored by hughchen's avatar hughchen
Browse files

Base on MediaDeviceType to ranking devices list

- This CL base on MediaDeviceType to ranking devices list.
  The order is followed below rule:
  1. USB-C audio device
  2. 3.5 mm audio devce
  3. Bluetooth device
  4. Cast device
  5. Cast group device
  6. Phone
- Add test case

Bug: 152633051
Test: make -j42 RunSettingsLibRoboTests
Change-Id: Ia224f6e3b420c5b9c6ea428bfc737e3624a6ebe4
parent e8c79b04
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -88,6 +88,13 @@ public class BluetoothMediaDevice extends MediaDevice {
        return false;
    }

    @Override
    public boolean isFastPairDevice() {
        return mCachedDevice != null
                && BluetoothUtils.getBooleanMetaData(
                mCachedDevice.getDevice(), BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET);
    }

    @Override
    public boolean isConnected() {
        return mCachedDevice.getBondState() == BluetoothDevice.BOND_BONDED
+2 −1
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -185,7 +186,7 @@ public class LocalMediaManager implements BluetoothCallback {
    }

    void dispatchDeviceListUpdate() {
        //TODO(b/149260820): Use new rule to rank device once device type api is ready.
        Collections.sort(mMediaDevices, COMPARATOR);
        for (DeviceCallback callback : getCallbacks()) {
            callback.onDeviceListUpdate(new ArrayList<>(mMediaDevices));
        }
+57 −32
Original line number Diff line number Diff line
@@ -278,16 +278,22 @@ public abstract class MediaDevice implements Comparable<MediaDevice> {

    /**
     * Rules:
     * 1. If there is one of the connected devices identified as a carkit, this carkit will
     * be always on the top of the device list. Rule 2 and Rule 3 can’t overrule this rule.
     * 1. If there is one of the connected devices identified as a carkit or fast pair device,
     * the fast pair device will be always on the first of the device list and carkit will be
     * second. Rule 2 and Rule 3 can’t overrule this rule.
     * 2. For devices without any usage data yet
     * WiFi device group sorted by alphabetical order + BT device group sorted by alphabetical
     * order + phone speaker
     * 3. For devices with usage record.
     * The most recent used one + device group with usage info sorted by how many times the
     * device has been used.
     * 4. Phone device always in the top and the connected Bluetooth devices, cast devices and
     * phone device will be always above on the disconnect Bluetooth devices.
     * 4. The order is followed below rule:
     *    1. USB-C audio device
     *    2. 3.5 mm audio device
     *    3. Bluetooth device
     *    4. Cast device
     *    5. Cast group device
     *    6. Phone
     *
     * So the device list will look like 5 slots ranked as below.
     * Rule 4 + Rule 1 + the most recently used device + Rule 3 + Rule 2
@@ -307,20 +313,24 @@ public abstract class MediaDevice implements Comparable<MediaDevice> {
            }
        }

        // Phone device always in the top.
        if (mType == MediaDeviceType.TYPE_PHONE_DEVICE) {
        if (mType == another.mType) {
            // Check fast pair device
            if (isFastPairDevice()) {
                return -1;
        } else if (another.mType == MediaDeviceType.TYPE_PHONE_DEVICE) {
            } else if (another.isFastPairDevice()) {
                return 1;
            }

            // Check carkit
            if (isCarKitDevice()) {
                return -1;
            } else if (another.isCarKitDevice()) {
                return 1;
            }

            // Set last used device at the first item
        String lastSelectedDevice = ConnectionRecordManager.getInstance().getLastSelectedDevice();
            final String lastSelectedDevice = ConnectionRecordManager.getInstance()
                    .getLastSelectedDevice();
            if (TextUtils.equals(lastSelectedDevice, getId())) {
                return -1;
            } else if (TextUtils.equals(lastSelectedDevice, another.getId())) {
@@ -331,15 +341,22 @@ public abstract class MediaDevice implements Comparable<MediaDevice> {
                    && (another.mConnectedRecord > 0 || mConnectedRecord > 0)) {
                return (another.mConnectedRecord - mConnectedRecord);
            }

            // Both devices have never been used
            // To devices with the same type, sort by alphabetical order
        if (mType == another.mType) {
            final String s1 = getName();
            final String s2 = another.getName();
            return s1.compareToIgnoreCase(s2);
        } else {
            // Both devices have never been used, the priority is:
            // 1. USB-C audio device
            // 2. 3.5 mm audio device
            // 3. Bluetooth device
            // 4. Cast device
            // 5. Cast group device
            // 6. Phone
            return mType < another.mType ? -1 : 1;
        }
        // Both devices have never been used, the priority is Phone > Cast > Bluetooth
        return mType - another.mType;
    }

    /**
@@ -350,6 +367,14 @@ public abstract class MediaDevice implements Comparable<MediaDevice> {
        return false;
    }

    /**
     * Check if it is FastPair device
     * @return {@code true} if it is FastPair device, otherwise return {@code false}
     */
    protected boolean isFastPairDevice() {
        return false;
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof MediaDevice)) {
+27 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.settingslib.media;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import android.bluetooth.BluetoothDevice;
@@ -69,4 +70,30 @@ public class BluetoothMediaDeviceTest {

        assertThat(mBluetoothMediaDevice.isConnected()).isFalse();
    }

    @Test
    public void isFastPairDevice_isUntetheredHeadset_returnTrue() {
        final BluetoothDevice bluetoothDevice = mock(BluetoothDevice.class);
        when(mDevice.getDevice()).thenReturn(bluetoothDevice);

        final String value = "True";
        final byte[] bytes = value.getBytes();
        when(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET))
                .thenReturn(bytes);

        assertThat(mBluetoothMediaDevice.isFastPairDevice()).isTrue();
    }

    @Test
    public void isFastPairDevice_isNotUntetheredHeadset_returnFalse() {
        final BluetoothDevice bluetoothDevice = mock(BluetoothDevice.class);
        when(mDevice.getDevice()).thenReturn(bluetoothDevice);

        final String value = "asjdaioshfaio";
        final byte[] bytes = value.getBytes();
        when(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET))
                .thenReturn(bytes);

        assertThat(mBluetoothMediaDevice.isFastPairDevice()).isFalse();
    }
}
+6 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.settingslib.media;

import static android.bluetooth.BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES;
import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR;

import static com.google.common.truth.Truth.assertThat;
@@ -28,6 +29,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.media.MediaRoute2Info;
@@ -659,6 +661,7 @@ public class LocalMediaManagerTest {
        final BluetoothDevice bluetoothDevice4 = mock(BluetoothDevice.class);
        final BluetoothDevice bluetoothDevice5 = mock(BluetoothDevice.class);
        final BluetoothDevice bluetoothDevice6 = mock(BluetoothDevice.class);
        final BluetoothClass bluetoothClass = mock(BluetoothClass.class);
        final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
        final CachedBluetoothDeviceManager cachedManager = mock(CachedBluetoothDeviceManager.class);
        bluetoothDevices.add(bluetoothDevice);
@@ -678,6 +681,9 @@ public class LocalMediaManagerTest {
        when(cachedManager.findDevice(bluetoothDevice6)).thenReturn(cachedDevice);
        when(cachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
        when(cachedDevice.isConnected()).thenReturn(false);
        when(cachedDevice.getDevice()).thenReturn(bluetoothDevice);
        when(bluetoothDevice.getBluetoothClass()).thenReturn(bluetoothClass);
        when(bluetoothClass.getDeviceClass()).thenReturn(AUDIO_VIDEO_HEADPHONES);

        when(device1.getId()).thenReturn(TEST_DEVICE_ID_1);
        when(device2.getId()).thenReturn(TEST_DEVICE_ID_2);
Loading