Add animation when switching output device
Bug: 155822415
Test: manual test
Merged-In: Ia3370222427b77099d987d59d5d5fd08c11557d7
Change-Id: Ia3370222427b77099d987d59d5d5fd08c11557d7
diff --git a/packages/SystemUI/res/layout/media_output_list_item.xml b/packages/SystemUI/res/layout/media_output_list_item.xml
index 92d0858..ac8b7b5 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 a4f87f0..f002a27 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1410,4 +1410,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 9b6a9ea..d1630eb 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 @@
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 @@
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 @@
@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 @@
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 @@
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 01dc6c4..2d3e77d 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.recyclerview.widget.RecyclerView;
import com.android.settingslib.media.MediaDevice;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
/**
@@ -50,6 +53,7 @@
private boolean mIsDragging;
private int mMargin;
+ private boolean mIsAnimating;
Context mContext;
View mHolderView;
@@ -75,7 +79,7 @@
return device.getName();
}
- boolean isCurrentConnected(MediaDevice device) {
+ boolean isCurrentlyConnected(MediaDevice device) {
return TextUtils.equals(device.getId(),
mController.getCurrentConnectedMediaDevice().getId());
}
@@ -84,10 +88,17 @@
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 @@
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 @@
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 @@
}
});
}
+
+ 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 a589b07..e3e399b 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 @@
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 0e376bd..2d460aa 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 void onItemClick_clickDevice_verifyConnectDevice() {
assertThat(mMediaDevice2.getState()).isEqualTo(
LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED);
+ mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1);
mViewHolder.mFrameLayout.performClick();