desktop-exploded-view: Implement the activate window behavior

Clicking on one task window in the desktop exploded view, it should
activate that task window.

Flag: com.android.launcher3.enable_desktop_exploded_view
Test: Manual
Bug: 353948437, 410888109
Change-Id: I1836bf0babcec039ef76b13ecd40f87a8ab4d822
This commit is contained in:
Xiaoqian Dai
2025-03-03 23:40:15 +00:00
parent 4753b6e83e
commit 107f85d20c
6 changed files with 96 additions and 22 deletions
@@ -46,10 +46,14 @@ class DesktopRecentsTransitionController(
private val depthController: DepthController?,
) {
/** Launch desktop tasks from recents view */
/**
* Launch desktop tasks from recents view and activate the new freeform task with id
* [taskIdToReorderToFront] if it's provided and already on the given desk.
*/
fun launchDesktopFromRecents(
desktopTaskView: DesktopTaskView,
animated: Boolean,
taskIdToReorderToFront: Int? = null,
callback: Consumer<Boolean>? = null,
) {
val animRunner =
@@ -62,9 +66,13 @@ class DesktopRecentsTransitionController(
)
val transition = RemoteTransition(animRunner, appThread, "RecentsToDesktop")
if (areMultiDesksFlagsEnabled()) {
systemUiProxy.activateDesk(desktopTaskView.deskId, transition)
systemUiProxy.activateDesk(desktopTaskView.deskId, transition, taskIdToReorderToFront)
} else {
systemUiProxy.showDesktopApps(desktopTaskView.displayId, transition)
systemUiProxy.showDesktopApps(
desktopTaskView.displayId,
transition,
taskIdToReorderToFront,
)
}
}
@@ -18,6 +18,7 @@ package com.android.quickstep
import android.app.ActivityManager
import android.app.ActivityManager.RunningTaskInfo
import android.app.ActivityOptions
import android.app.ActivityTaskManager.INVALID_TASK_ID
import android.app.PendingIntent
import android.content.ComponentName
import android.content.Context
@@ -1109,11 +1110,18 @@ class SystemUiProxy @Inject constructor(@ApplicationContext private val context:
/**
* Calls shell to activate the desk whose ID is `deskId` on whatever display it exists on. This
* will bring all tasks on this desk to the front.
* will show all tasks on this desk and bring [taskIdToReorderToFront] to the front if it's
* provided and already on the given desk. If the provided [taskIdToReorderToFront]'s value is
* null, do not change the windows' activation on the desk.
*/
fun activateDesk(deskId: Int, transition: RemoteTransition?) =
@JvmOverloads
fun activateDesk(
deskId: Int,
transition: RemoteTransition?,
taskIdToReorderToFront: Int? = null,
) =
executeWithErrorLog({ "Failed call activateDesk" }) {
desktopMode?.activateDesk(deskId, transition)
desktopMode?.activateDesk(deskId, transition, taskIdToReorderToFront ?: INVALID_TASK_ID)
}
/** Calls shell to remove the desk whose ID is `deskId`. */
@@ -1124,10 +1132,23 @@ class SystemUiProxy @Inject constructor(@ApplicationContext private val context:
fun removeAllDesks() =
executeWithErrorLog({ "Failed call removeAllDesks" }) { desktopMode?.removeAllDesks() }
/** Call shell to show all apps active on the desktop */
fun showDesktopApps(displayId: Int, transition: RemoteTransition?) =
/**
* Call shell to show all apps active on the desktop and bring [taskIdToReorderToFront] to front
* if it's valid on the default desk on the given display. If the provided
* [taskIdToReorderToFront]'s value is null, do not change the windows' activation on the desk.
*/
@JvmOverloads
fun showDesktopApps(
displayId: Int,
transition: RemoteTransition? = null,
taskIdToReorderToFront: Int? = null,
) =
executeWithErrorLog({ "Failed call showDesktopApps" }) {
desktopMode?.showDesktopApps(displayId, transition)
desktopMode?.showDesktopApps(
displayId,
transition,
taskIdToReorderToFront ?: INVALID_TASK_ID,
)
}
/** If task with the given id is on the desktop, bring it to front */
@@ -678,6 +678,13 @@ public final class TaskViewUtils {
// interfere with a rapid swipe up to home in the live tile + running task case.
@Override
public void onAnimationSuccess(Animator animation) {
// If we're relaunching the desktop tile when already entering Overview from
// desktop, no need to change the launcher visibility and taskbar visibility
// below.
boolean launchingLiveDesktop = v instanceof DesktopTaskView desktopTaskView
&& desktopTaskView.isRunningTask()
&& recentsView.getRemoteTargetHandles() != null;
recentsView.finishRecentsAnimation(false /* toRecents */, () -> {
recentsView.post(() -> {
stateManager.moveToRestState();
@@ -688,7 +695,7 @@ public final class TaskViewUtils {
// that launcher is still visible.
TaskbarUIController controller = recentsView.getSizeStrategy()
.getTaskbarController();
if (controller != null) {
if (controller != null && !launchingLiveDesktop) {
boolean launcherVisible = true;
for (RemoteAnimationTarget target : appTargets) {
launcherVisible &= target.isTranslucent;
@@ -116,6 +116,7 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy {
private int mOrientationStateId;
private SplitBounds mSplitBounds;
private Boolean mDrawsBelowRecents = null;
private Boolean mDrawAboveOtherApps = null;
private boolean mIsGridTask;
private final boolean mIsDesktopTask;
private boolean mIsAnimatingToCarousel = false;
@@ -304,6 +305,15 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy {
mIsGridTask = isGridTask;
}
/**
* Sets whether drawing this app above other apps during animation. It's currently used when
* activating an app window from the exploded desktop view which will launch the desktop tile
* and exit Overview.
*/
public void setDrawsAboveOtherApps(boolean drawsAboveOtherApps) {
mDrawAboveOtherApps = drawsAboveOtherApps;
}
/**
* Apply translations on TaskRect's starting location.
*/
@@ -544,15 +554,22 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy {
.setWindowCrop(mTmpCropRect)
.setCornerRadius(getCurrentCornerRadius());
// If mDrawsBelowRecents is unset, no reordering will be enforced.
if (mDrawsBelowRecents != null) {
// In shell transitions, the animation leashes are reparented to an animation container
// so we can bump layers as needed.
builder.setLayer(mDrawsBelowRecents
// 1000 is an arbitrary number to give room for multiple layers.
? Integer.MIN_VALUE + 1000 + app.prefixOrderIndex - mDesktopTaskIndex
: Integer.MAX_VALUE - 1000 + app.prefixOrderIndex - mDesktopTaskIndex);
if (mDrawsBelowRecents == null && mDrawAboveOtherApps == null) {
// No reordering will be enforced.
return;
}
// In shell transitions, the animation leashes are reparented to an animation container
// so we can bump layers as needed.
int baseLayer = app.prefixOrderIndex - mDesktopTaskIndex;
// 1000/2000 are arbitrary numbers to give room for multiple layers.
if (mDrawsBelowRecents != null) {
baseLayer += mDrawsBelowRecents ? Integer.MIN_VALUE + 2000 : Integer.MAX_VALUE - 2000;
}
if (mDrawAboveOtherApps != null && mDrawAboveOtherApps) {
baseLayer += 1000;
}
builder.setLayer(baseLayer);
}
/**
@@ -402,6 +402,11 @@ class DesktopTaskView @JvmOverloads constructor(context: Context, attrs: Attribu
} else {
taskContentView
}
if (enableDesktopExplodedView()) {
snapshotView.setOnClickListener {
launchTaskWithDesktopController(animated = true, task.key.id)
}
}
TaskContainer(
this,
@@ -481,7 +486,15 @@ class DesktopTaskView @JvmOverloads constructor(context: Context, attrs: Attribu
}
}
private fun launchTaskWithDesktopController(animated: Boolean): RunnableList? {
/**
* Launches the desktop task and activate the task with [taskIdToReorderToFront] if it's
* provided and already on the desktop. It will exit Overview to desktop and activate the
* according new task afterwards if applicable.
*/
private fun launchTaskWithDesktopController(
animated: Boolean,
taskIdToReorderToFront: Int? = null,
): RunnableList? {
val recentsView = recentsView ?: return null
TestLogging.recordEvent(
TestProtocol.SEQUENCE_MAIN,
@@ -492,8 +505,17 @@ class DesktopTaskView @JvmOverloads constructor(context: Context, attrs: Attribu
val desktopController = recentsView.desktopRecentsController
checkNotNull(desktopController) { "recentsController is null" }
if (taskIdToReorderToFront != null) {
// The to-be-activated window should animate on top of other apps during shell
// transition.
val remoteTargetHandle = getRemoteTargetHandle(taskIdToReorderToFront)
// The layer swapping is only applied after [createRecentsWindowAnimator] starts, which
// will bring the [remoteTargetHandles] above Recents, therefore this call won't affect
// the base surface in [DepthController].
remoteTargetHandle?.taskViewSimulator?.setDrawsAboveOtherApps(true)
}
val launchDesktopFromRecents = {
desktopController.launchDesktopFromRecents(this, animated) {
desktopController.launchDesktopFromRecents(this, animated, taskIdToReorderToFront) {
endCallback.executeAllAndDestroy()
}
}
@@ -302,8 +302,7 @@ public class LauncherRecentsView extends RecentsView<QuickstepLauncher, Launcher
desktopVisibilityController.setRecentsGestureEnd(endTarget);
}
if (showDesktopApps) {
SystemUiProxy.INSTANCE.get(mContainer).showDesktopApps(mContainer.getDisplayId(),
null /* transition */);
SystemUiProxy.INSTANCE.get(mContainer).showDesktopApps(mContainer.getDisplayId());
}
}
}