diff options
6 files changed, 110 insertions, 36 deletions
diff --git a/packages/SystemUI/res/layout/media_output_list_item.xml b/packages/SystemUI/res/layout/media_output_list_item.xml index 92d0858a1a31..ac8b7b5812bd 100644 --- a/packages/SystemUI/res/layout/media_output_list_item.xml +++ b/packages/SystemUI/res/layout/media_output_list_item.xml @@ -75,18 +75,6 @@              android:textSize="12sp"              android:fontFamily="roboto-regular"              android:visibility="gone"/> -        <ProgressBar -            android:id="@+id/volume_indeterminate_progress" -            style="@*android:style/Widget.Material.ProgressBar.Horizontal" -            android:layout_width="match_parent" -            android:layout_height="wrap_content" -            android:layout_marginStart="16dp" -            android:layout_marginEnd="15dp" -            android:layout_marginBottom="1dp" -            android:layout_alignParentBottom="true" -            android:indeterminate="true" -            android:indeterminateOnly="true" -            android:visibility="gone"/>          <SeekBar              android:id="@+id/volume_seekbar"              android:layout_width="match_parent" @@ -94,6 +82,17 @@              android:layout_alignParentBottom="true"/>      </RelativeLayout> +    <ProgressBar +        android:id="@+id/volume_indeterminate_progress" +        style="@*android:style/Widget.Material.ProgressBar.Horizontal" +        android:layout_width="258dp" +        android:layout_height="18dp" +        android:layout_marginStart="68dp" +        android:layout_marginTop="40dp" +        android:indeterminate="true" +        android:indeterminateOnly="true" +        android:visibility="gone"/> +      <View          android:layout_width="1dp"          android:layout_height="36dp" diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 2e56df3e1fb8..8777d5077b87 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1380,4 +1380,5 @@      <dimen name="media_output_dialog_header_back_icon_size">36dp</dimen>      <dimen name="media_output_dialog_header_icon_padding">16dp</dimen>      <dimen name="media_output_dialog_icon_corner_radius">16dp</dimen> +    <dimen name="media_output_dialog_title_anim_y_delta">12.5dp</dimen>  </resources> 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 9b6a9ea80ebe..d1630ebe8dc8 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java @@ -44,6 +44,8 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {      private static final String TAG = "MediaOutputAdapter";      private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); +    private ViewGroup mConnectedItem; +      public MediaOutputAdapter(MediaOutputController controller) {          super(controller);      } @@ -79,18 +81,6 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {          return mController.getMediaDevices().size();      } -    void onItemClick(MediaDevice device) { -        mController.connectDevice(device); -        device.setState(MediaDeviceState.STATE_CONNECTING); -        notifyDataSetChanged(); -    } - -    void onItemClick(int customizedItem) { -        if (customizedItem == CUSTOMIZED_ITEM_PAIR_NEW) { -            mController.launchBluetoothPairing(); -        } -    } -      @Override      CharSequence getItemTitle(MediaDevice device) {          if (device.getDeviceType() == MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE @@ -117,6 +107,10 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {          @Override          void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin) {              super.onBind(device, topMargin, bottomMargin); +            final boolean currentlyConnected = isCurrentlyConnected(device); +            if (currentlyConnected) { +                mConnectedItem = mFrameLayout; +            }              if (mController.isTransferring()) {                  if (device.getState() == MediaDeviceState.STATE_CONNECTING                          && !mController.hasAdjustVolumeUserRestriction()) { @@ -133,16 +127,16 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {                              false /* showSeekBar*/, false /* showProgressBar */,                              true /* showSubtitle */);                      mSubTitleText.setText(R.string.media_output_dialog_connect_failed); -                    mFrameLayout.setOnClickListener(v -> onItemClick(device)); +                    mFrameLayout.setOnClickListener(v -> onItemClick(v, device));                  } else if (!mController.hasAdjustVolumeUserRestriction() -                        && isCurrentConnected(device)) { +                        && currentlyConnected) {                      setTwoLineLayout(device, null /* title */, true /* bFocused */,                              true /* showSeekBar*/, false /* showProgressBar */,                              false /* showSubtitle */);                      initSeekbar(device);                  } else {                      setSingleLineLayout(getItemTitle(device), false /* bFocused */); -                    mFrameLayout.setOnClickListener(v -> onItemClick(device)); +                    mFrameLayout.setOnClickListener(v -> onItemClick(v, device));                  }              }          } @@ -160,5 +154,24 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {                  mFrameLayout.setOnClickListener(v -> onItemClick(CUSTOMIZED_ITEM_PAIR_NEW));              }          } + +        private void onItemClick(View view, MediaDevice device) { +            if (mController.isTransferring()) { +                return; +            } + +            playSwitchingAnim(mConnectedItem, view); +            mController.connectDevice(device); +            device.setState(MediaDeviceState.STATE_CONNECTING); +            if (!isAnimating()) { +                notifyDataSetChanged(); +            } +        } + +        private void onItemClick(int customizedItem) { +            if (customizedItem == CUSTOMIZED_ITEM_PAIR_NEW) { +                mController.launchBluetoothPairing(); +            } +        }      }  } 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 01dc6c4b71da..2d3e77db1ea3 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java @@ -16,6 +16,8 @@  package com.android.systemui.media.dialog; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter;  import android.content.Context;  import android.graphics.Typeface;  import android.text.TextUtils; @@ -33,6 +35,7 @@ import androidx.annotation.NonNull;  import androidx.recyclerview.widget.RecyclerView;  import com.android.settingslib.media.MediaDevice; +import com.android.systemui.Interpolators;  import com.android.systemui.R;  /** @@ -50,6 +53,7 @@ public abstract class MediaOutputBaseAdapter extends      private boolean mIsDragging;      private int mMargin; +    private boolean mIsAnimating;      Context mContext;      View mHolderView; @@ -75,7 +79,7 @@ public abstract class MediaOutputBaseAdapter extends          return device.getName();      } -    boolean isCurrentConnected(MediaDevice device) { +    boolean isCurrentlyConnected(MediaDevice device) {          return TextUtils.equals(device.getId(),                  mController.getCurrentConnectedMediaDevice().getId());      } @@ -84,10 +88,17 @@ public abstract class MediaOutputBaseAdapter extends          return mIsDragging;      } +    boolean isAnimating() { +        return mIsAnimating; +    } +      /**       * ViewHolder for binding device view.       */      abstract class MediaDeviceBaseViewHolder extends RecyclerView.ViewHolder { + +        private static final int ANIM_DURATION = 200; +          final FrameLayout mFrameLayout;          final TextView mTitleText;          final TextView mTwoLineTitleText; @@ -123,17 +134,16 @@ public abstract class MediaOutputBaseAdapter extends          private void setMargin(boolean topMargin, boolean bottomMargin) {              ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mFrameLayout                      .getLayoutParams(); -            if (topMargin) { -                params.topMargin = mMargin; -            } -            if (bottomMargin) { -                params.bottomMargin = mMargin; -            } +            params.topMargin = topMargin ? mMargin : 0; +            params.bottomMargin = bottomMargin ? mMargin : 0;              mFrameLayout.setLayoutParams(params);          } +          void setSingleLineLayout(CharSequence title, boolean bFocused) { -            mTitleText.setVisibility(View.VISIBLE);              mTwoLineLayout.setVisibility(View.GONE); +            mProgressBar.setVisibility(View.GONE); +            mTitleText.setVisibility(View.VISIBLE); +            mTitleText.setTranslationY(0);              mTitleText.setText(title);              if (bFocused) {                  mTitleText.setTypeface(Typeface.create(FONT_SELECTED_TITLE, Typeface.NORMAL)); @@ -146,9 +156,11 @@ public abstract class MediaOutputBaseAdapter extends                  boolean showSeekBar, boolean showProgressBar, boolean showSubtitle) {              mTitleText.setVisibility(View.GONE);              mTwoLineLayout.setVisibility(View.VISIBLE); +            mSeekBar.setAlpha(1);              mSeekBar.setVisibility(showSeekBar ? View.VISIBLE : View.GONE);              mProgressBar.setVisibility(showProgressBar ? View.VISIBLE : View.GONE);              mSubTitleText.setVisibility(showSubtitle ? View.VISIBLE : View.GONE); +            mTwoLineTitleText.setTranslationY(0);              if (device == null) {                  mTwoLineTitleText.setText(title);              } else { @@ -189,5 +201,53 @@ public abstract class MediaOutputBaseAdapter extends                  }              });          } + +        void playSwitchingAnim(@NonNull View from, @NonNull View to) { +            final float delta = (float) (mContext.getResources().getDimensionPixelSize( +                    R.dimen.media_output_dialog_title_anim_y_delta)); +            final SeekBar fromSeekBar = from.requireViewById(R.id.volume_seekbar); +            final TextView toTitleText = to.requireViewById(R.id.title); +            if (fromSeekBar.getVisibility() != View.VISIBLE || toTitleText.getVisibility() +                    != View.VISIBLE) { +                return; +            } +            mIsAnimating = true; +            // Animation for title text +            toTitleText.setTypeface(Typeface.create(FONT_SELECTED_TITLE, Typeface.NORMAL)); +            toTitleText.animate() +                    .setDuration(ANIM_DURATION) +                    .translationY(-delta) +                    .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) +                    .setListener(new AnimatorListenerAdapter() { +                        @Override +                        public void onAnimationEnd(Animator animation) { +                            to.requireViewById(R.id.volume_indeterminate_progress).setVisibility( +                                    View.VISIBLE); +                        } +                    }); +            // Animation for seek bar +            fromSeekBar.animate() +                    .alpha(0) +                    .setDuration(ANIM_DURATION) +                    .setListener(new AnimatorListenerAdapter() { +                        @Override +                        public void onAnimationEnd(Animator animation) { +                            final TextView fromTitleText = from.requireViewById( +                                    R.id.two_line_title); +                            fromTitleText.setTypeface(Typeface.create(FONT_TITLE, Typeface.NORMAL)); +                            fromTitleText.animate() +                                    .setDuration(ANIM_DURATION) +                                    .translationY(delta) +                                    .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) +                                    .setListener(new AnimatorListenerAdapter() { +                                        @Override +                                        public void onAnimationEnd(Animator animation) { +                                            mIsAnimating = false; +                                            notifyDataSetChanged(); +                                        } +                                    }); +                        } +                    }); +        }      }  } 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 ebca8a735ad5..3b8299913e5b 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java @@ -170,7 +170,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements              mHeaderSubtitle.setText(subTitle);              mHeaderTitle.setGravity(Gravity.NO_GRAVITY);          } -        if (!mAdapter.isDragging()) { +        if (!mAdapter.isDragging() && !mAdapter.isAnimating()) {              mAdapter.notifyDataSetChanged();          }          // Show when remote media session is available 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 0e376bd356a2..2d460aa0c9c1 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 @@ -192,6 +192,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase {      public void onItemClick_clickDevice_verifyConnectDevice() {          assertThat(mMediaDevice2.getState()).isEqualTo(                  LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED); +        mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);          mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1);          mViewHolder.mFrameLayout.performClick();  |