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

Commit 2c5ed10f authored by Tracy Zhou's avatar Tracy Zhou Committed by Android (Google) Code Review
Browse files

Merge "[Live Tile] Support launching another task (other than the current...

Merge "[Live Tile] Support launching another task (other than the current running task) in Overview" into ub-launcher3-master
parents b2b65a1e 8ed9707c
Loading
Loading
Loading
Loading
+5 −56
Original line number Diff line number Diff line
@@ -16,14 +16,10 @@

package com.android.launcher3;

import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.quickstep.TaskViewUtils.createRecentsWindowAnimator;
import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
@@ -32,11 +28,8 @@ import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PendingAnimation;
import com.android.quickstep.TaskViewUtils;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;

/**
@@ -53,60 +46,16 @@ public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransiti
    protected boolean isLaunchingFromRecents(@NonNull View v,
            @Nullable RemoteAnimationTargetCompat[] targets) {
        return mLauncher.getStateManager().getState().overviewUi
                && findTaskViewToLaunch(mLauncher, v, targets) != null;
                && findTaskViewToLaunch(mLauncher.getOverviewPanel(), v, targets) != null;
    }

    @Override
    protected void composeRecentsLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v,
            @NonNull RemoteAnimationTargetCompat[] appTargets,
            @NonNull RemoteAnimationTargetCompat[] wallpaperTargets, boolean launcherClosing) {
        RecentsView recentsView = mLauncher.getOverviewPanel();
        boolean skipLauncherChanges = !launcherClosing;

        TaskView taskView = findTaskViewToLaunch(mLauncher, v, appTargets);
        PendingAnimation pa = new PendingAnimation(RECENTS_LAUNCH_DURATION);
        createRecentsWindowAnimator(taskView, skipLauncherChanges, appTargets, wallpaperTargets,
                mLauncher.getDepthController(), pa);
        anim.play(pa.buildAnim());

        Animator childStateAnimation = null;
        // Found a visible recents task that matches the opening app, lets launch the app from there
        Animator launcherAnim;
        final AnimatorListenerAdapter windowAnimEndListener;
        if (launcherClosing) {
            launcherAnim = recentsView.createAdjacentPageAnimForTaskLaunch(taskView);
            launcherAnim.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR);
            launcherAnim.setDuration(RECENTS_LAUNCH_DURATION);

            // Make sure recents gets fixed up by resetting task alphas and scales, etc.
            windowAnimEndListener = new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    mLauncher.getStateManager().moveToRestState();
                    mLauncher.getStateManager().reapplyState();
                }
            };
        } else {
            AnimatorPlaybackController controller =
                    mLauncher.getStateManager().createAnimationToNewWorkspace(NORMAL,
                            RECENTS_LAUNCH_DURATION);
            controller.dispatchOnStart();
            childStateAnimation = controller.getTarget();
            launcherAnim = controller.getAnimationPlayer().setDuration(RECENTS_LAUNCH_DURATION);
            windowAnimEndListener = new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    mLauncher.getStateManager().goToState(NORMAL, false);
                }
            };
        }
        anim.play(launcherAnim);

        // Set the current animation first, before adding windowAnimEndListener. Setting current
        // animation adds some listeners which need to be called before windowAnimEndListener
        // (the ordering of listeners matter in this case).
        mLauncher.getStateManager().setCurrentAnimation(anim, childStateAnimation);
        anim.addListener(windowAnimEndListener);
        TaskViewUtils.composeRecentsLaunchAnimator(anim, v, appTargets, wallpaperTargets,
                launcherClosing, mLauncher.getStateManager(), mLauncher.getOverviewPanel(),
                mLauncher.getDepthController());
    }

    @Override
+80 −34
Original line number Diff line number Diff line
@@ -41,10 +41,14 @@ import static com.android.quickstep.GestureState.STATE_END_TARGET_ANIMATION_FINI
import static com.android.quickstep.GestureState.STATE_END_TARGET_SET;
import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHED;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.TaskUtils.taskIsATargetWithMode;
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.app.ActivityManager;
@@ -104,6 +108,7 @@ import com.android.systemui.shared.system.TaskInfoCompat;
import com.android.systemui.shared.system.TaskStackChangeListener;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.function.Consumer;

/**
@@ -1376,17 +1381,64 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<?>, Q extends
    private void setupLauncherUiAfterSwipeUpToRecentsAnimation() {
        endLauncherTransitionController();
        mActivityInterface.onSwipeUpToRecentsComplete();
        if (mRecentsAnimationController != null) {
            mRecentsAnimationController.setDeferCancelUntilNextTransition(true /* defer */,
                    true /* screenshot */);
        }
        mRecentsView.onSwipeUpAnimationSuccess();
        if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
            mTaskAnimationManager.setLaunchOtherTaskInLiveTileModeHandler(
                    this::launchOtherTaskInLiveTileMode);
        }

        SystemUiProxy.INSTANCE.get(mContext).onOverviewShown(false, TAG);
        doLogGesture(RECENTS, mRecentsView.getCurrentPageTaskView());
        reset();
    }

    private void launchOtherTaskInLiveTileMode(RemoteAnimationTargetCompat appearedTaskTarget) {
        TaskView taskView = mRecentsView.getTaskView(appearedTaskTarget.taskId);
        if (taskView == null) {
            return;
        }

        RemoteAnimationTargetCompat[] apps = Arrays.copyOf(
                mRecentsAnimationTargets.apps,
                mRecentsAnimationTargets.apps.length + 1);
        apps[apps.length - 1] = appearedTaskTarget;
        boolean launcherClosing =
                taskIsATargetWithMode(apps, mActivity.getTaskId(), MODE_CLOSING);

        AnimatorSet anim = new AnimatorSet();
        TaskViewUtils.composeRecentsLaunchAnimator(
                anim, taskView, apps,
                mRecentsAnimationTargets.wallpapers, launcherClosing,
                mActivity.getStateManager(), mRecentsView,
                mActivityInterface.getDepthController());
        anim.addListener(new AnimatorListenerAdapter(){

            @Override
            public void onAnimationEnd(Animator animator) {
                cleanUp(false);
            }

            @Override
            public void onAnimationCancel(Animator animator) {
                cleanUp(true);
            }

            private void cleanUp(boolean canceled) {
                if (mRecentsAnimationController != null) {
                    mRecentsAnimationController.finish(false /* toRecents */,
                            null /* onFinishComplete */);
                    if (canceled) {
                        mRecentsAnimationController = null;
                    } else {
                        mActivityInterface.onLaunchTaskSuccess();
                    }
                    ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", false);
                }
            }
        });
        anim.start();
    }

    private void addLiveTileOverlay() {
        if (LiveTileOverlay.INSTANCE.attach(mActivity.getRootView().getOverlay())) {
            mRecentsView.setLiveTileOverlayAttached(true);
@@ -1444,11 +1496,6 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<?>, Q extends

    protected void startNewTask(Consumer<Boolean> resultCallback) {
        // Launch the task user scrolled to (mRecentsView.getNextPage()).
        if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
            // We finish recents animation inside launchTask() when live tile is enabled.
            mRecentsView.getNextPageTaskView().launchTask(false /* animate */,
                    true /* freezeTaskList */);
        } else {
        if (!mCanceled) {
            TaskView nextTask = mRecentsView.getNextPageTaskView();
            if (nextTask != null) {
@@ -1477,7 +1524,6 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<?>, Q extends
        }
        mCanceled = false;
    }
    }

    /**
     * Runs the given {@param action} if the recents animation has already started, or queues it to
+0 −18
Original line number Diff line number Diff line
@@ -89,24 +89,6 @@ public class RecentsAnimationController {
        }
    }

    /**
     * Notifies the controller that we want to defer cancel until the next app transition starts.
     * If {@param screenshot} is set, then we will receive a screenshot on the next
     * {@link RecentsAnimationCallbacks#onAnimationCanceled(ThumbnailData)} and we must also call
     * {@link #cleanupScreenshot()} when that screenshot is no longer used.
     */
    public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) {
        mController.setDeferCancelUntilNextTransition(defer, screenshot);
    }

    /**
     * Cleans up the screenshot previously returned from
     * {@link RecentsAnimationCallbacks#onAnimationCanceled(ThumbnailData)}.
     */
    public void cleanupScreenshot() {
        UI_HELPER_EXECUTOR.execute(() -> mController.cleanupScreenshot());
    }

    /**
     * Remove task remote animation target from
     * {@link RecentsAnimationCallbacks#onTaskAppeared(RemoteAnimationTargetCompat)}}.
+23 −15
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ package com.android.quickstep;

import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_INITIALIZED;
import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_STARTED;

@@ -31,6 +32,8 @@ import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;

import java.util.function.Consumer;

public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener {

    private RecentsAnimationController mController;
@@ -39,6 +42,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
    // Temporary until we can hook into gesture state events
    private GestureState mLastGestureState;
    private RemoteAnimationTargetCompat mLastAppearedTaskTarget;
    private Consumer<RemoteAnimationTargetCompat> mLaunchOtherTaskHandler;

    /**
     * Preloads the recents animation.
@@ -88,22 +92,21 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn

            @Override
            public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
                if (thumbnailData != null) {
                    // If a screenshot is provided, switch to the screenshot before cleaning up
                    activityInterface.switchRunningTaskViewToScreenshot(thumbnailData,
                            () -> cleanUpRecentsAnimation(thumbnailData));
                } else {
                    cleanUpRecentsAnimation(null /* canceledThumbnail */);
                }
                cleanUpRecentsAnimation();
            }

            @Override
            public void onRecentsAnimationFinished(RecentsAnimationController controller) {
                cleanUpRecentsAnimation(null /* canceledThumbnail */);
                cleanUpRecentsAnimation();
            }

            @Override
            public void onTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
                if (mLaunchOtherTaskHandler != null
                        && mLastGestureState.getEndTarget() == RECENTS) {
                    mLaunchOtherTaskHandler.accept(appearedTaskTarget);
                    return;
                }
                if (mController != null) {
                    if (mLastAppearedTaskTarget == null
                            || appearedTaskTarget.taskId != mLastAppearedTaskTarget.taskId) {
@@ -137,6 +140,15 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
        return mCallbacks;
    }

    /**
     * The passed-in handler is used to render side task launch animation in recents in live tile
     * mode.
     */
    public void setLaunchOtherTaskInLiveTileModeHandler(
            Consumer<RemoteAnimationTargetCompat> handler) {
        mLaunchOtherTaskHandler = handler;
    }

    /**
     * Finishes the running recents animation.
     */
@@ -146,7 +158,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
            Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), toHome
                    ? mController::finishAnimationToHome
                    : mController::finishAnimationToApp);
            cleanUpRecentsAnimation(null /* canceledThumbnail */);
            cleanUpRecentsAnimation();
        }
    }

@@ -173,12 +185,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
    /**
     * Cleans up the recents animation entirely.
     */
    private void cleanUpRecentsAnimation(ThumbnailData canceledThumbnail) {
        // Clean up the screenshot if necessary
        if (mController != null && canceledThumbnail != null) {
            mController.cleanupScreenshot();
        }

    private void cleanUpRecentsAnimation() {
        // Release all the target leashes
        if (mTargets != null) {
            mTargets.release();
@@ -194,6 +201,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
        mTargets = null;
        mLastGestureState = null;
        mLastAppearedTaskTarget = null;
        mLaunchOtherTaskHandler = null;
    }

    public void dump() {
+66 −4
Original line number Diff line number Diff line
@@ -17,15 +17,20 @@ package com.android.quickstep;

import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.QuickstepAppTransitionManagerImpl.RECENTS_LAUNCH_DURATION;
import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
import static com.android.launcher3.anim.Interpolators.clampToProgress;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.annotation.TargetApi;
import android.content.ComponentName;
import android.content.Context;
@@ -35,12 +40,16 @@ import android.graphics.RectF;
import android.os.Build;
import android.view.View;

import androidx.annotation.NonNull;

import com.android.launcher3.BaseActivity;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.util.DisplayController;
import com.android.quickstep.util.SurfaceTransactionApplier;
import com.android.quickstep.util.TaskViewSimulator;
@@ -67,8 +76,7 @@ public final class TaskViewUtils {
     * opening remote target (which we don't get until onAnimationStart) will resolve to a TaskView.
     */
    public static TaskView findTaskViewToLaunch(
            BaseDraggingActivity activity, View v, RemoteAnimationTargetCompat[] targets) {
        RecentsView recentsView = activity.getOverviewPanel();
            RecentsView recentsView, View v, RemoteAnimationTargetCompat[] targets) {
        if (v instanceof TaskView) {
            TaskView taskView = (TaskView) v;
            return recentsView.isTaskViewVisible(taskView) ? taskView : null;
@@ -130,7 +138,8 @@ public final class TaskViewUtils {

        SurfaceTransactionApplier applier = new SurfaceTransactionApplier(v);
        final RemoteAnimationTargets targets =
                new RemoteAnimationTargets(appTargets, wallpaperTargets, MODE_OPENING);
                new RemoteAnimationTargets(appTargets, wallpaperTargets,
                        ENABLE_QUICKSTEP_LIVE_TILE.get() ? MODE_CLOSING : MODE_OPENING);
        targets.addReleaseCheck(applier);

        TransformParams params = new TransformParams()
@@ -235,4 +244,57 @@ public final class TaskViewUtils {
                    TOUCH_RESPONSE_INTERPOLATOR);
        }
    }

    public static void composeRecentsLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v,
            @NonNull RemoteAnimationTargetCompat[] appTargets,
            @NonNull RemoteAnimationTargetCompat[] wallpaperTargets, boolean launcherClosing,
            @NonNull StateManager stateManager, @NonNull RecentsView recentsView,
            @NonNull DepthController depthController) {
        boolean skipLauncherChanges = !launcherClosing;

        TaskView taskView = findTaskViewToLaunch(recentsView, v, appTargets);
        PendingAnimation pa = new PendingAnimation(RECENTS_LAUNCH_DURATION);
        createRecentsWindowAnimator(taskView, skipLauncherChanges, appTargets, wallpaperTargets,
                depthController, pa);
        anim.play(pa.buildAnim());

        Animator childStateAnimation = null;
        // Found a visible recents task that matches the opening app, lets launch the app from there
        Animator launcherAnim;
        final AnimatorListenerAdapter windowAnimEndListener;
        if (launcherClosing) {
            launcherAnim = recentsView.createAdjacentPageAnimForTaskLaunch(taskView);
            launcherAnim.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR);
            launcherAnim.setDuration(RECENTS_LAUNCH_DURATION);

            // Make sure recents gets fixed up by resetting task alphas and scales, etc.
            windowAnimEndListener = new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    stateManager.moveToRestState();
                    stateManager.reapplyState();
                }
            };
        } else {
            AnimatorPlaybackController controller =
                    stateManager.createAnimationToNewWorkspace(NORMAL,
                            RECENTS_LAUNCH_DURATION);
            controller.dispatchOnStart();
            childStateAnimation = controller.getTarget();
            launcherAnim = controller.getAnimationPlayer().setDuration(RECENTS_LAUNCH_DURATION);
            windowAnimEndListener = new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    stateManager.goToState(NORMAL, false);
                }
            };
        }
        anim.play(launcherAnim);

        // Set the current animation first, before adding windowAnimEndListener. Setting current
        // animation adds some listeners which need to be called before windowAnimEndListener
        // (the ordering of listeners matter in this case).
        stateManager.setCurrentAnimation(anim, childStateAnimation);
        anim.addListener(windowAnimEndListener);
    }
}