From 30678745593ee9f8166768b9d879a933cff92092 Mon Sep 17 00:00:00 2001 From: Ats Jenk Date: Thu, 18 May 2023 09:07:04 -0700 Subject: [PATCH] Support alt+tab for desktop tasks Updates keyboard quickswitch logic handle quickswitching while on desktop. When on desktop, alt+tab moves only between desktop tasks. Fullscreen tasks are shown in the overflow tile and can be accessed by going to overview. TODO: - when not in desktop and using quickswitch, show the desktop tile as a combined tile in the row, similar to what is shown in overview Flag: persist.wm.debug.desktop_mode_2 Bug: 280468885 Test: open some apps on desktop and have some fullscreen apps opened in the background, when on desktop, observe that alt+tab only switches between desktop tasks Test: same setup, but switch to a fullscreen app, observe that alt+tab only switches between fullscreen tasks and desktop is accessible from overview Change-Id: Ib19f2eaa24363bbd0669c8c8c3d99ed9d9118a17 --- .../KeyboardQuickSwitchController.java | 76 ++++++++++++++++--- .../taskbar/KeyboardQuickSwitchView.java | 8 +- .../KeyboardQuickSwitchViewController.java | 11 ++- .../quickstep/OverviewCommandHelper.java | 6 -- .../android/quickstep/RecentTasksList.java | 1 - .../com/android/quickstep/SystemUiProxy.java | 13 ++++ .../com/android/quickstep/util/GroupTask.java | 4 + 7 files changed, 100 insertions(+), 19 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java index 7f655cf231..ae1c979034 100644 --- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java +++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java @@ -22,9 +22,13 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.launcher3.R; +import com.android.launcher3.statehandlers.DesktopVisibilityController; import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext; +import com.android.quickstep.LauncherActivityInterface; import com.android.quickstep.RecentsModel; +import com.android.quickstep.util.DesktopTask; import com.android.quickstep.util.GroupTask; +import com.android.quickstep.views.DesktopTaskView; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.ThumbnailData; @@ -102,21 +106,75 @@ public final class KeyboardQuickSwitchController implements mQuickSwitchViewController = new KeyboardQuickSwitchViewController( mControllers, overlayContext, keyboardQuickSwitchView, mControllerCallbacks); + DesktopVisibilityController desktopController = + LauncherActivityInterface.INSTANCE.getDesktopVisibilityController(); + final boolean onDesktop = + DesktopTaskView.DESKTOP_IS_PROTO2_ENABLED + && desktopController != null + && desktopController.areFreeformTasksVisible(); + if (mModel.isTaskListValid(mTaskListChangeId)) { - mQuickSwitchViewController.openQuickSwitchView( - mTasks, mNumHiddenTasks, /* updateTasks= */ false, currentFocusedIndex); + mQuickSwitchViewController.openQuickSwitchView(mTasks, + mNumHiddenTasks, /* updateTasks= */ false, currentFocusedIndex, onDesktop); return; } + mTaskListChangeId = mModel.getTasks((tasks) -> { - // Only store MAX_TASK tasks, from most to least recent - Collections.reverse(tasks); - mTasks = tasks.stream().limit(MAX_TASKS).collect(Collectors.toList()); - mNumHiddenTasks = Math.max(0, tasks.size() - MAX_TASKS); - mQuickSwitchViewController.openQuickSwitchView( - mTasks, mNumHiddenTasks, /* updateTasks= */ true, currentFocusedIndex); + if (onDesktop) { + processLoadedTasksOnDesktop(tasks); + } else { + processLoadedTasks(tasks); + } + mQuickSwitchViewController.openQuickSwitchView(mTasks, + mNumHiddenTasks, /* updateTasks= */ true, currentFocusedIndex, onDesktop); }); } + private void processLoadedTasks(ArrayList tasks) { + // Only store MAX_TASK tasks, from most to least recent + Collections.reverse(tasks); + + // Hide all desktop tasks and show them on the hidden tile + int hiddenDesktopTasks = 0; + if (DesktopTaskView.DESKTOP_IS_PROTO2_ENABLED) { + // TODO(b/280468885): show desktop task as a grouped desktop tile + DesktopTask desktopTask = findDesktopTask(tasks); + if (desktopTask != null) { + hiddenDesktopTasks = desktopTask.tasks.size(); + tasks = tasks.stream() + .filter(t -> !(t instanceof DesktopTask)) + .collect(Collectors.toCollection(ArrayList::new)); + } + } + mTasks = tasks.stream() + .limit(MAX_TASKS) + .collect(Collectors.toList()); + mNumHiddenTasks = Math.max(0, tasks.size() - MAX_TASKS) + hiddenDesktopTasks; + } + + private void processLoadedTasksOnDesktop(ArrayList tasks) { + // Find the single desktop task that contains a grouping of desktop tasks + DesktopTask desktopTask = findDesktopTask(tasks); + + if (desktopTask != null) { + mTasks = desktopTask.tasks.stream().map(GroupTask::new).collect(Collectors.toList()); + // All other tasks, apart from the grouped desktop task, are hidden + mNumHiddenTasks = Math.max(0, tasks.size() - 1); + } else { + // Desktop tasks were visible, but the recents entry is missing. Fall back to empty list + mTasks = Collections.emptyList(); + mNumHiddenTasks = tasks.size(); + } + } + + @Nullable + private DesktopTask findDesktopTask(ArrayList tasks) { + return (DesktopTask) tasks.stream() + .filter(t -> t instanceof DesktopTask) + .findFirst() + .orElse(null); + } + void closeQuickSwitchView() { if (mQuickSwitchViewController == null) { return; @@ -169,7 +227,7 @@ public final class KeyboardQuickSwitchController implements class ControllerCallbacks { int getTaskCount() { - return mNumHiddenTasks == 0 ? mTasks.size() : MAX_TASKS + 1; + return mTasks.size() + (mNumHiddenTasks == 0 ? 0 : 1); } @Nullable diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java index 2cdfb18dc5..15f2914ae4 100644 --- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java +++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java @@ -190,8 +190,12 @@ public class KeyboardQuickSwitchView extends ConstraintLayout { ConstraintLayout.LayoutParams lp = new ConstraintLayout.LayoutParams( width, mTaskViewHeight); - lp.endToEnd = PARENT_ID; - lp.startToEnd = previousView.getId(); + if (previousView == null) { + lp.startToStart = PARENT_ID; + } else { + lp.endToEnd = PARENT_ID; + lp.startToEnd = previousView.getId(); + } lp.topToTop = PARENT_ID; lp.bottomToBottom = PARENT_ID; lp.setMarginEnd(mSpacing); diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java index 7bd8898dfc..edb71a59ff 100644 --- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java @@ -27,6 +27,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext; import com.android.launcher3.taskbar.overlay.TaskbarOverlayDragLayer; +import com.android.quickstep.SystemUiProxy; import com.android.quickstep.util.GroupTask; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.ThumbnailData; @@ -52,6 +53,8 @@ public class KeyboardQuickSwitchViewController { private int mCurrentFocusIndex = -1; + private boolean mOnDesktop; + protected KeyboardQuickSwitchViewController( @NonNull TaskbarControllers controllers, @NonNull TaskbarOverlayContext overlayContext, @@ -71,10 +74,12 @@ public class KeyboardQuickSwitchViewController { @NonNull List tasks, int numHiddenTasks, boolean updateTasks, - int currentFocusIndexOverride) { + int currentFocusIndexOverride, + boolean onDesktop) { TaskbarOverlayDragLayer dragLayer = mOverlayContext.getDragLayer(); dragLayer.addView(mKeyboardQuickSwitchView); dragLayer.runOnClickOnce(v -> closeQuickSwitchView(true)); + mOnDesktop = onDesktop; mKeyboardQuickSwitchView.applyLoadPlan( mOverlayContext, @@ -136,6 +141,10 @@ public class KeyboardQuickSwitchViewController { GroupTask task = mControllerCallbacks.getTaskAt(index); if (task == null) { return Math.max(0, index); + } else if (mOnDesktop) { + UI_HELPER_EXECUTOR.execute(() -> + SystemUiProxy.INSTANCE.get(mKeyboardQuickSwitchView.getContext()) + .showDesktopApp(task.task1.key.id)); } else if (task.task2 == null) { UI_HELPER_EXECUTOR.execute(() -> ActivityManagerWrapper.getInstance().startActivityFromRecents( diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java index 07db194ff4..a0d49a4f7e 100644 --- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java +++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java @@ -37,7 +37,6 @@ import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.taskbar.TaskbarUIController; import com.android.launcher3.util.RunnableList; import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener; -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.ThumbnailData; @@ -186,11 +185,6 @@ public class OverviewCommandHelper { && dp != null && (dp.isTablet || dp.isTwoPanels); - if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) { - // TODO(b/268075592): add support for quickswitch to/from desktop - allowQuickSwitch = false; - } - if (cmd.type == TYPE_HIDE) { if (!allowQuickSwitch) { return true; diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java index 38ac5bb9e2..34817c087b 100644 --- a/quickstep/src/com/android/quickstep/RecentTasksList.java +++ b/quickstep/src/com/android/quickstep/RecentTasksList.java @@ -308,7 +308,6 @@ public class RecentTasksList { task.setLastSnapshotData(taskInfo); task.positionInParent = taskInfo.positionInParent; task.appBounds = taskInfo.configuration.windowConfiguration.getAppBounds(); - // TODO(b/244348395): tasks should be sorted from oldest to most recently used tasks.add(task); } return new DesktopTask(tasks); diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java index 380aa69a1c..61fabe4fd9 100644 --- a/quickstep/src/com/android/quickstep/SystemUiProxy.java +++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java @@ -1186,6 +1186,19 @@ public class SystemUiProxy implements ISystemUiProxy { } } + /** + * If task with the given id is on the desktop, bring it to front + */ + public void showDesktopApp(int taskId) { + if (mDesktopMode != null) { + try { + mDesktopMode.showDesktopApp(taskId); + } catch (RemoteException e) { + Log.w(TAG, "Failed call showDesktopApp", e); + } + } + } + /** Call shell to get number of visible freeform tasks */ public int getVisibleDesktopTaskCount(int displayId) { if (mDesktopMode != null) { diff --git a/quickstep/src/com/android/quickstep/util/GroupTask.java b/quickstep/src/com/android/quickstep/util/GroupTask.java index 2be4f0a519..9c49647c41 100644 --- a/quickstep/src/com/android/quickstep/util/GroupTask.java +++ b/quickstep/src/com/android/quickstep/util/GroupTask.java @@ -37,6 +37,10 @@ public class GroupTask { @TaskView.Type public final int taskViewType; + public GroupTask(@NonNull Task task) { + this(task, null, null); + } + public GroupTask(@NonNull Task t1, @Nullable Task t2, @Nullable SplitBounds splitBounds) { this(t1, t2, splitBounds, t2 != null ? TaskView.Type.GROUPED : TaskView.Type.SINGLE); }