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

Commit 14699578 authored by arthurhung's avatar arthurhung
Browse files

Fix back gestrure doesn't work and ANR happens

The desired focused window may become unfocusable when user swiping
task to recents or in exit animating. We need to clear the current
focus when it can't be focusable so it could set the focus again
when the focus is back to the task.

Test: atest WindowFocusTests
Test: swiping task to recents, hold and back to task, back gesture.
Bug: 173380433
Change-Id: I3cb341735e0711e6ede45c429b30328fcae03670
parent 3af4bb54
Loading
Loading
Loading
Loading
+0 −6
Original line number Diff line number Diff line
@@ -626,12 +626,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
     */
    private boolean mInEnsureActivitiesVisible = false;

    /**
     * Last window to be requested focus via {@code SurfaceControl.Transaction#setFocusedWindow} to
     * prevent duplicate requests to input.
     */
    WindowState mLastRequestedFocus = null;

    private final Consumer<WindowState> mUpdateWindowsForAnimator = w -> {
        WindowStateAnimator winAnimator = w.mWinAnimator;
        final ActivityRecord activity = w.mActivityRecord;
+48 −41
Original line number Diff line number Diff line
@@ -73,8 +73,8 @@ import java.util.function.Consumer;
final class InputMonitor {
    private final WindowManagerService mService;

    // Current window with input focus for keys and other non-touch events.  May be null.
    private WindowState mInputFocus;
    // Current input focus token for keys and other non-touch events.  May be null.
    private IBinder mInputFocus = null;

    // When true, need to call updateInputWindowsLw().
    private boolean mUpdateInputWindowsNeeded = true;
@@ -377,14 +377,17 @@ final class InputMonitor {
    }

    /**
     * Called when the current input focus changes.
     * Called when the current input focus changes. Will apply it in next updateInputWindows.
     * Layer assignment is assumed to be complete by the time this is called.
     */
    public void setInputFocusLw(WindowState newWindow, boolean updateInputWindows) {
    void setInputFocusLw(WindowState newWindow, boolean updateInputWindows) {
        ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Input focus has changed to %s display=%d",
                newWindow, mDisplayId);
        final IBinder focus = newWindow != null ? newWindow.mInputChannelToken : null;
        if (focus == mInputFocus) {
            return;
        }

        if (newWindow != mInputFocus) {
        if (newWindow != null && newWindow.canReceiveKeys()) {
            // Displaying a window implicitly causes dispatching to be unpaused.
            // This is to protect against bugs if someone pauses dispatching but
@@ -392,16 +395,44 @@ final class InputMonitor {
            newWindow.mToken.paused = false;
        }

            mInputFocus = newWindow;
        setUpdateInputWindowsNeededLw();

        if (updateInputWindows) {
            updateInputWindowsLw(false /*force*/);
        }
    }

    /**
     * Called when the current input focus changes.
     */
    private void updateInputFocusRequest() {
        final WindowState focus = mDisplayContent.mCurrentFocus;
        final IBinder focusToken = focus != null ? focus.mInputChannelToken : null;

        if (focusToken == null) {
            mInputFocus = null;
            return;
        }

        if (!focus.mWinAnimator.hasSurface() || !focus.mInputWindowHandle.isFocusable()) {
            Slog.v(TAG_WM, "Focus not requested for window=%" + focus
                    + " because it has no surface or is not focusable.");
            mInputFocus = null;
            return;
        }

        if (focusToken == mInputFocus) {
            return;
        }

        mInputFocus = focusToken;
        mInputTransaction.setFocusedWindow(mInputFocus, mDisplayId);
        EventLog.writeEvent(LOGTAG_INPUT_FOCUS, "Focus request " + focus,
                "reason=UpdateInputWindows");
        ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Focus requested for window=%s", focus);
    }

    public void setFocusedAppLw(ActivityRecord newApp) {
    void setFocusedAppLw(ActivityRecord newApp) {
        // Focused app has changed.
        mService.mInputManager.setFocusedApplication(mDisplayId,
                newApp != null ? newApp.getInputApplicationHandle(true /* update */) : null);
@@ -482,30 +513,6 @@ final class InputMonitor {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }

        private void updateInputFocusRequest() {
            if (mDisplayContent.mLastRequestedFocus == mDisplayContent.mCurrentFocus) {
                return;
            }

            final WindowState focus = mDisplayContent.mCurrentFocus;
            if (focus == null || focus.mInputChannelToken == null) {
                mDisplayContent.mLastRequestedFocus = focus;
                return;
            }

            if (!focus.mWinAnimator.hasSurface()) {
                Slog.v(TAG_WM, "Focus not requested for window=%" + focus
                        + " because it has no surface.");
                return;
            }

            mInputTransaction.setFocusedWindow(focus.mInputChannelToken, mDisplayId);
            EventLog.writeEvent(LOGTAG_INPUT_FOCUS,
                    "Focus request " + focus, "reason=UpdateInputWindows");
            mDisplayContent.mLastRequestedFocus = focus;
            ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Focus requested for window=%s", focus);
        }

        @Override
        public void accept(WindowState w) {
            final InputWindowHandleWrapper inputWindowHandle = w.mInputWindowHandle;
+4 −0
Original line number Diff line number Diff line
@@ -63,6 +63,10 @@ class InputWindowHandleWrapper {
        return mHandle.displayId;
    }

    boolean isFocusable() {
        return mHandle.focusable;
    }

    InputApplicationHandle getInputApplicationHandle() {
        return mHandle.inputApplicationHandle;
    }