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

Commit 09edbf3c authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Ensure Recents Go layout finishes before remote anim begins" into ub-launcher3-qt-dev

parents 4743da38 141ab952
Loading
Loading
Loading
Loading
+41 −1
Original line number Diff line number Diff line
package com.android.launcher3;

import static com.android.launcher3.Utilities.postAsyncCallback;
import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.quickstep.TaskUtils.taskIsATargetWithMode;
import static com.android.quickstep.views.IconRecentsView.CONTENT_ALPHA;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;

import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.app.ActivityOptions;
import android.content.Context;
import android.os.Handler;
import android.view.View;

import com.android.quickstep.views.IconRecentsView;
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;

/**
@@ -28,6 +32,12 @@ public final class GoLauncherAppTransitionManagerImpl extends QuickstepAppTransi
        return mLauncher.getStateManager().getState().overviewUi;
    }

    @Override
    RemoteAnimationRunnerCompat getWallpaperOpenRunner(boolean fromUnlock) {
        return new GoWallpaperOpenLauncherAnimationRunner(mHandler,
                false /* startAtFrontOfQueue */, fromUnlock);
    }

    @Override
    protected void composeRecentsLaunchAnimator(AnimatorSet anim, View v,
            RemoteAnimationTargetCompat[] targets, boolean launcherClosing) {
@@ -51,4 +61,34 @@ public final class GoLauncherAppTransitionManagerImpl extends QuickstepAppTransi

        return mLauncher.getStateManager()::reapplyState;
    }

    /**
     * Remote animation runner for animation from app to Launcher. For Go, when going to recents,
     * we need to ensure that the recents view is ready for remote animation before starting.
     */
    private final class GoWallpaperOpenLauncherAnimationRunner extends
            WallpaperOpenLauncherAnimationRunner {
        public GoWallpaperOpenLauncherAnimationRunner(Handler handler, boolean startAtFrontOfQueue,
                boolean fromUnlock) {
            super(handler, startAtFrontOfQueue, fromUnlock);
        }

        @Override
        public void onCreateAnimation(RemoteAnimationTargetCompat[] targetCompats,
                AnimationResult result) {
            boolean isGoingToRecents =
                    taskIsATargetWithMode(targetCompats, mLauncher.getTaskId(), MODE_OPENING)
                    && (mLauncher.getStateManager().getState() == LauncherState.OVERVIEW);
            if (isGoingToRecents) {
                IconRecentsView recentsView = mLauncher.getOverviewPanel();
                if (!recentsView.isReadyForRemoteAnim()) {
                    recentsView.setOnReadyForRemoteAnimCallback(() ->
                        postAsyncCallback(mHandler, () -> onCreateAnimation(targetCompats, result))
                    );
                    return;
                }
            }
            super.onCreateAnimation(targetCompats, result);
        }
    }
}
+38 −0
Original line number Diff line number Diff line
@@ -378,6 +378,36 @@ public final class IconRecentsView extends FrameLayout implements Insettable {
        return view.getThumbnailView();
    }

    /**
     * Whether this view has processed all data changes and is ready to animate from the app to
     * the overview.
     *
     * @return true if ready to animate app to overview, false otherwise
     */
    public boolean isReadyForRemoteAnim() {
        return !mTaskRecyclerView.hasPendingAdapterUpdates();
    }

    /**
     * Set a callback for whenever this view is ready to do a remote animation from the app to
     * overview. See {@link #isReadyForRemoteAnim()}.
     *
     * @param callback callback to run when view is ready to animate
     */
    public void setOnReadyForRemoteAnimCallback(onReadyForRemoteAnimCallback callback) {
        mTaskRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(
                new ViewTreeObserver.OnGlobalLayoutListener() {
                    @Override
                    public void onGlobalLayout() {
                        if (isReadyForRemoteAnim()) {
                            callback.onReadyForRemoteAnim();
                            mTaskRecyclerView.getViewTreeObserver().
                                    removeOnGlobalLayoutListener(this);
                        }
                    }
                });
    }

    /**
     * Clear all tasks and animate out.
     */
@@ -557,4 +587,12 @@ public final class IconRecentsView extends FrameLayout implements Insettable {
        mTaskRecyclerView.setPadding(insets.left, insets.top, insets.right, insets.bottom);
        mTaskRecyclerView.invalidateItemDecorations();
    }

    /**
     * Callback for when this view is ready for a remote animation from app to overview.
     */
    public interface onReadyForRemoteAnimCallback {

        void onReadyForRemoteAnim();
    }
}
+79 −65
Original line number Diff line number Diff line
@@ -132,7 +132,7 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
    private final DragLayer mDragLayer;
    private final AlphaProperty mDragLayerAlpha;

    private final Handler mHandler;
    final Handler mHandler;
    private final boolean mIsRtl;

    private final float mContentTransY;
@@ -573,70 +573,9 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
     * @return Runner that plays when user goes to Launcher
     *         ie. pressing home, swiping up from nav bar.
     */
    private RemoteAnimationRunnerCompat getWallpaperOpenRunner(boolean fromUnlock) {
        return new LauncherAnimationRunner(mHandler, false /* startAtFrontOfQueue */) {
            @Override
            public void onCreateAnimation(RemoteAnimationTargetCompat[] targetCompats,
                    AnimationResult result) {
                if (!mLauncher.hasBeenResumed()) {
                    // If launcher is not resumed, wait until new async-frame after resume
                    mLauncher.setOnResumeCallback(() ->
                            postAsyncCallback(mHandler, () ->
                                    onCreateAnimation(targetCompats, result)));
                    return;
                }

                if (mLauncher.hasSomeInvisibleFlag(PENDING_INVISIBLE_BY_WALLPAPER_ANIMATION)) {
                    mLauncher.addForceInvisibleFlag(INVISIBLE_BY_PENDING_FLAGS);
                    mLauncher.getStateManager().moveToRestState();
                }

                AnimatorSet anim = null;
                RemoteAnimationProvider provider = mRemoteAnimationProvider;
                if (provider != null) {
                    anim = provider.createWindowAnimation(targetCompats);
                }

                if (anim == null) {
                    anim = new AnimatorSet();
                    anim.play(fromUnlock
                            ? getUnlockWindowAnimator(targetCompats)
                            : getClosingWindowAnimators(targetCompats));

                    // Normally, we run the launcher content animation when we are transitioning
                    // home, but if home is already visible, then we don't want to animate the
                    // contents of launcher unless we know that we are animating home as a result
                    // of the home button press with quickstep, which will result in launcher being
                    // started on touch down, prior to the animation home (and won't be in the
                    // targets list because it is already visible). In that case, we force
                    // invisibility on touch down, and only reset it after the animation to home
                    // is initialized.
                    if (launcherIsATargetWithMode(targetCompats, MODE_OPENING)
                            || mLauncher.isForceInvisible()) {
                        // Only register the content animation for cancellation when state changes
                        mLauncher.getStateManager().setCurrentAnimation(anim);
                        if (fromUnlock) {
                            Pair<AnimatorSet, Runnable> contentAnimator =
                                    getLauncherContentAnimator(false /* isAppOpening */,
                                            new float[] {mContentTransY, 0});
                            contentAnimator.first.setStartDelay(0);
                            anim.play(contentAnimator.first);
                            anim.addListener(new AnimatorListenerAdapter() {
                                @Override
                                public void onAnimationEnd(Animator animation) {
                                    contentAnimator.second.run();
                                }
                            });
                        } else {
                            createLauncherResumeAnimation(anim);
                        }
                    }
                }

                mLauncher.clearForceInvisibleFlag(INVISIBLE_ALL);
                result.setAnimation(anim);
            }
        };
    RemoteAnimationRunnerCompat getWallpaperOpenRunner(boolean fromUnlock) {
        return new WallpaperOpenLauncherAnimationRunner(mHandler, false /* startAtFrontOfQueue */,
                fromUnlock);
    }

    /**
@@ -773,4 +712,79 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
        return mLauncher.checkSelfPermission(CONTROL_REMOTE_APP_TRANSITION_PERMISSION)
                == PackageManager.PERMISSION_GRANTED;
    }

    /**
     * Remote animation runner for animation from the app to Launcher, including recents.
     */
    class WallpaperOpenLauncherAnimationRunner extends LauncherAnimationRunner {
        private final boolean mFromUnlock;

        public WallpaperOpenLauncherAnimationRunner(Handler handler, boolean startAtFrontOfQueue,
                boolean fromUnlock) {
            super(handler, startAtFrontOfQueue);
            mFromUnlock = fromUnlock;
        }

        @Override
        public void onCreateAnimation(RemoteAnimationTargetCompat[] targetCompats,
                LauncherAnimationRunner.AnimationResult result) {
            if (!mLauncher.hasBeenResumed()) {
                // If launcher is not resumed, wait until new async-frame after resume
                mLauncher.setOnResumeCallback(() ->
                        postAsyncCallback(mHandler, () ->
                                onCreateAnimation(targetCompats, result)));
                return;
            }

            if (mLauncher.hasSomeInvisibleFlag(PENDING_INVISIBLE_BY_WALLPAPER_ANIMATION)) {
                mLauncher.addForceInvisibleFlag(INVISIBLE_BY_PENDING_FLAGS);
                mLauncher.getStateManager().moveToRestState();
            }

            AnimatorSet anim = null;
            RemoteAnimationProvider provider = mRemoteAnimationProvider;
            if (provider != null) {
                anim = provider.createWindowAnimation(targetCompats);
            }

            if (anim == null) {
                anim = new AnimatorSet();
                anim.play(mFromUnlock
                        ? getUnlockWindowAnimator(targetCompats)
                        : getClosingWindowAnimators(targetCompats));

                // Normally, we run the launcher content animation when we are transitioning
                // home, but if home is already visible, then we don't want to animate the
                // contents of launcher unless we know that we are animating home as a result
                // of the home button press with quickstep, which will result in launcher being
                // started on touch down, prior to the animation home (and won't be in the
                // targets list because it is already visible). In that case, we force
                // invisibility on touch down, and only reset it after the animation to home
                // is initialized.
                if (launcherIsATargetWithMode(targetCompats, MODE_OPENING)
                        || mLauncher.isForceInvisible()) {
                    // Only register the content animation for cancellation when state changes
                    mLauncher.getStateManager().setCurrentAnimation(anim);
                    if (mFromUnlock) {
                        Pair<AnimatorSet, Runnable> contentAnimator =
                                getLauncherContentAnimator(false /* isAppOpening */,
                                        new float[] {mContentTransY, 0});
                        contentAnimator.first.setStartDelay(0);
                        anim.play(contentAnimator.first);
                        anim.addListener(new AnimatorListenerAdapter() {
                            @Override
                            public void onAnimationEnd(Animator animation) {
                                contentAnimator.second.run();
                            }
                        });
                    } else {
                        createLauncherResumeAnimation(anim);
                    }
                }
            }

            mLauncher.clearForceInvisibleFlag(INVISIBLE_ALL);
            result.setAnimation(anim);
        }
    }
}