• 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 static android.app.Instrumentation.DEBUG_START_ACTIVITY;
20 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
21 import static android.window.TaskFragmentOperation.OP_TYPE_CLEAR_ADJACENT_TASK_FRAGMENTS;
22 import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_TASK_FRAGMENT;
23 import static android.window.TaskFragmentOperation.OP_TYPE_DELETE_TASK_FRAGMENT;
24 import static android.window.TaskFragmentOperation.OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
25 import static android.window.TaskFragmentOperation.OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT;
26 import static android.window.TaskFragmentOperation.OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS;
27 import static android.window.TaskFragmentOperation.OP_TYPE_SET_COMPANION_TASK_FRAGMENT;
28 import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
29 
30 import android.annotation.FlaggedApi;
31 import android.annotation.IntDef;
32 import android.annotation.NonNull;
33 import android.annotation.Nullable;
34 import android.annotation.SuppressLint;
35 import android.annotation.TestApi;
36 import android.app.Instrumentation;
37 import android.app.PendingIntent;
38 import android.app.WindowConfiguration;
39 import android.app.WindowConfiguration.WindowingMode;
40 import android.content.Intent;
41 import android.content.pm.ActivityInfo;
42 import android.content.pm.ShortcutInfo;
43 import android.content.res.Configuration;
44 import android.graphics.Rect;
45 import android.os.Bundle;
46 import android.os.IBinder;
47 import android.os.Parcel;
48 import android.os.Parcelable;
49 import android.util.ArrayMap;
50 import android.util.Log;
51 import android.view.InsetsFrameProvider;
52 import android.view.InsetsSource;
53 import android.view.SurfaceControl;
54 import android.view.WindowInsets;
55 import android.view.WindowInsets.Type.InsetsType;
56 
57 import com.android.window.flags.Flags;
58 
59 import java.lang.annotation.Retention;
60 import java.lang.annotation.RetentionPolicy;
61 import java.util.ArrayList;
62 import java.util.Arrays;
63 import java.util.List;
64 import java.util.Map;
65 import java.util.Objects;
66 
67 /**
68  * Represents a collection of operations on some WindowContainers that should be applied all at
69  * once.
70  *
71  * @hide
72  */
73 @TestApi
74 public final class WindowContainerTransaction implements Parcelable {
75     private final ArrayMap<IBinder, Change> mChanges = new ArrayMap<>();
76 
77     // Flat list because re-order operations are order-dependent
78     private final ArrayList<HierarchyOp> mHierarchyOps = new ArrayList<>();
79 
80     @Nullable
81     private IBinder mErrorCallbackToken;
82 
83     @Nullable
84     private ITaskFragmentOrganizer mTaskFragmentOrganizer;
85 
WindowContainerTransaction()86     public WindowContainerTransaction() {}
87 
WindowContainerTransaction(@onNull Parcel in)88     private WindowContainerTransaction(@NonNull Parcel in) {
89         in.readMap(mChanges, null /* loader */);
90         in.readTypedList(mHierarchyOps, HierarchyOp.CREATOR);
91         mErrorCallbackToken = in.readStrongBinder();
92         mTaskFragmentOrganizer = ITaskFragmentOrganizer.Stub.asInterface(in.readStrongBinder());
93     }
94 
95     @NonNull
getOrCreateChange(IBinder token)96     private Change getOrCreateChange(IBinder token) {
97         Change out = mChanges.get(token);
98         if (out == null) {
99             out = new Change();
100             mChanges.put(token, out);
101         }
102         return out;
103     }
104 
105     /**
106      * Clear the transaction object.
107      * This is equivalent to a new empty {@link WindowContainerTransaction} in content.
108      *
109      * @hide
110      */
clear()111     public void clear() {
112         mChanges.clear();
113         mHierarchyOps.clear();
114         mErrorCallbackToken = null;
115         mTaskFragmentOrganizer = null;
116     }
117 
118     /*
119      * ===========================================================================================
120      * Window container properties
121      * ===========================================================================================
122      */
123 
124     /**
125      * Resize a container.
126      */
127     @NonNull
setBounds( @onNull WindowContainerToken container, @NonNull Rect bounds)128     public WindowContainerTransaction setBounds(
129             @NonNull WindowContainerToken container, @NonNull Rect bounds) {
130         final Change chg = getOrCreateChange(container.asBinder());
131         chg.mConfiguration.windowConfiguration.setBounds(bounds);
132         chg.mConfigSetMask |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
133         chg.mWindowSetMask |= WindowConfiguration.WINDOW_CONFIG_BOUNDS;
134         return this;
135     }
136 
137     /**
138      * Resize a container's app bounds. This is the bounds used to report appWidth/Height to an
139      * app's DisplayInfo. It is derived by subtracting the overlapping portion of the navbar from
140      * the full bounds.
141      */
142     @NonNull
setAppBounds( @onNull WindowContainerToken container, @NonNull Rect appBounds)143     public WindowContainerTransaction setAppBounds(
144             @NonNull WindowContainerToken container, @NonNull Rect appBounds) {
145         final Change chg = getOrCreateChange(container.asBinder());
146         chg.mConfiguration.windowConfiguration.setAppBounds(appBounds);
147         chg.mConfigSetMask |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
148         chg.mWindowSetMask |= WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS;
149         return this;
150     }
151 
152     /**
153      * Resize a container's configuration size. The configuration size is what gets reported to the
154      * app via screenWidth/HeightDp and influences which resources get loaded. This size is
155      * derived by subtracting the overlapping portions of both the statusbar and the navbar from
156      * the full bounds.
157      */
158     @NonNull
setScreenSizeDp( @onNull WindowContainerToken container, int w, int h)159     public WindowContainerTransaction setScreenSizeDp(
160             @NonNull WindowContainerToken container, int w, int h) {
161         final Change chg = getOrCreateChange(container.asBinder());
162         chg.mConfiguration.screenWidthDp = w;
163         chg.mConfiguration.screenHeightDp = h;
164         chg.mConfigSetMask |= ActivityInfo.CONFIG_SCREEN_SIZE;
165         return this;
166     }
167 
168     /**
169      * Sets the densityDpi value in the configuration for the given container.
170      * @hide
171      */
172     @NonNull
setDensityDpi(@onNull WindowContainerToken container, int densityDpi)173     public WindowContainerTransaction setDensityDpi(@NonNull WindowContainerToken container,
174             int densityDpi) {
175         final Change chg = getOrCreateChange(container.asBinder());
176         chg.mConfiguration.densityDpi = densityDpi;
177         chg.mConfigSetMask |= ActivityInfo.CONFIG_DENSITY;
178         return this;
179     }
180 
181     /**
182      * Send a SurfaceControl transaction to the server, which the server will apply in sync with
183      * the next bounds change. As this uses deferred transaction and not BLAST it is only
184      * able to sync with a single window, and the first visible window in this hierarchy of type
185      * BASE_APPLICATION to resize will be used. If there are bound changes included in this
186      * WindowContainer transaction (from setBounds or scheduleFinishEnterPip), the SurfaceControl
187      * transaction will be synced with those bounds. If there are no changes, then
188      * the SurfaceControl transaction will be synced with the next bounds change. This means
189      * that you can call this, apply the WindowContainer transaction, and then later call
190      * dismissPip() to achieve synchronization.
191      */
192     @NonNull
setBoundsChangeTransaction( @onNull WindowContainerToken container, @NonNull SurfaceControl.Transaction t)193     public WindowContainerTransaction setBoundsChangeTransaction(
194             @NonNull WindowContainerToken container, @NonNull SurfaceControl.Transaction t) {
195         final Change chg = getOrCreateChange(container.asBinder());
196         chg.mBoundsChangeTransaction = t;
197         chg.mChangeMask |= Change.CHANGE_BOUNDS_TRANSACTION;
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, @WindowingMode int windowingMode)210     public WindowContainerTransaction setActivityWindowingMode(
211             @NonNull WindowContainerToken container, @WindowingMode int windowingMode) {
212         final 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, @WindowingMode int windowingMode)221     public WindowContainerTransaction setWindowingMode(
222             @NonNull WindowContainerToken container, @WindowingMode int windowingMode) {
223         final 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         final Change chg = getOrCreateChange(container.asBinder());
237         chg.mFocusable = focusable;
238         chg.mChangeMask |= Change.CHANGE_FOCUSABLE;
239         return this;
240     }
241 
242     /**
243      * Sets whether the IME insets should be excluded by {@link com.android.server.wm.InsetsPolicy}.
244      * @hide
245      */
246     @SuppressLint("UnflaggedApi")
247     @NonNull
setExcludeImeInsets( @onNull WindowContainerToken container, boolean exclude)248     public WindowContainerTransaction setExcludeImeInsets(
249             @NonNull WindowContainerToken container, boolean exclude) {
250         final HierarchyOp hierarchyOp =
251                 new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_SET_EXCLUDE_INSETS_TYPES)
252                         .setContainer(container.asBinder())
253                         .setExcludeInsetsTypes(exclude ? WindowInsets.Type.ime() : 0)
254                         .build();
255         mHierarchyOps.add(hierarchyOp);
256         return this;
257     }
258 
259     /**
260      * Sets whether a container or its children should be hidden. When {@code false}, the existing
261      * visibility of the container applies, but when {@code true} the container will be forced
262      * to be hidden.
263      */
264     @NonNull
setHidden( @onNull WindowContainerToken container, boolean hidden)265     public WindowContainerTransaction setHidden(
266             @NonNull WindowContainerToken container, boolean hidden) {
267         final Change chg = getOrCreateChange(container.asBinder());
268         chg.mHidden = hidden;
269         chg.mChangeMask |= Change.CHANGE_HIDDEN;
270         return this;
271     }
272 
273     /**
274      * Set the smallestScreenWidth of a container.
275      */
276     @NonNull
setSmallestScreenWidthDp( @onNull WindowContainerToken container, int widthDp)277     public WindowContainerTransaction setSmallestScreenWidthDp(
278             @NonNull WindowContainerToken container, int widthDp) {
279         final Change cfg = getOrCreateChange(container.asBinder());
280         cfg.mConfiguration.smallestScreenWidthDp = widthDp;
281         cfg.mConfigSetMask |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
282         return this;
283     }
284 
285     /**
286      * Sets whether a container should ignore the orientation request from apps and windows below
287      * it. It currently only applies to {@link com.android.server.wm.DisplayArea}. When
288      * {@code false}, it may rotate based on the orientation request; When {@code true}, it can
289      * never specify orientation, but shows the fixed-orientation apps below it in the letterbox.
290      * @hide
291      */
292     @NonNull
setIgnoreOrientationRequest( @onNull WindowContainerToken container, boolean ignoreOrientationRequest)293     public WindowContainerTransaction setIgnoreOrientationRequest(
294             @NonNull WindowContainerToken container, boolean ignoreOrientationRequest) {
295         final Change chg = getOrCreateChange(container.asBinder());
296         chg.mIgnoreOrientationRequest = ignoreOrientationRequest;
297         chg.mChangeMask |= Change.CHANGE_IGNORE_ORIENTATION_REQUEST;
298         return this;
299     }
300 
301     /**
302      * Sets whether a task should be translucent. When {@code false}, the existing translucent of
303      * the task applies, but when {@code true} the task will be forced to be translucent.
304      * @hide
305      */
306     @NonNull
setForceTranslucent( @onNull WindowContainerToken container, boolean forceTranslucent)307     public WindowContainerTransaction setForceTranslucent(
308             @NonNull WindowContainerToken container, boolean forceTranslucent) {
309         final Change chg = getOrCreateChange(container.asBinder());
310         chg.mForceTranslucent = forceTranslucent;
311         chg.mChangeMask |= Change.CHANGE_FORCE_TRANSLUCENT;
312         return this;
313     }
314 
315     /**
316      * Used in conjunction with a shell-transition call (usually finishTransition). This is
317      * basically a message to the transition system that a particular task should NOT go into
318      * PIP even though it normally would. This is to deal with some edge-case situations where
319      * Recents will "commit" the transition to go home, but then not actually go-home.
320      * @hide
321      */
322     @NonNull
setDoNotPip(@onNull WindowContainerToken container)323     public WindowContainerTransaction setDoNotPip(@NonNull WindowContainerToken container) {
324         final Change chg = getOrCreateChange(container.asBinder());
325         chg.mChangeMask |= Change.CHANGE_FORCE_NO_PIP;
326         return this;
327     }
328 
329     /**
330      * Resizes a container by providing a bounds in its parent coordinate.
331      * This is only used by {@link TaskFragmentOrganizer}.
332      */
333     @NonNull
setRelativeBounds( @onNull WindowContainerToken container, @NonNull Rect relBounds)334     public WindowContainerTransaction setRelativeBounds(
335             @NonNull WindowContainerToken container, @NonNull Rect relBounds) {
336         final Change chg = getOrCreateChange(container.asBinder());
337         if (chg.mRelativeBounds == null) {
338             chg.mRelativeBounds = new Rect();
339         }
340         chg.mRelativeBounds.set(relBounds);
341         chg.mChangeMask |= Change.CHANGE_RELATIVE_BOUNDS;
342         // Bounds will be overridden.
343         chg.mConfigSetMask |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
344         chg.mWindowSetMask |= WindowConfiguration.WINDOW_CONFIG_BOUNDS;
345         return this;
346     }
347 
348     /**
349      * Sets whether a container is being drag-resized.
350      * When {@code true}, the client will reuse a single (larger) surface size to avoid
351      * continuous allocations on every size change.
352      *
353      * @param container WindowContainerToken of the task that changed its drag resizing state
354      * @hide
355      */
356     @NonNull
setDragResizing(@onNull WindowContainerToken container, boolean dragResizing)357     public WindowContainerTransaction setDragResizing(@NonNull WindowContainerToken container,
358             boolean dragResizing) {
359         final Change change = getOrCreateChange(container.asBinder());
360         change.mChangeMask |= Change.CHANGE_DRAG_RESIZING;
361         change.mDragResizing = dragResizing;
362         return this;
363     }
364 
365     /**
366      * Sets/removes the always on top flag for this {@code windowContainer}. See
367      * {@link com.android.server.wm.ConfigurationContainer#setAlwaysOnTop(boolean)}.
368      * Please note that this method is only intended to be used for a
369      * {@link com.android.server.wm.Task} or {@link com.android.server.wm.DisplayArea}.
370      *
371      * <p>
372      *     Setting always on top to {@code True} will also make the {@code windowContainer} to move
373      *     to the top.
374      * </p>
375      * <p>
376      *     Setting always on top to {@code False} will make this {@code windowContainer} to move
377      *     below the other always on top sibling containers.
378      * </p>
379      *
380      * @param windowContainer the container which the flag need to be updated for.
381      * @param alwaysOnTop denotes whether or not always on top flag should be set.
382      * @hide
383      */
384     @NonNull
setAlwaysOnTop( @onNull WindowContainerToken windowContainer, boolean alwaysOnTop)385     public WindowContainerTransaction setAlwaysOnTop(
386             @NonNull WindowContainerToken windowContainer, boolean alwaysOnTop) {
387         final HierarchyOp hierarchyOp =
388                 new HierarchyOp.Builder(
389                         HierarchyOp.HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP)
390                         .setContainer(windowContainer.asBinder())
391                         .setAlwaysOnTop(alwaysOnTop)
392                         .build();
393         mHierarchyOps.add(hierarchyOp);
394         return this;
395     }
396 
397     /**
398      * Sets/removes the reparent leaf task flag for this {@code windowContainer}.
399      * When this is set, the server side will try to reparent the leaf task to task display area
400      * if there is an existing activity in history during the activity launch. This operation only
401      * support on the organized root task.
402      * @hide
403      */
404     @NonNull
setReparentLeafTaskIfRelaunch( @onNull WindowContainerToken windowContainer, boolean reparentLeafTaskIfRelaunch)405     public WindowContainerTransaction setReparentLeafTaskIfRelaunch(
406             @NonNull WindowContainerToken windowContainer, boolean reparentLeafTaskIfRelaunch) {
407         final HierarchyOp hierarchyOp =
408                 new HierarchyOp.Builder(
409                         HierarchyOp.HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH)
410                         .setContainer(windowContainer.asBinder())
411                         .setReparentLeafTaskIfRelaunch(reparentLeafTaskIfRelaunch)
412                         .build();
413         mHierarchyOps.add(hierarchyOp);
414         return this;
415     }
416 
417     /**
418      * Defers client-facing configuration changes for activities in `container` until the end of
419      * the transition animation. The configuration will still be applied to the WMCore hierarchy
420      * at the normal time (beginning); so, special consideration must be made for this in the
421      * animation.
422      *
423      * @param container WindowContainerToken who's children should defer config notification.
424      * @hide
425      */
426     @NonNull
deferConfigToTransitionEnd( @onNull WindowContainerToken container)427     public WindowContainerTransaction deferConfigToTransitionEnd(
428             @NonNull WindowContainerToken container) {
429         final Change change = getOrCreateChange(container.asBinder());
430         change.mConfigAtTransitionEnd = true;
431         return this;
432     }
433 
434     /**
435      * Sets the task as trimmable or not. This can be used to prevent the task from being trimmed by
436      * recents. This attribute is set to true on task creation by default.
437      *
438      * @param isTrimmableFromRecents When {@code true}, task is set as trimmable from recents.
439      * @hide
440      */
441     @NonNull
setTaskTrimmableFromRecents( @onNull WindowContainerToken container, boolean isTrimmableFromRecents)442     public WindowContainerTransaction setTaskTrimmableFromRecents(
443             @NonNull WindowContainerToken container,
444             boolean isTrimmableFromRecents) {
445         mHierarchyOps.add(
446                 HierarchyOp.createForSetTaskTrimmableFromRecents(container.asBinder(),
447                         isTrimmableFromRecents));
448         return this;
449     }
450 
451     /**
452      * Sets a given safe region {@code Rect} on the {@code container}. Set {@code null} to reset
453      * safe region bounds. When a safe region is set on a WindowContainer, the activities which
454      * need to be within a safe region will be letterboxed within the set safe region bounds.
455      * <p>Note that if the position of the WindowContainer changes, the caller needs to update the
456      * safe region bounds.
457      *
458      * @param container        The window container that the safe region bounds are set on
459      * @param safeRegionBounds The rect for the safe region bounds which are absolute in nature.
460      * @hide
461      */
462     @NonNull
463     @FlaggedApi(Flags.FLAG_SAFE_REGION_LETTERBOXING)
setSafeRegionBounds( @onNull WindowContainerToken container, @Nullable Rect safeRegionBounds)464     public WindowContainerTransaction setSafeRegionBounds(
465             @NonNull WindowContainerToken container,
466             @Nullable Rect safeRegionBounds) {
467         mHierarchyOps.add(
468                 HierarchyOp.createForSetSafeRegionBounds(container.asBinder(), safeRegionBounds));
469         return this;
470     }
471 
472     /*
473      * ===========================================================================================
474      * Hierarchy updates (create/destroy/reorder/reparent containers)
475      * ===========================================================================================
476      */
477 
478     /**
479      * Reorders a container within its parent.
480      *
481      * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to
482      *              the bottom.
483      */
484     @NonNull
reorder(@onNull WindowContainerToken child, boolean onTop)485     public WindowContainerTransaction reorder(@NonNull WindowContainerToken child, boolean onTop) {
486         return reorder(child, onTop, false /* includingParents */);
487     }
488 
489     /**
490      * Reorders a container within its parent with an option to reorder all the parents in the
491      * hierarchy above among their respective siblings.
492      *
493      * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to
494      *              the bottom.
495      * @param includingParents When {@code true}, all the parents in the hierarchy above are also
496      *                         reordered among their respective siblings.
497      * @hide
498      */
499     @NonNull
reorder(@onNull WindowContainerToken child, boolean onTop, boolean includingParents)500     public WindowContainerTransaction reorder(@NonNull WindowContainerToken child, boolean onTop,
501             boolean includingParents) {
502         mHierarchyOps.add(HierarchyOp.createForReorder(child.asBinder(), onTop, includingParents));
503         return this;
504     }
505 
506     /**
507      * Reparents a container into another one. The effect of a {@code null} parent can vary. For
508      * example, reparenting a stack to {@code null} will reparent it to its display.
509      *
510      * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to
511      *              the bottom.
512      */
513     @NonNull
reparent(@onNull WindowContainerToken child, @Nullable WindowContainerToken parent, boolean onTop)514     public WindowContainerTransaction reparent(@NonNull WindowContainerToken child,
515             @Nullable WindowContainerToken parent, boolean onTop) {
516         mHierarchyOps.add(HierarchyOp.createForReparent(child.asBinder(),
517                 parent == null ? null : parent.asBinder(),
518                 onTop));
519         return this;
520     }
521 
522     /**
523      * Reparent's all children tasks or the top task of {@param currentParent} in the specified
524      * {@param windowingMode} and {@param activityType} to {@param newParent} in their current
525      * z-order.
526      *
527      * @param currentParent of the tasks to perform the operation no.
528      *                      {@code null} will perform the operation on the display.
529      * @param newParent for the tasks. {@code null} will perform the operation on the display.
530      * @param windowingModes of the tasks to reparent.
531      * @param activityTypes of the tasks to reparent.
532      * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to
533      *              the bottom.
534      * @param reparentTopOnly When {@code true}, only reparent the top task which fit windowingModes
535      *                        and activityTypes.
536      * @hide
537      */
538     @NonNull
reparentTasks(@ullable WindowContainerToken currentParent, @Nullable WindowContainerToken newParent, @Nullable int[] windowingModes, @Nullable int[] activityTypes, boolean onTop, boolean reparentTopOnly)539     public WindowContainerTransaction reparentTasks(@Nullable WindowContainerToken currentParent,
540             @Nullable WindowContainerToken newParent, @Nullable int[] windowingModes,
541             @Nullable int[] activityTypes, boolean onTop, boolean reparentTopOnly) {
542         mHierarchyOps.add(HierarchyOp.createForChildrenTasksReparent(
543                 currentParent != null ? currentParent.asBinder() : null,
544                 newParent != null ? newParent.asBinder() : null,
545                 windowingModes,
546                 activityTypes,
547                 onTop,
548                 reparentTopOnly));
549         return this;
550     }
551 
552     /**
553      * Reparent's all children tasks of {@param currentParent} in the specified
554      * {@param windowingMode} and {@param activityType} to {@param newParent} in their current
555      * z-order.
556      *
557      * @param currentParent of the tasks to perform the operation no.
558      *                      {@code null} will perform the operation on the display.
559      * @param newParent for the tasks. {@code null} will perform the operation on the display.
560      * @param windowingModes of the tasks to reparent. {@code null} ignore this attribute when
561      *                       perform the operation.
562      * @param activityTypes of the tasks to reparent.  {@code null} ignore this attribute when
563      *                      perform the operation.
564      * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to
565      *              the bottom.
566      */
567     @NonNull
reparentTasks(@ullable WindowContainerToken currentParent, @Nullable WindowContainerToken newParent, @Nullable int[] windowingModes, @Nullable int[] activityTypes, boolean onTop)568     public WindowContainerTransaction reparentTasks(@Nullable WindowContainerToken currentParent,
569             @Nullable WindowContainerToken newParent, @Nullable int[] windowingModes,
570             @Nullable int[] activityTypes, boolean onTop) {
571         return reparentTasks(currentParent, newParent, windowingModes, activityTypes, onTop,
572                 false /* reparentTopOnly */);
573     }
574 
575     /**
576      * Finds and removes a task and its children using its container token. The task is removed
577      * from recents.
578      *
579      * If the task is a root task, its leaves are removed but the root task is not. Use
580      * {@link #removeRootTask(WindowContainerToken)} to remove the root task.
581      *
582      * @param containerToken ContainerToken of Task to be removed
583      */
584     @NonNull
removeTask(@onNull WindowContainerToken containerToken)585     public WindowContainerTransaction removeTask(@NonNull WindowContainerToken containerToken) {
586         mHierarchyOps.add(HierarchyOp.createForRemoveTask(containerToken.asBinder()));
587         return this;
588     }
589 
590     /**
591      * Finds and removes a root task created by an organizer and its leaves using its container
592      * token.
593      *
594      * @param containerToken ContainerToken of the root task to be removed
595      * @hide
596      */
597     @NonNull
removeRootTask(@onNull WindowContainerToken containerToken)598     public WindowContainerTransaction removeRootTask(@NonNull WindowContainerToken containerToken) {
599         mHierarchyOps.add(HierarchyOp.createForRemoveRootTask(containerToken.asBinder()));
600         return this;
601     }
602 
603     /**
604      * If `container` was brought to front as a transient-launch (eg. recents), this will reorder
605      * the container back to where it was prior to the transient-launch. This way if a transient
606      * launch is "aborted", the z-ordering of containers in WM should be restored to before the
607      * launch.
608      * @hide
609      */
610     @NonNull
restoreTransientOrder( @onNull WindowContainerToken container)611     public WindowContainerTransaction restoreTransientOrder(
612             @NonNull WindowContainerToken container) {
613         final HierarchyOp hierarchyOp =
614                 new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER)
615                         .setContainer(container.asBinder())
616                         .build();
617         mHierarchyOps.add(hierarchyOp);
618         return this;
619     }
620 
621     /**
622      * Restore the back navigation target from visible to invisible for canceling gesture animation.
623      * @hide
624      */
625     @NonNull
restoreBackNavi()626     public WindowContainerTransaction restoreBackNavi() {
627         final HierarchyOp hierarchyOp =
628                 new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_RESTORE_BACK_NAVIGATION)
629                         .build();
630         mHierarchyOps.add(hierarchyOp);
631         return this;
632     }
633 
634     /*
635      * ===========================================================================================
636      * Activity launch
637      * ===========================================================================================
638      */
639 
640     /**
641      * Starts a task by id. The task is expected to already exist (eg. as a recent task).
642      * @param taskId Id of task to start.
643      * @param options bundle containing ActivityOptions for the task's top activity.
644      * @hide
645      */
646     @NonNull
startTask(int taskId, @Nullable Bundle options)647     public WindowContainerTransaction startTask(int taskId, @Nullable Bundle options) {
648         if (DEBUG_START_ACTIVITY) {
649             Log.d(Instrumentation.TAG, "WCT.startTask: taskId=" + taskId
650                     + " options=" + options, new Throwable());
651         }
652         mHierarchyOps.add(HierarchyOp.createForTaskLaunch(taskId, options));
653         return this;
654     }
655 
656     /**
657      * Sends a pending intent in sync.
658      * @param sender The PendingIntent sender.
659      * @param intent The fillIn intent to patch over the sender's base intent.
660      * @param options bundle containing ActivityOptions for the task's top activity.
661      * @hide
662      */
663     @NonNull
sendPendingIntent(@ullable PendingIntent sender, @Nullable Intent fillInIntent, @Nullable Bundle options)664     public WindowContainerTransaction sendPendingIntent(@Nullable PendingIntent sender,
665             @Nullable Intent fillInIntent, @Nullable Bundle options) {
666         if (DEBUG_START_ACTIVITY) {
667             Log.d(Instrumentation.TAG, "WCT.sendPendingIntent: sender=" + sender.getIntent()
668                     + " fillInIntent=" + fillInIntent + " options=" + options, new Throwable());
669         }
670         mHierarchyOps.add(new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_PENDING_INTENT)
671                 .setLaunchOptions(options)
672                 .setPendingIntent(sender)
673                 .setActivityIntent(fillInIntent)
674                 .build());
675         return this;
676     }
677 
678     /**
679      * Starts activity(s) from a shortcut.
680      * @param callingPackage The package launching the shortcut.
681      * @param shortcutInfo Information about the shortcut to start
682      * @param options bundle containing ActivityOptions for the task's top activity.
683      * @hide
684      */
685     @NonNull
startShortcut(@onNull String callingPackage, @NonNull ShortcutInfo shortcutInfo, @Nullable Bundle options)686     public WindowContainerTransaction startShortcut(@NonNull String callingPackage,
687             @NonNull ShortcutInfo shortcutInfo, @Nullable Bundle options) {
688         if (DEBUG_START_ACTIVITY) {
689             Log.d(Instrumentation.TAG, "WCT.startShortcut: shortcutInfo=" + shortcutInfo
690                     + " options=" + options, new Throwable());
691         }
692         mHierarchyOps.add(HierarchyOp.createForStartShortcut(
693                 callingPackage, shortcutInfo, options));
694         return this;
695     }
696 
697     /**
698      * Sets whether a container should be the launch root for the specified windowing mode and
699      * activity type. This currently only applies to Task containers created by organizer.
700      */
701     @NonNull
setLaunchRoot(@onNull WindowContainerToken container, @Nullable int[] windowingModes, @Nullable int[] activityTypes)702     public WindowContainerTransaction setLaunchRoot(@NonNull WindowContainerToken container,
703             @Nullable int[] windowingModes, @Nullable int[] activityTypes) {
704         mHierarchyOps.add(HierarchyOp.createForSetLaunchRoot(
705                 container.asBinder(),
706                 windowingModes,
707                 activityTypes));
708         return this;
709     }
710 
711     /*
712      * ===========================================================================================
713      * Multitasking
714      * ===========================================================================================
715      */
716 
717     /**
718      * Sets two containers adjacent to each other. Containers below two visible adjacent roots will
719      * be made invisible. This currently only applies to TaskFragment containers created by
720      * organizer.
721      * @param root1 the first root.
722      * @param root2 the second root.
723      * @deprecated replace with {@link #setAdjacentRootSet}
724      */
725     @SuppressWarnings("UnflaggedApi") // @TestApi without associated feature.
726     @Deprecated
727     @NonNull
setAdjacentRoots( @onNull WindowContainerToken root1, @NonNull WindowContainerToken root2)728     public WindowContainerTransaction setAdjacentRoots(
729             @NonNull WindowContainerToken root1, @NonNull WindowContainerToken root2) {
730         return setAdjacentRootSet(root1, root2);
731     }
732 
733     /**
734      * Sets multiple containers adjacent to each other. Containers below the visible adjacent roots
735      * will be made invisible. This currently only applies to Task containers created by organizer.
736      *
737      * To remove one container from the adjacent roots, one can call {@link #clearAdjacentRoots}
738      * with the target container.
739      * To remove all containers from the adjacent roots, one much call {@link #clearAdjacentRoots}
740      * on each container if there were more than two containers in the set.
741      *
742      * For non-Task TaskFragment, use {@link #setAdjacentTaskFragments} instead.
743      *
744      * @param roots the Tasks that should be adjacent to each other.
745      * @throws IllegalArgumentException if roots have size < 2.
746      * @hide // TODO(b/373709676) Rename to setAdjacentRoots and update CTS in 25Q4.
747      */
748     @NonNull
setAdjacentRootSet(@onNull WindowContainerToken... roots)749     public WindowContainerTransaction setAdjacentRootSet(@NonNull WindowContainerToken... roots) {
750         if (roots.length < 2) {
751             throw new IllegalArgumentException("setAdjacentRootSet must have size >= 2");
752         }
753         final IBinder[] rootTokens = new IBinder[roots.length];
754         for (int i = 0; i < roots.length; i++) {
755             rootTokens[i] = roots[i].asBinder();
756         }
757         mHierarchyOps.add(
758                 new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS)
759                         .setContainers(rootTokens)
760                         .build());
761         return this;
762     }
763 
764     /**
765      * Clears container adjacent.
766      * If {@link #setAdjacentRootSet} is called with more than 2 roots, calling this will only
767      * remove the given root from the adjacent set. The rest of roots will stay adjacent to each
768      * other.
769      *
770      * @param root the root container to clear the adjacent roots for.
771      * @hide
772      */
773     @NonNull
clearAdjacentRoots(@onNull WindowContainerToken root)774     public WindowContainerTransaction clearAdjacentRoots(@NonNull WindowContainerToken root) {
775         mHierarchyOps.add(HierarchyOp.createForClearAdjacentRoots(root.asBinder()));
776         return this;
777     }
778 
779     /**
780      * Sets the container as launch adjacent flag root. Task starting with
781      * {@link FLAG_ACTIVITY_LAUNCH_ADJACENT} will be launching to.
782      */
783     @NonNull
setLaunchAdjacentFlagRoot( @onNull WindowContainerToken container)784     public WindowContainerTransaction setLaunchAdjacentFlagRoot(
785             @NonNull WindowContainerToken container) {
786         mHierarchyOps.add(HierarchyOp.createForSetLaunchAdjacentFlagRoot(container.asBinder(),
787                 false /* clearRoot */));
788         return this;
789     }
790 
791     /**
792      * Clears launch adjacent flag root for the display area of passing container.
793      */
794     @NonNull
clearLaunchAdjacentFlagRoot( @onNull WindowContainerToken container)795     public WindowContainerTransaction clearLaunchAdjacentFlagRoot(
796             @NonNull WindowContainerToken container) {
797         mHierarchyOps.add(HierarchyOp.createForSetLaunchAdjacentFlagRoot(container.asBinder(),
798                 true /* clearRoot */));
799         return this;
800     }
801 
802     /**
803      * Disables or enables activities to be started in adjacent tasks (see
804      * {@link FLAG_ACTIVITY_LAUNCH_ADJACENT}) for the specified root of any child tasks.  This
805      * differs from {@link #setLaunchAdjacentFlagRoot(WindowContainerToken)} which controls the
806      * preferred launch-adjacent target and allows for selectively setting which root tasks can
807      * support launch-adjacent.
808      * @hide
809      */
810     @NonNull
setDisableLaunchAdjacent( @onNull WindowContainerToken container, boolean disabled)811     public WindowContainerTransaction setDisableLaunchAdjacent(
812             @NonNull WindowContainerToken container, boolean disabled) {
813         mHierarchyOps.add(HierarchyOp.createForSetDisableLaunchAdjacent(container.asBinder(),
814                 disabled));
815         return this;
816     }
817 
818     /*
819      * ===========================================================================================
820      * PIP
821      * ===========================================================================================
822      */
823 
824     /**
825      * Moves the PiP activity of a parent task to a pinned root task.
826      * @param parentToken the parent task of the PiP activity
827      * @param bounds the entry bounds
828      * @hide
829      */
830     @NonNull
movePipActivityToPinnedRootTask( @onNull WindowContainerToken parentToken, @NonNull Rect bounds)831     public WindowContainerTransaction movePipActivityToPinnedRootTask(
832             @NonNull WindowContainerToken parentToken, @NonNull Rect bounds) {
833         mHierarchyOps.add(new HierarchyOp
834                 .Builder(HierarchyOp.HIERARCHY_OP_TYPE_MOVE_PIP_ACTIVITY_TO_PINNED_TASK)
835                 .setContainer(parentToken.asBinder())
836                 .setBounds(bounds)
837                 .build());
838         return this;
839     }
840 
841     /**
842      * Notify {@link com.android.server.wm.PinnedTaskController} that the picture-in-picture task
843      * has finished the enter animation with the given bounds.
844      */
845     @NonNull
scheduleFinishEnterPip( @onNull WindowContainerToken container, @NonNull Rect bounds)846     public WindowContainerTransaction scheduleFinishEnterPip(
847             @NonNull WindowContainerToken container, @NonNull Rect bounds) {
848         final Change chg = getOrCreateChange(container.asBinder());
849         chg.mPinnedBounds = new Rect(bounds);
850         chg.mChangeMask |= Change.CHANGE_PIP_CALLBACK;
851 
852         return this;
853     }
854 
855     /*
856      * ===========================================================================================
857      * Insets
858      * ===========================================================================================
859      */
860 
861     /**
862      * Adds a given {@code Rect} as an insets source frame on the {@code receiver}.
863      *
864      * @param receiver The window container that the insets source is added to.
865      * @param owner    The owner of the insets source. An insets source can only be modified by its
866      *                 owner.
867      * @param index    An owner might add multiple insets sources with the same type.
868      *                 This identifies them.
869      * @param type     The {@link InsetsType} of the insets source.
870      * @param frame    The rectangle area of the insets source.
871      * @param boundingRects The bounding rects within this inset, relative to the |frame|.
872      * @hide
873      */
874     @NonNull
addInsetsSource( @onNull WindowContainerToken receiver, @Nullable IBinder owner, int index, @InsetsType int type, @Nullable Rect frame, @Nullable Rect[] boundingRects, @InsetsSource.Flags int flags)875     public WindowContainerTransaction addInsetsSource(
876             @NonNull WindowContainerToken receiver,
877             @Nullable IBinder owner, int index, @InsetsType int type, @Nullable Rect frame,
878             @Nullable Rect[] boundingRects, @InsetsSource.Flags int flags) {
879         final HierarchyOp hierarchyOp =
880                 new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_ADD_INSETS_FRAME_PROVIDER)
881                         .setContainer(receiver.asBinder())
882                         .setInsetsFrameProvider(new InsetsFrameProvider(owner, index, type)
883                                 .setSource(InsetsFrameProvider.SOURCE_ARBITRARY_RECTANGLE)
884                                 .setArbitraryRectangle(frame)
885                                 .setBoundingRects(boundingRects)
886                                 .setFlags(flags))
887                         .setInsetsFrameOwner(owner)
888                         .build();
889         mHierarchyOps.add(hierarchyOp);
890         return this;
891     }
892 
893     /**
894      * Removes the insets source from the {@code receiver}.
895      *
896      * @param receiver The window container that the insets source was added to.
897      * @param owner    The owner of the insets source. An insets source can only be modified by its
898      *                 owner.
899      * @param index    An owner might add multiple insets sources with the same type.
900      *                 This identifies them.
901      * @param type     The {@link InsetsType} of the insets source.
902      * @hide
903      */
904     @NonNull
removeInsetsSource(@onNull WindowContainerToken receiver, @Nullable IBinder owner, int index, @InsetsType int type)905     public WindowContainerTransaction removeInsetsSource(@NonNull WindowContainerToken receiver,
906             @Nullable IBinder owner, int index, @InsetsType int type) {
907         final HierarchyOp hierarchyOp =
908                 new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_REMOVE_INSETS_FRAME_PROVIDER)
909                         .setContainer(receiver.asBinder())
910                         .setInsetsFrameProvider(new InsetsFrameProvider(owner, index, type))
911                         .setInsetsFrameOwner(owner)
912                         .build();
913         mHierarchyOps.add(hierarchyOp);
914         return this;
915     }
916 
917     /*
918      * ===========================================================================================
919      * Keyguard
920      * ===========================================================================================
921      */
922 
923     /**
924      * Adds a {@link KeyguardState} to apply to the given displays.
925      *
926      * @hide
927      */
928     @NonNull
addKeyguardState(@onNull KeyguardState keyguardState)929     public WindowContainerTransaction addKeyguardState(@NonNull KeyguardState keyguardState) {
930         Objects.requireNonNull(keyguardState);
931         final HierarchyOp hierarchyOp =
932                 new HierarchyOp.Builder(
933                         HierarchyOp.HIERARCHY_OP_TYPE_SET_KEYGUARD_STATE)
934                         .setKeyguardState(keyguardState)
935                         .build();
936         mHierarchyOps.add(hierarchyOp);
937         return this;
938     }
939 
940     /*
941      * ===========================================================================================
942      * Task fragments
943      * ===========================================================================================
944      */
945 
946     /**
947      * Sets the {@link TaskFragmentOrganizer} that applies this {@link WindowContainerTransaction}.
948      * When this is set, the server side will not check for the permission of
949      * {@link android.Manifest.permission#MANAGE_ACTIVITY_TASKS}, but will ensure this WCT only
950      * contains operations that are allowed for this organizer, such as modifying TaskFragments that
951      * are organized by this organizer.
952      * @hide
953      */
954     @NonNull
setTaskFragmentOrganizer( @onNull ITaskFragmentOrganizer organizer)955     public WindowContainerTransaction setTaskFragmentOrganizer(
956             @NonNull ITaskFragmentOrganizer organizer) {
957         mTaskFragmentOrganizer = organizer;
958         return this;
959     }
960 
961     /**
962      * When this {@link WindowContainerTransaction} failed to finish on the server side, it will
963      * trigger callback with this {@param errorCallbackToken}.
964      * @param errorCallbackToken    client provided token that will be passed back as parameter in
965      *                              the callback if there is an error on the server side.
966      * @see ITaskFragmentOrganizer#onTaskFragmentError
967      */
968     @NonNull
setErrorCallbackToken(@onNull IBinder errorCallbackToken)969     public WindowContainerTransaction setErrorCallbackToken(@NonNull IBinder errorCallbackToken) {
970         if (mErrorCallbackToken != null) {
971             throw new IllegalStateException("Can't set multiple error token for one transaction.");
972         }
973         mErrorCallbackToken = errorCallbackToken;
974         return this;
975     }
976 
977     /**
978      * Creates a new TaskFragment with the given options.
979      * @param taskFragmentCreationParams the options used to create the TaskFragment.
980      */
981     @NonNull
createTaskFragment( @onNull TaskFragmentCreationParams taskFragmentCreationParams)982     public WindowContainerTransaction createTaskFragment(
983             @NonNull TaskFragmentCreationParams taskFragmentCreationParams) {
984         final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
985                 OP_TYPE_CREATE_TASK_FRAGMENT)
986                 .setTaskFragmentCreationParams(taskFragmentCreationParams)
987                 .build();
988         return addTaskFragmentOperation(taskFragmentCreationParams.getFragmentToken(), operation);
989     }
990 
991     /**
992      * Deletes an existing TaskFragment. Any remaining activities below it will be destroyed.
993      * @param fragmentToken client assigned unique token to create TaskFragment with specified in
994      *                      {@link TaskFragmentCreationParams#getFragmentToken()}.
995      */
996     @NonNull
deleteTaskFragment(@onNull IBinder fragmentToken)997     public WindowContainerTransaction deleteTaskFragment(@NonNull IBinder fragmentToken) {
998         final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
999                 OP_TYPE_DELETE_TASK_FRAGMENT)
1000                 .build();
1001         return addTaskFragmentOperation(fragmentToken, operation);
1002     }
1003 
1004     /**
1005      * Starts an activity in the TaskFragment.
1006      * @param fragmentToken client assigned unique token to create TaskFragment with specified in
1007      *                      {@link TaskFragmentCreationParams#getFragmentToken()}.
1008      * @param callerToken  the activity token that initialized the activity launch.
1009      * @param activityIntent    intent to start the activity.
1010      * @param activityOptions    ActivityOptions to start the activity with.
1011      * @see android.content.Context#startActivity(Intent, Bundle).
1012      */
1013     @NonNull
startActivityInTaskFragment( @onNull IBinder fragmentToken, @NonNull IBinder callerToken, @NonNull Intent activityIntent, @Nullable Bundle activityOptions)1014     public WindowContainerTransaction startActivityInTaskFragment(
1015             @NonNull IBinder fragmentToken, @NonNull IBinder callerToken,
1016             @NonNull Intent activityIntent, @Nullable Bundle activityOptions) {
1017         final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
1018                 OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT)
1019                 .setActivityToken(callerToken)
1020                 .setActivityIntent(activityIntent)
1021                 .setBundle(activityOptions)
1022                 .build();
1023         return addTaskFragmentOperation(fragmentToken, operation);
1024     }
1025 
1026     /**
1027      * Moves an activity into the TaskFragment.
1028      * @param fragmentToken client assigned unique token to create TaskFragment with specified in
1029      *                      {@link TaskFragmentCreationParams#getFragmentToken()}.
1030      * @param activityToken activity to be reparented.
1031      */
1032     @NonNull
reparentActivityToTaskFragment( @onNull IBinder fragmentToken, @NonNull IBinder activityToken)1033     public WindowContainerTransaction reparentActivityToTaskFragment(
1034             @NonNull IBinder fragmentToken, @NonNull IBinder activityToken) {
1035         final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
1036                 OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT)
1037                 .setActivityToken(activityToken)
1038                 .build();
1039         return addTaskFragmentOperation(fragmentToken, operation);
1040     }
1041 
1042     /**
1043      * Sets to TaskFragments adjacent to each other. Containers below two visible adjacent
1044      * TaskFragments will be made invisible. This is similar to
1045      * {@link #setAdjacentRootSet(WindowContainerToken...)}, but can be used with
1046      * fragmentTokens when that TaskFragments haven't been created (but will be created in the same
1047      * {@link WindowContainerTransaction}).
1048      * @param fragmentToken1    client assigned unique token to create TaskFragment with specified
1049      *                          in {@link TaskFragmentCreationParams#getFragmentToken()}.
1050      * @param fragmentToken2    client assigned unique token to create TaskFragment with specified
1051      *                          in {@link TaskFragmentCreationParams#getFragmentToken()}.
1052      */
1053     @NonNull
setAdjacentTaskFragments( @onNull IBinder fragmentToken1, @NonNull IBinder fragmentToken2, @Nullable TaskFragmentAdjacentParams params)1054     public WindowContainerTransaction setAdjacentTaskFragments(
1055             @NonNull IBinder fragmentToken1, @NonNull IBinder fragmentToken2,
1056             @Nullable TaskFragmentAdjacentParams params) {
1057         final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
1058                 OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS)
1059                 .setSecondaryFragmentToken(fragmentToken2)
1060                 .setBundle(params != null ? params.toBundle() : null)
1061                 .build();
1062         return addTaskFragmentOperation(fragmentToken1, operation);
1063     }
1064 
1065     /**
1066      * Clears the adjacent TaskFragments relationship that is previously set through
1067      * {@link #setAdjacentTaskFragments}. Clear operation on one TaskFragment will also clear its
1068      * current adjacent TaskFragment's.
1069      * @param fragmentToken     client assigned unique token to create TaskFragment with specified
1070      *                          in {@link TaskFragmentCreationParams#getFragmentToken()}.
1071      */
1072     @NonNull
clearAdjacentTaskFragments(@onNull IBinder fragmentToken)1073     public WindowContainerTransaction clearAdjacentTaskFragments(@NonNull IBinder fragmentToken) {
1074         final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
1075                 OP_TYPE_CLEAR_ADJACENT_TASK_FRAGMENTS)
1076                 .build();
1077         return addTaskFragmentOperation(fragmentToken, operation);
1078     }
1079 
1080     /**
1081      * Requests focus on the top running Activity in the given TaskFragment. This will only take
1082      * effect if there is no focus, or if the current focus is in the same Task as the requested
1083      * TaskFragment.
1084      * @param fragmentToken client assigned unique token to create TaskFragment with specified in
1085      *                      {@link TaskFragmentCreationParams#getFragmentToken()}.
1086      */
1087     @NonNull
requestFocusOnTaskFragment(@onNull IBinder fragmentToken)1088     public WindowContainerTransaction requestFocusOnTaskFragment(@NonNull IBinder fragmentToken) {
1089         final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
1090                 OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT)
1091                 .build();
1092         return addTaskFragmentOperation(fragmentToken, operation);
1093     }
1094 
1095     /**
1096      * Finishes the Activity.
1097      * Comparing to directly calling {@link android.app.Activity#finish()}, calling this can make
1098      * sure the finishing happens in the same transaction with other operations.
1099      * @param activityToken activity to be finished.
1100      */
1101     @NonNull
finishActivity(@onNull IBinder activityToken)1102     public WindowContainerTransaction finishActivity(@NonNull IBinder activityToken) {
1103         final HierarchyOp hierarchyOp =
1104                 new HierarchyOp.Builder(
1105                         HierarchyOp.HIERARCHY_OP_TYPE_FINISH_ACTIVITY)
1106                         .setContainer(activityToken)
1107                         .build();
1108         mHierarchyOps.add(hierarchyOp);
1109         return this;
1110     }
1111 
1112     /**
1113      * Sets the TaskFragment {@code fragmentToken} to have a companion TaskFragment
1114      * {@code companionFragmentToken}.
1115      * This indicates that the organizer will remove the TaskFragment when the companion
1116      * TaskFragment is removed.
1117      *
1118      * @param fragmentToken client assigned unique token to create TaskFragment with specified
1119      *                      in {@link TaskFragmentCreationParams#getFragmentToken()}.
1120      * @param companionFragmentToken client assigned unique token to create TaskFragment with
1121      *                               specified in
1122      *                               {@link TaskFragmentCreationParams#getFragmentToken()}.
1123      *                               If it is {@code null}, the transaction will reset the companion
1124      *                               TaskFragment.
1125      * @hide
1126      */
1127     @NonNull
setCompanionTaskFragment(@onNull IBinder fragmentToken, @Nullable IBinder companionFragmentToken)1128     public WindowContainerTransaction setCompanionTaskFragment(@NonNull IBinder fragmentToken,
1129             @Nullable IBinder companionFragmentToken) {
1130         final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
1131                 OP_TYPE_SET_COMPANION_TASK_FRAGMENT)
1132                 .setSecondaryFragmentToken(companionFragmentToken)
1133                 .build();
1134         return addTaskFragmentOperation(fragmentToken, operation);
1135     }
1136 
1137     /**
1138      * Adds a {@link TaskFragmentOperation} to apply to the given TaskFragment.
1139      *
1140      * @param fragmentToken client assigned unique token to create TaskFragment with specified in
1141      *                      {@link TaskFragmentCreationParams#getFragmentToken()}.
1142      * @param taskFragmentOperation the {@link TaskFragmentOperation} to apply to the given
1143      *                              TaskFramgent.
1144      * @hide
1145      */
1146     @NonNull
addTaskFragmentOperation(@onNull IBinder fragmentToken, @NonNull TaskFragmentOperation taskFragmentOperation)1147     public WindowContainerTransaction addTaskFragmentOperation(@NonNull IBinder fragmentToken,
1148             @NonNull TaskFragmentOperation taskFragmentOperation) {
1149         Objects.requireNonNull(fragmentToken);
1150         Objects.requireNonNull(taskFragmentOperation);
1151         final HierarchyOp hierarchyOp =
1152                 new HierarchyOp.Builder(
1153                         HierarchyOp.HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION)
1154                         .setContainer(fragmentToken)
1155                         .setTaskFragmentOperation(taskFragmentOperation)
1156                         .build();
1157         mHierarchyOps.add(hierarchyOp);
1158         return this;
1159     }
1160 
1161     /**
1162      * Adds a hierarchy op for app compat reachability.
1163      *
1164      * @param container The token for the container Task
1165      * @param taskId    The id of the current task
1166      * @hide
1167      */
setReachabilityOffset( @onNull WindowContainerToken container, int taskId, int x, int y)1168     public WindowContainerTransaction setReachabilityOffset(
1169             @NonNull WindowContainerToken container, int taskId, int x, int y) {
1170         mHierarchyOps.add(HierarchyOp.createForReachability(container.asBinder(), taskId, x, y));
1171         return this;
1172     }
1173 
1174     /**
1175      * Merges another WCT into this one.
1176      * @param transfer When true, this will transfer everything from other potentially leaving
1177      *                 other in an unusable state. When false, other is left alone, but
1178      *                 SurfaceFlinger Transactions will not be merged.
1179      * @hide
1180      */
merge(@onNull WindowContainerTransaction other, boolean transfer)1181     public void merge(@NonNull WindowContainerTransaction other, boolean transfer) {
1182         for (int i = 0, n = other.mChanges.size(); i < n; ++i) {
1183             final IBinder key = other.mChanges.keyAt(i);
1184             Change existing = mChanges.get(key);
1185             if (existing == null) {
1186                 existing = new Change();
1187                 mChanges.put(key, existing);
1188             }
1189             existing.merge(other.mChanges.valueAt(i), transfer);
1190         }
1191         for (int i = 0, n = other.mHierarchyOps.size(); i < n; ++i) {
1192             final HierarchyOp otherHierarchyOp = other.mHierarchyOps.get(i);
1193             mHierarchyOps.add(transfer ? otherHierarchyOp : new HierarchyOp(otherHierarchyOp));
1194         }
1195         if (mErrorCallbackToken != null && other.mErrorCallbackToken != null && mErrorCallbackToken
1196                 != other.mErrorCallbackToken) {
1197             throw new IllegalArgumentException("Can't merge two WCTs with different error token");
1198         }
1199         final IBinder taskFragmentOrganizerAsBinder = mTaskFragmentOrganizer != null
1200                 ? mTaskFragmentOrganizer.asBinder()
1201                 : null;
1202         final IBinder otherTaskFragmentOrganizerAsBinder = other.mTaskFragmentOrganizer != null
1203                 ? other.mTaskFragmentOrganizer.asBinder()
1204                 : null;
1205         if (!Objects.equals(taskFragmentOrganizerAsBinder, otherTaskFragmentOrganizerAsBinder)) {
1206             throw new IllegalArgumentException(
1207                     "Can't merge two WCTs from different TaskFragmentOrganizers");
1208         }
1209         mErrorCallbackToken = mErrorCallbackToken != null
1210                 ? mErrorCallbackToken
1211                 : other.mErrorCallbackToken;
1212     }
1213 
1214     /** @hide */
isEmpty()1215     public boolean isEmpty() {
1216         return mChanges.isEmpty() && mHierarchyOps.isEmpty();
1217     }
1218 
1219     /** @hide */
1220     @NonNull
getChanges()1221     public Map<IBinder, Change> getChanges() {
1222         return mChanges;
1223     }
1224 
1225     /** @hide */
1226     @NonNull
getHierarchyOps()1227     public List<HierarchyOp> getHierarchyOps() {
1228         return mHierarchyOps;
1229     }
1230 
1231     /** @hide */
1232     @Nullable
getErrorCallbackToken()1233     public IBinder getErrorCallbackToken() {
1234         return mErrorCallbackToken;
1235     }
1236 
1237     /** @hide */
1238     @Nullable
getTaskFragmentOrganizer()1239     public ITaskFragmentOrganizer getTaskFragmentOrganizer() {
1240         return mTaskFragmentOrganizer;
1241     }
1242 
1243     @Override
1244     @NonNull
toString()1245     public String toString() {
1246         return "WindowContainerTransaction {"
1247                 + " changes= " + mChanges
1248                 + " hops= " + mHierarchyOps
1249                 + " errorCallbackToken=" + mErrorCallbackToken
1250                 + " taskFragmentOrganizer=" + mTaskFragmentOrganizer
1251                 + " }";
1252     }
1253 
1254     @Override
writeToParcel(@onNull Parcel dest, int flags)1255     public void writeToParcel(@NonNull Parcel dest, int flags) {
1256         dest.writeMap(mChanges);
1257         dest.writeTypedList(mHierarchyOps);
1258         dest.writeStrongBinder(mErrorCallbackToken);
1259         dest.writeStrongInterface(mTaskFragmentOrganizer);
1260     }
1261 
1262     @Override
describeContents()1263     public int describeContents() {
1264         return 0;
1265     }
1266 
1267     @NonNull
1268     public static final Creator<WindowContainerTransaction> CREATOR =
1269             new Creator<>() {
1270                 @Override
1271                 public WindowContainerTransaction createFromParcel(@NonNull Parcel in) {
1272                     return new WindowContainerTransaction(in);
1273                 }
1274 
1275                 @Override
1276                 public WindowContainerTransaction[] newArray(int size) {
1277                     return new WindowContainerTransaction[size];
1278                 }
1279             };
1280 
1281     /**
1282      * Holds changes on a single WindowContainer including Configuration changes.
1283      * @hide
1284      */
1285     public static class Change implements Parcelable {
1286         public static final int CHANGE_FOCUSABLE = 1;
1287         public static final int CHANGE_BOUNDS_TRANSACTION = 1 << 1;
1288         public static final int CHANGE_PIP_CALLBACK = 1 << 2;
1289         public static final int CHANGE_HIDDEN = 1 << 3;
1290         public static final int CHANGE_IGNORE_ORIENTATION_REQUEST = 1 << 4;
1291         public static final int CHANGE_FORCE_NO_PIP = 1 << 5;
1292         public static final int CHANGE_FORCE_TRANSLUCENT = 1 << 6;
1293         public static final int CHANGE_DRAG_RESIZING = 1 << 7;
1294         public static final int CHANGE_RELATIVE_BOUNDS = 1 << 8;
1295 
1296         @IntDef(flag = true, prefix = { "CHANGE_" }, value = {
1297                 CHANGE_FOCUSABLE,
1298                 CHANGE_BOUNDS_TRANSACTION,
1299                 CHANGE_PIP_CALLBACK,
1300                 CHANGE_HIDDEN,
1301                 CHANGE_IGNORE_ORIENTATION_REQUEST,
1302                 CHANGE_FORCE_NO_PIP,
1303                 CHANGE_FORCE_TRANSLUCENT,
1304                 CHANGE_DRAG_RESIZING,
1305                 CHANGE_RELATIVE_BOUNDS
1306         })
1307         @Retention(RetentionPolicy.SOURCE)
1308         public @interface ChangeMask {}
1309 
1310         private final Configuration mConfiguration = new Configuration();
1311         private boolean mFocusable = true;
1312         private boolean mHidden = false;
1313         private boolean mIgnoreOrientationRequest = false;
1314         private boolean mForceTranslucent = false;
1315         private boolean mDragResizing = false;
1316 
1317         private @ChangeMask int mChangeMask = 0;
1318         private @ActivityInfo.Config int mConfigSetMask = 0;
1319         private @WindowConfiguration.WindowConfig int mWindowSetMask = 0;
1320 
1321         private Rect mPinnedBounds = null;
1322         private SurfaceControl.Transaction mBoundsChangeTransaction = null;
1323         @Nullable
1324         private Rect mRelativeBounds = null;
1325         private boolean mConfigAtTransitionEnd = false;
1326 
1327         private int mActivityWindowingMode = -1;
1328         private int mWindowingMode = -1;
1329 
Change()1330         private Change() {}
1331 
Change(@onNull Parcel in)1332         private Change(@NonNull Parcel in) {
1333             mConfiguration.readFromParcel(in);
1334             mFocusable = in.readBoolean();
1335             mHidden = in.readBoolean();
1336             mIgnoreOrientationRequest = in.readBoolean();
1337             mForceTranslucent = in.readBoolean();
1338             mDragResizing = in.readBoolean();
1339             mChangeMask = in.readInt();
1340             mConfigSetMask = in.readInt();
1341             mWindowSetMask = in.readInt();
1342             if ((mChangeMask & Change.CHANGE_PIP_CALLBACK) != 0) {
1343                 mPinnedBounds = new Rect();
1344                 mPinnedBounds.readFromParcel(in);
1345             }
1346             if ((mChangeMask & Change.CHANGE_BOUNDS_TRANSACTION) != 0) {
1347                 mBoundsChangeTransaction =
1348                     SurfaceControl.Transaction.CREATOR.createFromParcel(in);
1349             }
1350             if ((mChangeMask & Change.CHANGE_RELATIVE_BOUNDS) != 0) {
1351                 mRelativeBounds = new Rect();
1352                 mRelativeBounds.readFromParcel(in);
1353             }
1354             mConfigAtTransitionEnd = in.readBoolean();
1355 
1356             mWindowingMode = in.readInt();
1357             mActivityWindowingMode = in.readInt();
1358         }
1359 
1360         /**
1361          * @param transfer When true, this will transfer other into this leaving other in an
1362          *                 undefined state. Use this if you don't intend to use other. When false,
1363          *                 SurfaceFlinger Transactions will not merge.
1364          */
merge(@onNull Change other, boolean transfer)1365         public void merge(@NonNull Change other, boolean transfer) {
1366             mConfiguration.setTo(other.mConfiguration, other.mConfigSetMask, other.mWindowSetMask);
1367             mConfigSetMask |= other.mConfigSetMask;
1368             mWindowSetMask |= other.mWindowSetMask;
1369             if ((other.mChangeMask & CHANGE_FOCUSABLE) != 0) {
1370                 mFocusable = other.mFocusable;
1371             }
1372             if (transfer && (other.mChangeMask & CHANGE_BOUNDS_TRANSACTION) != 0) {
1373                 mBoundsChangeTransaction = other.mBoundsChangeTransaction;
1374                 other.mBoundsChangeTransaction = null;
1375             }
1376             if ((other.mChangeMask & CHANGE_PIP_CALLBACK) != 0) {
1377                 mPinnedBounds = transfer ? other.mPinnedBounds : new Rect(other.mPinnedBounds);
1378             }
1379             if ((other.mChangeMask & CHANGE_HIDDEN) != 0) {
1380                 mHidden = other.mHidden;
1381             }
1382             if ((other.mChangeMask & CHANGE_IGNORE_ORIENTATION_REQUEST) != 0) {
1383                 mIgnoreOrientationRequest = other.mIgnoreOrientationRequest;
1384             }
1385             if ((other.mChangeMask & CHANGE_FORCE_TRANSLUCENT) != 0) {
1386                 mForceTranslucent = other.mForceTranslucent;
1387             }
1388             if ((other.mChangeMask & CHANGE_DRAG_RESIZING) != 0) {
1389                 mDragResizing = other.mDragResizing;
1390             }
1391             mChangeMask |= other.mChangeMask;
1392             if (other.mActivityWindowingMode >= WINDOWING_MODE_UNDEFINED) {
1393                 mActivityWindowingMode = other.mActivityWindowingMode;
1394             }
1395             if (other.mWindowingMode >= WINDOWING_MODE_UNDEFINED) {
1396                 mWindowingMode = other.mWindowingMode;
1397             }
1398             if (other.mRelativeBounds != null) {
1399                 mRelativeBounds = transfer
1400                         ? other.mRelativeBounds
1401                         : new Rect(other.mRelativeBounds);
1402             }
1403             mConfigAtTransitionEnd = mConfigAtTransitionEnd
1404                     || other.mConfigAtTransitionEnd;
1405         }
1406 
getWindowingMode()1407         public int getWindowingMode() {
1408             return mWindowingMode;
1409         }
1410 
getActivityWindowingMode()1411         public int getActivityWindowingMode() {
1412             return mActivityWindowingMode;
1413         }
1414 
1415         @NonNull
getConfiguration()1416         public Configuration getConfiguration() {
1417             return mConfiguration;
1418         }
1419 
1420         /** Gets the requested focusable state */
getFocusable()1421         public boolean getFocusable() {
1422             if ((mChangeMask & CHANGE_FOCUSABLE) == 0) {
1423                 throw new RuntimeException("Focusable not set. check CHANGE_FOCUSABLE first");
1424             }
1425             return mFocusable;
1426         }
1427 
1428         /** Gets the requested hidden state */
getHidden()1429         public boolean getHidden() {
1430             if ((mChangeMask & CHANGE_HIDDEN) == 0) {
1431                 throw new RuntimeException("Hidden not set. check CHANGE_HIDDEN first");
1432             }
1433             return mHidden;
1434         }
1435 
1436         /** Gets the requested state of whether to ignore orientation request. */
getIgnoreOrientationRequest()1437         public boolean getIgnoreOrientationRequest() {
1438             if ((mChangeMask & CHANGE_IGNORE_ORIENTATION_REQUEST) == 0) {
1439                 throw new RuntimeException("IgnoreOrientationRequest not set. "
1440                         + "Check CHANGE_IGNORE_ORIENTATION_REQUEST first");
1441             }
1442             return mIgnoreOrientationRequest;
1443         }
1444 
1445         /** Gets the requested force translucent state. */
getForceTranslucent()1446         public boolean getForceTranslucent() {
1447             if ((mChangeMask & CHANGE_FORCE_TRANSLUCENT) == 0) {
1448                 throw new RuntimeException("Force translucent not set. "
1449                         + "Check CHANGE_FORCE_TRANSLUCENT first");
1450             }
1451             return mForceTranslucent;
1452         }
1453 
1454         /** Gets the requested drag resizing state. */
getDragResizing()1455         public boolean getDragResizing() {
1456             if ((mChangeMask & CHANGE_DRAG_RESIZING) == 0) {
1457                 throw new RuntimeException("Drag resizing not set. "
1458                         + "Check CHANGE_DRAG_RESIZING first");
1459             }
1460             return mDragResizing;
1461         }
1462 
1463         /** Gets whether the config should be sent to the client at the end of the transition. */
getConfigAtTransitionEnd()1464         public boolean getConfigAtTransitionEnd() {
1465             return mConfigAtTransitionEnd;
1466         }
1467 
1468         @ChangeMask
getChangeMask()1469         public int getChangeMask() {
1470             return mChangeMask;
1471         }
1472 
1473         @ActivityInfo.Config
getConfigSetMask()1474         public int getConfigSetMask() {
1475             return mConfigSetMask;
1476         }
1477 
1478         @WindowConfiguration.WindowConfig
getWindowSetMask()1479         public int getWindowSetMask() {
1480             return mWindowSetMask;
1481         }
1482 
1483         /**
1484          * Returns the bounds to be used for scheduling the enter pip callback
1485          * or null if no callback is to be scheduled.
1486          */
1487         @Nullable
getEnterPipBounds()1488         public Rect getEnterPipBounds() {
1489             return mPinnedBounds;
1490         }
1491 
1492         @Nullable
getBoundsChangeTransaction()1493         public SurfaceControl.Transaction getBoundsChangeTransaction() {
1494             return mBoundsChangeTransaction;
1495         }
1496 
1497         @Nullable
getRelativeBounds()1498         public Rect getRelativeBounds() {
1499             return mRelativeBounds;
1500         }
1501 
1502         @Override
toString()1503         public String toString() {
1504             final boolean changesBounds =
1505                     (mConfigSetMask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0
1506                             && ((mWindowSetMask & WindowConfiguration.WINDOW_CONFIG_BOUNDS)
1507                                     != 0);
1508             final boolean changesAppBounds =
1509                     (mConfigSetMask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0
1510                             && ((mWindowSetMask & WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS)
1511                                     != 0);
1512             final boolean changesSs = (mConfigSetMask & ActivityInfo.CONFIG_SCREEN_SIZE) != 0;
1513             final boolean changesSss =
1514                     (mConfigSetMask & ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE) != 0;
1515             StringBuilder sb = new StringBuilder();
1516             sb.append('{');
1517             if (changesBounds) {
1518                 sb.append("bounds:" + mConfiguration.windowConfiguration.getBounds() + ",");
1519             }
1520             if (changesAppBounds) {
1521                 sb.append("appbounds:" + mConfiguration.windowConfiguration.getAppBounds() + ",");
1522             }
1523             if (changesSss) {
1524                 sb.append("ssw:" + mConfiguration.smallestScreenWidthDp + ",");
1525             }
1526             if (changesSs) {
1527                 sb.append("sw/h:" + mConfiguration.screenWidthDp + "x"
1528                         + mConfiguration.screenHeightDp + ",");
1529             }
1530             if ((mChangeMask & CHANGE_FOCUSABLE) != 0) {
1531                 sb.append("focusable:" + mFocusable + ",");
1532             }
1533             if ((mChangeMask & CHANGE_FORCE_TRANSLUCENT) != 0) {
1534                 sb.append("forceTranslucent:" + mForceTranslucent + ",");
1535             }
1536             if ((mChangeMask & CHANGE_HIDDEN) != 0) {
1537                 sb.append("hidden:" + mHidden + ",");
1538             }
1539             if ((mChangeMask & CHANGE_DRAG_RESIZING) != 0) {
1540                 sb.append("dragResizing:" + mDragResizing + ",");
1541             }
1542             if (mBoundsChangeTransaction != null) {
1543                 sb.append("hasBoundsTransaction,");
1544             }
1545             if ((mChangeMask & CHANGE_IGNORE_ORIENTATION_REQUEST) != 0) {
1546                 sb.append("ignoreOrientationRequest:" + mIgnoreOrientationRequest + ",");
1547             }
1548             if ((mChangeMask & CHANGE_RELATIVE_BOUNDS) != 0) {
1549                 sb.append("relativeBounds:").append(mRelativeBounds).append(",");
1550             }
1551             if (mConfigAtTransitionEnd) {
1552                 sb.append("configAtTransitionEnd").append(",");
1553             }
1554             sb.append("}");
1555             return sb.toString();
1556         }
1557 
1558         @Override
writeToParcel(@onNull Parcel dest, int flags)1559         public void writeToParcel(@NonNull Parcel dest, int flags) {
1560             mConfiguration.writeToParcel(dest, flags);
1561             dest.writeBoolean(mFocusable);
1562             dest.writeBoolean(mHidden);
1563             dest.writeBoolean(mIgnoreOrientationRequest);
1564             dest.writeBoolean(mForceTranslucent);
1565             dest.writeBoolean(mDragResizing);
1566             dest.writeInt(mChangeMask);
1567             dest.writeInt(mConfigSetMask);
1568             dest.writeInt(mWindowSetMask);
1569 
1570             if (mPinnedBounds != null) {
1571                 mPinnedBounds.writeToParcel(dest, flags);
1572             }
1573             if (mBoundsChangeTransaction != null) {
1574                 mBoundsChangeTransaction.writeToParcel(dest, flags);
1575             }
1576             if (mRelativeBounds != null) {
1577                 mRelativeBounds.writeToParcel(dest, flags);
1578             }
1579             dest.writeBoolean(mConfigAtTransitionEnd);
1580 
1581             dest.writeInt(mWindowingMode);
1582             dest.writeInt(mActivityWindowingMode);
1583         }
1584 
1585         @Override
describeContents()1586         public int describeContents() {
1587             return 0;
1588         }
1589 
1590         public static final Creator<Change> CREATOR = new Creator<Change>() {
1591             @Override
1592             public Change createFromParcel(@NonNull Parcel in) {
1593                 return new Change(in);
1594             }
1595 
1596             @Override
1597             public Change[] newArray(int size) {
1598                 return new Change[size];
1599             }
1600         };
1601     }
1602 
1603     /**
1604      * Holds information about a reparent/reorder operation in the hierarchy. This is separate from
1605      * Changes because they must be executed in the same order that they are added.
1606      * @see com.android.server.wm.WindowOrganizerController#applyHierarchyOp
1607      * @hide
1608      */
1609     public static final class HierarchyOp implements Parcelable {
1610         public static final int HIERARCHY_OP_TYPE_REPARENT = 0;
1611         public static final int HIERARCHY_OP_TYPE_REORDER = 1;
1612         public static final int HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT = 2;
1613         public static final int HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT = 3;
1614         public static final int HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS = 4;
1615         public static final int HIERARCHY_OP_TYPE_LAUNCH_TASK = 5;
1616         public static final int HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT = 6;
1617         public static final int HIERARCHY_OP_TYPE_PENDING_INTENT = 7;
1618         public static final int HIERARCHY_OP_TYPE_START_SHORTCUT = 8;
1619         public static final int HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER = 9;
1620         public static final int HIERARCHY_OP_TYPE_ADD_INSETS_FRAME_PROVIDER = 10;
1621         public static final int HIERARCHY_OP_TYPE_REMOVE_INSETS_FRAME_PROVIDER = 11;
1622         public static final int HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP = 12;
1623         public static final int HIERARCHY_OP_TYPE_REMOVE_TASK = 13;
1624         public static final int HIERARCHY_OP_TYPE_FINISH_ACTIVITY = 14;
1625         public static final int HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS = 15;
1626         public static final int HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH = 16;
1627         public static final int HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION = 17;
1628         public static final int HIERARCHY_OP_TYPE_MOVE_PIP_ACTIVITY_TO_PINNED_TASK = 18;
1629         public static final int HIERARCHY_OP_TYPE_SET_IS_TRIMMABLE = 19;
1630         public static final int HIERARCHY_OP_TYPE_RESTORE_BACK_NAVIGATION = 20;
1631         public static final int HIERARCHY_OP_TYPE_SET_EXCLUDE_INSETS_TYPES = 21;
1632         public static final int HIERARCHY_OP_TYPE_SET_KEYGUARD_STATE = 22;
1633         public static final int HIERARCHY_OP_TYPE_SET_DISABLE_LAUNCH_ADJACENT = 23;
1634         public static final int HIERARCHY_OP_TYPE_REMOVE_ROOT_TASK = 24;
1635         public static final int HIERARCHY_OP_TYPE_APP_COMPAT_REACHABILITY = 25;
1636         public static final int HIERARCHY_OP_TYPE_SET_SAFE_REGION_BOUNDS = 26;
1637 
1638         @IntDef(prefix = {"HIERARCHY_OP_TYPE_"}, value = {
1639                 HIERARCHY_OP_TYPE_REPARENT,
1640                 HIERARCHY_OP_TYPE_REORDER,
1641                 HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT,
1642                 HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT,
1643                 HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS,
1644                 HIERARCHY_OP_TYPE_LAUNCH_TASK,
1645                 HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT,
1646                 HIERARCHY_OP_TYPE_PENDING_INTENT,
1647                 HIERARCHY_OP_TYPE_START_SHORTCUT,
1648                 HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER,
1649                 HIERARCHY_OP_TYPE_ADD_INSETS_FRAME_PROVIDER,
1650                 HIERARCHY_OP_TYPE_REMOVE_INSETS_FRAME_PROVIDER,
1651                 HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP,
1652                 HIERARCHY_OP_TYPE_REMOVE_TASK,
1653                 HIERARCHY_OP_TYPE_FINISH_ACTIVITY,
1654                 HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS,
1655                 HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH,
1656                 HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION,
1657                 HIERARCHY_OP_TYPE_MOVE_PIP_ACTIVITY_TO_PINNED_TASK,
1658                 HIERARCHY_OP_TYPE_SET_IS_TRIMMABLE,
1659                 HIERARCHY_OP_TYPE_RESTORE_BACK_NAVIGATION,
1660                 HIERARCHY_OP_TYPE_SET_EXCLUDE_INSETS_TYPES,
1661                 HIERARCHY_OP_TYPE_SET_KEYGUARD_STATE,
1662                 HIERARCHY_OP_TYPE_SET_DISABLE_LAUNCH_ADJACENT,
1663                 HIERARCHY_OP_TYPE_REMOVE_ROOT_TASK,
1664                 HIERARCHY_OP_TYPE_APP_COMPAT_REACHABILITY,
1665                 HIERARCHY_OP_TYPE_SET_SAFE_REGION_BOUNDS,
1666         })
1667         @Retention(RetentionPolicy.SOURCE)
1668         public @interface HierarchyOpType {
1669         }
1670 
1671         // The following key(s) are for use with mLaunchOptions:
1672         // When launching a task (eg. from recents), this is the taskId to be launched.
1673         public static final String LAUNCH_KEY_TASK_ID = "android:transaction.hop.taskId";
1674 
1675         // When starting from a shortcut, this contains the calling package.
1676         public static final String LAUNCH_KEY_SHORTCUT_CALLING_PACKAGE =
1677                 "android:transaction.hop.shortcut_calling_package";
1678 
1679         // The following keys are used to define the reachability direction after a double tap.
1680         public static final String REACHABILITY_EVENT_X = "android:transaction.reachability_x";
1681         public static final String REACHABILITY_EVENT_Y = "android:transaction.reachability_y";
1682 
1683         @HierarchyOpType
1684         private final int mType;
1685 
1686         // Container we are performing the operation on.
1687         @Nullable
1688         private IBinder mContainer;
1689 
1690         @Nullable
1691         private IBinder[] mContainers;
1692 
1693         // If this is same as mContainer, then only change position, don't reparent.
1694         @Nullable
1695         private IBinder mReparent;
1696 
1697         @Nullable
1698         private InsetsFrameProvider mInsetsFrameProvider;
1699 
1700         @Nullable
1701         private IBinder mInsetsFrameOwner;
1702 
1703         // Moves/reparents to top of parent when {@code true}, otherwise moves/reparents to bottom.
1704         private boolean mToTop;
1705 
1706         private boolean mReparentTopOnly;
1707 
1708         @Nullable
1709         private int[]  mWindowingModes;
1710 
1711         @Nullable
1712         private int[] mActivityTypes;
1713 
1714         @Nullable
1715         private Bundle mLaunchOptions;
1716 
1717         @Nullable
1718         private Bundle mAppCompatOptions;
1719 
1720         @Nullable
1721         private Intent mActivityIntent;
1722 
1723         /** Used as options for {@link #addTaskFragmentOperation}. */
1724         @Nullable
1725         private TaskFragmentOperation mTaskFragmentOperation;
1726 
1727         @Nullable
1728         private KeyguardState mKeyguardState;
1729 
1730         @Nullable
1731         private PendingIntent mPendingIntent;
1732 
1733         @Nullable
1734         private ShortcutInfo mShortcutInfo;
1735 
1736         @Nullable
1737         private Rect mBounds;
1738 
1739         private boolean mIncludingParents;
1740 
1741         private boolean mAlwaysOnTop;
1742 
1743         private boolean mReparentLeafTaskIfRelaunch;
1744 
1745         private boolean mIsTrimmableFromRecents;
1746 
1747         private @InsetsType int mExcludeInsetsTypes;
1748 
1749         private boolean mLaunchAdjacentDisabled;
1750 
1751         @Nullable
1752         private Rect mSafeRegionBounds;
1753 
1754         /** Creates a hierarchy operation for reparenting a container within the hierarchy. */
1755         @NonNull
createForReparent( @onNull IBinder container, @Nullable IBinder reparent, boolean toTop)1756         public static HierarchyOp createForReparent(
1757                 @NonNull IBinder container, @Nullable IBinder reparent, boolean toTop) {
1758             return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REPARENT)
1759                     .setContainer(container)
1760                     .setReparentContainer(reparent)
1761                     .setToTop(toTop)
1762                     .build();
1763         }
1764 
1765         /**
1766          * Creates a a hierarchy op for the reorder operation.
1767          *
1768          * @param container which needs to be reordered
1769          * @param toTop if true, the container reorders
1770          * @param includingParents if true, all the parents in the hierarchy above are also
1771          *                         reoredered among their respective siblings
1772          * @return
1773          */
1774         @NonNull
createForReorder(@onNull IBinder container, boolean toTop, boolean includingParents)1775         public static HierarchyOp createForReorder(@NonNull IBinder container, boolean toTop,
1776                 boolean includingParents) {
1777             return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REORDER)
1778                     .setContainer(container)
1779                     .setReparentContainer(container)
1780                     .setToTop(toTop)
1781                     .setIncludingParents(includingParents)
1782                     .build();
1783         }
1784 
1785         /** Creates a hierarchy op for reparenting child tasks from one container to another. */
1786         @NonNull
createForChildrenTasksReparent(@ullable IBinder currentParent, @Nullable IBinder newParent, @Nullable int[] windowingModes, @Nullable int[] activityTypes, boolean onTop, boolean reparentTopOnly)1787         public static HierarchyOp createForChildrenTasksReparent(@Nullable IBinder currentParent,
1788                 @Nullable IBinder newParent, @Nullable int[] windowingModes,
1789                 @Nullable int[] activityTypes, boolean onTop, boolean reparentTopOnly) {
1790             return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT)
1791                     .setContainer(currentParent)
1792                     .setReparentContainer(newParent)
1793                     .setWindowingModes(windowingModes)
1794                     .setActivityTypes(activityTypes)
1795                     .setToTop(onTop)
1796                     .setReparentTopOnly(reparentTopOnly)
1797                     .build();
1798         }
1799 
1800         /** Creates a hierarchy op for setting the launch root for tasks. */
1801         @NonNull
createForSetLaunchRoot(@ullable IBinder container, @Nullable int[] windowingModes, @Nullable int[] activityTypes)1802         public static HierarchyOp createForSetLaunchRoot(@Nullable IBinder container,
1803                 @Nullable int[] windowingModes, @Nullable int[] activityTypes) {
1804             return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT)
1805                     .setContainer(container)
1806                     .setWindowingModes(windowingModes)
1807                     .setActivityTypes(activityTypes)
1808                     .build();
1809         }
1810 
1811         /** Creates a hierarchy op for setting adjacent root tasks. */
1812         @NonNull
createForAdjacentRoots( @ullable IBinder root1, @Nullable IBinder root2)1813         public static HierarchyOp createForAdjacentRoots(
1814                 @Nullable IBinder root1, @Nullable IBinder root2) {
1815             return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS)
1816                     .setContainer(root1)
1817                     .setReparentContainer(root2)
1818                     .build();
1819         }
1820 
1821         /** Creates a hierarchy op for launching a task. */
1822         @NonNull
createForTaskLaunch(int taskId, @Nullable Bundle options)1823         public static HierarchyOp createForTaskLaunch(int taskId, @Nullable Bundle options) {
1824             final Bundle fullOptions = options == null ? new Bundle() : options;
1825             fullOptions.putInt(LAUNCH_KEY_TASK_ID, taskId);
1826             return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_LAUNCH_TASK)
1827                     .setToTop(true)
1828                     .setLaunchOptions(fullOptions)
1829                     .build();
1830         }
1831 
1832         /** Creates a hierarchy op for starting a shortcut. */
1833         @NonNull
createForStartShortcut(@onNull String callingPackage, @NonNull ShortcutInfo shortcutInfo, @Nullable Bundle options)1834         public static HierarchyOp createForStartShortcut(@NonNull String callingPackage,
1835                 @NonNull ShortcutInfo shortcutInfo, @Nullable Bundle options) {
1836             final Bundle fullOptions = options == null ? new Bundle() : options;
1837             fullOptions.putString(LAUNCH_KEY_SHORTCUT_CALLING_PACKAGE, callingPackage);
1838             return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_START_SHORTCUT)
1839                     .setShortcutInfo(shortcutInfo)
1840                     .setLaunchOptions(fullOptions)
1841                     .build();
1842         }
1843 
1844         /** Creates a hierarchy op for setting launch adjacent flag root. */
1845         @NonNull
createForSetLaunchAdjacentFlagRoot(@ullable IBinder container, boolean clearRoot)1846         public static HierarchyOp createForSetLaunchAdjacentFlagRoot(@Nullable IBinder container,
1847                 boolean clearRoot) {
1848             return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT)
1849                     .setContainer(container)
1850                     .setToTop(clearRoot)
1851                     .build();
1852         }
1853 
1854         /** Creates a hierarchy op for disabling launch adjacent. */
1855         @NonNull
createForSetDisableLaunchAdjacent(@ullable IBinder container, boolean disabled)1856         public static HierarchyOp createForSetDisableLaunchAdjacent(@Nullable IBinder container,
1857                 boolean disabled) {
1858             return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_SET_DISABLE_LAUNCH_ADJACENT)
1859                     .setContainer(container)
1860                     .setLaunchAdjacentDisabled(disabled)
1861                     .build();
1862         }
1863 
1864         /** Creates a hierarchy op for deleting a task **/
1865         @NonNull
createForRemoveTask(@onNull IBinder container)1866         public static HierarchyOp createForRemoveTask(@NonNull IBinder container) {
1867             return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REMOVE_TASK)
1868                     .setContainer(container)
1869                     .build();
1870         }
1871 
1872         /**
1873          * Creates a hierarchy op for deleting a root task
1874          *
1875          * @hide
1876          **/
1877         @NonNull
createForRemoveRootTask(@onNull IBinder container)1878         public static HierarchyOp createForRemoveRootTask(@NonNull IBinder container) {
1879             return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REMOVE_ROOT_TASK)
1880                     .setContainer(container)
1881                     .build();
1882         }
1883 
1884         /** Creates a hierarchy op for clearing adjacent root tasks. */
1885         @NonNull
createForClearAdjacentRoots(@onNull IBinder root)1886         public static HierarchyOp createForClearAdjacentRoots(@NonNull IBinder root) {
1887             return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS)
1888                     .setContainer(root)
1889                     .build();
1890         }
1891 
1892         /** Create a hierarchy op for app compat reachability. */
1893         @NonNull
createForReachability(IBinder container, int taskId, int x, int y)1894         public static HierarchyOp createForReachability(IBinder container, int taskId, int x,
1895                 int y) {
1896             final Bundle appCompatOptions = new Bundle();
1897             appCompatOptions.putInt(LAUNCH_KEY_TASK_ID, taskId);
1898             appCompatOptions.putInt(REACHABILITY_EVENT_X, x);
1899             appCompatOptions.putInt(REACHABILITY_EVENT_Y, y);
1900             return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_APP_COMPAT_REACHABILITY)
1901                     .setAppCompatOptions(appCompatOptions)
1902                     .setContainer(container)
1903                     .build();
1904         }
1905 
1906         /** Create a hierarchy op for setting a task non-trimmable by recents. */
1907         @NonNull
1908         @FlaggedApi(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
createForSetTaskTrimmableFromRecents(@onNull IBinder container, boolean isTrimmableFromRecents)1909         public static HierarchyOp createForSetTaskTrimmableFromRecents(@NonNull IBinder container,
1910                 boolean isTrimmableFromRecents) {
1911             return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_SET_IS_TRIMMABLE)
1912                     .setContainer(container)
1913                     .setIsTrimmableFromRecents(isTrimmableFromRecents)
1914                     .build();
1915         }
1916 
1917         /** Creates a hierarchy op for setting the safe region bounds. */
1918         @NonNull
1919         @FlaggedApi(Flags.FLAG_SAFE_REGION_LETTERBOXING)
createForSetSafeRegionBounds(@onNull IBinder container, @Nullable Rect safeRegionBounds)1920         public static HierarchyOp createForSetSafeRegionBounds(@NonNull IBinder container,
1921                 @Nullable Rect safeRegionBounds) {
1922             return new Builder(HIERARCHY_OP_TYPE_SET_SAFE_REGION_BOUNDS)
1923                     .setContainer(container)
1924                     .setSafeRegionBounds(safeRegionBounds)
1925                     .build();
1926         }
1927 
1928         /** Only creates through {@link Builder}. */
HierarchyOp(@ierarchyOpType int type)1929         private HierarchyOp(@HierarchyOpType int type) {
1930             mType = type;
1931         }
1932 
HierarchyOp(@onNull HierarchyOp copy)1933         public HierarchyOp(@NonNull HierarchyOp copy) {
1934             mType = copy.mType;
1935             mContainer = copy.mContainer;
1936             mContainers = copy.mContainers;
1937             mBounds = copy.mBounds;
1938             mIncludingParents = copy.mIncludingParents;
1939             mReparent = copy.mReparent;
1940             mInsetsFrameProvider = copy.mInsetsFrameProvider;
1941             mInsetsFrameOwner = copy.mInsetsFrameOwner;
1942             mToTop = copy.mToTop;
1943             mReparentTopOnly = copy.mReparentTopOnly;
1944             mWindowingModes = copy.mWindowingModes;
1945             mActivityTypes = copy.mActivityTypes;
1946             mLaunchOptions = copy.mLaunchOptions;
1947             mAppCompatOptions = copy.mAppCompatOptions;
1948             mActivityIntent = copy.mActivityIntent;
1949             mTaskFragmentOperation = copy.mTaskFragmentOperation;
1950             mKeyguardState = copy.mKeyguardState;
1951             mPendingIntent = copy.mPendingIntent;
1952             mShortcutInfo = copy.mShortcutInfo;
1953             mAlwaysOnTop = copy.mAlwaysOnTop;
1954             mReparentLeafTaskIfRelaunch = copy.mReparentLeafTaskIfRelaunch;
1955             mIsTrimmableFromRecents = copy.mIsTrimmableFromRecents;
1956             mExcludeInsetsTypes = copy.mExcludeInsetsTypes;
1957             mLaunchAdjacentDisabled = copy.mLaunchAdjacentDisabled;
1958             mSafeRegionBounds = copy.mSafeRegionBounds;
1959         }
1960 
HierarchyOp(@onNull Parcel in)1961         private HierarchyOp(@NonNull Parcel in) {
1962             mType = in.readInt();
1963             mContainer = in.readStrongBinder();
1964             mContainers = in.createBinderArray();
1965             mBounds = in.readTypedObject(Rect.CREATOR);
1966             mIncludingParents = in.readBoolean();
1967             mReparent = in.readStrongBinder();
1968             mInsetsFrameProvider = in.readTypedObject(InsetsFrameProvider.CREATOR);
1969             mInsetsFrameOwner = in.readStrongBinder();
1970             mToTop = in.readBoolean();
1971             mReparentTopOnly = in.readBoolean();
1972             mWindowingModes = in.createIntArray();
1973             mActivityTypes = in.createIntArray();
1974             mLaunchOptions = in.readBundle();
1975             mAppCompatOptions = in.readBundle(getClass().getClassLoader());
1976             mActivityIntent = in.readTypedObject(Intent.CREATOR);
1977             mTaskFragmentOperation = in.readTypedObject(TaskFragmentOperation.CREATOR);
1978             mKeyguardState = in.readTypedObject(KeyguardState.CREATOR);
1979             mPendingIntent = in.readTypedObject(PendingIntent.CREATOR);
1980             mShortcutInfo = in.readTypedObject(ShortcutInfo.CREATOR);
1981             mAlwaysOnTop = in.readBoolean();
1982             mReparentLeafTaskIfRelaunch = in.readBoolean();
1983             mIsTrimmableFromRecents = in.readBoolean();
1984             mExcludeInsetsTypes = in.readInt();
1985             mLaunchAdjacentDisabled = in.readBoolean();
1986             mSafeRegionBounds = in.readTypedObject(Rect.CREATOR);
1987         }
1988 
1989         @HierarchyOpType
getType()1990         public int getType() {
1991             return mType;
1992         }
1993 
isReparent()1994         public boolean isReparent() {
1995             return mType == HIERARCHY_OP_TYPE_REPARENT;
1996         }
1997 
1998         @Nullable
getNewParent()1999         public IBinder getNewParent() {
2000             return mReparent;
2001         }
2002 
2003         @Nullable
getInsetsFrameProvider()2004         public InsetsFrameProvider getInsetsFrameProvider() {
2005             return mInsetsFrameProvider;
2006         }
2007 
2008         @Nullable
getInsetsFrameOwner()2009         public IBinder getInsetsFrameOwner() {
2010             return mInsetsFrameOwner;
2011         }
2012 
2013         @NonNull
getContainer()2014         public IBinder getContainer() {
2015             return mContainer;
2016         }
2017 
2018         @NonNull
getContainers()2019         public IBinder[] getContainers() {
2020             return mContainers;
2021         }
2022 
getToTop()2023         public boolean getToTop() {
2024             return mToTop;
2025         }
2026 
getReparentTopOnly()2027         public boolean getReparentTopOnly() {
2028             return mReparentTopOnly;
2029         }
2030 
2031         @Nullable
getWindowingModes()2032         public int[] getWindowingModes() {
2033             return mWindowingModes;
2034         }
2035 
2036         @Nullable
getActivityTypes()2037         public int[] getActivityTypes() {
2038             return mActivityTypes;
2039         }
2040 
2041         @Nullable
getLaunchOptions()2042         public Bundle getLaunchOptions() {
2043             return mLaunchOptions;
2044         }
2045 
2046         @Nullable
getAppCompatOptions()2047         public Bundle getAppCompatOptions() {
2048             return mAppCompatOptions;
2049         }
2050 
2051         @Nullable
getActivityIntent()2052         public Intent getActivityIntent() {
2053             return mActivityIntent;
2054         }
2055 
isAlwaysOnTop()2056         public boolean isAlwaysOnTop() {
2057             return mAlwaysOnTop;
2058         }
2059 
isReparentLeafTaskIfRelaunch()2060         public boolean isReparentLeafTaskIfRelaunch() {
2061             return mReparentLeafTaskIfRelaunch;
2062         }
2063 
2064         @Nullable
getTaskFragmentOperation()2065         public TaskFragmentOperation getTaskFragmentOperation() {
2066             return mTaskFragmentOperation;
2067         }
2068 
2069         @Nullable
getKeyguardState()2070         public KeyguardState getKeyguardState() {
2071             return mKeyguardState;
2072         }
2073 
2074         @Nullable
getPendingIntent()2075         public PendingIntent getPendingIntent() {
2076             return mPendingIntent;
2077         }
2078 
2079         @Nullable
getShortcutInfo()2080         public ShortcutInfo getShortcutInfo() {
2081             return mShortcutInfo;
2082         }
2083 
2084         @NonNull
getBounds()2085         public Rect getBounds() {
2086             return mBounds;
2087         }
2088 
2089         /** Denotes whether the parents should also be included in the op. */
includingParents()2090         public boolean includingParents() {
2091             return mIncludingParents;
2092         }
2093 
2094         /** Denotes whether the task can be trimmable from recents */
isTrimmableFromRecents()2095         public boolean isTrimmableFromRecents() {
2096             return mIsTrimmableFromRecents;
2097         }
2098 
getExcludeInsetsTypes()2099         public @InsetsType int getExcludeInsetsTypes() {
2100             return mExcludeInsetsTypes;
2101         }
2102 
2103         /** Denotes whether launch-adjacent flag is respected from this task or its children */
isLaunchAdjacentDisabled()2104         public boolean isLaunchAdjacentDisabled() {
2105             return mLaunchAdjacentDisabled;
2106         }
2107 
2108         /** Denotes the safe region bounds */
2109         @Nullable
getSafeRegionBounds()2110         public Rect getSafeRegionBounds() {
2111             return mSafeRegionBounds;
2112         }
2113 
2114         /** Gets a string representation of a hierarchy-op type. */
hopToString(@ierarchyOpType int type)2115         public static String hopToString(@HierarchyOpType int type) {
2116             switch (type) {
2117                 case HIERARCHY_OP_TYPE_REPARENT: return "reparent";
2118                 case HIERARCHY_OP_TYPE_REORDER: return "reorder";
2119                 case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT: return "childrenTasksReparent";
2120                 case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: return "setLaunchRoot";
2121                 case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS: return "setAdjacentRoots";
2122                 case HIERARCHY_OP_TYPE_LAUNCH_TASK: return "launchTask";
2123                 case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT: return "setAdjacentFlagRoot";
2124                 case HIERARCHY_OP_TYPE_SET_DISABLE_LAUNCH_ADJACENT:
2125                     return "setDisableLaunchAdjacent";
2126                 case HIERARCHY_OP_TYPE_PENDING_INTENT: return "pendingIntent";
2127                 case HIERARCHY_OP_TYPE_START_SHORTCUT: return "startShortcut";
2128                 case HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER: return "restoreTransientOrder";
2129                 case HIERARCHY_OP_TYPE_ADD_INSETS_FRAME_PROVIDER: return "addInsetsFrameProvider";
2130                 case HIERARCHY_OP_TYPE_REMOVE_INSETS_FRAME_PROVIDER:
2131                     return "removeInsetsFrameProvider";
2132                 case HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP: return "setAlwaysOnTop";
2133                 case HIERARCHY_OP_TYPE_REMOVE_TASK: return "removeTask";
2134                 case HIERARCHY_OP_TYPE_REMOVE_ROOT_TASK: return "removeRootTask";
2135                 case HIERARCHY_OP_TYPE_FINISH_ACTIVITY: return "finishActivity";
2136                 case HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS: return "clearAdjacentRoots";
2137                 case HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH:
2138                     return "setReparentLeafTaskIfRelaunch";
2139                 case HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION:
2140                     return "addTaskFragmentOperation";
2141                 case HIERARCHY_OP_TYPE_MOVE_PIP_ACTIVITY_TO_PINNED_TASK:
2142                     return "movePipActivityToPinnedTask";
2143                 case HIERARCHY_OP_TYPE_SET_IS_TRIMMABLE: return "setIsTrimmable";
2144                 case HIERARCHY_OP_TYPE_RESTORE_BACK_NAVIGATION: return "restoreBackNav";
2145                 case HIERARCHY_OP_TYPE_SET_EXCLUDE_INSETS_TYPES: return "setExcludeInsetsTypes";
2146                 case HIERARCHY_OP_TYPE_SET_KEYGUARD_STATE: return "setKeyguardState";
2147                 case HIERARCHY_OP_TYPE_SET_SAFE_REGION_BOUNDS: return "setSafeRegionBounds";
2148                 default: return "HOP(" + type + ")";
2149             }
2150         }
2151 
2152         @Override
toString()2153         public String toString() {
2154             StringBuilder sb = new StringBuilder();
2155             sb.append("{").append(hopToString(mType)).append(": ");
2156             switch (mType) {
2157                 case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT:
2158                     sb.append("from=").append(mContainer).append(" to=").append(mReparent)
2159                             .append(" mToTop=").append(mToTop)
2160                             .append(" mReparentTopOnly=").append(mReparentTopOnly)
2161                             .append(" mWindowingMode=").append(Arrays.toString(mWindowingModes))
2162                             .append(" mActivityType=").append(Arrays.toString(mActivityTypes));
2163                     break;
2164                 case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT:
2165                     sb.append("container=").append(mContainer)
2166                             .append(" mWindowingMode=").append(Arrays.toString(mWindowingModes))
2167                             .append(" mActivityType=").append(Arrays.toString(mActivityTypes));
2168                     break;
2169                 case HIERARCHY_OP_TYPE_REPARENT:
2170                     sb.append(mContainer).append(" to ").append(mToTop ? "top of " : "bottom of ")
2171                             .append(mReparent);
2172                     break;
2173                 case HIERARCHY_OP_TYPE_REORDER:
2174                     sb.append(mContainer).append(" to ").append(mToTop ? "top" : "bottom");
2175                     break;
2176                 case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS:
2177                     for (IBinder container : mContainers) {
2178                         if (container == mContainers[0]) {
2179                             sb.append("adjacentRoots=").append(container);
2180                         } else {
2181                             sb.append(", ").append(container);
2182                         }
2183                     }
2184                     break;
2185                 case HIERARCHY_OP_TYPE_LAUNCH_TASK:
2186                     sb.append(mLaunchOptions);
2187                     break;
2188                 case HIERARCHY_OP_TYPE_APP_COMPAT_REACHABILITY:
2189                     sb.append(mAppCompatOptions);
2190                     break;
2191                 case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT:
2192                     sb.append("container=").append(mContainer).append(" clearRoot=").append(mToTop);
2193                     break;
2194                 case HIERARCHY_OP_TYPE_SET_DISABLE_LAUNCH_ADJACENT:
2195                     sb.append("container=").append(mContainer).append(" disabled=")
2196                             .append(mLaunchAdjacentDisabled);
2197                     break;
2198                 case HIERARCHY_OP_TYPE_START_SHORTCUT:
2199                     sb.append("options=").append(mLaunchOptions)
2200                             .append(" info=").append(mShortcutInfo);
2201                     break;
2202                 case HIERARCHY_OP_TYPE_PENDING_INTENT:
2203                     sb.append("options=").append(mLaunchOptions);
2204                     break;
2205                 case HIERARCHY_OP_TYPE_ADD_INSETS_FRAME_PROVIDER:
2206                 case HIERARCHY_OP_TYPE_REMOVE_INSETS_FRAME_PROVIDER:
2207                     sb.append("container=").append(mContainer)
2208                             .append(" provider=").append(mInsetsFrameProvider)
2209                             .append(" owner=").append(mInsetsFrameOwner);
2210                     break;
2211                 case HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP:
2212                     sb.append("container=").append(mContainer)
2213                             .append(" alwaysOnTop=").append(mAlwaysOnTop);
2214                     break;
2215                 case HIERARCHY_OP_TYPE_REMOVE_TASK:
2216                     sb.append("task=").append(mContainer);
2217                     break;
2218                 case HIERARCHY_OP_TYPE_REMOVE_ROOT_TASK:
2219                     sb.append("rootTask=").append(mContainer);
2220                     break;
2221                 case HIERARCHY_OP_TYPE_FINISH_ACTIVITY:
2222                     sb.append("activity=").append(mContainer);
2223                     break;
2224                 case HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS:
2225                     sb.append("container=").append(mContainer);
2226                     break;
2227                 case HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH:
2228                     sb.append("container= ").append(mContainer)
2229                             .append(" reparentLeafTaskIfRelaunch= ")
2230                             .append(mReparentLeafTaskIfRelaunch);
2231                     break;
2232                 case HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION:
2233                     sb.append("fragmentToken= ").append(mContainer)
2234                             .append(" operation= ").append(mTaskFragmentOperation);
2235                     break;
2236                 case HIERARCHY_OP_TYPE_SET_EXCLUDE_INSETS_TYPES:
2237                     sb.append("container= ").append(mContainer)
2238                             .append(" mExcludeInsetsTypes= ")
2239                             .append(WindowInsets.Type.toString(mExcludeInsetsTypes));
2240                     break;
2241                 case HIERARCHY_OP_TYPE_SET_KEYGUARD_STATE:
2242                     sb.append("KeyguardState= ").append(mKeyguardState);
2243                     break;
2244                 case HIERARCHY_OP_TYPE_SET_IS_TRIMMABLE:
2245                     sb.append("container= ").append(mContainer)
2246                             .append(" isTrimmable= ")
2247                             .append(mIsTrimmableFromRecents);
2248                     break;
2249                 case HIERARCHY_OP_TYPE_SET_SAFE_REGION_BOUNDS:
2250                     sb.append("container= ").append(mContainer)
2251                             .append(" safeRegionBounds= ")
2252                             .append(mSafeRegionBounds);
2253                 default:
2254                     sb.append("container=").append(mContainer)
2255                             .append(" reparent=").append(mReparent)
2256                             .append(" mToTop=").append(mToTop)
2257                             .append(" mWindowingMode=").append(Arrays.toString(mWindowingModes))
2258                             .append(" mActivityType=").append(Arrays.toString(mActivityTypes));
2259             }
2260             return sb.append("}").toString();
2261         }
2262 
2263         @Override
writeToParcel(@onNull Parcel dest, int flags)2264         public void writeToParcel(@NonNull Parcel dest, int flags) {
2265             dest.writeInt(mType);
2266             dest.writeStrongBinder(mContainer);
2267             dest.writeBinderArray(mContainers);
2268             dest.writeTypedObject(mBounds, flags);
2269             dest.writeBoolean(mIncludingParents);
2270             dest.writeStrongBinder(mReparent);
2271             dest.writeTypedObject(mInsetsFrameProvider, flags);
2272             dest.writeStrongBinder(mInsetsFrameOwner);
2273             dest.writeBoolean(mToTop);
2274             dest.writeBoolean(mReparentTopOnly);
2275             dest.writeIntArray(mWindowingModes);
2276             dest.writeIntArray(mActivityTypes);
2277             dest.writeBundle(mLaunchOptions);
2278             dest.writeBundle(mAppCompatOptions);
2279             dest.writeTypedObject(mActivityIntent, flags);
2280             dest.writeTypedObject(mTaskFragmentOperation, flags);
2281             dest.writeTypedObject(mKeyguardState, flags);
2282             dest.writeTypedObject(mPendingIntent, flags);
2283             dest.writeTypedObject(mShortcutInfo, flags);
2284             dest.writeBoolean(mAlwaysOnTop);
2285             dest.writeBoolean(mReparentLeafTaskIfRelaunch);
2286             dest.writeBoolean(mIsTrimmableFromRecents);
2287             dest.writeInt(mExcludeInsetsTypes);
2288             dest.writeBoolean(mLaunchAdjacentDisabled);
2289             dest.writeTypedObject(mSafeRegionBounds, flags);
2290         }
2291 
2292         @Override
describeContents()2293         public int describeContents() {
2294             return 0;
2295         }
2296 
2297         public static final Creator<HierarchyOp> CREATOR = new Creator<HierarchyOp>() {
2298             @Override
2299             public HierarchyOp createFromParcel(@NonNull Parcel in) {
2300                 return new HierarchyOp(in);
2301             }
2302 
2303             @Override
2304             public HierarchyOp[] newArray(int size) {
2305                 return new HierarchyOp[size];
2306             }
2307         };
2308 
2309         private static class Builder {
2310 
2311             @HierarchyOpType
2312             private final int mType;
2313 
2314             @Nullable
2315             private IBinder mContainer;
2316 
2317             @Nullable
2318             private IBinder[] mContainers;
2319 
2320             @Nullable
2321             private IBinder mReparent;
2322 
2323             @Nullable
2324             private InsetsFrameProvider mInsetsFrameProvider;
2325 
2326             @Nullable
2327             private IBinder mInsetsFrameOwner;
2328 
2329             private boolean mToTop;
2330 
2331             private boolean mReparentTopOnly;
2332 
2333             @Nullable
2334             private int[] mWindowingModes;
2335 
2336             @Nullable
2337             private int[] mActivityTypes;
2338 
2339             @Nullable
2340             private Bundle mLaunchOptions;
2341 
2342             @Nullable
2343             private Bundle mAppCompatOptions;
2344 
2345             @Nullable
2346             private Intent mActivityIntent;
2347 
2348             @Nullable
2349             private TaskFragmentOperation mTaskFragmentOperation;
2350 
2351             @Nullable
2352             private KeyguardState mKeyguardState;
2353 
2354             @Nullable
2355             private PendingIntent mPendingIntent;
2356 
2357             @Nullable
2358             private ShortcutInfo mShortcutInfo;
2359 
2360             @Nullable
2361             private Rect mBounds;
2362 
2363             private boolean mIncludingParents;
2364 
2365             private boolean mAlwaysOnTop;
2366 
2367             private boolean mReparentLeafTaskIfRelaunch;
2368 
2369             private boolean mIsTrimmableFromRecents;
2370 
2371             private @InsetsType int mExcludeInsetsTypes;
2372 
2373             private boolean mLaunchAdjacentDisabled;
2374 
2375             @Nullable
2376             private Rect mSafeRegionBounds;
2377 
Builder(@ierarchyOpType int type)2378             Builder(@HierarchyOpType int type) {
2379                 mType = type;
2380             }
2381 
setContainer(@ullable IBinder container)2382             Builder setContainer(@Nullable IBinder container) {
2383                 mContainer = container;
2384                 return this;
2385             }
2386 
setContainers(@ullable IBinder[] containers)2387             Builder setContainers(@Nullable IBinder[] containers) {
2388                 mContainers = containers;
2389                 return this;
2390             }
2391 
setReparentContainer(@ullable IBinder reparentContainer)2392             Builder setReparentContainer(@Nullable IBinder reparentContainer) {
2393                 mReparent = reparentContainer;
2394                 return this;
2395             }
2396 
setInsetsFrameProvider(InsetsFrameProvider provider)2397             Builder setInsetsFrameProvider(InsetsFrameProvider provider) {
2398                 mInsetsFrameProvider = provider;
2399                 return this;
2400             }
2401 
setInsetsFrameOwner(@ullable IBinder owner)2402             Builder setInsetsFrameOwner(@Nullable IBinder owner) {
2403                 mInsetsFrameOwner = owner;
2404                 return this;
2405             }
2406 
setToTop(boolean toTop)2407             Builder setToTop(boolean toTop) {
2408                 mToTop = toTop;
2409                 return this;
2410             }
2411 
setReparentTopOnly(boolean reparentTopOnly)2412             Builder setReparentTopOnly(boolean reparentTopOnly) {
2413                 mReparentTopOnly = reparentTopOnly;
2414                 return this;
2415             }
2416 
setWindowingModes(@ullable int[] windowingModes)2417             Builder setWindowingModes(@Nullable int[] windowingModes) {
2418                 mWindowingModes = windowingModes;
2419                 return this;
2420             }
2421 
setActivityTypes(@ullable int[] activityTypes)2422             Builder setActivityTypes(@Nullable int[] activityTypes) {
2423                 mActivityTypes = activityTypes;
2424                 return this;
2425             }
2426 
setLaunchOptions(@ullable Bundle launchOptions)2427             Builder setLaunchOptions(@Nullable Bundle launchOptions) {
2428                 mLaunchOptions = launchOptions;
2429                 return this;
2430             }
2431 
setAppCompatOptions(@ullable Bundle appCompatOptions)2432             Builder setAppCompatOptions(@Nullable Bundle appCompatOptions) {
2433                 mAppCompatOptions = appCompatOptions;
2434                 return this;
2435             }
2436 
setActivityIntent(@ullable Intent activityIntent)2437             Builder setActivityIntent(@Nullable Intent activityIntent) {
2438                 mActivityIntent = activityIntent;
2439                 return this;
2440             }
2441 
setPendingIntent(@ullable PendingIntent sender)2442             Builder setPendingIntent(@Nullable PendingIntent sender) {
2443                 mPendingIntent = sender;
2444                 return this;
2445             }
2446 
setAlwaysOnTop(boolean alwaysOnTop)2447             Builder setAlwaysOnTop(boolean alwaysOnTop) {
2448                 mAlwaysOnTop = alwaysOnTop;
2449                 return this;
2450             }
2451 
setTaskFragmentOperation( @ullable TaskFragmentOperation taskFragmentOperation)2452             Builder setTaskFragmentOperation(
2453                     @Nullable TaskFragmentOperation taskFragmentOperation) {
2454                 mTaskFragmentOperation = taskFragmentOperation;
2455                 return this;
2456             }
2457 
setKeyguardState( @ullable KeyguardState keyguardState)2458             Builder setKeyguardState(
2459                     @Nullable KeyguardState keyguardState) {
2460                 mKeyguardState = keyguardState;
2461                 return this;
2462             }
2463 
setReparentLeafTaskIfRelaunch(boolean reparentLeafTaskIfRelaunch)2464             Builder setReparentLeafTaskIfRelaunch(boolean reparentLeafTaskIfRelaunch) {
2465                 mReparentLeafTaskIfRelaunch = reparentLeafTaskIfRelaunch;
2466                 return this;
2467             }
2468 
setShortcutInfo(@ullable ShortcutInfo shortcutInfo)2469             Builder setShortcutInfo(@Nullable ShortcutInfo shortcutInfo) {
2470                 mShortcutInfo = shortcutInfo;
2471                 return this;
2472             }
2473 
setBounds(@onNull Rect bounds)2474             Builder setBounds(@NonNull Rect bounds) {
2475                 mBounds = bounds;
2476                 return this;
2477             }
2478 
setIncludingParents(boolean value)2479             Builder setIncludingParents(boolean value) {
2480                 mIncludingParents = value;
2481                 return this;
2482             }
2483 
setIsTrimmableFromRecents(boolean isTrimmableFromRecents)2484             Builder setIsTrimmableFromRecents(boolean isTrimmableFromRecents) {
2485                 mIsTrimmableFromRecents = isTrimmableFromRecents;
2486                 return this;
2487             }
2488 
setExcludeInsetsTypes(@nsetsType int excludeInsetsTypes)2489             Builder setExcludeInsetsTypes(@InsetsType int excludeInsetsTypes) {
2490                 mExcludeInsetsTypes = excludeInsetsTypes;
2491                 return this;
2492             }
2493 
setLaunchAdjacentDisabled(boolean disabled)2494             Builder setLaunchAdjacentDisabled(boolean disabled) {
2495                 mLaunchAdjacentDisabled = disabled;
2496                 return this;
2497             }
2498 
setSafeRegionBounds(Rect safeRegionBounds)2499             Builder setSafeRegionBounds(Rect safeRegionBounds) {
2500                 mSafeRegionBounds = safeRegionBounds;
2501                 return this;
2502             }
2503 
2504             @NonNull
build()2505             HierarchyOp build() {
2506                 final HierarchyOp hierarchyOp = new HierarchyOp(mType);
2507                 hierarchyOp.mContainer = mContainer;
2508                 hierarchyOp.mContainers = mContainers;
2509                 hierarchyOp.mReparent = mReparent;
2510                 hierarchyOp.mWindowingModes = mWindowingModes != null
2511                         ? Arrays.copyOf(mWindowingModes, mWindowingModes.length)
2512                         : null;
2513                 hierarchyOp.mActivityTypes = mActivityTypes != null
2514                         ? Arrays.copyOf(mActivityTypes, mActivityTypes.length)
2515                         : null;
2516                 hierarchyOp.mInsetsFrameProvider = mInsetsFrameProvider;
2517                 hierarchyOp.mInsetsFrameOwner = mInsetsFrameOwner;
2518                 hierarchyOp.mToTop = mToTop;
2519                 hierarchyOp.mReparentTopOnly = mReparentTopOnly;
2520                 hierarchyOp.mLaunchOptions = mLaunchOptions;
2521                 hierarchyOp.mAppCompatOptions = mAppCompatOptions;
2522                 hierarchyOp.mActivityIntent = mActivityIntent;
2523                 hierarchyOp.mPendingIntent = mPendingIntent;
2524                 hierarchyOp.mAlwaysOnTop = mAlwaysOnTop;
2525                 hierarchyOp.mTaskFragmentOperation = mTaskFragmentOperation;
2526                 hierarchyOp.mKeyguardState = mKeyguardState;
2527                 hierarchyOp.mShortcutInfo = mShortcutInfo;
2528                 hierarchyOp.mBounds = mBounds;
2529                 hierarchyOp.mIncludingParents = mIncludingParents;
2530                 hierarchyOp.mReparentLeafTaskIfRelaunch = mReparentLeafTaskIfRelaunch;
2531                 hierarchyOp.mIsTrimmableFromRecents = mIsTrimmableFromRecents;
2532                 hierarchyOp.mExcludeInsetsTypes = mExcludeInsetsTypes;
2533                 hierarchyOp.mLaunchAdjacentDisabled = mLaunchAdjacentDisabled;
2534                 hierarchyOp.mSafeRegionBounds = mSafeRegionBounds;
2535                 return hierarchyOp;
2536             }
2537         }
2538     }
2539 
2540     /**
2541      * Helper class for building an options Bundle that can be used to set adjacent rules of
2542      * TaskFragments.
2543      */
2544     public static class TaskFragmentAdjacentParams {
2545         private static final String DELAY_PRIMARY_LAST_ACTIVITY_REMOVAL =
2546                 "android:transaction.adjacent.option.delay_primary_removal";
2547         private static final String DELAY_SECONDARY_LAST_ACTIVITY_REMOVAL =
2548                 "android:transaction.adjacent.option.delay_secondary_removal";
2549 
2550         private boolean mDelayPrimaryLastActivityRemoval;
2551         private boolean mDelaySecondaryLastActivityRemoval;
2552 
TaskFragmentAdjacentParams()2553         public TaskFragmentAdjacentParams() {
2554         }
2555 
TaskFragmentAdjacentParams(@onNull Bundle bundle)2556         public TaskFragmentAdjacentParams(@NonNull Bundle bundle) {
2557             mDelayPrimaryLastActivityRemoval = bundle.getBoolean(
2558                     DELAY_PRIMARY_LAST_ACTIVITY_REMOVAL);
2559             mDelaySecondaryLastActivityRemoval = bundle.getBoolean(
2560                     DELAY_SECONDARY_LAST_ACTIVITY_REMOVAL);
2561         }
2562 
2563         /** @see #shouldDelayPrimaryLastActivityRemoval() */
setShouldDelayPrimaryLastActivityRemoval(boolean delay)2564         public void setShouldDelayPrimaryLastActivityRemoval(boolean delay) {
2565             mDelayPrimaryLastActivityRemoval = delay;
2566         }
2567 
2568         /** @see #shouldDelaySecondaryLastActivityRemoval() */
setShouldDelaySecondaryLastActivityRemoval(boolean delay)2569         public void setShouldDelaySecondaryLastActivityRemoval(boolean delay) {
2570             mDelaySecondaryLastActivityRemoval = delay;
2571         }
2572 
2573         /**
2574          * Whether to delay the last activity of the primary adjacent TaskFragment being immediately
2575          * removed while finishing.
2576          * <p>
2577          * It is usually set to {@code true} to give organizer an opportunity to perform other
2578          * actions or animations. An example is to finish together with the adjacent TaskFragment.
2579          * </p>
2580          */
shouldDelayPrimaryLastActivityRemoval()2581         public boolean shouldDelayPrimaryLastActivityRemoval() {
2582             return mDelayPrimaryLastActivityRemoval;
2583         }
2584 
2585         /**
2586          * Similar to {@link #shouldDelayPrimaryLastActivityRemoval()}, but for the secondary
2587          * TaskFragment.
2588          */
shouldDelaySecondaryLastActivityRemoval()2589         public boolean shouldDelaySecondaryLastActivityRemoval() {
2590             return mDelaySecondaryLastActivityRemoval;
2591         }
2592 
2593         @NonNull
toBundle()2594         Bundle toBundle() {
2595             final Bundle b = new Bundle();
2596             b.putBoolean(DELAY_PRIMARY_LAST_ACTIVITY_REMOVAL, mDelayPrimaryLastActivityRemoval);
2597             b.putBoolean(DELAY_SECONDARY_LAST_ACTIVITY_REMOVAL, mDelaySecondaryLastActivityRemoval);
2598             return b;
2599         }
2600     }
2601 }
2602