OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "ui/touch_selection/longpress_drag_selector.h" |
| 6 |
| 7 #include "testing/gtest/include/gtest/gtest.h" |
| 8 #include "ui/events/test/motion_event_test_utils.h" |
| 9 |
| 10 using ui::test::MockMotionEvent; |
| 11 |
| 12 namespace ui { |
| 13 namespace { |
| 14 |
| 15 const double kSlop = 10.; |
| 16 |
| 17 } // namespace |
| 18 |
| 19 class LongPressDragSelectorTest : public testing::Test, |
| 20 public LongPressDragSelectorClient { |
| 21 public: |
| 22 LongPressDragSelectorTest() |
| 23 : dragging_(false), active_state_changed_(false) {} |
| 24 |
| 25 ~LongPressDragSelectorTest() override {} |
| 26 |
| 27 void SetSelection(const gfx::PointF& start, const gfx::PointF& end) { |
| 28 selection_start_ = start; |
| 29 selection_end_ = end; |
| 30 } |
| 31 |
| 32 bool GetAndResetActiveStateChanged() { |
| 33 bool active_state_changed = active_state_changed_; |
| 34 active_state_changed_ = false; |
| 35 return active_state_changed; |
| 36 } |
| 37 |
| 38 bool IsDragging() const { return dragging_; } |
| 39 const gfx::PointF& DragPosition() const { return drag_position_; } |
| 40 |
| 41 // LongPressDragSelectorClient implementation. |
| 42 void OnDragBegin(const TouchSelectionDraggable& handler, |
| 43 const gfx::PointF& drag_position) override { |
| 44 dragging_ = true; |
| 45 drag_position_ = drag_position; |
| 46 } |
| 47 |
| 48 void OnDragUpdate(const TouchSelectionDraggable& handler, |
| 49 const gfx::PointF& drag_position) override { |
| 50 drag_position_ = drag_position; |
| 51 } |
| 52 |
| 53 void OnDragEnd(const TouchSelectionDraggable& handler) override { |
| 54 dragging_ = false; |
| 55 } |
| 56 |
| 57 bool IsWithinTapSlop(const gfx::Vector2dF& delta) const override { |
| 58 return delta.LengthSquared() < (kSlop * kSlop); |
| 59 } |
| 60 |
| 61 void OnLongPressDragActiveStateChanged() override { |
| 62 active_state_changed_ = true; |
| 63 } |
| 64 |
| 65 gfx::PointF GetSelectionStart() const override { return selection_start_; } |
| 66 |
| 67 gfx::PointF GetSelectionEnd() const override { return selection_end_; } |
| 68 |
| 69 private: |
| 70 bool dragging_; |
| 71 bool active_state_changed_; |
| 72 gfx::PointF drag_position_; |
| 73 |
| 74 gfx::PointF selection_start_; |
| 75 gfx::PointF selection_end_; |
| 76 }; |
| 77 |
| 78 TEST_F(LongPressDragSelectorTest, BasicDrag) { |
| 79 LongPressDragSelector selector(this); |
| 80 MockMotionEvent event; |
| 81 |
| 82 // Start a touch sequence. |
| 83 EXPECT_FALSE(selector.WillHandleTouchEvent(event.PressPoint(0, 0))); |
| 84 EXPECT_FALSE(GetAndResetActiveStateChanged()); |
| 85 |
| 86 // Activate a longpress-triggered selection. |
| 87 gfx::PointF selection_start(0, 10); |
| 88 gfx::PointF selection_end(10, 10); |
| 89 selector.OnLongPressEvent(event.GetEventTime(), gfx::PointF()); |
| 90 EXPECT_TRUE(GetAndResetActiveStateChanged()); |
| 91 |
| 92 // Motion should not be consumed until a selection is detected. |
| 93 EXPECT_FALSE(selector.WillHandleTouchEvent(event.MovePoint(0, 0, 0))); |
| 94 SetSelection(selection_start, selection_end); |
| 95 selector.OnSelectionActivated(); |
| 96 EXPECT_FALSE(IsDragging()); |
| 97 |
| 98 // Initiate drag motion. Note that the first move event after activation is |
| 99 // used to initialize the drag start anchor. |
| 100 EXPECT_TRUE(selector.WillHandleTouchEvent(event.MovePoint(0, 0, 0))); |
| 101 EXPECT_FALSE(IsDragging()); |
| 102 |
| 103 // The first slop exceeding motion will start the drag. As the motion is |
| 104 // downward, the end selection point should be moved. |
| 105 EXPECT_TRUE(selector.WillHandleTouchEvent(event.MovePoint(0, 0, kSlop))); |
| 106 EXPECT_TRUE(IsDragging()); |
| 107 EXPECT_EQ(selection_end, DragPosition()); |
| 108 |
| 109 // Subsequent motion will extend the selection. |
| 110 EXPECT_TRUE(selector.WillHandleTouchEvent(event.MovePoint(0, 0, kSlop * 2))); |
| 111 EXPECT_TRUE(IsDragging()); |
| 112 EXPECT_EQ(selection_end + gfx::Vector2dF(0, kSlop), DragPosition()); |
| 113 EXPECT_TRUE(selector.WillHandleTouchEvent(event.MovePoint(0, 0, kSlop * 3))); |
| 114 EXPECT_TRUE(IsDragging()); |
| 115 EXPECT_EQ(selection_end + gfx::Vector2dF(0, kSlop * 2), DragPosition()); |
| 116 |
| 117 // Release the touch sequence, ending the drag. The selector will never |
| 118 // consume the start/end events, only move events after a longpress. |
| 119 EXPECT_FALSE(selector.WillHandleTouchEvent(event.ReleasePoint())); |
| 120 EXPECT_FALSE(IsDragging()); |
| 121 EXPECT_TRUE(GetAndResetActiveStateChanged()); |
| 122 } |
| 123 |
| 124 TEST_F(LongPressDragSelectorTest, BasicReverseDrag) { |
| 125 LongPressDragSelector selector(this); |
| 126 MockMotionEvent event; |
| 127 |
| 128 // Start a touch sequence. |
| 129 EXPECT_FALSE(selector.WillHandleTouchEvent(event.PressPoint(0, 0))); |
| 130 EXPECT_FALSE(GetAndResetActiveStateChanged()); |
| 131 |
| 132 // Activate a longpress-triggered selection. |
| 133 gfx::PointF selection_start(0, 10); |
| 134 gfx::PointF selection_end(10, 10); |
| 135 selector.OnLongPressEvent(event.GetEventTime(), gfx::PointF()); |
| 136 EXPECT_TRUE(GetAndResetActiveStateChanged()); |
| 137 SetSelection(selection_start, selection_end); |
| 138 selector.OnSelectionActivated(); |
| 139 EXPECT_FALSE(IsDragging()); |
| 140 |
| 141 // Initiate drag motion. |
| 142 EXPECT_TRUE(selector.WillHandleTouchEvent(event.MovePoint(0, 0, 0))); |
| 143 EXPECT_FALSE(IsDragging()); |
| 144 |
| 145 // As the initial motion is leftward, toward the selection start, the |
| 146 // selection start should be the drag point. |
| 147 EXPECT_TRUE(selector.WillHandleTouchEvent(event.MovePoint(0, -kSlop, 0))); |
| 148 EXPECT_TRUE(IsDragging()); |
| 149 EXPECT_EQ(selection_start, DragPosition()); |
| 150 |
| 151 EXPECT_TRUE(selector.WillHandleTouchEvent(event.MovePoint(0, 0, -kSlop))); |
| 152 EXPECT_TRUE(IsDragging()); |
| 153 EXPECT_EQ(selection_start + gfx::Vector2dF(kSlop, -kSlop), DragPosition()); |
| 154 |
| 155 // Release the touch sequence, ending the drag. |
| 156 EXPECT_FALSE(selector.WillHandleTouchEvent(event.ReleasePoint())); |
| 157 EXPECT_FALSE(IsDragging()); |
| 158 EXPECT_TRUE(GetAndResetActiveStateChanged()); |
| 159 } |
| 160 |
| 161 TEST_F(LongPressDragSelectorTest, NoActiveTouch) { |
| 162 LongPressDragSelector selector(this); |
| 163 MockMotionEvent event; |
| 164 |
| 165 // Activate a longpress-triggered selection. |
| 166 gfx::PointF selection_start(0, 10); |
| 167 gfx::PointF selection_end(10, 10); |
| 168 selector.OnLongPressEvent(event.GetEventTime(), gfx::PointF()); |
| 169 SetSelection(selection_start, selection_end); |
| 170 selector.OnSelectionActivated(); |
| 171 EXPECT_FALSE(GetAndResetActiveStateChanged()); |
| 172 EXPECT_FALSE(IsDragging()); |
| 173 |
| 174 // Start a new touch sequence; it shouldn't initiate selection drag as there |
| 175 // was no active touch sequence when the longpress selection started. |
| 176 EXPECT_FALSE(selector.WillHandleTouchEvent(event.PressPoint(0, 0))); |
| 177 EXPECT_FALSE(selector.WillHandleTouchEvent(event.MovePoint(0, 0, 0))); |
| 178 EXPECT_FALSE(selector.WillHandleTouchEvent(event.MovePoint(0, 0, kSlop))); |
| 179 EXPECT_FALSE(selector.WillHandleTouchEvent(event.MovePoint(0, 0, kSlop * 2))); |
| 180 EXPECT_FALSE(IsDragging()); |
| 181 EXPECT_EQ(gfx::PointF(), DragPosition()); |
| 182 } |
| 183 |
| 184 TEST_F(LongPressDragSelectorTest, NoLongPress) { |
| 185 LongPressDragSelector selector(this); |
| 186 MockMotionEvent event; |
| 187 |
| 188 // Start a touch sequence. |
| 189 EXPECT_FALSE(selector.WillHandleTouchEvent(event.PressPoint(0, 0))); |
| 190 EXPECT_FALSE(GetAndResetActiveStateChanged()); |
| 191 |
| 192 // Activate a selection without a preceding longpress. |
| 193 gfx::PointF selection_start(0, 10); |
| 194 gfx::PointF selection_end(10, 10); |
| 195 SetSelection(selection_start, selection_end); |
| 196 selector.OnSelectionActivated(); |
| 197 EXPECT_FALSE(GetAndResetActiveStateChanged()); |
| 198 EXPECT_FALSE(IsDragging()); |
| 199 |
| 200 // Touch movement should not initiate selection drag. |
| 201 EXPECT_FALSE(selector.WillHandleTouchEvent(event.MovePoint(0, 0, 0))); |
| 202 EXPECT_FALSE(selector.WillHandleTouchEvent(event.MovePoint(0, 0, kSlop))); |
| 203 EXPECT_FALSE(selector.WillHandleTouchEvent(event.MovePoint(0, 0, kSlop * 2))); |
| 204 EXPECT_FALSE(IsDragging()); |
| 205 EXPECT_EQ(gfx::PointF(), DragPosition()); |
| 206 } |
| 207 |
| 208 TEST_F(LongPressDragSelectorTest, NoValidLongPress) { |
| 209 LongPressDragSelector selector(this); |
| 210 MockMotionEvent event; |
| 211 |
| 212 // Start a touch sequence. |
| 213 EXPECT_FALSE(selector.WillHandleTouchEvent(event.PressPoint(0, 0))); |
| 214 EXPECT_FALSE(GetAndResetActiveStateChanged()); |
| 215 |
| 216 gfx::PointF selection_start(0, 10); |
| 217 gfx::PointF selection_end(10, 10); |
| 218 SetSelection(selection_start, selection_end); |
| 219 |
| 220 // Activate a longpress-triggered selection, but at a time before the current |
| 221 // touch down event. |
| 222 selector.OnLongPressEvent( |
| 223 event.GetEventTime() - base::TimeDelta::FromSeconds(1), gfx::PointF()); |
| 224 selector.OnSelectionActivated(); |
| 225 EXPECT_FALSE(GetAndResetActiveStateChanged()); |
| 226 EXPECT_FALSE(IsDragging()); |
| 227 |
| 228 // Activate a longpress-triggered selection, but at a place different than the |
| 229 // current touch down event. |
| 230 selector.OnLongPressEvent(event.GetEventTime(), gfx::PointF(kSlop, 0)); |
| 231 selector.OnSelectionActivated(); |
| 232 EXPECT_FALSE(GetAndResetActiveStateChanged()); |
| 233 EXPECT_FALSE(IsDragging()); |
| 234 |
| 235 // Touch movement should not initiate selection drag. |
| 236 EXPECT_FALSE(selector.WillHandleTouchEvent(event.MovePoint(0, 0, 0))); |
| 237 EXPECT_FALSE(selector.WillHandleTouchEvent(event.MovePoint(0, 0, kSlop))); |
| 238 EXPECT_FALSE(selector.WillHandleTouchEvent(event.MovePoint(0, 0, kSlop * 2))); |
| 239 EXPECT_FALSE(IsDragging()); |
| 240 EXPECT_EQ(gfx::PointF(), DragPosition()); |
| 241 } |
| 242 |
| 243 TEST_F(LongPressDragSelectorTest, NoSelection) { |
| 244 LongPressDragSelector selector(this); |
| 245 MockMotionEvent event; |
| 246 |
| 247 // Start a touch sequence. |
| 248 EXPECT_FALSE(selector.WillHandleTouchEvent(event.PressPoint(0, 0))); |
| 249 EXPECT_FALSE(GetAndResetActiveStateChanged()); |
| 250 |
| 251 // Trigger a longpress. This will notify the client that detection is active, |
| 252 // but until there's a longpress no drag selection should occur. |
| 253 selector.OnLongPressEvent(event.GetEventTime(), gfx::PointF()); |
| 254 EXPECT_TRUE(GetAndResetActiveStateChanged()); |
| 255 EXPECT_FALSE(IsDragging()); |
| 256 |
| 257 // Touch movement should not initiate selection drag, as there is no active |
| 258 // selection. |
| 259 EXPECT_FALSE(selector.WillHandleTouchEvent(event.MovePoint(0, 0, 0))); |
| 260 EXPECT_FALSE(selector.WillHandleTouchEvent(event.MovePoint(0, 0, kSlop))); |
| 261 EXPECT_FALSE(selector.WillHandleTouchEvent(event.MovePoint(0, 0, kSlop * 2))); |
| 262 EXPECT_FALSE(IsDragging()); |
| 263 EXPECT_EQ(gfx::PointF(), DragPosition()); |
| 264 |
| 265 EXPECT_FALSE(selector.WillHandleTouchEvent(event.ReleasePoint())); |
| 266 EXPECT_TRUE(GetAndResetActiveStateChanged()); |
| 267 } |
| 268 |
| 269 TEST_F(LongPressDragSelectorTest, NoDragMotion) { |
| 270 LongPressDragSelector selector(this); |
| 271 MockMotionEvent event; |
| 272 |
| 273 // Start a touch sequence. |
| 274 EXPECT_FALSE(selector.WillHandleTouchEvent(event.PressPoint(0, 0))); |
| 275 EXPECT_FALSE(GetAndResetActiveStateChanged()); |
| 276 |
| 277 // Activate a longpress-triggered selection. |
| 278 selector.OnLongPressEvent(event.GetEventTime(), gfx::PointF()); |
| 279 EXPECT_TRUE(GetAndResetActiveStateChanged()); |
| 280 gfx::PointF selection_start(0, 10); |
| 281 gfx::PointF selection_end(10, 10); |
| 282 SetSelection(selection_start, selection_end); |
| 283 selector.OnSelectionActivated(); |
| 284 EXPECT_FALSE(IsDragging()); |
| 285 |
| 286 // Touch movement within the slop region should not initiate selection drag. |
| 287 EXPECT_TRUE(selector.WillHandleTouchEvent(event.MovePoint(0, 0, 0))); |
| 288 EXPECT_TRUE(selector.WillHandleTouchEvent(event.MovePoint(0, 0, kSlop / 2))); |
| 289 EXPECT_TRUE(selector.WillHandleTouchEvent(event.MovePoint(0, 0, -kSlop / 2))); |
| 290 EXPECT_FALSE(IsDragging()); |
| 291 EXPECT_EQ(gfx::PointF(), DragPosition()); |
| 292 |
| 293 EXPECT_FALSE(selector.WillHandleTouchEvent(event.ReleasePoint())); |
| 294 EXPECT_TRUE(GetAndResetActiveStateChanged()); |
| 295 } |
| 296 |
| 297 TEST_F(LongPressDragSelectorTest, SelectionDeactivated) { |
| 298 LongPressDragSelector selector(this); |
| 299 MockMotionEvent event; |
| 300 |
| 301 // Start a touch sequence. |
| 302 EXPECT_FALSE(selector.WillHandleTouchEvent(event.PressPoint(0, 0))); |
| 303 EXPECT_FALSE(GetAndResetActiveStateChanged()); |
| 304 |
| 305 // Activate a longpress-triggered selection. |
| 306 selector.OnLongPressEvent(event.GetEventTime(), gfx::PointF()); |
| 307 EXPECT_TRUE(GetAndResetActiveStateChanged()); |
| 308 gfx::PointF selection_start(0, 10); |
| 309 gfx::PointF selection_end(10, 10); |
| 310 SetSelection(selection_start, selection_end); |
| 311 selector.OnSelectionActivated(); |
| 312 EXPECT_FALSE(IsDragging()); |
| 313 |
| 314 // Start a drag selection. |
| 315 EXPECT_TRUE(selector.WillHandleTouchEvent(event.MovePoint(0, 0, 0))); |
| 316 EXPECT_TRUE(selector.WillHandleTouchEvent(event.MovePoint(0, 0, kSlop))); |
| 317 EXPECT_TRUE(selector.WillHandleTouchEvent(event.MovePoint(0, 0, kSlop * 2))); |
| 318 EXPECT_TRUE(IsDragging()); |
| 319 |
| 320 // Clearing the selection should force an end to the drag. |
| 321 selector.OnSelectionDeactivated(); |
| 322 EXPECT_TRUE(GetAndResetActiveStateChanged()); |
| 323 EXPECT_FALSE(IsDragging()); |
| 324 |
| 325 // Subsequent motion should not be consumed. |
| 326 EXPECT_FALSE(selector.WillHandleTouchEvent(event.MovePoint(0, 0, 0))); |
| 327 EXPECT_FALSE(selector.WillHandleTouchEvent(event.MovePoint(0, 0, kSlop))); |
| 328 EXPECT_FALSE(selector.WillHandleTouchEvent(event.MovePoint(0, 0, kSlop * 2))); |
| 329 EXPECT_FALSE(IsDragging()); |
| 330 EXPECT_FALSE(selector.WillHandleTouchEvent(event.ReleasePoint())); |
| 331 } |
| 332 |
| 333 } // namespace ui |
OLD | NEW |