[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:
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
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
|
@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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
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 {
|
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();
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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.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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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()
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user