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

Commit dd62ddc2 authored by Hiroki Sato's avatar Hiroki Sato
Browse files

Don't affect window focus on touchpad gesture

When using a multi-touch touchpad, it is the expected behavior in most
operating systems that the user is allowed to perform gestures (like
scroll, pinch, etc.) on an unfocused window without bringing it into
focus.

This change adds the NO_FOCUS_CHANGE flag to the MotionEvents generated
by GestureConverter. The behavior was initially added in commit [1] in
TouchInputMapper, but got lost when touchpad stack was introduced.

[1] I74e52f8daa13d4e6c047bc23982ec56942c555f6

Bug: 364460018
Test: GestureConverterTest
Test: Manually open two windows on desktop mode, and see if gesture won't change focus
Flag: com.android.input.flags.enable_touchpad_no_focus_change
Change-Id: I370189260c96965698ee2d0885edf32378dbca74
parent 385c3cec
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -185,3 +185,10 @@ flag {
  description: "Collect quality metrics on framework palm rejection."
  bug: "341717757"
}

flag {
  name: "enable_touchpad_no_focus_change"
  namespace: "input"
  description: "Prevents touchpad gesture changing window focus."
  bug: "364460018"
}
+25 −1
Original line number Diff line number Diff line
@@ -60,6 +60,21 @@ uint32_t gesturesButtonToMotionEventButton(uint32_t gesturesButton) {
    }
}

bool isGestureNoFocusChange(MotionClassification classification) {
    switch (classification) {
        case MotionClassification::TWO_FINGER_SWIPE:
        case MotionClassification::MULTI_FINGER_SWIPE:
        case MotionClassification::PINCH:
            // Most gestures can be performed on an unfocused window, so they should not
            // not affect window focus.
            return true;
        case MotionClassification::NONE:
        case MotionClassification::AMBIGUOUS_GESTURE:
        case MotionClassification::DEEP_PRESS:
            return false;
    }
}

} // namespace

GestureConverter::GestureConverter(InputReaderContext& readerContext,
@@ -67,6 +82,7 @@ GestureConverter::GestureConverter(InputReaderContext& readerContext,
      : mDeviceId(deviceId),
        mReaderContext(readerContext),
        mEnableFlingStop(input_flags::enable_touchpad_fling_stop()),
        mEnableNoFocusChange(input_flags::enable_touchpad_no_focus_change()),
        // We can safely assume that ABS_MT_POSITION_X and _Y axes will be available, as EventHub
        // won't classify a device as a touchpad if they're not present.
        mXAxisInfo(deviceContext.getAbsoluteAxisInfo(ABS_MT_POSITION_X).value()),
@@ -624,6 +640,14 @@ NotifyMotionArgs GestureConverter::makeMotionArgs(nsecs_t when, nsecs_t readTime
                                                  int32_t actionButton, int32_t buttonState,
                                                  uint32_t pointerCount,
                                                  const PointerCoords* pointerCoords) {
    int32_t flags = 0;
    if (action == AMOTION_EVENT_ACTION_CANCEL) {
        flags |= AMOTION_EVENT_FLAG_CANCELED;
    }
    if (mEnableNoFocusChange && isGestureNoFocusChange(mCurrentClassification)) {
        flags |= AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE;
    }

    return {mReaderContext.getNextId(),
            when,
            readTime,
@@ -633,7 +657,7 @@ NotifyMotionArgs GestureConverter::makeMotionArgs(nsecs_t when, nsecs_t readTime
            /* policyFlags= */ POLICY_FLAG_WAKE,
            action,
            /* actionButton= */ actionButton,
            /* flags= */ action == AMOTION_EVENT_ACTION_CANCEL ? AMOTION_EVENT_FLAG_CANCELED : 0,
            flags,
            mReaderContext.getGlobalMetaState(),
            buttonState,
            mCurrentClassification,
+1 −0
Original line number Diff line number Diff line
@@ -99,6 +99,7 @@ private:
    const int32_t mDeviceId;
    InputReaderContext& mReaderContext;
    const bool mEnableFlingStop;
    const bool mEnableNoFocusChange;

    std::optional<ui::LogicalDisplayId> mDisplayId;
    FloatRect mBoundsInLogicalDisplay{};
+32 −12
Original line number Diff line number Diff line
@@ -279,6 +279,8 @@ TEST_F(GestureConverterTest, DragWithButton) {
}

TEST_F(GestureConverterTest, Scroll) {
    input_flags::enable_touchpad_no_focus_change(true);

    const nsecs_t downTime = 12345;
    InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
    GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
@@ -300,7 +302,8 @@ TEST_F(GestureConverterTest, Scroll) {
    ASSERT_THAT(args,
                Each(VariantWith<NotifyMotionArgs>(
                        AllOf(WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE),
                              WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE),
                              WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE |
                                        AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE),
                              WithToolType(ToolType::FINGER),
                              WithDisplayId(ui::LogicalDisplayId::DEFAULT)))));

@@ -312,7 +315,8 @@ TEST_F(GestureConverterTest, Scroll) {
                              WithGestureScrollDistance(0, 5, EPSILON),
                              WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE),
                              WithToolType(ToolType::FINGER),
                              WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE),
                              WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE |
                                        AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE),
                              WithDisplayId(ui::LogicalDisplayId::DEFAULT)))));

    Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 1, 1,
@@ -325,7 +329,8 @@ TEST_F(GestureConverterTest, Scroll) {
                                          WithGestureScrollDistance(0, 0, EPSILON),
                                          WithMotionClassification(
                                                  MotionClassification::TWO_FINGER_SWIPE),
                                          WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE))),
                                          WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE |
                                                    AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))),
                            VariantWith<NotifyMotionArgs>(
                                    AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
                                          WithCoords(0, 0),
@@ -845,6 +850,8 @@ TEST_F(GestureConverterTest, FourFingerSwipe_Horizontal) {
}

TEST_F(GestureConverterTest, Pinch_Inwards) {
    input_flags::enable_touchpad_no_focus_change(true);

    InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
    GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
    converter.setDisplayId(ui::LogicalDisplayId::DEFAULT);
@@ -867,7 +874,8 @@ TEST_F(GestureConverterTest, Pinch_Inwards) {
                        AllOf(WithMotionClassification(MotionClassification::PINCH),
                              WithGesturePinchScaleFactor(1.0f, EPSILON),
                              WithToolType(ToolType::FINGER),
                              WithDisplayId(ui::LogicalDisplayId::DEFAULT)))));
                              WithDisplayId(ui::LogicalDisplayId::DEFAULT),
                              WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)))));

    Gesture updateGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
                          /* dz= */ 0.8, GESTURES_ZOOM_UPDATE);
@@ -879,7 +887,8 @@ TEST_F(GestureConverterTest, Pinch_Inwards) {
                              WithGesturePinchScaleFactor(0.8f, EPSILON),
                              WithPointerCoords(0, -80, 0), WithPointerCoords(1, 80, 0),
                              WithPointerCount(2u), WithToolType(ToolType::FINGER),
                              WithDisplayId(ui::LogicalDisplayId::DEFAULT)))));
                              WithDisplayId(ui::LogicalDisplayId::DEFAULT),
                              WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)))));

    Gesture endGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1,
                       GESTURES_ZOOM_END);
@@ -891,12 +900,14 @@ TEST_F(GestureConverterTest, Pinch_Inwards) {
                                                  1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
                                          WithMotionClassification(MotionClassification::PINCH),
                                          WithGesturePinchScaleFactor(1.0f, EPSILON),
                                          WithPointerCount(2u))),
                                          WithPointerCount(2u),
                                          WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))),
                            VariantWith<NotifyMotionArgs>(
                                    AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
                                          WithMotionClassification(MotionClassification::PINCH),
                                          WithGesturePinchScaleFactor(1.0f, EPSILON),
                                          WithPointerCount(1u))),
                                          WithPointerCount(1u),
                                          WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))),
                            VariantWith<NotifyMotionArgs>(
                                    AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
                                          WithCoords(0, 0),
@@ -908,6 +919,8 @@ TEST_F(GestureConverterTest, Pinch_Inwards) {
}

TEST_F(GestureConverterTest, Pinch_Outwards) {
    input_flags::enable_touchpad_no_focus_change(true);

    InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
    GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
    converter.setDisplayId(ui::LogicalDisplayId::DEFAULT);
@@ -930,7 +943,8 @@ TEST_F(GestureConverterTest, Pinch_Outwards) {
                        AllOf(WithMotionClassification(MotionClassification::PINCH),
                              WithGesturePinchScaleFactor(1.0f, EPSILON),
                              WithToolType(ToolType::FINGER),
                              WithDisplayId(ui::LogicalDisplayId::DEFAULT)))));
                              WithDisplayId(ui::LogicalDisplayId::DEFAULT),
                              WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)))));

    Gesture updateGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
                          /* dz= */ 1.1, GESTURES_ZOOM_UPDATE);
@@ -942,7 +956,8 @@ TEST_F(GestureConverterTest, Pinch_Outwards) {
                              WithGesturePinchScaleFactor(1.1f, EPSILON),
                              WithPointerCoords(0, -110, 0), WithPointerCoords(1, 110, 0),
                              WithPointerCount(2u), WithToolType(ToolType::FINGER),
                              WithDisplayId(ui::LogicalDisplayId::DEFAULT)))));
                              WithDisplayId(ui::LogicalDisplayId::DEFAULT),
                              WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)))));

    Gesture endGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1,
                       GESTURES_ZOOM_END);
@@ -954,12 +969,14 @@ TEST_F(GestureConverterTest, Pinch_Outwards) {
                                                  1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
                                          WithMotionClassification(MotionClassification::PINCH),
                                          WithGesturePinchScaleFactor(1.0f, EPSILON),
                                          WithPointerCount(2u))),
                                          WithPointerCount(2u),
                                          WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))),
                            VariantWith<NotifyMotionArgs>(
                                    AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
                                          WithMotionClassification(MotionClassification::PINCH),
                                          WithGesturePinchScaleFactor(1.0f, EPSILON),
                                          WithPointerCount(1u))),
                                          WithPointerCount(1u),
                                          WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))),
                            VariantWith<NotifyMotionArgs>(
                                    AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
                                          WithCoords(0, 0),
@@ -1055,6 +1072,8 @@ TEST_F(GestureConverterTest, ResetWithButtonPressed) {
}

TEST_F(GestureConverterTest, ResetDuringScroll) {
    input_flags::enable_touchpad_no_focus_change(true);

    InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
    GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
    converter.setDisplayId(ui::LogicalDisplayId::DEFAULT);
@@ -1070,7 +1089,8 @@ TEST_F(GestureConverterTest, ResetDuringScroll) {
                                          WithGestureScrollDistance(0, 0, EPSILON),
                                          WithMotionClassification(
                                                  MotionClassification::TWO_FINGER_SWIPE),
                                          WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE))),
                                          WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE |
                                                    AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))),
                            VariantWith<NotifyMotionArgs>(
                                    AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
                                          WithCoords(0, 0),