1 /*
2  * Copyright (C) 2020 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 
17 package android.window;
18 
19 import static android.window.TaskFragmentOperation.OP_TYPE_CLEAR_ADJACENT_TASK_FRAGMENTS;
20 import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_TASK_FRAGMENT;
21 import static android.window.TaskFragmentOperation.OP_TYPE_DELETE_TASK_FRAGMENT;
22 import static android.window.TaskFragmentOperation.OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
23 import static android.window.TaskFragmentOperation.OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT;
24 import static android.window.TaskFragmentOperation.OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS;
25 import static android.window.TaskFragmentOperation.OP_TYPE_SET_COMPANION_TASK_FRAGMENT;
26 import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
27 
28 import android.annotation.NonNull;
29 import android.annotation.Nullable;
30 import android.annotation.TestApi;
31 import android.app.PendingIntent;
32 import android.app.WindowConfiguration;
33 import android.content.Intent;
34 import android.content.pm.ActivityInfo;
35 import android.content.pm.ShortcutInfo;
36 import android.content.res.Configuration;
37 import android.graphics.Rect;
38 import android.os.Bundle;
39 import android.os.IBinder;
40 import android.os.Parcel;
41 import android.os.Parcelable;
42 import android.util.ArrayMap;
43 import android.view.InsetsFrameProvider;
44 import android.view.SurfaceControl;
45 import android.view.WindowInsets.Type.InsetsType;
46 
47 import java.util.ArrayList;
48 import java.util.Arrays;
49 import java.util.List;
50 import java.util.Map;
51 import java.util.Objects;
52 
53 /**
54  * Represents a collection of operations on some WindowContainers that should be applied all at
55  * once.
56  *
57  * @hide
58  */
59 @TestApi
60 public final class WindowContainerTransaction implements Parcelable {
61     private final ArrayMap<IBinder, Change> mChanges = new ArrayMap<>();
62 
63     // Flat list because re-order operations are order-dependent
64     private final ArrayList<HierarchyOp> mHierarchyOps = new ArrayList<>();
65 
66     @Nullable
67     private IBinder mErrorCallbackToken;
68 
69     @Nullable
70     private ITaskFragmentOrganizer mTaskFragmentOrganizer;
71 
WindowContainerTransaction()72     public WindowContainerTransaction() {}
73 
WindowContainerTransaction(Parcel in)74     private WindowContainerTransaction(Parcel in) {
75         in.readMap(mChanges, null /* loader */);
76         in.readTypedList(mHierarchyOps, HierarchyOp.CREATOR);
77         mErrorCallbackToken = in.readStrongBinder();
78         mTaskFragmentOrganizer = ITaskFragmentOrganizer.Stub.asInterface(in.readStrongBinder());
79     }
80 
getOrCreateChange(IBinder token)81     private Change getOrCreateChange(IBinder token) {
82         Change out = mChanges.get(token);
83         if (out == null) {
84             out = new Change();
85             mChanges.put(token, out);
86         }
87         return out;
88     }
89 
90     /**
91      * Clear the transaction object.
92      * This is equivalent to a new empty {@link WindowContainerTransaction} in content.
93      *
94      * @hide
95      */
clear()96     public void clear() {
97         mChanges.clear();
98         mHierarchyOps.clear();
99         mErrorCallbackToken = null;
100         mTaskFragmentOrganizer = null;
101     }
102 
103     /**
104      * Resize a container.
105      */
106     @NonNull
setBounds( @onNull WindowContainerToken container,@NonNull Rect bounds)107     public WindowContainerTransaction setBounds(
108             @NonNull WindowContainerToken container,@NonNull Rect bounds) {
109         Change chg = getOrCreateChange(container.asBinder());
110         chg.mConfiguration.windowConfiguration.setBounds(bounds);
111         chg.mConfigSetMask |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
112         chg.mWindowSetMask |= WindowConfiguration.WINDOW_CONFIG_BOUNDS;
113         return this;
114     }
115 
116     /**
117      * Resize a container's app bounds. This is the bounds used to report appWidth/Height to an
118      * app's DisplayInfo. It is derived by subtracting the overlapping portion of the navbar from
119      * the full bounds.
120      */
121     @NonNull
setAppBounds( @onNull WindowContainerToken container,@NonNull Rect appBounds)122     public WindowContainerTransaction setAppBounds(
123             @NonNull WindowContainerToken container,@NonNull Rect appBounds) {
124         Change chg = getOrCreateChange(container.asBinder());
125         chg.mConfiguration.windowConfiguration.setAppBounds(appBounds);
126         chg.mConfigSetMask |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
127         chg.mWindowSetMask |= WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS;
128         return this;
129     }
130 
131     /**
132      * Resize a container's configuration size. The configuration size is what gets reported to the
133      * app via screenWidth/HeightDp and influences which resources get loaded. This size is
134      * derived by subtracting the overlapping portions of both the statusbar and the navbar from
135      * the full bounds.
136      */
137     @NonNull
setScreenSizeDp( @onNull WindowContainerToken container, int w, int h)138     public WindowContainerTransaction setScreenSizeDp(
139             @NonNull WindowContainerToken container, int w, int h) {
140         Change chg = getOrCreateChange(container.asBinder());
141         chg.mConfiguration.screenWidthDp = w;
142         chg.mConfiguration.screenHeightDp = h;
143         chg.mConfigSetMask |= ActivityInfo.CONFIG_SCREEN_SIZE;
144         return this;
145     }
146 
147     /**
148      * Sets the densityDpi value in the configuration for the given container.
149      * @hide
150      */
151     @NonNull
setDensityDpi(@onNull WindowContainerToken container, int densityDpi)152     public WindowContainerTransaction setDensityDpi(@NonNull WindowContainerToken container,
153             int densityDpi) {
154         Change chg = getOrCreateChange(container.asBinder());
155         chg.mConfiguration.densityDpi = densityDpi;
156         chg.mConfigSetMask |= ActivityInfo.CONFIG_DENSITY;
157         return this;
158     }
159 
160     /**
161      * Notify {@link com.android.server.wm.PinnedTaskController} that the picture-in-picture task
162      * has finished the enter animation with the given bounds.
163      */
164     @NonNull
scheduleFinishEnterPip( @onNull WindowContainerToken container,@NonNull Rect bounds)165     public WindowContainerTransaction scheduleFinishEnterPip(
166             @NonNull WindowContainerToken container,@NonNull Rect bounds) {
167         Change chg = getOrCreateChange(container.asBinder());
168         chg.mPinnedBounds = new Rect(bounds);
169         chg.mChangeMask |= Change.CHANGE_PIP_CALLBACK;
170 
171         return this;
172     }
173 
174     /**
175      * Send a SurfaceControl transaction to the server, which the server will apply in sync with
176      * the next bounds change. As this uses deferred transaction and not BLAST it is only
177      * able to sync with a single window, and the first visible window in this hierarchy of type
178      * BASE_APPLICATION to resize will be used. If there are bound changes included in this
179      * WindowContainer transaction (from setBounds or scheduleFinishEnterPip), the SurfaceControl
180      * transaction will be synced with those bounds. If there are no changes, then
181      * the SurfaceControl transaction will be synced with the next bounds change. This means
182      * that you can call this, apply the WindowContainer transaction, and then later call
183      * dismissPip() to achieve synchronization.
184      */
185     @NonNull
setBoundsChangeTransaction( @onNull WindowContainerToken container,@NonNull SurfaceControl.Transaction t)186     public WindowContainerTransaction setBoundsChangeTransaction(
187             @NonNull WindowContainerToken container,@NonNull SurfaceControl.Transaction t) {
188         Change chg = getOrCreateChange(container.asBinder());
189         chg.mBoundsChangeTransaction = t;
190         chg.mChangeMask |= Change.CHANGE_BOUNDS_TRANSACTION;
191         return this;
192     }
193 
194     /**
195      * Like {@link #setBoundsChangeTransaction} but instead queues up a setPosition/WindowCrop
196      * on a container's surface control. This is useful when a boundsChangeTransaction needs to be
197      * queued up on a Task that won't be organized until the end of this window-container
198      * transaction.
199      *
200      * This requires that, at the end of this transaction, `task` will be organized; otherwise
201      * the server will throw an IllegalArgumentException.
202      *
203      * WARNING: Use this carefully. Whatever is set here should match the expected bounds after
204      *          the transaction completes since it will likely be replaced by it. This call is
205      *          intended to pre-emptively set bounds on a surface in sync with a buffer when
206      *          otherwise the new bounds and the new buffer would update on different frames.
207      *
208      * TODO(b/134365562): remove once TaskOrg drives full-screen or BLAST is enabled.
209      *
210      * @hide
211      */
212     @NonNull
setBoundsChangeTransaction( @onNull WindowContainerToken task, @NonNull Rect surfaceBounds)213     public WindowContainerTransaction setBoundsChangeTransaction(
214             @NonNull WindowContainerToken task, @NonNull Rect surfaceBounds) {
215         Change chg = getOrCreateChange(task.asBinder());
216         if (chg.mBoundsChangeSurfaceBounds == null) {
217             chg.mBoundsChangeSurfaceBounds = new Rect();
218         }
219         chg.mBoundsChangeSurfaceBounds.set(surfaceBounds);
220         chg.mChangeMask |= Change.CHANGE_BOUNDS_TRANSACTION_RECT;
221         return this;
222     }
223 
224     /**
225      * Set the windowing mode of children of a given root task, without changing
226      * the windowing mode of the Task itself. This can be used during transitions
227      * for example to make the activity render it's fullscreen configuration
228      * while the Task is still in PIP, so you can complete the animation.
229      *
230      * TODO(b/134365562): Can be removed once TaskOrg drives full-screen
231      */
232     @NonNull
setActivityWindowingMode( @onNull WindowContainerToken container, int windowingMode)233     public WindowContainerTransaction setActivityWindowingMode(
234             @NonNull WindowContainerToken container, int windowingMode) {
235         Change chg = getOrCreateChange(container.asBinder());
236         chg.mActivityWindowingMode = windowingMode;
237         return this;
238     }
239 
240     /**
241      * Sets the windowing mode of the given container.
242      */
243     @NonNull
setWindowingMode( @onNull WindowContainerToken container, int windowingMode)244     public WindowContainerTransaction setWindowingMode(
245             @NonNull WindowContainerToken container, int windowingMode) {
246         Change chg = getOrCreateChange(container.asBinder());
247         chg.mWindowingMode = windowingMode;
248         return this;
249     }
250 
251     /**
252      * Sets whether a container or any of its children can be focusable. When {@code false}, no
253      * child can be focused; however, when {@code true}, it is still possible for children to be
254      * non-focusable due to WM policy.
255      */
256     @NonNull
setFocusable( @onNull WindowContainerToken container, boolean focusable)257     public WindowContainerTransaction setFocusable(
258             @NonNull WindowContainerToken container, boolean focusable) {
259         Change chg = getOrCreateChange(container.asBinder());
260         chg.mFocusable = focusable;
261         chg.mChangeMask |= Change.CHANGE_FOCUSABLE;
262         return this;
263     }
264 
265     /**
266      * Sets whether a container or its children should be hidden. When {@code false}, the existing
267      * visibility of the container applies, but when {@code true} the container will be forced
268      * to be hidden.
269      */
270     @NonNull
setHidden( @onNull WindowContainerToken container, boolean hidden)271     public WindowContainerTransaction setHidden(
272             @NonNull WindowContainerToken container, boolean hidden) {
273         Change chg = getOrCreateChange(container.asBinder());
274         chg.mHidden = hidden;
275         chg.mChangeMask |= Change.CHANGE_HIDDEN;
276         return this;
277     }
278 
279     /**
280      * Set the smallestScreenWidth of a container.
281      */
282     @NonNull
setSmallestScreenWidthDp( @onNull WindowContainerToken container, int widthDp)283     public WindowContainerTransaction setSmallestScreenWidthDp(
284             @NonNull WindowContainerToken container, int widthDp) {
285         Change cfg = getOrCreateChange(container.asBinder());
286         cfg.mConfiguration.smallestScreenWidthDp = widthDp;
287         cfg.mConfigSetMask |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
288         return this;
289     }
290 
291     /**
292      * Sets whether a container should ignore the orientation request from apps and windows below
293      * it. It currently only applies to {@link com.android.server.wm.DisplayArea}. When
294      * {@code false}, it may rotate based on the orientation request; When {@code true}, it can
295      * never specify orientation, but shows the fixed-orientation apps below it in the letterbox.
296      * @hide
297      */
298     @NonNull
setIgnoreOrientationRequest( @onNull WindowContainerToken container, boolean ignoreOrientationRequest)299     public WindowContainerTransaction setIgnoreOrientationRequest(
300             @NonNull WindowContainerToken container, boolean ignoreOrientationRequest) {
301         Change chg = getOrCreateChange(container.asBinder());
302         chg.mIgnoreOrientationRequest = ignoreOrientationRequest;
303         chg.mChangeMask |= Change.CHANGE_IGNORE_ORIENTATION_REQUEST;
304         return this;
305     }
306 
307     /**
308      * Sets whether a task should be translucent. When {@code false}, the existing translucent of
309      * the task applies, but when {@code true} the task will be forced to be translucent.
310      * @hide
311      */
312     @NonNull
setForceTranslucent( @onNull WindowContainerToken container, boolean forceTranslucent)313     public WindowContainerTransaction setForceTranslucent(
314             @NonNull WindowContainerToken container, boolean forceTranslucent) {
315         Change chg = getOrCreateChange(container.asBinder());
316         chg.mForceTranslucent = forceTranslucent;
317         chg.mChangeMask |= Change.CHANGE_FORCE_TRANSLUCENT;
318         return this;
319     }
320 
321     /**
322      * Used in conjunction with a shell-transition call (usually finishTransition). This is
323      * basically a message to the transition system that a particular task should NOT go into
324      * PIP even though it normally would. This is to deal with some edge-case situations where
325      * Recents will "commit" the transition to go home, but then not actually go-home.
326      * @hide
327      */
328     @NonNull
setDoNotPip(@onNull WindowContainerToken container)329     public WindowContainerTransaction setDoNotPip(@NonNull WindowContainerToken container) {
330         Change chg = getOrCreateChange(container.asBinder());
331         chg.mChangeMask |= Change.CHANGE_FORCE_NO_PIP;
332         return this;
333     }
334 
335     /**
336      * Resizes a container by providing a bounds in its parent coordinate.
337      * This is only used by {@link TaskFragmentOrganizer}.
338      */
339     @NonNull
setRelativeBounds( @onNull WindowContainerToken container, @NonNull Rect relBounds)340     public WindowContainerTransaction setRelativeBounds(
341             @NonNull WindowContainerToken container, @NonNull Rect relBounds) {
342         Change chg = getOrCreateChange(container.asBinder());
343         if (chg.mRelativeBounds == null) {
344             chg.mRelativeBounds = new Rect();
345         }
346         chg.mRelativeBounds.set(relBounds);
347         chg.mChangeMask |= Change.CHANGE_RELATIVE_BOUNDS;
348         // Bounds will be overridden.
349         chg.mConfigSetMask |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
350         chg.mWindowSetMask |= WindowConfiguration.WINDOW_CONFIG_BOUNDS;
351         return this;
352     }
353 
354     /**
355      * Reparents a container into another one. The effect of a {@code null} parent can vary. For
356      * example, reparenting a stack to {@code null} will reparent it to its display.
357      *
358      * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to
359      *              the bottom.
360      */
361     @NonNull
reparent(@onNull WindowContainerToken child, @Nullable WindowContainerToken parent, boolean onTop)362     public WindowContainerTransaction reparent(@NonNull WindowContainerToken child,
363             @Nullable WindowContainerToken parent, boolean onTop) {
364         mHierarchyOps.add(HierarchyOp.createForReparent(child.asBinder(),
365                 parent == null ? null : parent.asBinder(),
366                 onTop));
367         return this;
368     }
369 
370     /**
371      * Reorders a container within its parent.
372      *
373      * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to
374      *              the bottom.
375      */
376     @NonNull
reorder(@onNull WindowContainerToken child, boolean onTop)377     public WindowContainerTransaction reorder(@NonNull WindowContainerToken child, boolean onTop) {
378         return reorder(child, onTop, false /* includingParents */);
379     }
380 
381     /**
382      * Reorders a container within its parent with an option to reorder all the parents in the
383      * hierarchy above among their respective siblings.
384      *
385      * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to
386      *              the bottom.
387      * @param includingParents When {@code true}, all the parents in the hierarchy above are also
388      *                         reordered among their respective siblings.
389      * @hide
390      */
391     @NonNull
reorder(@onNull WindowContainerToken child, boolean onTop, boolean includingParents)392     public WindowContainerTransaction reorder(@NonNull WindowContainerToken child, boolean onTop,
393             boolean includingParents) {
394         mHierarchyOps.add(HierarchyOp.createForReorder(child.asBinder(), onTop, includingParents));
395         return this;
396     }
397 
398     /**
399      * Reparent's all children tasks or the top task of {@param currentParent} in the specified
400      * {@param windowingMode} and {@param activityType} to {@param newParent} in their current
401      * z-order.
402      *
403      * @param currentParent of the tasks to perform the operation no.
404      *                      {@code null} will perform the operation on the display.
405      * @param newParent for the tasks. {@code null} will perform the operation on the display.
406      * @param windowingModes of the tasks to reparent.
407      * @param activityTypes of the tasks to reparent.
408      * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to
409      *              the bottom.
410      * @param reparentTopOnly When {@code true}, only reparent the top task which fit windowingModes
411      *                        and activityTypes.
412      * @hide
413      */
414     @NonNull
reparentTasks(@ullable WindowContainerToken currentParent, @Nullable WindowContainerToken newParent, @Nullable int[] windowingModes, @Nullable int[] activityTypes, boolean onTop, boolean reparentTopOnly)415     public WindowContainerTransaction reparentTasks(@Nullable WindowContainerToken currentParent,
416             @Nullable WindowContainerToken newParent, @Nullable int[] windowingModes,
417             @Nullable int[] activityTypes, boolean onTop, boolean reparentTopOnly) {
418         mHierarchyOps.add(HierarchyOp.createForChildrenTasksReparent(
419                 currentParent != null ? currentParent.asBinder() : null,
420                 newParent != null ? newParent.asBinder() : null,
421                 windowingModes,
422                 activityTypes,
423                 onTop,
424                 reparentTopOnly));
425         return this;
426     }
427 
428     /**
429      * Reparent's all children tasks of {@param currentParent} in the specified
430      * {@param windowingMode} and {@param activityType} to {@param newParent} in their current
431      * z-order.
432      *
433      * @param currentParent of the tasks to perform the operation no.
434      *                      {@code null} will perform the operation on the display.
435      * @param newParent for the tasks. {@code null} will perform the operation on the display.
436      * @param windowingModes of the tasks to reparent. {@code null} ignore this attribute when
437      *                       perform the operation.
438      * @param activityTypes of the tasks to reparent.  {@code null} ignore this attribute when
439      *                      perform the operation.
440      * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to
441      *              the bottom.
442      */
443     @NonNull
reparentTasks(@ullable WindowContainerToken currentParent, @Nullable WindowContainerToken newParent, @Nullable int[] windowingModes, @Nullable int[] activityTypes, boolean onTop)444     public WindowContainerTransaction reparentTasks(@Nullable WindowContainerToken currentParent,
445             @Nullable WindowContainerToken newParent, @Nullable int[] windowingModes,
446             @Nullable int[] activityTypes, boolean onTop) {
447         return reparentTasks(currentParent, newParent, windowingModes, activityTypes, onTop,
448                 false /* reparentTopOnly */);
449     }
450 
451     /**
452      * Sets whether a container should be the launch root for the specified windowing mode and
453      * activity type. This currently only applies to Task containers created by organizer.
454      */
455     @NonNull
setLaunchRoot(@onNull WindowContainerToken container, @Nullable int[] windowingModes, @Nullable int[] activityTypes)456     public WindowContainerTransaction setLaunchRoot(@NonNull WindowContainerToken container,
457             @Nullable int[] windowingModes, @Nullable int[] activityTypes) {
458         mHierarchyOps.add(HierarchyOp.createForSetLaunchRoot(
459                 container.asBinder(),
460                 windowingModes,
461                 activityTypes));
462         return this;
463     }
464 
465     /**
466      * Sets to containers adjacent to each other. Containers below two visible adjacent roots will
467      * be made invisible. This currently only applies to TaskFragment containers created by
468      * organizer.
469      * @param root1 the first root.
470      * @param root2 the second root.
471      */
472     @NonNull
setAdjacentRoots( @onNull WindowContainerToken root1, @NonNull WindowContainerToken root2)473     public WindowContainerTransaction setAdjacentRoots(
474             @NonNull WindowContainerToken root1, @NonNull WindowContainerToken root2) {
475         mHierarchyOps.add(HierarchyOp.createForAdjacentRoots(
476                 root1.asBinder(),
477                 root2.asBinder()));
478         return this;
479     }
480 
481     /**
482      * Sets the container as launch adjacent flag root. Task starting with
483      * {@link FLAG_ACTIVITY_LAUNCH_ADJACENT} will be launching to.
484      */
485     @NonNull
setLaunchAdjacentFlagRoot( @onNull WindowContainerToken container)486     public WindowContainerTransaction setLaunchAdjacentFlagRoot(
487             @NonNull WindowContainerToken container) {
488         mHierarchyOps.add(HierarchyOp.createForSetLaunchAdjacentFlagRoot(container.asBinder(),
489                 false /* clearRoot */));
490         return this;
491     }
492 
493     /**
494      * Clears launch adjacent flag root for the display area of passing container.
495      */
496     @NonNull
clearLaunchAdjacentFlagRoot( @onNull WindowContainerToken container)497     public WindowContainerTransaction clearLaunchAdjacentFlagRoot(
498             @NonNull WindowContainerToken container) {
499         mHierarchyOps.add(HierarchyOp.createForSetLaunchAdjacentFlagRoot(container.asBinder(),
500                 true /* clearRoot */));
501         return this;
502     }
503 
504     /**
505      * Starts a task by id. The task is expected to already exist (eg. as a recent task).
506      * @param taskId Id of task to start.
507      * @param options bundle containing ActivityOptions for the task's top activity.
508      * @hide
509      */
510     @NonNull
startTask(int taskId, @Nullable Bundle options)511     public WindowContainerTransaction startTask(int taskId, @Nullable Bundle options) {
512         mHierarchyOps.add(HierarchyOp.createForTaskLaunch(taskId, options));
513         return this;
514     }
515 
516     /**
517      * Finds and removes a task and its children using its container token. The task is removed
518      * from recents.
519      * @param containerToken ContainerToken of Task to be removed
520      */
521     @NonNull
removeTask(@onNull WindowContainerToken containerToken)522     public WindowContainerTransaction removeTask(@NonNull WindowContainerToken containerToken) {
523         mHierarchyOps.add(HierarchyOp.createForRemoveTask(containerToken.asBinder()));
524         return this;
525     }
526 
527     /**
528      * Sets whether a container is being drag-resized.
529      * When {@code true}, the client will reuse a single (larger) surface size to avoid
530      * continuous allocations on every size change.
531      *
532      * @param container WindowContainerToken of the task that changed its drag resizing state
533      * @hide
534      */
535     @NonNull
setDragResizing(@onNull WindowContainerToken container, boolean dragResizing)536     public WindowContainerTransaction setDragResizing(@NonNull WindowContainerToken container,
537             boolean dragResizing) {
538         final Change change = getOrCreateChange(container.asBinder());
539         change.mChangeMask |= Change.CHANGE_DRAG_RESIZING;
540         change.mDragResizing = dragResizing;
541         return this;
542     }
543 
544     /**
545      * Sends a pending intent in sync.
546      * @param sender The PendingIntent sender.
547      * @param intent The fillIn intent to patch over the sender's base intent.
548      * @param options bundle containing ActivityOptions for the task's top activity.
549      * @hide
550      */
551     @NonNull
sendPendingIntent(PendingIntent sender, Intent intent, @Nullable Bundle options)552     public WindowContainerTransaction sendPendingIntent(PendingIntent sender, Intent intent,
553             @Nullable Bundle options) {
554         mHierarchyOps.add(new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_PENDING_INTENT)
555                 .setLaunchOptions(options)
556                 .setPendingIntent(sender)
557                 .setActivityIntent(intent)
558                 .build());
559         return this;
560     }
561 
562     /**
563      * Starts activity(s) from a shortcut.
564      * @param callingPackage The package launching the shortcut.
565      * @param shortcutInfo Information about the shortcut to start
566      * @param options bundle containing ActivityOptions for the task's top activity.
567      * @hide
568      */
569     @NonNull
startShortcut(@onNull String callingPackage, @NonNull ShortcutInfo shortcutInfo, @Nullable Bundle options)570     public WindowContainerTransaction startShortcut(@NonNull String callingPackage,
571             @NonNull ShortcutInfo shortcutInfo, @Nullable Bundle options) {
572         mHierarchyOps.add(HierarchyOp.createForStartShortcut(
573                 callingPackage, shortcutInfo, options));
574         return this;
575     }
576 
577     /**
578      * Creates a new TaskFragment with the given options.
579      * @param taskFragmentCreationParams the options used to create the TaskFragment.
580      */
581     @NonNull
createTaskFragment( @onNull TaskFragmentCreationParams taskFragmentCreationParams)582     public WindowContainerTransaction createTaskFragment(
583             @NonNull TaskFragmentCreationParams taskFragmentCreationParams) {
584         final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
585                 OP_TYPE_CREATE_TASK_FRAGMENT)
586                 .setTaskFragmentCreationParams(taskFragmentCreationParams)
587                 .build();
588         return addTaskFragmentOperation(taskFragmentCreationParams.getFragmentToken(), operation);
589     }
590 
591     /**
592      * Deletes an existing TaskFragment. Any remaining activities below it will be destroyed.
593      * @param fragmentToken client assigned unique token to create TaskFragment with specified in
594      *                      {@link TaskFragmentCreationParams#getFragmentToken()}.
595      */
596     @NonNull
deleteTaskFragment(@onNull IBinder fragmentToken)597     public WindowContainerTransaction deleteTaskFragment(@NonNull IBinder fragmentToken) {
598         final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
599                 OP_TYPE_DELETE_TASK_FRAGMENT)
600                 .build();
601         return addTaskFragmentOperation(fragmentToken, operation);
602     }
603 
604     /**
605      * Starts an activity in the TaskFragment.
606      * @param fragmentToken client assigned unique token to create TaskFragment with specified in
607      *                      {@link TaskFragmentCreationParams#getFragmentToken()}.
608      * @param callerToken  the activity token that initialized the activity launch.
609      * @param activityIntent    intent to start the activity.
610      * @param activityOptions    ActivityOptions to start the activity with.
611      * @see android.content.Context#startActivity(Intent, Bundle).
612      */
613     @NonNull
startActivityInTaskFragment( @onNull IBinder fragmentToken, @NonNull IBinder callerToken, @NonNull Intent activityIntent, @Nullable Bundle activityOptions)614     public WindowContainerTransaction startActivityInTaskFragment(
615             @NonNull IBinder fragmentToken, @NonNull IBinder callerToken,
616             @NonNull Intent activityIntent, @Nullable Bundle activityOptions) {
617         final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
618                 OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT)
619                 .setActivityToken(callerToken)
620                 .setActivityIntent(activityIntent)
621                 .setBundle(activityOptions)
622                 .build();
623         return addTaskFragmentOperation(fragmentToken, operation);
624     }
625 
626     /**
627      * Moves an activity into the TaskFragment.
628      * @param fragmentToken client assigned unique token to create TaskFragment with specified in
629      *                      {@link TaskFragmentCreationParams#getFragmentToken()}.
630      * @param activityToken activity to be reparented.
631      */
632     @NonNull
reparentActivityToTaskFragment( @onNull IBinder fragmentToken, @NonNull IBinder activityToken)633     public WindowContainerTransaction reparentActivityToTaskFragment(
634             @NonNull IBinder fragmentToken, @NonNull IBinder activityToken) {
635         final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
636                 OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT)
637                 .setActivityToken(activityToken)
638                 .build();
639         return addTaskFragmentOperation(fragmentToken, operation);
640     }
641 
642     /**
643      * Sets to TaskFragments adjacent to each other. Containers below two visible adjacent
644      * TaskFragments will be made invisible. This is similar to
645      * {@link #setAdjacentRoots(WindowContainerToken, WindowContainerToken)}, but can be used with
646      * fragmentTokens when that TaskFragments haven't been created (but will be created in the same
647      * {@link WindowContainerTransaction}).
648      * @param fragmentToken1    client assigned unique token to create TaskFragment with specified
649      *                          in {@link TaskFragmentCreationParams#getFragmentToken()}.
650      * @param fragmentToken2    client assigned unique token to create TaskFragment with specified
651      *                          in {@link TaskFragmentCreationParams#getFragmentToken()}.
652      */
653     @NonNull
setAdjacentTaskFragments( @onNull IBinder fragmentToken1, @NonNull IBinder fragmentToken2, @Nullable TaskFragmentAdjacentParams params)654     public WindowContainerTransaction setAdjacentTaskFragments(
655             @NonNull IBinder fragmentToken1, @NonNull IBinder fragmentToken2,
656             @Nullable TaskFragmentAdjacentParams params) {
657         final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
658                 OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS)
659                 .setSecondaryFragmentToken(fragmentToken2)
660                 .setBundle(params != null ? params.toBundle() : null)
661                 .build();
662         return addTaskFragmentOperation(fragmentToken1, operation);
663     }
664 
665     /**
666      * Clears the adjacent TaskFragments relationship that is previously set through
667      * {@link #setAdjacentTaskFragments}. Clear operation on one TaskFragment will also clear its
668      * current adjacent TaskFragment's.
669      * @param fragmentToken     client assigned unique token to create TaskFragment with specified
670      *                          in {@link TaskFragmentCreationParams#getFragmentToken()}.
671      */
672     @NonNull
clearAdjacentTaskFragments(@onNull IBinder fragmentToken)673     public WindowContainerTransaction clearAdjacentTaskFragments(@NonNull IBinder fragmentToken) {
674         final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
675                 OP_TYPE_CLEAR_ADJACENT_TASK_FRAGMENTS)
676                 .build();
677         return addTaskFragmentOperation(fragmentToken, operation);
678     }
679 
680     /**
681      * If `container` was brought to front as a transient-launch (eg. recents), this will reorder
682      * the container back to where it was prior to the transient-launch. This way if a transient
683      * launch is "aborted", the z-ordering of containers in WM should be restored to before the
684      * launch.
685      * @hide
686      */
687     @NonNull
restoreTransientOrder( @onNull WindowContainerToken container)688     public WindowContainerTransaction restoreTransientOrder(
689             @NonNull WindowContainerToken container) {
690         final HierarchyOp hierarchyOp =
691                 new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER)
692                         .setContainer(container.asBinder())
693                         .build();
694         mHierarchyOps.add(hierarchyOp);
695         return this;
696     }
697 
698     /**
699      * Adds a given {@code Rect} as an insets source frame on the {@code receiver}.
700      *
701      * @param receiver The window container that the insets source is added to.
702      * @param owner    The owner of the insets source. An insets source can only be modified by its
703      *                 owner.
704      * @param index    An owner might add multiple insets sources with the same type.
705      *                 This identifies them.
706      * @param type     The {@link InsetsType} of the insets source.
707      * @param frame    The rectangle area of the insets source.
708      * @param boundingRects The bounding rects within this inset, relative to the |frame|.
709      * @hide
710      */
711     @NonNull
addInsetsSource( @onNull WindowContainerToken receiver, IBinder owner, int index, @InsetsType int type, Rect frame, Rect[] boundingRects)712     public WindowContainerTransaction addInsetsSource(
713             @NonNull WindowContainerToken receiver,
714             IBinder owner, int index, @InsetsType int type, Rect frame, Rect[] boundingRects) {
715         final HierarchyOp hierarchyOp =
716                 new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_ADD_INSETS_FRAME_PROVIDER)
717                         .setContainer(receiver.asBinder())
718                         .setInsetsFrameProvider(new InsetsFrameProvider(owner, index, type)
719                                 .setSource(InsetsFrameProvider.SOURCE_ARBITRARY_RECTANGLE)
720                                 .setArbitraryRectangle(frame)
721                                 .setBoundingRects(boundingRects))
722                         .setInsetsFrameOwner(owner)
723                         .build();
724         mHierarchyOps.add(hierarchyOp);
725         return this;
726     }
727 
728     /**
729      * Removes the insets source from the {@code receiver}.
730      *
731      * @param receiver The window container that the insets source was added to.
732      * @param owner    The owner of the insets source. An insets source can only be modified by its
733      *                 owner.
734      * @param index    An owner might add multiple insets sources with the same type.
735      *                 This identifies them.
736      * @param type     The {@link InsetsType} of the insets source.
737      * @hide
738      */
739     @NonNull
removeInsetsSource( @onNull WindowContainerToken receiver, IBinder owner, int index, @InsetsType int type)740     public WindowContainerTransaction removeInsetsSource(
741             @NonNull WindowContainerToken receiver,
742             IBinder owner, int index, @InsetsType int type) {
743         final HierarchyOp hierarchyOp =
744                 new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_REMOVE_INSETS_FRAME_PROVIDER)
745                         .setContainer(receiver.asBinder())
746                         .setInsetsFrameProvider(new InsetsFrameProvider(owner, index, type))
747                         .setInsetsFrameOwner(owner)
748                         .build();
749         mHierarchyOps.add(hierarchyOp);
750         return this;
751     }
752 
753     /**
754      * Requests focus on the top running Activity in the given TaskFragment. This will only take
755      * effect if there is no focus, or if the current focus is in the same Task as the requested
756      * TaskFragment.
757      * @param fragmentToken client assigned unique token to create TaskFragment with specified in
758      *                      {@link TaskFragmentCreationParams#getFragmentToken()}.
759      */
760     @NonNull
requestFocusOnTaskFragment(@onNull IBinder fragmentToken)761     public WindowContainerTransaction requestFocusOnTaskFragment(@NonNull IBinder fragmentToken) {
762         final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
763                 OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT)
764                 .build();
765         return addTaskFragmentOperation(fragmentToken, operation);
766     }
767 
768     /**
769      * Finishes the Activity.
770      * Comparing to directly calling {@link android.app.Activity#finish()}, calling this can make
771      * sure the finishing happens in the same transaction with other operations.
772      * @param activityToken activity to be finished.
773      */
774     @NonNull
finishActivity(@onNull IBinder activityToken)775     public WindowContainerTransaction finishActivity(@NonNull IBinder activityToken) {
776         final HierarchyOp hierarchyOp =
777                 new HierarchyOp.Builder(
778                         HierarchyOp.HIERARCHY_OP_TYPE_FINISH_ACTIVITY)
779                         .setContainer(activityToken)
780                         .build();
781         mHierarchyOps.add(hierarchyOp);
782         return this;
783     }
784 
785     /**
786      * Sets the TaskFragment {@code fragmentToken} to have a companion TaskFragment
787      * {@code companionFragmentToken}.
788      * This indicates that the organizer will remove the TaskFragment when the companion
789      * TaskFragment is removed.
790      *
791      * @param fragmentToken client assigned unique token to create TaskFragment with specified
792      *                      in {@link TaskFragmentCreationParams#getFragmentToken()}.
793      * @param companionFragmentToken client assigned unique token to create TaskFragment with
794      *                               specified in
795      *                               {@link TaskFragmentCreationParams#getFragmentToken()}.
796      *                               If it is {@code null}, the transaction will reset the companion
797      *                               TaskFragment.
798      * @hide
799      */
800     @NonNull
setCompanionTaskFragment(@onNull IBinder fragmentToken, @Nullable IBinder companionFragmentToken)801     public WindowContainerTransaction setCompanionTaskFragment(@NonNull IBinder fragmentToken,
802             @Nullable IBinder companionFragmentToken) {
803         final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
804                 OP_TYPE_SET_COMPANION_TASK_FRAGMENT)
805                 .setSecondaryFragmentToken(companionFragmentToken)
806                 .build();
807         return addTaskFragmentOperation(fragmentToken, operation);
808     }
809 
810     /**
811      * Adds a {@link TaskFragmentOperation} to apply to the given TaskFragment.
812      *
813      * @param fragmentToken client assigned unique token to create TaskFragment with specified in
814      *                      {@link TaskFragmentCreationParams#getFragmentToken()}.
815      * @param taskFragmentOperation the {@link TaskFragmentOperation} to apply to the given
816      *                              TaskFramgent.
817      * @hide
818      */
819     @NonNull
addTaskFragmentOperation(@onNull IBinder fragmentToken, @NonNull TaskFragmentOperation taskFragmentOperation)820     public WindowContainerTransaction addTaskFragmentOperation(@NonNull IBinder fragmentToken,
821             @NonNull TaskFragmentOperation taskFragmentOperation) {
822         Objects.requireNonNull(fragmentToken);
823         Objects.requireNonNull(taskFragmentOperation);
824         final HierarchyOp hierarchyOp =
825                 new HierarchyOp.Builder(
826                         HierarchyOp.HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION)
827                         .setContainer(fragmentToken)
828                         .setTaskFragmentOperation(taskFragmentOperation)
829                         .build();
830         mHierarchyOps.add(hierarchyOp);
831         return this;
832     }
833 
834     /**
835      * Sets/removes the always on top flag for this {@code windowContainer}. See
836      * {@link com.android.server.wm.ConfigurationContainer#setAlwaysOnTop(boolean)}.
837      * Please note that this method is only intended to be used for a
838      * {@link com.android.server.wm.Task} or {@link com.android.server.wm.DisplayArea}.
839      *
840      * <p>
841      *     Setting always on top to {@code True} will also make the {@code windowContainer} to move
842      *     to the top.
843      * </p>
844      * <p>
845      *     Setting always on top to {@code False} will make this {@code windowContainer} to move
846      *     below the other always on top sibling containers.
847      * </p>
848      *
849      * @param windowContainer the container which the flag need to be updated for.
850      * @param alwaysOnTop denotes whether or not always on top flag should be set.
851      * @hide
852      */
853     @NonNull
setAlwaysOnTop( @onNull WindowContainerToken windowContainer, boolean alwaysOnTop)854     public WindowContainerTransaction setAlwaysOnTop(
855             @NonNull WindowContainerToken windowContainer,
856             boolean alwaysOnTop) {
857         final HierarchyOp hierarchyOp =
858                 new HierarchyOp.Builder(
859                         HierarchyOp.HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP)
860                         .setContainer(windowContainer.asBinder())
861                         .setAlwaysOnTop(alwaysOnTop)
862                         .build();
863         mHierarchyOps.add(hierarchyOp);
864         return this;
865     }
866 
867     /**
868      * When this {@link WindowContainerTransaction} failed to finish on the server side, it will
869      * trigger callback with this {@param errorCallbackToken}.
870      * @param errorCallbackToken    client provided token that will be passed back as parameter in
871      *                              the callback if there is an error on the server side.
872      * @see ITaskFragmentOrganizer#onTaskFragmentError
873      */
874     @NonNull
setErrorCallbackToken(@onNull IBinder errorCallbackToken)875     public WindowContainerTransaction setErrorCallbackToken(@NonNull IBinder errorCallbackToken) {
876         if (mErrorCallbackToken != null) {
877             throw new IllegalStateException("Can't set multiple error token for one transaction.");
878         }
879         mErrorCallbackToken = errorCallbackToken;
880         return this;
881     }
882 
883     /**
884      * Sets the {@link TaskFragmentOrganizer} that applies this {@link WindowContainerTransaction}.
885      * When this is set, the server side will not check for the permission of
886      * {@link android.Manifest.permission#MANAGE_ACTIVITY_TASKS}, but will ensure this WCT only
887      * contains operations that are allowed for this organizer, such as modifying TaskFragments that
888      * are organized by this organizer.
889      * @hide
890      */
891     @NonNull
setTaskFragmentOrganizer( @onNull ITaskFragmentOrganizer organizer)892     public WindowContainerTransaction setTaskFragmentOrganizer(
893             @NonNull ITaskFragmentOrganizer organizer) {
894         mTaskFragmentOrganizer = organizer;
895         return this;
896     }
897 
898     /**
899      * Clears container adjacent.
900      * @param root the root container to clear the adjacent roots for.
901      * @hide
902      */
903     @NonNull
clearAdjacentRoots( @onNull WindowContainerToken root)904     public WindowContainerTransaction clearAdjacentRoots(
905             @NonNull WindowContainerToken root) {
906         mHierarchyOps.add(HierarchyOp.createForClearAdjacentRoots(root.asBinder()));
907         return this;
908     }
909 
910     /**
911      * Sets/removes the reparent leaf task flag for this {@code windowContainer}.
912      * When this is set, the server side will try to reparent the leaf task to task display area
913      * if there is an existing activity in history during the activity launch. This operation only
914      * support on the organized root task.
915      * @hide
916      */
917     @NonNull
setReparentLeafTaskIfRelaunch( @onNull WindowContainerToken windowContainer, boolean reparentLeafTaskIfRelaunch)918     public WindowContainerTransaction setReparentLeafTaskIfRelaunch(
919             @NonNull WindowContainerToken windowContainer, boolean reparentLeafTaskIfRelaunch) {
920         final HierarchyOp hierarchyOp =
921                 new HierarchyOp.Builder(
922                         HierarchyOp.HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH)
923                         .setContainer(windowContainer.asBinder())
924                         .setReparentLeafTaskIfRelaunch(reparentLeafTaskIfRelaunch)
925                         .build();
926         mHierarchyOps.add(hierarchyOp);
927         return this;
928     }
929 
930     /**
931      * Moves the PiP activity of a parent task to a pinned root task.
932      * @param parentToken the parent task of the PiP activity
933      * @param bounds the entry bounds
934      * @hide
935      */
936     @NonNull
movePipActivityToPinnedRootTask( @onNull WindowContainerToken parentToken, @NonNull Rect bounds)937     public WindowContainerTransaction movePipActivityToPinnedRootTask(
938             @NonNull WindowContainerToken parentToken, @NonNull Rect bounds) {
939         mHierarchyOps.add(new HierarchyOp
940                 .Builder(HierarchyOp.HIERARCHY_OP_TYPE_MOVE_PIP_ACTIVITY_TO_PINNED_TASK)
941                 .setContainer(parentToken.asBinder())
942                 .setBounds(bounds)
943                 .build());
944         return this;
945     }
946 
947     /**
948      * Defers client-facing configuration changes for activities in `container` until the end of
949      * the transition animation. The configuration will still be applied to the WMCore hierarchy
950      * at the normal time (beginning); so, special consideration must be made for this in the
951      * animation.
952      *
953      * @param container WindowContainerToken who's children should defer config notification.
954      * @hide
955      */
956     @NonNull
deferConfigToTransitionEnd( @onNull WindowContainerToken container)957     public WindowContainerTransaction deferConfigToTransitionEnd(
958             @NonNull WindowContainerToken container) {
959         final Change change = getOrCreateChange(container.asBinder());
960         change.mConfigAtTransitionEnd = true;
961         return this;
962     }
963 
964     /**
965      * Merges another WCT into this one.
966      * @param transfer When true, this will transfer everything from other potentially leaving
967      *                 other in an unusable state. When false, other is left alone, but
968      *                 SurfaceFlinger Transactions will not be merged.
969      * @hide
970      */
merge(WindowContainerTransaction other, boolean transfer)971     public void merge(WindowContainerTransaction other, boolean transfer) {
972         for (int i = 0, n = other.mChanges.size(); i < n; ++i) {
973             final IBinder key = other.mChanges.keyAt(i);
974             Change existing = mChanges.get(key);
975             if (existing == null) {
976                 existing = new Change();
977                 mChanges.put(key, existing);
978             }
979             existing.merge(other.mChanges.valueAt(i), transfer);
980         }
981         for (int i = 0, n = other.mHierarchyOps.size(); i < n; ++i) {
982             mHierarchyOps.add(transfer ? other.mHierarchyOps.get(i)
983                     : new HierarchyOp(other.mHierarchyOps.get(i)));
984         }
985         if (mErrorCallbackToken != null && other.mErrorCallbackToken != null && mErrorCallbackToken
986                 != other.mErrorCallbackToken) {
987             throw new IllegalArgumentException("Can't merge two WCTs with different error token");
988         }
989         final IBinder taskFragmentOrganizerAsBinder = mTaskFragmentOrganizer != null
990                 ? mTaskFragmentOrganizer.asBinder()
991                 : null;
992         final IBinder otherTaskFragmentOrganizerAsBinder = other.mTaskFragmentOrganizer != null
993                 ? other.mTaskFragmentOrganizer.asBinder()
994                 : null;
995         if (!Objects.equals(taskFragmentOrganizerAsBinder, otherTaskFragmentOrganizerAsBinder)) {
996             throw new IllegalArgumentException(
997                     "Can't merge two WCTs from different TaskFragmentOrganizers");
998         }
999         mErrorCallbackToken = mErrorCallbackToken != null
1000                 ? mErrorCallbackToken
1001                 : other.mErrorCallbackToken;
1002     }
1003 
1004     /** @hide */
isEmpty()1005     public boolean isEmpty() {
1006         return mChanges.isEmpty() && mHierarchyOps.isEmpty();
1007     }
1008 
1009     /** @hide */
getChanges()1010     public Map<IBinder, Change> getChanges() {
1011         return mChanges;
1012     }
1013 
1014     /** @hide */
getHierarchyOps()1015     public List<HierarchyOp> getHierarchyOps() {
1016         return mHierarchyOps;
1017     }
1018 
1019     /** @hide */
1020     @Nullable
getErrorCallbackToken()1021     public IBinder getErrorCallbackToken() {
1022         return mErrorCallbackToken;
1023     }
1024 
1025     /** @hide */
1026     @Nullable
getTaskFragmentOrganizer()1027     public ITaskFragmentOrganizer getTaskFragmentOrganizer() {
1028         return mTaskFragmentOrganizer;
1029     }
1030 
1031     @Override
1032     @NonNull
toString()1033     public String toString() {
1034         return "WindowContainerTransaction {"
1035                 + " changes = " + mChanges
1036                 + " hops = " + mHierarchyOps
1037                 + " errorCallbackToken=" + mErrorCallbackToken
1038                 + " taskFragmentOrganizer=" + mTaskFragmentOrganizer
1039                 + " }";
1040     }
1041 
1042     @Override
writeToParcel(@onNull Parcel dest, int flags)1043     public void writeToParcel(@NonNull Parcel dest, int flags) {
1044         dest.writeMap(mChanges);
1045         dest.writeTypedList(mHierarchyOps);
1046         dest.writeStrongBinder(mErrorCallbackToken);
1047         dest.writeStrongInterface(mTaskFragmentOrganizer);
1048     }
1049 
1050     @Override
describeContents()1051     public int describeContents() {
1052         return 0;
1053     }
1054 
1055     @NonNull
1056     public static final Creator<WindowContainerTransaction> CREATOR =
1057             new Creator<WindowContainerTransaction>() {
1058                 @Override
1059                 public WindowContainerTransaction createFromParcel(Parcel in) {
1060                     return new WindowContainerTransaction(in);
1061                 }
1062 
1063                 @Override
1064                 public WindowContainerTransaction[] newArray(int size) {
1065                     return new WindowContainerTransaction[size];
1066                 }
1067             };
1068 
1069     /**
1070      * Holds changes on a single WindowContainer including Configuration changes.
1071      * @hide
1072      */
1073     public static class Change implements Parcelable {
1074         public static final int CHANGE_FOCUSABLE = 1;
1075         public static final int CHANGE_BOUNDS_TRANSACTION = 1 << 1;
1076         public static final int CHANGE_PIP_CALLBACK = 1 << 2;
1077         public static final int CHANGE_HIDDEN = 1 << 3;
1078         public static final int CHANGE_BOUNDS_TRANSACTION_RECT = 1 << 4;
1079         public static final int CHANGE_IGNORE_ORIENTATION_REQUEST = 1 << 5;
1080         public static final int CHANGE_FORCE_NO_PIP = 1 << 6;
1081         public static final int CHANGE_FORCE_TRANSLUCENT = 1 << 7;
1082         public static final int CHANGE_DRAG_RESIZING = 1 << 8;
1083         public static final int CHANGE_RELATIVE_BOUNDS = 1 << 9;
1084 
1085         private final Configuration mConfiguration = new Configuration();
1086         private boolean mFocusable = true;
1087         private boolean mHidden = false;
1088         private boolean mIgnoreOrientationRequest = false;
1089         private boolean mForceTranslucent = false;
1090         private boolean mDragResizing = false;
1091 
1092         private int mChangeMask = 0;
1093         private @ActivityInfo.Config int mConfigSetMask = 0;
1094         private @WindowConfiguration.WindowConfig int mWindowSetMask = 0;
1095 
1096         private Rect mPinnedBounds = null;
1097         private SurfaceControl.Transaction mBoundsChangeTransaction = null;
1098         private Rect mBoundsChangeSurfaceBounds = null;
1099         @Nullable
1100         private Rect mRelativeBounds = null;
1101         private boolean mConfigAtTransitionEnd = false;
1102 
1103         private int mActivityWindowingMode = -1;
1104         private int mWindowingMode = -1;
1105 
Change()1106         public Change() {}
1107 
Change(Parcel in)1108         protected Change(Parcel in) {
1109             mConfiguration.readFromParcel(in);
1110             mFocusable = in.readBoolean();
1111             mHidden = in.readBoolean();
1112             mIgnoreOrientationRequest = in.readBoolean();
1113             mForceTranslucent = in.readBoolean();
1114             mDragResizing = in.readBoolean();
1115             mChangeMask = in.readInt();
1116             mConfigSetMask = in.readInt();
1117             mWindowSetMask = in.readInt();
1118             if ((mChangeMask & Change.CHANGE_PIP_CALLBACK) != 0) {
1119                 mPinnedBounds = new Rect();
1120                 mPinnedBounds.readFromParcel(in);
1121             }
1122             if ((mChangeMask & Change.CHANGE_BOUNDS_TRANSACTION) != 0) {
1123                 mBoundsChangeTransaction =
1124                     SurfaceControl.Transaction.CREATOR.createFromParcel(in);
1125             }
1126             if ((mChangeMask & Change.CHANGE_BOUNDS_TRANSACTION_RECT) != 0) {
1127                 mBoundsChangeSurfaceBounds = new Rect();
1128                 mBoundsChangeSurfaceBounds.readFromParcel(in);
1129             }
1130             if ((mChangeMask & Change.CHANGE_RELATIVE_BOUNDS) != 0) {
1131                 mRelativeBounds = new Rect();
1132                 mRelativeBounds.readFromParcel(in);
1133             }
1134             mConfigAtTransitionEnd = in.readBoolean();
1135 
1136             mWindowingMode = in.readInt();
1137             mActivityWindowingMode = in.readInt();
1138         }
1139 
1140         /**
1141          * @param transfer When true, this will transfer other into this leaving other in an
1142          *                 undefined state. Use this if you don't intend to use other. When false,
1143          *                 SurfaceFlinger Transactions will not merge.
1144          */
merge(Change other, boolean transfer)1145         public void merge(Change other, boolean transfer) {
1146             mConfiguration.setTo(other.mConfiguration, other.mConfigSetMask, other.mWindowSetMask);
1147             mConfigSetMask |= other.mConfigSetMask;
1148             mWindowSetMask |= other.mWindowSetMask;
1149             if ((other.mChangeMask & CHANGE_FOCUSABLE) != 0) {
1150                 mFocusable = other.mFocusable;
1151             }
1152             if (transfer && (other.mChangeMask & CHANGE_BOUNDS_TRANSACTION) != 0) {
1153                 mBoundsChangeTransaction = other.mBoundsChangeTransaction;
1154                 other.mBoundsChangeTransaction = null;
1155             }
1156             if ((other.mChangeMask & CHANGE_PIP_CALLBACK) != 0) {
1157                 mPinnedBounds = transfer ? other.mPinnedBounds : new Rect(other.mPinnedBounds);
1158             }
1159             if ((other.mChangeMask & CHANGE_HIDDEN) != 0) {
1160                 mHidden = other.mHidden;
1161             }
1162             if ((other.mChangeMask & CHANGE_IGNORE_ORIENTATION_REQUEST) != 0) {
1163                 mIgnoreOrientationRequest = other.mIgnoreOrientationRequest;
1164             }
1165             if ((other.mChangeMask & CHANGE_FORCE_TRANSLUCENT) != 0) {
1166                 mForceTranslucent = other.mForceTranslucent;
1167             }
1168             if ((other.mChangeMask & CHANGE_DRAG_RESIZING) != 0) {
1169                 mDragResizing = other.mDragResizing;
1170             }
1171             mChangeMask |= other.mChangeMask;
1172             if (other.mActivityWindowingMode >= 0) {
1173                 mActivityWindowingMode = other.mActivityWindowingMode;
1174             }
1175             if (other.mWindowingMode >= 0) {
1176                 mWindowingMode = other.mWindowingMode;
1177             }
1178             if (other.mBoundsChangeSurfaceBounds != null) {
1179                 mBoundsChangeSurfaceBounds = transfer ? other.mBoundsChangeSurfaceBounds
1180                         : new Rect(other.mBoundsChangeSurfaceBounds);
1181             }
1182             if (other.mRelativeBounds != null) {
1183                 mRelativeBounds = transfer
1184                         ? other.mRelativeBounds
1185                         : new Rect(other.mRelativeBounds);
1186             }
1187             mConfigAtTransitionEnd = mConfigAtTransitionEnd
1188                     || other.mConfigAtTransitionEnd;
1189         }
1190 
getWindowingMode()1191         public int getWindowingMode() {
1192             return mWindowingMode;
1193         }
1194 
getActivityWindowingMode()1195         public int getActivityWindowingMode() {
1196             return mActivityWindowingMode;
1197         }
1198 
getConfiguration()1199         public Configuration getConfiguration() {
1200             return mConfiguration;
1201         }
1202 
1203         /** Gets the requested focusable state */
getFocusable()1204         public boolean getFocusable() {
1205             if ((mChangeMask & CHANGE_FOCUSABLE) == 0) {
1206                 throw new RuntimeException("Focusable not set. check CHANGE_FOCUSABLE first");
1207             }
1208             return mFocusable;
1209         }
1210 
1211         /** Gets the requested hidden state */
getHidden()1212         public boolean getHidden() {
1213             if ((mChangeMask & CHANGE_HIDDEN) == 0) {
1214                 throw new RuntimeException("Hidden not set. check CHANGE_HIDDEN first");
1215             }
1216             return mHidden;
1217         }
1218 
1219         /** Gets the requested state of whether to ignore orientation request. */
getIgnoreOrientationRequest()1220         public boolean getIgnoreOrientationRequest() {
1221             if ((mChangeMask & CHANGE_IGNORE_ORIENTATION_REQUEST) == 0) {
1222                 throw new RuntimeException("IgnoreOrientationRequest not set. "
1223                         + "Check CHANGE_IGNORE_ORIENTATION_REQUEST first");
1224             }
1225             return mIgnoreOrientationRequest;
1226         }
1227 
1228         /** Gets the requested force translucent state. */
getForceTranslucent()1229         public boolean getForceTranslucent() {
1230             if ((mChangeMask & CHANGE_FORCE_TRANSLUCENT) == 0) {
1231                 throw new RuntimeException("Force translucent not set. "
1232                         + "Check CHANGE_FORCE_TRANSLUCENT first");
1233             }
1234             return mForceTranslucent;
1235         }
1236 
1237         /** Gets the requested drag resizing state. */
getDragResizing()1238         public boolean getDragResizing() {
1239             if ((mChangeMask & CHANGE_DRAG_RESIZING) == 0) {
1240                 throw new RuntimeException("Drag resizing not set. "
1241                         + "Check CHANGE_DRAG_RESIZING first");
1242             }
1243             return mDragResizing;
1244         }
1245 
1246         /** Gets whether the config should be sent to the client at the end of the transition. */
getConfigAtTransitionEnd()1247         public boolean getConfigAtTransitionEnd() {
1248             return mConfigAtTransitionEnd;
1249         }
1250 
getChangeMask()1251         public int getChangeMask() {
1252             return mChangeMask;
1253         }
1254 
1255         @ActivityInfo.Config
getConfigSetMask()1256         public int getConfigSetMask() {
1257             return mConfigSetMask;
1258         }
1259 
1260         @WindowConfiguration.WindowConfig
getWindowSetMask()1261         public int getWindowSetMask() {
1262             return mWindowSetMask;
1263         }
1264 
1265         /**
1266          * Returns the bounds to be used for scheduling the enter pip callback
1267          * or null if no callback is to be scheduled.
1268          */
getEnterPipBounds()1269         public Rect getEnterPipBounds() {
1270             return mPinnedBounds;
1271         }
1272 
getBoundsChangeTransaction()1273         public SurfaceControl.Transaction getBoundsChangeTransaction() {
1274             return mBoundsChangeTransaction;
1275         }
1276 
getBoundsChangeSurfaceBounds()1277         public Rect getBoundsChangeSurfaceBounds() {
1278             return mBoundsChangeSurfaceBounds;
1279         }
1280 
1281         @Nullable
getRelativeBounds()1282         public Rect getRelativeBounds() {
1283             return mRelativeBounds;
1284         }
1285 
1286         @Override
toString()1287         public String toString() {
1288             final boolean changesBounds =
1289                     (mConfigSetMask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0
1290                             && ((mWindowSetMask & WindowConfiguration.WINDOW_CONFIG_BOUNDS)
1291                                     != 0);
1292             final boolean changesAppBounds =
1293                     (mConfigSetMask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0
1294                             && ((mWindowSetMask & WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS)
1295                                     != 0);
1296             final boolean changesSs = (mConfigSetMask & ActivityInfo.CONFIG_SCREEN_SIZE) != 0;
1297             final boolean changesSss =
1298                     (mConfigSetMask & ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE) != 0;
1299             StringBuilder sb = new StringBuilder();
1300             sb.append('{');
1301             if (changesBounds) {
1302                 sb.append("bounds:" + mConfiguration.windowConfiguration.getBounds() + ",");
1303             }
1304             if (changesAppBounds) {
1305                 sb.append("appbounds:" + mConfiguration.windowConfiguration.getAppBounds() + ",");
1306             }
1307             if (changesSss) {
1308                 sb.append("ssw:" + mConfiguration.smallestScreenWidthDp + ",");
1309             }
1310             if (changesSs) {
1311                 sb.append("sw/h:" + mConfiguration.screenWidthDp + "x"
1312                         + mConfiguration.screenHeightDp + ",");
1313             }
1314             if ((mChangeMask & CHANGE_FOCUSABLE) != 0) {
1315                 sb.append("focusable:" + mFocusable + ",");
1316             }
1317             if ((mChangeMask & CHANGE_FORCE_TRANSLUCENT) != 0) {
1318                 sb.append("forceTranslucent:" + mForceTranslucent + ",");
1319             }
1320             if ((mChangeMask & CHANGE_HIDDEN) != 0) {
1321                 sb.append("hidden:" + mHidden + ",");
1322             }
1323             if ((mChangeMask & CHANGE_DRAG_RESIZING) != 0) {
1324                 sb.append("dragResizing:" + mDragResizing + ",");
1325             }
1326             if (mBoundsChangeTransaction != null) {
1327                 sb.append("hasBoundsTransaction,");
1328             }
1329             if ((mChangeMask & CHANGE_IGNORE_ORIENTATION_REQUEST) != 0) {
1330                 sb.append("ignoreOrientationRequest:" + mIgnoreOrientationRequest + ",");
1331             }
1332             if ((mChangeMask & CHANGE_RELATIVE_BOUNDS) != 0) {
1333                 sb.append("relativeBounds:").append(mRelativeBounds).append(",");
1334             }
1335             if (mConfigAtTransitionEnd) {
1336                 sb.append("configAtTransitionEnd").append(",");
1337             }
1338             sb.append("}");
1339             return sb.toString();
1340         }
1341 
1342         @Override
writeToParcel(Parcel dest, int flags)1343         public void writeToParcel(Parcel dest, int flags) {
1344             mConfiguration.writeToParcel(dest, flags);
1345             dest.writeBoolean(mFocusable);
1346             dest.writeBoolean(mHidden);
1347             dest.writeBoolean(mIgnoreOrientationRequest);
1348             dest.writeBoolean(mForceTranslucent);
1349             dest.writeBoolean(mDragResizing);
1350             dest.writeInt(mChangeMask);
1351             dest.writeInt(mConfigSetMask);
1352             dest.writeInt(mWindowSetMask);
1353 
1354             if (mPinnedBounds != null) {
1355                 mPinnedBounds.writeToParcel(dest, flags);
1356             }
1357             if (mBoundsChangeTransaction != null) {
1358                 mBoundsChangeTransaction.writeToParcel(dest, flags);
1359             }
1360             if (mBoundsChangeSurfaceBounds != null) {
1361                 mBoundsChangeSurfaceBounds.writeToParcel(dest, flags);
1362             }
1363             if (mRelativeBounds != null) {
1364                 mRelativeBounds.writeToParcel(dest, flags);
1365             }
1366             dest.writeBoolean(mConfigAtTransitionEnd);
1367 
1368             dest.writeInt(mWindowingMode);
1369             dest.writeInt(mActivityWindowingMode);
1370         }
1371 
1372         @Override
describeContents()1373         public int describeContents() {
1374             return 0;
1375         }
1376 
1377         public static final Creator<Change> CREATOR = new Creator<Change>() {
1378             @Override
1379             public Change createFromParcel(Parcel in) {
1380                 return new Change(in);
1381             }
1382 
1383             @Override
1384             public Change[] newArray(int size) {
1385                 return new Change[size];
1386             }
1387         };
1388     }
1389 
1390     /**
1391      * Holds information about a reparent/reorder operation in the hierarchy. This is separate from
1392      * Changes because they must be executed in the same order that they are added.
1393      * @hide
1394      */
1395     public static final class HierarchyOp implements Parcelable {
1396         public static final int HIERARCHY_OP_TYPE_REPARENT = 0;
1397         public static final int HIERARCHY_OP_TYPE_REORDER = 1;
1398         public static final int HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT = 2;
1399         public static final int HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT = 3;
1400         public static final int HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS = 4;
1401         public static final int HIERARCHY_OP_TYPE_LAUNCH_TASK = 5;
1402         public static final int HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT = 6;
1403         public static final int HIERARCHY_OP_TYPE_PENDING_INTENT = 7;
1404         public static final int HIERARCHY_OP_TYPE_START_SHORTCUT = 8;
1405         public static final int HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER = 9;
1406         public static final int HIERARCHY_OP_TYPE_ADD_INSETS_FRAME_PROVIDER = 10;
1407         public static final int HIERARCHY_OP_TYPE_REMOVE_INSETS_FRAME_PROVIDER = 11;
1408         public static final int HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP = 12;
1409         public static final int HIERARCHY_OP_TYPE_REMOVE_TASK = 13;
1410         public static final int HIERARCHY_OP_TYPE_FINISH_ACTIVITY = 14;
1411         public static final int HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS = 15;
1412         public static final int HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH = 16;
1413         public static final int HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION = 17;
1414         public static final int HIERARCHY_OP_TYPE_MOVE_PIP_ACTIVITY_TO_PINNED_TASK = 18;
1415 
1416         // The following key(s) are for use with mLaunchOptions:
1417         // When launching a task (eg. from recents), this is the taskId to be launched.
1418         public static final String LAUNCH_KEY_TASK_ID = "android:transaction.hop.taskId";
1419 
1420         // When starting from a shortcut, this contains the calling package.
1421         public static final String LAUNCH_KEY_SHORTCUT_CALLING_PACKAGE =
1422                 "android:transaction.hop.shortcut_calling_package";
1423 
1424         private final int mType;
1425 
1426         // Container we are performing the operation on.
1427         @Nullable
1428         private IBinder mContainer;
1429 
1430         // If this is same as mContainer, then only change position, don't reparent.
1431         @Nullable
1432         private IBinder mReparent;
1433 
1434         @Nullable
1435         private InsetsFrameProvider mInsetsFrameProvider;
1436 
1437         @Nullable
1438         private IBinder mInsetsFrameOwner;
1439 
1440         // Moves/reparents to top of parent when {@code true}, otherwise moves/reparents to bottom.
1441         private boolean mToTop;
1442 
1443         private boolean mReparentTopOnly;
1444 
1445         @Nullable
1446         private int[]  mWindowingModes;
1447 
1448         @Nullable
1449         private int[] mActivityTypes;
1450 
1451         @Nullable
1452         private Bundle mLaunchOptions;
1453 
1454         @Nullable
1455         private Intent mActivityIntent;
1456 
1457         /** Used as options for {@link #addTaskFragmentOperation}. */
1458         @Nullable
1459         private TaskFragmentOperation mTaskFragmentOperation;
1460 
1461         @Nullable
1462         private PendingIntent mPendingIntent;
1463 
1464         @Nullable
1465         private ShortcutInfo mShortcutInfo;
1466 
1467         @Nullable
1468         private Rect mBounds;
1469 
1470         private boolean mIncludingParents;
1471 
1472         private boolean mAlwaysOnTop;
1473 
1474         private boolean mReparentLeafTaskIfRelaunch;
1475 
createForReparent( @onNull IBinder container, @Nullable IBinder reparent, boolean toTop)1476         public static HierarchyOp createForReparent(
1477                 @NonNull IBinder container, @Nullable IBinder reparent, boolean toTop) {
1478             return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REPARENT)
1479                     .setContainer(container)
1480                     .setReparentContainer(reparent)
1481                     .setToTop(toTop)
1482                     .build();
1483         }
1484 
1485         /**
1486          * Creates the {@link HierarchyOp} for the reorder operation.
1487          *
1488          * @param container which needs to be reordered
1489          * @param toTop if true, the container reorders
1490          * @param includingParents if true, all the parents in the hierarchy above are also
1491          *                         reoredered among their respective siblings
1492          * @return
1493          */
createForReorder(@onNull IBinder container, boolean toTop, boolean includingParents)1494         public static HierarchyOp createForReorder(@NonNull IBinder container, boolean toTop,
1495                 boolean includingParents) {
1496             return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REORDER)
1497                     .setContainer(container)
1498                     .setReparentContainer(container)
1499                     .setToTop(toTop)
1500                     .setIncludingParents(includingParents)
1501                     .build();
1502         }
1503 
createForChildrenTasksReparent(IBinder currentParent, IBinder newParent, int[] windowingModes, int[] activityTypes, boolean onTop, boolean reparentTopOnly)1504         public static HierarchyOp createForChildrenTasksReparent(IBinder currentParent,
1505                 IBinder newParent, int[] windowingModes, int[] activityTypes, boolean onTop,
1506                 boolean reparentTopOnly) {
1507             return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT)
1508                     .setContainer(currentParent)
1509                     .setReparentContainer(newParent)
1510                     .setWindowingModes(windowingModes)
1511                     .setActivityTypes(activityTypes)
1512                     .setToTop(onTop)
1513                     .setReparentTopOnly(reparentTopOnly)
1514                     .build();
1515         }
1516 
createForSetLaunchRoot(IBinder container, int[] windowingModes, int[] activityTypes)1517         public static HierarchyOp createForSetLaunchRoot(IBinder container,
1518                 int[] windowingModes, int[] activityTypes) {
1519             return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT)
1520                     .setContainer(container)
1521                     .setWindowingModes(windowingModes)
1522                     .setActivityTypes(activityTypes)
1523                     .build();
1524         }
1525 
1526         /** Create a hierarchy op for setting adjacent root tasks. */
createForAdjacentRoots(IBinder root1, IBinder root2)1527         public static HierarchyOp createForAdjacentRoots(IBinder root1, IBinder root2) {
1528             return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS)
1529                     .setContainer(root1)
1530                     .setReparentContainer(root2)
1531                     .build();
1532         }
1533 
1534         /** Create a hierarchy op for launching a task. */
createForTaskLaunch(int taskId, @Nullable Bundle options)1535         public static HierarchyOp createForTaskLaunch(int taskId, @Nullable Bundle options) {
1536             final Bundle fullOptions = options == null ? new Bundle() : options;
1537             fullOptions.putInt(LAUNCH_KEY_TASK_ID, taskId);
1538             return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_LAUNCH_TASK)
1539                     .setToTop(true)
1540                     .setLaunchOptions(fullOptions)
1541                     .build();
1542         }
1543 
1544         /** Create a hierarchy op for starting a shortcut. */
createForStartShortcut(@onNull String callingPackage, @NonNull ShortcutInfo shortcutInfo, @Nullable Bundle options)1545         public static HierarchyOp createForStartShortcut(@NonNull String callingPackage,
1546                 @NonNull ShortcutInfo shortcutInfo, @Nullable Bundle options) {
1547             final Bundle fullOptions = options == null ? new Bundle() : options;
1548             fullOptions.putString(LAUNCH_KEY_SHORTCUT_CALLING_PACKAGE, callingPackage);
1549             return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_START_SHORTCUT)
1550                     .setShortcutInfo(shortcutInfo)
1551                     .setLaunchOptions(fullOptions)
1552                     .build();
1553         }
1554 
1555         /** Create a hierarchy op for setting launch adjacent flag root. */
createForSetLaunchAdjacentFlagRoot(IBinder container, boolean clearRoot)1556         public static HierarchyOp createForSetLaunchAdjacentFlagRoot(IBinder container,
1557                 boolean clearRoot) {
1558             return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT)
1559                     .setContainer(container)
1560                     .setToTop(clearRoot)
1561                     .build();
1562         }
1563 
1564         /** create a hierarchy op for deleting a task **/
createForRemoveTask(@onNull IBinder container)1565         public static HierarchyOp createForRemoveTask(@NonNull IBinder container) {
1566             return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REMOVE_TASK)
1567                     .setContainer(container)
1568                     .build();
1569         }
1570 
1571         /** Create a hierarchy op for clearing adjacent root tasks. */
createForClearAdjacentRoots(@onNull IBinder root)1572         public static HierarchyOp createForClearAdjacentRoots(@NonNull IBinder root) {
1573             return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS)
1574                     .setContainer(root)
1575                     .build();
1576         }
1577 
1578         /** Only creates through {@link Builder}. */
HierarchyOp(int type)1579         private HierarchyOp(int type) {
1580             mType = type;
1581         }
1582 
HierarchyOp(@onNull HierarchyOp copy)1583         public HierarchyOp(@NonNull HierarchyOp copy) {
1584             mType = copy.mType;
1585             mContainer = copy.mContainer;
1586             mBounds = copy.mBounds;
1587             mIncludingParents = copy.mIncludingParents;
1588             mReparent = copy.mReparent;
1589             mInsetsFrameProvider = copy.mInsetsFrameProvider;
1590             mInsetsFrameOwner = copy.mInsetsFrameOwner;
1591             mToTop = copy.mToTop;
1592             mReparentTopOnly = copy.mReparentTopOnly;
1593             mWindowingModes = copy.mWindowingModes;
1594             mActivityTypes = copy.mActivityTypes;
1595             mLaunchOptions = copy.mLaunchOptions;
1596             mActivityIntent = copy.mActivityIntent;
1597             mTaskFragmentOperation = copy.mTaskFragmentOperation;
1598             mPendingIntent = copy.mPendingIntent;
1599             mShortcutInfo = copy.mShortcutInfo;
1600             mAlwaysOnTop = copy.mAlwaysOnTop;
1601             mReparentLeafTaskIfRelaunch = copy.mReparentLeafTaskIfRelaunch;
1602         }
1603 
HierarchyOp(Parcel in)1604         protected HierarchyOp(Parcel in) {
1605             mType = in.readInt();
1606             mContainer = in.readStrongBinder();
1607             mBounds = in.readTypedObject(Rect.CREATOR);
1608             mIncludingParents = in.readBoolean();
1609             mReparent = in.readStrongBinder();
1610             mInsetsFrameProvider = in.readTypedObject(InsetsFrameProvider.CREATOR);
1611             mInsetsFrameOwner = in.readStrongBinder();
1612             mToTop = in.readBoolean();
1613             mReparentTopOnly = in.readBoolean();
1614             mWindowingModes = in.createIntArray();
1615             mActivityTypes = in.createIntArray();
1616             mLaunchOptions = in.readBundle();
1617             mActivityIntent = in.readTypedObject(Intent.CREATOR);
1618             mTaskFragmentOperation = in.readTypedObject(TaskFragmentOperation.CREATOR);
1619             mPendingIntent = in.readTypedObject(PendingIntent.CREATOR);
1620             mShortcutInfo = in.readTypedObject(ShortcutInfo.CREATOR);
1621             mAlwaysOnTop = in.readBoolean();
1622             mReparentLeafTaskIfRelaunch = in.readBoolean();
1623         }
1624 
getType()1625         public int getType() {
1626             return mType;
1627         }
1628 
isReparent()1629         public boolean isReparent() {
1630             return mType == HIERARCHY_OP_TYPE_REPARENT;
1631         }
1632 
1633         @Nullable
getNewParent()1634         public IBinder getNewParent() {
1635             return mReparent;
1636         }
1637 
1638         @Nullable
getInsetsFrameProvider()1639         public InsetsFrameProvider getInsetsFrameProvider() {
1640             return mInsetsFrameProvider;
1641         }
1642 
1643         @Nullable
getInsetsFrameOwner()1644         public IBinder getInsetsFrameOwner() {
1645             return mInsetsFrameOwner;
1646         }
1647 
1648         @NonNull
getContainer()1649         public IBinder getContainer() {
1650             return mContainer;
1651         }
1652 
1653         @NonNull
getAdjacentRoot()1654         public IBinder getAdjacentRoot() {
1655             return mReparent;
1656         }
1657 
getToTop()1658         public boolean getToTop() {
1659             return mToTop;
1660         }
1661 
getReparentTopOnly()1662         public boolean getReparentTopOnly() {
1663             return mReparentTopOnly;
1664         }
1665 
getWindowingModes()1666         public int[] getWindowingModes() {
1667             return mWindowingModes;
1668         }
1669 
getActivityTypes()1670         public int[] getActivityTypes() {
1671             return mActivityTypes;
1672         }
1673 
1674         @Nullable
getLaunchOptions()1675         public Bundle getLaunchOptions() {
1676             return mLaunchOptions;
1677         }
1678 
1679         @Nullable
getActivityIntent()1680         public Intent getActivityIntent() {
1681             return mActivityIntent;
1682         }
1683 
isAlwaysOnTop()1684         public boolean isAlwaysOnTop() {
1685             return mAlwaysOnTop;
1686         }
1687 
isReparentLeafTaskIfRelaunch()1688         public boolean isReparentLeafTaskIfRelaunch() {
1689             return mReparentLeafTaskIfRelaunch;
1690         }
1691 
1692         @Nullable
getTaskFragmentOperation()1693         public TaskFragmentOperation getTaskFragmentOperation() {
1694             return mTaskFragmentOperation;
1695         }
1696 
1697         @Nullable
getPendingIntent()1698         public PendingIntent getPendingIntent() {
1699             return mPendingIntent;
1700         }
1701 
1702         @Nullable
getShortcutInfo()1703         public ShortcutInfo getShortcutInfo() {
1704             return mShortcutInfo;
1705         }
1706 
1707         @NonNull
getBounds()1708         public Rect getBounds() {
1709             return mBounds;
1710         }
1711 
1712         /** Denotes whether the parents should also be included in the op. */
1713         @NonNull
includingParents()1714         public boolean includingParents() {
1715             return mIncludingParents;
1716         }
1717 
1718         /** Gets a string representation of a hierarchy-op type. */
hopToString(int type)1719         public static String hopToString(int type) {
1720             switch (type) {
1721                 case HIERARCHY_OP_TYPE_REPARENT: return "reparent";
1722                 case HIERARCHY_OP_TYPE_REORDER: return "reorder";
1723                 case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT: return "ChildrenTasksReparent";
1724                 case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: return "SetLaunchRoot";
1725                 case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS: return "SetAdjacentRoot";
1726                 case HIERARCHY_OP_TYPE_LAUNCH_TASK: return "LaunchTask";
1727                 case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT: return "SetAdjacentFlagRoot";
1728                 case HIERARCHY_OP_TYPE_PENDING_INTENT: return "PendingIntent";
1729                 case HIERARCHY_OP_TYPE_START_SHORTCUT: return "StartShortcut";
1730                 case HIERARCHY_OP_TYPE_ADD_INSETS_FRAME_PROVIDER: return "addInsetsFrameProvider";
1731                 case HIERARCHY_OP_TYPE_REMOVE_INSETS_FRAME_PROVIDER:
1732                     return "removeInsetsFrameProvider";
1733                 case HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP: return "setAlwaysOnTop";
1734                 case HIERARCHY_OP_TYPE_REMOVE_TASK: return "RemoveTask";
1735                 case HIERARCHY_OP_TYPE_FINISH_ACTIVITY: return "finishActivity";
1736                 case HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS: return "ClearAdjacentRoot";
1737                 case HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH:
1738                     return "setReparentLeafTaskIfRelaunch";
1739                 case HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION:
1740                     return "addTaskFragmentOperation";
1741                 default: return "HOP(" + type + ")";
1742             }
1743         }
1744 
1745         @Override
toString()1746         public String toString() {
1747             StringBuilder sb = new StringBuilder();
1748             sb.append("{").append(hopToString(mType)).append(": ");
1749             switch (mType) {
1750                 case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT:
1751                     sb.append("from=").append(mContainer).append(" to=").append(mReparent)
1752                             .append(" mToTop=").append(mToTop)
1753                             .append(" mReparentTopOnly=").append(mReparentTopOnly)
1754                             .append(" mWindowingMode=").append(Arrays.toString(mWindowingModes))
1755                             .append(" mActivityType=").append(Arrays.toString(mActivityTypes));
1756                     break;
1757                 case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT:
1758                     sb.append("container=").append(mContainer)
1759                             .append(" mWindowingMode=").append(Arrays.toString(mWindowingModes))
1760                             .append(" mActivityType=").append(Arrays.toString(mActivityTypes));
1761                     break;
1762                 case HIERARCHY_OP_TYPE_REPARENT:
1763                     sb.append(mContainer).append(" to ").append(mToTop ? "top of " : "bottom of ")
1764                             .append(mReparent);
1765                     break;
1766                 case HIERARCHY_OP_TYPE_REORDER:
1767                     sb.append(mContainer).append(" to ").append(mToTop ? "top" : "bottom");
1768                     break;
1769                 case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS:
1770                     sb.append("container=").append(mContainer)
1771                             .append(" adjacentRoot=").append(mReparent);
1772                     break;
1773                 case HIERARCHY_OP_TYPE_LAUNCH_TASK:
1774                     sb.append(mLaunchOptions);
1775                     break;
1776                 case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT:
1777                     sb.append("container=").append(mContainer).append(" clearRoot=").append(mToTop);
1778                     break;
1779                 case HIERARCHY_OP_TYPE_START_SHORTCUT:
1780                     sb.append("options=").append(mLaunchOptions)
1781                             .append(" info=").append(mShortcutInfo);
1782                     break;
1783                 case HIERARCHY_OP_TYPE_PENDING_INTENT:
1784                     sb.append("options=").append(mLaunchOptions);
1785                     break;
1786                 case HIERARCHY_OP_TYPE_ADD_INSETS_FRAME_PROVIDER:
1787                 case HIERARCHY_OP_TYPE_REMOVE_INSETS_FRAME_PROVIDER:
1788                     sb.append("container=").append(mContainer)
1789                             .append(" provider=").append(mInsetsFrameProvider)
1790                             .append(" owner=").append(mInsetsFrameOwner);
1791                     break;
1792                 case HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP:
1793                     sb.append("container=").append(mContainer)
1794                             .append(" alwaysOnTop=").append(mAlwaysOnTop);
1795                     break;
1796                 case HIERARCHY_OP_TYPE_REMOVE_TASK:
1797                     sb.append("task=").append(mContainer);
1798                     break;
1799                 case HIERARCHY_OP_TYPE_FINISH_ACTIVITY:
1800                     sb.append("activity=").append(mContainer);
1801                     break;
1802                 case HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS:
1803                     sb.append("container=").append(mContainer);
1804                     break;
1805                 case HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH:
1806                     sb.append("container= ").append(mContainer)
1807                             .append(" reparentLeafTaskIfRelaunch= ")
1808                             .append(mReparentLeafTaskIfRelaunch);
1809                     break;
1810                 case HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION:
1811                     sb.append("fragmentToken= ").append(mContainer)
1812                             .append(" operation= ").append(mTaskFragmentOperation);
1813                     break;
1814                 default:
1815                     sb.append("container=").append(mContainer)
1816                             .append(" reparent=").append(mReparent)
1817                             .append(" mToTop=").append(mToTop)
1818                             .append(" mWindowingMode=").append(Arrays.toString(mWindowingModes))
1819                             .append(" mActivityType=").append(Arrays.toString(mActivityTypes));
1820             }
1821             return sb.append("}").toString();
1822         }
1823 
1824         @Override
writeToParcel(Parcel dest, int flags)1825         public void writeToParcel(Parcel dest, int flags) {
1826             dest.writeInt(mType);
1827             dest.writeStrongBinder(mContainer);
1828             dest.writeTypedObject(mBounds, flags);
1829             dest.writeBoolean(mIncludingParents);
1830             dest.writeStrongBinder(mReparent);
1831             dest.writeTypedObject(mInsetsFrameProvider, flags);
1832             dest.writeStrongBinder(mInsetsFrameOwner);
1833             dest.writeBoolean(mToTop);
1834             dest.writeBoolean(mReparentTopOnly);
1835             dest.writeIntArray(mWindowingModes);
1836             dest.writeIntArray(mActivityTypes);
1837             dest.writeBundle(mLaunchOptions);
1838             dest.writeTypedObject(mActivityIntent, flags);
1839             dest.writeTypedObject(mTaskFragmentOperation, flags);
1840             dest.writeTypedObject(mPendingIntent, flags);
1841             dest.writeTypedObject(mShortcutInfo, flags);
1842             dest.writeBoolean(mAlwaysOnTop);
1843             dest.writeBoolean(mReparentLeafTaskIfRelaunch);
1844         }
1845 
1846         @Override
describeContents()1847         public int describeContents() {
1848             return 0;
1849         }
1850 
1851         public static final Creator<HierarchyOp> CREATOR = new Creator<HierarchyOp>() {
1852             @Override
1853             public HierarchyOp createFromParcel(Parcel in) {
1854                 return new HierarchyOp(in);
1855             }
1856 
1857             @Override
1858             public HierarchyOp[] newArray(int size) {
1859                 return new HierarchyOp[size];
1860             }
1861         };
1862 
1863         private static class Builder {
1864 
1865             private final int mType;
1866 
1867             @Nullable
1868             private IBinder mContainer;
1869 
1870             @Nullable
1871             private IBinder mReparent;
1872 
1873             @Nullable
1874             private InsetsFrameProvider mInsetsFrameProvider;
1875 
1876             @Nullable
1877             private IBinder mInsetsFrameOwner;
1878 
1879             private boolean mToTop;
1880 
1881             private boolean mReparentTopOnly;
1882 
1883             @Nullable
1884             private int[]  mWindowingModes;
1885 
1886             @Nullable
1887             private int[] mActivityTypes;
1888 
1889             @Nullable
1890             private Bundle mLaunchOptions;
1891 
1892             @Nullable
1893             private Intent mActivityIntent;
1894 
1895             @Nullable
1896             private TaskFragmentOperation mTaskFragmentOperation;
1897 
1898             @Nullable
1899             private PendingIntent mPendingIntent;
1900 
1901             @Nullable
1902             private ShortcutInfo mShortcutInfo;
1903 
1904             @Nullable
1905             private Rect mBounds;
1906 
1907             private boolean mIncludingParents;
1908 
1909             private boolean mAlwaysOnTop;
1910 
1911             private boolean mReparentLeafTaskIfRelaunch;
1912 
Builder(int type)1913             Builder(int type) {
1914                 mType = type;
1915             }
1916 
setContainer(@ullable IBinder container)1917             Builder setContainer(@Nullable IBinder container) {
1918                 mContainer = container;
1919                 return this;
1920             }
1921 
setReparentContainer(@ullable IBinder reparentContainer)1922             Builder setReparentContainer(@Nullable IBinder reparentContainer) {
1923                 mReparent = reparentContainer;
1924                 return this;
1925             }
1926 
setInsetsFrameProvider(InsetsFrameProvider provider)1927             Builder setInsetsFrameProvider(InsetsFrameProvider provider) {
1928                 mInsetsFrameProvider = provider;
1929                 return this;
1930             }
1931 
setInsetsFrameOwner(IBinder owner)1932             Builder setInsetsFrameOwner(IBinder owner) {
1933                 mInsetsFrameOwner = owner;
1934                 return this;
1935             }
1936 
setToTop(boolean toTop)1937             Builder setToTop(boolean toTop) {
1938                 mToTop = toTop;
1939                 return this;
1940             }
1941 
setReparentTopOnly(boolean reparentTopOnly)1942             Builder setReparentTopOnly(boolean reparentTopOnly) {
1943                 mReparentTopOnly = reparentTopOnly;
1944                 return this;
1945             }
1946 
setWindowingModes(@ullable int[] windowingModes)1947             Builder setWindowingModes(@Nullable int[] windowingModes) {
1948                 mWindowingModes = windowingModes;
1949                 return this;
1950             }
1951 
setActivityTypes(@ullable int[] activityTypes)1952             Builder setActivityTypes(@Nullable int[] activityTypes) {
1953                 mActivityTypes = activityTypes;
1954                 return this;
1955             }
1956 
setLaunchOptions(@ullable Bundle launchOptions)1957             Builder setLaunchOptions(@Nullable Bundle launchOptions) {
1958                 mLaunchOptions = launchOptions;
1959                 return this;
1960             }
1961 
setActivityIntent(@ullable Intent activityIntent)1962             Builder setActivityIntent(@Nullable Intent activityIntent) {
1963                 mActivityIntent = activityIntent;
1964                 return this;
1965             }
1966 
setPendingIntent(@ullable PendingIntent sender)1967             Builder setPendingIntent(@Nullable PendingIntent sender) {
1968                 mPendingIntent = sender;
1969                 return this;
1970             }
1971 
setAlwaysOnTop(boolean alwaysOnTop)1972             Builder setAlwaysOnTop(boolean alwaysOnTop) {
1973                 mAlwaysOnTop = alwaysOnTop;
1974                 return this;
1975             }
1976 
setTaskFragmentOperation( @ullable TaskFragmentOperation taskFragmentOperation)1977             Builder setTaskFragmentOperation(
1978                     @Nullable TaskFragmentOperation taskFragmentOperation) {
1979                 mTaskFragmentOperation = taskFragmentOperation;
1980                 return this;
1981             }
1982 
setReparentLeafTaskIfRelaunch(boolean reparentLeafTaskIfRelaunch)1983             Builder setReparentLeafTaskIfRelaunch(boolean reparentLeafTaskIfRelaunch) {
1984                 mReparentLeafTaskIfRelaunch = reparentLeafTaskIfRelaunch;
1985                 return this;
1986             }
1987 
setShortcutInfo(@ullable ShortcutInfo shortcutInfo)1988             Builder setShortcutInfo(@Nullable ShortcutInfo shortcutInfo) {
1989                 mShortcutInfo = shortcutInfo;
1990                 return this;
1991             }
1992 
setBounds(@onNull Rect bounds)1993             Builder setBounds(@NonNull Rect bounds) {
1994                 mBounds = bounds;
1995                 return this;
1996             }
1997 
setIncludingParents(boolean value)1998             Builder setIncludingParents(boolean value) {
1999                 mIncludingParents = value;
2000                 return this;
2001             }
2002 
build()2003             HierarchyOp build() {
2004                 final HierarchyOp hierarchyOp = new HierarchyOp(mType);
2005                 hierarchyOp.mContainer = mContainer;
2006                 hierarchyOp.mReparent = mReparent;
2007                 hierarchyOp.mWindowingModes = mWindowingModes != null
2008                         ? Arrays.copyOf(mWindowingModes, mWindowingModes.length)
2009                         : null;
2010                 hierarchyOp.mActivityTypes = mActivityTypes != null
2011                         ? Arrays.copyOf(mActivityTypes, mActivityTypes.length)
2012                         : null;
2013                 hierarchyOp.mInsetsFrameProvider = mInsetsFrameProvider;
2014                 hierarchyOp.mInsetsFrameOwner = mInsetsFrameOwner;
2015                 hierarchyOp.mToTop = mToTop;
2016                 hierarchyOp.mReparentTopOnly = mReparentTopOnly;
2017                 hierarchyOp.mLaunchOptions = mLaunchOptions;
2018                 hierarchyOp.mActivityIntent = mActivityIntent;
2019                 hierarchyOp.mPendingIntent = mPendingIntent;
2020                 hierarchyOp.mAlwaysOnTop = mAlwaysOnTop;
2021                 hierarchyOp.mTaskFragmentOperation = mTaskFragmentOperation;
2022                 hierarchyOp.mShortcutInfo = mShortcutInfo;
2023                 hierarchyOp.mBounds = mBounds;
2024                 hierarchyOp.mIncludingParents = mIncludingParents;
2025                 hierarchyOp.mReparentLeafTaskIfRelaunch = mReparentLeafTaskIfRelaunch;
2026 
2027                 return hierarchyOp;
2028             }
2029         }
2030     }
2031 
2032     /**
2033      * Helper class for building an options Bundle that can be used to set adjacent rules of
2034      * TaskFragments.
2035      */
2036     public static class TaskFragmentAdjacentParams {
2037         private static final String DELAY_PRIMARY_LAST_ACTIVITY_REMOVAL =
2038                 "android:transaction.adjacent.option.delay_primary_removal";
2039         private static final String DELAY_SECONDARY_LAST_ACTIVITY_REMOVAL =
2040                 "android:transaction.adjacent.option.delay_secondary_removal";
2041 
2042         private boolean mDelayPrimaryLastActivityRemoval;
2043         private boolean mDelaySecondaryLastActivityRemoval;
2044 
TaskFragmentAdjacentParams()2045         public TaskFragmentAdjacentParams() {
2046         }
2047 
TaskFragmentAdjacentParams(@onNull Bundle bundle)2048         public TaskFragmentAdjacentParams(@NonNull Bundle bundle) {
2049             mDelayPrimaryLastActivityRemoval = bundle.getBoolean(
2050                     DELAY_PRIMARY_LAST_ACTIVITY_REMOVAL);
2051             mDelaySecondaryLastActivityRemoval = bundle.getBoolean(
2052                     DELAY_SECONDARY_LAST_ACTIVITY_REMOVAL);
2053         }
2054 
2055         /** @see #shouldDelayPrimaryLastActivityRemoval() */
setShouldDelayPrimaryLastActivityRemoval(boolean delay)2056         public void setShouldDelayPrimaryLastActivityRemoval(boolean delay) {
2057             mDelayPrimaryLastActivityRemoval = delay;
2058         }
2059 
2060         /** @see #shouldDelaySecondaryLastActivityRemoval() */
setShouldDelaySecondaryLastActivityRemoval(boolean delay)2061         public void setShouldDelaySecondaryLastActivityRemoval(boolean delay) {
2062             mDelaySecondaryLastActivityRemoval = delay;
2063         }
2064 
2065         /**
2066          * Whether to delay the last activity of the primary adjacent TaskFragment being immediately
2067          * removed while finishing.
2068          * <p>
2069          * It is usually set to {@code true} to give organizer an opportunity to perform other
2070          * actions or animations. An example is to finish together with the adjacent TaskFragment.
2071          * </p>
2072          */
shouldDelayPrimaryLastActivityRemoval()2073         public boolean shouldDelayPrimaryLastActivityRemoval() {
2074             return mDelayPrimaryLastActivityRemoval;
2075         }
2076 
2077         /**
2078          * Similar to {@link #shouldDelayPrimaryLastActivityRemoval()}, but for the secondary
2079          * TaskFragment.
2080          */
shouldDelaySecondaryLastActivityRemoval()2081         public boolean shouldDelaySecondaryLastActivityRemoval() {
2082             return mDelaySecondaryLastActivityRemoval;
2083         }
2084 
toBundle()2085         Bundle toBundle() {
2086             final Bundle b = new Bundle();
2087             b.putBoolean(DELAY_PRIMARY_LAST_ACTIVITY_REMOVAL, mDelayPrimaryLastActivityRemoval);
2088             b.putBoolean(DELAY_SECONDARY_LAST_ACTIVITY_REMOVAL, mDelaySecondaryLastActivityRemoval);
2089             return b;
2090         }
2091     }
2092 }
2093