diff options
7 files changed, 139 insertions, 1 deletions
diff --git a/core/api/test-current.txt b/core/api/test-current.txt index b59b9d05b642..20a7ce4015fd 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -3388,6 +3388,7 @@ package android.window { method @NonNull public android.window.WindowContainerTransaction createTaskFragment(@NonNull android.window.TaskFragmentCreationParams); method @NonNull public android.window.WindowContainerTransaction deleteTaskFragment(@NonNull android.window.WindowContainerToken); method public int describeContents(); + method @NonNull public android.window.WindowContainerTransaction removeTask(@NonNull android.window.WindowContainerToken); method @NonNull public android.window.WindowContainerTransaction reorder(@NonNull android.window.WindowContainerToken, boolean); method @NonNull public android.window.WindowContainerTransaction reparent(@NonNull android.window.WindowContainerToken, @Nullable android.window.WindowContainerToken, boolean); method @NonNull public android.window.WindowContainerTransaction reparentActivityToTaskFragment(@NonNull android.os.IBinder, @NonNull android.os.IBinder); diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java index d3949b211b39..9ebdea82593b 100644 --- a/core/java/android/window/WindowContainerTransaction.java +++ b/core/java/android/window/WindowContainerTransaction.java @@ -456,6 +456,17 @@ public final class WindowContainerTransaction implements Parcelable { } /** + * Finds and removes a task and its children using its container token. The task is removed + * from recents. + * @param containerToken ContainerToken of Task to be removed + */ + @NonNull + public WindowContainerTransaction removeTask(@NonNull WindowContainerToken containerToken) { + mHierarchyOps.add(HierarchyOp.createForRemoveTask(containerToken.asBinder())); + return this; + } + + /** * Sends a pending intent in sync. * @param sender The PendingIntent sender. * @param intent The fillIn intent to patch over the sender's base intent. @@ -1153,6 +1164,7 @@ public final class WindowContainerTransaction implements Parcelable { public static final int HIERARCHY_OP_TYPE_REMOVE_INSETS_PROVIDER = 17; public static final int HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT = 18; public static final int HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP = 19; + public static final int HIERARCHY_OP_TYPE_REMOVE_TASK = 20; // The following key(s) are for use with mLaunchOptions: // When launching a task (eg. from recents), this is the taskId to be launched. @@ -1282,6 +1294,13 @@ public final class WindowContainerTransaction implements Parcelable { .build(); } + /** create a hierarchy op for deleting a task **/ + public static HierarchyOp createForRemoveTask(@NonNull IBinder container) { + return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REMOVE_TASK) + .setContainer(container) + .build(); + } + /** Only creates through {@link Builder}. */ private HierarchyOp(int type) { mType = type; @@ -1465,6 +1484,8 @@ public final class WindowContainerTransaction implements Parcelable { case HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP: return "{setAlwaysOnTop: container=" + mContainer + " alwaysOnTop=" + mAlwaysOnTop + "}"; + case HIERARCHY_OP_TYPE_REMOVE_TASK: + return "{RemoveTask: task=" + mContainer + "}"; default: return "{mType=" + mType + " container=" + mContainer + " reparent=" + mReparent + " mToTop=" + mToTop diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java index dd50fa0817c2..fd4c85fad77f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java @@ -92,6 +92,12 @@ public class FreeformTaskTransitionHandler @Override + public void startRemoveTransition(WindowContainerTransaction wct) { + final int type = WindowManager.TRANSIT_CLOSE; + mPendingTransitionTokens.add(mTransitions.startTransition(type, wct, this)); + } + + @Override public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startT, @NonNull SurfaceControl.Transaction finishT, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionStarter.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionStarter.java index c947cf1b8cd1..8da4c6ab4b36 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionStarter.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionStarter.java @@ -40,4 +40,12 @@ public interface FreeformTaskTransitionStarter { * */ void startMinimizedModeTransition(WindowContainerTransaction wct); + + /** + * Starts close window transition + * + * @param wct the {@link WindowContainerTransaction} that closes the task + * + */ + void startRemoveTransition(WindowContainerTransaction wct); }
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java index ad539568e3eb..83aa539d24d6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java @@ -148,7 +148,13 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel<Caption public void onClick(View v) { final int id = v.getId(); if (id == R.id.close_window) { - mActivityTaskManager.removeTask(mTaskId); + WindowContainerTransaction wct = new WindowContainerTransaction(); + wct.removeTask(mTaskToken); + if (Transitions.ENABLE_SHELL_TRANSITIONS) { + mTransitionStarter.startRemoveTransition(wct); + } else { + mSyncQueue.queue(wct); + } } else if (id == R.id.maximize_window) { WindowContainerTransaction wct = new WindowContainerTransaction(); RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId); diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 34a4bf1d9c2a..5fefc3762c0d 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -29,6 +29,7 @@ import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_LAUNCH_TASK; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_PENDING_INTENT; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REMOVE_INSETS_PROVIDER; +import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REMOVE_TASK; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT; @@ -703,6 +704,12 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub @Nullable ITaskFragmentOrganizer organizer, @Nullable Transition finishTransition) { final int type = hop.getType(); switch (type) { + case HIERARCHY_OP_TYPE_REMOVE_TASK: { + final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer()); + final Task task = wc != null ? wc.asTask() : null; + task.remove(true, "Applying remove task Hierarchy Op"); + break; + } case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: { final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer()); final Task task = wc != null ? wc.asTask() : null; diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTransactionTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTransactionTests.java new file mode 100644 index 000000000000..d2552718f218 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTransactionTests.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2022 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.server.wm; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.atLeast; + +import android.content.Intent; +import android.platform.test.annotations.Presubmit; +import android.window.WindowContainerToken; +import android.window.WindowContainerTransaction; + +import androidx.annotation.NonNull; +import androidx.test.filters.SmallTest; + +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Test class for {@link WindowContainerTransaction}. + * + * Build/Install/Run: + * atest WmTests:WindowContainerTransactionTests + */ +@SmallTest +@Presubmit +@RunWith(WindowTestRunner.class) +public class WindowContainerTransactionTests extends WindowTestsBase { + + @Test + public void testRemoveTask() { + final Task rootTask = createTask(mDisplayContent); + final Task task = createTaskInRootTask(rootTask, 0 /* userId */); + final ActivityRecord activity = createActivityRecord(mDisplayContent, task); + + WindowContainerTransaction wct = new WindowContainerTransaction(); + WindowContainerToken token = task.getTaskInfo().token; + wct.removeTask(token); + applyTransaction(wct); + + // There is still an activity to be destroyed, so the task is not removed immediately. + assertNotNull(task.getParent()); + assertTrue(rootTask.hasChild()); + assertTrue(task.hasChild()); + assertTrue(activity.finishing); + + activity.destroyed("testRemoveContainer"); + // Assert that the container was removed after the activity is destroyed. + assertNull(task.getParent()); + assertEquals(0, task.getChildCount()); + assertNull(activity.getParent()); + verify(mAtm.getLockTaskController(), atLeast(1)).clearLockedTask(task); + verify(mAtm.getLockTaskController(), atLeast(1)).clearLockedTask(rootTask); + } + + private Task createTask(int taskId) { + return new Task.Builder(mAtm) + .setTaskId(taskId) + .setIntent(new Intent()) + .setRealActivity(ActivityBuilder.getDefaultComponent()) + .setEffectiveUid(10050) + .buildInner(); + } + + private void applyTransaction(@NonNull WindowContainerTransaction t) { + if (!t.isEmpty()) { + mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); + } + } +} |