diff options
15 files changed, 576 insertions, 709 deletions
diff --git a/core/api/test-current.txt b/core/api/test-current.txt index e3554a5aa043..3bc11facad4a 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -3664,14 +3664,13 @@ package android.window { ctor public WindowContainerTransaction(); method @NonNull public android.window.WindowContainerTransaction clearLaunchAdjacentFlagRoot(@NonNull android.window.WindowContainerToken); method @NonNull public android.window.WindowContainerTransaction createTaskFragment(@NonNull android.window.TaskFragmentCreationParams); - method @NonNull public android.window.WindowContainerTransaction deleteTaskFragment(@NonNull android.window.WindowContainerToken); + method @NonNull public android.window.WindowContainerTransaction deleteTaskFragment(@NonNull android.os.IBinder); method public int describeContents(); method @NonNull public android.window.WindowContainerTransaction finishActivity(@NonNull android.os.IBinder); 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); - method @NonNull public android.window.WindowContainerTransaction reparentChildren(@NonNull android.window.WindowContainerToken, @Nullable android.window.WindowContainerToken); method @NonNull public android.window.WindowContainerTransaction reparentTasks(@Nullable android.window.WindowContainerToken, @Nullable android.window.WindowContainerToken, @Nullable int[], @Nullable int[], boolean); method @NonNull public android.window.WindowContainerTransaction requestFocusOnTaskFragment(@NonNull android.os.IBinder); method @NonNull public android.window.WindowContainerTransaction scheduleFinishEnterPip(@NonNull android.window.WindowContainerToken, @NonNull android.graphics.Rect); diff --git a/core/java/android/window/TaskFragmentAnimationParams.aidl b/core/java/android/window/TaskFragmentAnimationParams.aidl index 04dee58089d4..8ae84c22dda1 100644 --- a/core/java/android/window/TaskFragmentAnimationParams.aidl +++ b/core/java/android/window/TaskFragmentAnimationParams.aidl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 The Android Open Source Project + * Copyright (C) 2023 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. diff --git a/core/java/android/window/TaskFragmentAnimationParams.java b/core/java/android/window/TaskFragmentAnimationParams.java index a600a4db42b8..12ad91498626 100644 --- a/core/java/android/window/TaskFragmentAnimationParams.java +++ b/core/java/android/window/TaskFragmentAnimationParams.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 The Android Open Source Project + * Copyright (C) 2023 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. diff --git a/core/java/android/window/TaskFragmentOperation.aidl b/core/java/android/window/TaskFragmentOperation.aidl index c21700c6634b..c1ed0c7846e3 100644 --- a/core/java/android/window/TaskFragmentOperation.aidl +++ b/core/java/android/window/TaskFragmentOperation.aidl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 The Android Open Source Project + * Copyright (C) 2023 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. diff --git a/core/java/android/window/TaskFragmentOperation.java b/core/java/android/window/TaskFragmentOperation.java index bec6c58e4c8a..3272c3bc0d09 100644 --- a/core/java/android/window/TaskFragmentOperation.java +++ b/core/java/android/window/TaskFragmentOperation.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 The Android Open Source Project + * Copyright (C) 2023 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. @@ -19,6 +19,8 @@ package android.window; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.Intent; +import android.os.Bundle; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; @@ -30,41 +32,108 @@ import java.util.Objects; /** * Data object of params for TaskFragment related {@link WindowContainerTransaction} operation. * - * @see WindowContainerTransaction#setTaskFragmentOperation(IBinder, TaskFragmentOperation). + * @see WindowContainerTransaction#addTaskFragmentOperation(IBinder, TaskFragmentOperation). * @hide */ -// TODO(b/263436063): move other TaskFragment related operation here. public final class TaskFragmentOperation implements Parcelable { + /** + * Type for tracking other {@link WindowContainerTransaction} to TaskFragment that is not set + * through {@link TaskFragmentOperation}, such as {@link WindowContainerTransaction#setBounds}. + */ + public static final int OP_TYPE_UNKNOWN = -1; + + /** Creates a new TaskFragment. */ + public static final int OP_TYPE_CREATE_TASK_FRAGMENT = 0; + + /** Deletes the given TaskFragment. */ + public static final int OP_TYPE_DELETE_TASK_FRAGMENT = 1; + + /** Starts an Activity in the given TaskFragment. */ + public static final int OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT = 2; + + /** Reparents the given Activity to the given TaskFragment. */ + public static final int OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT = 3; + + /** Sets two TaskFragments adjacent to each other. */ + public static final int OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS = 4; + + /** Requests focus on the top running Activity in the given TaskFragment. */ + public static final int OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT = 5; + + /** Sets a given TaskFragment to have a companion TaskFragment. */ + public static final int OP_TYPE_SET_COMPANION_TASK_FRAGMENT = 6; + /** Sets the {@link TaskFragmentAnimationParams} for the given TaskFragment. */ - public static final int OP_TYPE_SET_ANIMATION_PARAMS = 0; + public static final int OP_TYPE_SET_ANIMATION_PARAMS = 7; @IntDef(prefix = { "OP_TYPE_" }, value = { + OP_TYPE_UNKNOWN, + OP_TYPE_CREATE_TASK_FRAGMENT, + OP_TYPE_DELETE_TASK_FRAGMENT, + OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT, + OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT, + OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS, + OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT, + OP_TYPE_SET_COMPANION_TASK_FRAGMENT, OP_TYPE_SET_ANIMATION_PARAMS }) @Retention(RetentionPolicy.SOURCE) - @interface OperationType {} + public @interface OperationType {} @OperationType private final int mOpType; @Nullable + private final TaskFragmentCreationParams mTaskFragmentCreationParams; + + @Nullable + private final IBinder mActivityToken; + + @Nullable + private final Intent mActivityIntent; + + @Nullable + private final Bundle mBundle; + + @Nullable + private final IBinder mSecondaryFragmentToken; + + @Nullable private final TaskFragmentAnimationParams mAnimationParams; private TaskFragmentOperation(@OperationType int opType, + @Nullable TaskFragmentCreationParams taskFragmentCreationParams, + @Nullable IBinder activityToken, @Nullable Intent activityIntent, + @Nullable Bundle bundle, @Nullable IBinder secondaryFragmentToken, @Nullable TaskFragmentAnimationParams animationParams) { mOpType = opType; + mTaskFragmentCreationParams = taskFragmentCreationParams; + mActivityToken = activityToken; + mActivityIntent = activityIntent; + mBundle = bundle; + mSecondaryFragmentToken = secondaryFragmentToken; mAnimationParams = animationParams; } private TaskFragmentOperation(Parcel in) { mOpType = in.readInt(); + mTaskFragmentCreationParams = in.readTypedObject(TaskFragmentCreationParams.CREATOR); + mActivityToken = in.readStrongBinder(); + mActivityIntent = in.readTypedObject(Intent.CREATOR); + mBundle = in.readBundle(getClass().getClassLoader()); + mSecondaryFragmentToken = in.readStrongBinder(); mAnimationParams = in.readTypedObject(TaskFragmentAnimationParams.CREATOR); } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mOpType); + dest.writeTypedObject(mTaskFragmentCreationParams, flags); + dest.writeStrongBinder(mActivityToken); + dest.writeTypedObject(mActivityIntent, flags); + dest.writeBundle(mBundle); + dest.writeStrongBinder(mSecondaryFragmentToken); dest.writeTypedObject(mAnimationParams, flags); } @@ -91,6 +160,46 @@ public final class TaskFragmentOperation implements Parcelable { } /** + * Gets the options to create a new TaskFragment. + */ + @Nullable + public TaskFragmentCreationParams getTaskFragmentCreationParams() { + return mTaskFragmentCreationParams; + } + + /** + * Gets the Activity token set in this operation. + */ + @Nullable + public IBinder getActivityToken() { + return mActivityToken; + } + + /** + * Gets the Intent to start a new Activity. + */ + @Nullable + public Intent getActivityIntent() { + return mActivityIntent; + } + + /** + * Gets the Bundle set in this operation. + */ + @Nullable + public Bundle getBundle() { + return mBundle; + } + + /** + * Gets the fragment token of the secondary TaskFragment set in this operation. + */ + @Nullable + public IBinder getSecondaryFragmentToken() { + return mSecondaryFragmentToken; + } + + /** * Gets the animation related override of TaskFragment. */ @Nullable @@ -102,6 +211,21 @@ public final class TaskFragmentOperation implements Parcelable { public String toString() { final StringBuilder sb = new StringBuilder(); sb.append("TaskFragmentOperation{ opType=").append(mOpType); + if (mTaskFragmentCreationParams != null) { + sb.append(", taskFragmentCreationParams=").append(mTaskFragmentCreationParams); + } + if (mActivityToken != null) { + sb.append(", activityToken=").append(mActivityToken); + } + if (mActivityIntent != null) { + sb.append(", activityIntent=").append(mActivityIntent); + } + if (mBundle != null) { + sb.append(", bundle=").append(mBundle); + } + if (mSecondaryFragmentToken != null) { + sb.append(", secondaryFragmentToken=").append(mSecondaryFragmentToken); + } if (mAnimationParams != null) { sb.append(", animationParams=").append(mAnimationParams); } @@ -112,9 +236,8 @@ public final class TaskFragmentOperation implements Parcelable { @Override public int hashCode() { - int result = mOpType; - result = result * 31 + mAnimationParams.hashCode(); - return result; + return Objects.hash(mOpType, mTaskFragmentCreationParams, mActivityToken, mActivityIntent, + mBundle, mSecondaryFragmentToken, mAnimationParams); } @Override @@ -124,6 +247,11 @@ public final class TaskFragmentOperation implements Parcelable { } final TaskFragmentOperation other = (TaskFragmentOperation) obj; return mOpType == other.mOpType + && Objects.equals(mTaskFragmentCreationParams, other.mTaskFragmentCreationParams) + && Objects.equals(mActivityToken, other.mActivityToken) + && Objects.equals(mActivityIntent, other.mActivityIntent) + && Objects.equals(mBundle, other.mBundle) + && Objects.equals(mSecondaryFragmentToken, other.mSecondaryFragmentToken) && Objects.equals(mAnimationParams, other.mAnimationParams); } @@ -139,6 +267,21 @@ public final class TaskFragmentOperation implements Parcelable { private final int mOpType; @Nullable + private TaskFragmentCreationParams mTaskFragmentCreationParams; + + @Nullable + private IBinder mActivityToken; + + @Nullable + private Intent mActivityIntent; + + @Nullable + private Bundle mBundle; + + @Nullable + private IBinder mSecondaryFragmentToken; + + @Nullable private TaskFragmentAnimationParams mAnimationParams; /** @@ -149,6 +292,52 @@ public final class TaskFragmentOperation implements Parcelable { } /** + * Sets the {@link TaskFragmentCreationParams} for creating a new TaskFragment. + */ + @NonNull + public Builder setTaskFragmentCreationParams( + @Nullable TaskFragmentCreationParams taskFragmentCreationParams) { + mTaskFragmentCreationParams = taskFragmentCreationParams; + return this; + } + + /** + * Sets an Activity token to this operation. + */ + @NonNull + public Builder setActivityToken(@Nullable IBinder activityToken) { + mActivityToken = activityToken; + return this; + } + + /** + * Sets the Intent to start a new Activity. + */ + @NonNull + public Builder setActivityIntent(@Nullable Intent activityIntent) { + mActivityIntent = activityIntent; + return this; + } + + /** + * Sets a Bundle to this operation. + */ + @NonNull + public Builder setBundle(@Nullable Bundle bundle) { + mBundle = bundle; + return this; + } + + /** + * Sets the secondary fragment token to this operation. + */ + @NonNull + public Builder setSecondaryFragmentToken(@Nullable IBinder secondaryFragmentToken) { + mSecondaryFragmentToken = secondaryFragmentToken; + return this; + } + + /** * Sets the {@link TaskFragmentAnimationParams} for the given TaskFragment. */ @NonNull @@ -162,7 +351,8 @@ public final class TaskFragmentOperation implements Parcelable { */ @NonNull public TaskFragmentOperation build() { - return new TaskFragmentOperation(mOpType, mAnimationParams); + return new TaskFragmentOperation(mOpType, mTaskFragmentCreationParams, mActivityToken, + mActivityIntent, mBundle, mSecondaryFragmentToken, mAnimationParams); } } } diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java index 283df7608806..f785a3d1514e 100644 --- a/core/java/android/window/TaskFragmentOrganizer.java +++ b/core/java/android/window/TaskFragmentOrganizer.java @@ -55,7 +55,7 @@ public class TaskFragmentOrganizer extends WindowOrganizer { public static final String KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO = "task_fragment_info"; /** - * Key to the {@link WindowContainerTransaction.HierarchyOp} in + * Key to the {@link TaskFragmentOperation.OperationType} in * {@link TaskFragmentTransaction.Change#getErrorBundle()}. */ public static final String KEY_ERROR_CALLBACK_OP_TYPE = "operation_type"; @@ -112,7 +112,7 @@ public class TaskFragmentOrganizer extends WindowOrganizer { * @hide */ public static @NonNull Bundle putErrorInfoInBundle(@NonNull Throwable exception, - @Nullable TaskFragmentInfo info, int opType) { + @Nullable TaskFragmentInfo info, @TaskFragmentOperation.OperationType int opType) { final Bundle errorBundle = new Bundle(); errorBundle.putSerializable(KEY_ERROR_CALLBACK_THROWABLE, exception); if (info != null) { diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java index 647ccf51b5ef..80b2161edf09 100644 --- a/core/java/android/window/WindowContainerTransaction.java +++ b/core/java/android/window/WindowContainerTransaction.java @@ -16,6 +16,14 @@ package android.window; +import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_TASK_FRAGMENT; +import static android.window.TaskFragmentOperation.OP_TYPE_DELETE_TASK_FRAGMENT; +import static android.window.TaskFragmentOperation.OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT; +import static android.window.TaskFragmentOperation.OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT; +import static android.window.TaskFragmentOperation.OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS; +import static android.window.TaskFragmentOperation.OP_TYPE_SET_COMPANION_TASK_FRAGMENT; +import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT; + import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; @@ -505,32 +513,29 @@ public final class WindowContainerTransaction implements Parcelable { /** * Creates a new TaskFragment with the given options. - * @param taskFragmentOptions the options used to create the TaskFragment. + * @param taskFragmentCreationParams the options used to create the TaskFragment. */ @NonNull public WindowContainerTransaction createTaskFragment( - @NonNull TaskFragmentCreationParams taskFragmentOptions) { - final HierarchyOp hierarchyOp = - new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT) - .setTaskFragmentCreationOptions(taskFragmentOptions) - .build(); - mHierarchyOps.add(hierarchyOp); - return this; + @NonNull TaskFragmentCreationParams taskFragmentCreationParams) { + final TaskFragmentOperation operation = new TaskFragmentOperation.Builder( + OP_TYPE_CREATE_TASK_FRAGMENT) + .setTaskFragmentCreationParams(taskFragmentCreationParams) + .build(); + return addTaskFragmentOperation(taskFragmentCreationParams.getFragmentToken(), operation); } /** * Deletes an existing TaskFragment. Any remaining activities below it will be destroyed. - * @param taskFragment the TaskFragment to be removed. + * @param fragmentToken client assigned unique token to create TaskFragment with specified in + * {@link TaskFragmentCreationParams#getFragmentToken()}. */ @NonNull - public WindowContainerTransaction deleteTaskFragment( - @NonNull WindowContainerToken taskFragment) { - final HierarchyOp hierarchyOp = - new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT) - .setContainer(taskFragment.asBinder()) - .build(); - mHierarchyOps.add(hierarchyOp); - return this; + public WindowContainerTransaction deleteTaskFragment(@NonNull IBinder fragmentToken) { + final TaskFragmentOperation operation = new TaskFragmentOperation.Builder( + OP_TYPE_DELETE_TASK_FRAGMENT) + .build(); + return addTaskFragmentOperation(fragmentToken, operation); } /** @@ -546,16 +551,13 @@ public final class WindowContainerTransaction implements Parcelable { public WindowContainerTransaction startActivityInTaskFragment( @NonNull IBinder fragmentToken, @NonNull IBinder callerToken, @NonNull Intent activityIntent, @Nullable Bundle activityOptions) { - final HierarchyOp hierarchyOp = - new HierarchyOp.Builder( - HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT) - .setContainer(fragmentToken) - .setReparentContainer(callerToken) - .setActivityIntent(activityIntent) - .setLaunchOptions(activityOptions) - .build(); - mHierarchyOps.add(hierarchyOp); - return this; + final TaskFragmentOperation operation = new TaskFragmentOperation.Builder( + OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT) + .setActivityToken(callerToken) + .setActivityIntent(activityIntent) + .setBundle(activityOptions) + .build(); + return addTaskFragmentOperation(fragmentToken, operation); } /** @@ -567,33 +569,11 @@ public final class WindowContainerTransaction implements Parcelable { @NonNull public WindowContainerTransaction reparentActivityToTaskFragment( @NonNull IBinder fragmentToken, @NonNull IBinder activityToken) { - final HierarchyOp hierarchyOp = - new HierarchyOp.Builder( - HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT) - .setReparentContainer(fragmentToken) - .setContainer(activityToken) - .build(); - mHierarchyOps.add(hierarchyOp); - return this; - } - - /** - * Reparents all children of one TaskFragment to another. - * @param oldParent children of this TaskFragment will be reparented. - * @param newParent the new parent TaskFragment to move the children to. If {@code null}, the - * children will be moved to the leaf Task. - */ - @NonNull - public WindowContainerTransaction reparentChildren( - @NonNull WindowContainerToken oldParent, - @Nullable WindowContainerToken newParent) { - final HierarchyOp hierarchyOp = - new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_CHILDREN) - .setContainer(oldParent.asBinder()) - .setReparentContainer(newParent != null ? newParent.asBinder() : null) - .build(); - mHierarchyOps.add(hierarchyOp); - return this; + final TaskFragmentOperation operation = new TaskFragmentOperation.Builder( + OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT) + .setActivityToken(activityToken) + .build(); + return addTaskFragmentOperation(fragmentToken, operation); } /** @@ -613,14 +593,12 @@ public final class WindowContainerTransaction implements Parcelable { public WindowContainerTransaction setAdjacentTaskFragments( @NonNull IBinder fragmentToken1, @Nullable IBinder fragmentToken2, @Nullable TaskFragmentAdjacentParams params) { - final HierarchyOp hierarchyOp = - new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS) - .setContainer(fragmentToken1) - .setReparentContainer(fragmentToken2) - .setLaunchOptions(params != null ? params.toBundle() : null) - .build(); - mHierarchyOps.add(hierarchyOp); - return this; + final TaskFragmentOperation operation = new TaskFragmentOperation.Builder( + OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS) + .setSecondaryFragmentToken(fragmentToken2) + .setBundle(params != null ? params.toBundle() : null) + .build(); + return addTaskFragmentOperation(fragmentToken1, operation); } /** @@ -700,14 +678,10 @@ public final class WindowContainerTransaction implements Parcelable { */ @NonNull public WindowContainerTransaction requestFocusOnTaskFragment(@NonNull IBinder fragmentToken) { - final HierarchyOp hierarchyOp = - new HierarchyOp.Builder( - HierarchyOp.HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT) - .setContainer(fragmentToken) - .build(); - mHierarchyOps.add(hierarchyOp); - return this; - + final TaskFragmentOperation operation = new TaskFragmentOperation.Builder( + OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT) + .build(); + return addTaskFragmentOperation(fragmentToken, operation); } /** @@ -728,30 +702,32 @@ public final class WindowContainerTransaction implements Parcelable { } /** - * Sets the TaskFragment {@code container} to have a companion TaskFragment {@code companion}. + * Sets the TaskFragment {@code fragmentToken} to have a companion TaskFragment + * {@code companionFragmentToken}. * This indicates that the organizer will remove the TaskFragment when the companion * TaskFragment is removed. * - * @param container the TaskFragment container - * @param companion the companion TaskFragment. If it is {@code null}, the transaction will - * reset the companion TaskFragment. + * @param fragmentToken client assigned unique token to create TaskFragment with specified + * in {@link TaskFragmentCreationParams#getFragmentToken()}. + * @param companionFragmentToken client assigned unique token to create TaskFragment with + * specified in + * {@link TaskFragmentCreationParams#getFragmentToken()}. + * If it is {@code null}, the transaction will reset the companion + * TaskFragment. * @hide */ @NonNull - public WindowContainerTransaction setCompanionTaskFragment(@NonNull IBinder container, - @Nullable IBinder companion) { - final HierarchyOp hierarchyOp = - new HierarchyOp.Builder( - HierarchyOp.HIERARCHY_OP_TYPE_SET_COMPANION_TASK_FRAGMENT) - .setContainer(container) - .setReparentContainer(companion) - .build(); - mHierarchyOps.add(hierarchyOp); - return this; + public WindowContainerTransaction setCompanionTaskFragment(@NonNull IBinder fragmentToken, + @Nullable IBinder companionFragmentToken) { + final TaskFragmentOperation operation = new TaskFragmentOperation.Builder( + OP_TYPE_SET_COMPANION_TASK_FRAGMENT) + .setSecondaryFragmentToken(companionFragmentToken) + .build(); + return addTaskFragmentOperation(fragmentToken, operation); } /** - * Sets the {@link TaskFragmentOperation} to apply to the given TaskFragment. + * Adds a {@link TaskFragmentOperation} to apply to the given TaskFragment. * * @param fragmentToken client assigned unique token to create TaskFragment with specified in * {@link TaskFragmentCreationParams#getFragmentToken()}. @@ -760,13 +736,13 @@ public final class WindowContainerTransaction implements Parcelable { * @hide */ @NonNull - public WindowContainerTransaction setTaskFragmentOperation(@NonNull IBinder fragmentToken, + public WindowContainerTransaction addTaskFragmentOperation(@NonNull IBinder fragmentToken, @NonNull TaskFragmentOperation taskFragmentOperation) { Objects.requireNonNull(fragmentToken); Objects.requireNonNull(taskFragmentOperation); final HierarchyOp hierarchyOp = new HierarchyOp.Builder( - HierarchyOp.HIERARCHY_OP_TYPE_SET_TASK_FRAGMENT_OPERATION) + HierarchyOp.HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION) .setContainer(fragmentToken) .setTaskFragmentOperation(taskFragmentOperation) .build(); @@ -1267,25 +1243,17 @@ public final class WindowContainerTransaction implements Parcelable { public static final int HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS = 4; public static final int HIERARCHY_OP_TYPE_LAUNCH_TASK = 5; public static final int HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT = 6; - public static final int HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT = 7; - public static final int HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT = 8; - public static final int HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT = 9; - public static final int HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT = 10; - public static final int HIERARCHY_OP_TYPE_REPARENT_CHILDREN = 11; - public static final int HIERARCHY_OP_TYPE_PENDING_INTENT = 12; - public static final int HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS = 13; - public static final int HIERARCHY_OP_TYPE_START_SHORTCUT = 14; - public static final int HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER = 15; - public static final int HIERARCHY_OP_TYPE_ADD_RECT_INSETS_PROVIDER = 16; - 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; - public static final int HIERARCHY_OP_TYPE_FINISH_ACTIVITY = 21; - public static final int HIERARCHY_OP_TYPE_SET_COMPANION_TASK_FRAGMENT = 22; - public static final int HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS = 23; - public static final int HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH = 24; - public static final int HIERARCHY_OP_TYPE_SET_TASK_FRAGMENT_OPERATION = 25; + public static final int HIERARCHY_OP_TYPE_PENDING_INTENT = 7; + public static final int HIERARCHY_OP_TYPE_START_SHORTCUT = 8; + public static final int HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER = 9; + public static final int HIERARCHY_OP_TYPE_ADD_RECT_INSETS_PROVIDER = 10; + public static final int HIERARCHY_OP_TYPE_REMOVE_INSETS_PROVIDER = 11; + public static final int HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP = 12; + public static final int HIERARCHY_OP_TYPE_REMOVE_TASK = 13; + public static final int HIERARCHY_OP_TYPE_FINISH_ACTIVITY = 14; + public static final int HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS = 15; + public static final int HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH = 16; + public static final int HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION = 17; // The following key(s) are for use with mLaunchOptions: // When launching a task (eg. from recents), this is the taskId to be launched. @@ -1326,11 +1294,7 @@ public final class WindowContainerTransaction implements Parcelable { @Nullable private Intent mActivityIntent; - /** Used as options for {@link #createTaskFragment}. */ - @Nullable - private TaskFragmentCreationParams mTaskFragmentCreationOptions; - - /** Used as options for {@link #setTaskFragmentOperation}. */ + /** Used as options for {@link #addTaskFragmentOperation}. */ @Nullable private TaskFragmentOperation mTaskFragmentOperation; @@ -1452,7 +1416,6 @@ public final class WindowContainerTransaction implements Parcelable { mActivityTypes = copy.mActivityTypes; mLaunchOptions = copy.mLaunchOptions; mActivityIntent = copy.mActivityIntent; - mTaskFragmentCreationOptions = copy.mTaskFragmentCreationOptions; mTaskFragmentOperation = copy.mTaskFragmentOperation; mPendingIntent = copy.mPendingIntent; mShortcutInfo = copy.mShortcutInfo; @@ -1476,7 +1439,6 @@ public final class WindowContainerTransaction implements Parcelable { mActivityTypes = in.createIntArray(); mLaunchOptions = in.readBundle(); mActivityIntent = in.readTypedObject(Intent.CREATOR); - mTaskFragmentCreationOptions = in.readTypedObject(TaskFragmentCreationParams.CREATOR); mTaskFragmentOperation = in.readTypedObject(TaskFragmentOperation.CREATOR); mPendingIntent = in.readTypedObject(PendingIntent.CREATOR); mShortcutInfo = in.readTypedObject(ShortcutInfo.CREATOR); @@ -1516,16 +1478,6 @@ public final class WindowContainerTransaction implements Parcelable { return mReparent; } - @NonNull - public IBinder getCompanionContainer() { - return mReparent; - } - - @NonNull - public IBinder getCallingActivity() { - return mReparent; - } - public boolean getToTop() { return mToTop; } @@ -1561,11 +1513,6 @@ public final class WindowContainerTransaction implements Parcelable { } @Nullable - public TaskFragmentCreationParams getTaskFragmentCreationOptions() { - return mTaskFragmentCreationOptions; - } - - @Nullable public TaskFragmentOperation getTaskFragmentOperation() { return mTaskFragmentOperation; } @@ -1605,22 +1552,6 @@ public final class WindowContainerTransaction implements Parcelable { case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT: return "{SetAdjacentFlagRoot: container=" + mContainer + " clearRoot=" + mToTop + "}"; - case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT: - return "{CreateTaskFragment: options=" + mTaskFragmentCreationOptions + "}"; - case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT: - return "{DeleteTaskFragment: taskFragment=" + mContainer + "}"; - case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT: - return "{StartActivityInTaskFragment: fragmentToken=" + mContainer + " intent=" - + mActivityIntent + " options=" + mLaunchOptions + "}"; - case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT: - return "{ReparentActivityToTaskFragment: fragmentToken=" + mReparent - + " activity=" + mContainer + "}"; - case HIERARCHY_OP_TYPE_REPARENT_CHILDREN: - return "{ReparentChildren: oldParent=" + mContainer + " newParent=" + mReparent - + "}"; - case HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS: - return "{SetAdjacentTaskFragments: container=" + mContainer - + " adjacentContainer=" + mReparent + "}"; case HIERARCHY_OP_TYPE_START_SHORTCUT: return "{StartShortcut: options=" + mLaunchOptions + " info=" + mShortcutInfo + "}"; @@ -1631,8 +1562,6 @@ public final class WindowContainerTransaction implements Parcelable { case HIERARCHY_OP_TYPE_REMOVE_INSETS_PROVIDER: return "{removeLocalInsetsProvider: container=" + mContainer + " insetsType=" + Arrays.toString(mInsetsTypes) + "}"; - case HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT: - return "{requestFocusOnTaskFragment: container=" + mContainer + "}"; case HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP: return "{setAlwaysOnTop: container=" + mContainer + " alwaysOnTop=" + mAlwaysOnTop + "}"; @@ -1640,16 +1569,13 @@ public final class WindowContainerTransaction implements Parcelable { return "{RemoveTask: task=" + mContainer + "}"; case HIERARCHY_OP_TYPE_FINISH_ACTIVITY: return "{finishActivity: activity=" + mContainer + "}"; - case HIERARCHY_OP_TYPE_SET_COMPANION_TASK_FRAGMENT: - return "{setCompanionTaskFragment: container = " + mContainer + " companion = " - + mReparent + "}"; case HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS: return "{ClearAdjacentRoot: container=" + mContainer + "}"; case HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH: return "{setReparentLeafTaskIfRelaunch: container= " + mContainer + " reparentLeafTaskIfRelaunch= " + mReparentLeafTaskIfRelaunch + "}"; - case HIERARCHY_OP_TYPE_SET_TASK_FRAGMENT_OPERATION: - return "{setTaskFragmentOperation: fragmentToken= " + mContainer + case HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION: + return "{addTaskFragmentOperation: fragmentToken= " + mContainer + " operation= " + mTaskFragmentOperation + "}"; default: return "{mType=" + mType + " container=" + mContainer + " reparent=" + mReparent @@ -1677,7 +1603,6 @@ public final class WindowContainerTransaction implements Parcelable { dest.writeIntArray(mActivityTypes); dest.writeBundle(mLaunchOptions); dest.writeTypedObject(mActivityIntent, flags); - dest.writeTypedObject(mTaskFragmentCreationOptions, flags); dest.writeTypedObject(mTaskFragmentOperation, flags); dest.writeTypedObject(mPendingIntent, flags); dest.writeTypedObject(mShortcutInfo, flags); @@ -1733,9 +1658,6 @@ public final class WindowContainerTransaction implements Parcelable { private Intent mActivityIntent; @Nullable - private TaskFragmentCreationParams mTaskFragmentCreationOptions; - - @Nullable private TaskFragmentOperation mTaskFragmentOperation; @Nullable @@ -1812,12 +1734,6 @@ public final class WindowContainerTransaction implements Parcelable { return this; } - Builder setTaskFragmentCreationOptions( - @Nullable TaskFragmentCreationParams taskFragmentCreationOptions) { - mTaskFragmentCreationOptions = taskFragmentCreationOptions; - return this; - } - Builder setTaskFragmentOperation( @Nullable TaskFragmentOperation taskFragmentOperation) { mTaskFragmentOperation = taskFragmentOperation; @@ -1852,7 +1768,6 @@ public final class WindowContainerTransaction implements Parcelable { hierarchyOp.mActivityIntent = mActivityIntent; hierarchyOp.mPendingIntent = mPendingIntent; hierarchyOp.mAlwaysOnTop = mAlwaysOnTop; - hierarchyOp.mTaskFragmentCreationOptions = mTaskFragmentCreationOptions; hierarchyOp.mTaskFragmentOperation = mTaskFragmentOperation; hierarchyOp.mShortcutInfo = mShortcutInfo; hierarchyOp.mReparentLeafTaskIfRelaunch = mReparentLeafTaskIfRelaunch; diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java index 00e13c94ea90..07d0d96a120b 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java @@ -310,16 +310,12 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { OP_TYPE_SET_ANIMATION_PARAMS) .setAnimationParams(animationParams) .build(); - wct.setTaskFragmentOperation(fragmentToken, operation); + wct.addTaskFragmentOperation(fragmentToken, operation); } void deleteTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken) { - if (!mFragmentInfos.containsKey(fragmentToken)) { - throw new IllegalArgumentException( - "Can't find an existing TaskFragment with fragmentToken=" + fragmentToken); - } - wct.deleteTaskFragment(mFragmentInfos.get(fragmentToken).getToken()); + wct.deleteTaskFragment(fragmentToken); } void updateTaskFragmentInfo(@NonNull TaskFragmentInfo taskFragmentInfo) { diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java index 868ced0e555e..b13c6724ed0e 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java @@ -20,6 +20,8 @@ import static android.app.ActivityManager.START_SUCCESS; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.Display.DEFAULT_DISPLAY; +import static android.window.TaskFragmentOperation.OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT; +import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT; import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_OP_TYPE; import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO; import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_THROWABLE; @@ -31,8 +33,6 @@ import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_ERROR; import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_INFO_CHANGED; import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED; import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_VANISHED; -import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT; -import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT; import static androidx.window.extensions.embedding.SplitContainer.getFinishPrimaryWithSecondaryBehavior; import static androidx.window.extensions.embedding.SplitContainer.getFinishSecondaryWithPrimaryBehavior; @@ -67,6 +67,7 @@ import android.util.SparseArray; import android.view.WindowMetrics; import android.window.TaskFragmentAnimationParams; import android.window.TaskFragmentInfo; +import android.window.TaskFragmentOperation; import android.window.TaskFragmentParentInfo; import android.window.TaskFragmentTransaction; import android.window.WindowContainerTransaction; @@ -592,11 +593,11 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen @GuardedBy("mLock") void onTaskFragmentError(@NonNull WindowContainerTransaction wct, @Nullable IBinder errorCallbackToken, @Nullable TaskFragmentInfo taskFragmentInfo, - int opType, @NonNull Throwable exception) { + @TaskFragmentOperation.OperationType int opType, @NonNull Throwable exception) { Log.e(TAG, "onTaskFragmentError=" + exception.getMessage()); switch (opType) { - case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT: - case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT: { + case OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT: + case OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT: { final TaskFragmentContainer container; if (taskFragmentInfo != null) { container = getContainer(taskFragmentInfo.getFragmentToken()); diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java index 0bf0bc85b511..a26311efc23e 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java @@ -20,13 +20,13 @@ import static android.app.ActivityManager.START_CANCELED; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.Display.DEFAULT_DISPLAY; +import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_TASK_FRAGMENT; import static android.window.TaskFragmentTransaction.TYPE_ACTIVITY_REPARENTED_TO_TASK; import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_APPEARED; import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_ERROR; import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_INFO_CHANGED; import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED; import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_VANISHED; -import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT; import static androidx.window.extensions.embedding.EmbeddingTestUtils.DEFAULT_FINISH_PRIMARY_WITH_SECONDARY; import static androidx.window.extensions.embedding.EmbeddingTestUtils.DEFAULT_FINISH_SECONDARY_WITH_PRIMARY; @@ -1139,7 +1139,7 @@ public class SplitControllerTest { final TaskFragmentTransaction transaction = new TaskFragmentTransaction(); final IBinder errorToken = new Binder(); final TaskFragmentInfo info = mock(TaskFragmentInfo.class); - final int opType = HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT; + final int opType = OP_TYPE_CREATE_TASK_FRAGMENT; final Exception exception = new SecurityException("test"); final Bundle errorBundle = TaskFragmentOrganizer.putErrorInfoInBundle(exception, info, opType); diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java index ff1256b47429..f3393c21b1ec 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java @@ -193,7 +193,7 @@ public class SplitPresenterTest { OP_TYPE_SET_ANIMATION_PARAMS) .setAnimationParams(animationParams) .build(); - verify(mTransaction).setTaskFragmentOperation(container.getTaskFragmentToken(), + verify(mTransaction).addTaskFragmentOperation(container.getTaskFragmentToken(), expectedOperation); assertTrue(container.areLastRequestedAnimationParamsEqual(animationParams)); @@ -202,7 +202,7 @@ public class SplitPresenterTest { mPresenter.updateAnimationParams(mTransaction, container.getTaskFragmentToken(), animationParams); - verify(mTransaction, never()).setTaskFragmentOperation(any(), any()); + verify(mTransaction, never()).addTaskFragmentOperation(any(), any()); } @Test diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 034f5c8128f6..464ce9770de4 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -56,7 +56,7 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.TRANSIT_NONE; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_FRONT; -import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT; +import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS; @@ -2830,7 +2830,7 @@ class ActivityStarter { if (taskFragment.isOrganized()) { mService.mWindowOrganizerController.sendTaskFragmentOperationFailure( taskFragment.getTaskFragmentOrganizer(), mRequest.errorCallbackToken, - taskFragment, HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT, + taskFragment, OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT, new SecurityException(errMsg)); } else { // If the taskFragment is not organized, just dump error message as warning logs. diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java index 90a0dffa25f2..5f186a178f2d 100644 --- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java @@ -49,6 +49,7 @@ import android.view.WindowManager; import android.window.ITaskFragmentOrganizer; import android.window.ITaskFragmentOrganizerController; import android.window.TaskFragmentInfo; +import android.window.TaskFragmentOperation; import android.window.TaskFragmentParentInfo; import android.window.TaskFragmentTransaction; import android.window.WindowContainerTransaction; @@ -297,7 +298,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr @NonNull TaskFragmentTransaction.Change prepareTaskFragmentError( @Nullable IBinder errorCallbackToken, @Nullable TaskFragment taskFragment, - int opType, @NonNull Throwable exception) { + @TaskFragmentOperation.OperationType int opType, @NonNull Throwable exception) { ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Sending TaskFragment error exception=%s", exception.toString()); final TaskFragmentInfo info = @@ -629,7 +630,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr void onTaskFragmentError(@NonNull ITaskFragmentOrganizer organizer, @Nullable IBinder errorCallbackToken, @Nullable TaskFragment taskFragment, - int opType, @NonNull Throwable exception) { + @TaskFragmentOperation.OperationType int opType, @NonNull Throwable exception) { if (taskFragment != null && taskFragment.mTaskFragmentVanishedSent) { return; } @@ -803,6 +804,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr // Set when the event is deferred due to the host task is invisible. The defer time will // be the last active time of the host task. private long mDeferTime; + @TaskFragmentOperation.OperationType private int mOpType; private PendingTaskFragmentEvent(@EventType int eventType, @@ -812,7 +814,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr @Nullable Throwable exception, @Nullable ActivityRecord activity, @Nullable Task task, - int opType) { + @TaskFragmentOperation.OperationType int opType) { mEventType = eventType; mTaskFragmentOrg = taskFragmentOrg; mTaskFragment = taskFragment; @@ -853,6 +855,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr private ActivityRecord mActivity; @Nullable private Task mTask; + @TaskFragmentOperation.OperationType private int mOpType; Builder(@EventType int eventType, @NonNull ITaskFragmentOrganizer taskFragmentOrg) { @@ -885,7 +888,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr return this; } - Builder setOpType(int opType) { + Builder setOpType(@TaskFragmentOperation.OperationType int opType) { mOpType = opType; return this; } diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index aac5ef6868df..dd70fca0ab0c 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -21,12 +21,19 @@ import static android.app.ActivityManager.isStartResultSuccessful; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.app.WindowConfiguration.WINDOW_CONFIG_BOUNDS; import static android.view.Display.DEFAULT_DISPLAY; +import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_TASK_FRAGMENT; +import static android.window.TaskFragmentOperation.OP_TYPE_DELETE_TASK_FRAGMENT; +import static android.window.TaskFragmentOperation.OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT; +import static android.window.TaskFragmentOperation.OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT; +import static android.window.TaskFragmentOperation.OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS; import static android.window.TaskFragmentOperation.OP_TYPE_SET_ANIMATION_PARAMS; +import static android.window.TaskFragmentOperation.OP_TYPE_SET_COMPANION_TASK_FRAGMENT; +import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT; +import static android.window.TaskFragmentOperation.OP_TYPE_UNKNOWN; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_ADD_RECT_INSETS_PROVIDER; +import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS; -import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT; -import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_FINISH_ACTIVITY; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_LAUNCH_TASK; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_PENDING_INTENT; @@ -34,19 +41,12 @@ import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP 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; -import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_CHILDREN; -import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS; -import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP; -import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_COMPANION_TASK_FRAGMENT; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH; -import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_TASK_FRAGMENT_OPERATION; -import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_SHORTCUT; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER; @@ -119,6 +119,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub private static final String TAG = "WindowOrganizerController"; + private static final int TRANSACT_EFFECTS_NONE = 0; /** Flag indicating that an applied transaction may have effected lifecycle */ private static final int TRANSACT_EFFECTS_CLIENT_CONFIG = 1; private static final int TRANSACT_EFFECTS_LIFECYCLE = 1 << 1; @@ -488,7 +489,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub private void applyTransaction(@NonNull WindowContainerTransaction t, int syncId, @Nullable Transition transition, @NonNull CallerInfo caller, @Nullable Transition finishTransition) { - int effects = 0; + int effects = TRANSACT_EFFECTS_NONE; ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Apply window transaction, syncId=%d", syncId); mService.deferWindowLayout(); mService.mTaskSupervisor.setDeferRootVisibilityUpdate(true /* deferUpdate */); @@ -630,7 +631,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub // masks here. final int configMask = change.getConfigSetMask() & CONTROLLABLE_CONFIGS; final int windowMask = change.getWindowSetMask() & CONTROLLABLE_WINDOW_CONFIGS; - int effects = 0; + int effects = TRANSACT_EFFECTS_NONE; final int windowingMode = change.getWindowingMode(); if (configMask != 0) { @@ -795,7 +796,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub @NonNull WindowContainerTransaction.Change c, @Nullable IBinder errorCallbackToken) { if (taskFragment.isEmbeddedTaskFragmentInPip()) { // No override from organizer for embedded TaskFragment in a PIP Task. - return 0; + return TRANSACT_EFFECTS_NONE; } // When the TaskFragment is resized, we may want to create a change transition for it, for @@ -861,197 +862,6 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub effects |= clearAdjacentRootsHierarchyOp(hop); break; } - case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT: { - final TaskFragmentCreationParams taskFragmentCreationOptions = - hop.getTaskFragmentCreationOptions(); - createTaskFragment(taskFragmentCreationOptions, errorCallbackToken, caller, - transition); - break; - } - case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT: { - final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer()); - if (wc == null || !wc.isAttached()) { - Slog.e(TAG, "Attempt to operate on unknown or detached container: " + wc); - break; - } - final TaskFragment taskFragment = wc.asTaskFragment(); - if (taskFragment == null || taskFragment.asTask() != null) { - throw new IllegalArgumentException( - "Can only delete organized TaskFragment, but not Task."); - } - if (isInLockTaskMode) { - final ActivityRecord bottomActivity = taskFragment.getActivity( - a -> !a.finishing, false /* traverseTopToBottom */); - if (bottomActivity != null - && mService.getLockTaskController().activityBlockedFromFinish( - bottomActivity)) { - Slog.w(TAG, "Skip removing TaskFragment due in lock task mode."); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, - taskFragment, type, new IllegalStateException( - "Not allow to delete task fragment in lock task mode.")); - break; - } - } - effects |= deleteTaskFragment(taskFragment, organizer, errorCallbackToken, - transition); - break; - } - case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT: { - final IBinder fragmentToken = hop.getContainer(); - final TaskFragment tf = mLaunchTaskFragments.get(fragmentToken); - if (tf == null) { - final Throwable exception = new IllegalArgumentException( - "Not allowed to operate with invalid fragment token"); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, tf, type, - exception); - break; - } - if (tf.isEmbeddedTaskFragmentInPip()) { - final Throwable exception = new IllegalArgumentException( - "Not allowed to start activity in PIP TaskFragment"); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, tf, type, - exception); - break; - } - final Intent activityIntent = hop.getActivityIntent(); - final Bundle activityOptions = hop.getLaunchOptions(); - final int result = mService.getActivityStartController() - .startActivityInTaskFragment(tf, activityIntent, activityOptions, - hop.getCallingActivity(), caller.mUid, caller.mPid, - errorCallbackToken); - if (!isStartResultSuccessful(result)) { - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, tf, type, - convertStartFailureToThrowable(result, activityIntent)); - } else { - effects |= TRANSACT_EFFECTS_LIFECYCLE; - } - break; - } - case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT: { - final IBinder fragmentToken = hop.getNewParent(); - final IBinder activityToken = hop.getContainer(); - ActivityRecord activity = ActivityRecord.forTokenLocked(activityToken); - if (activity == null) { - // The token may be a temporary token if the activity doesn't belong to - // the organizer process. - activity = mTaskFragmentOrganizerController - .getReparentActivityFromTemporaryToken(organizer, activityToken); - } - final TaskFragment parent = mLaunchTaskFragments.get(fragmentToken); - if (parent == null || activity == null) { - final Throwable exception = new IllegalArgumentException( - "Not allowed to operate with invalid fragment token or activity."); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, parent, type, - exception); - break; - } - if (parent.isEmbeddedTaskFragmentInPip()) { - final Throwable exception = new IllegalArgumentException( - "Not allowed to reparent activity to PIP TaskFragment"); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, parent, type, - exception); - break; - } - if (parent.isAllowedToEmbedActivity(activity) != EMBEDDING_ALLOWED) { - final Throwable exception = new SecurityException( - "The task fragment is not allowed to embed the given activity."); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, parent, type, - exception); - break; - } - if (parent.getTask() != activity.getTask()) { - final Throwable exception = new SecurityException("The reparented activity is" - + " not in the same Task as the target TaskFragment."); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, parent, type, - exception); - break; - } - - if (transition != null) { - transition.collect(activity); - if (activity.getParent() != null) { - // Collect the current parent. Its visibility may change as a result of - // this reparenting. - transition.collect(activity.getParent()); - } - transition.collect(parent); - } - activity.reparent(parent, POSITION_TOP); - effects |= TRANSACT_EFFECTS_LIFECYCLE; - break; - } - case HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS: { - final IBinder fragmentToken = hop.getContainer(); - final IBinder adjacentFragmentToken = hop.getAdjacentRoot(); - final TaskFragment tf1 = mLaunchTaskFragments.get(fragmentToken); - final TaskFragment tf2 = adjacentFragmentToken != null - ? mLaunchTaskFragments.get(adjacentFragmentToken) - : null; - if (tf1 == null || (adjacentFragmentToken != null && tf2 == null)) { - final Throwable exception = new IllegalArgumentException( - "Not allowed to set adjacent on invalid fragment tokens"); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, tf1, type, - exception); - break; - } - if (tf1.isEmbeddedTaskFragmentInPip() - || (tf2 != null && tf2.isEmbeddedTaskFragmentInPip())) { - final Throwable exception = new IllegalArgumentException( - "Not allowed to set adjacent on TaskFragment in PIP Task"); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, tf1, type, - exception); - break; - } - tf1.setAdjacentTaskFragment(tf2); - effects |= TRANSACT_EFFECTS_LIFECYCLE; - - // Clear the focused app if the focused app is no longer visible after reset the - // adjacent TaskFragments. - if (tf2 == null && tf1.getDisplayContent().mFocusedApp != null - && tf1.hasChild(tf1.getDisplayContent().mFocusedApp) - && !tf1.shouldBeVisible(null /* starting */)) { - tf1.getDisplayContent().setFocusedApp(null); - } - - final Bundle bundle = hop.getLaunchOptions(); - final WindowContainerTransaction.TaskFragmentAdjacentParams adjacentParams = - bundle != null ? new WindowContainerTransaction.TaskFragmentAdjacentParams( - bundle) : null; - if (adjacentParams == null) { - break; - } - - tf1.setDelayLastActivityRemoval( - adjacentParams.shouldDelayPrimaryLastActivityRemoval()); - if (tf2 != null) { - tf2.setDelayLastActivityRemoval( - adjacentParams.shouldDelaySecondaryLastActivityRemoval()); - } - break; - } - case HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT: { - final TaskFragment tf = mLaunchTaskFragments.get(hop.getContainer()); - if (tf == null || !tf.isAttached()) { - Slog.e(TAG, "Attempt to operate on detached container: " + tf); - break; - } - final ActivityRecord curFocus = tf.getDisplayContent().mFocusedApp; - if (curFocus != null && curFocus.getTaskFragment() == tf) { - Slog.d(TAG, "The requested TaskFragment already has the focus."); - break; - } - if (curFocus != null && curFocus.getTask() != tf.getTask()) { - Slog.d(TAG, "The Task of the requested TaskFragment doesn't have focus."); - break; - } - final ActivityRecord targetFocus = tf.getTopResumedActivity(); - if (targetFocus == null) { - Slog.d(TAG, "There is no resumed activity in the requested TaskFragment."); - break; - } - tf.getDisplayContent().setFocusedApp(targetFocus); - break; - } case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT: { effects |= reparentChildrenTasksHierarchyOp(hop, transition, syncId, isInLockTaskMode); @@ -1126,24 +936,9 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub effects |= sanitizeAndApplyHierarchyOp(wc, hop); break; } - case HIERARCHY_OP_TYPE_SET_COMPANION_TASK_FRAGMENT: { - final IBinder fragmentToken = hop.getContainer(); - final IBinder companionToken = hop.getCompanionContainer(); - final TaskFragment fragment = mLaunchTaskFragments.get(fragmentToken); - final TaskFragment companion = companionToken != null ? mLaunchTaskFragments.get( - companionToken) : null; - if (fragment == null || !fragment.isAttached()) { - final Throwable exception = new IllegalArgumentException( - "Not allowed to set companion on invalid fragment tokens"); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, fragment, type, - exception); - break; - } - fragment.setCompanionTaskFragment(companion); - break; - } - case HIERARCHY_OP_TYPE_SET_TASK_FRAGMENT_OPERATION: { - effects |= applyTaskFragmentOperation(hop, errorCallbackToken, organizer); + case HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION: { + effects |= applyTaskFragmentOperation(hop, transition, isInLockTaskMode, caller, + errorCallbackToken, organizer); break; } default: { @@ -1203,22 +998,6 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } break; } - case HIERARCHY_OP_TYPE_REPARENT_CHILDREN: { - final WindowContainer oldParent = WindowContainer.fromBinder(hop.getContainer()); - final WindowContainer newParent = hop.getNewParent() != null - ? WindowContainer.fromBinder(hop.getNewParent()) - : null; - if (oldParent == null || oldParent.asTaskFragment() == null - || !oldParent.isAttached()) { - Slog.e(TAG, "Attempt to operate on unknown or detached container: " - + oldParent); - break; - } - reparentTaskFragment(oldParent.asTaskFragment(), newParent, organizer, - errorCallbackToken, transition); - effects |= TRANSACT_EFFECTS_LIFECYCLE; - break; - } case HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER: { if (finishTransition == null) break; final WindowContainer container = WindowContainer.fromBinder(hop.getContainer()); @@ -1278,45 +1057,241 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub return effects; } - /** Applies change set through {@link WindowContainerTransaction#setTaskFragmentOperation}. */ + /** + * Applies change set through {@link WindowContainerTransaction#addTaskFragmentOperation}. + * @return an int to represent the transaction effects, such as {@link #TRANSACT_EFFECTS_NONE}, + * {@link #TRANSACT_EFFECTS_LIFECYCLE} or {@link #TRANSACT_EFFECTS_CLIENT_CONFIG}. + */ private int applyTaskFragmentOperation(@NonNull WindowContainerTransaction.HierarchyOp hop, + @Nullable Transition transition, boolean isInLockTaskMode, @NonNull CallerInfo caller, @Nullable IBinder errorCallbackToken, @Nullable ITaskFragmentOrganizer organizer) { + if (!validateTaskFragmentOperation(hop, errorCallbackToken, organizer)) { + return TRANSACT_EFFECTS_NONE; + } final IBinder fragmentToken = hop.getContainer(); final TaskFragment taskFragment = mLaunchTaskFragments.get(fragmentToken); final TaskFragmentOperation operation = hop.getTaskFragmentOperation(); - if (operation == null) { - final Throwable exception = new IllegalArgumentException( - "TaskFragmentOperation must be non-null"); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment, - HIERARCHY_OP_TYPE_SET_TASK_FRAGMENT_OPERATION, exception); - return 0; - } final int opType = operation.getOpType(); - if (taskFragment == null || !taskFragment.isAttached()) { - final Throwable exception = new IllegalArgumentException( - "Not allowed to apply operation on invalid fragment tokens opType=" + opType); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment, - HIERARCHY_OP_TYPE_SET_TASK_FRAGMENT_OPERATION, exception); - return 0; - } - int effect = 0; + int effects = TRANSACT_EFFECTS_NONE; switch (opType) { + case OP_TYPE_CREATE_TASK_FRAGMENT: { + final TaskFragmentCreationParams taskFragmentCreationParams = + operation.getTaskFragmentCreationParams(); + if (taskFragmentCreationParams == null) { + final Throwable exception = new IllegalArgumentException( + "TaskFragmentCreationParams must be non-null"); + sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment, + opType, exception); + break; + } + createTaskFragment(taskFragmentCreationParams, errorCallbackToken, caller, + transition); + break; + } + case OP_TYPE_DELETE_TASK_FRAGMENT: { + if (isInLockTaskMode) { + final ActivityRecord bottomActivity = taskFragment.getActivity( + a -> !a.finishing, false /* traverseTopToBottom */); + if (bottomActivity != null + && mService.getLockTaskController().activityBlockedFromFinish( + bottomActivity)) { + Slog.w(TAG, "Skip removing TaskFragment due in lock task mode."); + sendTaskFragmentOperationFailure(organizer, errorCallbackToken, + taskFragment, opType, new IllegalStateException( + "Not allow to delete task fragment in lock task mode.")); + break; + } + } + effects |= deleteTaskFragment(taskFragment, transition); + break; + } + case OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT: { + final IBinder callerActivityToken = operation.getActivityToken(); + final Intent activityIntent = operation.getActivityIntent(); + final Bundle activityOptions = operation.getBundle(); + final int result = mService.getActivityStartController() + .startActivityInTaskFragment(taskFragment, activityIntent, activityOptions, + callerActivityToken, caller.mUid, caller.mPid, + errorCallbackToken); + if (!isStartResultSuccessful(result)) { + sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment, + opType, convertStartFailureToThrowable(result, activityIntent)); + } else { + effects |= TRANSACT_EFFECTS_LIFECYCLE; + } + break; + } + case OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT: { + final IBinder activityToken = operation.getActivityToken(); + ActivityRecord activity = ActivityRecord.forTokenLocked(activityToken); + if (activity == null) { + // The token may be a temporary token if the activity doesn't belong to + // the organizer process. + activity = mTaskFragmentOrganizerController + .getReparentActivityFromTemporaryToken(organizer, activityToken); + } + if (activity == null) { + final Throwable exception = new IllegalArgumentException( + "Not allowed to operate with invalid activity."); + sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment, + opType, exception); + break; + } + if (taskFragment.isAllowedToEmbedActivity(activity) != EMBEDDING_ALLOWED) { + final Throwable exception = new SecurityException( + "The task fragment is not allowed to embed the given activity."); + sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment, + opType, exception); + break; + } + if (taskFragment.getTask() != activity.getTask()) { + final Throwable exception = new SecurityException("The reparented activity is" + + " not in the same Task as the target TaskFragment."); + sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment, + opType, exception); + break; + } + if (transition != null) { + transition.collect(activity); + if (activity.getParent() != null) { + // Collect the current parent. Its visibility may change as a result of + // this reparenting. + transition.collect(activity.getParent()); + } + transition.collect(taskFragment); + } + activity.reparent(taskFragment, POSITION_TOP); + effects |= TRANSACT_EFFECTS_LIFECYCLE; + break; + } + case OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS: { + final IBinder secondaryFragmentToken = operation.getSecondaryFragmentToken(); + final TaskFragment secondaryTaskFragment = secondaryFragmentToken != null + ? mLaunchTaskFragments.get(secondaryFragmentToken) + : null; + taskFragment.setAdjacentTaskFragment(secondaryTaskFragment); + effects |= TRANSACT_EFFECTS_LIFECYCLE; + + // Clear the focused app if the focused app is no longer visible after reset the + // adjacent TaskFragments. + if (secondaryTaskFragment == null + && taskFragment.getDisplayContent().mFocusedApp != null + && taskFragment.hasChild(taskFragment.getDisplayContent().mFocusedApp) + && !taskFragment.shouldBeVisible(null /* starting */)) { + taskFragment.getDisplayContent().setFocusedApp(null); + } + + final Bundle bundle = hop.getLaunchOptions(); + final WindowContainerTransaction.TaskFragmentAdjacentParams adjacentParams = + bundle != null ? new WindowContainerTransaction.TaskFragmentAdjacentParams( + bundle) : null; + if (adjacentParams == null) { + break; + } + + taskFragment.setDelayLastActivityRemoval( + adjacentParams.shouldDelayPrimaryLastActivityRemoval()); + if (secondaryTaskFragment != null) { + secondaryTaskFragment.setDelayLastActivityRemoval( + adjacentParams.shouldDelaySecondaryLastActivityRemoval()); + } + break; + } + case OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT: { + final ActivityRecord curFocus = taskFragment.getDisplayContent().mFocusedApp; + if (curFocus != null && curFocus.getTaskFragment() == taskFragment) { + Slog.d(TAG, "The requested TaskFragment already has the focus."); + break; + } + if (curFocus != null && curFocus.getTask() != taskFragment.getTask()) { + Slog.d(TAG, "The Task of the requested TaskFragment doesn't have focus."); + break; + } + final ActivityRecord targetFocus = taskFragment.getTopResumedActivity(); + if (targetFocus == null) { + Slog.d(TAG, "There is no resumed activity in the requested TaskFragment."); + break; + } + taskFragment.getDisplayContent().setFocusedApp(targetFocus); + break; + } + case OP_TYPE_SET_COMPANION_TASK_FRAGMENT: { + final IBinder companionFragmentToken = operation.getSecondaryFragmentToken(); + final TaskFragment companionTaskFragment = companionFragmentToken != null + ? mLaunchTaskFragments.get(companionFragmentToken) + : null; + taskFragment.setCompanionTaskFragment(companionTaskFragment); + break; + } case OP_TYPE_SET_ANIMATION_PARAMS: { final TaskFragmentAnimationParams animationParams = operation.getAnimationParams(); if (animationParams == null) { final Throwable exception = new IllegalArgumentException( "TaskFragmentAnimationParams must be non-null"); sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment, - HIERARCHY_OP_TYPE_SET_TASK_FRAGMENT_OPERATION, exception); + opType, exception); break; } taskFragment.setAnimationParams(animationParams); break; } - // TODO(b/263436063): move other TaskFragment related operation here. } - return effect; + return effects; + } + + private boolean validateTaskFragmentOperation( + @NonNull WindowContainerTransaction.HierarchyOp hop, + @Nullable IBinder errorCallbackToken, @Nullable ITaskFragmentOrganizer organizer) { + final TaskFragmentOperation operation = hop.getTaskFragmentOperation(); + final IBinder fragmentToken = hop.getContainer(); + final TaskFragment taskFragment = mLaunchTaskFragments.get(fragmentToken); + if (operation == null) { + final Throwable exception = new IllegalArgumentException( + "TaskFragmentOperation must be non-null"); + sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment, + OP_TYPE_UNKNOWN, exception); + return false; + } + final int opType = operation.getOpType(); + if (opType == OP_TYPE_CREATE_TASK_FRAGMENT) { + // No need to check TaskFragment. + return true; + } + + if (!validateTaskFragment(taskFragment, opType, errorCallbackToken, organizer)) { + return false; + } + + final IBinder secondaryFragmentToken = operation.getSecondaryFragmentToken(); + return secondaryFragmentToken == null + || validateTaskFragment(mLaunchTaskFragments.get(secondaryFragmentToken), opType, + errorCallbackToken, organizer); + } + + private boolean validateTaskFragment(@Nullable TaskFragment taskFragment, + @TaskFragmentOperation.OperationType int opType, @Nullable IBinder errorCallbackToken, + @Nullable ITaskFragmentOrganizer organizer) { + if (taskFragment == null || !taskFragment.isAttached()) { + // TaskFragment doesn't exist. + final Throwable exception = new IllegalArgumentException( + "Not allowed to apply operation on invalid fragment tokens opType=" + opType); + sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment, + opType, exception); + return false; + } + if (taskFragment.isEmbeddedTaskFragmentInPip() + && (opType != OP_TYPE_DELETE_TASK_FRAGMENT + // When the Task enters PiP before the organizer removes the empty TaskFragment, we + // should allow it to delete the TaskFragment for cleanup. + || taskFragment.getTopNonFinishingActivity() != null)) { + final Throwable exception = new IllegalArgumentException( + "Not allowed to apply operation on PIP TaskFragment"); + sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment, + opType, exception); + return false; + } + return true; } /** A helper method to send minimum dimension violation error to the client. */ @@ -1329,7 +1304,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub + taskFragment.getBounds() + " does not satisfy minimum dimensions:" + minDimensions + " " + reason); sendTaskFragmentOperationFailure(taskFragment.getTaskFragmentOrganizer(), - errorCallbackToken, taskFragment, -1 /* opType */, exception); + errorCallbackToken, taskFragment, OP_TYPE_UNKNOWN, exception); } /** @@ -1366,7 +1341,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub final DisplayContent dc = task.getDisplayContent(); if (dc == null) { Slog.w(TAG, "Container is no longer attached: " + task); - return 0; + return TRANSACT_EFFECTS_NONE; } final Task as = task; @@ -1379,7 +1354,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub : WindowContainer.fromBinder(hop.getNewParent()); if (newParent == null) { Slog.e(TAG, "Can't resolve parent window from token"); - return 0; + return TRANSACT_EFFECTS_NONE; } if (task.getParent() != newParent) { if (newParent.asTaskDisplayArea() != null) { @@ -1390,14 +1365,14 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub if (newParent.inPinnedWindowingMode()) { Slog.w(TAG, "Can't support moving a task to another PIP window..." + " newParent=" + newParent + " task=" + task); - return 0; + return TRANSACT_EFFECTS_NONE; } if (!task.supportsMultiWindowInDisplayArea( newParent.asTask().getDisplayArea())) { Slog.w(TAG, "Can't support task that doesn't support multi-window" + " mode in multi-window mode... newParent=" + newParent + " task=" + task); - return 0; + return TRANSACT_EFFECTS_NONE; } } task.reparent((Task) newParent, @@ -1459,22 +1434,22 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub if (currentParent == newParent) { Slog.e(TAG, "reparentChildrenTasksHierarchyOp parent not changing: " + hop); - return 0; + return TRANSACT_EFFECTS_NONE; } if (!currentParent.isAttached()) { Slog.e(TAG, "reparentChildrenTasksHierarchyOp currentParent detached=" + currentParent + " hop=" + hop); - return 0; + return TRANSACT_EFFECTS_NONE; } if (!newParent.isAttached()) { Slog.e(TAG, "reparentChildrenTasksHierarchyOp newParent detached=" + newParent + " hop=" + hop); - return 0; + return TRANSACT_EFFECTS_NONE; } if (newParent.inPinnedWindowingMode()) { Slog.e(TAG, "reparentChildrenTasksHierarchyOp newParent in PIP=" + newParent + " hop=" + hop); - return 0; + return TRANSACT_EFFECTS_NONE; } final boolean newParentInMultiWindow = newParent.inMultiWindowMode(); @@ -1553,10 +1528,6 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub throw new IllegalArgumentException("setAdjacentRootsHierarchyOp: Not created by" + " organizer root1=" + root1 + " root2=" + root2); } - if (root1.isEmbeddedTaskFragmentInPip() || root2.isEmbeddedTaskFragmentInPip()) { - Slog.e(TAG, "Attempt to set adjacent TaskFragment in PIP Task"); - return 0; - } root1.setAdjacentTaskFragment(root2); return TRANSACT_EFFECTS_LIFECYCLE; } @@ -1725,52 +1696,12 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub final int type = hop.getType(); // Check for each type of the operations that are allowed for TaskFragmentOrganizer. switch (type) { - case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT: - enforceTaskFragmentOrganized(func, - WindowContainer.fromBinder(hop.getContainer()), organizer); - break; - case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS: - enforceTaskFragmentOrganized(func, - WindowContainer.fromBinder(hop.getContainer()), organizer); - enforceTaskFragmentOrganized(func, - WindowContainer.fromBinder(hop.getAdjacentRoot()), - organizer); - break; - case HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS: - enforceTaskFragmentOrganized(func, - WindowContainer.fromBinder(hop.getContainer()), organizer); - break; - case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT: - // We are allowing organizer to create TaskFragment. We will check the - // ownerToken in #createTaskFragment, and trigger error callback if that is not - // valid. - break; - case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT: - case HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT: - case HIERARCHY_OP_TYPE_SET_TASK_FRAGMENT_OPERATION: - enforceTaskFragmentOrganized(func, hop.getContainer(), organizer); - break; - case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT: - enforceTaskFragmentOrganized(func, hop.getNewParent(), organizer); - break; - case HIERARCHY_OP_TYPE_SET_COMPANION_TASK_FRAGMENT: + case HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION: enforceTaskFragmentOrganized(func, hop.getContainer(), organizer); - if (hop.getCompanionContainer() != null) { - enforceTaskFragmentOrganized(func, hop.getCompanionContainer(), organizer); - } - break; - case HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS: - enforceTaskFragmentOrganized(func, hop.getContainer(), organizer); - if (hop.getAdjacentRoot() != null) { - enforceTaskFragmentOrganized(func, hop.getAdjacentRoot(), organizer); - } - break; - case HIERARCHY_OP_TYPE_REPARENT_CHILDREN: - enforceTaskFragmentOrganized(func, - WindowContainer.fromBinder(hop.getContainer()), organizer); - if (hop.getNewParent() != null) { + if (hop.getTaskFragmentOperation() != null + && hop.getTaskFragmentOperation().getSecondaryFragmentToken() != null) { enforceTaskFragmentOrganized(func, - WindowContainer.fromBinder(hop.getNewParent()), + hop.getTaskFragmentOperation().getSecondaryFragmentToken(), organizer); } break; @@ -1917,21 +1848,21 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub final Throwable exception = new IllegalArgumentException("TaskFragment token must be unique"); sendTaskFragmentOperationFailure(organizer, errorCallbackToken, null /* taskFragment */, - HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT, exception); + OP_TYPE_CREATE_TASK_FRAGMENT, exception); return; } if (ownerActivity == null || ownerActivity.getTask() == null) { final Throwable exception = new IllegalArgumentException("Not allowed to operate with invalid ownerToken"); sendTaskFragmentOperationFailure(organizer, errorCallbackToken, null /* taskFragment */, - HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT, exception); + OP_TYPE_CREATE_TASK_FRAGMENT, exception); return; } if (!ownerActivity.isResizeable()) { final IllegalArgumentException exception = new IllegalArgumentException("Not allowed" + " to operate with non-resizable owner Activity"); sendTaskFragmentOperationFailure(organizer, errorCallbackToken, null /* taskFragment */, - HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT, exception); + OP_TYPE_CREATE_TASK_FRAGMENT, exception); return; } // The ownerActivity has to belong to the same app as the target Task. @@ -1942,14 +1873,14 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub new SecurityException("Not allowed to operate with the ownerToken while " + "the root activity of the target task belong to the different app"); sendTaskFragmentOperationFailure(organizer, errorCallbackToken, null /* taskFragment */, - HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT, exception); + OP_TYPE_CREATE_TASK_FRAGMENT, exception); return; } if (ownerTask.inPinnedWindowingMode()) { final Throwable exception = new IllegalArgumentException( "Not allowed to create TaskFragment in PIP Task"); sendTaskFragmentOperationFailure(organizer, errorCallbackToken, null /* taskFragment */, - HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT, exception); + OP_TYPE_CREATE_TASK_FRAGMENT, exception); return; } final TaskFragment taskFragment = new TaskFragment(mService, @@ -1984,91 +1915,11 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub if (transition != null) transition.collectExistenceChange(taskFragment); } - private void reparentTaskFragment(@NonNull TaskFragment oldParent, - @Nullable WindowContainer<?> newParent, @Nullable ITaskFragmentOrganizer organizer, - @Nullable IBinder errorCallbackToken, @Nullable Transition transition) { - final TaskFragment newParentTF; - if (newParent == null) { - // Use the old parent's parent if the caller doesn't specify the new parent. - newParentTF = oldParent.getTask(); - } else { - newParentTF = newParent.asTaskFragment(); - } - if (newParentTF == null) { - final Throwable exception = - new IllegalArgumentException("Not allowed to operate with invalid container"); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, newParentTF, - HIERARCHY_OP_TYPE_REPARENT_CHILDREN, exception); - return; - } - if (newParentTF.getTaskFragmentOrganizer() != null) { - // We are reparenting activities to a new embedded TaskFragment, this operation is only - // allowed if the new parent is trusted by all reparent activities. - final boolean isEmbeddingDisallowed = oldParent.forAllActivities(activity -> - newParentTF.isAllowedToEmbedActivity(activity) != EMBEDDING_ALLOWED); - if (isEmbeddingDisallowed) { - final Throwable exception = new SecurityException( - "The new parent is not allowed to embed the activities."); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, newParentTF, - HIERARCHY_OP_TYPE_REPARENT_CHILDREN, exception); - return; - } - } - if (newParentTF.isEmbeddedTaskFragmentInPip() || oldParent.isEmbeddedTaskFragmentInPip()) { - final Throwable exception = new SecurityException( - "Not allow to reparent in TaskFragment in PIP Task."); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, newParentTF, - HIERARCHY_OP_TYPE_REPARENT_CHILDREN, exception); - return; - } - if (newParentTF.getTask() != oldParent.getTask()) { - final Throwable exception = new SecurityException( - "The new parent is not in the same Task as the old parent."); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, newParentTF, - HIERARCHY_OP_TYPE_REPARENT_CHILDREN, exception); - return; - } - if (transition != null) { - // Collect the current parent. It's visibility may change as a result of this - // reparenting. - transition.collect(oldParent); - transition.collect(newParentTF); - } - while (oldParent.hasChild()) { - final WindowContainer child = oldParent.getChildAt(0); - if (transition != null) { - transition.collect(child); - } - child.reparent(newParentTF, POSITION_TOP); - } - } - private int deleteTaskFragment(@NonNull TaskFragment taskFragment, - @Nullable ITaskFragmentOrganizer organizer, @Nullable IBinder errorCallbackToken, @Nullable Transition transition) { - final int index = mLaunchTaskFragments.indexOfValue(taskFragment); - if (index < 0) { - final Throwable exception = - new IllegalArgumentException("Not allowed to operate with invalid " - + "taskFragment"); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment, - HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT, exception); - return 0; - } - if (taskFragment.isEmbeddedTaskFragmentInPip() - // When the Task enters PiP before the organizer removes the empty TaskFragment, we - // should allow it to do the cleanup. - && taskFragment.getTopNonFinishingActivity() != null) { - final Throwable exception = new IllegalArgumentException( - "Not allowed to delete TaskFragment in PIP Task"); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment, - HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT, exception); - return 0; - } - if (transition != null) transition.collectExistenceChange(taskFragment); - mLaunchTaskFragments.removeAt(index); + mLaunchTaskFragments.remove(taskFragment.getFragmentToken()); taskFragment.remove(true /* withTransition */, "deleteTaskFragment"); return TRANSACT_EFFECTS_LIFECYCLE; } @@ -2093,8 +1944,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } void sendTaskFragmentOperationFailure(@NonNull ITaskFragmentOrganizer organizer, - @Nullable IBinder errorCallbackToken, @Nullable TaskFragment taskFragment, int opType, - @NonNull Throwable exception) { + @Nullable IBinder errorCallbackToken, @Nullable TaskFragment taskFragment, + @TaskFragmentOperation.OperationType int opType, @NonNull Throwable exception) { if (organizer == null) { throw new IllegalArgumentException("Not allowed to operate with invalid organizer"); } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java index 656c48659383..a405e5a84360 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java @@ -23,7 +23,12 @@ import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_NONE; import static android.view.WindowManager.TRANSIT_OPEN; +import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_TASK_FRAGMENT; +import static android.window.TaskFragmentOperation.OP_TYPE_DELETE_TASK_FRAGMENT; +import static android.window.TaskFragmentOperation.OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT; +import static android.window.TaskFragmentOperation.OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS; import static android.window.TaskFragmentOperation.OP_TYPE_SET_ANIMATION_PARAMS; +import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT; import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_OP_TYPE; import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_THROWABLE; import static android.window.TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_CHANGE; @@ -36,13 +41,6 @@ import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_ERROR; import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_INFO_CHANGED; import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED; import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_VANISHED; -import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT; -import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT; -import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT; -import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_CHILDREN; -import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS; -import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS; -import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; @@ -339,11 +337,11 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { final Throwable exception = new IllegalArgumentException("Test exception"); mController.onTaskFragmentError(mTaskFragment.getTaskFragmentOrganizer(), - mErrorToken, null /* taskFragment */, HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS, + mErrorToken, null /* taskFragment */, OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS, exception); mController.dispatchPendingEvents(); - assertTaskFragmentErrorTransaction(HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS, + assertTaskFragmentErrorTransaction(OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS, exception.getClass()); } @@ -519,50 +517,20 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { @Test public void testApplyTransaction_enforceHierarchyChange_deleteTaskFragment() { doReturn(true).when(mTaskFragment).isAttached(); - - // Throw exception if the transaction is trying to change a window that is not organized by - // the organizer. - mTransaction.deleteTaskFragment(mFragmentWindowToken); - - assertApplyTransactionDisallowed(mTransaction); - - // Allow transaction to change a TaskFragment created by the organizer. - mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */, - "Test:TaskFragmentOrganizer" /* processName */); - clearInvocations(mAtm.mRootWindowContainer); - - assertApplyTransactionAllowed(mTransaction); - - // No lifecycle update when the TaskFragment is not recorded. - verify(mAtm.mRootWindowContainer, never()).resumeFocusedTasksTopActivities(); - mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment); - assertApplyTransactionAllowed(mTransaction); - - verify(mAtm.mRootWindowContainer).resumeFocusedTasksTopActivities(); - } - - @Test - public void testApplyTransaction_enforceHierarchyChange_setAdjacentRoots() { - final TaskFragment taskFragment2 = - new TaskFragment(mAtm, new Binder(), true /* createdByOrganizer */); - final WindowContainerToken token2 = taskFragment2.mRemoteToken.toWindowContainerToken(); // Throw exception if the transaction is trying to change a window that is not organized by // the organizer. - mTransaction.setAdjacentRoots(mFragmentWindowToken, token2); + mTransaction.deleteTaskFragment(mFragmentToken); assertApplyTransactionDisallowed(mTransaction); // Allow transaction to change a TaskFragment created by the organizer. mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */, "Test:TaskFragmentOrganizer" /* processName */); - taskFragment2.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */, - "Test:TaskFragmentOrganizer" /* processName */); clearInvocations(mAtm.mRootWindowContainer); assertApplyTransactionAllowed(mTransaction); - verify(mAtm.mRootWindowContainer).resumeFocusedTasksTopActivities(); } @@ -693,7 +661,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { } @Test - public void testApplyTransaction_enforceTaskFragmentOrganized_setTaskFragmentOperation() { + public void testApplyTransaction_enforceTaskFragmentOrganized_addTaskFragmentOperation() { final Task task = createTask(mDisplayContent); mTaskFragment = new TaskFragmentBuilder(mAtm) .setParentTask(task) @@ -704,7 +672,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { OP_TYPE_SET_ANIMATION_PARAMS) .setAnimationParams(TaskFragmentAnimationParams.DEFAULT) .build(); - mTransaction.setTaskFragmentOperation(mFragmentToken, operation); + mTransaction.addTaskFragmentOperation(mFragmentToken, operation); mOrganizer.applyTransaction(mTransaction, TASK_FRAGMENT_TRANSIT_CHANGE, false /* shouldApplyIndependently */); @@ -718,7 +686,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { } @Test - public void testSetTaskFragmentOperation() { + public void testAddTaskFragmentOperation() { final Task task = createTask(mDisplayContent); mTaskFragment = new TaskFragmentBuilder(mAtm) .setParentTask(task) @@ -736,7 +704,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { OP_TYPE_SET_ANIMATION_PARAMS) .setAnimationParams(animationParams) .build(); - mTransaction.setTaskFragmentOperation(mFragmentToken, operation); + mTransaction.addTaskFragmentOperation(mFragmentToken, operation); mOrganizer.applyTransaction(mTransaction, TASK_FRAGMENT_TRANSIT_CHANGE, false /* shouldApplyIndependently */); assertApplyTransactionAllowed(mTransaction); @@ -845,26 +813,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { } @Test - public void testApplyTransaction_enforceHierarchyChange_reparentChildren() { - doReturn(true).when(mTaskFragment).isAttached(); - - // Throw exception if the transaction is trying to change a window that is not organized by - // the organizer. - mTransaction.reparentChildren(mFragmentWindowToken, null /* newParent */); - - assertApplyTransactionDisallowed(mTransaction); - - // Allow transaction to change a TaskFragment created by the organizer. - mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */, - "Test:TaskFragmentOrganizer" /* processName */); - clearInvocations(mAtm.mRootWindowContainer); - - assertApplyTransactionAllowed(mTransaction); - - verify(mAtm.mRootWindowContainer).resumeFocusedTasksTopActivities(); - } - - @Test public void testApplyTransaction_reparentActivityToTaskFragment_triggerLifecycleUpdate() { final Task task = createTask(mDisplayContent); final ActivityRecord activity = createActivityRecord(task); @@ -1040,7 +988,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { any(), any(), anyInt(), anyInt(), any()); verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer), eq(mErrorToken), eq(mTaskFragment), - eq(HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT), + eq(OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT), any(IllegalArgumentException.class)); } @@ -1057,7 +1005,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer), eq(mErrorToken), eq(mTaskFragment), - eq(HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT), + eq(OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT), any(IllegalArgumentException.class)); assertNull(activity.getOrganizedTaskFragment()); } @@ -1074,8 +1022,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { assertApplyTransactionAllowed(mTransaction); verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer), - eq(mErrorToken), eq(mTaskFragment), - eq(HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS), + eq(mErrorToken), eq(mTaskFragment), eq(OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS), any(IllegalArgumentException.class)); verify(mTaskFragment, never()).setAdjacentTaskFragment(any()); } @@ -1094,7 +1041,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { assertApplyTransactionAllowed(mTransaction); verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer), - eq(mErrorToken), eq(null), eq(HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT), + eq(mErrorToken), eq(null), eq(OP_TYPE_CREATE_TASK_FRAGMENT), any(IllegalArgumentException.class)); assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken)); } @@ -1105,12 +1052,12 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { spyOn(mWindowOrganizerController); // Not allow to delete a TaskFragment that is in a PIP Task. - mTransaction.deleteTaskFragment(mFragmentWindowToken) + mTransaction.deleteTaskFragment(mFragmentToken) .setErrorCallbackToken(mErrorToken); assertApplyTransactionAllowed(mTransaction); verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer), - eq(mErrorToken), eq(mTaskFragment), eq(HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT), + eq(mErrorToken), eq(mTaskFragment), eq(OP_TYPE_DELETE_TASK_FRAGMENT), any(IllegalArgumentException.class)); assertNotNull(mWindowOrganizerController.getTaskFragment(mFragmentToken)); @@ -1423,43 +1370,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { // The pending event will be dispatched on the handler (from requestTraversal). waitHandlerIdle(mWm.mAnimationHandler); - assertTaskFragmentErrorTransaction(HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT, - SecurityException.class); - } - - @Test - public void testMinDimensionViolation_ReparentChildren() { - final Task task = createTask(mDisplayContent); - final IBinder oldFragToken = new Binder(); - final TaskFragment oldTaskFrag = new TaskFragmentBuilder(mAtm) - .setParentTask(task) - .createActivityCount(1) - .setFragmentToken(oldFragToken) - .setOrganizer(mOrganizer) - .build(); - final ActivityRecord activity = oldTaskFrag.getTopMostActivity(); - // Make minWidth/minHeight exceeds mTaskFragment bounds. - activity.info.windowLayout = new ActivityInfo.WindowLayout( - 0, 0, 0, 0, 0, mTaskFragBounds.width() + 10, mTaskFragBounds.height() + 10); - mTaskFragment = new TaskFragmentBuilder(mAtm) - .setParentTask(task) - .setFragmentToken(mFragmentToken) - .setOrganizer(mOrganizer) - .setBounds(mTaskFragBounds) - .build(); - mWindowOrganizerController.mLaunchTaskFragments.put(oldFragToken, oldTaskFrag); - mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment); - - // Reparent oldTaskFrag's children to mTaskFragment, which is smaller than activity's - // minimum dimensions. - mTransaction.reparentChildren(oldTaskFrag.mRemoteToken.toWindowContainerToken(), - mTaskFragment.mRemoteToken.toWindowContainerToken()) - .setErrorCallbackToken(mErrorToken); - assertApplyTransactionAllowed(mTransaction); - // The pending event will be dispatched on the handler (from requestTraversal). - waitHandlerIdle(mWm.mAnimationHandler); - - assertTaskFragmentErrorTransaction(HIERARCHY_OP_TYPE_REPARENT_CHILDREN, + assertTaskFragmentErrorTransaction(OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT, SecurityException.class); } @@ -1634,7 +1545,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { } /** Asserts that there will be a transaction for TaskFragment error. */ - private void assertTaskFragmentErrorTransaction(int opType, @NonNull Class<?> exceptionClass) { + private void assertTaskFragmentErrorTransaction(@TaskFragmentOperation.OperationType int opType, + @NonNull Class<?> exceptionClass) { verify(mOrganizer).onTransactionReady(mTransactionCaptor.capture()); final TaskFragmentTransaction transaction = mTransactionCaptor.getValue(); final List<TaskFragmentTransaction.Change> changes = transaction.getChanges(); |