Loading libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java +207 −0 Original line number Diff line number Diff line Loading @@ -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 { Loading @@ -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; } } packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java +5 −211 Original line number Diff line number Diff line Loading @@ -16,30 +16,9 @@ package com.android.systemui.shared.system; 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_OPEN; import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY; 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 android.window.TransitionInfo.Change; Loading @@ -53,156 +32,6 @@ import java.util.function.Predicate; */ public class RemoteAnimationTargetCompat { 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; } } /** * Almost a copy of Transitions#setupStartState. * TODO: remove when there is proper cross-process transaction sync. */ @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; } /** * Represents a TransitionInfo object as an array of old-style app targets * Loading @@ -211,7 +40,7 @@ public class RemoteAnimationTargetCompat { */ public static RemoteAnimationTarget[] wrapApps(TransitionInfo info, SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap) { return wrap(info, t, leashMap, new LeafTaskFilter()); return wrap(info, t, leashMap, new TransitionUtil.LeafTaskFilter()); } /** Loading @@ -224,8 +53,8 @@ public class RemoteAnimationTargetCompat { */ public static RemoteAnimationTarget[] wrapNonApps(TransitionInfo info, boolean wallpapers, SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap) { return wrap(info, t, leashMap, (change) -> (wallpapers ? isWallpaper(change) : isNonApp(change))); return wrap(info, t, leashMap, (change) -> (wallpapers ? TransitionUtil.isWallpaper(change) : TransitionUtil.isNonApp(change))); } private static RemoteAnimationTarget[] wrap(TransitionInfo info, Loading @@ -235,45 +64,10 @@ public class RemoteAnimationTargetCompat { for (int i = 0; i < info.getChanges().size(); i++) { TransitionInfo.Change change = info.getChanges().get(i); if (filter.test(change)) { out.add(newTarget(change, info.getChanges().size() - i, info, t, leashMap)); out.add(TransitionUtil.newTarget( change, info.getChanges().size() - i, info, t, leashMap)); } } return out.toArray(new RemoteAnimationTarget[out.size()]); } /** Returns `true` if `change` is a wallpaper. */ public static boolean isWallpaper(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(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<Change> { private final SparseBooleanArray mChildTaskTargets = new SparseBooleanArray(); @Override public boolean test(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; } } } packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java +9 −11 Original line number Diff line number Diff line Loading @@ -21,8 +21,6 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED; import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.newTarget; import android.annotation.SuppressLint; import android.app.ActivityManager; import android.app.ActivityTaskManager; Loading Loading @@ -160,16 +158,15 @@ public class RemoteTransitionCompat { final ArrayList<RemoteAnimationTarget> apps = new ArrayList<>(); final ArrayList<RemoteAnimationTarget> wallpapers = new ArrayList<>(); RemoteAnimationTargetCompat.LeafTaskFilter leafTaskFilter = new RemoteAnimationTargetCompat.LeafTaskFilter(); TransitionUtil.LeafTaskFilter leafTaskFilter = new TransitionUtil.LeafTaskFilter(); // About layering: we divide up the "layer space" into 3 regions (each the size of // the change count). This lets us categorize things into above/below/between // while maintaining their relative ordering. for (int i = 0; i < info.getChanges().size(); ++i) { final TransitionInfo.Change change = info.getChanges().get(i); final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); if (RemoteAnimationTargetCompat.isWallpaper(change)) { final RemoteAnimationTarget target = newTarget(change, if (TransitionUtil.isWallpaper(change)) { final RemoteAnimationTarget target = TransitionUtil.newTarget(change, // wallpapers go into the "below" layer space info.getChanges().size() - i, info, t, mLeashMap); wallpapers.add(target); Loading @@ -177,7 +174,7 @@ public class RemoteTransitionCompat { t.setAlpha(target.leash, 1); } else if (leafTaskFilter.test(change)) { // start by putting everything into the "below" layer space. final RemoteAnimationTarget target = newTarget(change, final RemoteAnimationTarget target = TransitionUtil.newTarget(change, info.getChanges().size() - i, info, t, mLeashMap); apps.add(target); if (TransitionUtil.isClosingType(change.getMode())) { Loading Loading @@ -217,8 +214,8 @@ public class RemoteTransitionCompat { TransitionInfo.Change recentsOpening = null; boolean foundRecentsClosing = false; boolean hasChangingApp = false; final RemoteAnimationTargetCompat.LeafTaskFilter leafTaskFilter = new RemoteAnimationTargetCompat.LeafTaskFilter(); final TransitionUtil.LeafTaskFilter leafTaskFilter = new TransitionUtil.LeafTaskFilter(); for (int i = 0; i < info.getChanges().size(); ++i) { final TransitionInfo.Change change = info.getChanges().get(i); final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); Loading Loading @@ -308,7 +305,8 @@ public class RemoteTransitionCompat { int pausingIdx = TaskState.indexOf(mPausingTasks, change); if (pausingIdx >= 0) { // Something is showing/opening a previously-pausing app. targets[i] = newTarget(change, layer, mPausingTasks.get(pausingIdx).mLeash); targets[i] = TransitionUtil.newTarget(change, layer, mPausingTasks.get(pausingIdx).mLeash); mOpeningTasks.add(mPausingTasks.remove(pausingIdx)); // Setup hides opening tasks initially, so make it visible again (since we // are already showing it). Loading @@ -316,7 +314,7 @@ public class RemoteTransitionCompat { t.setAlpha(change.getLeash(), 1.f); } else { // We are receiving new opening tasks, so convert to onTasksAppeared. targets[i] = newTarget(change, layer, info, t, mLeashMap); targets[i] = TransitionUtil.newTarget(change, layer, info, t, mLeashMap); t.reparent(targets[i].leash, mInfo.getRootLeash()); t.setLayer(targets[i].leash, layer); mOpeningTasks.add(new TaskState(change, targets[i].leash)); Loading packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java +2 −1 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java +207 −0 Original line number Diff line number Diff line Loading @@ -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 { Loading @@ -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; } }
packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java +5 −211 Original line number Diff line number Diff line Loading @@ -16,30 +16,9 @@ package com.android.systemui.shared.system; 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_OPEN; import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY; 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 android.window.TransitionInfo.Change; Loading @@ -53,156 +32,6 @@ import java.util.function.Predicate; */ public class RemoteAnimationTargetCompat { 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; } } /** * Almost a copy of Transitions#setupStartState. * TODO: remove when there is proper cross-process transaction sync. */ @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; } /** * Represents a TransitionInfo object as an array of old-style app targets * Loading @@ -211,7 +40,7 @@ public class RemoteAnimationTargetCompat { */ public static RemoteAnimationTarget[] wrapApps(TransitionInfo info, SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap) { return wrap(info, t, leashMap, new LeafTaskFilter()); return wrap(info, t, leashMap, new TransitionUtil.LeafTaskFilter()); } /** Loading @@ -224,8 +53,8 @@ public class RemoteAnimationTargetCompat { */ public static RemoteAnimationTarget[] wrapNonApps(TransitionInfo info, boolean wallpapers, SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap) { return wrap(info, t, leashMap, (change) -> (wallpapers ? isWallpaper(change) : isNonApp(change))); return wrap(info, t, leashMap, (change) -> (wallpapers ? TransitionUtil.isWallpaper(change) : TransitionUtil.isNonApp(change))); } private static RemoteAnimationTarget[] wrap(TransitionInfo info, Loading @@ -235,45 +64,10 @@ public class RemoteAnimationTargetCompat { for (int i = 0; i < info.getChanges().size(); i++) { TransitionInfo.Change change = info.getChanges().get(i); if (filter.test(change)) { out.add(newTarget(change, info.getChanges().size() - i, info, t, leashMap)); out.add(TransitionUtil.newTarget( change, info.getChanges().size() - i, info, t, leashMap)); } } return out.toArray(new RemoteAnimationTarget[out.size()]); } /** Returns `true` if `change` is a wallpaper. */ public static boolean isWallpaper(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(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<Change> { private final SparseBooleanArray mChildTaskTargets = new SparseBooleanArray(); @Override public boolean test(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; } } }
packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java +9 −11 Original line number Diff line number Diff line Loading @@ -21,8 +21,6 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED; import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.newTarget; import android.annotation.SuppressLint; import android.app.ActivityManager; import android.app.ActivityTaskManager; Loading Loading @@ -160,16 +158,15 @@ public class RemoteTransitionCompat { final ArrayList<RemoteAnimationTarget> apps = new ArrayList<>(); final ArrayList<RemoteAnimationTarget> wallpapers = new ArrayList<>(); RemoteAnimationTargetCompat.LeafTaskFilter leafTaskFilter = new RemoteAnimationTargetCompat.LeafTaskFilter(); TransitionUtil.LeafTaskFilter leafTaskFilter = new TransitionUtil.LeafTaskFilter(); // About layering: we divide up the "layer space" into 3 regions (each the size of // the change count). This lets us categorize things into above/below/between // while maintaining their relative ordering. for (int i = 0; i < info.getChanges().size(); ++i) { final TransitionInfo.Change change = info.getChanges().get(i); final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); if (RemoteAnimationTargetCompat.isWallpaper(change)) { final RemoteAnimationTarget target = newTarget(change, if (TransitionUtil.isWallpaper(change)) { final RemoteAnimationTarget target = TransitionUtil.newTarget(change, // wallpapers go into the "below" layer space info.getChanges().size() - i, info, t, mLeashMap); wallpapers.add(target); Loading @@ -177,7 +174,7 @@ public class RemoteTransitionCompat { t.setAlpha(target.leash, 1); } else if (leafTaskFilter.test(change)) { // start by putting everything into the "below" layer space. final RemoteAnimationTarget target = newTarget(change, final RemoteAnimationTarget target = TransitionUtil.newTarget(change, info.getChanges().size() - i, info, t, mLeashMap); apps.add(target); if (TransitionUtil.isClosingType(change.getMode())) { Loading Loading @@ -217,8 +214,8 @@ public class RemoteTransitionCompat { TransitionInfo.Change recentsOpening = null; boolean foundRecentsClosing = false; boolean hasChangingApp = false; final RemoteAnimationTargetCompat.LeafTaskFilter leafTaskFilter = new RemoteAnimationTargetCompat.LeafTaskFilter(); final TransitionUtil.LeafTaskFilter leafTaskFilter = new TransitionUtil.LeafTaskFilter(); for (int i = 0; i < info.getChanges().size(); ++i) { final TransitionInfo.Change change = info.getChanges().get(i); final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); Loading Loading @@ -308,7 +305,8 @@ public class RemoteTransitionCompat { int pausingIdx = TaskState.indexOf(mPausingTasks, change); if (pausingIdx >= 0) { // Something is showing/opening a previously-pausing app. targets[i] = newTarget(change, layer, mPausingTasks.get(pausingIdx).mLeash); targets[i] = TransitionUtil.newTarget(change, layer, mPausingTasks.get(pausingIdx).mLeash); mOpeningTasks.add(mPausingTasks.remove(pausingIdx)); // Setup hides opening tasks initially, so make it visible again (since we // are already showing it). Loading @@ -316,7 +314,7 @@ public class RemoteTransitionCompat { t.setAlpha(change.getLeash(), 1.f); } else { // We are receiving new opening tasks, so convert to onTasksAppeared. targets[i] = newTarget(change, layer, info, t, mLeashMap); targets[i] = TransitionUtil.newTarget(change, layer, info, t, mLeashMap); t.reparent(targets[i].leash, mInfo.getRootLeash()); t.setLayer(targets[i].leash, layer); mOpeningTasks.add(new TaskState(change, targets[i].leash)); Loading
packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java +2 −1 File changed.Preview size limit exceeded, changes collapsed. Show changes