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/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"
41 // A simple view that makes sure RunShellDrag is invoked on mouse drag.
42 class DragTestView
: public views::View
{
44 DragTestView() : views::View() {
51 num_drag_updates_
= 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();
67 int num_drag_updates_
;
69 bool drag_done_received_
;
70 bool long_tap_received_
;
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
{
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 DragDropController
{
152 TestDragDropController() : DragDropController() { 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
,
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
);
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(
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_
;
208 base::string16 drag_string_
;
211 DISALLOW_COPY_AND_ASSIGN(TestDragDropController
);
214 class TestNativeWidgetAura
: public views::NativeWidgetAura
{
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();
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.
241 static_cast<TestNativeWidgetAura
*>(widget
->native_widget())->
242 set_check_if_capture_lost(value
);
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();
254 params
.native_widget
= new TestNativeWidgetAura(widget
);
255 widget
->Init(params
);
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::GestureEventDetails
event_details(gesture_type
, 0, 0);
277 event_details
.set_oldest_touch_id(1);
278 ui::GestureEvent
gesture_event(
279 location
.x(), location
.y(), 0, ui::EventTimeForNow(), event_details
);
280 ui::EventSource
* event_source
=
281 Shell::GetPrimaryRootWindow()->GetHost()->GetEventSource();
282 ui::EventSourceTestApi
event_source_test(event_source
);
283 ui::EventDispatchDetails details
=
284 event_source_test
.SendEventToProcessor(&gesture_event
);
285 CHECK(!details
.dispatcher_destroyed
);
290 class DragDropControllerTest
: public AshTestBase
{
292 DragDropControllerTest() : AshTestBase() {}
293 virtual ~DragDropControllerTest() {}
295 virtual void SetUp() OVERRIDE
{
296 AshTestBase::SetUp();
297 drag_drop_controller_
.reset(new TestDragDropController
);
298 drag_drop_controller_
->set_should_block_during_drag_drop(false);
299 aura::client::SetDragDropClient(Shell::GetPrimaryRootWindow(),
300 drag_drop_controller_
.get());
303 virtual void TearDown() OVERRIDE
{
304 aura::client::SetDragDropClient(Shell::GetPrimaryRootWindow(), NULL
);
305 drag_drop_controller_
.reset();
306 AshTestBase::TearDown();
309 void UpdateDragData(ui::OSExchangeData
* data
) {
310 drag_drop_controller_
->drag_data_
= data
;
313 aura::Window
* GetDragWindow() {
314 return drag_drop_controller_
->drag_window_
;
317 aura::Window
* GetDragSourceWindow() {
318 return drag_drop_controller_
->drag_source_window_
;
321 void SetDragSourceWindow(aura::Window
* drag_source_window
) {
322 drag_drop_controller_
->drag_source_window_
= drag_source_window
;
323 drag_source_window
->AddObserver(drag_drop_controller_
.get());
326 aura::Window
* GetDragImageWindow() {
327 return drag_drop_controller_
->drag_image_
.get() ?
328 drag_drop_controller_
->drag_image_
->GetWidget()->GetNativeWindow() :
332 DragDropTracker
* drag_drop_tracker() {
333 return drag_drop_controller_
->drag_drop_tracker_
.get();
336 void CompleteCancelAnimation() {
337 CompletableLinearAnimation
* animation
=
338 static_cast<CompletableLinearAnimation
*>(
339 drag_drop_controller_
->cancel_animation_
.get());
340 animation
->Complete();
344 scoped_ptr
<TestDragDropController
> drag_drop_controller_
;
347 DISALLOW_COPY_AND_ASSIGN(DragDropControllerTest
);
350 // TODO(win_aura) http://crbug.com/154081
352 #define MAYBE_DragDropInSingleViewTest DISABLED_DragDropInSingleViewTest
354 #define MAYBE_DragDropInSingleViewTest DragDropInSingleViewTest
356 TEST_F(DragDropControllerTest
, MAYBE_DragDropInSingleViewTest
) {
357 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
358 DragTestView
* drag_view
= new DragTestView
;
359 AddViewToWidgetAndResize(widget
.get(), drag_view
);
360 ui::OSExchangeData data
;
361 data
.SetString(base::UTF8ToUTF16("I am being dragged"));
362 aura::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
363 widget
->GetNativeView());
364 generator
.PressLeftButton();
367 SetCheckIfCaptureLost(widget
.get(), true);
368 for (int i
= 0; i
< num_drags
; ++i
) {
369 // Because we are not doing a blocking drag and drop, the original
370 // OSDragExchangeData object is lost as soon as we return from the drag
371 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
372 // drag_data_ to a fake drag data object that we created.
374 UpdateDragData(&data
);
375 // 7 comes from views::View::GetVerticalDragThreshold()).
377 SetCheckIfCaptureLost(widget
.get(), false);
379 generator
.MoveMouseBy(0, 1);
381 // Execute any scheduled draws to process deferred mouse events.
382 RunAllPendingInMessageLoop();
385 generator
.ReleaseLeftButton();
387 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
388 EXPECT_EQ(num_drags
- 1 - drag_view
->VerticalDragThreshold(),
389 drag_drop_controller_
->num_drag_updates_
);
390 EXPECT_TRUE(drag_drop_controller_
->drop_received_
);
391 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
392 drag_drop_controller_
->drag_string_
);
394 EXPECT_EQ(1, drag_view
->num_drag_enters_
);
395 EXPECT_EQ(num_drags
- 1 - drag_view
->VerticalDragThreshold(),
396 drag_view
->num_drag_updates_
);
397 EXPECT_EQ(1, drag_view
->num_drops_
);
398 EXPECT_EQ(0, drag_view
->num_drag_exits_
);
399 EXPECT_TRUE(drag_view
->drag_done_received_
);
402 TEST_F(DragDropControllerTest
, DragDropWithZeroDragUpdates
) {
403 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
404 DragTestView
* drag_view
= new DragTestView
;
405 AddViewToWidgetAndResize(widget
.get(), drag_view
);
406 ui::OSExchangeData data
;
407 data
.SetString(base::UTF8ToUTF16("I am being dragged"));
408 aura::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
409 widget
->GetNativeView());
410 generator
.PressLeftButton();
412 int num_drags
= drag_view
->VerticalDragThreshold() + 1;
413 for (int i
= 0; i
< num_drags
; ++i
) {
414 // Because we are not doing a blocking drag and drop, the original
415 // OSDragExchangeData object is lost as soon as we return from the drag
416 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
417 // drag_data_ to a fake drag data object that we created.
419 UpdateDragData(&data
);
420 generator
.MoveMouseBy(0, 1);
423 UpdateDragData(&data
);
425 generator
.ReleaseLeftButton();
427 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
428 EXPECT_EQ(num_drags
- 1 - drag_view
->VerticalDragThreshold() + 1,
429 drag_drop_controller_
->num_drag_updates_
);
430 EXPECT_TRUE(drag_drop_controller_
->drop_received_
);
432 EXPECT_EQ(1, drag_view
->num_drag_enters_
);
433 EXPECT_EQ(num_drags
- 1 - drag_view
->VerticalDragThreshold() + 1,
434 drag_view
->num_drag_updates_
);
435 EXPECT_EQ(1, drag_view
->num_drops_
);
436 EXPECT_EQ(0, drag_view
->num_drag_exits_
);
437 EXPECT_TRUE(drag_view
->drag_done_received_
);
440 // TODO(win_aura) http://crbug.com/154081
442 #define MAYBE_DragDropInMultipleViewsSingleWidgetTest DISABLED_DragDropInMultipleViewsSingleWidgetTest
444 #define MAYBE_DragDropInMultipleViewsSingleWidgetTest DragDropInMultipleViewsSingleWidgetTest
446 TEST_F(DragDropControllerTest
, MAYBE_DragDropInMultipleViewsSingleWidgetTest
) {
447 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
448 DragTestView
* drag_view1
= new DragTestView
;
449 AddViewToWidgetAndResize(widget
.get(), drag_view1
);
450 DragTestView
* drag_view2
= new DragTestView
;
451 AddViewToWidgetAndResize(widget
.get(), drag_view2
);
453 ui::OSExchangeData data
;
454 data
.SetString(base::UTF8ToUTF16("I am being dragged"));
456 aura::test::EventGenerator
generator(Shell::GetPrimaryRootWindow());
457 generator
.MoveMouseRelativeTo(widget
->GetNativeView(),
458 drag_view1
->bounds().CenterPoint());
459 generator
.PressLeftButton();
461 int num_drags
= drag_view1
->width();
462 for (int i
= 0; i
< num_drags
; ++i
) {
463 // Because we are not doing a blocking drag and drop, the original
464 // OSDragExchangeData object is lost as soon as we return from the drag
465 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
466 // drag_data_ to a fake drag data object that we created.
468 UpdateDragData(&data
);
469 generator
.MoveMouseBy(1, 0);
471 // Execute any scheduled draws to process deferred mouse events.
472 RunAllPendingInMessageLoop();
475 generator
.ReleaseLeftButton();
477 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
478 EXPECT_EQ(num_drags
- 1 - drag_view1
->HorizontalDragThreshold(),
479 drag_drop_controller_
->num_drag_updates_
);
480 EXPECT_TRUE(drag_drop_controller_
->drop_received_
);
481 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
482 drag_drop_controller_
->drag_string_
);
484 EXPECT_EQ(1, drag_view1
->num_drag_enters_
);
485 int num_expected_updates
= drag_view1
->bounds().width() -
486 drag_view1
->bounds().CenterPoint().x() - 2;
487 EXPECT_EQ(num_expected_updates
- drag_view1
->HorizontalDragThreshold(),
488 drag_view1
->num_drag_updates_
);
489 EXPECT_EQ(0, drag_view1
->num_drops_
);
490 EXPECT_EQ(1, drag_view1
->num_drag_exits_
);
491 EXPECT_TRUE(drag_view1
->drag_done_received_
);
493 EXPECT_EQ(1, drag_view2
->num_drag_enters_
);
494 num_expected_updates
= num_drags
- num_expected_updates
- 1;
495 EXPECT_EQ(num_expected_updates
, drag_view2
->num_drag_updates_
);
496 EXPECT_EQ(1, drag_view2
->num_drops_
);
497 EXPECT_EQ(0, drag_view2
->num_drag_exits_
);
498 EXPECT_FALSE(drag_view2
->drag_done_received_
);
501 // TODO(win_aura) http://crbug.com/154081
503 #define MAYBE_DragDropInMultipleViewsMultipleWidgetsTest DISABLED_DragDropInMultipleViewsMultipleWidgetsTest
505 #define MAYBE_DragDropInMultipleViewsMultipleWidgetsTest DragDropInMultipleViewsMultipleWidgetsTest
507 TEST_F(DragDropControllerTest
, MAYBE_DragDropInMultipleViewsMultipleWidgetsTest
) {
508 scoped_ptr
<views::Widget
> widget1(CreateNewWidget());
509 DragTestView
* drag_view1
= new DragTestView
;
510 AddViewToWidgetAndResize(widget1
.get(), drag_view1
);
511 scoped_ptr
<views::Widget
> widget2(CreateNewWidget());
512 DragTestView
* drag_view2
= new DragTestView
;
513 AddViewToWidgetAndResize(widget2
.get(), drag_view2
);
514 gfx::Rect widget1_bounds
= widget1
->GetClientAreaBoundsInScreen();
515 gfx::Rect widget2_bounds
= widget2
->GetClientAreaBoundsInScreen();
516 widget2
->SetBounds(gfx::Rect(widget1_bounds
.width(), 0,
517 widget2_bounds
.width(), widget2_bounds
.height()));
519 ui::OSExchangeData data
;
520 data
.SetString(base::UTF8ToUTF16("I am being dragged"));
522 aura::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
523 widget1
->GetNativeView());
524 generator
.PressLeftButton();
526 int num_drags
= drag_view1
->width();
527 for (int i
= 0; i
< num_drags
; ++i
) {
528 // Because we are not doing a blocking drag and drop, the original
529 // OSDragExchangeData object is lost as soon as we return from the drag
530 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
531 // drag_data_ to a fake drag data object that we created.
533 UpdateDragData(&data
);
534 generator
.MoveMouseBy(1, 0);
536 // Execute any scheduled draws to process deferred mouse events.
537 RunAllPendingInMessageLoop();
540 generator
.ReleaseLeftButton();
542 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
543 EXPECT_EQ(num_drags
- 1 - drag_view1
->HorizontalDragThreshold(),
544 drag_drop_controller_
->num_drag_updates_
);
545 EXPECT_TRUE(drag_drop_controller_
->drop_received_
);
546 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
547 drag_drop_controller_
->drag_string_
);
549 EXPECT_EQ(1, drag_view1
->num_drag_enters_
);
550 int num_expected_updates
= drag_view1
->bounds().width() -
551 drag_view1
->bounds().CenterPoint().x() - 2;
552 EXPECT_EQ(num_expected_updates
- drag_view1
->HorizontalDragThreshold(),
553 drag_view1
->num_drag_updates_
);
554 EXPECT_EQ(0, drag_view1
->num_drops_
);
555 EXPECT_EQ(1, drag_view1
->num_drag_exits_
);
556 EXPECT_TRUE(drag_view1
->drag_done_received_
);
558 EXPECT_EQ(1, drag_view2
->num_drag_enters_
);
559 num_expected_updates
= num_drags
- num_expected_updates
- 1;
560 EXPECT_EQ(num_expected_updates
, drag_view2
->num_drag_updates_
);
561 EXPECT_EQ(1, drag_view2
->num_drops_
);
562 EXPECT_EQ(0, drag_view2
->num_drag_exits_
);
563 EXPECT_FALSE(drag_view2
->drag_done_received_
);
566 // TODO(win_aura) http://crbug.com/154081
568 #define MAYBE_ViewRemovedWhileInDragDropTest DISABLED_ViewRemovedWhileInDragDropTest
570 #define MAYBE_ViewRemovedWhileInDragDropTest ViewRemovedWhileInDragDropTest
572 TEST_F(DragDropControllerTest
, MAYBE_ViewRemovedWhileInDragDropTest
) {
573 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
574 scoped_ptr
<DragTestView
> drag_view(new DragTestView
);
575 AddViewToWidgetAndResize(widget
.get(), drag_view
.get());
576 gfx::Point point
= gfx::Rect(drag_view
->bounds()).CenterPoint();
577 ui::OSExchangeData data
;
578 data
.SetString(base::UTF8ToUTF16("I am being dragged"));
580 aura::test::EventGenerator
generator(Shell::GetPrimaryRootWindow());
581 generator
.MoveMouseToCenterOf(widget
->GetNativeView());
582 generator
.PressLeftButton();
584 int num_drags_1
= 17;
585 for (int i
= 0; i
< num_drags_1
; ++i
) {
586 // Because we are not doing a blocking drag and drop, the original
587 // OSDragExchangeData object is lost as soon as we return from the drag
588 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
589 // drag_data_ to a fake drag data object that we created.
591 UpdateDragData(&data
);
592 generator
.MoveMouseBy(0, 1);
594 // Execute any scheduled draws to process deferred mouse events.
595 RunAllPendingInMessageLoop();
598 drag_view
->parent()->RemoveChildView(drag_view
.get());
599 // View has been removed. We will not get any of the following drag updates.
600 int num_drags_2
= 23;
601 for (int i
= 0; i
< num_drags_2
; ++i
) {
602 UpdateDragData(&data
);
603 generator
.MoveMouseBy(0, 1);
605 // Execute any scheduled draws to process deferred mouse events.
606 RunAllPendingInMessageLoop();
609 generator
.ReleaseLeftButton();
611 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
612 EXPECT_EQ(num_drags_1
+ num_drags_2
- 1 - drag_view
->VerticalDragThreshold(),
613 drag_drop_controller_
->num_drag_updates_
);
614 EXPECT_TRUE(drag_drop_controller_
->drop_received_
);
615 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
616 drag_drop_controller_
->drag_string_
);
618 EXPECT_EQ(1, drag_view
->num_drag_enters_
);
619 EXPECT_EQ(num_drags_1
- 1 - drag_view
->VerticalDragThreshold(),
620 drag_view
->num_drag_updates_
);
621 EXPECT_EQ(0, drag_view
->num_drops_
);
622 EXPECT_EQ(0, drag_view
->num_drag_exits_
);
623 EXPECT_TRUE(drag_view
->drag_done_received_
);
626 TEST_F(DragDropControllerTest
, DragLeavesClipboardAloneTest
) {
627 ui::Clipboard
* cb
= ui::Clipboard::GetForCurrentThread();
628 std::string
clip_str("I am on the clipboard");
630 // We first copy some text to the clipboard.
631 ui::ScopedClipboardWriter
scw(cb
, ui::CLIPBOARD_TYPE_COPY_PASTE
);
632 scw
.WriteText(base::ASCIIToUTF16(clip_str
));
634 EXPECT_TRUE(cb
->IsFormatAvailable(ui::Clipboard::GetPlainTextFormatType(),
635 ui::CLIPBOARD_TYPE_COPY_PASTE
));
637 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
638 DragTestView
* drag_view
= new DragTestView
;
639 AddViewToWidgetAndResize(widget
.get(), drag_view
);
641 aura::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
642 widget
->GetNativeView());
643 ui::OSExchangeData data
;
644 std::string
data_str("I am being dragged");
645 data
.SetString(base::ASCIIToUTF16(data_str
));
647 generator
.PressLeftButton();
648 generator
.MoveMouseBy(0, drag_view
->VerticalDragThreshold() + 1);
650 // Execute any scheduled draws to process deferred mouse events.
651 RunAllPendingInMessageLoop();
653 // Verify the clipboard contents haven't changed
655 EXPECT_TRUE(cb
->IsFormatAvailable(ui::Clipboard::GetPlainTextFormatType(),
656 ui::CLIPBOARD_TYPE_COPY_PASTE
));
657 cb
->ReadAsciiText(ui::CLIPBOARD_TYPE_COPY_PASTE
, &result
);
658 EXPECT_EQ(clip_str
, result
);
659 // Destory the clipboard here because ash doesn't delete it.
661 ui::Clipboard::DestroyClipboardForCurrentThread();
664 TEST_F(DragDropControllerTest
, WindowDestroyedDuringDragDrop
) {
665 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
666 DragTestView
* drag_view
= new DragTestView
;
667 AddViewToWidgetAndResize(widget
.get(), drag_view
);
668 aura::Window
* window
= widget
->GetNativeView();
670 ui::OSExchangeData data
;
671 data
.SetString(base::UTF8ToUTF16("I am being dragged"));
672 aura::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
673 widget
->GetNativeView());
674 generator
.PressLeftButton();
677 for (int i
= 0; i
< num_drags
; ++i
) {
678 // Because we are not doing a blocking drag and drop, the original
679 // OSDragExchangeData object is lost as soon as we return from the drag
680 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
681 // drag_data_ to a fake drag data object that we created.
683 UpdateDragData(&data
);
684 generator
.MoveMouseBy(0, 1);
686 // Execute any scheduled draws to process deferred mouse events.
687 RunAllPendingInMessageLoop();
689 if (i
> drag_view
->VerticalDragThreshold())
690 EXPECT_EQ(window
, GetDragWindow());
694 EXPECT_FALSE(GetDragWindow());
697 for (int i
= 0; i
< num_drags
; ++i
) {
699 UpdateDragData(&data
);
700 generator
.MoveMouseBy(0, 1);
701 // We should not crash here.
704 generator
.ReleaseLeftButton();
706 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
707 EXPECT_TRUE(drag_drop_controller_
->drop_received_
);
710 TEST_F(DragDropControllerTest
, SyntheticEventsDuringDragDrop
) {
711 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
712 DragTestView
* drag_view
= new DragTestView
;
713 AddViewToWidgetAndResize(widget
.get(), drag_view
);
714 ui::OSExchangeData data
;
715 data
.SetString(base::UTF8ToUTF16("I am being dragged"));
716 aura::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
717 widget
->GetNativeView());
718 generator
.PressLeftButton();
721 for (int i
= 0; i
< num_drags
; ++i
) {
722 // Because we are not doing a blocking drag and drop, the original
723 // OSDragExchangeData object is lost as soon as we return from the drag
724 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
725 // drag_data_ to a fake drag data object that we created.
727 UpdateDragData(&data
);
728 generator
.MoveMouseBy(0, 1);
730 // We send a unexpected mouse move event. Note that we cannot use
731 // EventGenerator since it implicitly turns these into mouse drag events.
732 // The DragDropController should simply ignore these events.
733 gfx::Point mouse_move_location
= drag_view
->bounds().CenterPoint();
734 ui::MouseEvent
mouse_move(ui::ET_MOUSE_MOVED
, mouse_move_location
,
735 mouse_move_location
, 0, 0);
736 ui::EventDispatchDetails details
= Shell::GetPrimaryRootWindow()->
737 GetHost()->event_processor()->OnEventFromSource(&mouse_move
);
738 ASSERT_FALSE(details
.dispatcher_destroyed
);
741 generator
.ReleaseLeftButton();
743 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
744 EXPECT_EQ(num_drags
- 1 - drag_view
->VerticalDragThreshold(),
745 drag_drop_controller_
->num_drag_updates_
);
746 EXPECT_TRUE(drag_drop_controller_
->drop_received_
);
747 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
748 drag_drop_controller_
->drag_string_
);
750 EXPECT_EQ(1, drag_view
->num_drag_enters_
);
751 EXPECT_EQ(num_drags
- 1 - drag_view
->VerticalDragThreshold(),
752 drag_view
->num_drag_updates_
);
753 EXPECT_EQ(1, drag_view
->num_drops_
);
754 EXPECT_EQ(0, drag_view
->num_drag_exits_
);
755 EXPECT_TRUE(drag_view
->drag_done_received_
);
758 // TODO(win_aura) http://crbug.com/154081
760 #define MAYBE_PressingEscapeCancelsDragDrop DISABLED_PressingEscapeCancelsDragDrop
761 #define MAYBE_CaptureLostCancelsDragDrop DISABLED_CaptureLostCancelsDragDrop
763 #define MAYBE_PressingEscapeCancelsDragDrop PressingEscapeCancelsDragDrop
764 #define MAYBE_CaptureLostCancelsDragDrop CaptureLostCancelsDragDrop
766 TEST_F(DragDropControllerTest
, MAYBE_PressingEscapeCancelsDragDrop
) {
767 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
768 DragTestView
* drag_view
= new DragTestView
;
769 AddViewToWidgetAndResize(widget
.get(), drag_view
);
770 ui::OSExchangeData data
;
771 data
.SetString(base::UTF8ToUTF16("I am being dragged"));
772 aura::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
773 widget
->GetNativeView());
774 generator
.PressLeftButton();
777 for (int i
= 0; i
< num_drags
; ++i
) {
778 // Because we are not doing a blocking drag and drop, the original
779 // OSDragExchangeData object is lost as soon as we return from the drag
780 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
781 // drag_data_ to a fake drag data object that we created.
783 UpdateDragData(&data
);
784 generator
.MoveMouseBy(0, 1);
786 // Execute any scheduled draws to process deferred mouse events.
787 RunAllPendingInMessageLoop();
790 generator
.PressKey(ui::VKEY_ESCAPE
, 0);
792 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
793 EXPECT_EQ(num_drags
- 1 - drag_view
->VerticalDragThreshold(),
794 drag_drop_controller_
->num_drag_updates_
);
795 EXPECT_FALSE(drag_drop_controller_
->drop_received_
);
796 EXPECT_TRUE(drag_drop_controller_
->drag_canceled_
);
797 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
798 drag_drop_controller_
->drag_string_
);
800 EXPECT_EQ(1, drag_view
->num_drag_enters_
);
801 EXPECT_EQ(num_drags
- 1 - drag_view
->VerticalDragThreshold(),
802 drag_view
->num_drag_updates_
);
803 EXPECT_EQ(0, drag_view
->num_drops_
);
804 EXPECT_EQ(1, drag_view
->num_drag_exits_
);
805 EXPECT_TRUE(drag_view
->drag_done_received_
);
808 TEST_F(DragDropControllerTest
, MAYBE_CaptureLostCancelsDragDrop
) {
809 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
810 DragTestView
* drag_view
= new DragTestView
;
811 AddViewToWidgetAndResize(widget
.get(), drag_view
);
812 ui::OSExchangeData data
;
813 data
.SetString(base::UTF8ToUTF16("I am being dragged"));
814 aura::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
815 widget
->GetNativeView());
816 generator
.PressLeftButton();
819 for (int i
= 0; i
< num_drags
; ++i
) {
820 // Because we are not doing a blocking drag and drop, the original
821 // OSDragExchangeData object is lost as soon as we return from the drag
822 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
823 // drag_data_ to a fake drag data object that we created.
825 UpdateDragData(&data
);
826 generator
.MoveMouseBy(0, 1);
828 // Execute any scheduled draws to process deferred mouse events.
829 RunAllPendingInMessageLoop();
831 // Make sure the capture window won't handle mouse events.
832 aura::Window
* capture_window
= drag_drop_tracker()->capture_window();
833 ASSERT_TRUE(!!capture_window
);
834 EXPECT_EQ("0x0", capture_window
->bounds().size().ToString());
836 capture_window
->GetEventHandlerForPoint(gfx::Point()));
838 capture_window
->GetTopWindowContainingPoint(gfx::Point()));
840 aura::client::GetCaptureClient(widget
->GetNativeView()->GetRootWindow())->
843 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
844 EXPECT_EQ(num_drags
- 1 - drag_view
->VerticalDragThreshold(),
845 drag_drop_controller_
->num_drag_updates_
);
846 EXPECT_FALSE(drag_drop_controller_
->drop_received_
);
847 EXPECT_TRUE(drag_drop_controller_
->drag_canceled_
);
848 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
849 drag_drop_controller_
->drag_string_
);
851 EXPECT_EQ(1, drag_view
->num_drag_enters_
);
852 EXPECT_EQ(num_drags
- 1 - drag_view
->VerticalDragThreshold(),
853 drag_view
->num_drag_updates_
);
854 EXPECT_EQ(0, drag_view
->num_drops_
);
855 EXPECT_EQ(1, drag_view
->num_drag_exits_
);
856 EXPECT_TRUE(drag_view
->drag_done_received_
);
859 TEST_F(DragDropControllerTest
, TouchDragDropInMultipleWindows
) {
860 CommandLine::ForCurrentProcess()->AppendSwitch(
861 switches::kEnableTouchDragDrop
);
862 scoped_ptr
<views::Widget
> widget1(CreateNewWidget());
863 DragTestView
* drag_view1
= new DragTestView
;
864 AddViewToWidgetAndResize(widget1
.get(), drag_view1
);
865 scoped_ptr
<views::Widget
> widget2(CreateNewWidget());
866 DragTestView
* drag_view2
= new DragTestView
;
867 AddViewToWidgetAndResize(widget2
.get(), drag_view2
);
868 gfx::Rect widget1_bounds
= widget1
->GetClientAreaBoundsInScreen();
869 gfx::Rect widget2_bounds
= widget2
->GetClientAreaBoundsInScreen();
870 widget2
->SetBounds(gfx::Rect(widget1_bounds
.width(), 0,
871 widget2_bounds
.width(), widget2_bounds
.height()));
873 ui::OSExchangeData data
;
874 data
.SetString(base::UTF8ToUTF16("I am being dragged"));
876 aura::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
877 widget1
->GetNativeView());
878 generator
.PressTouch();
879 gfx::Point point
= gfx::Rect(drag_view1
->bounds()).CenterPoint();
880 DispatchGesture(ui::ET_GESTURE_LONG_PRESS
, point
);
881 // Because we are not doing a blocking drag and drop, the original
882 // OSDragExchangeData object is lost as soon as we return from the drag
883 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
884 // drag_data_ to a fake drag data object that we created.
885 UpdateDragData(&data
);
886 gfx::Point gesture_location
= point
;
887 int num_drags
= drag_view1
->width();
888 for (int i
= 0; i
< num_drags
; ++i
) {
889 gesture_location
.Offset(1, 0);
890 DispatchGesture(ui::ET_GESTURE_SCROLL_UPDATE
, gesture_location
);
892 // Execute any scheduled draws to process deferred mouse events.
893 RunAllPendingInMessageLoop();
896 DispatchGesture(ui::ET_GESTURE_SCROLL_END
, gesture_location
);
898 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
899 EXPECT_EQ(num_drags
, drag_drop_controller_
->num_drag_updates_
);
900 EXPECT_TRUE(drag_drop_controller_
->drop_received_
);
901 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
902 drag_drop_controller_
->drag_string_
);
904 EXPECT_EQ(1, drag_view1
->num_drag_enters_
);
905 int num_expected_updates
= drag_view1
->bounds().width() -
906 drag_view1
->bounds().CenterPoint().x() - 1;
907 EXPECT_EQ(num_expected_updates
, drag_view1
->num_drag_updates_
);
908 EXPECT_EQ(0, drag_view1
->num_drops_
);
909 EXPECT_EQ(1, drag_view1
->num_drag_exits_
);
910 EXPECT_TRUE(drag_view1
->drag_done_received_
);
912 EXPECT_EQ(1, drag_view2
->num_drag_enters_
);
913 num_expected_updates
= num_drags
- num_expected_updates
;
914 EXPECT_EQ(num_expected_updates
, drag_view2
->num_drag_updates_
);
915 EXPECT_EQ(1, drag_view2
->num_drops_
);
916 EXPECT_EQ(0, drag_view2
->num_drag_exits_
);
917 EXPECT_FALSE(drag_view2
->drag_done_received_
);
920 TEST_F(DragDropControllerTest
, TouchDragDropCancelsOnLongTap
) {
921 CommandLine::ForCurrentProcess()->AppendSwitch(
922 switches::kEnableTouchDragDrop
);
923 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
924 DragTestView
* drag_view
= new DragTestView
;
925 AddViewToWidgetAndResize(widget
.get(), drag_view
);
926 aura::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
927 widget
->GetNativeView());
929 generator
.PressTouch();
930 gfx::Point point
= gfx::Rect(drag_view
->bounds()).CenterPoint();
931 DispatchGesture(ui::ET_GESTURE_LONG_PRESS
, point
);
932 DispatchGesture(ui::ET_GESTURE_LONG_TAP
, point
);
934 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
935 EXPECT_TRUE(drag_drop_controller_
->drag_canceled_
);
936 EXPECT_EQ(0, drag_drop_controller_
->num_drag_updates_
);
937 EXPECT_FALSE(drag_drop_controller_
->drop_received_
);
938 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
939 drag_drop_controller_
->drag_string_
);
940 EXPECT_EQ(0, drag_view
->num_drag_enters_
);
941 EXPECT_EQ(0, drag_view
->num_drops_
);
942 EXPECT_EQ(0, drag_view
->num_drag_exits_
);
943 EXPECT_TRUE(drag_view
->drag_done_received_
);
946 TEST_F(DragDropControllerTest
, TouchDragDropLongTapGestureIsForwarded
) {
947 CommandLine::ForCurrentProcess()->AppendSwitch(
948 switches::kEnableTouchDragDrop
);
949 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
950 DragTestView
* drag_view
= new DragTestView
;
951 AddViewToWidgetAndResize(widget
.get(), drag_view
);
952 aura::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
953 widget
->GetNativeView());
955 generator
.PressTouch();
956 gfx::Point point
= gfx::Rect(drag_view
->bounds()).CenterPoint();
957 DispatchGesture(ui::ET_GESTURE_LONG_PRESS
, point
);
959 // Since we are not running inside a nested loop, the |drag_source_window_|
960 // will get destroyed immediately. Hence we reassign it.
961 EXPECT_EQ(NULL
, GetDragSourceWindow());
962 SetDragSourceWindow(widget
->GetNativeView());
963 EXPECT_FALSE(drag_view
->long_tap_received_
);
964 DispatchGesture(ui::ET_GESTURE_LONG_TAP
, point
);
965 CompleteCancelAnimation();
966 EXPECT_TRUE(drag_view
->long_tap_received_
);
971 class DragImageWindowObserver
: public aura::WindowObserver
{
973 virtual void OnWindowDestroying(aura::Window
* window
) OVERRIDE
{
974 window_location_on_destroying_
= window
->GetBoundsInScreen().origin();
977 gfx::Point
window_location_on_destroying() const {
978 return window_location_on_destroying_
;
982 gfx::Point window_location_on_destroying_
;
987 // Verifies the drag image moves back to the position where drag is started
988 // across displays when drag is cancelled.
989 TEST_F(DragDropControllerTest
, DragCancelAcrossDisplays
) {
990 if (!SupportsMultipleDisplays())
993 UpdateDisplay("400x400,400x400");
994 aura::Window::Windows root_windows
=
995 Shell::GetInstance()->GetAllRootWindows();
996 for (aura::Window::Windows::iterator iter
= root_windows
.begin();
997 iter
!= root_windows
.end(); ++iter
) {
998 aura::client::SetDragDropClient(*iter
, drag_drop_controller_
.get());
1001 ui::OSExchangeData data
;
1002 data
.SetString(base::UTF8ToUTF16("I am being dragged"));
1004 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
1005 aura::Window
* window
= widget
->GetNativeWindow();
1006 drag_drop_controller_
->StartDragAndDrop(
1008 window
->GetRootWindow(),
1011 ui::DragDropTypes::DRAG_MOVE
,
1012 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE
);
1014 DragImageWindowObserver observer
;
1015 ASSERT_TRUE(GetDragImageWindow());
1016 GetDragImageWindow()->AddObserver(&observer
);
1019 ui::MouseEvent
e(ui::ET_MOUSE_DRAGGED
,
1024 drag_drop_controller_
->DragUpdate(window
, e
);
1027 ui::MouseEvent
e(ui::ET_MOUSE_DRAGGED
,
1032 drag_drop_controller_
->DragUpdate(window
, e
);
1035 drag_drop_controller_
->DragCancel();
1036 CompleteCancelAnimation();
1038 EXPECT_EQ("5,5", observer
.window_location_on_destroying().ToString());
1042 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
1043 aura::Window
* window
= widget
->GetNativeWindow();
1044 drag_drop_controller_
->StartDragAndDrop(
1046 window
->GetRootWindow(),
1048 gfx::Point(405, 405),
1049 ui::DragDropTypes::DRAG_MOVE
,
1050 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE
);
1051 DragImageWindowObserver observer
;
1052 ASSERT_TRUE(GetDragImageWindow());
1053 GetDragImageWindow()->AddObserver(&observer
);
1056 ui::MouseEvent
e(ui::ET_MOUSE_DRAGGED
,
1061 drag_drop_controller_
->DragUpdate(window
, e
);
1064 ui::MouseEvent
e(ui::ET_MOUSE_DRAGGED
,
1069 drag_drop_controller_
->DragUpdate(window
, e
);
1072 drag_drop_controller_
->DragCancel();
1073 CompleteCancelAnimation();
1075 EXPECT_EQ("405,405", observer
.window_location_on_destroying().ToString());
1077 for (aura::Window::Windows::iterator iter
= root_windows
.begin();
1078 iter
!= root_windows
.end(); ++iter
) {
1079 aura::client::SetDragDropClient(*iter
, NULL
);