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

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

9/ Clean up swipe shared state



- Add TaskAnimationManager which keeps track of the animation state whose
  lifecycle can be longer than the gesture.  Move some of the logic related
  to cleaning up old animations into this class (called when the state is
  shared across gestures).
- Instead of calling into the shared state directly via UIFactory, add
  callback to cleanup the animation and shared state from Launcher

Bug: 141886704

Change-Id: Ib6140b37162f7460a20fa1046cfd4f4068e4a1c6
Signed-off-by: default avatarWinson Chung <winsonc@google.com>
parent 9196cb11
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -88,6 +88,4 @@ public abstract class RecentsUiFactory {
    public static RotationMode getRotationMode(DeviceProfile dp) {
        return RotationMode.NORMAL;
    }

    public static void clearSwipeSharedState(Launcher launcher, boolean finishAnimation) { }
}
+0 −13
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@ package com.android.launcher3.uioverrides;

import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;

import android.content.Context;
@@ -45,7 +44,6 @@ import com.android.launcher3.util.UiThreadHelper;
import com.android.launcher3.util.UiThreadHelper.AsyncCommand;
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.TouchInteractionService;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.views.RecentsView;

@@ -188,17 +186,6 @@ public abstract class RecentsUiFactory {
        return new RecentsViewStateController(launcher);
    }

    /** Clears the swipe shared state for the current swipe gesture. */
    public static void clearSwipeSharedState(Launcher launcher, boolean finishAnimation) {
        if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
            launcher.<RecentsView>getOverviewPanel().switchToScreenshot(
                    () -> TouchInteractionService.getSwipeSharedState().clearAllState(
                            finishAnimation));
        } else {
            TouchInteractionService.getSwipeSharedState().clearAllState(finishAnimation);
        }
    }

    /**
     * Recents logic that triggers when launcher state changes or launcher activity stops/resumes.
     *
+10 −11
Original line number Diff line number Diff line
@@ -493,22 +493,21 @@ public final class LauncherActivityInterface implements BaseActivityInterface<La
    }

    @Override
    public void switchToScreenshot(ThumbnailData thumbnailData, Runnable runnable) {
    public void switchRunningTaskViewToScreenshot(ThumbnailData thumbnailData,
            Runnable onFinishRunnable) {
        Launcher launcher = getCreatedActivity();
        RecentsView recentsView = launcher.getOverviewPanel();
        if (recentsView == null) {
            if (runnable != null) {
                runnable.run();
            if (onFinishRunnable != null) {
                onFinishRunnable.run();
            }
            return;
        }
        TaskView taskView = recentsView.getRunningTaskView();
        if (taskView != null) {
            taskView.setShowScreenshot(true);
            taskView.getThumbnail().setThumbnail(taskView.getTask(), thumbnailData);
            ViewUtils.postDraw(taskView, runnable);
        } else if (runnable != null) {
            runnable.run();
        recentsView.switchToScreenshot(thumbnailData, onFinishRunnable);
    }

    @Override
    public void setOnDeferredActivityLaunchCallback(Runnable r) {
        getCreatedActivity().setOnDeferredActivityLaunchCallback(r);
    }
}
 No newline at end of file
+2 −126
Original line number Diff line number Diff line
@@ -15,32 +15,12 @@
 */
package com.android.quickstep;

import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;

import android.util.Log;

import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.Preconditions;
import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener;

import com.android.systemui.shared.recents.model.ThumbnailData;

import java.io.PrintWriter;

/**
 * Utility class used to store state information shared across multiple transitions.
 */
public class SwipeSharedState implements RecentsAnimationListener {

    private OverviewComponentObserver mOverviewComponentObserver;

    private RecentsAnimationCallbacks mRecentsAnimationListener;
    private RecentsAnimationController mLastRecentsAnimationController;
    private RecentsAnimationTargets mLastAnimationTarget;

    private boolean mLastAnimationCancelled = false;
    private boolean mLastAnimationRunning = false;
public class SwipeSharedState {

    public boolean canGestureBeContinued;
    public boolean goingToLauncher;
@@ -48,106 +28,6 @@ public class SwipeSharedState implements RecentsAnimationListener {
    public int nextRunningTaskId = -1;
    private int mLogId;

    public void setOverviewComponentObserver(OverviewComponentObserver observer) {
        mOverviewComponentObserver = observer;
    }

    @Override
    public final void onRecentsAnimationStart(RecentsAnimationController controller,
            RecentsAnimationTargets targets) {
        mLastRecentsAnimationController = controller;
        mLastAnimationTarget = targets;

        mLastAnimationCancelled = false;
        mLastAnimationRunning = true;
    }

    @Override
    public final void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
        if (thumbnailData != null) {
            mOverviewComponentObserver.getActivityInterface().switchToScreenshot(thumbnailData,
                    () -> {
                        mLastRecentsAnimationController.cleanupScreenshot();
                        clearAnimationState();
                    });
        } else {
            clearAnimationState();
        }
    }

    @Override
    public final void onRecentsAnimationFinished(RecentsAnimationController controller) {
        if (mLastRecentsAnimationController == controller) {
            mLastAnimationRunning = false;
        }
    }

    private void clearAnimationTarget() {
        if (mLastAnimationTarget != null) {
            mLastAnimationTarget.release();
            mLastAnimationTarget = null;
        }
    }

    private void clearAnimationState() {
        clearAnimationTarget();

        mLastAnimationCancelled = true;
        mLastAnimationRunning = false;
    }

    private void clearListenerState(boolean finishAnimation) {
        if (mRecentsAnimationListener != null) {
            mRecentsAnimationListener.removeListener(this);
            mRecentsAnimationListener.notifyAnimationCanceled();
            if (mLastAnimationRunning && mLastRecentsAnimationController != null) {
                Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(),
                        finishAnimation
                                ? mLastRecentsAnimationController::finishAnimationToHome
                                : mLastRecentsAnimationController::finishAnimationToApp);
                mLastRecentsAnimationController = null;
                mLastAnimationTarget = null;
            }
        }
        mRecentsAnimationListener = null;
        clearAnimationTarget();
        mLastAnimationCancelled = false;
        mLastAnimationRunning = false;
    }

    public RecentsAnimationCallbacks newRecentsAnimationCallbacks() {
        Preconditions.assertUIThread();

        if (mLastAnimationRunning) {
            String msg = "New animation started before completing old animation";
            if (FeatureFlags.IS_DOGFOOD_BUILD) {
                throw new IllegalArgumentException(msg);
            } else {
                Log.e("SwipeSharedState", msg, new Exception());
            }
        }

        clearListenerState(false /* finishAnimation */);
        boolean shouldMinimiseSplitScreen = mOverviewComponentObserver == null ? false
                : mOverviewComponentObserver.getActivityInterface().shouldMinimizeSplitScreen();
        mRecentsAnimationListener = new RecentsAnimationCallbacks(shouldMinimiseSplitScreen);
        mRecentsAnimationListener.addListener(this);
        return mRecentsAnimationListener;
    }

    public RecentsAnimationCallbacks getActiveListener() {
        return mRecentsAnimationListener;
    }

    public void applyActiveRecentsAnimationState(RecentsAnimationListener listener) {
        if (mLastRecentsAnimationController != null) {
            listener.onRecentsAnimationStart(mLastRecentsAnimationController,
                    mLastAnimationTarget);
        } else if (mLastAnimationCancelled) {
            listener.onRecentsAnimationCanceled(null);
        }
    }

    /**
     * Called when a recents animation has finished, but was interrupted before the next task was
     * launched. The given {@param runningTaskId} should be used as the running task for the
@@ -156,11 +36,9 @@ public class SwipeSharedState implements RecentsAnimationListener {
    public void setRecentsAnimationFinishInterrupted(int runningTaskId) {
        recentsAnimationFinishInterrupted = true;
        nextRunningTaskId = runningTaskId;
        mLastAnimationTarget = mLastAnimationTarget.cloneWithoutTargets();
    }

    public void clearAllState(boolean finishAnimation) {
        clearListenerState(finishAnimation);
    public void clearAllState() {
        canGestureBeContinued = false;
        recentsAnimationFinishInterrupted = false;
        nextRunningTaskId = -1;
@@ -172,8 +50,6 @@ public class SwipeSharedState implements RecentsAnimationListener {
        pw.println(prefix + "canGestureBeContinued=" + canGestureBeContinued);
        pw.println(prefix + "recentsAnimationFinishInterrupted=" + recentsAnimationFinishInterrupted);
        pw.println(prefix + "nextRunningTaskId=" + nextRunningTaskId);
        pw.println(prefix + "lastAnimationCancelled=" + mLastAnimationCancelled);
        pw.println(prefix + "lastAnimationRunning=" + mLastAnimationRunning);
        pw.println(prefix + "logTraceId=" + mLogId);
    }

+30 −19
Original line number Diff line number Diff line
@@ -250,10 +250,7 @@ public class TouchInteractionService extends Service implements
        return sSwipeSharedState;
    }

    private final InputConsumer mResetGestureInputConsumer =
            new ResetGestureInputConsumer(sSwipeSharedState);

    private final BaseSwipeUpHandler.Factory mWindowTreansformFactory =
    private final BaseSwipeUpHandler.Factory mWindowTransformFactory =
            this::createWindowTransformSwipeHandler;
    private final BaseSwipeUpHandler.Factory mFallbackNoButtonFactory =
            this::createFallbackNoButtonSwipeHandler;
@@ -264,10 +261,12 @@ public class TouchInteractionService extends Service implements
    private OverviewComponentObserver mOverviewComponentObserver;
    private InputConsumerController mInputConsumer;
    private RecentsAnimationDeviceState mDeviceState;
    private TaskAnimationManager mTaskAnimationManager;

    private InputConsumer mUncheckedConsumer = InputConsumer.NO_OP;
    private InputConsumer mConsumer = InputConsumer.NO_OP;
    private Choreographer mMainChoreographer;
    private InputConsumer mResetGestureInputConsumer;

    private InputMonitorCompat mInputMonitorCompat;
    private InputEventReceiver mInputEventReceiver;
@@ -338,13 +337,13 @@ public class TouchInteractionService extends Service implements

    @UiThread
    public void onUserUnlocked() {
        mTaskAnimationManager = new TaskAnimationManager();
        mRecentsModel = RecentsModel.INSTANCE.get(this);
        mOverviewComponentObserver = new OverviewComponentObserver(this, mDeviceState);
        mOverviewCommandHelper = new OverviewCommandHelper(this, mDeviceState,
                mOverviewComponentObserver);
        mResetGestureInputConsumer = new ResetGestureInputConsumer(mTaskAnimationManager);
        mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();

        sSwipeSharedState.setOverviewComponentObserver(mOverviewComponentObserver);
        mInputConsumer.registerInputConsumer();
        onSystemUiFlagsChanged();
        onAssistantVisibilityChanged();
@@ -356,6 +355,18 @@ public class TouchInteractionService extends Service implements
        resetHomeBounceSeenOnQuickstepEnabledFirstTime();
    }

    private void onDeferredActivityLaunch() {
        if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
            mOverviewComponentObserver.getActivityInterface().switchRunningTaskViewToScreenshot(
                    null, () -> {
                        mTaskAnimationManager.finishRunningRecentsAnimation(true /* toHome */);
                        sSwipeSharedState.clearAllState();
                    });
        } else {
            mTaskAnimationManager.finishRunningRecentsAnimation(true /* toHome */);
        }
    }

    private void resetHomeBounceSeenOnQuickstepEnabledFirstTime() {
        if (!mDeviceState.isUserUnlocked() || !mMode.hasGestures) {
            // Skip if not yet unlocked (can't read user shared prefs) or if the current navigation
@@ -509,7 +520,8 @@ public class TouchInteractionService extends Service implements
        RunningTaskInfo runningTaskInfo = TraceHelper.whitelistIpcs("getRunningTask.0",
                () -> mAM.getRunningTask(0));
        if (!useSharedState) {
            sSwipeSharedState.clearAllState(false /* finishAnimation */);
            mTaskAnimationManager.finishRunningRecentsAnimation(false /* toHome */);
            sSwipeSharedState.clearAllState();
        }
        if (mDeviceState.isKeyguardShowingOccluded()) {
            // This handles apps showing over the lockscreen (e.g. camera)
@@ -572,20 +584,20 @@ public class TouchInteractionService extends Service implements
        } else {
            shouldDefer = gestureState.getActivityInterface().deferStartingActivity(mDeviceState,
                    event);
            factory = mWindowTreansformFactory;
            factory = mWindowTransformFactory;
        }

        final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event);
        return new OtherActivityInputConsumer(this, mDeviceState, gestureState, runningTaskInfo,
                shouldDefer, this::onConsumerInactive, sSwipeSharedState, mInputMonitorCompat,
                disableHorizontalSwipe, factory, mLogId);
        return new OtherActivityInputConsumer(this, mDeviceState, mTaskAnimationManager,
                gestureState, runningTaskInfo, shouldDefer, this::onConsumerInactive,
                sSwipeSharedState, mInputMonitorCompat, disableHorizontalSwipe, factory, mLogId);
    }

    private InputConsumer createDeviceLockedInputConsumer(GestureState gestureState,
            RunningTaskInfo taskInfo) {
        if (mMode == Mode.NO_BUTTON && taskInfo != null) {
            return new DeviceLockedInputConsumer(this, mDeviceState, gestureState,
                    sSwipeSharedState, mInputMonitorCompat, taskInfo.taskId, mLogId);
            return new DeviceLockedInputConsumer(this, mDeviceState, mTaskAnimationManager,
                    gestureState, sSwipeSharedState, mInputMonitorCompat, taskInfo.taskId, mLogId);
        } else {
            return mResetGestureInputConsumer;
        }
@@ -647,9 +659,8 @@ public class TouchInteractionService extends Service implements
            return;
        }

        // Pass null animation handler to indicate this start is preload.
        startRecentsActivityAsync(mOverviewComponentObserver.getOverviewIntentIgnoreSysUiState(),
                null);
        mTaskAnimationManager.preloadRecentsAnimation(
                mOverviewComponentObserver.getOverviewIntentIgnoreSysUiState());
    }

    @Override
@@ -725,9 +736,9 @@ public class TouchInteractionService extends Service implements
    private BaseSwipeUpHandler createWindowTransformSwipeHandler(GestureState gestureState,
            RunningTaskInfo runningTask, long touchTimeMs, boolean continuingLastGesture,
            boolean isLikelyToStartNewTask) {
        return  new WindowTransformSwipeHandler(this, mDeviceState, gestureState, runningTask,
                touchTimeMs, mOverviewComponentObserver, continuingLastGesture, mInputConsumer,
                mRecentsModel);
        return  new WindowTransformSwipeHandler(this, mDeviceState, mTaskAnimationManager,
                gestureState, runningTask, touchTimeMs, mOverviewComponentObserver,
                continuingLastGesture, mInputConsumer, mRecentsModel);
    }

    private BaseSwipeUpHandler createFallbackNoButtonSwipeHandler(GestureState gestureState,
Loading