Merge "Intruduce Cross Activity Animator"

This commit is contained in:
Arthur Hung
2022-11-30 10:29:22 +00:00
committed by Android (Google) Code Review
8 changed files with 576 additions and 92 deletions

View File

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

View File

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

View File

@@ -138,14 +138,18 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
}
};
private final BackAnimationBackground mAnimationBackground;
public BackAnimationController(
@NonNull ShellInit shellInit,
@NonNull ShellController shellController,
@NonNull @ShellMainThread ShellExecutor shellExecutor,
@NonNull @ShellBackgroundThread Handler backgroundHandler,
Context context) {
Context context,
@NonNull BackAnimationBackground backAnimationBackground) {
this(shellInit, shellController, shellExecutor, backgroundHandler,
ActivityTaskManager.getService(), context, context.getContentResolver());
ActivityTaskManager.getService(), context, context.getContentResolver(),
backAnimationBackground);
}
@VisibleForTesting
@@ -155,7 +159,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
@NonNull @ShellMainThread ShellExecutor shellExecutor,
@NonNull @ShellBackgroundThread Handler bgHandler,
@NonNull IActivityTaskManager activityTaskManager,
Context context, ContentResolver contentResolver) {
Context context, ContentResolver contentResolver,
@NonNull BackAnimationBackground backAnimationBackground) {
mShellController = shellController;
mShellExecutor = shellExecutor;
mActivityTaskManager = activityTaskManager;
@@ -163,6 +168,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
mContentResolver = contentResolver;
mBgHandler = bgHandler;
shellInit.addInitCallback(this::onInit, this);
mAnimationBackground = backAnimationBackground;
}
@VisibleForTesting
@@ -184,10 +190,14 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
return;
}
final CrossTaskBackAnimation crossTaskAnimation = new CrossTaskBackAnimation(mContext);
final CrossTaskBackAnimation crossTaskAnimation =
new CrossTaskBackAnimation(mContext, mAnimationBackground);
mAnimationDefinition.set(BackNavigationInfo.TYPE_CROSS_TASK,
new BackAnimationRunner(crossTaskAnimation.mCallback, crossTaskAnimation.mRunner));
// TODO (238474994): register cross activity animation when it's completed.
crossTaskAnimation.mBackAnimationRunner);
final CrossActivityAnimation crossActivityAnimation =
new CrossActivityAnimation(mContext, mAnimationBackground);
mAnimationDefinition.set(BackNavigationInfo.TYPE_CROSS_ACTIVITY,
crossActivityAnimation.mBackAnimationRunner);
// TODO (236760237): register dialog close animation when it's completed.
}
@@ -275,7 +285,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
@Override
public void clearBackToLauncherCallback() {
executeRemoteCallWithTaskPermission(mController, "clearBackToLauncherCallback",
(controller) -> controller.clearBackToLauncherCallback());
(controller) -> controller.unregisterAnimation(
BackNavigationInfo.TYPE_RETURN_TO_HOME));
}
@Override
@@ -289,8 +300,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
mAnimationDefinition.set(type, runner);
}
private void clearBackToLauncherCallback() {
mAnimationDefinition.remove(BackNavigationInfo.TYPE_RETURN_TO_HOME);
void unregisterAnimation(@BackNavigationInfo.BackTargetType int type) {
mAnimationDefinition.remove(type);
}
/**

View File

@@ -0,0 +1,373 @@
/*
* 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.RemoteAnimationTarget.MODE_CLOSING;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.RemoteException;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IRemoteAnimationRunner;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.window.BackEvent;
import android.window.BackProgressAnimator;
import android.window.IOnBackInvokedCallback;
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.common.annotations.ShellMainThread;
/** Class that defines cross-activity animation. */
@ShellMainThread
class CrossActivityAnimation {
/**
* Minimum scale of the entering/closing window.
*/
private static final float MIN_WINDOW_SCALE = 0.9f;
/**
* Minimum alpha of the closing/entering window.
*/
private static final float CLOSING_MIN_WINDOW_ALPHA = 0.5f;
/**
* Progress value to fly out closing window and fly in entering window.
*/
private static final float SWITCH_ENTERING_WINDOW_PROGRESS = 0.5f;
/** Max window translation in the Y axis. */
private static final int WINDOW_MAX_DELTA_Y = 160;
/** Duration of fade in/out entering window. */
private static final int FADE_IN_DURATION = 100;
/** Duration of post animation after gesture committed. */
private static final int POST_ANIMATION_DURATION = 350;
private static final Interpolator INTERPOLATOR = Interpolators.EMPHASIZED;
private final Rect mStartTaskRect = new Rect();
private final float mCornerRadius;
// The closing window properties.
private final RectF mClosingRect = new RectF();
// The entering window properties.
private final Rect mEnteringStartRect = new Rect();
private final RectF mEnteringRect = new RectF();
private float mCurrentAlpha = 1.0f;
private float mEnteringMargin = 0;
private ValueAnimator mEnteringAnimator;
private boolean mEnteringWindowShow = false;
private final PointF mInitialTouchPos = new PointF();
private final Matrix mTransformMatrix = new Matrix();
private final float[] mTmpFloat9 = new float[9];
private RemoteAnimationTarget mEnteringTarget;
private RemoteAnimationTarget mClosingTarget;
private SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
private boolean mBackInProgress = false;
private PointF mTouchPos = new PointF();
private IRemoteAnimationFinishedCallback mFinishCallback;
private final BackProgressAnimator mProgressAnimator = new BackProgressAnimator();
final BackAnimationRunner mBackAnimationRunner;
private final BackAnimationBackground mBackground;
CrossActivityAnimation(Context context, BackAnimationBackground background) {
mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context);
mBackAnimationRunner = new BackAnimationRunner(new Callback(), new Runner());
mBackground = background;
}
private static float mapRange(float value, float min, float max) {
return min + (value * (max - min));
}
private float getInterpolatedProgress(float backProgress) {
return INTERPOLATOR.getInterpolation(backProgress);
}
private void startBackAnimation() {
if (mEnteringTarget == null || mClosingTarget == null) {
ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Entering target or closing target is null.");
return;
}
mTransaction.setAnimationTransaction();
// Offset start rectangle to align task bounds.
mStartTaskRect.set(mClosingTarget.windowConfiguration.getBounds());
mStartTaskRect.offsetTo(0, 0);
// Draw background with task background color.
mBackground.ensureBackground(
mEnteringTarget.taskInfo.taskDescription.getBackgroundColor(), mTransaction);
}
private void applyTransform(SurfaceControl leash, RectF targetRect, float targetAlpha) {
final float scale = targetRect.width() / mStartTaskRect.width();
mTransformMatrix.reset();
mTransformMatrix.setScale(scale, scale);
mTransformMatrix.postTranslate(targetRect.left, targetRect.top);
mTransaction.setAlpha(leash, targetAlpha)
.setMatrix(leash, mTransformMatrix, mTmpFloat9)
.setWindowCrop(leash, mStartTaskRect)
.setCornerRadius(leash, mCornerRadius);
}
private void finishAnimation() {
if (mEnteringTarget != null) {
mEnteringTarget.leash.release();
mEnteringTarget = null;
}
if (mClosingTarget != null) {
mClosingTarget.leash.release();
mClosingTarget = null;
}
if (mBackground != null) {
mBackground.removeBackground(mTransaction);
}
mTransaction.apply();
mBackInProgress = false;
mTransformMatrix.reset();
mInitialTouchPos.set(0, 0);
mEnteringWindowShow = false;
mEnteringMargin = 0;
if (mFinishCallback != null) {
try {
mFinishCallback.onAnimationFinished();
} catch (RemoteException e) {
e.printStackTrace();
}
mFinishCallback = null;
}
}
private void onGestureProgress(@NonNull BackEvent backEvent) {
if (!mBackInProgress) {
mInitialTouchPos.set(backEvent.getTouchX(), backEvent.getTouchY());
mBackInProgress = true;
}
mTouchPos.set(backEvent.getTouchX(), backEvent.getTouchY());
if (mEnteringTarget == null || mClosingTarget == null) {
return;
}
final float progress = getInterpolatedProgress(backEvent.getProgress());
final float touchY = mTouchPos.y;
final int width = mStartTaskRect.width();
final int height = mStartTaskRect.height();
final float closingScale = mapRange(progress, 1, MIN_WINDOW_SCALE);
final float closingWidth = closingScale * width;
final float closingHeight = (float) height / width * closingWidth;
// Move the window along the X axis.
final float closingLeft = mStartTaskRect.left + (width - closingWidth) / 2;
// Move the window along the Y axis.
final float deltaYRatio = (touchY - mInitialTouchPos.y) / height;
final float deltaY = (float) Math.sin(deltaYRatio * Math.PI * 0.5f) * WINDOW_MAX_DELTA_Y;
final float closingTop = (height - closingHeight) * 0.5f + deltaY;
mClosingRect.set(
closingLeft, closingTop, closingLeft + closingWidth, closingTop + closingHeight);
mEnteringRect.set(mClosingRect);
// Switch closing/entering targets while reach to the threshold progress.
if (showEnteringWindow(progress > 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();
}
}
}

View File

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

View File

@@ -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<BackAnimationController> 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)
//

View File

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

View File

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