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

Commit 28e9d486 authored by Chavi Weingarten's avatar Chavi Weingarten Committed by Android (Google) Code Review
Browse files

Merge "Add onPointerDownOutsideFocus for events outside the focused window (2/4)"

parents 722bbe81 fd6d3515
Loading
Loading
Loading
Loading
+13 −4
Original line number Diff line number Diff line
@@ -2055,7 +2055,7 @@ void InputDispatcher::enqueueDispatchEntryLocked(
            return; // skip the inconsistent event
        }

        dispatchPointerDownOutsideFocusIfNecessary(motionEntry->source,
        dispatchPointerDownOutsideFocus(motionEntry->source,
                dispatchEntry->resolvedAction, inputTarget->inputChannel->getToken());

        break;
@@ -2073,10 +2073,11 @@ void InputDispatcher::enqueueDispatchEntryLocked(

}

void InputDispatcher::dispatchPointerDownOutsideFocusIfNecessary(uint32_t source, int32_t action,
void InputDispatcher::dispatchPointerDownOutsideFocus(uint32_t source, int32_t action,
        const sp<IBinder>& newToken) {
    int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK;
    if (source != AINPUT_SOURCE_CLASS_POINTER || maskedAction != AMOTION_EVENT_ACTION_DOWN) {
    uint32_t maskedSource = source & AINPUT_SOURCE_CLASS_MASK;
    if (maskedSource != AINPUT_SOURCE_CLASS_POINTER || maskedAction != AMOTION_EVENT_ACTION_DOWN) {
        return;
    }

@@ -2095,7 +2096,9 @@ void InputDispatcher::dispatchPointerDownOutsideFocusIfNecessary(uint32_t source
        return;
    }

    // Dispatch onPointerDownOutsideFocus to the policy.
    CommandEntry* commandEntry = postCommandLocked(
            & InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible);
    commandEntry->newToken = newToken;
}

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
@@ -3997,6 +4000,12 @@ void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
    entry->release();
}

void InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible(CommandEntry* commandEntry) {
    mLock.unlock();
    mPolicy->onPointerDownOutsideFocus(commandEntry->newToken);
    mLock.lock();
}

void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(
        CommandEntry* commandEntry) {
    sp<Connection> connection = commandEntry->connection;
+10 −1
Original line number Diff line number Diff line
@@ -272,6 +272,13 @@ public:
     */
    virtual bool checkInjectEventsPermissionNonReentrant(
            int32_t injectorPid, int32_t injectorUid) = 0;

    /* Notifies the policy that a pointer down event has occurred outside the current focused
     * window.
     *
     * The touchedToken passed as an argument is the window that received the input event.
     */
    virtual void onPointerDownOutsideFocus(const sp<IBinder>& touchedToken) = 0;
};


@@ -1149,7 +1156,7 @@ private:
    void releaseDispatchEntry(DispatchEntry* dispatchEntry);
    static int handleReceiveCallback(int fd, int events, void* data);
    // The action sent should only be of type AMOTION_EVENT_*
    void dispatchPointerDownOutsideFocusIfNecessary(uint32_t source, int32_t action,
    void dispatchPointerDownOutsideFocus(uint32_t source, int32_t action,
            const sp<IBinder>& newToken) REQUIRES(mLock);

    void synthesizeCancelationEventsForAllConnectionsLocked(
@@ -1204,6 +1211,8 @@ private:
            DispatchEntry* dispatchEntry, MotionEntry* motionEntry, bool handled) REQUIRES(mLock);
    void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
    void initializeKeyEvent(KeyEvent* event, const KeyEntry* entry);
    void doOnPointerDownOutsideFocusLockedInterruptible(CommandEntry* commandEntry)
            REQUIRES(mLock);

    // Statistics gathering.
    void updateDispatchStatistics(nsecs_t currentTime, const EventEntry* entry,
+129 −12
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ public:
        mTime = -1;
        mAction = -1;
        mDisplayId = -1;
        mOnPointerDownToken.clear();
    }

    void assertFilterInputEventWasCalledWithExpectedArgs(const NotifyMotionArgs* args) {
@@ -87,11 +88,18 @@ public:
                << "Expected filterInputEvent() to not have been called.";
    }

    void assertOnPointerDownEquals(const sp<IBinder>& touchedToken) {
        ASSERT_EQ(mOnPointerDownToken, touchedToken)
                << "Expected token from onPointerDownOutsideFocus was not matched";
        reset();
    }

private:
    bool mInputEventFiltered;
    nsecs_t mTime;
    int32_t mAction;
    int32_t mDisplayId;
    sp<IBinder> mOnPointerDownToken;

    virtual void notifyConfigurationChanged(nsecs_t) {
    }
@@ -161,11 +169,16 @@ private:
        return false;
    }

    virtual void onPointerDownOutsideFocus(const sp<IBinder>& newToken) {
        mOnPointerDownToken = newToken;
    }

    void reset() {
        mInputEventFiltered = false;
        mTime = -1;
        mAction = -1;
        mDisplayId = -1;
        mOnPointerDownToken.clear();
    }
};

@@ -432,7 +445,7 @@ public:
    FakeWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle,
        const sp<InputDispatcher>& dispatcher, const std::string name, int32_t displayId) :
            FakeInputReceiver(dispatcher, name, displayId),
            mFocused(false) {
            mFocused(false), mFrame(Rect(0, 0, WIDTH, HEIGHT)), mLayoutParamFlags(0) {
            mServerChannel->setToken(new BBinder());
            mDispatcher->registerInputChannel(mServerChannel, displayId);

@@ -443,15 +456,15 @@ public:
    virtual bool updateInfo() {
        mInfo.token = mServerChannel ? mServerChannel->getToken() : nullptr;
        mInfo.name = mName;
        mInfo.layoutParamsFlags = 0;
        mInfo.layoutParamsFlags = mLayoutParamFlags;
        mInfo.layoutParamsType = InputWindowInfo::TYPE_APPLICATION;
        mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
        mInfo.frameLeft = 0;
        mInfo.frameTop = 0;
        mInfo.frameRight = WIDTH;
        mInfo.frameBottom = HEIGHT;
        mInfo.frameLeft = mFrame.left;
        mInfo.frameTop = mFrame.top;
        mInfo.frameRight = mFrame.right;
        mInfo.frameBottom = mFrame.bottom;
        mInfo.globalScaleFactor = 1.0;
        mInfo.addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT));
        mInfo.addTouchableRegion(mFrame);
        mInfo.visible = true;
        mInfo.canReceiveKeys = true;
        mInfo.hasFocus = mFocused;
@@ -470,6 +483,14 @@ public:
        mFocused = true;
    }

    void setFrame(const Rect& frame) {
        mFrame.set(frame);
    }

    void setLayoutParamFlags(int32_t flags) {
        mLayoutParamFlags = flags;
    }

    void releaseChannel() {
        mServerChannel.clear();
        InputWindowHandle::releaseChannel();
@@ -480,6 +501,8 @@ protected:
    }

    bool mFocused;
    Rect mFrame;
    int32_t mLayoutParamFlags;
};

static int32_t injectKeyDown(const sp<InputDispatcher>& dispatcher,
@@ -500,7 +523,7 @@ static int32_t injectKeyDown(const sp<InputDispatcher>& dispatcher,
}

static int32_t injectMotionDown(const sp<InputDispatcher>& dispatcher, int32_t source,
        int32_t displayId) {
        int32_t displayId, int32_t x = 100, int32_t y = 200) {
    MotionEvent event;
    PointerProperties pointerProperties[1];
    PointerCoords pointerCoords[1];
@@ -510,8 +533,8 @@ static int32_t injectMotionDown(const sp<InputDispatcher>& dispatcher, int32_t s
    pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;

    pointerCoords[0].clear();
    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 100);
    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 200);
    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);

    nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
    // Define a valid motion down event.
@@ -907,4 +930,98 @@ TEST_F(InputFilterTest, KeyEvent_InputFilter) {
    testNotifyKey(/*expectToBeFiltered*/ false);
}

class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest {
    virtual void SetUp() {
        InputDispatcherTest::SetUp();

        sp<FakeApplicationHandle> application = new FakeApplicationHandle();
        mUnfocusedWindow = new FakeWindowHandle(application, mDispatcher, "Top",
                ADISPLAY_ID_DEFAULT);
        mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
        // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this
        // window.
        mUnfocusedWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL);

        mWindowFocused = new FakeWindowHandle(application, mDispatcher, "Second",
                ADISPLAY_ID_DEFAULT);
        mWindowFocused->setFrame(Rect(50, 50, 100, 100));
        mWindowFocused->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL);
        mWindowFocusedTouchPoint = 60;

        // Set focused application.
        mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
        mWindowFocused->setFocus();

        // Expect one focus window exist in display.
        std::vector<sp<InputWindowHandle>> inputWindowHandles;
        inputWindowHandles.push_back(mUnfocusedWindow);
        inputWindowHandles.push_back(mWindowFocused);
        mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
    }

    virtual void TearDown() {
        InputDispatcherTest::TearDown();

        mUnfocusedWindow.clear();
        mWindowFocused.clear();
    }

protected:
    sp<FakeWindowHandle> mUnfocusedWindow;
    sp<FakeWindowHandle> mWindowFocused;
    int32_t mWindowFocusedTouchPoint;
};

// Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action
// DOWN on the window that doesn't have focus. Ensure the window that didn't have focus received
// the onPointerDownOutsideFocus callback.
TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_Success) {
    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher,
            AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, 20, 20))
            << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
    // Call monitor to wait for the command queue to get flushed.
    mDispatcher->monitor();

    mFakePolicy->assertOnPointerDownEquals(mUnfocusedWindow->getToken());
}

// Have two windows, one with focus. Inject MotionEvent with source TRACKBALL and action
// DOWN on the window that doesn't have focus. Ensure no window received the
// onPointerDownOutsideFocus callback.
TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonPointerSource) {
    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher,
            AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_DEFAULT, 20, 20))
            << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
    // Call monitor to wait for the command queue to get flushed.
    mDispatcher->monitor();

    mFakePolicy->assertOnPointerDownEquals(nullptr);
}

// Have two windows, one with focus. Inject KeyEvent with action DOWN on the window that doesn't
// have focus. Ensure no window received the onPointerDownOutsideFocus callback.
TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonMotionFailure) {
    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT))
            << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
    // Call monitor to wait for the command queue to get flushed.
    mDispatcher->monitor();

    mFakePolicy->assertOnPointerDownEquals(nullptr);
}

// Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action
// DOWN on the window that already has focus. Ensure no window received the
// onPointerDownOutsideFocus callback.
TEST_F(InputDispatcherOnPointerDownOutsideFocus,
        OnPointerDownOutsideFocus_OnAlreadyFocusedWindow) {
    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher,
            AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, mWindowFocusedTouchPoint,
            mWindowFocusedTouchPoint))
            << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
    // Call monitor to wait for the command queue to get flushed.
    mDispatcher->monitor();

    mFakePolicy->assertOnPointerDownEquals(nullptr);
}

} // namespace android