From 3a55579cf2ddea6877a52b9f5d8127baa008ca00 Mon Sep 17 00:00:00 2001 From: Arthur Hung Date: Mon, 14 Nov 2022 03:55:51 +0000 Subject: [PATCH] Intruduce Cross Activity Animator Add a new animator to support `TYPE_CROSS_ACTIVITY` when starting a back navigation and it will return to another activity. This also introduces the background controller that could show the animation background surface attached to the display area. Bug: 236759828 Bug: 238474994 Test: atest BackAnimationControllerTest BackNavigationControllerTests Change-Id: I6574b6ce969cb905ba8b4a797560216aed2ee3cb --- .../wm/shell/animation/Interpolators.java | 16 + .../shell/back/BackAnimationBackground.java | 69 ++++ .../shell/back/BackAnimationController.java | 29 +- .../wm/shell/back/CrossActivityAnimation.java | 373 ++++++++++++++++++ .../wm/shell/back/CrossTaskBackAnimation.java | 114 +++--- .../wm/shell/dagger/WMShellBaseModule.java | 18 +- .../back/BackAnimationControllerTest.java | 15 +- .../server/wm/BackNavigationController.java | 34 +- 8 files changed, 576 insertions(+), 92 deletions(-) create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationBackground.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityAnimation.java diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java index a0dde6ad168d0..2ec9e8b12fc6d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java @@ -16,6 +16,7 @@ package com.android.wm.shell.animation; +import android.graphics.Path; import android.view.animation.Interpolator; import android.view.animation.LinearInterpolator; import android.view.animation.PathInterpolator; @@ -52,6 +53,11 @@ public class Interpolators { */ public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f); + /** + * The default emphasized interpolator. Used for hero / emphasized movement of content. + */ + public static final Interpolator EMPHASIZED = createEmphasizedInterpolator(); + /** * The accelerated emphasized interpolator. Used for hero / emphasized movement of content that * is disappearing e.g. when moving off screen. @@ -81,4 +87,14 @@ public class Interpolators { public static final PathInterpolator DIM_INTERPOLATOR = new PathInterpolator(.23f, .87f, .52f, -0.11f); + + // Create the default emphasized interpolator + private static PathInterpolator createEmphasizedInterpolator() { + Path path = new Path(); + // Doing the same as fast_out_extra_slow_in + path.moveTo(0f, 0f); + path.cubicTo(0.05f, 0f, 0.133333f, 0.06f, 0.166666f, 0.4f); + path.cubicTo(0.208333f, 0.82f, 0.25f, 1f, 1f, 1f); + return new PathInterpolator(path); + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationBackground.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationBackground.java new file mode 100644 index 0000000000000..36cf29a4c4f3d --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationBackground.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2022 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.wm.shell.back; + +import static android.view.Display.DEFAULT_DISPLAY; + +import android.annotation.NonNull; +import android.graphics.Color; +import android.view.SurfaceControl; + +import com.android.wm.shell.RootTaskDisplayAreaOrganizer; + +/** + * Controls background surface for the back animations + */ +public class BackAnimationBackground { + private static final int BACKGROUND_LAYER = -1; + private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer; + private SurfaceControl mBackgroundSurface; + + public BackAnimationBackground(RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) { + mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer; + } + + void ensureBackground(int color, @NonNull SurfaceControl.Transaction transaction) { + if (mBackgroundSurface != null) { + return; + } + + final float[] colorComponents = new float[] { Color.red(color) / 255.f, + Color.green(color) / 255.f, Color.blue(color) / 255.f }; + + final SurfaceControl.Builder colorLayerBuilder = new SurfaceControl.Builder() + .setName("back-animation-background") + .setCallsite("BackAnimationBackground") + .setColorLayer(); + + mRootTaskDisplayAreaOrganizer.attachToDisplayArea(DEFAULT_DISPLAY, colorLayerBuilder); + mBackgroundSurface = colorLayerBuilder.build(); + transaction.setColor(mBackgroundSurface, colorComponents) + .setLayer(mBackgroundSurface, BACKGROUND_LAYER) + .show(mBackgroundSurface); + } + + void removeBackground(@NonNull SurfaceControl.Transaction transaction) { + if (mBackgroundSurface == null) { + return; + } + + if (mBackgroundSurface.isValid()) { + transaction.remove(mBackgroundSurface); + } + mBackgroundSurface = null; + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java index f811940fd3040..0133f6b44d2bf 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java @@ -138,14 +138,18 @@ public class BackAnimationController implements RemoteCallable controller.clearBackToLauncherCallback()); + (controller) -> controller.unregisterAnimation( + BackNavigationInfo.TYPE_RETURN_TO_HOME)); } @Override @@ -289,8 +300,8 @@ public class BackAnimationController implements RemoteCallable SWITCH_ENTERING_WINDOW_PROGRESS)) { + return; + } + + // Present windows and update the alpha. + mCurrentAlpha = Math.max(mapRange(progress, 1.0f, 0), CLOSING_MIN_WINDOW_ALPHA); + mClosingRect.offset(mEnteringMargin, 0); + mEnteringRect.offset(mEnteringMargin - width, 0); + + applyTransform( + mClosingTarget.leash, mClosingRect, mEnteringWindowShow ? 0.01f : mCurrentAlpha); + applyTransform( + mEnteringTarget.leash, mEnteringRect, mEnteringWindowShow ? mCurrentAlpha : 0.01f); + mTransaction.apply(); + } + + private boolean showEnteringWindow(boolean show) { + if (mEnteringAnimator == null) { + mEnteringAnimator = ValueAnimator.ofFloat(1f, 0f).setDuration(FADE_IN_DURATION); + mEnteringAnimator.setInterpolator(new AccelerateInterpolator()); + mEnteringAnimator.addUpdateListener(animation -> { + float progress = animation.getAnimatedFraction(); + final int width = mStartTaskRect.width(); + mEnteringMargin = width * progress; + // We don't animate to 0 or the surface would become invisible and lose focus. + final float alpha = progress >= 0.5f ? 0.01f + : mapRange(progress * 2, mCurrentAlpha, 0.01f); + mClosingRect.offset(mEnteringMargin, 0); + mEnteringRect.offset(mEnteringMargin - width, 0); + + applyTransform(mClosingTarget.leash, mClosingRect, alpha); + applyTransform(mEnteringTarget.leash, mEnteringRect, mCurrentAlpha); + mTransaction.apply(); + }); + } + + if (mEnteringAnimator.isRunning()) { + return true; + } + + if (mEnteringWindowShow == show) { + return false; + } + + mEnteringWindowShow = show; + if (show) { + mEnteringAnimator.start(); + } else { + mEnteringAnimator.reverse(); + } + return true; + } + + private void onGestureCommitted() { + if (mEnteringTarget == null || mClosingTarget == null) { + finishAnimation(); + return; + } + + // End the fade in animation. + if (mEnteringAnimator.isRunning()) { + mEnteringAnimator.cancel(); + } + + // We enter phase 2 of the animation, the starting coordinates for phase 2 are the current + // coordinate of the gesture driven phase. + mEnteringRect.round(mEnteringStartRect); + mTransaction.hide(mClosingTarget.leash); + + ValueAnimator valueAnimator = + ValueAnimator.ofFloat(1f, 0f).setDuration(POST_ANIMATION_DURATION); + valueAnimator.setInterpolator(new DecelerateInterpolator()); + valueAnimator.addUpdateListener(animation -> { + float progress = animation.getAnimatedFraction(); + updatePostCommitEnteringAnimation(progress); + mTransaction.apply(); + }); + + valueAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + finishAnimation(); + } + }); + valueAnimator.start(); + } + + private void updatePostCommitEnteringAnimation(float progress) { + float left = mapRange(progress, mEnteringStartRect.left, mStartTaskRect.left); + float top = mapRange(progress, mEnteringStartRect.top, mStartTaskRect.top); + float width = mapRange(progress, mEnteringStartRect.width(), mStartTaskRect.width()); + float height = mapRange(progress, mEnteringStartRect.height(), mStartTaskRect.height()); + float alpha = mapRange(progress, mCurrentAlpha, 1.0f); + + mEnteringRect.set(left, top, left + width, top + height); + applyTransform(mEnteringTarget.leash, mEnteringRect, alpha); + } + + private final class Callback extends IOnBackInvokedCallback.Default { + @Override + public void onBackStarted(BackEvent backEvent) { + mProgressAnimator.onBackStarted(backEvent, + CrossActivityAnimation.this::onGestureProgress); + } + + @Override + public void onBackProgressed(@NonNull BackEvent backEvent) { + mProgressAnimator.onBackProgressed(backEvent); + } + + @Override + public void onBackCancelled() { + // End the fade in animation. + if (mEnteringAnimator.isRunning()) { + mEnteringAnimator.cancel(); + } + // TODO (b259608500): Let BackProgressAnimator could play cancel animation. + mProgressAnimator.reset(); + finishAnimation(); + } + + @Override + public void onBackInvoked() { + mProgressAnimator.reset(); + onGestureCommitted(); + } + } + + private final class Runner extends IRemoteAnimationRunner.Default { + @Override + public void onAnimationStart( + int transit, + RemoteAnimationTarget[] apps, + RemoteAnimationTarget[] wallpapers, + RemoteAnimationTarget[] nonApps, + IRemoteAnimationFinishedCallback finishedCallback) { + ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Start back to activity animation."); + for (RemoteAnimationTarget a : apps) { + if (a.mode == MODE_CLOSING) { + mClosingTarget = a; + } + if (a.mode == MODE_OPENING) { + mEnteringTarget = a; + } + } + + startBackAnimation(); + mFinishCallback = finishedCallback; + } + + @Override + public void onAnimationCancelled(boolean isKeyguardOccluded) { + finishAnimation(); + } + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java index 2074b6ab44f29..a9a7b7742d2f1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java @@ -61,7 +61,7 @@ import com.android.wm.shell.common.annotations.ShellMainThread; */ @ShellMainThread class CrossTaskBackAnimation { - private static final float[] BACKGROUNDCOLOR = {0.263f, 0.263f, 0.227f}; + private static final int BACKGROUNDCOLOR = 0x43433A; /** * Minimum scale of the entering window. @@ -106,7 +106,6 @@ class CrossTaskBackAnimation { private RemoteAnimationTarget mEnteringTarget; private RemoteAnimationTarget mClosingTarget; - private SurfaceControl mBackgroundSurface; private SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction(); private boolean mBackInProgress = false; @@ -115,56 +114,15 @@ class CrossTaskBackAnimation { private float mProgress = 0; private PointF mTouchPos = new PointF(); private IRemoteAnimationFinishedCallback mFinishCallback; - private BackProgressAnimator mProgressAnimator = new BackProgressAnimator(); + final BackAnimationRunner mBackAnimationRunner; - final IOnBackInvokedCallback mCallback = new IOnBackInvokedCallback.Default() { - @Override - public void onBackStarted(BackEvent backEvent) { - mProgressAnimator.onBackStarted(backEvent, - CrossTaskBackAnimation.this::onGestureProgress); - } + private final BackAnimationBackground mBackground; - @Override - public void onBackProgressed(@NonNull BackEvent backEvent) { - mProgressAnimator.onBackProgressed(backEvent); - } - - @Override - public void onBackCancelled() { - mProgressAnimator.reset(); - finishAnimation(); - } - - @Override - public void onBackInvoked() { - mProgressAnimator.reset(); - onGestureCommitted(); - } - }; - - final IRemoteAnimationRunner mRunner = new IRemoteAnimationRunner.Default() { - @Override - public void onAnimationStart(int transit, RemoteAnimationTarget[] apps, - RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, - IRemoteAnimationFinishedCallback finishedCallback) { - ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Start back to task animation."); - for (RemoteAnimationTarget a : apps) { - if (a.mode == MODE_CLOSING) { - mClosingTarget = a; - } - if (a.mode == MODE_OPENING) { - mEnteringTarget = a; - } - } - - startBackAnimation(); - mFinishCallback = finishedCallback; - } - }; - - CrossTaskBackAnimation(Context context) { + CrossTaskBackAnimation(Context context, BackAnimationBackground background) { mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context); + mBackAnimationRunner = new BackAnimationRunner(new Callback(), new Runner()); + mBackground = background; } private float getInterpolatedProgress(float backProgress) { @@ -182,14 +140,7 @@ class CrossTaskBackAnimation { mStartTaskRect.offsetTo(0, 0); // Draw background. - mBackgroundSurface = new SurfaceControl.Builder() - .setName("Background of Back Navigation") - .setColorLayer() - .setHidden(false) - .build(); - mTransaction.setColor(mBackgroundSurface, BACKGROUNDCOLOR) - .setLayer(mBackgroundSurface, -1); - mTransaction.apply(); + mBackground.ensureBackground(BACKGROUNDCOLOR, mTransaction); } private void updateGestureBackProgress(float progress, BackEvent event) { @@ -300,11 +251,11 @@ class CrossTaskBackAnimation { mClosingTarget = null; } - if (mBackgroundSurface != null) { - mBackgroundSurface.release(); - mBackgroundSurface = null; + if (mBackground != null) { + mBackground.removeBackground(mTransaction); } + mTransaction.apply(); mBackInProgress = false; mTransformMatrix.reset(); mClosingCurrentRect.setEmpty(); @@ -362,4 +313,49 @@ class CrossTaskBackAnimation { private static float mapRange(float value, float min, float max) { return min + (value * (max - min)); } + + private final class Callback extends IOnBackInvokedCallback.Default { + @Override + public void onBackStarted(BackEvent backEvent) { + mProgressAnimator.onBackStarted(backEvent, + CrossTaskBackAnimation.this::onGestureProgress); + } + + @Override + public void onBackProgressed(@NonNull BackEvent backEvent) { + mProgressAnimator.onBackProgressed(backEvent); + } + + @Override + public void onBackCancelled() { + mProgressAnimator.reset(); + finishAnimation(); + } + + @Override + public void onBackInvoked() { + mProgressAnimator.reset(); + onGestureCommitted(); + } + }; + + private final class Runner extends IRemoteAnimationRunner.Default { + @Override + public void onAnimationStart(int transit, RemoteAnimationTarget[] apps, + RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, + IRemoteAnimationFinishedCallback finishedCallback) { + ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Start back to task animation."); + for (RemoteAnimationTarget a : apps) { + if (a.mode == MODE_CLOSING) { + mClosingTarget = a; + } + if (a.mode == MODE_OPENING) { + mEnteringTarget = a; + } + } + + startBackAnimation(); + mFinishCallback = finishedCallback; + } + }; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java index 962be9da2111b..4ea8a5dbc5a99 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java @@ -38,6 +38,7 @@ import com.android.wm.shell.TaskViewTransitions; import com.android.wm.shell.WindowManagerShellWrapper; import com.android.wm.shell.activityembedding.ActivityEmbeddingController; import com.android.wm.shell.back.BackAnimation; +import com.android.wm.shell.back.BackAnimationBackground; import com.android.wm.shell.back.BackAnimationController; import com.android.wm.shell.bubbles.BubbleController; import com.android.wm.shell.bubbles.Bubbles; @@ -93,13 +94,13 @@ import com.android.wm.shell.unfold.UnfoldAnimationController; import com.android.wm.shell.unfold.UnfoldTransitionHandler; import com.android.wm.shell.windowdecor.WindowDecorViewModel; -import java.util.Optional; - import dagger.BindsOptionalOf; import dagger.Lazy; import dagger.Module; import dagger.Provides; +import java.util.Optional; + /** * Provides basic dependencies from {@link com.android.wm.shell}, these dependencies are only * accessible from components within the WM subcomponent (can be explicitly exposed to the @@ -253,6 +254,13 @@ public abstract class WMShellBaseModule { return backAnimationController.map(BackAnimationController::getBackAnimationImpl); } + @WMSingleton + @Provides + static BackAnimationBackground provideBackAnimationBackground( + RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) { + return new BackAnimationBackground(rootTaskDisplayAreaOrganizer); + } + @WMSingleton @Provides static Optional provideBackAnimationController( @@ -260,16 +268,18 @@ public abstract class WMShellBaseModule { ShellInit shellInit, ShellController shellController, @ShellMainThread ShellExecutor shellExecutor, - @ShellBackgroundThread Handler backgroundHandler + @ShellBackgroundThread Handler backgroundHandler, + BackAnimationBackground backAnimationBackground ) { if (BackAnimationController.IS_ENABLED) { return Optional.of( new BackAnimationController(shellInit, shellController, shellExecutor, - backgroundHandler, context)); + backgroundHandler, context, backAnimationBackground)); } return Optional.empty(); } + // // Bubbles (optional feature) // diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java index d75c36c99a4cd..bee9a90ec6b81 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java @@ -110,6 +110,9 @@ public class BackAnimationControllerTest extends ShellTestCase { @Mock private ShellController mShellController; + @Mock + private BackAnimationBackground mAnimationBackground; + private BackAnimationController mController; private TestableContentResolver mContentResolver; private TestableLooper mTestableLooper; @@ -127,7 +130,7 @@ public class BackAnimationControllerTest extends ShellTestCase { mController = new BackAnimationController(mShellInit, mShellController, mShellExecutor, new Handler(mTestableLooper.getLooper()), mActivityTaskManager, mContext, - mContentResolver); + mContentResolver, mAnimationBackground); mController.setEnableUAnimation(true); mShellInit.init(); mShellExecutor.flushAll(); @@ -239,7 +242,7 @@ public class BackAnimationControllerTest extends ShellTestCase { mController = new BackAnimationController(shellInit, mShellController, mShellExecutor, new Handler(mTestableLooper.getLooper()), mActivityTaskManager, mContext, - mContentResolver); + mContentResolver, mAnimationBackground); shellInit.init(); registerAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME); @@ -353,6 +356,10 @@ public class BackAnimationControllerTest extends ShellTestCase { BackNavigationInfo.TYPE_CROSS_ACTIVITY, BackNavigationInfo.TYPE_DIALOG_CLOSE}; + for (int type: testTypes) { + unregisterAnimation(type); + } + for (int type: testTypes) { final ResultListener result = new ResultListener(); createNavigationInfo(new BackNavigationInfo.Builder() @@ -431,6 +438,10 @@ public class BackAnimationControllerTest extends ShellTestCase { new BackAnimationRunner(mAnimatorCallback, mBackAnimationRunner)); } + private void unregisterAnimation(int type) { + mController.unregisterAnimation(type); + } + private static class ResultListener implements RemoteCallback.OnResultListener { boolean mBackNavigationDone = false; boolean mTriggerBack = false; diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java index 14d6d7bdfb7dd..798e73906761e 100644 --- a/services/core/java/com/android/server/wm/BackNavigationController.java +++ b/services/core/java/com/android/server/wm/BackNavigationController.java @@ -241,6 +241,7 @@ class BackNavigationController { // We have another Activity in the same currentTask to go to backType = BackNavigationInfo.TYPE_CROSS_ACTIVITY; removedWindowContainer = currentActivity; + prevTask = prevActivity.getTask(); } else if (currentTask.returnsToHomeRootTask()) { // Our Task should bring back to home removedWindowContainer = currentTask; @@ -608,26 +609,23 @@ class BackNavigationController { // reset leash after animation finished. leashes.add(screenshotSurface); } - } else if (prevTask != null) { - prevActivity = prevTask.getTopNonFinishingActivity(); - if (prevActivity != null) { - // Make previous task show from behind by marking its top activity as visible - // and launch-behind to bump its visibility for the duration of the back gesture. - setLaunchBehind(prevActivity); + } else if (prevTask != null && prevActivity != null) { + // Make previous task show from behind by marking its top activity as visible + // and launch-behind to bump its visibility for the duration of the back gesture. + setLaunchBehind(prevActivity); - final SurfaceControl leash = prevActivity.makeAnimationLeash() - .setName("BackPreview Leash for " + prevActivity) - .setHidden(false) - .build(); - prevActivity.reparentSurfaceControl(startedTransaction, leash); - behindAppTarget = createRemoteAnimationTargetLocked( - prevTask, leash, MODE_OPENING); + final SurfaceControl leash = prevActivity.makeAnimationLeash() + .setName("BackPreview Leash for " + prevActivity) + .setHidden(false) + .build(); + prevActivity.reparentSurfaceControl(startedTransaction, leash); + behindAppTarget = createRemoteAnimationTargetLocked( + prevTask, leash, MODE_OPENING); - // reset leash after animation finished. - leashes.add(leash); - prevActivity.reparentSurfaceControl(finishedTransaction, - prevActivity.getParentSurfaceControl()); - } + // reset leash after animation finished. + leashes.add(leash); + prevActivity.reparentSurfaceControl(finishedTransaction, + prevActivity.getParentSurfaceControl()); } if (mShowWallpaper) {