Merge "[Output Switcher] Add group title" into tm-qpr-dev am: b379d5c37d
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20689811 Change-Id: I05397020d743426077eda66d6f0ca9acb8fec16b Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -2406,6 +2406,8 @@
|
|||||||
<string name="media_output_dialog_accessibility_seekbar">Volume</string>
|
<string name="media_output_dialog_accessibility_seekbar">Volume</string>
|
||||||
<!-- Summary for media output volume of a device in percentage [CHAR LIMIT=NONE] -->
|
<!-- Summary for media output volume of a device in percentage [CHAR LIMIT=NONE] -->
|
||||||
<string name="media_output_dialog_volume_percentage"><xliff:g id="percentage" example="10">%1$d</xliff:g>%%</string>
|
<string name="media_output_dialog_volume_percentage"><xliff:g id="percentage" example="10">%1$d</xliff:g>%%</string>
|
||||||
|
<!-- Title for Speakers and Displays group. [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="media_output_group_title_speakers_and_displays">Speakers & Displays</string>
|
||||||
|
|
||||||
<!-- Media Output Broadcast Dialog -->
|
<!-- Media Output Broadcast Dialog -->
|
||||||
<!-- Title for Broadcast First Notify Dialog [CHAR LIMIT=60] -->
|
<!-- Title for Broadcast First Notify Dialog [CHAR LIMIT=60] -->
|
||||||
|
|||||||
@@ -70,6 +70,13 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
|
|||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
|
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
|
||||||
if (mController.isAdvancedLayoutSupported()) {
|
if (mController.isAdvancedLayoutSupported()) {
|
||||||
|
if (position >= mController.getMediaItemList().size()) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "Incorrect position: " + position + " list size: "
|
||||||
|
+ mController.getMediaItemList().size());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
MediaItem currentMediaItem = mController.getMediaItemList().get(position);
|
MediaItem currentMediaItem = mController.getMediaItemList().get(position);
|
||||||
switch (currentMediaItem.getMediaItemType()) {
|
switch (currentMediaItem.getMediaItemType()) {
|
||||||
case MediaItem.MediaItemType.TYPE_GROUP_DIVIDER:
|
case MediaItem.MediaItemType.TYPE_GROUP_DIVIDER:
|
||||||
|
|||||||
@@ -84,8 +84,7 @@ public abstract class MediaOutputBaseAdapter extends
|
|||||||
int viewType) {
|
int viewType) {
|
||||||
mContext = viewGroup.getContext();
|
mContext = viewGroup.getContext();
|
||||||
mHolderView = LayoutInflater.from(mContext).inflate(
|
mHolderView = LayoutInflater.from(mContext).inflate(
|
||||||
mController.isAdvancedLayoutSupported() ? MediaItem.getMediaLayoutId(
|
mController.isAdvancedLayoutSupported() ? MediaItem.getMediaLayoutId(viewType)
|
||||||
viewType) /*R.layout.media_output_list_item_advanced*/
|
|
||||||
: R.layout.media_output_list_item, viewGroup, false);
|
: R.layout.media_output_list_item, viewGroup, false);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -308,9 +307,10 @@ public abstract class MediaOutputBaseAdapter extends
|
|||||||
updateTitleIcon(currentVolume == 0 ? R.drawable.media_output_icon_volume_off
|
updateTitleIcon(currentVolume == 0 ? R.drawable.media_output_icon_volume_off
|
||||||
: R.drawable.media_output_icon_volume,
|
: R.drawable.media_output_icon_volume,
|
||||||
mController.getColorItemContent());
|
mController.getColorItemContent());
|
||||||
|
} else {
|
||||||
|
animateCornerAndVolume(mSeekBar.getProgress(),
|
||||||
|
MediaOutputSeekbar.scaleVolumeToProgress(currentVolume));
|
||||||
}
|
}
|
||||||
animateCornerAndVolume(mSeekBar.getProgress(),
|
|
||||||
MediaOutputSeekbar.scaleVolumeToProgress(currentVolume));
|
|
||||||
} else {
|
} else {
|
||||||
if (!mVolumeAnimator.isStarted()) {
|
if (!mVolumeAnimator.isStarted()) {
|
||||||
if (mController.isAdvancedLayoutSupported()) {
|
if (mController.isAdvancedLayoutSupported()) {
|
||||||
@@ -396,23 +396,18 @@ public abstract class MediaOutputBaseAdapter extends
|
|||||||
}
|
}
|
||||||
|
|
||||||
void updateMutedVolumeIcon() {
|
void updateMutedVolumeIcon() {
|
||||||
|
mIconAreaLayout.setBackground(
|
||||||
|
mContext.getDrawable(R.drawable.media_output_item_background_active));
|
||||||
updateTitleIcon(R.drawable.media_output_icon_volume_off,
|
updateTitleIcon(R.drawable.media_output_icon_volume_off,
|
||||||
mController.getColorItemContent());
|
mController.getColorItemContent());
|
||||||
final GradientDrawable iconAreaBackgroundDrawable =
|
|
||||||
(GradientDrawable) mIconAreaLayout.getBackground();
|
|
||||||
iconAreaBackgroundDrawable.setCornerRadius(mController.getActiveRadius());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateUnmutedVolumeIcon() {
|
void updateUnmutedVolumeIcon() {
|
||||||
|
mIconAreaLayout.setBackground(
|
||||||
|
mContext.getDrawable(R.drawable.media_output_title_icon_area)
|
||||||
|
);
|
||||||
updateTitleIcon(R.drawable.media_output_icon_volume,
|
updateTitleIcon(R.drawable.media_output_icon_volume,
|
||||||
mController.getColorItemContent());
|
mController.getColorItemContent());
|
||||||
final GradientDrawable iconAreaBackgroundDrawable =
|
|
||||||
(GradientDrawable) mIconAreaLayout.getBackground();
|
|
||||||
iconAreaBackgroundDrawable.setCornerRadii(new float[]{
|
|
||||||
mController.getActiveRadius(),
|
|
||||||
mController.getActiveRadius(),
|
|
||||||
0, 0, 0, 0, mController.getActiveRadius(), mController.getActiveRadius()
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateTitleIcon(@DrawableRes int id, int color) {
|
void updateTitleIcon(@DrawableRes int id, int color) {
|
||||||
|
|||||||
@@ -87,9 +87,11 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
@@ -275,7 +277,9 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceListUpdate(List<MediaDevice> devices) {
|
public void onDeviceListUpdate(List<MediaDevice> devices) {
|
||||||
if (mMediaDevices.isEmpty() || !mIsRefreshing) {
|
boolean isListEmpty =
|
||||||
|
isAdvancedLayoutSupported() ? mMediaItemList.isEmpty() : mMediaDevices.isEmpty();
|
||||||
|
if (isListEmpty || !mIsRefreshing) {
|
||||||
buildMediaDevices(devices);
|
buildMediaDevices(devices);
|
||||||
mCallback.onDeviceListChanged();
|
mCallback.onDeviceListChanged();
|
||||||
} else {
|
} else {
|
||||||
@@ -646,16 +650,19 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
|
|||||||
for (MediaDevice device : devices) {
|
for (MediaDevice device : devices) {
|
||||||
if (device.isMutingExpectedDevice()) {
|
if (device.isMutingExpectedDevice()) {
|
||||||
mMediaItemList.add(0, new MediaItem(device));
|
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 {
|
} else {
|
||||||
mMediaItemList.add(new MediaItem(device));
|
mMediaItemList.add(new MediaItem(device));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mMediaItemList.add(new MediaItem());
|
||||||
} else {
|
} else {
|
||||||
mMediaItemList.addAll(
|
mMediaItemList.addAll(
|
||||||
devices.stream().map(MediaItem::new).collect(Collectors.toList()));
|
devices.stream().map(MediaItem::new).collect(Collectors.toList()));
|
||||||
|
categorizeMediaItems(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
categorizeMediaItems();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// selected device exist
|
// selected device exist
|
||||||
@@ -666,11 +673,12 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
|
|||||||
mMediaItemList.add(new MediaItem(device));
|
mMediaItemList.add(new MediaItem(device));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
categorizeMediaItems();
|
categorizeMediaItems(connectedMediaDevice);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// To keep the same list order
|
// To keep the same list order
|
||||||
final List<MediaDevice> targetMediaDevices = new ArrayList<>();
|
final List<MediaDevice> targetMediaDevices = new ArrayList<>();
|
||||||
|
final Map<Integer, MediaItem> dividerItems = new HashMap<>();
|
||||||
for (MediaItem originalMediaItem : mMediaItemList) {
|
for (MediaItem originalMediaItem : mMediaItemList) {
|
||||||
for (MediaDevice newDevice : devices) {
|
for (MediaDevice newDevice : devices) {
|
||||||
if (originalMediaItem.getMediaDevice().isPresent()
|
if (originalMediaItem.getMediaDevice().isPresent()
|
||||||
@@ -680,6 +688,10 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (originalMediaItem.getMediaItemType()
|
||||||
|
== MediaItem.MediaItemType.TYPE_GROUP_DIVIDER) {
|
||||||
|
dividerItems.put(mMediaItemList.indexOf(originalMediaItem), originalMediaItem);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (targetMediaDevices.size() != devices.size()) {
|
if (targetMediaDevices.size() != devices.size()) {
|
||||||
devices.removeAll(targetMediaDevices);
|
devices.removeAll(targetMediaDevices);
|
||||||
@@ -688,13 +700,34 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
|
|||||||
mMediaItemList.clear();
|
mMediaItemList.clear();
|
||||||
mMediaItemList.addAll(
|
mMediaItemList.addAll(
|
||||||
targetMediaDevices.stream().map(MediaItem::new).collect(Collectors.toList()));
|
targetMediaDevices.stream().map(MediaItem::new).collect(Collectors.toList()));
|
||||||
categorizeMediaItems();
|
dividerItems.forEach((key, item) -> {
|
||||||
|
mMediaItemList.add(key, item);
|
||||||
|
});
|
||||||
|
mMediaItemList.add(new MediaItem());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void categorizeMediaItems() {
|
private void categorizeMediaItems(MediaDevice connectedMediaDevice) {
|
||||||
synchronized (mMediaDevicesLock) {
|
synchronized (mMediaDevicesLock) {
|
||||||
//TODO(255124239): do the categorization here
|
Set<String> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
mMediaItemList.add(new MediaItem());
|
mMediaItemList.add(new MediaItem());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,6 +102,8 @@ public class MediaOutputControllerTest extends SysuiTestCase {
|
|||||||
private MediaOutputController.Callback mCb = mock(MediaOutputController.Callback.class);
|
private MediaOutputController.Callback mCb = mock(MediaOutputController.Callback.class);
|
||||||
private MediaDevice mMediaDevice1 = mock(MediaDevice.class);
|
private MediaDevice mMediaDevice1 = mock(MediaDevice.class);
|
||||||
private MediaDevice mMediaDevice2 = 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 mNearbyDevice1 = mock(NearbyDevice.class);
|
||||||
private NearbyDevice mNearbyDevice2 = mock(NearbyDevice.class);
|
private NearbyDevice mNearbyDevice2 = mock(NearbyDevice.class);
|
||||||
private MediaMetadata mMediaMetadata = mock(MediaMetadata.class);
|
private MediaMetadata mMediaMetadata = mock(MediaMetadata.class);
|
||||||
@@ -125,6 +127,7 @@ public class MediaOutputControllerTest extends SysuiTestCase {
|
|||||||
private LocalMediaManager mLocalMediaManager;
|
private LocalMediaManager mLocalMediaManager;
|
||||||
private List<MediaController> mMediaControllers = new ArrayList<>();
|
private List<MediaController> mMediaControllers = new ArrayList<>();
|
||||||
private List<MediaDevice> mMediaDevices = new ArrayList<>();
|
private List<MediaDevice> mMediaDevices = new ArrayList<>();
|
||||||
|
private List<MediaItem> mMediaItemList = new ArrayList<>();
|
||||||
private List<NearbyDevice> mNearbyDevices = new ArrayList<>();
|
private List<NearbyDevice> mNearbyDevices = new ArrayList<>();
|
||||||
private MediaDescription mMediaDescription;
|
private MediaDescription mMediaDescription;
|
||||||
private List<RoutingSessionInfo> mRoutingSessionInfos = new ArrayList<>();
|
private List<RoutingSessionInfo> mRoutingSessionInfos = new ArrayList<>();
|
||||||
@@ -157,6 +160,11 @@ public class MediaOutputControllerTest extends SysuiTestCase {
|
|||||||
when(mMediaDevice2.getId()).thenReturn(TEST_DEVICE_2_ID);
|
when(mMediaDevice2.getId()).thenReturn(TEST_DEVICE_2_ID);
|
||||||
mMediaDevices.add(mMediaDevice1);
|
mMediaDevices.add(mMediaDevice1);
|
||||||
mMediaDevices.add(mMediaDevice2);
|
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);
|
when(mNearbyDevice1.getMediaRoute2Id()).thenReturn(TEST_DEVICE_1_ID);
|
||||||
when(mNearbyDevice1.getRangeZone()).thenReturn(NearbyDevice.RANGE_CLOSE);
|
when(mNearbyDevice1.getRangeZone()).thenReturn(NearbyDevice.RANGE_CLOSE);
|
||||||
@@ -313,6 +321,18 @@ public class MediaOutputControllerTest extends SysuiTestCase {
|
|||||||
assertThat(mMediaOutputController.mNeedRefresh).isTrue();
|
assertThat(mMediaOutputController.mNeedRefresh).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void advanced_onDeviceListUpdate_isRefreshing_updatesNeedRefreshToTrue() {
|
||||||
|
when(mFlags.isEnabled(Flags.OUTPUT_SWITCHER_ADVANCED_LAYOUT)).thenReturn(true);
|
||||||
|
mMediaOutputController.start(mCb);
|
||||||
|
reset(mCb);
|
||||||
|
mMediaOutputController.mIsRefreshing = true;
|
||||||
|
|
||||||
|
mMediaOutputController.onDeviceListUpdate(mMediaDevices);
|
||||||
|
|
||||||
|
assertThat(mMediaOutputController.mNeedRefresh).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void cancelMuteAwaitConnection_cancelsWithMediaManager() {
|
public void cancelMuteAwaitConnection_cancelsWithMediaManager() {
|
||||||
when(mAudioManager.getMutingExpectedDevice()).thenReturn(mock(AudioDeviceAttributes.class));
|
when(mAudioManager.getMutingExpectedDevice()).thenReturn(mock(AudioDeviceAttributes.class));
|
||||||
|
|||||||
Reference in New Issue
Block a user