[RESTRICT AUTOMERGE]BackGestureAnimation: a lightweight recents

animation controller

Copy most of code from RecentsAnimationController to back gesture
animation controller(BackNaviAnimationController), the infrastructure
can be reused for either back-to-home/back-to-task/back-to-activity
animations if needed. Since the infrasturcture of legacy recents
animation controller should be stable already, we don't need to
worry about issues like leak leashes/flickers/fixed rotation.

BackAnimationAdaptor is a temporary class to help migrate to shell
transition, the target is to replace it by RemoteTransition.

Next step: Migrate to shell transition, decouple animation info from
BackNavigationInfo.
Test: manually play back to home animation to verify no flicker/black
background/leak surface. Also test that there can play back to home
animation even when quick swipe.
Test: atest BackNavigationTest
Test: atest BackNavigationControllerTests BackAnimationControllerTest
Bug: 237642535

Change-Id: I436a3dcf5011c56c08d131b40168f19128cc8723
This commit is contained in:
wilsonshih
2022-07-26 11:23:59 +08:00
committed by Arthur Hung
parent 3292a30a1c
commit c9c9a757a8
18 changed files with 993 additions and 122 deletions

View File

@@ -72,6 +72,7 @@ import android.view.IRemoteAnimationRunner;
import android.view.IWindowFocusObserver; import android.view.IWindowFocusObserver;
import android.view.RemoteAnimationDefinition; import android.view.RemoteAnimationDefinition;
import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationAdapter;
import android.window.BackAnimationAdaptor;
import android.window.IWindowOrganizerController; import android.window.IWindowOrganizerController;
import android.window.BackNavigationInfo; import android.window.BackNavigationInfo;
import android.window.SplashScreenView; import android.window.SplashScreenView;
@@ -356,5 +357,5 @@ interface IActivityTaskManager {
* @param focusObserver a remote callback to nofify shell when the focused window lost focus. * @param focusObserver a remote callback to nofify shell when the focused window lost focus.
*/ */
android.window.BackNavigationInfo startBackNavigation(in boolean requestAnimation, android.window.BackNavigationInfo startBackNavigation(in boolean requestAnimation,
in IWindowFocusObserver focusObserver); in IWindowFocusObserver focusObserver, in BackAnimationAdaptor adaptor);
} }

View File

@@ -0,0 +1,22 @@
/*
* 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 android.window;
/**
* @hide
*/
parcelable BackAnimationAdaptor;

View File

@@ -0,0 +1,72 @@
/*
* 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 android.window;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Object that describes how to run a remote back animation.
*
* @hide
*/
public class BackAnimationAdaptor implements Parcelable {
private final IBackAnimationRunner mRunner;
@BackNavigationInfo.BackTargetType
private final int mSupportType;
public BackAnimationAdaptor(IBackAnimationRunner runner, int supportType) {
mRunner = runner;
mSupportType = supportType;
}
public BackAnimationAdaptor(Parcel in) {
mRunner = IBackAnimationRunner.Stub.asInterface(in.readStrongBinder());
mSupportType = in.readInt();
}
public IBackAnimationRunner getRunner() {
return mRunner;
}
@BackNavigationInfo.BackTargetType public int getSupportType() {
return mSupportType;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeStrongInterface(mRunner);
dest.writeInt(mSupportType);
}
public static final @android.annotation.NonNull Creator<BackAnimationAdaptor> CREATOR =
new Creator<BackAnimationAdaptor>() {
public BackAnimationAdaptor createFromParcel(Parcel in) {
return new BackAnimationAdaptor(in);
}
public BackAnimationAdaptor[] newArray(int size) {
return new BackAnimationAdaptor[size];
}
};
}

View File

@@ -101,6 +101,8 @@ public final class BackNavigationInfo implements Parcelable {
@Nullable @Nullable
private final IOnBackInvokedCallback mOnBackInvokedCallback; private final IOnBackInvokedCallback mOnBackInvokedCallback;
private final boolean mIsPrepareRemoteAnimation;
/** /**
* Create a new {@link BackNavigationInfo} instance. * Create a new {@link BackNavigationInfo} instance.
* *
@@ -117,6 +119,9 @@ public final class BackNavigationInfo implements Parcelable {
* @param onBackNavigationDone The callback to be called once the client is done with the * @param onBackNavigationDone The callback to be called once the client is done with the
* back preview. * back preview.
* @param onBackInvokedCallback The back callback registered by the current top level window. * @param onBackInvokedCallback The back callback registered by the current top level window.
* @param isPrepareRemoteAnimation Return whether the core is preparing a back gesture
* animation, if true, the caller of startBackNavigation should
* be expected to receive an animation start callback.
*/ */
private BackNavigationInfo(@BackTargetType int type, private BackNavigationInfo(@BackTargetType int type,
@Nullable RemoteAnimationTarget departingAnimationTarget, @Nullable RemoteAnimationTarget departingAnimationTarget,
@@ -124,7 +129,8 @@ public final class BackNavigationInfo implements Parcelable {
@Nullable HardwareBuffer screenshotBuffer, @Nullable HardwareBuffer screenshotBuffer,
@Nullable WindowConfiguration taskWindowConfiguration, @Nullable WindowConfiguration taskWindowConfiguration,
@Nullable RemoteCallback onBackNavigationDone, @Nullable RemoteCallback onBackNavigationDone,
@Nullable IOnBackInvokedCallback onBackInvokedCallback) { @Nullable IOnBackInvokedCallback onBackInvokedCallback,
boolean isPrepareRemoteAnimation) {
mType = type; mType = type;
mDepartingAnimationTarget = departingAnimationTarget; mDepartingAnimationTarget = departingAnimationTarget;
mScreenshotSurface = screenshotSurface; mScreenshotSurface = screenshotSurface;
@@ -132,6 +138,7 @@ public final class BackNavigationInfo implements Parcelable {
mTaskWindowConfiguration = taskWindowConfiguration; mTaskWindowConfiguration = taskWindowConfiguration;
mOnBackNavigationDone = onBackNavigationDone; mOnBackNavigationDone = onBackNavigationDone;
mOnBackInvokedCallback = onBackInvokedCallback; mOnBackInvokedCallback = onBackInvokedCallback;
mIsPrepareRemoteAnimation = isPrepareRemoteAnimation;
} }
private BackNavigationInfo(@NonNull Parcel in) { private BackNavigationInfo(@NonNull Parcel in) {
@@ -142,6 +149,7 @@ public final class BackNavigationInfo implements Parcelable {
mTaskWindowConfiguration = in.readTypedObject(WindowConfiguration.CREATOR); mTaskWindowConfiguration = in.readTypedObject(WindowConfiguration.CREATOR);
mOnBackNavigationDone = in.readTypedObject(RemoteCallback.CREATOR); mOnBackNavigationDone = in.readTypedObject(RemoteCallback.CREATOR);
mOnBackInvokedCallback = IOnBackInvokedCallback.Stub.asInterface(in.readStrongBinder()); mOnBackInvokedCallback = IOnBackInvokedCallback.Stub.asInterface(in.readStrongBinder());
mIsPrepareRemoteAnimation = in.readBoolean();
} }
@Override @Override
@@ -153,6 +161,7 @@ public final class BackNavigationInfo implements Parcelable {
dest.writeTypedObject(mTaskWindowConfiguration, flags); dest.writeTypedObject(mTaskWindowConfiguration, flags);
dest.writeTypedObject(mOnBackNavigationDone, flags); dest.writeTypedObject(mOnBackNavigationDone, flags);
dest.writeStrongInterface(mOnBackInvokedCallback); dest.writeStrongInterface(mOnBackInvokedCallback);
dest.writeBoolean(mIsPrepareRemoteAnimation);
} }
/** /**
@@ -221,6 +230,10 @@ public final class BackNavigationInfo implements Parcelable {
return mOnBackInvokedCallback; return mOnBackInvokedCallback;
} }
public boolean isPrepareRemoteAnimation() {
return mIsPrepareRemoteAnimation;
}
/** /**
* Callback to be called when the back preview is finished in order to notify the server that * Callback to be called when the back preview is finished in order to notify the server that
* it can clean up the resources created for the animation. * it can clean up the resources created for the animation.
@@ -306,6 +319,8 @@ public final class BackNavigationInfo implements Parcelable {
@Nullable @Nullable
private IOnBackInvokedCallback mOnBackInvokedCallback = null; private IOnBackInvokedCallback mOnBackInvokedCallback = null;
private boolean mPrepareAnimation;
/** /**
* @see BackNavigationInfo#getType() * @see BackNavigationInfo#getType()
*/ */
@@ -365,13 +380,21 @@ public final class BackNavigationInfo implements Parcelable {
return this; return this;
} }
/**
* @param prepareAnimation Whether core prepare animation for shell.
*/
public Builder setPrepareAnimation(boolean prepareAnimation) {
mPrepareAnimation = prepareAnimation;
return this;
}
/** /**
* Builds and returns an instance of {@link BackNavigationInfo} * Builds and returns an instance of {@link BackNavigationInfo}
*/ */
public BackNavigationInfo build() { public BackNavigationInfo build() {
return new BackNavigationInfo(mType, mDepartingAnimationTarget, mScreenshotSurface, return new BackNavigationInfo(mType, mDepartingAnimationTarget, mScreenshotSurface,
mScreenshotBuffer, mTaskWindowConfiguration, mOnBackNavigationDone, mScreenshotBuffer, mTaskWindowConfiguration, mOnBackNavigationDone,
mOnBackInvokedCallback); mOnBackInvokedCallback, mPrepareAnimation);
} }
} }
} }

View File

@@ -0,0 +1,45 @@
/*
* 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 android.window;
import android.view.RemoteAnimationTarget;
import android.window.IBackNaviAnimationController;
/**
* Interface that is used to callback from window manager to the process that runs a back gesture
* animation to start or cancel it.
*
* {@hide}
*/
oneway interface IBackAnimationRunner {
/**
* Called when the system needs to cancel the current animation. This can be due to the
* wallpaper not drawing in time, or the handler not finishing the animation within a predefined
* amount of time.
*
*/
void onAnimationCancelled() = 1;
/**
* Called when the system is ready for the handler to start animating all the visible tasks.
*
*/
void onAnimationStart(in IBackNaviAnimationController controller, in int type,
in RemoteAnimationTarget[] apps, in RemoteAnimationTarget[] wallpapers,
in RemoteAnimationTarget[] nonApps) = 2;
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (C) 2020 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 android.window;
/**
* Interface to be invoked by the controlling process when a back animation has finished.
*
* @param trigger Whether the back gesture has passed the triggering threshold.
* {@hide}
*/
interface IBackNaviAnimationController {
void finish(in boolean triggerBack);
}

View File

@@ -92,7 +92,7 @@ public class BackNavigationTest {
try { try {
mInstrumentation.getUiAutomation().waitForIdle(500, 1000); mInstrumentation.getUiAutomation().waitForIdle(500, 1000);
BackNavigationInfo info = ActivityTaskManager.getService() BackNavigationInfo info = ActivityTaskManager.getService()
.startBackNavigation(true, null); .startBackNavigation(true, null, null);
assertNotNull("BackNavigationInfo is null", info); assertNotNull("BackNavigationInfo is null", info);
assertNotNull("OnBackInvokedCallback is null", info.getOnBackInvokedCallback()); assertNotNull("OnBackInvokedCallback is null", info.getOnBackInvokedCallback());
info.getOnBackInvokedCallback().onBackInvoked(); info.getOnBackInvokedCallback().onBackInvoked();

View File

@@ -16,6 +16,9 @@
package com.android.wm.shell.back; 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.common.ExecutorUtils.executeRemoteCallWithTaskPermission; import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW; import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW;
@@ -27,8 +30,6 @@ import android.app.WindowConfiguration;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.database.ContentObserver; import android.database.ContentObserver;
import android.graphics.Point;
import android.graphics.PointF;
import android.hardware.HardwareBuffer; import android.hardware.HardwareBuffer;
import android.hardware.input.InputManager; import android.hardware.input.InputManager;
import android.net.Uri; import android.net.Uri;
@@ -47,8 +48,11 @@ import android.view.KeyEvent;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.RemoteAnimationTarget; import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl; import android.view.SurfaceControl;
import android.window.BackAnimationAdaptor;
import android.window.BackEvent; import android.window.BackEvent;
import android.window.BackNavigationInfo; import android.window.BackNavigationInfo;
import android.window.IBackAnimationRunner;
import android.window.IBackNaviAnimationController;
import android.window.IOnBackInvokedCallback; import android.window.IOnBackInvokedCallback;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
@@ -76,22 +80,15 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
private static final int PROGRESS_THRESHOLD = SystemProperties private static final int PROGRESS_THRESHOLD = SystemProperties
.getInt(PREDICTIVE_BACK_PROGRESS_THRESHOLD_PROP, -1); .getInt(PREDICTIVE_BACK_PROGRESS_THRESHOLD_PROP, -1);
private final AtomicBoolean mEnableAnimations = new AtomicBoolean(false); private final AtomicBoolean mEnableAnimations = new AtomicBoolean(false);
// TODO (b/241808055) Find a appropriate time to remove during refactor
private static final boolean USE_TRANSITION =
SystemProperties.getInt("persist.wm.debug.predictive_back_ani_trans", 1) != 0;
/** /**
* Max duration to wait for a transition to finish before accepting another gesture start * Max duration to wait for a transition to finish before accepting another gesture start
* request. * request.
*/ */
private static final long MAX_TRANSITION_DURATION = 2000; private static final long MAX_TRANSITION_DURATION = 2000;
/**
* Location of the initial touch event of the back gesture.
*/
private final PointF mInitTouchLocation = new PointF();
/**
* Raw delta between {@link #mInitTouchLocation} and the last touch location.
*/
private final Point mTouchEventDelta = new Point();
/** True when a back gesture is ongoing */ /** True when a back gesture is ongoing */
private boolean mBackGestureStarted = false; private boolean mBackGestureStarted = false;
@@ -119,6 +116,15 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
mTransitionInProgress = false; mTransitionInProgress = false;
}; };
private RemoteAnimationTarget mAnimationTarget;
IBackAnimationRunner mIBackAnimationRunner;
private IBackNaviAnimationController mBackAnimationController;
private BackAnimationAdaptor mBackAnimationAdaptor;
private boolean mWaitingAnimationStart;
private final TouchTracker mTouchTracker = new TouchTracker();
private final CachingBackDispatcher mCachingBackDispatcher = new CachingBackDispatcher();
@VisibleForTesting @VisibleForTesting
final IWindowFocusObserver mFocusObserver = new IWindowFocusObserver.Stub() { final IWindowFocusObserver mFocusObserver = new IWindowFocusObserver.Stub() {
@Override @Override
@@ -137,6 +143,92 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
} }
}; };
/**
* Helper class to record the touch location for gesture start and latest.
*/
private static class TouchTracker {
/**
* Location of the latest touch event
*/
private float mLatestTouchX;
private float mLatestTouchY;
private int mSwipeEdge;
/**
* Location of the initial touch event of the back gesture.
*/
private float mInitTouchX;
private float mInitTouchY;
void update(float touchX, float touchY, int swipeEdge) {
mLatestTouchX = touchX;
mLatestTouchY = touchY;
mSwipeEdge = swipeEdge;
}
void setGestureStartLocation(float touchX, float touchY) {
mInitTouchX = touchX;
mInitTouchY = touchY;
}
int getDeltaFromGestureStart(float touchX) {
return Math.round(touchX - mInitTouchX);
}
void reset() {
mInitTouchX = 0;
mInitTouchY = 0;
}
}
/**
* Cache the temporary callback and trigger result if gesture was finish before received
* BackAnimationRunner#onAnimationStart/cancel, so there can continue play the animation.
*/
private class CachingBackDispatcher {
private IOnBackInvokedCallback mOnBackCallback;
private boolean mTriggerBack;
// Whether we are waiting to receive onAnimationStart
private boolean mWaitingAnimation;
void startWaitingAnimation() {
mWaitingAnimation = true;
}
boolean set(IOnBackInvokedCallback callback, boolean triggerBack) {
if (mWaitingAnimation) {
mOnBackCallback = callback;
mTriggerBack = triggerBack;
return true;
}
return false;
}
boolean consume() {
boolean consumed = false;
if (mWaitingAnimation && mOnBackCallback != null) {
if (mTriggerBack) {
final BackEvent backFinish = new BackEvent(
mTouchTracker.mLatestTouchX, mTouchTracker.mLatestTouchY, 1,
mTouchTracker.mSwipeEdge, mAnimationTarget);
dispatchOnBackProgressed(mBackToLauncherCallback, backFinish);
dispatchOnBackInvoked(mOnBackCallback);
} else {
final BackEvent backFinish = new BackEvent(
mTouchTracker.mLatestTouchX, mTouchTracker.mLatestTouchY, 0,
mTouchTracker.mSwipeEdge, mAnimationTarget);
dispatchOnBackProgressed(mBackToLauncherCallback, backFinish);
dispatchOnBackCancelled(mOnBackCallback);
}
startTransition();
consumed = true;
}
mOnBackCallback = null;
mWaitingAnimation = false;
return consumed;
}
}
public BackAnimationController( public BackAnimationController(
@NonNull ShellInit shellInit, @NonNull ShellInit shellInit,
@NonNull @ShellMainThread ShellExecutor shellExecutor, @NonNull @ShellMainThread ShellExecutor shellExecutor,
@@ -272,6 +364,9 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
@VisibleForTesting @VisibleForTesting
void setBackToLauncherCallback(IOnBackInvokedCallback callback) { void setBackToLauncherCallback(IOnBackInvokedCallback callback) {
mBackToLauncherCallback = callback; mBackToLauncherCallback = callback;
if (USE_TRANSITION) {
createAdaptor();
}
} }
private void clearBackToLauncherCallback() { private void clearBackToLauncherCallback() {
@@ -280,15 +375,18 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
@VisibleForTesting @VisibleForTesting
void onBackToLauncherAnimationFinished() { void onBackToLauncherAnimationFinished() {
if (mBackNavigationInfo != null) { final boolean triggerBack = mTriggerBack;
IOnBackInvokedCallback callback = mBackNavigationInfo.getOnBackInvokedCallback(); IOnBackInvokedCallback callback = mBackNavigationInfo != null
if (mTriggerBack) { ? mBackNavigationInfo.getOnBackInvokedCallback() : null;
// Make sure the notification sequence should be controller > client.
finishAnimation();
if (callback != null) {
if (triggerBack) {
dispatchOnBackInvoked(callback); dispatchOnBackInvoked(callback);
} else { } else {
dispatchOnBackCancelled(callback); dispatchOnBackCancelled(callback);
} }
} }
finishAnimation();
} }
/** /**
@@ -300,6 +398,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
if (mTransitionInProgress) { if (mTransitionInProgress) {
return; return;
} }
mTouchTracker.update(touchX, touchY, swipeEdge);
if (keyAction == MotionEvent.ACTION_DOWN) { if (keyAction == MotionEvent.ACTION_DOWN) {
if (!mBackGestureStarted) { if (!mBackGestureStarted) {
mShouldStartOnNextMoveEvent = true; mShouldStartOnNextMoveEvent = true;
@@ -330,13 +430,13 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
finishAnimation(); finishAnimation();
} }
mInitTouchLocation.set(touchX, touchY); mTouchTracker.setGestureStartLocation(touchX, touchY);
mBackGestureStarted = true; mBackGestureStarted = true;
try { try {
boolean requestAnimation = mEnableAnimations.get(); boolean requestAnimation = mEnableAnimations.get();
mBackNavigationInfo = mBackNavigationInfo = mActivityTaskManager.startBackNavigation(requestAnimation,
mActivityTaskManager.startBackNavigation(requestAnimation, mFocusObserver); mFocusObserver, mBackAnimationAdaptor);
onBackNavigationInfoReceived(mBackNavigationInfo); onBackNavigationInfoReceived(mBackNavigationInfo);
} catch (RemoteException remoteException) { } catch (RemoteException remoteException) {
Log.e(TAG, "Failed to initAnimation", remoteException); Log.e(TAG, "Failed to initAnimation", remoteException);
@@ -352,6 +452,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
} }
int backType = backNavigationInfo.getType(); int backType = backNavigationInfo.getType();
IOnBackInvokedCallback targetCallback = null; IOnBackInvokedCallback targetCallback = null;
final boolean dispatchToLauncher = shouldDispatchToLauncher(backType);
if (backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY) { if (backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY) {
HardwareBuffer hardwareBuffer = backNavigationInfo.getScreenshotHardwareBuffer(); HardwareBuffer hardwareBuffer = backNavigationInfo.getScreenshotHardwareBuffer();
if (hardwareBuffer != null) { if (hardwareBuffer != null) {
@@ -359,12 +460,17 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
backNavigationInfo.getTaskWindowConfiguration()); backNavigationInfo.getTaskWindowConfiguration());
} }
mTransaction.apply(); mTransaction.apply();
} else if (shouldDispatchToLauncher(backType)) { } else if (dispatchToLauncher) {
targetCallback = mBackToLauncherCallback; targetCallback = mBackToLauncherCallback;
if (USE_TRANSITION) {
mCachingBackDispatcher.startWaitingAnimation();
}
} else if (backType == BackNavigationInfo.TYPE_CALLBACK) { } else if (backType == BackNavigationInfo.TYPE_CALLBACK) {
targetCallback = mBackNavigationInfo.getOnBackInvokedCallback(); targetCallback = mBackNavigationInfo.getOnBackInvokedCallback();
} }
dispatchOnBackStarted(targetCallback); if (!USE_TRANSITION || !dispatchToLauncher) {
dispatchOnBackStarted(targetCallback);
}
} }
/** /**
@@ -403,24 +509,33 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
if (!mBackGestureStarted || mBackNavigationInfo == null) { if (!mBackGestureStarted || mBackNavigationInfo == null) {
return; return;
} }
int deltaX = Math.round(touchX - mInitTouchLocation.x); int deltaX = mTouchTracker.getDeltaFromGestureStart(touchX);
float progressThreshold = PROGRESS_THRESHOLD >= 0 ? PROGRESS_THRESHOLD : mProgressThreshold; float progressThreshold = PROGRESS_THRESHOLD >= 0 ? PROGRESS_THRESHOLD : mProgressThreshold;
float progress = Math.min(Math.max(Math.abs(deltaX) / progressThreshold, 0), 1); float progress = Math.min(Math.max(Math.abs(deltaX) / progressThreshold, 0), 1);
int backType = mBackNavigationInfo.getType(); if (USE_TRANSITION) {
RemoteAnimationTarget animationTarget = mBackNavigationInfo.getDepartingAnimationTarget(); if (mBackAnimationController != null && mAnimationTarget != null) {
final BackEvent backEvent = new BackEvent(
touchX, touchY, progress, swipeEdge, mAnimationTarget);
dispatchOnBackProgressed(mBackToLauncherCallback, backEvent);
}
} else {
int backType = mBackNavigationInfo.getType();
RemoteAnimationTarget animationTarget =
mBackNavigationInfo.getDepartingAnimationTarget();
BackEvent backEvent = new BackEvent( BackEvent backEvent = new BackEvent(
touchX, touchY, progress, swipeEdge, animationTarget); touchX, touchY, progress, swipeEdge, animationTarget);
IOnBackInvokedCallback targetCallback = null; IOnBackInvokedCallback targetCallback = null;
if (shouldDispatchToLauncher(backType)) { if (shouldDispatchToLauncher(backType)) {
targetCallback = mBackToLauncherCallback; targetCallback = mBackToLauncherCallback;
} else if (backType == BackNavigationInfo.TYPE_CROSS_TASK } else if (backType == BackNavigationInfo.TYPE_CROSS_TASK
|| backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY) { || backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY) {
// TODO(208427216) Run the actual animation // TODO(208427216) Run the actual animation
} else if (backType == BackNavigationInfo.TYPE_CALLBACK) { } else if (backType == BackNavigationInfo.TYPE_CALLBACK) {
targetCallback = mBackNavigationInfo.getOnBackInvokedCallback(); targetCallback = mBackNavigationInfo.getOnBackInvokedCallback();
}
dispatchOnBackProgressed(targetCallback, backEvent);
} }
dispatchOnBackProgressed(targetCallback, backEvent);
} }
private void injectBackKey() { private void injectBackKey() {
@@ -474,6 +589,9 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
IOnBackInvokedCallback targetCallback = shouldDispatchToLauncher IOnBackInvokedCallback targetCallback = shouldDispatchToLauncher
? mBackToLauncherCallback ? mBackToLauncherCallback
: mBackNavigationInfo.getOnBackInvokedCallback(); : mBackNavigationInfo.getOnBackInvokedCallback();
if (mCachingBackDispatcher.set(targetCallback, mTriggerBack)) {
return;
}
if (shouldDispatchToLauncher) { if (shouldDispatchToLauncher) {
startTransition(); startTransition();
} }
@@ -493,7 +611,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
&& mBackToLauncherCallback != null && mBackToLauncherCallback != null
&& mEnableAnimations.get() && mEnableAnimations.get()
&& mBackNavigationInfo != null && mBackNavigationInfo != null
&& mBackNavigationInfo.getDepartingAnimationTarget() != null; && ((USE_TRANSITION && mBackNavigationInfo.isPrepareRemoteAnimation())
|| mBackNavigationInfo.getDepartingAnimationTarget() != null);
} }
private static void dispatchOnBackStarted(IOnBackInvokedCallback callback) { private static void dispatchOnBackStarted(IOnBackInvokedCallback callback) {
@@ -558,8 +677,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
private void finishAnimation() { private void finishAnimation() {
ProtoLog.d(WM_SHELL_BACK_PREVIEW, "BackAnimationController: finishAnimation()"); ProtoLog.d(WM_SHELL_BACK_PREVIEW, "BackAnimationController: finishAnimation()");
mTouchEventDelta.set(0, 0); mTouchTracker.reset();
mInitTouchLocation.set(0, 0);
BackNavigationInfo backNavigationInfo = mBackNavigationInfo; BackNavigationInfo backNavigationInfo = mBackNavigationInfo;
boolean triggerBack = mTriggerBack; boolean triggerBack = mTriggerBack;
mBackNavigationInfo = null; mBackNavigationInfo = null;
@@ -569,19 +687,33 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
return; return;
} }
RemoteAnimationTarget animationTarget = backNavigationInfo.getDepartingAnimationTarget(); if (!USE_TRANSITION) {
if (animationTarget != null) { RemoteAnimationTarget animationTarget = backNavigationInfo
if (animationTarget.leash != null && animationTarget.leash.isValid()) { .getDepartingAnimationTarget();
mTransaction.remove(animationTarget.leash); if (animationTarget != null) {
if (animationTarget.leash != null && animationTarget.leash.isValid()) {
mTransaction.remove(animationTarget.leash);
}
} }
SurfaceControl screenshotSurface = backNavigationInfo.getScreenshotSurface();
if (screenshotSurface != null && screenshotSurface.isValid()) {
mTransaction.remove(screenshotSurface);
}
mTransaction.apply();
} }
SurfaceControl screenshotSurface = backNavigationInfo.getScreenshotSurface();
if (screenshotSurface != null && screenshotSurface.isValid()) {
mTransaction.remove(screenshotSurface);
}
mTransaction.apply();
stopTransition(); stopTransition();
backNavigationInfo.onBackNavigationFinished(triggerBack); backNavigationInfo.onBackNavigationFinished(triggerBack);
if (USE_TRANSITION) {
final IBackNaviAnimationController controller = mBackAnimationController;
if (controller != null) {
try {
controller.finish(triggerBack);
} catch (RemoteException r) {
// Oh no!
}
}
mBackAnimationController = null;
}
} }
private void startTransition() { private void startTransition() {
@@ -599,4 +731,50 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
mShellExecutor.removeCallbacks(mResetTransitionRunnable); mShellExecutor.removeCallbacks(mResetTransitionRunnable);
mTransitionInProgress = false; mTransitionInProgress = false;
} }
private void createAdaptor() {
mIBackAnimationRunner = new IBackAnimationRunner.Stub() {
@Override
public void onAnimationCancelled() {
// no op for now
}
@Override // Binder interface
public void onAnimationStart(IBackNaviAnimationController controller, int type,
RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers,
RemoteAnimationTarget[] nonApps) {
mShellExecutor.execute(() -> {
mBackAnimationController = controller;
for (int i = 0; i < apps.length; i++) {
final RemoteAnimationTarget target = apps[i];
if (MODE_CLOSING == target.mode) {
mAnimationTarget = target;
} else if (MODE_OPENING == target.mode) {
// TODO Home activity should handle the visibility for itself
// once it finish relayout for orientation change
SurfaceControl.Transaction tx =
new SurfaceControl.Transaction();
tx.setAlpha(target.leash, 1);
tx.apply();
}
}
// TODO animation target should be passed at onBackStarted
dispatchOnBackStarted(mBackToLauncherCallback);
// TODO This is Workaround for LauncherBackAnimationController, there will need
// to dispatch onBackProgressed twice(startBack & updateBackProgress) to
// initialize the animation data, for now that would happen when onMove
// called, but there will no expected animation if the down -> up gesture
// happen very fast which ACTION_MOVE only happen once.
final BackEvent backInit = new BackEvent(
mTouchTracker.mLatestTouchX, mTouchTracker.mLatestTouchY, 0,
mTouchTracker.mSwipeEdge, mAnimationTarget);
dispatchOnBackProgressed(mBackToLauncherCallback, backInit);
if (!mCachingBackDispatcher.consume()) {
dispatchOnBackProgressed(mBackToLauncherCallback, backInit);
}
});
}
};
mBackAnimationAdaptor = new BackAnimationAdaptor(mIBackAnimationRunner,
BackNavigationInfo.TYPE_RETURN_TO_HOME);
}
} }

View File

@@ -48,9 +48,10 @@ public class TestShellExecutor implements ShellExecutor {
} }
public void flushAll() { public void flushAll() {
for (Runnable r : mRunnables) { final ArrayList<Runnable> tmpRunnable = new ArrayList<>(mRunnables);
mRunnables.clear();
for (Runnable r : tmpRunnable) {
r.run(); r.run();
} }
mRunnables.clear();
} }
} }

View File

@@ -54,6 +54,7 @@ import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl; import android.view.SurfaceControl;
import android.window.BackEvent; import android.window.BackEvent;
import android.window.BackNavigationInfo; import android.window.BackNavigationInfo;
import android.window.IBackNaviAnimationController;
import android.window.IOnBackInvokedCallback; import android.window.IOnBackInvokedCallback;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
@@ -98,6 +99,9 @@ public class BackAnimationControllerTest extends ShellTestCase {
@Mock @Mock
private IOnBackInvokedCallback mIOnBackInvokedCallback; private IOnBackInvokedCallback mIOnBackInvokedCallback;
@Mock
private IBackNaviAnimationController mIBackNaviAnimationController;
private BackAnimationController mController; private BackAnimationController mController;
private int mEventTime = 0; private int mEventTime = 0;
@@ -127,7 +131,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
SurfaceControl screenshotSurface, SurfaceControl screenshotSurface,
HardwareBuffer hardwareBuffer, HardwareBuffer hardwareBuffer,
int backType, int backType,
IOnBackInvokedCallback onBackInvokedCallback) { IOnBackInvokedCallback onBackInvokedCallback, boolean prepareAnimation) {
BackNavigationInfo.Builder builder = new BackNavigationInfo.Builder() BackNavigationInfo.Builder builder = new BackNavigationInfo.Builder()
.setType(backType) .setType(backType)
.setDepartingAnimationTarget(topAnimationTarget) .setDepartingAnimationTarget(topAnimationTarget)
@@ -135,7 +139,8 @@ public class BackAnimationControllerTest extends ShellTestCase {
.setScreenshotBuffer(hardwareBuffer) .setScreenshotBuffer(hardwareBuffer)
.setTaskWindowConfiguration(new WindowConfiguration()) .setTaskWindowConfiguration(new WindowConfiguration())
.setOnBackNavigationDone(new RemoteCallback((bundle) -> {})) .setOnBackNavigationDone(new RemoteCallback((bundle) -> {}))
.setOnBackInvokedCallback(onBackInvokedCallback); .setOnBackInvokedCallback(onBackInvokedCallback)
.setPrepareAnimation(prepareAnimation);
createNavigationInfo(builder); createNavigationInfo(builder);
} }
@@ -143,7 +148,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
private void createNavigationInfo(BackNavigationInfo.Builder builder) { private void createNavigationInfo(BackNavigationInfo.Builder builder) {
try { try {
doReturn(builder.build()).when(mActivityTaskManager) doReturn(builder.build()).when(mActivityTaskManager)
.startBackNavigation(anyBoolean(), any()); .startBackNavigation(anyBoolean(), any(), any());
} catch (RemoteException ex) { } catch (RemoteException ex) {
ex.rethrowFromSystemServer(); ex.rethrowFromSystemServer();
} }
@@ -175,7 +180,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
SurfaceControl screenshotSurface = new SurfaceControl(); SurfaceControl screenshotSurface = new SurfaceControl();
HardwareBuffer hardwareBuffer = mock(HardwareBuffer.class); HardwareBuffer hardwareBuffer = mock(HardwareBuffer.class);
createNavigationInfo(createAnimationTarget(), screenshotSurface, hardwareBuffer, createNavigationInfo(createAnimationTarget(), screenshotSurface, hardwareBuffer,
BackNavigationInfo.TYPE_CROSS_ACTIVITY, null); BackNavigationInfo.TYPE_CROSS_ACTIVITY, null, true);
doMotionEvent(MotionEvent.ACTION_DOWN, 0); doMotionEvent(MotionEvent.ACTION_DOWN, 0);
verify(mTransaction).setBuffer(screenshotSurface, hardwareBuffer); verify(mTransaction).setBuffer(screenshotSurface, hardwareBuffer);
verify(mTransaction).setVisibility(screenshotSurface, true); verify(mTransaction).setVisibility(screenshotSurface, true);
@@ -188,7 +193,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
HardwareBuffer hardwareBuffer = mock(HardwareBuffer.class); HardwareBuffer hardwareBuffer = mock(HardwareBuffer.class);
RemoteAnimationTarget animationTarget = createAnimationTarget(); RemoteAnimationTarget animationTarget = createAnimationTarget();
createNavigationInfo(animationTarget, screenshotSurface, hardwareBuffer, createNavigationInfo(animationTarget, screenshotSurface, hardwareBuffer,
BackNavigationInfo.TYPE_CROSS_ACTIVITY, null); BackNavigationInfo.TYPE_CROSS_ACTIVITY, null, true);
doMotionEvent(MotionEvent.ACTION_DOWN, 0); doMotionEvent(MotionEvent.ACTION_DOWN, 0);
doMotionEvent(MotionEvent.ACTION_MOVE, 100); doMotionEvent(MotionEvent.ACTION_MOVE, 100);
// b/207481538, we check that the surface is not moved for now, we can re-enable this once // b/207481538, we check that the surface is not moved for now, we can re-enable this once
@@ -222,15 +227,16 @@ public class BackAnimationControllerTest extends ShellTestCase {
mController.setBackToLauncherCallback(mIOnBackInvokedCallback); mController.setBackToLauncherCallback(mIOnBackInvokedCallback);
RemoteAnimationTarget animationTarget = createAnimationTarget(); RemoteAnimationTarget animationTarget = createAnimationTarget();
createNavigationInfo(animationTarget, null, null, createNavigationInfo(animationTarget, null, null,
BackNavigationInfo.TYPE_RETURN_TO_HOME, null); BackNavigationInfo.TYPE_RETURN_TO_HOME, null, true);
doMotionEvent(MotionEvent.ACTION_DOWN, 0); doMotionEvent(MotionEvent.ACTION_DOWN, 0);
// Check that back start and progress is dispatched when first move. // Check that back start and progress is dispatched when first move.
doMotionEvent(MotionEvent.ACTION_MOVE, 100); doMotionEvent(MotionEvent.ACTION_MOVE, 100);
simulateRemoteAnimationStart(BackNavigationInfo.TYPE_RETURN_TO_HOME, animationTarget);
verify(mIOnBackInvokedCallback).onBackStarted(); verify(mIOnBackInvokedCallback).onBackStarted();
ArgumentCaptor<BackEvent> backEventCaptor = ArgumentCaptor.forClass(BackEvent.class); ArgumentCaptor<BackEvent> backEventCaptor = ArgumentCaptor.forClass(BackEvent.class);
verify(mIOnBackInvokedCallback).onBackProgressed(backEventCaptor.capture()); verify(mIOnBackInvokedCallback, atLeastOnce()).onBackProgressed(backEventCaptor.capture());
assertEquals(animationTarget, backEventCaptor.getValue().getDepartingAnimationTarget()); assertEquals(animationTarget, backEventCaptor.getValue().getDepartingAnimationTarget());
// Check that back invocation is dispatched. // Check that back invocation is dispatched.
@@ -255,7 +261,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
IOnBackInvokedCallback appCallback = mock(IOnBackInvokedCallback.class); IOnBackInvokedCallback appCallback = mock(IOnBackInvokedCallback.class);
ArgumentCaptor<BackEvent> backEventCaptor = ArgumentCaptor.forClass(BackEvent.class); ArgumentCaptor<BackEvent> backEventCaptor = ArgumentCaptor.forClass(BackEvent.class);
createNavigationInfo(animationTarget, null, null, createNavigationInfo(animationTarget, null, null,
BackNavigationInfo.TYPE_RETURN_TO_HOME, appCallback); BackNavigationInfo.TYPE_RETURN_TO_HOME, appCallback, false);
triggerBackGesture(); triggerBackGesture();
@@ -273,9 +279,10 @@ public class BackAnimationControllerTest extends ShellTestCase {
mController.setBackToLauncherCallback(mIOnBackInvokedCallback); mController.setBackToLauncherCallback(mIOnBackInvokedCallback);
RemoteAnimationTarget animationTarget = createAnimationTarget(); RemoteAnimationTarget animationTarget = createAnimationTarget();
createNavigationInfo(animationTarget, null, null, createNavigationInfo(animationTarget, null, null,
BackNavigationInfo.TYPE_RETURN_TO_HOME, null); BackNavigationInfo.TYPE_RETURN_TO_HOME, null, true);
triggerBackGesture(); triggerBackGesture();
simulateRemoteAnimationStart(BackNavigationInfo.TYPE_RETURN_TO_HOME, animationTarget);
// Check that back invocation is dispatched. // Check that back invocation is dispatched.
verify(mIOnBackInvokedCallback).onBackInvoked(); verify(mIOnBackInvokedCallback).onBackInvoked();
@@ -294,6 +301,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
// Verify that we start accepting gestures again once transition finishes. // Verify that we start accepting gestures again once transition finishes.
doMotionEvent(MotionEvent.ACTION_DOWN, 0); doMotionEvent(MotionEvent.ACTION_DOWN, 0);
doMotionEvent(MotionEvent.ACTION_MOVE, 100); doMotionEvent(MotionEvent.ACTION_MOVE, 100);
simulateRemoteAnimationStart(BackNavigationInfo.TYPE_RETURN_TO_HOME, animationTarget);
verify(mIOnBackInvokedCallback).onBackStarted(); verify(mIOnBackInvokedCallback).onBackStarted();
} }
@@ -302,15 +310,17 @@ public class BackAnimationControllerTest extends ShellTestCase {
mController.setBackToLauncherCallback(mIOnBackInvokedCallback); mController.setBackToLauncherCallback(mIOnBackInvokedCallback);
RemoteAnimationTarget animationTarget = createAnimationTarget(); RemoteAnimationTarget animationTarget = createAnimationTarget();
createNavigationInfo(animationTarget, null, null, createNavigationInfo(animationTarget, null, null,
BackNavigationInfo.TYPE_RETURN_TO_HOME, null); BackNavigationInfo.TYPE_RETURN_TO_HOME, null, true);
triggerBackGesture(); triggerBackGesture();
simulateRemoteAnimationStart(BackNavigationInfo.TYPE_RETURN_TO_HOME, animationTarget);
reset(mIOnBackInvokedCallback); reset(mIOnBackInvokedCallback);
// Simulate transition timeout. // Simulate transition timeout.
mShellExecutor.flushAll(); mShellExecutor.flushAll();
doMotionEvent(MotionEvent.ACTION_DOWN, 0); doMotionEvent(MotionEvent.ACTION_DOWN, 0);
doMotionEvent(MotionEvent.ACTION_MOVE, 100); doMotionEvent(MotionEvent.ACTION_MOVE, 100);
simulateRemoteAnimationStart(BackNavigationInfo.TYPE_RETURN_TO_HOME, animationTarget);
verify(mIOnBackInvokedCallback).onBackStarted(); verify(mIOnBackInvokedCallback).onBackStarted();
} }
@@ -321,11 +331,12 @@ public class BackAnimationControllerTest extends ShellTestCase {
RemoteAnimationTarget animationTarget = createAnimationTarget(); RemoteAnimationTarget animationTarget = createAnimationTarget();
createNavigationInfo(animationTarget, null, null, createNavigationInfo(animationTarget, null, null,
BackNavigationInfo.TYPE_RETURN_TO_HOME, null); BackNavigationInfo.TYPE_RETURN_TO_HOME, null, true);
doMotionEvent(MotionEvent.ACTION_DOWN, 0); doMotionEvent(MotionEvent.ACTION_DOWN, 0);
// Check that back start and progress is dispatched when first move. // Check that back start and progress is dispatched when first move.
doMotionEvent(MotionEvent.ACTION_MOVE, 100); doMotionEvent(MotionEvent.ACTION_MOVE, 100);
simulateRemoteAnimationStart(BackNavigationInfo.TYPE_RETURN_TO_HOME, animationTarget);
verify(mIOnBackInvokedCallback).onBackStarted(); verify(mIOnBackInvokedCallback).onBackStarted();
// Check that back invocation is dispatched. // Check that back invocation is dispatched.
@@ -349,4 +360,14 @@ public class BackAnimationControllerTest extends ShellTestCase {
BackEvent.EDGE_LEFT); BackEvent.EDGE_LEFT);
mEventTime += 10; mEventTime += 10;
} }
private void simulateRemoteAnimationStart(int type, RemoteAnimationTarget animationTarget)
throws RemoteException {
if (mController.mIBackAnimationRunner != null) {
final RemoteAnimationTarget[] targets = new RemoteAnimationTarget[]{animationTarget};
mController.mIBackAnimationRunner.onAnimationStart(mIBackNaviAnimationController, type,
targets, null, null);
mShellExecutor.flushAll();
}
}
} }

View File

@@ -226,6 +226,7 @@ import android.view.IWindowFocusObserver;
import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationDefinition; import android.view.RemoteAnimationDefinition;
import android.view.WindowManager; import android.view.WindowManager;
import android.window.BackAnimationAdaptor;
import android.window.BackNavigationInfo; import android.window.BackNavigationInfo;
import android.window.IWindowOrganizerController; import android.window.IWindowOrganizerController;
import android.window.SplashScreenView.SplashScreenViewParcelable; import android.window.SplashScreenView.SplashScreenViewParcelable;
@@ -457,7 +458,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
private final ClientLifecycleManager mLifecycleManager; private final ClientLifecycleManager mLifecycleManager;
@Nullable @Nullable
private final BackNavigationController mBackNavigationController; final BackNavigationController mBackNavigationController;
private TaskChangeNotificationController mTaskChangeNotificationController; private TaskChangeNotificationController mTaskChangeNotificationController;
/** The controller for all operations related to locktask. */ /** The controller for all operations related to locktask. */
@@ -1836,13 +1837,14 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override @Override
public BackNavigationInfo startBackNavigation(boolean requestAnimation, public BackNavigationInfo startBackNavigation(boolean requestAnimation,
IWindowFocusObserver observer) { IWindowFocusObserver observer, BackAnimationAdaptor backAnimationAdaptor) {
mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS, mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS,
"startBackNavigation()"); "startBackNavigation()");
if (mBackNavigationController == null) { if (mBackNavigationController == null) {
return null; return null;
} }
return mBackNavigationController.startBackNavigation(requestAnimation, observer); return mBackNavigationController.startBackNavigation(
requestAnimation, observer, backAnimationAdaptor);
} }
/** /**

View File

@@ -0,0 +1,418 @@
/*
* 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.server.wm;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.view.RemoteAnimationTarget.MODE_CLOSING;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import android.annotation.NonNull;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.view.WindowInsets;
import android.window.BackNavigationInfo;
import android.window.IBackAnimationRunner;
import android.window.IBackNaviAnimationController;
import com.android.server.wm.utils.InsetUtils;
import java.io.PrintWriter;
import java.util.ArrayList;
/**
* Controls the back navigation animation.
* This is throw-away code and should only be used for Android T, most code is duplicated from
* RecentsAnimationController which should be stable to handle animation leash resources/flicker/
* fixed rotation, etc. Remove this class at U and migrate to shell transition.
*/
public class BackNaviAnimationController implements IBinder.DeathRecipient {
private static final String TAG = BackNavigationController.TAG;
// Constant for a yet-to-be-calculated {@link RemoteAnimationTarget#Mode} state
private static final int MODE_UNKNOWN = -1;
// The activity which host this animation
private ActivityRecord mTargetActivityRecord;
// The original top activity
private ActivityRecord mTopActivity;
private final DisplayContent mDisplayContent;
private final WindowManagerService mWindowManagerService;
private final BackNavigationController mBackNavigationController;
// We start the BackAnimationController in a pending-start state since we need to wait for
// the wallpaper/activity to draw before we can give control to the handler to start animating
// the visible task surfaces
private boolean mPendingStart;
private IBackAnimationRunner mRunner;
final IBackNaviAnimationController mRemoteController;
private boolean mLinkedToDeathOfRunner;
private final ArrayList<TaskAnimationAdapter> mPendingAnimations = new ArrayList<>();
BackNaviAnimationController(IBackAnimationRunner runner,
BackNavigationController backNavigationController, int displayId) {
mRunner = runner;
mBackNavigationController = backNavigationController;
mWindowManagerService = mBackNavigationController.mWindowManagerService;
mDisplayContent = mWindowManagerService.mRoot.getDisplayContent(displayId);
mRemoteController = new IBackNaviAnimationController.Stub() {
@Override
public void finish(boolean triggerBack) {
synchronized (mWindowManagerService.getWindowManagerLock()) {
final long token = Binder.clearCallingIdentity();
try {
mWindowManagerService.inSurfaceTransaction(() -> {
mWindowManagerService.mAtmService.deferWindowLayout();
try {
if (triggerBack) {
mDisplayContent.mFixedRotationTransitionListener
.notifyRecentsWillBeTop();
if (mTopActivity != null) {
mWindowManagerService.mTaskSnapshotController
.recordTaskSnapshot(mTopActivity.getTask(), false);
// TODO consume moveTaskToBack?
mTopActivity.commitVisibility(false, false, true);
}
} else {
mTargetActivityRecord.mTaskSupervisor
.scheduleLaunchTaskBehindComplete(
mTargetActivityRecord.token);
}
cleanupAnimation();
} finally {
mWindowManagerService.mAtmService.continueWindowLayout();
}
});
} finally {
Binder.restoreCallingIdentity(token);
}
}
}
};
}
/**
* @param targetActivity The home or opening activity which should host the wallpaper
* @param topActivity The current top activity before animation start.
*/
void initialize(ActivityRecord targetActivity, ActivityRecord topActivity) {
mTargetActivityRecord = targetActivity;
mTopActivity = topActivity;
final Task topTask = mTopActivity.getTask();
createAnimationAdapter(topTask, (type, anim) -> topTask.forAllWindows(
win -> {
win.onAnimationFinished(type, anim);
}, true));
final Task homeTask = mTargetActivityRecord.getRootTask();
createAnimationAdapter(homeTask, (type, anim) -> homeTask.forAllWindows(
win -> {
win.onAnimationFinished(type, anim);
}, true));
try {
linkToDeathOfRunner();
} catch (RemoteException e) {
cancelAnimation();
return;
}
if (targetActivity.windowsCanBeWallpaperTarget()) {
mDisplayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
mDisplayContent.setLayoutNeeded();
}
mWindowManagerService.mWindowPlacerLocked.performSurfacePlacement();
mDisplayContent.mFixedRotationTransitionListener.onStartRecentsAnimation(targetActivity);
mPendingStart = true;
}
void cleanupAnimation() {
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i);
removeAnimationAdapter(taskAdapter);
taskAdapter.onCleanup();
}
mTargetActivityRecord.mLaunchTaskBehind = false;
// Clear references to the runner
unlinkToDeathOfRunner();
mRunner = null;
// Update the input windows after the animation is complete
final InputMonitor inputMonitor = mDisplayContent.getInputMonitor();
inputMonitor.updateInputWindowsLw(true /*force*/);
mDisplayContent.mFixedRotationTransitionListener.onFinishRecentsAnimation();
mBackNavigationController.finishAnimation();
}
void removeAnimationAdapter(TaskAnimationAdapter taskAdapter) {
taskAdapter.onRemove();
mPendingAnimations.remove(taskAdapter);
}
void checkAnimationReady(WallpaperController wallpaperController) {
if (mPendingStart) {
final boolean wallpaperReady = !isTargetOverWallpaper()
|| (wallpaperController.getWallpaperTarget() != null
&& wallpaperController.wallpaperTransitionReady());
if (wallpaperReady) {
startAnimation();
}
}
}
boolean isWallpaperVisible(WindowState w) {
return w != null && w.mAttrs.type == TYPE_BASE_APPLICATION
&& ((w.mActivityRecord != null && mTargetActivityRecord == w.mActivityRecord)
|| isAnimatingTask(w.getTask()))
&& isTargetOverWallpaper() && w.isOnScreen();
}
boolean isAnimatingTask(Task task) {
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
if (task == mPendingAnimations.get(i).mTask) {
return true;
}
}
return false;
}
void linkFixedRotationTransformIfNeeded(@NonNull WindowToken wallpaper) {
if (mTargetActivityRecord == null) {
return;
}
wallpaper.linkFixedRotationTransform(mTargetActivityRecord);
}
private void linkToDeathOfRunner() throws RemoteException {
if (!mLinkedToDeathOfRunner) {
mRunner.asBinder().linkToDeath(this, 0);
mLinkedToDeathOfRunner = true;
}
}
private void unlinkToDeathOfRunner() {
if (mLinkedToDeathOfRunner) {
mRunner.asBinder().unlinkToDeath(this, 0);
mLinkedToDeathOfRunner = false;
}
}
void startAnimation() {
if (!mPendingStart) {
// Skip starting if we've already started or canceled the animation
return;
}
// Create the app targets
final RemoteAnimationTarget[] appTargets = createAppAnimations();
// Skip the animation if there is nothing to animate
if (appTargets.length == 0) {
cancelAnimation();
return;
}
mPendingStart = false;
try {
mRunner.onAnimationStart(mRemoteController, BackNavigationInfo.TYPE_RETURN_TO_HOME,
appTargets, null /* wallpapers */, null /*nonApps*/);
} catch (RemoteException e) {
cancelAnimation();
}
}
@Override
public void binderDied() {
cancelAnimation();
}
TaskAnimationAdapter createAnimationAdapter(Task task,
SurfaceAnimator.OnAnimationFinishedCallback finishedCallback) {
final TaskAnimationAdapter taskAdapter = new TaskAnimationAdapter(task,
mTargetActivityRecord, this::cancelAnimation);
// borrow from recents since we cannot start back animation if recents is playing
task.startAnimation(task.getPendingTransaction(), taskAdapter, false /* hidden */,
ANIMATION_TYPE_RECENTS, finishedCallback);
task.commitPendingTransaction();
mPendingAnimations.add(taskAdapter);
return taskAdapter;
}
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(INVALID_TASK_ID, MODE_UNKNOWN);
if (target != null) {
targets.add(target);
} else {
removeAnimationAdapter(taskAdapter);
}
}
return targets.toArray(new RemoteAnimationTarget[targets.size()]);
}
private void cancelAnimation() {
synchronized (mWindowManagerService.getWindowManagerLock()) {
// Notify the runner and clean up the animation immediately
// Note: In the fallback case, this can trigger multiple onAnimationCancel() calls
// to the runner if we this actually triggers cancel twice on the caller
try {
mRunner.onAnimationCancelled();
} catch (RemoteException e) {
Slog.e(TAG, "Failed to cancel recents animation", e);
}
cleanupAnimation();
}
}
private boolean isTargetOverWallpaper() {
if (mTargetActivityRecord == null) {
return false;
}
return mTargetActivityRecord.windowsCanBeWallpaperTarget();
}
private static class TaskAnimationAdapter implements AnimationAdapter {
private final Task mTask;
private SurfaceControl mCapturedLeash;
private SurfaceAnimator.OnAnimationFinishedCallback mCapturedFinishCallback;
@SurfaceAnimator.AnimationType private int mLastAnimationType;
private RemoteAnimationTarget mTarget;
private final ActivityRecord mTargetActivityRecord;
private final Runnable mCancelCallback;
private final Rect mBounds = new Rect();
// The bounds of the target relative to its parent.
private final Rect mLocalBounds = new Rect();
TaskAnimationAdapter(Task task, ActivityRecord target, Runnable cancelCallback) {
mTask = task;
mBounds.set(mTask.getBounds());
mLocalBounds.set(mBounds);
Point tmpPos = new Point();
mTask.getRelativePosition(tmpPos);
mLocalBounds.offsetTo(tmpPos.x, tmpPos.y);
mTargetActivityRecord = target;
mCancelCallback = cancelCallback;
}
// Keep overrideTaskId and overrideMode now, if we need to add other type of back animation
// on legacy transition system then they can be useful.
RemoteAnimationTarget createRemoteAnimationTarget(int overrideTaskId, int overrideMode) {
ActivityRecord topApp = mTask.getTopRealVisibleActivity();
if (topApp == null) {
topApp = mTask.getTopVisibleActivity();
}
final WindowState mainWindow = topApp != null
? topApp.findMainWindow()
: null;
if (mainWindow == null) {
return null;
}
final Rect insets =
mainWindow.getInsetsStateWithVisibilityOverride().calculateInsets(
mBounds, WindowInsets.Type.systemBars(),
false /* ignoreVisibility */).toRect();
InsetUtils.addInsets(insets, mainWindow.mActivityRecord.getLetterboxInsets());
final int mode = overrideMode != MODE_UNKNOWN
? overrideMode
: topApp.getActivityType() == mTargetActivityRecord.getActivityType()
? MODE_OPENING
: MODE_CLOSING;
if (overrideTaskId < 0) {
overrideTaskId = mTask.mTaskId;
}
mTarget = new RemoteAnimationTarget(overrideTaskId, mode, mCapturedLeash,
!topApp.fillsParent(), new Rect(),
insets, mTask.getPrefixOrderIndex(), new Point(mBounds.left, mBounds.top),
mLocalBounds, mBounds, mTask.getWindowConfiguration(),
true /* isNotInRecents */, null, null, mTask.getTaskInfo(),
topApp.checkEnterPictureInPictureAppOpsState());
return mTarget;
}
@Override
public boolean getShowWallpaper() {
return false;
}
@Override
public void startAnimation(SurfaceControl animationLeash, SurfaceControl.Transaction t,
@SurfaceAnimator.AnimationType int type,
@NonNull SurfaceAnimator.OnAnimationFinishedCallback finishCallback) {
t.setPosition(animationLeash, mLocalBounds.left, mLocalBounds.top);
final Rect tmpRect = new Rect();
tmpRect.set(mLocalBounds);
tmpRect.offsetTo(0, 0);
t.setWindowCrop(animationLeash, tmpRect);
mCapturedLeash = animationLeash;
mCapturedFinishCallback = finishCallback;
mLastAnimationType = type;
}
@Override
public void onAnimationCancelled(SurfaceControl animationLeash) {
mCancelCallback.run();
}
void onRemove() {
mCapturedFinishCallback.onAnimationFinished(mLastAnimationType, this);
}
void onCleanup() {
final SurfaceControl.Transaction pendingTransaction = mTask.getPendingTransaction();
if (!mTask.isAttached()) {
// Apply the task's pending transaction in case it is detached and its transaction
// is not reachable.
pendingTransaction.apply();
}
}
@Override
public long getDurationHint() {
return 0;
}
@Override
public long getStatusBarTransitionsStartTime() {
return SystemClock.uptimeMillis();
}
@Override
public void dump(PrintWriter pw, String prefix) { }
@Override
public void dumpDebug(ProtoOutputStream proto) { }
}
}

View File

@@ -34,6 +34,7 @@ import android.util.Slog;
import android.view.IWindowFocusObserver; import android.view.IWindowFocusObserver;
import android.view.RemoteAnimationTarget; import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl; import android.view.SurfaceControl;
import android.window.BackAnimationAdaptor;
import android.window.BackNavigationInfo; import android.window.BackNavigationInfo;
import android.window.OnBackInvokedCallbackInfo; import android.window.OnBackInvokedCallbackInfo;
import android.window.TaskSnapshot; import android.window.TaskSnapshot;
@@ -46,9 +47,15 @@ import com.android.server.LocalServices;
* Controller to handle actions related to the back gesture on the server side. * Controller to handle actions related to the back gesture on the server side.
*/ */
class BackNavigationController { class BackNavigationController {
private static final String TAG = "BackNavigationController"; static final String TAG = "BackNavigationController";
private WindowManagerService mWindowManagerService; WindowManagerService mWindowManagerService;
private IWindowFocusObserver mFocusObserver; private IWindowFocusObserver mFocusObserver;
// TODO (b/241808055) Find a appropriate time to remove during refactor
// Execute back animation with legacy transition system. Temporary flag for easier debugging.
static final boolean USE_TRANSITION =
SystemProperties.getInt("persist.wm.debug.predictive_back_ani_trans", 1) != 0;
BackNaviAnimationController mBackNaviAnimationController;
/** /**
* Returns true if the back predictability feature is enabled * Returns true if the back predictability feature is enabled
@@ -72,7 +79,7 @@ class BackNavigationController {
@VisibleForTesting @VisibleForTesting
@Nullable @Nullable
BackNavigationInfo startBackNavigation(boolean requestAnimation, BackNavigationInfo startBackNavigation(boolean requestAnimation,
IWindowFocusObserver observer) { IWindowFocusObserver observer, BackAnimationAdaptor backAnimationAdaptor) {
final WindowManagerService wmService = mWindowManagerService; final WindowManagerService wmService = mWindowManagerService;
final SurfaceControl.Transaction tx = wmService.mTransactionFactory.get(); final SurfaceControl.Transaction tx = wmService.mTransactionFactory.get();
mFocusObserver = observer; mFocusObserver = observer;
@@ -259,6 +266,8 @@ class BackNavigationController {
&& requestAnimation && requestAnimation
// Only create a new leash if no leash has been created. // Only create a new leash if no leash has been created.
// Otherwise return null for animation target to avoid conflict. // Otherwise return null for animation target to avoid conflict.
// TODO isAnimating, recents can cancel app transition animation, can't back
// cancel like recents?
&& !removedWindowContainer.hasCommittedReparentToAnimationLeash(); && !removedWindowContainer.hasCommittedReparentToAnimationLeash();
if (prepareAnimation) { if (prepareAnimation) {
@@ -266,19 +275,21 @@ class BackNavigationController {
currentTask.getTaskInfo().configuration.windowConfiguration; currentTask.getTaskInfo().configuration.windowConfiguration;
infoBuilder.setTaskWindowConfiguration(taskWindowConfiguration); infoBuilder.setTaskWindowConfiguration(taskWindowConfiguration);
// Prepare a leash to animate the current top window if (!USE_TRANSITION) {
// TODO(b/220934562): Use surface animator to better manage animation conflicts. // Prepare a leash to animate the current top window
SurfaceControl animLeash = removedWindowContainer.makeAnimationLeash() // TODO(b/220934562): Use surface animator to better manage animation conflicts.
.setName("BackPreview Leash for " + removedWindowContainer) SurfaceControl animLeash = removedWindowContainer.makeAnimationLeash()
.setHidden(false) .setName("BackPreview Leash for " + removedWindowContainer)
.setBLASTLayer() .setHidden(false)
.build(); .setBLASTLayer()
removedWindowContainer.reparentSurfaceControl(tx, animLeash); .build();
animationLeashParent = removedWindowContainer.getAnimationLeashParent(); removedWindowContainer.reparentSurfaceControl(tx, animLeash);
topAppTarget = createRemoteAnimationTargetLocked(removedWindowContainer, animationLeashParent = removedWindowContainer.getAnimationLeashParent();
currentActivity, topAppTarget = createRemoteAnimationTargetLocked(removedWindowContainer,
currentTask, animLeash); currentActivity,
infoBuilder.setDepartingAnimationTarget(topAppTarget); currentTask, animLeash);
infoBuilder.setDepartingAnimationTarget(topAppTarget);
}
} }
//TODO(207481538) Remove once the infrastructure to support per-activity screenshot is //TODO(207481538) Remove once the infrastructure to support per-activity screenshot is
@@ -293,21 +304,32 @@ class BackNavigationController {
// Special handling for back to home animation // Special handling for back to home animation
if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && prepareAnimation if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && prepareAnimation
&& prevTask != null) { && prevTask != null) {
currentTask.mBackGestureStarted = true; if (USE_TRANSITION && mBackNaviAnimationController == null) {
// Make launcher show from behind by marking its top activity as visible and if (backAnimationAdaptor != null
// launch-behind to bump its visibility for the duration of the back gesture. && backAnimationAdaptor.getSupportType() == backType) {
prevActivity = prevTask.getTopNonFinishingActivity(); mBackNaviAnimationController = new BackNaviAnimationController(
if (prevActivity != null) { backAnimationAdaptor.getRunner(), this,
if (!prevActivity.mVisibleRequested) { currentActivity.getDisplayId());
prevActivity.setVisibility(true); prepareBackToHomeTransition(currentTask, prevTask);
infoBuilder.setPrepareAnimation(true);
}
} else {
currentTask.mBackGestureStarted = true;
// Make launcher show from behind by marking its top activity as visible and
// launch-behind to bump its visibility for the duration of the back gesture.
prevActivity = prevTask.getTopNonFinishingActivity();
if (prevActivity != null) {
if (!prevActivity.mVisibleRequested) {
prevActivity.setVisibility(true);
}
prevActivity.mLaunchTaskBehind = true;
ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
"Setting Activity.mLauncherTaskBehind to true. Activity=%s",
prevActivity);
prevActivity.mRootWindowContainer.ensureActivitiesVisible(
null /* starting */, 0 /* configChanges */,
false /* preserveWindows */);
} }
prevActivity.mLaunchTaskBehind = true;
ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
"Setting Activity.mLauncherTaskBehind to true. Activity=%s",
prevActivity);
prevActivity.mRootWindowContainer.ensureActivitiesVisible(
null /* starting */, 0 /* configChanges */,
false /* preserveWindows */);
} }
} }
} // Release wm Lock } // Release wm Lock
@@ -388,29 +410,30 @@ class BackNavigationController {
BackNavigationInfo.KEY_TRIGGER_BACK); BackNavigationInfo.KEY_TRIGGER_BACK);
ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "onBackNavigationDone backType=%s, " ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "onBackNavigationDone backType=%s, "
+ "task=%s, prevActivity=%s", backType, task, prevActivity); + "task=%s, prevActivity=%s", backType, task, prevActivity);
if (!USE_TRANSITION) {
if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && prepareAnimation) { if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && prepareAnimation) {
if (triggerBack) { if (triggerBack) {
if (surfaceControl != null && surfaceControl.isValid()) { if (surfaceControl != null && surfaceControl.isValid()) {
// When going back to home, hide the task surface before it is re-parented to // When going back to home, hide the task surface before it is re-parented
// avoid flicker. // to avoid flicker.
SurfaceControl.Transaction t = windowContainer.getSyncTransaction(); SurfaceControl.Transaction t = windowContainer.getSyncTransaction();
t.hide(surfaceControl); t.hide(surfaceControl);
t.apply(); t.apply();
}
} }
if (prevActivity != null && !triggerBack) {
// Restore the launch-behind state.
task.mTaskSupervisor.scheduleLaunchTaskBehindComplete(prevActivity.token);
prevActivity.mLaunchTaskBehind = false;
ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
"Setting Activity.mLauncherTaskBehind to false. Activity=%s",
prevActivity);
}
} else {
task.mBackGestureStarted = false;
} }
if (prevActivity != null && !triggerBack) { resetSurfaces(windowContainer);
// Restore the launch-behind state.
task.mTaskSupervisor.scheduleLaunchTaskBehindComplete(prevActivity.token);
prevActivity.mLaunchTaskBehind = false;
ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
"Setting Activity.mLauncherTaskBehind to false. Activity=%s",
prevActivity);
}
} else if (task != null) {
task.mBackGestureStarted = false;
} }
resetSurfaces(windowContainer);
if (mFocusObserver != null) { if (mFocusObserver != null) {
focusedWindow.unregisterFocusObserver(mFocusObserver); focusedWindow.unregisterFocusObserver(mFocusObserver);
@@ -465,4 +488,21 @@ class BackNavigationController {
void setWindowManager(WindowManagerService wm) { void setWindowManager(WindowManagerService wm) {
mWindowManagerService = wm; mWindowManagerService = wm;
} }
private void prepareBackToHomeTransition(Task currentTask, Task homeTask) {
final DisplayContent dc = currentTask.getDisplayContent();
final ActivityRecord homeActivity = homeTask.getTopNonFinishingActivity();
if (!homeActivity.mVisibleRequested) {
homeActivity.setVisibility(true);
}
homeActivity.mLaunchTaskBehind = true;
dc.ensureActivitiesVisible(
null /* starting */, 0 /* configChanges */,
false /* preserveWindows */, true);
mBackNaviAnimationController.initialize(homeActivity, currentTask.getTopMostActivity());
}
void finishAnimation() {
mBackNaviAnimationController = null;
}
} }

View File

@@ -847,6 +847,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
if (recentsAnimationController != null) { if (recentsAnimationController != null) {
recentsAnimationController.checkAnimationReady(defaultDisplay.mWallpaperController); recentsAnimationController.checkAnimationReady(defaultDisplay.mWallpaperController);
} }
final BackNaviAnimationController bnac = mWmService.getBackNaviAnimationController();
if (bnac != null) {
bnac.checkAnimationReady(defaultDisplay.mWallpaperController);
}
for (int displayNdx = 0; displayNdx < mChildren.size(); ++displayNdx) { for (int displayNdx = 0; displayNdx < mChildren.size(); ++displayNdx) {
final DisplayContent displayContent = mChildren.get(displayNdx); final DisplayContent displayContent = mChildren.get(displayNdx);

View File

@@ -186,7 +186,7 @@ class WallpaperController {
&& animatingContainer.getAnimation() != null && animatingContainer.getAnimation() != null
&& animatingContainer.getAnimation().getShowWallpaper(); && animatingContainer.getAnimation().getShowWallpaper();
final boolean hasWallpaper = w.hasWallpaper() || animationWallpaper; final boolean hasWallpaper = w.hasWallpaper() || animationWallpaper;
if (isRecentsTransitionTarget(w)) { if (isRecentsTransitionTarget(w) || isBackAnimationTarget(w)) {
if (DEBUG_WALLPAPER) Slog.v(TAG, "Found recents animation wallpaper target: " + w); if (DEBUG_WALLPAPER) Slog.v(TAG, "Found recents animation wallpaper target: " + w);
mFindResults.setWallpaperTarget(w); mFindResults.setWallpaperTarget(w);
return true; return true;
@@ -226,6 +226,13 @@ class WallpaperController {
return controller != null && controller.isWallpaperVisible(w); return controller != null && controller.isWallpaperVisible(w);
} }
private boolean isBackAnimationTarget(WindowState w) {
// The window is either the back activity or is in the task animating by the back gesture.
final BackNaviAnimationController bthController = mService.getBackNaviAnimationController();
return bthController != null && bthController.isWallpaperVisible(w);
}
/** /**
* @see #computeLastWallpaperZoomOut() * @see #computeLastWallpaperZoomOut()
*/ */

View File

@@ -128,12 +128,15 @@ class WallpaperWindowToken extends WindowToken {
if (visible && wallpaperTarget != null) { if (visible && wallpaperTarget != null) {
final RecentsAnimationController recentsAnimationController = final RecentsAnimationController recentsAnimationController =
mWmService.getRecentsAnimationController(); mWmService.getRecentsAnimationController();
final BackNaviAnimationController bac = mWmService.getBackNaviAnimationController();
if (recentsAnimationController != null if (recentsAnimationController != null
&& recentsAnimationController.isAnimatingTask(wallpaperTarget.getTask())) { && recentsAnimationController.isAnimatingTask(wallpaperTarget.getTask())) {
// If the Recents animation is running, and the wallpaper target is the animating // If the Recents animation is running, and the wallpaper target is the animating
// task we want the wallpaper to be rotated in the same orientation as the // task we want the wallpaper to be rotated in the same orientation as the
// RecentsAnimation's target (e.g the launcher) // RecentsAnimation's target (e.g the launcher)
recentsAnimationController.linkFixedRotationTransformIfNeeded(this); recentsAnimationController.linkFixedRotationTransformIfNeeded(this);
} else if (bac != null && bac.isAnimatingTask(wallpaperTarget.getTask())) {
bac.linkFixedRotationTransformIfNeeded(this);
} else if ((wallpaperTarget.mActivityRecord == null } else if ((wallpaperTarget.mActivityRecord == null
// Ignore invisible activity because it may be moving to background. // Ignore invisible activity because it may be moving to background.
|| wallpaperTarget.mActivityRecord.mVisibleRequested) || wallpaperTarget.mActivityRecord.mVisibleRequested)

View File

@@ -9298,4 +9298,9 @@ public class WindowManagerService extends IWindowManager.Stub
"Unexpected letterbox background type: " + letterboxBackgroundType); "Unexpected letterbox background type: " + letterboxBackgroundType);
} }
} }
BackNaviAnimationController getBackNaviAnimationController() {
return mAtmService.mBackNavigationController != null
? mAtmService.mBackNavigationController.mBackNaviAnimationController : null;
}
} }

View File

@@ -80,10 +80,12 @@ public class BackNavigationControllerTests extends WindowTestsBase {
IOnBackInvokedCallback callback = withSystemCallback(task); IOnBackInvokedCallback callback = withSystemCallback(task);
BackNavigationInfo backNavigationInfo = BackNavigationInfo backNavigationInfo =
mBackNavigationController.startBackNavigation(true, null); mBackNavigationController.startBackNavigation(true, null, null);
assertWithMessage("BackNavigationInfo").that(backNavigationInfo).isNotNull(); assertWithMessage("BackNavigationInfo").that(backNavigationInfo).isNotNull();
assertThat(backNavigationInfo.getDepartingAnimationTarget()).isNotNull(); if (!BackNavigationController.USE_TRANSITION) {
assertThat(backNavigationInfo.getTaskWindowConfiguration()).isNotNull(); assertThat(backNavigationInfo.getDepartingAnimationTarget()).isNotNull();
assertThat(backNavigationInfo.getTaskWindowConfiguration()).isNotNull();
}
assertThat(backNavigationInfo.getOnBackInvokedCallback()).isEqualTo(callback); assertThat(backNavigationInfo.getOnBackInvokedCallback()).isEqualTo(callback);
assertThat(typeToString(backNavigationInfo.getType())) assertThat(typeToString(backNavigationInfo.getType()))
.isEqualTo(typeToString(BackNavigationInfo.TYPE_RETURN_TO_HOME)); .isEqualTo(typeToString(BackNavigationInfo.TYPE_RETURN_TO_HOME));
@@ -233,7 +235,7 @@ public class BackNavigationControllerTests extends WindowTestsBase {
@Nullable @Nullable
private BackNavigationInfo startBackNavigation() { private BackNavigationInfo startBackNavigation() {
return mBackNavigationController.startBackNavigation(true, null); return mBackNavigationController.startBackNavigation(true, null, null);
} }
@NonNull @NonNull