Merge "[RESTRICT AUTOMERGE]BackGestureAnimation: a lightweight recents animation controller" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
4ec0b52029
@@ -72,6 +72,7 @@ import android.view.IRemoteAnimationRunner;
|
||||
import android.view.IWindowFocusObserver;
|
||||
import android.view.RemoteAnimationDefinition;
|
||||
import android.view.RemoteAnimationAdapter;
|
||||
import android.window.BackAnimationAdaptor;
|
||||
import android.window.IWindowOrganizerController;
|
||||
import android.window.BackNavigationInfo;
|
||||
import android.window.SplashScreenView;
|
||||
@@ -356,5 +357,5 @@ interface IActivityTaskManager {
|
||||
* @param focusObserver a remote callback to nofify shell when the focused window lost focus.
|
||||
*/
|
||||
android.window.BackNavigationInfo startBackNavigation(in boolean requestAnimation,
|
||||
in IWindowFocusObserver focusObserver);
|
||||
in IWindowFocusObserver focusObserver, in BackAnimationAdaptor adaptor);
|
||||
}
|
||||
|
||||
22
core/java/android/window/BackAnimationAdaptor.aidl
Normal file
22
core/java/android/window/BackAnimationAdaptor.aidl
Normal 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;
|
||||
72
core/java/android/window/BackAnimationAdaptor.java
Normal file
72
core/java/android/window/BackAnimationAdaptor.java
Normal 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];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -101,6 +101,8 @@ public final class BackNavigationInfo implements Parcelable {
|
||||
@Nullable
|
||||
private final IOnBackInvokedCallback mOnBackInvokedCallback;
|
||||
|
||||
private final boolean mIsPrepareRemoteAnimation;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* back preview.
|
||||
* @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,
|
||||
@Nullable RemoteAnimationTarget departingAnimationTarget,
|
||||
@@ -124,7 +129,8 @@ public final class BackNavigationInfo implements Parcelable {
|
||||
@Nullable HardwareBuffer screenshotBuffer,
|
||||
@Nullable WindowConfiguration taskWindowConfiguration,
|
||||
@Nullable RemoteCallback onBackNavigationDone,
|
||||
@Nullable IOnBackInvokedCallback onBackInvokedCallback) {
|
||||
@Nullable IOnBackInvokedCallback onBackInvokedCallback,
|
||||
boolean isPrepareRemoteAnimation) {
|
||||
mType = type;
|
||||
mDepartingAnimationTarget = departingAnimationTarget;
|
||||
mScreenshotSurface = screenshotSurface;
|
||||
@@ -132,6 +138,7 @@ public final class BackNavigationInfo implements Parcelable {
|
||||
mTaskWindowConfiguration = taskWindowConfiguration;
|
||||
mOnBackNavigationDone = onBackNavigationDone;
|
||||
mOnBackInvokedCallback = onBackInvokedCallback;
|
||||
mIsPrepareRemoteAnimation = isPrepareRemoteAnimation;
|
||||
}
|
||||
|
||||
private BackNavigationInfo(@NonNull Parcel in) {
|
||||
@@ -142,6 +149,7 @@ public final class BackNavigationInfo implements Parcelable {
|
||||
mTaskWindowConfiguration = in.readTypedObject(WindowConfiguration.CREATOR);
|
||||
mOnBackNavigationDone = in.readTypedObject(RemoteCallback.CREATOR);
|
||||
mOnBackInvokedCallback = IOnBackInvokedCallback.Stub.asInterface(in.readStrongBinder());
|
||||
mIsPrepareRemoteAnimation = in.readBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -153,6 +161,7 @@ public final class BackNavigationInfo implements Parcelable {
|
||||
dest.writeTypedObject(mTaskWindowConfiguration, flags);
|
||||
dest.writeTypedObject(mOnBackNavigationDone, flags);
|
||||
dest.writeStrongInterface(mOnBackInvokedCallback);
|
||||
dest.writeBoolean(mIsPrepareRemoteAnimation);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -221,6 +230,10 @@ public final class BackNavigationInfo implements Parcelable {
|
||||
return mOnBackInvokedCallback;
|
||||
}
|
||||
|
||||
public boolean isPrepareRemoteAnimation() {
|
||||
return mIsPrepareRemoteAnimation;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@@ -306,6 +319,8 @@ public final class BackNavigationInfo implements Parcelable {
|
||||
@Nullable
|
||||
private IOnBackInvokedCallback mOnBackInvokedCallback = null;
|
||||
|
||||
private boolean mPrepareAnimation;
|
||||
|
||||
/**
|
||||
* @see BackNavigationInfo#getType()
|
||||
*/
|
||||
@@ -365,13 +380,21 @@ public final class BackNavigationInfo implements Parcelable {
|
||||
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}
|
||||
*/
|
||||
public BackNavigationInfo build() {
|
||||
return new BackNavigationInfo(mType, mDepartingAnimationTarget, mScreenshotSurface,
|
||||
mScreenshotBuffer, mTaskWindowConfiguration, mOnBackNavigationDone,
|
||||
mOnBackInvokedCallback);
|
||||
mOnBackInvokedCallback, mPrepareAnimation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
45
core/java/android/window/IBackAnimationRunner.aidl
Normal file
45
core/java/android/window/IBackAnimationRunner.aidl
Normal 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;
|
||||
}
|
||||
27
core/java/android/window/IBackNaviAnimationController.aidl
Normal file
27
core/java/android/window/IBackNaviAnimationController.aidl
Normal 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);
|
||||
}
|
||||
@@ -92,7 +92,7 @@ public class BackNavigationTest {
|
||||
try {
|
||||
mInstrumentation.getUiAutomation().waitForIdle(500, 1000);
|
||||
BackNavigationInfo info = ActivityTaskManager.getService()
|
||||
.startBackNavigation(true, null);
|
||||
.startBackNavigation(true, null, null);
|
||||
assertNotNull("BackNavigationInfo is null", info);
|
||||
assertNotNull("OnBackInvokedCallback is null", info.getOnBackInvokedCallback());
|
||||
info.getOnBackInvokedCallback().onBackInvoked();
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
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.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW;
|
||||
|
||||
@@ -27,8 +30,6 @@ import android.app.WindowConfiguration;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.database.ContentObserver;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.PointF;
|
||||
import android.hardware.HardwareBuffer;
|
||||
import android.hardware.input.InputManager;
|
||||
import android.net.Uri;
|
||||
@@ -47,8 +48,11 @@ import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.RemoteAnimationTarget;
|
||||
import android.view.SurfaceControl;
|
||||
import android.window.BackAnimationAdaptor;
|
||||
import android.window.BackEvent;
|
||||
import android.window.BackNavigationInfo;
|
||||
import android.window.IBackAnimationRunner;
|
||||
import android.window.IBackNaviAnimationController;
|
||||
import android.window.IOnBackInvokedCallback;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
@@ -76,22 +80,15 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
|
||||
private static final int PROGRESS_THRESHOLD = SystemProperties
|
||||
.getInt(PREDICTIVE_BACK_PROGRESS_THRESHOLD_PROP, -1);
|
||||
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
|
||||
* request.
|
||||
*/
|
||||
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 */
|
||||
private boolean mBackGestureStarted = false;
|
||||
|
||||
@@ -119,6 +116,15 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
|
||||
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
|
||||
final IWindowFocusObserver mFocusObserver = new IWindowFocusObserver.Stub() {
|
||||
@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(
|
||||
@NonNull ShellInit shellInit,
|
||||
@NonNull @ShellMainThread ShellExecutor shellExecutor,
|
||||
@@ -272,6 +364,9 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
|
||||
@VisibleForTesting
|
||||
void setBackToLauncherCallback(IOnBackInvokedCallback callback) {
|
||||
mBackToLauncherCallback = callback;
|
||||
if (USE_TRANSITION) {
|
||||
createAdaptor();
|
||||
}
|
||||
}
|
||||
|
||||
private void clearBackToLauncherCallback() {
|
||||
@@ -280,15 +375,18 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
|
||||
|
||||
@VisibleForTesting
|
||||
void onBackToLauncherAnimationFinished() {
|
||||
if (mBackNavigationInfo != null) {
|
||||
IOnBackInvokedCallback callback = mBackNavigationInfo.getOnBackInvokedCallback();
|
||||
if (mTriggerBack) {
|
||||
final boolean triggerBack = mTriggerBack;
|
||||
IOnBackInvokedCallback callback = mBackNavigationInfo != null
|
||||
? mBackNavigationInfo.getOnBackInvokedCallback() : null;
|
||||
// Make sure the notification sequence should be controller > client.
|
||||
finishAnimation();
|
||||
if (callback != null) {
|
||||
if (triggerBack) {
|
||||
dispatchOnBackInvoked(callback);
|
||||
} else {
|
||||
dispatchOnBackCancelled(callback);
|
||||
}
|
||||
}
|
||||
finishAnimation();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -300,6 +398,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
|
||||
if (mTransitionInProgress) {
|
||||
return;
|
||||
}
|
||||
|
||||
mTouchTracker.update(touchX, touchY, swipeEdge);
|
||||
if (keyAction == MotionEvent.ACTION_DOWN) {
|
||||
if (!mBackGestureStarted) {
|
||||
mShouldStartOnNextMoveEvent = true;
|
||||
@@ -330,13 +430,13 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
|
||||
finishAnimation();
|
||||
}
|
||||
|
||||
mInitTouchLocation.set(touchX, touchY);
|
||||
mTouchTracker.setGestureStartLocation(touchX, touchY);
|
||||
mBackGestureStarted = true;
|
||||
|
||||
try {
|
||||
boolean requestAnimation = mEnableAnimations.get();
|
||||
mBackNavigationInfo =
|
||||
mActivityTaskManager.startBackNavigation(requestAnimation, mFocusObserver);
|
||||
mBackNavigationInfo = mActivityTaskManager.startBackNavigation(requestAnimation,
|
||||
mFocusObserver, mBackAnimationAdaptor);
|
||||
onBackNavigationInfoReceived(mBackNavigationInfo);
|
||||
} catch (RemoteException remoteException) {
|
||||
Log.e(TAG, "Failed to initAnimation", remoteException);
|
||||
@@ -352,6 +452,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
|
||||
}
|
||||
int backType = backNavigationInfo.getType();
|
||||
IOnBackInvokedCallback targetCallback = null;
|
||||
final boolean dispatchToLauncher = shouldDispatchToLauncher(backType);
|
||||
if (backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY) {
|
||||
HardwareBuffer hardwareBuffer = backNavigationInfo.getScreenshotHardwareBuffer();
|
||||
if (hardwareBuffer != null) {
|
||||
@@ -359,12 +460,17 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
|
||||
backNavigationInfo.getTaskWindowConfiguration());
|
||||
}
|
||||
mTransaction.apply();
|
||||
} else if (shouldDispatchToLauncher(backType)) {
|
||||
} else if (dispatchToLauncher) {
|
||||
targetCallback = mBackToLauncherCallback;
|
||||
if (USE_TRANSITION) {
|
||||
mCachingBackDispatcher.startWaitingAnimation();
|
||||
}
|
||||
} else if (backType == BackNavigationInfo.TYPE_CALLBACK) {
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
int deltaX = Math.round(touchX - mInitTouchLocation.x);
|
||||
int deltaX = mTouchTracker.getDeltaFromGestureStart(touchX);
|
||||
float progressThreshold = PROGRESS_THRESHOLD >= 0 ? PROGRESS_THRESHOLD : mProgressThreshold;
|
||||
float progress = Math.min(Math.max(Math.abs(deltaX) / progressThreshold, 0), 1);
|
||||
int backType = mBackNavigationInfo.getType();
|
||||
RemoteAnimationTarget animationTarget = mBackNavigationInfo.getDepartingAnimationTarget();
|
||||
if (USE_TRANSITION) {
|
||||
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(
|
||||
touchX, touchY, progress, swipeEdge, animationTarget);
|
||||
IOnBackInvokedCallback targetCallback = null;
|
||||
if (shouldDispatchToLauncher(backType)) {
|
||||
targetCallback = mBackToLauncherCallback;
|
||||
} else if (backType == BackNavigationInfo.TYPE_CROSS_TASK
|
||||
|| backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY) {
|
||||
// TODO(208427216) Run the actual animation
|
||||
} else if (backType == BackNavigationInfo.TYPE_CALLBACK) {
|
||||
targetCallback = mBackNavigationInfo.getOnBackInvokedCallback();
|
||||
BackEvent backEvent = new BackEvent(
|
||||
touchX, touchY, progress, swipeEdge, animationTarget);
|
||||
IOnBackInvokedCallback targetCallback = null;
|
||||
if (shouldDispatchToLauncher(backType)) {
|
||||
targetCallback = mBackToLauncherCallback;
|
||||
} else if (backType == BackNavigationInfo.TYPE_CROSS_TASK
|
||||
|| backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY) {
|
||||
// TODO(208427216) Run the actual animation
|
||||
} else if (backType == BackNavigationInfo.TYPE_CALLBACK) {
|
||||
targetCallback = mBackNavigationInfo.getOnBackInvokedCallback();
|
||||
}
|
||||
dispatchOnBackProgressed(targetCallback, backEvent);
|
||||
}
|
||||
dispatchOnBackProgressed(targetCallback, backEvent);
|
||||
}
|
||||
|
||||
private void injectBackKey() {
|
||||
@@ -474,6 +589,9 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
|
||||
IOnBackInvokedCallback targetCallback = shouldDispatchToLauncher
|
||||
? mBackToLauncherCallback
|
||||
: mBackNavigationInfo.getOnBackInvokedCallback();
|
||||
if (mCachingBackDispatcher.set(targetCallback, mTriggerBack)) {
|
||||
return;
|
||||
}
|
||||
if (shouldDispatchToLauncher) {
|
||||
startTransition();
|
||||
}
|
||||
@@ -493,7 +611,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
|
||||
&& mBackToLauncherCallback != null
|
||||
&& mEnableAnimations.get()
|
||||
&& mBackNavigationInfo != null
|
||||
&& mBackNavigationInfo.getDepartingAnimationTarget() != null;
|
||||
&& ((USE_TRANSITION && mBackNavigationInfo.isPrepareRemoteAnimation())
|
||||
|| mBackNavigationInfo.getDepartingAnimationTarget() != null);
|
||||
}
|
||||
|
||||
private static void dispatchOnBackStarted(IOnBackInvokedCallback callback) {
|
||||
@@ -558,8 +677,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
|
||||
|
||||
private void finishAnimation() {
|
||||
ProtoLog.d(WM_SHELL_BACK_PREVIEW, "BackAnimationController: finishAnimation()");
|
||||
mTouchEventDelta.set(0, 0);
|
||||
mInitTouchLocation.set(0, 0);
|
||||
mTouchTracker.reset();
|
||||
BackNavigationInfo backNavigationInfo = mBackNavigationInfo;
|
||||
boolean triggerBack = mTriggerBack;
|
||||
mBackNavigationInfo = null;
|
||||
@@ -569,19 +687,33 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
|
||||
return;
|
||||
}
|
||||
|
||||
RemoteAnimationTarget animationTarget = backNavigationInfo.getDepartingAnimationTarget();
|
||||
if (animationTarget != null) {
|
||||
if (animationTarget.leash != null && animationTarget.leash.isValid()) {
|
||||
mTransaction.remove(animationTarget.leash);
|
||||
if (!USE_TRANSITION) {
|
||||
RemoteAnimationTarget animationTarget = backNavigationInfo
|
||||
.getDepartingAnimationTarget();
|
||||
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();
|
||||
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() {
|
||||
@@ -599,4 +731,50 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
|
||||
mShellExecutor.removeCallbacks(mResetTransitionRunnable);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,9 +48,10 @@ public class TestShellExecutor implements ShellExecutor {
|
||||
}
|
||||
|
||||
public void flushAll() {
|
||||
for (Runnable r : mRunnables) {
|
||||
final ArrayList<Runnable> tmpRunnable = new ArrayList<>(mRunnables);
|
||||
mRunnables.clear();
|
||||
for (Runnable r : tmpRunnable) {
|
||||
r.run();
|
||||
}
|
||||
mRunnables.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ import android.view.RemoteAnimationTarget;
|
||||
import android.view.SurfaceControl;
|
||||
import android.window.BackEvent;
|
||||
import android.window.BackNavigationInfo;
|
||||
import android.window.IBackNaviAnimationController;
|
||||
import android.window.IOnBackInvokedCallback;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
@@ -98,6 +99,9 @@ public class BackAnimationControllerTest extends ShellTestCase {
|
||||
@Mock
|
||||
private IOnBackInvokedCallback mIOnBackInvokedCallback;
|
||||
|
||||
@Mock
|
||||
private IBackNaviAnimationController mIBackNaviAnimationController;
|
||||
|
||||
private BackAnimationController mController;
|
||||
|
||||
private int mEventTime = 0;
|
||||
@@ -127,7 +131,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
|
||||
SurfaceControl screenshotSurface,
|
||||
HardwareBuffer hardwareBuffer,
|
||||
int backType,
|
||||
IOnBackInvokedCallback onBackInvokedCallback) {
|
||||
IOnBackInvokedCallback onBackInvokedCallback, boolean prepareAnimation) {
|
||||
BackNavigationInfo.Builder builder = new BackNavigationInfo.Builder()
|
||||
.setType(backType)
|
||||
.setDepartingAnimationTarget(topAnimationTarget)
|
||||
@@ -135,7 +139,8 @@ public class BackAnimationControllerTest extends ShellTestCase {
|
||||
.setScreenshotBuffer(hardwareBuffer)
|
||||
.setTaskWindowConfiguration(new WindowConfiguration())
|
||||
.setOnBackNavigationDone(new RemoteCallback((bundle) -> {}))
|
||||
.setOnBackInvokedCallback(onBackInvokedCallback);
|
||||
.setOnBackInvokedCallback(onBackInvokedCallback)
|
||||
.setPrepareAnimation(prepareAnimation);
|
||||
|
||||
createNavigationInfo(builder);
|
||||
}
|
||||
@@ -143,7 +148,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
|
||||
private void createNavigationInfo(BackNavigationInfo.Builder builder) {
|
||||
try {
|
||||
doReturn(builder.build()).when(mActivityTaskManager)
|
||||
.startBackNavigation(anyBoolean(), any());
|
||||
.startBackNavigation(anyBoolean(), any(), any());
|
||||
} catch (RemoteException ex) {
|
||||
ex.rethrowFromSystemServer();
|
||||
}
|
||||
@@ -175,7 +180,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
|
||||
SurfaceControl screenshotSurface = new SurfaceControl();
|
||||
HardwareBuffer hardwareBuffer = mock(HardwareBuffer.class);
|
||||
createNavigationInfo(createAnimationTarget(), screenshotSurface, hardwareBuffer,
|
||||
BackNavigationInfo.TYPE_CROSS_ACTIVITY, null);
|
||||
BackNavigationInfo.TYPE_CROSS_ACTIVITY, null, true);
|
||||
doMotionEvent(MotionEvent.ACTION_DOWN, 0);
|
||||
verify(mTransaction).setBuffer(screenshotSurface, hardwareBuffer);
|
||||
verify(mTransaction).setVisibility(screenshotSurface, true);
|
||||
@@ -188,7 +193,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
|
||||
HardwareBuffer hardwareBuffer = mock(HardwareBuffer.class);
|
||||
RemoteAnimationTarget animationTarget = createAnimationTarget();
|
||||
createNavigationInfo(animationTarget, screenshotSurface, hardwareBuffer,
|
||||
BackNavigationInfo.TYPE_CROSS_ACTIVITY, null);
|
||||
BackNavigationInfo.TYPE_CROSS_ACTIVITY, null, true);
|
||||
doMotionEvent(MotionEvent.ACTION_DOWN, 0);
|
||||
doMotionEvent(MotionEvent.ACTION_MOVE, 100);
|
||||
// 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);
|
||||
RemoteAnimationTarget animationTarget = createAnimationTarget();
|
||||
createNavigationInfo(animationTarget, null, null,
|
||||
BackNavigationInfo.TYPE_RETURN_TO_HOME, null);
|
||||
BackNavigationInfo.TYPE_RETURN_TO_HOME, null, true);
|
||||
|
||||
doMotionEvent(MotionEvent.ACTION_DOWN, 0);
|
||||
|
||||
// Check that back start and progress is dispatched when first move.
|
||||
doMotionEvent(MotionEvent.ACTION_MOVE, 100);
|
||||
simulateRemoteAnimationStart(BackNavigationInfo.TYPE_RETURN_TO_HOME, animationTarget);
|
||||
verify(mIOnBackInvokedCallback).onBackStarted();
|
||||
ArgumentCaptor<BackEvent> backEventCaptor = ArgumentCaptor.forClass(BackEvent.class);
|
||||
verify(mIOnBackInvokedCallback).onBackProgressed(backEventCaptor.capture());
|
||||
verify(mIOnBackInvokedCallback, atLeastOnce()).onBackProgressed(backEventCaptor.capture());
|
||||
assertEquals(animationTarget, backEventCaptor.getValue().getDepartingAnimationTarget());
|
||||
|
||||
// Check that back invocation is dispatched.
|
||||
@@ -255,7 +261,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
|
||||
IOnBackInvokedCallback appCallback = mock(IOnBackInvokedCallback.class);
|
||||
ArgumentCaptor<BackEvent> backEventCaptor = ArgumentCaptor.forClass(BackEvent.class);
|
||||
createNavigationInfo(animationTarget, null, null,
|
||||
BackNavigationInfo.TYPE_RETURN_TO_HOME, appCallback);
|
||||
BackNavigationInfo.TYPE_RETURN_TO_HOME, appCallback, false);
|
||||
|
||||
triggerBackGesture();
|
||||
|
||||
@@ -273,9 +279,10 @@ public class BackAnimationControllerTest extends ShellTestCase {
|
||||
mController.setBackToLauncherCallback(mIOnBackInvokedCallback);
|
||||
RemoteAnimationTarget animationTarget = createAnimationTarget();
|
||||
createNavigationInfo(animationTarget, null, null,
|
||||
BackNavigationInfo.TYPE_RETURN_TO_HOME, null);
|
||||
BackNavigationInfo.TYPE_RETURN_TO_HOME, null, true);
|
||||
|
||||
triggerBackGesture();
|
||||
simulateRemoteAnimationStart(BackNavigationInfo.TYPE_RETURN_TO_HOME, animationTarget);
|
||||
// Check that back invocation is dispatched.
|
||||
verify(mIOnBackInvokedCallback).onBackInvoked();
|
||||
|
||||
@@ -294,6 +301,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
|
||||
// Verify that we start accepting gestures again once transition finishes.
|
||||
doMotionEvent(MotionEvent.ACTION_DOWN, 0);
|
||||
doMotionEvent(MotionEvent.ACTION_MOVE, 100);
|
||||
simulateRemoteAnimationStart(BackNavigationInfo.TYPE_RETURN_TO_HOME, animationTarget);
|
||||
verify(mIOnBackInvokedCallback).onBackStarted();
|
||||
}
|
||||
|
||||
@@ -302,15 +310,17 @@ public class BackAnimationControllerTest extends ShellTestCase {
|
||||
mController.setBackToLauncherCallback(mIOnBackInvokedCallback);
|
||||
RemoteAnimationTarget animationTarget = createAnimationTarget();
|
||||
createNavigationInfo(animationTarget, null, null,
|
||||
BackNavigationInfo.TYPE_RETURN_TO_HOME, null);
|
||||
BackNavigationInfo.TYPE_RETURN_TO_HOME, null, true);
|
||||
|
||||
triggerBackGesture();
|
||||
simulateRemoteAnimationStart(BackNavigationInfo.TYPE_RETURN_TO_HOME, animationTarget);
|
||||
reset(mIOnBackInvokedCallback);
|
||||
|
||||
// Simulate transition timeout.
|
||||
mShellExecutor.flushAll();
|
||||
doMotionEvent(MotionEvent.ACTION_DOWN, 0);
|
||||
doMotionEvent(MotionEvent.ACTION_MOVE, 100);
|
||||
simulateRemoteAnimationStart(BackNavigationInfo.TYPE_RETURN_TO_HOME, animationTarget);
|
||||
verify(mIOnBackInvokedCallback).onBackStarted();
|
||||
}
|
||||
|
||||
@@ -321,11 +331,12 @@ public class BackAnimationControllerTest extends ShellTestCase {
|
||||
RemoteAnimationTarget animationTarget = createAnimationTarget();
|
||||
|
||||
createNavigationInfo(animationTarget, null, null,
|
||||
BackNavigationInfo.TYPE_RETURN_TO_HOME, null);
|
||||
BackNavigationInfo.TYPE_RETURN_TO_HOME, null, true);
|
||||
|
||||
doMotionEvent(MotionEvent.ACTION_DOWN, 0);
|
||||
// Check that back start and progress is dispatched when first move.
|
||||
doMotionEvent(MotionEvent.ACTION_MOVE, 100);
|
||||
simulateRemoteAnimationStart(BackNavigationInfo.TYPE_RETURN_TO_HOME, animationTarget);
|
||||
verify(mIOnBackInvokedCallback).onBackStarted();
|
||||
|
||||
// Check that back invocation is dispatched.
|
||||
@@ -349,4 +360,14 @@ public class BackAnimationControllerTest extends ShellTestCase {
|
||||
BackEvent.EDGE_LEFT);
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,6 +226,7 @@ import android.view.IWindowFocusObserver;
|
||||
import android.view.RemoteAnimationAdapter;
|
||||
import android.view.RemoteAnimationDefinition;
|
||||
import android.view.WindowManager;
|
||||
import android.window.BackAnimationAdaptor;
|
||||
import android.window.BackNavigationInfo;
|
||||
import android.window.IWindowOrganizerController;
|
||||
import android.window.SplashScreenView.SplashScreenViewParcelable;
|
||||
@@ -457,7 +458,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
|
||||
private final ClientLifecycleManager mLifecycleManager;
|
||||
|
||||
@Nullable
|
||||
private final BackNavigationController mBackNavigationController;
|
||||
final BackNavigationController mBackNavigationController;
|
||||
|
||||
private TaskChangeNotificationController mTaskChangeNotificationController;
|
||||
/** The controller for all operations related to locktask. */
|
||||
@@ -1836,13 +1837,14 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
|
||||
|
||||
@Override
|
||||
public BackNavigationInfo startBackNavigation(boolean requestAnimation,
|
||||
IWindowFocusObserver observer) {
|
||||
IWindowFocusObserver observer, BackAnimationAdaptor backAnimationAdaptor) {
|
||||
mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS,
|
||||
"startBackNavigation()");
|
||||
if (mBackNavigationController == null) {
|
||||
return null;
|
||||
}
|
||||
return mBackNavigationController.startBackNavigation(requestAnimation, observer);
|
||||
return mBackNavigationController.startBackNavigation(
|
||||
requestAnimation, observer, backAnimationAdaptor);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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) { }
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,7 @@ import android.util.Slog;
|
||||
import android.view.IWindowFocusObserver;
|
||||
import android.view.RemoteAnimationTarget;
|
||||
import android.view.SurfaceControl;
|
||||
import android.window.BackAnimationAdaptor;
|
||||
import android.window.BackNavigationInfo;
|
||||
import android.window.OnBackInvokedCallbackInfo;
|
||||
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.
|
||||
*/
|
||||
class BackNavigationController {
|
||||
private static final String TAG = "BackNavigationController";
|
||||
private WindowManagerService mWindowManagerService;
|
||||
static final String TAG = "BackNavigationController";
|
||||
WindowManagerService mWindowManagerService;
|
||||
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
|
||||
@@ -72,7 +79,7 @@ class BackNavigationController {
|
||||
@VisibleForTesting
|
||||
@Nullable
|
||||
BackNavigationInfo startBackNavigation(boolean requestAnimation,
|
||||
IWindowFocusObserver observer) {
|
||||
IWindowFocusObserver observer, BackAnimationAdaptor backAnimationAdaptor) {
|
||||
final WindowManagerService wmService = mWindowManagerService;
|
||||
final SurfaceControl.Transaction tx = wmService.mTransactionFactory.get();
|
||||
mFocusObserver = observer;
|
||||
@@ -259,6 +266,8 @@ class BackNavigationController {
|
||||
&& requestAnimation
|
||||
// Only create a new leash if no leash has been created.
|
||||
// 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();
|
||||
|
||||
if (prepareAnimation) {
|
||||
@@ -266,19 +275,21 @@ class BackNavigationController {
|
||||
currentTask.getTaskInfo().configuration.windowConfiguration;
|
||||
|
||||
infoBuilder.setTaskWindowConfiguration(taskWindowConfiguration);
|
||||
// Prepare a leash to animate the current top window
|
||||
// TODO(b/220934562): Use surface animator to better manage animation conflicts.
|
||||
SurfaceControl animLeash = removedWindowContainer.makeAnimationLeash()
|
||||
.setName("BackPreview Leash for " + removedWindowContainer)
|
||||
.setHidden(false)
|
||||
.setBLASTLayer()
|
||||
.build();
|
||||
removedWindowContainer.reparentSurfaceControl(tx, animLeash);
|
||||
animationLeashParent = removedWindowContainer.getAnimationLeashParent();
|
||||
topAppTarget = createRemoteAnimationTargetLocked(removedWindowContainer,
|
||||
currentActivity,
|
||||
currentTask, animLeash);
|
||||
infoBuilder.setDepartingAnimationTarget(topAppTarget);
|
||||
if (!USE_TRANSITION) {
|
||||
// Prepare a leash to animate the current top window
|
||||
// TODO(b/220934562): Use surface animator to better manage animation conflicts.
|
||||
SurfaceControl animLeash = removedWindowContainer.makeAnimationLeash()
|
||||
.setName("BackPreview Leash for " + removedWindowContainer)
|
||||
.setHidden(false)
|
||||
.setBLASTLayer()
|
||||
.build();
|
||||
removedWindowContainer.reparentSurfaceControl(tx, animLeash);
|
||||
animationLeashParent = removedWindowContainer.getAnimationLeashParent();
|
||||
topAppTarget = createRemoteAnimationTargetLocked(removedWindowContainer,
|
||||
currentActivity,
|
||||
currentTask, animLeash);
|
||||
infoBuilder.setDepartingAnimationTarget(topAppTarget);
|
||||
}
|
||||
}
|
||||
|
||||
//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
|
||||
if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && prepareAnimation
|
||||
&& prevTask != null) {
|
||||
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);
|
||||
if (USE_TRANSITION && mBackNaviAnimationController == null) {
|
||||
if (backAnimationAdaptor != null
|
||||
&& backAnimationAdaptor.getSupportType() == backType) {
|
||||
mBackNaviAnimationController = new BackNaviAnimationController(
|
||||
backAnimationAdaptor.getRunner(), this,
|
||||
currentActivity.getDisplayId());
|
||||
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
|
||||
@@ -388,29 +410,30 @@ class BackNavigationController {
|
||||
BackNavigationInfo.KEY_TRIGGER_BACK);
|
||||
ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "onBackNavigationDone backType=%s, "
|
||||
+ "task=%s, prevActivity=%s", backType, task, prevActivity);
|
||||
|
||||
if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && prepareAnimation) {
|
||||
if (triggerBack) {
|
||||
if (surfaceControl != null && surfaceControl.isValid()) {
|
||||
// When going back to home, hide the task surface before it is re-parented to
|
||||
// avoid flicker.
|
||||
SurfaceControl.Transaction t = windowContainer.getSyncTransaction();
|
||||
t.hide(surfaceControl);
|
||||
t.apply();
|
||||
if (!USE_TRANSITION) {
|
||||
if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && prepareAnimation) {
|
||||
if (triggerBack) {
|
||||
if (surfaceControl != null && surfaceControl.isValid()) {
|
||||
// When going back to home, hide the task surface before it is re-parented
|
||||
// to avoid flicker.
|
||||
SurfaceControl.Transaction t = windowContainer.getSyncTransaction();
|
||||
t.hide(surfaceControl);
|
||||
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) {
|
||||
// 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);
|
||||
}
|
||||
resetSurfaces(windowContainer);
|
||||
|
||||
if (mFocusObserver != null) {
|
||||
focusedWindow.unregisterFocusObserver(mFocusObserver);
|
||||
@@ -465,4 +488,21 @@ class BackNavigationController {
|
||||
void setWindowManager(WindowManagerService 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -847,6 +847,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
|
||||
if (recentsAnimationController != null) {
|
||||
recentsAnimationController.checkAnimationReady(defaultDisplay.mWallpaperController);
|
||||
}
|
||||
final BackNaviAnimationController bnac = mWmService.getBackNaviAnimationController();
|
||||
if (bnac != null) {
|
||||
bnac.checkAnimationReady(defaultDisplay.mWallpaperController);
|
||||
}
|
||||
|
||||
for (int displayNdx = 0; displayNdx < mChildren.size(); ++displayNdx) {
|
||||
final DisplayContent displayContent = mChildren.get(displayNdx);
|
||||
|
||||
@@ -186,7 +186,7 @@ class WallpaperController {
|
||||
&& animatingContainer.getAnimation() != null
|
||||
&& animatingContainer.getAnimation().getShowWallpaper();
|
||||
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);
|
||||
mFindResults.setWallpaperTarget(w);
|
||||
return true;
|
||||
@@ -226,6 +226,13 @@ class WallpaperController {
|
||||
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()
|
||||
*/
|
||||
|
||||
@@ -128,12 +128,15 @@ class WallpaperWindowToken extends WindowToken {
|
||||
if (visible && wallpaperTarget != null) {
|
||||
final RecentsAnimationController recentsAnimationController =
|
||||
mWmService.getRecentsAnimationController();
|
||||
final BackNaviAnimationController bac = mWmService.getBackNaviAnimationController();
|
||||
if (recentsAnimationController != null
|
||||
&& recentsAnimationController.isAnimatingTask(wallpaperTarget.getTask())) {
|
||||
// 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
|
||||
// RecentsAnimation's target (e.g the launcher)
|
||||
recentsAnimationController.linkFixedRotationTransformIfNeeded(this);
|
||||
} else if (bac != null && bac.isAnimatingTask(wallpaperTarget.getTask())) {
|
||||
bac.linkFixedRotationTransformIfNeeded(this);
|
||||
} else if ((wallpaperTarget.mActivityRecord == null
|
||||
// Ignore invisible activity because it may be moving to background.
|
||||
|| wallpaperTarget.mActivityRecord.mVisibleRequested)
|
||||
|
||||
@@ -9280,4 +9280,9 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
"Unexpected letterbox background type: " + letterboxBackgroundType);
|
||||
}
|
||||
}
|
||||
|
||||
BackNaviAnimationController getBackNaviAnimationController() {
|
||||
return mAtmService.mBackNavigationController != null
|
||||
? mAtmService.mBackNavigationController.mBackNaviAnimationController : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,10 +80,12 @@ public class BackNavigationControllerTests extends WindowTestsBase {
|
||||
IOnBackInvokedCallback callback = withSystemCallback(task);
|
||||
|
||||
BackNavigationInfo backNavigationInfo =
|
||||
mBackNavigationController.startBackNavigation(true, null);
|
||||
mBackNavigationController.startBackNavigation(true, null, null);
|
||||
assertWithMessage("BackNavigationInfo").that(backNavigationInfo).isNotNull();
|
||||
assertThat(backNavigationInfo.getDepartingAnimationTarget()).isNotNull();
|
||||
assertThat(backNavigationInfo.getTaskWindowConfiguration()).isNotNull();
|
||||
if (!BackNavigationController.USE_TRANSITION) {
|
||||
assertThat(backNavigationInfo.getDepartingAnimationTarget()).isNotNull();
|
||||
assertThat(backNavigationInfo.getTaskWindowConfiguration()).isNotNull();
|
||||
}
|
||||
assertThat(backNavigationInfo.getOnBackInvokedCallback()).isEqualTo(callback);
|
||||
assertThat(typeToString(backNavigationInfo.getType()))
|
||||
.isEqualTo(typeToString(BackNavigationInfo.TYPE_RETURN_TO_HOME));
|
||||
@@ -233,7 +235,7 @@ public class BackNavigationControllerTests extends WindowTestsBase {
|
||||
|
||||
@Nullable
|
||||
private BackNavigationInfo startBackNavigation() {
|
||||
return mBackNavigationController.startBackNavigation(true, null);
|
||||
return mBackNavigationController.startBackNavigation(true, null, null);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
||||
Reference in New Issue
Block a user