From e8c79b042ef46e73fda01902a07cfc807c821ca2 Mon Sep 17 00:00:00 2001 From: hughchen Date: Tue, 21 Apr 2020 17:26:21 +0800 Subject: [PATCH 1/3] Add new route type for support 3.5 mm headset and usb headset - This CL add new route type for support 3.5 mm headset and usb headset. - Add test case. Bug: 153711362 Test: make -j42 RunSettingsLibRoboTests Change-Id: I6daa22a7bec161fbe47e554a27ae51e4feab1185 --- .../settingslib/media/InfoMediaManager.java | 18 ++++++-- .../settingslib/media/MediaDevice.java | 12 +++++ .../settingslib/media/PhoneMediaDevice.java | 17 +++++++ .../media/InfoMediaManagerTest.java | 46 +++++++++++++++++++ .../media/PhoneMediaDeviceTest.java | 5 +- 5 files changed, 93 insertions(+), 5 deletions(-) diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java index 19c8b20b7822b..d14cb25beff03 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java @@ -17,11 +17,16 @@ package com.android.settingslib.media; import static android.media.MediaRoute2Info.TYPE_BLUETOOTH_A2DP; import static android.media.MediaRoute2Info.TYPE_BUILTIN_SPEAKER; +import static android.media.MediaRoute2Info.TYPE_DOCK; import static android.media.MediaRoute2Info.TYPE_GROUP; +import static android.media.MediaRoute2Info.TYPE_HDMI; import static android.media.MediaRoute2Info.TYPE_HEARING_AID; import static android.media.MediaRoute2Info.TYPE_REMOTE_SPEAKER; import static android.media.MediaRoute2Info.TYPE_REMOTE_TV; import static android.media.MediaRoute2Info.TYPE_UNKNOWN; +import static android.media.MediaRoute2Info.TYPE_USB_ACCESSORY; +import static android.media.MediaRoute2Info.TYPE_USB_DEVICE; +import static android.media.MediaRoute2Info.TYPE_USB_HEADSET; import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES; import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET; import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR; @@ -339,7 +344,7 @@ public class InfoMediaManager extends MediaManager { for (MediaRoute2Info route : mRouterManager.getAllRoutes()) { if (DEBUG) { Log.d(TAG, "buildAllRoutes() route : " + route.getName() + ", volume : " - + route.getVolume()); + + route.getVolume() + ", type : " + route.getType()); } if (route.isSystemRoute()) { addMediaDevice(route); @@ -350,13 +355,15 @@ public class InfoMediaManager extends MediaManager { private void buildAvailableRoutes() { for (MediaRoute2Info route : mRouterManager.getAvailableRoutes(mPackageName)) { if (DEBUG) { - Log.d(TAG, "buildAvailableRoutes() route : " + route.getName()); + Log.d(TAG, "buildAvailableRoutes() route : " + route.getName() + + ", type : " + route.getType()); } addMediaDevice(route); } } - private void addMediaDevice(MediaRoute2Info route) { + @VisibleForTesting + void addMediaDevice(MediaRoute2Info route) { final int deviceType = route.getType(); MediaDevice mediaDevice = null; switch (deviceType) { @@ -374,6 +381,11 @@ public class InfoMediaManager extends MediaManager { } break; case TYPE_BUILTIN_SPEAKER: + case TYPE_USB_DEVICE: + case TYPE_USB_HEADSET: + case TYPE_USB_ACCESSORY: + case TYPE_DOCK: + case TYPE_HDMI: case TYPE_WIRED_HEADSET: case TYPE_WIRED_HEADPHONES: mediaDevice = diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java index 6aff301f57d47..ae5348b106da2 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java @@ -17,11 +17,16 @@ package com.android.settingslib.media; import static android.media.MediaRoute2Info.TYPE_BLUETOOTH_A2DP; import static android.media.MediaRoute2Info.TYPE_BUILTIN_SPEAKER; +import static android.media.MediaRoute2Info.TYPE_DOCK; import static android.media.MediaRoute2Info.TYPE_GROUP; +import static android.media.MediaRoute2Info.TYPE_HDMI; import static android.media.MediaRoute2Info.TYPE_HEARING_AID; import static android.media.MediaRoute2Info.TYPE_REMOTE_SPEAKER; import static android.media.MediaRoute2Info.TYPE_REMOTE_TV; import static android.media.MediaRoute2Info.TYPE_UNKNOWN; +import static android.media.MediaRoute2Info.TYPE_USB_ACCESSORY; +import static android.media.MediaRoute2Info.TYPE_USB_DEVICE; +import static android.media.MediaRoute2Info.TYPE_USB_HEADSET; import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES; import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET; @@ -102,6 +107,13 @@ public abstract class MediaDevice implements Comparable { case TYPE_WIRED_HEADPHONES: mType = MediaDeviceType.TYPE_3POINT5_MM_AUDIO_DEVICE; break; + case TYPE_USB_DEVICE: + case TYPE_USB_HEADSET: + case TYPE_USB_ACCESSORY: + case TYPE_DOCK: + case TYPE_HDMI: + mType = MediaDeviceType.TYPE_USB_C_AUDIO_DEVICE; + break; case TYPE_HEARING_AID: case TYPE_BLUETOOTH_A2DP: mType = MediaDeviceType.TYPE_BLUETOOTH_DEVICE; diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java index c6c5ade90eb5c..42f2542e5c304 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java @@ -16,6 +16,11 @@ package com.android.settingslib.media; import static android.media.MediaRoute2Info.TYPE_BUILTIN_SPEAKER; +import static android.media.MediaRoute2Info.TYPE_DOCK; +import static android.media.MediaRoute2Info.TYPE_HDMI; +import static android.media.MediaRoute2Info.TYPE_USB_ACCESSORY; +import static android.media.MediaRoute2Info.TYPE_USB_DEVICE; +import static android.media.MediaRoute2Info.TYPE_USB_HEADSET; import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES; import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET; @@ -53,6 +58,13 @@ public class PhoneMediaDevice extends MediaDevice { switch (mRouteInfo.getType()) { case TYPE_WIRED_HEADSET: case TYPE_WIRED_HEADPHONES: + name = mContext.getString(R.string.media_transfer_wired_device_name); + break; + case TYPE_USB_DEVICE: + case TYPE_USB_HEADSET: + case TYPE_USB_ACCESSORY: + case TYPE_DOCK: + case TYPE_HDMI: name = mRouteInfo.getName(); break; case TYPE_BUILTIN_SPEAKER: @@ -78,6 +90,11 @@ public class PhoneMediaDevice extends MediaDevice { int getDrawableResId() { int resId; switch (mRouteInfo.getType()) { + case TYPE_USB_DEVICE: + case TYPE_USB_HEADSET: + case TYPE_USB_ACCESSORY: + case TYPE_DOCK: + case TYPE_HDMI: case TYPE_WIRED_HEADSET: case TYPE_WIRED_HEADPHONES: resId = com.android.internal.R.drawable.ic_bt_headphones_a2dp; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java index c21582cdf203c..b5dc1f7f8f4eb 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java @@ -16,20 +16,29 @@ package com.android.settingslib.media; +import static android.media.MediaRoute2Info.TYPE_BLUETOOTH_A2DP; +import static android.media.MediaRoute2Info.TYPE_BUILTIN_SPEAKER; +import static android.media.MediaRoute2Info.TYPE_REMOTE_SPEAKER; +import static android.media.MediaRoute2Info.TYPE_USB_DEVICE; +import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET; import static android.media.MediaRoute2ProviderService.REASON_NETWORK_ERROR; import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.bluetooth.BluetoothDevice; import android.content.Context; import android.media.MediaRoute2Info; import android.media.MediaRouter2Manager; import android.media.RoutingSessionInfo; +import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.testutils.shadow.ShadowRouter2Manager; @@ -601,4 +610,41 @@ public class InfoMediaManagerTest { assertThat(mInfoMediaManager.mMediaDevices).hasSize(routes.size()); verify(mCallback).onConnectedDeviceChanged(null); } + + @Test + public void addMediaDevice_verifyDeviceTypeCanCorrespondToMediaDevice() { + final MediaRoute2Info route2Info = mock(MediaRoute2Info.class); + final CachedBluetoothDeviceManager cachedBluetoothDeviceManager = + mock(CachedBluetoothDeviceManager.class); + final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class); + + when(route2Info.getType()).thenReturn(TYPE_REMOTE_SPEAKER); + mInfoMediaManager.addMediaDevice(route2Info); + assertThat(mInfoMediaManager.mMediaDevices.get(0) instanceof InfoMediaDevice).isTrue(); + + when(route2Info.getType()).thenReturn(TYPE_USB_DEVICE); + mInfoMediaManager.mMediaDevices.clear(); + mInfoMediaManager.addMediaDevice(route2Info); + assertThat(mInfoMediaManager.mMediaDevices.get(0) instanceof PhoneMediaDevice).isTrue(); + + when(route2Info.getType()).thenReturn(TYPE_WIRED_HEADSET); + mInfoMediaManager.mMediaDevices.clear(); + mInfoMediaManager.addMediaDevice(route2Info); + assertThat(mInfoMediaManager.mMediaDevices.get(0) instanceof PhoneMediaDevice).isTrue(); + + when(route2Info.getType()).thenReturn(TYPE_BLUETOOTH_A2DP); + when(route2Info.getOriginalId()).thenReturn("00:00:00:00:00:00"); + when(mLocalBluetoothManager.getCachedDeviceManager()) + .thenReturn(cachedBluetoothDeviceManager); + when(cachedBluetoothDeviceManager.findDevice(any(BluetoothDevice.class))) + .thenReturn(cachedDevice); + mInfoMediaManager.mMediaDevices.clear(); + mInfoMediaManager.addMediaDevice(route2Info); + assertThat(mInfoMediaManager.mMediaDevices.get(0) instanceof BluetoothMediaDevice).isTrue(); + + when(route2Info.getType()).thenReturn(TYPE_BUILTIN_SPEAKER); + mInfoMediaManager.mMediaDevices.clear(); + mInfoMediaManager.addMediaDevice(route2Info); + assertThat(mInfoMediaManager.mMediaDevices.get(0) instanceof PhoneMediaDevice).isTrue(); + } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java index 4c5cd9682b0f5..6f265dd603e51 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java @@ -17,6 +17,7 @@ package com.android.settingslib.media; import static android.media.MediaRoute2Info.TYPE_BUILTIN_SPEAKER; +import static android.media.MediaRoute2Info.TYPE_USB_DEVICE; import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES; import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET; @@ -95,9 +96,9 @@ public class PhoneMediaDeviceTest { when(mInfo.getName()).thenReturn(deviceName); assertThat(mPhoneMediaDevice.getName()) - .isEqualTo(deviceName); + .isEqualTo(mContext.getString(R.string.media_transfer_wired_device_name)); - when(mInfo.getType()).thenReturn(TYPE_WIRED_HEADSET); + when(mInfo.getType()).thenReturn(TYPE_USB_DEVICE); assertThat(mPhoneMediaDevice.getName()) .isEqualTo(deviceName); From 31901c037b0ffb0739b8e77653249239bbcf0eaf Mon Sep 17 00:00:00 2001 From: hughchen Date: Wed, 22 Apr 2020 19:31:28 +0800 Subject: [PATCH 2/3] 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 --- .../media/BluetoothMediaDevice.java | 7 ++ .../settingslib/media/LocalMediaManager.java | 3 +- .../settingslib/media/MediaDevice.java | 89 ++++++++++++------- .../media/BluetoothMediaDeviceTest.java | 27 ++++++ .../media/LocalMediaManagerTest.java | 6 ++ .../settingslib/media/MediaDeviceTest.java | 72 +++++++++++---- 6 files changed, 152 insertions(+), 52 deletions(-) diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java index ee8fb38ef08ca..74a59399feee6 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java @@ -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 diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java index a62d76f732da0..af691783e85d5 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java @@ -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)); } diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java index ae5348b106da2..f1c0f6b44150f 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java @@ -278,16 +278,22 @@ public abstract class MediaDevice implements Comparable { /** * 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,39 +313,50 @@ public abstract class MediaDevice implements Comparable { } } - // Phone device always in the top. - if (mType == MediaDeviceType.TYPE_PHONE_DEVICE) { - return -1; - } else if (another.mType == MediaDeviceType.TYPE_PHONE_DEVICE) { - 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(); - if (TextUtils.equals(lastSelectedDevice, getId())) { - return -1; - } else if (TextUtils.equals(lastSelectedDevice, another.getId())) { - return 1; - } - // Sort by how many times the device has been used if there is usage record - if ((mConnectedRecord != another.mConnectedRecord) - && (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) { + // Check fast pair device + if (isFastPairDevice()) { + return -1; + } 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 + final String lastSelectedDevice = ConnectionRecordManager.getInstance() + .getLastSelectedDevice(); + if (TextUtils.equals(lastSelectedDevice, getId())) { + return -1; + } else if (TextUtils.equals(lastSelectedDevice, another.getId())) { + return 1; + } + // Sort by how many times the device has been used if there is usage record + if ((mConnectedRecord != another.mConnectedRecord) + && (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 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 { 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)) { diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java index a39bcb7f08f63..8973d116e4389 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java @@ -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(); + } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java index 206c8590a9525..f3b49a69201bc 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java @@ -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); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java index db05b768f5db6..6664870a62578 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java @@ -18,9 +18,11 @@ package com.android.settingslib.media; import static android.media.MediaRoute2Info.TYPE_BLUETOOTH_A2DP; import static android.media.MediaRoute2Info.TYPE_BUILTIN_SPEAKER; import static android.media.MediaRoute2Info.TYPE_REMOTE_SPEAKER; +import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -210,14 +212,14 @@ public class MediaDeviceTest { } @Test - public void compareTo_carKit_phone_phoneFirst() { + public void compareTo_carKit_phone_carKitFirst() { when(mDevice1.getBluetoothClass()).thenReturn(mCarkitClass); - mMediaDevices.add(mBluetoothMediaDevice1); mMediaDevices.add(mPhoneMediaDevice); + mMediaDevices.add(mBluetoothMediaDevice1); - assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1); - Collections.sort(mMediaDevices, COMPARATOR); assertThat(mMediaDevices.get(0)).isEqualTo(mPhoneMediaDevice); + Collections.sort(mMediaDevices, COMPARATOR); + assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1); } @Test @@ -281,7 +283,7 @@ public class MediaDeviceTest { } @Test - public void compareTo_info_bluetooth_infoFirst() { + public void compareTo_info_bluetooth_bluetoothFirst() { mMediaDevices.add(mInfoMediaDevice1); mMediaDevices.add(mBluetoothMediaDevice1); @@ -291,13 +293,45 @@ public class MediaDeviceTest { } @Test - public void compareTo_bluetooth_phone_phoneFirst() { - mMediaDevices.add(mBluetoothMediaDevice1); + public void compareTo_bluetooth_phone_bluetoothFirst() { mMediaDevices.add(mPhoneMediaDevice); + mMediaDevices.add(mBluetoothMediaDevice1); + + assertThat(mMediaDevices.get(0)).isEqualTo(mPhoneMediaDevice); + Collections.sort(mMediaDevices, COMPARATOR); + assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1); + } + + @Test + public void compareTo_bluetooth_wiredHeadset_wiredHeadsetFirst() { + final MediaRoute2Info phoneRouteInfo = mock(MediaRoute2Info.class); + when(phoneRouteInfo.getType()).thenReturn(TYPE_WIRED_HEADPHONES); + + final PhoneMediaDevice phoneMediaDevice = new PhoneMediaDevice(mContext, + mMediaRouter2Manager, phoneRouteInfo, TEST_PACKAGE_NAME); + + mMediaDevices.add(mBluetoothMediaDevice1); + mMediaDevices.add(phoneMediaDevice); assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1); Collections.sort(mMediaDevices, COMPARATOR); - assertThat(mMediaDevices.get(0)).isEqualTo(mPhoneMediaDevice); + assertThat(mMediaDevices.get(0)).isEqualTo(phoneMediaDevice); + } + + @Test + public void compareTo_info_wiredHeadset_wiredHeadsetFirst() { + final MediaRoute2Info phoneRouteInfo = mock(MediaRoute2Info.class); + when(phoneRouteInfo.getType()).thenReturn(TYPE_WIRED_HEADPHONES); + + final PhoneMediaDevice phoneMediaDevice = new PhoneMediaDevice(mContext, + mMediaRouter2Manager, phoneRouteInfo, TEST_PACKAGE_NAME); + + mMediaDevices.add(mInfoMediaDevice1); + mMediaDevices.add(phoneMediaDevice); + + assertThat(mMediaDevices.get(0)).isEqualTo(mInfoMediaDevice1); + Collections.sort(mMediaDevices, COMPARATOR); + assertThat(mMediaDevices.get(0)).isEqualTo(phoneMediaDevice); } @Test @@ -338,7 +372,7 @@ public class MediaDeviceTest { // 5.mBluetoothMediaDevice2: * 2 times usage // 6.mBluetoothMediaDevice3: * 1 time usage // 7.mPhoneMediaDevice: * 0 time usage - // Order: 7 -> 2 -> 1 -> 5 -> 3 -> 6 -> 4 + // Order: 2 -> 5 -> 6 -> 1 -> 3 -> 4 -> 7 @Test public void compareTo_mixedDevices_carKitFirst() { when(mDevice1.getBluetoothClass()).thenReturn(mCarkitClass); @@ -360,13 +394,13 @@ public class MediaDeviceTest { mInfoMediaDevice1.connect(); Collections.sort(mMediaDevices, COMPARATOR); - assertThat(mMediaDevices.get(0)).isEqualTo(mPhoneMediaDevice); - assertThat(mMediaDevices.get(1)).isEqualTo(mBluetoothMediaDevice1); - assertThat(mMediaDevices.get(2)).isEqualTo(mInfoMediaDevice1); - assertThat(mMediaDevices.get(3)).isEqualTo(mBluetoothMediaDevice2); + assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1); + assertThat(mMediaDevices.get(1)).isEqualTo(mBluetoothMediaDevice2); + assertThat(mMediaDevices.get(2)).isEqualTo(mBluetoothMediaDevice3); + assertThat(mMediaDevices.get(3)).isEqualTo(mInfoMediaDevice1); assertThat(mMediaDevices.get(4)).isEqualTo(mInfoMediaDevice2); - assertThat(mMediaDevices.get(5)).isEqualTo(mBluetoothMediaDevice3); - assertThat(mMediaDevices.get(6)).isEqualTo(mInfoMediaDevice3); + assertThat(mMediaDevices.get(5)).isEqualTo(mInfoMediaDevice3); + assertThat(mMediaDevices.get(6)).isEqualTo(mPhoneMediaDevice); } // 1.mInfoMediaDevice1: Last Selected device @@ -376,7 +410,7 @@ public class MediaDeviceTest { // 5.mBluetoothMediaDevice2: * 4 times usage not connected // 6.mBluetoothMediaDevice3: * 1 time usage // 7.mPhoneMediaDevice: * 0 time usage - // Order: 7 -> 1 -> 3 -> 6 -> 4 -> 2 -> 5 + // Order: 6 -> 1 -> 3 -> 4 -> 7 -> 2 -> 5 @Test public void compareTo_mixedDevices_connectDeviceFirst() { when(mDevice1.getBluetoothClass()).thenReturn(mCarkitClass); @@ -402,11 +436,11 @@ public class MediaDeviceTest { mInfoMediaDevice1.connect(); Collections.sort(mMediaDevices, COMPARATOR); - assertThat(mMediaDevices.get(0)).isEqualTo(mPhoneMediaDevice); + assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice3); assertThat(mMediaDevices.get(1)).isEqualTo(mInfoMediaDevice1); assertThat(mMediaDevices.get(2)).isEqualTo(mInfoMediaDevice2); - assertThat(mMediaDevices.get(3)).isEqualTo(mBluetoothMediaDevice3); - assertThat(mMediaDevices.get(4)).isEqualTo(mInfoMediaDevice3); + assertThat(mMediaDevices.get(3)).isEqualTo(mInfoMediaDevice3); + assertThat(mMediaDevices.get(4)).isEqualTo(mPhoneMediaDevice); assertThat(mMediaDevices.get(5)).isEqualTo(mBluetoothMediaDevice1); assertThat(mMediaDevices.get(6)).isEqualTo(mBluetoothMediaDevice2); } From 71a7f826dcf9ca31877f85e1e64ad5ec6c73b552 Mon Sep 17 00:00:00 2001 From: hughchen Date: Fri, 24 Apr 2020 14:59:05 +0800 Subject: [PATCH 3/3] Add null check when build MediaDevice - We may not found CachedBluetoothDevice through CachedBluetoothDeviceManager. This CL add null check before we build the MediaDevice. - Add test case Bug: 154152005 Test: make -j42 RunSettingsLibRoboTests Change-Id: I042912317e1924d8b9bdababf0b7dcb69836f9e2 --- .../settingslib/media/InfoMediaManager.java | 6 ++++-- .../media/InfoMediaManagerTest.java | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java index d14cb25beff03..002bbec609244 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java @@ -397,8 +397,10 @@ public class InfoMediaManager extends MediaManager { BluetoothAdapter.getDefaultAdapter().getRemoteDevice(route.getOriginalId()); final CachedBluetoothDevice cachedDevice = mBluetoothManager.getCachedDeviceManager().findDevice(device); - mediaDevice = new BluetoothMediaDevice(mContext, cachedDevice, mRouterManager, - route, mPackageName); + if (cachedDevice != null) { + mediaDevice = new BluetoothMediaDevice(mContext, cachedDevice, mRouterManager, + route, mPackageName); + } break; default: Log.w(TAG, "addMediaDevice() unknown device type : " + deviceType); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java index b5dc1f7f8f4eb..76eea67f97655 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java @@ -647,4 +647,23 @@ public class InfoMediaManagerTest { mInfoMediaManager.addMediaDevice(route2Info); assertThat(mInfoMediaManager.mMediaDevices.get(0) instanceof PhoneMediaDevice).isTrue(); } + + @Test + public void addMediaDevice_cachedBluetoothDeviceIsNull_shouldNotAdded() { + final MediaRoute2Info route2Info = mock(MediaRoute2Info.class); + final CachedBluetoothDeviceManager cachedBluetoothDeviceManager = + mock(CachedBluetoothDeviceManager.class); + + when(route2Info.getType()).thenReturn(TYPE_BLUETOOTH_A2DP); + when(route2Info.getOriginalId()).thenReturn("00:00:00:00:00:00"); + when(mLocalBluetoothManager.getCachedDeviceManager()) + .thenReturn(cachedBluetoothDeviceManager); + when(cachedBluetoothDeviceManager.findDevice(any(BluetoothDevice.class))) + .thenReturn(null); + + mInfoMediaManager.mMediaDevices.clear(); + mInfoMediaManager.addMediaDevice(route2Info); + + assertThat(mInfoMediaManager.mMediaDevices.size()).isEqualTo(0); + } }