blob: 56b49515f419bd155a283c2a496be2f606b77071 [file] [log] [blame]
Evan Roskyddedfd42019-10-04 13:38:38 -07001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view;
18
Evan Roskya8fde152020-01-07 19:09:13 -080019import android.annotation.NonNull;
20import android.annotation.Nullable;
Evan Roskyddedfd42019-10-04 13:38:38 -070021import android.app.WindowConfiguration;
22import android.content.pm.ActivityInfo;
23import android.content.res.Configuration;
24import android.graphics.Rect;
25import android.os.IBinder;
26import android.os.Parcel;
27import android.os.Parcelable;
28import android.util.ArrayMap;
Robert Carr711e7052020-02-19 11:14:33 -080029import android.view.SurfaceControl;
Evan Roskyddedfd42019-10-04 13:38:38 -070030
Evan Roskya8fde152020-01-07 19:09:13 -080031import java.util.ArrayList;
32import java.util.List;
Evan Roskyddedfd42019-10-04 13:38:38 -070033import java.util.Map;
34
35/**
36 * Represents a collection of operations on some WindowContainers that should be applied all at
37 * once.
38 *
39 * @hide
40 */
41public class WindowContainerTransaction implements Parcelable {
42 private final ArrayMap<IBinder, Change> mChanges = new ArrayMap<>();
43
Evan Roskya8fde152020-01-07 19:09:13 -080044 // Flat list because re-order operations are order-dependent
45 private final ArrayList<HierarchyOp> mHierarchyOps = new ArrayList<>();
46
Evan Roskyddedfd42019-10-04 13:38:38 -070047 public WindowContainerTransaction() {}
48
49 protected WindowContainerTransaction(Parcel in) {
50 in.readMap(mChanges, null /* loader */);
Evan Roskya8fde152020-01-07 19:09:13 -080051 in.readList(mHierarchyOps, null /* loader */);
Evan Roskyddedfd42019-10-04 13:38:38 -070052 }
53
54 private Change getOrCreateChange(IBinder token) {
55 Change out = mChanges.get(token);
56 if (out == null) {
57 out = new Change();
58 mChanges.put(token, out);
59 }
60 return out;
61 }
62
63 /**
64 * Resize a container.
65 */
66 public WindowContainerTransaction setBounds(IWindowContainer container, Rect bounds) {
67 Change chg = getOrCreateChange(container.asBinder());
68 chg.mConfiguration.windowConfiguration.setBounds(bounds);
69 chg.mConfigSetMask |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
70 chg.mWindowSetMask |= WindowConfiguration.WINDOW_CONFIG_BOUNDS;
71 return this;
72 }
73
Robert Carr8a2f9132019-11-11 15:03:15 -080074 /**
Evan Rosky05ec8862020-02-28 19:37:04 -080075 * Resize a container's app bounds. This is the bounds used to report appWidth/Height to an
76 * app's DisplayInfo. It is derived by subtracting the overlapping portion of the navbar from
77 * the full bounds.
78 */
79 public WindowContainerTransaction setAppBounds(IWindowContainer container, Rect appBounds) {
80 Change chg = getOrCreateChange(container.asBinder());
81 chg.mConfiguration.windowConfiguration.setAppBounds(appBounds);
82 chg.mConfigSetMask |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
83 chg.mWindowSetMask |= WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS;
84 return this;
85 }
86
87 /**
88 * Resize a container's configuration size. The configuration size is what gets reported to the
89 * app via screenWidth/HeightDp and influences which resources get loaded. This size is
90 * derived by subtracting the overlapping portions of both the statusbar and the navbar from
91 * the full bounds.
92 */
93 public WindowContainerTransaction setScreenSizeDp(IWindowContainer container, int w, int h) {
94 Change chg = getOrCreateChange(container.asBinder());
95 chg.mConfiguration.screenWidthDp = w;
96 chg.mConfiguration.screenHeightDp = h;
97 chg.mConfigSetMask |= ActivityInfo.CONFIG_SCREEN_SIZE;
98 return this;
99 }
100
101 /**
Robert Carr8a2f9132019-11-11 15:03:15 -0800102 * Notify activies within the hiearchy of a container that they have entered picture-in-picture
103 * mode with the given bounds.
104 */
105 public WindowContainerTransaction scheduleFinishEnterPip(IWindowContainer container,
106 Rect bounds) {
107 Change chg = getOrCreateChange(container.asBinder());
Robert Carr8a2f9132019-11-11 15:03:15 -0800108 chg.mPinnedBounds = new Rect(bounds);
Robert Carr711e7052020-02-19 11:14:33 -0800109 chg.mChangeMask |= Change.CHANGE_PIP_CALLBACK;
110
111 return this;
112 }
113
114 /**
115 * Send a SurfaceControl transaction to the server, which the server will apply in sync with
116 * the next bounds change. As this uses deferred transaction and not BLAST it is only
117 * able to sync with a single window, and the first visible window in this hierarchy of type
118 * BASE_APPLICATION to resize will be used. If there are bound changes included in this
119 * WindowContainer transaction (from setBounds or scheduleFinishEnterPip), the SurfaceControl
120 * transaction will be synced with those bounds. If there are no changes, then
121 * the SurfaceControl transaction will be synced with the next bounds change. This means
122 * that you can call this, apply the WindowContainer transaction, and then later call
123 * dismissPip() to achieve synchronization.
124 */
125 public WindowContainerTransaction setBoundsChangeTransaction(IWindowContainer container,
126 SurfaceControl.Transaction t) {
127 Change chg = getOrCreateChange(container.asBinder());
128 chg.mBoundsChangeTransaction = t;
129 chg.mChangeMask |= Change.CHANGE_BOUNDS_TRANSACTION;
Robert Carr8a2f9132019-11-11 15:03:15 -0800130 return this;
131 }
132
Evan Rosky226de132020-01-03 18:00:29 -0800133 /**
Robert Carr2bed6212020-02-20 16:55:07 -0800134 * Set the windowing mode of children of a given root task, without changing
135 * the windowing mode of the Task itself. This can be used during transitions
136 * for example to make the activity render it's fullscreen configuration
137 * while the Task is still in PIP, so you can complete the animation.
138 *
139 * TODO(b/134365562): Can be removed once TaskOrg drives full-screen
140 */
141 public WindowContainerTransaction setActivityWindowingMode(IWindowContainer container,
142 int windowingMode) {
143 Change chg = getOrCreateChange(container.asBinder());
144 chg.mActivityWindowingMode = windowingMode;
145 return this;
146 }
147
148 /**
149 * Sets the windowing mode of the given container.
150 */
151 public WindowContainerTransaction setWindowingMode(IWindowContainer container,
152 int windowingMode) {
153 Change chg = getOrCreateChange(container.asBinder());
154 chg.mWindowingMode = windowingMode;
155 return this;
156 }
157
158 /**
Evan Rosky226de132020-01-03 18:00:29 -0800159 * Sets whether a container or any of its children can be focusable. When {@code false}, no
160 * child can be focused; however, when {@code true}, it is still possible for children to be
161 * non-focusable due to WM policy.
162 */
163 public WindowContainerTransaction setFocusable(IWindowContainer container, boolean focusable) {
164 Change chg = getOrCreateChange(container.asBinder());
165 chg.mFocusable = focusable;
166 chg.mChangeMask |= Change.CHANGE_FOCUSABLE;
167 return this;
168 }
169
Evan Rosky0037e5f2019-11-05 10:26:24 -0800170 /**
Robert Carrf6878a42019-12-18 02:13:12 -0800171 * Sets whether a container or its children should be hidden. When {@code false}, the existing
172 * visibility of the container applies, but when {@code true} the container will be forced
173 * to be hidden.
174 */
175 public WindowContainerTransaction setHidden(IWindowContainer container, boolean hidden) {
176 Change chg = getOrCreateChange(container.asBinder());
177 chg.mHidden = hidden;
178 chg.mChangeMask |= Change.CHANGE_HIDDEN;
179 return this;
180 }
181
182 /**
Evan Rosky0037e5f2019-11-05 10:26:24 -0800183 * Set the smallestScreenWidth of a container.
184 */
185 public WindowContainerTransaction setSmallestScreenWidthDp(IWindowContainer container,
186 int widthDp) {
187 Change cfg = getOrCreateChange(container.asBinder());
188 cfg.mConfiguration.smallestScreenWidthDp = widthDp;
189 cfg.mConfigSetMask |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
190 return this;
191 }
192
Evan Roskya8fde152020-01-07 19:09:13 -0800193 /**
194 * Reparents a container into another one. The effect of a {@code null} parent can vary. For
195 * example, reparenting a stack to {@code null} will reparent it to its display.
196 *
197 * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to
198 * the bottom.
199 */
200 public WindowContainerTransaction reparent(@NonNull IWindowContainer child,
201 @Nullable IWindowContainer parent, boolean onTop) {
202 mHierarchyOps.add(new HierarchyOp(child.asBinder(),
203 parent == null ? null : parent.asBinder(), onTop));
204 return this;
205 }
206
207 /**
208 * Reorders a container within its parent.
209 *
210 * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to
211 * the bottom.
212 */
213 public WindowContainerTransaction reorder(@NonNull IWindowContainer child, boolean onTop) {
214 mHierarchyOps.add(new HierarchyOp(child.asBinder(), onTop));
215 return this;
216 }
217
Evan Roskyddedfd42019-10-04 13:38:38 -0700218 public Map<IBinder, Change> getChanges() {
219 return mChanges;
220 }
221
Evan Roskya8fde152020-01-07 19:09:13 -0800222 public List<HierarchyOp> getHierarchyOps() {
223 return mHierarchyOps;
224 }
225
Evan Roskyddedfd42019-10-04 13:38:38 -0700226 @Override
227 public String toString() {
Evan Rosky05ec8862020-02-28 19:37:04 -0800228 return "WindowContainerTransaction { changes = " + mChanges + " hops = " + mHierarchyOps
229 + " }";
Evan Roskyddedfd42019-10-04 13:38:38 -0700230 }
231
232 @Override
233 public void writeToParcel(Parcel dest, int flags) {
234 dest.writeMap(mChanges);
Evan Roskya8fde152020-01-07 19:09:13 -0800235 dest.writeList(mHierarchyOps);
Evan Roskyddedfd42019-10-04 13:38:38 -0700236 }
237
238 @Override
239 public int describeContents() {
240 return 0;
241 }
242
243 public static final Creator<WindowContainerTransaction> CREATOR =
244 new Creator<WindowContainerTransaction>() {
245 @Override
246 public WindowContainerTransaction createFromParcel(Parcel in) {
247 return new WindowContainerTransaction(in);
248 }
249
250 @Override
251 public WindowContainerTransaction[] newArray(int size) {
252 return new WindowContainerTransaction[size];
253 }
254 };
255
256 /**
257 * Holds changes on a single WindowContainer including Configuration changes.
258 *
259 * @hide
260 */
261 public static class Change implements Parcelable {
Evan Rosky226de132020-01-03 18:00:29 -0800262 public static final int CHANGE_FOCUSABLE = 1;
Robert Carr711e7052020-02-19 11:14:33 -0800263 public static final int CHANGE_BOUNDS_TRANSACTION = 1 << 1;
264 public static final int CHANGE_PIP_CALLBACK = 1 << 2;
Robert Carrf6878a42019-12-18 02:13:12 -0800265 public static final int CHANGE_HIDDEN = 1 << 3;
Evan Rosky226de132020-01-03 18:00:29 -0800266
Evan Roskyddedfd42019-10-04 13:38:38 -0700267 private final Configuration mConfiguration = new Configuration();
Evan Rosky226de132020-01-03 18:00:29 -0800268 private boolean mFocusable = true;
Robert Carrf6878a42019-12-18 02:13:12 -0800269 private boolean mHidden = false;
Evan Rosky226de132020-01-03 18:00:29 -0800270 private int mChangeMask = 0;
Evan Roskyddedfd42019-10-04 13:38:38 -0700271 private @ActivityInfo.Config int mConfigSetMask = 0;
272 private @WindowConfiguration.WindowConfig int mWindowSetMask = 0;
273
Robert Carr8a2f9132019-11-11 15:03:15 -0800274 private Rect mPinnedBounds = null;
Robert Carr711e7052020-02-19 11:14:33 -0800275 private SurfaceControl.Transaction mBoundsChangeTransaction = null;
Robert Carr8a2f9132019-11-11 15:03:15 -0800276
Robert Carr2bed6212020-02-20 16:55:07 -0800277 private int mActivityWindowingMode = -1;
278 private int mWindowingMode = -1;
279
Evan Roskyddedfd42019-10-04 13:38:38 -0700280 public Change() {}
281
282 protected Change(Parcel in) {
283 mConfiguration.readFromParcel(in);
Evan Rosky226de132020-01-03 18:00:29 -0800284 mFocusable = in.readBoolean();
Robert Carrf6878a42019-12-18 02:13:12 -0800285 mHidden = in.readBoolean();
Evan Rosky226de132020-01-03 18:00:29 -0800286 mChangeMask = in.readInt();
Evan Roskyddedfd42019-10-04 13:38:38 -0700287 mConfigSetMask = in.readInt();
288 mWindowSetMask = in.readInt();
Robert Carr711e7052020-02-19 11:14:33 -0800289 if ((mChangeMask & Change.CHANGE_PIP_CALLBACK) != 0) {
Robert Carr8a2f9132019-11-11 15:03:15 -0800290 mPinnedBounds = new Rect();
291 mPinnedBounds.readFromParcel(in);
292 }
Robert Carr711e7052020-02-19 11:14:33 -0800293 if ((mChangeMask & Change.CHANGE_BOUNDS_TRANSACTION) != 0) {
294 mBoundsChangeTransaction =
295 SurfaceControl.Transaction.CREATOR.createFromParcel(in);
296 }
Robert Carr2bed6212020-02-20 16:55:07 -0800297
298 mWindowingMode = in.readInt();
299 mActivityWindowingMode = in.readInt();
300 }
301
302 public int getWindowingMode() {
303 return mWindowingMode;
304 }
305
306 public int getActivityWindowingMode() {
307 return mActivityWindowingMode;
Evan Roskyddedfd42019-10-04 13:38:38 -0700308 }
309
310 public Configuration getConfiguration() {
311 return mConfiguration;
312 }
313
Robert Carrf6878a42019-12-18 02:13:12 -0800314 /** Gets the requested focusable state */
Evan Rosky226de132020-01-03 18:00:29 -0800315 public boolean getFocusable() {
316 if ((mChangeMask & CHANGE_FOCUSABLE) == 0) {
317 throw new RuntimeException("Focusable not set. check CHANGE_FOCUSABLE first");
318 }
319 return mFocusable;
320 }
321
Robert Carrf6878a42019-12-18 02:13:12 -0800322 /** Gets the requested hidden state */
323 public boolean getHidden() {
324 if ((mChangeMask & CHANGE_HIDDEN) == 0) {
325 throw new RuntimeException("Hidden not set. check CHANGE_HIDDEN first");
326 }
327 return mHidden;
328 }
329
Evan Rosky226de132020-01-03 18:00:29 -0800330 public int getChangeMask() {
331 return mChangeMask;
332 }
333
Evan Roskyddedfd42019-10-04 13:38:38 -0700334 @ActivityInfo.Config
335 public int getConfigSetMask() {
336 return mConfigSetMask;
337 }
338
339 @WindowConfiguration.WindowConfig
340 public int getWindowSetMask() {
341 return mWindowSetMask;
342 }
343
Robert Carr8a2f9132019-11-11 15:03:15 -0800344 /**
345 * Returns the bounds to be used for scheduling the enter pip callback
346 * or null if no callback is to be scheduled.
347 */
348 public Rect getEnterPipBounds() {
349 return mPinnedBounds;
350 }
351
Robert Carr711e7052020-02-19 11:14:33 -0800352 public SurfaceControl.Transaction getBoundsChangeTransaction() {
353 return mBoundsChangeTransaction;
354 }
355
Evan Roskyddedfd42019-10-04 13:38:38 -0700356 @Override
357 public String toString() {
358 final boolean changesBounds =
359 (mConfigSetMask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0
360 && ((mWindowSetMask & WindowConfiguration.WINDOW_CONFIG_BOUNDS)
361 != 0);
Evan Rosky05ec8862020-02-28 19:37:04 -0800362 final boolean changesAppBounds =
363 (mConfigSetMask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0
364 && ((mWindowSetMask & WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS)
365 != 0);
366 final boolean changesSs = (mConfigSetMask & ActivityInfo.CONFIG_SCREEN_SIZE) != 0;
Evan Roskyddedfd42019-10-04 13:38:38 -0700367 final boolean changesSss =
368 (mConfigSetMask & ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE) != 0;
369 StringBuilder sb = new StringBuilder();
370 sb.append('{');
371 if (changesBounds) {
372 sb.append("bounds:" + mConfiguration.windowConfiguration.getBounds() + ",");
373 }
Evan Rosky05ec8862020-02-28 19:37:04 -0800374 if (changesAppBounds) {
375 sb.append("appbounds:" + mConfiguration.windowConfiguration.getAppBounds() + ",");
376 }
Evan Roskyddedfd42019-10-04 13:38:38 -0700377 if (changesSss) {
378 sb.append("ssw:" + mConfiguration.smallestScreenWidthDp + ",");
379 }
Evan Rosky05ec8862020-02-28 19:37:04 -0800380 if (changesSs) {
381 sb.append("sw/h:" + mConfiguration.screenWidthDp + "x"
382 + mConfiguration.screenHeightDp + ",");
383 }
Evan Rosky226de132020-01-03 18:00:29 -0800384 if ((mChangeMask & CHANGE_FOCUSABLE) != 0) {
385 sb.append("focusable:" + mFocusable + ",");
386 }
Evan Roskyddedfd42019-10-04 13:38:38 -0700387 sb.append("}");
388 return sb.toString();
389 }
390
391 @Override
392 public void writeToParcel(Parcel dest, int flags) {
393 mConfiguration.writeToParcel(dest, flags);
Evan Rosky226de132020-01-03 18:00:29 -0800394 dest.writeBoolean(mFocusable);
Robert Carrf6878a42019-12-18 02:13:12 -0800395 dest.writeBoolean(mHidden);
Evan Rosky226de132020-01-03 18:00:29 -0800396 dest.writeInt(mChangeMask);
Evan Roskyddedfd42019-10-04 13:38:38 -0700397 dest.writeInt(mConfigSetMask);
398 dest.writeInt(mWindowSetMask);
Robert Carr8a2f9132019-11-11 15:03:15 -0800399
Robert Carr711e7052020-02-19 11:14:33 -0800400 if (mPinnedBounds != null) {
Robert Carr8a2f9132019-11-11 15:03:15 -0800401 mPinnedBounds.writeToParcel(dest, flags);
402 }
Robert Carr711e7052020-02-19 11:14:33 -0800403 if (mBoundsChangeTransaction != null) {
404 mBoundsChangeTransaction.writeToParcel(dest, flags);
405 }
Robert Carr2bed6212020-02-20 16:55:07 -0800406
407 dest.writeInt(mWindowingMode);
408 dest.writeInt(mActivityWindowingMode);
Evan Roskyddedfd42019-10-04 13:38:38 -0700409 }
410
411 @Override
412 public int describeContents() {
413 return 0;
414 }
415
416 public static final Creator<Change> CREATOR = new Creator<Change>() {
417 @Override
418 public Change createFromParcel(Parcel in) {
419 return new Change(in);
420 }
421
422 @Override
423 public Change[] newArray(int size) {
424 return new Change[size];
425 }
426 };
427 }
Evan Roskya8fde152020-01-07 19:09:13 -0800428
429 /**
430 * Holds information about a reparent/reorder operation in the hierarchy. This is separate from
431 * Changes because they must be executed in the same order that they are added.
432 */
433 public static class HierarchyOp implements Parcelable {
434 private final IBinder mContainer;
435
436 // If this is same as mContainer, then only change position, don't reparent.
437 private final IBinder mReparent;
438
439 // Moves/reparents to top of parent when {@code true}, otherwise moves/reparents to bottom.
440 private final boolean mToTop;
441
442 public HierarchyOp(@NonNull IBinder container, @Nullable IBinder reparent, boolean toTop) {
443 mContainer = container;
444 mReparent = reparent;
445 mToTop = toTop;
446 }
447
448 public HierarchyOp(@NonNull IBinder container, boolean toTop) {
449 mContainer = container;
450 mReparent = container;
451 mToTop = toTop;
452 }
453
454 protected HierarchyOp(Parcel in) {
455 mContainer = in.readStrongBinder();
456 mReparent = in.readStrongBinder();
457 mToTop = in.readBoolean();
458 }
459
460 public boolean isReparent() {
461 return mContainer != mReparent;
462 }
463
464 @Nullable
465 public IBinder getNewParent() {
466 return mReparent;
467 }
468
469 @NonNull
470 public IBinder getContainer() {
471 return mContainer;
472 }
473
474 public boolean getToTop() {
475 return mToTop;
476 }
477
478 @Override
479 public String toString() {
480 if (isReparent()) {
481 return "{reparent: " + mContainer + " to " + (mToTop ? "top of " : "bottom of ")
482 + mReparent + "}";
483 } else {
484 return "{reorder: " + mContainer + " to " + (mToTop ? "top" : "bottom") + "}";
485 }
486 }
487
488 @Override
489 public void writeToParcel(Parcel dest, int flags) {
490 dest.writeStrongBinder(mContainer);
491 dest.writeStrongBinder(mReparent);
492 dest.writeBoolean(mToTop);
493 }
494
495 @Override
496 public int describeContents() {
497 return 0;
498 }
499
500 public static final Creator<HierarchyOp> CREATOR = new Creator<HierarchyOp>() {
501 @Override
502 public HierarchyOp createFromParcel(Parcel in) {
503 return new HierarchyOp(in);
504 }
505
506 @Override
507 public HierarchyOp[] newArray(int size) {
508 return new HierarchyOp[size];
509 }
510 };
511 }
Evan Roskyddedfd42019-10-04 13:38:38 -0700512}