Implement transition for docking task in recents #5

- Move task along a curved path.

Bug: 27607141
Change-Id: I945071de55efed0d327b68045e48fea6989adf63
This commit is contained in:
Jorim Jaggi
2016-03-15 10:52:40 +01:00
parent 8448f339f9
commit 787e9dd6c8
4 changed files with 111 additions and 26 deletions

View File

@@ -29,8 +29,9 @@ import android.util.Log;
* This class holds a collection of Keyframe objects and is called by ValueAnimator to calculate
* values between those keyframes for a given animation. The class internal to the animation
* package because it is an implementation detail of how Keyframes are stored and used.
* @hide
*/
class KeyframeSet implements Keyframes {
public class KeyframeSet implements Keyframes {
int mNumKeyframes;

View File

@@ -34,8 +34,9 @@ import java.util.ArrayList;
* Typically, the returned type is a PointF, but the individual components can be extracted
* as either an IntKeyframes or FloatKeyframes.
* </p>
* @hide
*/
class PathKeyframes implements Keyframes {
public class PathKeyframes implements Keyframes {
private static final int FRACTION_OFFSET = 0;
private static final int X_OFFSET = 1;
private static final int Y_OFFSET = 2;

View File

@@ -50,6 +50,7 @@ import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Path;
import android.graphics.Rect;
import android.os.Debug;
import android.os.IBinder;
@@ -71,11 +72,13 @@ import android.view.animation.PathInterpolator;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import com.android.internal.R;
import com.android.internal.util.DumpUtils.Dump;
import com.android.server.AttributeCache;
import com.android.server.wm.WindowManagerService.H;
import com.android.server.wm.animation.ClipRectLRAnimation;
import com.android.server.wm.animation.ClipRectTBAnimation;
import com.android.server.wm.animation.CurvedTranslateAnimation;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -150,7 +153,6 @@ public class AppTransition implements Dump {
*/
private static final int MAX_CLIP_REVEAL_TRANSITION_DURATION = 420;
private static final int THUMBNAIL_APP_TRANSITION_DURATION = 336;
private static final int THUMBNAIL_APP_TRANSITION_ALPHA_DURATION = 336;
private static final long APP_TRANSITION_TIMEOUT_MS = 5000;
private final Context mContext;
@@ -211,6 +213,7 @@ public class AppTransition implements Dump {
private final Interpolator mThumbnailFadeOutInterpolator;
private final Interpolator mLinearOutSlowInInterpolator;
private final Interpolator mFastOutLinearInInterpolator;
private final Interpolator mFastOutSlowInInterpolator;
private final Interpolator mClipHorizontalInterpolator = new PathInterpolator(0, 0, 0.4f, 1f);
private final int mClipRevealTranslationY;
@@ -231,6 +234,8 @@ public class AppTransition implements Dump {
com.android.internal.R.interpolator.linear_out_slow_in);
mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
com.android.internal.R.interpolator.fast_out_linear_in);
mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
com.android.internal.R.interpolator.fast_out_slow_in);
mConfigShortAnimTime = context.getResources().getInteger(
com.android.internal.R.integer.config_shortAnimTime);
mDecelerateInterpolator = AnimationUtils.loadInterpolator(context,
@@ -817,7 +822,7 @@ public class AppTransition implements Dump {
* Prepares the specified animation with a standard duration, interpolator, etc.
*/
Animation prepareThumbnailAnimationWithDuration(Animation a, int appWidth, int appHeight,
int duration, Interpolator interpolator) {
long duration, Interpolator interpolator) {
if (duration > 0) {
a.setDuration(duration);
}
@@ -887,17 +892,19 @@ public class AppTransition implements Dump {
final float fromX = mTmpRect.left;
final float pivotX = mTmpRect.width() / 2;
final float pivotY = mTmpRect.height() / 2;
final long duration = getAspectScaleDuration();
final Interpolator interpolator = getAspectScaleInterpolator();
if (mNextAppTransitionScaleUp) {
// Animation up from the thumbnail to the full screen
Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW, pivotX, pivotY);
scale.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
scale.setInterpolator(interpolator);
scale.setDuration(duration);
Animation alpha = new AlphaAnimation(1f, 0f);
alpha.setInterpolator(mThumbnailFadeOutInterpolator);
alpha.setDuration(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION);
Animation translate = new TranslateAnimation(fromX, toX, fromY, toY);
translate.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
alpha.setDuration(duration);
Animation translate = createCurvedMotion(fromX, toX, fromY, toY);
translate.setInterpolator(interpolator);
translate.setDuration(duration);
mTmpFromClipRect.set(0, 0, thumbWidthI, thumbHeightI);
mTmpToClipRect.set(appRect);
@@ -916,8 +923,8 @@ public class AppTransition implements Dump {
}
Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
clipAnim.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
clipAnim.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
clipAnim.setInterpolator(interpolator);
clipAnim.setDuration(duration);
// This AnimationSet uses the Interpolators assigned above.
AnimationSet set = new AnimationSet(false);
@@ -929,14 +936,14 @@ public class AppTransition implements Dump {
} else {
// Animation down from the full screen to the thumbnail
Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f, pivotX, pivotY);
scale.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
scale.setInterpolator(interpolator);
scale.setDuration(duration);
Animation alpha = new AlphaAnimation(0f, 1f);
alpha.setInterpolator(mThumbnailFadeInInterpolator);
alpha.setDuration(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION);
Animation translate = new TranslateAnimation(toX, fromX, toY, fromY);
translate.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
alpha.setDuration(duration);
Animation translate = createCurvedMotion(toX, fromX, toY, fromY);
translate.setInterpolator(interpolator);
translate.setDuration(duration);
// This AnimationSet uses the Interpolators assigned above.
AnimationSet set = new AnimationSet(false);
@@ -950,6 +957,40 @@ public class AppTransition implements Dump {
TOUCH_RESPONSE_INTERPOLATOR);
}
private Animation createCurvedMotion(float fromX, float toX, float fromY, float toY) {
// Almost no x-change - use linear animation
if (Math.abs(toX - fromX) < 1f) {
return new TranslateAnimation(fromX, toX, fromY, toY);
} else {
final Path path = createCurvedPath(fromX, toX, fromY, toY);
return new CurvedTranslateAnimation(path);
}
}
private Path createCurvedPath(float fromX, float toX, float fromY, float toY) {
final Path path = new Path();
path.moveTo(fromX, fromY);
path.cubicTo(fromX, fromY, toX, 0.9f * fromY + 0.1f * toY, toX, toY);
return path;
}
private long getAspectScaleDuration() {
if (mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS) {
return (long) (THUMBNAIL_APP_TRANSITION_DURATION * 1f);
} else {
return THUMBNAIL_APP_TRANSITION_DURATION;
}
}
private Interpolator getAspectScaleInterpolator() {
if (mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS) {
return mFastOutSlowInInterpolator;
} else {
return TOUCH_RESPONSE_INTERPOLATOR;
}
}
/**
* This alternate animation is created when we are doing a thumbnail transition, for the
* activity that is leaving, and the activity that is entering.
@@ -1017,8 +1058,8 @@ public class AppTransition implements Dump {
? new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect)
: new ClipRectAnimation(mTmpToClipRect, mTmpFromClipRect);
Animation translateAnim = scaleUp
? new TranslateAnimation(startX, 0, startY - scaledTopDecor, 0)
: new TranslateAnimation(0, startX, 0, startY - scaledTopDecor);
? createCurvedMotion(startX, 0, startY - scaledTopDecor, 0)
: createCurvedMotion(0, startX, 0, startY - scaledTopDecor);
set.addAnimation(clipAnim);
set.addAnimation(scaleAnim);
set.addAnimation(translateAnim);
@@ -1032,8 +1073,10 @@ public class AppTransition implements Dump {
? new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect)
: new ClipRectAnimation(mTmpToClipRect, mTmpFromClipRect);
Animation translateAnim = scaleUp
? new TranslateAnimation(thumbStartX, 0, thumbStartY - contentInsets.top, 0)
: new TranslateAnimation(0, thumbStartX, 0, thumbStartY - contentInsets.top);
? createCurvedMotion(thumbStartX, 0,
thumbStartY - contentInsets.top, 0)
: createCurvedMotion(0, thumbStartX, 0,
thumbStartY - contentInsets.top);
set.addAnimation(clipAnim);
set.addAnimation(translateAnim);
@@ -1070,10 +1113,8 @@ public class AppTransition implements Dump {
throw new RuntimeException("Invalid thumbnail transition state");
}
int duration = Math.max(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION,
THUMBNAIL_APP_TRANSITION_DURATION);
return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration,
TOUCH_RESPONSE_INTERPOLATOR);
return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight,
getAspectScaleDuration(), getAspectScaleInterpolator());
}
private Animation createAspectScaledThumbnailEnterFreeformAnimationLocked(Rect frame,

View File

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.server.wm.animation;
import android.animation.KeyframeSet;
import android.animation.PathKeyframes;
import android.graphics.Path;
import android.graphics.PointF;
import android.view.animation.Animation;
import android.view.animation.Transformation;
/**
* Translate animation which follows a curved path.
*/
public class CurvedTranslateAnimation extends Animation {
private final PathKeyframes mKeyframes;
public CurvedTranslateAnimation(Path path) {
mKeyframes = KeyframeSet.ofPath(path);
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
PointF location = (PointF) mKeyframes.getValue(interpolatedTime);
t.getMatrix().setTranslate(location.x, location.y);
}
}