Add ClipReveal window transition for application launch
Issue #19362772 Better material launch animations
Change-Id: Ic94fde910b6b5554ee954dfbbf374949f9eb189d
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index c0d54e1..a569322 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -17,12 +17,16 @@
package com.android.server.wm;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.os.Debug;
import android.os.Handler;
import android.os.IRemoteCallback;
+import android.os.UserHandle;
+import android.util.Log;
import android.util.Slog;
import android.view.WindowManager;
import android.view.animation.AlphaAnimation;
@@ -30,9 +34,14 @@
import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
import android.view.animation.ClipRectAnimation;
+import android.view.animation.ClipRectLRAnimation;
+import android.view.animation.ClipRectTBAnimation;
import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
+import android.view.animation.TranslateXAnimation;
+import android.view.animation.TranslateYAnimation;
import com.android.internal.util.DumpUtils.Dump;
import com.android.server.AttributeCache;
import com.android.server.wm.WindowManagerService.H;
@@ -134,6 +143,7 @@
private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP = 5;
private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN = 6;
private static final int NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE = 7;
+ private static final int NEXT_TRANSIT_TYPE_CLIP_REVEAL = 8;
private int mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
// These are the possible states for the enter/exit activities during a thumbnail transition
@@ -169,19 +179,24 @@
private final Interpolator mDecelerateInterpolator;
private final Interpolator mThumbnailFadeInInterpolator;
private final Interpolator mThumbnailFadeOutInterpolator;
- private final Interpolator mThumbnailFastOutSlowInInterpolator;
+ private final Interpolator mLinearOutSlowInInterpolator;
+ private final Interpolator mFastOutSlowInInterpolator;
+ private final LinearInterpolator mLinearInterpolator;
private int mCurrentUserId = 0;
AppTransition(Context context, Handler h) {
mContext = context;
mH = h;
+ mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+ com.android.internal.R.interpolator.linear_out_slow_in);
+ mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+ com.android.internal.R.interpolator.fast_out_slow_in);
+ mLinearInterpolator = new LinearInterpolator();
mConfigShortAnimTime = context.getResources().getInteger(
com.android.internal.R.integer.config_shortAnimTime);
mDecelerateInterpolator = AnimationUtils.loadInterpolator(context,
com.android.internal.R.interpolator.decelerate_cubic);
- mThumbnailFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_slow_in);
mThumbnailFadeInInterpolator = new Interpolator() {
@Override
public float getInterpolation(float input) {
@@ -447,6 +462,83 @@
return a;
}
+ private Animation createClipRevealAnimationLocked(int transit, boolean enter,
+ int appWidth, int appHeight) {
+ final Animation anim;
+ if (enter) {
+ // Reveal will expand and move faster in horizontal direction
+
+ // Start from size of launch icon, expand to full width/height
+ Animation clipAnimLR = new ClipRectLRAnimation(
+ (appWidth - mNextAppTransitionStartWidth) / 2,
+ (appWidth + mNextAppTransitionStartWidth) / 2, 0, appWidth);
+ clipAnimLR.setInterpolator(mLinearOutSlowInInterpolator);
+ clipAnimLR.setDuration(DEFAULT_APP_TRANSITION_DURATION);
+ Animation clipAnimTB = new ClipRectTBAnimation(
+ (appHeight - mNextAppTransitionStartHeight) / 2,
+ (appHeight + mNextAppTransitionStartHeight) / 2, 0, appHeight);
+ clipAnimTB.setInterpolator(mFastOutSlowInInterpolator);
+ clipAnimTB.setDuration(DEFAULT_APP_TRANSITION_DURATION);
+
+ // Start from middle of launch icon area, move to 0, 0
+ int startMiddleX = mNextAppTransitionStartX +
+ (mNextAppTransitionStartWidth - appWidth) / 2;
+ int startMiddleY = mNextAppTransitionStartY +
+ (mNextAppTransitionStartHeight - appHeight) / 2;
+
+ TranslateXAnimation translateX = new TranslateXAnimation(
+ Animation.ABSOLUTE, startMiddleX, Animation.ABSOLUTE, 0);
+ translateX.setInterpolator(mLinearOutSlowInInterpolator);
+ translateX.setDuration(DEFAULT_APP_TRANSITION_DURATION);
+ TranslateYAnimation translateY = new TranslateYAnimation(
+ Animation.ABSOLUTE, startMiddleY, Animation.ABSOLUTE, 0);
+ translateY.setInterpolator(mFastOutSlowInInterpolator);
+ translateY.setDuration(DEFAULT_APP_TRANSITION_DURATION);
+
+ // Quick fade-in from icon to app window
+ final int alphaDuration = 100;
+ AlphaAnimation alpha = new AlphaAnimation(0.1f, 1);
+ alpha.setDuration(alphaDuration);
+ alpha.setInterpolator(mLinearInterpolator);
+
+ AnimationSet set = new AnimationSet(false);
+ set.addAnimation(clipAnimLR);
+ set.addAnimation(clipAnimTB);
+ set.addAnimation(translateX);
+ set.addAnimation(translateY);
+ set.addAnimation(alpha);
+ set.initialize(appWidth, appHeight, appWidth, appHeight);
+ anim = set;
+ } else {
+ final long duration;
+ switch (transit) {
+ case TRANSIT_ACTIVITY_OPEN:
+ case TRANSIT_ACTIVITY_CLOSE:
+ duration = mConfigShortAnimTime;
+ break;
+ default:
+ duration = DEFAULT_APP_TRANSITION_DURATION;
+ break;
+ }
+ if (transit == TRANSIT_WALLPAPER_INTRA_OPEN ||
+ transit == TRANSIT_WALLPAPER_INTRA_CLOSE) {
+ // If we are on top of the wallpaper, we need an animation that
+ // correctly handles the wallpaper staying static behind all of
+ // the animated elements. To do this, will just have the existing
+ // element fade out.
+ anim = new AlphaAnimation(1, 0);
+ anim.setDetachWallpaper(true);
+ } else {
+ // For normal animations, the exiting element just holds in place.
+ anim = new AlphaAnimation(1, 1);
+ }
+ anim.setInterpolator(mDecelerateInterpolator);
+ anim.setDuration(duration);
+ anim.setFillAfter(true);
+ }
+ return anim;
+ }
+
/**
* Prepares the specified animation with a standard duration, interpolator, etc.
*/
@@ -522,14 +614,14 @@
Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW,
mNextAppTransitionStartX + (thumbWidth / 2f),
mNextAppTransitionStartY + (thumbHeight / 2f));
- scale.setInterpolator(mThumbnailFastOutSlowInInterpolator);
+ scale.setInterpolator(mFastOutSlowInInterpolator);
scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
Animation alpha = new AlphaAnimation(1, 0);
alpha.setInterpolator(mThumbnailFadeOutInterpolator);
alpha.setDuration(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION);
Animation translate = new TranslateAnimation(0, 0, 0, -unscaledStartY +
mNextAppTransitionInsets.top);
- translate.setInterpolator(mThumbnailFastOutSlowInInterpolator);
+ translate.setInterpolator(mFastOutSlowInInterpolator);
translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
// This AnimationSet uses the Interpolators assigned above.
@@ -543,14 +635,14 @@
Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f,
mNextAppTransitionStartX + (thumbWidth / 2f),
mNextAppTransitionStartY + (thumbHeight / 2f));
- scale.setInterpolator(mThumbnailFastOutSlowInInterpolator);
+ scale.setInterpolator(mFastOutSlowInInterpolator);
scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
Animation alpha = new AlphaAnimation(0f, 1f);
alpha.setInterpolator(mThumbnailFadeInInterpolator);
alpha.setDuration(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION);
Animation translate = new TranslateAnimation(0, 0, -unscaledStartY +
mNextAppTransitionInsets.top, 0);
- translate.setInterpolator(mThumbnailFastOutSlowInInterpolator);
+ translate.setInterpolator(mFastOutSlowInInterpolator);
translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
// This AnimationSet uses the Interpolators assigned above.
@@ -562,7 +654,7 @@
}
return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, 0,
- mThumbnailFastOutSlowInInterpolator);
+ mFastOutSlowInInterpolator);
}
/**
@@ -698,7 +790,7 @@
int duration = Math.max(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION,
THUMBNAIL_APP_TRANSITION_DURATION);
return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration,
- mThumbnailFastOutSlowInInterpolator);
+ mFastOutSlowInInterpolator);
}
/**
@@ -845,6 +937,12 @@
"applyAnimation:"
+ " anim=" + a + " nextAppTransition=ANIM_CUSTOM_IN_PLACE"
+ " transit=" + transit + " Callers=" + Debug.getCallers(3));
+ } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL) {
+ a = createClipRevealAnimationLocked(transit, enter, appWidth, appHeight);
+ if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
+ "applyAnimation:"
+ + " anim=" + a + " nextAppTransition=ANIM_CLIP_REVEAL"
+ + " Callers=" + Debug.getCallers(3));
} else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) {
a = createScaleUpAnimationLocked(transit, enter, appWidth, appHeight);
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
@@ -987,6 +1085,19 @@
}
}
+ void overridePendingAppTransitionClipReveal(int startX, int startY,
+ int startWidth, int startHeight) {
+ if (isTransitionSet()) {
+ mNextAppTransitionType = NEXT_TRANSIT_TYPE_CLIP_REVEAL;
+ mNextAppTransitionStartX = startX;
+ mNextAppTransitionStartY = startY;
+ mNextAppTransitionStartWidth = startWidth;
+ mNextAppTransitionStartHeight = startHeight;
+ postAnimationCallback();
+ mNextAppTransitionCallback = null;
+ }
+ }
+
void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX, int startY,
IRemoteCallback startedCallback, boolean scaleUp) {
if (isTransitionSet()) {