Moving dim calculation into the stack layout.

- This simplifies code and also prepares the code for dimming certain
  tasks when focused.
- Ensuring that cancelling transitions will completely remove all 
  listeners in a given animation.

Change-Id: I77050d94097f9af404250c287522d83c146cfb25
This commit is contained in:
Winson
2016-02-10 13:29:39 -08:00
parent c4524a97c4
commit 1bcf3c4742
10 changed files with 89 additions and 100 deletions

View File

@@ -165,9 +165,6 @@
<!-- The animation duration for entering and exiting the history. -->
<integer name="recents_history_transition_duration">250</integer>
<!-- The minimum alpha for the dim applied to cards that go deeper into the stack. -->
<integer name="recents_max_task_stack_view_dim">96</integer>
<!-- The delay to enforce between each alt-tab key press. -->
<integer name="recents_alt_tab_key_delay">200</integer>

View File

@@ -17,6 +17,7 @@
package com.android.systemui.recents.misc;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -30,6 +31,7 @@ import android.view.ViewParent;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.views.TaskViewTransform;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -154,11 +156,24 @@ public class Utilities {
*/
public static void cancelAnimationWithoutCallbacks(Animator animator) {
if (animator != null) {
animator.removeAllListeners();
removeAnimationListenersRecursive(animator);
animator.cancel();
}
}
/**
* Recursively removes all the listeners of all children of this animator
*/
public static void removeAnimationListenersRecursive(Animator animator) {
if (animator instanceof AnimatorSet) {
ArrayList<Animator> animators = ((AnimatorSet) animator).getChildAnimations();
for (int i = animators.size() - 1; i >= 0; i--) {
removeAnimationListenersRecursive(animators.get(i));
}
}
animator.removeAllListeners();
}
/**
* Updates {@param transforms} to be the same size as {@param tasks}.
*/

View File

@@ -25,6 +25,9 @@ import android.view.ViewOutlineProvider;
/* An outline provider that has a clip and outline that can be animated. */
public class AnimateableViewBounds extends ViewOutlineProvider {
private static final float MIN_ALPHA = 0.1f;
private static final float MAX_ALPHA = 0.8f;
View mSourceView;
@ViewDebug.ExportedProperty(category="recents")
Rect mClipRect = new Rect();
@@ -36,7 +39,6 @@ public class AnimateableViewBounds extends ViewOutlineProvider {
int mCornerRadius;
@ViewDebug.ExportedProperty(category="recents")
float mAlpha = 1f;
final float mMinAlpha = 0.25f;
public AnimateableViewBounds(View source, int cornerRadius) {
mSourceView = source;
@@ -53,7 +55,7 @@ public class AnimateableViewBounds extends ViewOutlineProvider {
@Override
public void getOutline(View view, Outline outline) {
outline.setAlpha(mMinAlpha + mAlpha / (1f - mMinAlpha));
outline.setAlpha(MIN_ALPHA + mAlpha * (MAX_ALPHA - MIN_ALPHA));
if (mCornerRadius > 0) {
outline.setRoundRect(mClipRect.left, mClipRect.top,
mSourceView.getWidth() - mClipRect.right,
@@ -66,7 +68,9 @@ public class AnimateableViewBounds extends ViewOutlineProvider {
}
}
/** Sets the view outline alpha. */
/**
* Sets the view outline alpha.
*/
void setAlpha(float alpha) {
if (Float.compare(alpha, mAlpha) != 0) {
mAlpha = alpha;

View File

@@ -49,6 +49,7 @@ public class AnimationProps {
public static final int ALPHA = 4;
public static final int SCALE = 5;
public static final int BOUNDS = 6;
public static final int DIM_ALPHA = 7;
private SparseLongArray mPropStartDelay;
private SparseLongArray mPropDuration;

View File

@@ -152,10 +152,11 @@ public class FreeformWorkspaceLayoutAlgorithm {
transformOut.scale = 1f;
transformOut.alpha = 1f;
transformOut.translationZ = stackLayout.mMaxTranslationZ;
transformOut.dimAlpha = 0f;
transformOut.rect.set(ffRect);
transformOut.rect.offset(stackLayout.mFreeformRect.left, stackLayout.mFreeformRect.top);
transformOut.visible = true;
transformOut.p = 1f;
transformOut.relativeTaskProgress = 0f;
return transformOut;
}
return null;

View File

@@ -26,6 +26,7 @@ import android.util.ArraySet;
import android.util.FloatProperty;
import android.util.Property;
import android.view.ViewDebug;
import android.view.animation.AccelerateInterpolator;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -107,6 +108,10 @@ public class TaskStackLayoutAlgorithm {
// The scale factor to apply to the user movement in the stack to unfocus it
private static final float UNFOCUS_MULTIPLIER = 0.8f;
// The distribution of dim to apply to tasks in the stack
private static final AccelerateInterpolator DIM_INTERPOLATOR = new AccelerateInterpolator(3f);
public static final float DIM_MAX_VALUE = 0.35f;
// The various focus states
public static final float STATE_FOCUSED = 1f;
public static final float STATE_UNFOCUSED = 0f;
@@ -719,12 +724,14 @@ public class TaskStackLayoutAlgorithm {
transformOut.scale = 1f;
transformOut.alpha = 1f;
transformOut.translationZ = z;
transformOut.dimAlpha = DIM_MAX_VALUE * DIM_INTERPOLATOR.getInterpolation(1f -
Math.max(0f, Math.min(1f, relP)));
transformOut.rect.set(mTaskRect);
transformOut.rect.offset(x, y);
Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale);
transformOut.visible = (transformOut.rect.top < mStackRect.bottom) &&
(frontTransform == null || transformOut.rect.top != frontTransform.rect.top);
transformOut.p = relP;
transformOut.relativeTaskProgress = relP;
}
/**

View File

@@ -560,7 +560,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
tv.updateViewPropertiesToTaskTransform(transform, AnimationProps.IMMEDIATE,
mRequestUpdateClippingListener);
} else {
if (Float.compare(transform.p, 0f) <= 0) {
if (Float.compare(transform.relativeTaskProgress, 0f) <= 0) {
tv.updateViewPropertiesToTaskTransform(
mLayoutAlgorithm.getBackOfStackTransform(),
AnimationProps.IMMEDIATE, mRequestUpdateClippingListener);

View File

@@ -30,7 +30,6 @@ import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewDebug;
import android.view.ViewParent;
import android.view.animation.Animation;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
@@ -45,7 +44,6 @@ import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.HideRecentsEvent;
import com.android.systemui.recents.events.ui.StackViewScrolledEvent;
import com.android.systemui.recents.events.ui.TaskViewDismissedEvent;
import com.android.systemui.recents.misc.RectFEvaluator;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.Utilities;
import com.android.systemui.recents.model.Task;
@@ -547,7 +545,8 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
// We only really need to interpolate the bounds, progress and translation
mTmpTransform.rect.set(Utilities.RECTF_EVALUATOR.evaluate(dismissFraction,
fromTransform.rect, toTransform.rect));
mTmpTransform.p = fromTransform.p + (toTransform.p - fromTransform.p) * dismissFraction;
mTmpTransform.dimAlpha = fromTransform.dimAlpha + (toTransform.dimAlpha - fromTransform.dimAlpha) *
dismissFraction;
mTmpTransform.translationZ = fromTransform.translationZ +
(toTransform.translationZ - fromTransform.translationZ) * dismissFraction;

View File

@@ -31,13 +31,11 @@ import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.util.IntProperty;
import android.util.Property;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewOutlineProvider;
import android.view.animation.AccelerateInterpolator;
import android.widget.Toast;
import com.android.internal.logging.MetricsLogger;
@@ -81,39 +79,21 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
* The dim overlay is generally calculated from the task progress, but occasionally (like when
* launching) needs to be animated independently of the task progress.
*/
public static final Property<TaskView, Integer> DIM =
new IntProperty<TaskView>("dim") {
public static final Property<TaskView, Float> DIM_ALPHA =
new FloatProperty<TaskView>("dim") {
@Override
public void setValue(TaskView tv, int dim) {
tv.setDim(dim);
}
@Override
public Integer get(TaskView tv) {
return tv.getDim();
}
};
public static final Property<TaskView, Float> TASK_PROGRESS =
new FloatProperty<TaskView>("taskProgress") {
@Override
public void setValue(TaskView tv, float p) {
tv.setTaskProgress(p);
public void setValue(TaskView tv, float dimAlpha) {
tv.setDimAlpha(dimAlpha);
}
@Override
public Float get(TaskView tv) {
return tv.getTaskProgress();
return tv.getDimAlpha();
}
};
@ViewDebug.ExportedProperty(category="recents")
float mTaskProgress;
@ViewDebug.ExportedProperty(category="recents")
float mMaxDimScale;
@ViewDebug.ExportedProperty(category="recents")
int mDimAlpha;
AccelerateInterpolator mDimInterpolator = new AccelerateInterpolator(3f);
float mDimAlpha;
PorterDuffColorFilter mDimColorFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_ATOP);
Paint mDimLayerPaint = new Paint();
float mActionButtonTranslationZ;
@@ -163,7 +143,6 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
super(context, attrs, defStyleAttr, defStyleRes);
RecentsConfiguration config = Recents.getConfiguration();
Resources res = context.getResources();
mMaxDimScale = res.getInteger(R.integer.recents_max_task_stack_view_dim) / 255f;
mViewBounds = new AnimateableViewBounds(this, res.getDimensionPixelSize(
R.dimen.recents_task_view_rounded_corners_radius));
if (config.fakeShadows) {
@@ -269,8 +248,8 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
mTmpAnimators.clear();
toTransform.applyToTaskView(this, mTmpAnimators, toAnimation, !config.fakeShadows);
if (toAnimation.isImmediate()) {
if (Float.compare(getTaskProgress(), toTransform.p) != 0) {
setTaskProgress(toTransform.p);
if (Float.compare(getDimAlpha(), toTransform.dimAlpha) != 0) {
setDimAlpha(toTransform.dimAlpha);
}
// Manually call back to the animator listener and update callback
if (toAnimation.getListener() != null) {
@@ -281,9 +260,9 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
}
} else {
// Both the progress and the update are a function of the bounds movement of the task
if (Float.compare(getTaskProgress(), toTransform.p) != 0) {
ObjectAnimator anim = ObjectAnimator.ofFloat(this, TASK_PROGRESS, getTaskProgress(),
toTransform.p);
if (Float.compare(getDimAlpha(), toTransform.dimAlpha) != 0) {
ObjectAnimator anim = ObjectAnimator.ofFloat(this, DIM_ALPHA, getDimAlpha(),
toTransform.dimAlpha);
mTmpAnimators.add(toAnimation.apply(AnimationProps.BOUNDS, anim));
}
if (updateCallback != null) {
@@ -301,7 +280,7 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
/** Resets this view's properties */
void resetViewProperties() {
cancelTransformAnimation();
setDim(0);
setDimAlpha(0);
setVisibility(View.VISIBLE);
getViewBounds().reset();
getHeaderView().reset();
@@ -376,76 +355,58 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
}
}
/** Sets the current task progress. */
public void setTaskProgress(float p) {
mTaskProgress = p;
mViewBounds.setAlpha(p);
updateDimFromTaskProgress();
}
public TaskViewHeader getHeaderView() {
return mHeaderView;
}
/** Returns the current task progress. */
public float getTaskProgress() {
return mTaskProgress;
}
/** Returns the current dim. */
public void setDim(int dim) {
/**
* Sets the current dim.
*/
public void setDimAlpha(float dimAlpha) {
RecentsConfiguration config = Recents.getConfiguration();
mDimAlpha = dim;
int dimAlphaInt = (int) (dimAlpha * 255);
mDimAlpha = dimAlpha;
mViewBounds.setAlpha(1f - (dimAlpha / TaskStackLayoutAlgorithm.DIM_MAX_VALUE));
if (config.useHardwareLayers) {
// Defer setting hardware layers if we have not yet measured, or there is no dim to draw
if (getMeasuredWidth() > 0 && getMeasuredHeight() > 0) {
mDimColorFilter.setColor(Color.argb(mDimAlpha, 0, 0, 0));
mDimColorFilter.setColor(Color.argb(dimAlphaInt, 0, 0, 0));
mDimLayerPaint.setColorFilter(mDimColorFilter);
mContent.setLayerType(LAYER_TYPE_HARDWARE, mDimLayerPaint);
}
} else {
float dimAlpha = mDimAlpha / 255.0f;
mThumbnailView.setDimAlpha(dimAlpha);
mHeaderView.setDimAlpha(dimAlpha);
}
}
/** Returns the current dim. */
public int getDim() {
/**
* Returns the current dim.
*/
public float getDimAlpha() {
return mDimAlpha;
}
/** Animates the dim to the task progress. */
void animateDimToProgress(int duration, Animator.AnimatorListener animListener) {
/**
* Animates the dim to the given value.
*/
void animateDimAlpha(float toDimAlpha, AnimationProps animation) {
// Animate the dim into view as well
int toDim = getDimFromTaskProgress();
if (toDim != getDim()) {
ObjectAnimator anim = ObjectAnimator.ofInt(this, DIM, getDim(), toDim);
anim.setDuration(duration);
if (animListener != null) {
anim.addListener(animListener);
if (Float.compare(toDimAlpha, getDimAlpha()) != 0) {
Animator anim = animation.apply(AnimationProps.DIM_ALPHA, ObjectAnimator.ofFloat(this,
DIM_ALPHA, getDimAlpha(), toDimAlpha));
if (animation.getListener() != null) {
anim.addListener(animation.getListener());
}
anim.start();
} else {
animListener.onAnimationEnd(null);
if (animation.getListener() != null) {
animation.getListener().onAnimationEnd(null);
}
}
}
/** Compute the dim as a function of the scale of this view. */
int getDimFromTaskProgress() {
float x = mTaskProgress < 0
? 1f
: mDimInterpolator.getInterpolation(1f - mTaskProgress);
float dim = mMaxDimScale * x;
return (int) (dim * 255);
}
/** Update the dim as a function of the scale of this view. */
void updateDimFromTaskProgress() {
setDim(getDimFromTaskProgress());
}
/**
* Explicitly sets the focused state of this task.
*/
@@ -532,15 +493,18 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
@Override
public void onPrepareLaunchTargetForEnterAnimation() {
// These values will be animated in when onStartLaunchTargetEnterAnimation() is called
setDim(0);
setDimAlpha(0);
mActionButtonView.setAlpha(0f);
}
@Override
public void onStartLaunchTargetEnterAnimation(int duration, boolean screenPinningEnabled,
ReferenceCountedTrigger postAnimationTrigger) {
// Un-dim the view before launching the target
AnimationProps animation = new AnimationProps(duration, Interpolators.ALPHA_OUT)
.setListener(postAnimationTrigger.decrementOnAnimationEnd());
postAnimationTrigger.increment();
animateDimToProgress(duration, postAnimationTrigger.decrementOnAnimationEnd());
animateDimAlpha(0, animation);
if (screenPinningEnabled) {
showActionButton(true /* fadeIn */, duration /* fadeInDuration */);
@@ -550,12 +514,9 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
@Override
public void onStartLaunchTargetLaunchAnimation(int duration, boolean screenPinningRequested,
ReferenceCountedTrigger postAnimationTrigger) {
if (mDimAlpha > 0) {
ObjectAnimator anim = ObjectAnimator.ofInt(this, DIM, getDim(), 0);
anim.setDuration(duration);
anim.setInterpolator(Interpolators.ALPHA_OUT);
anim.start();
}
// Un-dim the view before launching the target
AnimationProps animation = new AnimationProps(duration, Interpolators.ALPHA_OUT);
animateDimAlpha(0, animation);
postAnimationTrigger.increment();
hideActionButton(true /* fadeOut */, duration,

View File

@@ -86,12 +86,13 @@ public class TaskViewTransform {
public float translationZ = 0;
public float scale = 1f;
public float alpha = 1f;
public float dimAlpha = 0f;
public boolean visible = false;
// This is the relative task progress of this task, relative to the stack scroll at which this
// transform was computed
public float p = 0f;
public float relativeTaskProgress = 0f;
// This is a window-space rect used for positioning the task in the stack and freeform workspace
public RectF rect = new RectF();
@@ -104,7 +105,8 @@ public class TaskViewTransform {
scale = tv.getScaleX();
alpha = tv.getAlpha();
visible = true;
p = tv.getTaskProgress();
dimAlpha = tv.getDimAlpha();
relativeTaskProgress = 0f;
rect.set(tv.getLeft(), tv.getTop(), tv.getRight(), tv.getBottom());
}
@@ -116,7 +118,8 @@ public class TaskViewTransform {
scale = other.scale;
alpha = other.alpha;
visible = other.visible;
p = other.p;
dimAlpha = other.dimAlpha;
relativeTaskProgress = other.relativeTaskProgress;
rect.set(other.rect);
}
@@ -127,9 +130,10 @@ public class TaskViewTransform {
translationZ = 0;
scale = 1f;
alpha = 1f;
dimAlpha = 0f;
relativeTaskProgress = 0f;
visible = false;
rect.setEmpty();
p = 0f;
}
/** Convenience functions to compare against current property values */