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

Commit 8f43aee7 authored by Prabir Pradhan's avatar Prabir Pradhan Committed by Android (Google) Code Review
Browse files

Merge changes I63990ccf,I76ef8b55 into main

* changes:
  InputDispatcher: Send cancellations from losing focus windows
  InputDispatcher: Only dispatch fallback keys when there's a window
parents 26201ec2 4b9b1a1d
Loading
Loading
Loading
Loading
+53 −29
Original line number Diff line number Diff line
@@ -5195,6 +5195,7 @@ void InputDispatcher::setInputWindowsLocked(

    // Copy old handles for release if they are no longer present.
    const std::vector<sp<WindowInfoHandle>> oldWindowHandles = getWindowHandlesLocked(displayId);
    const sp<WindowInfoHandle> removedFocusedWindowHandle = getFocusedWindowHandleLocked(displayId);

    updateWindowHandlesForDisplayLocked(windowInfoHandles, displayId);

@@ -5203,7 +5204,7 @@ void InputDispatcher::setInputWindowsLocked(
    std::optional<FocusResolver::FocusChanges> changes =
            mFocusResolver.setInputWindows(displayId, windowHandles);
    if (changes) {
        onFocusChangedLocked(*changes);
        onFocusChangedLocked(*changes, removedFocusedWindowHandle);
    }

    std::unordered_map<int32_t, TouchState>::iterator stateIt =
@@ -5325,14 +5326,16 @@ void InputDispatcher::setFocusedDisplay(int32_t displayId) {
            sp<IBinder> oldFocusedWindowToken =
                    mFocusResolver.getFocusedWindowToken(mFocusedDisplayId);
            if (oldFocusedWindowToken != nullptr) {
                std::shared_ptr<Connection> connection = getConnectionLocked(oldFocusedWindowToken);
                if (connection != nullptr) {
                const auto windowHandle =
                        getWindowHandleLocked(oldFocusedWindowToken, mFocusedDisplayId);
                if (windowHandle == nullptr) {
                    LOG(FATAL) << __func__ << ": Previously focused token did not have a window";
                }
                CancelationOptions
                        options(CancelationOptions::Mode::CANCEL_NON_POINTER_EVENTS,
                                "The display which contains this window no longer has focus.");
                options.displayId = ADISPLAY_ID_NONE;
                    synthesizeCancelationEventsForConnectionLocked(connection, options);
                }
                synthesizeCancelationEventsForWindowLocked(windowHandle, options);
            }
            mFocusedDisplayId = displayId;

@@ -6207,8 +6210,18 @@ void InputDispatcher::doDispatchCycleFinishedCommand(nsecs_t finishTime,
        }
        traceWaitQueueLength(*connection);
        if (fallbackKeyEntry && connection->status == Connection::Status::NORMAL) {
            const InputTarget target{.connection = connection, .flags = dispatchEntry->targetFlags};
            enqueueDispatchEntryLocked(connection, std::move(fallbackKeyEntry), target);
            const auto windowHandle = getWindowHandleLocked(connection->getToken());
            // Only dispatch fallbacks if there is a window for the connection.
            if (windowHandle != nullptr) {
                const auto inputTarget =
                        createInputTargetLocked(windowHandle, InputTarget::DispatchMode::AS_IS,
                                                dispatchEntry->targetFlags,
                                                fallbackKeyEntry->downTime);
                if (inputTarget.has_value()) {
                    enqueueDispatchEntryLocked(connection, std::move(fallbackKeyEntry),
                                               *inputTarget);
                }
            }
        }
        releaseDispatchEntry(std::move(dispatchEntry));
    }
@@ -6440,8 +6453,11 @@ std::unique_ptr<const KeyEntry> InputDispatcher::afterKeyEventLockedInterruptabl

            mLock.lock();

            // Cancel the fallback key.
            // Cancel the fallback key, but only if we still have a window for the channel.
            // It could have been removed during the policy call.
            if (*fallbackKeyCode != AKEYCODE_UNKNOWN) {
                const auto windowHandle = getWindowHandleLocked(connection->getToken());
                if (windowHandle != nullptr) {
                    CancelationOptions options(CancelationOptions::Mode::CANCEL_FALLBACK_EVENTS,
                                               "application handled the original non-fallback key "
                                               "or is no longer a foreground target, "
@@ -6449,6 +6465,7 @@ std::unique_ptr<const KeyEntry> InputDispatcher::afterKeyEventLockedInterruptabl
                    options.keyCode = *fallbackKeyCode;
                    synthesizeCancelationEventsForConnectionLocked(connection, options);
                }
            }
            connection->inputState.removeFallbackKey(originalKeyCode);
        }
    } else {
@@ -6523,10 +6540,13 @@ std::unique_ptr<const KeyEntry> InputDispatcher::afterKeyEventLockedInterruptabl
                }
            }

            const auto windowHandle = getWindowHandleLocked(connection->getToken());
            if (windowHandle != nullptr) {
                CancelationOptions options(CancelationOptions::Mode::CANCEL_FALLBACK_EVENTS,
                                           "canceling fallback, policy no longer desires it");
                options.keyCode = *fallbackKeyCode;
                synthesizeCancelationEventsForConnectionLocked(connection, options);
            }

            fallback = false;
            *fallbackKeyCode = AKEYCODE_UNKNOWN;
@@ -6665,16 +6685,20 @@ void InputDispatcher::setFocusedWindow(const FocusRequest& request) {
    mLooper->wake();
}

void InputDispatcher::onFocusChangedLocked(const FocusResolver::FocusChanges& changes) {
void InputDispatcher::onFocusChangedLocked(const FocusResolver::FocusChanges& changes,
                                           const sp<WindowInfoHandle> removedFocusedWindowHandle) {
    if (changes.oldFocus) {
        std::shared_ptr<Connection> focusedConnection = getConnectionLocked(changes.oldFocus);
        if (focusedConnection) {
        const auto resolvedWindow = removedFocusedWindowHandle != nullptr
                ? removedFocusedWindowHandle
                : getWindowHandleLocked(changes.oldFocus, changes.displayId);
        if (resolvedWindow == nullptr) {
            LOG(FATAL) << __func__ << ": Previously focused token did not have a window";
        }
        CancelationOptions options(CancelationOptions::Mode::CANCEL_NON_POINTER_EVENTS,
                                   "focus left window");
            synthesizeCancelationEventsForConnectionLocked(focusedConnection, options);
        synthesizeCancelationEventsForWindowLocked(resolvedWindow, options);
        enqueueFocusEventLocked(changes.oldFocus, /*hasFocus=*/false, changes.reason);
    }
    }
    if (changes.newFocus) {
        resetNoFocusedWindowTimeoutLocked();
        enqueueFocusEventLocked(changes.newFocus, /*hasFocus=*/true, changes.reason);
+3 −1
Original line number Diff line number Diff line
@@ -653,7 +653,9 @@ private:
                                        bool handled, nsecs_t consumeTime) REQUIRES(mLock);
    void doInterceptKeyBeforeDispatchingCommand(const sp<IBinder>& focusedWindowToken,
                                                const KeyEntry& entry) REQUIRES(mLock);
    void onFocusChangedLocked(const FocusResolver::FocusChanges& changes) REQUIRES(mLock);
    void onFocusChangedLocked(const FocusResolver::FocusChanges& changes,
                              const sp<gui::WindowInfoHandle> removedFocusedWindowHandle = nullptr)
            REQUIRES(mLock);
    void sendFocusChangedCommandLocked(const sp<IBinder>& oldToken, const sp<IBinder>& newToken)
            REQUIRES(mLock);
    void sendDropWindowCommandLocked(const sp<IBinder>& token, float x, float y) REQUIRES(mLock);
+66 −1
Original line number Diff line number Diff line
@@ -7263,7 +7263,7 @@ TEST_F(InputDispatcherFallbackKeyTest, CanceledKeyCancelsFallback) {
    mWindow->assertNoEvents();
}
TEST_F(InputDispatcherFallbackKeyTest, WindowRemovedDuringPolicyCall) {
TEST_F(InputDispatcherFallbackKeyTest, InputChannelRemovedDuringPolicyCall) {
    setFallback(AKEYCODE_B);
    mDispatcher->notifyKey(
            KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
@@ -7296,6 +7296,71 @@ TEST_F(InputDispatcherFallbackKeyTest, WindowRemovedDuringPolicyCall) {
    ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
}
TEST_F(InputDispatcherFallbackKeyTest, WindowRemovedDuringPolicyCall) {
    setFallback(AKEYCODE_B);
    mDispatcher->notifyKey(
            KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
    // Do not handle this key event.
    consumeKey(/*handled=*/false,
               AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
    ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
    consumeKey(/*handled=*/true,
               AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
                     WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
    mFakePolicy->setUnhandledKeyHandler([&](const KeyEvent& event) {
        // When the unhandled key is reported to the policy next, remove the window.
        mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
        return KeyEventBuilder(event).keyCode(AKEYCODE_B).build();
    });
    // Release the original key, which the app will not handle. When this unhandled key is reported
    // to the policy, the window will be removed.
    mDispatcher->notifyKey(
            KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
    consumeKey(/*handled=*/false,
               AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A), WithFlags(0)));
    ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
    // Since the window was removed, it loses focus, and the channel state will be reset.
    consumeKey(/*handled=*/true,
               AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
                     WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
    mWindow->consumeFocusEvent(false);
    mWindow->assertNoEvents();
}
TEST_F(InputDispatcherFallbackKeyTest, WindowRemovedWhileAwaitingFinishedSignal) {
    setFallback(AKEYCODE_B);
    mDispatcher->notifyKey(
            KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
    // Do not handle this key event.
    consumeKey(/*handled=*/false,
               AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_A), WithFlags(0)));
    ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertUnhandledKeyReported(AKEYCODE_A));
    const auto [seq, event] = mWindow->receiveEvent();
    ASSERT_TRUE(seq.has_value() && event != nullptr) << "Failed to receive fallback event";
    ASSERT_EQ(event->getType(), InputEventType::KEY);
    ASSERT_THAT(static_cast<const KeyEvent&>(*event),
                AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_B),
                      WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
    // Remove the window now, which should generate a cancellations and make the window lose focus.
    mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
    consumeKey(/*handled=*/true,
               AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_A),
                     WithFlags(AKEY_EVENT_FLAG_CANCELED)));
    consumeKey(/*handled=*/true,
               AllOf(WithKeyAction(ACTION_UP), WithKeyCode(AKEYCODE_B),
                     WithFlags(AKEY_EVENT_FLAG_FALLBACK | AKEY_EVENT_FLAG_CANCELED)));
    mWindow->consumeFocusEvent(false);
    // Finish the event by reporting it as handled.
    mWindow->finishEvent(*seq);
    mWindow->assertNoEvents();
}
class InputDispatcherKeyRepeatTest : public InputDispatcherTest {
protected:
    static constexpr std::chrono::nanoseconds KEY_REPEAT_TIMEOUT = 40ms;