Loading libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java +54 −24 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static android.view.WindowManager.TRANSIT_FIRST_CUSTOM; 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_IS_WALLPAPER; import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT; import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; Loading Loading @@ -226,18 +227,11 @@ public class Transitions implements RemoteCallable<Transitions> { } /** * Reparents all participants into a shared parent and orders them based on: the global transit * type, their transit mode, and their destination z-order. * Sets up visibility/alpha/transforms to resemble the starting state of an animation. */ private static void setupStartState(@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t, @NonNull SurfaceControl.Transaction finishT) { boolean isOpening = isOpeningType(info.getType()); if (info.getRootLeash().isValid()) { t.show(info.getRootLeash()); } // 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 for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); final SurfaceControl leash = change.getLeash(); Loading @@ -254,6 +248,52 @@ public class Transitions implements RemoteCallable<Transitions> { continue; } if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) { t.show(leash); t.setMatrix(leash, 1, 0, 0, 1); if (isOpening // If this is a transferred starting window, we want it immediately visible. && (change.getFlags() & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) == 0) { t.setAlpha(leash, 0.f); // fix alpha in finish transaction in case the animator itself no-ops. finishT.setAlpha(leash, 1.f); } } else if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) { // Wallpaper is a bit of an anomaly: it's visibility is tied to other WindowStates. // As a result, we actually can't hide it's WindowToken because there may not be a // transition associated with it becoming visible again. Fortunately, since it is // always z-ordered to the back, we don't have to worry about it flickering to the // front during reparenting, so the hide here isn't necessary for it. if ((change.getFlags() & FLAG_IS_WALLPAPER) == 0) { finishT.hide(leash); } } } } /** * Reparents all participants into a shared parent and orders them based on: the global transit * type, their transit mode, and their destination z-order. */ private static void setupAnimHierarchy(@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t, @NonNull SurfaceControl.Transaction finishT) { boolean isOpening = isOpeningType(info.getType()); if (info.getRootLeash().isValid()) { t.show(info.getRootLeash()); } // 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 for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); final SurfaceControl leash = change.getLeash(); final int mode = info.getChanges().get(i).getMode(); // Don't reparent anything that isn't independent within its parents if (!TransitionInfo.isIndependent(change, info)) { continue; } boolean hasParent = change.getParent() != null; if (!hasParent) { Loading @@ -263,24 +303,12 @@ public class Transitions implements RemoteCallable<Transitions> { } // Put all the OPEN/SHOW on top if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) { t.show(leash); t.setMatrix(leash, 1, 0, 0, 1); if (isOpening) { // put on top with 0 alpha // put on top t.setLayer(leash, zSplitLine + info.getChanges().size() - i); if ((change.getFlags() & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) { // This received a transferred starting window, so make it immediately // visible. t.setAlpha(leash, 1.f); } else { t.setAlpha(leash, 0.f); // fix alpha in finish transaction in case the animator itself no-ops. finishT.setAlpha(leash, 1.f); } } else { // put on bottom and leave it visible // put on bottom t.setLayer(leash, zSplitLine - i); t.setAlpha(leash, 1.f); } } else if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) { if (isOpening) { Loading @@ -290,7 +318,7 @@ public class Transitions implements RemoteCallable<Transitions> { // put on top t.setLayer(leash, zSplitLine + info.getChanges().size() - i); } } else { // CHANGE } else { // CHANGE or other t.setLayer(leash, zSplitLine + info.getChanges().size() - i); } } Loading Loading @@ -329,6 +357,8 @@ public class Transitions implements RemoteCallable<Transitions> { active.mInfo = info; active.mStartT = t; active.mFinishT = finishT; setupStartState(active.mInfo, active.mStartT, active.mFinishT); if (activeIdx > 0) { // This is now playing at the same time as an existing animation, so try merging it. attemptMergeTransition(mActiveTransitions.get(0), active); Loading Loading @@ -357,7 +387,7 @@ public class Transitions implements RemoteCallable<Transitions> { } void playTransition(@NonNull ActiveTransition active) { setupStartState(active.mInfo, active.mStartT, active.mFinishT); setupAnimHierarchy(active.mInfo, active.mStartT, active.mFinishT); // If a handler already chose to run this animation, try delegating to it first. if (active.mHandler != null) { Loading packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java +13 −5 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; import android.annotation.SuppressLint; import android.os.IBinder; import android.os.RemoteException; import android.util.ArrayMap; import android.util.Log; import android.view.IRemoteAnimationFinishedCallback; import android.view.IRemoteAnimationRunner; Loading Loading @@ -158,10 +159,11 @@ public class RemoteAnimationAdapterCompat { public void startAnimation(IBinder token, TransitionInfo info, SurfaceControl.Transaction t, IRemoteTransitionFinishedCallback finishCallback) { final ArrayMap<SurfaceControl, SurfaceControl> leashMap = new ArrayMap<>(); final RemoteAnimationTargetCompat[] appsCompat = RemoteAnimationTargetCompat.wrap(info, false /* wallpapers */); RemoteAnimationTargetCompat.wrap(info, false /* wallpapers */, t, leashMap); final RemoteAnimationTargetCompat[] wallpapersCompat = RemoteAnimationTargetCompat.wrap(info, true /* wallpapers */); RemoteAnimationTargetCompat.wrap(info, true /* wallpapers */, t, leashMap); // TODO(bc-unlock): Build wrapped object for non-apps target. final RemoteAnimationTargetCompat[] nonAppsCompat = new RemoteAnimationTargetCompat[0]; Loading Loading @@ -211,7 +213,7 @@ public class RemoteAnimationAdapterCompat { // Need to "boost" the closing things since that's what launcher expects. for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); final SurfaceControl leash = change.getLeash(); final SurfaceControl leash = leashMap.get(change.getLeash()); final int mode = info.getChanges().get(i).getMode(); // Only deal with independent layers if (!TransitionInfo.isIndependent(change, info)) continue; Loading @@ -227,14 +229,14 @@ public class RemoteAnimationAdapterCompat { } } else { if (launcherTask != null) { counterLauncher.addChild(t, launcherTask.getLeash()); counterLauncher.addChild(t, leashMap.get(launcherTask.getLeash())); } if (wallpaper != null && rotateDelta != 0 && wallpaper.getParent() != null) { counterWallpaper.setup(t, info.getChange(wallpaper.getParent()).getLeash(), rotateDelta, displayW, displayH); if (counterWallpaper.mSurface != null) { t.setLayer(counterWallpaper.mSurface, -1); counterWallpaper.addChild(t, wallpaper.getLeash()); counterWallpaper.addChild(t, leashMap.get(wallpaper.getLeash())); } } } Loading @@ -252,6 +254,12 @@ public class RemoteAnimationAdapterCompat { for (int i = 0; i < info.getChanges().size(); ++i) { info.getChanges().get(i).getLeash().release(); } SurfaceControl.Transaction t = new SurfaceControl.Transaction(); for (int i = 0; i < leashMap.size(); ++i) { if (leashMap.keyAt(i) == leashMap.valueAt(i)) continue; t.remove(leashMap.valueAt(i)); } t.apply(); finishCallback.onTransitionFinished(null /* wct */); } catch (RemoteException e) { Log.e("ActivityOptionsCompat", "Failed to call app controlled animation" Loading packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java +104 −4 Original line number Diff line number Diff line Loading @@ -17,11 +17,21 @@ package com.android.systemui.shared.system; import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; 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_IS_WALLPAPER; import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT; import android.annotation.NonNull; import android.annotation.SuppressLint; import android.app.ActivityManager; import android.app.WindowConfiguration; import android.graphics.Point; import android.graphics.Rect; import android.util.ArrayMap; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.WindowManager; Loading Loading @@ -97,10 +107,94 @@ public class RemoteAnimationTargetCompat { } } public RemoteAnimationTargetCompat(TransitionInfo.Change change, int order) { /** * 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) { boolean isOpening = info.getType() == TRANSIT_OPEN || info.getType() == TRANSIT_TO_FRONT; // 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(); // Don't move anything that isn't independent within its parents if (!TransitionInfo.isIndependent(change, info)) { if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT || mode == TRANSIT_CHANGE) { t.show(leash); t.setPosition(leash, change.getEndRelOffset().x, change.getEndRelOffset().y); } return; } boolean hasParent = change.getParent() != null; if (!hasParent) { t.reparent(leash, info.getRootLeash()); t.setPosition(leash, change.getStartAbsBounds().left - info.getRootOffset().x, change.getStartAbsBounds().top - info.getRootOffset().y); } t.show(leash); // Put all the OPEN/SHOW on top if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) { 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 (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) { 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().setParent(change.getParent() == null ? info.getRootLeash() : info.getChange(change.getParent()).getLeash()).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; } public RemoteAnimationTargetCompat(TransitionInfo.Change change, int order, TransitionInfo info, SurfaceControl.Transaction t) { taskId = change.getTaskInfo() != null ? change.getTaskInfo().taskId : -1; mode = newModeToLegacyMode(change.getMode()); leash = new SurfaceControlCompat(change.getLeash()); // TODO: once we can properly sync transactions across process, then get rid of this leash. leash = new SurfaceControlCompat(createLeash(info, change, order, t)); isTranslucent = (change.getFlags() & TransitionInfo.FLAG_TRANSLUCENT) != 0 || (change.getFlags() & TransitionInfo.FLAG_SHOW_WALLPAPER) != 0; clipRect = null; Loading Loading @@ -139,15 +233,21 @@ public class RemoteAnimationTargetCompat { * * @param wallpapers If true, this will return wallpaper targets; otherwise it returns * non-wallpaper targets. * @param leashMap Temporary map of change leash -> launcher leash. Is an output, so should be * populated by this function. If null, it is ignored. */ public static RemoteAnimationTargetCompat[] wrap(TransitionInfo info, boolean wallpapers) { public static RemoteAnimationTargetCompat[] wrap(TransitionInfo info, boolean wallpapers, SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap) { final ArrayList<RemoteAnimationTargetCompat> out = new ArrayList<>(); for (int i = 0; i < info.getChanges().size(); i++) { boolean changeIsWallpaper = (info.getChanges().get(i).getFlags() & TransitionInfo.FLAG_IS_WALLPAPER) != 0; if (wallpapers != changeIsWallpaper) continue; out.add(new RemoteAnimationTargetCompat(info.getChanges().get(i), info.getChanges().size() - i)); info.getChanges().size() - i, info, t)); if (leashMap == null) continue; leashMap.put(info.getChanges().get(i).getLeash(), out.get(out.size() - 1).leash.mSurfaceControl); } return out.toArray(new RemoteAnimationTargetCompat[out.size()]); } Loading packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java +26 −9 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import android.graphics.Rect; import android.os.IBinder; import android.os.Parcelable; import android.os.RemoteException; import android.util.ArrayMap; import android.util.Log; import android.view.IRecentsAnimationController; import android.view.SurfaceControl; Loading Loading @@ -108,10 +109,11 @@ public class RemoteTransitionCompat implements Parcelable { public void startAnimation(IBinder transition, TransitionInfo info, SurfaceControl.Transaction t, IRemoteTransitionFinishedCallback finishedCallback) { final ArrayMap<SurfaceControl, SurfaceControl> leashMap = new ArrayMap<>(); final RemoteAnimationTargetCompat[] apps = RemoteAnimationTargetCompat.wrap(info, false /* wallpapers */); RemoteAnimationTargetCompat.wrap(info, false /* wallpapers */, t, leashMap); final RemoteAnimationTargetCompat[] wallpapers = RemoteAnimationTargetCompat.wrap(info, true /* wallpapers */); RemoteAnimationTargetCompat.wrap(info, true /* wallpapers */, t, leashMap); // TODO(b/177438007): Move this set-up logic into launcher's animation impl. mToken = transition; // This transition is for opening recents, so recents is on-top. We want to draw Loading @@ -120,7 +122,8 @@ public class RemoteTransitionCompat implements Parcelable { for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); if (change.getMode() == TRANSIT_CLOSE || change.getMode() == TRANSIT_TO_BACK) { t.setLayer(change.getLeash(), info.getChanges().size() * 3 - i); t.setLayer(leashMap.get(change.getLeash()), info.getChanges().size() * 3 - i); if (change.getTaskInfo() != null) { pausingTask = change.getTaskInfo().token; } Loading @@ -131,7 +134,8 @@ public class RemoteTransitionCompat implements Parcelable { t.setAlpha(wallpapers[i].leash.mSurfaceControl, 1); } t.apply(); mRecentsSession.setup(controller, info, finishedCallback, pausingTask); mRecentsSession.setup(controller, info, finishedCallback, pausingTask, leashMap); recents.onAnimationStart(mRecentsSession, apps, wallpapers, new Rect(0, 0, 0, 0), new Rect()); } Loading Loading @@ -173,9 +177,11 @@ public class RemoteTransitionCompat implements Parcelable { private WindowContainerToken mPausingTask = null; private TransitionInfo mInfo = null; private SurfaceControl mOpeningLeash = null; private ArrayMap<SurfaceControl, SurfaceControl> mLeashMap = null; void setup(RecentsAnimationControllerCompat wrapped, TransitionInfo info, IRemoteTransitionFinishedCallback finishCB, WindowContainerToken pausingTask) { IRemoteTransitionFinishedCallback finishCB, WindowContainerToken pausingTask, ArrayMap<SurfaceControl, SurfaceControl> leashMap) { if (mInfo != null) { throw new IllegalStateException("Trying to run a new recents animation while" + " recents is already active."); Loading @@ -184,6 +190,7 @@ public class RemoteTransitionCompat implements Parcelable { mInfo = info; mFinishCB = finishCB; mPausingTask = pausingTask; mLeashMap = leashMap; } @SuppressLint("NewApi") Loading Loading @@ -211,11 +218,14 @@ public class RemoteTransitionCompat implements Parcelable { } // We are receiving a new opening task, so convert to onTaskAppeared. final int layer = mInfo.getChanges().size() * 3; t.reparent(mOpeningLeash, mInfo.getRootLeash()); t.setLayer(mOpeningLeash, layer); t.hide(mOpeningLeash); final RemoteAnimationTargetCompat target = new RemoteAnimationTargetCompat( openingTask, layer, mInfo, t); mLeashMap.put(mOpeningLeash, target.leash.mSurfaceControl); t.reparent(target.leash.mSurfaceControl, mInfo.getRootLeash()); t.setLayer(target.leash.mSurfaceControl, layer); t.hide(target.leash.mSurfaceControl); t.apply(); recents.onTaskAppeared(new RemoteAnimationTargetCompat(openingTask, layer)); recents.onTaskAppeared(target); return true; } Loading Loading @@ -272,6 +282,12 @@ public class RemoteTransitionCompat implements Parcelable { } // Release surface references now. This is apparently to free GPU // memory while doing quick operations (eg. during CTS). SurfaceControl.Transaction t = new SurfaceControl.Transaction(); for (int i = 0; i < mLeashMap.size(); ++i) { if (mLeashMap.keyAt(i) == mLeashMap.valueAt(i)) continue; t.remove(mLeashMap.valueAt(i)); } t.apply(); for (int i = 0; i < mInfo.getChanges().size(); ++i) { mInfo.getChanges().get(i).getLeash().release(); } Loading @@ -281,6 +297,7 @@ public class RemoteTransitionCompat implements Parcelable { mPausingTask = null; mInfo = null; mOpeningLeash = null; mLeashMap = null; } @Override public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) { Loading packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java +11 −11 Original line number Diff line number Diff line Loading @@ -68,8 +68,8 @@ public class RemoteTransitionTest extends SysuiTestCase { .addChange(TRANSIT_CLOSE, 0 /* flags */) .addChange(TRANSIT_OPEN, FLAG_IS_WALLPAPER).build(); // Check non-wallpaper extraction RemoteAnimationTargetCompat[] wrapped = RemoteAnimationTargetCompat.wrap(combined, false /* wallpapers */); RemoteAnimationTargetCompat[] wrapped = RemoteAnimationTargetCompat.wrap(combined, false /* wallpapers */, mock(SurfaceControl.Transaction.class), null /* leashes */); assertEquals(2, wrapped.length); int changeLayer = -1; int closeLayer = -1; Loading @@ -86,8 +86,8 @@ public class RemoteTransitionTest extends SysuiTestCase { assertTrue(closeLayer < changeLayer); // Check wallpaper extraction RemoteAnimationTargetCompat[] wallps = RemoteAnimationTargetCompat.wrap(combined, true /* wallpapers */); RemoteAnimationTargetCompat[] wallps = RemoteAnimationTargetCompat.wrap(combined, true /* wallpapers */, mock(SurfaceControl.Transaction.class), null /* leashes */); assertEquals(1, wallps.length); assertTrue(wallps[0].prefixOrderIndex < closeLayer); assertEquals(MODE_OPENING, wallps[0].mode); Loading @@ -95,16 +95,15 @@ public class RemoteTransitionTest extends SysuiTestCase { @Test public void testLegacyTargetWrapper() { TransitionInfo tinfo = new TransitionInfoBuilder(TRANSIT_CLOSE) .addChange(TRANSIT_CHANGE, FLAG_TRANSLUCENT).build(); final TransitionInfo.Change change = tinfo.getChanges().get(0); final Rect endBounds = new Rect(40, 60, 140, 200); final TransitionInfo.Change change = new TransitionInfo.Change(null /* token */, null /* leash */); change.setTaskInfo(createTaskInfo(1 /* taskId */, ACTIVITY_TYPE_HOME)); change.setMode(TRANSIT_CHANGE); change.setEndAbsBounds(endBounds); change.setEndRelOffset(0, 0); change.setFlags(FLAG_TRANSLUCENT); final RemoteAnimationTargetCompat wrapped = new RemoteAnimationTargetCompat(change, 0 /* order */); final RemoteAnimationTargetCompat wrapped = new RemoteAnimationTargetCompat(change, 0 /* order */, tinfo, mock(SurfaceControl.Transaction.class)); assertEquals(ACTIVITY_TYPE_HOME, wrapped.activityType); assertEquals(new Rect(0, 0, 100, 140), wrapped.localBounds); assertEquals(endBounds, wrapped.screenSpaceBounds); Loading @@ -122,7 +121,7 @@ public class RemoteTransitionTest extends SysuiTestCase { TransitionInfoBuilder addChange(@WindowManager.TransitionType int mode, @TransitionInfo.ChangeFlags int flags) { final TransitionInfo.Change change = new TransitionInfo.Change(null /* token */, null /* leash */); new TransitionInfo.Change(null /* token */, createMockSurface(true)); change.setMode(mode); change.setFlags(flags); mInfo.addChange(change); Loading @@ -138,6 +137,7 @@ public class RemoteTransitionTest extends SysuiTestCase { SurfaceControl sc = mock(SurfaceControl.class); if (valid) { doReturn(true).when(sc).isValid(); doReturn("TestSurface").when(sc).toString(); } return sc; } Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java +54 −24 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static android.view.WindowManager.TRANSIT_FIRST_CUSTOM; 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_IS_WALLPAPER; import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT; import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; Loading Loading @@ -226,18 +227,11 @@ public class Transitions implements RemoteCallable<Transitions> { } /** * Reparents all participants into a shared parent and orders them based on: the global transit * type, their transit mode, and their destination z-order. * Sets up visibility/alpha/transforms to resemble the starting state of an animation. */ private static void setupStartState(@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t, @NonNull SurfaceControl.Transaction finishT) { boolean isOpening = isOpeningType(info.getType()); if (info.getRootLeash().isValid()) { t.show(info.getRootLeash()); } // 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 for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); final SurfaceControl leash = change.getLeash(); Loading @@ -254,6 +248,52 @@ public class Transitions implements RemoteCallable<Transitions> { continue; } if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) { t.show(leash); t.setMatrix(leash, 1, 0, 0, 1); if (isOpening // If this is a transferred starting window, we want it immediately visible. && (change.getFlags() & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) == 0) { t.setAlpha(leash, 0.f); // fix alpha in finish transaction in case the animator itself no-ops. finishT.setAlpha(leash, 1.f); } } else if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) { // Wallpaper is a bit of an anomaly: it's visibility is tied to other WindowStates. // As a result, we actually can't hide it's WindowToken because there may not be a // transition associated with it becoming visible again. Fortunately, since it is // always z-ordered to the back, we don't have to worry about it flickering to the // front during reparenting, so the hide here isn't necessary for it. if ((change.getFlags() & FLAG_IS_WALLPAPER) == 0) { finishT.hide(leash); } } } } /** * Reparents all participants into a shared parent and orders them based on: the global transit * type, their transit mode, and their destination z-order. */ private static void setupAnimHierarchy(@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t, @NonNull SurfaceControl.Transaction finishT) { boolean isOpening = isOpeningType(info.getType()); if (info.getRootLeash().isValid()) { t.show(info.getRootLeash()); } // 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 for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); final SurfaceControl leash = change.getLeash(); final int mode = info.getChanges().get(i).getMode(); // Don't reparent anything that isn't independent within its parents if (!TransitionInfo.isIndependent(change, info)) { continue; } boolean hasParent = change.getParent() != null; if (!hasParent) { Loading @@ -263,24 +303,12 @@ public class Transitions implements RemoteCallable<Transitions> { } // Put all the OPEN/SHOW on top if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) { t.show(leash); t.setMatrix(leash, 1, 0, 0, 1); if (isOpening) { // put on top with 0 alpha // put on top t.setLayer(leash, zSplitLine + info.getChanges().size() - i); if ((change.getFlags() & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) { // This received a transferred starting window, so make it immediately // visible. t.setAlpha(leash, 1.f); } else { t.setAlpha(leash, 0.f); // fix alpha in finish transaction in case the animator itself no-ops. finishT.setAlpha(leash, 1.f); } } else { // put on bottom and leave it visible // put on bottom t.setLayer(leash, zSplitLine - i); t.setAlpha(leash, 1.f); } } else if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) { if (isOpening) { Loading @@ -290,7 +318,7 @@ public class Transitions implements RemoteCallable<Transitions> { // put on top t.setLayer(leash, zSplitLine + info.getChanges().size() - i); } } else { // CHANGE } else { // CHANGE or other t.setLayer(leash, zSplitLine + info.getChanges().size() - i); } } Loading Loading @@ -329,6 +357,8 @@ public class Transitions implements RemoteCallable<Transitions> { active.mInfo = info; active.mStartT = t; active.mFinishT = finishT; setupStartState(active.mInfo, active.mStartT, active.mFinishT); if (activeIdx > 0) { // This is now playing at the same time as an existing animation, so try merging it. attemptMergeTransition(mActiveTransitions.get(0), active); Loading Loading @@ -357,7 +387,7 @@ public class Transitions implements RemoteCallable<Transitions> { } void playTransition(@NonNull ActiveTransition active) { setupStartState(active.mInfo, active.mStartT, active.mFinishT); setupAnimHierarchy(active.mInfo, active.mStartT, active.mFinishT); // If a handler already chose to run this animation, try delegating to it first. if (active.mHandler != null) { Loading
packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java +13 −5 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; import android.annotation.SuppressLint; import android.os.IBinder; import android.os.RemoteException; import android.util.ArrayMap; import android.util.Log; import android.view.IRemoteAnimationFinishedCallback; import android.view.IRemoteAnimationRunner; Loading Loading @@ -158,10 +159,11 @@ public class RemoteAnimationAdapterCompat { public void startAnimation(IBinder token, TransitionInfo info, SurfaceControl.Transaction t, IRemoteTransitionFinishedCallback finishCallback) { final ArrayMap<SurfaceControl, SurfaceControl> leashMap = new ArrayMap<>(); final RemoteAnimationTargetCompat[] appsCompat = RemoteAnimationTargetCompat.wrap(info, false /* wallpapers */); RemoteAnimationTargetCompat.wrap(info, false /* wallpapers */, t, leashMap); final RemoteAnimationTargetCompat[] wallpapersCompat = RemoteAnimationTargetCompat.wrap(info, true /* wallpapers */); RemoteAnimationTargetCompat.wrap(info, true /* wallpapers */, t, leashMap); // TODO(bc-unlock): Build wrapped object for non-apps target. final RemoteAnimationTargetCompat[] nonAppsCompat = new RemoteAnimationTargetCompat[0]; Loading Loading @@ -211,7 +213,7 @@ public class RemoteAnimationAdapterCompat { // Need to "boost" the closing things since that's what launcher expects. for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); final SurfaceControl leash = change.getLeash(); final SurfaceControl leash = leashMap.get(change.getLeash()); final int mode = info.getChanges().get(i).getMode(); // Only deal with independent layers if (!TransitionInfo.isIndependent(change, info)) continue; Loading @@ -227,14 +229,14 @@ public class RemoteAnimationAdapterCompat { } } else { if (launcherTask != null) { counterLauncher.addChild(t, launcherTask.getLeash()); counterLauncher.addChild(t, leashMap.get(launcherTask.getLeash())); } if (wallpaper != null && rotateDelta != 0 && wallpaper.getParent() != null) { counterWallpaper.setup(t, info.getChange(wallpaper.getParent()).getLeash(), rotateDelta, displayW, displayH); if (counterWallpaper.mSurface != null) { t.setLayer(counterWallpaper.mSurface, -1); counterWallpaper.addChild(t, wallpaper.getLeash()); counterWallpaper.addChild(t, leashMap.get(wallpaper.getLeash())); } } } Loading @@ -252,6 +254,12 @@ public class RemoteAnimationAdapterCompat { for (int i = 0; i < info.getChanges().size(); ++i) { info.getChanges().get(i).getLeash().release(); } SurfaceControl.Transaction t = new SurfaceControl.Transaction(); for (int i = 0; i < leashMap.size(); ++i) { if (leashMap.keyAt(i) == leashMap.valueAt(i)) continue; t.remove(leashMap.valueAt(i)); } t.apply(); finishCallback.onTransitionFinished(null /* wct */); } catch (RemoteException e) { Log.e("ActivityOptionsCompat", "Failed to call app controlled animation" Loading
packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java +104 −4 Original line number Diff line number Diff line Loading @@ -17,11 +17,21 @@ package com.android.systemui.shared.system; import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; 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_IS_WALLPAPER; import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT; import android.annotation.NonNull; import android.annotation.SuppressLint; import android.app.ActivityManager; import android.app.WindowConfiguration; import android.graphics.Point; import android.graphics.Rect; import android.util.ArrayMap; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.WindowManager; Loading Loading @@ -97,10 +107,94 @@ public class RemoteAnimationTargetCompat { } } public RemoteAnimationTargetCompat(TransitionInfo.Change change, int order) { /** * 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) { boolean isOpening = info.getType() == TRANSIT_OPEN || info.getType() == TRANSIT_TO_FRONT; // 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(); // Don't move anything that isn't independent within its parents if (!TransitionInfo.isIndependent(change, info)) { if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT || mode == TRANSIT_CHANGE) { t.show(leash); t.setPosition(leash, change.getEndRelOffset().x, change.getEndRelOffset().y); } return; } boolean hasParent = change.getParent() != null; if (!hasParent) { t.reparent(leash, info.getRootLeash()); t.setPosition(leash, change.getStartAbsBounds().left - info.getRootOffset().x, change.getStartAbsBounds().top - info.getRootOffset().y); } t.show(leash); // Put all the OPEN/SHOW on top if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) { 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 (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) { 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().setParent(change.getParent() == null ? info.getRootLeash() : info.getChange(change.getParent()).getLeash()).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; } public RemoteAnimationTargetCompat(TransitionInfo.Change change, int order, TransitionInfo info, SurfaceControl.Transaction t) { taskId = change.getTaskInfo() != null ? change.getTaskInfo().taskId : -1; mode = newModeToLegacyMode(change.getMode()); leash = new SurfaceControlCompat(change.getLeash()); // TODO: once we can properly sync transactions across process, then get rid of this leash. leash = new SurfaceControlCompat(createLeash(info, change, order, t)); isTranslucent = (change.getFlags() & TransitionInfo.FLAG_TRANSLUCENT) != 0 || (change.getFlags() & TransitionInfo.FLAG_SHOW_WALLPAPER) != 0; clipRect = null; Loading Loading @@ -139,15 +233,21 @@ public class RemoteAnimationTargetCompat { * * @param wallpapers If true, this will return wallpaper targets; otherwise it returns * non-wallpaper targets. * @param leashMap Temporary map of change leash -> launcher leash. Is an output, so should be * populated by this function. If null, it is ignored. */ public static RemoteAnimationTargetCompat[] wrap(TransitionInfo info, boolean wallpapers) { public static RemoteAnimationTargetCompat[] wrap(TransitionInfo info, boolean wallpapers, SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap) { final ArrayList<RemoteAnimationTargetCompat> out = new ArrayList<>(); for (int i = 0; i < info.getChanges().size(); i++) { boolean changeIsWallpaper = (info.getChanges().get(i).getFlags() & TransitionInfo.FLAG_IS_WALLPAPER) != 0; if (wallpapers != changeIsWallpaper) continue; out.add(new RemoteAnimationTargetCompat(info.getChanges().get(i), info.getChanges().size() - i)); info.getChanges().size() - i, info, t)); if (leashMap == null) continue; leashMap.put(info.getChanges().get(i).getLeash(), out.get(out.size() - 1).leash.mSurfaceControl); } return out.toArray(new RemoteAnimationTargetCompat[out.size()]); } Loading
packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java +26 −9 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import android.graphics.Rect; import android.os.IBinder; import android.os.Parcelable; import android.os.RemoteException; import android.util.ArrayMap; import android.util.Log; import android.view.IRecentsAnimationController; import android.view.SurfaceControl; Loading Loading @@ -108,10 +109,11 @@ public class RemoteTransitionCompat implements Parcelable { public void startAnimation(IBinder transition, TransitionInfo info, SurfaceControl.Transaction t, IRemoteTransitionFinishedCallback finishedCallback) { final ArrayMap<SurfaceControl, SurfaceControl> leashMap = new ArrayMap<>(); final RemoteAnimationTargetCompat[] apps = RemoteAnimationTargetCompat.wrap(info, false /* wallpapers */); RemoteAnimationTargetCompat.wrap(info, false /* wallpapers */, t, leashMap); final RemoteAnimationTargetCompat[] wallpapers = RemoteAnimationTargetCompat.wrap(info, true /* wallpapers */); RemoteAnimationTargetCompat.wrap(info, true /* wallpapers */, t, leashMap); // TODO(b/177438007): Move this set-up logic into launcher's animation impl. mToken = transition; // This transition is for opening recents, so recents is on-top. We want to draw Loading @@ -120,7 +122,8 @@ public class RemoteTransitionCompat implements Parcelable { for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); if (change.getMode() == TRANSIT_CLOSE || change.getMode() == TRANSIT_TO_BACK) { t.setLayer(change.getLeash(), info.getChanges().size() * 3 - i); t.setLayer(leashMap.get(change.getLeash()), info.getChanges().size() * 3 - i); if (change.getTaskInfo() != null) { pausingTask = change.getTaskInfo().token; } Loading @@ -131,7 +134,8 @@ public class RemoteTransitionCompat implements Parcelable { t.setAlpha(wallpapers[i].leash.mSurfaceControl, 1); } t.apply(); mRecentsSession.setup(controller, info, finishedCallback, pausingTask); mRecentsSession.setup(controller, info, finishedCallback, pausingTask, leashMap); recents.onAnimationStart(mRecentsSession, apps, wallpapers, new Rect(0, 0, 0, 0), new Rect()); } Loading Loading @@ -173,9 +177,11 @@ public class RemoteTransitionCompat implements Parcelable { private WindowContainerToken mPausingTask = null; private TransitionInfo mInfo = null; private SurfaceControl mOpeningLeash = null; private ArrayMap<SurfaceControl, SurfaceControl> mLeashMap = null; void setup(RecentsAnimationControllerCompat wrapped, TransitionInfo info, IRemoteTransitionFinishedCallback finishCB, WindowContainerToken pausingTask) { IRemoteTransitionFinishedCallback finishCB, WindowContainerToken pausingTask, ArrayMap<SurfaceControl, SurfaceControl> leashMap) { if (mInfo != null) { throw new IllegalStateException("Trying to run a new recents animation while" + " recents is already active."); Loading @@ -184,6 +190,7 @@ public class RemoteTransitionCompat implements Parcelable { mInfo = info; mFinishCB = finishCB; mPausingTask = pausingTask; mLeashMap = leashMap; } @SuppressLint("NewApi") Loading Loading @@ -211,11 +218,14 @@ public class RemoteTransitionCompat implements Parcelable { } // We are receiving a new opening task, so convert to onTaskAppeared. final int layer = mInfo.getChanges().size() * 3; t.reparent(mOpeningLeash, mInfo.getRootLeash()); t.setLayer(mOpeningLeash, layer); t.hide(mOpeningLeash); final RemoteAnimationTargetCompat target = new RemoteAnimationTargetCompat( openingTask, layer, mInfo, t); mLeashMap.put(mOpeningLeash, target.leash.mSurfaceControl); t.reparent(target.leash.mSurfaceControl, mInfo.getRootLeash()); t.setLayer(target.leash.mSurfaceControl, layer); t.hide(target.leash.mSurfaceControl); t.apply(); recents.onTaskAppeared(new RemoteAnimationTargetCompat(openingTask, layer)); recents.onTaskAppeared(target); return true; } Loading Loading @@ -272,6 +282,12 @@ public class RemoteTransitionCompat implements Parcelable { } // Release surface references now. This is apparently to free GPU // memory while doing quick operations (eg. during CTS). SurfaceControl.Transaction t = new SurfaceControl.Transaction(); for (int i = 0; i < mLeashMap.size(); ++i) { if (mLeashMap.keyAt(i) == mLeashMap.valueAt(i)) continue; t.remove(mLeashMap.valueAt(i)); } t.apply(); for (int i = 0; i < mInfo.getChanges().size(); ++i) { mInfo.getChanges().get(i).getLeash().release(); } Loading @@ -281,6 +297,7 @@ public class RemoteTransitionCompat implements Parcelable { mPausingTask = null; mInfo = null; mOpeningLeash = null; mLeashMap = null; } @Override public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) { Loading
packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java +11 −11 Original line number Diff line number Diff line Loading @@ -68,8 +68,8 @@ public class RemoteTransitionTest extends SysuiTestCase { .addChange(TRANSIT_CLOSE, 0 /* flags */) .addChange(TRANSIT_OPEN, FLAG_IS_WALLPAPER).build(); // Check non-wallpaper extraction RemoteAnimationTargetCompat[] wrapped = RemoteAnimationTargetCompat.wrap(combined, false /* wallpapers */); RemoteAnimationTargetCompat[] wrapped = RemoteAnimationTargetCompat.wrap(combined, false /* wallpapers */, mock(SurfaceControl.Transaction.class), null /* leashes */); assertEquals(2, wrapped.length); int changeLayer = -1; int closeLayer = -1; Loading @@ -86,8 +86,8 @@ public class RemoteTransitionTest extends SysuiTestCase { assertTrue(closeLayer < changeLayer); // Check wallpaper extraction RemoteAnimationTargetCompat[] wallps = RemoteAnimationTargetCompat.wrap(combined, true /* wallpapers */); RemoteAnimationTargetCompat[] wallps = RemoteAnimationTargetCompat.wrap(combined, true /* wallpapers */, mock(SurfaceControl.Transaction.class), null /* leashes */); assertEquals(1, wallps.length); assertTrue(wallps[0].prefixOrderIndex < closeLayer); assertEquals(MODE_OPENING, wallps[0].mode); Loading @@ -95,16 +95,15 @@ public class RemoteTransitionTest extends SysuiTestCase { @Test public void testLegacyTargetWrapper() { TransitionInfo tinfo = new TransitionInfoBuilder(TRANSIT_CLOSE) .addChange(TRANSIT_CHANGE, FLAG_TRANSLUCENT).build(); final TransitionInfo.Change change = tinfo.getChanges().get(0); final Rect endBounds = new Rect(40, 60, 140, 200); final TransitionInfo.Change change = new TransitionInfo.Change(null /* token */, null /* leash */); change.setTaskInfo(createTaskInfo(1 /* taskId */, ACTIVITY_TYPE_HOME)); change.setMode(TRANSIT_CHANGE); change.setEndAbsBounds(endBounds); change.setEndRelOffset(0, 0); change.setFlags(FLAG_TRANSLUCENT); final RemoteAnimationTargetCompat wrapped = new RemoteAnimationTargetCompat(change, 0 /* order */); final RemoteAnimationTargetCompat wrapped = new RemoteAnimationTargetCompat(change, 0 /* order */, tinfo, mock(SurfaceControl.Transaction.class)); assertEquals(ACTIVITY_TYPE_HOME, wrapped.activityType); assertEquals(new Rect(0, 0, 100, 140), wrapped.localBounds); assertEquals(endBounds, wrapped.screenSpaceBounds); Loading @@ -122,7 +121,7 @@ public class RemoteTransitionTest extends SysuiTestCase { TransitionInfoBuilder addChange(@WindowManager.TransitionType int mode, @TransitionInfo.ChangeFlags int flags) { final TransitionInfo.Change change = new TransitionInfo.Change(null /* token */, null /* leash */); new TransitionInfo.Change(null /* token */, createMockSurface(true)); change.setMode(mode); change.setFlags(flags); mInfo.addChange(change); Loading @@ -138,6 +137,7 @@ public class RemoteTransitionTest extends SysuiTestCase { SurfaceControl sc = mock(SurfaceControl.class); if (valid) { doReturn(true).when(sc).isValid(); doReturn("TestSurface").when(sc).toString(); } return sc; } Loading