diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index a2f15f5ff3..6da2201dc9 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -48,6 +48,7 @@ import static com.android.quickstep.MultiStateCallback.DEBUG_STATES; import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE; import static com.android.quickstep.views.RecentsView.RECENTS_GRID_PROGRESS; import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD; +import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME; import android.animation.Animator; @@ -616,7 +617,7 @@ public abstract class AbsSwipeUpHandler, final boolean passed = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW; if (passed != mPassedOverviewThreshold) { mPassedOverviewThreshold = passed; - if (!mDeviceState.isFullyGesturalNavMode()) { + if (!mDeviceState.isTwoButtonNavMode()) { performHapticFeedback(); } } @@ -722,6 +723,9 @@ public abstract class AbsSwipeUpHandler, @UiThread public void onGestureStarted(boolean isLikelyToStartNewTask) { + mActivityInterface.closeOverlay(); + TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS); + if (mRecentsView != null) { InteractionJankMonitorWrapper.begin(mRecentsView, InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH, 2000 /* ms timeout */); @@ -849,6 +853,10 @@ public abstract class AbsSwipeUpHandler, private GestureEndTarget calculateEndTarget(PointF velocity, float endVelocity, boolean isFling, boolean isCancel) { + if (mDeviceState.isButtonNavMode()) { + // Button mode, this is only used to go to recents + return RECENTS; + } final GestureEndTarget endTarget; final boolean goingToNewTask; if (mRecentsView != null) { @@ -953,15 +961,20 @@ public abstract class AbsSwipeUpHandler, } else if (endTarget == RECENTS) { if (mRecentsView != null) { int nearestPage = mRecentsView.getDestinationPage(); + boolean isScrolling = false; if (mRecentsView.getNextPage() != nearestPage) { // We shouldn't really scroll to the next page when swiping up to recents. // Only allow settling on the next page if it's nearest to the center. mRecentsView.snapToPage(nearestPage, Math.toIntExact(duration)); + isScrolling = true; } if (mRecentsView.getScroller().getDuration() > MAX_SWIPE_DURATION) { mRecentsView.snapToPage(mRecentsView.getNextPage(), (int) MAX_SWIPE_DURATION); + isScrolling = true; + } + if (!mDeviceState.isButtonNavMode() || isScrolling) { + duration = Math.max(duration, mRecentsView.getScroller().getDuration()); } - duration = Math.max(duration, mRecentsView.getScroller().getDuration()); } } @@ -1764,7 +1777,6 @@ public abstract class AbsSwipeUpHandler, public interface Factory { - AbsSwipeUpHandler newHandler( - GestureState gestureState, long touchTimeMs, boolean continuingLastGesture); + AbsSwipeUpHandler newHandler(GestureState gestureState, long touchTimeMs); } } diff --git a/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java b/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java deleted file mode 100644 index d159fa0904..0000000000 --- a/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (C) 2019 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.launcher3.LauncherState.BACKGROUND_APP; -import static com.android.launcher3.LauncherState.OVERVIEW; -import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR; -import static com.android.launcher3.anim.Interpolators.clampToProgress; -import static com.android.launcher3.statehandlers.DepthController.DEPTH; -import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING; - -import android.animation.Animator; -import android.animation.AnimatorSet; -import android.app.ActivityManager.RunningTaskInfo; -import android.util.Log; -import android.view.animation.Interpolator; - -import com.android.launcher3.AbstractFloatingView; -import com.android.launcher3.anim.AnimationSuccessListener; -import com.android.launcher3.anim.PendingAnimation; -import com.android.launcher3.statehandlers.DepthController; -import com.android.launcher3.statemanager.StatefulActivity; -import com.android.launcher3.taskbar.TaskbarController; -import com.android.quickstep.util.RemoteAnimationProvider; -import com.android.quickstep.util.SurfaceTransactionApplier; -import com.android.quickstep.util.TaskViewSimulator; -import com.android.quickstep.util.TransformParams; -import com.android.quickstep.views.RecentsView; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; - -/** - * Provider for the atomic (for 3-button mode) remote window animation from the app to the overview. - * - * @param activity that contains the overview - */ -final class AppToOverviewAnimationProvider> extends - RemoteAnimationProvider { - - private static final long RECENTS_LAUNCH_DURATION = 250; - private static final String TAG = "AppToOverviewAnimationProvider"; - - private final BaseActivityInterface mActivityInterface; - // The id of the currently running task that is transitioning to overview. - private final RunningTaskInfo mTargetTask; - private final RecentsAnimationDeviceState mDeviceState; - - private T mActivity; - private RecentsView mRecentsView; - - AppToOverviewAnimationProvider( - BaseActivityInterface activityInterface, RunningTaskInfo targetTask, - RecentsAnimationDeviceState deviceState) { - mActivityInterface = activityInterface; - mTargetTask = targetTask; - mDeviceState = deviceState; - } - - /** - * Callback for when the activity is ready/initialized. - * - * @param activity the activity that is ready - * @param wasVisible true if it was visible before - */ - boolean onActivityReady(T activity, Boolean wasVisible) { - activity.getOverviewPanel().showCurrentTask(mTargetTask); - AbstractFloatingView.closeAllOpenViews(activity, wasVisible); - BaseActivityInterface.AnimationFactory factory = mActivityInterface.prepareRecentsUI( - mDeviceState, - wasVisible, (controller) -> { - controller.getNormalController().dispatchOnStart(); - controller.getNormalController().getAnimationPlayer().end(); - }); - factory.createActivityInterface(RECENTS_LAUNCH_DURATION); - factory.setRecentsAttachedToAppWindow(true, false); - mActivity = activity; - mRecentsView = mActivity.getOverviewPanel(); - return false; - } - - /** - * Create remote window animation from the currently running app to the overview panel. - * - * @param appTargets the target apps - * @return animation from app to overview - */ - @Override - public AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets, - RemoteAnimationTargetCompat[] wallpaperTargets) { - PendingAnimation pa = new PendingAnimation(RECENTS_LAUNCH_DURATION); - if (mActivity == null) { - Log.e(TAG, "Animation created, before activity"); - return pa.buildAnim(); - } - - mRecentsView.setRunningTaskIconScaledDown(true); - pa.addListener(new AnimationSuccessListener() { - @Override - public void onAnimationSuccess(Animator animator) { - mActivityInterface.onSwipeUpToRecentsComplete(); - mRecentsView.animateUpRunningTaskIconScale(); - } - }); - - DepthController depthController = mActivityInterface.getDepthController(); - if (depthController != null) { - pa.addFloat(depthController, DEPTH, BACKGROUND_APP.getDepth(mActivity), - OVERVIEW.getDepth(mActivity), TOUCH_RESPONSE_INTERPOLATOR); - } - - TaskbarController taskbarController = mActivityInterface.getTaskbarController(); - if (taskbarController != null) { - pa.add(taskbarController.createAnimToLauncher(OVERVIEW, getRecentsLaunchDuration())); - } - - RemoteAnimationTargets targets = new RemoteAnimationTargets(appTargets, - wallpaperTargets, MODE_CLOSING); - - // Use the top closing app to determine the insets for the animation - RemoteAnimationTargetCompat runningTaskTarget = mTargetTask == null ? null - : targets.findTask(mTargetTask.taskId); - if (runningTaskTarget == null) { - Log.e(TAG, "No closing app"); - return pa.buildAnim(); - } - - TaskViewSimulator tsv = new TaskViewSimulator(mActivity, mRecentsView.getSizeStrategy()); - tsv.setDp(mActivity.getDeviceProfile()); - tsv.setOrientationState(mRecentsView.getPagedViewOrientedState()); - tsv.setPreview(runningTaskTarget); - - TransformParams params = new TransformParams() - .setTargetSet(targets) - .setSyncTransactionApplier(new SurfaceTransactionApplier(mActivity.getRootView())); - - AnimatedFloat recentsAlpha = new AnimatedFloat(() -> { }); - params.setBaseBuilderProxy((builder, app, p) - -> builder.withAlpha(recentsAlpha.value)); - - Interpolator taskInterpolator; - if (targets.isAnimatingHome()) { - params.setHomeBuilderProxy((builder, app, p) -> builder.withAlpha(1 - p.getProgress())); - - taskInterpolator = TOUCH_RESPONSE_INTERPOLATOR; - pa.addFloat(recentsAlpha, AnimatedFloat.VALUE, 0, 1, TOUCH_RESPONSE_INTERPOLATOR); - } else { - // When animation from app to recents, the recents layer is drawn on top of the app. To - // prevent the overlap, we animate the task first and then quickly fade in the recents. - taskInterpolator = clampToProgress(TOUCH_RESPONSE_INTERPOLATOR, 0, 0.8f); - pa.addFloat(recentsAlpha, AnimatedFloat.VALUE, 0, 1, - clampToProgress(TOUCH_RESPONSE_INTERPOLATOR, 0.8f, 1)); - } - - pa.addFloat(params, TransformParams.PROGRESS, 0, 1, taskInterpolator); - tsv.addAppToOverviewAnim(pa, taskInterpolator); - pa.addOnFrameCallback(() -> tsv.apply(params)); - return pa.buildAnim(); - } - - /** - * Get duration of animation from app to overview. - * - * @return duration of animation - */ - long getRecentsLaunchDuration() { - return RECENTS_LAUNCH_DURATION; - } -} diff --git a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java index bffe3a1498..e13d1a4511 100644 --- a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java +++ b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java @@ -105,7 +105,7 @@ public final class FallbackActivityInterface extends @Override public RecentsView getVisibleRecentsView() { RecentsActivity activity = getCreatedActivity(); - if (activity != null && activity.hasWindowFocus()) { + if (activity != null && activity.hasBeenResumed()) { return activity.getOverviewPanel(); } return null; diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java index ca5765e469..98b96b2c6c 100644 --- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java +++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java @@ -177,7 +177,7 @@ public final class LauncherActivityInterface extends @UiThread private Launcher getVisibleLauncher() { Launcher launcher = getCreatedActivity(); - return (launcher != null) && launcher.isStarted() && launcher.hasWindowFocus() + return (launcher != null) && launcher.isStarted() && launcher.hasBeenResumed() ? launcher : null; } @@ -188,6 +188,7 @@ public final class LauncherActivityInterface extends return false; } + closeOverlay(); launcher.getStateManager().goToState(OVERVIEW, launcher.getStateManager().shouldAnimateStateChange(), onCompleteCallback); return true; diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java index 63fdd0b554..923d4f1e40 100644 --- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java +++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java @@ -16,29 +16,28 @@ package com.android.quickstep; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; -import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; +import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.AnimatorSet; import android.annotation.TargetApi; -import android.content.Context; +import android.content.Intent; +import android.graphics.PointF; import android.os.Build; import android.os.SystemClock; import android.os.Trace; -import android.view.ViewConfiguration; import androidx.annotation.BinderThread; +import androidx.annotation.Nullable; +import androidx.annotation.UiThread; import com.android.launcher3.statemanager.StatefulActivity; -import com.android.quickstep.util.ActivityInitListener; -import com.android.quickstep.util.RemoteAnimationProvider; +import com.android.launcher3.util.RunnableList; +import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; -import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.InteractionJankMonitorWrapper; -import com.android.systemui.shared.system.LatencyTrackerCompat; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; + +import java.util.ArrayList; /** * Helper class to handle various atomic commands for switching between Overview. @@ -46,66 +45,191 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat; @TargetApi(Build.VERSION_CODES.P) public class OverviewCommandHelper { - private final Context mContext; - private final RecentsAnimationDeviceState mDeviceState; + public static final int TYPE_SHOW = 1; + public static final int TYPE_SHOW_NEXT_FOCUS = 2; + public static final int TYPE_HIDE = 3; + public static final int TYPE_TOGGLE = 4; + + private static final String TRANSITION_NAME = "Transition:toOverview"; + + private final TouchInteractionService mService; private final OverviewComponentObserver mOverviewComponentObserver; + private final TaskAnimationManager mTaskAnimationManager; + private final ArrayList mPendingCommands = new ArrayList<>(); - private long mLastToggleTime; - - public OverviewCommandHelper(Context context, RecentsAnimationDeviceState deviceState, - OverviewComponentObserver observer) { - mContext = context; - mDeviceState = deviceState; + public OverviewCommandHelper(TouchInteractionService service, + OverviewComponentObserver observer, + TaskAnimationManager taskAnimationManager) { + mService = service; mOverviewComponentObserver = observer; + mTaskAnimationManager = taskAnimationManager; } - @BinderThread - public void onOverviewToggle() { - // If currently screen pinning, do not enter overview - if (mDeviceState.isScreenPinningActive()) { + /** + * Called when the command finishes execution. + */ + private void scheduleNextTask(CommandInfo command) { + if (!mPendingCommands.isEmpty() && mPendingCommands.get(0) == command) { + mPendingCommands.remove(0); + executeNext(); + } + } + + /** + * Executes the next command from the queue. If the command finishes immediately (returns true), + * it continues to execute the next command, until the queue is empty of a command defer's its + * completion (returns false). + */ + @UiThread + private void executeNext() { + if (mPendingCommands.isEmpty()) { return; } - - TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS); - MAIN_EXECUTOR.execute(new RecentsActivityCommand<>()); + CommandInfo cmd = mPendingCommands.get(0); + if (executeCommand(cmd)) { + scheduleNextTask(cmd); + } } + @UiThread + private void addCommand(CommandInfo cmd) { + boolean wasEmpty = mPendingCommands.isEmpty(); + mPendingCommands.add(cmd); + if (wasEmpty) { + executeNext(); + } + } + + /** + * Adds a command to be executed next, after all pending tasks are completed + */ @BinderThread - public void onOverviewShown(boolean triggeredFromAltTab) { - if (triggeredFromAltTab) { - TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS); - } - MAIN_EXECUTOR.execute(new ShowRecentsCommand(triggeredFromAltTab)); + public void addCommand(int type) { + CommandInfo cmd = new CommandInfo(type); + MAIN_EXECUTOR.execute(() -> addCommand(cmd)); } - @BinderThread - public void onOverviewHidden() { - MAIN_EXECUTOR.execute(new HideRecentsCommand()); + private TaskView getNextTask(RecentsView view) { + final TaskView runningTaskView = view.getRunningTaskView(); + + if (runningTaskView == null) { + return view.getTaskViewCount() > 0 ? view.getTaskViewAt(0) : null; + } else { + final TaskView nextTask = view.getNextTaskView(); + return nextTask != null ? nextTask : runningTaskView; + } } - private class ShowRecentsCommand extends RecentsActivityCommand { - - private final boolean mTriggeredFromAltTab; - - ShowRecentsCommand(boolean triggeredFromAltTab) { - mTriggeredFromAltTab = triggeredFromAltTab; + private boolean launchTask(RecentsView recents, @Nullable TaskView taskView, CommandInfo cmd) { + RunnableList callbackList = null; + if (taskView != null) { + taskView.setEndQuickswitchCuj(true); + callbackList = taskView.launchTaskAnimated(); } - @Override - protected boolean handleCommand(long elapsedTime) { - // TODO: Go to the next page if started from alt-tab. - return mActivityInterface.getVisibleRecentsView() != null; + if (callbackList != null) { + callbackList.add(() -> scheduleNextTask(cmd)); + return false; + } else { + recents.startHome(); + return true; } + } - @Override - protected void onTransitionComplete() { - // TODO(b/138729100) This doesn't execute first time launcher is run - if (mTriggeredFromAltTab) { - RecentsView rv = mActivityInterface.getVisibleRecentsView(); - if (rv == null) { - return; + /** + * Executes the task and returns true if next task can be executed. If false, then the next + * task is deferred until {@link #scheduleNextTask} is called + */ + private > boolean executeCommand(CommandInfo cmd) { + BaseActivityInterface activityInterface = + mOverviewComponentObserver.getActivityInterface(); + RecentsView recents = activityInterface.getVisibleRecentsView(); + if (recents == null) { + if (cmd.type == TYPE_HIDE) { + // already hidden + return true; + } + } else { + switch (cmd.type) { + case TYPE_SHOW: + // already visible + return true; + case TYPE_HIDE: { + int currentPage = recents.getNextPage(); + TaskView tv = (currentPage >= 0 && currentPage < recents.getTaskViewCount()) + ? (TaskView) recents.getPageAt(currentPage) + : null; + return launchTask(recents, tv, cmd); } + case TYPE_TOGGLE: + return launchTask(recents, getNextTask(recents), cmd); + } + } + if (activityInterface.switchToRecentsIfVisible(() -> scheduleNextTask(cmd))) { + // If successfully switched, wait until animation finishes + return false; + } + + final T activity = activityInterface.getCreatedActivity(); + if (activity != null) { + InteractionJankMonitorWrapper.begin( + activity.getRootView(), + InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH); + } + + GestureState gestureState = mService.createGestureState(GestureState.DEFAULT_STATE); + AbsSwipeUpHandler interactionHandler = mService.getSwipeUpHandlerFactory() + .newHandler(gestureState, cmd.createTime); + interactionHandler.setGestureEndCallback( + () -> onTransitionComplete(cmd, interactionHandler)); + + Intent intent = new Intent(interactionHandler.getLaunchIntent()); + interactionHandler.initWhenReady(intent); + + RecentsAnimationListener recentAnimListener = new RecentsAnimationListener() { + @Override + public void onRecentsAnimationStart(RecentsAnimationController controller, + RecentsAnimationTargets targets) { + interactionHandler.onGestureEnded(0, new PointF(), new PointF()); + cmd.removeListener(this); + } + + @Override + public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) { + interactionHandler.onGestureCancelled(); + cmd.removeListener(this); + } + }; + + if (mTaskAnimationManager.isRecentsAnimationRunning()) { + cmd.mActiveCallbacks = mTaskAnimationManager.continueRecentsAnimation(gestureState); + cmd.mActiveCallbacks.addListener(interactionHandler); + mTaskAnimationManager.notifyRecentsAnimationState(interactionHandler); + interactionHandler.onGestureStarted(true /*isLikelyToStartNewTask*/); + + cmd.mActiveCallbacks.addListener(recentAnimListener); + mTaskAnimationManager.notifyRecentsAnimationState(recentAnimListener); + } else { + intent.putExtra(INTENT_EXTRA_LOG_TRACE_ID, gestureState.getGestureId()); + cmd.mActiveCallbacks = mTaskAnimationManager.startRecentsAnimation( + gestureState, intent, interactionHandler); + interactionHandler.onGestureStarted(false /*isLikelyToStartNewTask*/); + cmd.mActiveCallbacks.addListener(recentAnimListener); + } + + Trace.beginAsyncSection(TRANSITION_NAME, 0); + return false; + } + + private void onTransitionComplete(CommandInfo cmd, AbsSwipeUpHandler handler) { + cmd.removeListener(handler); + Trace.endAsyncSection(TRANSITION_NAME, 0); + + if (cmd.type == TYPE_SHOW_NEXT_FOCUS) { + RecentsView rv = + mOverviewComponentObserver.getActivityInterface().getVisibleRecentsView(); + if (rv != null) { // Ensure that recents view has focus so that it receives the followup key inputs TaskView taskView = rv.getNextTaskView(); if (taskView == null) { @@ -120,130 +244,22 @@ public class OverviewCommandHelper { } } } + scheduleNextTask(cmd); } - private class HideRecentsCommand extends RecentsActivityCommand { + private static class CommandInfo { + public final long createTime = SystemClock.elapsedRealtime(); + public final int type; + RecentsAnimationCallbacks mActiveCallbacks; - @Override - protected boolean handleCommand(long elapsedTime) { - RecentsView recents = mActivityInterface.getVisibleRecentsView(); - if (recents == null) { - return false; - } - int currentPage = recents.getNextPage(); - if (currentPage >= 0 && currentPage < recents.getTaskViewCount()) { - ((TaskView) recents.getPageAt(currentPage)).launchTaskAnimated(); - } else { - recents.startHome(); - } - return true; - } - } - - private class RecentsActivityCommand> implements Runnable { - - private static final String TRANSITION_NAME = "Transition:toOverview"; - protected final BaseActivityInterface mActivityInterface; - private final long mCreateTime; - private final AppToOverviewAnimationProvider mAnimationProvider; - - private final long mToggleClickedTime = SystemClock.uptimeMillis(); - private ActivityInitListener mListener; - - public RecentsActivityCommand() { - mActivityInterface = mOverviewComponentObserver.getActivityInterface(); - mCreateTime = SystemClock.elapsedRealtime(); - mAnimationProvider = new AppToOverviewAnimationProvider<>(mActivityInterface, - ActivityManagerWrapper.getInstance().getRunningTask(), mDeviceState); - - // Preload the plan - RecentsModel.INSTANCE.get(mContext).getTasks(null); + CommandInfo(int type) { + this.type = type; } - @Override - public void run() { - long elapsedTime = mCreateTime - mLastToggleTime; - mLastToggleTime = mCreateTime; - - if (handleCommand(elapsedTime)) { - // Command already handled. - return; + void removeListener(RecentsAnimationListener listener) { + if (mActiveCallbacks != null) { + mActiveCallbacks.removeListener(listener); } - - if (mActivityInterface.switchToRecentsIfVisible(this::onTransitionComplete)) { - // If successfully switched, then return - return; - } - - final T activity = mActivityInterface.getCreatedActivity(); - if (activity != null) { - InteractionJankMonitorWrapper.begin( - activity.getRootView(), - InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH); - } - - // Otherwise, start overview. - mListener = mActivityInterface.createActivityInitListener(this::onActivityReady); - mListener.registerAndStartActivity(mOverviewComponentObserver.getOverviewIntent(), - new RemoteAnimationProvider() { - @Override - public AnimatorSet createWindowAnimation( - RemoteAnimationTargetCompat[] appTargets, - RemoteAnimationTargetCompat[] wallpaperTargets) { - return RecentsActivityCommand.this.createWindowAnimation(appTargets, - wallpaperTargets); - } - }, mContext, MAIN_EXECUTOR.getHandler(), - mAnimationProvider.getRecentsLaunchDuration()); } - - protected boolean handleCommand(long elapsedTime) { - // TODO: We need to fix this case with PIP, when an activity first enters PIP, it shows - // the menu activity which takes window focus, preventing the right condition from - // being run below - RecentsView recents = mActivityInterface.getVisibleRecentsView(); - if (recents != null) { - // Launch the next task - recents.showNextTask(); - return true; - } 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 true; - } - return false; - } - - private boolean onActivityReady(Boolean wasVisible) { - final T activity = mActivityInterface.getCreatedActivity(); - return mAnimationProvider.onActivityReady(activity, wasVisible); - } - - private AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets, - RemoteAnimationTargetCompat[] wallpaperTargets) { - LatencyTrackerCompat.logToggleRecents( - mContext, (int) (SystemClock.uptimeMillis() - mToggleClickedTime)); - - mListener.unregister(); - - AnimatorSet animatorSet = mAnimationProvider.createWindowAnimation(appTargets, - wallpaperTargets); - animatorSet.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - Trace.beginAsyncSection(TRANSITION_NAME, 0); - super.onAnimationStart(animation); - } - - @Override - public void onAnimationEnd(Animator animation) { - onTransitionComplete(); - Trace.endAsyncSection(TRANSITION_NAME, 0); - } - }); - return animatorSet; - } - - protected void onTransitionComplete() { } } } diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java index f99b7e6af4..458f45a75d 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java @@ -17,12 +17,13 @@ package com.android.quickstep; import static android.content.Intent.ACTION_USER_UNLOCKED; -import static com.android.launcher3.util.SettingsCache.ONE_HANDED_ENABLED; -import static com.android.launcher3.util.SettingsCache.ONE_HANDED_SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED; import static com.android.launcher3.util.DisplayController.DisplayHolder.CHANGE_ALL; import static com.android.launcher3.util.DisplayController.DisplayHolder.CHANGE_FRAME_DELAY; +import static com.android.launcher3.util.SettingsCache.ONE_HANDED_ENABLED; +import static com.android.launcher3.util.SettingsCache.ONE_HANDED_SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED; import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON; import static com.android.quickstep.SysUINavigationMode.Mode.THREE_BUTTONS; +import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY; @@ -60,11 +61,11 @@ import androidx.annotation.BinderThread; import com.android.launcher3.R; import com.android.launcher3.Utilities; -import com.android.launcher3.util.SettingsCache; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.DisplayController.DisplayHolder; import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener; import com.android.launcher3.util.DisplayController.Info; +import com.android.launcher3.util.SettingsCache; import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener; import com.android.quickstep.SysUINavigationMode.OneHandedModeChangeListener; import com.android.quickstep.util.NavBarPosition; @@ -303,6 +304,13 @@ public class RecentsAnimationDeviceState implements return mMode.hasGestures; } + /** + * @return whether the current nav mode is 2-button-based. + */ + public boolean isTwoButtonNavMode() { + return mMode == TWO_BUTTONS; + } + /** * @return whether the current nav mode is button-based. */ diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java index fc805d0794..8e6f663bed 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -24,6 +24,7 @@ import static com.android.launcher3.config.FeatureFlags.ASSISTANT_GIVES_LAUNCHER import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.quickstep.GestureState.DEFAULT_STATE; import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE; +import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED; @@ -157,13 +158,23 @@ public class TouchInteractionService extends Service implements PluginListener extends PagedView } } - public void showNextTask() { - final TaskView runningTaskView = getRunningTaskView(); - final TaskView targetTask; - - if (runningTaskView == null) { - // Launch the first task - if (getTaskViewCount() > 0) { - targetTask = getTaskViewAt(0); - } else { - return; - } - } else { - final TaskView nextTask = getNextTaskView(); - if (nextTask != null) { - targetTask = nextTask; - } else { - targetTask = runningTaskView; - } - } - targetTask.setEndQuickswitchCuj(true); - targetTask.launchTaskAnimated(); - } - public void setRunningTaskIconScaledDown(boolean isScaledDown) { if (mRunningTaskIconScaledDown != isScaledDown) { mRunningTaskIconScaledDown = isScaledDown;