diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java index c829bc316246a..d6586db1b50aa 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java @@ -184,6 +184,15 @@ public abstract class MediaDevice implements Comparable { */ public abstract String getId(); + /** + * Checks if device is suggested device from application + * + * @return true if device is suggested device + */ + public boolean isSuggestedDevice() { + return false; + } + void setConnectedRecord() { mConnectedRecord++; ConnectionRecordManager.getInstance().setConnectionRecord(mContext, getId(), diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index d70373c6e7dd1..db338b63da780 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2414,6 +2414,8 @@ %1$d%% Speakers & Displays + + Suggested Devices diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java index 316b64209f838..7bc0c0cc614ba 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java @@ -637,44 +637,21 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback, } // For the first time building list, to make sure the top device is the connected // device. + boolean needToHandleMutingExpectedDevice = + hasMutingExpectedDevice() && !isCurrentConnectedDeviceRemote(); + final MediaDevice connectedMediaDevice = + needToHandleMutingExpectedDevice ? null + : getCurrentConnectedMediaDevice(); if (mMediaItemList.isEmpty()) { - boolean needToHandleMutingExpectedDevice = - hasMutingExpectedDevice() && !isCurrentConnectedDeviceRemote(); - final MediaDevice connectedMediaDevice = - needToHandleMutingExpectedDevice ? null - : getCurrentConnectedMediaDevice(); if (connectedMediaDevice == null) { if (DEBUG) { Log.d(TAG, "No connected media device or muting expected device exist."); } - if (needToHandleMutingExpectedDevice) { - for (MediaDevice device : devices) { - if (device.isMutingExpectedDevice()) { - mMediaItemList.add(0, new MediaItem(device)); - mMediaItemList.add(1, new MediaItem(mContext.getString( - R.string.media_output_group_title_speakers_and_displays), - MediaItem.MediaItemType.TYPE_GROUP_DIVIDER)); - } else { - mMediaItemList.add(new MediaItem(device)); - } - } - mMediaItemList.add(new MediaItem()); - } else { - mMediaItemList.addAll( - devices.stream().map(MediaItem::new).collect(Collectors.toList())); - categorizeMediaItems(null); - } + categorizeMediaItems(null, devices, needToHandleMutingExpectedDevice); return; } // selected device exist - for (MediaDevice device : devices) { - if (TextUtils.equals(device.getId(), connectedMediaDevice.getId())) { - mMediaItemList.add(0, new MediaItem(device)); - } else { - mMediaItemList.add(new MediaItem(device)); - } - } - categorizeMediaItems(connectedMediaDevice); + categorizeMediaItems(connectedMediaDevice, devices, false); return; } // To keep the same list order @@ -708,31 +685,46 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback, } } - private void categorizeMediaItems(MediaDevice connectedMediaDevice) { + private void categorizeMediaItems(MediaDevice connectedMediaDevice, List devices, + boolean needToHandleMutingExpectedDevice) { synchronized (mMediaDevicesLock) { Set selectedDevicesIds = getSelectedMediaDevice().stream().map( MediaDevice::getId).collect(Collectors.toSet()); if (connectedMediaDevice != null) { selectedDevicesIds.add(connectedMediaDevice.getId()); } - int latestSelected = 1; - for (MediaItem item : mMediaItemList) { - if (item.getMediaDevice().isPresent()) { - MediaDevice device = item.getMediaDevice().get(); - if (selectedDevicesIds.contains(device.getId())) { - latestSelected = mMediaItemList.indexOf(item) + 1; - } else { - mMediaItemList.add(latestSelected, new MediaItem(mContext.getString( - R.string.media_output_group_title_speakers_and_displays), - MediaItem.MediaItemType.TYPE_GROUP_DIVIDER)); - break; + boolean suggestedDeviceAdded = false; + boolean displayGroupAdded = false; + for (MediaDevice device : devices) { + if (needToHandleMutingExpectedDevice && device.isMutingExpectedDevice()) { + mMediaItemList.add(0, new MediaItem(device)); + } else if (!needToHandleMutingExpectedDevice && selectedDevicesIds.contains( + device.getId())) { + mMediaItemList.add(0, new MediaItem(device)); + } else { + if (device.isSuggestedDevice() && !suggestedDeviceAdded) { + attachGroupDivider(mContext.getString( + R.string.media_output_group_title_suggested_device)); + suggestedDeviceAdded = true; + } else if (!device.isSuggestedDevice() && !displayGroupAdded) { + attachGroupDivider(mContext.getString( + R.string.media_output_group_title_speakers_and_displays)); + displayGroupAdded = true; } + mMediaItemList.add(new MediaItem(device)); } } mMediaItemList.add(new MediaItem()); } } + private void attachGroupDivider(String title) { + synchronized (mMediaDevicesLock) { + mMediaItemList.add( + new MediaItem(title, MediaItem.MediaItemType.TYPE_GROUP_DIVIDER)); + } + } + private void attachRangeInfo(List devices) { for (MediaDevice mediaDevice : devices) { if (mNearbyDeviceInfoMap.containsKey(mediaDevice.getId())) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java index 2ef2c5ee74bf4..f5432e22c57e2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java @@ -102,8 +102,6 @@ public class MediaOutputControllerTest extends SysuiTestCase { private MediaOutputController.Callback mCb = mock(MediaOutputController.Callback.class); private MediaDevice mMediaDevice1 = mock(MediaDevice.class); private MediaDevice mMediaDevice2 = mock(MediaDevice.class); - private MediaItem mMediaItem1 = mock(MediaItem.class); - private MediaItem mMediaItem2 = mock(MediaItem.class); private NearbyDevice mNearbyDevice1 = mock(NearbyDevice.class); private NearbyDevice mNearbyDevice2 = mock(NearbyDevice.class); private MediaMetadata mMediaMetadata = mock(MediaMetadata.class); @@ -127,7 +125,6 @@ public class MediaOutputControllerTest extends SysuiTestCase { private LocalMediaManager mLocalMediaManager; private List mMediaControllers = new ArrayList<>(); private List mMediaDevices = new ArrayList<>(); - private List mMediaItemList = new ArrayList<>(); private List mNearbyDevices = new ArrayList<>(); private MediaDescription mMediaDescription; private List mRoutingSessionInfos = new ArrayList<>(); @@ -162,10 +159,6 @@ public class MediaOutputControllerTest extends SysuiTestCase { when(mMediaDevice2.getId()).thenReturn(TEST_DEVICE_2_ID); mMediaDevices.add(mMediaDevice1); mMediaDevices.add(mMediaDevice2); - when(mMediaItem1.getMediaDevice()).thenReturn(Optional.of(mMediaDevice1)); - when(mMediaItem2.getMediaDevice()).thenReturn(Optional.of(mMediaDevice2)); - mMediaItemList.add(mMediaItem1); - mMediaItemList.add(mMediaItem2); when(mNearbyDevice1.getMediaRoute2Id()).thenReturn(TEST_DEVICE_1_ID); @@ -337,6 +330,35 @@ public class MediaOutputControllerTest extends SysuiTestCase { assertThat(devices.containsAll(mMediaDevices)).isTrue(); assertThat(devices.size()).isEqualTo(mMediaDevices.size()); + assertThat(mMediaOutputController.getMediaItemList().size()).isEqualTo( + mMediaDevices.size() + 2); + verify(mCb).onDeviceListChanged(); + } + + @Test + public void advanced_categorizeMediaItems_withSuggestedDevice_verifyDeviceListSize() { + when(mFlags.isEnabled(Flags.OUTPUT_SWITCHER_ADVANCED_LAYOUT)).thenReturn(true); + when(mMediaDevice1.isSuggestedDevice()).thenReturn(true); + when(mMediaDevice2.isSuggestedDevice()).thenReturn(false); + + mMediaOutputController.start(mCb); + reset(mCb); + mMediaOutputController.getMediaItemList().clear(); + mMediaOutputController.onDeviceListUpdate(mMediaDevices); + final List devices = new ArrayList<>(); + int dividerSize = 0; + for (MediaItem item : mMediaOutputController.getMediaItemList()) { + if (item.getMediaDevice().isPresent()) { + devices.add(item.getMediaDevice().get()); + } + if (item.getMediaItemType() == MediaItem.MediaItemType.TYPE_GROUP_DIVIDER) { + dividerSize++; + } + } + + assertThat(devices.containsAll(mMediaDevices)).isTrue(); + assertThat(devices.size()).isEqualTo(mMediaDevices.size()); + assertThat(dividerSize).isEqualTo(2); verify(mCb).onDeviceListChanged(); }