Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2022 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #include <gtest/gtest.h> |
| 18 | #include "../PreferStylusOverTouchBlocker.h" |
| 19 | |
| 20 | namespace android { |
| 21 | |
| 22 | constexpr int32_t TOUCH_DEVICE_ID = 3; |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 23 | constexpr int32_t SECOND_TOUCH_DEVICE_ID = 4; |
| 24 | constexpr int32_t STYLUS_DEVICE_ID = 5; |
| 25 | constexpr int32_t SECOND_STYLUS_DEVICE_ID = 6; |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 26 | |
| 27 | constexpr int DOWN = AMOTION_EVENT_ACTION_DOWN; |
| 28 | constexpr int MOVE = AMOTION_EVENT_ACTION_MOVE; |
| 29 | constexpr int UP = AMOTION_EVENT_ACTION_UP; |
| 30 | constexpr int CANCEL = AMOTION_EVENT_ACTION_CANCEL; |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 31 | static constexpr int32_t POINTER_1_DOWN = |
| 32 | AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 33 | constexpr int32_t TOUCHSCREEN = AINPUT_SOURCE_TOUCHSCREEN; |
| 34 | constexpr int32_t STYLUS = AINPUT_SOURCE_STYLUS; |
| 35 | |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 36 | static NotifyMotionArgs generateMotionArgs(nsecs_t downTime, nsecs_t eventTime, int32_t action, |
Siarhei Vishniakou | b8fd3ef | 2022-10-10 08:03:54 -0700 | [diff] [blame] | 37 | const std::vector<Point>& points, uint32_t source) { |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 38 | size_t pointerCount = points.size(); |
| 39 | if (action == DOWN || action == UP) { |
| 40 | EXPECT_EQ(1U, pointerCount) << "Actions DOWN and UP can only contain a single pointer"; |
| 41 | } |
| 42 | |
| 43 | PointerProperties pointerProperties[pointerCount]; |
| 44 | PointerCoords pointerCoords[pointerCount]; |
| 45 | |
| 46 | const int32_t deviceId = isFromSource(source, TOUCHSCREEN) ? TOUCH_DEVICE_ID : STYLUS_DEVICE_ID; |
Siarhei Vishniakou | 09a8fe4 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 47 | const ToolType toolType = |
| 48 | isFromSource(source, TOUCHSCREEN) ? ToolType::FINGER : ToolType::STYLUS; |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 49 | for (size_t i = 0; i < pointerCount; i++) { |
| 50 | pointerProperties[i].clear(); |
| 51 | pointerProperties[i].id = i; |
| 52 | pointerProperties[i].toolType = toolType; |
| 53 | |
| 54 | pointerCoords[i].clear(); |
| 55 | pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, points[i].x); |
| 56 | pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, points[i].y); |
| 57 | } |
| 58 | |
| 59 | // Currently, can't have STYLUS source without it also being a TOUCH source. Update the source |
| 60 | // accordingly. |
| 61 | if (isFromSource(source, STYLUS)) { |
| 62 | source |= TOUCHSCREEN; |
| 63 | } |
| 64 | |
| 65 | // Define a valid motion event. |
Linnan Li | 13bf76a | 2024-05-05 19:18:02 +0800 | [diff] [blame] | 66 | NotifyMotionArgs args(/*id=*/0, eventTime, /*readTime=*/0, deviceId, source, |
Siarhei Vishniakou | cfbee53 | 2024-05-10 13:41:35 -0700 | [diff] [blame] | 67 | ui::LogicalDisplayId::DEFAULT, POLICY_FLAG_PASS_TO_USER, action, |
Linnan Li | 13bf76a | 2024-05-05 19:18:02 +0800 | [diff] [blame] | 68 | /* actionButton */ 0, |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 69 | /*flags=*/0, AMETA_NONE, /*buttonState=*/0, MotionClassification::NONE, |
| 70 | AMOTION_EVENT_EDGE_FLAG_NONE, pointerCount, pointerProperties, |
| 71 | pointerCoords, /*xPrecision=*/0, /*yPrecision=*/0, |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 72 | AMOTION_EVENT_INVALID_CURSOR_POSITION, |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 73 | AMOTION_EVENT_INVALID_CURSOR_POSITION, downTime, /*videoFrames=*/{}); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 74 | |
| 75 | return args; |
| 76 | } |
| 77 | |
| 78 | class PreferStylusOverTouchTest : public testing::Test { |
| 79 | protected: |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 80 | void assertNotBlocked(const NotifyMotionArgs& args) { assertResponse(args, {args}); } |
| 81 | |
| 82 | void assertDropped(const NotifyMotionArgs& args) { assertResponse(args, {}); } |
| 83 | |
| 84 | void assertResponse(const NotifyMotionArgs& args, |
| 85 | const std::vector<NotifyMotionArgs>& expected) { |
| 86 | std::vector<NotifyMotionArgs> receivedArgs = mBlocker.processMotion(args); |
| 87 | ASSERT_EQ(expected.size(), receivedArgs.size()); |
| 88 | for (size_t i = 0; i < expected.size(); i++) { |
| 89 | // The 'eventTime' of CANCEL events is dynamically generated. Don't check this field. |
| 90 | if (expected[i].action == CANCEL && receivedArgs[i].action == CANCEL) { |
| 91 | receivedArgs[i].eventTime = expected[i].eventTime; |
| 92 | } |
| 93 | |
| 94 | ASSERT_EQ(expected[i], receivedArgs[i]) |
| 95 | << expected[i].dump() << " vs " << receivedArgs[i].dump(); |
| 96 | } |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 97 | } |
| 98 | |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 99 | void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& devices) { |
| 100 | mBlocker.notifyInputDevicesChanged(devices); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 101 | } |
| 102 | |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 103 | void dump() const { ALOGI("Blocker: \n%s\n", mBlocker.dump().c_str()); } |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 104 | |
| 105 | private: |
| 106 | PreferStylusOverTouchBlocker mBlocker; |
| 107 | }; |
| 108 | |
| 109 | TEST_F(PreferStylusOverTouchTest, TouchGestureIsNotBlocked) { |
| 110 | NotifyMotionArgs args; |
| 111 | |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 112 | args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, DOWN, {{1, 2}}, TOUCHSCREEN); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 113 | assertNotBlocked(args); |
| 114 | |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 115 | args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/1, MOVE, {{1, 3}}, TOUCHSCREEN); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 116 | assertNotBlocked(args); |
| 117 | |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 118 | args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/2, UP, {{1, 3}}, TOUCHSCREEN); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 119 | assertNotBlocked(args); |
| 120 | } |
| 121 | |
| 122 | TEST_F(PreferStylusOverTouchTest, StylusGestureIsNotBlocked) { |
| 123 | NotifyMotionArgs args; |
| 124 | |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 125 | args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, DOWN, {{1, 2}}, STYLUS); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 126 | assertNotBlocked(args); |
| 127 | |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 128 | args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/1, MOVE, {{1, 3}}, STYLUS); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 129 | assertNotBlocked(args); |
| 130 | |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 131 | args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/2, UP, {{1, 3}}, STYLUS); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 132 | assertNotBlocked(args); |
| 133 | } |
| 134 | |
| 135 | /** |
| 136 | * Existing touch gesture should be canceled when stylus goes down. There should be an ACTION_CANCEL |
| 137 | * event generated. |
| 138 | */ |
| 139 | TEST_F(PreferStylusOverTouchTest, TouchIsCanceledWhenStylusGoesDown) { |
| 140 | NotifyMotionArgs args; |
| 141 | |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 142 | args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, DOWN, {{1, 2}}, TOUCHSCREEN); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 143 | assertNotBlocked(args); |
| 144 | |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 145 | args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/1, MOVE, {{1, 3}}, TOUCHSCREEN); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 146 | assertNotBlocked(args); |
| 147 | |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 148 | args = generateMotionArgs(/*downTime=*/3, /*eventTime=*/3, DOWN, {{10, 30}}, STYLUS); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 149 | NotifyMotionArgs cancelArgs = |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 150 | generateMotionArgs(/*downTime=*/0, /*eventTime=*/1, CANCEL, {{1, 3}}, TOUCHSCREEN); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 151 | cancelArgs.flags |= AMOTION_EVENT_FLAG_CANCELED; |
| 152 | assertResponse(args, {cancelArgs, args}); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 153 | |
| 154 | // Both stylus and touch events continue. Stylus should be not blocked, and touch should be |
| 155 | // blocked |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 156 | args = generateMotionArgs(/*downTime=*/3, /*eventTime=*/4, MOVE, {{10, 31}}, STYLUS); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 157 | assertNotBlocked(args); |
| 158 | |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 159 | args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/5, MOVE, {{1, 4}}, TOUCHSCREEN); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 160 | assertDropped(args); |
| 161 | } |
| 162 | |
| 163 | /** |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 164 | * Stylus goes down after touch gesture. |
| 165 | */ |
| 166 | TEST_F(PreferStylusOverTouchTest, StylusDownAfterTouch) { |
| 167 | NotifyMotionArgs args; |
| 168 | |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 169 | args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, DOWN, {{1, 2}}, TOUCHSCREEN); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 170 | assertNotBlocked(args); |
| 171 | |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 172 | args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/1, MOVE, {{1, 3}}, TOUCHSCREEN); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 173 | assertNotBlocked(args); |
| 174 | |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 175 | args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/2, UP, {{1, 3}}, TOUCHSCREEN); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 176 | assertNotBlocked(args); |
| 177 | |
| 178 | // Stylus goes down |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 179 | args = generateMotionArgs(/*downTime=*/3, /*eventTime=*/3, DOWN, {{10, 30}}, STYLUS); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 180 | assertNotBlocked(args); |
| 181 | } |
| 182 | |
| 183 | /** |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 184 | * New touch events should be simply blocked (dropped) when stylus is down. No CANCEL event should |
| 185 | * be generated. |
| 186 | */ |
| 187 | TEST_F(PreferStylusOverTouchTest, NewTouchIsBlockedWhenStylusIsDown) { |
| 188 | NotifyMotionArgs args; |
| 189 | constexpr nsecs_t stylusDownTime = 0; |
| 190 | constexpr nsecs_t touchDownTime = 1; |
| 191 | |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 192 | args = generateMotionArgs(stylusDownTime, /*eventTime=*/0, DOWN, {{10, 30}}, STYLUS); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 193 | assertNotBlocked(args); |
| 194 | |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 195 | args = generateMotionArgs(touchDownTime, /*eventTime=*/1, DOWN, {{1, 2}}, TOUCHSCREEN); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 196 | assertDropped(args); |
| 197 | |
| 198 | // Stylus should continue to work |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 199 | args = generateMotionArgs(stylusDownTime, /*eventTime=*/2, MOVE, {{10, 31}}, STYLUS); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 200 | assertNotBlocked(args); |
| 201 | |
| 202 | // Touch should continue to be blocked |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 203 | args = generateMotionArgs(touchDownTime, /*eventTime=*/1, MOVE, {{1, 3}}, TOUCHSCREEN); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 204 | assertDropped(args); |
| 205 | |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 206 | args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/5, MOVE, {{1, 4}}, TOUCHSCREEN); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 207 | assertDropped(args); |
| 208 | } |
| 209 | |
| 210 | /** |
| 211 | * New touch events should be simply blocked (dropped) when stylus is down. No CANCEL event should |
| 212 | * be generated. |
| 213 | */ |
| 214 | TEST_F(PreferStylusOverTouchTest, NewTouchWorksAfterStylusIsLifted) { |
| 215 | NotifyMotionArgs args; |
| 216 | constexpr nsecs_t stylusDownTime = 0; |
| 217 | constexpr nsecs_t touchDownTime = 4; |
| 218 | |
| 219 | // Stylus goes down and up |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 220 | args = generateMotionArgs(stylusDownTime, /*eventTime=*/0, DOWN, {{10, 30}}, STYLUS); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 221 | assertNotBlocked(args); |
| 222 | |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 223 | args = generateMotionArgs(stylusDownTime, /*eventTime=*/2, MOVE, {{10, 31}}, STYLUS); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 224 | assertNotBlocked(args); |
| 225 | |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 226 | args = generateMotionArgs(stylusDownTime, /*eventTime=*/3, UP, {{10, 31}}, STYLUS); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 227 | assertNotBlocked(args); |
| 228 | |
| 229 | // New touch goes down. It should not be blocked |
| 230 | args = generateMotionArgs(touchDownTime, touchDownTime, DOWN, {{1, 2}}, TOUCHSCREEN); |
| 231 | assertNotBlocked(args); |
| 232 | |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 233 | args = generateMotionArgs(touchDownTime, /*eventTime=*/5, MOVE, {{1, 3}}, TOUCHSCREEN); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 234 | assertNotBlocked(args); |
| 235 | |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 236 | args = generateMotionArgs(touchDownTime, /*eventTime=*/6, UP, {{1, 3}}, TOUCHSCREEN); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 237 | assertNotBlocked(args); |
| 238 | } |
| 239 | |
| 240 | /** |
| 241 | * Once a touch gesture is canceled, it should continue to be canceled, even if the stylus has been |
| 242 | * lifted. |
| 243 | */ |
| 244 | TEST_F(PreferStylusOverTouchTest, AfterStylusIsLiftedCurrentTouchIsBlocked) { |
| 245 | NotifyMotionArgs args; |
| 246 | constexpr nsecs_t stylusDownTime = 0; |
| 247 | constexpr nsecs_t touchDownTime = 1; |
| 248 | |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 249 | assertNotBlocked(generateMotionArgs(stylusDownTime, /*eventTime=*/0, DOWN, {{10, 30}}, STYLUS)); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 250 | |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 251 | args = generateMotionArgs(touchDownTime, /*eventTime=*/1, DOWN, {{1, 2}}, TOUCHSCREEN); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 252 | assertDropped(args); |
| 253 | |
| 254 | // Lift the stylus |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 255 | args = generateMotionArgs(stylusDownTime, /*eventTime=*/2, UP, {{10, 30}}, STYLUS); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 256 | assertNotBlocked(args); |
| 257 | |
| 258 | // Touch should continue to be blocked |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 259 | args = generateMotionArgs(touchDownTime, /*eventTime=*/3, MOVE, {{1, 3}}, TOUCHSCREEN); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 260 | assertDropped(args); |
| 261 | |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 262 | args = generateMotionArgs(touchDownTime, /*eventTime=*/4, UP, {{1, 3}}, TOUCHSCREEN); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 263 | assertDropped(args); |
| 264 | |
| 265 | // New touch should go through, though. |
| 266 | constexpr nsecs_t newTouchDownTime = 5; |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 267 | args = generateMotionArgs(newTouchDownTime, /*eventTime=*/5, DOWN, {{10, 20}}, TOUCHSCREEN); |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 268 | assertNotBlocked(args); |
| 269 | } |
| 270 | |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 271 | /** |
| 272 | * If an event with mixed stylus and touch pointers is encountered, it should be ignored. Touches |
| 273 | * from such should pass, even if stylus from the same device goes down. |
| 274 | */ |
| 275 | TEST_F(PreferStylusOverTouchTest, MixedStylusAndTouchPointersAreIgnored) { |
| 276 | NotifyMotionArgs args; |
| 277 | |
| 278 | // Event from a stylus device, but with finger tool type |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 279 | args = generateMotionArgs(/*downTime=*/1, /*eventTime=*/1, DOWN, {{1, 2}}, STYLUS); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 280 | // Keep source stylus, but make the tool type touch |
Siarhei Vishniakou | 09a8fe4 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 281 | args.pointerProperties[0].toolType = ToolType::FINGER; |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 282 | assertNotBlocked(args); |
| 283 | |
| 284 | // Second pointer (stylus pointer) goes down, from the same device |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 285 | args = generateMotionArgs(/*downTime=*/1, /*eventTime=*/2, POINTER_1_DOWN, {{1, 2}, {10, 20}}, |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 286 | STYLUS); |
| 287 | // Keep source stylus, but make the tool type touch |
Siarhei Vishniakou | 09a8fe4 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 288 | args.pointerProperties[0].toolType = ToolType::STYLUS; |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 289 | assertNotBlocked(args); |
| 290 | |
| 291 | // Second pointer (stylus pointer) goes down, from the same device |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 292 | args = generateMotionArgs(/*downTime=*/1, /*eventTime=*/3, MOVE, {{2, 3}, {11, 21}}, STYLUS); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 293 | // Keep source stylus, but make the tool type touch |
Siarhei Vishniakou | 09a8fe4 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 294 | args.pointerProperties[0].toolType = ToolType::FINGER; |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 295 | assertNotBlocked(args); |
| 296 | } |
| 297 | |
| 298 | /** |
| 299 | * When there are two touch devices, stylus down should cancel all current touch streams. |
| 300 | */ |
| 301 | TEST_F(PreferStylusOverTouchTest, TouchFromTwoDevicesAndStylus) { |
| 302 | NotifyMotionArgs touch1Down = |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 303 | generateMotionArgs(/*downTime=*/1, /*eventTime=*/1, DOWN, {{1, 2}}, TOUCHSCREEN); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 304 | assertNotBlocked(touch1Down); |
| 305 | |
| 306 | NotifyMotionArgs touch2Down = |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 307 | generateMotionArgs(/*downTime=*/2, /*eventTime=*/2, DOWN, {{3, 4}}, TOUCHSCREEN); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 308 | touch2Down.deviceId = SECOND_TOUCH_DEVICE_ID; |
| 309 | assertNotBlocked(touch2Down); |
| 310 | |
| 311 | NotifyMotionArgs stylusDown = |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 312 | generateMotionArgs(/*downTime=*/3, /*eventTime=*/3, DOWN, {{10, 30}}, STYLUS); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 313 | NotifyMotionArgs cancelArgs1 = touch1Down; |
| 314 | cancelArgs1.action = CANCEL; |
| 315 | cancelArgs1.flags |= AMOTION_EVENT_FLAG_CANCELED; |
| 316 | NotifyMotionArgs cancelArgs2 = touch2Down; |
| 317 | cancelArgs2.action = CANCEL; |
| 318 | cancelArgs2.flags |= AMOTION_EVENT_FLAG_CANCELED; |
| 319 | assertResponse(stylusDown, {cancelArgs1, cancelArgs2, stylusDown}); |
| 320 | } |
| 321 | |
| 322 | /** |
| 323 | * Touch should be canceled when stylus goes down. After the stylus lifts up, the touch from that |
| 324 | * device should continue to be canceled. |
| 325 | * If one of the devices is already canceled, it should remain canceled, but new touches from a |
| 326 | * different device should go through. |
| 327 | */ |
| 328 | TEST_F(PreferStylusOverTouchTest, AllTouchMustLiftAfterCanceledByStylus) { |
| 329 | // First device touches down |
| 330 | NotifyMotionArgs touch1Down = |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 331 | generateMotionArgs(/*downTime=*/1, /*eventTime=*/1, DOWN, {{1, 2}}, TOUCHSCREEN); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 332 | assertNotBlocked(touch1Down); |
| 333 | |
| 334 | // Stylus goes down - touch should be canceled |
| 335 | NotifyMotionArgs stylusDown = |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 336 | generateMotionArgs(/*downTime=*/2, /*eventTime=*/2, DOWN, {{10, 30}}, STYLUS); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 337 | NotifyMotionArgs cancelArgs1 = touch1Down; |
| 338 | cancelArgs1.action = CANCEL; |
| 339 | cancelArgs1.flags |= AMOTION_EVENT_FLAG_CANCELED; |
| 340 | assertResponse(stylusDown, {cancelArgs1, stylusDown}); |
| 341 | |
| 342 | // Stylus goes up |
| 343 | NotifyMotionArgs stylusUp = |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 344 | generateMotionArgs(/*downTime=*/2, /*eventTime=*/3, UP, {{10, 30}}, STYLUS); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 345 | assertNotBlocked(stylusUp); |
| 346 | |
| 347 | // Touch from the first device remains blocked |
| 348 | NotifyMotionArgs touch1Move = |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 349 | generateMotionArgs(/*downTime=*/1, /*eventTime=*/4, MOVE, {{2, 3}}, TOUCHSCREEN); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 350 | assertDropped(touch1Move); |
| 351 | |
| 352 | // Second touch goes down. It should not be blocked because stylus has already lifted. |
| 353 | NotifyMotionArgs touch2Down = |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 354 | generateMotionArgs(/*downTime=*/5, /*eventTime=*/5, DOWN, {{31, 32}}, TOUCHSCREEN); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 355 | touch2Down.deviceId = SECOND_TOUCH_DEVICE_ID; |
| 356 | assertNotBlocked(touch2Down); |
| 357 | |
| 358 | // First device is lifted up. It's already been canceled, so the UP event should be dropped. |
| 359 | NotifyMotionArgs touch1Up = |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 360 | generateMotionArgs(/*downTime=*/1, /*eventTime=*/6, UP, {{2, 3}}, TOUCHSCREEN); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 361 | assertDropped(touch1Up); |
| 362 | |
| 363 | // Touch from second device touch should continue to work |
| 364 | NotifyMotionArgs touch2Move = |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 365 | generateMotionArgs(/*downTime=*/5, /*eventTime=*/7, MOVE, {{32, 33}}, TOUCHSCREEN); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 366 | touch2Move.deviceId = SECOND_TOUCH_DEVICE_ID; |
| 367 | assertNotBlocked(touch2Move); |
| 368 | |
| 369 | // Second touch lifts up |
| 370 | NotifyMotionArgs touch2Up = |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 371 | generateMotionArgs(/*downTime=*/5, /*eventTime=*/8, UP, {{32, 33}}, TOUCHSCREEN); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 372 | touch2Up.deviceId = SECOND_TOUCH_DEVICE_ID; |
| 373 | assertNotBlocked(touch2Up); |
| 374 | |
| 375 | // Now that all touch has been lifted, new touch from either first or second device should work |
| 376 | NotifyMotionArgs touch3Down = |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 377 | generateMotionArgs(/*downTime=*/9, /*eventTime=*/9, DOWN, {{1, 2}}, TOUCHSCREEN); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 378 | assertNotBlocked(touch3Down); |
| 379 | |
| 380 | NotifyMotionArgs touch4Down = |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 381 | generateMotionArgs(/*downTime=*/10, /*eventTime=*/10, DOWN, {{100, 200}}, TOUCHSCREEN); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 382 | touch4Down.deviceId = SECOND_TOUCH_DEVICE_ID; |
| 383 | assertNotBlocked(touch4Down); |
| 384 | } |
| 385 | |
| 386 | /** |
| 387 | * When we don't know that a specific device does both stylus and touch, and we only see touch |
| 388 | * pointers from it, we should treat it as a touch device. That means, the device events should be |
| 389 | * canceled when stylus from another device goes down. When we detect simultaneous touch and stylus |
| 390 | * from this device though, we should just pass this device through without canceling anything. |
| 391 | * |
| 392 | * In this test: |
| 393 | * 1. Start by touching down with device 1 |
| 394 | * 2. Device 2 has stylus going down |
| 395 | * 3. Device 1 should be canceled. |
| 396 | * 4. When we add stylus pointers to the device 1, they should continue to be canceled. |
| 397 | * 5. Device 1 lifts up. |
| 398 | * 6. Subsequent events from device 1 should not be canceled even if stylus is down. |
| 399 | * 7. If a reset happens, and such device is no longer there, then we should |
| 400 | * Therefore, the device 1 is "ignored" and does not participate into "prefer stylus over touch" |
| 401 | * behaviour. |
| 402 | */ |
| 403 | TEST_F(PreferStylusOverTouchTest, MixedStylusAndTouchDeviceIsCanceledAtFirst) { |
| 404 | // Touch from device 1 goes down |
| 405 | NotifyMotionArgs touchDown = |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 406 | generateMotionArgs(/*downTime=*/1, /*eventTime=*/1, DOWN, {{1, 2}}, TOUCHSCREEN); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 407 | touchDown.source = STYLUS; |
| 408 | assertNotBlocked(touchDown); |
| 409 | |
| 410 | // Stylus from device 2 goes down. Touch should be canceled. |
| 411 | NotifyMotionArgs args = |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 412 | generateMotionArgs(/*downTime=*/2, /*eventTime=*/2, DOWN, {{10, 20}}, STYLUS); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 413 | NotifyMotionArgs cancelTouchArgs = touchDown; |
| 414 | cancelTouchArgs.action = CANCEL; |
| 415 | cancelTouchArgs.flags |= AMOTION_EVENT_FLAG_CANCELED; |
| 416 | assertResponse(args, {cancelTouchArgs, args}); |
| 417 | |
| 418 | // Introduce a stylus pointer into the device 1 stream. It should be ignored. |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 419 | args = generateMotionArgs(/*downTime=*/1, /*eventTime=*/3, POINTER_1_DOWN, {{1, 2}, {3, 4}}, |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 420 | TOUCHSCREEN); |
Siarhei Vishniakou | 09a8fe4 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 421 | args.pointerProperties[1].toolType = ToolType::STYLUS; |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 422 | args.source = STYLUS; |
| 423 | assertDropped(args); |
| 424 | |
| 425 | // Lift up touch from the mixed touch/stylus device |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 426 | args = generateMotionArgs(/*downTime=*/1, /*eventTime=*/4, CANCEL, {{1, 2}, {3, 4}}, |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 427 | TOUCHSCREEN); |
Siarhei Vishniakou | 09a8fe4 | 2022-07-21 17:27:03 -0700 | [diff] [blame] | 428 | args.pointerProperties[1].toolType = ToolType::STYLUS; |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 429 | args.source = STYLUS; |
| 430 | assertDropped(args); |
| 431 | |
| 432 | // Stylus from device 2 is still down. Since the device 1 is now identified as a mixed |
| 433 | // touch/stylus device, its events should go through, even if they are touch. |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 434 | args = generateMotionArgs(/*downTime=*/5, /*eventTime=*/5, DOWN, {{21, 22}}, TOUCHSCREEN); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 435 | touchDown.source = STYLUS; |
| 436 | assertResponse(args, {args}); |
| 437 | |
| 438 | // Reconfigure such that only the stylus device remains |
| 439 | InputDeviceInfo stylusDevice; |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 440 | stylusDevice.initialize(STYLUS_DEVICE_ID, /*generation=*/1, /*controllerNumber=*/1, |
| 441 | /*identifier=*/{}, "stylus device", /*external=*/false, |
Siarhei Vishniakou | cfbee53 | 2024-05-10 13:41:35 -0700 | [diff] [blame] | 442 | /*hasMic=*/false, ui::LogicalDisplayId::INVALID); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 443 | notifyInputDevicesChanged({stylusDevice}); |
| 444 | // The touchscreen device was removed, so we no longer remember anything about it. We should |
| 445 | // again start blocking touch events from it. |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 446 | args = generateMotionArgs(/*downTime=*/6, /*eventTime=*/6, DOWN, {{1, 2}}, TOUCHSCREEN); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 447 | args.source = STYLUS; |
| 448 | assertDropped(args); |
| 449 | } |
| 450 | |
| 451 | /** |
| 452 | * If two styli are active at the same time, touch should be blocked until both of them are lifted. |
| 453 | * If one of them lifts, touch should continue to be blocked. |
| 454 | */ |
| 455 | TEST_F(PreferStylusOverTouchTest, TouchIsBlockedWhenTwoStyliAreUsed) { |
| 456 | NotifyMotionArgs args; |
| 457 | |
| 458 | // First stylus is down |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 459 | assertNotBlocked(generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, DOWN, {{10, 30}}, STYLUS)); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 460 | |
| 461 | // Second stylus is down |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 462 | args = generateMotionArgs(/*downTime=*/1, /*eventTime=*/1, DOWN, {{20, 40}}, STYLUS); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 463 | args.deviceId = SECOND_STYLUS_DEVICE_ID; |
| 464 | assertNotBlocked(args); |
| 465 | |
| 466 | // Touch goes down. It should be ignored. |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 467 | args = generateMotionArgs(/*downTime=*/2, /*eventTime=*/2, DOWN, {{1, 2}}, TOUCHSCREEN); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 468 | assertDropped(args); |
| 469 | |
| 470 | // Lift the first stylus |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 471 | args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/3, UP, {{10, 30}}, STYLUS); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 472 | assertNotBlocked(args); |
| 473 | |
| 474 | // Touch should continue to be blocked |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 475 | args = generateMotionArgs(/*downTime=*/2, /*eventTime=*/4, UP, {{1, 2}}, TOUCHSCREEN); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 476 | assertDropped(args); |
| 477 | |
| 478 | // New touch should be blocked because second stylus is still down |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 479 | args = generateMotionArgs(/*downTime=*/5, /*eventTime=*/5, DOWN, {{5, 6}}, TOUCHSCREEN); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 480 | assertDropped(args); |
| 481 | |
| 482 | // Second stylus goes up |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 483 | args = generateMotionArgs(/*downTime=*/1, /*eventTime=*/6, UP, {{20, 40}}, STYLUS); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 484 | args.deviceId = SECOND_STYLUS_DEVICE_ID; |
| 485 | assertNotBlocked(args); |
| 486 | |
| 487 | // Current touch gesture should continue to be blocked |
| 488 | // Touch should continue to be blocked |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 489 | args = generateMotionArgs(/*downTime=*/5, /*eventTime=*/7, UP, {{5, 6}}, TOUCHSCREEN); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 490 | assertDropped(args); |
| 491 | |
| 492 | // Now that all styli were lifted, new touch should go through |
Harry Cutts | 3347623 | 2023-01-30 19:57:29 +0000 | [diff] [blame] | 493 | args = generateMotionArgs(/*downTime=*/8, /*eventTime=*/8, DOWN, {{7, 8}}, TOUCHSCREEN); |
Siarhei Vishniakou | a6a660f | 2022-03-04 15:12:16 -0800 | [diff] [blame] | 494 | assertNotBlocked(args); |
| 495 | } |
| 496 | |
Siarhei Vishniakou | a3c8e51 | 2022-02-10 19:46:34 -0800 | [diff] [blame] | 497 | } // namespace android |