adjust browser_tests exclusion list for Dr.Memory bots
[chromium-blink-merge.git] / ash / drag_drop / drag_drop_controller_unittest.cc
blobce4810ef14bb043959f6a3bb6eb9fdcbd285b5bb
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/test/event_generator.h"
16 #include "ui/aura/window_event_dispatcher.h"
17 #include "ui/aura/window_tree_host.h"
18 #include "ui/base/clipboard/clipboard.h"
19 #include "ui/base/clipboard/scoped_clipboard_writer.h"
20 #include "ui/base/dragdrop/drag_drop_types.h"
21 #include "ui/base/dragdrop/drag_utils.h"
22 #include "ui/base/dragdrop/os_exchange_data.h"
23 #include "ui/base/ui_base_switches.h"
24 #include "ui/events/event.h"
25 #include "ui/events/event_utils.h"
26 #include "ui/events/gestures/gesture_types.h"
27 #include "ui/events/test/events_test_utils.h"
28 #include "ui/gfx/animation/linear_animation.h"
29 #include "ui/gfx/image/image_skia_rep.h"
30 #include "ui/views/view.h"
31 #include "ui/views/views_delegate.h"
32 #include "ui/views/widget/native_widget_aura.h"
33 #include "ui/views/widget/native_widget_delegate.h"
34 #include "ui/views/widget/widget.h"
36 namespace ash {
37 namespace test {
39 namespace {
41 // A simple view that makes sure RunShellDrag is invoked on mouse drag.
42 class DragTestView : public views::View {
43 public:
44 DragTestView() : views::View() {
45 Reset();
48 void Reset() {
49 num_drag_enters_ = 0;
50 num_drag_exits_ = 0;
51 num_drag_updates_ = 0;
52 num_drops_ = 0;
53 drag_done_received_ = false;
54 long_tap_received_ = false;
57 int VerticalDragThreshold() {
58 return views::View::GetVerticalDragThreshold();
61 int HorizontalDragThreshold() {
62 return views::View::GetHorizontalDragThreshold();
65 int num_drag_enters_;
66 int num_drag_exits_;
67 int num_drag_updates_;
68 int num_drops_;
69 bool drag_done_received_;
70 bool long_tap_received_;
72 private:
73 // View overrides:
74 virtual int GetDragOperations(const gfx::Point& press_pt) OVERRIDE {
75 return ui::DragDropTypes::DRAG_COPY;
78 virtual void WriteDragData(const gfx::Point& p,
79 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 virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
88 return true;
91 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
92 if (event->type() == ui::ET_GESTURE_LONG_TAP)
93 long_tap_received_ = true;
94 return;
97 virtual bool GetDropFormats(
98 int* formats,
99 std::set<OSExchangeData::CustomFormat>* custom_formats) OVERRIDE {
100 *formats = ui::OSExchangeData::STRING;
101 return true;
104 virtual bool CanDrop(const OSExchangeData& data) OVERRIDE {
105 return true;
108 virtual void OnDragEntered(const ui::DropTargetEvent& event) OVERRIDE {
109 num_drag_enters_++;
112 virtual int OnDragUpdated(const ui::DropTargetEvent& event) OVERRIDE {
113 num_drag_updates_++;
114 return ui::DragDropTypes::DRAG_COPY;
117 virtual void OnDragExited() OVERRIDE {
118 num_drag_exits_++;
121 virtual int OnPerformDrop(const ui::DropTargetEvent& event) OVERRIDE {
122 num_drops_++;
123 return ui::DragDropTypes::DRAG_COPY;
126 virtual void OnDragDone() OVERRIDE {
127 drag_done_received_ = true;
130 DISALLOW_COPY_AND_ASSIGN(DragTestView);
133 class CompletableLinearAnimation : public gfx::LinearAnimation {
134 public:
135 CompletableLinearAnimation(int duration,
136 int frame_rate,
137 gfx::AnimationDelegate* delegate)
138 : gfx::LinearAnimation(duration, frame_rate, delegate),
139 duration_(duration) {
142 void Complete() {
143 Step(start_time() + base::TimeDelta::FromMilliseconds(duration_));
146 private:
147 int duration_;
150 class TestDragDropController : public DragDropController {
151 public:
152 TestDragDropController() : DragDropController() { Reset(); }
154 void Reset() {
155 drag_start_received_ = false;
156 num_drag_updates_ = 0;
157 drop_received_ = false;
158 drag_canceled_ = false;
159 drag_string_.clear();
162 virtual int StartDragAndDrop(
163 const ui::OSExchangeData& data,
164 aura::Window* root_window,
165 aura::Window* source_window,
166 const gfx::Point& location,
167 int operation,
168 ui::DragDropTypes::DragEventSource source) OVERRIDE {
169 drag_start_received_ = true;
170 data.GetString(&drag_string_);
171 return DragDropController::StartDragAndDrop(
172 data, root_window, source_window, location, operation, source);
175 virtual void DragUpdate(aura::Window* target,
176 const ui::LocatedEvent& event) OVERRIDE {
177 DragDropController::DragUpdate(target, event);
178 num_drag_updates_++;
181 virtual void Drop(aura::Window* target,
182 const ui::LocatedEvent& event) OVERRIDE {
183 DragDropController::Drop(target, event);
184 drop_received_ = true;
187 virtual void DragCancel() OVERRIDE {
188 DragDropController::DragCancel();
189 drag_canceled_ = true;
192 virtual gfx::LinearAnimation* CreateCancelAnimation(
193 int duration,
194 int frame_rate,
195 gfx::AnimationDelegate* delegate) OVERRIDE {
196 return new CompletableLinearAnimation(duration, frame_rate, delegate);
199 virtual void DoDragCancel(int animation_duration_ms) OVERRIDE {
200 DragDropController::DoDragCancel(animation_duration_ms);
201 drag_canceled_ = true;
204 bool drag_start_received_;
205 int num_drag_updates_;
206 bool drop_received_;
207 bool drag_canceled_;
208 base::string16 drag_string_;
210 private:
211 DISALLOW_COPY_AND_ASSIGN(TestDragDropController);
214 class TestNativeWidgetAura : public views::NativeWidgetAura {
215 public:
216 explicit TestNativeWidgetAura(views::internal::NativeWidgetDelegate* delegate)
217 : NativeWidgetAura(delegate),
218 check_if_capture_lost_(false) {
221 void set_check_if_capture_lost(bool value) {
222 check_if_capture_lost_ = value;
225 virtual void OnCaptureLost() OVERRIDE {
226 DCHECK(!check_if_capture_lost_);
227 views::NativeWidgetAura::OnCaptureLost();
230 private:
231 bool check_if_capture_lost_;
233 DISALLOW_COPY_AND_ASSIGN(TestNativeWidgetAura);
236 // TODO(sky): this is for debugging, remove when track down failure.
237 void SetCheckIfCaptureLost(views::Widget* widget, bool value) {
238 // On Windows, the DCHECK triggers when running on bot or locally through RDP,
239 // but not when logged in locally.
240 #if !defined(OS_WIN)
241 static_cast<TestNativeWidgetAura*>(widget->native_widget())->
242 set_check_if_capture_lost(value);
243 #endif
246 views::Widget* CreateNewWidget() {
247 views::Widget* widget = new views::Widget;
248 views::Widget::InitParams params;
249 params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
250 params.accept_events = true;
251 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
252 params.parent = Shell::GetPrimaryRootWindow();
253 params.child = true;
254 params.native_widget = new TestNativeWidgetAura(widget);
255 widget->Init(params);
256 widget->Show();
257 return widget;
260 void AddViewToWidgetAndResize(views::Widget* widget, views::View* view) {
261 if (!widget->GetContentsView()) {
262 views::View* contents_view = new views::View;
263 widget->SetContentsView(contents_view);
266 views::View* contents_view = widget->GetContentsView();
267 contents_view->AddChildView(view);
268 view->SetBounds(contents_view->width(), 0, 100, 100);
269 gfx::Rect contents_view_bounds = contents_view->bounds();
270 contents_view_bounds.Union(view->bounds());
271 contents_view->SetBoundsRect(contents_view_bounds);
272 widget->SetBounds(contents_view_bounds);
275 void DispatchGesture(ui::EventType gesture_type, gfx::Point location) {
276 ui::GestureEvent gesture_event(
277 gesture_type,
278 location.x(),
279 location.y(),
281 ui::EventTimeForNow(),
282 ui::GestureEventDetails(gesture_type, 0, 0),
284 ui::EventSource* event_source =
285 Shell::GetPrimaryRootWindow()->GetHost()->GetEventSource();
286 ui::EventSourceTestApi event_source_test(event_source);
287 ui::EventDispatchDetails details =
288 event_source_test.SendEventToProcessor(&gesture_event);
289 CHECK(!details.dispatcher_destroyed);
292 } // namespace
294 class DragDropControllerTest : public AshTestBase {
295 public:
296 DragDropControllerTest() : AshTestBase() {}
297 virtual ~DragDropControllerTest() {}
299 virtual void SetUp() OVERRIDE {
300 AshTestBase::SetUp();
301 drag_drop_controller_.reset(new TestDragDropController);
302 drag_drop_controller_->set_should_block_during_drag_drop(false);
303 aura::client::SetDragDropClient(Shell::GetPrimaryRootWindow(),
304 drag_drop_controller_.get());
307 virtual void TearDown() OVERRIDE {
308 aura::client::SetDragDropClient(Shell::GetPrimaryRootWindow(), NULL);
309 drag_drop_controller_.reset();
310 AshTestBase::TearDown();
313 void UpdateDragData(ui::OSExchangeData* data) {
314 drag_drop_controller_->drag_data_ = data;
317 aura::Window* GetDragWindow() {
318 return drag_drop_controller_->drag_window_;
321 aura::Window* GetDragSourceWindow() {
322 return drag_drop_controller_->drag_source_window_;
325 void SetDragSourceWindow(aura::Window* drag_source_window) {
326 drag_drop_controller_->drag_source_window_ = drag_source_window;
327 drag_source_window->AddObserver(drag_drop_controller_.get());
330 aura::Window* GetDragImageWindow() {
331 return drag_drop_controller_->drag_image_.get() ?
332 drag_drop_controller_->drag_image_->GetWidget()->GetNativeWindow() :
333 NULL;
336 DragDropTracker* drag_drop_tracker() {
337 return drag_drop_controller_->drag_drop_tracker_.get();
340 void CompleteCancelAnimation() {
341 CompletableLinearAnimation* animation =
342 static_cast<CompletableLinearAnimation*>(
343 drag_drop_controller_->cancel_animation_.get());
344 animation->Complete();
347 protected:
348 scoped_ptr<TestDragDropController> drag_drop_controller_;
350 private:
351 DISALLOW_COPY_AND_ASSIGN(DragDropControllerTest);
354 // TODO(win_aura) http://crbug.com/154081
355 #if defined(OS_WIN)
356 #define MAYBE_DragDropInSingleViewTest DISABLED_DragDropInSingleViewTest
357 #else
358 #define MAYBE_DragDropInSingleViewTest DragDropInSingleViewTest
359 #endif
360 TEST_F(DragDropControllerTest, MAYBE_DragDropInSingleViewTest) {
361 scoped_ptr<views::Widget> widget(CreateNewWidget());
362 DragTestView* drag_view = new DragTestView;
363 AddViewToWidgetAndResize(widget.get(), drag_view);
364 ui::OSExchangeData data;
365 data.SetString(base::UTF8ToUTF16("I am being dragged"));
366 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
367 widget->GetNativeView());
368 generator.PressLeftButton();
370 int num_drags = 17;
371 SetCheckIfCaptureLost(widget.get(), true);
372 for (int i = 0; i < num_drags; ++i) {
373 // Because we are not doing a blocking drag and drop, the original
374 // OSDragExchangeData object is lost as soon as we return from the drag
375 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
376 // drag_data_ to a fake drag data object that we created.
377 if (i > 0)
378 UpdateDragData(&data);
379 // 7 comes from views::View::GetVerticalDragThreshold()).
380 if (i >= 7)
381 SetCheckIfCaptureLost(widget.get(), false);
383 generator.MoveMouseBy(0, 1);
385 // Execute any scheduled draws to process deferred mouse events.
386 RunAllPendingInMessageLoop();
389 generator.ReleaseLeftButton();
391 EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
392 EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
393 drag_drop_controller_->num_drag_updates_);
394 EXPECT_TRUE(drag_drop_controller_->drop_received_);
395 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
396 drag_drop_controller_->drag_string_);
398 EXPECT_EQ(1, drag_view->num_drag_enters_);
399 EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
400 drag_view->num_drag_updates_);
401 EXPECT_EQ(1, drag_view->num_drops_);
402 EXPECT_EQ(0, drag_view->num_drag_exits_);
403 EXPECT_TRUE(drag_view->drag_done_received_);
406 TEST_F(DragDropControllerTest, DragDropWithZeroDragUpdates) {
407 scoped_ptr<views::Widget> widget(CreateNewWidget());
408 DragTestView* drag_view = new DragTestView;
409 AddViewToWidgetAndResize(widget.get(), drag_view);
410 ui::OSExchangeData data;
411 data.SetString(base::UTF8ToUTF16("I am being dragged"));
412 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
413 widget->GetNativeView());
414 generator.PressLeftButton();
416 int num_drags = drag_view->VerticalDragThreshold() + 1;
417 for (int i = 0; i < num_drags; ++i) {
418 // Because we are not doing a blocking drag and drop, the original
419 // OSDragExchangeData object is lost as soon as we return from the drag
420 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
421 // drag_data_ to a fake drag data object that we created.
422 if (i > 0)
423 UpdateDragData(&data);
424 generator.MoveMouseBy(0, 1);
427 UpdateDragData(&data);
429 generator.ReleaseLeftButton();
431 EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
432 EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold() + 1,
433 drag_drop_controller_->num_drag_updates_);
434 EXPECT_TRUE(drag_drop_controller_->drop_received_);
436 EXPECT_EQ(1, drag_view->num_drag_enters_);
437 EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold() + 1,
438 drag_view->num_drag_updates_);
439 EXPECT_EQ(1, drag_view->num_drops_);
440 EXPECT_EQ(0, drag_view->num_drag_exits_);
441 EXPECT_TRUE(drag_view->drag_done_received_);
444 // TODO(win_aura) http://crbug.com/154081
445 #if defined(OS_WIN)
446 #define MAYBE_DragDropInMultipleViewsSingleWidgetTest DISABLED_DragDropInMultipleViewsSingleWidgetTest
447 #else
448 #define MAYBE_DragDropInMultipleViewsSingleWidgetTest DragDropInMultipleViewsSingleWidgetTest
449 #endif
450 TEST_F(DragDropControllerTest, MAYBE_DragDropInMultipleViewsSingleWidgetTest) {
451 scoped_ptr<views::Widget> widget(CreateNewWidget());
452 DragTestView* drag_view1 = new DragTestView;
453 AddViewToWidgetAndResize(widget.get(), drag_view1);
454 DragTestView* drag_view2 = new DragTestView;
455 AddViewToWidgetAndResize(widget.get(), drag_view2);
457 ui::OSExchangeData data;
458 data.SetString(base::UTF8ToUTF16("I am being dragged"));
460 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
461 generator.MoveMouseRelativeTo(widget->GetNativeView(),
462 drag_view1->bounds().CenterPoint());
463 generator.PressLeftButton();
465 int num_drags = drag_view1->width();
466 for (int i = 0; i < num_drags; ++i) {
467 // Because we are not doing a blocking drag and drop, the original
468 // OSDragExchangeData object is lost as soon as we return from the drag
469 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
470 // drag_data_ to a fake drag data object that we created.
471 if (i > 0)
472 UpdateDragData(&data);
473 generator.MoveMouseBy(1, 0);
475 // Execute any scheduled draws to process deferred mouse events.
476 RunAllPendingInMessageLoop();
479 generator.ReleaseLeftButton();
481 EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
482 EXPECT_EQ(num_drags - 1 - drag_view1->HorizontalDragThreshold(),
483 drag_drop_controller_->num_drag_updates_);
484 EXPECT_TRUE(drag_drop_controller_->drop_received_);
485 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
486 drag_drop_controller_->drag_string_);
488 EXPECT_EQ(1, drag_view1->num_drag_enters_);
489 int num_expected_updates = drag_view1->bounds().width() -
490 drag_view1->bounds().CenterPoint().x() - 2;
491 EXPECT_EQ(num_expected_updates - drag_view1->HorizontalDragThreshold(),
492 drag_view1->num_drag_updates_);
493 EXPECT_EQ(0, drag_view1->num_drops_);
494 EXPECT_EQ(1, drag_view1->num_drag_exits_);
495 EXPECT_TRUE(drag_view1->drag_done_received_);
497 EXPECT_EQ(1, drag_view2->num_drag_enters_);
498 num_expected_updates = num_drags - num_expected_updates - 1;
499 EXPECT_EQ(num_expected_updates, drag_view2->num_drag_updates_);
500 EXPECT_EQ(1, drag_view2->num_drops_);
501 EXPECT_EQ(0, drag_view2->num_drag_exits_);
502 EXPECT_FALSE(drag_view2->drag_done_received_);
505 // TODO(win_aura) http://crbug.com/154081
506 #if defined(OS_WIN)
507 #define MAYBE_DragDropInMultipleViewsMultipleWidgetsTest DISABLED_DragDropInMultipleViewsMultipleWidgetsTest
508 #else
509 #define MAYBE_DragDropInMultipleViewsMultipleWidgetsTest DragDropInMultipleViewsMultipleWidgetsTest
510 #endif
511 TEST_F(DragDropControllerTest, MAYBE_DragDropInMultipleViewsMultipleWidgetsTest) {
512 scoped_ptr<views::Widget> widget1(CreateNewWidget());
513 DragTestView* drag_view1 = new DragTestView;
514 AddViewToWidgetAndResize(widget1.get(), drag_view1);
515 scoped_ptr<views::Widget> widget2(CreateNewWidget());
516 DragTestView* drag_view2 = new DragTestView;
517 AddViewToWidgetAndResize(widget2.get(), drag_view2);
518 gfx::Rect widget1_bounds = widget1->GetClientAreaBoundsInScreen();
519 gfx::Rect widget2_bounds = widget2->GetClientAreaBoundsInScreen();
520 widget2->SetBounds(gfx::Rect(widget1_bounds.width(), 0,
521 widget2_bounds.width(), widget2_bounds.height()));
523 ui::OSExchangeData data;
524 data.SetString(base::UTF8ToUTF16("I am being dragged"));
526 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
527 widget1->GetNativeView());
528 generator.PressLeftButton();
530 int num_drags = drag_view1->width();
531 for (int i = 0; i < num_drags; ++i) {
532 // Because we are not doing a blocking drag and drop, the original
533 // OSDragExchangeData object is lost as soon as we return from the drag
534 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
535 // drag_data_ to a fake drag data object that we created.
536 if (i > 0)
537 UpdateDragData(&data);
538 generator.MoveMouseBy(1, 0);
540 // Execute any scheduled draws to process deferred mouse events.
541 RunAllPendingInMessageLoop();
544 generator.ReleaseLeftButton();
546 EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
547 EXPECT_EQ(num_drags - 1 - drag_view1->HorizontalDragThreshold(),
548 drag_drop_controller_->num_drag_updates_);
549 EXPECT_TRUE(drag_drop_controller_->drop_received_);
550 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
551 drag_drop_controller_->drag_string_);
553 EXPECT_EQ(1, drag_view1->num_drag_enters_);
554 int num_expected_updates = drag_view1->bounds().width() -
555 drag_view1->bounds().CenterPoint().x() - 2;
556 EXPECT_EQ(num_expected_updates - drag_view1->HorizontalDragThreshold(),
557 drag_view1->num_drag_updates_);
558 EXPECT_EQ(0, drag_view1->num_drops_);
559 EXPECT_EQ(1, drag_view1->num_drag_exits_);
560 EXPECT_TRUE(drag_view1->drag_done_received_);
562 EXPECT_EQ(1, drag_view2->num_drag_enters_);
563 num_expected_updates = num_drags - num_expected_updates - 1;
564 EXPECT_EQ(num_expected_updates, drag_view2->num_drag_updates_);
565 EXPECT_EQ(1, drag_view2->num_drops_);
566 EXPECT_EQ(0, drag_view2->num_drag_exits_);
567 EXPECT_FALSE(drag_view2->drag_done_received_);
570 // TODO(win_aura) http://crbug.com/154081
571 #if defined(OS_WIN)
572 #define MAYBE_ViewRemovedWhileInDragDropTest DISABLED_ViewRemovedWhileInDragDropTest
573 #else
574 #define MAYBE_ViewRemovedWhileInDragDropTest ViewRemovedWhileInDragDropTest
575 #endif
576 TEST_F(DragDropControllerTest, MAYBE_ViewRemovedWhileInDragDropTest) {
577 scoped_ptr<views::Widget> widget(CreateNewWidget());
578 scoped_ptr<DragTestView> drag_view(new DragTestView);
579 AddViewToWidgetAndResize(widget.get(), drag_view.get());
580 gfx::Point point = gfx::Rect(drag_view->bounds()).CenterPoint();
581 ui::OSExchangeData data;
582 data.SetString(base::UTF8ToUTF16("I am being dragged"));
584 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
585 generator.MoveMouseToCenterOf(widget->GetNativeView());
586 generator.PressLeftButton();
588 int num_drags_1 = 17;
589 for (int i = 0; i < num_drags_1; ++i) {
590 // Because we are not doing a blocking drag and drop, the original
591 // OSDragExchangeData object is lost as soon as we return from the drag
592 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
593 // drag_data_ to a fake drag data object that we created.
594 if (i > 0)
595 UpdateDragData(&data);
596 generator.MoveMouseBy(0, 1);
598 // Execute any scheduled draws to process deferred mouse events.
599 RunAllPendingInMessageLoop();
602 drag_view->parent()->RemoveChildView(drag_view.get());
603 // View has been removed. We will not get any of the following drag updates.
604 int num_drags_2 = 23;
605 for (int i = 0; i < num_drags_2; ++i) {
606 UpdateDragData(&data);
607 generator.MoveMouseBy(0, 1);
609 // Execute any scheduled draws to process deferred mouse events.
610 RunAllPendingInMessageLoop();
613 generator.ReleaseLeftButton();
615 EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
616 EXPECT_EQ(num_drags_1 + num_drags_2 - 1 - drag_view->VerticalDragThreshold(),
617 drag_drop_controller_->num_drag_updates_);
618 EXPECT_TRUE(drag_drop_controller_->drop_received_);
619 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
620 drag_drop_controller_->drag_string_);
622 EXPECT_EQ(1, drag_view->num_drag_enters_);
623 EXPECT_EQ(num_drags_1 - 1 - drag_view->VerticalDragThreshold(),
624 drag_view->num_drag_updates_);
625 EXPECT_EQ(0, drag_view->num_drops_);
626 EXPECT_EQ(0, drag_view->num_drag_exits_);
627 EXPECT_TRUE(drag_view->drag_done_received_);
630 TEST_F(DragDropControllerTest, DragLeavesClipboardAloneTest) {
631 ui::Clipboard* cb = ui::Clipboard::GetForCurrentThread();
632 std::string clip_str("I am on the clipboard");
634 // We first copy some text to the clipboard.
635 ui::ScopedClipboardWriter scw(cb, ui::CLIPBOARD_TYPE_COPY_PASTE);
636 scw.WriteText(base::ASCIIToUTF16(clip_str));
638 EXPECT_TRUE(cb->IsFormatAvailable(ui::Clipboard::GetPlainTextFormatType(),
639 ui::CLIPBOARD_TYPE_COPY_PASTE));
641 scoped_ptr<views::Widget> widget(CreateNewWidget());
642 DragTestView* drag_view = new DragTestView;
643 AddViewToWidgetAndResize(widget.get(), drag_view);
645 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
646 widget->GetNativeView());
647 ui::OSExchangeData data;
648 std::string data_str("I am being dragged");
649 data.SetString(base::ASCIIToUTF16(data_str));
651 generator.PressLeftButton();
652 generator.MoveMouseBy(0, drag_view->VerticalDragThreshold() + 1);
654 // Execute any scheduled draws to process deferred mouse events.
655 RunAllPendingInMessageLoop();
657 // Verify the clipboard contents haven't changed
658 std::string result;
659 EXPECT_TRUE(cb->IsFormatAvailable(ui::Clipboard::GetPlainTextFormatType(),
660 ui::CLIPBOARD_TYPE_COPY_PASTE));
661 cb->ReadAsciiText(ui::CLIPBOARD_TYPE_COPY_PASTE, &result);
662 EXPECT_EQ(clip_str, result);
663 // Destory the clipboard here because ash doesn't delete it.
664 // crbug.com/158150.
665 ui::Clipboard::DestroyClipboardForCurrentThread();
668 TEST_F(DragDropControllerTest, WindowDestroyedDuringDragDrop) {
669 scoped_ptr<views::Widget> widget(CreateNewWidget());
670 DragTestView* drag_view = new DragTestView;
671 AddViewToWidgetAndResize(widget.get(), drag_view);
672 aura::Window* window = widget->GetNativeView();
674 ui::OSExchangeData data;
675 data.SetString(base::UTF8ToUTF16("I am being dragged"));
676 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
677 widget->GetNativeView());
678 generator.PressLeftButton();
680 int num_drags = 17;
681 for (int i = 0; i < num_drags; ++i) {
682 // Because we are not doing a blocking drag and drop, the original
683 // OSDragExchangeData object is lost as soon as we return from the drag
684 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
685 // drag_data_ to a fake drag data object that we created.
686 if (i > 0)
687 UpdateDragData(&data);
688 generator.MoveMouseBy(0, 1);
690 // Execute any scheduled draws to process deferred mouse events.
691 RunAllPendingInMessageLoop();
693 if (i > drag_view->VerticalDragThreshold())
694 EXPECT_EQ(window, GetDragWindow());
697 widget->CloseNow();
698 EXPECT_FALSE(GetDragWindow());
700 num_drags = 23;
701 for (int i = 0; i < num_drags; ++i) {
702 if (i > 0)
703 UpdateDragData(&data);
704 generator.MoveMouseBy(0, 1);
705 // We should not crash here.
708 generator.ReleaseLeftButton();
710 EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
711 EXPECT_TRUE(drag_drop_controller_->drop_received_);
714 TEST_F(DragDropControllerTest, SyntheticEventsDuringDragDrop) {
715 scoped_ptr<views::Widget> widget(CreateNewWidget());
716 DragTestView* drag_view = new DragTestView;
717 AddViewToWidgetAndResize(widget.get(), drag_view);
718 ui::OSExchangeData data;
719 data.SetString(base::UTF8ToUTF16("I am being dragged"));
720 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
721 widget->GetNativeView());
722 generator.PressLeftButton();
724 int num_drags = 17;
725 for (int i = 0; i < num_drags; ++i) {
726 // Because we are not doing a blocking drag and drop, the original
727 // OSDragExchangeData object is lost as soon as we return from the drag
728 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
729 // drag_data_ to a fake drag data object that we created.
730 if (i > 0)
731 UpdateDragData(&data);
732 generator.MoveMouseBy(0, 1);
734 // We send a unexpected mouse move event. Note that we cannot use
735 // EventGenerator since it implicitly turns these into mouse drag events.
736 // The DragDropController should simply ignore these events.
737 gfx::Point mouse_move_location = drag_view->bounds().CenterPoint();
738 ui::MouseEvent mouse_move(ui::ET_MOUSE_MOVED, mouse_move_location,
739 mouse_move_location, 0, 0);
740 ui::EventDispatchDetails details = Shell::GetPrimaryRootWindow()->
741 GetHost()->event_processor()->OnEventFromSource(&mouse_move);
742 ASSERT_FALSE(details.dispatcher_destroyed);
745 generator.ReleaseLeftButton();
747 EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
748 EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
749 drag_drop_controller_->num_drag_updates_);
750 EXPECT_TRUE(drag_drop_controller_->drop_received_);
751 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
752 drag_drop_controller_->drag_string_);
754 EXPECT_EQ(1, drag_view->num_drag_enters_);
755 EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
756 drag_view->num_drag_updates_);
757 EXPECT_EQ(1, drag_view->num_drops_);
758 EXPECT_EQ(0, drag_view->num_drag_exits_);
759 EXPECT_TRUE(drag_view->drag_done_received_);
762 // TODO(win_aura) http://crbug.com/154081
763 #if defined(OS_WIN)
764 #define MAYBE_PressingEscapeCancelsDragDrop DISABLED_PressingEscapeCancelsDragDrop
765 #define MAYBE_CaptureLostCancelsDragDrop DISABLED_CaptureLostCancelsDragDrop
766 #else
767 #define MAYBE_PressingEscapeCancelsDragDrop PressingEscapeCancelsDragDrop
768 #define MAYBE_CaptureLostCancelsDragDrop CaptureLostCancelsDragDrop
769 #endif
770 TEST_F(DragDropControllerTest, MAYBE_PressingEscapeCancelsDragDrop) {
771 scoped_ptr<views::Widget> widget(CreateNewWidget());
772 DragTestView* drag_view = new DragTestView;
773 AddViewToWidgetAndResize(widget.get(), drag_view);
774 ui::OSExchangeData data;
775 data.SetString(base::UTF8ToUTF16("I am being dragged"));
776 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
777 widget->GetNativeView());
778 generator.PressLeftButton();
780 int num_drags = 17;
781 for (int i = 0; i < num_drags; ++i) {
782 // Because we are not doing a blocking drag and drop, the original
783 // OSDragExchangeData object is lost as soon as we return from the drag
784 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
785 // drag_data_ to a fake drag data object that we created.
786 if (i > 0)
787 UpdateDragData(&data);
788 generator.MoveMouseBy(0, 1);
790 // Execute any scheduled draws to process deferred mouse events.
791 RunAllPendingInMessageLoop();
794 generator.PressKey(ui::VKEY_ESCAPE, 0);
796 EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
797 EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
798 drag_drop_controller_->num_drag_updates_);
799 EXPECT_FALSE(drag_drop_controller_->drop_received_);
800 EXPECT_TRUE(drag_drop_controller_->drag_canceled_);
801 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
802 drag_drop_controller_->drag_string_);
804 EXPECT_EQ(1, drag_view->num_drag_enters_);
805 EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
806 drag_view->num_drag_updates_);
807 EXPECT_EQ(0, drag_view->num_drops_);
808 EXPECT_EQ(1, drag_view->num_drag_exits_);
809 EXPECT_TRUE(drag_view->drag_done_received_);
812 TEST_F(DragDropControllerTest, MAYBE_CaptureLostCancelsDragDrop) {
813 scoped_ptr<views::Widget> widget(CreateNewWidget());
814 DragTestView* drag_view = new DragTestView;
815 AddViewToWidgetAndResize(widget.get(), drag_view);
816 ui::OSExchangeData data;
817 data.SetString(base::UTF8ToUTF16("I am being dragged"));
818 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
819 widget->GetNativeView());
820 generator.PressLeftButton();
822 int num_drags = 17;
823 for (int i = 0; i < num_drags; ++i) {
824 // Because we are not doing a blocking drag and drop, the original
825 // OSDragExchangeData object is lost as soon as we return from the drag
826 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
827 // drag_data_ to a fake drag data object that we created.
828 if (i > 0)
829 UpdateDragData(&data);
830 generator.MoveMouseBy(0, 1);
832 // Execute any scheduled draws to process deferred mouse events.
833 RunAllPendingInMessageLoop();
835 // Make sure the capture window won't handle mouse events.
836 aura::Window* capture_window = drag_drop_tracker()->capture_window();
837 ASSERT_TRUE(!!capture_window);
838 EXPECT_EQ("0x0", capture_window->bounds().size().ToString());
839 EXPECT_EQ(NULL,
840 capture_window->GetEventHandlerForPoint(gfx::Point()));
841 EXPECT_EQ(NULL,
842 capture_window->GetTopWindowContainingPoint(gfx::Point()));
844 aura::client::GetCaptureClient(widget->GetNativeView()->GetRootWindow())->
845 SetCapture(NULL);
847 EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
848 EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
849 drag_drop_controller_->num_drag_updates_);
850 EXPECT_FALSE(drag_drop_controller_->drop_received_);
851 EXPECT_TRUE(drag_drop_controller_->drag_canceled_);
852 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
853 drag_drop_controller_->drag_string_);
855 EXPECT_EQ(1, drag_view->num_drag_enters_);
856 EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
857 drag_view->num_drag_updates_);
858 EXPECT_EQ(0, drag_view->num_drops_);
859 EXPECT_EQ(1, drag_view->num_drag_exits_);
860 EXPECT_TRUE(drag_view->drag_done_received_);
863 TEST_F(DragDropControllerTest, TouchDragDropInMultipleWindows) {
864 CommandLine::ForCurrentProcess()->AppendSwitch(
865 switches::kEnableTouchDragDrop);
866 scoped_ptr<views::Widget> widget1(CreateNewWidget());
867 DragTestView* drag_view1 = new DragTestView;
868 AddViewToWidgetAndResize(widget1.get(), drag_view1);
869 scoped_ptr<views::Widget> widget2(CreateNewWidget());
870 DragTestView* drag_view2 = new DragTestView;
871 AddViewToWidgetAndResize(widget2.get(), drag_view2);
872 gfx::Rect widget1_bounds = widget1->GetClientAreaBoundsInScreen();
873 gfx::Rect widget2_bounds = widget2->GetClientAreaBoundsInScreen();
874 widget2->SetBounds(gfx::Rect(widget1_bounds.width(), 0,
875 widget2_bounds.width(), widget2_bounds.height()));
877 ui::OSExchangeData data;
878 data.SetString(base::UTF8ToUTF16("I am being dragged"));
880 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
881 widget1->GetNativeView());
882 generator.PressTouch();
883 gfx::Point point = gfx::Rect(drag_view1->bounds()).CenterPoint();
884 DispatchGesture(ui::ET_GESTURE_LONG_PRESS, point);
885 // Because we are not doing a blocking drag and drop, the original
886 // OSDragExchangeData object is lost as soon as we return from the drag
887 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
888 // drag_data_ to a fake drag data object that we created.
889 UpdateDragData(&data);
890 gfx::Point gesture_location = point;
891 int num_drags = drag_view1->width();
892 for (int i = 0; i < num_drags; ++i) {
893 gesture_location.Offset(1, 0);
894 DispatchGesture(ui::ET_GESTURE_SCROLL_UPDATE, gesture_location);
896 // Execute any scheduled draws to process deferred mouse events.
897 RunAllPendingInMessageLoop();
900 DispatchGesture(ui::ET_GESTURE_SCROLL_END, gesture_location);
902 EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
903 EXPECT_EQ(num_drags, drag_drop_controller_->num_drag_updates_);
904 EXPECT_TRUE(drag_drop_controller_->drop_received_);
905 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
906 drag_drop_controller_->drag_string_);
908 EXPECT_EQ(1, drag_view1->num_drag_enters_);
909 int num_expected_updates = drag_view1->bounds().width() -
910 drag_view1->bounds().CenterPoint().x() - 1;
911 EXPECT_EQ(num_expected_updates, drag_view1->num_drag_updates_);
912 EXPECT_EQ(0, drag_view1->num_drops_);
913 EXPECT_EQ(1, drag_view1->num_drag_exits_);
914 EXPECT_TRUE(drag_view1->drag_done_received_);
916 EXPECT_EQ(1, drag_view2->num_drag_enters_);
917 num_expected_updates = num_drags - num_expected_updates;
918 EXPECT_EQ(num_expected_updates, drag_view2->num_drag_updates_);
919 EXPECT_EQ(1, drag_view2->num_drops_);
920 EXPECT_EQ(0, drag_view2->num_drag_exits_);
921 EXPECT_FALSE(drag_view2->drag_done_received_);
924 TEST_F(DragDropControllerTest, TouchDragDropCancelsOnLongTap) {
925 CommandLine::ForCurrentProcess()->AppendSwitch(
926 switches::kEnableTouchDragDrop);
927 scoped_ptr<views::Widget> widget(CreateNewWidget());
928 DragTestView* drag_view = new DragTestView;
929 AddViewToWidgetAndResize(widget.get(), drag_view);
930 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
931 widget->GetNativeView());
933 generator.PressTouch();
934 gfx::Point point = gfx::Rect(drag_view->bounds()).CenterPoint();
935 DispatchGesture(ui::ET_GESTURE_LONG_PRESS, point);
936 DispatchGesture(ui::ET_GESTURE_LONG_TAP, point);
938 EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
939 EXPECT_TRUE(drag_drop_controller_->drag_canceled_);
940 EXPECT_EQ(0, drag_drop_controller_->num_drag_updates_);
941 EXPECT_FALSE(drag_drop_controller_->drop_received_);
942 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
943 drag_drop_controller_->drag_string_);
944 EXPECT_EQ(0, drag_view->num_drag_enters_);
945 EXPECT_EQ(0, drag_view->num_drops_);
946 EXPECT_EQ(0, drag_view->num_drag_exits_);
947 EXPECT_TRUE(drag_view->drag_done_received_);
950 TEST_F(DragDropControllerTest, TouchDragDropLongTapGestureIsForwarded) {
951 CommandLine::ForCurrentProcess()->AppendSwitch(
952 switches::kEnableTouchDragDrop);
953 scoped_ptr<views::Widget> widget(CreateNewWidget());
954 DragTestView* drag_view = new DragTestView;
955 AddViewToWidgetAndResize(widget.get(), drag_view);
956 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
957 widget->GetNativeView());
959 generator.PressTouch();
960 gfx::Point point = gfx::Rect(drag_view->bounds()).CenterPoint();
961 DispatchGesture(ui::ET_GESTURE_LONG_PRESS, point);
963 // Since we are not running inside a nested loop, the |drag_source_window_|
964 // will get destroyed immediately. Hence we reassign it.
965 EXPECT_EQ(NULL, GetDragSourceWindow());
966 SetDragSourceWindow(widget->GetNativeView());
967 EXPECT_FALSE(drag_view->long_tap_received_);
968 DispatchGesture(ui::ET_GESTURE_LONG_TAP, point);
969 CompleteCancelAnimation();
970 EXPECT_TRUE(drag_view->long_tap_received_);
973 namespace {
975 class DragImageWindowObserver : public aura::WindowObserver {
976 public:
977 virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
978 window_location_on_destroying_ = window->GetBoundsInScreen().origin();
981 gfx::Point window_location_on_destroying() const {
982 return window_location_on_destroying_;
985 public:
986 gfx::Point window_location_on_destroying_;
991 // Verifies the drag image moves back to the position where drag is started
992 // across displays when drag is cancelled.
993 TEST_F(DragDropControllerTest, DragCancelAcrossDisplays) {
994 if (!SupportsMultipleDisplays())
995 return;
997 UpdateDisplay("400x400,400x400");
998 aura::Window::Windows root_windows =
999 Shell::GetInstance()->GetAllRootWindows();
1000 for (aura::Window::Windows::iterator iter = root_windows.begin();
1001 iter != root_windows.end(); ++iter) {
1002 aura::client::SetDragDropClient(*iter, drag_drop_controller_.get());
1005 ui::OSExchangeData data;
1006 data.SetString(base::UTF8ToUTF16("I am being dragged"));
1008 scoped_ptr<views::Widget> widget(CreateNewWidget());
1009 aura::Window* window = widget->GetNativeWindow();
1010 drag_drop_controller_->StartDragAndDrop(
1011 data,
1012 window->GetRootWindow(),
1013 window,
1014 gfx::Point(5, 5),
1015 ui::DragDropTypes::DRAG_MOVE,
1016 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
1018 DragImageWindowObserver observer;
1019 ASSERT_TRUE(GetDragImageWindow());
1020 GetDragImageWindow()->AddObserver(&observer);
1023 ui::MouseEvent e(ui::ET_MOUSE_DRAGGED,
1024 gfx::Point(200, 0),
1025 gfx::Point(200, 0),
1026 ui::EF_NONE,
1027 ui::EF_NONE);
1028 drag_drop_controller_->DragUpdate(window, e);
1031 ui::MouseEvent e(ui::ET_MOUSE_DRAGGED,
1032 gfx::Point(600, 0),
1033 gfx::Point(600, 0),
1034 ui::EF_NONE,
1035 ui::EF_NONE);
1036 drag_drop_controller_->DragUpdate(window, e);
1039 drag_drop_controller_->DragCancel();
1040 CompleteCancelAnimation();
1042 EXPECT_EQ("5,5", observer.window_location_on_destroying().ToString());
1046 scoped_ptr<views::Widget> widget(CreateNewWidget());
1047 aura::Window* window = widget->GetNativeWindow();
1048 drag_drop_controller_->StartDragAndDrop(
1049 data,
1050 window->GetRootWindow(),
1051 window,
1052 gfx::Point(405, 405),
1053 ui::DragDropTypes::DRAG_MOVE,
1054 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
1055 DragImageWindowObserver observer;
1056 ASSERT_TRUE(GetDragImageWindow());
1057 GetDragImageWindow()->AddObserver(&observer);
1060 ui::MouseEvent e(ui::ET_MOUSE_DRAGGED,
1061 gfx::Point(600, 0),
1062 gfx::Point(600, 0),
1063 ui::EF_NONE,
1064 ui::EF_NONE);
1065 drag_drop_controller_->DragUpdate(window, e);
1068 ui::MouseEvent e(ui::ET_MOUSE_DRAGGED,
1069 gfx::Point(200, 0),
1070 gfx::Point(200, 0),
1071 ui::EF_NONE,
1072 ui::EF_NONE);
1073 drag_drop_controller_->DragUpdate(window, e);
1076 drag_drop_controller_->DragCancel();
1077 CompleteCancelAnimation();
1079 EXPECT_EQ("405,405", observer.window_location_on_destroying().ToString());
1081 for (aura::Window::Windows::iterator iter = root_windows.begin();
1082 iter != root_windows.end(); ++iter) {
1083 aura::client::SetDragDropClient(*iter, NULL);
1087 } // namespace test
1088 } // namespace aura