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"
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/root_window.h"
16 #include "ui/aura/test/event_generator.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/gestures/gesture_types.h"
26 #include "ui/gfx/animation/linear_animation.h"
27 #include "ui/gfx/image/image_skia_rep.h"
28 #include "ui/views/test/test_views_delegate.h"
29 #include "ui/views/view.h"
30 #include "ui/views/views_delegate.h"
31 #include "ui/views/widget/native_widget_aura.h"
32 #include "ui/views/widget/native_widget_delegate.h"
33 #include "ui/views/widget/widget.h"
40 // A simple view that makes sure RunShellDrag is invoked on mouse drag.
41 class DragTestView
: public views::View
{
43 DragTestView() : views::View() {
50 num_drag_updates_
= 0;
52 drag_done_received_
= false;
53 long_tap_received_
= false;
56 int VerticalDragThreshold() {
57 return views::View::GetVerticalDragThreshold();
60 int HorizontalDragThreshold() {
61 return views::View::GetHorizontalDragThreshold();
66 int num_drag_updates_
;
68 bool drag_done_received_
;
69 bool long_tap_received_
;
73 virtual int GetDragOperations(const gfx::Point
& press_pt
) OVERRIDE
{
74 return ui::DragDropTypes::DRAG_COPY
;
77 virtual void WriteDragData(const gfx::Point
& p
,
78 OSExchangeData
* data
) OVERRIDE
{
79 data
->SetString(UTF8ToUTF16("I am being dragged"));
80 gfx::ImageSkiaRep
image_rep(gfx::Size(10, 20), 1.0f
);
81 gfx::ImageSkia
image_skia(image_rep
);
83 drag_utils::SetDragImageOnDataObject(
84 image_skia
, image_skia
.size(), gfx::Vector2d(), data
);
87 virtual bool OnMousePressed(const ui::MouseEvent
& event
) OVERRIDE
{
91 virtual void OnGestureEvent(ui::GestureEvent
* event
) OVERRIDE
{
92 if (event
->type() == ui::ET_GESTURE_LONG_TAP
)
93 long_tap_received_
= true;
97 virtual bool GetDropFormats(
99 std::set
<OSExchangeData::CustomFormat
>* custom_formats
) OVERRIDE
{
100 *formats
= ui::OSExchangeData::STRING
;
104 virtual bool CanDrop(const OSExchangeData
& data
) OVERRIDE
{
108 virtual void OnDragEntered(const ui::DropTargetEvent
& event
) OVERRIDE
{
112 virtual int OnDragUpdated(const ui::DropTargetEvent
& event
) OVERRIDE
{
114 return ui::DragDropTypes::DRAG_COPY
;
117 virtual void OnDragExited() OVERRIDE
{
121 virtual int OnPerformDrop(const ui::DropTargetEvent
& event
) OVERRIDE
{
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
{
135 CompletableLinearAnimation(int duration
,
137 gfx::AnimationDelegate
* delegate
)
138 : gfx::LinearAnimation(duration
, frame_rate
, delegate
),
139 duration_(duration
) {
143 Step(start_time() + base::TimeDelta::FromMilliseconds(duration_
));
150 class TestDragDropController
: public internal::DragDropController
{
152 TestDragDropController() : internal::DragDropController() {
157 drag_start_received_
= false;
158 num_drag_updates_
= 0;
159 drop_received_
= false;
160 drag_canceled_
= false;
161 drag_string_
.clear();
164 virtual int StartDragAndDrop(
165 const ui::OSExchangeData
& data
,
166 aura::RootWindow
* root_window
,
167 aura::Window
* source_window
,
168 const gfx::Point
& location
,
170 ui::DragDropTypes::DragEventSource source
) OVERRIDE
{
171 drag_start_received_
= true;
172 data
.GetString(&drag_string_
);
173 return DragDropController::StartDragAndDrop(
174 data
, root_window
, source_window
, location
, operation
, source
);
177 virtual void DragUpdate(aura::Window
* target
,
178 const ui::LocatedEvent
& event
) OVERRIDE
{
179 DragDropController::DragUpdate(target
, event
);
183 virtual void Drop(aura::Window
* target
,
184 const ui::LocatedEvent
& event
) OVERRIDE
{
185 DragDropController::Drop(target
, event
);
186 drop_received_
= true;
189 virtual void DragCancel() OVERRIDE
{
190 DragDropController::DragCancel();
191 drag_canceled_
= true;
194 virtual gfx::LinearAnimation
* CreateCancelAnimation(
197 gfx::AnimationDelegate
* delegate
) OVERRIDE
{
198 return new CompletableLinearAnimation(duration
, frame_rate
, delegate
);
201 virtual void DoDragCancel(int animation_duration_ms
) OVERRIDE
{
202 DragDropController::DoDragCancel(animation_duration_ms
);
203 drag_canceled_
= true;
206 bool drag_start_received_
;
207 int num_drag_updates_
;
210 base::string16 drag_string_
;
213 DISALLOW_COPY_AND_ASSIGN(TestDragDropController
);
216 class TestNativeWidgetAura
: public views::NativeWidgetAura
{
218 explicit TestNativeWidgetAura(views::internal::NativeWidgetDelegate
* delegate
)
219 : NativeWidgetAura(delegate
),
220 check_if_capture_lost_(false) {
223 void set_check_if_capture_lost(bool value
) {
224 check_if_capture_lost_
= value
;
227 virtual void OnCaptureLost() OVERRIDE
{
228 DCHECK(!check_if_capture_lost_
);
229 views::NativeWidgetAura::OnCaptureLost();
233 bool check_if_capture_lost_
;
235 DISALLOW_COPY_AND_ASSIGN(TestNativeWidgetAura
);
238 // TODO(sky): this is for debugging, remove when track down failure.
239 void SetCheckIfCaptureLost(views::Widget
* widget
, bool value
) {
240 // On Windows, the DCHECK triggers when running on bot or locally through RDP,
241 // but not when logged in locally.
243 static_cast<TestNativeWidgetAura
*>(widget
->native_widget())->
244 set_check_if_capture_lost(value
);
248 views::Widget
* CreateNewWidget() {
249 views::Widget
* widget
= new views::Widget
;
250 views::Widget::InitParams params
;
251 params
.type
= views::Widget::InitParams::TYPE_WINDOW_FRAMELESS
;
252 params
.accept_events
= true;
253 params
.ownership
= views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
254 params
.parent
= Shell::GetPrimaryRootWindow();
256 params
.native_widget
= new TestNativeWidgetAura(widget
);
257 widget
->Init(params
);
262 void AddViewToWidgetAndResize(views::Widget
* widget
, views::View
* view
) {
263 if (!widget
->GetContentsView()) {
264 views::View
* contents_view
= new views::View
;
265 widget
->SetContentsView(contents_view
);
268 views::View
* contents_view
= widget
->GetContentsView();
269 contents_view
->AddChildView(view
);
270 view
->SetBounds(contents_view
->width(), 0, 100, 100);
271 gfx::Rect contents_view_bounds
= contents_view
->bounds();
272 contents_view_bounds
.Union(view
->bounds());
273 contents_view
->SetBoundsRect(contents_view_bounds
);
274 widget
->SetBounds(contents_view_bounds
);
277 void DispatchGesture(ui::EventType gesture_type
, gfx::Point location
) {
278 ui::GestureEvent
gesture_event(
283 ui::EventTimeForNow(),
284 ui::GestureEventDetails(gesture_type
, 0, 0),
286 Shell::GetPrimaryRootWindow()->DispatchGestureEvent(&gesture_event
);
289 bool IsGestureEventType(ui::EventType type
) {
291 case ui::ET_GESTURE_SCROLL_BEGIN
:
292 case ui::ET_GESTURE_SCROLL_END
:
293 case ui::ET_GESTURE_SCROLL_UPDATE
:
294 case ui::ET_GESTURE_TAP
:
295 case ui::ET_GESTURE_TAP_CANCEL
:
296 case ui::ET_GESTURE_TAP_DOWN
:
297 case ui::ET_GESTURE_BEGIN
:
298 case ui::ET_GESTURE_END
:
299 case ui::ET_GESTURE_TWO_FINGER_TAP
:
300 case ui::ET_GESTURE_PINCH_BEGIN
:
301 case ui::ET_GESTURE_PINCH_END
:
302 case ui::ET_GESTURE_PINCH_UPDATE
:
303 case ui::ET_GESTURE_LONG_PRESS
:
304 case ui::ET_GESTURE_LONG_TAP
:
305 case ui::ET_GESTURE_MULTIFINGER_SWIPE
:
306 case ui::ET_SCROLL_FLING_CANCEL
:
307 case ui::ET_SCROLL_FLING_START
:
317 class DragDropControllerTest
: public AshTestBase
{
319 DragDropControllerTest() : AshTestBase() {}
320 virtual ~DragDropControllerTest() {}
322 virtual void SetUp() OVERRIDE
{
323 AshTestBase::SetUp();
324 drag_drop_controller_
.reset(new TestDragDropController
);
325 drag_drop_controller_
->set_should_block_during_drag_drop(false);
326 aura::client::SetDragDropClient(Shell::GetPrimaryRootWindow(),
327 drag_drop_controller_
.get());
328 views_delegate_
.reset(new views::TestViewsDelegate
);
331 virtual void TearDown() OVERRIDE
{
332 aura::client::SetDragDropClient(Shell::GetPrimaryRootWindow(), NULL
);
333 drag_drop_controller_
.reset();
334 AshTestBase::TearDown();
337 void UpdateDragData(ui::OSExchangeData
* data
) {
338 drag_drop_controller_
->drag_data_
= data
;
341 aura::Window
* GetDragWindow() {
342 return drag_drop_controller_
->drag_window_
;
345 aura::Window
* GetDragSourceWindow() {
346 return drag_drop_controller_
->drag_source_window_
;
349 void SetDragSourceWindow(aura::Window
* drag_source_window
) {
350 drag_drop_controller_
->drag_source_window_
= drag_source_window
;
351 drag_source_window
->AddObserver(drag_drop_controller_
.get());
354 aura::Window
* GetDragImageWindow() {
355 return drag_drop_controller_
->drag_image_
.get() ?
356 drag_drop_controller_
->drag_image_
->GetWidget()->GetNativeWindow() :
360 internal::DragDropTracker
* drag_drop_tracker() {
361 return drag_drop_controller_
->drag_drop_tracker_
.get();
364 void CompleteCancelAnimation() {
365 CompletableLinearAnimation
* animation
=
366 static_cast<CompletableLinearAnimation
*>(
367 drag_drop_controller_
->cancel_animation_
.get());
368 animation
->Complete();
372 scoped_ptr
<TestDragDropController
> drag_drop_controller_
;
373 scoped_ptr
<views::TestViewsDelegate
> views_delegate_
;
376 DISALLOW_COPY_AND_ASSIGN(DragDropControllerTest
);
379 // TODO(win_aura) http://crbug.com/154081
381 #define MAYBE_DragDropInSingleViewTest DISABLED_DragDropInSingleViewTest
383 #define MAYBE_DragDropInSingleViewTest DragDropInSingleViewTest
385 TEST_F(DragDropControllerTest
, MAYBE_DragDropInSingleViewTest
) {
386 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
387 DragTestView
* drag_view
= new DragTestView
;
388 AddViewToWidgetAndResize(widget
.get(), drag_view
);
389 ui::OSExchangeData data
;
390 data
.SetString(UTF8ToUTF16("I am being dragged"));
391 aura::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
392 widget
->GetNativeView());
393 generator
.PressLeftButton();
396 SetCheckIfCaptureLost(widget
.get(), true);
397 for (int i
= 0; i
< num_drags
; ++i
) {
398 // Because we are not doing a blocking drag and drop, the original
399 // OSDragExchangeData object is lost as soon as we return from the drag
400 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
401 // drag_data_ to a fake drag data object that we created.
403 UpdateDragData(&data
);
404 // 7 comes from views::View::GetVerticalDragThreshold()).
406 SetCheckIfCaptureLost(widget
.get(), false);
408 generator
.MoveMouseBy(0, 1);
410 // Execute any scheduled draws to process deferred mouse events.
411 RunAllPendingInMessageLoop();
414 generator
.ReleaseLeftButton();
416 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
417 EXPECT_EQ(num_drags
- 1 - drag_view
->VerticalDragThreshold(),
418 drag_drop_controller_
->num_drag_updates_
);
419 EXPECT_TRUE(drag_drop_controller_
->drop_received_
);
420 EXPECT_EQ(UTF8ToUTF16("I am being dragged"),
421 drag_drop_controller_
->drag_string_
);
423 EXPECT_EQ(1, drag_view
->num_drag_enters_
);
424 EXPECT_EQ(num_drags
- 1 - drag_view
->VerticalDragThreshold(),
425 drag_view
->num_drag_updates_
);
426 EXPECT_EQ(1, drag_view
->num_drops_
);
427 EXPECT_EQ(0, drag_view
->num_drag_exits_
);
428 EXPECT_TRUE(drag_view
->drag_done_received_
);
431 TEST_F(DragDropControllerTest
, DragDropWithZeroDragUpdates
) {
432 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
433 DragTestView
* drag_view
= new DragTestView
;
434 AddViewToWidgetAndResize(widget
.get(), drag_view
);
435 ui::OSExchangeData data
;
436 data
.SetString(UTF8ToUTF16("I am being dragged"));
437 aura::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
438 widget
->GetNativeView());
439 generator
.PressLeftButton();
441 int num_drags
= drag_view
->VerticalDragThreshold() + 1;
442 for (int i
= 0; i
< num_drags
; ++i
) {
443 // Because we are not doing a blocking drag and drop, the original
444 // OSDragExchangeData object is lost as soon as we return from the drag
445 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
446 // drag_data_ to a fake drag data object that we created.
448 UpdateDragData(&data
);
449 generator
.MoveMouseBy(0, 1);
452 UpdateDragData(&data
);
454 generator
.ReleaseLeftButton();
456 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
457 EXPECT_EQ(num_drags
- 1 - drag_view
->VerticalDragThreshold() + 1,
458 drag_drop_controller_
->num_drag_updates_
);
459 EXPECT_TRUE(drag_drop_controller_
->drop_received_
);
461 EXPECT_EQ(1, drag_view
->num_drag_enters_
);
462 EXPECT_EQ(num_drags
- 1 - drag_view
->VerticalDragThreshold() + 1,
463 drag_view
->num_drag_updates_
);
464 EXPECT_EQ(1, drag_view
->num_drops_
);
465 EXPECT_EQ(0, drag_view
->num_drag_exits_
);
466 EXPECT_TRUE(drag_view
->drag_done_received_
);
469 // TODO(win_aura) http://crbug.com/154081
471 #define MAYBE_DragDropInMultipleViewsSingleWidgetTest DISABLED_DragDropInMultipleViewsSingleWidgetTest
473 #define MAYBE_DragDropInMultipleViewsSingleWidgetTest DragDropInMultipleViewsSingleWidgetTest
475 TEST_F(DragDropControllerTest
, MAYBE_DragDropInMultipleViewsSingleWidgetTest
) {
476 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
477 DragTestView
* drag_view1
= new DragTestView
;
478 AddViewToWidgetAndResize(widget
.get(), drag_view1
);
479 DragTestView
* drag_view2
= new DragTestView
;
480 AddViewToWidgetAndResize(widget
.get(), drag_view2
);
482 ui::OSExchangeData data
;
483 data
.SetString(UTF8ToUTF16("I am being dragged"));
485 aura::test::EventGenerator
generator(Shell::GetPrimaryRootWindow());
486 generator
.MoveMouseRelativeTo(widget
->GetNativeView(),
487 drag_view1
->bounds().CenterPoint());
488 generator
.PressLeftButton();
490 int num_drags
= drag_view1
->width();
491 for (int i
= 0; i
< num_drags
; ++i
) {
492 // Because we are not doing a blocking drag and drop, the original
493 // OSDragExchangeData object is lost as soon as we return from the drag
494 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
495 // drag_data_ to a fake drag data object that we created.
497 UpdateDragData(&data
);
498 generator
.MoveMouseBy(1, 0);
500 // Execute any scheduled draws to process deferred mouse events.
501 RunAllPendingInMessageLoop();
504 generator
.ReleaseLeftButton();
506 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
507 EXPECT_EQ(num_drags
- 1 - drag_view1
->HorizontalDragThreshold(),
508 drag_drop_controller_
->num_drag_updates_
);
509 EXPECT_TRUE(drag_drop_controller_
->drop_received_
);
510 EXPECT_EQ(UTF8ToUTF16("I am being dragged"),
511 drag_drop_controller_
->drag_string_
);
513 EXPECT_EQ(1, drag_view1
->num_drag_enters_
);
514 int num_expected_updates
= drag_view1
->bounds().width() -
515 drag_view1
->bounds().CenterPoint().x() - 2;
516 EXPECT_EQ(num_expected_updates
- drag_view1
->HorizontalDragThreshold(),
517 drag_view1
->num_drag_updates_
);
518 EXPECT_EQ(0, drag_view1
->num_drops_
);
519 EXPECT_EQ(1, drag_view1
->num_drag_exits_
);
520 EXPECT_TRUE(drag_view1
->drag_done_received_
);
522 EXPECT_EQ(1, drag_view2
->num_drag_enters_
);
523 num_expected_updates
= num_drags
- num_expected_updates
- 1;
524 EXPECT_EQ(num_expected_updates
, drag_view2
->num_drag_updates_
);
525 EXPECT_EQ(1, drag_view2
->num_drops_
);
526 EXPECT_EQ(0, drag_view2
->num_drag_exits_
);
527 EXPECT_FALSE(drag_view2
->drag_done_received_
);
530 // TODO(win_aura) http://crbug.com/154081
532 #define MAYBE_DragDropInMultipleViewsMultipleWidgetsTest DISABLED_DragDropInMultipleViewsMultipleWidgetsTest
534 #define MAYBE_DragDropInMultipleViewsMultipleWidgetsTest DragDropInMultipleViewsMultipleWidgetsTest
536 TEST_F(DragDropControllerTest
, MAYBE_DragDropInMultipleViewsMultipleWidgetsTest
) {
537 scoped_ptr
<views::Widget
> widget1(CreateNewWidget());
538 DragTestView
* drag_view1
= new DragTestView
;
539 AddViewToWidgetAndResize(widget1
.get(), drag_view1
);
540 scoped_ptr
<views::Widget
> widget2(CreateNewWidget());
541 DragTestView
* drag_view2
= new DragTestView
;
542 AddViewToWidgetAndResize(widget2
.get(), drag_view2
);
543 gfx::Rect widget1_bounds
= widget1
->GetClientAreaBoundsInScreen();
544 gfx::Rect widget2_bounds
= widget2
->GetClientAreaBoundsInScreen();
545 widget2
->SetBounds(gfx::Rect(widget1_bounds
.width(), 0,
546 widget2_bounds
.width(), widget2_bounds
.height()));
548 ui::OSExchangeData data
;
549 data
.SetString(UTF8ToUTF16("I am being dragged"));
551 aura::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
552 widget1
->GetNativeView());
553 generator
.PressLeftButton();
555 int num_drags
= drag_view1
->width();
556 for (int i
= 0; i
< num_drags
; ++i
) {
557 // Because we are not doing a blocking drag and drop, the original
558 // OSDragExchangeData object is lost as soon as we return from the drag
559 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
560 // drag_data_ to a fake drag data object that we created.
562 UpdateDragData(&data
);
563 generator
.MoveMouseBy(1, 0);
565 // Execute any scheduled draws to process deferred mouse events.
566 RunAllPendingInMessageLoop();
569 generator
.ReleaseLeftButton();
571 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
572 EXPECT_EQ(num_drags
- 1 - drag_view1
->HorizontalDragThreshold(),
573 drag_drop_controller_
->num_drag_updates_
);
574 EXPECT_TRUE(drag_drop_controller_
->drop_received_
);
575 EXPECT_EQ(UTF8ToUTF16("I am being dragged"),
576 drag_drop_controller_
->drag_string_
);
578 EXPECT_EQ(1, drag_view1
->num_drag_enters_
);
579 int num_expected_updates
= drag_view1
->bounds().width() -
580 drag_view1
->bounds().CenterPoint().x() - 2;
581 EXPECT_EQ(num_expected_updates
- drag_view1
->HorizontalDragThreshold(),
582 drag_view1
->num_drag_updates_
);
583 EXPECT_EQ(0, drag_view1
->num_drops_
);
584 EXPECT_EQ(1, drag_view1
->num_drag_exits_
);
585 EXPECT_TRUE(drag_view1
->drag_done_received_
);
587 EXPECT_EQ(1, drag_view2
->num_drag_enters_
);
588 num_expected_updates
= num_drags
- num_expected_updates
- 1;
589 EXPECT_EQ(num_expected_updates
, drag_view2
->num_drag_updates_
);
590 EXPECT_EQ(1, drag_view2
->num_drops_
);
591 EXPECT_EQ(0, drag_view2
->num_drag_exits_
);
592 EXPECT_FALSE(drag_view2
->drag_done_received_
);
595 // TODO(win_aura) http://crbug.com/154081
597 #define MAYBE_ViewRemovedWhileInDragDropTest DISABLED_ViewRemovedWhileInDragDropTest
599 #define MAYBE_ViewRemovedWhileInDragDropTest ViewRemovedWhileInDragDropTest
601 TEST_F(DragDropControllerTest
, MAYBE_ViewRemovedWhileInDragDropTest
) {
602 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
603 scoped_ptr
<DragTestView
> drag_view(new DragTestView
);
604 AddViewToWidgetAndResize(widget
.get(), drag_view
.get());
605 gfx::Point point
= gfx::Rect(drag_view
->bounds()).CenterPoint();
606 ui::OSExchangeData data
;
607 data
.SetString(UTF8ToUTF16("I am being dragged"));
609 aura::test::EventGenerator
generator(Shell::GetPrimaryRootWindow());
610 generator
.MoveMouseToCenterOf(widget
->GetNativeView());
611 generator
.PressLeftButton();
613 int num_drags_1
= 17;
614 for (int i
= 0; i
< num_drags_1
; ++i
) {
615 // Because we are not doing a blocking drag and drop, the original
616 // OSDragExchangeData object is lost as soon as we return from the drag
617 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
618 // drag_data_ to a fake drag data object that we created.
620 UpdateDragData(&data
);
621 generator
.MoveMouseBy(0, 1);
623 // Execute any scheduled draws to process deferred mouse events.
624 RunAllPendingInMessageLoop();
627 drag_view
->parent()->RemoveChildView(drag_view
.get());
628 // View has been removed. We will not get any of the following drag updates.
629 int num_drags_2
= 23;
630 for (int i
= 0; i
< num_drags_2
; ++i
) {
631 UpdateDragData(&data
);
632 generator
.MoveMouseBy(0, 1);
634 // Execute any scheduled draws to process deferred mouse events.
635 RunAllPendingInMessageLoop();
638 generator
.ReleaseLeftButton();
640 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
641 EXPECT_EQ(num_drags_1
+ num_drags_2
- 1 - drag_view
->VerticalDragThreshold(),
642 drag_drop_controller_
->num_drag_updates_
);
643 EXPECT_TRUE(drag_drop_controller_
->drop_received_
);
644 EXPECT_EQ(UTF8ToUTF16("I am being dragged"),
645 drag_drop_controller_
->drag_string_
);
647 EXPECT_EQ(1, drag_view
->num_drag_enters_
);
648 EXPECT_EQ(num_drags_1
- 1 - drag_view
->VerticalDragThreshold(),
649 drag_view
->num_drag_updates_
);
650 EXPECT_EQ(0, drag_view
->num_drops_
);
651 EXPECT_EQ(0, drag_view
->num_drag_exits_
);
652 EXPECT_TRUE(drag_view
->drag_done_received_
);
655 TEST_F(DragDropControllerTest
, DragLeavesClipboardAloneTest
) {
656 ui::Clipboard
* cb
= ui::Clipboard::GetForCurrentThread();
657 std::string
clip_str("I am on the clipboard");
659 // We first copy some text to the clipboard.
660 ui::ScopedClipboardWriter
scw(cb
, ui::Clipboard::BUFFER_STANDARD
);
661 scw
.WriteText(ASCIIToUTF16(clip_str
));
663 EXPECT_TRUE(cb
->IsFormatAvailable(ui::Clipboard::GetPlainTextFormatType(),
664 ui::Clipboard::BUFFER_STANDARD
));
666 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
667 DragTestView
* drag_view
= new DragTestView
;
668 AddViewToWidgetAndResize(widget
.get(), drag_view
);
670 aura::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
671 widget
->GetNativeView());
672 ui::OSExchangeData data
;
673 std::string
data_str("I am being dragged");
674 data
.SetString(ASCIIToUTF16(data_str
));
676 generator
.PressLeftButton();
677 generator
.MoveMouseBy(0, drag_view
->VerticalDragThreshold() + 1);
679 // Execute any scheduled draws to process deferred mouse events.
680 RunAllPendingInMessageLoop();
682 // Verify the clipboard contents haven't changed
684 EXPECT_TRUE(cb
->IsFormatAvailable(ui::Clipboard::GetPlainTextFormatType(),
685 ui::Clipboard::BUFFER_STANDARD
));
686 cb
->ReadAsciiText(ui::Clipboard::BUFFER_STANDARD
, &result
);
687 EXPECT_EQ(clip_str
, result
);
688 // Destory the clipboard here because ash doesn't delete it.
690 ui::Clipboard::DestroyClipboardForCurrentThread();
693 TEST_F(DragDropControllerTest
, WindowDestroyedDuringDragDrop
) {
694 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
695 DragTestView
* drag_view
= new DragTestView
;
696 AddViewToWidgetAndResize(widget
.get(), drag_view
);
697 aura::Window
* window
= widget
->GetNativeView();
699 ui::OSExchangeData data
;
700 data
.SetString(UTF8ToUTF16("I am being dragged"));
701 aura::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
702 widget
->GetNativeView());
703 generator
.PressLeftButton();
706 for (int i
= 0; i
< num_drags
; ++i
) {
707 // Because we are not doing a blocking drag and drop, the original
708 // OSDragExchangeData object is lost as soon as we return from the drag
709 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
710 // drag_data_ to a fake drag data object that we created.
712 UpdateDragData(&data
);
713 generator
.MoveMouseBy(0, 1);
715 // Execute any scheduled draws to process deferred mouse events.
716 RunAllPendingInMessageLoop();
718 if (i
> drag_view
->VerticalDragThreshold())
719 EXPECT_EQ(window
, GetDragWindow());
723 EXPECT_FALSE(GetDragWindow());
726 for (int i
= 0; i
< num_drags
; ++i
) {
728 UpdateDragData(&data
);
729 generator
.MoveMouseBy(0, 1);
730 // We should not crash here.
733 generator
.ReleaseLeftButton();
735 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
736 EXPECT_TRUE(drag_drop_controller_
->drop_received_
);
739 TEST_F(DragDropControllerTest
, SyntheticEventsDuringDragDrop
) {
740 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
741 DragTestView
* drag_view
= new DragTestView
;
742 AddViewToWidgetAndResize(widget
.get(), drag_view
);
743 ui::OSExchangeData data
;
744 data
.SetString(UTF8ToUTF16("I am being dragged"));
745 aura::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
746 widget
->GetNativeView());
747 generator
.PressLeftButton();
750 for (int i
= 0; i
< num_drags
; ++i
) {
751 // Because we are not doing a blocking drag and drop, the original
752 // OSDragExchangeData object is lost as soon as we return from the drag
753 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
754 // drag_data_ to a fake drag data object that we created.
756 UpdateDragData(&data
);
757 generator
.MoveMouseBy(0, 1);
759 // We send a unexpected mouse move event. Note that we cannot use
760 // EventGenerator since it implicitly turns these into mouse drag events.
761 // The DragDropController should simply ignore these events.
762 gfx::Point mouse_move_location
= drag_view
->bounds().CenterPoint();
763 ui::MouseEvent
mouse_move(ui::ET_MOUSE_MOVED
, mouse_move_location
,
764 mouse_move_location
, 0);
765 Shell::GetPrimaryRootWindow()->AsRootWindowHostDelegate()->OnHostMouseEvent(
769 generator
.ReleaseLeftButton();
771 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
772 EXPECT_EQ(num_drags
- 1 - drag_view
->VerticalDragThreshold(),
773 drag_drop_controller_
->num_drag_updates_
);
774 EXPECT_TRUE(drag_drop_controller_
->drop_received_
);
775 EXPECT_EQ(UTF8ToUTF16("I am being dragged"),
776 drag_drop_controller_
->drag_string_
);
778 EXPECT_EQ(1, drag_view
->num_drag_enters_
);
779 EXPECT_EQ(num_drags
- 1 - drag_view
->VerticalDragThreshold(),
780 drag_view
->num_drag_updates_
);
781 EXPECT_EQ(1, drag_view
->num_drops_
);
782 EXPECT_EQ(0, drag_view
->num_drag_exits_
);
783 EXPECT_TRUE(drag_view
->drag_done_received_
);
786 // TODO(win_aura) http://crbug.com/154081
788 #define MAYBE_PressingEscapeCancelsDragDrop DISABLED_PressingEscapeCancelsDragDrop
789 #define MAYBE_CaptureLostCancelsDragDrop DISABLED_CaptureLostCancelsDragDrop
791 #define MAYBE_PressingEscapeCancelsDragDrop PressingEscapeCancelsDragDrop
792 #define MAYBE_CaptureLostCancelsDragDrop CaptureLostCancelsDragDrop
794 TEST_F(DragDropControllerTest
, MAYBE_PressingEscapeCancelsDragDrop
) {
795 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
796 DragTestView
* drag_view
= new DragTestView
;
797 AddViewToWidgetAndResize(widget
.get(), drag_view
);
798 ui::OSExchangeData data
;
799 data
.SetString(UTF8ToUTF16("I am being dragged"));
800 aura::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
801 widget
->GetNativeView());
802 generator
.PressLeftButton();
805 for (int i
= 0; i
< num_drags
; ++i
) {
806 // Because we are not doing a blocking drag and drop, the original
807 // OSDragExchangeData object is lost as soon as we return from the drag
808 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
809 // drag_data_ to a fake drag data object that we created.
811 UpdateDragData(&data
);
812 generator
.MoveMouseBy(0, 1);
814 // Execute any scheduled draws to process deferred mouse events.
815 RunAllPendingInMessageLoop();
818 generator
.PressKey(ui::VKEY_ESCAPE
, 0);
820 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
821 EXPECT_EQ(num_drags
- 1 - drag_view
->VerticalDragThreshold(),
822 drag_drop_controller_
->num_drag_updates_
);
823 EXPECT_FALSE(drag_drop_controller_
->drop_received_
);
824 EXPECT_TRUE(drag_drop_controller_
->drag_canceled_
);
825 EXPECT_EQ(UTF8ToUTF16("I am being dragged"),
826 drag_drop_controller_
->drag_string_
);
828 EXPECT_EQ(1, drag_view
->num_drag_enters_
);
829 EXPECT_EQ(num_drags
- 1 - drag_view
->VerticalDragThreshold(),
830 drag_view
->num_drag_updates_
);
831 EXPECT_EQ(0, drag_view
->num_drops_
);
832 EXPECT_EQ(1, drag_view
->num_drag_exits_
);
833 EXPECT_TRUE(drag_view
->drag_done_received_
);
836 TEST_F(DragDropControllerTest
, MAYBE_CaptureLostCancelsDragDrop
) {
837 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
838 DragTestView
* drag_view
= new DragTestView
;
839 AddViewToWidgetAndResize(widget
.get(), drag_view
);
840 ui::OSExchangeData data
;
841 data
.SetString(UTF8ToUTF16("I am being dragged"));
842 aura::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
843 widget
->GetNativeView());
844 generator
.PressLeftButton();
847 for (int i
= 0; i
< num_drags
; ++i
) {
848 // Because we are not doing a blocking drag and drop, the original
849 // OSDragExchangeData object is lost as soon as we return from the drag
850 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
851 // drag_data_ to a fake drag data object that we created.
853 UpdateDragData(&data
);
854 generator
.MoveMouseBy(0, 1);
856 // Execute any scheduled draws to process deferred mouse events.
857 RunAllPendingInMessageLoop();
859 // Make sure the capture window won't handle mouse events.
860 aura::Window
* capture_window
= drag_drop_tracker()->capture_window();
861 ASSERT_TRUE(!!capture_window
);
862 EXPECT_EQ("0x0", capture_window
->bounds().size().ToString());
864 capture_window
->GetEventHandlerForPoint(gfx::Point()));
866 capture_window
->GetTopWindowContainingPoint(gfx::Point()));
868 aura::client::GetCaptureClient(widget
->GetNativeView()->GetRootWindow())->
871 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
872 EXPECT_EQ(num_drags
- 1 - drag_view
->VerticalDragThreshold(),
873 drag_drop_controller_
->num_drag_updates_
);
874 EXPECT_FALSE(drag_drop_controller_
->drop_received_
);
875 EXPECT_TRUE(drag_drop_controller_
->drag_canceled_
);
876 EXPECT_EQ(UTF8ToUTF16("I am being dragged"),
877 drag_drop_controller_
->drag_string_
);
879 EXPECT_EQ(1, drag_view
->num_drag_enters_
);
880 EXPECT_EQ(num_drags
- 1 - drag_view
->VerticalDragThreshold(),
881 drag_view
->num_drag_updates_
);
882 EXPECT_EQ(0, drag_view
->num_drops_
);
883 EXPECT_EQ(1, drag_view
->num_drag_exits_
);
884 EXPECT_TRUE(drag_view
->drag_done_received_
);
887 TEST_F(DragDropControllerTest
, TouchDragDropInMultipleWindows
) {
888 CommandLine::ForCurrentProcess()->AppendSwitch(
889 switches::kEnableTouchDragDrop
);
890 scoped_ptr
<views::Widget
> widget1(CreateNewWidget());
891 DragTestView
* drag_view1
= new DragTestView
;
892 AddViewToWidgetAndResize(widget1
.get(), drag_view1
);
893 scoped_ptr
<views::Widget
> widget2(CreateNewWidget());
894 DragTestView
* drag_view2
= new DragTestView
;
895 AddViewToWidgetAndResize(widget2
.get(), drag_view2
);
896 gfx::Rect widget1_bounds
= widget1
->GetClientAreaBoundsInScreen();
897 gfx::Rect widget2_bounds
= widget2
->GetClientAreaBoundsInScreen();
898 widget2
->SetBounds(gfx::Rect(widget1_bounds
.width(), 0,
899 widget2_bounds
.width(), widget2_bounds
.height()));
901 ui::OSExchangeData data
;
902 data
.SetString(UTF8ToUTF16("I am being dragged"));
904 aura::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
905 widget1
->GetNativeView());
906 generator
.PressTouch();
907 gfx::Point point
= gfx::Rect(drag_view1
->bounds()).CenterPoint();
908 DispatchGesture(ui::ET_GESTURE_LONG_PRESS
, point
);
909 // Because we are not doing a blocking drag and drop, the original
910 // OSDragExchangeData object is lost as soon as we return from the drag
911 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
912 // drag_data_ to a fake drag data object that we created.
913 UpdateDragData(&data
);
914 gfx::Point gesture_location
= point
;
915 int num_drags
= drag_view1
->width();
916 for (int i
= 0; i
< num_drags
; ++i
) {
917 gesture_location
.Offset(1, 0);
918 DispatchGesture(ui::ET_GESTURE_SCROLL_UPDATE
, gesture_location
);
920 // Execute any scheduled draws to process deferred mouse events.
921 RunAllPendingInMessageLoop();
924 DispatchGesture(ui::ET_GESTURE_SCROLL_END
, gesture_location
);
926 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
927 EXPECT_EQ(num_drags
, drag_drop_controller_
->num_drag_updates_
);
928 EXPECT_TRUE(drag_drop_controller_
->drop_received_
);
929 EXPECT_EQ(UTF8ToUTF16("I am being dragged"),
930 drag_drop_controller_
->drag_string_
);
932 EXPECT_EQ(1, drag_view1
->num_drag_enters_
);
933 int num_expected_updates
= drag_view1
->bounds().width() -
934 drag_view1
->bounds().CenterPoint().x() - 1;
935 EXPECT_EQ(num_expected_updates
, drag_view1
->num_drag_updates_
);
936 EXPECT_EQ(0, drag_view1
->num_drops_
);
937 EXPECT_EQ(1, drag_view1
->num_drag_exits_
);
938 EXPECT_TRUE(drag_view1
->drag_done_received_
);
940 EXPECT_EQ(1, drag_view2
->num_drag_enters_
);
941 num_expected_updates
= num_drags
- num_expected_updates
;
942 EXPECT_EQ(num_expected_updates
, drag_view2
->num_drag_updates_
);
943 EXPECT_EQ(1, drag_view2
->num_drops_
);
944 EXPECT_EQ(0, drag_view2
->num_drag_exits_
);
945 EXPECT_FALSE(drag_view2
->drag_done_received_
);
948 TEST_F(DragDropControllerTest
, TouchDragDropCancelsOnLongTap
) {
949 CommandLine::ForCurrentProcess()->AppendSwitch(
950 switches::kEnableTouchDragDrop
);
951 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
952 DragTestView
* drag_view
= new DragTestView
;
953 AddViewToWidgetAndResize(widget
.get(), drag_view
);
954 aura::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
955 widget
->GetNativeView());
957 generator
.PressTouch();
958 gfx::Point point
= gfx::Rect(drag_view
->bounds()).CenterPoint();
959 DispatchGesture(ui::ET_GESTURE_LONG_PRESS
, point
);
960 DispatchGesture(ui::ET_GESTURE_LONG_TAP
, point
);
962 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
963 EXPECT_TRUE(drag_drop_controller_
->drag_canceled_
);
964 EXPECT_EQ(0, drag_drop_controller_
->num_drag_updates_
);
965 EXPECT_FALSE(drag_drop_controller_
->drop_received_
);
966 EXPECT_EQ(UTF8ToUTF16("I am being dragged"),
967 drag_drop_controller_
->drag_string_
);
968 EXPECT_EQ(0, drag_view
->num_drag_enters_
);
969 EXPECT_EQ(0, drag_view
->num_drops_
);
970 EXPECT_EQ(0, drag_view
->num_drag_exits_
);
971 EXPECT_TRUE(drag_view
->drag_done_received_
);
974 TEST_F(DragDropControllerTest
, TouchDragDropLongTapGestureIsForwarded
) {
975 CommandLine::ForCurrentProcess()->AppendSwitch(
976 switches::kEnableTouchDragDrop
);
977 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
978 DragTestView
* drag_view
= new DragTestView
;
979 AddViewToWidgetAndResize(widget
.get(), drag_view
);
980 aura::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
981 widget
->GetNativeView());
983 generator
.PressTouch();
984 gfx::Point point
= gfx::Rect(drag_view
->bounds()).CenterPoint();
985 DispatchGesture(ui::ET_GESTURE_LONG_PRESS
, point
);
987 // Since we are not running inside a nested loop, the |drag_source_window_|
988 // will get destroyed immediately. Hence we reassign it.
989 EXPECT_EQ(NULL
, GetDragSourceWindow());
990 SetDragSourceWindow(widget
->GetNativeView());
991 EXPECT_FALSE(drag_view
->long_tap_received_
);
992 DispatchGesture(ui::ET_GESTURE_LONG_TAP
, point
);
993 CompleteCancelAnimation();
994 EXPECT_TRUE(drag_view
->long_tap_received_
);
999 class DragImageWindowObserver
: public aura::WindowObserver
{
1001 virtual void OnWindowDestroying(aura::Window
* window
) OVERRIDE
{
1002 window_location_on_destroying_
= window
->GetBoundsInScreen().origin();
1005 gfx::Point
window_location_on_destroying() const {
1006 return window_location_on_destroying_
;
1010 gfx::Point window_location_on_destroying_
;
1015 // Verifies the drag image moves back to the position where drag is started
1016 // across displays when drag is cancelled.
1017 TEST_F(DragDropControllerTest
, DragCancelAcrossDisplays
) {
1018 if (!SupportsMultipleDisplays())
1021 UpdateDisplay("400x400,400x400");
1022 Shell::RootWindowList root_windows
=
1023 Shell::GetInstance()->GetAllRootWindows();
1024 for (Shell::RootWindowList::iterator iter
= root_windows
.begin();
1025 iter
!= root_windows
.end(); ++iter
) {
1026 aura::client::SetDragDropClient(*iter
, drag_drop_controller_
.get());
1029 ui::OSExchangeData data
;
1030 data
.SetString(UTF8ToUTF16("I am being dragged"));
1032 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
1033 aura::Window
* window
= widget
->GetNativeWindow();
1034 drag_drop_controller_
->StartDragAndDrop(
1036 window
->GetRootWindow(),
1039 ui::DragDropTypes::DRAG_MOVE
,
1040 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE
);
1042 DragImageWindowObserver observer
;
1043 ASSERT_TRUE(GetDragImageWindow());
1044 GetDragImageWindow()->AddObserver(&observer
);
1047 ui::MouseEvent
e(ui::ET_MOUSE_DRAGGED
,
1051 drag_drop_controller_
->DragUpdate(window
, e
);
1054 ui::MouseEvent
e(ui::ET_MOUSE_DRAGGED
,
1058 drag_drop_controller_
->DragUpdate(window
, e
);
1061 drag_drop_controller_
->DragCancel();
1062 CompleteCancelAnimation();
1064 EXPECT_EQ("5,5", observer
.window_location_on_destroying().ToString());
1068 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
1069 aura::Window
* window
= widget
->GetNativeWindow();
1070 drag_drop_controller_
->StartDragAndDrop(
1072 window
->GetRootWindow(),
1074 gfx::Point(405, 405),
1075 ui::DragDropTypes::DRAG_MOVE
,
1076 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE
);
1077 DragImageWindowObserver observer
;
1078 ASSERT_TRUE(GetDragImageWindow());
1079 GetDragImageWindow()->AddObserver(&observer
);
1082 ui::MouseEvent
e(ui::ET_MOUSE_DRAGGED
,
1086 drag_drop_controller_
->DragUpdate(window
, e
);
1089 ui::MouseEvent
e(ui::ET_MOUSE_DRAGGED
,
1093 drag_drop_controller_
->DragUpdate(window
, e
);
1096 drag_drop_controller_
->DragCancel();
1097 CompleteCancelAnimation();
1099 EXPECT_EQ("405,405", observer
.window_location_on_destroying().ToString());
1101 for (Shell::RootWindowList::iterator iter
= root_windows
.begin();
1102 iter
!= root_windows
.end(); ++iter
) {
1103 aura::client::SetDragDropClient(*iter
, NULL
);