summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Evan Rosky <erosky@google.com> 2021-03-05 16:48:32 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2021-03-05 16:48:32 +0000
commit86234a6ebdc9c5d44b37f0373a1ecbd57ed9ee3e (patch)
tree6de14e6a1e4c02c5d3a1216c60c1225553c0e7c4
parentb2832745cc264d91d0d64f76c14a8b1cd7a1e3b9 (diff)
parent7e3bc7154e38579abd7d8d7898a8ec47a51f9af1 (diff)
Merge "Abstract some transition checks so they can be expanded." into sc-dev
-rw-r--r--core/java/android/window/TransitionFilter.java4
-rw-r--r--core/java/android/window/TransitionInfo.java27
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java14
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java27
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskSupervisor.java8
-rw-r--r--services/core/java/com/android/server/wm/Transition.java26
-rw-r--r--services/core/java/com/android/server/wm/TransitionController.java14
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TransitionTests.java73
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) {