summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/window/TransitionInfo.java63
-rw-r--r--data/etc/services.core.protolog.json6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java11
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java9
-rw-r--r--services/core/java/com/android/server/wm/Transition.java90
-rw-r--r--services/core/java/com/android/server/wm/WallpaperController.java2
-rw-r--r--services/core/java/com/android/server/wm/WallpaperWindowToken.java13
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java17
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java11
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TransitionTests.java58
10 files changed, 264 insertions, 16 deletions
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index 52ab38fa2889..da291cf0fd2c 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -57,6 +57,32 @@ public final class TransitionInfo implements Parcelable {
})
public @interface TransitionMode {}
+ /** No flags */
+ public static final int FLAG_NONE = 0;
+
+ /** The container shows the wallpaper behind it. */
+ public static final int FLAG_SHOW_WALLPAPER = 1;
+
+ /** The container IS the wallpaper. */
+ public static final int FLAG_IS_WALLPAPER = 1 << 1;
+
+ /** The container is translucent. */
+ public static final int FLAG_TRANSLUCENT = 1 << 2;
+
+ // TODO: remove when starting-window is moved to Task
+ /** The container is the recipient of a transferred starting-window */
+ public static final int FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT = 1 << 3;
+
+ /** @hide */
+ @IntDef(prefix = { "FLAG_" }, value = {
+ FLAG_NONE,
+ FLAG_SHOW_WALLPAPER,
+ FLAG_IS_WALLPAPER,
+ FLAG_TRANSLUCENT,
+ FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT
+ })
+ public @interface ChangeFlags {}
+
private final @WindowManager.TransitionOldType int mType;
private final @WindowManager.TransitionFlags int mFlags;
private final ArrayList<Change> mChanges = new ArrayList<>();
@@ -198,12 +224,33 @@ public final class TransitionInfo implements Parcelable {
}
}
+ /** Converts change flags into a string representation. */
+ @NonNull
+ public static String flagsToString(@ChangeFlags int flags) {
+ if (flags == 0) return "NONE";
+ final StringBuilder sb = new StringBuilder();
+ if ((flags & FLAG_SHOW_WALLPAPER) != 0) {
+ sb.append("SHOW_WALLPAPER");
+ }
+ if ((flags & FLAG_IS_WALLPAPER) != 0) {
+ sb.append("IS_WALLPAPER");
+ }
+ if ((flags & FLAG_TRANSLUCENT) != 0) {
+ sb.append((sb.length() == 0 ? "" : "|") + "TRANSLUCENT");
+ }
+ if ((flags & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) {
+ sb.append((sb.length() == 0 ? "" : "|") + "STARTING_WINDOW_TRANSFER");
+ }
+ return sb.toString();
+ }
+
/** Represents the change a WindowContainer undergoes during a transition */
public static final class Change implements Parcelable {
private final WindowContainerToken mContainer;
private WindowContainerToken mParent;
private final SurfaceControl mLeash;
private @TransitionMode int mMode = TRANSIT_NONE;
+ private @ChangeFlags int mFlags = FLAG_NONE;
private final Rect mStartAbsBounds = new Rect();
private final Rect mEndAbsBounds = new Rect();
private final Point mEndRelOffset = new Point();
@@ -219,6 +266,7 @@ public final class TransitionInfo implements Parcelable {
mLeash = new SurfaceControl();
mLeash.readFromParcel(in);
mMode = in.readInt();
+ mFlags = in.readInt();
mStartAbsBounds.readFromParcel(in);
mEndAbsBounds.readFromParcel(in);
mEndRelOffset.readFromParcel(in);
@@ -234,6 +282,11 @@ public final class TransitionInfo implements Parcelable {
mMode = mode;
}
+ /** Sets the flags for this change */
+ public void setFlags(@ChangeFlags int flags) {
+ mFlags = flags;
+ }
+
/** Sets the bounds this container occupied before the change in screen space */
public void setStartAbsBounds(@Nullable Rect rect) {
mStartAbsBounds.set(rect);
@@ -269,6 +322,11 @@ public final class TransitionInfo implements Parcelable {
return mMode;
}
+ /** @return the flags for this change. */
+ public @ChangeFlags int getFlags() {
+ return mFlags;
+ }
+
/**
* @return the bounds of the container before the change. It may be empty if the container
* is coming into existence.
@@ -308,6 +366,7 @@ public final class TransitionInfo implements Parcelable {
dest.writeTypedObject(mParent, flags);
mLeash.writeToParcel(dest, flags);
dest.writeInt(mMode);
+ dest.writeInt(mFlags);
mStartAbsBounds.writeToParcel(dest, flags);
mEndAbsBounds.writeToParcel(dest, flags);
mEndRelOffset.writeToParcel(dest, flags);
@@ -336,8 +395,8 @@ public final class TransitionInfo implements Parcelable {
@Override
public String toString() {
return "{" + mContainer + "(" + mParent + ") leash=" + mLeash
- + " m=" + modeToString(mMode) + " sb=" + mStartAbsBounds
- + " eb=" + mEndAbsBounds + " eo=" + mEndRelOffset + "}";
+ + " m=" + modeToString(mMode) + " f=" + flagsToString(mFlags) + " sb="
+ + mStartAbsBounds + " eb=" + mEndAbsBounds + " eo=" + mEndRelOffset + "}";
}
}
}
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index faf49733050a..3f66efa505c8 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -73,6 +73,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-2036671725": {
+ "message": " SKIP: is wallpaper",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
"-2029985709": {
"message": "setFocusedTask: taskId=%d",
"level": "DEBUG",
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java
index a779531f8b91..54863d23643a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java
@@ -20,6 +20,7 @@ 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_STARTING_WINDOW_TRANSFER_RECIPIENT;
import android.animation.Animator;
import android.animation.ValueAnimator;
@@ -166,8 +167,14 @@ public class Transitions {
if (isOpening) {
// put on top and fade in
t.setLayer(leash, info.getChanges().size() - i);
- t.setAlpha(leash, 0.f);
- startExampleAnimation(transitionToken, leash, true /* show */);
+ 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);
+ startExampleAnimation(transitionToken, leash, true /* show */);
+ }
} else {
// put on bottom and leave it visible without fade
t.setLayer(leash, -i);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index ef845c843c5f..a930730ee09c 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -569,7 +569,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
private final WindowState.UpdateReportedVisibilityResults mReportedVisibilityResults =
new WindowState.UpdateReportedVisibilityResults();
- private boolean mUseTransferredAnimation;
+ boolean mUseTransferredAnimation;
/**
* @see #currentLaunchCanTurnScreenOn()
@@ -3492,8 +3492,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
ProtoLog.v(WM_DEBUG_ADD_REMOVE,
"Removing starting %s from %s", tStartingWindow, fromActivity);
- fromActivity.removeChild(tStartingWindow);
- addWindow(tStartingWindow);
+ mAtmService.getTransitionController().collect(tStartingWindow);
+ tStartingWindow.reparent(this, POSITION_TOP);
// Propagate other interesting state between the tokens. If the old token is displayed,
// we should immediately force the new one to be displayed. If it is animating, we need
@@ -3518,6 +3518,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// the token we transfer the animation over. Thus, set this flag to indicate
// we've transferred the animation.
mUseTransferredAnimation = true;
+ } else if (mAtmService.getTransitionController().getTransitionPlayer() != null) {
+ // In the new transit system, just set this every time we transfer the window
+ mUseTransferredAnimation = true;
}
// Post cleanup after the visibility and animation are transferred.
fromActivity.postWindowRemoveStartingWindowCleanup(tStartingWindow);
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 14504d896052..be78d7a18377 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -30,6 +30,10 @@ import static android.view.WindowManager.TRANSIT_NONE;
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_SHOW_WALLPAPER;
+import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
+import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -160,8 +164,20 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
}
if (mParticipants.contains(wc)) return;
mSyncEngine.addToSyncSet(mSyncId, wc);
- mChanges.put(wc, new ChangeInfo(wc));
+ ChangeInfo info = mChanges.get(wc);
+ if (info == null) {
+ info = new ChangeInfo(wc);
+ mChanges.put(wc, info);
+ }
mParticipants.add(wc);
+ if (info.mShowWallpaper) {
+ // Collect the wallpaper so it is part of the sync set.
+ final WindowContainer wallpaper =
+ wc.getDisplayContent().mWallpaperController.getTopVisibleWallpaper();
+ if (wallpaper != null) {
+ collect(wallpaper);
+ }
+ }
}
/**
@@ -386,6 +402,10 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
return -1;
}
+ private static boolean isWallpaper(WindowContainer wc) {
+ return wc instanceof WallpaperWindowToken;
+ }
+
/**
* Under some conditions (eg. all visible targets within a parent container are transitioning
* the same way) the transition can be "promoted" to the parent container. This means an
@@ -403,6 +423,10 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
parent == null ? "no parent" : ("parent can't be target " + parent));
return false;
}
+ if (isWallpaper(target)) {
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, " SKIP: is wallpaper");
+ return false;
+ }
@TransitionInfo.TransitionMode int mode = TRANSIT_NONE;
// Go through all siblings of this target to see if any of them would prevent
// the target from promoting.
@@ -604,18 +628,32 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
static TransitionInfo calculateTransitionInfo(int type, int flags,
ArraySet<WindowContainer> targets, ArrayMap<WindowContainer, ChangeInfo> changes) {
final TransitionInfo out = new TransitionInfo(type, flags);
- if (targets.isEmpty()) {
+
+ final ArraySet<WindowContainer> appTargets = new ArraySet<>();
+ final ArraySet<WindowContainer> wallpapers = new ArraySet<>();
+ for (int i = targets.size() - 1; i >= 0; --i) {
+ (isWallpaper(targets.valueAt(i)) ? wallpapers : appTargets).add(targets.valueAt(i));
+ }
+
+ // Find the top-most shared ancestor of app targets
+ WindowContainer ancestor = null;
+ for (int i = appTargets.size() - 1; i >= 0; --i) {
+ final WindowContainer wc = appTargets.valueAt(i);
+ ancestor = wc;
+ break;
+ }
+ if (ancestor == null) {
out.setRootLeash(new SurfaceControl(), 0, 0);
return out;
}
+ ancestor = ancestor.getParent();
- // Find the top-most shared ancestor
- WindowContainer ancestor = targets.valueAt(0).getParent();
- // Go up ancestor parent chain until all topTargets are descendants.
+ // Go up ancestor parent chain until all targets are descendants.
ancestorLoop:
while (ancestor != null) {
- for (int i = 1; i < targets.size(); ++i) {
- if (!targets.valueAt(i).isDescendantOf(ancestor)) {
+ for (int i = appTargets.size() - 1; i >= 0; --i) {
+ final WindowContainer wc = appTargets.valueAt(i);
+ if (!wc.isDescendantOf(ancestor)) {
ancestor = ancestor.getParent();
continue ancestorLoop;
}
@@ -623,7 +661,8 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
break;
}
- // Sort targets top-to-bottom in Z.
+ // Sort targets top-to-bottom in Z. Check ALL targets here in case the display area itself
+ // is animating: then we want to include wallpapers at the right position.
ArrayList<WindowContainer> sortedTargets = new ArrayList<>();
addMembersInOrder(ancestor, targets, sortedTargets);
@@ -640,6 +679,14 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
t.close();
out.setRootLeash(rootLeash, ancestor.getBounds().left, ancestor.getBounds().top);
+ // add the wallpapers at the bottom
+ for (int i = wallpapers.size() - 1; i >= 0; --i) {
+ final WindowContainer wc = wallpapers.valueAt(i);
+ // If the displayarea itself is animating, then the wallpaper was already added.
+ if (wc.isDescendantOf(ancestor)) break;
+ sortedTargets.add(wc);
+ }
+
// Convert all the resolved ChangeInfos into TransactionInfo.Change objects in order.
final int count = sortedTargets.size();
for (int i = 0; i < count; ++i) {
@@ -656,6 +703,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
change.setEndAbsBounds(target.getBounds());
change.setEndRelOffset(target.getBounds().left - target.getParent().getBounds().left,
target.getBounds().top - target.getParent().getBounds().top);
+ change.setFlags(info.getChangeFlags(target));
out.addChange(change);
}
@@ -678,17 +726,20 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
boolean mVisible;
int mWindowingMode;
final Rect mAbsoluteBounds = new Rect();
+ boolean mShowWallpaper;
ChangeInfo(@NonNull WindowContainer origState) {
mVisible = origState.isVisibleRequested();
mWindowingMode = origState.getWindowingMode();
mAbsoluteBounds.set(origState.getBounds());
+ mShowWallpaper = origState.showWallpaper();
}
@VisibleForTesting
ChangeInfo(boolean visible, boolean existChange) {
mVisible = visible;
mExistenceChanged = existChange;
+ mShowWallpaper = false;
}
boolean hasChanged(@NonNull WindowContainer newState) {
@@ -716,6 +767,29 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
}
}
+ @TransitionInfo.ChangeFlags
+ int getChangeFlags(@NonNull WindowContainer wc) {
+ int flags = 0;
+ if (mShowWallpaper || wc.showWallpaper()) {
+ flags |= FLAG_SHOW_WALLPAPER;
+ }
+ if (!wc.fillsParent()) {
+ // TODO(b/172695805): hierarchical check. This is non-trivial because for containers
+ // it is effected by child visibility but needs to work even
+ // before visibility is committed. This means refactoring some
+ // checks to use requested visibility.
+ flags |= FLAG_TRANSLUCENT;
+ }
+ if (wc instanceof ActivityRecord
+ && wc.asActivityRecord().mUseTransferredAnimation) {
+ flags |= FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
+ }
+ if (isWallpaper(wc)) {
+ flags |= FLAG_IS_WALLPAPER;
+ }
+ return flags;
+ }
+
void addChild(@NonNull WindowContainer wc) {
if (mChildren == null) {
mChildren = new ArraySet<>();
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 7809cbc2a167..1a3138d492c8 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -779,7 +779,7 @@ class WallpaperController {
wallpaperBuffer.getHardwareBuffer(), wallpaperBuffer.getColorSpace());
}
- private WindowState getTopVisibleWallpaper() {
+ WindowState getTopVisibleWallpaper() {
mTmpTopWallpaper = null;
for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index c27d0cda22ab..f572e8e2f0aa 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -96,6 +96,7 @@ class WallpaperWindowToken extends WindowToken {
void updateWallpaperVisibility(boolean visible) {
if (isVisible() != visible) {
+ mWmService.mAtmService.getTransitionController().collect(this);
// Need to do a layout to ensure the wallpaper now has the correct size.
mDisplayContent.setLayoutNeeded();
}
@@ -126,6 +127,7 @@ class WallpaperWindowToken extends WindowToken {
if (isVisible() != visible) {
if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG,
"Wallpaper token " + token + " visible=" + visible);
+ mWmService.mAtmService.getTransitionController().collect(this);
// Need to do a layout to ensure the wallpaper now has the correct size.
mDisplayContent.setLayoutNeeded();
}
@@ -200,6 +202,17 @@ class WallpaperWindowToken extends WindowToken {
}
@Override
+ boolean fillsParent() {
+ return true;
+ }
+
+ @Override
+ boolean showWallpaper() {
+ return false;
+ }
+
+
+ @Override
public String toString() {
if (stringName == null) {
StringBuilder sb = new StringBuilder();
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 576d22487437..19a750abe1a7 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -3077,6 +3077,23 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
return true;
}
+ /** @return {@code true} if the wallpaper is visible behind this container. */
+ boolean showWallpaper() {
+ if (!isVisibleRequested()
+ // in multi-window mode, wallpaper is always visible at the back and not tied to
+ // the app (there is no wallpaper target).
+ || inMultiWindowMode()) {
+ return false;
+ }
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final WindowContainer child = mChildren.get(i);
+ if (child.showWallpaper()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@Nullable
static WindowContainer fromBinder(IBinder binder) {
return RemoteToken.fromBinder(binder).getContainer();
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index a8f4bae1d519..11ed0a2b27e5 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -5736,6 +5736,17 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return mAttrs.type == TYPE_APPLICATION_STARTING;
}
+ @Override
+ boolean showWallpaper() {
+ if (!isVisibleRequested()
+ // in multi-window mode, wallpaper is always visible at the back and not tied to
+ // the app (there is no wallpaper target).
+ || inMultiWindowMode()) {
+ return false;
+ }
+ return (mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0;
+ }
+
/**
* When using the two WindowOrganizer sync-primitives (BoundsChangeTransaction, BLASTSync)
* it can be a little difficult to predict whether your change will actually trigger redrawing
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 00c2aa5ebc63..74248a950a38 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -19,14 +19,21 @@ package com.android.server.wm;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
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 com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -280,4 +287,55 @@ public class TransitionTests extends WindowTestsBase {
info.getChanges().get(i).getContainer());
}
}
+
+ @Test
+ public void testCreateInfo_wallpaper() {
+ final Transition transition = createTestTransition(TRANSIT_OLD_TASK_OPEN);
+ // pick some number with a high enough chance of being out-of-order when added to set.
+ final int taskCount = 4;
+ final int showWallpaperTask = 2;
+
+ final Task[] tasks = new Task[taskCount];
+ for (int i = 0; i < taskCount; ++i) {
+ // Each add goes on top, so at the end of this, task[9] should be on top
+ tasks[i] = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, mDisplayContent);
+ final ActivityRecord act = createActivityRecord(tasks[i]);
+ // alternate so that the transition doesn't get promoted to the display area
+ act.mVisibleRequested = (i % 2) == 0; // starts invisible
+ if (i == showWallpaperTask) {
+ doReturn(true).when(act).showWallpaper();
+ }
+ }
+
+ final WallpaperWindowToken wallpaperWindowToken = spy(new WallpaperWindowToken(mWm,
+ mock(IBinder.class), true, mDisplayContent, true /* ownerCanManageAppTokens */));
+ final WindowState wallpaperWindow = createWindow(null, TYPE_WALLPAPER, wallpaperWindowToken,
+ "wallpaperWindow");
+ wallpaperWindow.mWallpaperVisible = false;
+ transition.collect(wallpaperWindowToken);
+ wallpaperWindow.mWallpaperVisible = true;
+ wallpaperWindow.mHasSurface = true;
+
+ // doesn't matter which order collected since participants is a set
+ for (int i = 0; i < taskCount; ++i) {
+ transition.collectExistenceChange(tasks[i]);
+ final ActivityRecord act = tasks[i].getTopMostActivity();
+ transition.collect(act);
+ tasks[i].getTopMostActivity().mVisibleRequested = (i % 2) != 0;
+ }
+
+ ArraySet<WindowContainer> targets = Transition.calculateTargets(
+ transition.mParticipants, transition.mChanges);
+ TransitionInfo info = Transition.calculateTransitionInfo(
+ 0, 0, targets, transition.mChanges);
+ // verify that wallpaper is at bottom
+ assertEquals(taskCount + 1, info.getChanges().size());
+ // The wallpaper is not organized, so it won't have a token; however, it will be marked
+ // as IS_WALLPAPER
+ assertEquals(FLAG_IS_WALLPAPER,
+ info.getChanges().get(info.getChanges().size() - 1).getFlags());
+ assertEquals(FLAG_SHOW_WALLPAPER, info.getChange(
+ tasks[showWallpaperTask].mRemoteToken.toWindowContainerToken()).getFlags());
+ }
}