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

Commit 721e26f1 authored by Tiger Huang's avatar Tiger Huang
Browse files

Track focus changes on external displays (1/4)

Let InputDispatcher can have multiple focused windows (each display
has one). If an event is display-specific, then it will be dispatched
to the focused window in the corresponding display. Otherwise, it will
be dispatched to the focused window in the focused display which is
the display that the user most recently interacted with.

Modified API:
    void setFocusedApplication(
            const sp<InputApplicationHandle>& inputApplicationHandle,
            int32_t displayId)

New API:
    void setFocusedDisplay(int32_t displayId)

Test: atest -a inputflinger_tests
Test: atest ActivityManagerMultiDisplayTests
Test: atest CtsWindowManagerDeviceTestCases
Test: atest com.android.server.wm.DisplayContentTests
Bug: 111361570
Change-Id: I19420deff854c0ee74992569330eaae08e2516e7
parent 0c799a23
Loading
Loading
Loading
Loading
+163 −46
Original line number Diff line number Diff line
@@ -235,6 +235,12 @@ static void dumpRegion(std::string& dump, const Region& region) {
    }
}

template<typename T, typename U>
static T getValueByKey(std::unordered_map<U, T>& map, U key) {
    typename std::unordered_map<U, T>::const_iterator it = map.find(key);
    return it != map.end() ? it->second : T{};
}


// --- InputDispatcher ---

@@ -244,6 +250,7 @@ InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& polic
    mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
    mNextUnblockedEvent(nullptr),
    mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false),
    mFocusedDisplayId(ADISPLAY_ID_DEFAULT),
    mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
    mLooper = new Looper(false);

@@ -808,8 +815,10 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
        if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
            CommandEntry* commandEntry = postCommandLocked(
                    & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
            if (mFocusedWindowHandle != nullptr) {
                commandEntry->inputWindowHandle = mFocusedWindowHandle;
            sp<InputWindowHandle> focusedWindowHandle =
                    getValueByKey(mFocusedWindowHandlesByDisplay, getTargetDisplayId(entry));
            if (focusedWindowHandle != nullptr) {
                commandEntry->inputWindowHandle = focusedWindowHandle;
            }
            commandEntry->keyEntry = entry;
            entry->refCount += 1;
@@ -1108,17 +1117,49 @@ void InputDispatcher::resetANRTimeoutsLocked() {
    mInputTargetWaitApplicationHandle.clear();
}

/**
 * Get the display id that the given event should go to. If this event specifies a valid display id,
 * then it should be dispatched to that display. Otherwise, the event goes to the focused display.
 * Focused display is the display that the user most recently interacted with.
 */
int32_t InputDispatcher::getTargetDisplayId(const EventEntry* entry) {
    int32_t displayId;
    switch (entry->type) {
    case EventEntry::TYPE_KEY: {
        const KeyEntry* typedEntry = static_cast<const KeyEntry*>(entry);
        displayId = typedEntry->displayId;
        break;
    }
    case EventEntry::TYPE_MOTION: {
        const MotionEntry* typedEntry = static_cast<const MotionEntry*>(entry);
        displayId = typedEntry->displayId;
        break;
    }
    default: {
        ALOGE("Unsupported event type '%" PRId32 "' for target display.", entry->type);
        return ADISPLAY_ID_NONE;
    }
    }
    return displayId == ADISPLAY_ID_NONE ? mFocusedDisplayId : displayId;
}

int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
        const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) {
    int32_t injectionResult;
    std::string reason;

    int32_t displayId = getTargetDisplayId(entry);
    sp<InputWindowHandle> focusedWindowHandle =
            getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
    sp<InputApplicationHandle> focusedApplicationHandle =
            getValueByKey(mFocusedApplicationHandlesByDisplay, displayId);

    // If there is no currently focused window and no focused application
    // then drop the event.
    if (mFocusedWindowHandle == nullptr) {
        if (mFocusedApplicationHandle != nullptr) {
    if (focusedWindowHandle == nullptr) {
        if (focusedApplicationHandle != nullptr) {
            injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
                    mFocusedApplicationHandle, nullptr, nextWakeupTime,
                    focusedApplicationHandle, nullptr, nextWakeupTime,
                    "Waiting because no window has focus but there is a "
                    "focused application that may eventually add a window "
                    "when it finishes starting up.");
@@ -1131,23 +1172,23 @@ int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
    }

    // Check permissions.
    if (! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState)) {
    if (!checkInjectionPermission(focusedWindowHandle, entry->injectionState)) {
        injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
        goto Failed;
    }

    // Check whether the window is ready for more input.
    reason = checkWindowReadyForMoreInputLocked(currentTime,
            mFocusedWindowHandle, entry, "focused");
            focusedWindowHandle, entry, "focused");
    if (!reason.empty()) {
        injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
                mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, reason.c_str());
                focusedApplicationHandle, focusedWindowHandle, nextWakeupTime, reason.c_str());
        goto Unresponsive;
    }

    // Success!  Output targets.
    injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
    addWindowTargetLocked(mFocusedWindowHandle,
    addWindowTargetLocked(focusedWindowHandle,
            InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0),
            inputTargets);

@@ -1802,8 +1843,11 @@ std::string InputDispatcher::getApplicationWindowLabelLocked(
}

void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) {
    if (mFocusedWindowHandle != nullptr) {
        const InputWindowInfo* info = mFocusedWindowHandle->getInfo();
    int32_t displayId = getTargetDisplayId(eventEntry);
    sp<InputWindowHandle> focusedWindowHandle =
            getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
    if (focusedWindowHandle != nullptr) {
        const InputWindowInfo* info = focusedWindowHandle->getInfo();
        if (info->inputFeatures & InputWindowInfo::INPUT_FEATURE_DISABLE_USER_ACTIVITY) {
#if DEBUG_DISPATCH_CYCLE
            ALOGD("Not poking user activity: disabled by window '%s'.", info->name.c_str());
@@ -2978,18 +3022,7 @@ void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle>>& input
        // Copy old handles for release if they are no longer present.
        const Vector<sp<InputWindowHandle>> oldWindowHandles = getWindowHandlesLocked(displayId);

        // TODO(b/111361570): multi-display focus, one focus window per display.
        sp<InputWindowHandle> newFocusedWindowHandle = mFocusedWindowHandle;
        // Reset newFocusedWindowHandle to nullptr if current display own the focus window,
        // that will be updated below when going through all window handles in current display.
        // And if list of window handles becomes empty then it will be updated by other display.
        if (mFocusedWindowHandle != nullptr) {
            const InputWindowInfo* info = mFocusedWindowHandle->getInfo();
            if (info == nullptr || info->displayId == displayId) {
                newFocusedWindowHandle = nullptr;
            }
        }

        sp<InputWindowHandle> newFocusedWindowHandle = nullptr;
        bool foundHoveredWindow = false;

        if (inputWindowHandles.isEmpty()) {
@@ -3026,28 +3059,31 @@ void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle>>& input
            mLastHoverWindowHandle = nullptr;
        }

        // TODO(b/111361570): multi-display focus, one focus in all display in current.
        if (mFocusedWindowHandle != newFocusedWindowHandle) {
            if (mFocusedWindowHandle != nullptr) {
        sp<InputWindowHandle> oldFocusedWindowHandle =
                getValueByKey(mFocusedWindowHandlesByDisplay, displayId);

        if (oldFocusedWindowHandle != newFocusedWindowHandle) {
            if (oldFocusedWindowHandle != nullptr) {
#if DEBUG_FOCUS
                ALOGD("Focus left window: %s",
                        mFocusedWindowHandle->getName().c_str());
                        oldFocusedWindowHandle->getName().c_str());
#endif
                sp<InputChannel> focusedInputChannel = mFocusedWindowHandle->getInputChannel();
                sp<InputChannel> focusedInputChannel = oldFocusedWindowHandle->getInputChannel();
                if (focusedInputChannel != nullptr) {
                    CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS,
                            "focus left window");
                    synthesizeCancelationEventsForInputChannelLocked(
                            focusedInputChannel, options);
                }
                mFocusedWindowHandlesByDisplay.erase(displayId);
            }
            if (newFocusedWindowHandle != nullptr) {
#if DEBUG_FOCUS
                ALOGD("Focus entered window: %s",
                        newFocusedWindowHandle->getName().c_str());
#endif
                mFocusedWindowHandlesByDisplay[displayId] = newFocusedWindowHandle;
            }
            mFocusedWindowHandle = newFocusedWindowHandle;
        }

        ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(displayId);
@@ -3096,25 +3132,28 @@ void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle>>& input
}

void InputDispatcher::setFocusedApplication(
        const sp<InputApplicationHandle>& inputApplicationHandle) {
        int32_t displayId, const sp<InputApplicationHandle>& inputApplicationHandle) {
#if DEBUG_FOCUS
    ALOGD("setFocusedApplication");
#endif
    { // acquire lock
        AutoMutex _l(mLock);

        sp<InputApplicationHandle> oldFocusedApplicationHandle =
                getValueByKey(mFocusedApplicationHandlesByDisplay, displayId);
        if (inputApplicationHandle != nullptr && inputApplicationHandle->updateInfo()) {
            if (mFocusedApplicationHandle != inputApplicationHandle) {
                if (mFocusedApplicationHandle != nullptr) {
            if (oldFocusedApplicationHandle != inputApplicationHandle) {
                if (oldFocusedApplicationHandle != nullptr) {
                    resetANRTimeoutsLocked();
                    mFocusedApplicationHandle->releaseInfo();
                    oldFocusedApplicationHandle->releaseInfo();
                }
                mFocusedApplicationHandle = inputApplicationHandle;
                mFocusedApplicationHandlesByDisplay[displayId] = inputApplicationHandle;
            }
        } else if (mFocusedApplicationHandle != nullptr) {
        } else if (oldFocusedApplicationHandle != nullptr) {
            resetANRTimeoutsLocked();
            mFocusedApplicationHandle->releaseInfo();
            mFocusedApplicationHandle.clear();
            oldFocusedApplicationHandle->releaseInfo();
            oldFocusedApplicationHandle.clear();
            mFocusedApplicationHandlesByDisplay.erase(displayId);
        }

#if DEBUG_FOCUS
@@ -3126,6 +3165,62 @@ void InputDispatcher::setFocusedApplication(
    mLooper->wake();
}

/**
 * Sets the focused display, which is responsible for receiving focus-dispatched input events where
 * the display not specified.
 *
 * We track any unreleased events for each window. If a window loses the ability to receive the
 * released event, we will send a cancel event to it. So when the focused display is changed, we
 * cancel all the unreleased display-unspecified events for the focused window on the old focused
 * display. The display-specified events won't be affected.
 */
void InputDispatcher::setFocusedDisplay(int32_t displayId) {
#if DEBUG_FOCUS
    ALOGD("setFocusedDisplay displayId=%" PRId32, displayId);
#endif
    { // acquire lock
        AutoMutex _l(mLock);

        if (mFocusedDisplayId != displayId) {
            sp<InputWindowHandle> oldFocusedWindowHandle =
                    getValueByKey(mFocusedWindowHandlesByDisplay, mFocusedDisplayId);
            if (oldFocusedWindowHandle != nullptr) {
                sp<InputChannel> inputChannel = oldFocusedWindowHandle->getInputChannel();
                if (inputChannel != nullptr) {
                    CancelationOptions options(
                            CancelationOptions::CANCEL_DISPLAY_UNSPECIFIED_EVENTS,
                            "The display which contains this window no longer has focus.");
                    synthesizeCancelationEventsForInputChannelLocked(inputChannel, options);
                }
            }
            mFocusedDisplayId = displayId;

            // Sanity check
            sp<InputWindowHandle> newFocusedWindowHandle =
                    getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
            if (newFocusedWindowHandle == nullptr) {
                ALOGW("Focused display #%" PRId32 " does not have a focused window.", displayId);
                if (!mFocusedWindowHandlesByDisplay.empty()) {
                    ALOGE("But another display has a focused window:");
                    for (auto& it : mFocusedWindowHandlesByDisplay) {
                        const int32_t displayId = it.first;
                        const sp<InputWindowHandle>& windowHandle = it.second;
                        ALOGE("Display #%" PRId32 " has focused window: '%s'\n",
                                displayId, windowHandle->getName().c_str());
                    }
                }
            }
        }

#if DEBUG_FOCUS
        logDispatchStateLocked();
#endif
    } // release lock

    // Wake up poll loop since it may need to make new input dispatching choices.
    mLooper->wake();
}

void InputDispatcher::setInputDispatchMode(bool enabled, bool frozen) {
#if DEBUG_FOCUS
    ALOGD("setInputDispatchMode: enabled=%d, frozen=%d", enabled, frozen);
@@ -3152,7 +3247,7 @@ void InputDispatcher::setInputDispatchMode(bool enabled, bool frozen) {
        }

#if DEBUG_FOCUS
        //logDispatchStateLocked();
        logDispatchStateLocked();
#endif
    } // release lock

@@ -3297,17 +3392,35 @@ void InputDispatcher::logDispatchStateLocked() {
void InputDispatcher::dumpDispatchStateLocked(std::string& dump) {
    dump += StringPrintf(INDENT "DispatchEnabled: %d\n", mDispatchEnabled);
    dump += StringPrintf(INDENT "DispatchFrozen: %d\n", mDispatchFrozen);

    if (mFocusedApplicationHandle != nullptr) {
        dump += StringPrintf(INDENT "FocusedApplication: name='%s', dispatchingTimeout=%0.3fms\n",
                mFocusedApplicationHandle->getName().c_str(),
                mFocusedApplicationHandle->getDispatchingTimeout(
    dump += StringPrintf(INDENT "FocusedDisplayId: %" PRId32 "\n", mFocusedDisplayId);

    if (!mFocusedApplicationHandlesByDisplay.empty()) {
        dump += StringPrintf(INDENT "FocusedApplications:\n");
        for (auto& it : mFocusedApplicationHandlesByDisplay) {
            const int32_t displayId = it.first;
            const sp<InputApplicationHandle>& applicationHandle = it.second;
            dump += StringPrintf(
                    INDENT2 "displayId=%" PRId32 ", name='%s', dispatchingTimeout=%0.3fms\n",
                    displayId,
                    applicationHandle->getName().c_str(),
                    applicationHandle->getDispatchingTimeout(
                            DEFAULT_INPUT_DISPATCHING_TIMEOUT) / 1000000.0);
        }
    } else {
        dump += StringPrintf(INDENT "FocusedApplications: <none>\n");
    }

    if (!mFocusedWindowHandlesByDisplay.empty()) {
        dump += StringPrintf(INDENT "FocusedWindows:\n");
        for (auto& it : mFocusedWindowHandlesByDisplay) {
            const int32_t displayId = it.first;
            const sp<InputWindowHandle>& windowHandle = it.second;
            dump += StringPrintf(INDENT2 "displayId=%" PRId32 ", name='%s'\n",
                    displayId, windowHandle->getName().c_str());
        }
    } else {
        dump += StringPrintf(INDENT "FocusedApplication: <null>\n");
        dump += StringPrintf(INDENT "FocusedWindows: <none>\n");
    }
    dump += StringPrintf(INDENT "FocusedWindow: name='%s'\n",
            mFocusedWindowHandle != nullptr ? mFocusedWindowHandle->getName().c_str() : "<null>");

    if (!mTouchStatesByDisplay.isEmpty()) {
        dump += StringPrintf(INDENT "TouchStatesByDisplay:\n");
@@ -4527,6 +4640,8 @@ bool InputDispatcher::InputState::shouldCancelKey(const KeyMemento& memento,
        return true;
    case CancelationOptions::CANCEL_FALLBACK_EVENTS:
        return memento.flags & AKEY_EVENT_FLAG_FALLBACK;
    case CancelationOptions::CANCEL_DISPLAY_UNSPECIFIED_EVENTS:
        return memento.displayId == ADISPLAY_ID_NONE;
    default:
        return false;
    }
@@ -4545,6 +4660,8 @@ bool InputDispatcher::InputState::shouldCancelMotion(const MotionMemento& mement
        return memento.source & AINPUT_SOURCE_CLASS_POINTER;
    case CancelationOptions::CANCEL_NON_POINTER_EVENTS:
        return !(memento.source & AINPUT_SOURCE_CLASS_POINTER);
    case CancelationOptions::CANCEL_DISPLAY_UNSPECIFIED_EVENTS:
        return memento.displayId == ADISPLAY_ID_NONE;
    default:
        return false;
    }
+22 −6
Original line number Diff line number Diff line
@@ -311,12 +311,18 @@ public:
    virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles,
            int32_t displayId) = 0;

    /* Sets the focused application.
    /* Sets the focused application on the given display.
     *
     * This method may be called on any thread (usually by the input manager).
     */
    virtual void setFocusedApplication(
            const sp<InputApplicationHandle>& inputApplicationHandle) = 0;
            int32_t displayId, const sp<InputApplicationHandle>& inputApplicationHandle) = 0;

    /* Sets the focused display.
     *
     * This method may be called on any thread (usually by the input manager).
     */
    virtual void setFocusedDisplay(int32_t displayId) = 0;

    /* Sets the input dispatching mode.
     *
@@ -391,7 +397,9 @@ public:

    virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles,
            int32_t displayId);
    virtual void setFocusedApplication(const sp<InputApplicationHandle>& inputApplicationHandle);
    virtual void setFocusedApplication(int32_t displayId,
            const sp<InputApplicationHandle>& inputApplicationHandle);
    virtual void setFocusedDisplay(int32_t displayId);
    virtual void setInputDispatchMode(bool enabled, bool frozen);
    virtual void setInputFilterEnabled(bool enabled);

@@ -686,6 +694,10 @@ private:
            CANCEL_POINTER_EVENTS = 1,
            CANCEL_NON_POINTER_EVENTS = 2,
            CANCEL_FALLBACK_EVENTS = 3,

            /* Cancel events where the display not specified. These events would go to the focused
             * display. */
            CANCEL_DISPLAY_UNSPECIFIED_EVENTS = 4,
        };

        // The criterion to use to determine which events should be canceled.
@@ -966,7 +978,7 @@ private:
    bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const;

    // Focus tracking for keys, trackball, etc.
    sp<InputWindowHandle> mFocusedWindowHandle;
    std::unordered_map<int32_t, sp<InputWindowHandle>> mFocusedWindowHandlesByDisplay;

    // Focus tracking for touch.
    struct TouchedWindow {
@@ -997,8 +1009,11 @@ private:
    KeyedVector<int32_t, TouchState> mTouchStatesByDisplay;
    TouchState mTempTouchState;

    // Focused application.
    sp<InputApplicationHandle> mFocusedApplicationHandle;
    // Focused applications.
    std::unordered_map<int32_t, sp<InputApplicationHandle>> mFocusedApplicationHandlesByDisplay;

    // Top focused display.
    int32_t mFocusedDisplayId;

    // Dispatcher state at time of last ANR.
    std::string mLastANRState;
@@ -1046,6 +1061,7 @@ private:
    nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime);
    void resetANRTimeoutsLocked();

    int32_t getTargetDisplayId(const EventEntry* entry);
    int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry,
            Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime);
    int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry,
+20 −7
Original line number Diff line number Diff line
@@ -382,12 +382,13 @@ public:
        int32_t mDisplayId;
};

static int32_t injectKeyDown(const sp<InputDispatcher>& dispatcher) {
static int32_t injectKeyDown(const sp<InputDispatcher>& dispatcher,
        int32_t displayId = ADISPLAY_ID_NONE) {
    KeyEvent event;
    nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);

    // Define a valid key down event.
    event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
    event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, displayId,
            AKEY_EVENT_ACTION_DOWN, /* flags */ 0,
            AKEYCODE_A, KEY_A, AMETA_NONE, /* repeatCount */ 0, currentTime, currentTime);

@@ -466,7 +467,7 @@ TEST_F(InputDispatcherTest, SetInputWindow_FocusedWindow) {
    sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second");

    // Set focus application.
    mDispatcher->setFocusedApplication(application);
    mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);

    // Expect one focus window exist in display.
    windowSecond->setFocus();
@@ -511,15 +512,21 @@ TEST_F(InputDispatcherTest, SetInputWindow_MultiDisplayTouch) {
    windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, SECOND_DISPLAY_ID);
}

// TODO(b/111361570): multi-display focus, one focus window per display.
TEST_F(InputDispatcherTest, SetInputWindow_FocusedInMultiDisplay) {
    sp<FakeApplicationHandle> application = new FakeApplicationHandle();
    sp<FakeWindowHandle> windowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1");
    sp<FakeApplicationHandle> application2 = new FakeApplicationHandle();
    sp<FakeWindowHandle> windowInSecondary = new FakeWindowHandle(application2, mDispatcher, "D_2");

    constexpr int32_t SECOND_DISPLAY_ID = 1;

    // Set focus to primary display window.
    mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
    windowInPrimary->setFocus();

    // Set focus to second display window.
    mDispatcher->setFocusedApplication(application2);
    mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID);
    mDispatcher->setFocusedApplication(SECOND_DISPLAY_ID, application2);
    windowInSecondary->setFocus();

    // Update all windows per displays.
@@ -527,13 +534,18 @@ TEST_F(InputDispatcherTest, SetInputWindow_FocusedInMultiDisplay) {
    inputWindowHandles.push(windowInPrimary);
    mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);

    constexpr int32_t SECOND_DISPLAY_ID = 1;
    windowInSecondary->setDisplayId(SECOND_DISPLAY_ID);
    Vector<sp<InputWindowHandle>> inputWindowHandles_Second;
    inputWindowHandles_Second.push(windowInSecondary);
    mDispatcher->setInputWindows(inputWindowHandles_Second, SECOND_DISPLAY_ID);

    // Test inject a key down.
    // Test inject a key down with display id specified.
    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT))
            << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
    windowInPrimary->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_DEFAULT);
    windowInSecondary->assertNoEvents();

    // Test inject a key down without display id specified.
    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
            << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
    windowInPrimary->assertNoEvents();
@@ -545,6 +557,7 @@ TEST_F(InputDispatcherTest, SetInputWindow_FocusedInMultiDisplay) {

    // Expect old focus should receive a cancel event.
    windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
    // TODO(b/111361570): Validate that the event here was marked as canceled.

    // Test inject a key down, should timeout because of no target window.
    ASSERT_EQ(INPUT_EVENT_INJECTION_TIMED_OUT, injectKeyDown(mDispatcher))