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

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

Merge "Pointer Icon Refactor: Integrate setPointerIconVisible" into main

parents 93a8c86d 502ddbdb
Loading
Loading
Loading
Loading
+37 −5
Original line number Diff line number Diff line
@@ -109,7 +109,9 @@ NotifyMotionArgs PointerChoreographer::processMouseEventLocked(const NotifyMotio
    const float deltaX = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
    const float deltaY = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
    pc.move(deltaX, deltaY);
    if (canUnfadeOnDisplay(displayId)) {
        pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
    }

    const auto [x, y] = pc.getPosition();
    NotifyMotionArgs newArgs(args);
@@ -131,7 +133,9 @@ NotifyMotionArgs PointerChoreographer::processTouchpadEventLocked(const NotifyMo
        const float deltaX = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
        const float deltaY = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
        pc.move(deltaX, deltaY);
        if (canUnfadeOnDisplay(displayId)) {
            pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
        }

        const auto [x, y] = pc.getPosition();
        newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
@@ -140,7 +144,9 @@ NotifyMotionArgs PointerChoreographer::processTouchpadEventLocked(const NotifyMo
        newArgs.yCursorPosition = y;
    } else {
        // This is a trackpad gesture with fake finger(s) that should not move the mouse pointer.
        if (canUnfadeOnDisplay(displayId)) {
            pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
        }

        const auto [x, y] = pc.getPosition();
        for (uint32_t i = 0; i < newArgs.getPointerCount(); i++) {
@@ -223,7 +229,7 @@ void PointerChoreographer::processStylusHoverEventLocked(const NotifyMotionArgs&
    if (args.action == AMOTION_EVENT_ACTION_HOVER_EXIT) {
        pc.fade(PointerControllerInterface::Transition::IMMEDIATE);
        pc.updatePointerIcon(PointerIconStyle::TYPE_NOT_SPECIFIED);
    } else {
    } else if (canUnfadeOnDisplay(args.displayId)) {
        pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
    }
}
@@ -323,6 +329,10 @@ InputDeviceInfo* PointerChoreographer::findInputDeviceLocked(DeviceId deviceId)
    return it != mInputDeviceInfos.end() ? &(*it) : nullptr;
}

bool PointerChoreographer::canUnfadeOnDisplay(int32_t displayId) {
    return mDisplaysWithPointersHidden.find(displayId) == mDisplaysWithPointersHidden.end();
}

void PointerChoreographer::updatePointerControllersLocked() {
    std::set<int32_t /*displayId*/> mouseDisplaysToKeep;
    std::set<DeviceId> touchDevicesToKeep;
@@ -342,7 +352,7 @@ void PointerChoreographer::updatePointerControllersLocked() {
                    mMousePointersByDisplay.try_emplace(displayId,
                                                        getMouseControllerConstructor(displayId));
            auto [_, isNewMouseDevice] = mMouseDevices.emplace(info.getId());
            if (isNewMouseDevice || isNewMousePointer) {
            if ((isNewMouseDevice || isNewMousePointer) && canUnfadeOnDisplay(displayId)) {
                mousePointerIt->second->unfade(PointerControllerInterface::Transition::IMMEDIATE);
            }
        }
@@ -513,6 +523,28 @@ bool PointerChoreographer::setPointerIcon(
    return true;
}

void PointerChoreographer::setPointerIconVisibility(int32_t displayId, bool visible) {
    std::scoped_lock lock(mLock);
    if (visible) {
        mDisplaysWithPointersHidden.erase(displayId);
        // We do not unfade the icons here, because we don't know when the last event happened.
        return;
    }

    mDisplaysWithPointersHidden.emplace(displayId);

    // Hide any icons that are currently visible on the display.
    if (auto it = mMousePointersByDisplay.find(displayId); it != mMousePointersByDisplay.end()) {
        const auto& [_, controller] = *it;
        controller->fade(PointerControllerInterface::Transition::IMMEDIATE);
    }
    for (const auto& [_, controller] : mStylusPointersByDevice) {
        if (controller->getDisplayId() == displayId) {
            controller->fade(PointerControllerInterface::Transition::IMMEDIATE);
        }
    }
}

PointerChoreographer::ControllerConstructor PointerChoreographer::getMouseControllerConstructor(
        int32_t displayId) {
    std::function<std::shared_ptr<PointerControllerInterface>()> ctor =
+8 −0
Original line number Diff line number Diff line
@@ -67,6 +67,11 @@ public:
     */
    virtual bool setPointerIcon(std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon,
                                int32_t displayId, DeviceId deviceId) = 0;
    /**
     * Set whether pointer icons for mice, touchpads, and styluses should be visible on the
     * given display.
     */
    virtual void setPointerIconVisibility(int32_t displayId, bool visible) = 0;

    /**
     * This method may be called on any thread (usually by the input manager on a binder thread).
@@ -89,6 +94,7 @@ public:
    void setStylusPointerIconEnabled(bool enabled) override;
    bool setPointerIcon(std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon,
                        int32_t displayId, DeviceId deviceId) override;
    void setPointerIconVisibility(int32_t displayId, bool visible) override;

    void notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) override;
    void notifyConfigurationChanged(const NotifyConfigurationChangedArgs& args) override;
@@ -110,6 +116,7 @@ private:
    std::pair<int32_t, PointerControllerInterface&> getDisplayIdAndMouseControllerLocked(
            int32_t associatedDisplayId) REQUIRES(mLock);
    InputDeviceInfo* findInputDeviceLocked(DeviceId deviceId) REQUIRES(mLock);
    bool canUnfadeOnDisplay(int32_t displayId) REQUIRES(mLock);

    NotifyMotionArgs processMotion(const NotifyMotionArgs& args);
    NotifyMotionArgs processMouseEventLocked(const NotifyMotionArgs& args) REQUIRES(mLock);
@@ -143,6 +150,7 @@ private:
    std::vector<DisplayViewport> mViewports GUARDED_BY(mLock);
    bool mShowTouchesEnabled GUARDED_BY(mLock);
    bool mStylusPointerIconEnabled GUARDED_BY(mLock);
    std::set<int32_t /*displayId*/> mDisplaysWithPointersHidden;
};

} // namespace android
+118 −0
Original line number Diff line number Diff line
@@ -1557,4 +1557,122 @@ TEST_F(PointerChoreographerTest, SetsPointerIconForMouseAndStylus) {
    mousePc->assertPointerIconNotSet();
}

TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerOnDisplay) {
    // Make sure there are two PointerControllers on different displays.
    mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
    mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
    mChoreographer.notifyInputDevicesChanged(
            {/*id=*/0,
             {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_NONE),
              generateTestDeviceInfo(SECOND_DEVICE_ID, AINPUT_SOURCE_MOUSE, ANOTHER_DISPLAY_ID)}});
    auto firstMousePc = assertPointerControllerCreated(ControllerType::MOUSE);
    ASSERT_EQ(DISPLAY_ID, firstMousePc->getDisplayId());
    auto secondMousePc = assertPointerControllerCreated(ControllerType::MOUSE);
    ASSERT_EQ(ANOTHER_DISPLAY_ID, secondMousePc->getDisplayId());

    // Both pointers should be visible.
    ASSERT_TRUE(firstMousePc->isPointerShown());
    ASSERT_TRUE(secondMousePc->isPointerShown());

    // Hide the icon on the second display.
    mChoreographer.setPointerIconVisibility(ANOTHER_DISPLAY_ID, false);
    ASSERT_TRUE(firstMousePc->isPointerShown());
    ASSERT_FALSE(secondMousePc->isPointerShown());

    // Move and set pointer icons for both mice. The second pointer should still be hidden.
    mChoreographer.notifyMotion(
            MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
                    .pointer(MOUSE_POINTER)
                    .deviceId(DEVICE_ID)
                    .displayId(DISPLAY_ID)
                    .build());
    mChoreographer.notifyMotion(
            MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
                    .pointer(MOUSE_POINTER)
                    .deviceId(SECOND_DEVICE_ID)
                    .displayId(ANOTHER_DISPLAY_ID)
                    .build());
    ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID));
    ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, ANOTHER_DISPLAY_ID,
                                              SECOND_DEVICE_ID));
    firstMousePc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
    secondMousePc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
    ASSERT_TRUE(firstMousePc->isPointerShown());
    ASSERT_FALSE(secondMousePc->isPointerShown());

    // Allow the icon to be visible on the second display, and move the mouse.
    mChoreographer.setPointerIconVisibility(ANOTHER_DISPLAY_ID, true);
    mChoreographer.notifyMotion(
            MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
                    .pointer(MOUSE_POINTER)
                    .deviceId(SECOND_DEVICE_ID)
                    .displayId(ANOTHER_DISPLAY_ID)
                    .build());
    ASSERT_TRUE(firstMousePc->isPointerShown());
    ASSERT_TRUE(secondMousePc->isPointerShown());
}

TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerWhenDeviceConnected) {
    mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
    mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);

    // Hide the pointer on the display, and then connect the mouse.
    mChoreographer.setPointerIconVisibility(DISPLAY_ID, false);
    mChoreographer.notifyInputDevicesChanged(
            {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_NONE)}});
    auto mousePc = assertPointerControllerCreated(ControllerType::MOUSE);
    ASSERT_EQ(DISPLAY_ID, mousePc->getDisplayId());

    // The pointer should not be visible.
    ASSERT_FALSE(mousePc->isPointerShown());
}

TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerForTouchpad) {
    mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
    mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);

    // Hide the pointer on the display.
    mChoreographer.setPointerIconVisibility(DISPLAY_ID, false);

    mChoreographer.notifyInputDevicesChanged(
            {/*id=*/0,
             {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
                                     ADISPLAY_ID_NONE)}});
    auto touchpadPc = assertPointerControllerCreated(ControllerType::MOUSE);
    ASSERT_EQ(DISPLAY_ID, touchpadPc->getDisplayId());

    mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
                                                  AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD)
                                        .pointer(TOUCHPAD_POINTER)
                                        .deviceId(DEVICE_ID)
                                        .displayId(DISPLAY_ID)
                                        .build());

    // The pointer should not be visible.
    ASSERT_FALSE(touchpadPc->isPointerShown());
}

TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerForStylus) {
    mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
    mChoreographer.setStylusPointerIconEnabled(true);

    // Hide the pointer on the display.
    mChoreographer.setPointerIconVisibility(DISPLAY_ID, false);

    mChoreographer.notifyInputDevicesChanged(
            {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID)}});
    mChoreographer.notifyMotion(
            MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
                    .pointer(STYLUS_POINTER)
                    .deviceId(DEVICE_ID)
                    .displayId(DISPLAY_ID)
                    .build());
    ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID));
    auto pc = assertPointerControllerCreated(ControllerType::STYLUS);
    pc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);

    // The pointer should not be visible.
    ASSERT_FALSE(pc->isPointerShown());
}

} // namespace android