Add animation when switching output device
Bug: 155822415 Test: manual test Merged-In: Ia3370222427b77099d987d59d5d5fd08c11557d7 Change-Id: Ia3370222427b77099d987d59d5d5fd08c11557d7
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user