diff options
3 files changed, 128 insertions, 78 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java index 3078a943be32..bd727883d93c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java @@ -246,6 +246,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase { assertThat(mViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE); assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE); assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mViewHolder.mEndClickIcon.getVisibility()).isEqualTo(View.GONE); assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE); assertThat(mViewHolder.mEndTouchArea.getVisibility()).isEqualTo(View.VISIBLE); } @@ -297,6 +298,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase { assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE); assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE); assertThat(mViewHolder.mEndTouchArea.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mViewHolder.mEndClickIcon.getVisibility()).isEqualTo(View.VISIBLE); } @Test @@ -312,12 +314,12 @@ public class MediaOutputAdapterTest extends SysuiTestCase { assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE); assertThat(mViewHolder.mTitleText.getText().toString()).isEqualTo(TEST_DEVICE_NAME_1); assertThat(mViewHolder.mStatusIcon.getVisibility()).isEqualTo(View.GONE); - assertThat(mViewHolder.mEndClickIcon.getVisibility()).isEqualTo(View.VISIBLE); assertThat(mViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE); assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE); assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE); assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE); assertThat(mViewHolder.mEndTouchArea.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mViewHolder.mEndClickIcon.getVisibility()).isEqualTo(View.VISIBLE); } @Test @@ -383,7 +385,9 @@ public class MediaOutputAdapterTest extends SysuiTestCase { mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1); assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mEndTouchArea.getVisibility()).isEqualTo(View.VISIBLE); assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mViewHolder.mEndClickIcon.getVisibility()).isEqualTo(View.GONE); assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE); assertThat(mViewHolder.mTitleText.getText().toString()).isEqualTo(TEST_DEVICE_NAME_2); assertThat(mViewHolder.mContainerLayout.isFocusable()).isTrue(); 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 bc6b2beb2ddb..53ebdfa8ddfe 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java @@ -34,6 +34,7 @@ import android.widget.TextView; import androidx.annotation.DoNotInline; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import androidx.core.widget.CompoundButtonCompat; import androidx.recyclerview.widget.RecyclerView; @@ -184,6 +185,11 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter { + "]"); } + boolean isDeviceGroup = false; + GroupStatus groupStatus = null; + OngoingSessionStatus ongoingSessionStatus = null; + ConnectionState connectionState = ConnectionState.DISCONNECTED; + if (mCurrentActivePosition == position) { mCurrentActivePosition = -1; } @@ -194,11 +200,11 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter { if (mController.isAnyDeviceTransferring()) { if (device.getState() == MediaDeviceState.STATE_CONNECTING && !mController.hasAdjustVolumeUserRestriction()) { + connectionState = ConnectionState.CONNECTING; setUpDeviceIcon(device); updateProgressBarColor(); setSingleLineLayout(device.getName(), false /* showSeekBar*/, - true /* showProgressBar */, false /* showCheckBox */, - false /* showEndTouchArea */); + true /* showProgressBar */); } else { setUpDeviceIcon(device); setSingleLineLayout(device.getName()); @@ -217,47 +223,38 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter { && isDeviceIncluded(mController.getSelectedMediaDevice(), device)) { if (!mediaItem.isFirstDeviceInGroup()) { mItemLayout.setVisibility(View.GONE); - mEndTouchArea.setVisibility(View.GONE); + return; } else { + isDeviceGroup = true; String sessionName = mController.getSessionName().toString(); updateUnmutedVolumeIcon(null); - updateEndClickAreaWithIcon( - v -> { - mShouldGroupSelectedMediaItems = false; - notifyDataSetChanged(); - }, - R.drawable.media_output_item_expand_group, - R.string.accessibility_expand_group); disableFocusPropertyForView(mContainerLayout); setUpContentDescriptionForView(mSeekBar, mContext.getString( R.string.accessibility_cast_name, sessionName)); setSingleLineLayout(sessionName, true /* showSeekBar */, - false /* showProgressBar */, false /* showCheckBox */, - true /* showEndTouchArea */); + false /* showProgressBar */); initGroupSeekbar(isCurrentSeekbarInvisible); } } else if (device.hasSubtext()) { boolean isActiveWithOngoingSession = device.hasOngoingSession() && (currentlyConnected || isSelected); - boolean isHost = device.isHostForOngoingSession() - && isActiveWithOngoingSession; if (isActiveWithOngoingSession) { mCurrentActivePosition = position; updateUnmutedVolumeIcon(device); mSubTitleText.setText(device.getSubtextString()); updateContentAlpha(DEVICE_CONNECTED_ALPHA); - updateEndClickAreaAsSessionEditing(device, - isHost ? R.drawable.media_output_status_edit_session - : R.drawable.ic_sound_bars_anim); + ongoingSessionStatus = new OngoingSessionStatus( + device.isHostForOngoingSession()); setTwoLineLayout(device.getName() /* title */, true /* showSeekBar */, false /* showProgressBar */, - true /* showSubtitle */, false /* showStatus */, - true /* showEndTouchArea */); + true /* showSubtitle */, false /* showStatus */); + connectionState = ConnectionState.CONNECTED; initSeekbar(device, isCurrentSeekbarInvisible); } else { if (currentlyConnected) { mCurrentActivePosition = position; updateUnmutedVolumeIcon(device); + connectionState = ConnectionState.CONNECTED; } else { setUpDeviceIcon(device); } @@ -288,22 +285,22 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter { false /* showProgressBar */, true /* showSubtitle */, true /* showStatus */); } else if (device.getState() == MediaDeviceState.STATE_GROUPING) { + connectionState = ConnectionState.CONNECTING; setUpDeviceIcon(device); updateProgressBarColor(); setSingleLineLayout(device.getName(), false /* showSeekBar*/, - true /* showProgressBar */, false /* showCheckBox */, - false /* showEndTouchArea */); + true /* showProgressBar */); } else if (mController.getSelectedMediaDevice().size() > 1 && isSelected) { // selected device in group - boolean showEndArea = - !Flags.enableOutputSwitcherSessionGrouping() || isDeselectable; updateUnmutedVolumeIcon(device); - updateEndAreaForGroupCheckbox(device, true /* isSelected */, isDeselectable); + groupStatus = new GroupStatus( + true /* selected */, + isDeselectable /* deselectable */); disableFocusPropertyForView(mContainerLayout); setUpContentDescriptionForView(mSeekBar, device); setSingleLineLayout(device.getName(), true /* showSeekBar */, - false /* showProgressBar */, true /* showCheckBox */, - showEndArea /* showEndTouchArea */); + false /* showProgressBar */); + connectionState = ConnectionState.CONNECTED; initSeekbar(device, isCurrentSeekbarInvisible); } else if (!mController.hasAdjustVolumeUserRestriction() && currentlyConnected) { @@ -317,26 +314,25 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter { } else if (device.hasOngoingSession()) { mCurrentActivePosition = position; updateUnmutedVolumeIcon(device); - updateEndClickAreaAsSessionEditing(device, device.isHostForOngoingSession() - ? R.drawable.media_output_status_edit_session - : R.drawable.ic_sound_bars_anim); - mEndClickIcon.setVisibility(View.VISIBLE); + ongoingSessionStatus = new OngoingSessionStatus( + device.isHostForOngoingSession()); setSingleLineLayout(device.getName(), true /* showSeekBar */, - false /* showProgressBar */, false /* showCheckBox */, - true /* showEndTouchArea */); + false /* showProgressBar */); + connectionState = ConnectionState.CONNECTED; initSeekbar(device, isCurrentSeekbarInvisible); } else if (mController.isCurrentConnectedDeviceRemote() && !mController.getSelectableMediaDevice().isEmpty()) { //If device is connected and there's other selectable devices, layout as // one of selected devices. updateUnmutedVolumeIcon(device); - updateEndAreaForGroupCheckbox(device, true /* isSelected */, - isDeselectable); + groupStatus = new GroupStatus( + true /* selected */, + isDeselectable /* isDeselectable */); disableFocusPropertyForView(mContainerLayout); setUpContentDescriptionForView(mSeekBar, device); setSingleLineLayout(device.getName(), true /* showSeekBar */, - false /* showProgressBar */, true /* showCheckBox */, - true /* showEndTouchArea */); + false /* showProgressBar */); + connectionState = ConnectionState.CONNECTED; initSeekbar(device, isCurrentSeekbarInvisible); } else { updateUnmutedVolumeIcon(device); @@ -344,23 +340,21 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter { setUpContentDescriptionForView(mSeekBar, device); mCurrentActivePosition = position; setSingleLineLayout(device.getName(), true /* showSeekBar */, - false /* showProgressBar */, false /* showCheckBox */, - false /* showEndTouchArea */); + false /* showProgressBar */); + connectionState = ConnectionState.CONNECTED; initSeekbar(device, isCurrentSeekbarInvisible); } } else if (isSelectable) { //groupable device setUpDeviceIcon(device); - updateEndAreaForGroupCheckbox(device, false /* isSelected */, - true /* isDeselectable */); + groupStatus = new GroupStatus(false /* selected */, true /* deselectable */); if (!Flags.disableTransferWhenAppsDoNotSupport() || isTransferable || hasRouteListingPreferenceItem) { updateFullItemClickListener(v -> onItemClick(v, device)); } setSingleLineLayout(device.getName(), false /* showSeekBar */, - false /* showProgressBar */, true /* showCheckBox */, - true /* showEndTouchArea */); + false /* showProgressBar */); } else { setUpDeviceIcon(device); setSingleLineLayout(device.getName()); @@ -379,6 +373,44 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter { ? DEVICE_CONNECTED_ALPHA : DEVICE_DISCONNECTED_ALPHA); } } + + if (isDeviceGroup) { + updateEndAreaForDeviceGroup(); + } else { + updateEndArea(device, connectionState, groupStatus, ongoingSessionStatus); + } + } + + /** Renders the right side round pill button / checkbox. */ + private void updateEndArea(@NonNull MediaDevice device, ConnectionState connectionState, + @Nullable GroupStatus groupStatus, + @Nullable OngoingSessionStatus ongoingSessionStatus) { + boolean showEndArea = false; + boolean isCheckbox = false; + // If both group status and the ongoing session status are present, only the ongoing + // session controls are displayed. The current layout design doesn't allow both group + // and ongoing session controls to be rendered simultaneously. + if (ongoingSessionStatus != null && connectionState == ConnectionState.CONNECTED) { + showEndArea = true; + updateEndAreaForOngoingSession(device, ongoingSessionStatus.host()); + } else if (groupStatus != null && shouldShowGroupCheckbox(groupStatus)) { + showEndArea = true; + isCheckbox = true; + updateEndAreaForGroupCheckBox(device, groupStatus); + } + updateEndAreaVisibility(showEndArea, isCheckbox); + } + + private boolean shouldShowGroupCheckbox(@NonNull GroupStatus groupStatus) { + if (Flags.enableOutputSwitcherSessionGrouping()) { + return isGroupCheckboxEnabled(groupStatus); + } + return true; + } + + private boolean isGroupCheckboxEnabled(@NonNull GroupStatus groupStatus) { + boolean disabled = groupStatus.selected() && !groupStatus.deselectable(); + return !disabled; } public void setCheckBoxColor(CheckBox checkBox, int color) { @@ -395,14 +427,26 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter { mStatusIcon.setAlpha(alphaValue); } - private void updateEndClickAreaAsSessionEditing(MediaDevice device, @DrawableRes int id) { - updateEndClickAreaWithIcon( + private void updateEndAreaForDeviceGroup() { + updateEndAreaWithIcon( + v -> { + mShouldGroupSelectedMediaItems = false; + notifyDataSetChanged(); + }, + R.drawable.media_output_item_expand_group, + R.string.accessibility_expand_group); + updateEndAreaVisibility(true /* showEndArea */, false /* isCheckbox */); + } + + private void updateEndAreaForOngoingSession(@NonNull MediaDevice device, boolean isHost) { + updateEndAreaWithIcon( v -> mController.tryToLaunchInAppRoutingIntent(device.getId(), v), - id, + isHost ? R.drawable.media_output_status_edit_session + : R.drawable.ic_sound_bars_anim, R.string.accessibility_open_application); } - private void updateEndClickAreaWithIcon(View.OnClickListener clickListener, + private void updateEndAreaWithIcon(View.OnClickListener clickListener, @DrawableRes int iconDrawableId, @StringRes int accessibilityStringId) { updateEndAreaColor(mController.getColorSeekbarProgress()); @@ -454,22 +498,20 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter { ColorStateList.valueOf(mController.getColorItemContent())); } - public void updateEndAreaForGroupCheckbox(MediaDevice device, boolean isSelected, - boolean isDeselectable) { - mEndTouchArea.setOnClickListener(null); + public void updateEndAreaForGroupCheckBox(@NonNull MediaDevice device, + @NonNull GroupStatus groupStatus) { + boolean isEnabled = isGroupCheckboxEnabled(groupStatus); mEndTouchArea.setOnClickListener( - isDeselectable ? (v) -> mCheckBox.performClick() : null); - mEndTouchArea.setImportantForAccessibility( - View.IMPORTANT_FOR_ACCESSIBILITY_YES); - updateEndAreaColor(isSelected ? mController.getColorSeekbarProgress() + isEnabled ? (v) -> mCheckBox.performClick() : null); + mEndTouchArea.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); + updateEndAreaColor(groupStatus.selected() ? mController.getColorSeekbarProgress() : mController.getColorItemBackground()); setUpContentDescriptionForView(mEndTouchArea, device); - mCheckBox.setOnCheckedChangeListener(null); - mCheckBox.setChecked(isSelected); + mCheckBox.setChecked(groupStatus.selected()); mCheckBox.setOnCheckedChangeListener( - isDeselectable ? (buttonView, isChecked) -> onGroupActionTriggered(!isSelected, - device) : null); - mCheckBox.setEnabled(isDeselectable); + isEnabled ? (buttonView, isChecked) -> onGroupActionTriggered( + !groupStatus.selected(), device) : null); + mCheckBox.setEnabled(isEnabled); setCheckBoxColor(mCheckBox, mController.getColorItemContent()); } @@ -546,7 +588,7 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter { view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO); } - private void setUpContentDescriptionForView(View view, MediaDevice device) { + private void setUpContentDescriptionForView(View view, @NonNull MediaDevice device) { setUpContentDescriptionForView( view, mContext.getString(device.getDeviceType() 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 a7786c8f0b57..52567581b48e 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java @@ -56,6 +56,16 @@ import java.util.List; public abstract class MediaOutputBaseAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { + record OngoingSessionStatus(boolean host) {} + + record GroupStatus(Boolean selected, Boolean deselectable) {} + + enum ConnectionState { + CONNECTED, + CONNECTING, + DISCONNECTED, + } + protected final MediaSwitchingController mController; private static final int UNMUTE_DEFAULT_VOLUME = 2; @@ -175,6 +185,7 @@ public abstract class MediaOutputBaseAdapter extends mCheckBox.setVisibility(View.GONE); mStatusIcon.setVisibility(View.GONE); mEndTouchArea.setVisibility(View.GONE); + mEndClickIcon.setVisibility(View.GONE); mEndTouchArea.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); mContainerLayout.setOnClickListener(null); mContainerLayout.setContentDescription(null); @@ -187,11 +198,10 @@ public abstract class MediaOutputBaseAdapter extends } void setSingleLineLayout(CharSequence title) { - setSingleLineLayout(title, false, false, false, false); + setSingleLineLayout(title, false, false); } - void setSingleLineLayout(CharSequence title, boolean showSeekBar, - boolean showProgressBar, boolean showCheckBox, boolean showEndTouchArea) { + void setSingleLineLayout(CharSequence title, boolean showSeekBar, boolean showProgressBar) { boolean isActive = showSeekBar || showProgressBar; if (!mCornerAnimator.isRunning()) { final Drawable backgroundDrawable = @@ -216,22 +226,11 @@ public abstract class MediaOutputBaseAdapter extends mSeekBar.resetVolume(); } mTitleText.setText(title); - mCheckBox.setVisibility(showCheckBox ? View.VISIBLE : View.GONE); - mEndTouchArea.setVisibility(showEndTouchArea ? View.VISIBLE : View.GONE); - if (Flags.enableOutputSwitcherSessionGrouping()) { - mEndClickIcon.setVisibility( - !showCheckBox && showEndTouchArea ? View.VISIBLE : View.GONE); - } - } - - void setTwoLineLayout(CharSequence title, boolean showSeekBar, - boolean showProgressBar, boolean showSubtitle, boolean showStatus) { - setTwoLineLayout(title, showSeekBar, showProgressBar, showSubtitle, showStatus, false); } void setTwoLineLayout(CharSequence title, boolean showSeekBar, boolean showProgressBar, boolean showSubtitle, - boolean showStatus , boolean showEndTouchArea) { + boolean showStatus) { mStatusIcon.setVisibility(showStatus ? View.VISIBLE : View.GONE); mSeekBar.setAlpha(1); mSeekBar.setVisibility(showSeekBar ? View.VISIBLE : View.GONE); @@ -246,15 +245,20 @@ public abstract class MediaOutputBaseAdapter extends if (showSeekBar) { updateSeekbarProgressBackground(); } - //update end click area by isActive - mEndTouchArea.setVisibility(showEndTouchArea ? View.VISIBLE : View.GONE); - mEndClickIcon.setVisibility(showEndTouchArea ? View.VISIBLE : View.GONE); mItemLayout.setBackground(backgroundDrawable); mProgressBar.setVisibility(showProgressBar ? View.VISIBLE : View.GONE); mSubTitleText.setVisibility(showSubtitle ? View.VISIBLE : View.GONE); mTitleText.setText(title); } + protected void updateEndAreaVisibility(boolean showEndTouchArea, boolean isCheckbox) { + mEndTouchArea.setVisibility(showEndTouchArea ? View.VISIBLE : View.GONE); + if (showEndTouchArea) { + mCheckBox.setVisibility(isCheckbox ? View.VISIBLE : View.GONE); + mEndClickIcon.setVisibility(!isCheckbox ? View.VISIBLE : View.GONE); + } + } + void updateSeekbarProgressBackground() { final ClipDrawable clipDrawable = (ClipDrawable) ((LayerDrawable) mSeekBar.getProgressDrawable()) |