Add abhijeet.k@samsung.com to AUTHORS list.
[chromium-blink-merge.git] / ash / drag_drop / drag_drop_controller_unittest.cc
blob6ee3a59a76ccd59712c308eaa6682c304cd0d4eb
1 // Copyright (c) 2012 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.
5 #include "ash/drag_drop/drag_drop_controller.h"
7 #include "ash/drag_drop/drag_drop_tracker.h"
8 #include "ash/drag_drop/drag_image_view.h"
9 #include "ash/shell.h"
10 #include "ash/test/ash_test_base.h"
11 #include "base/command_line.h"
12 #include "base/location.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "ui/aura/client/capture_client.h"
15 #include "ui/aura/window_event_dispatcher.h"
16 #include "ui/aura/window_tree_host.h"
17 #include "ui/base/clipboard/clipboard.h"
18 #include "ui/base/clipboard/scoped_clipboard_writer.h"
19 #include "ui/base/dragdrop/drag_drop_types.h"
20 #include "ui/base/dragdrop/drag_utils.h"
21 #include "ui/base/dragdrop/os_exchange_data.h"
22 #include "ui/base/ui_base_switches.h"
23 #include "ui/events/event.h"
24 #include "ui/events/event_utils.h"
25 #include "ui/events/gesture_detection/gesture_configuration.h"
26 #include "ui/events/gestures/gesture_types.h"
27 #include "ui/events/test/event_generator.h"
28 #include "ui/events/test/events_test_utils.h"
29 #include "ui/gfx/animation/linear_animation.h"
30 #include "ui/gfx/image/image_skia_rep.h"
31 #include "ui/views/view.h"
32 #include "ui/views/views_delegate.h"
33 #include "ui/views/widget/native_widget_aura.h"
34 #include "ui/views/widget/native_widget_delegate.h"
35 #include "ui/views/widget/widget.h"
37 namespace ash {
38 namespace test {
40 namespace {
42 // A simple view that makes sure RunShellDrag is invoked on mouse drag.
43 class DragTestView : public views::View {
44 public:
45 DragTestView() : views::View() {
46 Reset();
49 void Reset() {
50 num_drag_enters_ = 0;
51 num_drag_exits_ = 0;
52 num_drag_updates_ = 0;
53 num_drops_ = 0;
54 drag_done_received_ = false;
55 long_tap_received_ = false;
58 int VerticalDragThreshold() {
59 return views::View::GetVerticalDragThreshold();
62 int HorizontalDragThreshold() {
63 return views::View::GetHorizontalDragThreshold();
66 int num_drag_enters_;
67 int num_drag_exits_;
68 int num_drag_updates_;
69 int num_drops_;
70 bool drag_done_received_;
71 bool long_tap_received_;
73 private:
74 // View overrides:
75 int GetDragOperations(const gfx::Point& press_pt) override {
76 return ui::DragDropTypes::DRAG_COPY;
79 void WriteDragData(const gfx::Point& p, OSExchangeData* data) override {
80 data->SetString(base::UTF8ToUTF16("I am being dragged"));
81 gfx::ImageSkiaRep image_rep(gfx::Size(10, 20), 1.0f);
82 gfx::ImageSkia image_skia(image_rep);
84 drag_utils::SetDragImageOnDataObject(image_skia, gfx::Vector2d(), data);
87 bool OnMousePressed(const ui::MouseEvent& event) override { return true; }
89 void OnGestureEvent(ui::GestureEvent* event) override {
90 if (event->type() == ui::ET_GESTURE_LONG_TAP)
91 long_tap_received_ = true;
92 return;
95 bool GetDropFormats(
96 int* formats,
97 std::set<OSExchangeData::CustomFormat>* custom_formats) override {
98 *formats = ui::OSExchangeData::STRING;
99 return true;
102 bool CanDrop(const OSExchangeData& data) override { return true; }
104 void OnDragEntered(const ui::DropTargetEvent& event) override {
105 num_drag_enters_++;
108 int OnDragUpdated(const ui::DropTargetEvent& event) override {
109 num_drag_updates_++;
110 return ui::DragDropTypes::DRAG_COPY;
113 void OnDragExited() override { num_drag_exits_++; }
115 int OnPerformDrop(const ui::DropTargetEvent& event) override {
116 num_drops_++;
117 return ui::DragDropTypes::DRAG_COPY;
120 void OnDragDone() override { drag_done_received_ = true; }
122 DISALLOW_COPY_AND_ASSIGN(DragTestView);
125 class CompletableLinearAnimation : public gfx::LinearAnimation {
126 public:
127 CompletableLinearAnimation(int duration,
128 int frame_rate,
129 gfx::AnimationDelegate* delegate)
130 : gfx::LinearAnimation(duration, frame_rate, delegate),
131 duration_(duration) {
134 void Complete() {
135 Step(start_time() + base::TimeDelta::FromMilliseconds(duration_));
138 private:
139 int duration_;
142 class TestDragDropController : public DragDropController {
143 public:
144 TestDragDropController() : DragDropController() { Reset(); }
146 void Reset() {
147 drag_start_received_ = false;
148 num_drag_updates_ = 0;
149 drop_received_ = false;
150 drag_canceled_ = false;
151 drag_string_.clear();
154 int StartDragAndDrop(const ui::OSExchangeData& data,
155 aura::Window* root_window,
156 aura::Window* source_window,
157 const gfx::Point& location,
158 int operation,
159 ui::DragDropTypes::DragEventSource source) override {
160 drag_start_received_ = true;
161 data.GetString(&drag_string_);
162 return DragDropController::StartDragAndDrop(
163 data, root_window, source_window, location, operation, source);
166 void DragUpdate(aura::Window* target,
167 const ui::LocatedEvent& event) override {
168 DragDropController::DragUpdate(target, event);
169 num_drag_updates_++;
172 void Drop(aura::Window* target, const ui::LocatedEvent& event) override {
173 DragDropController::Drop(target, event);
174 drop_received_ = true;
177 void DragCancel() override {
178 DragDropController::DragCancel();
179 drag_canceled_ = true;
182 gfx::LinearAnimation* CreateCancelAnimation(
183 int duration,
184 int frame_rate,
185 gfx::AnimationDelegate* delegate) override {
186 return new CompletableLinearAnimation(duration, frame_rate, delegate);
189 void DoDragCancel(int animation_duration_ms) override {
190 DragDropController::DoDragCancel(animation_duration_ms);
191 drag_canceled_ = true;
194 bool drag_start_received_;
195 int num_drag_updates_;
196 bool drop_received_;
197 bool drag_canceled_;
198 base::string16 drag_string_;
200 private:
201 DISALLOW_COPY_AND_ASSIGN(TestDragDropController);
204 class TestNativeWidgetAura : public views::NativeWidgetAura {
205 public:
206 explicit TestNativeWidgetAura(views::internal::NativeWidgetDelegate* delegate)
207 : NativeWidgetAura(delegate),
208 check_if_capture_lost_(false) {
211 void set_check_if_capture_lost(bool value) {
212 check_if_capture_lost_ = value;
215 void OnCaptureLost() override {
216 DCHECK(!check_if_capture_lost_);
217 views::NativeWidgetAura::OnCaptureLost();
220 private:
221 bool check_if_capture_lost_;
223 DISALLOW_COPY_AND_ASSIGN(TestNativeWidgetAura);
226 // TODO(sky): this is for debugging, remove when track down failure.
227 void SetCheckIfCaptureLost(views::Widget* widget, bool value) {
228 // On Windows, the DCHECK triggers when running on bot or locally through RDP,
229 // but not when logged in locally.
230 #if !defined(OS_WIN)
231 static_cast<TestNativeWidgetAura*>(widget->native_widget())->
232 set_check_if_capture_lost(value);
233 #endif
236 views::Widget* CreateNewWidget() {
237 views::Widget* widget = new views::Widget;
238 views::Widget::InitParams params;
239 params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
240 params.accept_events = true;
241 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
242 params.parent = Shell::GetPrimaryRootWindow();
243 params.child = true;
244 params.native_widget = new TestNativeWidgetAura(widget);
245 widget->Init(params);
246 widget->Show();
247 return widget;
250 void AddViewToWidgetAndResize(views::Widget* widget, views::View* view) {
251 if (!widget->GetContentsView()) {
252 views::View* contents_view = new views::View;
253 widget->SetContentsView(contents_view);
256 views::View* contents_view = widget->GetContentsView();
257 contents_view->AddChildView(view);
258 view->SetBounds(contents_view->width(), 0, 100, 100);
259 gfx::Rect contents_view_bounds = contents_view->bounds();
260 contents_view_bounds.Union(view->bounds());
261 contents_view->SetBoundsRect(contents_view_bounds);
262 widget->SetBounds(contents_view_bounds);
265 void DispatchGesture(ui::EventType gesture_type, gfx::Point location) {
266 ui::GestureEventDetails event_details(gesture_type);
267 event_details.set_oldest_touch_id(1);
268 ui::GestureEvent gesture_event(
269 location.x(), location.y(), 0, ui::EventTimeForNow(), event_details);
270 ui::EventSource* event_source =
271 Shell::GetPrimaryRootWindow()->GetHost()->GetEventSource();
272 ui::EventSourceTestApi event_source_test(event_source);
273 ui::EventDispatchDetails details =
274 event_source_test.SendEventToProcessor(&gesture_event);
275 CHECK(!details.dispatcher_destroyed);
278 } // namespace
280 class DragDropControllerTest : public AshTestBase {
281 public:
282 DragDropControllerTest() : AshTestBase() {}
283 ~DragDropControllerTest() override {}
285 void SetUp() override {
286 AshTestBase::SetUp();
287 drag_drop_controller_.reset(new TestDragDropController);
288 drag_drop_controller_->set_should_block_during_drag_drop(false);
289 aura::client::SetDragDropClient(Shell::GetPrimaryRootWindow(),
290 drag_drop_controller_.get());
293 void TearDown() override {
294 aura::client::SetDragDropClient(Shell::GetPrimaryRootWindow(), NULL);
295 drag_drop_controller_.reset();
296 AshTestBase::TearDown();
299 void UpdateDragData(ui::OSExchangeData* data) {
300 drag_drop_controller_->drag_data_ = data;
303 aura::Window* GetDragWindow() {
304 return drag_drop_controller_->drag_window_;
307 aura::Window* GetDragSourceWindow() {
308 return drag_drop_controller_->drag_source_window_;
311 void SetDragSourceWindow(aura::Window* drag_source_window) {
312 drag_drop_controller_->drag_source_window_ = drag_source_window;
313 drag_source_window->AddObserver(drag_drop_controller_.get());
316 aura::Window* GetDragImageWindow() {
317 return drag_drop_controller_->drag_image_.get() ?
318 drag_drop_controller_->drag_image_->GetWidget()->GetNativeWindow() :
319 NULL;
322 DragDropTracker* drag_drop_tracker() {
323 return drag_drop_controller_->drag_drop_tracker_.get();
326 void CompleteCancelAnimation() {
327 CompletableLinearAnimation* animation =
328 static_cast<CompletableLinearAnimation*>(
329 drag_drop_controller_->cancel_animation_.get());
330 animation->Complete();
333 protected:
334 scoped_ptr<TestDragDropController> drag_drop_controller_;
336 private:
337 DISALLOW_COPY_AND_ASSIGN(DragDropControllerTest);
340 // TODO(win_aura) http://crbug.com/154081
341 #if defined(OS_WIN)
342 #define MAYBE_DragDropInSingleViewTest DISABLED_DragDropInSingleViewTest
343 #else
344 #define MAYBE_DragDropInSingleViewTest DragDropInSingleViewTest
345 #endif
346 TEST_F(DragDropControllerTest, MAYBE_DragDropInSingleViewTest) {
347 scoped_ptr<views::Widget> widget(CreateNewWidget());
348 DragTestView* drag_view = new DragTestView;
349 AddViewToWidgetAndResize(widget.get(), drag_view);
350 ui::OSExchangeData data;
351 data.SetString(base::UTF8ToUTF16("I am being dragged"));
352 ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
353 widget->GetNativeView());
354 generator.PressLeftButton();
356 int num_drags = 17;
357 SetCheckIfCaptureLost(widget.get(), true);
358 for (int i = 0; i < num_drags; ++i) {
359 // Because we are not doing a blocking drag and drop, the original
360 // OSDragExchangeData object is lost as soon as we return from the drag
361 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
362 // drag_data_ to a fake drag data object that we created.
363 if (i > 0)
364 UpdateDragData(&data);
365 // 7 comes from views::View::GetVerticalDragThreshold()).
366 if (i >= 7)
367 SetCheckIfCaptureLost(widget.get(), false);
369 generator.MoveMouseBy(0, 1);
371 // Execute any scheduled draws to process deferred mouse events.
372 RunAllPendingInMessageLoop();
375 generator.ReleaseLeftButton();
377 EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
378 EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
379 drag_drop_controller_->num_drag_updates_);
380 EXPECT_TRUE(drag_drop_controller_->drop_received_);
381 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
382 drag_drop_controller_->drag_string_);
384 EXPECT_EQ(1, drag_view->num_drag_enters_);
385 EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
386 drag_view->num_drag_updates_);
387 EXPECT_EQ(1, drag_view->num_drops_);
388 EXPECT_EQ(0, drag_view->num_drag_exits_);
389 EXPECT_TRUE(drag_view->drag_done_received_);
392 TEST_F(DragDropControllerTest, DragDropWithZeroDragUpdates) {
393 scoped_ptr<views::Widget> widget(CreateNewWidget());
394 DragTestView* drag_view = new DragTestView;
395 AddViewToWidgetAndResize(widget.get(), drag_view);
396 ui::OSExchangeData data;
397 data.SetString(base::UTF8ToUTF16("I am being dragged"));
398 ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
399 widget->GetNativeView());
400 generator.PressLeftButton();
402 int num_drags = drag_view->VerticalDragThreshold() + 1;
403 for (int i = 0; i < num_drags; ++i) {
404 // Because we are not doing a blocking drag and drop, the original
405 // OSDragExchangeData object is lost as soon as we return from the drag
406 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
407 // drag_data_ to a fake drag data object that we created.
408 if (i > 0)
409 UpdateDragData(&data);
410 generator.MoveMouseBy(0, 1);
413 UpdateDragData(&data);
415 generator.ReleaseLeftButton();
417 EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
418 EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold() + 1,
419 drag_drop_controller_->num_drag_updates_);
420 EXPECT_TRUE(drag_drop_controller_->drop_received_);
422 EXPECT_EQ(1, drag_view->num_drag_enters_);
423 EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold() + 1,
424 drag_view->num_drag_updates_);
425 EXPECT_EQ(1, drag_view->num_drops_);
426 EXPECT_EQ(0, drag_view->num_drag_exits_);
427 EXPECT_TRUE(drag_view->drag_done_received_);
430 // TODO(win_aura) http://crbug.com/154081
431 #if defined(OS_WIN)
432 #define MAYBE_DragDropInMultipleViewsSingleWidgetTest DISABLED_DragDropInMultipleViewsSingleWidgetTest
433 #else
434 #define MAYBE_DragDropInMultipleViewsSingleWidgetTest DragDropInMultipleViewsSingleWidgetTest
435 #endif
436 TEST_F(DragDropControllerTest, MAYBE_DragDropInMultipleViewsSingleWidgetTest) {
437 scoped_ptr<views::Widget> widget(CreateNewWidget());
438 DragTestView* drag_view1 = new DragTestView;
439 AddViewToWidgetAndResize(widget.get(), drag_view1);
440 DragTestView* drag_view2 = new DragTestView;
441 AddViewToWidgetAndResize(widget.get(), drag_view2);
443 ui::OSExchangeData data;
444 data.SetString(base::UTF8ToUTF16("I am being dragged"));
446 ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
447 generator.MoveMouseRelativeTo(widget->GetNativeView(),
448 drag_view1->bounds().CenterPoint());
449 generator.PressLeftButton();
451 int num_drags = drag_view1->width();
452 for (int i = 0; i < num_drags; ++i) {
453 // Because we are not doing a blocking drag and drop, the original
454 // OSDragExchangeData object is lost as soon as we return from the drag
455 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
456 // drag_data_ to a fake drag data object that we created.
457 if (i > 0)
458 UpdateDragData(&data);
459 generator.MoveMouseBy(1, 0);
461 // Execute any scheduled draws to process deferred mouse events.
462 RunAllPendingInMessageLoop();
465 generator.ReleaseLeftButton();
467 EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
468 EXPECT_EQ(num_drags - 1 - drag_view1->HorizontalDragThreshold(),
469 drag_drop_controller_->num_drag_updates_);
470 EXPECT_TRUE(drag_drop_controller_->drop_received_);
471 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
472 drag_drop_controller_->drag_string_);
474 EXPECT_EQ(1, drag_view1->num_drag_enters_);
475 int num_expected_updates = drag_view1->bounds().width() -
476 drag_view1->bounds().CenterPoint().x() - 2;
477 EXPECT_EQ(num_expected_updates - drag_view1->HorizontalDragThreshold(),
478 drag_view1->num_drag_updates_);
479 EXPECT_EQ(0, drag_view1->num_drops_);
480 EXPECT_EQ(1, drag_view1->num_drag_exits_);
481 EXPECT_TRUE(drag_view1->drag_done_received_);
483 EXPECT_EQ(1, drag_view2->num_drag_enters_);
484 num_expected_updates = num_drags - num_expected_updates - 1;
485 EXPECT_EQ(num_expected_updates, drag_view2->num_drag_updates_);
486 EXPECT_EQ(1, drag_view2->num_drops_);
487 EXPECT_EQ(0, drag_view2->num_drag_exits_);
488 EXPECT_FALSE(drag_view2->drag_done_received_);
491 // TODO(win_aura) http://crbug.com/154081
492 #if defined(OS_WIN)
493 #define MAYBE_DragDropInMultipleViewsMultipleWidgetsTest DISABLED_DragDropInMultipleViewsMultipleWidgetsTest
494 #else
495 #define MAYBE_DragDropInMultipleViewsMultipleWidgetsTest DragDropInMultipleViewsMultipleWidgetsTest
496 #endif
497 TEST_F(DragDropControllerTest, MAYBE_DragDropInMultipleViewsMultipleWidgetsTest) {
498 scoped_ptr<views::Widget> widget1(CreateNewWidget());
499 DragTestView* drag_view1 = new DragTestView;
500 AddViewToWidgetAndResize(widget1.get(), drag_view1);
501 scoped_ptr<views::Widget> widget2(CreateNewWidget());
502 DragTestView* drag_view2 = new DragTestView;
503 AddViewToWidgetAndResize(widget2.get(), drag_view2);
504 gfx::Rect widget1_bounds = widget1->GetClientAreaBoundsInScreen();
505 gfx::Rect widget2_bounds = widget2->GetClientAreaBoundsInScreen();
506 widget2->SetBounds(gfx::Rect(widget1_bounds.width(), 0,
507 widget2_bounds.width(), widget2_bounds.height()));
509 ui::OSExchangeData data;
510 data.SetString(base::UTF8ToUTF16("I am being dragged"));
512 ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
513 widget1->GetNativeView());
514 generator.PressLeftButton();
516 int num_drags = drag_view1->width();
517 for (int i = 0; i < num_drags; ++i) {
518 // Because we are not doing a blocking drag and drop, the original
519 // OSDragExchangeData object is lost as soon as we return from the drag
520 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
521 // drag_data_ to a fake drag data object that we created.
522 if (i > 0)
523 UpdateDragData(&data);
524 generator.MoveMouseBy(1, 0);
526 // Execute any scheduled draws to process deferred mouse events.
527 RunAllPendingInMessageLoop();
530 generator.ReleaseLeftButton();
532 EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
533 EXPECT_EQ(num_drags - 1 - drag_view1->HorizontalDragThreshold(),
534 drag_drop_controller_->num_drag_updates_);
535 EXPECT_TRUE(drag_drop_controller_->drop_received_);
536 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
537 drag_drop_controller_->drag_string_);
539 EXPECT_EQ(1, drag_view1->num_drag_enters_);
540 int num_expected_updates = drag_view1->bounds().width() -
541 drag_view1->bounds().CenterPoint().x() - 2;
542 EXPECT_EQ(num_expected_updates - drag_view1->HorizontalDragThreshold(),
543 drag_view1->num_drag_updates_);
544 EXPECT_EQ(0, drag_view1->num_drops_);
545 EXPECT_EQ(1, drag_view1->num_drag_exits_);
546 EXPECT_TRUE(drag_view1->drag_done_received_);
548 EXPECT_EQ(1, drag_view2->num_drag_enters_);
549 num_expected_updates = num_drags - num_expected_updates - 1;
550 EXPECT_EQ(num_expected_updates, drag_view2->num_drag_updates_);
551 EXPECT_EQ(1, drag_view2->num_drops_);
552 EXPECT_EQ(0, drag_view2->num_drag_exits_);
553 EXPECT_FALSE(drag_view2->drag_done_received_);
556 // TODO(win_aura) http://crbug.com/154081
557 #if defined(OS_WIN)
558 #define MAYBE_ViewRemovedWhileInDragDropTest DISABLED_ViewRemovedWhileInDragDropTest
559 #else
560 #define MAYBE_ViewRemovedWhileInDragDropTest ViewRemovedWhileInDragDropTest
561 #endif
562 TEST_F(DragDropControllerTest, MAYBE_ViewRemovedWhileInDragDropTest) {
563 scoped_ptr<views::Widget> widget(CreateNewWidget());
564 scoped_ptr<DragTestView> drag_view(new DragTestView);
565 AddViewToWidgetAndResize(widget.get(), drag_view.get());
566 gfx::Point point = gfx::Rect(drag_view->bounds()).CenterPoint();
567 ui::OSExchangeData data;
568 data.SetString(base::UTF8ToUTF16("I am being dragged"));
570 ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
571 generator.MoveMouseToCenterOf(widget->GetNativeView());
572 generator.PressLeftButton();
574 int num_drags_1 = 17;
575 for (int i = 0; i < num_drags_1; ++i) {
576 // Because we are not doing a blocking drag and drop, the original
577 // OSDragExchangeData object is lost as soon as we return from the drag
578 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
579 // drag_data_ to a fake drag data object that we created.
580 if (i > 0)
581 UpdateDragData(&data);
582 generator.MoveMouseBy(0, 1);
584 // Execute any scheduled draws to process deferred mouse events.
585 RunAllPendingInMessageLoop();
588 drag_view->parent()->RemoveChildView(drag_view.get());
589 // View has been removed. We will not get any of the following drag updates.
590 int num_drags_2 = 23;
591 for (int i = 0; i < num_drags_2; ++i) {
592 UpdateDragData(&data);
593 generator.MoveMouseBy(0, 1);
595 // Execute any scheduled draws to process deferred mouse events.
596 RunAllPendingInMessageLoop();
599 generator.ReleaseLeftButton();
601 EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
602 EXPECT_EQ(num_drags_1 + num_drags_2 - 1 - drag_view->VerticalDragThreshold(),
603 drag_drop_controller_->num_drag_updates_);
604 EXPECT_TRUE(drag_drop_controller_->drop_received_);
605 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
606 drag_drop_controller_->drag_string_);
608 EXPECT_EQ(1, drag_view->num_drag_enters_);
609 EXPECT_EQ(num_drags_1 - 1 - drag_view->VerticalDragThreshold(),
610 drag_view->num_drag_updates_);
611 EXPECT_EQ(0, drag_view->num_drops_);
612 EXPECT_EQ(0, drag_view->num_drag_exits_);
613 EXPECT_TRUE(drag_view->drag_done_received_);
616 TEST_F(DragDropControllerTest, DragLeavesClipboardAloneTest) {
617 ui::Clipboard* cb = ui::Clipboard::GetForCurrentThread();
618 std::string clip_str("I am on the clipboard");
620 // We first copy some text to the clipboard.
621 ui::ScopedClipboardWriter scw(ui::CLIPBOARD_TYPE_COPY_PASTE);
622 scw.WriteText(base::ASCIIToUTF16(clip_str));
624 EXPECT_TRUE(cb->IsFormatAvailable(ui::Clipboard::GetPlainTextFormatType(),
625 ui::CLIPBOARD_TYPE_COPY_PASTE));
627 scoped_ptr<views::Widget> widget(CreateNewWidget());
628 DragTestView* drag_view = new DragTestView;
629 AddViewToWidgetAndResize(widget.get(), drag_view);
631 ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
632 widget->GetNativeView());
633 ui::OSExchangeData data;
634 std::string data_str("I am being dragged");
635 data.SetString(base::ASCIIToUTF16(data_str));
637 generator.PressLeftButton();
638 generator.MoveMouseBy(0, drag_view->VerticalDragThreshold() + 1);
640 // Execute any scheduled draws to process deferred mouse events.
641 RunAllPendingInMessageLoop();
643 // Verify the clipboard contents haven't changed
644 std::string result;
645 EXPECT_TRUE(cb->IsFormatAvailable(ui::Clipboard::GetPlainTextFormatType(),
646 ui::CLIPBOARD_TYPE_COPY_PASTE));
647 cb->ReadAsciiText(ui::CLIPBOARD_TYPE_COPY_PASTE, &result);
648 EXPECT_EQ(clip_str, result);
649 // Destory the clipboard here because ash doesn't delete it.
650 // crbug.com/158150.
651 ui::Clipboard::DestroyClipboardForCurrentThread();
654 TEST_F(DragDropControllerTest, WindowDestroyedDuringDragDrop) {
655 scoped_ptr<views::Widget> widget(CreateNewWidget());
656 DragTestView* drag_view = new DragTestView;
657 AddViewToWidgetAndResize(widget.get(), drag_view);
658 aura::Window* window = widget->GetNativeView();
660 ui::OSExchangeData data;
661 data.SetString(base::UTF8ToUTF16("I am being dragged"));
662 ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
663 widget->GetNativeView());
664 generator.PressLeftButton();
666 int num_drags = 17;
667 for (int i = 0; i < num_drags; ++i) {
668 // Because we are not doing a blocking drag and drop, the original
669 // OSDragExchangeData object is lost as soon as we return from the drag
670 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
671 // drag_data_ to a fake drag data object that we created.
672 if (i > 0)
673 UpdateDragData(&data);
674 generator.MoveMouseBy(0, 1);
676 // Execute any scheduled draws to process deferred mouse events.
677 RunAllPendingInMessageLoop();
679 if (i > drag_view->VerticalDragThreshold())
680 EXPECT_EQ(window, GetDragWindow());
683 widget->CloseNow();
684 EXPECT_FALSE(GetDragWindow());
686 num_drags = 23;
687 for (int i = 0; i < num_drags; ++i) {
688 if (i > 0)
689 UpdateDragData(&data);
690 generator.MoveMouseBy(0, 1);
691 // We should not crash here.
694 generator.ReleaseLeftButton();
696 EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
697 EXPECT_TRUE(drag_drop_controller_->drop_received_);
700 TEST_F(DragDropControllerTest, SyntheticEventsDuringDragDrop) {
701 scoped_ptr<views::Widget> widget(CreateNewWidget());
702 DragTestView* drag_view = new DragTestView;
703 AddViewToWidgetAndResize(widget.get(), drag_view);
704 ui::OSExchangeData data;
705 data.SetString(base::UTF8ToUTF16("I am being dragged"));
706 ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
707 widget->GetNativeView());
708 generator.PressLeftButton();
710 int num_drags = 17;
711 for (int i = 0; i < num_drags; ++i) {
712 // Because we are not doing a blocking drag and drop, the original
713 // OSDragExchangeData object is lost as soon as we return from the drag
714 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
715 // drag_data_ to a fake drag data object that we created.
716 if (i > 0)
717 UpdateDragData(&data);
718 generator.MoveMouseBy(0, 1);
720 // We send a unexpected mouse move event. Note that we cannot use
721 // EventGenerator since it implicitly turns these into mouse drag events.
722 // The DragDropController should simply ignore these events.
723 gfx::Point mouse_move_location = drag_view->bounds().CenterPoint();
724 ui::MouseEvent mouse_move(ui::ET_MOUSE_MOVED, mouse_move_location,
725 mouse_move_location, ui::EventTimeForNow(), 0, 0);
726 ui::EventDispatchDetails details = Shell::GetPrimaryRootWindow()->
727 GetHost()->event_processor()->OnEventFromSource(&mouse_move);
728 ASSERT_FALSE(details.dispatcher_destroyed);
731 generator.ReleaseLeftButton();
733 EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
734 EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
735 drag_drop_controller_->num_drag_updates_);
736 EXPECT_TRUE(drag_drop_controller_->drop_received_);
737 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
738 drag_drop_controller_->drag_string_);
740 EXPECT_EQ(1, drag_view->num_drag_enters_);
741 EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
742 drag_view->num_drag_updates_);
743 EXPECT_EQ(1, drag_view->num_drops_);
744 EXPECT_EQ(0, drag_view->num_drag_exits_);
745 EXPECT_TRUE(drag_view->drag_done_received_);
748 // TODO(win_aura) http://crbug.com/154081
749 #if defined(OS_WIN)
750 #define MAYBE_PressingEscapeCancelsDragDrop DISABLED_PressingEscapeCancelsDragDrop
751 #define MAYBE_CaptureLostCancelsDragDrop DISABLED_CaptureLostCancelsDragDrop
752 #else
753 #define MAYBE_PressingEscapeCancelsDragDrop PressingEscapeCancelsDragDrop
754 #define MAYBE_CaptureLostCancelsDragDrop CaptureLostCancelsDragDrop
755 #endif
756 TEST_F(DragDropControllerTest, MAYBE_PressingEscapeCancelsDragDrop) {
757 scoped_ptr<views::Widget> widget(CreateNewWidget());
758 DragTestView* drag_view = new DragTestView;
759 AddViewToWidgetAndResize(widget.get(), drag_view);
760 ui::OSExchangeData data;
761 data.SetString(base::UTF8ToUTF16("I am being dragged"));
762 ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
763 widget->GetNativeView());
764 generator.PressLeftButton();
766 int num_drags = 17;
767 for (int i = 0; i < num_drags; ++i) {
768 // Because we are not doing a blocking drag and drop, the original
769 // OSDragExchangeData object is lost as soon as we return from the drag
770 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
771 // drag_data_ to a fake drag data object that we created.
772 if (i > 0)
773 UpdateDragData(&data);
774 generator.MoveMouseBy(0, 1);
776 // Execute any scheduled draws to process deferred mouse events.
777 RunAllPendingInMessageLoop();
780 generator.PressKey(ui::VKEY_ESCAPE, 0);
782 EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
783 EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
784 drag_drop_controller_->num_drag_updates_);
785 EXPECT_FALSE(drag_drop_controller_->drop_received_);
786 EXPECT_TRUE(drag_drop_controller_->drag_canceled_);
787 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
788 drag_drop_controller_->drag_string_);
790 EXPECT_EQ(1, drag_view->num_drag_enters_);
791 EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
792 drag_view->num_drag_updates_);
793 EXPECT_EQ(0, drag_view->num_drops_);
794 EXPECT_EQ(1, drag_view->num_drag_exits_);
795 EXPECT_TRUE(drag_view->drag_done_received_);
798 TEST_F(DragDropControllerTest, MAYBE_CaptureLostCancelsDragDrop) {
799 scoped_ptr<views::Widget> widget(CreateNewWidget());
800 DragTestView* drag_view = new DragTestView;
801 AddViewToWidgetAndResize(widget.get(), drag_view);
802 ui::OSExchangeData data;
803 data.SetString(base::UTF8ToUTF16("I am being dragged"));
804 ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
805 widget->GetNativeView());
806 generator.PressLeftButton();
808 int num_drags = 17;
809 for (int i = 0; i < num_drags; ++i) {
810 // Because we are not doing a blocking drag and drop, the original
811 // OSDragExchangeData object is lost as soon as we return from the drag
812 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
813 // drag_data_ to a fake drag data object that we created.
814 if (i > 0)
815 UpdateDragData(&data);
816 generator.MoveMouseBy(0, 1);
818 // Execute any scheduled draws to process deferred mouse events.
819 RunAllPendingInMessageLoop();
821 // Make sure the capture window won't handle mouse events.
822 aura::Window* capture_window = drag_drop_tracker()->capture_window();
823 ASSERT_TRUE(!!capture_window);
824 EXPECT_EQ("0x0", capture_window->bounds().size().ToString());
825 EXPECT_EQ(NULL,
826 capture_window->GetEventHandlerForPoint(gfx::Point()));
827 EXPECT_EQ(NULL,
828 capture_window->GetTopWindowContainingPoint(gfx::Point()));
830 aura::client::GetCaptureClient(widget->GetNativeView()->GetRootWindow())->
831 SetCapture(NULL);
833 EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
834 EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
835 drag_drop_controller_->num_drag_updates_);
836 EXPECT_FALSE(drag_drop_controller_->drop_received_);
837 EXPECT_TRUE(drag_drop_controller_->drag_canceled_);
838 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
839 drag_drop_controller_->drag_string_);
841 EXPECT_EQ(1, drag_view->num_drag_enters_);
842 EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
843 drag_view->num_drag_updates_);
844 EXPECT_EQ(0, drag_view->num_drops_);
845 EXPECT_EQ(1, drag_view->num_drag_exits_);
846 EXPECT_TRUE(drag_view->drag_done_received_);
849 TEST_F(DragDropControllerTest, TouchDragDropInMultipleWindows) {
850 base::CommandLine::ForCurrentProcess()->AppendSwitch(
851 switches::kEnableTouchDragDrop);
852 scoped_ptr<views::Widget> widget1(CreateNewWidget());
853 DragTestView* drag_view1 = new DragTestView;
854 AddViewToWidgetAndResize(widget1.get(), drag_view1);
855 scoped_ptr<views::Widget> widget2(CreateNewWidget());
856 DragTestView* drag_view2 = new DragTestView;
857 AddViewToWidgetAndResize(widget2.get(), drag_view2);
858 gfx::Rect widget1_bounds = widget1->GetClientAreaBoundsInScreen();
859 gfx::Rect widget2_bounds = widget2->GetClientAreaBoundsInScreen();
860 widget2->SetBounds(gfx::Rect(widget1_bounds.width(), 0,
861 widget2_bounds.width(), widget2_bounds.height()));
863 ui::OSExchangeData data;
864 data.SetString(base::UTF8ToUTF16("I am being dragged"));
866 ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
867 widget1->GetNativeView());
868 generator.PressTouch();
869 gfx::Point point = gfx::Rect(drag_view1->bounds()).CenterPoint();
870 DispatchGesture(ui::ET_GESTURE_LONG_PRESS, point);
871 // Because we are not doing a blocking drag and drop, the original
872 // OSDragExchangeData object is lost as soon as we return from the drag
873 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
874 // drag_data_ to a fake drag data object that we created.
875 UpdateDragData(&data);
876 gfx::Point gesture_location = point;
877 int num_drags = drag_view1->width();
878 for (int i = 0; i < num_drags; ++i) {
879 gesture_location.Offset(1, 0);
880 DispatchGesture(ui::ET_GESTURE_SCROLL_UPDATE, gesture_location);
882 // Execute any scheduled draws to process deferred mouse events.
883 RunAllPendingInMessageLoop();
886 DispatchGesture(ui::ET_GESTURE_SCROLL_END, gesture_location);
888 EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
889 EXPECT_EQ(num_drags, drag_drop_controller_->num_drag_updates_);
890 EXPECT_TRUE(drag_drop_controller_->drop_received_);
891 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
892 drag_drop_controller_->drag_string_);
894 EXPECT_EQ(1, drag_view1->num_drag_enters_);
895 int num_expected_updates = drag_view1->bounds().width() -
896 drag_view1->bounds().CenterPoint().x() - 1;
897 EXPECT_EQ(num_expected_updates, drag_view1->num_drag_updates_);
898 EXPECT_EQ(0, drag_view1->num_drops_);
899 EXPECT_EQ(1, drag_view1->num_drag_exits_);
900 EXPECT_TRUE(drag_view1->drag_done_received_);
902 EXPECT_EQ(1, drag_view2->num_drag_enters_);
903 num_expected_updates = num_drags - num_expected_updates;
904 EXPECT_EQ(num_expected_updates, drag_view2->num_drag_updates_);
905 EXPECT_EQ(1, drag_view2->num_drops_);
906 EXPECT_EQ(0, drag_view2->num_drag_exits_);
907 EXPECT_FALSE(drag_view2->drag_done_received_);
910 TEST_F(DragDropControllerTest, TouchDragDropCancelsOnLongTap) {
911 base::CommandLine::ForCurrentProcess()->AppendSwitch(
912 switches::kEnableTouchDragDrop);
913 scoped_ptr<views::Widget> widget(CreateNewWidget());
914 DragTestView* drag_view = new DragTestView;
915 AddViewToWidgetAndResize(widget.get(), drag_view);
916 ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
917 widget->GetNativeView());
919 generator.PressTouch();
920 gfx::Point point = gfx::Rect(drag_view->bounds()).CenterPoint();
921 DispatchGesture(ui::ET_GESTURE_LONG_PRESS, point);
922 DispatchGesture(ui::ET_GESTURE_LONG_TAP, point);
924 EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
925 EXPECT_TRUE(drag_drop_controller_->drag_canceled_);
926 EXPECT_EQ(0, drag_drop_controller_->num_drag_updates_);
927 EXPECT_FALSE(drag_drop_controller_->drop_received_);
928 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
929 drag_drop_controller_->drag_string_);
930 EXPECT_EQ(0, drag_view->num_drag_enters_);
931 EXPECT_EQ(0, drag_view->num_drops_);
932 EXPECT_EQ(0, drag_view->num_drag_exits_);
933 EXPECT_TRUE(drag_view->drag_done_received_);
936 TEST_F(DragDropControllerTest, TouchDragDropLongTapGestureIsForwarded) {
937 base::CommandLine::ForCurrentProcess()->AppendSwitch(
938 switches::kEnableTouchDragDrop);
939 scoped_ptr<views::Widget> widget(CreateNewWidget());
940 DragTestView* drag_view = new DragTestView;
941 AddViewToWidgetAndResize(widget.get(), drag_view);
942 ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
943 widget->GetNativeView());
945 generator.PressTouch();
946 gfx::Point point = gfx::Rect(drag_view->bounds()).CenterPoint();
947 DispatchGesture(ui::ET_GESTURE_LONG_PRESS, point);
949 // Since we are not running inside a nested loop, the |drag_source_window_|
950 // will get destroyed immediately. Hence we reassign it.
951 EXPECT_EQ(NULL, GetDragSourceWindow());
952 SetDragSourceWindow(widget->GetNativeView());
953 EXPECT_FALSE(drag_view->long_tap_received_);
954 DispatchGesture(ui::ET_GESTURE_LONG_TAP, point);
955 CompleteCancelAnimation();
956 EXPECT_TRUE(drag_view->long_tap_received_);
959 namespace {
961 class DragImageWindowObserver : public aura::WindowObserver {
962 public:
963 void OnWindowDestroying(aura::Window* window) override {
964 window_location_on_destroying_ = window->GetBoundsInScreen().origin();
967 gfx::Point window_location_on_destroying() const {
968 return window_location_on_destroying_;
971 public:
972 gfx::Point window_location_on_destroying_;
977 // Verifies the drag image moves back to the position where drag is started
978 // across displays when drag is cancelled.
979 TEST_F(DragDropControllerTest, DragCancelAcrossDisplays) {
980 if (!SupportsMultipleDisplays())
981 return;
983 UpdateDisplay("400x400,400x400");
984 aura::Window::Windows root_windows =
985 Shell::GetInstance()->GetAllRootWindows();
986 for (aura::Window::Windows::iterator iter = root_windows.begin();
987 iter != root_windows.end(); ++iter) {
988 aura::client::SetDragDropClient(*iter, drag_drop_controller_.get());
991 ui::OSExchangeData data;
992 data.SetString(base::UTF8ToUTF16("I am being dragged"));
994 scoped_ptr<views::Widget> widget(CreateNewWidget());
995 aura::Window* window = widget->GetNativeWindow();
996 drag_drop_controller_->StartDragAndDrop(
997 data,
998 window->GetRootWindow(),
999 window,
1000 gfx::Point(5, 5),
1001 ui::DragDropTypes::DRAG_MOVE,
1002 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
1004 DragImageWindowObserver observer;
1005 ASSERT_TRUE(GetDragImageWindow());
1006 GetDragImageWindow()->AddObserver(&observer);
1009 ui::MouseEvent e(ui::ET_MOUSE_DRAGGED, gfx::Point(200, 0),
1010 gfx::Point(200, 0), ui::EventTimeForNow(), ui::EF_NONE,
1011 ui::EF_NONE);
1012 drag_drop_controller_->DragUpdate(window, e);
1015 ui::MouseEvent e(ui::ET_MOUSE_DRAGGED, gfx::Point(600, 0),
1016 gfx::Point(600, 0), ui::EventTimeForNow(), ui::EF_NONE,
1017 ui::EF_NONE);
1018 drag_drop_controller_->DragUpdate(window, e);
1021 drag_drop_controller_->DragCancel();
1022 CompleteCancelAnimation();
1024 EXPECT_EQ("5,5", observer.window_location_on_destroying().ToString());
1028 scoped_ptr<views::Widget> widget(CreateNewWidget());
1029 aura::Window* window = widget->GetNativeWindow();
1030 drag_drop_controller_->StartDragAndDrop(
1031 data,
1032 window->GetRootWindow(),
1033 window,
1034 gfx::Point(405, 405),
1035 ui::DragDropTypes::DRAG_MOVE,
1036 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
1037 DragImageWindowObserver observer;
1038 ASSERT_TRUE(GetDragImageWindow());
1039 GetDragImageWindow()->AddObserver(&observer);
1042 ui::MouseEvent e(ui::ET_MOUSE_DRAGGED, gfx::Point(600, 0),
1043 gfx::Point(600, 0), ui::EventTimeForNow(), ui::EF_NONE,
1044 ui::EF_NONE);
1045 drag_drop_controller_->DragUpdate(window, e);
1048 ui::MouseEvent e(ui::ET_MOUSE_DRAGGED, gfx::Point(200, 0),
1049 gfx::Point(200, 0), ui::EventTimeForNow(), ui::EF_NONE,
1050 ui::EF_NONE);
1051 drag_drop_controller_->DragUpdate(window, e);
1054 drag_drop_controller_->DragCancel();
1055 CompleteCancelAnimation();
1057 EXPECT_EQ("405,405", observer.window_location_on_destroying().ToString());
1059 for (aura::Window::Windows::iterator iter = root_windows.begin();
1060 iter != root_windows.end(); ++iter) {
1061 aura::client::SetDragDropClient(*iter, NULL);
1065 TEST_F(DragDropControllerTest, TouchDragDropCompletesOnFling) {
1066 base::CommandLine::ForCurrentProcess()->AppendSwitch(
1067 switches::kEnableTouchDragDrop);
1068 ui::GestureConfiguration::GetInstance()
1069 ->set_max_touch_move_in_pixels_for_click(1);
1070 scoped_ptr<views::Widget> widget(CreateNewWidget());
1071 DragTestView* drag_view = new DragTestView;
1072 AddViewToWidgetAndResize(widget.get(), drag_view);
1073 ui::OSExchangeData data;
1074 data.SetString(base::UTF8ToUTF16("I am being dragged"));
1075 ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
1076 widget->GetNativeView());
1078 gfx::Point start = gfx::Rect(drag_view->bounds()).CenterPoint();
1079 gfx::Point mid = start + gfx::Vector2d(drag_view->bounds().width() / 6, 0);
1080 gfx::Point end = start + gfx::Vector2d(drag_view->bounds().width() / 3, 0);
1082 base::TimeDelta timestamp = ui::EventTimeForNow();
1083 ui::TouchEvent press(ui::ET_TOUCH_PRESSED, start, 0, timestamp);
1084 generator.Dispatch(&press);
1086 DispatchGesture(ui::ET_GESTURE_LONG_PRESS, start);
1087 UpdateDragData(&data);
1088 timestamp += base::TimeDelta::FromMilliseconds(10);
1089 ui::TouchEvent move1(ui::ET_TOUCH_MOVED, mid, 0, timestamp);
1090 generator.Dispatch(&move1);
1091 // Doing two moves instead of one will guarantee to generate a fling at the
1092 // end.
1093 timestamp += base::TimeDelta::FromMilliseconds(10);
1094 ui::TouchEvent move2(ui::ET_TOUCH_MOVED, end, 0, timestamp);
1095 generator.Dispatch(&move2);
1096 ui::TouchEvent release(ui::ET_TOUCH_RELEASED, end, 0, timestamp);
1097 generator.Dispatch(&release);
1099 EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
1100 EXPECT_FALSE(drag_drop_controller_->drag_canceled_);
1101 EXPECT_EQ(2, drag_drop_controller_->num_drag_updates_);
1102 EXPECT_TRUE(drag_drop_controller_->drop_received_);
1103 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
1104 drag_drop_controller_->drag_string_);
1105 EXPECT_EQ(1, drag_view->num_drag_enters_);
1106 EXPECT_EQ(2, drag_view->num_drag_updates_);
1107 EXPECT_EQ(1, drag_view->num_drops_);
1108 EXPECT_EQ(0, drag_view->num_drag_exits_);
1109 EXPECT_TRUE(drag_view->drag_done_received_);
1112 } // namespace test
1113 } // namespace aura