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