Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cb414be0 authored by Jorim Jaggi's avatar Jorim Jaggi Committed by Android (Google) Code Review
Browse files

Merge "Optimize hot launching recents" into oc-dev

parents b2bd3292 34795e31
Loading
Loading
Loading
Loading
+30 −45
Original line number Original line Diff line number Diff line
@@ -38,6 +38,7 @@ import android.transition.TransitionManager;
import android.util.Pair;
import android.util.Pair;
import android.util.Slog;
import android.util.Slog;
import android.view.AppTransitionAnimationSpec;
import android.view.AppTransitionAnimationSpec;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.View;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup;
import android.view.Window;
import android.view.Window;
@@ -213,6 +214,7 @@ public class ActivityOptions {


    private static final String KEY_INSTANT_APP_VERIFICATION_BUNDLE
    private static final String KEY_INSTANT_APP_VERIFICATION_BUNDLE
            = "android:instantapps.installerbundle";
            = "android:instantapps.installerbundle";
    private static final String KEY_SPECS_FUTURE = "android:activity.specsFuture";


    /** @hide */
    /** @hide */
    public static final int ANIM_NONE = 0;
    public static final int ANIM_NONE = 0;
@@ -268,6 +270,7 @@ public class ActivityOptions {
    private AppTransitionAnimationSpec mAnimSpecs[];
    private AppTransitionAnimationSpec mAnimSpecs[];
    private int mRotationAnimationHint = -1;
    private int mRotationAnimationHint = -1;
    private Bundle mAppVerificationBundle;
    private Bundle mAppVerificationBundle;
    private IAppTransitionAnimationSpecsFuture mSpecsFuture;


    /**
    /**
     * Create an ActivityOptions specifying a custom animation to run when
     * 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.
     * is not executed, the callback will happen immediately.
     * @return Returns a new ActivityOptions object that you can use to
     * @return Returns a new ActivityOptions object that you can use to
     * supply these options as the options Bundle when starting an activity.
     * 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) {
            Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) {
        return makeThumbnailAnimation(source, thumbnail, startX, startY, listener, true);
        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,
    private static ActivityOptions makeThumbnailAnimation(View source,
            Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener,
            Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener,
            boolean scaleUp) {
            boolean scaleUp) {
@@ -537,29 +517,21 @@ public class ActivityOptions {
    }
    }


    /**
    /**
     * Create an ActivityOptions specifying an animation where the new activity
     * Create an ActivityOptions specifying an animation where a list of activity windows and
     * window and a thumbnail is aspect-scaled to a new location.
     * thumbnails are aspect scaled to/from 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.
     * @hide
     * @hide
     */
     */
    public static ActivityOptions makeThumbnailAspectScaleUpAnimation(View source,
    public static ActivityOptions makeMultiThumbFutureAspectScaleAnimation(Context context,
            Bitmap thumbnail, int startX, int startY, int targetWidth, int targetHeight,
            Handler handler, IAppTransitionAnimationSpecsFuture specsFuture,
            Handler handler, OnAnimationStartedListener listener) {
            OnAnimationStartedListener listener, boolean scaleUp) {
        return makeAspectScaledThumbnailAnimation(source, thumbnail, startX, startY,
        ActivityOptions opts = new ActivityOptions();
                targetWidth, targetHeight, handler, listener, true);
        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);
        mRotationAnimationHint = opts.getInt(KEY_ROTATION_ANIMATION_HINT);
        mAppVerificationBundle = opts.getBundle(KEY_INSTANT_APP_VERIFICATION_BUNDLE);
        mAppVerificationBundle = opts.getBundle(KEY_INSTANT_APP_VERIFICATION_BUNDLE);
        if (opts.containsKey(KEY_SPECS_FUTURE)) {
            mSpecsFuture = IAppTransitionAnimationSpecsFuture.Stub.asInterface(opts.getBinder(
                    KEY_SPECS_FUTURE));
        }
    }
    }


    /**
    /**
@@ -1028,6 +1004,11 @@ public class ActivityOptions {
    /** @hide */
    /** @hide */
    public AppTransitionAnimationSpec[] getAnimSpecs() { return mAnimSpecs; }
    public AppTransitionAnimationSpec[] getAnimSpecs() { return mAnimSpecs; }


    /** @hide */
    public IAppTransitionAnimationSpecsFuture getSpecsFuture() {
        return mSpecsFuture;
    }

    /** @hide */
    /** @hide */
    public static ActivityOptions fromBundle(Bundle bOptions) {
    public static ActivityOptions fromBundle(Bundle bOptions) {
        return bOptions != null ? new ActivityOptions(bOptions) : null;
        return bOptions != null ? new ActivityOptions(bOptions) : null;
@@ -1205,6 +1186,7 @@ public class ActivityOptions {
        }
        }
        mAnimSpecs = otherOptions.mAnimSpecs;
        mAnimSpecs = otherOptions.mAnimSpecs;
        mAnimationFinishedListener = otherOptions.mAnimationFinishedListener;
        mAnimationFinishedListener = otherOptions.mAnimationFinishedListener;
        mSpecsFuture = otherOptions.mSpecsFuture;
    }
    }


    /**
    /**
@@ -1279,6 +1261,9 @@ public class ActivityOptions {
        if (mAnimationFinishedListener != null) {
        if (mAnimationFinishedListener != null) {
            b.putBinder(KEY_ANIMATION_FINISHED_LISTENER, mAnimationFinishedListener.asBinder());
            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);
        b.putInt(KEY_ROTATION_ANIMATION_HINT, mRotationAnimationHint);
        if (mAppVerificationBundle != null) {
        if (mAppVerificationBundle != null) {
            b.putBundle(KEY_INSTANT_APP_VERIFICATION_BUNDLE, mAppVerificationBundle);
            b.putBundle(KEY_INSTANT_APP_VERIFICATION_BUNDLE, mAppVerificationBundle);
+4 −2
Original line number Original line Diff line number Diff line
@@ -477,7 +477,8 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener


        // Launch the task
        // Launch the task
        ssp.startActivityFromRecents(
        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
        // Launch the task
        ssp.startActivityFromRecents(
        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() {
    public void showNextAffiliatedTask() {
+41 −21
Original line number Original line Diff line number Diff line
@@ -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 static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;


import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManager;
import android.app.ActivityManager.StackInfo;
import android.app.ActivityManager.StackInfo;
import android.app.ActivityManager.TaskSnapshot;
import android.app.ActivityManager.TaskSnapshot;
@@ -70,6 +71,7 @@ import android.util.ArraySet;
import android.util.IconDrawableFactory;
import android.util.IconDrawableFactory;
import android.util.Log;
import android.util.Log;
import android.util.MutableBoolean;
import android.util.MutableBoolean;
import android.view.AppTransitionAnimationSpec;
import android.view.Display;
import android.view.Display;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IDockedStackListener;
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.RecentsImpl;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.ThumbnailData;
import com.android.systemui.recents.model.ThumbnailData;
import com.android.systemui.recents.views.RecentsTransitionHelper.AnimationSpecComposer;


import java.io.IOException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.ArrayList;
@@ -1116,10 +1119,12 @@ public class SystemServicesProxy {
    }
    }


    /** Starts an activity from recents. */
    /** Starts an activity from recents. */
    public boolean startActivityFromRecents(Context context, Task.TaskKey taskKey, String taskName,
    public void startActivityFromRecents(Context context, Task.TaskKey taskKey, String taskName,
            ActivityOptions options, int stackId) {
            ActivityOptions options, int stackId,
        if (mIam != null) {
            @Nullable final StartActivityFromRecentsResultListener resultListener) {
            try {
        if (mIam == null) {
            return;
        }
        if (taskKey.stackId == DOCKED_STACK_ID) {
        if (taskKey.stackId == DOCKED_STACK_ID) {
            // We show non-visible docked tasks in Recents, but we always want to launch
            // We show non-visible docked tasks in Recents, but we always want to launch
            // them in the fullscreen stack.
            // them in the fullscreen stack.
@@ -1133,14 +1138,25 @@ public class SystemServicesProxy {
            }
            }
            options.setLaunchStackId(stackId);
            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 {
                mIam.startActivityFromRecents(
                mIam.startActivityFromRecents(
                        taskKey.id, options == null ? null : options.toBundle());
                        taskKey.id, finalOptions == null ? null : finalOptions.toBundle());
                return true;
                if (resultListener != null) {
                    mHandler.post(() -> resultListener.onStartActivityResult(true));
                }
            } catch (Exception e) {
            } 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. */
    /** 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 final class H extends Handler {
        private static final int ON_TASK_STACK_CHANGED = 1;
        private static final int ON_TASK_STACK_CHANGED = 1;
        private static final int ON_TASK_SNAPSHOT_CHANGED = 2;
        private static final int ON_TASK_SNAPSHOT_CHANGED = 2;
+92 −73
Original line number Original line Diff line number Diff line
@@ -101,24 +101,18 @@ public class RecentsTransitionHelper {
     */
     */
    public void launchTaskFromRecents(final TaskStack stack, @Nullable final Task task,
    public void launchTaskFromRecents(final TaskStack stack, @Nullable final Task task,
            final TaskStackView stackView, final TaskView taskView,
            final TaskStackView stackView, final TaskView taskView,
            final boolean screenPinningRequested, final Rect bounds, final int destinationStack) {
            final boolean screenPinningRequested, final int destinationStack) {
        final ActivityOptions opts = ActivityOptions.makeBasic();
        if (bounds != null) {
            opts.setLaunchBounds(bounds.isEmpty() ? null : bounds);
        }


        final ActivityOptions.OnAnimationStartedListener animStartedListener;
        final ActivityOptions.OnAnimationStartedListener animStartedListener;
        final IAppTransitionAnimationSpecsFuture transitionFuture;
        final AppTransitionAnimationSpecsFuture transitionFuture;
        if (taskView != null) {
        if (taskView != null) {
            transitionFuture = getAppTransitionFuture(new AnimationSpecComposer() {

                @Override
            // Fetch window rect here already in order not to be blocked on lock contention in WM
                public List<AppTransitionAnimationSpec> composeSpecs() {
            // when the future calls it.
                    return composeAnimationSpecs(task, stackView, destinationStack);
            final Rect windowRect = Recents.getSystemServices().getWindowRect();
                }
            transitionFuture = getAppTransitionFuture(
            });
                    () -> composeAnimationSpecs(task, stackView, destinationStack, windowRect));
            animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
            animStartedListener = () -> {
                @Override
                public void onAnimationStarted() {
                // If we are launching into another task, cancel the previous task's
                // If we are launching into another task, cancel the previous task's
                // window transition
                // window transition
                EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
                EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
@@ -130,28 +124,26 @@ public class RecentsTransitionHelper {
                    mStartScreenPinningRunnable.taskId = task.key.id;
                    mStartScreenPinningRunnable.taskId = task.key.id;
                    mHandler.postDelayed(mStartScreenPinningRunnable, 350);
                    mHandler.postDelayed(mStartScreenPinningRunnable, 350);
                }
                }
                }
            };
            };
        } else {
        } else {
            // This is only the case if the task is not on screen (scrolled offscreen for example)
            // This is only the case if the task is not on screen (scrolled offscreen for example)
            transitionFuture = null;
            transitionFuture = null;
            animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
            animStartedListener = () -> {
                @Override
                public void onAnimationStarted() {
                // If we are launching into another task, cancel the previous task's
                // If we are launching into another task, cancel the previous task's
                // window transition
                // window transition
                EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
                EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
                EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
                EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
                stackView.cancelAllTaskViewAnimations();
                stackView.cancelAllTaskViewAnimations();
                }
            };
            };
        }
        }


        final ActivityOptions opts = ActivityOptions.makeMultiThumbFutureAspectScaleAnimation(mContext,
                mHandler, transitionFuture != null ? transitionFuture.future : null,
                animStartedListener, true /* scaleUp */);
        if (taskView == null) {
        if (taskView == null) {
            // If there is no task view, then we do not need to worry about animating out occluding
            // If there is no task view, then we do not need to worry about animating out occluding
            // task views, and we can launch immediately
            // task views, and we can launch immediately
            startTaskActivity(stack, task, taskView, opts, transitionFuture, animStartedListener,
            startTaskActivity(stack, task, taskView, opts, transitionFuture, destinationStack);
                    destinationStack);
        } else {
        } else {
            LaunchTaskStartedEvent launchStartedEvent = new LaunchTaskStartedEvent(taskView,
            LaunchTaskStartedEvent launchStartedEvent = new LaunchTaskStartedEvent(taskView,
                    screenPinningRequested);
                    screenPinningRequested);
@@ -160,14 +152,13 @@ public class RecentsTransitionHelper {
                    @Override
                    @Override
                    public void run() {
                    public void run() {
                        startTaskActivity(stack, task, taskView, opts, transitionFuture,
                        startTaskActivity(stack, task, taskView, opts, transitionFuture,
                                animStartedListener, destinationStack);
                                destinationStack);
                    }
                    }
                });
                });
                EventBus.getDefault().send(launchStartedEvent);
                EventBus.getDefault().send(launchStartedEvent);
            } else {
            } else {
                EventBus.getDefault().send(launchStartedEvent);
                EventBus.getDefault().send(launchStartedEvent);
                startTaskActivity(stack, task, taskView, opts, transitionFuture,
                startTaskActivity(stack, task, taskView, opts, transitionFuture, destinationStack);
                        animStartedListener, destinationStack);
            }
            }
        }
        }
        Recents.getSystemServices().sendCloseSystemWindows(
        Recents.getSystemServices().sendCloseSystemWindows(
@@ -199,10 +190,12 @@ public class RecentsTransitionHelper {
     * @param destinationStack id of the stack to put the task into.
     * @param destinationStack id of the stack to put the task into.
     */
     */
    private void startTaskActivity(TaskStack stack, Task task, @Nullable TaskView taskView,
    private void startTaskActivity(TaskStack stack, Task task, @Nullable TaskView taskView,
            ActivityOptions opts, IAppTransitionAnimationSpecsFuture transitionFuture,
            ActivityOptions opts, AppTransitionAnimationSpecsFuture transitionFuture,
            final OnAnimationStartedListener animStartedListener, int destinationStack) {
            int destinationStack) {
        SystemServicesProxy ssp = Recents.getSystemServices();
        SystemServicesProxy ssp = Recents.getSystemServices();
        if (ssp.startActivityFromRecents(mContext, task.key, task.title, opts, destinationStack)) {
        ssp.startActivityFromRecents(mContext, task.key, task.title, opts, destinationStack,
                succeeded -> {
            if (succeeded) {
                // Keep track of the index of the task launch
                // Keep track of the index of the task launch
                int taskIndexFromFront = 0;
                int taskIndexFromFront = 0;
                int taskIndex = stack.indexOfStackTask(task);
                int taskIndex = stack.indexOfStackTask(task);
@@ -219,10 +212,9 @@ public class RecentsTransitionHelper {
                // Keep track of failed launches
                // Keep track of failed launches
                EventBus.getDefault().send(new LaunchTaskFailedEvent());
                EventBus.getDefault().send(new LaunchTaskFailedEvent());
            }
            }

        });
        if (transitionFuture != null) {
        if (transitionFuture != null) {
            ssp.overridePendingAppTransitionMultiThumbFuture(transitionFuture,
            mHandler.post(transitionFuture::precacheSpecs);
                    wrapStartedListener(animStartedListener), true /* scaleUp */);
        }
        }
    }
    }


@@ -231,22 +223,19 @@ public class RecentsTransitionHelper {
     *
     *
     * @param composer The implementation that composes the specs on the UI thread.
     * @param composer The implementation that composes the specs on the UI thread.
     */
     */
    public IAppTransitionAnimationSpecsFuture getAppTransitionFuture(
    public AppTransitionAnimationSpecsFuture getAppTransitionFuture(
            final AnimationSpecComposer composer) {
            final AnimationSpecComposer composer) {
        synchronized (this) {
        synchronized (this) {
            mAppTransitionAnimationSpecs = SPECS_WAITING;
            mAppTransitionAnimationSpecs = SPECS_WAITING;
        }
        }
        return new IAppTransitionAnimationSpecsFuture.Stub() {
        IAppTransitionAnimationSpecsFuture future = new IAppTransitionAnimationSpecsFuture.Stub() {
            @Override
            @Override
            public AppTransitionAnimationSpec[] get() throws RemoteException {
            public AppTransitionAnimationSpec[] get() throws RemoteException {
                mHandler.post(new Runnable() {
                mHandler.post(() -> {
                    @Override
                    public void run() {
                    synchronized (RecentsTransitionHelper.this) {
                    synchronized (RecentsTransitionHelper.this) {
                        mAppTransitionAnimationSpecs = composer.composeSpecs();
                        mAppTransitionAnimationSpecs = composer.composeSpecs();
                        RecentsTransitionHelper.this.notifyAll();
                        RecentsTransitionHelper.this.notifyAll();
                    }
                    }
                    }
                });
                });
                synchronized (RecentsTransitionHelper.this) {
                synchronized (RecentsTransitionHelper.this) {
                    while (mAppTransitionAnimationSpecs == SPECS_WAITING) {
                    while (mAppTransitionAnimationSpecs == SPECS_WAITING) {
@@ -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.
     * Composes the animation specs for all the tasks in the target stack.
     */
     */
    private List<AppTransitionAnimationSpec> composeAnimationSpecs(final Task task,
    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
        // Ensure we have a valid target stack id
        final int targetStackId = destinationStack != INVALID_STACK_ID ?
        final int targetStackId = destinationStack != INVALID_STACK_ID ?
                destinationStack : task.key.stackId;
                destinationStack : task.key.stackId;
@@ -309,8 +299,7 @@ public class RecentsTransitionHelper {
                specs.add(composeOffscreenAnimationSpec(task, offscreenTaskRect));
                specs.add(composeOffscreenAnimationSpec(task, offscreenTaskRect));
            } else {
            } else {
                mTmpTransform.fillIn(taskView);
                mTmpTransform.fillIn(taskView);
                stackLayout.transformToScreenCoordinates(mTmpTransform,
                stackLayout.transformToScreenCoordinates(mTmpTransform, windowRect);
                        null /* windowOverrideRect */);
                AppTransitionAnimationSpec spec = composeAnimationSpec(stackView, taskView,
                AppTransitionAnimationSpec spec = composeAnimationSpec(stackView, taskView,
                        mTmpTransform, true /* addHeaderBitmap */);
                        mTmpTransform, true /* addHeaderBitmap */);
                if (spec != null) {
                if (spec != null) {
@@ -430,4 +419,34 @@ public class RecentsTransitionHelper {
    public interface AnimationSpecComposer {
    public interface AnimationSpecComposer {
        List<AppTransitionAnimationSpec> composeSpecs();
        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();
            }
        }
    }
}
}
+4 −8
Original line number Original line Diff line number Diff line
@@ -24,19 +24,16 @@ import android.app.ActivityOptions.OnAnimationStartedListener;
import android.content.Context;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Color;
import android.graphics.Outline;
import android.graphics.Rect;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Drawable;
import android.util.ArraySet;
import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.AttributeSet;
import android.view.AppTransitionAnimationSpec;
import android.view.AppTransitionAnimationSpec;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.LayoutInflater;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewDebug;
import android.view.ViewOutlineProvider;
import android.view.ViewPropertyAnimator;
import android.view.ViewPropertyAnimator;
import android.view.WindowInsets;
import android.view.WindowInsets;
import android.widget.FrameLayout;
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.Task;
import com.android.systemui.recents.model.TaskStack;
import com.android.systemui.recents.model.TaskStack;
import com.android.systemui.recents.views.RecentsTransitionHelper.AnimationSpecComposer;
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.stackdivider.WindowManagerProxy;
import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.FlingAnimationUtils;


import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.List;
import java.util.List;
@@ -440,8 +437,7 @@ public class RecentsView extends FrameLayout {
    public final void onBusEvent(LaunchTaskEvent event) {
    public final void onBusEvent(LaunchTaskEvent event) {
        mLastTaskLaunchedWasFreeform = event.task.isFreeformTask();
        mLastTaskLaunchedWasFreeform = event.task.isFreeformTask();
        mTransitionHelper.launchTaskFromRecents(getStack(), event.task, mTaskStackView,
        mTransitionHelper.launchTaskFromRecents(getStack(), event.task, mTaskStackView,
                event.taskView, event.screenPinningRequested, event.targetTaskBounds,
                event.taskView, event.screenPinningRequested, event.targetTaskStack);
                event.targetTaskStack);
    }
    }


    public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
    public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
@@ -523,7 +519,7 @@ public class RecentsView extends FrameLayout {
                };
                };


                final Rect taskRect = getTaskRect(event.taskView);
                final Rect taskRect = getTaskRect(event.taskView);
                IAppTransitionAnimationSpecsFuture future =
                AppTransitionAnimationSpecsFuture future =
                        mTransitionHelper.getAppTransitionFuture(
                        mTransitionHelper.getAppTransitionFuture(
                                new AnimationSpecComposer() {
                                new AnimationSpecComposer() {
                                    @Override
                                    @Override
@@ -532,7 +528,7 @@ public class RecentsView extends FrameLayout {
                                                event.taskView, taskRect);
                                                event.taskView, taskRect);
                                    }
                                    }
                                });
                                });
                ssp.overridePendingAppTransitionMultiThumbFuture(future,
                ssp.overridePendingAppTransitionMultiThumbFuture(future.getFuture(),
                        mTransitionHelper.wrapStartedListener(startedListener),
                        mTransitionHelper.wrapStartedListener(startedListener),
                        true /* scaleUp */);
                        true /* scaleUp */);


Loading