Merge "Abstract some transition checks so they can be expanded." into sc-dev

This commit is contained in:
Evan Rosky
2021-03-05 16:48:32 +00:00
committed by Android (Google) Code Review
9 changed files with 162 additions and 35 deletions

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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,

View File

@@ -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);

View File

@@ -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());

View File

@@ -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");
@@ -112,6 +112,14 @@ class TransitionController {
return mCollectingTransition != null;
}
/**
* @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)) {

View File

@@ -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) {