From 3de24ae2c56b8e8ae5e053012ec16168264a96f4 Mon Sep 17 00:00:00 2001 From: timhypeng Date: Mon, 19 Oct 2020 09:26:30 +0800 Subject: [PATCH] Enhancement for group operation in output switcher -Add new group components in xml layout and assets -Adjust view objects in adapter for new layout -Add aboveStatusbar in MediaOutputControllter to keep the dialog style when switching -Add getGroupMediaDevices() in MediaOutputController to provide available device list for group operation -Update test cases Bug: 155822415 Test: atest MediaOutputAdapterTest MediaOutputControllerTest MediaOutputBaseDialogTest MediaOutputDialogTest Merged-In: If74bf2efb89a8ece61f4e0cf13e4dcfa30cb0a8a Change-Id: If74bf2efb89a8ece61f4e0cf13e4dcfa30cb0a8a --- .../SystemUI/res/drawable/ic_check_box.xml | 26 +++ .../res/drawable/ic_check_box_blue_24dp.xml | 26 +++ .../drawable/ic_check_box_outline_24dp.xml | 26 +++ .../drawable/ic_speaker_group_black_24dp.xml | 31 +++ .../res/layout/media_output_list_item.xml | 181 ++++++++++-------- .../media/dialog/MediaOutputAdapter.java | 47 +++-- .../media/dialog/MediaOutputBaseAdapter.java | 65 +++++-- .../media/dialog/MediaOutputBaseDialog.java | 5 + .../media/dialog/MediaOutputController.java | 60 +++++- .../media/dialog/MediaOutputDialogFactory.kt | 5 +- .../media/dialog/MediaOutputAdapterTest.java | 51 ++++- .../dialog/MediaOutputBaseDialogTest.java | 2 +- .../dialog/MediaOutputControllerTest.java | 88 ++++++++- .../media/dialog/MediaOutputDialogTest.java | 2 +- 14 files changed, 479 insertions(+), 136 deletions(-) create mode 100644 packages/SystemUI/res/drawable/ic_check_box.xml create mode 100644 packages/SystemUI/res/drawable/ic_check_box_blue_24dp.xml create mode 100644 packages/SystemUI/res/drawable/ic_check_box_outline_24dp.xml create mode 100644 packages/SystemUI/res/drawable/ic_speaker_group_black_24dp.xml diff --git a/packages/SystemUI/res/drawable/ic_check_box.xml b/packages/SystemUI/res/drawable/ic_check_box.xml new file mode 100644 index 0000000000000..a8d1a652b35b4 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_check_box.xml @@ -0,0 +1,26 @@ + + + + + + diff --git a/packages/SystemUI/res/drawable/ic_check_box_blue_24dp.xml b/packages/SystemUI/res/drawable/ic_check_box_blue_24dp.xml new file mode 100644 index 0000000000000..43cae69839811 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_check_box_blue_24dp.xml @@ -0,0 +1,26 @@ + + + + + + diff --git a/packages/SystemUI/res/drawable/ic_check_box_outline_24dp.xml b/packages/SystemUI/res/drawable/ic_check_box_outline_24dp.xml new file mode 100644 index 0000000000000..f6f453af2a262 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_check_box_outline_24dp.xml @@ -0,0 +1,26 @@ + + + + + + diff --git a/packages/SystemUI/res/drawable/ic_speaker_group_black_24dp.xml b/packages/SystemUI/res/drawable/ic_speaker_group_black_24dp.xml new file mode 100644 index 0000000000000..ae0d56217fd9e --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_speaker_group_black_24dp.xml @@ -0,0 +1,31 @@ + + + + + + + diff --git a/packages/SystemUI/res/layout/media_output_list_item.xml b/packages/SystemUI/res/layout/media_output_list_item.xml index ac8b7b5812bdc..c98c3a0beb658 100644 --- a/packages/SystemUI/res/layout/media_output_list_item.xml +++ b/packages/SystemUI/res/layout/media_output_list_item.xml @@ -15,97 +15,124 @@ ~ limitations under the License. --> - - + android:layout_height="wrap_content" + android:orientation="vertical"> - - + android:layout_width="match_parent" + android:layout_height="64dp"> - + + + - - - - - + + + + + + + + + + + + + + - - - \ No newline at end of file + \ No newline at end of file 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 d1630ebe8dc87..d26f7ab6d78c6 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java @@ -109,34 +109,45 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter { super.onBind(device, topMargin, bottomMargin); final boolean currentlyConnected = isCurrentlyConnected(device); if (currentlyConnected) { - mConnectedItem = mFrameLayout; + mConnectedItem = mContainerLayout; + } + mBottomDivider.setVisibility(View.GONE); + mCheckBox.setVisibility(View.GONE); + if (currentlyConnected && mController.isActiveRemoteDevice(device)) { + // Init active device layout + mDivider.setVisibility(View.VISIBLE); + mDivider.setTransitionAlpha(1); + mAddIcon.setVisibility(View.VISIBLE); + mAddIcon.setTransitionAlpha(1); + mAddIcon.setOnClickListener(v -> onEndItemClick()); + } else { + // Init non-active device layout + mDivider.setVisibility(View.GONE); + mAddIcon.setVisibility(View.GONE); } if (mController.isTransferring()) { if (device.getState() == MediaDeviceState.STATE_CONNECTING && !mController.hasAdjustVolumeUserRestriction()) { - setTwoLineLayout(device, null /* title */, true /* bFocused */, - false /* showSeekBar*/, true /* showProgressBar */, - false /* showSubtitle */); + setTwoLineLayout(device, true /* bFocused */, false /* showSeekBar*/, + true /* showProgressBar */, false /* showSubtitle */); } else { setSingleLineLayout(getItemTitle(device), false /* bFocused */); } } else { // Set different layout for each device if (device.getState() == MediaDeviceState.STATE_CONNECTING_FAILED) { - setTwoLineLayout(device, null /* title */, false /* bFocused */, - false /* showSeekBar*/, false /* showProgressBar */, + setTwoLineLayout(device, false /* bFocused */, + false /* showSeekBar */, false /* showProgressBar */, true /* showSubtitle */); mSubTitleText.setText(R.string.media_output_dialog_connect_failed); - mFrameLayout.setOnClickListener(v -> onItemClick(v, device)); - } else if (!mController.hasAdjustVolumeUserRestriction() - && currentlyConnected) { - setTwoLineLayout(device, null /* title */, true /* bFocused */, - true /* showSeekBar*/, false /* showProgressBar */, - false /* showSubtitle */); + mContainerLayout.setOnClickListener(v -> onItemClick(v, device)); + } else if (!mController.hasAdjustVolumeUserRestriction() && currentlyConnected) { + setTwoLineLayout(device, true /* bFocused */, true /* showSeekBar */, + false /* showProgressBar */, false /* showSubtitle */); initSeekbar(device); } else { setSingleLineLayout(getItemTitle(device), false /* bFocused */); - mFrameLayout.setOnClickListener(v -> onItemClick(v, device)); + mContainerLayout.setOnClickListener(v -> onItemClick(v, device)); } } } @@ -145,13 +156,17 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter { void onBind(int customizedItem, boolean topMargin, boolean bottomMargin) { super.onBind(customizedItem, topMargin, bottomMargin); if (customizedItem == CUSTOMIZED_ITEM_PAIR_NEW) { + mCheckBox.setVisibility(View.GONE); + mDivider.setVisibility(View.GONE); + mAddIcon.setVisibility(View.GONE); + mBottomDivider.setVisibility(View.GONE); setSingleLineLayout(mContext.getText(R.string.media_output_dialog_pairing_new), false /* bFocused */); final Drawable d = mContext.getDrawable(R.drawable.ic_add); d.setColorFilter(new PorterDuffColorFilter( Utils.getColorAccentDefaultColor(mContext), PorterDuff.Mode.SRC_IN)); mTitleIcon.setImageDrawable(d); - mFrameLayout.setOnClickListener(v -> onItemClick(CUSTOMIZED_ITEM_PAIR_NEW)); + mContainerLayout.setOnClickListener(v -> onItemClick(CUSTOMIZED_ITEM_PAIR_NEW)); } } @@ -173,5 +188,9 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter { mController.launchBluetoothPairing(); } } + + private void onEndItemClick() { + mController.launchMediaOutputGroupDialog(); + } } } 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 2d3e77db1ea3c..536b7598ce223 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java @@ -24,8 +24,9 @@ import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.FrameLayout; +import android.widget.CheckBox; import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.SeekBar; @@ -44,19 +45,17 @@ import com.android.systemui.R; public abstract class MediaOutputBaseAdapter extends RecyclerView.Adapter { - private static final String FONT_SELECTED_TITLE = "sans-serif-medium"; - private static final String FONT_TITLE = "sans-serif"; - static final int CUSTOMIZED_ITEM_PAIR_NEW = 1; + static final int CUSTOMIZED_ITEM_GROUP = 2; final MediaOutputController mController; - private boolean mIsDragging; private int mMargin; private boolean mIsAnimating; Context mContext; View mHolderView; + boolean mIsDragging; public MediaOutputBaseAdapter(MediaOutputController controller) { mController = controller; @@ -99,27 +98,33 @@ public abstract class MediaOutputBaseAdapter extends private static final int ANIM_DURATION = 200; - final FrameLayout mFrameLayout; + final LinearLayout mContainerLayout; final TextView mTitleText; final TextView mTwoLineTitleText; final TextView mSubTitleText; final ImageView mTitleIcon; - final ImageView mEndIcon; + final ImageView mAddIcon; final ProgressBar mProgressBar; final SeekBar mSeekBar; final RelativeLayout mTwoLineLayout; + final View mDivider; + final View mBottomDivider; + final CheckBox mCheckBox; MediaDeviceBaseViewHolder(View view) { super(view); - mFrameLayout = view.requireViewById(R.id.device_container); + mContainerLayout = view.requireViewById(R.id.device_container); mTitleText = view.requireViewById(R.id.title); mSubTitleText = view.requireViewById(R.id.subtitle); mTwoLineLayout = view.requireViewById(R.id.two_line_layout); mTwoLineTitleText = view.requireViewById(R.id.two_line_title); mTitleIcon = view.requireViewById(R.id.title_icon); - mEndIcon = view.requireViewById(R.id.end_icon); mProgressBar = view.requireViewById(R.id.volume_indeterminate_progress); mSeekBar = view.requireViewById(R.id.volume_seekbar); + mDivider = view.requireViewById(R.id.end_divider); + mBottomDivider = view.requireViewById(R.id.bottom_divider); + mAddIcon = view.requireViewById(R.id.add_icon); + mCheckBox = view.requireViewById(R.id.check_box); } void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin) { @@ -132,11 +137,11 @@ public abstract class MediaOutputBaseAdapter extends } private void setMargin(boolean topMargin, boolean bottomMargin) { - ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mFrameLayout + ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mContainerLayout .getLayoutParams(); params.topMargin = topMargin ? mMargin : 0; params.bottomMargin = bottomMargin ? mMargin : 0; - mFrameLayout.setLayoutParams(params); + mContainerLayout.setLayoutParams(params); } void setSingleLineLayout(CharSequence title, boolean bFocused) { @@ -146,13 +151,26 @@ public abstract class MediaOutputBaseAdapter extends mTitleText.setTranslationY(0); mTitleText.setText(title); if (bFocused) { - mTitleText.setTypeface(Typeface.create(FONT_SELECTED_TITLE, Typeface.NORMAL)); + mTitleText.setTypeface(Typeface.create(mContext.getString( + com.android.internal.R.string.config_headlineFontFamilyMedium), + Typeface.NORMAL)); } else { - mTitleText.setTypeface(Typeface.create(FONT_TITLE, Typeface.NORMAL)); + mTitleText.setTypeface(Typeface.create(mContext.getString( + com.android.internal.R.string.config_headlineFontFamily), Typeface.NORMAL)); } } - void setTwoLineLayout(MediaDevice device, CharSequence title, boolean bFocused, + void setTwoLineLayout(MediaDevice device, boolean bFocused, boolean showSeekBar, + boolean showProgressBar, boolean showSubtitle) { + setTwoLineLayout(device, null, bFocused, showSeekBar, showProgressBar, showSubtitle); + } + + void setTwoLineLayout(CharSequence title, boolean bFocused, boolean showSeekBar, + boolean showProgressBar, boolean showSubtitle) { + setTwoLineLayout(null, title, bFocused, showSeekBar, showProgressBar, showSubtitle); + } + + private void setTwoLineLayout(MediaDevice device, CharSequence title, boolean bFocused, boolean showSeekBar, boolean showProgressBar, boolean showSubtitle) { mTitleText.setVisibility(View.GONE); mTwoLineLayout.setVisibility(View.VISIBLE); @@ -168,18 +186,21 @@ public abstract class MediaOutputBaseAdapter extends } if (bFocused) { - mTwoLineTitleText.setTypeface(Typeface.create(FONT_SELECTED_TITLE, + mTwoLineTitleText.setTypeface(Typeface.create(mContext.getString( + com.android.internal.R.string.config_headlineFontFamilyMedium), Typeface.NORMAL)); } else { - mTwoLineTitleText.setTypeface(Typeface.create(FONT_TITLE, Typeface.NORMAL)); + mTwoLineTitleText.setTypeface(Typeface.create(mContext.getString( + com.android.internal.R.string.config_headlineFontFamily), Typeface.NORMAL)); } } void initSeekbar(MediaDevice device) { mSeekBar.setMax(device.getMaxVolume()); mSeekBar.setMin(0); - if (mSeekBar.getProgress() != device.getCurrentVolume()) { - mSeekBar.setProgress(device.getCurrentVolume()); + final int currentVolume = device.getCurrentVolume(); + if (mSeekBar.getProgress() != currentVolume) { + mSeekBar.setProgress(currentVolume); } mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override @@ -213,7 +234,9 @@ public abstract class MediaOutputBaseAdapter extends } mIsAnimating = true; // Animation for title text - toTitleText.setTypeface(Typeface.create(FONT_SELECTED_TITLE, Typeface.NORMAL)); + toTitleText.setTypeface(Typeface.create(mContext.getString( + com.android.internal.R.string.config_headlineFontFamilyMedium), + Typeface.NORMAL)); toTitleText.animate() .setDuration(ANIM_DURATION) .translationY(-delta) @@ -234,7 +257,9 @@ public abstract class MediaOutputBaseAdapter extends public void onAnimationEnd(Animator animation) { final TextView fromTitleText = from.requireViewById( R.id.two_line_title); - fromTitleText.setTypeface(Typeface.create(FONT_TITLE, Typeface.NORMAL)); + fromTitleText.setTypeface(Typeface.create(mContext.getString( + com.android.internal.R.string.config_headlineFontFamily), + Typeface.NORMAL)); fromTitleText.animate() .setDuration(ANIM_DURATION) .translationY(delta) diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java index 2faf56a5022c8..dd9a808fb35b6 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java @@ -119,6 +119,8 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements // Init device list mDevicesRecyclerView.setLayoutManager(mLayoutManager); mDevicesRecyclerView.setAdapter(mAdapter); + // Init header icon + mHeaderIcon.setOnClickListener(v -> onHeaderIconClick()); // Init bottom buttons mDoneButton.setOnClickListener(v -> dismiss()); mStopButton.setOnClickListener(v -> { @@ -218,4 +220,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements dismiss(); } } + + void onHeaderIconClick() { + } } 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 b1f1bda25961c..b9fa872521253 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java @@ -71,6 +71,8 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback{ private final MediaSessionManager mMediaSessionManager; private final ShadeController mShadeController; private final ActivityStarter mActivityStarter; + private final List mGroupMediaDevices = new CopyOnWriteArrayList<>(); + private final boolean mAboveStatusbar; @VisibleForTesting final List mMediaDevices = new CopyOnWriteArrayList<>(); @@ -82,13 +84,14 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback{ @Inject public MediaOutputController(@NonNull Context context, String packageName, - MediaSessionManager mediaSessionManager, LocalBluetoothManager + boolean aboveStatusbar, MediaSessionManager mediaSessionManager, LocalBluetoothManager lbm, ShadeController shadeController, ActivityStarter starter) { mContext = context; mPackageName = packageName; mMediaSessionManager = mediaSessionManager; mShadeController = shadeController; mActivityStarter = starter; + mAboveStatusbar = aboveStatusbar; InfoMediaManager imm = new InfoMediaManager(mContext, packageName, null, lbm); mLocalMediaManager = new LocalMediaManager(mContext, lbm, imm, packageName); } @@ -271,6 +274,42 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback{ mMediaDevices.addAll(targetMediaDevices); } + List getGroupMediaDevices() { + final List selectedDevices = getSelectedMediaDevice(); + final List selectableDevices = getSelectableMediaDevice(); + if (mGroupMediaDevices.isEmpty()) { + mGroupMediaDevices.addAll(selectedDevices); + mGroupMediaDevices.addAll(selectableDevices); + return mGroupMediaDevices; + } + // To keep the same list order + final Collection sourceDevices = new ArrayList<>(); + final Collection targetMediaDevices = new ArrayList<>(); + sourceDevices.addAll(selectedDevices); + sourceDevices.addAll(selectableDevices); + for (MediaDevice originalDevice : mGroupMediaDevices) { + for (MediaDevice newDevice : sourceDevices) { + if (TextUtils.equals(originalDevice.getId(), newDevice.getId())) { + targetMediaDevices.add(newDevice); + sourceDevices.remove(newDevice); + break; + } + } + } + // Add new devices at the end of list if necessary + if (!sourceDevices.isEmpty()) { + targetMediaDevices.addAll(sourceDevices); + } + mGroupMediaDevices.clear(); + mGroupMediaDevices.addAll(targetMediaDevices); + + return mGroupMediaDevices; + } + + void resetGroupMediaDevices() { + mGroupMediaDevices.clear(); + } + void connectDevice(MediaDevice device) { ThreadUtils.postOnBackgroundThread(() -> { mLocalMediaManager.connectDevice(device); @@ -309,15 +348,6 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback{ return mLocalMediaManager.getDeselectableMediaDevice(); } - boolean isDeviceIncluded(Collection deviceCollection, MediaDevice targetDevice) { - for (MediaDevice device : deviceCollection) { - if (TextUtils.equals(device.getId(), targetDevice.getId())) { - return true; - } - } - return false; - } - void adjustSessionVolume(String sessionId, int volume) { mLocalMediaManager.adjustSessionVolume(sessionId, volume); } @@ -407,6 +437,16 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback{ mActivityStarter.dismissKeyguardThenExecute(postKeyguardAction, null, true); } + void launchMediaOutputDialog() { + mCallback.dismissDialog(); + new MediaOutputDialog(mContext, mAboveStatusbar, this); + } + + void launchMediaOutputGroupDialog() { + mCallback.dismissDialog(); + new MediaOutputGroupDialog(mContext, mAboveStatusbar, this); + } + boolean isActiveRemoteDevice(@NonNull MediaDevice device) { final List features = device.getFeatures(); return (features.contains(MediaRoute2Info.FEATURE_REMOTE_PLAYBACK) diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt index 4cdca4cbcf1e1..e912b7d1b08fc 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt @@ -40,9 +40,8 @@ class MediaOutputDialogFactory @Inject constructor( /** Creates a [MediaOutputDialog] for the given package. */ fun create(packageName: String, aboveStatusBar: Boolean) { mediaOutputDialog?.dismiss() - - mediaOutputDialog = MediaOutputController(context, packageName, mediaSessionManager, lbm, - shadeController, starter).run { + mediaOutputDialog = MediaOutputController(context, packageName, aboveStatusBar, + mediaSessionManager, lbm, shadeController, starter).run { MediaOutputDialog(context, aboveStatusBar, this) } } 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 2d460aa0c9c1a..521888658d682 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 @@ -25,7 +25,7 @@ import static org.mockito.Mockito.when; import android.graphics.drawable.Icon; import android.testing.AndroidTestingRunner; import android.view.View; -import android.widget.FrameLayout; +import android.widget.LinearLayout; import androidx.core.graphics.drawable.IconCompat; import androidx.test.filters.SmallTest; @@ -66,7 +66,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase { public void setUp() { mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController); mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter - .onCreateViewHolder(new FrameLayout(mContext), 0); + .onCreateViewHolder(new LinearLayout(mContext), 0); when(mMediaOutputController.getMediaDevices()).thenReturn(mMediaDevices); when(mMediaOutputController.hasAdjustVolumeUserRestriction()).thenReturn(false); @@ -75,6 +75,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase { when(mMediaOutputController.getDeviceIconCompat(mMediaDevice1)).thenReturn(mIconCompat); when(mMediaOutputController.getDeviceIconCompat(mMediaDevice2)).thenReturn(mIconCompat); when(mMediaOutputController.getCurrentConnectedMediaDevice()).thenReturn(mMediaDevice1); + when(mMediaOutputController.isActiveRemoteDevice(mMediaDevice1)).thenReturn(true); when(mIconCompat.toIcon(mContext)).thenReturn(mIcon); when(mMediaDevice1.getName()).thenReturn(TEST_DEVICE_NAME_1); when(mMediaDevice1.getId()).thenReturn(TEST_DEVICE_ID_1); @@ -107,6 +108,11 @@ public class MediaOutputAdapterTest extends SysuiTestCase { assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE); assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE); assertThat(mViewHolder.mTitleText.getText()).isEqualTo(mContext.getText( R.string.media_output_dialog_pairing_new)); } @@ -118,11 +124,29 @@ public class MediaOutputAdapterTest extends SysuiTestCase { assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE); assertThat(mViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE); assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE); assertThat(mViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE); assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.VISIBLE); assertThat(mViewHolder.mTwoLineTitleText.getText()).isEqualTo(TEST_DEVICE_NAME_1); } + @Test + public void onBindViewHolder_bindNonActiveConnectedDevice_verifyView() { + mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1); + + assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mViewHolder.mTitleText.getText().toString()).isEqualTo(TEST_DEVICE_NAME_2); + } + @Test public void onBindViewHolder_bindDisconnectedBluetoothDevice_verifyView() { when(mMediaDevice2.getDeviceType()).thenReturn( @@ -130,7 +154,11 @@ public class MediaOutputAdapterTest extends SysuiTestCase { when(mMediaDevice2.isConnected()).thenReturn(false); mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1); + assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE); assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE); assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE); assertThat(mViewHolder.mTitleText.getText().toString()).isEqualTo( mContext.getString(R.string.media_output_dialog_disconnected, TEST_DEVICE_NAME_2)); @@ -142,9 +170,13 @@ public class MediaOutputAdapterTest extends SysuiTestCase { LocalMediaManager.MediaDeviceState.STATE_CONNECTING_FAILED); mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1); + assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE); assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE); assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.GONE); assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE); assertThat(mViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.VISIBLE); assertThat(mViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE); assertThat(mViewHolder.mSubTitleText.getText()).isEqualTo(mContext.getText( @@ -162,7 +194,11 @@ public class MediaOutputAdapterTest extends SysuiTestCase { assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE); assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.GONE); assertThat(mViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE); assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.VISIBLE); assertThat(mViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE); assertThat(mViewHolder.mTwoLineTitleText.getText()).isEqualTo(TEST_DEVICE_NAME_1); } @@ -174,8 +210,13 @@ public class MediaOutputAdapterTest extends SysuiTestCase { LocalMediaManager.MediaDeviceState.STATE_CONNECTING); mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0); - assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE); assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.VISIBLE); assertThat(mViewHolder.mTitleText.getText()).isEqualTo(TEST_DEVICE_NAME_1); } @@ -183,7 +224,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase { public void onItemClick_clickPairNew_verifyLaunchBluetoothPairing() { when(mMediaOutputController.isZeroMode()).thenReturn(true); mMediaOutputAdapter.onBindViewHolder(mViewHolder, 2); - mViewHolder.mFrameLayout.performClick(); + mViewHolder.mContainerLayout.performClick(); verify(mMediaOutputController).launchBluetoothPairing(); } @@ -194,7 +235,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase { LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED); mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0); mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1); - mViewHolder.mFrameLayout.performClick(); + mViewHolder.mContainerLayout.performClick(); verify(mMediaOutputController).connectDevice(mMediaDevice2); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java index 27b5b7fda6848..4639dcbb1685c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java @@ -68,7 +68,7 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase { @Before public void setUp() { - mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, + mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false, mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter); mMediaOutputBaseDialogImpl = new MediaOutputBaseDialogImpl(mContext, mMediaOutputController); 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 0dcdecfdaadb1..0576667484df1 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 @@ -34,6 +34,7 @@ import android.media.RoutingSessionInfo; import android.media.session.MediaController; import android.media.session.MediaSessionManager; import android.testing.AndroidTestingRunner; +import android.text.TextUtils; import androidx.test.filters.SmallTest; @@ -60,6 +61,9 @@ public class MediaOutputControllerTest extends SysuiTestCase { private static final String TEST_PACKAGE_NAME = "com.test.package.name"; private static final String TEST_DEVICE_1_ID = "test_device_1_id"; private static final String TEST_DEVICE_2_ID = "test_device_2_id"; + private static final String TEST_DEVICE_3_ID = "test_device_3_id"; + private static final String TEST_DEVICE_4_ID = "test_device_4_id"; + private static final String TEST_DEVICE_5_ID = "test_device_5_id"; private static final String TEST_ARTIST = "test_artist"; private static final String TEST_SONG = "test_song"; private static final String TEST_SESSION_ID = "test_session_id"; @@ -96,7 +100,7 @@ public class MediaOutputControllerTest extends SysuiTestCase { MediaSessionManager.class); when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn( mCachedBluetoothDeviceManager); - mMediaOutputController = new MediaOutputController(mSpyContext, TEST_PACKAGE_NAME, + mMediaOutputController = new MediaOutputController(mSpyContext, TEST_PACKAGE_NAME, false, mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter); mLocalMediaManager = spy(mMediaOutputController.mLocalMediaManager); mMediaOutputController.mLocalMediaManager = mLocalMediaManager; @@ -139,8 +143,8 @@ public class MediaOutputControllerTest extends SysuiTestCase { @Test public void start_withoutPackageName_verifyMediaControllerInit() { - mMediaOutputController = new MediaOutputController(mSpyContext, null, mMediaSessionManager, - mLocalBluetoothManager, mShadeController, mStarter); + mMediaOutputController = new MediaOutputController(mSpyContext, null, false, + mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter); mMediaOutputController.start(mCb); @@ -159,8 +163,8 @@ public class MediaOutputControllerTest extends SysuiTestCase { @Test public void stop_withoutPackageName_verifyMediaControllerDeinit() { - mMediaOutputController = new MediaOutputController(mSpyContext, null, mMediaSessionManager, - mLocalBluetoothManager, mShadeController, mStarter); + mMediaOutputController = new MediaOutputController(mSpyContext, null, false, + mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter); mMediaOutputController.start(mCb); mMediaOutputController.stop(); @@ -345,4 +349,78 @@ public class MediaOutputControllerTest extends SysuiTestCase { assertThat(mMediaOutputController.isZeroMode()).isFalse(); } + + @Test + public void getGroupMediaDevices_differentDeviceOrder_showingSameOrder() { + final MediaDevice selectedMediaDevice1 = mock(MediaDevice.class); + final MediaDevice selectedMediaDevice2 = mock(MediaDevice.class); + final MediaDevice selectableMediaDevice1 = mock(MediaDevice.class); + final MediaDevice selectableMediaDevice2 = mock(MediaDevice.class); + final List selectedMediaDevices = new ArrayList<>(); + final List selectableMediaDevices = new ArrayList<>(); + when(selectedMediaDevice1.getId()).thenReturn(TEST_DEVICE_1_ID); + when(selectedMediaDevice2.getId()).thenReturn(TEST_DEVICE_2_ID); + when(selectableMediaDevice1.getId()).thenReturn(TEST_DEVICE_3_ID); + when(selectableMediaDevice2.getId()).thenReturn(TEST_DEVICE_4_ID); + selectedMediaDevices.add(selectedMediaDevice1); + selectedMediaDevices.add(selectedMediaDevice2); + selectableMediaDevices.add(selectableMediaDevice1); + selectableMediaDevices.add(selectableMediaDevice2); + doReturn(selectedMediaDevices).when(mLocalMediaManager).getSelectedMediaDevice(); + doReturn(selectableMediaDevices).when(mLocalMediaManager).getSelectableMediaDevice(); + final List groupMediaDevices = mMediaOutputController.getGroupMediaDevices(); + // Reset order + selectedMediaDevices.clear(); + selectedMediaDevices.add(selectedMediaDevice2); + selectedMediaDevices.add(selectedMediaDevice1); + selectableMediaDevices.clear(); + selectableMediaDevices.add(selectableMediaDevice2); + selectableMediaDevices.add(selectableMediaDevice1); + final List newDevices = mMediaOutputController.getGroupMediaDevices(); + + assertThat(newDevices.size()).isEqualTo(groupMediaDevices.size()); + for (int i = 0; i < groupMediaDevices.size(); i++) { + assertThat(TextUtils.equals(groupMediaDevices.get(i).getId(), + newDevices.get(i).getId())).isTrue(); + } + } + + @Test + public void getGroupMediaDevices_newDevice_verifyDeviceOrder() { + final MediaDevice selectedMediaDevice1 = mock(MediaDevice.class); + final MediaDevice selectedMediaDevice2 = mock(MediaDevice.class); + final MediaDevice selectableMediaDevice1 = mock(MediaDevice.class); + final MediaDevice selectableMediaDevice2 = mock(MediaDevice.class); + final MediaDevice selectableMediaDevice3 = mock(MediaDevice.class); + final List selectedMediaDevices = new ArrayList<>(); + final List selectableMediaDevices = new ArrayList<>(); + when(selectedMediaDevice1.getId()).thenReturn(TEST_DEVICE_1_ID); + when(selectedMediaDevice2.getId()).thenReturn(TEST_DEVICE_2_ID); + when(selectableMediaDevice1.getId()).thenReturn(TEST_DEVICE_3_ID); + when(selectableMediaDevice2.getId()).thenReturn(TEST_DEVICE_4_ID); + when(selectableMediaDevice3.getId()).thenReturn(TEST_DEVICE_5_ID); + selectedMediaDevices.add(selectedMediaDevice1); + selectedMediaDevices.add(selectedMediaDevice2); + selectableMediaDevices.add(selectableMediaDevice1); + selectableMediaDevices.add(selectableMediaDevice2); + doReturn(selectedMediaDevices).when(mLocalMediaManager).getSelectedMediaDevice(); + doReturn(selectableMediaDevices).when(mLocalMediaManager).getSelectableMediaDevice(); + final List groupMediaDevices = mMediaOutputController.getGroupMediaDevices(); + // Reset order + selectedMediaDevices.clear(); + selectedMediaDevices.add(selectedMediaDevice2); + selectedMediaDevices.add(selectedMediaDevice1); + selectableMediaDevices.clear(); + selectableMediaDevices.add(selectableMediaDevice3); + selectableMediaDevices.add(selectableMediaDevice2); + selectableMediaDevices.add(selectableMediaDevice1); + final List newDevices = mMediaOutputController.getGroupMediaDevices(); + + assertThat(newDevices.size()).isEqualTo(5); + for (int i = 0; i < groupMediaDevices.size(); i++) { + assertThat(TextUtils.equals(groupMediaDevices.get(i).getId(), + newDevices.get(i).getId())).isTrue(); + } + assertThat(newDevices.get(4).getId()).isEqualTo(TEST_DEVICE_5_ID); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java index ca328fbe44fb5..4b00d9eefd9c4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java @@ -64,7 +64,7 @@ public class MediaOutputDialogTest extends SysuiTestCase { @Before public void setUp() { - mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, + mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false, mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter); mMediaOutputController.mLocalMediaManager = mLocalMediaManager; mMediaOutputDialog = new MediaOutputDialog(mContext, false, mMediaOutputController);