Add wallpaper leash for remote and recents animations
Bug: 140626334
Test: atest RecentsAnimationControllerTest
Test: atest RemoteAnimationControllerTest
Change-Id: Id638256983801e722b57da0abd22e3e480d5559d
Signed-off-by: Winson Chung <winsonc@google.com>
diff --git a/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java b/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java
index 2b6f455..9cfc3d2 100644
--- a/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java
+++ b/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java
@@ -188,8 +188,8 @@
@Override
public void onAnimationStart(IRecentsAnimationController controller,
- RemoteAnimationTarget[] apps, Rect homeContentInsets,
- Rect minimizedHomeBounds) throws RemoteException {
+ RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers,
+ Rect homeContentInsets, Rect minimizedHomeBounds) throws RemoteException {
final Pair<String, Boolean> finishCase = finishCases.get(mIteration++ % 2);
final boolean moveRecentsToTop = finishCase.second;
makeInterval();
diff --git a/core/java/android/view/IRecentsAnimationRunner.aidl b/core/java/android/view/IRecentsAnimationRunner.aidl
index 724d96e..6eb90fc 100644
--- a/core/java/android/view/IRecentsAnimationRunner.aidl
+++ b/core/java/android/view/IRecentsAnimationRunner.aidl
@@ -54,6 +54,6 @@
*/
@UnsupportedAppUsage
void onAnimationStart(in IRecentsAnimationController controller,
- in RemoteAnimationTarget[] apps, in Rect homeContentInsets,
- in Rect minimizedHomeBounds) = 2;
+ in RemoteAnimationTarget[] apps, in RemoteAnimationTarget[] wallpapers,
+ in Rect homeContentInsets, in Rect minimizedHomeBounds) = 2;
}
diff --git a/core/java/android/view/IRemoteAnimationRunner.aidl b/core/java/android/view/IRemoteAnimationRunner.aidl
index 73b023c..7b35aa2 100644
--- a/core/java/android/view/IRemoteAnimationRunner.aidl
+++ b/core/java/android/view/IRemoteAnimationRunner.aidl
@@ -34,7 +34,7 @@
* @param finishedCallback The callback to invoke when the animation is finished.
*/
@UnsupportedAppUsage
- void onAnimationStart(in RemoteAnimationTarget[] apps,
+ void onAnimationStart(in RemoteAnimationTarget[] apps, in RemoteAnimationTarget[] wallpapers,
in IRemoteAnimationFinishedCallback finishedCallback);
/**
diff --git a/core/java/android/view/SyncRtSurfaceTransactionApplier.java b/core/java/android/view/SyncRtSurfaceTransactionApplier.java
index 1b6c575..a6536f5d 100644
--- a/core/java/android/view/SyncRtSurfaceTransactionApplier.java
+++ b/core/java/android/view/SyncRtSurfaceTransactionApplier.java
@@ -255,7 +255,7 @@
this.surface = surface;
this.alpha = alpha;
this.matrix = new Matrix(matrix);
- this.windowCrop = new Rect(windowCrop);
+ this.windowCrop = windowCrop != null ? new Rect(windowCrop) : null;
this.layer = layer;
this.cornerRadius = cornerRadius;
this.visible = visible;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 82287873..00e8b53 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -225,14 +225,16 @@
runner = new IRecentsAnimationRunner.Stub() {
@Override
public void onAnimationStart(IRecentsAnimationController controller,
- RemoteAnimationTarget[] apps, Rect homeContentInsets,
- Rect minimizedHomeBounds) {
+ RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers,
+ Rect homeContentInsets, Rect minimizedHomeBounds) {
final RecentsAnimationControllerCompat controllerCompat =
new RecentsAnimationControllerCompat(controller);
final RemoteAnimationTargetCompat[] appsCompat =
RemoteAnimationTargetCompat.wrap(apps);
+ final RemoteAnimationTargetCompat[] wallpapersCompat =
+ RemoteAnimationTargetCompat.wrap(wallpapers);
animationHandler.onAnimationStart(controllerCompat, appsCompat,
- homeContentInsets, minimizedHomeBounds);
+ wallpapersCompat, homeContentInsets, minimizedHomeBounds);
}
@Override
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
index 579858a..2c99c5c 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
@@ -21,12 +21,12 @@
import com.android.systemui.shared.recents.model.ThumbnailData;
public interface RecentsAnimationListener {
-
/**
* Called when the animation into Recents can start. This call is made on the binder thread.
*/
void onAnimationStart(RecentsAnimationControllerCompat controller,
- RemoteAnimationTargetCompat[] apps, Rect homeContentInsets, Rect minimizedHomeBounds);
+ RemoteAnimationTargetCompat[] apps, RemoteAnimationTargetCompat[] wallpapers,
+ Rect homeContentInsets, Rect minimizedHomeBounds);
/**
* Called when the animation into Recents was canceled. This call is made on the binder thread.
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 61be076..02e509e 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
@@ -45,9 +45,12 @@
return new IRemoteAnimationRunner.Stub() {
@Override
public void onAnimationStart(RemoteAnimationTarget[] apps,
+ RemoteAnimationTarget[] wallpapers,
final IRemoteAnimationFinishedCallback finishedCallback) {
final RemoteAnimationTargetCompat[] appsCompat =
RemoteAnimationTargetCompat.wrap(apps);
+ final RemoteAnimationTargetCompat[] wallpapersCompat =
+ RemoteAnimationTargetCompat.wrap(wallpapers);
final Runnable animationFinishedCallback = new Runnable() {
@Override
public void run() {
@@ -59,7 +62,8 @@
}
}
};
- remoteAnimationAdapter.onAnimationStart(appsCompat, animationFinishedCallback);
+ remoteAnimationAdapter.onAnimationStart(appsCompat, wallpapersCompat,
+ animationFinishedCallback);
}
@Override
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java
index 5a85df9..33372f6 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java
@@ -17,6 +17,7 @@
package com.android.systemui.shared.system;
public interface RemoteAnimationRunnerCompat {
- void onAnimationStart(RemoteAnimationTargetCompat[] apps, Runnable finishedCallback);
+ void onAnimationStart(RemoteAnimationTargetCompat[] apps,
+ RemoteAnimationTargetCompat[] wallpapers, Runnable finishedCallback);
void onAnimationCancelled();
}
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
index 221782e..ca88f13 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
@@ -68,7 +68,7 @@
public static RemoteAnimationTargetCompat[] wrap(RemoteAnimationTarget[] apps) {
final RemoteAnimationTargetCompat[] appsCompat =
- new RemoteAnimationTargetCompat[apps.length];
+ new RemoteAnimationTargetCompat[apps != null ? apps.length : 0];
for (int i = 0; i < apps.length; i++) {
appsCompat[i] = new RemoteAnimationTargetCompat(apps[i]);
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
index 9ba21a3..e80b437 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
@@ -142,7 +142,9 @@
public static void applyParams(TransactionCompat t,
SyncRtSurfaceTransactionApplierCompat.SurfaceParams params) {
t.setMatrix(params.surface, params.matrix);
- t.setWindowCrop(params.surface, params.windowCrop);
+ if (params.windowCrop != null) {
+ t.setWindowCrop(params.surface, params.windowCrop);
+ }
t.setAlpha(params.surface, params.alpha);
t.setLayer(params.surface, params.layer);
t.setCornerRadius(params.surface, params.cornerRadius);
@@ -187,14 +189,14 @@
* @param surface The surface to modify.
* @param alpha Alpha to apply.
* @param matrix Matrix to apply.
- * @param windowCrop Crop to apply.
+ * @param windowCrop Crop to apply, only applied if not {@code null}
*/
public SurfaceParams(SurfaceControlCompat surface, float alpha, Matrix matrix,
Rect windowCrop, int layer, float cornerRadius) {
this.surface = surface;
this.alpha = alpha;
this.matrix = new Matrix(matrix);
- this.windowCrop = new Rect(windowCrop);
+ this.windowCrop = windowCrop != null ? new Rect(windowCrop) : null;
this.layer = layer;
this.cornerRadius = cornerRadius;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
index 91d4707..13c6f27 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
@@ -34,7 +34,6 @@
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.systemui.Interpolators;
-import com.android.systemui.shared.system.SurfaceControlCompat;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment;
@@ -145,6 +144,7 @@
@Override
public void onAnimationStart(RemoteAnimationTarget[] remoteAnimationTargets,
+ RemoteAnimationTarget[] remoteAnimationWallpaperTargets,
IRemoteAnimationFinishedCallback iRemoteAnimationFinishedCallback)
throws RemoteException {
mSourceNotification.post(() -> {
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 19b5f31..985c77a 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -93,6 +93,8 @@
private IRecentsAnimationRunner mRunner;
private final RecentsAnimationCallbacks mCallbacks;
private final ArrayList<TaskAnimationAdapter> mPendingAnimations = new ArrayList<>();
+ private final ArrayList<WallpaperAnimationAdapter> mPendingWallpaperAnimations =
+ new ArrayList<>();
private final int mDisplayId;
private final Runnable mFailsafeRunnable = () ->
cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "failSafeRunnable");
@@ -434,6 +436,13 @@
mPendingAnimations.remove(taskAdapter);
}
+ @VisibleForTesting
+ void removeWallpaperAnimation(WallpaperAnimationAdapter wallpaperAdapter) {
+ if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "removeWallpaperAnimation()");
+ wallpaperAdapter.getLeashFinishedCallback().onAnimationFinished(wallpaperAdapter);
+ mPendingWallpaperAnimations.remove(wallpaperAdapter);
+ }
+
void startAnimation() {
if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "startAnimation(): mPendingStart=" + mPendingStart
+ " mCanceled=" + mCanceled);
@@ -442,25 +451,18 @@
return;
}
try {
- final ArrayList<RemoteAnimationTarget> appAnimations = new ArrayList<>();
- for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
- final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i);
- final RemoteAnimationTarget target = taskAdapter.createRemoteAnimationApp();
- if (target != null) {
- appAnimations.add(target);
- } else {
- removeAnimation(taskAdapter);
- }
- }
+ // Create the app targets
+ final RemoteAnimationTarget[] appTargets = createAppAnimations();
// Skip the animation if there is nothing to animate
- if (appAnimations.isEmpty()) {
+ if (appTargets.length == 0) {
cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "startAnimation-noAppWindows");
return;
}
- final RemoteAnimationTarget[] appTargets = appAnimations.toArray(
- new RemoteAnimationTarget[appAnimations.size()]);
+ // Create the wallpaper targets
+ final RemoteAnimationTarget[] wallpaperTargets = createWallpaperAnimations();
+
mPendingStart = false;
// Perform layout if it was scheduled before to make sure that we get correct content
@@ -479,7 +481,8 @@
mService.getStableInsets(mDisplayId, mTmpRect);
contentInsets = mTmpRect;
}
- mRunner.onAnimationStart(mController, appTargets, contentInsets, minimizedHomeBounds);
+ mRunner.onAnimationStart(mController, appTargets, wallpaperTargets, contentInsets,
+ minimizedHomeBounds);
if (DEBUG_RECENTS_ANIMATIONS) {
Slog.d(TAG, "startAnimation(): Notify animation start:");
for (int i = 0; i < mPendingAnimations.size(); i++) {
@@ -495,6 +498,32 @@
mService.mAtmInternal.notifyAppTransitionStarting(reasons, SystemClock.uptimeMillis());
}
+ private RemoteAnimationTarget[] createAppAnimations() {
+ final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>();
+ for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
+ final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i);
+ final RemoteAnimationTarget target = taskAdapter.createRemoteAnimationTarget();
+ if (target != null) {
+ targets.add(target);
+ } else {
+ removeAnimation(taskAdapter);
+ }
+ }
+ return targets.toArray(new RemoteAnimationTarget[targets.size()]);
+ }
+
+ private RemoteAnimationTarget[] createWallpaperAnimations() {
+ if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "createWallpaperAnimations()");
+ return WallpaperAnimationAdapter.startWallpaperAnimations(mService, 0L, 0L,
+ adapter -> {
+ synchronized (mService.mGlobalLock) {
+ // If the wallpaper animation is canceled, continue with the recents
+ // animation
+ mPendingWallpaperAnimations.remove(adapter);
+ }
+ }, mPendingWallpaperAnimations);
+ }
+
void cancelAnimation(@ReorderMode int reorderMode, String reason) {
cancelAnimation(reorderMode, false /*screenshot */, reason);
}
@@ -619,6 +648,11 @@
removeAnimation(taskAdapter);
}
+ for (int i = mPendingWallpaperAnimations.size() - 1; i >= 0; i--) {
+ final WallpaperAnimationAdapter wallpaperAdapter = mPendingWallpaperAnimations.get(i);
+ removeWallpaperAnimation(wallpaperAdapter);
+ }
+
// Clear any pending failsafe runnables
mService.mH.removeCallbacks(mFailsafeRunnable);
mDisplayContent.mAppTransition.unregisterListener(mAppTransitionListener);
@@ -747,6 +781,15 @@
return false;
}
+ boolean isAnimatingWallpaper(WallpaperWindowToken token) {
+ for (int i = mPendingWallpaperAnimations.size() - 1; i >= 0; i--) {
+ if (token == mPendingWallpaperAnimations.get(i).getToken()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private boolean isAnimatingApp(AppWindowToken appToken) {
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
final Task task = mPendingAnimations.get(i).mTask;
@@ -784,7 +827,7 @@
mBounds.set(container.getDisplayedBounds());
}
- RemoteAnimationTarget createRemoteAnimationApp() {
+ RemoteAnimationTarget createRemoteAnimationTarget() {
final AppWindowToken topApp = mTask.getTopVisibleAppToken();
final WindowState mainWindow = topApp != null
? topApp.findMainWindow()
@@ -830,6 +873,7 @@
@Override
public void onAnimationCancelled(SurfaceControl animationLeash) {
+ // Cancel the animation immediately if any single task animator is canceled
cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "taskAnimationAdapterCanceled");
}
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index 7448e00..42430ba 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -58,6 +58,8 @@
private final WindowManagerService mService;
private final RemoteAnimationAdapter mRemoteAnimationAdapter;
private final ArrayList<RemoteAnimationRecord> mPendingAnimations = new ArrayList<>();
+ private final ArrayList<WallpaperAnimationAdapter> mPendingWallpaperAnimations =
+ new ArrayList<>();
private final Rect mTmpRect = new Rect();
private final Handler mHandler;
private final Runnable mTimeoutRunnable = () -> cancelAnimation("timeoutRunnable");
@@ -110,16 +112,21 @@
(long) (TIMEOUT_MS * mService.getCurrentAnimatorScale()));
mFinishedCallback = new FinishedCallback(this);
- final RemoteAnimationTarget[] animations = createAnimations();
- if (animations.length == 0) {
+ // Create the app targets
+ final RemoteAnimationTarget[] appTargets = createAppAnimations();
+ if (appTargets.length == 0) {
if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "goodToGo(): No apps to animate");
onAnimationFinished();
return;
}
+
+ // Create the remote wallpaper animation targets (if any)
+ final RemoteAnimationTarget[] wallpaperTargets = createWallpaperAnimations();
mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
try {
linkToDeathOfRunner();
- mRemoteAnimationAdapter.getRunner().onAnimationStart(animations, mFinishedCallback);
+ mRemoteAnimationAdapter.getRunner().onAnimationStart(appTargets, wallpaperTargets,
+ mFinishedCallback);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to start remote animation", e);
onAnimationFinished();
@@ -155,8 +162,8 @@
Slog.i(TAG, sw.toString());
}
- private RemoteAnimationTarget[] createAnimations() {
- if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "createAnimations()");
+ private RemoteAnimationTarget[] createAppAnimations() {
+ if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "createAppAnimations()");
final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>();
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
final RemoteAnimationRecord wrappers = mPendingAnimations.get(i);
@@ -186,6 +193,19 @@
return targets.toArray(new RemoteAnimationTarget[targets.size()]);
}
+ private RemoteAnimationTarget[] createWallpaperAnimations() {
+ if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "createWallpaperAnimations()");
+ return WallpaperAnimationAdapter.startWallpaperAnimations(mService,
+ mRemoteAnimationAdapter.getDuration(),
+ mRemoteAnimationAdapter.getStatusBarTransitionDelay(),
+ adapter -> {
+ synchronized (mService.mGlobalLock) {
+ // If the wallpaper animation is canceled, continue with the app animation
+ mPendingWallpaperAnimations.remove(adapter);
+ }
+ }, mPendingWallpaperAnimations);
+ }
+
private void onAnimationFinished() {
if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "onAnimationFinished(): mPendingAnimations="
+ mPendingAnimations.size());
@@ -207,7 +227,15 @@
adapters.mThumbnailAdapter.mCapturedFinishCallback
.onAnimationFinished(adapters.mThumbnailAdapter);
}
- if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "\t" + adapters.mAppWindowToken);
+ mPendingAnimations.remove(i);
+ if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "\tapp=" + adapters.mAppWindowToken);
+ }
+
+ for (int i = mPendingWallpaperAnimations.size() - 1; i >= 0; i--) {
+ final WallpaperAnimationAdapter adapter = mPendingWallpaperAnimations.get(i);
+ adapter.getLeashFinishedCallback().onAnimationFinished(adapter);
+ mPendingWallpaperAnimations.remove(i);
+ if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "\twallpaper=" + adapter.getToken());
}
} catch (Exception e) {
Slog.e(TAG, "Failed to finish remote animation", e);
@@ -424,10 +452,7 @@
mPendingAnimations.remove(mRecord);
}
if (mPendingAnimations.isEmpty()) {
- mHandler.removeCallbacks(mTimeoutRunnable);
- releaseFinishedCallback();
- invokeAnimationCancelled();
- setRunningRemoteAnimation(false);
+ cancelAnimation("allAppAnimationsCanceled");
}
}
diff --git a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
new file mode 100644
index 0000000..895350b
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.wm;
+
+import static com.android.server.wm.AnimationAdapterProto.REMOTE;
+import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_REMOTE_ANIMATIONS;
+
+import android.graphics.Point;
+import android.os.SystemClock;
+import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
+import android.view.RemoteAnimationTarget;
+import android.view.SurfaceControl;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.function.Consumer;
+
+/**
+ * An animation adapter for wallpaper windows.
+ */
+class WallpaperAnimationAdapter implements AnimationAdapter {
+ private static final String TAG = "WallpaperAnimationAdapter";
+
+ private final WallpaperWindowToken mWallpaperToken;
+ private SurfaceControl mCapturedLeash;
+ private SurfaceAnimator.OnAnimationFinishedCallback mCapturedLeashFinishCallback;
+
+ private long mDurationHint;
+ private long mStatusBarTransitionDelay;
+
+ private Consumer<WallpaperAnimationAdapter> mAnimationCanceledRunnable;
+ private RemoteAnimationTarget mTarget;
+
+ WallpaperAnimationAdapter(WallpaperWindowToken wallpaperToken,
+ long durationHint, long statusBarTransitionDelay,
+ Consumer<WallpaperAnimationAdapter> animationCanceledRunnable) {
+ mWallpaperToken = wallpaperToken;
+ mDurationHint = durationHint;
+ mStatusBarTransitionDelay = statusBarTransitionDelay;
+ mAnimationCanceledRunnable = animationCanceledRunnable;
+ }
+
+ /**
+ * Creates and starts remote animations for all the visible wallpaper windows.
+ *
+ * @return RemoteAnimationTarget[] targets for all the visible wallpaper windows
+ */
+ public static RemoteAnimationTarget[] startWallpaperAnimations(WindowManagerService service,
+ long durationHint, long statusBarTransitionDelay,
+ Consumer<WallpaperAnimationAdapter> animationCanceledRunnable,
+ ArrayList<WallpaperAnimationAdapter> adaptersOut) {
+ final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>();
+ service.mRoot.forAllWallpaperWindows(wallpaperWindow -> {
+ if (!wallpaperWindow.getDisplayContent().mWallpaperController.isWallpaperVisible()) {
+ if (DEBUG_REMOTE_ANIMATIONS || DEBUG_RECENTS_ANIMATIONS) {
+ Slog.d(TAG, "\tNot visible=" + wallpaperWindow);
+ }
+ return;
+ }
+
+ if (DEBUG_REMOTE_ANIMATIONS || DEBUG_RECENTS_ANIMATIONS) {
+ Slog.d(TAG, "\tvisible=" + wallpaperWindow);
+ }
+ final WallpaperAnimationAdapter wallpaperAdapter = new WallpaperAnimationAdapter(
+ wallpaperWindow, durationHint, statusBarTransitionDelay,
+ animationCanceledRunnable);
+ wallpaperWindow.startAnimation(wallpaperWindow.getPendingTransaction(),
+ wallpaperAdapter, false /* hidden */);
+ targets.add(wallpaperAdapter.createRemoteAnimationTarget());
+ adaptersOut.add(wallpaperAdapter);
+ });
+ return targets.toArray(new RemoteAnimationTarget[targets.size()]);
+ }
+
+ /**
+ * Create a remote animation target for this animation adapter.
+ */
+ RemoteAnimationTarget createRemoteAnimationTarget() {
+ mTarget = new RemoteAnimationTarget(-1, -1, getLeash(), false, null, null,
+ mWallpaperToken.getPrefixOrderIndex(), new Point(), null,
+ mWallpaperToken.getWindowConfiguration(), true, null, null);
+ return mTarget;
+ }
+
+ /**
+ * @return the leash for this animation (only valid after the wallpaper window surface animation
+ * has started).
+ */
+ SurfaceControl getLeash() {
+ return mCapturedLeash;
+ }
+
+ /**
+ * @return the callback to call to clean up when the animation has finished.
+ */
+ SurfaceAnimator.OnAnimationFinishedCallback getLeashFinishedCallback() {
+ return mCapturedLeashFinishCallback;
+ }
+
+ /**
+ * @return the wallpaper window
+ */
+ WallpaperWindowToken getToken() {
+ return mWallpaperToken;
+ }
+
+ @Override
+ public boolean getShowWallpaper() {
+ // Not used
+ return false;
+ }
+
+ @Override
+ public void startAnimation(SurfaceControl animationLeash, SurfaceControl.Transaction t,
+ SurfaceAnimator.OnAnimationFinishedCallback finishCallback) {
+ if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "startAnimation");
+
+ // Restore z-layering until client has a chance to modify it.
+ t.setLayer(animationLeash, mWallpaperToken.getPrefixOrderIndex());
+ mCapturedLeash = animationLeash;
+ mCapturedLeashFinishCallback = finishCallback;
+ }
+
+ @Override
+ public void onAnimationCancelled(SurfaceControl animationLeash) {
+ if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "onAnimationCancelled");
+ mAnimationCanceledRunnable.accept(this);
+ }
+
+ @Override
+ public long getDurationHint() {
+ return mDurationHint;
+ }
+
+ @Override
+ public long getStatusBarTransitionsStartTime() {
+ return SystemClock.uptimeMillis() + mStatusBarTransitionDelay;
+ }
+
+ @Override
+ public void dump(PrintWriter pw, String prefix) {
+ pw.print(prefix);
+ pw.print("token=");
+ pw.println(mWallpaperToken);
+ if (mTarget != null) {
+ pw.print(prefix);
+ pw.println("Target:");
+ mTarget.dump(pw, prefix + " ");
+ } else {
+ pw.print(prefix);
+ pw.println("Target: null");
+ }
+ }
+
+ @Override
+ public void writeToProto(ProtoOutputStream proto) {
+ final long token = proto.start(REMOTE);
+ if (mTarget != null) {
+ mTarget.writeToProto(proto, TARGET);
+ }
+ proto.end(token);
+ }
+}
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index e15b783..528cece 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -29,6 +30,8 @@
import android.view.DisplayInfo;
import android.view.animation.Animation;
+import java.util.function.Consumer;
+
/**
* A token that represents a set of wallpaper windows.
*/
@@ -153,6 +156,11 @@
}
@Override
+ void forAllWallpaperWindows(Consumer<WallpaperWindowToken> callback) {
+ callback.accept(this);
+ }
+
+ @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 e280a663..586375f 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -895,6 +895,12 @@
}
}
+ void forAllWallpaperWindows(Consumer<WallpaperWindowToken> callback) {
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ mChildren.get(i).forAllWallpaperWindows(callback);
+ }
+ }
+
/**
* For all tasks at or below this container call the callback.
*
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 8444ab2..30c8eb3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -658,6 +658,7 @@
@Override
public void onAnimationStart(RemoteAnimationTarget[] apps,
+ RemoteAnimationTarget[] wallpapers,
IRemoteAnimationFinishedCallback finishedCallback) {
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
index 035568f..629a954 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
@@ -75,6 +75,7 @@
class TestRemoteAnimationRunner implements IRemoteAnimationRunner {
@Override
public void onAnimationStart(RemoteAnimationTarget[] apps,
+ RemoteAnimationTarget[] wallpapers,
IRemoteAnimationFinishedCallback finishedCallback) {
for (RemoteAnimationTarget target : apps) {
assertNotNull(target.startBounds);
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index c162b6a..45e6890 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -248,6 +248,7 @@
boolean mCancelled = false;
@Override
public void onAnimationStart(RemoteAnimationTarget[] apps,
+ RemoteAnimationTarget[] wallpapers,
IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException {
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 9ca0180..f792b0d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -26,13 +26,17 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMoreInteractions;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
+import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_TOP;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -44,9 +48,12 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import android.app.ActivityManager.TaskSnapshot;
import android.os.Binder;
+import android.os.IBinder;
import android.os.IInterface;
import android.platform.test.annotations.Presubmit;
import android.util.SparseBooleanArray;
@@ -88,8 +95,8 @@
doReturn(mDisplayContent).when(mWm.mRoot).getDisplayContent(anyInt());
}
when(mMockRunner.asBinder()).thenReturn(new Binder());
- mController = new RecentsAnimationController(mWm, mMockRunner, mAnimationCallbacks,
- DEFAULT_DISPLAY);
+ mController = spy(new RecentsAnimationController(mWm, mMockRunner, mAnimationCallbacks,
+ DEFAULT_DISPLAY));
}
@Test
@@ -133,11 +140,11 @@
@Test
public void testIncludedApps_expectTargetAndVisible() {
mWm.setRecentsAnimationController(mController);
- final ActivityStack homStack = mDisplayContent.mAcitvityDisplay.getOrCreateStack(
+ final ActivityStack homeStack = mDisplayContent.mAcitvityDisplay.getOrCreateStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
final AppWindowToken homeAppWindow =
new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
- .setStack(homStack)
+ .setStack(homeStack)
.setCreateTask(true)
.build()
.mAppWindowToken;
@@ -157,6 +164,102 @@
}
@Test
+ public void testWallpaperIncluded_expectTarget() throws Exception {
+ mWm.setRecentsAnimationController(mController);
+ final ActivityStack homeStack = mDisplayContent.mAcitvityDisplay.getOrCreateStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
+ final AppWindowToken homeAppWindow =
+ new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
+ .setStack(homeStack)
+ .setCreateTask(true)
+ .build()
+ .mAppWindowToken;
+ final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, appWindow, "win1");
+ appWindow.addWindow(win1);
+ final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm,
+ mock(IBinder.class), true, mDisplayContent, true /* ownerCanManageAppTokens */);
+ spyOn(mDisplayContent.mWallpaperController);
+ doReturn(true).when(mDisplayContent.mWallpaperController).isWallpaperVisible();
+
+ mDisplayContent.getConfiguration().windowConfiguration.setRotation(
+ mDisplayContent.getRotation());
+ mController.initialize(ACTIVITY_TYPE_HOME, new SparseBooleanArray());
+ mController.startAnimation();
+
+ // Ensure that we are animating the app and wallpaper target
+ assertTrue(mController.isAnimatingTask(appWindow.getTask()));
+ assertTrue(mController.isAnimatingWallpaper(wallpaperWindowToken));
+ }
+
+ @Test
+ public void testWallpaperAnimatorCanceled_expectAnimationKeepsRunning() throws Exception {
+ mWm.setRecentsAnimationController(mController);
+ final ActivityStack homeStack = mDisplayContent.mAcitvityDisplay.getOrCreateStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
+ final AppWindowToken homeAppWindow =
+ new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
+ .setStack(homeStack)
+ .setCreateTask(true)
+ .build()
+ .mAppWindowToken;
+ final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, appWindow, "win1");
+ appWindow.addWindow(win1);
+ final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm,
+ mock(IBinder.class), true, mDisplayContent, true /* ownerCanManageAppTokens */);
+ spyOn(mDisplayContent.mWallpaperController);
+ doReturn(true).when(mDisplayContent.mWallpaperController).isWallpaperVisible();
+
+ mDisplayContent.getConfiguration().windowConfiguration.setRotation(
+ mDisplayContent.getRotation());
+ mController.initialize(ACTIVITY_TYPE_HOME, new SparseBooleanArray());
+ mController.startAnimation();
+
+ // Cancel the animation and ensure the controller is still running
+ wallpaperWindowToken.cancelAnimation();
+ assertTrue(mController.isAnimatingTask(appWindow.getTask()));
+ assertFalse(mController.isAnimatingWallpaper(wallpaperWindowToken));
+ verify(mMockRunner, never()).onAnimationCanceled(null /* taskSnapshot */);
+ }
+
+ @Test
+ public void testFinish_expectTargetAndWallpaperAdaptersRemoved() {
+ mWm.setRecentsAnimationController(mController);
+ final ActivityStack homeStack = mDisplayContent.mAcitvityDisplay.getOrCreateStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
+ final AppWindowToken homeAppWindow =
+ new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
+ .setStack(homeStack)
+ .setCreateTask(true)
+ .build()
+ .mAppWindowToken;
+ final WindowState hwin1 = createWindow(null, TYPE_BASE_APPLICATION, homeAppWindow, "hwin1");
+ homeAppWindow.addWindow(hwin1);
+ final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, appWindow, "win1");
+ appWindow.addWindow(win1);
+ final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm,
+ mock(IBinder.class), true, mDisplayContent, true /* ownerCanManageAppTokens */);
+ spyOn(mDisplayContent.mWallpaperController);
+ doReturn(true).when(mDisplayContent.mWallpaperController).isWallpaperVisible();
+
+ // Start and finish the animation
+ mController.initialize(ACTIVITY_TYPE_HOME, new SparseBooleanArray());
+ mController.startAnimation();
+ // Reset at this point since we may remove adapters that couldn't be created
+ reset(mController);
+ mController.cleanupAnimation(REORDER_MOVE_TO_TOP);
+
+ // Ensure that we remove the task (home & app) and wallpaper adapters
+ verify(mController, times(2)).removeAnimation(any());
+ verify(mController, times(1)).removeWallpaperAnimation(any());
+ }
+
+ @Test
public void testDeferCancelAnimation() throws Exception {
mWm.setRecentsAnimationController(mController);
final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index 3e05dcc..3b9c3bb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -19,7 +19,9 @@
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMoreInteractions;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
@@ -27,10 +29,12 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Binder;
+import android.os.IBinder;
import android.os.IInterface;
import android.platform.test.annotations.Presubmit;
import android.view.IRemoteAnimationFinishedCallback;
@@ -96,9 +100,12 @@
mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+ final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
+ ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
- verify(mMockRunner).onAnimationStart(appsCaptor.capture(), finishedCaptor.capture());
+ verify(mMockRunner).onAnimationStart(appsCaptor.capture(), wallpapersCaptor.capture(),
+ finishedCaptor.capture());
assertEquals(1, appsCaptor.getValue().length);
final RemoteAnimationTarget app = appsCaptor.getValue()[0];
assertEquals(new Point(50, 100), app.position);
@@ -201,9 +208,12 @@
mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+ final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
+ ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
- verify(mMockRunner).onAnimationStart(appsCaptor.capture(), finishedCaptor.capture());
+ verify(mMockRunner).onAnimationStart(appsCaptor.capture(), wallpapersCaptor.capture(),
+ finishedCaptor.capture());
assertEquals(1, appsCaptor.getValue().length);
assertEquals(mMockLeash, appsCaptor.getValue()[0].leash);
}
@@ -237,9 +247,12 @@
mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+ final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
+ ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
- verify(mMockRunner).onAnimationStart(appsCaptor.capture(), finishedCaptor.capture());
+ verify(mMockRunner).onAnimationStart(appsCaptor.capture(), wallpapersCaptor.capture(),
+ finishedCaptor.capture());
assertEquals(1, appsCaptor.getValue().length);
final RemoteAnimationTarget app = appsCaptor.getValue()[0];
assertEquals(RemoteAnimationTarget.MODE_CHANGING, app.mode);
@@ -264,6 +277,66 @@
}
}
+ @Test
+ public void testWallpaperIncluded_expectTarget() throws Exception {
+ final WindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm, mock(IBinder.class),
+ true, mDisplayContent, true /* ownerCanManageAppTokens */);
+ spyOn(mDisplayContent.mWallpaperController);
+ doReturn(true).when(mDisplayContent.mWallpaperController).isWallpaperVisible();
+ final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
+ mDisplayContent.mOpeningApps.add(win.mAppToken);
+ try {
+ final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mAppToken,
+ new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
+ adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
+ mController.goodToGo();
+ mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
+ ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+ final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
+ ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+ final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
+ ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
+ verify(mMockRunner).onAnimationStart(appsCaptor.capture(), wallpapersCaptor.capture(),
+ finishedCaptor.capture());
+ assertEquals(1, wallpapersCaptor.getValue().length);
+ } finally {
+ mDisplayContent.mOpeningApps.clear();
+ }
+ }
+
+ @Test
+ public void testWallpaperAnimatorCanceled_expectAnimationKeepsRunning() throws Exception {
+ final WindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm, mock(IBinder.class),
+ true, mDisplayContent, true /* ownerCanManageAppTokens */);
+ spyOn(mDisplayContent.mWallpaperController);
+ doReturn(true).when(mDisplayContent.mWallpaperController).isWallpaperVisible();
+ final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
+ mDisplayContent.mOpeningApps.add(win.mAppToken);
+ try {
+ final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mAppToken,
+ new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
+ adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
+ mController.goodToGo();
+ mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
+ ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+ final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
+ ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+ final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
+ ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
+ verify(mMockRunner).onAnimationStart(appsCaptor.capture(), wallpapersCaptor.capture(),
+ finishedCaptor.capture());
+ assertEquals(1, wallpapersCaptor.getValue().length);
+
+ // Cancel the wallpaper window animator and ensure the runner is not canceled
+ wallpaperWindowToken.cancelAnimation();
+ verify(mMockRunner, never()).onAnimationCancelled();
+ } finally {
+ mDisplayContent.mOpeningApps.clear();
+ }
+ }
+
private static void verifyNoMoreInteractionsExceptAsBinder(IInterface binder) {
verify(binder, atLeast(0)).asBinder();
verifyNoMoreInteractions(binder);