summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/wm/AppTransitionController.java2
-rw-r--r--services/core/java/com/android/server/wm/BackNavigationController.java217
-rw-r--r--services/core/java/com/android/server/wm/Transition.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java18
4 files changed, 134 insertions, 111 deletions
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 01a5115d8311..597c8bf45132 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -258,7 +258,7 @@ public class AppTransitionController {
tmpCloseApps = new ArraySet<>(mDisplayContent.mClosingApps);
if (mDisplayContent.mAtmService.mBackNavigationController
.removeIfContainsBackAnimationTargets(tmpOpenApps, tmpCloseApps)) {
- mDisplayContent.mAtmService.mBackNavigationController.clearBackAnimations(null);
+ mDisplayContent.mAtmService.mBackNavigationController.clearBackAnimations();
}
}
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index 0d1f2ce8d63f..587e7204f993 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -62,13 +62,12 @@ import com.android.server.wm.utils.InsetUtils;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Objects;
-import java.util.function.Consumer;
/**
* Controller to handle actions related to the back gesture on the server side.
*/
class BackNavigationController {
- private static final String TAG = "BackNavigationController";
+ private static final String TAG = "CoreBackPreview";
private WindowManagerService mWindowManagerService;
private boolean mBackAnimationInProgress;
private @BackNavigationInfo.BackTargetType int mLastBackType;
@@ -76,7 +75,13 @@ class BackNavigationController {
private Runnable mPendingAnimation;
private final NavigationMonitor mNavigationMonitor = new NavigationMonitor();
- AnimationHandler mAnimationHandler;
+ private AnimationHandler mAnimationHandler;
+
+ /**
+ * The transition who match the back navigation targets,
+ * release animation after this transition finish.
+ */
+ private Transition mWaitTransitionFinish;
private final ArrayList<WindowContainer> mTmpOpenApps = new ArrayList<>();
private final ArrayList<WindowContainer> mTmpCloseApps = new ArrayList<>();
@@ -140,6 +145,11 @@ class BackNavigationController {
BackNavigationInfo.Builder infoBuilder = new BackNavigationInfo.Builder();
synchronized (wmService.mGlobalLock) {
+ if (isMonitoringTransition()) {
+ Slog.w(TAG, "Previous animation hasn't finish, status: " + mAnimationHandler);
+ // Don't start any animation for it.
+ return null;
+ }
WindowManagerInternal windowManagerInternal =
LocalServices.getService(WindowManagerInternal.class);
IBinder focusedWindowToken = windowManagerInternal.getFocusedWindowToken();
@@ -374,7 +384,7 @@ class BackNavigationController {
}
boolean isMonitoringTransition() {
- return isWaitBackTransition() || mNavigationMonitor.isMonitoring();
+ return mAnimationHandler.mComposed || mNavigationMonitor.isMonitorForRemote();
}
private void scheduleAnimation(@NonNull AnimationHandler.ScheduleAnimationBuilder builder) {
@@ -477,7 +487,7 @@ class BackNavigationController {
return false;
}
- private static class NavigationMonitor {
+ private class NavigationMonitor {
// The window which triggering the back navigation.
private WindowState mNavigatingWindow;
private RemoteCallback mObserver;
@@ -487,15 +497,23 @@ class BackNavigationController {
mObserver = observer;
}
- void stopMonitor() {
- mNavigatingWindow = null;
+ void stopMonitorForRemote() {
mObserver = null;
}
- boolean isMonitoring() {
+ void stopMonitorTransition() {
+ mNavigatingWindow = null;
+ }
+
+ boolean isMonitorForRemote() {
return mNavigatingWindow != null && mObserver != null;
}
+ boolean isMonitorAnimationOrTransition() {
+ return mNavigatingWindow != null
+ && (mAnimationHandler.mComposed || mAnimationHandler.mWaitTransition);
+ }
+
/**
* Notify focus window changed during back navigation. This will cancel the gesture for
* scenarios like: a system window popup, or when an activity add a new window.
@@ -506,7 +524,8 @@ class BackNavigationController {
* a short time, but we should not cancel the navigation.
*/
private void onFocusWindowChanged(WindowState newFocus) {
- if (!isMonitoring() || !atSameDisplay(newFocus)) {
+ if (!atSameDisplay(newFocus)
+ || !(isMonitorForRemote() || isMonitorAnimationOrTransition())) {
return;
}
// Keep navigating if either new focus == navigating window or null.
@@ -514,7 +533,13 @@ class BackNavigationController {
&& (newFocus.mActivityRecord == null
|| (newFocus.mActivityRecord == mNavigatingWindow.mActivityRecord))) {
EventLogTags.writeWmBackNaviCanceled("focusWindowChanged");
- mObserver.sendResult(null /* result */);
+ if (isMonitorForRemote()) {
+ mObserver.sendResult(null /* result */);
+ }
+ if (isMonitorAnimationOrTransition()) {
+ // transition won't happen, cancel internal status
+ clearBackAnimations();
+ }
}
}
@@ -523,7 +548,7 @@ class BackNavigationController {
*/
private void onTransitionReadyWhileNavigate(ArrayList<WindowContainer> opening,
ArrayList<WindowContainer> closing) {
- if (!isMonitoring()) {
+ if (!isMonitorForRemote() && !isMonitorAnimationOrTransition()) {
return;
}
final ArrayList<WindowContainer> all = new ArrayList<>(opening);
@@ -531,7 +556,12 @@ class BackNavigationController {
for (WindowContainer app : all) {
if (app.hasChild(mNavigatingWindow)) {
EventLogTags.writeWmBackNaviCanceled("transitionHappens");
- mObserver.sendResult(null /* result */);
+ if (isMonitorForRemote()) {
+ mObserver.sendResult(null /* result */);
+ }
+ if (isMonitorAnimationOrTransition()) {
+ clearBackAnimations();
+ }
break;
}
}
@@ -539,6 +569,9 @@ class BackNavigationController {
}
private boolean atSameDisplay(WindowState newFocus) {
+ if (mNavigatingWindow == null) {
+ return false;
+ }
final int navigatingDisplayId = mNavigatingWindow.getDisplayId();
return newFocus == null || newFocus.getDisplayId() == navigatingDisplayId;
}
@@ -546,17 +579,15 @@ class BackNavigationController {
// For shell transition
/**
- * Check whether the transition targets was animated by back gesture animation.
- * Because the opening target could request to do other stuff at onResume, so it could become
- * close target for a transition. So the condition here is
- * The closing target should only exist in close list, but the opening target can be either in
- * open or close list.
- * @return {@code true} if the participants of this transition was animated by back gesture
- * animations, and shouldn't join next transition.
+ * Check whether the transition targets was animated by back gesture animation.
+ * Because the opening target could request to do other stuff at onResume, so it could become
+ * close target for a transition. So the condition here is
+ * The closing target should only exist in close list, but the opening target can be either in
+ * open or close list.
*/
- boolean containsBackAnimationTargets(Transition transition) {
+ void onTransactionReady(Transition transition) {
if (!isMonitoringTransition()) {
- return false;
+ return;
}
final ArraySet<WindowContainer> targets = transition.mParticipants;
for (int i = targets.size() - 1; i >= 0; --i) {
@@ -576,33 +607,44 @@ class BackNavigationController {
&& mAnimationHandler.containsBackAnimationTargets(mTmpOpenApps, mTmpCloseApps);
if (!matchAnimationTargets) {
mNavigationMonitor.onTransitionReadyWhileNavigate(mTmpOpenApps, mTmpCloseApps);
+ } else {
+ if (mWaitTransitionFinish != null) {
+ Slog.e(TAG, "Gesture animation is applied on another transition?");
+ }
+ mWaitTransitionFinish = transition;
}
mTmpOpenApps.clear();
mTmpCloseApps.clear();
- return matchAnimationTargets;
}
boolean isMonitorTransitionTarget(WindowContainer wc) {
- if (!isWaitBackTransition()) {
+ if (!isWaitBackTransition() || mWaitTransitionFinish == null) {
return false;
}
return mAnimationHandler.isTarget(wc, wc.isVisibleRequested() /* open */);
}
/**
- * Cleanup animation, this can either happen when transition ready or finish.
- * @param cleanupTransaction The transaction which the caller want to apply the internal
- * cleanup together.
+ * Cleanup animation, this can either happen when legacy transition ready, or when the Shell
+ * transition finish.
*/
- void clearBackAnimations(SurfaceControl.Transaction cleanupTransaction) {
- mAnimationHandler.clearBackAnimateTarget(cleanupTransaction);
+ void clearBackAnimations() {
+ mAnimationHandler.clearBackAnimateTarget();
+ mNavigationMonitor.stopMonitorTransition();
+ mWaitTransitionFinish = null;
}
- /**
+ /**
+ * Called when a transition finished.
* Handle the pending animation when the running transition finished.
* @param targets The final animation targets derived in transition.
- */
- boolean handleDeferredBackAnimation(@NonNull ArrayList<Transition.ChangeInfo> targets) {
+ * @param finishedTransition The finished transition target.
+ */
+ boolean onTransitionFinish(ArrayList<Transition.ChangeInfo> targets,
+ @NonNull Transition finishedTransition) {
+ if (finishedTransition == mWaitTransitionFinish) {
+ clearBackAnimations();
+ }
if (!mBackAnimationInProgress || mPendingAnimationBuilder == null) {
return false;
}
@@ -660,7 +702,7 @@ class BackNavigationController {
private boolean mComposed;
private boolean mWaitTransition;
private int mSwitchType = UNKNOWN;
- private SurfaceControl.Transaction mFinishedTransaction;
+
// This will be set before transition happen, to know whether the real opening target
// exactly match animating target. When target match, reparent the starting surface to
// the opening target like starting window do.
@@ -669,6 +711,7 @@ class BackNavigationController {
// request one during animating.
private int mRequestedStartingSurfaceTaskId;
private SurfaceControl mStartingSurface;
+ private ActivityRecord mOpenActivity;
AnimationHandler(WindowManagerService wms) {
mWindowManagerService = wms;
@@ -697,7 +740,8 @@ class BackNavigationController {
return true;
}
- private void initiate(WindowContainer close, WindowContainer open) {
+ private void initiate(WindowContainer close, WindowContainer open,
+ ActivityRecord openActivity) {
WindowContainer closeTarget;
if (isActivitySwitch(close, open)) {
mSwitchType = ACTIVITY_SWITCH;
@@ -712,22 +756,26 @@ class BackNavigationController {
mCloseAdaptor = createAdaptor(closeTarget, false /* isOpen */);
mOpenAdaptor = createAdaptor(open, true /* isOpen */);
-
+ mOpenActivity = openActivity;
if (mCloseAdaptor.mAnimationTarget == null || mOpenAdaptor.mAnimationTarget == null) {
Slog.w(TAG, "composeNewAnimations fail, skip");
- clearBackAnimateTarget(null /* cleanupTransaction */);
+ clearBackAnimateTarget();
}
}
- private boolean composeAnimations(@NonNull WindowContainer close,
- @NonNull WindowContainer open) {
- clearBackAnimateTarget(null /* cleanupTransaction */);
- if (close == null || open == null) {
+ boolean composeAnimations(@NonNull WindowContainer close, @NonNull WindowContainer open,
+ ActivityRecord openActivity) {
+ if (mComposed || mWaitTransition) {
+ Slog.e(TAG, "Previous animation is running " + this);
+ return false;
+ }
+ clearBackAnimateTarget();
+ if (close == null || open == null || openActivity == null) {
Slog.e(TAG, "reset animation with null target close: "
+ close + " open: " + open);
return false;
}
- initiate(close, open);
+ initiate(close, open, openActivity);
if (mSwitchType == UNKNOWN) {
return false;
}
@@ -791,24 +839,10 @@ class BackNavigationController {
return false;
}
- boolean setFinishTransaction(SurfaceControl.Transaction finishTransaction) {
- if (!mComposed) {
- return false;
- }
- mFinishedTransaction = finishTransaction;
- return true;
- }
-
- void finishPresentAnimations(SurfaceControl.Transaction t) {
+ void finishPresentAnimations() {
if (!mComposed) {
return;
}
- final SurfaceControl.Transaction pt = t != null ? t
- : mOpenAdaptor.mTarget.getPendingTransaction();
- if (mFinishedTransaction != null) {
- pt.merge(mFinishedTransaction);
- mFinishedTransaction = null;
- }
cleanUpWindowlessSurface();
if (mCloseAdaptor != null) {
@@ -819,6 +853,9 @@ class BackNavigationController {
mOpenAdaptor.mTarget.cancelAnimation();
mOpenAdaptor = null;
}
+ if (mOpenActivity != null && mOpenActivity.mLaunchTaskBehind) {
+ restoreLaunchBehind(mOpenActivity);
+ }
}
private void cleanUpWindowlessSurface() {
@@ -845,22 +882,14 @@ class BackNavigationController {
}
}
- void clearBackAnimateTarget(SurfaceControl.Transaction cleanupTransaction) {
- finishPresentAnimations(cleanupTransaction);
+ void clearBackAnimateTarget() {
+ finishPresentAnimations();
mComposed = false;
mWaitTransition = false;
mOpenTransitionTargetMatch = false;
mRequestedStartingSurfaceTaskId = 0;
mSwitchType = UNKNOWN;
- if (mFinishedTransaction != null) {
- Slog.w(TAG, "Clear back animation, found un-processed finished transaction");
- if (cleanupTransaction != null) {
- cleanupTransaction.merge(mFinishedTransaction);
- } else {
- mFinishedTransaction.apply();
- }
- mFinishedTransaction = null;
- }
+ mOpenActivity = null;
}
// The close target must in close list
@@ -876,9 +905,9 @@ class BackNavigationController {
public String toString() {
return "AnimationTargets{"
+ " openTarget= "
- + mOpenAdaptor.mTarget
+ + (mOpenAdaptor != null ? mOpenAdaptor.mTarget : "null")
+ " closeTarget= "
- + mCloseAdaptor.mTarget
+ + (mCloseAdaptor != null ? mCloseAdaptor.mTarget : "null")
+ " mSwitchType= "
+ mSwitchType
+ " mComposed= "
@@ -1048,14 +1077,13 @@ class BackNavigationController {
* @return If the preview strategy is launch behind, returns the Activity that has
* launchBehind set, or null otherwise.
*/
- private ActivityRecord applyPreviewStrategy(WindowContainer open,
+ private void applyPreviewStrategy(WindowContainer open,
ActivityRecord visibleOpenActivity) {
if (isSupportWindowlessSurface() && mShowWindowlessSurface && !mIsLaunchBehind) {
createStartingSurface(getSnapshot(open));
- return null;
+ return;
}
setLaunchBehind(visibleOpenActivity);
- return visibleOpenActivity;
}
Runnable build() {
@@ -1071,19 +1099,12 @@ class BackNavigationController {
return null;
}
- if (!composeAnimations(mCloseTarget, mOpenTarget)) {
+ if (!composeAnimations(mCloseTarget, mOpenTarget, openActivity)) {
return null;
}
- final ActivityRecord launchBehindActivity =
- applyPreviewStrategy(mOpenTarget, openActivity);
+ applyPreviewStrategy(mOpenTarget, openActivity);
- final IBackAnimationFinishedCallback callback = makeAnimationFinishedCallback(
- launchBehindActivity != null ? triggerBack -> {
- if (!triggerBack) {
- restoreLaunchBehind(launchBehindActivity);
- }
- } : null,
- mCloseTarget);
+ final IBackAnimationFinishedCallback callback = makeAnimationFinishedCallback();
final RemoteAnimationTarget[] targets = getAnimationTargets();
return () -> {
@@ -1096,31 +1117,17 @@ class BackNavigationController {
};
}
- private IBackAnimationFinishedCallback makeAnimationFinishedCallback(
- Consumer<Boolean> b, WindowContainer closeTarget) {
+ private IBackAnimationFinishedCallback makeAnimationFinishedCallback() {
return new IBackAnimationFinishedCallback.Stub() {
@Override
public void onAnimationFinished(boolean triggerBack) {
- final SurfaceControl.Transaction finishedTransaction =
- new SurfaceControl.Transaction();
synchronized (mWindowManagerService.mGlobalLock) {
- if (b != null) {
- b.accept(triggerBack);
- }
- if (triggerBack) {
- final SurfaceControl surfaceControl =
- closeTarget.getSurfaceControl();
- if (surfaceControl != null && surfaceControl.isValid()) {
- // Hide the close target surface when transition start.
- finishedTransaction.hide(surfaceControl);
- }
- }
- if (!setFinishTransaction(finishedTransaction)) {
- finishedTransaction.apply();
+ if (!mComposed) {
+ // animation was canceled
+ return;
}
if (!triggerBack) {
- clearBackAnimateTarget(
- null /* cleanupTransaction */);
+ clearBackAnimateTarget();
} else {
mWaitTransition = true;
}
@@ -1180,6 +1187,14 @@ class BackNavigationController {
}
void startAnimation() {
+ if (!mBackAnimationInProgress) {
+ // gesture is already finished, do not start animation
+ if (mPendingAnimation != null) {
+ clearBackAnimations();
+ mPendingAnimation = null;
+ }
+ return;
+ }
if (mPendingAnimation != null) {
mPendingAnimation.run();
mPendingAnimation = null;
@@ -1192,7 +1207,7 @@ class BackNavigationController {
ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "onBackNavigationDone backType=%s, "
+ "triggerBack=%b", backType, triggerBack);
- mNavigationMonitor.stopMonitor();
+ mNavigationMonitor.stopMonitorForRemote();
mBackAnimationInProgress = false;
mShowWallpaper = false;
mPendingAnimationBuilder = null;
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 951a71d2ddb9..683767e474ef 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1031,7 +1031,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
mTmpTransaction.apply();
// Handle back animation if it's already started.
- mController.mAtm.mBackNavigationController.handleDeferredBackAnimation(mTargets);
+ mController.mAtm.mBackNavigationController.onTransitionFinish(mTargets, this);
mController.mFinishingTransition = null;
}
@@ -1136,8 +1136,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
mFlags |= TRANSIT_FLAG_KEYGUARD_LOCKED;
}
// Check whether the participants were animated from back navigation.
- final boolean markBackAnimated = mController.mAtm.mBackNavigationController
- .containsBackAnimationTargets(this);
+ mController.mAtm.mBackNavigationController.onTransactionReady(this);
// Resolve the animating targets from the participants.
mTargets = calculateTargets(mParticipants, mChanges);
final TransitionInfo info = calculateTransitionInfo(mType, mFlags, mTargets, transaction);
@@ -1150,9 +1149,6 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
mTargetDisplays.add(dc);
}
- if (markBackAnimated) {
- mController.mAtm.mBackNavigationController.clearBackAnimations(mStartTransaction);
- }
if (mOverrideOptions != null) {
info.setAnimationOptions(mOverrideOptions);
if (mOverrideOptions.getType() == ANIM_OPEN_CROSS_PROFILE_APPS) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
index d0628f12336c..17ae215c2930 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -89,11 +89,12 @@ public class BackNavigationControllerTests extends WindowTestsBase {
@Before
public void setUp() throws Exception {
- mBackNavigationController = Mockito.spy(new BackNavigationController());
+ final BackNavigationController original = new BackNavigationController();
+ original.setWindowManager(mWm);
+ mBackNavigationController = Mockito.spy(original);
LocalServices.removeServiceForTest(WindowManagerInternal.class);
mWindowManagerInternal = mock(WindowManagerInternal.class);
LocalServices.addService(WindowManagerInternal.class, mWindowManagerInternal);
- mBackNavigationController.setWindowManager(mWm);
mBackAnimationAdapter = mock(BackAnimationAdapter.class);
mRootHomeTask = initHomeActivity();
}
@@ -129,7 +130,9 @@ public class BackNavigationControllerTests extends WindowTestsBase {
// verify if back animation would start.
assertTrue("Animation scheduled", backNavigationInfo.isPrepareRemoteAnimation());
- // reset drawning status
+ // reset drawing status
+ backNavigationInfo.onBackNavigationFinished(false);
+ mBackNavigationController.clearBackAnimations();
topTask.forAllWindows(w -> {
makeWindowVisibleAndDrawn(w);
}, true);
@@ -138,6 +141,8 @@ public class BackNavigationControllerTests extends WindowTestsBase {
assertThat(typeToString(backNavigationInfo.getType()))
.isEqualTo(typeToString(BackNavigationInfo.TYPE_CALLBACK));
+ backNavigationInfo.onBackNavigationFinished(false);
+ mBackNavigationController.clearBackAnimations();
doReturn(true).when(recordA).canShowWhenLocked();
backNavigationInfo = startBackNavigation();
assertThat(typeToString(backNavigationInfo.getType()))
@@ -194,6 +199,8 @@ public class BackNavigationControllerTests extends WindowTestsBase {
assertTrue("Animation scheduled", backNavigationInfo.isPrepareRemoteAnimation());
// reset drawing status
+ backNavigationInfo.onBackNavigationFinished(false);
+ mBackNavigationController.clearBackAnimations();
testCase.recordFront.forAllWindows(w -> {
makeWindowVisibleAndDrawn(w);
}, true);
@@ -202,6 +209,8 @@ public class BackNavigationControllerTests extends WindowTestsBase {
assertThat(typeToString(backNavigationInfo.getType()))
.isEqualTo(typeToString(BackNavigationInfo.TYPE_CALLBACK));
+ backNavigationInfo.onBackNavigationFinished(false);
+ mBackNavigationController.clearBackAnimations();
doReturn(true).when(testCase.recordBack).canShowWhenLocked();
backNavigationInfo = startBackNavigation();
assertThat(typeToString(backNavigationInfo.getType()))
@@ -240,6 +249,8 @@ public class BackNavigationControllerTests extends WindowTestsBase {
assertThat(typeToString(backNavigationInfo.getType()))
.isEqualTo(typeToString(BackNavigationInfo.TYPE_RETURN_TO_HOME));
+ backNavigationInfo.onBackNavigationFinished(false);
+ mBackNavigationController.clearBackAnimations();
setupKeyguardOccluded();
backNavigationInfo = startBackNavigation();
assertThat(typeToString(backNavigationInfo.getType()))
@@ -553,6 +564,7 @@ public class BackNavigationControllerTests extends WindowTestsBase {
assertTrue(toHomeBuilder.mIsLaunchBehind);
toHomeBuilder.build();
verify(animationHandler, never()).createStartingSurface(any());
+ animationHandler.clearBackAnimateTarget();
// Back to ACTIVITY and TASK have the same logic, just with different target.
final ActivityRecord topActivity = createActivityRecord(task);