diff options
Diffstat (limited to 'libs')
| -rw-r--r-- | libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java index 145f759d4de2..8c6e1e7f5f1b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java @@ -16,18 +16,40 @@ package com.android.wm.shell.util; +import static android.app.ActivityTaskManager.INVALID_TASK_ID; +import static android.view.RemoteAnimationTarget.MODE_CHANGING; +import static android.view.RemoteAnimationTarget.MODE_CLOSING; +import static android.view.RemoteAnimationTarget.MODE_OPENING; +import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE; +import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_TO_FRONT; +import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY; import static android.window.TransitionInfo.FLAG_IS_DISPLAY; +import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; +import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT; + +import static com.android.wm.shell.common.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SuppressLint; +import android.app.ActivityManager; +import android.app.WindowConfiguration; +import android.graphics.Rect; +import android.util.ArrayMap; +import android.util.SparseBooleanArray; +import android.view.RemoteAnimationTarget; +import android.view.SurfaceControl; import android.view.WindowManager; import android.window.TransitionInfo; +import java.util.function.Predicate; + /** Various utility functions for transitions. */ public class TransitionUtil { @@ -54,4 +76,189 @@ public class TransitionUtil { return false; } + /** Returns `true` if `change` is a wallpaper. */ + public static boolean isWallpaper(TransitionInfo.Change change) { + return (change.getTaskInfo() == null) + && change.hasFlags(FLAG_IS_WALLPAPER) + && !change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY); + } + + /** Returns `true` if `change` is not an app window or wallpaper. */ + public static boolean isNonApp(TransitionInfo.Change change) { + return (change.getTaskInfo() == null) + && !change.hasFlags(FLAG_IS_WALLPAPER) + && !change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY); + } + + /** + * Filter that selects leaf-tasks only. THIS IS ORDER-DEPENDENT! For it to work properly, you + * MUST call `test` in the same order that the changes appear in the TransitionInfo. + */ + public static class LeafTaskFilter implements Predicate<TransitionInfo.Change> { + private final SparseBooleanArray mChildTaskTargets = new SparseBooleanArray(); + + @Override + public boolean test(TransitionInfo.Change change) { + final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); + // Children always come before parent since changes are in top-to-bottom z-order. + if ((taskInfo == null) || mChildTaskTargets.get(taskInfo.taskId)) { + // has children, so not a leaf. Skip. + return false; + } + if (taskInfo.hasParentTask()) { + mChildTaskTargets.put(taskInfo.parentTaskId, true); + } + return true; + } + } + + + private static int newModeToLegacyMode(int newMode) { + switch (newMode) { + case WindowManager.TRANSIT_OPEN: + case WindowManager.TRANSIT_TO_FRONT: + return MODE_OPENING; + case WindowManager.TRANSIT_CLOSE: + case WindowManager.TRANSIT_TO_BACK: + return MODE_CLOSING; + default: + return MODE_CHANGING; + } + } + + /** + * Very similar to Transitions#setupAnimHierarchy but specialized for leashes. + */ + @SuppressLint("NewApi") + private static void setupLeash(@NonNull SurfaceControl leash, + @NonNull TransitionInfo.Change change, int layer, + @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t) { + final boolean isOpening = TransitionUtil.isOpeningType(info.getType()); + // Put animating stuff above this line and put static stuff below it. + int zSplitLine = info.getChanges().size(); + // changes should be ordered top-to-bottom in z + final int mode = change.getMode(); + + t.reparent(leash, info.getRootLeash()); + final Rect absBounds = + (mode == TRANSIT_OPEN) ? change.getEndAbsBounds() : change.getStartAbsBounds(); + t.setPosition(leash, absBounds.left - info.getRootOffset().x, + absBounds.top - info.getRootOffset().y); + + // Put all the OPEN/SHOW on top + if (TransitionUtil.isOpeningType(mode)) { + if (isOpening) { + t.setLayer(leash, zSplitLine + info.getChanges().size() - layer); + if ((change.getFlags() & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) == 0) { + // if transferred, it should be left visible. + t.setAlpha(leash, 0.f); + } + } else { + // put on bottom and leave it visible + t.setLayer(leash, zSplitLine - layer); + } + } else if (TransitionUtil.isClosingType(mode)) { + if (isOpening) { + // put on bottom and leave visible + t.setLayer(leash, zSplitLine - layer); + } else { + // put on top + t.setLayer(leash, zSplitLine + info.getChanges().size() - layer); + } + } else { // CHANGE + t.setLayer(leash, zSplitLine + info.getChanges().size() - layer); + } + } + + @SuppressLint("NewApi") + private static SurfaceControl createLeash(TransitionInfo info, TransitionInfo.Change change, + int order, SurfaceControl.Transaction t) { + // TODO: once we can properly sync transactions across process, then get rid of this leash. + if (change.getParent() != null && (change.getFlags() & FLAG_IS_WALLPAPER) != 0) { + // Special case for wallpaper atm. Normally these are left alone; but, a quirk of + // making leashes means we have to handle them specially. + return change.getLeash(); + } + SurfaceControl leashSurface = new SurfaceControl.Builder() + .setName(change.getLeash().toString() + "_transition-leash") + .setContainerLayer() + // Initial the surface visible to respect the visibility of the original surface. + .setHidden(false) + .setParent(info.getRootLeash()) + .build(); + // Copied Transitions setup code (which expects bottom-to-top order, so we swap here) + setupLeash(leashSurface, change, info.getChanges().size() - order, info, t); + t.reparent(change.getLeash(), leashSurface); + t.setAlpha(change.getLeash(), 1.0f); + t.show(change.getLeash()); + t.setPosition(change.getLeash(), 0, 0); + t.setLayer(change.getLeash(), 0); + return leashSurface; + } + + /** + * Creates a new RemoteAnimationTarget from the provided change info + */ + public static RemoteAnimationTarget newTarget(TransitionInfo.Change change, int order, + TransitionInfo info, SurfaceControl.Transaction t, + @Nullable ArrayMap<SurfaceControl, SurfaceControl> leashMap) { + final SurfaceControl leash = createLeash(info, change, order, t); + if (leashMap != null) { + leashMap.put(change.getLeash(), leash); + } + return newTarget(change, order, leash); + } + + /** + * Creates a new RemoteAnimationTarget from the provided change and leash + */ + public static RemoteAnimationTarget newTarget(TransitionInfo.Change change, int order, + SurfaceControl leash) { + int taskId; + boolean isNotInRecents; + ActivityManager.RunningTaskInfo taskInfo; + WindowConfiguration windowConfiguration; + + taskInfo = change.getTaskInfo(); + if (taskInfo != null) { + taskId = taskInfo.taskId; + isNotInRecents = !taskInfo.isRunning; + windowConfiguration = taskInfo.configuration.windowConfiguration; + } else { + taskId = INVALID_TASK_ID; + isNotInRecents = true; + windowConfiguration = new WindowConfiguration(); + } + + Rect localBounds = new Rect(change.getEndAbsBounds()); + localBounds.offsetTo(change.getEndRelOffset().x, change.getEndRelOffset().y); + + RemoteAnimationTarget target = new RemoteAnimationTarget( + taskId, + newModeToLegacyMode(change.getMode()), + // TODO: once we can properly sync transactions across process, + // then get rid of this leash. + leash, + (change.getFlags() & TransitionInfo.FLAG_TRANSLUCENT) != 0, + null, + // TODO(shell-transitions): we need to send content insets? evaluate how its used. + new Rect(0, 0, 0, 0), + order, + null, + localBounds, + new Rect(change.getEndAbsBounds()), + windowConfiguration, + isNotInRecents, + null, + new Rect(change.getStartAbsBounds()), + taskInfo, + change.getAllowEnterPip(), + (change.getFlags() & FLAG_IS_DIVIDER_BAR) != 0 + ? TYPE_DOCK_DIVIDER : INVALID_WINDOW_TYPE + ); + target.setWillShowImeOnTarget( + (change.getFlags() & TransitionInfo.FLAG_WILL_IME_SHOWN) != 0); + target.setRotationChange(change.getEndRotation() - change.getStartRotation()); + return target; + } } |