diff options
6 files changed, 179 insertions, 150 deletions
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index 3eec596fcb17..53608fbdd4bb 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -38,6 +38,7 @@ import android.transition.TransitionManager; import android.util.Pair; import android.util.Slog; import android.view.AppTransitionAnimationSpec; +import android.view.IAppTransitionAnimationSpecsFuture; import android.view.View; import android.view.ViewGroup; import android.view.Window; @@ -213,6 +214,7 @@ public class ActivityOptions { private static final String KEY_INSTANT_APP_VERIFICATION_BUNDLE = "android:instantapps.installerbundle"; + private static final String KEY_SPECS_FUTURE = "android:activity.specsFuture"; /** @hide */ public static final int ANIM_NONE = 0; @@ -268,6 +270,7 @@ public class ActivityOptions { private AppTransitionAnimationSpec mAnimSpecs[]; private int mRotationAnimationHint = -1; private Bundle mAppVerificationBundle; + private IAppTransitionAnimationSpecsFuture mSpecsFuture; /** * Create an ActivityOptions specifying a custom animation to run when @@ -492,35 +495,12 @@ public class ActivityOptions { * is not executed, the callback will happen immediately. * @return Returns a new ActivityOptions object that you can use to * supply these options as the options Bundle when starting an activity. - * @hide */ - public static ActivityOptions makeThumbnailScaleUpAnimation(View source, + private static ActivityOptions makeThumbnailScaleUpAnimation(View source, Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) { return makeThumbnailAnimation(source, thumbnail, startX, startY, listener, true); } - /** - * Create an ActivityOptions specifying an animation where an activity window - * is scaled from a given position to a thumbnail at a specified location. - * - * @param source The View that this thumbnail is animating to. This - * defines the coordinate space for <var>startX</var> and <var>startY</var>. - * @param thumbnail The bitmap that will be shown as the final thumbnail - * of the animation. - * @param startX The x end location of the bitmap, relative to <var>source</var>. - * @param startY The y end location of the bitmap, relative to <var>source</var>. - * @param listener Optional OnAnimationStartedListener to find out when the - * requested animation has started running. If for some reason the animation - * is not executed, the callback will happen immediately. - * @return Returns a new ActivityOptions object that you can use to - * supply these options as the options Bundle when starting an activity. - * @hide - */ - public static ActivityOptions makeThumbnailScaleDownAnimation(View source, - Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) { - return makeThumbnailAnimation(source, thumbnail, startX, startY, listener, false); - } - private static ActivityOptions makeThumbnailAnimation(View source, Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener, boolean scaleUp) { @@ -537,29 +517,21 @@ public class ActivityOptions { } /** - * Create an ActivityOptions specifying an animation where the new activity - * window and a thumbnail is aspect-scaled to a new location. - * - * @param source The View that this thumbnail is animating from. This - * defines the coordinate space for <var>startX</var> and <var>startY</var>. - * @param thumbnail The bitmap that will be shown as the initial thumbnail - * of the animation. - * @param startX The x starting location of the bitmap, relative to <var>source</var>. - * @param startY The y starting location of the bitmap, relative to <var>source</var>. - * @param handler If <var>listener</var> is non-null this must be a valid - * Handler on which to dispatch the callback; otherwise it should be null. - * @param listener Optional OnAnimationStartedListener to find out when the - * requested animation has started running. If for some reason the animation - * is not executed, the callback will happen immediately. - * @return Returns a new ActivityOptions object that you can use to - * supply these options as the options Bundle when starting an activity. + * Create an ActivityOptions specifying an animation where a list of activity windows and + * thumbnails are aspect scaled to/from a new location. * @hide */ - public static ActivityOptions makeThumbnailAspectScaleUpAnimation(View source, - Bitmap thumbnail, int startX, int startY, int targetWidth, int targetHeight, - Handler handler, OnAnimationStartedListener listener) { - return makeAspectScaledThumbnailAnimation(source, thumbnail, startX, startY, - targetWidth, targetHeight, handler, listener, true); + public static ActivityOptions makeMultiThumbFutureAspectScaleAnimation(Context context, + Handler handler, IAppTransitionAnimationSpecsFuture specsFuture, + OnAnimationStartedListener listener, boolean scaleUp) { + ActivityOptions opts = new ActivityOptions(); + opts.mPackageName = context.getPackageName(); + opts.mAnimationType = scaleUp + ? ANIM_THUMBNAIL_ASPECT_SCALE_UP + : ANIM_THUMBNAIL_ASPECT_SCALE_DOWN; + opts.mSpecsFuture = specsFuture; + opts.setOnAnimationStartedListener(handler, listener); + return opts; } /** @@ -891,6 +863,10 @@ public class ActivityOptions { } mRotationAnimationHint = opts.getInt(KEY_ROTATION_ANIMATION_HINT); mAppVerificationBundle = opts.getBundle(KEY_INSTANT_APP_VERIFICATION_BUNDLE); + if (opts.containsKey(KEY_SPECS_FUTURE)) { + mSpecsFuture = IAppTransitionAnimationSpecsFuture.Stub.asInterface(opts.getBinder( + KEY_SPECS_FUTURE)); + } } /** @@ -1029,6 +1005,11 @@ public class ActivityOptions { public AppTransitionAnimationSpec[] getAnimSpecs() { return mAnimSpecs; } /** @hide */ + public IAppTransitionAnimationSpecsFuture getSpecsFuture() { + return mSpecsFuture; + } + + /** @hide */ public static ActivityOptions fromBundle(Bundle bOptions) { return bOptions != null ? new ActivityOptions(bOptions) : null; } @@ -1205,6 +1186,7 @@ public class ActivityOptions { } mAnimSpecs = otherOptions.mAnimSpecs; mAnimationFinishedListener = otherOptions.mAnimationFinishedListener; + mSpecsFuture = otherOptions.mSpecsFuture; } /** @@ -1279,6 +1261,9 @@ public class ActivityOptions { if (mAnimationFinishedListener != null) { b.putBinder(KEY_ANIMATION_FINISHED_LISTENER, mAnimationFinishedListener.asBinder()); } + if (mSpecsFuture != null) { + b.putBinder(KEY_SPECS_FUTURE, mSpecsFuture.asBinder()); + } b.putInt(KEY_ROTATION_ANIMATION_HINT, mRotationAnimationHint); if (mAppVerificationBundle != null) { b.putBundle(KEY_INSTANT_APP_VERIFICATION_BUNDLE, mAppVerificationBundle); diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java index 2b812a5f7ac3..2522d0f9107a 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java @@ -477,7 +477,8 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener // Launch the task ssp.startActivityFromRecents( - mContext, toTask.key, toTask.title, launchOpts, INVALID_STACK_ID); + mContext, toTask.key, toTask.title, launchOpts, INVALID_STACK_ID, + null /* resultListener */); } /** @@ -550,7 +551,8 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener // Launch the task ssp.startActivityFromRecents( - mContext, toTask.key, toTask.title, launchOpts, INVALID_STACK_ID); + mContext, toTask.key, toTask.title, launchOpts, INVALID_STACK_ID, + null /* resultListener */); } public void showNextAffiliatedTask() { diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index 8594ec629dfd..1dc3c8212de4 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -26,6 +26,7 @@ import static android.app.ActivityManager.StackId.RECENTS_STACK_ID; import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManager.StackInfo; import android.app.ActivityManager.TaskSnapshot; @@ -70,6 +71,7 @@ import android.util.ArraySet; import android.util.IconDrawableFactory; import android.util.Log; import android.util.MutableBoolean; +import android.view.AppTransitionAnimationSpec; import android.view.Display; import android.view.IAppTransitionAnimationSpecsFuture; import android.view.IDockedStackListener; @@ -89,6 +91,7 @@ import com.android.systemui.recents.RecentsDebugFlags; import com.android.systemui.recents.RecentsImpl; import com.android.systemui.recents.model.Task; import com.android.systemui.recents.model.ThumbnailData; +import com.android.systemui.recents.views.RecentsTransitionHelper.AnimationSpecComposer; import java.io.IOException; import java.util.ArrayList; @@ -1116,31 +1119,44 @@ public class SystemServicesProxy { } /** Starts an activity from recents. */ - public boolean startActivityFromRecents(Context context, Task.TaskKey taskKey, String taskName, - ActivityOptions options, int stackId) { - if (mIam != null) { + public void startActivityFromRecents(Context context, Task.TaskKey taskKey, String taskName, + ActivityOptions options, int stackId, + @Nullable final StartActivityFromRecentsResultListener resultListener) { + if (mIam == null) { + return; + } + if (taskKey.stackId == DOCKED_STACK_ID) { + // We show non-visible docked tasks in Recents, but we always want to launch + // them in the fullscreen stack. + if (options == null) { + options = ActivityOptions.makeBasic(); + } + options.setLaunchStackId(FULLSCREEN_WORKSPACE_STACK_ID); + } else if (stackId != INVALID_STACK_ID) { + if (options == null) { + options = ActivityOptions.makeBasic(); + } + options.setLaunchStackId(stackId); + } + final ActivityOptions finalOptions = options; + + // Execute this from another thread such that we can do other things (like caching the + // bitmap for the thumbnail) while AM is busy starting our activity. + mOnewayExecutor.submit(() -> { try { - if (taskKey.stackId == DOCKED_STACK_ID) { - // We show non-visible docked tasks in Recents, but we always want to launch - // them in the fullscreen stack. - if (options == null) { - options = ActivityOptions.makeBasic(); - } - options.setLaunchStackId(FULLSCREEN_WORKSPACE_STACK_ID); - } else if (stackId != INVALID_STACK_ID){ - if (options == null) { - options = ActivityOptions.makeBasic(); - } - options.setLaunchStackId(stackId); - } mIam.startActivityFromRecents( - taskKey.id, options == null ? null : options.toBundle()); - return true; + taskKey.id, finalOptions == null ? null : finalOptions.toBundle()); + if (resultListener != null) { + mHandler.post(() -> resultListener.onStartActivityResult(true)); + } } catch (Exception e) { - Log.e(TAG, context.getString(R.string.recents_launch_error_message, taskName), e); + Log.e(TAG, context.getString( + R.string.recents_launch_error_message, taskName), e); + if (resultListener != null) { + mHandler.post(() -> resultListener.onStartActivityResult(false)); + } } - } - return false; + }); } /** Starts an in-place animation on the front most application windows. */ @@ -1258,6 +1274,10 @@ public class SystemServicesProxy { } } + public interface StartActivityFromRecentsResultListener { + void onStartActivityResult(boolean succeeded); + } + private final class H extends Handler { private static final int ON_TASK_STACK_CHANGED = 1; private static final int ON_TASK_SNAPSHOT_CHANGED = 2; diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java index 8882cab1b68b..d7d264e3aa07 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java @@ -101,57 +101,49 @@ public class RecentsTransitionHelper { */ public void launchTaskFromRecents(final TaskStack stack, @Nullable final Task task, final TaskStackView stackView, final TaskView taskView, - final boolean screenPinningRequested, final Rect bounds, final int destinationStack) { - final ActivityOptions opts = ActivityOptions.makeBasic(); - if (bounds != null) { - opts.setLaunchBounds(bounds.isEmpty() ? null : bounds); - } + final boolean screenPinningRequested, final int destinationStack) { final ActivityOptions.OnAnimationStartedListener animStartedListener; - final IAppTransitionAnimationSpecsFuture transitionFuture; + final AppTransitionAnimationSpecsFuture transitionFuture; if (taskView != null) { - transitionFuture = getAppTransitionFuture(new AnimationSpecComposer() { - @Override - public List<AppTransitionAnimationSpec> composeSpecs() { - return composeAnimationSpecs(task, stackView, destinationStack); - } - }); - animStartedListener = new ActivityOptions.OnAnimationStartedListener() { - @Override - public void onAnimationStarted() { - // If we are launching into another task, cancel the previous task's - // window transition - EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task)); - EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent()); - stackView.cancelAllTaskViewAnimations(); - - if (screenPinningRequested) { - // Request screen pinning after the animation runs - mStartScreenPinningRunnable.taskId = task.key.id; - mHandler.postDelayed(mStartScreenPinningRunnable, 350); - } + + // Fetch window rect here already in order not to be blocked on lock contention in WM + // when the future calls it. + final Rect windowRect = Recents.getSystemServices().getWindowRect(); + transitionFuture = getAppTransitionFuture( + () -> composeAnimationSpecs(task, stackView, destinationStack, windowRect)); + animStartedListener = () -> { + // If we are launching into another task, cancel the previous task's + // window transition + EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task)); + EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent()); + stackView.cancelAllTaskViewAnimations(); + + if (screenPinningRequested) { + // Request screen pinning after the animation runs + mStartScreenPinningRunnable.taskId = task.key.id; + mHandler.postDelayed(mStartScreenPinningRunnable, 350); } }; } else { // This is only the case if the task is not on screen (scrolled offscreen for example) transitionFuture = null; - animStartedListener = new ActivityOptions.OnAnimationStartedListener() { - @Override - public void onAnimationStarted() { - // If we are launching into another task, cancel the previous task's - // window transition - EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task)); - EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent()); - stackView.cancelAllTaskViewAnimations(); - } + animStartedListener = () -> { + // If we are launching into another task, cancel the previous task's + // window transition + EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task)); + EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent()); + stackView.cancelAllTaskViewAnimations(); }; } + final ActivityOptions opts = ActivityOptions.makeMultiThumbFutureAspectScaleAnimation(mContext, + mHandler, transitionFuture != null ? transitionFuture.future : null, + animStartedListener, true /* scaleUp */); if (taskView == null) { // If there is no task view, then we do not need to worry about animating out occluding // task views, and we can launch immediately - startTaskActivity(stack, task, taskView, opts, transitionFuture, animStartedListener, - destinationStack); + startTaskActivity(stack, task, taskView, opts, transitionFuture, destinationStack); } else { LaunchTaskStartedEvent launchStartedEvent = new LaunchTaskStartedEvent(taskView, screenPinningRequested); @@ -160,14 +152,13 @@ public class RecentsTransitionHelper { @Override public void run() { startTaskActivity(stack, task, taskView, opts, transitionFuture, - animStartedListener, destinationStack); + destinationStack); } }); EventBus.getDefault().send(launchStartedEvent); } else { EventBus.getDefault().send(launchStartedEvent); - startTaskActivity(stack, task, taskView, opts, transitionFuture, - animStartedListener, destinationStack); + startTaskActivity(stack, task, taskView, opts, transitionFuture, destinationStack); } } Recents.getSystemServices().sendCloseSystemWindows( @@ -199,30 +190,31 @@ public class RecentsTransitionHelper { * @param destinationStack id of the stack to put the task into. */ private void startTaskActivity(TaskStack stack, Task task, @Nullable TaskView taskView, - ActivityOptions opts, IAppTransitionAnimationSpecsFuture transitionFuture, - final OnAnimationStartedListener animStartedListener, int destinationStack) { + ActivityOptions opts, AppTransitionAnimationSpecsFuture transitionFuture, + int destinationStack) { SystemServicesProxy ssp = Recents.getSystemServices(); - if (ssp.startActivityFromRecents(mContext, task.key, task.title, opts, destinationStack)) { - // Keep track of the index of the task launch - int taskIndexFromFront = 0; - int taskIndex = stack.indexOfStackTask(task); - if (taskIndex > -1) { - taskIndexFromFront = stack.getTaskCount() - taskIndex - 1; - } - EventBus.getDefault().send(new LaunchTaskSucceededEvent(taskIndexFromFront)); - } else { - // Dismiss the task if we fail to launch it - if (taskView != null) { - taskView.dismissTask(); - } - - // Keep track of failed launches - EventBus.getDefault().send(new LaunchTaskFailedEvent()); - } + ssp.startActivityFromRecents(mContext, task.key, task.title, opts, destinationStack, + succeeded -> { + if (succeeded) { + // Keep track of the index of the task launch + int taskIndexFromFront = 0; + int taskIndex = stack.indexOfStackTask(task); + if (taskIndex > -1) { + taskIndexFromFront = stack.getTaskCount() - taskIndex - 1; + } + EventBus.getDefault().send(new LaunchTaskSucceededEvent(taskIndexFromFront)); + } else { + // Dismiss the task if we fail to launch it + if (taskView != null) { + taskView.dismissTask(); + } + // Keep track of failed launches + EventBus.getDefault().send(new LaunchTaskFailedEvent()); + } + }); if (transitionFuture != null) { - ssp.overridePendingAppTransitionMultiThumbFuture(transitionFuture, - wrapStartedListener(animStartedListener), true /* scaleUp */); + mHandler.post(transitionFuture::precacheSpecs); } } @@ -231,21 +223,18 @@ public class RecentsTransitionHelper { * * @param composer The implementation that composes the specs on the UI thread. */ - public IAppTransitionAnimationSpecsFuture getAppTransitionFuture( + public AppTransitionAnimationSpecsFuture getAppTransitionFuture( final AnimationSpecComposer composer) { synchronized (this) { mAppTransitionAnimationSpecs = SPECS_WAITING; } - return new IAppTransitionAnimationSpecsFuture.Stub() { + IAppTransitionAnimationSpecsFuture future = new IAppTransitionAnimationSpecsFuture.Stub() { @Override public AppTransitionAnimationSpec[] get() throws RemoteException { - mHandler.post(new Runnable() { - @Override - public void run() { - synchronized (RecentsTransitionHelper.this) { - mAppTransitionAnimationSpecs = composer.composeSpecs(); - RecentsTransitionHelper.this.notifyAll(); - } + mHandler.post(() -> { + synchronized (RecentsTransitionHelper.this) { + mAppTransitionAnimationSpecs = composer.composeSpecs(); + RecentsTransitionHelper.this.notifyAll(); } }); synchronized (RecentsTransitionHelper.this) { @@ -265,6 +254,7 @@ public class RecentsTransitionHelper { } } }; + return new AppTransitionAnimationSpecsFuture(composer, future); } /** @@ -283,7 +273,7 @@ public class RecentsTransitionHelper { * Composes the animation specs for all the tasks in the target stack. */ private List<AppTransitionAnimationSpec> composeAnimationSpecs(final Task task, - final TaskStackView stackView, final int destinationStack) { + final TaskStackView stackView, final int destinationStack, Rect windowRect) { // Ensure we have a valid target stack id final int targetStackId = destinationStack != INVALID_STACK_ID ? destinationStack : task.key.stackId; @@ -309,8 +299,7 @@ public class RecentsTransitionHelper { specs.add(composeOffscreenAnimationSpec(task, offscreenTaskRect)); } else { mTmpTransform.fillIn(taskView); - stackLayout.transformToScreenCoordinates(mTmpTransform, - null /* windowOverrideRect */); + stackLayout.transformToScreenCoordinates(mTmpTransform, windowRect); AppTransitionAnimationSpec spec = composeAnimationSpec(stackView, taskView, mTmpTransform, true /* addHeaderBitmap */); if (spec != null) { @@ -430,4 +419,34 @@ public class RecentsTransitionHelper { public interface AnimationSpecComposer { List<AppTransitionAnimationSpec> composeSpecs(); } + + /** + * Class to be returned from {@link #composeAnimationSpec} that gives access to both the future + * and the anonymous class used for composing. + */ + public class AppTransitionAnimationSpecsFuture { + + private final AnimationSpecComposer composer; + private final IAppTransitionAnimationSpecsFuture future; + + private AppTransitionAnimationSpecsFuture(AnimationSpecComposer composer, + IAppTransitionAnimationSpecsFuture future) { + this.composer = composer; + this.future = future; + } + + public IAppTransitionAnimationSpecsFuture getFuture() { + return future; + } + + /** + * Manually generates and caches the spec such that they are already available when the + * future needs. + */ + public void precacheSpecs() { + synchronized (RecentsTransitionHelper.this) { + mAppTransitionAnimationSpecs = composer.composeSpecs(); + } + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java index 8f9c457c255b..e06c40c6cfe7 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -24,19 +24,16 @@ import android.app.ActivityOptions.OnAnimationStartedListener; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; -import android.graphics.Outline; import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.util.ArraySet; import android.util.AttributeSet; import android.view.AppTransitionAnimationSpec; -import android.view.IAppTransitionAnimationSpecsFuture; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewDebug; -import android.view.ViewOutlineProvider; import android.view.ViewPropertyAnimator; import android.view.WindowInsets; import android.widget.FrameLayout; @@ -73,10 +70,10 @@ import com.android.systemui.recents.misc.Utilities; import com.android.systemui.recents.model.Task; import com.android.systemui.recents.model.TaskStack; import com.android.systemui.recents.views.RecentsTransitionHelper.AnimationSpecComposer; +import com.android.systemui.recents.views.RecentsTransitionHelper.AppTransitionAnimationSpecsFuture; import com.android.systemui.stackdivider.WindowManagerProxy; import com.android.systemui.statusbar.FlingAnimationUtils; -import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; @@ -440,8 +437,7 @@ public class RecentsView extends FrameLayout { public final void onBusEvent(LaunchTaskEvent event) { mLastTaskLaunchedWasFreeform = event.task.isFreeformTask(); mTransitionHelper.launchTaskFromRecents(getStack(), event.task, mTaskStackView, - event.taskView, event.screenPinningRequested, event.targetTaskBounds, - event.targetTaskStack); + event.taskView, event.screenPinningRequested, event.targetTaskStack); } public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) { @@ -523,7 +519,7 @@ public class RecentsView extends FrameLayout { }; final Rect taskRect = getTaskRect(event.taskView); - IAppTransitionAnimationSpecsFuture future = + AppTransitionAnimationSpecsFuture future = mTransitionHelper.getAppTransitionFuture( new AnimationSpecComposer() { @Override @@ -532,7 +528,7 @@ public class RecentsView extends FrameLayout { event.taskView, taskRect); } }); - ssp.overridePendingAppTransitionMultiThumbFuture(future, + ssp.overridePendingAppTransitionMultiThumbFuture(future.getFuture(), mTransitionHelper.wrapStartedListener(startedListener), true /* scaleUp */); diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 4e00f2dc4023..bd8e7f741b1b 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -149,6 +149,7 @@ import android.util.MergedConfiguration; import android.util.Slog; import android.util.TimeUtils; import android.view.AppTransitionAnimationSpec; +import android.view.IAppTransitionAnimationSpecsFuture; import android.view.IApplicationToken; import android.view.WindowManager.LayoutParams; @@ -1437,7 +1438,13 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo case ANIM_THUMBNAIL_ASPECT_SCALE_UP: case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN: final AppTransitionAnimationSpec[] specs = pendingOptions.getAnimSpecs(); - if (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_DOWN + final IAppTransitionAnimationSpecsFuture specsFuture = + pendingOptions.getSpecsFuture(); + if (specsFuture != null) { + service.mWindowManager.overridePendingAppTransitionMultiThumbFuture( + specsFuture, pendingOptions.getOnAnimationStartListener(), + animationType == ANIM_THUMBNAIL_ASPECT_SCALE_UP); + } else if (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_DOWN && specs != null) { service.mWindowManager.overridePendingAppTransitionMultiThumb( specs, pendingOptions.getOnAnimationStartListener(), |