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

Commit 0fe3485b authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 8548586 from 7b2bea28 to tm-qpr1-release

Change-Id: I9d68f2f4267a2b16162c2492c78b30922b7c43da
parents 6a34dda2 7b2bea28
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -26,7 +26,8 @@ namespace android {
namespace inputdispatcher {

struct DragState {
    DragState(const sp<android::gui::WindowInfoHandle>& windowHandle) : dragWindow(windowHandle) {}
    DragState(const sp<android::gui::WindowInfoHandle>& windowHandle, int32_t pointerId)
          : dragWindow(windowHandle), pointerId(pointerId) {}
    void dump(std::string& dump, const char* prefix = "");

    // The window being dragged.
@@ -37,6 +38,8 @@ struct DragState {
    bool isStartDrag = false;
    // Indicate if the stylus button is down at the start of the drag.
    bool isStylusButtonDownAtStart = false;
    // Indicate which pointer id is tracked by the drag and drop.
    const int32_t pointerId;
};

} // namespace inputdispatcher
+79 −43
Original line number Diff line number Diff line
@@ -1747,18 +1747,12 @@ bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr<
}

void InputDispatcher::enqueueDragEventLocked(const sp<WindowInfoHandle>& windowHandle,
                                             bool isExiting, const MotionEntry& motionEntry) {
    // If the window needs enqueue a drag event, the pointerCount should be 1 and the action should
    // be AMOTION_EVENT_ACTION_MOVE, that could guarantee the first pointer is always valid.
    LOG_ALWAYS_FATAL_IF(motionEntry.pointerCount != 1);
    PointerCoords pointerCoords;
    pointerCoords.copyFrom(motionEntry.pointerCoords[0]);
    pointerCoords.transform(windowHandle->getInfo()->transform);

                                             bool isExiting, const int32_t rawX,
                                             const int32_t rawY) {
    const vec2 xy = windowHandle->getInfo()->transform.transform(vec2(rawX, rawY));
    std::unique_ptr<DragEntry> dragEntry =
            std::make_unique<DragEntry>(mIdGenerator.nextId(), motionEntry.eventTime,
                                        windowHandle->getToken(), isExiting, pointerCoords.getX(),
                                        pointerCoords.getY());
            std::make_unique<DragEntry>(mIdGenerator.nextId(), now(), windowHandle->getToken(),
                                        isExiting, xy.x, xy.y);

    enqueueInboundEventLocked(std::move(dragEntry));
}
@@ -2546,13 +2540,14 @@ void InputDispatcher::finishDragAndDrop(int32_t displayId, float x, float y) {
        vec2 local = dropWindow->getInfo()->transform.transform(x, y);
        sendDropWindowCommandLocked(dropWindow->getToken(), local.x, local.y);
    } else {
        ALOGW("No window found when drop.");
        sendDropWindowCommandLocked(nullptr, 0, 0);
    }
    mDragState.reset();
}

void InputDispatcher::addDragEventLocked(const MotionEntry& entry) {
    if (entry.pointerCount != 1 || !mDragState) {
    if (!mDragState) {
        return;
    }

@@ -2562,42 +2557,75 @@ void InputDispatcher::addDragEventLocked(const MotionEntry& entry) {
                (entry.buttonState & AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) != 0;
    }

    int32_t maskedAction = entry.action & AMOTION_EVENT_ACTION_MASK;
    int32_t x = static_cast<int32_t>(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
    int32_t y = static_cast<int32_t>(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
    if (maskedAction == AMOTION_EVENT_ACTION_MOVE) {
    // Find the pointer index by id.
    int32_t pointerIndex = 0;
    for (; static_cast<uint32_t>(pointerIndex) < entry.pointerCount; pointerIndex++) {
        const PointerProperties& pointerProperties = entry.pointerProperties[pointerIndex];
        if (pointerProperties.id == mDragState->pointerId) {
            break;
        }
    }

    if (uint32_t(pointerIndex) == entry.pointerCount) {
        LOG_ALWAYS_FATAL("Should find a valid pointer index by id %d", mDragState->pointerId);
        sendDropWindowCommandLocked(nullptr, 0, 0);
        mDragState.reset();
        return;
    }

    const int32_t maskedAction = entry.action & AMOTION_EVENT_ACTION_MASK;
    const int32_t x = entry.pointerCoords[pointerIndex].getX();
    const int32_t y = entry.pointerCoords[pointerIndex].getY();

    switch (maskedAction) {
        case AMOTION_EVENT_ACTION_MOVE: {
            // Handle the special case : stylus button no longer pressed.
        bool isStylusButtonDown = (entry.buttonState & AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) != 0;
            bool isStylusButtonDown =
                    (entry.buttonState & AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) != 0;
            if (mDragState->isStylusButtonDownAtStart && !isStylusButtonDown) {
                finishDragAndDrop(entry.displayId, x, y);
                return;
            }

        // Prevent stylus interceptor windows from affecting drag and drop behavior for now, until
        // we have an explicit reason to support it.
            // Prevent stylus interceptor windows from affecting drag and drop behavior for now,
            // until we have an explicit reason to support it.
            constexpr bool isStylus = false;

            const sp<WindowInfoHandle> hoverWindowHandle =
                findTouchedWindowAtLocked(entry.displayId, x, y, nullptr /*touchState*/, isStylus,
                                          false /*addOutsideTargets*/, true /*ignoreDragWindow*/);
                    findTouchedWindowAtLocked(entry.displayId, x, y, nullptr /*touchState*/,
                                              isStylus, false /*addOutsideTargets*/,
                                              true /*ignoreDragWindow*/);
            // enqueue drag exit if needed.
            if (hoverWindowHandle != mDragState->dragHoverWindowHandle &&
                !haveSameToken(hoverWindowHandle, mDragState->dragHoverWindowHandle)) {
                if (mDragState->dragHoverWindowHandle != nullptr) {
                enqueueDragEventLocked(mDragState->dragHoverWindowHandle, true /*isExiting*/,
                                       entry);
                    enqueueDragEventLocked(mDragState->dragHoverWindowHandle, true /*isExiting*/, x,
                                           y);
                }
                mDragState->dragHoverWindowHandle = hoverWindowHandle;
            }
            // enqueue drag location if needed.
            if (hoverWindowHandle != nullptr) {
            enqueueDragEventLocked(hoverWindowHandle, false /*isExiting*/, entry);
                enqueueDragEventLocked(hoverWindowHandle, false /*isExiting*/, x, y);
            }
            break;
        }

        case AMOTION_EVENT_ACTION_POINTER_UP:
            if (getMotionEventActionPointerIndex(entry.action) != pointerIndex) {
                break;
            }
    } else if (maskedAction == AMOTION_EVENT_ACTION_UP) {
            // The drag pointer is up.
            [[fallthrough]];
        case AMOTION_EVENT_ACTION_UP:
            finishDragAndDrop(entry.displayId, x, y);
    } else if (maskedAction == AMOTION_EVENT_ACTION_CANCEL) {
            break;
        case AMOTION_EVENT_ACTION_CANCEL: {
            ALOGD("Receiving cancel when drag and drop.");
            sendDropWindowCommandLocked(nullptr, 0, 0);
            mDragState.reset();
            break;
        }
    }
}

@@ -5117,7 +5145,15 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp<

        // Store the dragging window.
        if (isDragDrop) {
            mDragState = std::make_unique<DragState>(toWindowHandle);
            if (pointerIds.count() > 1) {
                ALOGW("The drag and drop cannot be started when there is more than 1 pointer on the"
                      " window.");
                return false;
            }
            // If the window didn't not support split or the source is mouse, the pointerIds count
            // would be 0, so we have to track the pointer 0.
            const int32_t id = pointerIds.count() == 0 ? 0 : pointerIds.firstMarkedBit();
            mDragState = std::make_unique<DragState>(toWindowHandle, id);
        }

        // Synthesize cancel for old window and down for new window.
+2 −1
Original line number Diff line number Diff line
@@ -221,7 +221,8 @@ private:
                                 const std::string& reason) REQUIRES(mLock);
    // Enqueues a drag event.
    void enqueueDragEventLocked(const sp<android::gui::WindowInfoHandle>& windowToken,
                                bool isExiting, const MotionEntry& motionEntry) REQUIRES(mLock);
                                bool isExiting, const int32_t rawX, const int32_t rawY)
            REQUIRES(mLock);

    // Adds an event to a queue of recent events for debugging purposes.
    void addRecentEventLocked(std::shared_ptr<EventEntry> entry) REQUIRES(mLock);
+102 −7
Original line number Diff line number Diff line
@@ -6110,8 +6110,7 @@ protected:
        mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}});
    }

    // Start performing drag, we will create a drag window and transfer touch to it.
    void performDrag() {
    void injectDown() {
        ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
                  injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
                                   {50, 50}))
@@ -6119,6 +6118,15 @@ protected:

        // Window should receive motion event.
        mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
    }

    // Start performing drag, we will create a drag window and transfer touch to it.
    // @param sendDown : if true, send a motion down on first window before perform drag and drop.
    // Returns true on success.
    bool performDrag(bool sendDown = true) {
        if (sendDown) {
            injectDown();
        }

        // The drag window covers the entire display
        mDragWindow = new FakeWindowHandle(mApp, mDispatcher, "DragWindow", ADISPLAY_ID_DEFAULT);
@@ -6126,11 +6134,15 @@ protected:
                {{ADISPLAY_ID_DEFAULT, {mDragWindow, mWindow, mSecondWindow}}});

        // Transfer touch focus to the drag window
        bool transferred =
                mDispatcher->transferTouchFocus(mWindow->getToken(), mDragWindow->getToken(),
                                                true /* isDragDrop */);
        if (transferred) {
            mWindow->consumeMotionCancel();
            mDragWindow->consumeMotionDown();
        }
        return transferred;
    }

    // Start performing drag, we will create a drag window and transfer touch to it.
    void performStylusDrag() {
@@ -6276,7 +6288,7 @@ TEST_F(InputDispatcherDragTests, StylusDragAndDrop) {
    mSecondWindow->assertNoEvents();
}

TEST_F(InputDispatcherDragTests, DragAndDrop_InvalidWindow) {
TEST_F(InputDispatcherDragTests, DragAndDropOnInvalidWindow) {
    performDrag();

    // Set second window invisible.
@@ -6312,6 +6324,89 @@ TEST_F(InputDispatcherDragTests, DragAndDrop_InvalidWindow) {
    mSecondWindow->assertNoEvents();
}

TEST_F(InputDispatcherDragTests, NoDragAndDropWhenMultiFingers) {
    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
              injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
                               {50, 50}))
            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
    mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);

    const MotionEvent secondFingerDownEvent =
            MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
                    .displayId(ADISPLAY_ID_DEFAULT)
                    .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
                    .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
                    .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(75).y(50))
                    .build();
    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
              injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
                                InputEventInjectionSync::WAIT_FOR_RESULT))
            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
    mWindow->consumeMotionPointerDown(1 /* pointerIndex */);

    // Should not perform drag and drop when window has multi fingers.
    ASSERT_FALSE(performDrag(false));
}

TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) {
    // First down on second window.
    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
              injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
                               {150, 50}))
            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";

    mSecondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);

    // Second down on first window.
    const MotionEvent secondFingerDownEvent =
            MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
                    .displayId(ADISPLAY_ID_DEFAULT)
                    .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
                    .pointer(
                            PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(50))
                    .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
                    .build();
    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
              injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
                                InputEventInjectionSync::WAIT_FOR_RESULT))
            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
    mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);

    // Perform drag and drop from first window.
    ASSERT_TRUE(performDrag(false));

    // Move on window.
    const MotionEvent secondFingerMoveEvent =
            MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
                    .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
                    .pointer(
                            PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(50))
                    .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
                    .build();
    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
              injectMotionEvent(mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT,
                                InputEventInjectionSync::WAIT_FOR_RESULT));
    mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
    mWindow->consumeDragEvent(false, 50, 50);
    mSecondWindow->consumeMotionMove();

    // Release the drag pointer should perform drop.
    const MotionEvent secondFingerUpEvent =
            MotionEventBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
                    .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
                    .pointer(
                            PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(50))
                    .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
                    .build();
    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
              injectMotionEvent(mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT,
                                InputEventInjectionSync::WAIT_FOR_RESULT));
    mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT);
    mFakePolicy->assertDropTargetEquals(mWindow->getToken());
    mWindow->assertNoEvents();
    mSecondWindow->consumeMotionMove();
}

class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {};

TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) {