Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 60b300a2 authored by Louis Chang's avatar Louis Chang Committed by Android (Google) Code Review
Browse files

Merge "Slightly delay touch outside event on embedded activity" into main

parents c520acac c6ac5086
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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.
+73 −25
Original line number Diff line number Diff line
@@ -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;
@@ -5896,7 +5903,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;
                }
@@ -7922,7 +7930,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 */);
            }
        }

@@ -8997,21 +9006,60 @@ 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;
        }
        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();
        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
                // 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;
            }

            final WindowState w = t.getWindowState();
            if (w != null) {
                final Task task = w.getTask();
@@ -9021,8 +9069,7 @@ public class WindowManagerService extends IWindowManager.Stub
                }
            }

        ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "onPointerDownOutsideFocusLocked called on %s",
                t);
            ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "onPointerDownOutsideFocusLocked called on %s", t);
            if (mFocusedInputTarget != t && mFocusedInputTarget != null) {
                mFocusedInputTarget.handleTapOutsideFocusOutsideSelf();
            }
@@ -9031,6 +9078,7 @@ public class WindowManagerService extends IWindowManager.Stub
            t.handleTapOutsideFocusInsideSelf();
            mAtmService.mTaskSupervisor.mUserLeaving = false;
        }
    }

    @VisibleForTesting
    void handleTaskFocusChange(Task task, ActivityRecord touchedActivity) {