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