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