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