diff --git a/packages/SystemUI/res/drawable/ic_circle_check_box.xml b/packages/SystemUI/res/drawable/ic_circle_check_box.xml
index b44a32dda1723..00c10cecfe952 100644
--- a/packages/SystemUI/res/drawable/ic_circle_check_box.xml
+++ b/packages/SystemUI/res/drawable/ic_circle_check_box.xml
@@ -18,7 +18,7 @@
+ android:drawable="@drawable/media_output_status_filled_checked" />
-
+
+
+
+
+
diff --git a/packages/SystemUI/res/drawable/media_output_status_checked.xml b/packages/SystemUI/res/drawable/media_output_status_checked.xml
new file mode 100644
index 0000000000000..8f83ee2fa1609
--- /dev/null
+++ b/packages/SystemUI/res/drawable/media_output_status_checked.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
diff --git a/packages/SystemUI/res/drawable/media_output_status_check.xml b/packages/SystemUI/res/drawable/media_output_status_filled_checked.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/media_output_status_check.xml
rename to packages/SystemUI/res/drawable/media_output_status_filled_checked.xml
diff --git a/packages/SystemUI/res/drawable/media_output_status_selectable.xml b/packages/SystemUI/res/drawable/media_output_status_selectable.xml
new file mode 100644
index 0000000000000..5465aa7300abb
--- /dev/null
+++ b/packages/SystemUI/res/drawable/media_output_status_selectable.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
diff --git a/packages/SystemUI/res/layout/media_output_list_item_advanced.xml b/packages/SystemUI/res/layout/media_output_list_item_advanced.xml
index 9d0bfd74af8ee..d49b9f1058031 100644
--- a/packages/SystemUI/res/layout/media_output_list_item_advanced.xml
+++ b/packages/SystemUI/res/layout/media_output_list_item_advanced.xml
@@ -1,6 +1,6 @@
-
+ android:layout_height="wrap_content">
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 3bec72ecd2b36..f3d2638c4ee7c 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1208,6 +1208,8 @@
20dp
16dp
28dp
+ 16dp
+ 80dp
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index 72d4e947b30fc..3dccae03e906a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -166,6 +166,20 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
setUpDeviceIcon(device);
updateFullItemClickListener(v -> cancelMuteAwaitConnection());
setSingleLineLayout(getItemTitle(device));
+ } else if (mController.isCurrentConnectedDeviceRemote()
+ && !mController.getSelectableMediaDevice().isEmpty()
+ && mController.isAdvancedLayoutSupported()) {
+ //If device is connected and there's other selectable devices, layout as
+ // one of selected devices.
+ boolean isDeviceDeselectable = isDeviceIncluded(
+ mController.getDeselectableMediaDevice(), device);
+ updateGroupableCheckBox(true, isDeviceDeselectable, device);
+ updateEndClickArea(device, isDeviceDeselectable);
+ setUpContentDescriptionForView(mContainerLayout, false, device);
+ setSingleLineLayout(getItemTitle(device), true /* showSeekBar */,
+ false /* showProgressBar */, true /* showCheckBox */,
+ true /* showEndTouchArea */);
+ initSeekbar(device, isCurrentSeekbarInvisible);
} else {
updateTitleIcon(R.drawable.media_output_icon_volume,
mController.getColorItemContent());
@@ -179,7 +193,12 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
} else if (isDeviceIncluded(mController.getSelectableMediaDevice(), device)) {
setUpDeviceIcon(device);
updateGroupableCheckBox(false, true, device);
- updateFullItemClickListener(v -> onGroupActionTriggered(true, device));
+ if (mController.isAdvancedLayoutSupported()) {
+ updateEndClickArea(device, true);
+ }
+ updateFullItemClickListener(mController.isAdvancedLayoutSupported()
+ ? v -> onItemClick(v, device)
+ : v -> onGroupActionTriggered(true, device));
setSingleLineLayout(getItemTitle(device), false /* showSeekBar */,
false /* showProgressBar */, true /* showCheckBox */,
true /* showEndTouchArea */);
@@ -217,6 +236,11 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
isDeviceDeselectable ? (v) -> mCheckBox.performClick() : null);
mEndTouchArea.setImportantForAccessibility(
View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+ if (mController.isAdvancedLayoutSupported()) {
+ mEndTouchArea.getBackground().setColorFilter(
+ new PorterDuffColorFilter(mController.getColorItemBackground(),
+ PorterDuff.Mode.SRC_IN));
+ }
setUpContentDescriptionForView(mEndTouchArea, true, device);
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
index 8987e7ca9efb4..db62e51be7e7a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -133,7 +133,7 @@ public abstract class MediaOutputBaseAdapter extends
private static final int ANIM_DURATION = 500;
- final LinearLayout mContainerLayout;
+ final ViewGroup mContainerLayout;
final FrameLayout mItemLayout;
final FrameLayout mIconAreaLayout;
final TextView mTitleText;
@@ -146,7 +146,7 @@ public abstract class MediaOutputBaseAdapter extends
final LinearLayout mTwoLineLayout;
final ImageView mStatusIcon;
final CheckBox mCheckBox;
- final LinearLayout mEndTouchArea;
+ final ViewGroup mEndTouchArea;
private String mDeviceId;
private ValueAnimator mCornerAnimator;
private ValueAnimator mVolumeAnimator;
@@ -253,6 +253,13 @@ public abstract class MediaOutputBaseAdapter extends
mTitleText.setVisibility(View.VISIBLE);
mCheckBox.setVisibility(showCheckBox ? View.VISIBLE : View.GONE);
mEndTouchArea.setVisibility(showEndTouchArea ? View.VISIBLE : View.GONE);
+ if (mController.isAdvancedLayoutSupported()) {
+ ViewGroup.MarginLayoutParams params =
+ (ViewGroup.MarginLayoutParams) mItemLayout.getLayoutParams();
+ params.rightMargin = showEndTouchArea ? mController.getItemMarginEndSelectable()
+ : mController.getItemMarginEndDefault();
+ }
+ mTitleIcon.setColorFilter(mController.getColorItemContent());
}
void setTwoLineLayout(MediaDevice device, boolean bFocused, boolean showSeekBar,
@@ -531,6 +538,7 @@ public abstract class MediaOutputBaseAdapter extends
return;
}
mTitleIcon.setImageIcon(icon);
+ mTitleIcon.setColorFilter(mController.getColorItemContent());
});
});
}
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 ecfc0e6d75740..9b361e3edc57b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -147,6 +147,8 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
private int mColorConnectedItemBackground;
private int mColorPositiveButtonText;
private int mColorDialogBackground;
+ private int mItemMarginEndDefault;
+ private int mItemMarginEndSelectable;
private float mInactiveRadius;
private float mActiveRadius;
private FeatureFlags mFeatureFlags;
@@ -200,6 +202,10 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
R.dimen.media_output_dialog_active_background_radius);
mColorDialogBackground = Utils.getColorStateListDefaultColor(mContext,
R.color.media_dialog_background);
+ mItemMarginEndDefault = (int) mContext.getResources().getDimension(
+ R.dimen.media_output_dialog_default_margin_end);
+ mItemMarginEndSelectable = (int) mContext.getResources().getDimension(
+ R.dimen.media_output_dialog_selectable_margin_end);
}
void start(@NonNull Callback cb) {
@@ -532,6 +538,14 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
return mActiveRadius;
}
+ public int getItemMarginEndDefault() {
+ return mItemMarginEndDefault;
+ }
+
+ public int getItemMarginEndSelectable() {
+ return mItemMarginEndSelectable;
+ }
+
private void buildMediaDevices(List devices) {
synchronized (mMediaDevicesLock) {
attachRangeInfo(devices);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
index 5f643363bd2e2..5c0f0fee096aa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
@@ -38,6 +38,8 @@ import com.android.settingslib.media.MediaDevice;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.google.common.collect.ImmutableList;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -73,11 +75,6 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
@Before
public void setUp() {
- mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController);
- mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
- .onCreateViewHolder(new LinearLayout(mContext), 0);
- mSpyMediaOutputSeekbar = spy(mViewHolder.mSeekBar);
-
when(mMediaOutputController.getMediaDevices()).thenReturn(mMediaDevices);
when(mMediaOutputController.hasAdjustVolumeUserRestriction()).thenReturn(false);
when(mMediaOutputController.isAnyDeviceTransferring()).thenReturn(false);
@@ -85,6 +82,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
when(mMediaOutputController.getDeviceIconCompat(mMediaDevice2)).thenReturn(mIconCompat);
when(mMediaOutputController.getCurrentConnectedMediaDevice()).thenReturn(mMediaDevice1);
when(mMediaOutputController.isActiveRemoteDevice(mMediaDevice1)).thenReturn(true);
+ when(mMediaOutputController.isAdvancedLayoutSupported()).thenReturn(false);
when(mIconCompat.toIcon(mContext)).thenReturn(mIcon);
when(mMediaDevice1.getName()).thenReturn(TEST_DEVICE_NAME_1);
when(mMediaDevice1.getId()).thenReturn(TEST_DEVICE_ID_1);
@@ -96,6 +94,11 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED);
mMediaDevices.add(mMediaDevice1);
mMediaDevices.add(mMediaDevice2);
+
+ mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController);
+ mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ .onCreateViewHolder(new LinearLayout(mContext), 0);
+ mSpyMediaOutputSeekbar = spy(mViewHolder.mSeekBar);
}
@Test
@@ -168,6 +171,63 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
}
+ @Test
+ public void advanced_onBindViewHolder_bindNonRemoteConnectedDevice_verifyView() {
+ when(mMediaOutputController.isAdvancedLayoutSupported()).thenReturn(true);
+ when(mMediaOutputController.isActiveRemoteDevice(mMediaDevice1)).thenReturn(false);
+ mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ .onCreateViewHolder(new LinearLayout(mContext), 0);
+ mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
+
+ assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mTitleText.getText().toString()).isEqualTo(TEST_DEVICE_NAME_1);
+ assertThat(mViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
+ }
+
+ @Test
+ public void advanced_onBindViewHolder_bindConnectedRemoteDevice_verifyView() {
+ when(mMediaOutputController.isAdvancedLayoutSupported()).thenReturn(true);
+ when(mMediaOutputController.getSelectableMediaDevice()).thenReturn(
+ ImmutableList.of(mMediaDevice2));
+ when(mMediaOutputController.isCurrentConnectedDeviceRemote()).thenReturn(true);
+ mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ .onCreateViewHolder(new LinearLayout(mContext), 0);
+ mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
+
+ assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mTitleText.getText().toString()).isEqualTo(TEST_DEVICE_NAME_1);
+ assertThat(mViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mEndTouchArea.getVisibility()).isEqualTo(View.VISIBLE);
+ }
+
+ @Test
+ public void advanced_onBindViewHolder_bindSingleConnectedRemoteDevice_verifyView() {
+ when(mMediaOutputController.isAdvancedLayoutSupported()).thenReturn(true);
+ when(mMediaOutputController.getSelectableMediaDevice()).thenReturn(
+ ImmutableList.of());
+ when(mMediaOutputController.isCurrentConnectedDeviceRemote()).thenReturn(true);
+ mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ .onCreateViewHolder(new LinearLayout(mContext), 0);
+ mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
+
+ assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mTitleText.getText().toString()).isEqualTo(TEST_DEVICE_NAME_1);
+ assertThat(mViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mEndTouchArea.getVisibility()).isEqualTo(View.GONE);
+ }
+
@Test
public void onBindViewHolder_bindConnectedDeviceWithMutingExpectedDeviceExist_verifyView() {
when(mMediaOutputController.hasMutingExpectedDevice()).thenReturn(true);
@@ -351,6 +411,38 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
verify(mMediaOutputController).addDeviceToPlayMedia(mMediaDevice2);
}
+ @Test
+ public void advanced_onGroupActionTriggered_clicksEndAreaOfSelectableDevice_triggerGrouping() {
+ when(mMediaOutputController.isAdvancedLayoutSupported()).thenReturn(true);
+ List selectableDevices = new ArrayList<>();
+ selectableDevices.add(mMediaDevice2);
+ when(mMediaOutputController.getSelectableMediaDevice()).thenReturn(selectableDevices);
+ mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ .onCreateViewHolder(new LinearLayout(mContext), 0);
+ mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1);
+
+ mViewHolder.mEndTouchArea.performClick();
+
+ verify(mMediaOutputController).addDeviceToPlayMedia(mMediaDevice2);
+ }
+
+ @Test
+ public void advanced_onGroupActionTriggered_clickSelectedRemoteDevice_triggerUngrouping() {
+ when(mMediaOutputController.isAdvancedLayoutSupported()).thenReturn(true);
+ when(mMediaOutputController.getSelectableMediaDevice()).thenReturn(
+ ImmutableList.of(mMediaDevice2));
+ when(mMediaOutputController.getDeselectableMediaDevice()).thenReturn(
+ ImmutableList.of(mMediaDevice1));
+ when(mMediaOutputController.isCurrentConnectedDeviceRemote()).thenReturn(true);
+ mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ .onCreateViewHolder(new LinearLayout(mContext), 0);
+ mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
+
+ mViewHolder.mEndTouchArea.performClick();
+
+ verify(mMediaOutputController).removeDeviceFromPlayMedia(mMediaDevice1);
+ }
+
@Test
public void onItemClick_onGroupActionTriggered_verifySeekbarDisabled() {
when(mMediaOutputController.getSelectedMediaDevice()).thenReturn(mMediaDevices);