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

Commit 2b9d41cd authored by Siarhei Vishniakou's avatar Siarhei Vishniakou
Browse files

Move display to top in beforeQueueuing synchronously

When a key targeting a non-focused display is processed, run the
'moveDisplayToTop' synchronously to ensure that setInputWindows with the
correct window focus information is completed.

For the upcoming focus change, this would ensure that the focus event is
enqueued before the key event.

The function interceptKeyBeforeQueueing is called into policy without
the dispatcher lock held.

Currently, we are already holding up the input dispatcher processing
when interceptKeyBeforeDispatching is called.

The current change is temporary, and several improvements can be made to
fix the synchronous nature:
1) Make per-display focus permanently enabled
This would allow us to simply get rid of this code block
2) Switch focused display inside input, and move display to top
asynchronously. This would mean that the config "per-display-focus" is
processed in input, while the windowmanager only adjusts the relative
heights, and determines whether activities are resumed or paused. This
would also mean that it would now be possible for a window to have focus
while an activity is paused.

Bug: 70668286
Test: atest WindowFocusTests
Change-Id: Id1cfd913babf1a170aeb1045789ceb3f5b8df465
parent 00f61363
Loading
Loading
Loading
Loading
+17 −40
Original line number Diff line number Diff line
@@ -562,10 +562,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    private boolean mScreenshotChordPowerKeyTriggered;
    private long mScreenshotChordPowerKeyTime;

    private static final long MOVING_DISPLAY_TO_TOP_DURATION_MILLIS = 10;
    private volatile boolean mMovingDisplayToTopKeyTriggered;
    private volatile long mMovingDisplayToTopKeyTime;

    // Ringer toggle should reuse timing and triggering from screenshot power and a11y vol up
    private int mRingerToggleChord = VOLUME_HUSH_OFF;

@@ -633,7 +629,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    private static final int MSG_POWER_VERY_LONG_PRESS = 25;
    private static final int MSG_NOTIFY_USER_ACTIVITY = 26;
    private static final int MSG_RINGER_TOGGLE_CHORD = 27;
    private static final int MSG_MOVE_DISPLAY_TO_TOP = 28;

    private class PolicyHandler extends Handler {
        @Override
@@ -723,10 +718,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                case MSG_RINGER_TOGGLE_CHORD:
                    handleRingerChordGesture();
                    break;
                case MSG_MOVE_DISPLAY_TO_TOP:
                    mWindowManagerFuncs.moveDisplayToTop(msg.arg1);
                    mMovingDisplayToTopKeyTriggered = false;
                    break;
            }
        }
    }
@@ -2545,36 +2536,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    @Override
    public long interceptKeyBeforeDispatching(IBinder focusedToken, KeyEvent event,
            int policyFlags) {
        final long result = interceptKeyBeforeDispatchingInner(focusedToken, event, policyFlags);
        final int eventDisplayId = event.getDisplayId();
        if (result == 0 && !mPerDisplayFocusEnabled
                && eventDisplayId != INVALID_DISPLAY && eventDisplayId != mTopFocusedDisplayId) {
            // An event is targeting a non-focused display. Try to move the display to top so that
            // it can become the focused display to interact with the user.
            final long eventDownTime = event.getDownTime();
            if (mMovingDisplayToTopKeyTime < eventDownTime) {
                // We have not handled this event yet. Move the display to top, and then tell
                // dispatcher to try again later.
                mMovingDisplayToTopKeyTime = eventDownTime;
                mMovingDisplayToTopKeyTriggered = true;
                mHandler.sendMessage(
                        mHandler.obtainMessage(MSG_MOVE_DISPLAY_TO_TOP, eventDisplayId, 0));
                return MOVING_DISPLAY_TO_TOP_DURATION_MILLIS;
            } else if (mMovingDisplayToTopKeyTriggered) {
                // The message has not been handled yet. Tell dispatcher to try again later.
                return MOVING_DISPLAY_TO_TOP_DURATION_MILLIS;
            }
            // The target display is still not the top focused display. Drop the event because the
            // display may not contain any window which can receive keys.
            Slog.w(TAG, "Dropping key targeting non-focused display #" + eventDisplayId
                    + " keyCode=" + KeyEvent.keyCodeToString(event.getKeyCode()));
            return -1;
        }
        return result;
    }

    private long interceptKeyBeforeDispatchingInner(IBinder focusedToken, KeyEvent event,
            int policyFlags) {
        final boolean keyguardOn = keyguardOn();
        final int keyCode = event.getKeyCode();
        final int repeatCount = event.getRepeatCount();
@@ -3613,7 +3574,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        final boolean canceled = event.isCanceled();
        final int keyCode = event.getKeyCode();
        final int displayId = event.getDisplayId();

        final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;

        // If screen is off then we treat the case where the keyguard is open but hidden
@@ -4035,6 +3995,23 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                    PowerManager.WAKE_REASON_WAKE_KEY, "android.policy:KEY");
        }

        if ((result & ACTION_PASS_TO_USER) != 0) {
            // If the key event is targeted to a specific display, then the user is interacting with
            // that display. Therefore, give focus to the display that the user is interacting with.
            if (!mPerDisplayFocusEnabled
                    && displayId != INVALID_DISPLAY && displayId != mTopFocusedDisplayId) {
                // An event is targeting a non-focused display. Move the display to top so that
                // it can become the focused display to interact with the user.
                // This should be done asynchronously, once the focus logic is fully moved to input
                // from windowmanager. Currently, we need to ensure the setInputWindows completes,
                // which would force the focus event to be queued before the current key event.
                // TODO(b/70668286): post call to 'moveDisplayToTop' to mHandler instead
                Log.i(TAG, "Moving non-focused display " + displayId + " to top "
                        + "because a key is targeting it");
                mWindowManagerFuncs.moveDisplayToTop(displayId);
            }
        }

        return result;
    }

+1 −0
Original line number Diff line number Diff line
@@ -2768,6 +2768,7 @@ public class WindowManagerService extends IWindowManager.Stub
                        true /* includingParents */);
            }
        }
        syncInputTransactions();
    }

    /**