• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.window;
18 
19 import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
20 import static android.view.WindowManager.TRANSIT_CHANGE;
21 import static android.view.WindowManager.TRANSIT_CLOSE;
22 import static android.view.WindowManager.TRANSIT_NONE;
23 import static android.view.WindowManager.TRANSIT_OPEN;
24 import static android.view.WindowManager.TRANSIT_TO_BACK;
25 import static android.view.WindowManager.TRANSIT_TO_FRONT;
26 import static android.view.WindowManager.transitTypeToString;
27 
28 import android.annotation.IntDef;
29 import android.annotation.NonNull;
30 import android.annotation.Nullable;
31 import android.app.ActivityManager;
32 import android.graphics.Point;
33 import android.graphics.Rect;
34 import android.os.Parcel;
35 import android.os.Parcelable;
36 import android.view.Surface;
37 import android.view.SurfaceControl;
38 import android.view.WindowManager;
39 
40 import java.util.ArrayList;
41 import java.util.List;
42 
43 /**
44  * Used to communicate information about what is changing during a transition to a TransitionPlayer.
45  * @hide
46  */
47 public final class TransitionInfo implements Parcelable {
48 
49     /**
50      * Modes are only a sub-set of all the transit-types since they are per-container
51      * @hide
52      */
53     @IntDef(prefix = { "TRANSIT_" }, value = {
54             TRANSIT_NONE,
55             TRANSIT_OPEN,
56             TRANSIT_CLOSE,
57             // Note: to_front/to_back really mean show/hide respectively at the container level.
58             TRANSIT_TO_FRONT,
59             TRANSIT_TO_BACK,
60             TRANSIT_CHANGE
61     })
62     public @interface TransitionMode {}
63 
64     /** No flags */
65     public static final int FLAG_NONE = 0;
66 
67     /** The container shows the wallpaper behind it. */
68     public static final int FLAG_SHOW_WALLPAPER = 1;
69 
70     /** The container IS the wallpaper. */
71     public static final int FLAG_IS_WALLPAPER = 1 << 1;
72 
73     /** The container is translucent. */
74     public static final int FLAG_TRANSLUCENT = 1 << 2;
75 
76     // TODO: remove when starting-window is moved to Task
77     /** The container is the recipient of a transferred starting-window */
78     public static final int FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT = 1 << 3;
79 
80     /** The container has voice session. */
81     public static final int FLAG_IS_VOICE_INTERACTION = 1 << 4;
82 
83     /** The first unused bit. This can be used by remotes to attach custom flags to this change. */
84     public static final int FLAG_FIRST_CUSTOM = 1 << 5;
85 
86     /** @hide */
87     @IntDef(prefix = { "FLAG_" }, value = {
88             FLAG_NONE,
89             FLAG_SHOW_WALLPAPER,
90             FLAG_IS_WALLPAPER,
91             FLAG_TRANSLUCENT,
92             FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT,
93             FLAG_IS_VOICE_INTERACTION,
94             FLAG_FIRST_CUSTOM
95     })
96     public @interface ChangeFlags {}
97 
98     private final @WindowManager.TransitionOldType int mType;
99     private final @WindowManager.TransitionFlags int mFlags;
100     private final ArrayList<Change> mChanges = new ArrayList<>();
101 
102     private SurfaceControl mRootLeash;
103     private final Point mRootOffset = new Point();
104 
105     /** @hide */
TransitionInfo(@indowManager.TransitionOldType int type, @WindowManager.TransitionFlags int flags)106     public TransitionInfo(@WindowManager.TransitionOldType int type,
107             @WindowManager.TransitionFlags int flags) {
108         mType = type;
109         mFlags = flags;
110     }
111 
TransitionInfo(Parcel in)112     private TransitionInfo(Parcel in) {
113         mType = in.readInt();
114         mFlags = in.readInt();
115         in.readList(mChanges, null /* classLoader */);
116         mRootLeash = new SurfaceControl();
117         mRootLeash.readFromParcel(in);
118         mRootOffset.readFromParcel(in);
119     }
120 
121     @Override
122     /** @hide */
writeToParcel(@onNull Parcel dest, int flags)123     public void writeToParcel(@NonNull Parcel dest, int flags) {
124         dest.writeInt(mType);
125         dest.writeInt(mFlags);
126         dest.writeList(mChanges);
127         mRootLeash.writeToParcel(dest, flags);
128         mRootOffset.writeToParcel(dest, flags);
129     }
130 
131     @NonNull
132     public static final Creator<TransitionInfo> CREATOR =
133             new Creator<TransitionInfo>() {
134                 @Override
135                 public TransitionInfo createFromParcel(Parcel in) {
136                     return new TransitionInfo(in);
137                 }
138 
139                 @Override
140                 public TransitionInfo[] newArray(int size) {
141                     return new TransitionInfo[size];
142                 }
143             };
144 
145     @Override
146     /** @hide */
describeContents()147     public int describeContents() {
148         return 0;
149     }
150 
151     /** @see #getRootLeash() */
setRootLeash(@onNull SurfaceControl leash, int offsetLeft, int offsetTop)152     public void setRootLeash(@NonNull SurfaceControl leash, int offsetLeft, int offsetTop) {
153         mRootLeash = leash;
154         mRootOffset.set(offsetLeft, offsetTop);
155     }
156 
getType()157     public int getType() {
158         return mType;
159     }
160 
getFlags()161     public int getFlags() {
162         return mFlags;
163     }
164 
165     /**
166      * @return a surfacecontrol that can serve as a parent surfacecontrol for all the changing
167      * participants to animate within. This will generally be placed at the highest-z-order
168      * shared ancestor of all participants. While this is non-null, it's possible for the rootleash
169      * to be invalid if the transition is a no-op.
170      */
171     @NonNull
getRootLeash()172     public SurfaceControl getRootLeash() {
173         if (mRootLeash == null) {
174             throw new IllegalStateException("Trying to get a leash which wasn't set");
175         }
176         return mRootLeash;
177     }
178 
179     /** @return the offset (relative to the screen) of the root leash. */
180     @NonNull
getRootOffset()181     public Point getRootOffset() {
182         return mRootOffset;
183     }
184 
185     @NonNull
getChanges()186     public List<Change> getChanges() {
187         return mChanges;
188     }
189 
190     /**
191      * @return the Change that a window is undergoing or {@code null} if not directly
192      * represented.
193      */
194     @Nullable
getChange(@onNull WindowContainerToken token)195     public Change getChange(@NonNull WindowContainerToken token) {
196         for (int i = mChanges.size() - 1; i >= 0; --i) {
197             if (token.equals(mChanges.get(i).mContainer)) {
198                 return mChanges.get(i);
199             }
200         }
201         return null;
202     }
203 
204     /**
205      * Add a {@link Change} to this transition.
206      */
addChange(@onNull Change change)207     public void addChange(@NonNull Change change) {
208         mChanges.add(change);
209     }
210 
211     @Override
toString()212     public String toString() {
213         StringBuilder sb = new StringBuilder();
214         sb.append("{t=" + transitTypeToString(mType) + " f=" + Integer.toHexString(mFlags)
215                 + " ro=" + mRootOffset + " c=[");
216         for (int i = 0; i < mChanges.size(); ++i) {
217             if (i > 0) {
218                 sb.append(',');
219             }
220             sb.append(mChanges.get(i));
221         }
222         sb.append("]}");
223         return sb.toString();
224     }
225 
226     /** Converts a transition mode/action to its string representation. */
227     @NonNull
modeToString(@ransitionMode int mode)228     public static String modeToString(@TransitionMode int mode) {
229         switch(mode) {
230             case TRANSIT_NONE: return "NONE";
231             case TRANSIT_OPEN: return "OPEN";
232             case TRANSIT_CLOSE: return "CLOSE";
233             case TRANSIT_TO_FRONT: return "SHOW";
234             case TRANSIT_TO_BACK: return "HIDE";
235             case TRANSIT_CHANGE: return "CHANGE";
236             default: return "<unknown:" + mode + ">";
237         }
238     }
239 
240     /** Converts change flags into a string representation. */
241     @NonNull
flagsToString(@hangeFlags int flags)242     public static String flagsToString(@ChangeFlags int flags) {
243         if (flags == 0) return "NONE";
244         final StringBuilder sb = new StringBuilder();
245         if ((flags & FLAG_SHOW_WALLPAPER) != 0) {
246             sb.append("SHOW_WALLPAPER");
247         }
248         if ((flags & FLAG_IS_WALLPAPER) != 0) {
249             sb.append("IS_WALLPAPER");
250         }
251         if ((flags & FLAG_TRANSLUCENT) != 0) {
252             sb.append((sb.length() == 0 ? "" : "|") + "TRANSLUCENT");
253         }
254         if ((flags & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) {
255             sb.append((sb.length() == 0 ? "" : "|") + "STARTING_WINDOW_TRANSFER");
256         }
257         if ((flags & FLAG_IS_VOICE_INTERACTION) != 0) {
258             sb.append((sb.length() == 0 ? "" : "|") + "IS_VOICE_INTERACTION");
259         }
260         if ((flags & FLAG_FIRST_CUSTOM) != 0) {
261             sb.append((sb.length() == 0 ? "" : "|") + "FIRST_CUSTOM");
262         }
263         return sb.toString();
264     }
265 
266     /**
267      * Indication that `change` is independent of parents (ie. it has a different type of
268      * transition vs. "going along for the ride")
269      */
isIndependent(@onNull TransitionInfo.Change change, @NonNull TransitionInfo info)270     public static boolean isIndependent(@NonNull TransitionInfo.Change change,
271             @NonNull TransitionInfo info) {
272         // If the change has no parent (it is root), then it is independent
273         if (change.getParent() == null) return true;
274 
275         // non-visibility changes will just be folded into the parent change, so they aren't
276         // independent either.
277         if (change.getMode() == TRANSIT_CHANGE) return false;
278 
279         TransitionInfo.Change parentChg = info.getChange(change.getParent());
280         while (parentChg != null) {
281             // If the parent is a visibility change, it will include the results of all child
282             // changes into itself, so none of its children can be independent.
283             if (parentChg.getMode() != TRANSIT_CHANGE) return false;
284 
285             // If there are no more parents left, then all the parents, so far, have not been
286             // visibility changes which means this change is indpendent.
287             if (parentChg.getParent() == null) return true;
288 
289             parentChg = info.getChange(parentChg.getParent());
290         }
291         return false;
292     }
293 
294     /** Represents the change a WindowContainer undergoes during a transition */
295     public static final class Change implements Parcelable {
296         private final WindowContainerToken mContainer;
297         private WindowContainerToken mParent;
298         private final SurfaceControl mLeash;
299         private @TransitionMode int mMode = TRANSIT_NONE;
300         private @ChangeFlags int mFlags = FLAG_NONE;
301         private final Rect mStartAbsBounds = new Rect();
302         private final Rect mEndAbsBounds = new Rect();
303         private final Point mEndRelOffset = new Point();
304         private ActivityManager.RunningTaskInfo mTaskInfo = null;
305         private int mStartRotation = ROTATION_UNDEFINED;
306         private int mEndRotation = ROTATION_UNDEFINED;
307 
Change(@ullable WindowContainerToken container, @NonNull SurfaceControl leash)308         public Change(@Nullable WindowContainerToken container, @NonNull SurfaceControl leash) {
309             mContainer = container;
310             mLeash = leash;
311         }
312 
Change(Parcel in)313         private Change(Parcel in) {
314             mContainer = in.readTypedObject(WindowContainerToken.CREATOR);
315             mParent = in.readTypedObject(WindowContainerToken.CREATOR);
316             mLeash = new SurfaceControl();
317             mLeash.readFromParcel(in);
318             mMode = in.readInt();
319             mFlags = in.readInt();
320             mStartAbsBounds.readFromParcel(in);
321             mEndAbsBounds.readFromParcel(in);
322             mEndRelOffset.readFromParcel(in);
323             mTaskInfo = in.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR);
324             mStartRotation = in.readInt();
325             mEndRotation = in.readInt();
326         }
327 
328         /** Sets the parent of this change's container. The parent must be a participant or null. */
setParent(@ullable WindowContainerToken parent)329         public void setParent(@Nullable WindowContainerToken parent) {
330             mParent = parent;
331         }
332 
333         /** Sets the transition mode for this change */
setMode(@ransitionMode int mode)334         public void setMode(@TransitionMode int mode) {
335             mMode = mode;
336         }
337 
338         /** Sets the flags for this change */
setFlags(@hangeFlags int flags)339         public void setFlags(@ChangeFlags int flags) {
340             mFlags = flags;
341         }
342 
343         /** Sets the bounds this container occupied before the change in screen space */
setStartAbsBounds(@ullable Rect rect)344         public void setStartAbsBounds(@Nullable Rect rect) {
345             mStartAbsBounds.set(rect);
346         }
347 
348         /** Sets the bounds this container will occupy after the change in screen space */
setEndAbsBounds(@ullable Rect rect)349         public void setEndAbsBounds(@Nullable Rect rect) {
350             mEndAbsBounds.set(rect);
351         }
352 
353         /** Sets the offset of this container from its parent surface */
setEndRelOffset(int left, int top)354         public void setEndRelOffset(int left, int top) {
355             mEndRelOffset.set(left, top);
356         }
357 
358         /**
359          * Sets the taskinfo of this container if this is a task. WARNING: this takes the
360          * reference, so don't modify it afterwards.
361          */
setTaskInfo(@ullable ActivityManager.RunningTaskInfo taskInfo)362         public void setTaskInfo(@Nullable ActivityManager.RunningTaskInfo taskInfo) {
363             mTaskInfo = taskInfo;
364         }
365 
366         /** Sets the start and end rotation of this container. */
setRotation(@urface.Rotation int start, @Surface.Rotation int end)367         public void setRotation(@Surface.Rotation int start, @Surface.Rotation int end) {
368             mStartRotation = start;
369             mEndRotation = end;
370         }
371 
372         /** @return the container that is changing. May be null if non-remotable (eg. activity) */
373         @Nullable
getContainer()374         public WindowContainerToken getContainer() {
375             return mContainer;
376         }
377 
378         /**
379          * @return the parent of the changing container. This is the parent within the participants,
380          * not necessarily the actual parent.
381          */
382         @Nullable
getParent()383         public WindowContainerToken getParent() {
384             return mParent;
385         }
386 
387         /** @return which action this change represents. */
getMode()388         public @TransitionMode int getMode() {
389             return mMode;
390         }
391 
392         /** @return the flags for this change. */
getFlags()393         public @ChangeFlags int getFlags() {
394             return mFlags;
395         }
396 
397         /**
398          * @return the bounds of the container before the change. It may be empty if the container
399          * is coming into existence.
400          */
401         @NonNull
getStartAbsBounds()402         public Rect getStartAbsBounds() {
403             return mStartAbsBounds;
404         }
405 
406         /**
407          * @return the bounds of the container after the change. It may be empty if the container
408          * is disappearing.
409          */
410         @NonNull
getEndAbsBounds()411         public Rect getEndAbsBounds() {
412             return mEndAbsBounds;
413         }
414 
415         /**
416          * @return the offset of the container's surface from its parent surface after the change.
417          */
418         @NonNull
getEndRelOffset()419         public Point getEndRelOffset() {
420             return mEndRelOffset;
421         }
422 
423         /** @return the leash or surface to animate for this container */
424         @NonNull
getLeash()425         public SurfaceControl getLeash() {
426             return mLeash;
427         }
428 
429         /** @return the task info or null if this isn't a task */
430         @NonNull
getTaskInfo()431         public ActivityManager.RunningTaskInfo getTaskInfo() {
432             return mTaskInfo;
433         }
434 
getStartRotation()435         public int getStartRotation() {
436             return mStartRotation;
437         }
438 
getEndRotation()439         public int getEndRotation() {
440             return mEndRotation;
441         }
442 
443         /** @hide */
444         @Override
writeToParcel(@onNull Parcel dest, int flags)445         public void writeToParcel(@NonNull Parcel dest, int flags) {
446             dest.writeTypedObject(mContainer, flags);
447             dest.writeTypedObject(mParent, flags);
448             mLeash.writeToParcel(dest, flags);
449             dest.writeInt(mMode);
450             dest.writeInt(mFlags);
451             mStartAbsBounds.writeToParcel(dest, flags);
452             mEndAbsBounds.writeToParcel(dest, flags);
453             mEndRelOffset.writeToParcel(dest, flags);
454             dest.writeTypedObject(mTaskInfo, flags);
455             dest.writeInt(mStartRotation);
456             dest.writeInt(mEndRotation);
457         }
458 
459         @NonNull
460         public static final Creator<Change> CREATOR =
461                 new Creator<Change>() {
462                     @Override
463                     public Change createFromParcel(Parcel in) {
464                         return new Change(in);
465                     }
466 
467                     @Override
468                     public Change[] newArray(int size) {
469                         return new Change[size];
470                     }
471                 };
472 
473         /** @hide */
474         @Override
describeContents()475         public int describeContents() {
476             return 0;
477         }
478 
479         @Override
toString()480         public String toString() {
481             return "{" + mContainer + "(" + mParent + ") leash=" + mLeash
482                     + " m=" + modeToString(mMode) + " f=" + flagsToString(mFlags) + " sb="
483                     + mStartAbsBounds + " eb=" + mEndAbsBounds + " eo=" + mEndRelOffset + " r="
484                     + mStartRotation + "->" + mEndRotation + "}";
485         }
486     }
487 }
488