From f6d75c98a94d173ae59afc9bd126d1e72d1b28fa Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Thu, 19 Jan 2023 21:59:07 +0000 Subject: [PATCH 1/4] Prevent falling into OtherActivityInputConsumer when over lockscreen - When opening the emergency dialer from the bouncer, there's a brief period where notificationPanelExpanded=false and occluded=false which currently means canStartSystemGesture=true and isKeyguardShowingOccluded=false, which falls through to other activity input consumer. In this state, we can't properly finish the gesture stream because Launcher never shows (it's behind the lockscreen) and the recents animation never finishes. Bug: 242704576 Test: atest NexusLauncherTests Change-Id: I7795abe0aebefca2d42998a672abfd12f951d501 --- .../src/com/android/quickstep/RecentsAnimationDeviceState.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java index 99a02e15ce..8d17cf4b81 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java @@ -41,6 +41,7 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_O import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED; import android.app.ActivityManager; @@ -419,6 +420,7 @@ public class RecentsAnimationDeviceState implements || mRotationTouchHelper.isTaskListFrozen(); return canStartWithNavHidden && (mSystemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) == 0 + && (mSystemUiStateFlags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING) == 0 && (mSystemUiStateFlags & SYSUI_STATE_QUICK_SETTINGS_EXPANDED) == 0 && (mSystemUiStateFlags & SYSUI_STATE_MAGNIFICATION_OVERLAP) == 0 && ((mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) == 0 From beecffed7caebe0186f852826acaee2c717b0f29 Mon Sep 17 00:00:00 2001 From: Nicolo' Mazzucato Date: Fri, 20 Jan 2023 12:28:33 +0000 Subject: [PATCH 2/4] Fix CUJ_RECENTS_SCROLLING The atom was output also when swiping from the bottom to open overview. Now, it's only reported on horizontal swipes between tasks. Fixes: 265790869 Test: checked perfetto traces Change-Id: Ic70f440a30ea2c61e44f84098d84b0485a85905e --- quickstep/src/com/android/quickstep/views/RecentsView.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index c11f7ed27a..2726cc3817 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -1351,8 +1351,10 @@ public abstract class RecentsView Date: Tue, 17 Jan 2023 09:41:10 -0800 Subject: [PATCH 3/4] Support desktop tasks in recents animation Desktop tasks are using freeform windowing mode. Update recents animation to support freeform tasks when desktop mode feature flag is enabled. Changes: - set initial size for freeform tasks to be the size of the thumbnail instead of size of the screen - support multiple individual remote animation targets when starting the recents animation TODO: - there are flickers when starting and ending the recents animation Bug: 263264985 Test: swipe up when more than 1 desktop task is visible Change-Id: I27ee02774281b3a433d779c0bb8825cdb6ea5457 --- .../android/quickstep/AbsSwipeUpHandler.java | 7 +- .../quickstep/RecentsAnimationTargets.java | 22 +++++++ .../android/quickstep/RemoteTargetGluer.java | 66 +++++++++++++++++-- .../com/android/quickstep/SystemUiProxy.java | 12 ++++ .../com/android/quickstep/TaskViewUtils.java | 9 ++- .../quickstep/util/TaskViewSimulator.java | 15 +++++ .../android/quickstep/views/RecentsView.java | 13 +++- 7 files changed, 134 insertions(+), 10 deletions(-) diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 45f6742bb8..73fbcd6dad 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -127,6 +127,7 @@ import com.android.quickstep.util.SurfaceTransaction; import com.android.quickstep.util.SurfaceTransactionApplier; import com.android.quickstep.util.SwipePipToHomeAnimator; import com.android.quickstep.util.TaskViewSimulator; +import com.android.quickstep.views.DesktopTaskView; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.Task; @@ -877,7 +878,11 @@ public abstract class AbsSwipeUpHandler, public void onRecentsAnimationStart(RecentsAnimationController controller, RecentsAnimationTargets targets) { super.onRecentsAnimationStart(controller, targets); - mRemoteTargetHandles = mTargetGluer.assignTargetsForSplitScreen(mContext, targets); + if (DesktopTaskView.DESKTOP_MODE_SUPPORTED && targets.hasDesktopTasks()) { + mRemoteTargetHandles = mTargetGluer.assignTargetsForDesktop(targets); + } else { + mRemoteTargetHandles = mTargetGluer.assignTargetsForSplitScreen(mContext, targets); + } mRecentsAnimationController = controller; mRecentsAnimationTargets = targets; mSwipePipToHomeReleaseCheck = new RemoteAnimationTargets.ReleaseCheck(); diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java index 388e1256d8..15e1365998 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java @@ -15,11 +15,15 @@ */ package com.android.quickstep; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.view.RemoteAnimationTarget.MODE_CLOSING; +import android.app.WindowConfiguration; import android.graphics.Rect; import android.view.RemoteAnimationTarget; +import com.android.quickstep.views.DesktopTaskView; + /** * Extension of {@link RemoteAnimationTargets} with additional information about swipe * up animation @@ -40,4 +44,22 @@ public class RecentsAnimationTargets extends RemoteAnimationTargets { public boolean hasTargets() { return unfilteredApps.length != 0; } + + /** + * Check if target apps contain desktop tasks which have windowing mode set to {@link + * WindowConfiguration#WINDOWING_MODE_FREEFORM} + * + * @return {@code true} if at least one target app is a desktop task + */ + public boolean hasDesktopTasks() { + if (!DesktopTaskView.DESKTOP_MODE_SUPPORTED) { + return false; + } + for (RemoteAnimationTarget target : apps) { + if (target.windowConfiguration.getWindowingMode() == WINDOWING_MODE_FREEFORM) { + return true; + } + } + return false; + } } diff --git a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java index 4c41bef26a..9b00dcf765 100644 --- a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java +++ b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java @@ -26,6 +26,7 @@ import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds; import com.android.quickstep.util.AnimatorControllerWithResistance; import com.android.quickstep.util.TaskViewSimulator; import com.android.quickstep.util.TransformParams; +import com.android.quickstep.views.DesktopTaskView; import java.util.ArrayList; @@ -41,8 +42,8 @@ public class RemoteTargetGluer { * Use this constructor if remote targets are split-screen independent */ public RemoteTargetGluer(Context context, BaseActivityInterface sizingStrategy, - RemoteAnimationTargets targets) { - mRemoteTargetHandles = createHandles(context, sizingStrategy, targets.apps.length); + RemoteAnimationTargets targets, boolean forDesktop) { + init(context, sizingStrategy, targets.apps.length, forDesktop); } /** @@ -50,15 +51,31 @@ public class RemoteTargetGluer { * running tasks */ public RemoteTargetGluer(Context context, BaseActivityInterface sizingStrategy) { + if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) { + // TODO: binder call, only for prototyping. Creating the gluer should be postponed so + // we can create it when we have the remote animation targets ready. + int desktopTasks = SystemUiProxy.INSTANCE.get(context).getVisibleDesktopTaskCount(); + if (desktopTasks > 0) { + init(context, sizingStrategy, desktopTasks, true /* forDesktop */); + return; + } + } + int[] splitIds = TopTaskTracker.INSTANCE.get(context).getRunningSplitTaskIds(); - mRemoteTargetHandles = createHandles(context, sizingStrategy, splitIds.length == 2 ? 2 : 1); + init(context, sizingStrategy, splitIds.length == 2 ? 2 : 1, false /* forDesktop */); + } + + private void init(Context context, BaseActivityInterface sizingStrategy, int numHandles, + boolean forDesktop) { + mRemoteTargetHandles = createHandles(context, sizingStrategy, numHandles, forDesktop); } private RemoteTargetHandle[] createHandles(Context context, - BaseActivityInterface sizingStrategy, int numHandles) { + BaseActivityInterface sizingStrategy, int numHandles, boolean forDesktop) { RemoteTargetHandle[] handles = new RemoteTargetHandle[numHandles]; for (int i = 0; i < numHandles; i++) { TaskViewSimulator tvs = new TaskViewSimulator(context, sizingStrategy); + tvs.setIsDesktopTask(forDesktop); TransformParams transformParams = new TransformParams(); handles[i] = new RemoteTargetHandle(tvs, transformParams); } @@ -135,6 +152,20 @@ public class RemoteTargetGluer { return mRemoteTargetHandles; } + /** + * Similar to {@link #assignTargets(RemoteAnimationTargets)}, except this creates distinct + * transform params per app in {@code targets.apps} list. + */ + public RemoteTargetHandle[] assignTargetsForDesktop(RemoteAnimationTargets targets) { + for (int i = 0; i < mRemoteTargetHandles.length; i++) { + RemoteAnimationTarget primaryTaskTarget = targets.apps[i]; + mRemoteTargetHandles[i].mTransformParams.setTargetSet( + createRemoteAnimationTargetsForTaskId(targets, primaryTaskTarget.taskId)); + mRemoteTargetHandles[i].mTaskViewSimulator.setPreview(primaryTaskTarget, null); + } + return mRemoteTargetHandles; + } + private Rect getStartBounds(RemoteAnimationTarget target) { return target.startBounds == null ? target.screenSpaceBounds : target.startBounds; } @@ -172,6 +203,33 @@ public class RemoteTargetGluer { filteredApps, targets.wallpapers, targets.nonApps, targets.targetMode); } + /** + * Ensures that we only animate one specific app target. Includes ancillary targets such as + * home/recents + * + * @param targets remote animation targets to filter + * @param taskId id for a task that we want this remote animation to apply to + * @return {@link RemoteAnimationTargets} where app target only includes the app that has the + * {@code taskId} that was passed in + */ + private RemoteAnimationTargets createRemoteAnimationTargetsForTaskId( + RemoteAnimationTargets targets, int taskId) { + RemoteAnimationTarget[] targetApp = null; + for (RemoteAnimationTarget targetCompat : targets.unfilteredApps) { + if (targetCompat.taskId == taskId) { + targetApp = new RemoteAnimationTarget[]{targetCompat}; + break; + } + } + + if (targetApp == null) { + targetApp = new RemoteAnimationTarget[0]; + } + + return new RemoteAnimationTargets(targetApp, targets.wallpapers, targets.nonApps, + targets.targetMode); + } + public RemoteTargetHandle[] getRemoteTargetHandles() { return mRemoteTargetHandles; } diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java index bb973342d5..abca46a985 100644 --- a/quickstep/src/com/android/quickstep/SystemUiProxy.java +++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java @@ -952,4 +952,16 @@ public class SystemUiProxy implements ISystemUiProxy { } } } + + /** Call shell to get number of visible freeform tasks */ + public int getVisibleDesktopTaskCount() { + if (mDesktopMode != null) { + try { + return mDesktopMode.getVisibleTaskCount(); + } catch (RemoteException e) { + Log.w(TAG, "Failed call getVisibleDesktopTaskCount", e); + } + } + return 0; + } } diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java index 67de4b1679..1a72e3f746 100644 --- a/quickstep/src/com/android/quickstep/TaskViewUtils.java +++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java @@ -39,6 +39,7 @@ 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.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE; +import static com.android.quickstep.views.DesktopTaskView.DESKTOP_MODE_SUPPORTED; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -78,6 +79,7 @@ import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties; import com.android.quickstep.util.SurfaceTransactionApplier; import com.android.quickstep.util.TaskViewSimulator; import com.android.quickstep.util.TransformParams; +import com.android.quickstep.views.DesktopTaskView; import com.android.quickstep.views.GroupedTaskView; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskThumbnailView; @@ -182,9 +184,12 @@ public final class TaskViewUtils { // Re-use existing handles remoteTargetHandles = recentsViewHandles; } else { + boolean forDesktop = DESKTOP_MODE_SUPPORTED && v instanceof DesktopTaskView; RemoteTargetGluer gluer = new RemoteTargetGluer(v.getContext(), - recentsView.getSizeStrategy(), targets); - if (v.containsMultipleTasks()) { + recentsView.getSizeStrategy(), targets, forDesktop); + if (forDesktop) { + remoteTargetHandles = gluer.assignTargetsForDesktop(targets); + } else if (v.containsMultipleTasks()) { remoteTargetHandles = gluer.assignTargetsForSplitScreen(targets, v.getTaskIds()); } else { remoteTargetHandles = gluer.assignTargets(targets); diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java index 04af19f729..69f9ce3447 100644 --- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java +++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java @@ -104,6 +104,7 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { private SplitBounds mSplitBounds; private Boolean mDrawsBelowRecents = null; private boolean mIsGridTask; + private boolean mIsDesktopTask; private int mTaskRectTranslationX; private int mTaskRectTranslationY; @@ -145,6 +146,13 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { if (mDp == null) { return 1; } + + if (mIsDesktopTask) { + mTaskRect.set(mThumbnailPosition); + mPivot.set(mTaskRect.centerX(), mTaskRect.centerY()); + return 1; + } + if (mIsGridTask) { mSizeStrategy.calculateGridTaskSize(mContext, mDp, mTaskRect, mOrientationState.getOrientationHandler()); @@ -227,6 +235,13 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { mIsGridTask = isGridTask; } + /** + * Sets whether this task is part of desktop tasks in overview. + */ + public void setIsDesktopTask(boolean desktop) { + mIsDesktopTask = desktop; + } + /** * Apply translations on TaskRect's starting location. */ diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index c11f7ed27a..f3e2e7963e 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -4909,9 +4909,16 @@ public abstract class RecentsView Date: Sun, 22 Jan 2023 09:55:13 -0800 Subject: [PATCH 4/4] Only interrupt taskbar state during gesture. We only want to prevent updating taskbar stash state during the swipe-to-overview gesture. Previously, we were blocking all resumes into a "non-aligned-with-hotseat" state to prevent the taskbar from hiding until the gesture completed. This, however, also selected for situations where the launcher is resumed directly into Overview outside of a transition (which is triggered by some Tapl tests). This narrows the check to only when resuming into a non-interactive state (which basically just selects for BackgroundApp state). Bug: 266246618 Test: TaplTestsQuickstep on a device with taskbar Change-Id: I414ba7384f4ca3901211855b26c6c200319a2996 --- .../launcher3/taskbar/LauncherTaskbarUIController.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java index 335482c854..edb87219c4 100644 --- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java @@ -19,6 +19,7 @@ import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR; import static com.android.launcher3.QuickstepTransitionManager.TRANSIENT_TASKBAR_TRANSITION_DURATION; import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_EDU_TOOLTIP; +import static com.android.launcher3.statemanager.BaseState.FLAG_NON_INTERACTIVE; import static com.android.launcher3.taskbar.TaskbarEduTooltipControllerKt.TOOLTIP_STEP_FEATURES; import static com.android.launcher3.taskbar.TaskbarLauncherStateController.FLAG_RESUMED; import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS; @@ -181,10 +182,12 @@ public class LauncherTaskbarUIController extends TaskbarUIController { } } + // Launcher is resumed during the swipe-to-overview gesture under shell-transitions, so + // avoid updating taskbar state in that situation (when it's non-interactive -- or + // "background") to avoid premature animations. if (ENABLE_SHELL_TRANSITIONS && isResumed + && mLauncher.getStateManager().getState().hasFlag(FLAG_NON_INTERACTIVE) && !mLauncher.getStateManager().getState().isTaskbarAlignedWithHotseat(mLauncher)) { - // Launcher is resumed, but in a state where taskbar is still independent, so - // ignore the state change. return null; }