Merge "Refactor TaskFragment related WindowContainerTransaction"

This commit is contained in:
TreeHugger Robot
2023-01-11 10:48:26 +00:00
committed by Android (Google) Code Review
15 changed files with 576 additions and 709 deletions

View File

@@ -3664,14 +3664,13 @@ package android.window {
ctor public WindowContainerTransaction();
method @NonNull public android.window.WindowContainerTransaction clearLaunchAdjacentFlagRoot(@NonNull android.window.WindowContainerToken);
method @NonNull public android.window.WindowContainerTransaction createTaskFragment(@NonNull android.window.TaskFragmentCreationParams);
method @NonNull public android.window.WindowContainerTransaction deleteTaskFragment(@NonNull android.window.WindowContainerToken);
method @NonNull public android.window.WindowContainerTransaction deleteTaskFragment(@NonNull android.os.IBinder);
method public int describeContents();
method @NonNull public android.window.WindowContainerTransaction finishActivity(@NonNull android.os.IBinder);
method @NonNull public android.window.WindowContainerTransaction removeTask(@NonNull android.window.WindowContainerToken);
method @NonNull public android.window.WindowContainerTransaction reorder(@NonNull android.window.WindowContainerToken, boolean);
method @NonNull public android.window.WindowContainerTransaction reparent(@NonNull android.window.WindowContainerToken, @Nullable android.window.WindowContainerToken, boolean);
method @NonNull public android.window.WindowContainerTransaction reparentActivityToTaskFragment(@NonNull android.os.IBinder, @NonNull android.os.IBinder);
method @NonNull public android.window.WindowContainerTransaction reparentChildren(@NonNull android.window.WindowContainerToken, @Nullable android.window.WindowContainerToken);
method @NonNull public android.window.WindowContainerTransaction reparentTasks(@Nullable android.window.WindowContainerToken, @Nullable android.window.WindowContainerToken, @Nullable int[], @Nullable int[], boolean);
method @NonNull public android.window.WindowContainerTransaction requestFocusOnTaskFragment(@NonNull android.os.IBinder);
method @NonNull public android.window.WindowContainerTransaction scheduleFinishEnterPip(@NonNull android.window.WindowContainerToken, @NonNull android.graphics.Rect);

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022 The Android Open Source Project
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +19,8 @@ package android.window;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
@@ -30,41 +32,108 @@ import java.util.Objects;
/**
* Data object of params for TaskFragment related {@link WindowContainerTransaction} operation.
*
* @see WindowContainerTransaction#setTaskFragmentOperation(IBinder, TaskFragmentOperation).
* @see WindowContainerTransaction#addTaskFragmentOperation(IBinder, TaskFragmentOperation).
* @hide
*/
// TODO(b/263436063): move other TaskFragment related operation here.
public final class TaskFragmentOperation implements Parcelable {
/**
* Type for tracking other {@link WindowContainerTransaction} to TaskFragment that is not set
* through {@link TaskFragmentOperation}, such as {@link WindowContainerTransaction#setBounds}.
*/
public static final int OP_TYPE_UNKNOWN = -1;
/** Creates a new TaskFragment. */
public static final int OP_TYPE_CREATE_TASK_FRAGMENT = 0;
/** Deletes the given TaskFragment. */
public static final int OP_TYPE_DELETE_TASK_FRAGMENT = 1;
/** Starts an Activity in the given TaskFragment. */
public static final int OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT = 2;
/** Reparents the given Activity to the given TaskFragment. */
public static final int OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT = 3;
/** Sets two TaskFragments adjacent to each other. */
public static final int OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS = 4;
/** Requests focus on the top running Activity in the given TaskFragment. */
public static final int OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT = 5;
/** Sets a given TaskFragment to have a companion TaskFragment. */
public static final int OP_TYPE_SET_COMPANION_TASK_FRAGMENT = 6;
/** Sets the {@link TaskFragmentAnimationParams} for the given TaskFragment. */
public static final int OP_TYPE_SET_ANIMATION_PARAMS = 0;
public static final int OP_TYPE_SET_ANIMATION_PARAMS = 7;
@IntDef(prefix = { "OP_TYPE_" }, value = {
OP_TYPE_UNKNOWN,
OP_TYPE_CREATE_TASK_FRAGMENT,
OP_TYPE_DELETE_TASK_FRAGMENT,
OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT,
OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT,
OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS,
OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT,
OP_TYPE_SET_COMPANION_TASK_FRAGMENT,
OP_TYPE_SET_ANIMATION_PARAMS
})
@Retention(RetentionPolicy.SOURCE)
@interface OperationType {}
public @interface OperationType {}
@OperationType
private final int mOpType;
@Nullable
private final TaskFragmentCreationParams mTaskFragmentCreationParams;
@Nullable
private final IBinder mActivityToken;
@Nullable
private final Intent mActivityIntent;
@Nullable
private final Bundle mBundle;
@Nullable
private final IBinder mSecondaryFragmentToken;
@Nullable
private final TaskFragmentAnimationParams mAnimationParams;
private TaskFragmentOperation(@OperationType int opType,
@Nullable TaskFragmentCreationParams taskFragmentCreationParams,
@Nullable IBinder activityToken, @Nullable Intent activityIntent,
@Nullable Bundle bundle, @Nullable IBinder secondaryFragmentToken,
@Nullable TaskFragmentAnimationParams animationParams) {
mOpType = opType;
mTaskFragmentCreationParams = taskFragmentCreationParams;
mActivityToken = activityToken;
mActivityIntent = activityIntent;
mBundle = bundle;
mSecondaryFragmentToken = secondaryFragmentToken;
mAnimationParams = animationParams;
}
private TaskFragmentOperation(Parcel in) {
mOpType = in.readInt();
mTaskFragmentCreationParams = in.readTypedObject(TaskFragmentCreationParams.CREATOR);
mActivityToken = in.readStrongBinder();
mActivityIntent = in.readTypedObject(Intent.CREATOR);
mBundle = in.readBundle(getClass().getClassLoader());
mSecondaryFragmentToken = in.readStrongBinder();
mAnimationParams = in.readTypedObject(TaskFragmentAnimationParams.CREATOR);
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mOpType);
dest.writeTypedObject(mTaskFragmentCreationParams, flags);
dest.writeStrongBinder(mActivityToken);
dest.writeTypedObject(mActivityIntent, flags);
dest.writeBundle(mBundle);
dest.writeStrongBinder(mSecondaryFragmentToken);
dest.writeTypedObject(mAnimationParams, flags);
}
@@ -90,6 +159,46 @@ public final class TaskFragmentOperation implements Parcelable {
return mOpType;
}
/**
* 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.
*/
@@ -102,6 +211,21 @@ public final class TaskFragmentOperation implements Parcelable {
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("TaskFragmentOperation{ opType=").append(mOpType);
if (mTaskFragmentCreationParams != null) {
sb.append(", taskFragmentCreationParams=").append(mTaskFragmentCreationParams);
}
if (mActivityToken != null) {
sb.append(", activityToken=").append(mActivityToken);
}
if (mActivityIntent != null) {
sb.append(", activityIntent=").append(mActivityIntent);
}
if (mBundle != null) {
sb.append(", bundle=").append(mBundle);
}
if (mSecondaryFragmentToken != null) {
sb.append(", secondaryFragmentToken=").append(mSecondaryFragmentToken);
}
if (mAnimationParams != null) {
sb.append(", animationParams=").append(mAnimationParams);
}
@@ -112,9 +236,8 @@ public final class TaskFragmentOperation implements Parcelable {
@Override
public int hashCode() {
int result = mOpType;
result = result * 31 + mAnimationParams.hashCode();
return result;
return Objects.hash(mOpType, mTaskFragmentCreationParams, mActivityToken, mActivityIntent,
mBundle, mSecondaryFragmentToken, mAnimationParams);
}
@Override
@@ -124,6 +247,11 @@ public final class TaskFragmentOperation implements Parcelable {
}
final TaskFragmentOperation other = (TaskFragmentOperation) obj;
return mOpType == other.mOpType
&& Objects.equals(mTaskFragmentCreationParams, other.mTaskFragmentCreationParams)
&& Objects.equals(mActivityToken, other.mActivityToken)
&& Objects.equals(mActivityIntent, other.mActivityIntent)
&& Objects.equals(mBundle, other.mBundle)
&& Objects.equals(mSecondaryFragmentToken, other.mSecondaryFragmentToken)
&& Objects.equals(mAnimationParams, other.mAnimationParams);
}
@@ -138,6 +266,21 @@ public final class TaskFragmentOperation implements Parcelable {
@OperationType
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;
@@ -148,6 +291,52 @@ public final class TaskFragmentOperation implements Parcelable {
mOpType = opType;
}
/**
* 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.
*/
@@ -162,7 +351,8 @@ public final class TaskFragmentOperation implements Parcelable {
*/
@NonNull
public TaskFragmentOperation build() {
return new TaskFragmentOperation(mOpType, mAnimationParams);
return new TaskFragmentOperation(mOpType, mTaskFragmentCreationParams, mActivityToken,
mActivityIntent, mBundle, mSecondaryFragmentToken, mAnimationParams);
}
}
}

View File

@@ -55,7 +55,7 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
public static final String KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO = "task_fragment_info";
/**
* Key to the {@link WindowContainerTransaction.HierarchyOp} in
* Key to the {@link TaskFragmentOperation.OperationType} in
* {@link TaskFragmentTransaction.Change#getErrorBundle()}.
*/
public static final String KEY_ERROR_CALLBACK_OP_TYPE = "operation_type";
@@ -112,7 +112,7 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
* @hide
*/
public static @NonNull Bundle putErrorInfoInBundle(@NonNull Throwable exception,
@Nullable TaskFragmentInfo info, int opType) {
@Nullable TaskFragmentInfo info, @TaskFragmentOperation.OperationType int opType) {
final Bundle errorBundle = new Bundle();
errorBundle.putSerializable(KEY_ERROR_CALLBACK_THROWABLE, exception);
if (info != null) {

View File

@@ -16,6 +16,14 @@
package android.window;
import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_DELETE_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_COMPANION_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
@@ -505,32 +513,29 @@ public final class WindowContainerTransaction implements Parcelable {
/**
* Creates a new TaskFragment with the given options.
* @param taskFragmentOptions the options used to create the TaskFragment.
* @param taskFragmentCreationParams the options used to create the TaskFragment.
*/
@NonNull
public WindowContainerTransaction createTaskFragment(
@NonNull TaskFragmentCreationParams taskFragmentOptions) {
final HierarchyOp hierarchyOp =
new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT)
.setTaskFragmentCreationOptions(taskFragmentOptions)
.build();
mHierarchyOps.add(hierarchyOp);
return this;
@NonNull TaskFragmentCreationParams taskFragmentCreationParams) {
final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
OP_TYPE_CREATE_TASK_FRAGMENT)
.setTaskFragmentCreationParams(taskFragmentCreationParams)
.build();
return addTaskFragmentOperation(taskFragmentCreationParams.getFragmentToken(), operation);
}
/**
* Deletes an existing TaskFragment. Any remaining activities below it will be destroyed.
* @param taskFragment the TaskFragment to be removed.
* @param fragmentToken client assigned unique token to create TaskFragment with specified in
* {@link TaskFragmentCreationParams#getFragmentToken()}.
*/
@NonNull
public WindowContainerTransaction deleteTaskFragment(
@NonNull WindowContainerToken taskFragment) {
final HierarchyOp hierarchyOp =
new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT)
.setContainer(taskFragment.asBinder())
.build();
mHierarchyOps.add(hierarchyOp);
return this;
public WindowContainerTransaction deleteTaskFragment(@NonNull IBinder fragmentToken) {
final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
OP_TYPE_DELETE_TASK_FRAGMENT)
.build();
return addTaskFragmentOperation(fragmentToken, operation);
}
/**
@@ -546,16 +551,13 @@ public final class WindowContainerTransaction implements Parcelable {
public WindowContainerTransaction startActivityInTaskFragment(
@NonNull IBinder fragmentToken, @NonNull IBinder callerToken,
@NonNull Intent activityIntent, @Nullable Bundle activityOptions) {
final HierarchyOp hierarchyOp =
new HierarchyOp.Builder(
HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT)
.setContainer(fragmentToken)
.setReparentContainer(callerToken)
.setActivityIntent(activityIntent)
.setLaunchOptions(activityOptions)
.build();
mHierarchyOps.add(hierarchyOp);
return this;
final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT)
.setActivityToken(callerToken)
.setActivityIntent(activityIntent)
.setBundle(activityOptions)
.build();
return addTaskFragmentOperation(fragmentToken, operation);
}
/**
@@ -567,33 +569,11 @@ public final class WindowContainerTransaction implements Parcelable {
@NonNull
public WindowContainerTransaction reparentActivityToTaskFragment(
@NonNull IBinder fragmentToken, @NonNull IBinder activityToken) {
final HierarchyOp hierarchyOp =
new HierarchyOp.Builder(
HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT)
.setReparentContainer(fragmentToken)
.setContainer(activityToken)
.build();
mHierarchyOps.add(hierarchyOp);
return this;
}
/**
* Reparents all children of one TaskFragment to another.
* @param oldParent children of this TaskFragment will be reparented.
* @param newParent the new parent TaskFragment to move the children to. If {@code null}, the
* children will be moved to the leaf Task.
*/
@NonNull
public WindowContainerTransaction reparentChildren(
@NonNull WindowContainerToken oldParent,
@Nullable WindowContainerToken newParent) {
final HierarchyOp hierarchyOp =
new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_CHILDREN)
.setContainer(oldParent.asBinder())
.setReparentContainer(newParent != null ? newParent.asBinder() : null)
.build();
mHierarchyOps.add(hierarchyOp);
return this;
final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT)
.setActivityToken(activityToken)
.build();
return addTaskFragmentOperation(fragmentToken, operation);
}
/**
@@ -613,14 +593,12 @@ public final class WindowContainerTransaction implements Parcelable {
public WindowContainerTransaction setAdjacentTaskFragments(
@NonNull IBinder fragmentToken1, @Nullable IBinder fragmentToken2,
@Nullable TaskFragmentAdjacentParams params) {
final HierarchyOp hierarchyOp =
new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS)
.setContainer(fragmentToken1)
.setReparentContainer(fragmentToken2)
.setLaunchOptions(params != null ? params.toBundle() : null)
.build();
mHierarchyOps.add(hierarchyOp);
return this;
final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS)
.setSecondaryFragmentToken(fragmentToken2)
.setBundle(params != null ? params.toBundle() : null)
.build();
return addTaskFragmentOperation(fragmentToken1, operation);
}
/**
@@ -700,14 +678,10 @@ public final class WindowContainerTransaction implements Parcelable {
*/
@NonNull
public WindowContainerTransaction requestFocusOnTaskFragment(@NonNull IBinder fragmentToken) {
final HierarchyOp hierarchyOp =
new HierarchyOp.Builder(
HierarchyOp.HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT)
.setContainer(fragmentToken)
.build();
mHierarchyOps.add(hierarchyOp);
return this;
final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT)
.build();
return addTaskFragmentOperation(fragmentToken, operation);
}
/**
@@ -728,30 +702,32 @@ public final class WindowContainerTransaction implements Parcelable {
}
/**
* Sets the TaskFragment {@code container} to have a companion TaskFragment {@code companion}.
* Sets the TaskFragment {@code fragmentToken} to have a companion TaskFragment
* {@code companionFragmentToken}.
* This indicates that the organizer will remove the TaskFragment when the companion
* TaskFragment is removed.
*
* @param container the TaskFragment container
* @param companion the companion TaskFragment. If it is {@code null}, the transaction will
* reset the companion TaskFragment.
* @param fragmentToken client assigned unique token to create TaskFragment with specified
* in {@link TaskFragmentCreationParams#getFragmentToken()}.
* @param companionFragmentToken client assigned unique token to create TaskFragment with
* specified in
* {@link TaskFragmentCreationParams#getFragmentToken()}.
* If it is {@code null}, the transaction will reset the companion
* TaskFragment.
* @hide
*/
@NonNull
public WindowContainerTransaction setCompanionTaskFragment(@NonNull IBinder container,
@Nullable IBinder companion) {
final HierarchyOp hierarchyOp =
new HierarchyOp.Builder(
HierarchyOp.HIERARCHY_OP_TYPE_SET_COMPANION_TASK_FRAGMENT)
.setContainer(container)
.setReparentContainer(companion)
.build();
mHierarchyOps.add(hierarchyOp);
return this;
public WindowContainerTransaction setCompanionTaskFragment(@NonNull IBinder fragmentToken,
@Nullable IBinder companionFragmentToken) {
final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
OP_TYPE_SET_COMPANION_TASK_FRAGMENT)
.setSecondaryFragmentToken(companionFragmentToken)
.build();
return addTaskFragmentOperation(fragmentToken, operation);
}
/**
* Sets the {@link TaskFragmentOperation} to apply to the given TaskFragment.
* Adds a {@link TaskFragmentOperation} to apply to the given TaskFragment.
*
* @param fragmentToken client assigned unique token to create TaskFragment with specified in
* {@link TaskFragmentCreationParams#getFragmentToken()}.
@@ -760,13 +736,13 @@ public final class WindowContainerTransaction implements Parcelable {
* @hide
*/
@NonNull
public WindowContainerTransaction setTaskFragmentOperation(@NonNull IBinder fragmentToken,
public WindowContainerTransaction addTaskFragmentOperation(@NonNull IBinder fragmentToken,
@NonNull TaskFragmentOperation taskFragmentOperation) {
Objects.requireNonNull(fragmentToken);
Objects.requireNonNull(taskFragmentOperation);
final HierarchyOp hierarchyOp =
new HierarchyOp.Builder(
HierarchyOp.HIERARCHY_OP_TYPE_SET_TASK_FRAGMENT_OPERATION)
HierarchyOp.HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION)
.setContainer(fragmentToken)
.setTaskFragmentOperation(taskFragmentOperation)
.build();
@@ -1267,25 +1243,17 @@ public final class WindowContainerTransaction implements Parcelable {
public static final int HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS = 4;
public static final int HIERARCHY_OP_TYPE_LAUNCH_TASK = 5;
public static final int HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT = 6;
public static final int HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT = 7;
public static final int HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT = 8;
public static final int HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT = 9;
public static final int HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT = 10;
public static final int HIERARCHY_OP_TYPE_REPARENT_CHILDREN = 11;
public static final int HIERARCHY_OP_TYPE_PENDING_INTENT = 12;
public static final int HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS = 13;
public static final int HIERARCHY_OP_TYPE_START_SHORTCUT = 14;
public static final int HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER = 15;
public static final int HIERARCHY_OP_TYPE_ADD_RECT_INSETS_PROVIDER = 16;
public static final int HIERARCHY_OP_TYPE_REMOVE_INSETS_PROVIDER = 17;
public static final int HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT = 18;
public static final int HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP = 19;
public static final int HIERARCHY_OP_TYPE_REMOVE_TASK = 20;
public static final int HIERARCHY_OP_TYPE_FINISH_ACTIVITY = 21;
public static final int HIERARCHY_OP_TYPE_SET_COMPANION_TASK_FRAGMENT = 22;
public static final int HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS = 23;
public static final int HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH = 24;
public static final int HIERARCHY_OP_TYPE_SET_TASK_FRAGMENT_OPERATION = 25;
public static final int HIERARCHY_OP_TYPE_PENDING_INTENT = 7;
public static final int HIERARCHY_OP_TYPE_START_SHORTCUT = 8;
public static final int HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER = 9;
public static final int HIERARCHY_OP_TYPE_ADD_RECT_INSETS_PROVIDER = 10;
public static final int HIERARCHY_OP_TYPE_REMOVE_INSETS_PROVIDER = 11;
public static final int HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP = 12;
public static final int HIERARCHY_OP_TYPE_REMOVE_TASK = 13;
public static final int HIERARCHY_OP_TYPE_FINISH_ACTIVITY = 14;
public static final int HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS = 15;
public static final int HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH = 16;
public static final int HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION = 17;
// The following key(s) are for use with mLaunchOptions:
// When launching a task (eg. from recents), this is the taskId to be launched.
@@ -1326,11 +1294,7 @@ public final class WindowContainerTransaction implements Parcelable {
@Nullable
private Intent mActivityIntent;
/** Used as options for {@link #createTaskFragment}. */
@Nullable
private TaskFragmentCreationParams mTaskFragmentCreationOptions;
/** Used as options for {@link #setTaskFragmentOperation}. */
/** Used as options for {@link #addTaskFragmentOperation}. */
@Nullable
private TaskFragmentOperation mTaskFragmentOperation;
@@ -1452,7 +1416,6 @@ public final class WindowContainerTransaction implements Parcelable {
mActivityTypes = copy.mActivityTypes;
mLaunchOptions = copy.mLaunchOptions;
mActivityIntent = copy.mActivityIntent;
mTaskFragmentCreationOptions = copy.mTaskFragmentCreationOptions;
mTaskFragmentOperation = copy.mTaskFragmentOperation;
mPendingIntent = copy.mPendingIntent;
mShortcutInfo = copy.mShortcutInfo;
@@ -1476,7 +1439,6 @@ public final class WindowContainerTransaction implements Parcelable {
mActivityTypes = in.createIntArray();
mLaunchOptions = in.readBundle();
mActivityIntent = in.readTypedObject(Intent.CREATOR);
mTaskFragmentCreationOptions = in.readTypedObject(TaskFragmentCreationParams.CREATOR);
mTaskFragmentOperation = in.readTypedObject(TaskFragmentOperation.CREATOR);
mPendingIntent = in.readTypedObject(PendingIntent.CREATOR);
mShortcutInfo = in.readTypedObject(ShortcutInfo.CREATOR);
@@ -1516,16 +1478,6 @@ public final class WindowContainerTransaction implements Parcelable {
return mReparent;
}
@NonNull
public IBinder getCompanionContainer() {
return mReparent;
}
@NonNull
public IBinder getCallingActivity() {
return mReparent;
}
public boolean getToTop() {
return mToTop;
}
@@ -1560,11 +1512,6 @@ public final class WindowContainerTransaction implements Parcelable {
return mReparentLeafTaskIfRelaunch;
}
@Nullable
public TaskFragmentCreationParams getTaskFragmentCreationOptions() {
return mTaskFragmentCreationOptions;
}
@Nullable
public TaskFragmentOperation getTaskFragmentOperation() {
return mTaskFragmentOperation;
@@ -1605,22 +1552,6 @@ public final class WindowContainerTransaction implements Parcelable {
case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT:
return "{SetAdjacentFlagRoot: container=" + mContainer + " clearRoot=" + mToTop
+ "}";
case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT:
return "{CreateTaskFragment: options=" + mTaskFragmentCreationOptions + "}";
case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT:
return "{DeleteTaskFragment: taskFragment=" + mContainer + "}";
case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT:
return "{StartActivityInTaskFragment: fragmentToken=" + mContainer + " intent="
+ mActivityIntent + " options=" + mLaunchOptions + "}";
case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT:
return "{ReparentActivityToTaskFragment: fragmentToken=" + mReparent
+ " activity=" + mContainer + "}";
case HIERARCHY_OP_TYPE_REPARENT_CHILDREN:
return "{ReparentChildren: oldParent=" + mContainer + " newParent=" + mReparent
+ "}";
case HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS:
return "{SetAdjacentTaskFragments: container=" + mContainer
+ " adjacentContainer=" + mReparent + "}";
case HIERARCHY_OP_TYPE_START_SHORTCUT:
return "{StartShortcut: options=" + mLaunchOptions + " info=" + mShortcutInfo
+ "}";
@@ -1631,8 +1562,6 @@ public final class WindowContainerTransaction implements Parcelable {
case HIERARCHY_OP_TYPE_REMOVE_INSETS_PROVIDER:
return "{removeLocalInsetsProvider: container=" + mContainer
+ " insetsType=" + Arrays.toString(mInsetsTypes) + "}";
case HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT:
return "{requestFocusOnTaskFragment: container=" + mContainer + "}";
case HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP:
return "{setAlwaysOnTop: container=" + mContainer
+ " alwaysOnTop=" + mAlwaysOnTop + "}";
@@ -1640,16 +1569,13 @@ public final class WindowContainerTransaction implements Parcelable {
return "{RemoveTask: task=" + mContainer + "}";
case HIERARCHY_OP_TYPE_FINISH_ACTIVITY:
return "{finishActivity: activity=" + mContainer + "}";
case HIERARCHY_OP_TYPE_SET_COMPANION_TASK_FRAGMENT:
return "{setCompanionTaskFragment: container = " + mContainer + " companion = "
+ mReparent + "}";
case HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS:
return "{ClearAdjacentRoot: container=" + mContainer + "}";
case HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH:
return "{setReparentLeafTaskIfRelaunch: container= " + mContainer
+ " reparentLeafTaskIfRelaunch= " + mReparentLeafTaskIfRelaunch + "}";
case HIERARCHY_OP_TYPE_SET_TASK_FRAGMENT_OPERATION:
return "{setTaskFragmentOperation: fragmentToken= " + mContainer
case HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION:
return "{addTaskFragmentOperation: fragmentToken= " + mContainer
+ " operation= " + mTaskFragmentOperation + "}";
default:
return "{mType=" + mType + " container=" + mContainer + " reparent=" + mReparent
@@ -1677,7 +1603,6 @@ public final class WindowContainerTransaction implements Parcelable {
dest.writeIntArray(mActivityTypes);
dest.writeBundle(mLaunchOptions);
dest.writeTypedObject(mActivityIntent, flags);
dest.writeTypedObject(mTaskFragmentCreationOptions, flags);
dest.writeTypedObject(mTaskFragmentOperation, flags);
dest.writeTypedObject(mPendingIntent, flags);
dest.writeTypedObject(mShortcutInfo, flags);
@@ -1732,9 +1657,6 @@ public final class WindowContainerTransaction implements Parcelable {
@Nullable
private Intent mActivityIntent;
@Nullable
private TaskFragmentCreationParams mTaskFragmentCreationOptions;
@Nullable
private TaskFragmentOperation mTaskFragmentOperation;
@@ -1812,12 +1734,6 @@ public final class WindowContainerTransaction implements Parcelable {
return this;
}
Builder setTaskFragmentCreationOptions(
@Nullable TaskFragmentCreationParams taskFragmentCreationOptions) {
mTaskFragmentCreationOptions = taskFragmentCreationOptions;
return this;
}
Builder setTaskFragmentOperation(
@Nullable TaskFragmentOperation taskFragmentOperation) {
mTaskFragmentOperation = taskFragmentOperation;
@@ -1852,7 +1768,6 @@ public final class WindowContainerTransaction implements Parcelable {
hierarchyOp.mActivityIntent = mActivityIntent;
hierarchyOp.mPendingIntent = mPendingIntent;
hierarchyOp.mAlwaysOnTop = mAlwaysOnTop;
hierarchyOp.mTaskFragmentCreationOptions = mTaskFragmentCreationOptions;
hierarchyOp.mTaskFragmentOperation = mTaskFragmentOperation;
hierarchyOp.mShortcutInfo = mShortcutInfo;
hierarchyOp.mReparentLeafTaskIfRelaunch = mReparentLeafTaskIfRelaunch;

View File

@@ -310,16 +310,12 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
OP_TYPE_SET_ANIMATION_PARAMS)
.setAnimationParams(animationParams)
.build();
wct.setTaskFragmentOperation(fragmentToken, operation);
wct.addTaskFragmentOperation(fragmentToken, operation);
}
void deleteTaskFragment(@NonNull WindowContainerTransaction wct,
@NonNull IBinder fragmentToken) {
if (!mFragmentInfos.containsKey(fragmentToken)) {
throw new IllegalArgumentException(
"Can't find an existing TaskFragment with fragmentToken=" + fragmentToken);
}
wct.deleteTaskFragment(mFragmentInfos.get(fragmentToken).getToken());
wct.deleteTaskFragment(fragmentToken);
}
void updateTaskFragmentInfo(@NonNull TaskFragmentInfo taskFragmentInfo) {

View File

@@ -20,6 +20,8 @@ import static android.app.ActivityManager.START_SUCCESS;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.window.TaskFragmentOperation.OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_OP_TYPE;
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO;
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_THROWABLE;
@@ -31,8 +33,6 @@ import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_ERROR;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_INFO_CHANGED;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_VANISHED;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
import static androidx.window.extensions.embedding.SplitContainer.getFinishPrimaryWithSecondaryBehavior;
import static androidx.window.extensions.embedding.SplitContainer.getFinishSecondaryWithPrimaryBehavior;
@@ -67,6 +67,7 @@ import android.util.SparseArray;
import android.view.WindowMetrics;
import android.window.TaskFragmentAnimationParams;
import android.window.TaskFragmentInfo;
import android.window.TaskFragmentOperation;
import android.window.TaskFragmentParentInfo;
import android.window.TaskFragmentTransaction;
import android.window.WindowContainerTransaction;
@@ -592,11 +593,11 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
@GuardedBy("mLock")
void onTaskFragmentError(@NonNull WindowContainerTransaction wct,
@Nullable IBinder errorCallbackToken, @Nullable TaskFragmentInfo taskFragmentInfo,
int opType, @NonNull Throwable exception) {
@TaskFragmentOperation.OperationType int opType, @NonNull Throwable exception) {
Log.e(TAG, "onTaskFragmentError=" + exception.getMessage());
switch (opType) {
case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT:
case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT: {
case OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT:
case OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT: {
final TaskFragmentContainer container;
if (taskFragmentInfo != null) {
container = getContainer(taskFragmentInfo.getFragmentToken());

View File

@@ -20,13 +20,13 @@ import static android.app.ActivityManager.START_CANCELED;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_TASK_FRAGMENT;
import static android.window.TaskFragmentTransaction.TYPE_ACTIVITY_REPARENTED_TO_TASK;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_APPEARED;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_ERROR;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_INFO_CHANGED;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_VANISHED;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.DEFAULT_FINISH_PRIMARY_WITH_SECONDARY;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.DEFAULT_FINISH_SECONDARY_WITH_PRIMARY;
@@ -1139,7 +1139,7 @@ public class SplitControllerTest {
final TaskFragmentTransaction transaction = new TaskFragmentTransaction();
final IBinder errorToken = new Binder();
final TaskFragmentInfo info = mock(TaskFragmentInfo.class);
final int opType = HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT;
final int opType = OP_TYPE_CREATE_TASK_FRAGMENT;
final Exception exception = new SecurityException("test");
final Bundle errorBundle = TaskFragmentOrganizer.putErrorInfoInBundle(exception, info,
opType);

View File

@@ -193,7 +193,7 @@ public class SplitPresenterTest {
OP_TYPE_SET_ANIMATION_PARAMS)
.setAnimationParams(animationParams)
.build();
verify(mTransaction).setTaskFragmentOperation(container.getTaskFragmentToken(),
verify(mTransaction).addTaskFragmentOperation(container.getTaskFragmentToken(),
expectedOperation);
assertTrue(container.areLastRequestedAnimationParamsEqual(animationParams));
@@ -202,7 +202,7 @@ public class SplitPresenterTest {
mPresenter.updateAnimationParams(mTransaction, container.getTaskFragmentToken(),
animationParams);
verify(mTransaction, never()).setTaskFragmentOperation(any(), any());
verify(mTransaction, never()).addTaskFragmentOperation(any(), any());
}
@Test

View File

@@ -56,7 +56,7 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.TRANSIT_NONE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
@@ -2889,7 +2889,7 @@ class ActivityStarter {
if (taskFragment.isOrganized()) {
mService.mWindowOrganizerController.sendTaskFragmentOperationFailure(
taskFragment.getTaskFragmentOrganizer(), mRequest.errorCallbackToken,
taskFragment, HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT,
taskFragment, OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT,
new SecurityException(errMsg));
} else {
// If the taskFragment is not organized, just dump error message as warning logs.

View File

@@ -49,6 +49,7 @@ import android.view.WindowManager;
import android.window.ITaskFragmentOrganizer;
import android.window.ITaskFragmentOrganizerController;
import android.window.TaskFragmentInfo;
import android.window.TaskFragmentOperation;
import android.window.TaskFragmentParentInfo;
import android.window.TaskFragmentTransaction;
import android.window.WindowContainerTransaction;
@@ -297,7 +298,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
@NonNull
TaskFragmentTransaction.Change prepareTaskFragmentError(
@Nullable IBinder errorCallbackToken, @Nullable TaskFragment taskFragment,
int opType, @NonNull Throwable exception) {
@TaskFragmentOperation.OperationType int opType, @NonNull Throwable exception) {
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
"Sending TaskFragment error exception=%s", exception.toString());
final TaskFragmentInfo info =
@@ -629,7 +630,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
void onTaskFragmentError(@NonNull ITaskFragmentOrganizer organizer,
@Nullable IBinder errorCallbackToken, @Nullable TaskFragment taskFragment,
int opType, @NonNull Throwable exception) {
@TaskFragmentOperation.OperationType int opType, @NonNull Throwable exception) {
if (taskFragment != null && taskFragment.mTaskFragmentVanishedSent) {
return;
}
@@ -803,6 +804,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
// Set when the event is deferred due to the host task is invisible. The defer time will
// be the last active time of the host task.
private long mDeferTime;
@TaskFragmentOperation.OperationType
private int mOpType;
private PendingTaskFragmentEvent(@EventType int eventType,
@@ -812,7 +814,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
@Nullable Throwable exception,
@Nullable ActivityRecord activity,
@Nullable Task task,
int opType) {
@TaskFragmentOperation.OperationType int opType) {
mEventType = eventType;
mTaskFragmentOrg = taskFragmentOrg;
mTaskFragment = taskFragment;
@@ -853,6 +855,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
private ActivityRecord mActivity;
@Nullable
private Task mTask;
@TaskFragmentOperation.OperationType
private int mOpType;
Builder(@EventType int eventType, @NonNull ITaskFragmentOrganizer taskFragmentOrg) {
@@ -885,7 +888,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
return this;
}
Builder setOpType(int opType) {
Builder setOpType(@TaskFragmentOperation.OperationType int opType) {
mOpType = opType;
return this;
}

View File

@@ -21,12 +21,19 @@ import static android.app.ActivityManager.isStartResultSuccessful;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOW_CONFIG_BOUNDS;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_DELETE_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_ANIMATION_PARAMS;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_COMPANION_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_UNKNOWN;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_ADD_RECT_INSETS_PROVIDER;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_FINISH_ACTIVITY;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_LAUNCH_TASK;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_PENDING_INTENT;
@@ -34,19 +41,12 @@ import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REMOVE_TASK;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_CHILDREN;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_COMPANION_TASK_FRAGMENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_TASK_FRAGMENT_OPERATION;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_SHORTCUT;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
@@ -119,6 +119,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
private static final String TAG = "WindowOrganizerController";
private static final int TRANSACT_EFFECTS_NONE = 0;
/** Flag indicating that an applied transaction may have effected lifecycle */
private static final int TRANSACT_EFFECTS_CLIENT_CONFIG = 1;
private static final int TRANSACT_EFFECTS_LIFECYCLE = 1 << 1;
@@ -488,7 +489,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
private void applyTransaction(@NonNull WindowContainerTransaction t, int syncId,
@Nullable Transition transition, @NonNull CallerInfo caller,
@Nullable Transition finishTransition) {
int effects = 0;
int effects = TRANSACT_EFFECTS_NONE;
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Apply window transaction, syncId=%d", syncId);
mService.deferWindowLayout();
mService.mTaskSupervisor.setDeferRootVisibilityUpdate(true /* deferUpdate */);
@@ -630,7 +631,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
// masks here.
final int configMask = change.getConfigSetMask() & CONTROLLABLE_CONFIGS;
final int windowMask = change.getWindowSetMask() & CONTROLLABLE_WINDOW_CONFIGS;
int effects = 0;
int effects = TRANSACT_EFFECTS_NONE;
final int windowingMode = change.getWindowingMode();
if (configMask != 0) {
@@ -795,7 +796,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
@NonNull WindowContainerTransaction.Change c, @Nullable IBinder errorCallbackToken) {
if (taskFragment.isEmbeddedTaskFragmentInPip()) {
// No override from organizer for embedded TaskFragment in a PIP Task.
return 0;
return TRANSACT_EFFECTS_NONE;
}
// When the TaskFragment is resized, we may want to create a change transition for it, for
@@ -861,197 +862,6 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
effects |= clearAdjacentRootsHierarchyOp(hop);
break;
}
case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT: {
final TaskFragmentCreationParams taskFragmentCreationOptions =
hop.getTaskFragmentCreationOptions();
createTaskFragment(taskFragmentCreationOptions, errorCallbackToken, caller,
transition);
break;
}
case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT: {
final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
if (wc == null || !wc.isAttached()) {
Slog.e(TAG, "Attempt to operate on unknown or detached container: " + wc);
break;
}
final TaskFragment taskFragment = wc.asTaskFragment();
if (taskFragment == null || taskFragment.asTask() != null) {
throw new IllegalArgumentException(
"Can only delete organized TaskFragment, but not Task.");
}
if (isInLockTaskMode) {
final ActivityRecord bottomActivity = taskFragment.getActivity(
a -> !a.finishing, false /* traverseTopToBottom */);
if (bottomActivity != null
&& mService.getLockTaskController().activityBlockedFromFinish(
bottomActivity)) {
Slog.w(TAG, "Skip removing TaskFragment due in lock task mode.");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken,
taskFragment, type, new IllegalStateException(
"Not allow to delete task fragment in lock task mode."));
break;
}
}
effects |= deleteTaskFragment(taskFragment, organizer, errorCallbackToken,
transition);
break;
}
case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT: {
final IBinder fragmentToken = hop.getContainer();
final TaskFragment tf = mLaunchTaskFragments.get(fragmentToken);
if (tf == null) {
final Throwable exception = new IllegalArgumentException(
"Not allowed to operate with invalid fragment token");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, tf, type,
exception);
break;
}
if (tf.isEmbeddedTaskFragmentInPip()) {
final Throwable exception = new IllegalArgumentException(
"Not allowed to start activity in PIP TaskFragment");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, tf, type,
exception);
break;
}
final Intent activityIntent = hop.getActivityIntent();
final Bundle activityOptions = hop.getLaunchOptions();
final int result = mService.getActivityStartController()
.startActivityInTaskFragment(tf, activityIntent, activityOptions,
hop.getCallingActivity(), caller.mUid, caller.mPid,
errorCallbackToken);
if (!isStartResultSuccessful(result)) {
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, tf, type,
convertStartFailureToThrowable(result, activityIntent));
} else {
effects |= TRANSACT_EFFECTS_LIFECYCLE;
}
break;
}
case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT: {
final IBinder fragmentToken = hop.getNewParent();
final IBinder activityToken = hop.getContainer();
ActivityRecord activity = ActivityRecord.forTokenLocked(activityToken);
if (activity == null) {
// The token may be a temporary token if the activity doesn't belong to
// the organizer process.
activity = mTaskFragmentOrganizerController
.getReparentActivityFromTemporaryToken(organizer, activityToken);
}
final TaskFragment parent = mLaunchTaskFragments.get(fragmentToken);
if (parent == null || activity == null) {
final Throwable exception = new IllegalArgumentException(
"Not allowed to operate with invalid fragment token or activity.");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, parent, type,
exception);
break;
}
if (parent.isEmbeddedTaskFragmentInPip()) {
final Throwable exception = new IllegalArgumentException(
"Not allowed to reparent activity to PIP TaskFragment");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, parent, type,
exception);
break;
}
if (parent.isAllowedToEmbedActivity(activity) != EMBEDDING_ALLOWED) {
final Throwable exception = new SecurityException(
"The task fragment is not allowed to embed the given activity.");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, parent, type,
exception);
break;
}
if (parent.getTask() != activity.getTask()) {
final Throwable exception = new SecurityException("The reparented activity is"
+ " not in the same Task as the target TaskFragment.");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, parent, type,
exception);
break;
}
if (transition != null) {
transition.collect(activity);
if (activity.getParent() != null) {
// Collect the current parent. Its visibility may change as a result of
// this reparenting.
transition.collect(activity.getParent());
}
transition.collect(parent);
}
activity.reparent(parent, POSITION_TOP);
effects |= TRANSACT_EFFECTS_LIFECYCLE;
break;
}
case HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS: {
final IBinder fragmentToken = hop.getContainer();
final IBinder adjacentFragmentToken = hop.getAdjacentRoot();
final TaskFragment tf1 = mLaunchTaskFragments.get(fragmentToken);
final TaskFragment tf2 = adjacentFragmentToken != null
? mLaunchTaskFragments.get(adjacentFragmentToken)
: null;
if (tf1 == null || (adjacentFragmentToken != null && tf2 == null)) {
final Throwable exception = new IllegalArgumentException(
"Not allowed to set adjacent on invalid fragment tokens");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, tf1, type,
exception);
break;
}
if (tf1.isEmbeddedTaskFragmentInPip()
|| (tf2 != null && tf2.isEmbeddedTaskFragmentInPip())) {
final Throwable exception = new IllegalArgumentException(
"Not allowed to set adjacent on TaskFragment in PIP Task");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, tf1, type,
exception);
break;
}
tf1.setAdjacentTaskFragment(tf2);
effects |= TRANSACT_EFFECTS_LIFECYCLE;
// Clear the focused app if the focused app is no longer visible after reset the
// adjacent TaskFragments.
if (tf2 == null && tf1.getDisplayContent().mFocusedApp != null
&& tf1.hasChild(tf1.getDisplayContent().mFocusedApp)
&& !tf1.shouldBeVisible(null /* starting */)) {
tf1.getDisplayContent().setFocusedApp(null);
}
final Bundle bundle = hop.getLaunchOptions();
final WindowContainerTransaction.TaskFragmentAdjacentParams adjacentParams =
bundle != null ? new WindowContainerTransaction.TaskFragmentAdjacentParams(
bundle) : null;
if (adjacentParams == null) {
break;
}
tf1.setDelayLastActivityRemoval(
adjacentParams.shouldDelayPrimaryLastActivityRemoval());
if (tf2 != null) {
tf2.setDelayLastActivityRemoval(
adjacentParams.shouldDelaySecondaryLastActivityRemoval());
}
break;
}
case HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT: {
final TaskFragment tf = mLaunchTaskFragments.get(hop.getContainer());
if (tf == null || !tf.isAttached()) {
Slog.e(TAG, "Attempt to operate on detached container: " + tf);
break;
}
final ActivityRecord curFocus = tf.getDisplayContent().mFocusedApp;
if (curFocus != null && curFocus.getTaskFragment() == tf) {
Slog.d(TAG, "The requested TaskFragment already has the focus.");
break;
}
if (curFocus != null && curFocus.getTask() != tf.getTask()) {
Slog.d(TAG, "The Task of the requested TaskFragment doesn't have focus.");
break;
}
final ActivityRecord targetFocus = tf.getTopResumedActivity();
if (targetFocus == null) {
Slog.d(TAG, "There is no resumed activity in the requested TaskFragment.");
break;
}
tf.getDisplayContent().setFocusedApp(targetFocus);
break;
}
case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT: {
effects |= reparentChildrenTasksHierarchyOp(hop, transition, syncId,
isInLockTaskMode);
@@ -1126,24 +936,9 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
effects |= sanitizeAndApplyHierarchyOp(wc, hop);
break;
}
case HIERARCHY_OP_TYPE_SET_COMPANION_TASK_FRAGMENT: {
final IBinder fragmentToken = hop.getContainer();
final IBinder companionToken = hop.getCompanionContainer();
final TaskFragment fragment = mLaunchTaskFragments.get(fragmentToken);
final TaskFragment companion = companionToken != null ? mLaunchTaskFragments.get(
companionToken) : null;
if (fragment == null || !fragment.isAttached()) {
final Throwable exception = new IllegalArgumentException(
"Not allowed to set companion on invalid fragment tokens");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, fragment, type,
exception);
break;
}
fragment.setCompanionTaskFragment(companion);
break;
}
case HIERARCHY_OP_TYPE_SET_TASK_FRAGMENT_OPERATION: {
effects |= applyTaskFragmentOperation(hop, errorCallbackToken, organizer);
case HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION: {
effects |= applyTaskFragmentOperation(hop, transition, isInLockTaskMode, caller,
errorCallbackToken, organizer);
break;
}
default: {
@@ -1203,22 +998,6 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
break;
}
case HIERARCHY_OP_TYPE_REPARENT_CHILDREN: {
final WindowContainer oldParent = WindowContainer.fromBinder(hop.getContainer());
final WindowContainer newParent = hop.getNewParent() != null
? WindowContainer.fromBinder(hop.getNewParent())
: null;
if (oldParent == null || oldParent.asTaskFragment() == null
|| !oldParent.isAttached()) {
Slog.e(TAG, "Attempt to operate on unknown or detached container: "
+ oldParent);
break;
}
reparentTaskFragment(oldParent.asTaskFragment(), newParent, organizer,
errorCallbackToken, transition);
effects |= TRANSACT_EFFECTS_LIFECYCLE;
break;
}
case HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER: {
if (finishTransition == null) break;
final WindowContainer container = WindowContainer.fromBinder(hop.getContainer());
@@ -1278,45 +1057,241 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
return effects;
}
/** Applies change set through {@link WindowContainerTransaction#setTaskFragmentOperation}. */
/**
* Applies change set through {@link WindowContainerTransaction#addTaskFragmentOperation}.
* @return an int to represent the transaction effects, such as {@link #TRANSACT_EFFECTS_NONE},
* {@link #TRANSACT_EFFECTS_LIFECYCLE} or {@link #TRANSACT_EFFECTS_CLIENT_CONFIG}.
*/
private int applyTaskFragmentOperation(@NonNull WindowContainerTransaction.HierarchyOp hop,
@Nullable Transition transition, boolean isInLockTaskMode, @NonNull CallerInfo caller,
@Nullable IBinder errorCallbackToken, @Nullable ITaskFragmentOrganizer organizer) {
if (!validateTaskFragmentOperation(hop, errorCallbackToken, organizer)) {
return TRANSACT_EFFECTS_NONE;
}
final IBinder fragmentToken = hop.getContainer();
final TaskFragment taskFragment = mLaunchTaskFragments.get(fragmentToken);
final TaskFragmentOperation operation = hop.getTaskFragmentOperation();
if (operation == null) {
final Throwable exception = new IllegalArgumentException(
"TaskFragmentOperation must be non-null");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
HIERARCHY_OP_TYPE_SET_TASK_FRAGMENT_OPERATION, exception);
return 0;
}
final int opType = operation.getOpType();
if (taskFragment == null || !taskFragment.isAttached()) {
final Throwable exception = new IllegalArgumentException(
"Not allowed to apply operation on invalid fragment tokens opType=" + opType);
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
HIERARCHY_OP_TYPE_SET_TASK_FRAGMENT_OPERATION, exception);
return 0;
}
int effect = 0;
int effects = TRANSACT_EFFECTS_NONE;
switch (opType) {
case OP_TYPE_CREATE_TASK_FRAGMENT: {
final TaskFragmentCreationParams taskFragmentCreationParams =
operation.getTaskFragmentCreationParams();
if (taskFragmentCreationParams == null) {
final Throwable exception = new IllegalArgumentException(
"TaskFragmentCreationParams must be non-null");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
opType, exception);
break;
}
createTaskFragment(taskFragmentCreationParams, errorCallbackToken, caller,
transition);
break;
}
case OP_TYPE_DELETE_TASK_FRAGMENT: {
if (isInLockTaskMode) {
final ActivityRecord bottomActivity = taskFragment.getActivity(
a -> !a.finishing, false /* traverseTopToBottom */);
if (bottomActivity != null
&& mService.getLockTaskController().activityBlockedFromFinish(
bottomActivity)) {
Slog.w(TAG, "Skip removing TaskFragment due in lock task mode.");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken,
taskFragment, opType, new IllegalStateException(
"Not allow to delete task fragment in lock task mode."));
break;
}
}
effects |= deleteTaskFragment(taskFragment, transition);
break;
}
case OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT: {
final IBinder callerActivityToken = operation.getActivityToken();
final Intent activityIntent = operation.getActivityIntent();
final Bundle activityOptions = operation.getBundle();
final int result = mService.getActivityStartController()
.startActivityInTaskFragment(taskFragment, activityIntent, activityOptions,
callerActivityToken, caller.mUid, caller.mPid,
errorCallbackToken);
if (!isStartResultSuccessful(result)) {
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
opType, convertStartFailureToThrowable(result, activityIntent));
} else {
effects |= TRANSACT_EFFECTS_LIFECYCLE;
}
break;
}
case OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT: {
final IBinder activityToken = operation.getActivityToken();
ActivityRecord activity = ActivityRecord.forTokenLocked(activityToken);
if (activity == null) {
// The token may be a temporary token if the activity doesn't belong to
// the organizer process.
activity = mTaskFragmentOrganizerController
.getReparentActivityFromTemporaryToken(organizer, activityToken);
}
if (activity == null) {
final Throwable exception = new IllegalArgumentException(
"Not allowed to operate with invalid activity.");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
opType, exception);
break;
}
if (taskFragment.isAllowedToEmbedActivity(activity) != EMBEDDING_ALLOWED) {
final Throwable exception = new SecurityException(
"The task fragment is not allowed to embed the given activity.");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
opType, exception);
break;
}
if (taskFragment.getTask() != activity.getTask()) {
final Throwable exception = new SecurityException("The reparented activity is"
+ " not in the same Task as the target TaskFragment.");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
opType, exception);
break;
}
if (transition != null) {
transition.collect(activity);
if (activity.getParent() != null) {
// Collect the current parent. Its visibility may change as a result of
// this reparenting.
transition.collect(activity.getParent());
}
transition.collect(taskFragment);
}
activity.reparent(taskFragment, POSITION_TOP);
effects |= TRANSACT_EFFECTS_LIFECYCLE;
break;
}
case OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS: {
final IBinder secondaryFragmentToken = operation.getSecondaryFragmentToken();
final TaskFragment secondaryTaskFragment = secondaryFragmentToken != null
? mLaunchTaskFragments.get(secondaryFragmentToken)
: null;
taskFragment.setAdjacentTaskFragment(secondaryTaskFragment);
effects |= TRANSACT_EFFECTS_LIFECYCLE;
// Clear the focused app if the focused app is no longer visible after reset the
// adjacent TaskFragments.
if (secondaryTaskFragment == null
&& taskFragment.getDisplayContent().mFocusedApp != null
&& taskFragment.hasChild(taskFragment.getDisplayContent().mFocusedApp)
&& !taskFragment.shouldBeVisible(null /* starting */)) {
taskFragment.getDisplayContent().setFocusedApp(null);
}
final Bundle bundle = hop.getLaunchOptions();
final WindowContainerTransaction.TaskFragmentAdjacentParams adjacentParams =
bundle != null ? new WindowContainerTransaction.TaskFragmentAdjacentParams(
bundle) : null;
if (adjacentParams == null) {
break;
}
taskFragment.setDelayLastActivityRemoval(
adjacentParams.shouldDelayPrimaryLastActivityRemoval());
if (secondaryTaskFragment != null) {
secondaryTaskFragment.setDelayLastActivityRemoval(
adjacentParams.shouldDelaySecondaryLastActivityRemoval());
}
break;
}
case OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT: {
final ActivityRecord curFocus = taskFragment.getDisplayContent().mFocusedApp;
if (curFocus != null && curFocus.getTaskFragment() == taskFragment) {
Slog.d(TAG, "The requested TaskFragment already has the focus.");
break;
}
if (curFocus != null && curFocus.getTask() != taskFragment.getTask()) {
Slog.d(TAG, "The Task of the requested TaskFragment doesn't have focus.");
break;
}
final ActivityRecord targetFocus = taskFragment.getTopResumedActivity();
if (targetFocus == null) {
Slog.d(TAG, "There is no resumed activity in the requested TaskFragment.");
break;
}
taskFragment.getDisplayContent().setFocusedApp(targetFocus);
break;
}
case OP_TYPE_SET_COMPANION_TASK_FRAGMENT: {
final IBinder companionFragmentToken = operation.getSecondaryFragmentToken();
final TaskFragment companionTaskFragment = companionFragmentToken != null
? mLaunchTaskFragments.get(companionFragmentToken)
: null;
taskFragment.setCompanionTaskFragment(companionTaskFragment);
break;
}
case OP_TYPE_SET_ANIMATION_PARAMS: {
final TaskFragmentAnimationParams animationParams = operation.getAnimationParams();
if (animationParams == null) {
final Throwable exception = new IllegalArgumentException(
"TaskFragmentAnimationParams must be non-null");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
HIERARCHY_OP_TYPE_SET_TASK_FRAGMENT_OPERATION, exception);
opType, exception);
break;
}
taskFragment.setAnimationParams(animationParams);
break;
}
// TODO(b/263436063): move other TaskFragment related operation here.
}
return effect;
return effects;
}
private boolean validateTaskFragmentOperation(
@NonNull WindowContainerTransaction.HierarchyOp hop,
@Nullable IBinder errorCallbackToken, @Nullable ITaskFragmentOrganizer organizer) {
final TaskFragmentOperation operation = hop.getTaskFragmentOperation();
final IBinder fragmentToken = hop.getContainer();
final TaskFragment taskFragment = mLaunchTaskFragments.get(fragmentToken);
if (operation == null) {
final Throwable exception = new IllegalArgumentException(
"TaskFragmentOperation must be non-null");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
OP_TYPE_UNKNOWN, exception);
return false;
}
final int opType = operation.getOpType();
if (opType == OP_TYPE_CREATE_TASK_FRAGMENT) {
// No need to check TaskFragment.
return true;
}
if (!validateTaskFragment(taskFragment, opType, errorCallbackToken, organizer)) {
return false;
}
final IBinder secondaryFragmentToken = operation.getSecondaryFragmentToken();
return secondaryFragmentToken == null
|| validateTaskFragment(mLaunchTaskFragments.get(secondaryFragmentToken), opType,
errorCallbackToken, organizer);
}
private boolean validateTaskFragment(@Nullable TaskFragment taskFragment,
@TaskFragmentOperation.OperationType int opType, @Nullable IBinder errorCallbackToken,
@Nullable ITaskFragmentOrganizer organizer) {
if (taskFragment == null || !taskFragment.isAttached()) {
// TaskFragment doesn't exist.
final Throwable exception = new IllegalArgumentException(
"Not allowed to apply operation on invalid fragment tokens opType=" + opType);
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
opType, exception);
return false;
}
if (taskFragment.isEmbeddedTaskFragmentInPip()
&& (opType != OP_TYPE_DELETE_TASK_FRAGMENT
// When the Task enters PiP before the organizer removes the empty TaskFragment, we
// should allow it to delete the TaskFragment for cleanup.
|| taskFragment.getTopNonFinishingActivity() != null)) {
final Throwable exception = new IllegalArgumentException(
"Not allowed to apply operation on PIP TaskFragment");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
opType, exception);
return false;
}
return true;
}
/** A helper method to send minimum dimension violation error to the client. */
@@ -1329,7 +1304,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
+ taskFragment.getBounds() + " does not satisfy minimum dimensions:"
+ minDimensions + " " + reason);
sendTaskFragmentOperationFailure(taskFragment.getTaskFragmentOrganizer(),
errorCallbackToken, taskFragment, -1 /* opType */, exception);
errorCallbackToken, taskFragment, OP_TYPE_UNKNOWN, exception);
}
/**
@@ -1366,7 +1341,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
final DisplayContent dc = task.getDisplayContent();
if (dc == null) {
Slog.w(TAG, "Container is no longer attached: " + task);
return 0;
return TRANSACT_EFFECTS_NONE;
}
final Task as = task;
@@ -1379,7 +1354,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
: WindowContainer.fromBinder(hop.getNewParent());
if (newParent == null) {
Slog.e(TAG, "Can't resolve parent window from token");
return 0;
return TRANSACT_EFFECTS_NONE;
}
if (task.getParent() != newParent) {
if (newParent.asTaskDisplayArea() != null) {
@@ -1390,14 +1365,14 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
if (newParent.inPinnedWindowingMode()) {
Slog.w(TAG, "Can't support moving a task to another PIP window..."
+ " newParent=" + newParent + " task=" + task);
return 0;
return TRANSACT_EFFECTS_NONE;
}
if (!task.supportsMultiWindowInDisplayArea(
newParent.asTask().getDisplayArea())) {
Slog.w(TAG, "Can't support task that doesn't support multi-window"
+ " mode in multi-window mode... newParent=" + newParent
+ " task=" + task);
return 0;
return TRANSACT_EFFECTS_NONE;
}
}
task.reparent((Task) newParent,
@@ -1459,22 +1434,22 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
if (currentParent == newParent) {
Slog.e(TAG, "reparentChildrenTasksHierarchyOp parent not changing: " + hop);
return 0;
return TRANSACT_EFFECTS_NONE;
}
if (!currentParent.isAttached()) {
Slog.e(TAG, "reparentChildrenTasksHierarchyOp currentParent detached="
+ currentParent + " hop=" + hop);
return 0;
return TRANSACT_EFFECTS_NONE;
}
if (!newParent.isAttached()) {
Slog.e(TAG, "reparentChildrenTasksHierarchyOp newParent detached="
+ newParent + " hop=" + hop);
return 0;
return TRANSACT_EFFECTS_NONE;
}
if (newParent.inPinnedWindowingMode()) {
Slog.e(TAG, "reparentChildrenTasksHierarchyOp newParent in PIP="
+ newParent + " hop=" + hop);
return 0;
return TRANSACT_EFFECTS_NONE;
}
final boolean newParentInMultiWindow = newParent.inMultiWindowMode();
@@ -1553,10 +1528,6 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
throw new IllegalArgumentException("setAdjacentRootsHierarchyOp: Not created by"
+ " organizer root1=" + root1 + " root2=" + root2);
}
if (root1.isEmbeddedTaskFragmentInPip() || root2.isEmbeddedTaskFragmentInPip()) {
Slog.e(TAG, "Attempt to set adjacent TaskFragment in PIP Task");
return 0;
}
root1.setAdjacentTaskFragment(root2);
return TRANSACT_EFFECTS_LIFECYCLE;
}
@@ -1725,52 +1696,12 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
final int type = hop.getType();
// Check for each type of the operations that are allowed for TaskFragmentOrganizer.
switch (type) {
case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT:
enforceTaskFragmentOrganized(func,
WindowContainer.fromBinder(hop.getContainer()), organizer);
break;
case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS:
enforceTaskFragmentOrganized(func,
WindowContainer.fromBinder(hop.getContainer()), organizer);
enforceTaskFragmentOrganized(func,
WindowContainer.fromBinder(hop.getAdjacentRoot()),
organizer);
break;
case HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS:
enforceTaskFragmentOrganized(func,
WindowContainer.fromBinder(hop.getContainer()), organizer);
break;
case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT:
// We are allowing organizer to create TaskFragment. We will check the
// ownerToken in #createTaskFragment, and trigger error callback if that is not
// valid.
break;
case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT:
case HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT:
case HIERARCHY_OP_TYPE_SET_TASK_FRAGMENT_OPERATION:
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 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
final Throwable exception =
new IllegalArgumentException("TaskFragment token must be unique");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, null /* taskFragment */,
HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT, exception);
OP_TYPE_CREATE_TASK_FRAGMENT, exception);
return;
}
if (ownerActivity == null || ownerActivity.getTask() == null) {
final Throwable exception =
new IllegalArgumentException("Not allowed to operate with invalid ownerToken");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, null /* taskFragment */,
HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT, exception);
OP_TYPE_CREATE_TASK_FRAGMENT, exception);
return;
}
if (!ownerActivity.isResizeable()) {
final IllegalArgumentException exception = new IllegalArgumentException("Not allowed"
+ " to operate with non-resizable owner Activity");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, null /* taskFragment */,
HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT, exception);
OP_TYPE_CREATE_TASK_FRAGMENT, exception);
return;
}
// The ownerActivity has to belong to the same app as the target Task.
@@ -1942,14 +1873,14 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
new SecurityException("Not allowed to operate with the ownerToken while "
+ "the root activity of the target task belong to the different app");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, null /* taskFragment */,
HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT, exception);
OP_TYPE_CREATE_TASK_FRAGMENT, exception);
return;
}
if (ownerTask.inPinnedWindowingMode()) {
final Throwable exception = new IllegalArgumentException(
"Not allowed to create TaskFragment in PIP Task");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, null /* taskFragment */,
HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT, exception);
OP_TYPE_CREATE_TASK_FRAGMENT, exception);
return;
}
final TaskFragment taskFragment = new TaskFragment(mService,
@@ -1984,91 +1915,11 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
if (transition != null) transition.collectExistenceChange(taskFragment);
}
private void reparentTaskFragment(@NonNull TaskFragment oldParent,
@Nullable WindowContainer<?> newParent, @Nullable ITaskFragmentOrganizer organizer,
@Nullable IBinder errorCallbackToken, @Nullable Transition transition) {
final TaskFragment newParentTF;
if (newParent == null) {
// Use the old parent's parent if the caller doesn't specify the new parent.
newParentTF = oldParent.getTask();
} else {
newParentTF = newParent.asTaskFragment();
}
if (newParentTF == null) {
final Throwable exception =
new IllegalArgumentException("Not allowed to operate with invalid container");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, newParentTF,
HIERARCHY_OP_TYPE_REPARENT_CHILDREN, exception);
return;
}
if (newParentTF.getTaskFragmentOrganizer() != null) {
// We are reparenting activities to a new embedded TaskFragment, this operation is only
// allowed if the new parent is trusted by all reparent activities.
final boolean isEmbeddingDisallowed = oldParent.forAllActivities(activity ->
newParentTF.isAllowedToEmbedActivity(activity) != EMBEDDING_ALLOWED);
if (isEmbeddingDisallowed) {
final Throwable exception = new SecurityException(
"The new parent is not allowed to embed the activities.");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, newParentTF,
HIERARCHY_OP_TYPE_REPARENT_CHILDREN, exception);
return;
}
}
if (newParentTF.isEmbeddedTaskFragmentInPip() || oldParent.isEmbeddedTaskFragmentInPip()) {
final Throwable exception = new SecurityException(
"Not allow to reparent in TaskFragment in PIP Task.");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, newParentTF,
HIERARCHY_OP_TYPE_REPARENT_CHILDREN, exception);
return;
}
if (newParentTF.getTask() != oldParent.getTask()) {
final Throwable exception = new SecurityException(
"The new parent is not in the same Task as the old parent.");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, newParentTF,
HIERARCHY_OP_TYPE_REPARENT_CHILDREN, exception);
return;
}
if (transition != null) {
// Collect the current parent. It's visibility may change as a result of this
// reparenting.
transition.collect(oldParent);
transition.collect(newParentTF);
}
while (oldParent.hasChild()) {
final WindowContainer child = oldParent.getChildAt(0);
if (transition != null) {
transition.collect(child);
}
child.reparent(newParentTF, POSITION_TOP);
}
}
private int deleteTaskFragment(@NonNull TaskFragment taskFragment,
@Nullable ITaskFragmentOrganizer organizer, @Nullable IBinder errorCallbackToken,
@Nullable Transition transition) {
final int index = mLaunchTaskFragments.indexOfValue(taskFragment);
if (index < 0) {
final Throwable exception =
new IllegalArgumentException("Not allowed to operate with invalid "
+ "taskFragment");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT, exception);
return 0;
}
if (taskFragment.isEmbeddedTaskFragmentInPip()
// When the Task enters PiP before the organizer removes the empty TaskFragment, we
// should allow it to do the cleanup.
&& taskFragment.getTopNonFinishingActivity() != null) {
final Throwable exception = new IllegalArgumentException(
"Not allowed to delete TaskFragment in PIP Task");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT, exception);
return 0;
}
if (transition != null) transition.collectExistenceChange(taskFragment);
mLaunchTaskFragments.removeAt(index);
mLaunchTaskFragments.remove(taskFragment.getFragmentToken());
taskFragment.remove(true /* withTransition */, "deleteTaskFragment");
return TRANSACT_EFFECTS_LIFECYCLE;
}
@@ -2093,8 +1944,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
void sendTaskFragmentOperationFailure(@NonNull ITaskFragmentOrganizer organizer,
@Nullable IBinder errorCallbackToken, @Nullable TaskFragment taskFragment, int opType,
@NonNull Throwable exception) {
@Nullable IBinder errorCallbackToken, @Nullable TaskFragment taskFragment,
@TaskFragmentOperation.OperationType int opType, @NonNull Throwable exception) {
if (organizer == null) {
throw new IllegalArgumentException("Not allowed to operate with invalid organizer");
}

View File

@@ -23,7 +23,12 @@ import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_NONE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_DELETE_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_ANIMATION_PARAMS;
import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_OP_TYPE;
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_THROWABLE;
import static android.window.TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_CHANGE;
@@ -36,13 +41,6 @@ import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_ERROR;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_INFO_CHANGED;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_VANISHED;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_CHILDREN;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -339,11 +337,11 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
final Throwable exception = new IllegalArgumentException("Test exception");
mController.onTaskFragmentError(mTaskFragment.getTaskFragmentOrganizer(),
mErrorToken, null /* taskFragment */, HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS,
mErrorToken, null /* taskFragment */, OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS,
exception);
mController.dispatchPendingEvents();
assertTaskFragmentErrorTransaction(HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS,
assertTaskFragmentErrorTransaction(OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS,
exception.getClass());
}
@@ -519,50 +517,20 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
@Test
public void testApplyTransaction_enforceHierarchyChange_deleteTaskFragment() {
doReturn(true).when(mTaskFragment).isAttached();
// Throw exception if the transaction is trying to change a window that is not organized by
// the organizer.
mTransaction.deleteTaskFragment(mFragmentWindowToken);
assertApplyTransactionDisallowed(mTransaction);
// Allow transaction to change a TaskFragment created by the organizer.
mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
"Test:TaskFragmentOrganizer" /* processName */);
clearInvocations(mAtm.mRootWindowContainer);
assertApplyTransactionAllowed(mTransaction);
// No lifecycle update when the TaskFragment is not recorded.
verify(mAtm.mRootWindowContainer, never()).resumeFocusedTasksTopActivities();
mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
assertApplyTransactionAllowed(mTransaction);
verify(mAtm.mRootWindowContainer).resumeFocusedTasksTopActivities();
}
@Test
public void testApplyTransaction_enforceHierarchyChange_setAdjacentRoots() {
final TaskFragment taskFragment2 =
new TaskFragment(mAtm, new Binder(), true /* createdByOrganizer */);
final WindowContainerToken token2 = taskFragment2.mRemoteToken.toWindowContainerToken();
// Throw exception if the transaction is trying to change a window that is not organized by
// the organizer.
mTransaction.setAdjacentRoots(mFragmentWindowToken, token2);
mTransaction.deleteTaskFragment(mFragmentToken);
assertApplyTransactionDisallowed(mTransaction);
// Allow transaction to change a TaskFragment created by the organizer.
mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
"Test:TaskFragmentOrganizer" /* processName */);
taskFragment2.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
"Test:TaskFragmentOrganizer" /* processName */);
clearInvocations(mAtm.mRootWindowContainer);
assertApplyTransactionAllowed(mTransaction);
verify(mAtm.mRootWindowContainer).resumeFocusedTasksTopActivities();
}
@@ -693,7 +661,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
}
@Test
public void testApplyTransaction_enforceTaskFragmentOrganized_setTaskFragmentOperation() {
public void testApplyTransaction_enforceTaskFragmentOrganized_addTaskFragmentOperation() {
final Task task = createTask(mDisplayContent);
mTaskFragment = new TaskFragmentBuilder(mAtm)
.setParentTask(task)
@@ -704,7 +672,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
OP_TYPE_SET_ANIMATION_PARAMS)
.setAnimationParams(TaskFragmentAnimationParams.DEFAULT)
.build();
mTransaction.setTaskFragmentOperation(mFragmentToken, operation);
mTransaction.addTaskFragmentOperation(mFragmentToken, operation);
mOrganizer.applyTransaction(mTransaction, TASK_FRAGMENT_TRANSIT_CHANGE,
false /* shouldApplyIndependently */);
@@ -718,7 +686,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
}
@Test
public void testSetTaskFragmentOperation() {
public void testAddTaskFragmentOperation() {
final Task task = createTask(mDisplayContent);
mTaskFragment = new TaskFragmentBuilder(mAtm)
.setParentTask(task)
@@ -736,7 +704,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
OP_TYPE_SET_ANIMATION_PARAMS)
.setAnimationParams(animationParams)
.build();
mTransaction.setTaskFragmentOperation(mFragmentToken, operation);
mTransaction.addTaskFragmentOperation(mFragmentToken, operation);
mOrganizer.applyTransaction(mTransaction, TASK_FRAGMENT_TRANSIT_CHANGE,
false /* shouldApplyIndependently */);
assertApplyTransactionAllowed(mTransaction);
@@ -844,26 +812,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
task.mChildren.indexOf(mTaskFragment));
}
@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);
@@ -1040,7 +988,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
any(), any(), anyInt(), anyInt(), any());
verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
eq(mErrorToken), eq(mTaskFragment),
eq(HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT),
eq(OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT),
any(IllegalArgumentException.class));
}
@@ -1057,7 +1005,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
eq(mErrorToken), eq(mTaskFragment),
eq(HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT),
eq(OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT),
any(IllegalArgumentException.class));
assertNull(activity.getOrganizedTaskFragment());
}
@@ -1074,8 +1022,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
assertApplyTransactionAllowed(mTransaction);
verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
eq(mErrorToken), eq(mTaskFragment),
eq(HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS),
eq(mErrorToken), eq(mTaskFragment), eq(OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS),
any(IllegalArgumentException.class));
verify(mTaskFragment, never()).setAdjacentTaskFragment(any());
}
@@ -1094,7 +1041,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
assertApplyTransactionAllowed(mTransaction);
verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
eq(mErrorToken), eq(null), eq(HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT),
eq(mErrorToken), eq(null), eq(OP_TYPE_CREATE_TASK_FRAGMENT),
any(IllegalArgumentException.class));
assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
}
@@ -1105,12 +1052,12 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
spyOn(mWindowOrganizerController);
// Not allow to delete a TaskFragment that is in a PIP Task.
mTransaction.deleteTaskFragment(mFragmentWindowToken)
mTransaction.deleteTaskFragment(mFragmentToken)
.setErrorCallbackToken(mErrorToken);
assertApplyTransactionAllowed(mTransaction);
verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
eq(mErrorToken), eq(mTaskFragment), eq(HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT),
eq(mErrorToken), eq(mTaskFragment), eq(OP_TYPE_DELETE_TASK_FRAGMENT),
any(IllegalArgumentException.class));
assertNotNull(mWindowOrganizerController.getTaskFragment(mFragmentToken));
@@ -1423,43 +1370,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
// The pending event will be dispatched on the handler (from requestTraversal).
waitHandlerIdle(mWm.mAnimationHandler);
assertTaskFragmentErrorTransaction(HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT,
SecurityException.class);
}
@Test
public void testMinDimensionViolation_ReparentChildren() {
final Task task = createTask(mDisplayContent);
final IBinder oldFragToken = new Binder();
final TaskFragment oldTaskFrag = new TaskFragmentBuilder(mAtm)
.setParentTask(task)
.createActivityCount(1)
.setFragmentToken(oldFragToken)
.setOrganizer(mOrganizer)
.build();
final ActivityRecord activity = oldTaskFrag.getTopMostActivity();
// Make minWidth/minHeight exceeds mTaskFragment bounds.
activity.info.windowLayout = new ActivityInfo.WindowLayout(
0, 0, 0, 0, 0, mTaskFragBounds.width() + 10, mTaskFragBounds.height() + 10);
mTaskFragment = new TaskFragmentBuilder(mAtm)
.setParentTask(task)
.setFragmentToken(mFragmentToken)
.setOrganizer(mOrganizer)
.setBounds(mTaskFragBounds)
.build();
mWindowOrganizerController.mLaunchTaskFragments.put(oldFragToken, oldTaskFrag);
mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
// Reparent oldTaskFrag's children to mTaskFragment, which is smaller than activity's
// minimum dimensions.
mTransaction.reparentChildren(oldTaskFrag.mRemoteToken.toWindowContainerToken(),
mTaskFragment.mRemoteToken.toWindowContainerToken())
.setErrorCallbackToken(mErrorToken);
assertApplyTransactionAllowed(mTransaction);
// The pending event will be dispatched on the handler (from requestTraversal).
waitHandlerIdle(mWm.mAnimationHandler);
assertTaskFragmentErrorTransaction(HIERARCHY_OP_TYPE_REPARENT_CHILDREN,
assertTaskFragmentErrorTransaction(OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT,
SecurityException.class);
}
@@ -1634,7 +1545,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
}
/** Asserts that there will be a transaction for TaskFragment error. */
private void assertTaskFragmentErrorTransaction(int opType, @NonNull Class<?> exceptionClass) {
private void assertTaskFragmentErrorTransaction(@TaskFragmentOperation.OperationType int opType,
@NonNull Class<?> exceptionClass) {
verify(mOrganizer).onTransactionReady(mTransactionCaptor.capture());
final TaskFragmentTransaction transaction = mTransactionCaptor.getValue();
final List<TaskFragmentTransaction.Change> changes = transaction.getChanges();