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.view.RemoteAnimationTargetProto.CLIP_RECT;
20 import static android.view.RemoteAnimationTargetProto.CONTENT_INSETS;
21 import static android.view.RemoteAnimationTargetProto.IS_TRANSLUCENT;
22 import static android.view.RemoteAnimationTargetProto.LEASH;
23 import static android.view.RemoteAnimationTargetProto.LOCAL_BOUNDS;
24 import static android.view.RemoteAnimationTargetProto.MODE;
25 import static android.view.RemoteAnimationTargetProto.POSITION;
26 import static android.view.RemoteAnimationTargetProto.PREFIX_ORDER_INDEX;
27 import static android.view.RemoteAnimationTargetProto.SCREEN_SPACE_BOUNDS;
28 import static android.view.RemoteAnimationTargetProto.SOURCE_CONTAINER_BOUNDS;
29 import static android.view.RemoteAnimationTargetProto.START_BOUNDS;
30 import static android.view.RemoteAnimationTargetProto.START_LEASH;
31 import static android.view.RemoteAnimationTargetProto.TASK_ID;
32 import static android.view.RemoteAnimationTargetProto.WINDOW_CONFIGURATION;
33 
34 import android.annotation.IntDef;
35 import android.app.WindowConfiguration;
36 import android.compat.annotation.UnsupportedAppUsage;
37 import android.graphics.Point;
38 import android.graphics.Rect;
39 import android.os.Parcel;
40 import android.os.Parcelable;
41 import android.util.proto.ProtoOutputStream;
42 
43 import java.io.PrintWriter;
44 import java.lang.annotation.Retention;
45 import java.lang.annotation.RetentionPolicy;
46 
47 /**
48  * Describes an activity to be animated as part of a remote animation.
49  *
50  * @hide
51  */
52 public class RemoteAnimationTarget implements Parcelable {
53 
54     /**
55      * The app is in the set of opening apps of this transition.
56      */
57     public static final int MODE_OPENING = 0;
58 
59     /**
60      * The app is in the set of closing apps of this transition.
61      */
62     public static final int MODE_CLOSING = 1;
63 
64     /**
65      * The app is in the set of resizing apps (eg. mode change) of this transition.
66      */
67     public static final int MODE_CHANGING = 2;
68 
69     @IntDef(prefix = { "MODE_" }, value = {
70             MODE_OPENING,
71             MODE_CLOSING,
72             MODE_CHANGING
73     })
74     @Retention(RetentionPolicy.SOURCE)
75     public @interface Mode {}
76 
77     /**
78      * The {@link Mode} to describe whether this app is opening or closing.
79      */
80     @UnsupportedAppUsage
81     public final @Mode int mode;
82 
83     /**
84      * The id of the task this app belongs to.
85      */
86     @UnsupportedAppUsage
87     public final int taskId;
88 
89     /**
90      * The {@link SurfaceControl} object to actually control the transform of the app.
91      */
92     @UnsupportedAppUsage
93     public final SurfaceControl leash;
94 
95     /**
96      * The {@link SurfaceControl} for the starting state of a target if this transition is
97      * MODE_CHANGING, {@code null)} otherwise. This is relative to the app window.
98      */
99     @UnsupportedAppUsage
100     public final SurfaceControl startLeash;
101 
102     /**
103      * Whether the app is translucent and may reveal apps behind.
104      */
105     @UnsupportedAppUsage
106     public final boolean isTranslucent;
107 
108     /**
109      * The clip rect window manager applies when clipping the app's main surface in screen space
110      * coordinates. This is just a hint to the animation runner: If running a clip-rect animation,
111      * anything that extends beyond these bounds will not have any effect. This implies that any
112      * clip-rect animation should likely stop at these bounds.
113      */
114     @UnsupportedAppUsage
115     public final Rect clipRect;
116 
117     /**
118      * The insets of the main app window.
119      */
120     @UnsupportedAppUsage
121     public final Rect contentInsets;
122 
123     /**
124      * The index of the element in the tree in prefix order. This should be used for z-layering
125      * to preserve original z-layer order in the hierarchy tree assuming no "boosting" needs to
126      * happen.
127      */
128     @UnsupportedAppUsage
129     public final int prefixOrderIndex;
130 
131     /**
132      * The source position of the app, in screen spaces coordinates. If the position of the leash
133      * is modified from the controlling app, any animation transform needs to be offset by this
134      * amount.
135      * @deprecated Use {@link #localBounds} instead.
136      */
137     @Deprecated
138     @UnsupportedAppUsage
139     public final Point position;
140 
141     /**
142      * Bounds of the target relative to its parent.
143      * When the app target animating on its parent, we need to use the local coordinates relative to
144      * its parent with {@code localBounds.left} & {@code localBounds.top} rather than using
145      * {@code position} in screen coordinates.
146      */
147     public final Rect localBounds;
148 
149     /**
150      * The bounds of the source container the app lives in, in screen space coordinates. If the crop
151      * of the leash is modified from the controlling app, it needs to take the source container
152      * bounds into account when calculating the crop.
153      * @deprecated Renamed to {@link #screenSpaceBounds}
154      */
155     @Deprecated
156     @UnsupportedAppUsage
157     public final Rect sourceContainerBounds;
158 
159     /**
160      * Bounds of the target relative to the screen. If the crop of the leash is modified from the
161      * controlling app, it needs to take the screen space bounds into account when calculating the
162      * crop.
163      */
164     public final Rect screenSpaceBounds;
165 
166     /**
167      * The starting bounds of the source container in screen space coordinates. This is {@code null}
168      * if the animation target isn't MODE_CHANGING. Since this is the starting bounds, it's size
169      * should be equivalent to the size of the starting thumbnail. Note that sourceContainerBounds
170      * is the end bounds of a change transition.
171      */
172     @UnsupportedAppUsage
173     public final Rect startBounds;
174 
175     /**
176      * The window configuration for the target.
177      */
178     @UnsupportedAppUsage
179     public final WindowConfiguration windowConfiguration;
180 
181     /**
182      * Whether the task is not presented in Recents UI.
183      */
184     @UnsupportedAppUsage
185     public boolean isNotInRecents;
186 
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)187     public RemoteAnimationTarget(int taskId, int mode, SurfaceControl leash, boolean isTranslucent,
188             Rect clipRect, Rect contentInsets, int prefixOrderIndex, Point position,
189             Rect localBounds, Rect screenSpaceBounds,
190             WindowConfiguration windowConfig, boolean isNotInRecents,
191             SurfaceControl startLeash, Rect startBounds) {
192         this.mode = mode;
193         this.taskId = taskId;
194         this.leash = leash;
195         this.isTranslucent = isTranslucent;
196         this.clipRect = new Rect(clipRect);
197         this.contentInsets = new Rect(contentInsets);
198         this.prefixOrderIndex = prefixOrderIndex;
199         this.position = new Point(position);
200         this.localBounds = new Rect(localBounds);
201         this.sourceContainerBounds = new Rect(screenSpaceBounds);
202         this.screenSpaceBounds = new Rect(screenSpaceBounds);
203         this.windowConfiguration = windowConfig;
204         this.isNotInRecents = isNotInRecents;
205         this.startLeash = startLeash;
206         this.startBounds = startBounds == null ? null : new Rect(startBounds);
207     }
208 
RemoteAnimationTarget(Parcel in)209     public RemoteAnimationTarget(Parcel in) {
210         taskId = in.readInt();
211         mode = in.readInt();
212         leash = in.readParcelable(null);
213         isTranslucent = in.readBoolean();
214         clipRect = in.readParcelable(null);
215         contentInsets = in.readParcelable(null);
216         prefixOrderIndex = in.readInt();
217         position = in.readParcelable(null);
218         localBounds = in.readParcelable(null);
219         sourceContainerBounds = in.readParcelable(null);
220         screenSpaceBounds = in.readParcelable(null);
221         windowConfiguration = in.readParcelable(null);
222         isNotInRecents = in.readBoolean();
223         startLeash = in.readParcelable(null);
224         startBounds = in.readParcelable(null);
225     }
226 
227     @Override
describeContents()228     public int describeContents() {
229         return 0;
230     }
231 
232     @Override
writeToParcel(Parcel dest, int flags)233     public void writeToParcel(Parcel dest, int flags) {
234         dest.writeInt(taskId);
235         dest.writeInt(mode);
236         dest.writeParcelable(leash, 0 /* flags */);
237         dest.writeBoolean(isTranslucent);
238         dest.writeParcelable(clipRect, 0 /* flags */);
239         dest.writeParcelable(contentInsets, 0 /* flags */);
240         dest.writeInt(prefixOrderIndex);
241         dest.writeParcelable(position, 0 /* flags */);
242         dest.writeParcelable(localBounds, 0 /* flags */);
243         dest.writeParcelable(sourceContainerBounds, 0 /* flags */);
244         dest.writeParcelable(screenSpaceBounds, 0 /* flags */);
245         dest.writeParcelable(windowConfiguration, 0 /* flags */);
246         dest.writeBoolean(isNotInRecents);
247         dest.writeParcelable(startLeash, 0 /* flags */);
248         dest.writeParcelable(startBounds, 0 /* flags */);
249     }
250 
dump(PrintWriter pw, String prefix)251     public void dump(PrintWriter pw, String prefix) {
252         pw.print(prefix); pw.print("mode="); pw.print(mode);
253         pw.print(" taskId="); pw.print(taskId);
254         pw.print(" isTranslucent="); pw.print(isTranslucent);
255         pw.print(" clipRect="); clipRect.printShortString(pw);
256         pw.print(" contentInsets="); contentInsets.printShortString(pw);
257         pw.print(" prefixOrderIndex="); pw.print(prefixOrderIndex);
258         pw.print(" position="); position.printShortString(pw);
259         pw.print(" sourceContainerBounds="); sourceContainerBounds.printShortString(pw);
260         pw.print(" screenSpaceBounds="); screenSpaceBounds.printShortString(pw);
261         pw.print(" localBounds="); localBounds.printShortString(pw);
262         pw.println();
263         pw.print(prefix); pw.print("windowConfiguration="); pw.println(windowConfiguration);
264         pw.print(prefix); pw.print("leash="); pw.println(leash);
265     }
266 
dumpDebug(ProtoOutputStream proto, long fieldId)267     public void dumpDebug(ProtoOutputStream proto, long fieldId) {
268         final long token = proto.start(fieldId);
269         proto.write(TASK_ID, taskId);
270         proto.write(MODE, mode);
271         leash.dumpDebug(proto, LEASH);
272         proto.write(IS_TRANSLUCENT, isTranslucent);
273         clipRect.dumpDebug(proto, CLIP_RECT);
274         contentInsets.dumpDebug(proto, CONTENT_INSETS);
275         proto.write(PREFIX_ORDER_INDEX, prefixOrderIndex);
276         position.dumpDebug(proto, POSITION);
277         sourceContainerBounds.dumpDebug(proto, SOURCE_CONTAINER_BOUNDS);
278         screenSpaceBounds.dumpDebug(proto, SCREEN_SPACE_BOUNDS);
279         localBounds.dumpDebug(proto, LOCAL_BOUNDS);
280         windowConfiguration.dumpDebug(proto, WINDOW_CONFIGURATION);
281         if (startLeash != null) {
282             startLeash.dumpDebug(proto, START_LEASH);
283         }
284         if (startBounds != null) {
285             startBounds.dumpDebug(proto, START_BOUNDS);
286         }
287         proto.end(token);
288     }
289 
290     public static final @android.annotation.NonNull Creator<RemoteAnimationTarget> CREATOR
291             = new Creator<RemoteAnimationTarget>() {
292         public RemoteAnimationTarget createFromParcel(Parcel in) {
293             return new RemoteAnimationTarget(in);
294         }
295 
296         public RemoteAnimationTarget[] newArray(int size) {
297             return new RemoteAnimationTarget[size];
298         }
299     };
300 }
301