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();