Freeform to recents app transition.
Bug: 24913782
Change-Id: I54fcbe38c51e5d75fa5ad2cb38de89d371b47bed
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 821621e..0266a37 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -25,10 +25,12 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.IRemoteCallback;
+import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.util.Pair;
import android.util.Slog;
+import android.view.AppTransitionAnimationSpec;
import android.view.View;
import android.view.Window;
@@ -129,6 +131,11 @@
public static final String KEY_ANIM_START_LISTENER = "android:activity.animStartListener";
/**
+ * Descriptions of app transition animations to be played during the activity launch.
+ */
+ private static final String KEY_ANIM_SPECS = "android:activity.animSpecs";
+
+ /**
* Where the docked stack should be positioned.
* @hide
*/
@@ -199,6 +206,7 @@
private int mExitCoordinatorIndex;
private PendingIntent mUsageTimeReport;
private int mDockCreateMode = DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+ private AppTransitionAnimationSpec mAnimSpecs[];
/**
* Create an ActivityOptions specifying a custom animation to run when
@@ -512,6 +520,18 @@
return opts;
}
+ /** @hide */
+ public static ActivityOptions makeThumbnailAspectScaleDownAnimation(View source,
+ AppTransitionAnimationSpec[] specs, Handler handler,
+ OnAnimationStartedListener listener) {
+ ActivityOptions opts = new ActivityOptions();
+ opts.mPackageName = source.getContext().getPackageName();
+ opts.mAnimationType = ANIM_THUMBNAIL_ASPECT_SCALE_DOWN;
+ opts.mAnimSpecs = specs;
+ opts.setOnAnimationStartedListener(handler, listener);
+ return opts;
+ }
+
/**
* Create an ActivityOptions to transition between Activities using cross-Activity scene
* animations. This method carries the position of one shared element to the started Activity.
@@ -698,6 +718,13 @@
break;
}
mDockCreateMode = opts.getInt(KEY_DOCK_CREATE_MODE, DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT);
+ if (opts.containsKey(KEY_ANIM_SPECS)) {
+ Parcelable[] specs = opts.getParcelableArray(KEY_ANIM_SPECS);
+ mAnimSpecs = new AppTransitionAnimationSpec[specs.length];
+ for (int i = specs.length - 1; i >= 0; i--) {
+ mAnimSpecs[i] = (AppTransitionAnimationSpec) specs[i];
+ }
+ }
}
/** @hide */
@@ -810,6 +837,9 @@
}
/** @hide */
+ public AppTransitionAnimationSpec[] getAnimSpecs() { return mAnimSpecs; }
+
+ /** @hide */
public static void abort(Bundle options) {
if (options != null) {
(new ActivityOptions(options)).abort();
@@ -898,6 +928,7 @@
mExitCoordinatorIndex = otherOptions.mExitCoordinatorIndex;
break;
}
+ mAnimSpecs = otherOptions.mAnimSpecs;
}
/**
@@ -964,6 +995,9 @@
break;
}
b.putInt(KEY_DOCK_CREATE_MODE, mDockCreateMode);
+ if (mAnimSpecs != null) {
+ b.putParcelableArray(KEY_ANIM_SPECS, mAnimSpecs);
+ }
return b;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index b05e1fe..03265d3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -16,6 +16,8 @@
package com.android.systemui.recents;
+import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
+
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.ITaskStackListener;
@@ -31,8 +33,10 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.MutableBoolean;
+import android.view.AppTransitionAnimationSpec;
import android.view.LayoutInflater;
import android.view.View;
+
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.Prefs;
import com.android.systemui.R;
@@ -558,12 +562,44 @@
*/
private ActivityOptions getThumbnailTransitionActivityOptions(
ActivityManager.RunningTaskInfo topTask, TaskStack stack, TaskStackView stackView) {
+ if (topTask.stackId == FREEFORM_WORKSPACE_STACK_ID) {
+ ArrayList<AppTransitionAnimationSpec> specs = new ArrayList<>();
+ stackView.getScroller().setStackScrollToInitialState();
+ ArrayList<Task> tasks = stack.getTasks();
+ for (int i = tasks.size() - 1; i >= 0; i--) {
+ Task task = tasks.get(i);
+ if (SystemServicesProxy.isFreeformStack(task.key.stackId)) {
+ mTmpTransform = stackView.getStackAlgorithm().getStackTransform(task,
+ stackView.getScroller().getStackScroll(), mTmpTransform, null);
+ Rect toTaskRect = new Rect();
+ mTmpTransform.rect.round(toTaskRect);
+ Bitmap thumbnail = getThumbnailBitmap(topTask, task, mTmpTransform);
+ specs.add(new AppTransitionAnimationSpec(task.key.id, thumbnail, toTaskRect));
+ }
+ }
+ AppTransitionAnimationSpec[] specsArray = new AppTransitionAnimationSpec[specs.size()];
+ specs.toArray(specsArray);
+ return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
+ specsArray, mHandler, this);
+ } else {
+ // Update the destination rect
+ Task toTask = new Task();
+ TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
+ topTask.id, toTask);
+ RectF toTaskRect = toTransform.rect;
+ Bitmap thumbnail = getThumbnailBitmap(topTask, toTask, toTransform);
+ if (thumbnail != null) {
+ return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
+ thumbnail, (int) toTaskRect.left, (int) toTaskRect.top,
+ (int) toTaskRect.width(), (int) toTaskRect.height(), mHandler, this);
+ }
+ // If both the screenshot and thumbnail fails, then just fall back to the default transition
+ return getUnknownTransitionActivityOptions();
+ }
+ }
- // Update the destination rect
- Task toTask = new Task();
- TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
- topTask.id, toTask);
- RectF toTaskRect = toTransform.rect;
+ private Bitmap getThumbnailBitmap(ActivityManager.RunningTaskInfo topTask, Task toTask,
+ TaskViewTransform toTransform) {
Bitmap thumbnail;
if (mThumbnailTransitionBitmapCacheKey != null
&& mThumbnailTransitionBitmapCacheKey.key != null
@@ -575,14 +611,7 @@
preloadIcon(topTask);
thumbnail = drawThumbnailTransitionBitmap(toTask, toTransform);
}
- if (thumbnail != null) {
- return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
- thumbnail, (int) toTaskRect.left, (int) toTaskRect.top,
- (int) toTaskRect.width(), (int) toTaskRect.height(), mHandler, this);
- }
-
- // If both the screenshot and thumbnail fails, then just fall back to the default transition
- return getUnknownTransitionActivityOptions();
+ return thumbnail;
}
/**
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 4671cb0..8061a92 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -53,6 +53,7 @@
import android.util.Log;
import android.util.Slog;
import android.util.TimeUtils;
+import android.view.AppTransitionAnimationSpec;
import android.view.IApplicationToken;
import android.view.WindowManager;
@@ -863,17 +864,24 @@
break;
case ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_UP:
case ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_DOWN:
- service.mWindowManager.overridePendingAppTransitionAspectScaledThumb(
- pendingOptions.getThumbnail(),
- pendingOptions.getStartX(), pendingOptions.getStartY(),
- pendingOptions.getWidth(), pendingOptions.getHeight(),
- pendingOptions.getOnAnimationStartListener(),
- (animationType == ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_UP));
- if (intent.getSourceBounds() == null) {
- intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
- pendingOptions.getStartY(),
- pendingOptions.getStartX() + pendingOptions.getWidth(),
- pendingOptions.getStartY() + pendingOptions.getHeight()));
+ final AppTransitionAnimationSpec[] specs = pendingOptions.getAnimSpecs();
+ if (animationType == ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_DOWN
+ && specs != null) {
+ service.mWindowManager.overridePendingAppTransitionMultiThumb(
+ specs, pendingOptions.getOnAnimationStartListener(), false);
+ } else {
+ service.mWindowManager.overridePendingAppTransitionAspectScaledThumb(
+ pendingOptions.getThumbnail(),
+ pendingOptions.getStartX(), pendingOptions.getStartY(),
+ pendingOptions.getWidth(), pendingOptions.getHeight(),
+ pendingOptions.getOnAnimationStartListener(),
+ (animationType == ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_UP));
+ if (intent.getSourceBounds() == null) {
+ intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
+ pendingOptions.getStartY(),
+ pendingOptions.getStartX() + pendingOptions.getWidth(),
+ pendingOptions.getStartY() + pendingOptions.getHeight()));
+ }
}
break;
default:
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 1cd3758..51042cb 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -4376,7 +4376,7 @@
RunningTaskInfo ci = new RunningTaskInfo();
ci.id = task.taskId;
- ci.stackId = (task.stack == null) ? INVALID_STACK_ID : task.stack.getStackId();
+ ci.stackId = mStackId;
ci.baseActivity = r.intent.getComponent();
ci.topActivity = top.intent.getComponent();
ci.lastActiveTime = task.lastActiveTime;
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index dc34904..eb0ca23 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -64,7 +64,6 @@
import android.view.animation.PathInterpolator;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
-import android.view.animation.TranslateYAnimation;
import com.android.internal.util.DumpUtils.Dump;
import com.android.server.AttributeCache;
@@ -175,7 +174,7 @@
private Rect mTmpFromClipRect = new Rect();
private Rect mTmpToClipRect = new Rect();
- private final Rect mTmpStartRect = new Rect();
+ private final Rect mTmpRect = new Rect();
private final static int APP_STATE_IDLE = 0;
private final static int APP_STATE_READY = 1;
@@ -459,16 +458,16 @@
private Animation createScaleUpAnimationLocked(int transit, boolean enter,
Rect containingFrame) {
Animation a;
- getDefaultNextAppTransitionStartRect(mTmpStartRect);
+ getDefaultNextAppTransitionStartRect(mTmpRect);
final int appWidth = containingFrame.width();
final int appHeight = containingFrame.height();
if (enter) {
// Entering app zooms out from the center of the initial rect.
- float scaleW = mTmpStartRect.width() / (float) appWidth;
- float scaleH = mTmpStartRect.height() / (float) appHeight;
+ float scaleW = mTmpRect.width() / (float) appWidth;
+ float scaleH = mTmpRect.height() / (float) appHeight;
Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
- computePivot(mTmpStartRect.left, scaleW),
- computePivot(mTmpStartRect.right, scaleH));
+ computePivot(mTmpRect.left, scaleW),
+ computePivot(mTmpRect.right, scaleH));
scale.setInterpolator(mDecelerateInterpolator);
Animation alpha = new AlphaAnimation(0, 1);
@@ -545,20 +544,20 @@
final int appWidth = appFrame.width();
final int appHeight = appFrame.height();
- // mTmpStartRect will contain an area around the launcher icon that was pressed. We will
+ // mTmpRect will contain an area around the launcher icon that was pressed. We will
// clip reveal from that area in the final area of the app.
- getDefaultNextAppTransitionStartRect(mTmpStartRect);
+ getDefaultNextAppTransitionStartRect(mTmpRect);
float t = 0f;
if (appHeight > 0) {
- t = (float) mTmpStartRect.left / appHeight;
+ t = (float) mTmpRect.left / appHeight;
}
int translationY = mClipRevealTranslationY + (int)(appHeight / 7f * t);
- int centerX = mTmpStartRect.centerX();
- int centerY = mTmpStartRect.centerY();
- int halfWidth = mTmpStartRect.width() / 2;
- int halfHeight = mTmpStartRect.height() / 2;
+ int centerX = mTmpRect.centerX();
+ int centerY = mTmpRect.centerY();
+ int halfWidth = mTmpRect.width() / 2;
+ int halfHeight = mTmpRect.height() / 2;
// Clip third of the from size of launch icon, expand to full width/height
Animation clipAnimLR = new ClipRectLRAnimation(
@@ -693,19 +692,19 @@
float scaleW = appWidth / thumbWidth;
float unscaledHeight = thumbHeight * scaleW;
- getNextAppTransitionStartRect(taskId, mTmpStartRect);
- float unscaledStartY = mTmpStartRect.top - (unscaledHeight - thumbHeight) / 2f;
+ getNextAppTransitionStartRect(taskId, mTmpRect);
+ float unscaledStartY = mTmpRect.top - (unscaledHeight - thumbHeight) / 2f;
if (mNextAppTransitionScaleUp) {
// Animation up from the thumbnail to the full screen
Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW,
- mTmpStartRect.left + (thumbWidth / 2f), mTmpStartRect.top + (thumbHeight / 2f));
+ mTmpRect.left + (thumbWidth / 2f), mTmpRect.top + (thumbHeight / 2f));
scale.setInterpolator(mTouchResponseInterpolator);
scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
Animation alpha = new AlphaAnimation(1, 0);
alpha.setInterpolator(mThumbnailFadeOutInterpolator);
alpha.setDuration(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION);
final float toX = appRect.left + appRect.width() / 2 -
- (mTmpStartRect.left + thumbWidth / 2);
+ (mTmpRect.left + thumbWidth / 2);
final float toY = appRect.top + mNextAppTransitionInsets.top + -unscaledStartY;
Animation translate = new TranslateAnimation(0, toX, 0, toY);
translate.setInterpolator(mTouchResponseInterpolator);
@@ -720,7 +719,7 @@
} else {
// Animation down from the full screen to the thumbnail
Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f,
- mTmpStartRect.left + (thumbWidth / 2f), mTmpStartRect.top + (thumbHeight / 2f));
+ mTmpRect.left + (thumbWidth / 2f), mTmpRect.top + (thumbHeight / 2f));
scale.setInterpolator(mTouchResponseInterpolator);
scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
Animation alpha = new AlphaAnimation(0f, 1f);
@@ -753,10 +752,10 @@
Animation a;
final int appWidth = containingFrame.width();
final int appHeight = containingFrame.height();
- getDefaultNextAppTransitionStartRect(mTmpStartRect);
- final int thumbWidthI = mTmpStartRect.width();
+ getDefaultNextAppTransitionStartRect(mTmpRect);
+ final int thumbWidthI = mTmpRect.width();
final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
- final int thumbHeightI = mTmpStartRect.height();
+ final int thumbHeightI = mTmpRect.height();
final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
// Used for the ENTER_SCALE_UP and EXIT_SCALE_DOWN transitions
@@ -766,7 +765,7 @@
switch (thumbTransitState) {
case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: {
if (freeform) {
- a = createAspectScaledThumbnailEnterNonFullscreenAnimationLocked(
+ a = createAspectScaledThumbnailEnterFreeformAnimationLocked(
containingFrame, surfaceInsets, taskId);
} else {
mTmpFromClipRect.set(containingFrame);
@@ -797,8 +796,8 @@
mNextAppTransitionInsets.set(contentInsets);
Animation scaleAnim = new ScaleAnimation(scale, 1, scale, 1,
- computePivot(mTmpStartRect.left, scale),
- computePivot(mTmpStartRect.top, scale));
+ computePivot(mTmpRect.left, scale),
+ computePivot(mTmpRect.top, scale));
Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
Animation translateAnim = new TranslateAnimation(0, 0, -scaledTopDecor, 0);
@@ -834,44 +833,49 @@
}
case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
// App window scaling down from full screen
- mTmpFromClipRect.set(containingFrame);
- mTmpToClipRect.set(containingFrame);
- // exclude top screen decor (status bar) region from the destination clip.
- mTmpToClipRect.top = contentInsets.top;
- if (orientation == Configuration.ORIENTATION_PORTRAIT) {
- // In portrait, we scale the width and clip to the top/left square
- scale = thumbWidth / appWidth;
- scaledTopDecor = (int) (scale * contentInsets.top);
- int unscaledThumbHeight = (int) (thumbHeight / scale);
- mTmpToClipRect.bottom = mTmpToClipRect.top + unscaledThumbHeight;
+ if (freeform) {
+ a = createAspectScaledThumbnailExitFreeformAnimationLocked(
+ containingFrame, surfaceInsets, taskId);
} else {
- // In landscape, we scale the height and clip to the top/left square. We only
- // scale the part that is not covered by status bar and the nav bar.
- scale = thumbHeight / (appHeight - contentInsets.top - contentInsets.bottom);
- scaledTopDecor = (int) (scale * contentInsets.top);
- int unscaledThumbWidth = (int) (thumbWidth / scale);
- mTmpToClipRect.right = mTmpToClipRect.left + unscaledThumbWidth;
- // This removes the navigation bar from the last frame, so it better matches the
- // thumbnail. We need to do this explicitly in landscape, because in portrait we
- // already crop vertically.
- mTmpToClipRect.bottom = mTmpToClipRect.bottom - contentInsets.bottom;
+ mTmpFromClipRect.set(containingFrame);
+ mTmpToClipRect.set(containingFrame);
+ // exclude top screen decor (status bar) region from the destination clip.
+ mTmpToClipRect.top = contentInsets.top;
+ if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+ // In portrait, we scale the width and clip to the top/left square
+ scale = thumbWidth / appWidth;
+ scaledTopDecor = (int) (scale * contentInsets.top);
+ int unscaledThumbHeight = (int) (thumbHeight / scale);
+ mTmpToClipRect.bottom = mTmpToClipRect.top + unscaledThumbHeight;
+ } else {
+ // In landscape, we scale the height and clip to the top/left square. We only
+ // scale the part that is not covered by status bar and the nav bar.
+ scale = thumbHeight / (appHeight - contentInsets.top - contentInsets.bottom);
+ scaledTopDecor = (int) (scale * contentInsets.top);
+ int unscaledThumbWidth = (int) (thumbWidth / scale);
+ mTmpToClipRect.right = mTmpToClipRect.left + unscaledThumbWidth;
+ // This removes the navigation bar from the last frame, so it better matches the
+ // thumbnail. We need to do this explicitly in landscape, because in portrait we
+ // already crop vertically.
+ mTmpToClipRect.bottom = mTmpToClipRect.bottom - contentInsets.bottom;
+ }
+
+ mNextAppTransitionInsets.set(contentInsets);
+
+ Animation scaleAnim = new ScaleAnimation(1, scale, 1, scale,
+ computePivot(mTmpRect.left, scale),
+ computePivot(mTmpRect.top, scale));
+ Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
+ Animation translateAnim = new TranslateAnimation(0, 0, 0, -scaledTopDecor);
+
+ AnimationSet set = new AnimationSet(true);
+ set.addAnimation(clipAnim);
+ set.addAnimation(scaleAnim);
+ set.addAnimation(translateAnim);
+
+ a = set;
+ a.setZAdjustment(Animation.ZORDER_TOP);
}
-
- mNextAppTransitionInsets.set(contentInsets);
-
- Animation scaleAnim = new ScaleAnimation(1, scale, 1, scale,
- computePivot(mTmpStartRect.left, scale),
- computePivot(mTmpStartRect.top, scale));
- Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
- Animation translateAnim = new TranslateAnimation(0, 0, 0, -scaledTopDecor);
-
- AnimationSet set = new AnimationSet(true);
- set.addAnimation(clipAnim);
- set.addAnimation(scaleAnim);
- set.addAnimation(translateAnim);
-
- a = set;
- a.setZAdjustment(Animation.ZORDER_TOP);
break;
}
default:
@@ -884,27 +888,48 @@
mTouchResponseInterpolator);
}
- private Animation createAspectScaledThumbnailEnterNonFullscreenAnimationLocked(
- Rect frame, @Nullable Rect surfaceInsets, int taskId) {
- getNextAppTransitionStartRect(taskId, mTmpStartRect);
- float width = frame.width();
- float height = frame.height();
- float scaleWidth = mTmpStartRect.width() / width;
- float scaleHeight = mTmpStartRect.height() / height;
+ private Animation createAspectScaledThumbnailEnterFreeformAnimationLocked(Rect frame,
+ @Nullable Rect surfaceInsets, int taskId) {
+ getNextAppTransitionStartRect(taskId, mTmpRect);
+ return createAspectScaledThumbnailFreeformAnimationLocked(mTmpRect, frame, surfaceInsets,
+ true);
+ }
+
+ private Animation createAspectScaledThumbnailExitFreeformAnimationLocked(Rect frame,
+ @Nullable Rect surfaceInsets, int taskId) {
+ getNextAppTransitionStartRect(taskId, mTmpRect);
+ return createAspectScaledThumbnailFreeformAnimationLocked(frame, mTmpRect, surfaceInsets,
+ false);
+ }
+
+ private AnimationSet createAspectScaledThumbnailFreeformAnimationLocked(Rect sourceFrame,
+ Rect destFrame, @Nullable Rect surfaceInsets, boolean enter) {
+ final float sourceWidth = sourceFrame.width();
+ final float sourceHeight = sourceFrame.height();
+ final float destWidth = destFrame.width();
+ final float destHeight = destFrame.height();
+ final float scaleH = enter ? sourceWidth / destWidth : destWidth / sourceWidth;
+ final float scaleV = enter ? sourceHeight / destHeight : destHeight / sourceHeight;
AnimationSet set = new AnimationSet(true);
- int surfaceInsetsHorizontal = surfaceInsets == null
+ final int surfaceInsetsH = surfaceInsets == null
? 0 : surfaceInsets.left + surfaceInsets.right;
- int surfaceInsetsVertical = surfaceInsets == null
+ final int surfaceInsetsV = surfaceInsets == null
? 0 : surfaceInsets.top + surfaceInsets.bottom;
// We want the scaling to happen from the center of the surface. In order to achieve that,
// we need to account for surface insets that will be used to enlarge the surface.
- ScaleAnimation scale = new ScaleAnimation(scaleWidth, 1, scaleHeight, 1,
- (width + surfaceInsetsHorizontal) / 2, (height + surfaceInsetsVertical) / 2);
- int fromX = mTmpStartRect.left + mTmpStartRect.width() / 2
- - (frame.left + frame.width() / 2);
- int fromY = mTmpStartRect.top + mTmpStartRect.height() / 2
- - (frame.top + frame.height() / 2);
- TranslateAnimation translation = new TranslateAnimation(fromX, 0, fromY, 0);
+ final float scaleHCenter = ((enter ? destWidth : sourceWidth) + surfaceInsetsH) / 2;
+ final float scaleVCenter = ((enter ? destHeight : sourceHeight) + surfaceInsetsV) / 2;
+ final ScaleAnimation scale = enter ?
+ new ScaleAnimation(scaleH, 1, scaleV, 1, scaleHCenter, scaleVCenter)
+ : new ScaleAnimation(1, scaleH, 1, scaleV, scaleHCenter, scaleVCenter);
+ final int sourceHCenter = sourceFrame.left + sourceFrame.width() / 2;
+ final int sourceVCenter = sourceFrame.top + sourceFrame.height() / 2;
+ final int destHCenter = destFrame.left + destFrame.width() / 2;
+ final int destVCenter = destFrame.top + destFrame.height() / 2;
+ final int fromX = enter ? sourceHCenter - destHCenter : destHCenter - sourceHCenter;
+ final int fromY = enter ? sourceVCenter - destVCenter : destVCenter - sourceVCenter;
+ final TranslateAnimation translation = enter ? new TranslateAnimation(fromX, 0, fromY, 0)
+ : new TranslateAnimation(0, fromX, 0, fromY);
set.addAnimation(scale);
set.addAnimation(translation);
return set;
@@ -917,7 +942,7 @@
Animation createThumbnailScaleAnimationLocked(int appWidth, int appHeight, int transit,
Bitmap thumbnailHeader) {
Animation a;
- getDefaultNextAppTransitionStartRect(mTmpStartRect);
+ getDefaultNextAppTransitionStartRect(mTmpRect);
final int thumbWidthI = thumbnailHeader.getWidth();
final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
final int thumbHeightI = thumbnailHeader.getHeight();
@@ -928,8 +953,8 @@
float scaleW = appWidth / thumbWidth;
float scaleH = appHeight / thumbHeight;
Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
- computePivot(mTmpStartRect.left, 1 / scaleW),
- computePivot(mTmpStartRect.top, 1 / scaleH));
+ computePivot(mTmpRect.left, 1 / scaleW),
+ computePivot(mTmpRect.top, 1 / scaleH));
scale.setInterpolator(mDecelerateInterpolator);
Animation alpha = new AlphaAnimation(1, 0);
@@ -945,8 +970,8 @@
float scaleW = appWidth / thumbWidth;
float scaleH = appHeight / thumbHeight;
a = new ScaleAnimation(scaleW, 1, scaleH, 1,
- computePivot(mTmpStartRect.left, 1 / scaleW),
- computePivot(mTmpStartRect.top, 1 / scaleH));
+ computePivot(mTmpRect.left, 1 / scaleW),
+ computePivot(mTmpRect.top, 1 / scaleH));
}
return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
@@ -962,7 +987,7 @@
final int appHeight = containingFrame.height();
Bitmap thumbnailHeader = getAppTransitionThumbnailHeader(taskId);
Animation a;
- getDefaultNextAppTransitionStartRect(mTmpStartRect);
+ getDefaultNextAppTransitionStartRect(mTmpRect);
final int thumbWidthI = thumbnailHeader != null ? thumbnailHeader.getWidth() : appWidth;
final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
final int thumbHeightI = thumbnailHeader != null ? thumbnailHeader.getHeight() : appHeight;
@@ -974,8 +999,8 @@
float scaleW = thumbWidth / appWidth;
float scaleH = thumbHeight / appHeight;
a = new ScaleAnimation(scaleW, 1, scaleH, 1,
- computePivot(mTmpStartRect.left, scaleW),
- computePivot(mTmpStartRect.top, scaleH));
+ computePivot(mTmpRect.left, scaleW),
+ computePivot(mTmpRect.top, scaleH));
break;
}
case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: {
@@ -1002,8 +1027,8 @@
float scaleW = thumbWidth / appWidth;
float scaleH = thumbHeight / appHeight;
Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
- computePivot(mTmpStartRect.left, scaleW),
- computePivot(mTmpStartRect.top, scaleH));
+ computePivot(mTmpRect.left, scaleW),
+ computePivot(mTmpRect.top, scaleH));
Animation alpha = new AlphaAnimation(1, 0);
@@ -1492,15 +1517,15 @@
pw.print(Integer.toHexString(mNextAppTransitionInPlace));
break;
case NEXT_TRANSIT_TYPE_SCALE_UP: {
- getDefaultNextAppTransitionStartRect(mTmpStartRect);
+ getDefaultNextAppTransitionStartRect(mTmpRect);
pw.print(prefix); pw.print("mNextAppTransitionStartX=");
- pw.print(mTmpStartRect.left);
+ pw.print(mTmpRect.left);
pw.print(" mNextAppTransitionStartY=");
- pw.println(mTmpStartRect.top);
+ pw.println(mTmpRect.top);
pw.print(prefix); pw.print("mNextAppTransitionStartWidth=");
- pw.print(mTmpStartRect.width());
+ pw.print(mTmpRect.width());
pw.print(" mNextAppTransitionStartHeight=");
- pw.println(mTmpStartRect.height());
+ pw.println(mTmpRect.height());
break;
}
case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP: