Refactor TaskFragment related WindowContainerTransaction
Refactor TaskFragment related WCT to a single transaction type. As we will likely to add more TaskFragment transactions in the future, putting them into a standalone type can make them more organized, as well as not confusing other users of WCT, especially because WCT already have a lot of operation types. Refactor deleteTaskFragment to take fragment token instead of WindowContainerToken to be consistent with other TaskFragmentOperation. Remove support of setAdjacentRoots/clearAdjacentRoots for TaskFragmentOrganizer since we have setAdjacentTaskFragments. Remove reparentChildren because it is never used. Bug: 263436063 Test: pass existing tests. Change-Id: If01fde450f03f1f6677e583f4bdf97fcd1192553
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -56,7 +56,7 @@ import static android.view.Display.DEFAULT_DISPLAY;
|
||||
import static android.view.WindowManager.TRANSIT_NONE;
|
||||
import static android.view.WindowManager.TRANSIT_OPEN;
|
||||
import static android.view.WindowManager.TRANSIT_TO_FRONT;
|
||||
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
|
||||
import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
|
||||
|
||||
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
|
||||
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
|
||||
@@ -2830,7 +2830,7 @@ class ActivityStarter {
|
||||
if (taskFragment.isOrganized()) {
|
||||
mService.mWindowOrganizerController.sendTaskFragmentOperationFailure(
|
||||
taskFragment.getTaskFragmentOrganizer(), mRequest.errorCallbackToken,
|
||||
taskFragment, HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT,
|
||||
taskFragment, OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT,
|
||||
new SecurityException(errMsg));
|
||||
} else {
|
||||
// If the taskFragment is not organized, just dump error message as warning logs.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user