blob: cf34b0bad78d992991f68a711419103002bb2402 [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;
29
Evan Roskya8fde152020-01-07 19:09:13 -080030import java.util.ArrayList;
31import java.util.List;
Evan Roskyddedfd42019-10-04 13:38:38 -070032import java.util.Map;
33
34/**
35 * Represents a collection of operations on some WindowContainers that should be applied all at
36 * once.
37 *
38 * @hide
39 */
40public class WindowContainerTransaction implements Parcelable {
41 private final ArrayMap<IBinder, Change> mChanges = new ArrayMap<>();
42
Evan Roskya8fde152020-01-07 19:09:13 -080043 // Flat list because re-order operations are order-dependent
44 private final ArrayList<HierarchyOp> mHierarchyOps = new ArrayList<>();
45
Evan Roskyddedfd42019-10-04 13:38:38 -070046 public WindowContainerTransaction() {}
47
48 protected WindowContainerTransaction(Parcel in) {
49 in.readMap(mChanges, null /* loader */);
Evan Roskya8fde152020-01-07 19:09:13 -080050 in.readList(mHierarchyOps, null /* loader */);
Evan Roskyddedfd42019-10-04 13:38:38 -070051 }
52
53 private Change getOrCreateChange(IBinder token) {
54 Change out = mChanges.get(token);
55 if (out == null) {
56 out = new Change();
57 mChanges.put(token, out);
58 }
59 return out;
60 }
61
62 /**
63 * Resize a container.
64 */
65 public WindowContainerTransaction setBounds(IWindowContainer container, Rect bounds) {
66 Change chg = getOrCreateChange(container.asBinder());
67 chg.mConfiguration.windowConfiguration.setBounds(bounds);
68 chg.mConfigSetMask |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
69 chg.mWindowSetMask |= WindowConfiguration.WINDOW_CONFIG_BOUNDS;
70 return this;
71 }
72
Robert Carr8a2f9132019-11-11 15:03:15 -080073 /**
74 * Notify activies within the hiearchy of a container that they have entered picture-in-picture
75 * mode with the given bounds.
76 */
77 public WindowContainerTransaction scheduleFinishEnterPip(IWindowContainer container,
78 Rect bounds) {
79 Change chg = getOrCreateChange(container.asBinder());
80 chg.mSchedulePipCallback = true;
81 chg.mPinnedBounds = new Rect(bounds);
82 return this;
83 }
84
Evan Rosky226de132020-01-03 18:00:29 -080085 /**
86 * Sets whether a container or any of its children can be focusable. When {@code false}, no
87 * child can be focused; however, when {@code true}, it is still possible for children to be
88 * non-focusable due to WM policy.
89 */
90 public WindowContainerTransaction setFocusable(IWindowContainer container, boolean focusable) {
91 Change chg = getOrCreateChange(container.asBinder());
92 chg.mFocusable = focusable;
93 chg.mChangeMask |= Change.CHANGE_FOCUSABLE;
94 return this;
95 }
96
Evan Rosky0037e5f2019-11-05 10:26:24 -080097 /**
98 * Set the smallestScreenWidth of a container.
99 */
100 public WindowContainerTransaction setSmallestScreenWidthDp(IWindowContainer container,
101 int widthDp) {
102 Change cfg = getOrCreateChange(container.asBinder());
103 cfg.mConfiguration.smallestScreenWidthDp = widthDp;
104 cfg.mConfigSetMask |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
105 return this;
106 }
107
Evan Roskya8fde152020-01-07 19:09:13 -0800108 /**
109 * Reparents a container into another one. The effect of a {@code null} parent can vary. For
110 * example, reparenting a stack to {@code null} will reparent it to its display.
111 *
112 * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to
113 * the bottom.
114 */
115 public WindowContainerTransaction reparent(@NonNull IWindowContainer child,
116 @Nullable IWindowContainer parent, boolean onTop) {
117 mHierarchyOps.add(new HierarchyOp(child.asBinder(),
118 parent == null ? null : parent.asBinder(), onTop));
119 return this;
120 }
121
122 /**
123 * Reorders a container within its parent.
124 *
125 * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to
126 * the bottom.
127 */
128 public WindowContainerTransaction reorder(@NonNull IWindowContainer child, boolean onTop) {
129 mHierarchyOps.add(new HierarchyOp(child.asBinder(), onTop));
130 return this;
131 }
132
Evan Roskyddedfd42019-10-04 13:38:38 -0700133 public Map<IBinder, Change> getChanges() {
134 return mChanges;
135 }
136
Evan Roskya8fde152020-01-07 19:09:13 -0800137 public List<HierarchyOp> getHierarchyOps() {
138 return mHierarchyOps;
139 }
140
Evan Roskyddedfd42019-10-04 13:38:38 -0700141 @Override
142 public String toString() {
143 return "WindowContainerTransaction { changes = " + mChanges + " }";
144 }
145
146 @Override
147 public void writeToParcel(Parcel dest, int flags) {
148 dest.writeMap(mChanges);
Evan Roskya8fde152020-01-07 19:09:13 -0800149 dest.writeList(mHierarchyOps);
Evan Roskyddedfd42019-10-04 13:38:38 -0700150 }
151
152 @Override
153 public int describeContents() {
154 return 0;
155 }
156
157 public static final Creator<WindowContainerTransaction> CREATOR =
158 new Creator<WindowContainerTransaction>() {
159 @Override
160 public WindowContainerTransaction createFromParcel(Parcel in) {
161 return new WindowContainerTransaction(in);
162 }
163
164 @Override
165 public WindowContainerTransaction[] newArray(int size) {
166 return new WindowContainerTransaction[size];
167 }
168 };
169
170 /**
171 * Holds changes on a single WindowContainer including Configuration changes.
172 *
173 * @hide
174 */
175 public static class Change implements Parcelable {
Evan Rosky226de132020-01-03 18:00:29 -0800176 public static final int CHANGE_FOCUSABLE = 1;
177
Evan Roskyddedfd42019-10-04 13:38:38 -0700178 private final Configuration mConfiguration = new Configuration();
Evan Rosky226de132020-01-03 18:00:29 -0800179 private boolean mFocusable = true;
180 private int mChangeMask = 0;
Evan Roskyddedfd42019-10-04 13:38:38 -0700181 private @ActivityInfo.Config int mConfigSetMask = 0;
182 private @WindowConfiguration.WindowConfig int mWindowSetMask = 0;
183
Robert Carr8a2f9132019-11-11 15:03:15 -0800184 private boolean mSchedulePipCallback = false;
185 private Rect mPinnedBounds = null;
186
Evan Roskyddedfd42019-10-04 13:38:38 -0700187 public Change() {}
188
189 protected Change(Parcel in) {
190 mConfiguration.readFromParcel(in);
Evan Rosky226de132020-01-03 18:00:29 -0800191 mFocusable = in.readBoolean();
192 mChangeMask = in.readInt();
Evan Roskyddedfd42019-10-04 13:38:38 -0700193 mConfigSetMask = in.readInt();
194 mWindowSetMask = in.readInt();
Robert Carr8a2f9132019-11-11 15:03:15 -0800195 mSchedulePipCallback = (in.readInt() != 0);
196 if (mSchedulePipCallback ) {
197 mPinnedBounds = new Rect();
198 mPinnedBounds.readFromParcel(in);
199 }
Evan Roskyddedfd42019-10-04 13:38:38 -0700200 }
201
202 public Configuration getConfiguration() {
203 return mConfiguration;
204 }
205
Evan Rosky226de132020-01-03 18:00:29 -0800206 /** Gets the requested focusable value */
207 public boolean getFocusable() {
208 if ((mChangeMask & CHANGE_FOCUSABLE) == 0) {
209 throw new RuntimeException("Focusable not set. check CHANGE_FOCUSABLE first");
210 }
211 return mFocusable;
212 }
213
214 public int getChangeMask() {
215 return mChangeMask;
216 }
217
Evan Roskyddedfd42019-10-04 13:38:38 -0700218 @ActivityInfo.Config
219 public int getConfigSetMask() {
220 return mConfigSetMask;
221 }
222
223 @WindowConfiguration.WindowConfig
224 public int getWindowSetMask() {
225 return mWindowSetMask;
226 }
227
Robert Carr8a2f9132019-11-11 15:03:15 -0800228 /**
229 * Returns the bounds to be used for scheduling the enter pip callback
230 * or null if no callback is to be scheduled.
231 */
232 public Rect getEnterPipBounds() {
233 return mPinnedBounds;
234 }
235
Evan Roskyddedfd42019-10-04 13:38:38 -0700236 @Override
237 public String toString() {
238 final boolean changesBounds =
239 (mConfigSetMask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0
240 && ((mWindowSetMask & WindowConfiguration.WINDOW_CONFIG_BOUNDS)
241 != 0);
242 final boolean changesSss =
243 (mConfigSetMask & ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE) != 0;
244 StringBuilder sb = new StringBuilder();
245 sb.append('{');
246 if (changesBounds) {
247 sb.append("bounds:" + mConfiguration.windowConfiguration.getBounds() + ",");
248 }
249 if (changesSss) {
250 sb.append("ssw:" + mConfiguration.smallestScreenWidthDp + ",");
251 }
Evan Rosky226de132020-01-03 18:00:29 -0800252 if ((mChangeMask & CHANGE_FOCUSABLE) != 0) {
253 sb.append("focusable:" + mFocusable + ",");
254 }
Evan Roskyddedfd42019-10-04 13:38:38 -0700255 sb.append("}");
256 return sb.toString();
257 }
258
259 @Override
260 public void writeToParcel(Parcel dest, int flags) {
261 mConfiguration.writeToParcel(dest, flags);
Evan Rosky226de132020-01-03 18:00:29 -0800262 dest.writeBoolean(mFocusable);
263 dest.writeInt(mChangeMask);
Evan Roskyddedfd42019-10-04 13:38:38 -0700264 dest.writeInt(mConfigSetMask);
265 dest.writeInt(mWindowSetMask);
Robert Carr8a2f9132019-11-11 15:03:15 -0800266
267 dest.writeInt(mSchedulePipCallback ? 1 : 0);
268 if (mSchedulePipCallback ) {
269 mPinnedBounds.writeToParcel(dest, flags);
270 }
Evan Roskyddedfd42019-10-04 13:38:38 -0700271 }
272
273 @Override
274 public int describeContents() {
275 return 0;
276 }
277
278 public static final Creator<Change> CREATOR = new Creator<Change>() {
279 @Override
280 public Change createFromParcel(Parcel in) {
281 return new Change(in);
282 }
283
284 @Override
285 public Change[] newArray(int size) {
286 return new Change[size];
287 }
288 };
289 }
Evan Roskya8fde152020-01-07 19:09:13 -0800290
291 /**
292 * Holds information about a reparent/reorder operation in the hierarchy. This is separate from
293 * Changes because they must be executed in the same order that they are added.
294 */
295 public static class HierarchyOp implements Parcelable {
296 private final IBinder mContainer;
297
298 // If this is same as mContainer, then only change position, don't reparent.
299 private final IBinder mReparent;
300
301 // Moves/reparents to top of parent when {@code true}, otherwise moves/reparents to bottom.
302 private final boolean mToTop;
303
304 public HierarchyOp(@NonNull IBinder container, @Nullable IBinder reparent, boolean toTop) {
305 mContainer = container;
306 mReparent = reparent;
307 mToTop = toTop;
308 }
309
310 public HierarchyOp(@NonNull IBinder container, boolean toTop) {
311 mContainer = container;
312 mReparent = container;
313 mToTop = toTop;
314 }
315
316 protected HierarchyOp(Parcel in) {
317 mContainer = in.readStrongBinder();
318 mReparent = in.readStrongBinder();
319 mToTop = in.readBoolean();
320 }
321
322 public boolean isReparent() {
323 return mContainer != mReparent;
324 }
325
326 @Nullable
327 public IBinder getNewParent() {
328 return mReparent;
329 }
330
331 @NonNull
332 public IBinder getContainer() {
333 return mContainer;
334 }
335
336 public boolean getToTop() {
337 return mToTop;
338 }
339
340 @Override
341 public String toString() {
342 if (isReparent()) {
343 return "{reparent: " + mContainer + " to " + (mToTop ? "top of " : "bottom of ")
344 + mReparent + "}";
345 } else {
346 return "{reorder: " + mContainer + " to " + (mToTop ? "top" : "bottom") + "}";
347 }
348 }
349
350 @Override
351 public void writeToParcel(Parcel dest, int flags) {
352 dest.writeStrongBinder(mContainer);
353 dest.writeStrongBinder(mReparent);
354 dest.writeBoolean(mToTop);
355 }
356
357 @Override
358 public int describeContents() {
359 return 0;
360 }
361
362 public static final Creator<HierarchyOp> CREATOR = new Creator<HierarchyOp>() {
363 @Override
364 public HierarchyOp createFromParcel(Parcel in) {
365 return new HierarchyOp(in);
366 }
367
368 @Override
369 public HierarchyOp[] newArray(int size) {
370 return new HierarchyOp[size];
371 }
372 };
373 }
Evan Roskyddedfd42019-10-04 13:38:38 -0700374}