Chromium Code Reviews| 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()); | |
|
mfomitchev
2015/05/14 21:58:32
Sorry, I don't get it: we've moved by (-kSlop, -kS
jdduke (slow)
2015/05/14 22:19:28
Hmm, maybe switching from x to y coordinate is con
mfomitchev
2015/05/14 22:33:57
AH, right. For some reason I was reading this as r
| |
| 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 |