Merge "Cleanup TaskFragment WindowContainerTransaction Change"
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 7f1a4d1..474e148 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -3829,6 +3829,7 @@
method @NonNull public android.window.WindowContainerTransaction setHidden(@NonNull android.window.WindowContainerToken, boolean);
method @NonNull public android.window.WindowContainerTransaction setLaunchAdjacentFlagRoot(@NonNull android.window.WindowContainerToken);
method @NonNull public android.window.WindowContainerTransaction setLaunchRoot(@NonNull android.window.WindowContainerToken, @Nullable int[], @Nullable int[]);
+ method @NonNull public android.window.WindowContainerTransaction setRelativeBounds(@NonNull android.window.WindowContainerToken, @NonNull android.graphics.Rect);
method @NonNull public android.window.WindowContainerTransaction setScreenSizeDp(@NonNull android.window.WindowContainerToken, int, int);
method @NonNull public android.window.WindowContainerTransaction setSmallestScreenWidthDp(@NonNull android.window.WindowContainerToken, int);
method @NonNull public android.window.WindowContainerTransaction setWindowingMode(@NonNull android.window.WindowContainerToken, int);
diff --git a/core/java/android/window/TaskFragmentInfo.java b/core/java/android/window/TaskFragmentInfo.java
index dc60edd..a881a05 100644
--- a/core/java/android/window/TaskFragmentInfo.java
+++ b/core/java/android/window/TaskFragmentInfo.java
@@ -23,7 +23,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
-import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
@@ -89,9 +88,9 @@
private final boolean mIsClearedForReorderActivityToFront;
/**
- * The maximum {@link ActivityInfo.WindowLayout#minWidth} and
- * {@link ActivityInfo.WindowLayout#minHeight} aggregated from the TaskFragment's child
- * activities.
+ * The maximum {@link android.content.pm.ActivityInfo.WindowLayout#minWidth} and
+ * {@link android.content.pm.ActivityInfo.WindowLayout#minHeight} aggregated from the
+ * TaskFragment's child activities.
*/
@NonNull
private final Point mMinimumDimensions = new Point();
@@ -179,7 +178,7 @@
/**
* Returns the minimum width this TaskFragment can be resized to.
- * Client side must not {@link WindowContainerTransaction#setBounds(WindowContainerToken, Rect)}
+ * Client side must not {@link WindowContainerTransaction#setRelativeBounds}
* that {@link Rect#width()} is shorter than the reported value.
* @hide pending unhide
*/
@@ -189,7 +188,7 @@
/**
* Returns the minimum width this TaskFragment can be resized to.
- * Client side must not {@link WindowContainerTransaction#setBounds(WindowContainerToken, Rect)}
+ * Client side must not {@link WindowContainerTransaction#setRelativeBounds}
* that {@link Rect#height()} is shorter than the reported value.
* @hide pending unhide
*/
diff --git a/core/java/android/window/TaskFragmentOperation.java b/core/java/android/window/TaskFragmentOperation.java
index 0d6a58b..413f0cc 100644
--- a/core/java/android/window/TaskFragmentOperation.java
+++ b/core/java/android/window/TaskFragmentOperation.java
@@ -38,8 +38,8 @@
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}.
+ * Type for tracking other unknown TaskFragment operation that is not set through
+ * {@link TaskFragmentOperation}, such as invalid request.
*/
public static final int OP_TYPE_UNKNOWN = -1;
@@ -70,6 +70,9 @@
/** Sets the {@link TaskFragmentAnimationParams} for the given TaskFragment. */
public static final int OP_TYPE_SET_ANIMATION_PARAMS = 8;
+ /** Sets the relative bounds with {@link WindowContainerTransaction#setRelativeBounds}. */
+ public static final int OP_TYPE_SET_RELATIVE_BOUNDS = 9;
+
@IntDef(prefix = { "OP_TYPE_" }, value = {
OP_TYPE_UNKNOWN,
OP_TYPE_CREATE_TASK_FRAGMENT,
@@ -80,7 +83,8 @@
OP_TYPE_CLEAR_ADJACENT_TASK_FRAGMENTS,
OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT,
OP_TYPE_SET_COMPANION_TASK_FRAGMENT,
- OP_TYPE_SET_ANIMATION_PARAMS
+ OP_TYPE_SET_ANIMATION_PARAMS,
+ OP_TYPE_SET_RELATIVE_BOUNDS
})
@Retention(RetentionPolicy.SOURCE)
public @interface OperationType {}
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index a2fa162..a3209f6 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -308,7 +308,6 @@
/**
* Resizes a container by providing a bounds in its parent coordinate.
* This is only used by {@link TaskFragmentOrganizer}.
- * @hide
*/
@NonNull
public WindowContainerTransaction setRelativeBounds(
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 957d99a..f9592cc 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -29,6 +29,7 @@
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_SET_RELATIVE_BOUNDS;
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.Change.CHANGE_RELATIVE_BOUNDS;
@@ -94,6 +95,7 @@
import android.window.TaskFragmentAnimationParams;
import android.window.TaskFragmentCreationParams;
import android.window.TaskFragmentOperation;
+import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import com.android.internal.annotations.VisibleForTesting;
@@ -784,8 +786,8 @@
taskFragment.deferOrganizedTaskFragmentSurfaceUpdate();
final Rect relBounds = c.getRelativeBounds();
if (relBounds != null) {
- // Make sure the TaskFragment bounds satisfied the min dimensions requirement.
- adjustTaskFragmentBoundsForMinDimensionsIfNeeded(taskFragment, relBounds,
+ // Make sure the requested bounds satisfied the min dimensions requirement.
+ adjustTaskFragmentRelativeBoundsForMinDimensionsIfNeeded(taskFragment, relBounds,
errorCallbackToken);
// For embedded TaskFragment, the organizer set the bounds in parent coordinate to
@@ -797,13 +799,6 @@
parentBounds);
c.getConfiguration().windowConfiguration.setBounds(absBounds);
taskFragment.setRelativeEmbeddedBounds(relBounds);
- } else if ((c.getWindowSetMask() & WINDOW_CONFIG_BOUNDS) != 0) {
- // TODO(b/265271880): remove after we drop support to setBounds for TaskFragment in next
- // release.
- adjustTaskFragmentBoundsForMinDimensionsIfNeeded(taskFragment, c.getConfiguration()
- .windowConfiguration.getBounds(), errorCallbackToken);
- // Reset the relative embedded bounds if WCT#setBounds is used instead for CTS compat.
- taskFragment.setRelativeEmbeddedBounds(new Rect());
}
final int effects = applyChanges(taskFragment, c);
if (taskFragment.shouldStartChangeTransition(mTmpBounds0, mTmpBounds1)) {
@@ -814,25 +809,27 @@
}
/**
- * Adjusts the override absolute bounds on {@link TaskFragment} to make sure it satisfies the
+ * Adjusts the requested relative bounds on {@link TaskFragment} to make sure it satisfies the
* activity min dimensions.
*/
- private void adjustTaskFragmentBoundsForMinDimensionsIfNeeded(
- @NonNull TaskFragment taskFragment, @NonNull Rect inOutBounds,
+ private void adjustTaskFragmentRelativeBoundsForMinDimensionsIfNeeded(
+ @NonNull TaskFragment taskFragment, @NonNull Rect inOutRelativeBounds,
@Nullable IBinder errorCallbackToken) {
- if (inOutBounds.isEmpty()) {
+ if (inOutRelativeBounds.isEmpty()) {
return;
}
final Point minDimensions = taskFragment.calculateMinDimension();
- if (inOutBounds.width() < minDimensions.x || inOutBounds.height() < minDimensions.y) {
- // Reset to match parent bounds.
- inOutBounds.setEmpty();
+ if (inOutRelativeBounds.width() < minDimensions.x
+ || inOutRelativeBounds.height() < minDimensions.y) {
// Notify organizer about the request failure.
- final Throwable exception = new SecurityException("The task fragment's bounds:"
- + taskFragment.getBounds() + " does not satisfy minimum dimensions:"
+ final Throwable exception = new SecurityException("The requested relative bounds:"
+ + inOutRelativeBounds + " does not satisfy minimum dimensions:"
+ minDimensions);
sendTaskFragmentOperationFailure(taskFragment.getTaskFragmentOrganizer(),
- errorCallbackToken, taskFragment, OP_TYPE_UNKNOWN, exception);
+ errorCallbackToken, taskFragment, OP_TYPE_SET_RELATIVE_BOUNDS, exception);
+
+ // Reset to match parent bounds.
+ inOutRelativeBounds.setEmpty();
}
}
@@ -1726,9 +1723,7 @@
t.getChanges().entrySet().iterator();
while (entries.hasNext()) {
final Map.Entry<IBinder, WindowContainerTransaction.Change> entry = entries.next();
- // Only allow to apply changes to TaskFragment that is created by this organizer.
final WindowContainer wc = WindowContainer.fromBinder(entry.getKey());
- enforceTaskFragmentOrganized(func, wc, organizer);
enforceTaskFragmentConfigChangeAllowed(func, wc, entry.getValue(), organizer);
}
@@ -1764,27 +1759,6 @@
}
/**
- * Makes sure that the given {@link WindowContainer} is a {@link TaskFragment} organized by the
- * given {@link ITaskFragmentOrganizer}.
- */
- private void enforceTaskFragmentOrganized(@NonNull String func, @Nullable WindowContainer wc,
- @NonNull ITaskFragmentOrganizer organizer) {
- if (wc == null) {
- Slog.e(TAG, "Attempt to operate on window that no longer exists");
- return;
- }
-
- final TaskFragment tf = wc.asTaskFragment();
- if (tf == null || !tf.hasTaskFragmentOrganizer(organizer)) {
- String msg = "Permission Denial: " + func + " from pid=" + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid() + " trying to modify window container not"
- + " belonging to the TaskFragmentOrganizer=" + organizer;
- Slog.w(TAG, msg);
- throw new SecurityException(msg);
- }
- }
-
- /**
* Makes sure that the {@link TaskFragment} of the given fragment token is created and organized
* by the given {@link ITaskFragmentOrganizer}.
*/
@@ -1805,81 +1779,49 @@
}
/**
- * Makes sure that SurfaceControl transactions and the ability to set bounds outside of the
- * parent bounds are not allowed for embedding without full trust between the host and the
- * target.
+ * For config change on {@link TaskFragment}, we only support the following operations:
+ * {@link WindowContainerTransaction#setRelativeBounds(WindowContainerToken, Rect)},
+ * {@link WindowContainerTransaction#setWindowingMode(WindowContainerToken, int)}.
*/
- private void enforceTaskFragmentConfigChangeAllowed(String func, @Nullable WindowContainer wc,
- WindowContainerTransaction.Change change, ITaskFragmentOrganizer organizer) {
+ private void enforceTaskFragmentConfigChangeAllowed(@NonNull String func,
+ @Nullable WindowContainer wc, @NonNull WindowContainerTransaction.Change change,
+ @NonNull ITaskFragmentOrganizer organizer) {
if (wc == null) {
Slog.e(TAG, "Attempt to operate on task fragment that no longer exists");
return;
}
- if (change == null) {
+ final TaskFragment tf = wc.asTaskFragment();
+ if (tf == null || !tf.hasTaskFragmentOrganizer(organizer)) {
+ // Only allow to apply changes to TaskFragment that is organized by this organizer.
+ String msg = "Permission Denial: " + func + " from pid=" + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid() + " trying to modify window container"
+ + " not belonging to the TaskFragmentOrganizer=" + organizer;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+
+ final int changeMask = change.getChangeMask();
+ final int configSetMask = change.getConfigSetMask();
+ final int windowSetMask = change.getWindowSetMask();
+ if (changeMask == 0 && configSetMask == 0 && windowSetMask == 0
+ && change.getWindowingMode() >= 0) {
+ // The change contains only setWindowingMode, which is allowed.
return;
}
- final int changeMask = change.getChangeMask();
- if (changeMask != 0 && changeMask != CHANGE_RELATIVE_BOUNDS) {
+ if (changeMask != CHANGE_RELATIVE_BOUNDS
+ || configSetMask != ActivityInfo.CONFIG_WINDOW_CONFIGURATION
+ || windowSetMask != WindowConfiguration.WINDOW_CONFIG_BOUNDS) {
// None of the change should be requested from a TaskFragment organizer except
- // setRelativeBounds.
+ // setRelativeBounds and setWindowingMode.
// For setRelativeBounds, we don't need to check whether it is outside of the Task
// bounds, because it is possible that the Task is also resizing, for which we don't
// want to throw an exception. The bounds will be adjusted in
// TaskFragment#translateRelativeBoundsToAbsoluteBounds.
String msg = "Permission Denial: " + func + " from pid="
+ Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
- + " trying to apply changes of " + changeMask + " to TaskFragment"
- + " TaskFragmentOrganizer=" + organizer;
- Slog.w(TAG, msg);
- throw new SecurityException(msg);
- }
- // Check if TaskFragment is embedded in fully trusted mode.
- if (wc.asTaskFragment().isAllowedToBeEmbeddedInTrustedMode()) {
- // Fully trusted, no need to check further
- return;
- }
- final WindowContainer wcParent = wc.getParent();
- if (wcParent == null) {
- Slog.e(TAG, "Attempt to apply config change on task fragment that has no parent");
- return;
- }
- // TODO(b/265271880): we can remove those and only support WCT#setRelativeBounds.
- final Configuration requestedConfig = change.getConfiguration();
- final Configuration parentConfig = wcParent.getConfiguration();
- if (parentConfig.screenWidthDp < requestedConfig.screenWidthDp
- || parentConfig.screenHeightDp < requestedConfig.screenHeightDp
- || parentConfig.smallestScreenWidthDp < requestedConfig.smallestScreenWidthDp) {
- String msg = "Permission Denial: " + func + " from pid="
- + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
- + " trying to apply screen width/height greater than parent's for non-trusted"
- + " host, TaskFragmentOrganizer=" + organizer;
- Slog.w(TAG, msg);
- throw new SecurityException(msg);
- }
- if (change.getWindowSetMask() == 0) {
- // No bounds change.
- return;
- }
- final WindowConfiguration requestedWindowConfig = requestedConfig.windowConfiguration;
- final WindowConfiguration parentWindowConfig = parentConfig.windowConfiguration;
- if (!requestedWindowConfig.getBounds().isEmpty()
- && !parentWindowConfig.getBounds().contains(requestedWindowConfig.getBounds())) {
- String msg = "Permission Denial: " + func + " from pid="
- + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
- + " trying to apply bounds outside of parent for non-trusted host,"
- + " TaskFragmentOrganizer=" + organizer;
- Slog.w(TAG, msg);
- throw new SecurityException(msg);
- }
- if (requestedWindowConfig.getAppBounds() != null
- && !requestedWindowConfig.getAppBounds().isEmpty()
- && parentWindowConfig.getAppBounds() != null
- && !parentWindowConfig.getAppBounds().contains(
- requestedWindowConfig.getAppBounds())) {
- String msg = "Permission Denial: " + func + " from pid="
- + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
- + " trying to apply app bounds outside of parent for non-trusted host,"
- + " TaskFragmentOrganizer=" + organizer;
+ + " trying to apply changes of changeMask=" + changeMask
+ + " configSetMask=" + configSetMask + " windowSetMask=" + windowSetMask
+ + " to TaskFragment=" + tf + " TaskFragmentOrganizer=" + organizer;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index 060f9d8..378e8be 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -511,7 +511,7 @@
public void testApplyTransaction_enforceConfigurationChangeOnOrganizedTaskFragment() {
// Throw exception if the transaction is trying to change a window that is not organized by
// the organizer.
- mTransaction.setBounds(mFragmentWindowToken, new Rect(0, 0, 100, 100));
+ mTransaction.setRelativeBounds(mFragmentWindowToken, new Rect(0, 0, 100, 100));
assertApplyTransactionDisallowed(mTransaction);
@@ -1154,10 +1154,12 @@
setupTaskFragmentInPip();
spyOn(mWindowOrganizerController);
- // Set bounds is ignored on a TaskFragment that is in a PIP Task.
- mTransaction.setBounds(mFragmentWindowToken, new Rect(0, 0, 100, 100));
+ // Set relative bounds is ignored on a TaskFragment that is in a PIP Task.
+ mTransaction.setRelativeBounds(mFragmentWindowToken, new Rect(0, 0, 100, 100));
- verify(mTaskFragment, never()).setBounds(any());
+ assertApplyTransactionAllowed(mTransaction);
+
+ verify(mTaskFragment, never()).setRelativeEmbeddedBounds(any());
}
@Test
@@ -1368,7 +1370,7 @@
}
/**
- * For config change to untrusted embedded TaskFragment, we only allow bounds change within
+ * For config change to untrusted embedded TaskFragment, the bounds should be always within
* its parent bounds.
*/
@Test
@@ -1378,51 +1380,17 @@
doReturn(false).when(mTaskFragment).isAllowedToBeEmbeddedInTrustedMode();
final Task task = createTask(mDisplayContent);
final Rect taskBounds = new Rect(task.getBounds());
- final Rect taskAppBounds = new Rect(task.getWindowConfiguration().getAppBounds());
- final int taskScreenWidthDp = task.getConfiguration().screenWidthDp;
- final int taskScreenHeightDp = task.getConfiguration().screenHeightDp;
- final int taskSmallestScreenWidthDp = task.getConfiguration().smallestScreenWidthDp;
task.addChild(mTaskFragment, POSITION_TOP);
- // Throw exception if the transaction is trying to change bounds of an untrusted outside of
- // its parent's.
-
- // setBounds
+ // When set a relative bounds outside of its parent's, it is allowed, but the actual
+ // TaskFragment bounds will be updated to be fit the parent's bounds.
final Rect tfBounds = new Rect(taskBounds);
tfBounds.right++;
- mTransaction.setBounds(mFragmentWindowToken, tfBounds);
- assertApplyTransactionDisallowed(mTransaction);
-
- mTransaction.setBounds(mFragmentWindowToken, taskBounds);
+ mTransaction.setRelativeBounds(mFragmentWindowToken, tfBounds);
assertApplyTransactionAllowed(mTransaction);
- // setAppBounds
- final Rect tfAppBounds = new Rect(taskAppBounds);
- tfAppBounds.right++;
- mTransaction.setAppBounds(mFragmentWindowToken, tfAppBounds);
- assertApplyTransactionDisallowed(mTransaction);
-
- mTransaction.setAppBounds(mFragmentWindowToken, taskAppBounds);
- assertApplyTransactionAllowed(mTransaction);
-
- // setScreenSizeDp
- mTransaction.setScreenSizeDp(mFragmentWindowToken, taskScreenWidthDp + 1,
- taskScreenHeightDp + 1);
- assertApplyTransactionDisallowed(mTransaction);
-
- mTransaction.setScreenSizeDp(mFragmentWindowToken, taskScreenWidthDp, taskScreenHeightDp);
- assertApplyTransactionAllowed(mTransaction);
-
- // setSmallestScreenWidthDp
- mTransaction.setSmallestScreenWidthDp(mFragmentWindowToken, taskSmallestScreenWidthDp + 1);
- assertApplyTransactionDisallowed(mTransaction);
-
- mTransaction.setSmallestScreenWidthDp(mFragmentWindowToken, taskSmallestScreenWidthDp);
- assertApplyTransactionAllowed(mTransaction);
-
- // Any of the change mask is not allowed.
- mTransaction.setFocusable(mFragmentWindowToken, false);
- assertApplyTransactionDisallowed(mTransaction);
+ assertEquals(tfBounds, mTaskFragment.getRelativeEmbeddedBounds());
+ assertEquals(taskBounds, mTaskFragment.getBounds());
}
// TODO(b/232871351): add test for minimum dimension violation in startActivityInTaskFragment
@@ -1454,7 +1422,7 @@
}
@Test
- public void testMinDimensionViolation_SetBounds() {
+ public void testMinDimensionViolation_setRelativeBounds() {
final Task task = createTask(mDisplayContent);
mTaskFragment = new TaskFragmentBuilder(mAtm)
.setParentTask(task)
@@ -1472,12 +1440,14 @@
// Shrink the TaskFragment to mTaskFragBounds to make its bounds smaller than activity's
// minimum dimensions.
- mTransaction.setBounds(mTaskFragment.mRemoteToken.toWindowContainerToken(), mTaskFragBounds)
+ mTransaction.setRelativeBounds(mTaskFragment.mRemoteToken.toWindowContainerToken(),
+ mTaskFragBounds)
.setErrorCallbackToken(mErrorToken);
assertApplyTransactionAllowed(mTransaction);
- assertWithMessage("setBounds must not be performed.")
- .that(mTaskFragment.getBounds()).isEqualTo(task.getBounds());
+ // When the requested bounds do not satisfy the min dimension, it will be reset to empty.
+ assertWithMessage("setRelativeBounds must not be performed.")
+ .that(mTaskFragment.getRelativeEmbeddedBounds()).isEqualTo(new Rect());
}
@Test