1 /*
2  * Copyright (C) 2018 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.view;
18 
19 import static android.graphics.GraphicsProtos.dumpPointProto;
20 import static android.view.RemoteAnimationTargetProto.CLIP_RECT;
21 import static android.view.RemoteAnimationTargetProto.CONTENT_INSETS;
22 import static android.view.RemoteAnimationTargetProto.IS_TRANSLUCENT;
23 import static android.view.RemoteAnimationTargetProto.LEASH;
24 import static android.view.RemoteAnimationTargetProto.LOCAL_BOUNDS;
25 import static android.view.RemoteAnimationTargetProto.MODE;
26 import static android.view.RemoteAnimationTargetProto.POSITION;
27 import static android.view.RemoteAnimationTargetProto.PREFIX_ORDER_INDEX;
28 import static android.view.RemoteAnimationTargetProto.SCREEN_SPACE_BOUNDS;
29 import static android.view.RemoteAnimationTargetProto.SOURCE_CONTAINER_BOUNDS;
30 import static android.view.RemoteAnimationTargetProto.START_BOUNDS;
31 import static android.view.RemoteAnimationTargetProto.START_LEASH;
32 import static android.view.RemoteAnimationTargetProto.TASK_ID;
33 import static android.view.RemoteAnimationTargetProto.WINDOW_CONFIGURATION;
34 import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
35 
36 import android.annotation.ColorInt;
37 import android.annotation.IntDef;
38 import android.annotation.Nullable;
39 import android.app.ActivityManager;
40 import android.app.TaskInfo;
41 import android.app.WindowConfiguration;
42 import android.compat.annotation.UnsupportedAppUsage;
43 import android.graphics.Point;
44 import android.graphics.Rect;
45 import android.os.Build;
46 import android.os.Parcel;
47 import android.os.Parcelable;
48 import android.util.proto.ProtoOutputStream;
49 import android.window.TaskSnapshot;
50 
51 import java.io.PrintWriter;
52 import java.lang.annotation.Retention;
53 import java.lang.annotation.RetentionPolicy;
54 
55 /**
56  * Describes an activity to be animated as part of a remote animation.
57  *
58  * @hide
59  */
60 public class RemoteAnimationTarget implements Parcelable {
61 
62     /**
63      * The app is in the set of opening apps of this transition.
64      */
65     public static final int MODE_OPENING = 0;
66 
67     /**
68      * The app is in the set of closing apps of this transition.
69      */
70     public static final int MODE_CLOSING = 1;
71 
72     /**
73      * The app is in the set of resizing apps (eg. mode change) of this transition.
74      */
75     public static final int MODE_CHANGING = 2;
76 
77     @IntDef(prefix = { "MODE_" }, value = {
78             MODE_OPENING,
79             MODE_CLOSING,
80             MODE_CHANGING
81     })
82     @Retention(RetentionPolicy.SOURCE)
83     public @interface Mode {}
84 
85     /**
86      * The {@link Mode} to describe whether this app is opening or closing.
87      */
88     @UnsupportedAppUsage
89     public final @Mode int mode;
90 
91     /**
92      * The id of the task this app belongs to.
93      */
94     @UnsupportedAppUsage
95     public final int taskId;
96 
97     /**
98      * The {@link SurfaceControl} object to actually control the transform of the app.
99      */
100     @UnsupportedAppUsage
101     public final SurfaceControl leash;
102 
103     /**
104      * The {@link SurfaceControl} for the starting state of a target if this transition is
105      * MODE_CHANGING, {@code null)} otherwise. This is relative to the app window.
106      */
107     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
108     public final SurfaceControl startLeash;
109 
110     /**
111      * Whether the app is translucent and may reveal apps behind.
112      */
113     @UnsupportedAppUsage
114     public final boolean isTranslucent;
115 
116     /**
117      * The clip rect window manager applies when clipping the app's main surface in screen space
118      * coordinates. This is just a hint to the animation runner: If running a clip-rect animation,
119      * anything that extends beyond these bounds will not have any effect. This implies that any
120      * clip-rect animation should likely stop at these bounds.
121      */
122     @UnsupportedAppUsage
123     public final Rect clipRect;
124 
125     /**
126      * The insets of the main app window.
127      */
128     @UnsupportedAppUsage
129     public final Rect contentInsets;
130 
131     /**
132      * The index of the element in the tree in prefix order. This should be used for z-layering
133      * to preserve original z-layer order in the hierarchy tree assuming no "boosting" needs to
134      * happen.
135      * @deprecated WindowManager may set a z-order different from the prefix order, and has set the
136      *             correct layer for the animation leash already, so this should not be used for
137      *             layer any more.
138      */
139     @Deprecated
140     @UnsupportedAppUsage
141     public final int prefixOrderIndex;
142 
143     /**
144      * The source position of the app, in screen spaces coordinates. If the position of the leash
145      * is modified from the controlling app, any animation transform needs to be offset by this
146      * amount.
147      * @deprecated Use {@link #localBounds} instead.
148      */
149     @Deprecated
150     @UnsupportedAppUsage
151     public final Point position;
152 
153     /**
154      * Bounds of the target relative to its parent.
155      * When the app target animating on its parent, we need to use the local coordinates relative to
156      * its parent with {@code localBounds.left} & {@code localBounds.top} rather than using
157      * {@code position} in screen coordinates.
158      */
159     public final Rect localBounds;
160 
161     /**
162      * The bounds of the source container the app lives in, in screen space coordinates. If the crop
163      * of the leash is modified from the controlling app, it needs to take the source container
164      * bounds into account when calculating the crop.
165      * @deprecated Renamed to {@link #screenSpaceBounds}
166      */
167     @Deprecated
168     @UnsupportedAppUsage
169     public final Rect sourceContainerBounds;
170 
171     /**
172      * Bounds of the target relative to the screen. If the crop of the leash is modified from the
173      * controlling app, it needs to take the screen space bounds into account when calculating the
174      * crop.
175      */
176     public final Rect screenSpaceBounds;
177 
178     /**
179      * The starting bounds of the source container in screen space coordinates.
180      * For {@link #MODE_OPENING}, this will be equivalent to {@link #screenSpaceBounds}.
181      * For {@link #MODE_CLOSING}, this will be equivalent to {@link #screenSpaceBounds} unless the
182      * closing container is also resizing. For example, when ActivityEmbedding split pair becomes
183      * stacked, the container on the back will be resized to fullscreen, but will also be covered
184      * (closing) by the container in the front.
185      * For {@link #MODE_CHANGING}, since this is the starting bounds, its size should be equivalent
186      * to the bounds of the starting thumbnail.
187      *
188      * Note that {@link #screenSpaceBounds} is the end bounds of a transition.
189      */
190     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
191     public final Rect startBounds;
192 
193     /**
194      * The window configuration for the target.
195      */
196     @UnsupportedAppUsage
197     public final WindowConfiguration windowConfiguration;
198 
199     /**
200      * Whether the task is not presented in Recents UI.
201      */
202     @UnsupportedAppUsage
203     public boolean isNotInRecents;
204 
205     /**
206      * {@link TaskInfo} to allow the controller to identify information about the task.
207      *
208      * TODO: add this to proto dump
209      */
210     public ActivityManager.RunningTaskInfo taskInfo;
211 
212     /**
213      * {@code true} if picture-in-picture permission is granted in {@link android.app.AppOpsManager}
214      */
215     @UnsupportedAppUsage
216     public boolean allowEnterPip;
217 
218     /**
219      * The {@link android.view.WindowManager.LayoutParams.WindowType} of this window. It's only used
220      * for non-app window.
221      */
222     public final @WindowManager.LayoutParams.WindowType int windowType;
223 
224     /**
225      * {@code true} if its parent is also a {@link RemoteAnimationTarget} in the same transition.
226      *
227      * For example, when a TaskFragment is resizing while one of its children is open/close, both
228      * windows will be animation targets. This value will be {@code true} for the child, so that
229      * the handler can choose to handle it differently.
230      */
231     public boolean hasAnimatingParent;
232 
233     /**
234      * Whether an activity has enabled {@link android.R.styleable#Animation_showBackdrop} for
235      * transition.
236      */
237     public boolean showBackdrop;
238 
239     /**
240      * The background color of animation in case the task info is not available if the transition
241      * is activity level.
242      */
243     public @ColorInt int backgroundColor;
244 
245     /**
246      * Whether the activity is going to show IME on the target window after the app transition.
247      * @see TaskSnapshot#hasImeSurface() that used the task snapshot during animating task.
248      */
249     public boolean willShowImeOnTarget;
250 
251     public int rotationChange;
252 
RemoteAnimationTarget(int taskId, int mode, SurfaceControl leash, boolean isTranslucent, Rect clipRect, Rect contentInsets, int prefixOrderIndex, Point position, Rect localBounds, Rect screenSpaceBounds, WindowConfiguration windowConfig, boolean isNotInRecents, SurfaceControl startLeash, @Nullable Rect startBounds, ActivityManager.RunningTaskInfo taskInfo, boolean allowEnterPip)253     public RemoteAnimationTarget(int taskId, int mode, SurfaceControl leash, boolean isTranslucent,
254             Rect clipRect, Rect contentInsets, int prefixOrderIndex, Point position,
255             Rect localBounds, Rect screenSpaceBounds,
256             WindowConfiguration windowConfig, boolean isNotInRecents,
257             SurfaceControl startLeash, @Nullable Rect startBounds,
258             ActivityManager.RunningTaskInfo taskInfo,
259             boolean allowEnterPip) {
260         this(taskId, mode, leash, isTranslucent, clipRect, contentInsets, prefixOrderIndex,
261                 position, localBounds, screenSpaceBounds, windowConfig, isNotInRecents, startLeash,
262                 startBounds, taskInfo, allowEnterPip, INVALID_WINDOW_TYPE);
263     }
264 
RemoteAnimationTarget(int taskId, int mode, SurfaceControl leash, boolean isTranslucent, Rect clipRect, Rect contentInsets, int prefixOrderIndex, Point position, Rect localBounds, Rect screenSpaceBounds, WindowConfiguration windowConfig, boolean isNotInRecents, SurfaceControl startLeash, @Nullable Rect startBounds, ActivityManager.RunningTaskInfo taskInfo, boolean allowEnterPip, @WindowManager.LayoutParams.WindowType int windowType)265     public RemoteAnimationTarget(int taskId, int mode, SurfaceControl leash, boolean isTranslucent,
266             Rect clipRect, Rect contentInsets, int prefixOrderIndex, Point position,
267             Rect localBounds, Rect screenSpaceBounds,
268             WindowConfiguration windowConfig, boolean isNotInRecents,
269             SurfaceControl startLeash, @Nullable Rect startBounds,
270             ActivityManager.RunningTaskInfo taskInfo, boolean allowEnterPip,
271             @WindowManager.LayoutParams.WindowType int windowType) {
272         this.mode = mode;
273         this.taskId = taskId;
274         this.leash = leash;
275         this.isTranslucent = isTranslucent;
276         this.clipRect = new Rect(clipRect);
277         this.contentInsets = new Rect(contentInsets);
278         this.prefixOrderIndex = prefixOrderIndex;
279         this.position = position == null ? new Point() : new Point(position);
280         this.localBounds = new Rect(localBounds);
281         this.sourceContainerBounds = new Rect(screenSpaceBounds);
282         this.screenSpaceBounds = new Rect(screenSpaceBounds);
283         this.windowConfiguration = windowConfig;
284         this.isNotInRecents = isNotInRecents;
285         this.startLeash = startLeash;
286         this.taskInfo = taskInfo;
287         this.allowEnterPip = allowEnterPip;
288         this.windowType = windowType;
289         // Same as screenSpaceBounds if the window is not resizing.
290         this.startBounds = startBounds == null
291                 ? new Rect(screenSpaceBounds)
292                 : new Rect(startBounds);
293     }
294 
RemoteAnimationTarget(Parcel in)295     public RemoteAnimationTarget(Parcel in) {
296         taskId = in.readInt();
297         mode = in.readInt();
298         leash = in.readTypedObject(SurfaceControl.CREATOR);
299         if (leash != null) {
300             leash.setUnreleasedWarningCallSite("RemoteAnimationTarget[leash]");
301         }
302         isTranslucent = in.readBoolean();
303         clipRect = in.readTypedObject(Rect.CREATOR);
304         contentInsets = in.readTypedObject(Rect.CREATOR);
305         prefixOrderIndex = in.readInt();
306         position = in.readTypedObject(Point.CREATOR);
307         localBounds = in.readTypedObject(Rect.CREATOR);
308         sourceContainerBounds = in.readTypedObject(Rect.CREATOR);
309         screenSpaceBounds = in.readTypedObject(Rect.CREATOR);
310         windowConfiguration = in.readTypedObject(WindowConfiguration.CREATOR);
311         isNotInRecents = in.readBoolean();
312         startLeash = in.readTypedObject(SurfaceControl.CREATOR);
313         if (startLeash != null) {
314             startLeash.setUnreleasedWarningCallSite("RemoteAnimationTarget[startLeash]");
315         }
316         startBounds = in.readTypedObject(Rect.CREATOR);
317         taskInfo = in.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR);
318         allowEnterPip = in.readBoolean();
319         windowType = in.readInt();
320         hasAnimatingParent = in.readBoolean();
321         backgroundColor = in.readInt();
322         showBackdrop = in.readBoolean();
323         willShowImeOnTarget = in.readBoolean();
324         rotationChange = in.readInt();
325     }
326 
setShowBackdrop(boolean shouldShowBackdrop)327     public void setShowBackdrop(boolean shouldShowBackdrop) {
328         showBackdrop = shouldShowBackdrop;
329     }
330 
setWillShowImeOnTarget(boolean showImeOnTarget)331     public void setWillShowImeOnTarget(boolean showImeOnTarget) {
332         willShowImeOnTarget = showImeOnTarget;
333     }
334 
willShowImeOnTarget()335     public boolean willShowImeOnTarget() {
336         return willShowImeOnTarget;
337     }
338 
setRotationChange(int rotationChange)339     public void setRotationChange(int rotationChange) {
340         this.rotationChange = rotationChange;
341     }
342 
getRotationChange()343     public int getRotationChange() {
344         return rotationChange;
345     }
346 
347     @Override
describeContents()348     public int describeContents() {
349         return 0;
350     }
351 
352     @Override
writeToParcel(Parcel dest, int flags)353     public void writeToParcel(Parcel dest, int flags) {
354         dest.writeInt(taskId);
355         dest.writeInt(mode);
356         dest.writeTypedObject(leash, 0 /* flags */);
357         dest.writeBoolean(isTranslucent);
358         dest.writeTypedObject(clipRect, 0 /* flags */);
359         dest.writeTypedObject(contentInsets, 0 /* flags */);
360         dest.writeInt(prefixOrderIndex);
361         dest.writeTypedObject(position, 0 /* flags */);
362         dest.writeTypedObject(localBounds, 0 /* flags */);
363         dest.writeTypedObject(sourceContainerBounds, 0 /* flags */);
364         dest.writeTypedObject(screenSpaceBounds, 0 /* flags */);
365         dest.writeTypedObject(windowConfiguration, 0 /* flags */);
366         dest.writeBoolean(isNotInRecents);
367         dest.writeTypedObject(startLeash, 0 /* flags */);
368         dest.writeTypedObject(startBounds, 0 /* flags */);
369         dest.writeTypedObject(taskInfo, 0 /* flags */);
370         dest.writeBoolean(allowEnterPip);
371         dest.writeInt(windowType);
372         dest.writeBoolean(hasAnimatingParent);
373         dest.writeInt(backgroundColor);
374         dest.writeBoolean(showBackdrop);
375         dest.writeBoolean(willShowImeOnTarget);
376         dest.writeInt(rotationChange);
377     }
378 
dump(PrintWriter pw, String prefix)379     public void dump(PrintWriter pw, String prefix) {
380         pw.print(prefix); pw.print("mode="); pw.print(mode);
381         pw.print(" taskId="); pw.print(taskId);
382         pw.print(" isTranslucent="); pw.print(isTranslucent);
383         pw.print(" clipRect="); clipRect.printShortString(pw);
384         pw.print(" contentInsets="); contentInsets.printShortString(pw);
385         pw.print(" prefixOrderIndex="); pw.print(prefixOrderIndex);
386         pw.print(" position="); printPoint(position, pw);
387         pw.print(" sourceContainerBounds="); sourceContainerBounds.printShortString(pw);
388         pw.print(" screenSpaceBounds="); screenSpaceBounds.printShortString(pw);
389         pw.print(" localBounds="); localBounds.printShortString(pw);
390         pw.println();
391         pw.print(prefix); pw.print("windowConfiguration="); pw.println(windowConfiguration);
392         pw.print(prefix); pw.print("leash="); pw.println(leash);
393         pw.print(prefix); pw.print("taskInfo="); pw.println(taskInfo);
394         pw.print(prefix); pw.print("allowEnterPip="); pw.println(allowEnterPip);
395         pw.print(prefix); pw.print("windowType="); pw.println(windowType);
396         pw.print(prefix); pw.print("hasAnimatingParent="); pw.println(hasAnimatingParent);
397         pw.print(prefix); pw.print("backgroundColor="); pw.println(backgroundColor);
398         pw.print(prefix); pw.print("showBackdrop="); pw.println(showBackdrop);
399         pw.print(prefix); pw.print("willShowImeOnTarget="); pw.println(willShowImeOnTarget);
400     }
401 
dumpDebug(ProtoOutputStream proto, long fieldId)402     public void dumpDebug(ProtoOutputStream proto, long fieldId) {
403         final long token = proto.start(fieldId);
404         proto.write(TASK_ID, taskId);
405         proto.write(MODE, mode);
406         leash.dumpDebug(proto, LEASH);
407         proto.write(IS_TRANSLUCENT, isTranslucent);
408         clipRect.dumpDebug(proto, CLIP_RECT);
409         contentInsets.dumpDebug(proto, CONTENT_INSETS);
410         proto.write(PREFIX_ORDER_INDEX, prefixOrderIndex);
411         dumpPointProto(position, proto, POSITION);
412         sourceContainerBounds.dumpDebug(proto, SOURCE_CONTAINER_BOUNDS);
413         screenSpaceBounds.dumpDebug(proto, SCREEN_SPACE_BOUNDS);
414         localBounds.dumpDebug(proto, LOCAL_BOUNDS);
415         windowConfiguration.dumpDebug(proto, WINDOW_CONFIGURATION);
416         if (startLeash != null) {
417             startLeash.dumpDebug(proto, START_LEASH);
418         }
419         startBounds.dumpDebug(proto, START_BOUNDS);
420         proto.end(token);
421     }
422 
printPoint(Point p, PrintWriter pw)423     private static void printPoint(Point p, PrintWriter pw) {
424         pw.print("["); pw.print(p.x); pw.print(","); pw.print(p.y); pw.print("]");
425     }
426 
427     public static final @android.annotation.NonNull Creator<RemoteAnimationTarget> CREATOR
428             = new Creator<RemoteAnimationTarget>() {
429         public RemoteAnimationTarget createFromParcel(Parcel in) {
430             return new RemoteAnimationTarget(in);
431         }
432 
433         public RemoteAnimationTarget[] newArray(int size) {
434             return new RemoteAnimationTarget[size];
435         }
436     };
437 }
438