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
diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig
index b8a8d76..f1c4aed 100644
--- a/libs/input/input_flags.aconfig
+++ b/libs/input/input_flags.aconfig
@@ -185,3 +185,10 @@
   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"
+}
diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
index 9924d0d..feabb4e 100644
--- a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
@@ -60,6 +60,21 @@
     }
 }
 
+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 @@
       : 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 @@
                                                   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 @@
             /* policyFlags= */ POLICY_FLAG_WAKE,
             action,
             /* actionButton= */ actionButton,
-            /* flags= */ action == AMOTION_EVENT_ACTION_CANCEL ? AMOTION_EVENT_FLAG_CANCELED : 0,
+            flags,
             mReaderContext.getGlobalMetaState(),
             buttonState,
             mCurrentClassification,
diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.h b/services/inputflinger/reader/mapper/gestures/GestureConverter.h
index 829fb92..c9a35c1 100644
--- a/services/inputflinger/reader/mapper/gestures/GestureConverter.h
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.h
@@ -99,6 +99,7 @@
     const int32_t mDeviceId;
     InputReaderContext& mReaderContext;
     const bool mEnableFlingStop;
+    const bool mEnableNoFocusChange;
 
     std::optional<ui::LogicalDisplayId> mDisplayId;
     FloatRect mBoundsInLogicalDisplay{};
diff --git a/services/inputflinger/tests/GestureConverter_test.cpp b/services/inputflinger/tests/GestureConverter_test.cpp
index d0cd677..225ae0f 100644
--- a/services/inputflinger/tests/GestureConverter_test.cpp
+++ b/services/inputflinger/tests/GestureConverter_test.cpp
@@ -279,6 +279,8 @@
 }
 
 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 @@
     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 @@
                               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 @@
                                           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, 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 @@
                         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 @@
                               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 @@
                                                   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_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 @@
                         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 @@
                               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 @@
                                                   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, 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 @@
                                           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),