Smooth out the alpha / colour animation for drag to split
Previously there were 2 animating surfaces, one for the highlight and
one for the splashscreen. When they animated together there was a bit
of undesirable crossfading.
This change makes it so that the colours and alpha animate together via
ArgbEvaluator and are only applied to 1 surface (the background color
drawable).
It also seems like you can continue to get drag events even after a
drop, so if a drop has happened skip animating. When a drag is
initiated again then mHasDropped is reset again.
Test: manual - drag an app into split and move it between the two split
dropzones, note that the colour animation is smooth.
- wildly drag between the two dropzones & drop, check that
on the next drag that animations animate from alpha 0 rather
than jump cutting to an alpha > 0.
Bug: 207011867
Change-Id: I8a5a681530d889c5c6ef4ad3a0b31af17998af73
This commit is contained in:
@@ -24,7 +24,6 @@ import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSIT
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityTaskManager;
|
||||
@@ -156,10 +155,6 @@ public class DragLayout extends LinearLayout {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasDropTarget() {
|
||||
return mCurrentTarget != null;
|
||||
}
|
||||
|
||||
public boolean hasDropped() {
|
||||
return mHasDropped;
|
||||
}
|
||||
@@ -271,6 +266,9 @@ public class DragLayout extends LinearLayout {
|
||||
* Updates the visible drop target as the user drags.
|
||||
*/
|
||||
public void update(DragEvent event) {
|
||||
if (mHasDropped) {
|
||||
return;
|
||||
}
|
||||
// Find containing region, if the same as mCurrentRegion, then skip, otherwise, animate the
|
||||
// visibility of the current region
|
||||
DragAndDropPolicy.Target target = mPolicy.getTargetAtLocation(
|
||||
@@ -286,7 +284,8 @@ public class DragLayout extends LinearLayout {
|
||||
animateHighlight(target);
|
||||
} else {
|
||||
// Switching between targets
|
||||
animateHighlight(target);
|
||||
mDropZoneView1.animateSwitch();
|
||||
mDropZoneView2.animateSwitch();
|
||||
}
|
||||
mCurrentTarget = target;
|
||||
}
|
||||
@@ -323,7 +322,7 @@ public class DragLayout extends LinearLayout {
|
||||
: DISABLE_NONE);
|
||||
mDropZoneView1.setShowingMargin(visible);
|
||||
mDropZoneView2.setShowingMargin(visible);
|
||||
ObjectAnimator animator = mDropZoneView1.getAnimator();
|
||||
Animator animator = mDropZoneView1.getAnimator();
|
||||
if (animCompleteCallback != null) {
|
||||
if (animator != null) {
|
||||
animator.addListener(new AnimatorListenerAdapter() {
|
||||
@@ -343,17 +342,11 @@ public class DragLayout extends LinearLayout {
|
||||
if (target.type == DragAndDropPolicy.Target.TYPE_SPLIT_LEFT
|
||||
|| target.type == DragAndDropPolicy.Target.TYPE_SPLIT_TOP) {
|
||||
mDropZoneView1.setShowingHighlight(true);
|
||||
mDropZoneView1.setShowingSplash(false);
|
||||
|
||||
mDropZoneView2.setShowingHighlight(false);
|
||||
mDropZoneView2.setShowingSplash(true);
|
||||
} else if (target.type == DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT
|
||||
|| target.type == DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM) {
|
||||
mDropZoneView1.setShowingHighlight(false);
|
||||
mDropZoneView1.setShowingSplash(true);
|
||||
|
||||
mDropZoneView2.setShowingHighlight(true);
|
||||
mDropZoneView2.setShowingSplash(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.wm.shell.draganddrop;
|
||||
|
||||
import static com.android.wm.shell.animation.Interpolators.FAST_OUT_SLOW_IN;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
@@ -27,7 +28,6 @@ import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.FloatProperty;
|
||||
import android.util.IntProperty;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
@@ -43,8 +43,8 @@ import com.android.wm.shell.R;
|
||||
*/
|
||||
public class DropZoneView extends FrameLayout {
|
||||
|
||||
private static final int SPLASHSCREEN_ALPHA_INT = (int) (255 * 0.90f);
|
||||
private static final int HIGHLIGHT_ALPHA_INT = 255;
|
||||
private static final float SPLASHSCREEN_ALPHA = 0.90f;
|
||||
private static final float HIGHLIGHT_ALPHA = 1f;
|
||||
private static final int MARGIN_ANIMATION_ENTER_DURATION = 400;
|
||||
private static final int MARGIN_ANIMATION_EXIT_DURATION = 250;
|
||||
|
||||
@@ -61,54 +61,27 @@ public class DropZoneView extends FrameLayout {
|
||||
}
|
||||
};
|
||||
|
||||
private static final IntProperty<ColorDrawable> SPLASHSCREEN_ALPHA =
|
||||
new IntProperty<ColorDrawable>("splashscreen") {
|
||||
@Override
|
||||
public void setValue(ColorDrawable d, int alpha) {
|
||||
d.setAlpha(alpha);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer get(ColorDrawable d) {
|
||||
return d.getAlpha();
|
||||
}
|
||||
};
|
||||
|
||||
private static final IntProperty<ColorDrawable> HIGHLIGHT_ALPHA =
|
||||
new IntProperty<ColorDrawable>("highlight") {
|
||||
@Override
|
||||
public void setValue(ColorDrawable d, int alpha) {
|
||||
d.setAlpha(alpha);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer get(ColorDrawable d) {
|
||||
return d.getAlpha();
|
||||
}
|
||||
};
|
||||
|
||||
private final Path mPath = new Path();
|
||||
private final float[] mContainerMargin = new float[4];
|
||||
private float mCornerRadius;
|
||||
private float mBottomInset;
|
||||
private int mMarginColor; // i.e. color used for negative space like the container insets
|
||||
private int mHighlightColor;
|
||||
|
||||
private boolean mShowingHighlight;
|
||||
private boolean mShowingSplash;
|
||||
private boolean mShowingMargin;
|
||||
|
||||
// TODO: might be more seamless to animate between splash/highlight color instead of 2 separate
|
||||
private ObjectAnimator mSplashAnimator;
|
||||
private ObjectAnimator mHighlightAnimator;
|
||||
private int mSplashScreenColor;
|
||||
private int mHighlightColor;
|
||||
|
||||
private ObjectAnimator mBackgroundAnimator;
|
||||
private ObjectAnimator mMarginAnimator;
|
||||
private float mMarginPercent;
|
||||
|
||||
// Renders a highlight or neutral transparent color
|
||||
private ColorDrawable mDropZoneDrawable;
|
||||
private ColorDrawable mColorDrawable;
|
||||
// Renders the translucent splashscreen with the app icon in the middle
|
||||
private ImageView mSplashScreenView;
|
||||
private ColorDrawable mSplashBackgroundDrawable;
|
||||
// Renders the margin / insets around the dropzone container
|
||||
private MarginView mMarginView;
|
||||
|
||||
@@ -130,19 +103,14 @@ public class DropZoneView extends FrameLayout {
|
||||
|
||||
mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context);
|
||||
mMarginColor = getResources().getColor(R.color.taskbar_background);
|
||||
mHighlightColor = getResources().getColor(android.R.color.system_accent1_500);
|
||||
|
||||
mDropZoneDrawable = new ColorDrawable();
|
||||
mDropZoneDrawable.setColor(mHighlightColor);
|
||||
mDropZoneDrawable.setAlpha(0);
|
||||
setBackgroundDrawable(mDropZoneDrawable);
|
||||
int c = getResources().getColor(android.R.color.system_accent1_500);
|
||||
mHighlightColor = Color.argb(HIGHLIGHT_ALPHA, Color.red(c), Color.green(c), Color.blue(c));
|
||||
mSplashScreenColor = Color.argb(SPLASHSCREEN_ALPHA, 0, 0, 0);
|
||||
mColorDrawable = new ColorDrawable();
|
||||
setBackgroundDrawable(mColorDrawable);
|
||||
|
||||
mSplashScreenView = new ImageView(context);
|
||||
mSplashScreenView.setScaleType(ImageView.ScaleType.CENTER);
|
||||
mSplashBackgroundDrawable = new ColorDrawable();
|
||||
mSplashBackgroundDrawable.setColor(Color.WHITE);
|
||||
mSplashBackgroundDrawable.setAlpha(SPLASHSCREEN_ALPHA_INT);
|
||||
mSplashScreenView.setBackgroundDrawable(mSplashBackgroundDrawable);
|
||||
addView(mSplashScreenView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
mSplashScreenView.setAlpha(0f);
|
||||
@@ -157,10 +125,6 @@ public class DropZoneView extends FrameLayout {
|
||||
mMarginColor = getResources().getColor(R.color.taskbar_background);
|
||||
mHighlightColor = getResources().getColor(android.R.color.system_accent1_500);
|
||||
|
||||
final int alpha = mDropZoneDrawable.getAlpha();
|
||||
mDropZoneDrawable.setColor(mHighlightColor);
|
||||
mDropZoneDrawable.setAlpha(alpha);
|
||||
|
||||
if (mMarginPercent > 0) {
|
||||
mMarginView.invalidate();
|
||||
}
|
||||
@@ -187,38 +151,39 @@ public class DropZoneView extends FrameLayout {
|
||||
}
|
||||
|
||||
/** Sets the color and icon to use for the splashscreen when shown. */
|
||||
public void setAppInfo(int splashScreenColor, Drawable appIcon) {
|
||||
mSplashBackgroundDrawable.setColor(splashScreenColor);
|
||||
public void setAppInfo(int color, Drawable appIcon) {
|
||||
Color c = Color.valueOf(color);
|
||||
mSplashScreenColor = Color.argb(SPLASHSCREEN_ALPHA, c.red(), c.green(), c.blue());
|
||||
mSplashScreenView.setImageDrawable(appIcon);
|
||||
}
|
||||
|
||||
/** @return an active animator for this view if one exists. */
|
||||
@Nullable
|
||||
public ObjectAnimator getAnimator() {
|
||||
public Animator getAnimator() {
|
||||
if (mMarginAnimator != null && mMarginAnimator.isRunning()) {
|
||||
return mMarginAnimator;
|
||||
} else if (mHighlightAnimator != null && mHighlightAnimator.isRunning()) {
|
||||
return mHighlightAnimator;
|
||||
} else if (mSplashAnimator != null && mSplashAnimator.isRunning()) {
|
||||
return mSplashAnimator;
|
||||
} else if (mBackgroundAnimator != null && mBackgroundAnimator.isRunning()) {
|
||||
return mBackgroundAnimator;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Animates the splashscreen to show or hide. */
|
||||
public void setShowingSplash(boolean showingSplash) {
|
||||
if (mShowingSplash != showingSplash) {
|
||||
mShowingSplash = showingSplash;
|
||||
animateSplashToState();
|
||||
}
|
||||
/** Animates between highlight and splashscreen depending on current state. */
|
||||
public void animateSwitch() {
|
||||
mShowingHighlight = !mShowingHighlight;
|
||||
mShowingSplash = !mShowingHighlight;
|
||||
final int newColor = mShowingHighlight ? mHighlightColor : mSplashScreenColor;
|
||||
animateBackground(mColorDrawable.getColor(), newColor);
|
||||
animateSplashScreenIcon();
|
||||
}
|
||||
|
||||
/** Animates the highlight indicating the zone is hovered on or not. */
|
||||
public void setShowingHighlight(boolean showingHighlight) {
|
||||
if (mShowingHighlight != showingHighlight) {
|
||||
mShowingHighlight = showingHighlight;
|
||||
animateHighlightToState();
|
||||
}
|
||||
mShowingHighlight = showingHighlight;
|
||||
mShowingSplash = !mShowingHighlight;
|
||||
final int newColor = mShowingHighlight ? mHighlightColor : mSplashScreenColor;
|
||||
animateBackground(Color.TRANSPARENT, newColor);
|
||||
animateSplashScreenIcon();
|
||||
}
|
||||
|
||||
/** Animates the margins around the drop zone to show or hide. */
|
||||
@@ -228,40 +193,31 @@ public class DropZoneView extends FrameLayout {
|
||||
animateMarginToState();
|
||||
}
|
||||
if (!mShowingMargin) {
|
||||
setShowingHighlight(false);
|
||||
setShowingSplash(false);
|
||||
mShowingHighlight = false;
|
||||
mShowingSplash = false;
|
||||
animateBackground(mColorDrawable.getColor(), Color.TRANSPARENT);
|
||||
animateSplashScreenIcon();
|
||||
}
|
||||
}
|
||||
|
||||
private void animateSplashToState() {
|
||||
if (mSplashAnimator != null) {
|
||||
mSplashAnimator.cancel();
|
||||
private void animateBackground(int startColor, int endColor) {
|
||||
if (mBackgroundAnimator != null) {
|
||||
mBackgroundAnimator.cancel();
|
||||
}
|
||||
mSplashAnimator = ObjectAnimator.ofInt(mSplashBackgroundDrawable,
|
||||
SPLASHSCREEN_ALPHA,
|
||||
mSplashBackgroundDrawable.getAlpha(),
|
||||
mShowingSplash ? SPLASHSCREEN_ALPHA_INT : 0);
|
||||
if (!mShowingSplash) {
|
||||
mSplashAnimator.setInterpolator(FAST_OUT_SLOW_IN);
|
||||
mBackgroundAnimator = ObjectAnimator.ofArgb(mColorDrawable,
|
||||
"color",
|
||||
startColor,
|
||||
endColor);
|
||||
if (!mShowingSplash && !mShowingHighlight) {
|
||||
mBackgroundAnimator.setInterpolator(FAST_OUT_SLOW_IN);
|
||||
}
|
||||
mSplashAnimator.start();
|
||||
mBackgroundAnimator.start();
|
||||
}
|
||||
|
||||
private void animateSplashScreenIcon() {
|
||||
mSplashScreenView.animate().alpha(mShowingSplash ? 1f : 0f).start();
|
||||
}
|
||||
|
||||
private void animateHighlightToState() {
|
||||
if (mHighlightAnimator != null) {
|
||||
mHighlightAnimator.cancel();
|
||||
}
|
||||
mHighlightAnimator = ObjectAnimator.ofInt(mDropZoneDrawable,
|
||||
HIGHLIGHT_ALPHA,
|
||||
mDropZoneDrawable.getAlpha(),
|
||||
mShowingHighlight ? HIGHLIGHT_ALPHA_INT : 0);
|
||||
if (!mShowingHighlight) {
|
||||
mHighlightAnimator.setInterpolator(FAST_OUT_SLOW_IN);
|
||||
}
|
||||
mHighlightAnimator.start();
|
||||
}
|
||||
|
||||
private void animateMarginToState() {
|
||||
if (mMarginAnimator != null) {
|
||||
mMarginAnimator.cancel();
|
||||
|
||||
Reference in New Issue
Block a user