Merge "Refactor TaskFragment related WindowContainerTransaction"
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index e3554a5..3bc11fa 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -3664,14 +3664,13 @@
     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 04dee58..8ae84c2 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 a600a4d..12ad914 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 c21700c..c1ed0c7 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 bec6c58..3272c3b 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 @@
 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 @@
 /**
  * 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 @@
     }
 
     /**
+     * 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 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 @@
 
     @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 @@
         }
         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 @@
         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 @@
         }
 
         /**
+         * 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 @@
          */
         @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 283df76..f785a3d 100644
--- a/core/java/android/window/TaskFragmentOrganizer.java
+++ b/core/java/android/window/TaskFragmentOrganizer.java
@@ -55,7 +55,7 @@
     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 @@
      * @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 647ccf5..80b2161 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 @@
 
     /**
      * 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 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 @@
     @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 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 @@
      */
     @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 @@
     }
 
     /**
-     * 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 @@
      * @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 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 @@
         @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 @@
             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 @@
             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 @@
             return mReparent;
         }
 
-        @NonNull
-        public IBinder getCompanionContainer() {
-            return mReparent;
-        }
-
-        @NonNull
-        public IBinder getCallingActivity() {
-            return mReparent;
-        }
-
         public boolean getToTop() {
             return mToTop;
         }
@@ -1561,11 +1513,6 @@
         }
 
         @Nullable
-        public TaskFragmentCreationParams getTaskFragmentCreationOptions() {
-            return mTaskFragmentCreationOptions;
-        }
-
-        @Nullable
         public TaskFragmentOperation getTaskFragmentOperation() {
             return mTaskFragmentOperation;
         }
@@ -1605,22 +1552,6 @@
                 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 @@
                 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 @@
                     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 @@
             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 @@
             private Intent mActivityIntent;
 
             @Nullable
-            private TaskFragmentCreationParams mTaskFragmentCreationOptions;
-
-            @Nullable
             private TaskFragmentOperation mTaskFragmentOperation;
 
             @Nullable
@@ -1812,12 +1734,6 @@
                 return this;
             }
 
-            Builder setTaskFragmentCreationOptions(
-                    @Nullable TaskFragmentCreationParams taskFragmentCreationOptions) {
-                mTaskFragmentCreationOptions = taskFragmentCreationOptions;
-                return this;
-            }
-
             Builder setTaskFragmentOperation(
                     @Nullable TaskFragmentOperation taskFragmentOperation) {
                 mTaskFragmentOperation = taskFragmentOperation;
@@ -1852,7 +1768,6 @@
                 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 00e13c9..07d0d96 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 @@
                 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 868ced0..b13c672 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.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_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.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 @@
     @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 0bf0bc8..a26311e 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.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 @@
         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 ff1256b..f3393c2 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 @@
                 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 @@
         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 86493eb..0ca74d9 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.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;
@@ -2889,7 +2889,7 @@
         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 90a0dff..5f186a1 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.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 @@
         @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 @@
 
     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 @@
         // 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 @@
                 @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 @@
             private ActivityRecord mActivity;
             @Nullable
             private Task mTask;
+            @TaskFragmentOperation.OperationType
             private int mOpType;
 
             Builder(@EventType int eventType, @NonNull ITaskFragmentOrganizer taskFragmentOrg) {
@@ -885,7 +888,7 @@
                 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 aac5ef6..dd70fca 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.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_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 @@
 
     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 @@
     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 @@
         // 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 @@
             @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 @@
                 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 @@
                 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 @@
                 }
                 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 @@
         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 @@
                 + 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 @@
         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 @@
                         : 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 @@
                             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 @@
 
         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 @@
             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 @@
             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:
+                case HIERARCHY_OP_TYPE_ADD_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:
-                    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 @@
             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 @@
                     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 @@
         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 @@
     }
 
     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 656c486..a405e5a 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_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_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 @@
         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 @@
     @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 @@
     }
 
     @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 @@
                 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 @@
     }
 
     @Test
-    public void testSetTaskFragmentOperation() {
+    public void testAddTaskFragmentOperation() {
         final Task task = createTask(mDisplayContent);
         mTaskFragment = new TaskFragmentBuilder(mAtm)
                 .setParentTask(task)
@@ -736,7 +704,7 @@
                 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 @@
     }
 
     @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 @@
                 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 @@
 
         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 @@
         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 @@
         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 @@
         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 @@
         // 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 @@
     }
 
     /** 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();