Merge "Abstract some transition checks so they can be expanded." into sc-dev
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user