diff options
4 files changed, 107 insertions, 3 deletions
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java index 231e024e835f..9a732455113c 100644 --- a/core/java/android/window/WindowContainerTransaction.java +++ b/core/java/android/window/WindowContainerTransaction.java @@ -141,6 +141,36 @@ public final class WindowContainerTransaction implements Parcelable { } /** + * Like {@link #setBoundsChangeTransaction} but instead queues up a setPosition/WindowCrop + * on a container's surface control. This is useful when a boundsChangeTransaction needs to be + * queued up on a Task that won't be organized until the end of this window-container + * transaction. + * + * This requires that, at the end of this transaction, `task` will be organized; otherwise + * the server will throw an IllegalArgumentException. + * + * WARNING: Use this carefully. Whatever is set here should match the expected bounds after + * the transaction completes since it will likely be replaced by it. This call is + * intended to pre-emptively set bounds on a surface in sync with a buffer when + * otherwise the new bounds and the new buffer would update on different frames. + * + * TODO(b/134365562): remove once TaskOrg drives full-screen or BLAST is enabled. + * + * @hide + */ + @NonNull + public WindowContainerTransaction setBoundsChangeTransaction( + @NonNull WindowContainerToken task, @NonNull Rect surfaceBounds) { + Change chg = getOrCreateChange(task.asBinder()); + if (chg.mBoundsChangeSurfaceBounds == null) { + chg.mBoundsChangeSurfaceBounds = new Rect(); + } + chg.mBoundsChangeSurfaceBounds.set(surfaceBounds); + chg.mChangeMask |= Change.CHANGE_BOUNDS_TRANSACTION_RECT; + return this; + } + + /** * Set the windowing mode of children of a given root task, without changing * the windowing mode of the Task itself. This can be used during transitions * for example to make the activity render it's fullscreen configuration @@ -287,6 +317,7 @@ public final class WindowContainerTransaction implements Parcelable { public static final int CHANGE_BOUNDS_TRANSACTION = 1 << 1; public static final int CHANGE_PIP_CALLBACK = 1 << 2; public static final int CHANGE_HIDDEN = 1 << 3; + public static final int CHANGE_BOUNDS_TRANSACTION_RECT = 1 << 4; private final Configuration mConfiguration = new Configuration(); private boolean mFocusable = true; @@ -297,6 +328,7 @@ public final class WindowContainerTransaction implements Parcelable { private Rect mPinnedBounds = null; private SurfaceControl.Transaction mBoundsChangeTransaction = null; + private Rect mBoundsChangeSurfaceBounds = null; private int mActivityWindowingMode = -1; private int mWindowingMode = -1; @@ -318,6 +350,10 @@ public final class WindowContainerTransaction implements Parcelable { mBoundsChangeTransaction = SurfaceControl.Transaction.CREATOR.createFromParcel(in); } + if ((mChangeMask & Change.CHANGE_BOUNDS_TRANSACTION_RECT) != 0) { + mBoundsChangeSurfaceBounds = new Rect(); + mBoundsChangeSurfaceBounds.readFromParcel(in); + } mWindowingMode = in.readInt(); mActivityWindowingMode = in.readInt(); @@ -377,6 +413,10 @@ public final class WindowContainerTransaction implements Parcelable { return mBoundsChangeTransaction; } + public Rect getBoundsChangeSurfaceBounds() { + return mBoundsChangeSurfaceBounds; + } + @Override public String toString() { final boolean changesBounds = @@ -408,6 +448,9 @@ public final class WindowContainerTransaction implements Parcelable { if ((mChangeMask & CHANGE_FOCUSABLE) != 0) { sb.append("focusable:" + mFocusable + ","); } + if (mBoundsChangeTransaction != null) { + sb.append("hasBoundsTransaction,"); + } sb.append("}"); return sb.toString(); } @@ -427,6 +470,9 @@ public final class WindowContainerTransaction implements Parcelable { if (mBoundsChangeTransaction != null) { mBoundsChangeTransaction.writeToParcel(dest, flags); } + if (mBoundsChangeSurfaceBounds != null) { + mBoundsChangeSurfaceBounds.writeToParcel(dest, flags); + } dest.writeInt(mWindowingMode); dest.writeInt(mActivityWindowingMode); diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index cc72dcfb0be2..61d08e16407b 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -436,7 +436,12 @@ class Task extends WindowContainer<WindowContainer> { static final int FLAG_FORCE_HIDDEN_FOR_TASK_ORG = 1 << 1; private int mForceHiddenFlags = 0; + // When non-null, this is a transaction that will get applied on the next frame returned after + // a relayout is requested from the client. While this is only valid on a leaf task; since the + // transaction can effect an ancestor task, this also needs to keep track of the ancestor task + // that this transaction manipulates because deferUntilFrame acts on individual surfaces. SurfaceControl.Transaction mMainWindowSizeChangeTransaction; + Task mMainWindowSizeChangeTask; private final FindRootHelper mFindRootHelper = new FindRootHelper(); private class FindRootHelper { @@ -1745,7 +1750,7 @@ class Task extends WindowContainer<WindowContainer> { } if (isOrganized()) { - mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(this, true /* force */); + mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(this, false /* force */); } } @@ -4513,13 +4518,32 @@ class Task extends WindowContainer<WindowContainer> { * to resize, and it will defer the transaction until that resize frame completes. */ void setMainWindowSizeChangeTransaction(SurfaceControl.Transaction t) { + setMainWindowSizeChangeTransaction(t, this); + } + + private void setMainWindowSizeChangeTransaction(SurfaceControl.Transaction t, Task origin) { + // This is only meaningful on an activity's task, so put it on the top one. + ActivityRecord topActivity = getTopNonFinishingActivity(); + Task leaf = topActivity != null ? topActivity.getTask() : null; + if (leaf == null) { + return; + } + if (leaf != this) { + leaf.setMainWindowSizeChangeTransaction(t, origin); + return; + } mMainWindowSizeChangeTransaction = t; + mMainWindowSizeChangeTask = t == null ? null : origin; } SurfaceControl.Transaction getMainWindowSizeChangeTransaction() { return mMainWindowSizeChangeTransaction; } + Task getMainWindowSizeChangeTask() { + return mMainWindowSizeChangeTask; + } + void setActivityWindowingMode(int windowingMode) { PooledConsumer c = PooledLambda.obtainConsumer(ActivityRecord::setWindowingMode, PooledLambda.__(ActivityRecord.class), windowingMode); diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 707a7898f8b6..a3faa86758cd 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -163,8 +163,42 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub Slog.e(TAG, "Attempt to operate on detached container: " + wc); continue; } + if (syncId >= 0) { + mBLASTSyncEngine.addToSyncSet(syncId, wc); + } effects |= sanitizeAndApplyHierarchyOp(wc, hop); } + // Queue-up bounds-change transactions for tasks which are now organized. Do + // this after hierarchy ops so we have the final organized state. + entries = t.getChanges().entrySet().iterator(); + while (entries.hasNext()) { + final Map.Entry<IBinder, WindowContainerTransaction.Change> entry = + entries.next(); + final Task task = WindowContainer.fromBinder(entry.getKey()).asTask(); + final Rect surfaceBounds = entry.getValue().getBoundsChangeSurfaceBounds(); + if (task == null || !task.isAttached() || surfaceBounds == null) { + continue; + } + if (!task.isOrganized()) { + final Task parent = + task.getParent() != null ? task.getParent().asTask() : null; + // Also allow direct children of created-by-organizer tasks to be + // controlled. In the future, these will become organized anyways. + if (parent == null || !parent.mCreatedByOrganizer) { + throw new IllegalArgumentException( + "Can't manipulate non-organized task surface " + task); + } + } + final SurfaceControl.Transaction sft = new SurfaceControl.Transaction(); + final SurfaceControl sc = task.getSurfaceControl(); + sft.setPosition(sc, surfaceBounds.left, surfaceBounds.top); + if (surfaceBounds.isEmpty()) { + sft.setWindowCrop(sc, null); + } else { + sft.setWindowCrop(sc, surfaceBounds.width(), surfaceBounds.height()); + } + task.setMainWindowSizeChangeTransaction(sft); + } if ((effects & TRANSACT_EFFECTS_LIFECYCLE) != 0) { // Already calls ensureActivityConfig mService.mRootWindowContainer.ensureActivitiesVisible( diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index b30d40824a05..42c21930bdf7 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -904,8 +904,8 @@ class WindowStateAnimator { } if (shouldConsumeMainWindowSizeTransaction()) { - task.getSurfaceControl().deferTransactionUntil(mWin.getClientViewRootSurface(), - mWin.getFrameNumber()); + task.getMainWindowSizeChangeTask().getSurfaceControl().deferTransactionUntil( + mWin.getClientViewRootSurface(), mWin.getFrameNumber()); mSurfaceController.deferTransactionUntil(mWin.getClientViewRootSurface(), mWin.getFrameNumber()); SurfaceControl.mergeToGlobalTransaction(task.getMainWindowSizeChangeTransaction()); |