From e02fc4cbba60e02e01dbdde00595ae553173bcf7 Mon Sep 17 00:00:00 2001 From: Evan Rosky Date: Thu, 29 Jul 2021 10:17:09 -0700 Subject: [PATCH] Don't let IME move to recents activity during recents transition In shell transitions, recents opens on top, but in transient mode (meaning it doesn't cause the other apps to pause). This means the other apps should be running un-interrupted. This includes not taking the IME away. To handle this, adjust the IME logic so that transient-launching activities are NOT canBeImeTarget. Also fix a bug in isVisibleOrAdding where it was using visibleRequested instead of visible (if you look at the change history, !hiddenRequested was incorrectly replaced by visibleRequested instead of visible). Also fix a bug where a defer/continue of updateImeTarget was updating the target even when an update was never requested while it was deferred. This was causing it to be called prematurely during activitystarter (where global lock is held). Bug: 193565597 Test: atest ReOpenImeWindowTest SwitchImeWindowsFromGestureNavTest Change-Id: Ic537d77c8b0e10e80444dd46d7b49e5a9bd63d6c --- data/etc/services.core.protolog.json | 6 ++++ .../android/server/wm/ActivityStarter.java | 12 ++++---- .../com/android/server/wm/DisplayContent.java | 7 ++++- .../com/android/server/wm/Transition.java | 17 +++++++++++ .../server/wm/TransitionController.java | 30 +++++++++++++++---- .../server/wm/WindowManagerService.java | 2 +- .../com/android/server/wm/WindowState.java | 9 +++++- 7 files changed, 69 insertions(+), 14 deletions(-) diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 0d7225be9e03a..119c939135a67 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -1207,6 +1207,12 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "-779535710": { + "message": "Transition %d: Set %s as transient-launch", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" + }, "-775004869": { "message": "Not a match: %s", "level": "DEBUG", diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 3b43e48a53af4..c721c248710e4 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -30,7 +30,6 @@ import static android.app.ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION; import static android.app.ActivityManager.START_SUCCESS; import static android.app.ActivityManager.START_TASK_TO_FRONT; import static android.app.ActivityTaskManager.INVALID_TASK_ID; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; @@ -1573,11 +1572,7 @@ class ActivityStarter { newTransition.setRemoteTransition(remoteTransition); } mService.getTransitionController().collect(r); - // TODO(b/188669821): Remove when navbar reparenting moves to shell - if (r.getActivityType() == ACTIVITY_TYPE_HOME && r.getOptions() != null - && r.getOptions().getTransientLaunch()) { - mService.getTransitionController().setIsLegacyRecents(); - } + final boolean isTransient = r.getOptions() != null && r.getOptions().getTransientLaunch(); try { mService.deferWindowLayout(); Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner"); @@ -1625,6 +1620,11 @@ class ActivityStarter { // it as an existence change. mService.getTransitionController().collectExistenceChange(r); } + if (isTransient) { + // `r` isn't guaranteed to be the actual relevant activity, so we must wait + // until after we launched to identify the relevant activity. + mService.getTransitionController().setTransientLaunch(mLastStartActivityRecord); + } if (newTransition != null) { mService.getTransitionController().requestStartTransition(newTransition, mTargetTask, remoteTransition); diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 953cf174cde7a..467cc5e45fb90 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -578,6 +578,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp * Specifies the count to determine whether to defer updating the IME target until ready. */ private int mDeferUpdateImeTargetCount; + private boolean mUpdateImeRequestedWhileDeferred; private MagnificationSpec mMagnificationSpec; @@ -3729,6 +3730,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp final WindowState curTarget = mImeLayeringTarget; if (!canUpdateImeTarget()) { if (DEBUG_INPUT_METHOD) Slog.w(TAG_WM, "Defer updating IME target"); + mUpdateImeRequestedWhileDeferred = true; return curTarget; } @@ -4991,6 +4993,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp * Increment the deferral count to determine whether to update the IME target. */ void deferUpdateImeTarget() { + if (mDeferUpdateImeTargetCount == 0) { + mUpdateImeRequestedWhileDeferred = false; + } mDeferUpdateImeTargetCount++; } @@ -5004,7 +5009,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } mDeferUpdateImeTargetCount--; - if (mDeferUpdateImeTargetCount == 0) { + if (mDeferUpdateImeTargetCount == 0 && mUpdateImeRequestedWhileDeferred) { computeImeTarget(true /* updateImeTarget */); } } diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 6b93364232d7a..1a46d0f9a8778 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -148,6 +148,9 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe */ private final ArraySet mVisibleAtTransitionEndTokens = new ArraySet<>(); + /** Set of transient activities (lifecycle initially tied to this transition). */ + private ArraySet mTransientLaunches = null; + /** Custom activity-level animation options and callbacks. */ private TransitionInfo.AnimationOptions mOverrideOptions; private IRemoteCallback mClientAnimationStartCallback = null; @@ -174,6 +177,20 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe mFlags |= flag; } + /** Records an activity as transient-launch. This activity must be already collected. */ + void setTransientLaunch(@NonNull ActivityRecord activity) { + if (mTransientLaunches == null) { + mTransientLaunches = new ArraySet<>(); + } + mTransientLaunches.add(activity); + ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Transition %d: Set %s as " + + "transient-launch", mSyncId, activity); + } + + boolean isTransientLaunch(@NonNull ActivityRecord activity) { + return mTransientLaunches != null && mTransientLaunches.contains(activity); + } + @VisibleForTesting int getSyncId() { return mSyncId; diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java index 69e6a541e009a..c1d0f80adbb7e 100644 --- a/services/core/java/com/android/server/wm/TransitionController.java +++ b/services/core/java/com/android/server/wm/TransitionController.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_FLAG_IS_RECENTS; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY; @@ -185,6 +186,20 @@ class TransitionController { return false; } + /** + * @return {@code true} if {@param ar} is part of a transient-launch activity in an active + * transition. + */ + boolean isTransientLaunch(@NonNull ActivityRecord ar) { + if (mCollectingTransition != null && mCollectingTransition.isTransientLaunch(ar)) { + return true; + } + for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) { + if (mPlayingTransitions.get(i).isTransientLaunch(ar)) return true; + } + return false; + } + @WindowManager.TransitionType int getCollectingTransitionType() { return mCollectingTransition != null ? mCollectingTransition.mType : TRANSIT_NONE; @@ -331,13 +346,18 @@ class TransitionController { } /** - * Explicitly mark the collectingTransition as being part of recents gesture. Used for legacy - * behaviors. - * TODO(b/188669821): Remove once legacy recents behavior is moved to shell. + * Record that the launch of {@param activity} is transient (meaning its lifecycle is currently + * tied to the transition). */ - void setIsLegacyRecents() { + void setTransientLaunch(@NonNull ActivityRecord activity) { if (mCollectingTransition == null) return; - mCollectingTransition.addFlag(TRANSIT_FLAG_IS_RECENTS); + mCollectingTransition.setTransientLaunch(activity); + + // TODO(b/188669821): Remove once legacy recents behavior is moved to shell. + // Also interpret HOME transient launch as recents + if (activity.getActivityType() == ACTIVITY_TYPE_HOME) { + mCollectingTransition.addFlag(TRANSIT_FLAG_IS_RECENTS); + } } void legacyDetachNavigationBarFromApp(@NonNull IBinder token) { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 4340a365775a5..4cbfacd048708 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -7726,7 +7726,7 @@ public class WindowManagerService extends IWindowManager.Stub final WindowState currentFocus = displayContent.mCurrentFocus; if (currentFocus != null && currentFocus.mSession.mUid == uid && currentFocus.mSession.mPid == pid) { - return true; + return currentFocus.canBeImeTarget(); } } return false; diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 22db2975ef41a..7e0518a80ce66 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -1980,7 +1980,7 @@ class WindowState extends WindowContainer implements WindowManagerP final ActivityRecord atoken = mActivityRecord; return (mHasSurface || (!mRelayoutCalled && mViewVisibility == View.VISIBLE)) && isVisibleByPolicy() && !isParentWindowHidden() - && (atoken == null || atoken.mVisibleRequested) + && (atoken == null || atoken.isVisible()) && !mAnimatingExit && !mDestroying; } @@ -2706,6 +2706,13 @@ class WindowState extends WindowContainer implements WindowManagerP } } + // Don't allow transient-launch activities to take IME. + if (rootTask != null && mActivityRecord != null + && mWmService.mAtmService.getTransitionController().isTransientLaunch( + mActivityRecord)) { + return false; + } + if (DEBUG_INPUT_METHOD) { Slog.i(TAG_WM, "isVisibleOrAdding " + this + ": " + isVisibleOrAdding()); if (!isVisibleOrAdding()) {