diff options
| author | 2021-03-05 16:48:32 +0000 | |
|---|---|---|
| committer | 2021-03-05 16:48:32 +0000 | |
| commit | 86234a6ebdc9c5d44b37f0373a1ecbd57ed9ee3e (patch) | |
| tree | 6de14e6a1e4c02c5d3a1216c60c1225553c0e7c4 | |
| parent | b2832745cc264d91d0d64f76c14a8b1cd7a1e3b9 (diff) | |
| parent | 7e3bc7154e38579abd7d8d7898a8ec47a51f9af1 (diff) | |
Merge "Abstract some transition checks so they can be expanded." into sc-dev
9 files changed, 162 insertions, 35 deletions
diff --git a/core/java/android/window/TransitionFilter.java b/core/java/android/window/TransitionFilter.java index 4421f06460a0..141f47b130d1 100644 --- a/core/java/android/window/TransitionFilter.java +++ b/core/java/android/window/TransitionFilter.java @@ -139,8 +139,8 @@ public final class TransitionFilter implements Parcelable { boolean matches(@NonNull TransitionInfo info) { for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); - if (change.getParent() != null) { - // Only look at the top animating windows. + if (!TransitionInfo.isIndependent(change, info)) { + // Only look at independent animating windows. continue; } if (mActivityType != ACTIVITY_TYPE_UNDEFINED) { diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java index d1d49b6d4722..499ce25f8bb9 100644 --- a/core/java/android/window/TransitionInfo.java +++ b/core/java/android/window/TransitionInfo.java @@ -246,6 +246,33 @@ public final class TransitionInfo implements Parcelable { return sb.toString(); } + /** + * Indication that `change` is independent of parents (ie. it has a different type of + * transition vs. "going along for the ride") + */ + public static boolean isIndependent(TransitionInfo.Change change, TransitionInfo info) { + // If the change has no parent (it is root), then it is independent + if (change.getParent() == null) return true; + + // non-visibility changes will just be folded into the parent change, so they aren't + // independent either. + if (change.getMode() == TRANSIT_CHANGE) return false; + + TransitionInfo.Change parentChg = info.getChange(change.getParent()); + while (parentChg != null) { + // If the parent is a visibility change, it will include the results of all child + // changes into itself, so none of its children can be independent. + if (parentChg.getMode() != TRANSIT_CHANGE) return false; + + // If there are no more parents left, then all the parents, so far, have not been + // visibility changes which means this change is indpendent. + if (parentChg.getParent() == null) return true; + + parentChg = info.getChange(parentChg.getParent()); + } + return false; + } + /** Represents the change a WindowContainer undergoes during a transition */ public static final class Change implements Parcelable { private final WindowContainerToken mContainer; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java index 2182ee5590e1..629ff0db6b4a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java @@ -97,8 +97,8 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); - // Don't animate anything with an animating parent - if (change.getParent() != null) continue; + // Don't animate anything that isn't independent. + if (!TransitionInfo.isIndependent(change, info)) continue; Animation a = loadAnimation(info.getType(), change); if (a != null) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java index 89eee67bf5af..677db10d07a7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java @@ -214,8 +214,8 @@ public class Transitions { final SurfaceControl leash = change.getLeash(); final int mode = info.getChanges().get(i).getMode(); - // Don't move anything with an animating parent - if (change.getParent() != null) { + // 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.setMatrix(leash, 1, 0, 0, 1); @@ -225,9 +225,13 @@ public class Transitions { continue; } - t.reparent(leash, info.getRootLeash()); - t.setPosition(leash, change.getStartAbsBounds().left - info.getRootOffset().x, - change.getStartAbsBounds().top - info.getRootOffset().y); + 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); + } // Put all the OPEN/SHOW on top if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) { t.show(leash); diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java index e6477f158c27..400bf15f8c65 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java @@ -113,17 +113,6 @@ public class RemoteAnimationAdapterCompat { // TODO(bc-unlock): Build wrapped object for non-apps target. final RemoteAnimationTargetCompat[] nonAppsCompat = new RemoteAnimationTargetCompat[0]; - final Runnable animationFinishedCallback = new Runnable() { - @Override - public void run() { - try { - finishCallback.onTransitionFinished(null /* wct */); - } catch (RemoteException e) { - Log.e("ActivityOptionsCompat", "Failed to call app controlled animation" - + " finished callback", e); - } - } - }; // TODO(b/177438007): Move this set-up logic into launcher's animation impl. boolean isReturnToHome = false; @@ -143,8 +132,8 @@ public class RemoteAnimationAdapterCompat { final TransitionInfo.Change change = info.getChanges().get(i); final SurfaceControl leash = change.getLeash(); final int mode = info.getChanges().get(i).getMode(); - // Only deal with roots - if (change.getParent() != null) continue; + // Only deal with independent layers + if (!TransitionInfo.isIndependent(change, info)) continue; if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) { t.setLayer(leash, info.getChanges().size() * 3 - i); } @@ -156,6 +145,18 @@ public class RemoteAnimationAdapterCompat { } } t.apply(); + + final Runnable animationFinishedCallback = new Runnable() { + @Override + public void run() { + try { + finishCallback.onTransitionFinished(null /* wct */); + } catch (RemoteException e) { + Log.e("ActivityOptionsCompat", "Failed to call app controlled animation" + + " finished callback", e); + } + } + }; // TODO(bc-unlcok): Pass correct transit type. remoteAnimationAdapter.onAnimationStart( TRANSIT_OLD_NONE, diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index bb0f1f0b6f5f..db751e9759fa 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -1504,7 +1504,13 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { // Prevent recursion. return; } - mService.getTransitionController().requestTransitionIfNeeded(TRANSIT_CLOSE, task); + if (task.isVisible()) { + mService.getTransitionController().requestTransitionIfNeeded(TRANSIT_CLOSE, task); + } else { + // Removing a non-visible task doesn't require a transition, but if there is one + // collecting, this should be a member just in case. + mService.getTransitionController().collect(task); + } task.mInRemoveTask = true; try { task.performClearTask(reason); diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index ee4c66d05eb4..aadb2722a313 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -240,16 +240,18 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe for (int i = mTargets.size() - 1; i >= 0; --i) { final WindowContainer target = mTargets.valueAt(i); if (target.getParent() != null) { + final SurfaceControl targetLeash = getLeashSurface(target); + final SurfaceControl origParent = getOrigParentSurface(target); // Ensure surfaceControls are re-parented back into the hierarchy. - t.reparent(target.getSurfaceControl(), target.getParent().getSurfaceControl()); - t.setLayer(target.getSurfaceControl(), target.getLastLayer()); + t.reparent(targetLeash, origParent); + t.setLayer(targetLeash, target.getLastLayer()); // TODO(shell-transitions): Once all remotables have been moved, see if there is // a more appropriate place to do the following. This may // involve passing an SF transaction from shell on finish. target.getRelativePosition(tmpPos); - t.setPosition(target.getSurfaceControl(), tmpPos.x, tmpPos.y); - t.setCornerRadius(target.getSurfaceControl(), 0); - t.setShadowRadius(target.getSurfaceControl(), 0); + t.setPosition(targetLeash, tmpPos.x, tmpPos.y); + t.setCornerRadius(targetLeash, 0); + t.setShadowRadius(targetLeash, 0); displays.add(target.getDisplayContent()); } } @@ -465,8 +467,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe final int depth = getChildDepth(topTargets.valueAt(j), sibling); if (depth < 0) continue; if (depth == 0) { - final int siblingMode = sibling.isVisibleRequested() - ? TRANSIT_OPEN : TRANSIT_CLOSE; + final int siblingMode = changes.get(sibling).getTransitMode(sibling); ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, " sibling is a top target with mode %s", TransitionInfo.modeToString(siblingMode)); @@ -648,6 +649,15 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe } } + /** Gets the leash surface for a window container */ + private static SurfaceControl getLeashSurface(WindowContainer wc) { + return wc.getSurfaceControl(); + } + + private static SurfaceControl getOrigParentSurface(WindowContainer wc) { + return wc.getParent().getSurfaceControl(); + } + /** * Construct a TransitionInfo object from a set of targets and changes. Also populates the * root surface. @@ -723,7 +733,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe final ChangeInfo info = changes.get(target); final TransitionInfo.Change change = new TransitionInfo.Change( target.mRemoteToken != null ? target.mRemoteToken.toWindowContainerToken() - : null, target.getSurfaceControl()); + : null, getLeashSurface(target)); // TODO(shell-transitions): Use leash for non-organized windows. if (info.mParent != null) { change.setParent(info.mParent.mRemoteToken.toWindowContainerToken()); diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java index 5f46ffe604a6..6338f39e2e67 100644 --- a/services/core/java/com/android/server/wm/TransitionController.java +++ b/services/core/java/com/android/server/wm/TransitionController.java @@ -69,7 +69,7 @@ class TransitionController { * Creates a transition. It can immediately collect participants. */ @NonNull - Transition createTransition(@WindowManager.TransitionOldType int type, + Transition createTransition(@WindowManager.TransitionType int type, @WindowManager.TransitionFlags int flags) { if (mTransitionPlayer == null) { throw new IllegalStateException("Shell Transitions not enabled"); @@ -113,6 +113,14 @@ class TransitionController { } /** + * @return {@code true} if transition is actively collecting changes and `wc` is one of them. + * This is {@code false} once a transition is playing. + */ + boolean isCollecting(@NonNull WindowContainer wc) { + return mCollectingTransition != null && mCollectingTransition.mParticipants.contains(wc); + } + + /** * @return {@code true} if transition is actively playing. This is not necessarily {@code true} * during collection. */ @@ -128,9 +136,7 @@ class TransitionController { /** @return {@code true} if wc is in a participant subtree */ boolean inTransition(@NonNull WindowContainer wc) { - if (mCollectingTransition != null && mCollectingTransition.mParticipants.contains(wc)) { - return true; - } + if (isCollecting(wc)) return true; for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) { for (WindowContainer p = wc; p != null; p = p.getParent()) { if (mPlayingTransitions.get(i).mParticipants.contains(p)) { diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java index 154a899fb5ff..79ef8680dfec 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java @@ -25,11 +25,14 @@ import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; import static android.window.TransitionInfo.FLAG_SHOW_WALLPAPER; +import static android.window.TransitionInfo.isIndependent; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; @@ -343,6 +346,76 @@ public class TransitionTests extends WindowTestsBase { tasks[showWallpaperTask].mRemoteToken.toWindowContainerToken()).getFlags()); } + @Test + public void testIndependent() { + final Transition transition = createTestTransition(TRANSIT_OPEN); + ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges; + ArraySet<WindowContainer> participants = transition.mParticipants; + ITaskOrganizer mockOrg = mock(ITaskOrganizer.class); + + final Task openTask = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN, + ACTIVITY_TYPE_STANDARD, mDisplayContent); + final Task openInOpenTask = createTaskInStack(openTask, 0); + final ActivityRecord openInOpen = createActivityRecord(openInOpenTask); + + final Task changeTask = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN, + ACTIVITY_TYPE_STANDARD, mDisplayContent); + final Task changeInChangeTask = createTaskInStack(changeTask, 0); + final Task openInChangeTask = createTaskInStack(changeTask, 0); + final ActivityRecord changeInChange = createActivityRecord(changeInChangeTask); + final ActivityRecord openInChange = createActivityRecord(openInChangeTask); + // set organizer for everything so that they all get added to transition info + for (Task t : new Task[]{ + openTask, openInOpenTask, changeTask, changeInChangeTask, openInChangeTask}) { + t.mTaskOrganizer = mockOrg; + } + + // Start states. + changes.put(openTask, new Transition.ChangeInfo(false /* vis */, true /* exChg */)); + changes.put(changeTask, new Transition.ChangeInfo(true /* vis */, false /* exChg */)); + changes.put(openInOpenTask, new Transition.ChangeInfo(false /* vis */, true /* exChg */)); + changes.put(openInChangeTask, new Transition.ChangeInfo(false /* vis */, true /* exChg */)); + changes.put(changeInChangeTask, + new Transition.ChangeInfo(true /* vis */, false /* exChg */)); + changes.put(openInOpen, new Transition.ChangeInfo(false /* vis */, true /* exChg */)); + changes.put(openInChange, new Transition.ChangeInfo(false /* vis */, true /* exChg */)); + changes.put(changeInChange, new Transition.ChangeInfo(true /* vis */, false /* exChg */)); + fillChangeMap(changes, openTask); + // End states. + changeInChange.mVisibleRequested = true; + openInOpen.mVisibleRequested = true; + openInChange.mVisibleRequested = true; + + int transit = TRANSIT_OLD_TASK_OPEN; + int flags = 0; + + // Check full promotion from leaf + participants.add(changeInChange); + participants.add(openInOpen); + participants.add(openInChange); + // Explicitly add changeTask (to test independence with parents) + participants.add(changeTask); + ArraySet<WindowContainer> targets = Transition.calculateTargets(participants, changes); + TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, changes); + // Root changes should always be considered independent + assertTrue(isIndependent( + info.getChange(openTask.mRemoteToken.toWindowContainerToken()), info)); + assertTrue(isIndependent( + info.getChange(changeTask.mRemoteToken.toWindowContainerToken()), info)); + + // Children of a open/close change are not independent + assertFalse(isIndependent( + info.getChange(openInOpenTask.mRemoteToken.toWindowContainerToken()), info)); + + // Non-root changes are not independent + assertFalse(isIndependent( + info.getChange(changeInChangeTask.mRemoteToken.toWindowContainerToken()), info)); + + // open/close within a change are independent + assertTrue(isIndependent( + info.getChange(openInChangeTask.mRemoteToken.toWindowContainerToken()), info)); + } + /** Fill the change map with all the parents of top. Change maps are usually fully populated */ private static void fillChangeMap(ArrayMap<WindowContainer, Transition.ChangeInfo> changes, WindowContainer top) { |