diff options
| -rw-r--r-- | services/core/java/com/android/server/wm/BackNavigationController.java | 3 | ||||
| -rw-r--r-- | services/core/java/com/android/server/wm/WindowManagerService.java | 98 | 
2 files changed, 76 insertions, 25 deletions
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java index 14ae918129f7..4c0fee275d65 100644 --- a/services/core/java/com/android/server/wm/BackNavigationController.java +++ b/services/core/java/com/android/server/wm/BackNavigationController.java @@ -210,6 +210,9 @@ class BackNavigationController {                              + "topRunningActivity=%s, callbackInfo=%s, currentFocus=%s",                      currentTask, currentActivity, callbackInfo, window); +            // Clear the pointer down outside focus if any. +            mWindowManagerService.clearPointerDownOutsideFocusRunnable(); +              // If we don't need to set up the animation, we return early. This is the case when              // - We have an application callback.              // - We don't have any ActivityRecord or Task to animate. diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 521560936d81..98d1bf6b4dfd 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -732,6 +732,13 @@ public class WindowManagerService extends IWindowManager.Stub      final DisplayWindowListenerController mDisplayNotificationController;      final TaskSystemBarsListenerController mTaskSystemBarsListenerController; +    /** Amount of time (in milliseconds) to delay the pointer down outside focus handling */ +    private static final int POINTER_DOWN_OUTSIDE_FOCUS_TIMEOUT_MS = 50; + +    /** A runnable to handle pointer down outside focus event. */ +    @Nullable +    private Runnable mPointerDownOutsideFocusRunnable; +      boolean mDisplayFrozen = false;      long mDisplayFreezeTime = 0;      int mLastDisplayFreezeDuration = 0; @@ -5891,7 +5898,8 @@ public class WindowManagerService extends IWindowManager.Stub                  case ON_POINTER_DOWN_OUTSIDE_FOCUS: {                      synchronized (mGlobalLock) {                          final IBinder touchedToken = (IBinder) msg.obj; -                        onPointerDownOutsideFocusLocked(getInputTargetFromToken(touchedToken)); +                        onPointerDownOutsideFocusLocked(getInputTargetFromToken(touchedToken), +                                true /* fromHandler */);                      }                      break;                  } @@ -7917,7 +7925,8 @@ public class WindowManagerService extends IWindowManager.Stub              synchronized (mGlobalLock) {                  final InputTarget inputTarget =                          WindowManagerService.this.getInputTargetFromWindowTokenLocked(windowToken); -                WindowManagerService.this.onPointerDownOutsideFocusLocked(inputTarget); +                WindowManagerService.this.onPointerDownOutsideFocusLocked(inputTarget, +                        false /* fromHandler */);              }          } @@ -8972,39 +8981,78 @@ public class WindowManagerService extends IWindowManager.Stub          }      } -    private void onPointerDownOutsideFocusLocked(InputTarget t) { +    void clearPointerDownOutsideFocusRunnable() { +        if (mPointerDownOutsideFocusRunnable == null) return; + +        mH.removeCallbacks(mPointerDownOutsideFocusRunnable); +        mPointerDownOutsideFocusRunnable = null; +    } + +    private void onPointerDownOutsideFocusLocked(InputTarget t, boolean fromHandler) {          if (t == null || !t.receiveFocusFromTapOutside()) {              // If the window that received the input event cannot receive keys, don't move the              // display it's on to the top since that window won't be able to get focus anyway.              return;          } -        if (mRecentsAnimationController != null -            && mRecentsAnimationController.getTargetAppMainWindow() == t) { -            // If there is an active recents animation and touched window is the target, then ignore -            // the touch. The target already handles touches using its own input monitor and we -            // don't want to trigger any lifecycle changes from focusing another window. -            // TODO(b/186770026): We should remove this once we support multiple resumed activities -            //                    while in overview -            return; -        } +        clearPointerDownOutsideFocusRunnable(); + +        // For embedded activity that is showing side-by-side with another activity, delay +        // handling the touch-outside event to prevent focus rapid changes back-n-forth. +        // Otherwise, handle the touch-outside event directly.          final WindowState w = t.getWindowState(); -        if (w != null) { -            final Task task = w.getTask(); -            if (task != null && w.mTransitionController.isTransientHide(task)) { -                // Don't disturb transient animation by accident touch. +        final ActivityRecord activity = w != null ? w.getActivityRecord() : null; +        if (activity != null && activity.isEmbedded() +                && activity.getTaskFragment().getAdjacentTaskFragment() != null) { +            mPointerDownOutsideFocusRunnable = () -> handlePointerDownOutsideFocus(t); +            mH.postDelayed(mPointerDownOutsideFocusRunnable, POINTER_DOWN_OUTSIDE_FOCUS_TIMEOUT_MS); +        } else if (!fromHandler) { +            // Still post the runnable to handler thread in case there is already a runnable +            // in execution, but still waiting to hold the wm lock. +            mPointerDownOutsideFocusRunnable = () -> handlePointerDownOutsideFocus(t); +            mH.post(mPointerDownOutsideFocusRunnable); +        } else { +            handlePointerDownOutsideFocus(t); +        } +    } + +    private void handlePointerDownOutsideFocus(InputTarget t) { +        synchronized (mGlobalLock) { +            if (mPointerDownOutsideFocusRunnable != null +                    && mH.hasCallbacks(mPointerDownOutsideFocusRunnable)) { +                // Skip if there's another pending pointer-down-outside-focus event. +                return; +            } +            clearPointerDownOutsideFocusRunnable(); + +            if (mRecentsAnimationController != null +                    && mRecentsAnimationController.getTargetAppMainWindow() == t) { +                // If there is an active recents animation and touched window is the target, +                // then ignore the touch. The target already handles touches using its own +                // input monitor and we don't want to trigger any lifecycle changes from +                // focusing another window. +                // TODO(b/186770026): We should remove this once we support multiple resumed +                //  activities while in overview                  return;              } -        } -        ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "onPointerDownOutsideFocusLocked called on %s", -                t); -        if (mFocusedInputTarget != t && mFocusedInputTarget != null) { -            mFocusedInputTarget.handleTapOutsideFocusOutsideSelf(); +            final WindowState w = t.getWindowState(); +            if (w != null) { +                final Task task = w.getTask(); +                if (task != null && w.mTransitionController.isTransientHide(task)) { +                    // Don't disturb transient animation by accident touch. +                    return; +                } +            } + +            ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "onPointerDownOutsideFocusLocked called on %s", t); +            if (mFocusedInputTarget != t && mFocusedInputTarget != null) { +                mFocusedInputTarget.handleTapOutsideFocusOutsideSelf(); +            } +            // Trigger Activity#onUserLeaveHint() if the order change of task pauses any activities. +            mAtmService.mTaskSupervisor.mUserLeaving = true; +            t.handleTapOutsideFocusInsideSelf(); +            mAtmService.mTaskSupervisor.mUserLeaving = false;          } -        // Trigger Activity#onUserLeaveHint() if the order change of task pauses any activities. -        mAtmService.mTaskSupervisor.mUserLeaving = true; -        t.handleTapOutsideFocusInsideSelf(); -        mAtmService.mTaskSupervisor.mUserLeaving = false;      }      @VisibleForTesting  |