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

Commit c50aa8bf authored by randypfohl's avatar randypfohl
Browse files

Limited recents in window introductory cl

Test: Built and tested locally

Flag: com.android.launcher3.enable_fallback_overview_in_window

Bug:292269949

Change-Id: I5352ba0b6c5bc196fbd1322d435a7e27e884f7b5
parent f29dc7c5
Loading
Loading
Loading
Loading
+19 −10
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
import static com.android.quickstep.BaseContainerInterface.AnimationFactory;
import static com.android.quickstep.GestureState.GestureEndTarget.HOME;
import static com.android.quickstep.GestureState.GestureEndTarget.LAST_TASK;
import static com.android.quickstep.GestureState.GestureEndTarget.NEW_TASK;
@@ -103,6 +104,7 @@ import com.android.internal.jank.Cuj;
import com.android.internal.util.LatencyTracker;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Flags;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
@@ -112,6 +114,7 @@ import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.StatsLogManager.StatsLogger;
import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.statemanager.StatefulContainer;
import com.android.launcher3.taskbar.TaskbarThresholdUtils;
import com.android.launcher3.taskbar.TaskbarUIController;
import com.android.launcher3.uioverrides.QuickstepLauncher;
@@ -120,9 +123,9 @@ import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.TraceHelper;
import com.android.launcher3.util.VibratorWrapper;
import com.android.launcher3.util.WindowBounds;
import com.android.quickstep.BaseActivityInterface.AnimationFactory;
import com.android.quickstep.GestureState.GestureEndTarget;
import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle;
import com.android.quickstep.fallback.window.RecentsWindowManager;
import com.android.quickstep.util.ActiveGestureErrorDetector;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.ActivityInitListener;
@@ -156,8 +159,6 @@ import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.shared.startingsurface.SplashScreenExitAnimationUtils;

import kotlin.Unit;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -167,15 +168,16 @@ import java.util.Optional;
import java.util.OptionalInt;
import java.util.function.Consumer;

import kotlin.Unit;

/**
 * Handles the navigation gestures when Launcher is the default home activity.
 */
public abstract class AbsSwipeUpHandler<
        RECENTS_CONTAINER extends Context & RecentsViewContainer,
        RECENTS_VIEW extends RecentsView<RECENTS_CONTAINER, STATE>,
        STATE extends BaseState<STATE>>
        extends SwipeUpAnimationLogic
        implements OnApplyWindowInsetsListener, RecentsAnimationCallbacks.RecentsAnimationListener {
        RECENTS_CONTAINER extends Context & RecentsViewContainer & StatefulContainer<STATE>,
        RECENTS_VIEW extends RecentsView<RECENTS_CONTAINER, STATE>, STATE extends BaseState<STATE>>
        extends SwipeUpAnimationLogic implements OnApplyWindowInsetsListener,
        RecentsAnimationCallbacks.RecentsAnimationListener {
    private static final String TAG = "AbsSwipeUpHandler";

    private static final ArrayList<String> STATE_NAMES = new ArrayList<>();
@@ -356,6 +358,10 @@ public abstract class AbsSwipeUpHandler<
            InputConsumerController inputConsumer) {
        super(context, deviceState, gestureState);
        mContainerInterface = gestureState.getContainerInterface();
        if (Flags.enableFallbackOverviewInWindow()) {
            RecentsWindowManager.Companion.getInstanceOrNull()
                    .registerInitListener(this::onActivityInit);
        }
        mActivityInitListener =
                mContainerInterface.createActivityInitListener(this::onActivityInit);
        mInputConsumerProxy =
@@ -819,7 +825,7 @@ public abstract class AbsSwipeUpHandler<
            return;
        }
        initTransitionEndpoints(mContainer.getDeviceProfile());
        mAnimationFactory.createActivityInterface(mTransitionDragLength);
        mAnimationFactory.createContainerInterface(mTransitionDragLength);
    }

    /**
@@ -863,10 +869,13 @@ public abstract class AbsSwipeUpHandler<
        }
    }

    public Intent getHomeIntent() {
        return mGestureState.getHomeIntent();
    }

    public Intent getLaunchIntent() {
        return mGestureState.getOverviewIntent();
    }

    /**
     * Called when the value of {@link #mCurrentShift} changes
     */
+2 −48
Original line number Diff line number Diff line
@@ -61,17 +61,14 @@ import java.util.function.Consumer;
public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_TYPE>,
        ACTIVITY_TYPE extends StatefulActivity<STATE_TYPE> & RecentsViewContainer> extends
        BaseContainerInterface<STATE_TYPE, ACTIVITY_TYPE> {
    private final STATE_TYPE mBackgroundState;

    private STATE_TYPE mTargetState;

    @Nullable private Runnable mOnInitBackgroundStateUICallback = null;

    protected BaseActivityInterface(boolean rotationSupportedByActivity,
            STATE_TYPE overviewState, STATE_TYPE backgroundState) {
        super(backgroundState);
        this.rotationSupportedByActivity = rotationSupportedByActivity;
        mTargetState = overviewState;
        mBackgroundState = backgroundState;
    }

    /**
@@ -155,49 +152,6 @@ public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_T
        recentsView.switchToScreenshot(thumbnailDatas, runnable);
    }


    protected void runOnInitBackgroundStateUI(Runnable callback) {
        ACTIVITY_TYPE activity = getCreatedContainer();
        if (activity != null && activity.getStateManager().getState() == mBackgroundState) {
            callback.run();
            onInitBackgroundStateUI();
            return;
        }
        mOnInitBackgroundStateUICallback = callback;
    }

    private void onInitBackgroundStateUI() {
        if (mOnInitBackgroundStateUICallback != null) {
            mOnInitBackgroundStateUICallback.run();
            mOnInitBackgroundStateUICallback = null;
        }
    }

    public interface AnimationFactory {

        void createActivityInterface(long transitionLength);

        /**
         * @param attached Whether to show RecentsView alongside the app window. If false, recents
         *                 will be hidden by some property we can animate, e.g. alpha.
         * @param animate Whether to animate recents to/from its new attached state.
         * @param updateRunningTaskAlpha Whether to update the running task's attached alpha
         */
        default void setRecentsAttachedToAppWindow(
                boolean attached, boolean animate, boolean updateRunningTaskAlpha) { }

        default boolean isRecentsAttachedToAppWindow() {
            return false;
        }

        default boolean hasRecentsEverAttachedToAppWindow() {
            return false;
        }

        /** Called when the gesture ends and we know what state it is going towards */
        default void setEndTarget(GestureState.GestureEndTarget endTarget) { }
    }

    class DefaultAnimationFactory implements AnimationFactory {

        protected final ACTIVITY_TYPE mActivity;
@@ -226,7 +180,7 @@ public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_T
        }

        @Override
        public void createActivityInterface(long transitionLength) {
        public void createContainerInterface(long transitionLength) {
            PendingAnimation pa = new PendingAnimation(transitionLength * 2);
            createBackgroundToOverviewAnim(mActivity, pa);
            AnimatorPlaybackController controller = pa.createPlaybackController();
+54 −4
Original line number Diff line number Diff line
@@ -41,10 +41,12 @@ import com.android.launcher3.Flags;
import com.android.launcher3.R;
import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.statemanager.StatefulContainer;
import com.android.launcher3.taskbar.TaskbarUIController;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.WindowBounds;
import com.android.launcher3.views.ScrimView;
import com.android.quickstep.fallback.window.RecentsWindowManager;
import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.AnimatorControllerWithResistance;
@@ -58,10 +60,14 @@ import java.util.function.Consumer;
import java.util.function.Predicate;

public abstract class BaseContainerInterface<STATE_TYPE extends BaseState<STATE_TYPE>,
        CONTAINER_TYPE extends RecentsViewContainer> {

        CONTAINER_TYPE extends RecentsViewContainer & StatefulContainer<STATE_TYPE>> {

    public boolean rotationSupportedByActivity = false;
    protected final STATE_TYPE mBackgroundState;

    protected BaseContainerInterface(STATE_TYPE backgroundState) {
        mBackgroundState = backgroundState;
    }

    @UiThread
    @Nullable
@@ -73,6 +79,9 @@ public abstract class BaseContainerInterface<STATE_TYPE extends BaseState<STATE_
    @Nullable
    public abstract CONTAINER_TYPE getCreatedContainer();

    @Nullable
    protected Runnable mOnInitBackgroundStateUICallback = null;

    public abstract boolean isInLiveTileMode();

    public abstract void onAssistantVisibilityChanged(float assistantVisibility);
@@ -97,7 +106,32 @@ public abstract class BaseContainerInterface<STATE_TYPE extends BaseState<STATE_
    @Nullable
    public abstract TaskbarUIController getTaskbarController();

    public abstract BaseActivityInterface.AnimationFactory prepareRecentsUI(
    public interface AnimationFactory {

        void createContainerInterface(long transitionLength);

        /**
         * @param attached Whether to show RecentsView alongside the app window. If false, recents
         *                 will be hidden by some property we can animate, e.g. alpha.
         * @param animate Whether to animate recents to/from its new attached state.
         * @param updateRunningTaskAlpha Whether to update the running task's attached alpha
         */
        default void setRecentsAttachedToAppWindow(
                boolean attached, boolean animate, boolean updateRunningTaskAlpha) { }

        default boolean isRecentsAttachedToAppWindow() {
            return false;
        }

        default boolean hasRecentsEverAttachedToAppWindow() {
            return false;
        }

        /** Called when the gesture ends and we know what state it is going towards */
        default void setEndTarget(GestureState.GestureEndTarget endTarget) { }
    }

    public abstract BaseContainerInterface.AnimationFactory prepareRecentsUI(
            RecentsAnimationDeviceState deviceState, boolean activityVisible,
            Consumer<AnimatorControllerWithResistance> callback);

@@ -135,7 +169,16 @@ public abstract class BaseContainerInterface<STATE_TYPE extends BaseState<STATE_
        return false;
    }

    abstract void runOnInitBackgroundStateUI(Runnable callback);
    public void runOnInitBackgroundStateUI(Runnable callback) {
        StatefulContainer container = getCreatedContainer();
        if (container != null
                && container.getStateManager().getState() == mBackgroundState) {
            callback.run();
            onInitBackgroundStateUI();
            return;
        }
        mOnInitBackgroundStateUICallback = callback;
    }

    @Nullable
    public DesktopVisibilityController getDesktopVisibilityController() {
@@ -414,4 +457,11 @@ public abstract class BaseContainerInterface<STATE_TYPE extends BaseState<STATE_
                outRect,
                orientationHandler);
    }

    protected void onInitBackgroundStateUI() {
        if (mOnInitBackgroundStateUICallback != null) {
            mOnInitBackgroundStateUICallback.run();
            mOnInitBackgroundStateUICallback = null;
        }
    }
}
+259 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.quickstep;

import static com.android.app.animation.Interpolators.ACCELERATE_2;
import static com.android.app.animation.Interpolators.INSTANT;
import static com.android.app.animation.Interpolators.LINEAR;
import static com.android.launcher3.MotionEventsUtils.isTrackpadMultiFingerSwipe;
import static com.android.quickstep.AbsSwipeUpHandler.RECENTS_ATTACH_DURATION;
import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_FADE_ANIM;
import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_TRANSLATE_X_ANIM;
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.util.Log;
import android.view.MotionEvent;

import androidx.annotation.Nullable;

import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.taskbar.TaskbarUIController;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.NavigationMode;
import com.android.quickstep.fallback.RecentsState;
import com.android.quickstep.fallback.window.RecentsWindowManager;
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.recents.model.ThumbnailData;

import java.util.HashMap;
import java.util.Optional;
import java.util.function.Consumer;

/**
 * Temporary utility class in place for differences needed between
 * Recents in Window in Launcher vs Fallback
 */
public abstract class BaseWindowInterface extends
        BaseContainerInterface<RecentsState, RecentsWindowManager> {

    final String TAG = "BaseWindowInterface";
    private RecentsState mTargetState;


    protected BaseWindowInterface(RecentsState overviewState, RecentsState backgroundState) {
        super(backgroundState);
        mTargetState = overviewState;
    }

    @Nullable
    public abstract RecentsWindowManager getCreatedContainer();

    @Nullable
    public DepthController getDepthController() {
        return null;
    }

    public final boolean isResumed() {
        return isStarted();
    }

    public final boolean isStarted() {
        RecentsWindowManager windowManager = getCreatedContainer();
        return windowManager != null && windowManager.isStarted();
    }

    public boolean deferStartingActivity(RecentsAnimationDeviceState deviceState, MotionEvent ev) {
        TaskbarUIController controller = getTaskbarController();
        boolean isEventOverBubbleBarStashHandle =
                controller != null && controller.isEventOverBubbleBarViews(ev);
        return deviceState.isInDeferredGestureRegion(ev) || deviceState.isImeRenderingNavButtons()
                || isTrackpadMultiFingerSwipe(ev) || isEventOverBubbleBarStashHandle;
    }

    /**
     * Closes any overlays.
     */
    public void closeOverlay() {
        Optional.ofNullable(getTaskbarController()).ifPresent(
                TaskbarUIController::hideOverlayWindow);
    }

    public void switchRunningTaskViewToScreenshot(HashMap<Integer, ThumbnailData> thumbnailDatas,
            Runnable runnable) {
        RecentsWindowManager windowManager = getCreatedContainer();
        if (windowManager == null) {
            return;
        }
        RecentsView recentsView = windowManager.getOverviewPanel();
        if (recentsView == null) {
            if (runnable != null) {
                runnable.run();
            }
            return;
        }
        recentsView.switchToScreenshot(thumbnailDatas, runnable);
    }

    /**
     * todo: Create an abstract animation factory to handle both activity and window implementations
     * todo: move new factory into BaseContainerInterface and cleanup.
      */

    class DefaultAnimationFactory implements AnimationFactory {

        protected final RecentsWindowManager mRecentsWindowManager;
        private final RecentsState mStartState;
        private final Consumer<AnimatorControllerWithResistance> mCallback;

        private boolean mIsAttachedToWindow;
        private boolean mHasEverAttachedToWindow;

        DefaultAnimationFactory(Consumer<AnimatorControllerWithResistance> callback) {
            mCallback = callback;

            mRecentsWindowManager = getCreatedContainer();
            mStartState = mRecentsWindowManager.getStateManager().getState();
        }

        protected RecentsWindowManager initBackgroundStateUI() {
            RecentsState resetState = mStartState;
            if (mStartState.shouldDisableRestore()) {
                resetState = mRecentsWindowManager.getStateManager().getRestState();
            }
            mRecentsWindowManager.getStateManager().setRestState(resetState);
            mRecentsWindowManager.getStateManager().goToState(mBackgroundState, false);
            onInitBackgroundStateUI();
            return mRecentsWindowManager;
        }

        @Override
        public void createContainerInterface(long transitionLength) {
            PendingAnimation pa = new PendingAnimation(transitionLength * 2);
            createBackgroundToOverviewAnim(mRecentsWindowManager, pa);
            AnimatorPlaybackController controller = pa.createPlaybackController();
            mRecentsWindowManager.getStateManager().setCurrentUserControlledAnimation(controller);

            // Since we are changing the start position of the UI, reapply the state, at the end
            controller.setEndAction(() -> {
                mRecentsWindowManager.getStateManager().goToState(
                        controller.getInterpolatedProgress() > 0.5 ? mTargetState
                                : mBackgroundState,
                        /* animated= */ false);
            });

            RecentsView recentsView = mRecentsWindowManager.getOverviewPanel();
            AnimatorControllerWithResistance controllerWithResistance =
                    AnimatorControllerWithResistance.createForRecents(controller,
                            mRecentsWindowManager, recentsView.getPagedViewOrientedState(),
                            mRecentsWindowManager.getDeviceProfile(), recentsView,
                            RECENTS_SCALE_PROPERTY, recentsView, TASK_SECONDARY_TRANSLATION);
            mCallback.accept(controllerWithResistance);

            // Creating the activity controller animation sometimes reapplies the launcher state
            // (because we set the animation as the current state animation), so we reapply the
            // attached state here as well to ensure recents is shown/hidden appropriately.
            if (DisplayController.getNavigationMode(mRecentsWindowManager)
                    == NavigationMode.NO_BUTTON) {
                setRecentsAttachedToAppWindow(mIsAttachedToWindow, false, false);
            }
        }

        @Override
        public void setRecentsAttachedToAppWindow(boolean attached, boolean animate,
                boolean updateRunningTaskAlpha) {

            if (mIsAttachedToWindow == attached && animate) {
                return;
            }
            mRecentsWindowManager.getStateManager()
                    .cancelStateElementAnimation(INDEX_RECENTS_FADE_ANIM);
            mRecentsWindowManager.getStateManager()
                    .cancelStateElementAnimation(INDEX_RECENTS_TRANSLATE_X_ANIM);

            AnimatorSet animatorSet = new AnimatorSet();
            animatorSet.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationStart(Animator animation) {
                    super.onAnimationStart(animation);
                    mIsAttachedToWindow = attached;
                    if (attached) {
                        mHasEverAttachedToWindow = true;
                    }
                }});

            long animationDuration = animate ? RECENTS_ATTACH_DURATION : 0;
            Animator fadeAnim = mRecentsWindowManager.getStateManager()
                    .createStateElementAnimation(INDEX_RECENTS_FADE_ANIM, attached ? 1 : 0);
            fadeAnim.setInterpolator(attached ? INSTANT : ACCELERATE_2);
            fadeAnim.setDuration(animationDuration);
            animatorSet.play(fadeAnim);

            float fromTranslation = ADJACENT_PAGE_HORIZONTAL_OFFSET.get(
                    mRecentsWindowManager.getOverviewPanel());
            float toTranslation = attached ? 0 : 1;

            Animator translationAnimator =
                    mRecentsWindowManager.getStateManager().createStateElementAnimation(
                            INDEX_RECENTS_TRANSLATE_X_ANIM, fromTranslation, toTranslation);
            translationAnimator.setDuration(animationDuration);
            animatorSet.play(translationAnimator);
            animatorSet.start();
        }

        @Override
        public boolean isRecentsAttachedToAppWindow() {
            return mIsAttachedToWindow;
        }

        @Override
        public boolean hasRecentsEverAttachedToAppWindow() {
            return mHasEverAttachedToWindow;
        }

        @Override
        public void setEndTarget(GestureState.GestureEndTarget endTarget) {
            mTargetState = stateFromGestureEndTarget(endTarget);
        }

        protected void createBackgroundToOverviewAnim(RecentsWindowManager container,
                PendingAnimation pa) {
            //  Scale down recents from being full screen to being in overview.
            RecentsView recentsView = container.getOverviewPanel();
            pa.addFloat(recentsView, RECENTS_SCALE_PROPERTY,
                    recentsView.getMaxScaleForFullScreen(), 1, LINEAR);
            pa.addFloat(recentsView, FULLSCREEN_PROGRESS, 1, 0, LINEAR);

            pa.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationStart(Animator animation) {
                    TaskbarUIController taskbarUIController = getTaskbarController();
                    if (taskbarUIController != null) {
                        taskbarUIController.setSystemGestureInProgress(true);
                    }
                }
            });
        }
    }
}
 No newline at end of file
+6 −25
Original line number Diff line number Diff line
@@ -45,35 +45,16 @@ import java.util.function.Consumer;
import java.util.function.Predicate;

/**
 * {@link BaseActivityInterface} for recents when the default launcher is different than the
 * currently running one and apps should interact with the {@link RecentsActivity} as opposed
 * {@link BaseWindowInterface} for recents when the default launcher is different than the
 * currently running one and apps should interact with the {@link RecentsWindowManager} as opposed
 * to the in-launcher one.
 */
public final class FallbackWindowInterface extends BaseWindowInterface{

    private static FallbackWindowInterface INSTANCE;
    public static final FallbackWindowInterface INSTANCE = new FallbackWindowInterface();

    private final RecentsWindowManager mRecentsWindowManager;

    @Nullable
    public static FallbackWindowInterface getInstance(){
        return INSTANCE;
    }

    public static FallbackWindowInterface init(RecentsWindowManager recentsWindowManager) {
       if (INSTANCE == null) {
           INSTANCE = new FallbackWindowInterface(recentsWindowManager);
       }
       return INSTANCE;
    }

    private FallbackWindowInterface(RecentsWindowManager recentsWindowManager) {
    private FallbackWindowInterface() {
        super( DEFAULT, BACKGROUND_APP);
        mRecentsWindowManager = recentsWindowManager;
    }

    public void destroy() {
        INSTANCE = null;
    }

    /** 2 */
@@ -119,7 +100,7 @@ public final class FallbackWindowInterface extends BaseWindowInterface{
    @Nullable
    @Override
    public RecentsWindowManager getCreatedContainer() {
        return mRecentsWindowManager;
        return RecentsWindowManager.Companion.getInstanceOrNull();
    }

    @Override
Loading