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

Commit af4fb215 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Add InputDispatcherInterface::transferTouch api" into sc-dev am: 23cb5990

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/native/+/13857990

Change-Id: I9584b37487ecd6fb73cbfe71655db4455f4a2d58
parents 0eb33e9e 23cb5990
Loading
Loading
Loading
Loading
+34 −0
Original line number Diff line number Diff line
@@ -4747,6 +4747,40 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp<
    return true;
}

// Binder call
bool InputDispatcher::transferTouch(const sp<IBinder>& destChannelToken) {
    sp<IBinder> fromToken;
    { // acquire lock
        std::scoped_lock _l(mLock);

        sp<InputWindowHandle> toWindowHandle = getWindowHandleLocked(destChannelToken);
        if (toWindowHandle == nullptr) {
            ALOGW("Could not find window associated with token=%p", destChannelToken.get());
            return false;
        }

        const int32_t displayId = toWindowHandle->getInfo()->displayId;

        auto touchStateIt = mTouchStatesByDisplay.find(displayId);
        if (touchStateIt == mTouchStatesByDisplay.end()) {
            ALOGD("Could not transfer touch because the display %" PRId32 " is not being touched",
                  displayId);
            return false;
        }

        TouchState& state = touchStateIt->second;
        if (state.windows.size() != 1) {
            ALOGW("Cannot transfer touch state because there are %zu windows being touched",
                  state.windows.size());
            return false;
        }
        const TouchedWindow& touchedWindow = state.windows[0];
        fromToken = touchedWindow.windowHandle->getToken();
    } // release lock

    return transferTouchFocus(fromToken, destChannelToken);
}

void InputDispatcher::resetAndDropEverythingLocked(const char* reason) {
    if (DEBUG_FOCUS) {
        ALOGD("Resetting and dropping all events (%s).", reason);
+42 −42
Original line number Diff line number Diff line
@@ -81,60 +81,60 @@ class Connection;
 */
class InputDispatcher : public android::InputDispatcherInterface {
protected:
    virtual ~InputDispatcher();
    ~InputDispatcher() override;

public:
    explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy);

    virtual void dump(std::string& dump) override;
    virtual void monitor() override;
    virtual bool waitForIdle() override;
    virtual status_t start() override;
    virtual status_t stop() override;

    virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
    virtual void notifyKey(const NotifyKeyArgs* args) override;
    virtual void notifyMotion(const NotifyMotionArgs* args) override;
    virtual void notifySwitch(const NotifySwitchArgs* args) override;
    virtual void notifySensor(const NotifySensorArgs* args) override;
    virtual void notifyVibratorState(const NotifyVibratorStateArgs* args) override;
    virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
    virtual void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;

    virtual android::os::InputEventInjectionResult injectInputEvent(
    void dump(std::string& dump) override;
    void monitor() override;
    bool waitForIdle() override;
    status_t start() override;
    status_t stop() override;

    void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
    void notifyKey(const NotifyKeyArgs* args) override;
    void notifyMotion(const NotifyMotionArgs* args) override;
    void notifySwitch(const NotifySwitchArgs* args) override;
    void notifySensor(const NotifySensorArgs* args) override;
    void notifyVibratorState(const NotifyVibratorStateArgs* args) override;
    void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
    void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;

    android::os::InputEventInjectionResult injectInputEvent(
            const InputEvent* event, int32_t injectorPid, int32_t injectorUid,
            android::os::InputEventInjectionSync syncMode, std::chrono::milliseconds timeout,
            uint32_t policyFlags) override;

    virtual std::unique_ptr<VerifiedInputEvent> verifyInputEvent(const InputEvent& event) override;
    std::unique_ptr<VerifiedInputEvent> verifyInputEvent(const InputEvent& event) override;

    virtual void setInputWindows(
            const std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>>&
    void setInputWindows(const std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>>&
                                 handlesPerDisplay) override;
    virtual void setFocusedApplication(
    void setFocusedApplication(
            int32_t displayId,
            const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle) override;
    virtual void setFocusedDisplay(int32_t displayId) override;
    virtual void setInputDispatchMode(bool enabled, bool frozen) override;
    virtual void setInputFilterEnabled(bool enabled) override;
    virtual void setInTouchMode(bool inTouchMode) override;
    virtual void setMaximumObscuringOpacityForTouch(float opacity) override;
    virtual void setBlockUntrustedTouchesMode(android::os::BlockUntrustedTouchesMode mode) override;

    virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken,
    void setFocusedDisplay(int32_t displayId) override;
    void setInputDispatchMode(bool enabled, bool frozen) override;
    void setInputFilterEnabled(bool enabled) override;
    void setInTouchMode(bool inTouchMode) override;
    void setMaximumObscuringOpacityForTouch(float opacity) override;
    void setBlockUntrustedTouchesMode(android::os::BlockUntrustedTouchesMode mode) override;

    bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken,
                            bool isDragDrop = false) override;
    bool transferTouch(const sp<IBinder>& destChannelToken) override;

    virtual base::Result<std::unique_ptr<InputChannel>> createInputChannel(
    base::Result<std::unique_ptr<InputChannel>> createInputChannel(
            const std::string& name) override;
    virtual void setFocusedWindow(const FocusRequest&) override;
    virtual base::Result<std::unique_ptr<InputChannel>> createInputMonitor(int32_t displayId,
    void setFocusedWindow(const FocusRequest&) override;
    base::Result<std::unique_ptr<InputChannel>> createInputMonitor(int32_t displayId,
                                                                   bool isGestureMonitor,
                                                                   const std::string& name,
                                                                   int32_t pid) override;
    virtual status_t removeInputChannel(const sp<IBinder>& connectionToken) override;
    virtual status_t pilferPointers(const sp<IBinder>& token) override;
    virtual void requestPointerCapture(const sp<IBinder>& windowToken, bool enabled) override;
    virtual bool flushSensor(int deviceId, InputDeviceSensorType sensorType) override;
    status_t removeInputChannel(const sp<IBinder>& connectionToken) override;
    status_t pilferPointers(const sp<IBinder>& token) override;
    void requestPointerCapture(const sp<IBinder>& windowToken, bool enabled) override;
    bool flushSensor(int deviceId, InputDeviceSensorType sensorType) override;

    std::array<uint8_t, 32> sign(const VerifiedInputEvent& event) const;

+8 −0
Original line number Diff line number Diff line
@@ -151,6 +151,14 @@ public:
     */
    virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken,
                                    bool isDragDrop) = 0;

    /**
     * Transfer touch focus to the provided channel, no matter where the current touch is.
     *
     * Return true on success, false if there was no on-going touch.
     */
    virtual bool transferTouch(const sp<IBinder>& destChannelToken) = 0;

    /**
     * Sets focus on the specified window.
     */
+106 −5
Original line number Diff line number Diff line
@@ -1714,7 +1714,13 @@ TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsMotionStream) {
                         0 /*expectedFlags*/);
}

TEST_F(InputDispatcherTest, TransferTouchFocus_OnePointer) {
using TransferFunction =
        std::function<bool(sp<InputDispatcher> dispatcher, sp<IBinder>, sp<IBinder>)>;

class TransferTouchFixture : public InputDispatcherTest,
                             public ::testing::WithParamInterface<TransferFunction> {};

TEST_P(TransferTouchFixture, TransferTouch_OnePointer) {
    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();

    // Create a couple of windows
@@ -1735,8 +1741,10 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_OnePointer) {
    firstWindow->consumeMotionDown();
    secondWindow->assertNoEvents();

    // Transfer touch focus to the second window
    mDispatcher->transferTouchFocus(firstWindow->getToken(), secondWindow->getToken());
    // Transfer touch to the second window
    TransferFunction f = GetParam();
    const bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
    ASSERT_TRUE(success);
    // The first window gets cancel and the second gets down
    firstWindow->consumeMotionCancel();
    secondWindow->consumeMotionDown();
@@ -1751,7 +1759,7 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_OnePointer) {
    secondWindow->consumeMotionUp();
}

TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointerNoSplitTouch) {
TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) {
    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();

    PointF touchPoint = {10, 10};
@@ -1786,7 +1794,9 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointerNoSplitTouch) {
    secondWindow->assertNoEvents();

    // Transfer touch focus to the second window
    mDispatcher->transferTouchFocus(firstWindow->getToken(), secondWindow->getToken());
    TransferFunction f = GetParam();
    bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
    ASSERT_TRUE(success);
    // The first window gets cancel and the second gets down and pointer down
    firstWindow->consumeMotionCancel();
    secondWindow->consumeMotionDown();
@@ -1813,6 +1823,21 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointerNoSplitTouch) {
    secondWindow->consumeMotionUp();
}

// For the cases of single pointer touch and two pointers non-split touch, the api's
// 'transferTouch' and 'transferTouchFocus' are equivalent in behaviour. They only differ
// for the case where there are multiple pointers split across several windows.
INSTANTIATE_TEST_SUITE_P(TransferFunctionTests, TransferTouchFixture,
                         ::testing::Values(
                                 [&](sp<InputDispatcher> dispatcher, sp<IBinder> /*ignored*/,
                                     sp<IBinder> destChannelToken) {
                                     return dispatcher->transferTouch(destChannelToken);
                                 },
                                 [&](sp<InputDispatcher> dispatcher, sp<IBinder> from,
                                     sp<IBinder> to) {
                                     return dispatcher->transferTouchFocus(from, to,
                                                                           false /*isDragAndDrop*/);
                                 }));

TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) {
    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();

@@ -1883,6 +1908,82 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) {
    secondWindow->consumeMotionUp();
}

// Same as TransferTouchFocus_TwoPointersSplitTouch, but using 'transferTouch' api.
// Unlike 'transferTouchFocus', calling 'transferTouch' when there are two windows receiving
// touch is not supported, so the touch should continue on those windows and the transferred-to
// window should get nothing.
TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) {
    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();

    // Create a non touch modal window that supports split touch
    sp<FakeWindowHandle> firstWindow =
            new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
    firstWindow->setFrame(Rect(0, 0, 600, 400));
    firstWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL |
                          InputWindowInfo::Flag::SPLIT_TOUCH);

    // Create a non touch modal window that supports split touch
    sp<FakeWindowHandle> secondWindow =
            new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
    secondWindow->setFrame(Rect(0, 400, 600, 800));
    secondWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL |
                           InputWindowInfo::Flag::SPLIT_TOUCH);

    // Add the windows to the dispatcher
    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}});

    PointF pointInFirst = {300, 200};
    PointF pointInSecond = {300, 600};

    // Send down to the first window
    NotifyMotionArgs firstDownMotionArgs =
            generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
                               ADISPLAY_ID_DEFAULT, {pointInFirst});
    mDispatcher->notifyMotion(&firstDownMotionArgs);
    // Only the first window should get the down event
    firstWindow->consumeMotionDown();
    secondWindow->assertNoEvents();

    // Send down to the second window
    NotifyMotionArgs secondDownMotionArgs =
            generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_DOWN |
                                       (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
                               AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
                               {pointInFirst, pointInSecond});
    mDispatcher->notifyMotion(&secondDownMotionArgs);
    // The first window gets a move and the second a down
    firstWindow->consumeMotionMove();
    secondWindow->consumeMotionDown();

    // Transfer touch focus to the second window
    const bool transferred = mDispatcher->transferTouch(secondWindow->getToken());
    // The 'transferTouch' call should not succeed, because there are 2 touched windows
    ASSERT_FALSE(transferred);
    firstWindow->assertNoEvents();
    secondWindow->assertNoEvents();

    // The rest of the dispatch should proceed as normal
    // Send pointer up to the second window
    NotifyMotionArgs pointerUpMotionArgs =
            generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_UP |
                                       (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
                               AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
                               {pointInFirst, pointInSecond});
    mDispatcher->notifyMotion(&pointerUpMotionArgs);
    // The first window gets MOVE and the second gets pointer up
    firstWindow->consumeMotionMove();
    secondWindow->consumeMotionUp();

    // Send up event to the first window
    NotifyMotionArgs upMotionArgs =
            generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
                               ADISPLAY_ID_DEFAULT);
    mDispatcher->notifyMotion(&upMotionArgs);
    // The first window gets nothing and the second gets up
    firstWindow->consumeMotionUp();
    secondWindow->assertNoEvents();
}

TEST_F(InputDispatcherTest, FocusedWindow_ReceivesFocusEventAndKeyEvent) {
    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
    sp<FakeWindowHandle> window =