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

Commit bc5bfc11 authored by Winson Chung's avatar Winson Chung
Browse files

Make recents animation work with fallback activity.

Bug: 77157702
Bug: 77152886
Change-Id: Ide312b750efb8214a7c262f7380b5dbd2ef4647f
parent 6097be23
Loading
Loading
Loading
Loading
+35 −4
Original line number Diff line number Diff line
@@ -106,6 +106,8 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
    private DeviceProfile mDeviceProfile;
    private View mFloatingView;

    private RemoteAnimationRunnerCompat mRemoteAnimationOverride;

    private final AnimatorListenerAdapter mReapplyStateListener = new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
@@ -175,6 +177,10 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
        return getDefaultActivityLaunchOptions(launcher, v);
    }

    public void setRemoteAnimationOverride(RemoteAnimationRunnerCompat remoteAnimationOverride) {
        mRemoteAnimationOverride = remoteAnimationOverride;
    }

    /**
     * Try to find a TaskView that corresponds with the component of the launched view.
     *
@@ -635,6 +641,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
     * Registers remote animations used when closing apps to home screen.
     */
    private void registerRemoteAnimations() {
        // Unregister this
        if (hasControlRemoteAppTransitionPermission()) {
            try {
                RemoteAnimationDefinitionCompat definition = new RemoteAnimationDefinitionCompat();
@@ -669,12 +676,36 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
    private RemoteAnimationRunnerCompat getWallpaperOpenRunner() {
        return new LauncherAnimationRunner(mHandler) {
            @Override
            public AnimatorSet getAnimator(RemoteAnimationTargetCompat[] targetCompats) {
                if (mLauncher.getStateManager().getState().overviewUi) {
                    // We use a separate transition for Overview mode.
                    return null;
            public void onAnimationStart(RemoteAnimationTargetCompat[] targetCompats,
                    Runnable runnable) {
                if (mLauncher.getStateManager().getState().overviewUi
                        && mRemoteAnimationOverride != null) {
                    // This transition is only used for the fallback activity and should not be
                    // managed here (but necessary to implement here since the defined remote
                    // animation currently takes precendence over the one defined in the activity
                    // options).
                    mRemoteAnimationOverride.onAnimationStart(targetCompats, runnable);
                    return;
                }
                super.onAnimationStart(targetCompats, runnable);
            }

            @Override
            public void onAnimationCancelled() {
                if (mLauncher.getStateManager().getState().overviewUi
                        && mRemoteAnimationOverride != null) {
                    // This transition is only used for the fallback activity and should not be
                    // managed here (but necessary to implement here since the defined remote
                    // animation currently takes precendence over the one defined in the activity
                    // options).
                    mRemoteAnimationOverride.onAnimationCancelled();
                    return;
                }
                super.onAnimationCancelled();
            }

            @Override
            public AnimatorSet getAnimator(RemoteAnimationTargetCompat[] targetCompats) {
                AnimatorSet anim = new AnimatorSet();
                anim.play(getClosingWindowAnimators(targetCompats));

+50 −11
Original line number Diff line number Diff line
@@ -36,8 +36,10 @@ import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherAppTransitionManagerImpl;
import com.android.launcher3.LauncherInitListener;
import com.android.launcher3.LauncherState;
import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.util.ViewOnDrawExecutor;
@@ -80,7 +82,10 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {

    ActivityInitListener createActivityInitListener(BiPredicate<T, Boolean> onInitListener);

    void startRecents(Context context, Intent intent, AssistDataReceiver assistDataReceiver,
    void startRecentsFromSwipe(Intent intent, AssistDataReceiver assistDataReceiver,
            final RecentsAnimationListener remoteAnimationListener);

    void startRecentsFromButton(Context context, Intent intent,
            RecentsAnimationListener remoteAnimationListener);

    @UiThread
@@ -203,21 +208,44 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
        }

        @Override
        public void startRecents(Context context, Intent intent,
                AssistDataReceiver assistDataReceiver,
                RecentsAnimationListener remoteAnimationListener) {
        public void startRecentsFromSwipe(Intent intent, AssistDataReceiver assistDataReceiver,
                final RecentsAnimationListener remoteAnimationListener) {
            ActivityManagerWrapper.getInstance().startRecentsActivity(
                    intent, assistDataReceiver, remoteAnimationListener, null, null);
        }

        @Override
        public void startRecentsFromButton(Context context, Intent intent,
                RecentsAnimationListener remoteAnimationListener) {
            // We should use the remove animation for the fallback activity recents button case,
            // it works better with PiP.  In Launcher, we have already registered the remote
            // animation definition, which takes priority over explicitly defined remote
            // animations in the provided activity options when starting the activity, so we
            // just register a remote animation factory to get a callback to handle this.
            LauncherAppTransitionManagerImpl appTransitionManager =
                    (LauncherAppTransitionManagerImpl) getLauncher().getAppTransitionManager();
            appTransitionManager.setRemoteAnimationOverride(new RecentsAnimationActivityOptions(
                    remoteAnimationListener, () -> {
                        // Once the controller is finished, also reset the remote animation override
                        appTransitionManager.setRemoteAnimationOverride(null);
                    }));
            context.startActivity(intent);
        }

        @Nullable
        @UiThread
        private Launcher getVisibleLaucher() {
        private Launcher getLauncher() {
            LauncherAppState app = LauncherAppState.getInstanceNoCreate();
            if (app == null) {
                return null;
            }
            Launcher launcher = (Launcher) app.getModel().getCallback();
            return (Launcher) app.getModel().getCallback();
        }

        @Nullable
        @UiThread
        private Launcher getVisibleLaucher() {
            Launcher launcher = getLauncher();
            return (launcher != null) && launcher.isStarted() && launcher.hasWindowFocus() ?
                    launcher : null;
        }
@@ -325,12 +353,23 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
        }

        @Override
        public void startRecents(Context context, Intent intent,
                AssistDataReceiver assistDataReceiver,
        public void startRecentsFromSwipe(Intent intent, AssistDataReceiver assistDataReceiver,
                final RecentsAnimationListener remoteAnimationListener) {
            ActivityOptions options =
                    ActivityOptionsCompat.makeRemoteAnimation(new RemoteAnimationAdapterCompat(
                            new FallbackActivityOptions(remoteAnimationListener), 10000, 10000));
            // We can use the normal recents animation for swipe up
            ActivityManagerWrapper.getInstance().startRecentsActivity(
                    intent, assistDataReceiver, remoteAnimationListener, null, null);
        }

        @Override
        public void startRecentsFromButton(Context context, Intent intent,
                RecentsAnimationListener remoteAnimationListener) {
            // We should use the remove animation for the fallback activity recents button case,
            // it works better with PiP. For the fallback activity, we should not have registered
            // the launcher app transition manager, so we should just start the remote animation here.
            ActivityOptions options = ActivityOptionsCompat.makeRemoteAnimation(
                    new RemoteAnimationAdapterCompat(
                            new RecentsAnimationActivityOptions(remoteAnimationListener, null),
                            10000, 10000));
            context.startActivity(intent, options.toBundle());
        }

+1 −1
Original line number Diff line number Diff line
@@ -218,7 +218,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
        handler.initWhenReady();

        TraceHelper.beginSection("RecentsController");
        Runnable startActivity = () -> mActivityControlHelper.startRecents(this, mHomeIntent,
        Runnable startActivity = () -> mActivityControlHelper.startRecentsFromSwipe(mHomeIntent,
                new AssistDataReceiver() {
                    @Override
                    public void onHandleAssistData(Bundle bundle) {
+33 −36
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ import com.android.quickstep.ActivityControlHelper.LauncherActivityControllerHel
import com.android.quickstep.util.SysuiEventLogger;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat;
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
import com.android.systemui.shared.recents.view.RecentsTransition;
@@ -77,7 +78,7 @@ public class OverviewCommandHelper extends InternalStateHandler {
    private static final int RID_CANCEL_CONTROLLER = 1;
    private static final int RID_CANCEL_ZOOM_OUT_ANIMATION = 2;

    private static final long RECENTS_LAUNCH_DURATION = 150;
    private static final long RECENTS_LAUNCH_DURATION = 200;

    private static final String TAG = "OverviewCommandHelper";
    private static final boolean DEBUG_START_FALLBACK_ACTIVITY = false;
@@ -151,12 +152,13 @@ public class OverviewCommandHelper extends InternalStateHandler {
    private void initSwipeHandler(ActivityControlHelper helper, long time,
            Consumer<WindowTransformSwipeHandler> onAnimationInitCallback) {
        final int commandId = mCurrentCommandId;
        RunningTaskInfo taskInfo = ActivityManagerWrapper.getInstance().getRunningTask();
        final RunningTaskInfo runningTask = ActivityManagerWrapper.getInstance().getRunningTask();
        final int runningTaskId = runningTask.id;
        final WindowTransformSwipeHandler handler =
                new WindowTransformSwipeHandler(taskInfo, mContext, time, helper);
                new WindowTransformSwipeHandler(runningTask, mContext, time, helper);

        // Preload the plan
        mRecentsModel.loadTasks(taskInfo.id, null);
        mRecentsModel.loadTasks(runningTaskId, null);
        mWindowTransformSwipeHandler = handler;

        mTempTaskTargetRect.setEmpty();
@@ -172,13 +174,8 @@ public class OverviewCommandHelper extends InternalStateHandler {
        addFinishCommand(commandId, RID_RESET_SWIPE_HANDLER, handler::reset);

        TraceHelper.beginSection(TAG);
        Runnable startActivity = () -> helper.startRecents(mContext, homeIntent,
                new AssistDataReceiver() {
                    @Override
                    public void onHandleAssistData(Bundle bundle) {
                        mRecentsModel.preloadAssistData(taskInfo.id, bundle);
                    }
                },
        Runnable startActivity = () -> helper.startRecentsFromButton(mContext,
                addToIntent(homeIntent),
                new RecentsAnimationListener() {
                    public void onAnimationStart(
                            RecentsAnimationControllerCompat controller,
@@ -190,11 +187,17 @@ public class OverviewCommandHelper extends InternalStateHandler {
                                    minimizedHomeBounds);
                            mTempTaskTargetRect.set(handler.getTargetRect(mWindowSize));

                            ThumbnailData thumbnail = mAM.getTaskThumbnail(runningTaskId,
                                    true /* reducedResolution */);
                            mMainThreadExecutor.execute(() -> {
                                addFinishCommand(commandId,
                                        RID_CANCEL_CONTROLLER, () -> controller.finish(true));
                                if (commandId == mCurrentCommandId) {
                                    onAnimationInitCallback.accept(handler);

                                    // The animation has started, which means the other activity
                                    // should be paused, lets update the thumbnail
                                    handler.switchToScreenshotImmediate(thumbnail);
                                }
                            });
                        } else {
@@ -230,7 +233,7 @@ public class OverviewCommandHelper extends InternalStateHandler {
        });
        handler.onGestureStarted();
        anim.setDuration(RECENTS_LAUNCH_DURATION);
        anim.setInterpolator(Interpolators.AGGRESSIVE_EASE);
        anim.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
        anim.start();
        addFinishCommand(commandId, RID_CANCEL_ZOOM_OUT_ANIMATION, anim::cancel);
    }
@@ -241,6 +244,7 @@ public class OverviewCommandHelper extends InternalStateHandler {
            return;
        }

        ActivityManagerWrapper.getInstance().closeSystemWindows("recentapps");
        long time = SystemClock.elapsedRealtime();
        mMainThreadExecutor.execute(() -> {
            long elapsedTime = time - mLastToggleTime;
@@ -248,40 +252,37 @@ public class OverviewCommandHelper extends InternalStateHandler {

            mCurrentCommandId++;
            mTempTaskTargetRect.round(mTaskTargetRect);
            boolean isQuickTap = elapsedTime < ViewConfiguration.getDoubleTapTimeout();
            int runnableCount = mCurrentCommandFinishRunnables.size();
            if (runnableCount > 0) {
                for (int i = 0; i < runnableCount; i++) {
                    mCurrentCommandFinishRunnables.valueAt(i).run();
                }
                mCurrentCommandFinishRunnables.clear();
                isQuickTap = true;
            }

            // TODO: We need to fix this case with PIP, when an activity first enters PIP, it shows
            //       the menu activity which takes window focus, prevening the right condition from
            //       being run below
            ActivityControlHelper helper = getActivityControlHelper();
            RecentsView recents = helper.getVisibleRecentsView();
            if (recents != null) {
                int childCount = recents.getChildCount();
                if (childCount != 0) {
                    ((TaskView) recents.getChildAt(childCount >= 2 ? 1 : 0)).launchTask(true);
                }

                // There are not enough tasks. Skip
                // Launch the next task
                recents.showNextTask();
            } else {
                if (elapsedTime < ViewConfiguration.getDoubleTapTimeout()) {
                    // The user tried to launch back into overview too quickly, either after
                    // launching an app, or before overview has actually shown, just ignore for now
                    return;
                }

            if (isQuickTap) {
                // Focus last task. Start is on background thread so that all ActivityManager calls
                // are serialized
                BackgroundExecutor.get().submit(this::startLastTask);
                return;
            }
                // Start overview
                if (helper.switchToRecentsIfVisible()) {
                    SysuiEventLogger.writeDummyRecentsTransition(0);
                return;
            }

                    // Do nothing
                } else {
                    initSwipeHandler(helper, time, this::startZoomOutAnim);
                }
            }
        });
    }

@@ -362,10 +363,6 @@ public class OverviewCommandHelper extends InternalStateHandler {
        return false;
    }

    public boolean isUsingFallbackActivity() {
        return DEBUG_START_FALLBACK_ACTIVITY;
    }

    public ActivityControlHelper getActivityControlHelper() {
        if (DEBUG_START_FALLBACK_ACTIVITY) {
            return new FallbackActivityControllerHelper();
+20 −11
Original line number Diff line number Diff line
@@ -24,24 +24,33 @@ import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.TransactionCompat;
import com.android.systemui.shared.system.WindowManagerWrapper;
import java.util.function.Consumer;

/**
 * Temporary class to create activity options to emulate recents transition for fallback activtiy.
 * Class to create activity options to emulate recents transition.
 */
public class FallbackActivityOptions implements RemoteAnimationRunnerCompat {
public class RecentsAnimationActivityOptions implements RemoteAnimationRunnerCompat {

    private final RecentsAnimationListener mListener;
    private final Runnable mFinishCallback;

    public FallbackActivityOptions(RecentsAnimationListener listener) {
    public RecentsAnimationActivityOptions(RecentsAnimationListener listener,
            Runnable finishCallback) {
        mListener = listener;
        mFinishCallback = finishCallback;
    }

    @Override
    public void onAnimationStart(RemoteAnimationTargetCompat[] targetCompats,
            Runnable runnable) {
        showOpeningTarget(targetCompats);
        DummyRecentsAnimationControllerCompat dummyRecentsAnim =
                new DummyRecentsAnimationControllerCompat(runnable);
        RemoteRecentsAnimationControllerCompat dummyRecentsAnim =
                new RemoteRecentsAnimationControllerCompat(() -> {
                    runnable.run();
                    if (mFinishCallback != null) {
                        mFinishCallback.run();
                    }
                });

        Rect insets = new Rect();
        WindowManagerWrapper.getInstance().getStableInsets(insets);
@@ -54,23 +63,22 @@ public class FallbackActivityOptions implements RemoteAnimationRunnerCompat {
    }

    private void showOpeningTarget(RemoteAnimationTargetCompat[] targetCompats) {
        for (RemoteAnimationTargetCompat target : targetCompats) {
        TransactionCompat t = new TransactionCompat();
        for (RemoteAnimationTargetCompat target : targetCompats) {
            int layer = target.mode == RemoteAnimationTargetCompat.MODE_CLOSING
                    ? Integer.MAX_VALUE
                    : target.prefixOrderIndex;
            t.setLayer(target.leash, layer);
            t.show(target.leash);
            t.apply();
        }
        t.apply();
    }

    private static class DummyRecentsAnimationControllerCompat
            extends RecentsAnimationControllerCompat {
    private class RemoteRecentsAnimationControllerCompat extends RecentsAnimationControllerCompat {

        final Runnable mFinishCallback;

        public DummyRecentsAnimationControllerCompat(Runnable finishCallback) {
        public RemoteRecentsAnimationControllerCompat(Runnable finishCallback) {
            mFinishCallback = finishCallback;
        }

@@ -87,7 +95,8 @@ public class FallbackActivityOptions implements RemoteAnimationRunnerCompat {

        @Override
        public void finish(boolean toHome) {
            if (toHome) {
            // This should never be called with toHome == false
            if (mFinishCallback != null) {
                mFinishCallback.run();
            }
        }
Loading