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/window_event_dispatcher.h"
16 #include "ui/aura/window_tree_host.h"
17 #include "ui/base/clipboard/clipboard.h"
18 #include "ui/base/clipboard/scoped_clipboard_writer.h"
19 #include "ui/base/dragdrop/drag_drop_types.h"
20 #include "ui/base/dragdrop/drag_utils.h"
21 #include "ui/base/dragdrop/os_exchange_data.h"
22 #include "ui/base/ui_base_switches.h"
23 #include "ui/events/event.h"
24 #include "ui/events/event_utils.h"
25 #include "ui/events/gesture_detection/gesture_configuration.h"
26 #include "ui/events/gestures/gesture_types.h"
27 #include "ui/events/test/event_generator.h"
28 #include "ui/events/test/events_test_utils.h"
29 #include "ui/gfx/animation/linear_animation.h"
30 #include "ui/gfx/image/image_skia_rep.h"
31 #include "ui/views/view.h"
32 #include "ui/views/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 int GetDragOperations(const gfx::Point
& press_pt
) override
{
75 return ui::DragDropTypes::DRAG_COPY
;
78 void WriteDragData(const gfx::Point
& p
, OSExchangeData
* data
) override
{
79 data
->SetString(base::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(image_skia
, gfx::Vector2d(), data
);
86 bool OnMousePressed(const ui::MouseEvent
& event
) override
{ return true; }
88 void OnGestureEvent(ui::GestureEvent
* event
) override
{
89 if (event
->type() == ui::ET_GESTURE_LONG_TAP
)
90 long_tap_received_
= true;
96 std::set
<OSExchangeData::CustomFormat
>* custom_formats
) override
{
97 *formats
= ui::OSExchangeData::STRING
;
101 bool CanDrop(const OSExchangeData
& data
) override
{ return true; }
103 void OnDragEntered(const ui::DropTargetEvent
& event
) override
{
107 int OnDragUpdated(const ui::DropTargetEvent
& event
) override
{
109 return ui::DragDropTypes::DRAG_COPY
;
112 void OnDragExited() override
{ num_drag_exits_
++; }
114 int OnPerformDrop(const ui::DropTargetEvent
& event
) override
{
116 return ui::DragDropTypes::DRAG_COPY
;
119 void OnDragDone() override
{ drag_done_received_
= true; }
121 DISALLOW_COPY_AND_ASSIGN(DragTestView
);
124 class CompletableLinearAnimation
: public gfx::LinearAnimation
{
126 CompletableLinearAnimation(int duration
,
128 gfx::AnimationDelegate
* delegate
)
129 : gfx::LinearAnimation(duration
, frame_rate
, delegate
),
130 duration_(duration
) {
134 Step(start_time() + base::TimeDelta::FromMilliseconds(duration_
));
141 class TestDragDropController
: public DragDropController
{
143 TestDragDropController() : DragDropController() { Reset(); }
146 drag_start_received_
= false;
147 num_drag_updates_
= 0;
148 drop_received_
= false;
149 drag_canceled_
= false;
150 drag_string_
.clear();
153 int StartDragAndDrop(const ui::OSExchangeData
& data
,
154 aura::Window
* root_window
,
155 aura::Window
* source_window
,
156 const gfx::Point
& location
,
158 ui::DragDropTypes::DragEventSource source
) override
{
159 drag_start_received_
= true;
160 data
.GetString(&drag_string_
);
161 return DragDropController::StartDragAndDrop(
162 data
, root_window
, source_window
, location
, operation
, source
);
165 void DragUpdate(aura::Window
* target
,
166 const ui::LocatedEvent
& event
) override
{
167 DragDropController::DragUpdate(target
, event
);
171 void Drop(aura::Window
* target
, const ui::LocatedEvent
& event
) override
{
172 DragDropController::Drop(target
, event
);
173 drop_received_
= true;
176 void DragCancel() override
{
177 DragDropController::DragCancel();
178 drag_canceled_
= true;
181 gfx::LinearAnimation
* CreateCancelAnimation(
184 gfx::AnimationDelegate
* delegate
) override
{
185 return new CompletableLinearAnimation(duration
, frame_rate
, delegate
);
188 void DoDragCancel(int animation_duration_ms
) override
{
189 DragDropController::DoDragCancel(animation_duration_ms
);
190 drag_canceled_
= true;
193 bool drag_start_received_
;
194 int num_drag_updates_
;
197 base::string16 drag_string_
;
200 DISALLOW_COPY_AND_ASSIGN(TestDragDropController
);
203 class TestNativeWidgetAura
: public views::NativeWidgetAura
{
205 explicit TestNativeWidgetAura(views::internal::NativeWidgetDelegate
* delegate
)
206 : NativeWidgetAura(delegate
),
207 check_if_capture_lost_(false) {
210 void set_check_if_capture_lost(bool value
) {
211 check_if_capture_lost_
= value
;
214 void OnCaptureLost() override
{
215 DCHECK(!check_if_capture_lost_
);
216 views::NativeWidgetAura::OnCaptureLost();
220 bool check_if_capture_lost_
;
222 DISALLOW_COPY_AND_ASSIGN(TestNativeWidgetAura
);
225 // TODO(sky): this is for debugging, remove when track down failure.
226 void SetCheckIfCaptureLost(views::Widget
* widget
, bool value
) {
227 // On Windows, the DCHECK triggers when running on bot or locally through RDP,
228 // but not when logged in locally.
230 static_cast<TestNativeWidgetAura
*>(widget
->native_widget())->
231 set_check_if_capture_lost(value
);
235 views::Widget
* CreateNewWidget() {
236 views::Widget
* widget
= new views::Widget
;
237 views::Widget::InitParams params
;
238 params
.type
= views::Widget::InitParams::TYPE_WINDOW_FRAMELESS
;
239 params
.accept_events
= true;
240 params
.ownership
= views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
241 params
.parent
= Shell::GetPrimaryRootWindow();
243 params
.native_widget
= new TestNativeWidgetAura(widget
);
244 widget
->Init(params
);
249 void AddViewToWidgetAndResize(views::Widget
* widget
, views::View
* view
) {
250 if (!widget
->GetContentsView()) {
251 views::View
* contents_view
= new views::View
;
252 widget
->SetContentsView(contents_view
);
255 views::View
* contents_view
= widget
->GetContentsView();
256 contents_view
->AddChildView(view
);
257 view
->SetBounds(contents_view
->width(), 0, 100, 100);
258 gfx::Rect contents_view_bounds
= contents_view
->bounds();
259 contents_view_bounds
.Union(view
->bounds());
260 contents_view
->SetBoundsRect(contents_view_bounds
);
261 widget
->SetBounds(contents_view_bounds
);
264 void DispatchGesture(ui::EventType gesture_type
, gfx::Point location
) {
265 ui::GestureEventDetails
event_details(gesture_type
);
266 event_details
.set_oldest_touch_id(1);
267 ui::GestureEvent
gesture_event(
268 location
.x(), location
.y(), 0, ui::EventTimeForNow(), event_details
);
269 ui::EventSource
* event_source
=
270 Shell::GetPrimaryRootWindow()->GetHost()->GetEventSource();
271 ui::EventSourceTestApi
event_source_test(event_source
);
272 ui::EventDispatchDetails details
=
273 event_source_test
.SendEventToProcessor(&gesture_event
);
274 CHECK(!details
.dispatcher_destroyed
);
279 class DragDropControllerTest
: public AshTestBase
{
281 DragDropControllerTest() : AshTestBase() {}
282 ~DragDropControllerTest() override
{}
284 void SetUp() override
{
285 AshTestBase::SetUp();
286 drag_drop_controller_
.reset(new TestDragDropController
);
287 drag_drop_controller_
->set_should_block_during_drag_drop(false);
288 aura::client::SetDragDropClient(Shell::GetPrimaryRootWindow(),
289 drag_drop_controller_
.get());
292 void TearDown() override
{
293 aura::client::SetDragDropClient(Shell::GetPrimaryRootWindow(), NULL
);
294 drag_drop_controller_
.reset();
295 AshTestBase::TearDown();
298 void UpdateDragData(ui::OSExchangeData
* data
) {
299 drag_drop_controller_
->drag_data_
= data
;
302 aura::Window
* GetDragWindow() {
303 return drag_drop_controller_
->drag_window_
;
306 aura::Window
* GetDragSourceWindow() {
307 return drag_drop_controller_
->drag_source_window_
;
310 void SetDragSourceWindow(aura::Window
* drag_source_window
) {
311 drag_drop_controller_
->drag_source_window_
= drag_source_window
;
312 drag_source_window
->AddObserver(drag_drop_controller_
.get());
315 aura::Window
* GetDragImageWindow() {
316 return drag_drop_controller_
->drag_image_
.get() ?
317 drag_drop_controller_
->drag_image_
->GetWidget()->GetNativeWindow() :
321 DragDropTracker
* drag_drop_tracker() {
322 return drag_drop_controller_
->drag_drop_tracker_
.get();
325 void CompleteCancelAnimation() {
326 CompletableLinearAnimation
* animation
=
327 static_cast<CompletableLinearAnimation
*>(
328 drag_drop_controller_
->cancel_animation_
.get());
329 animation
->Complete();
333 scoped_ptr
<TestDragDropController
> drag_drop_controller_
;
336 DISALLOW_COPY_AND_ASSIGN(DragDropControllerTest
);
339 // TODO(win_aura) http://crbug.com/154081
341 #define MAYBE_DragDropInSingleViewTest DISABLED_DragDropInSingleViewTest
343 #define MAYBE_DragDropInSingleViewTest DragDropInSingleViewTest
345 TEST_F(DragDropControllerTest
, MAYBE_DragDropInSingleViewTest
) {
346 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
347 DragTestView
* drag_view
= new DragTestView
;
348 AddViewToWidgetAndResize(widget
.get(), drag_view
);
349 ui::OSExchangeData data
;
350 data
.SetString(base::UTF8ToUTF16("I am being dragged"));
351 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
352 widget
->GetNativeView());
353 generator
.PressLeftButton();
356 SetCheckIfCaptureLost(widget
.get(), true);
357 for (int i
= 0; i
< num_drags
; ++i
) {
358 // Because we are not doing a blocking drag and drop, the original
359 // OSDragExchangeData object is lost as soon as we return from the drag
360 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
361 // drag_data_ to a fake drag data object that we created.
363 UpdateDragData(&data
);
364 // 7 comes from views::View::GetVerticalDragThreshold()).
366 SetCheckIfCaptureLost(widget
.get(), false);
368 generator
.MoveMouseBy(0, 1);
370 // Execute any scheduled draws to process deferred mouse events.
371 RunAllPendingInMessageLoop();
374 generator
.ReleaseLeftButton();
376 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
377 EXPECT_EQ(num_drags
- 1 - drag_view
->VerticalDragThreshold(),
378 drag_drop_controller_
->num_drag_updates_
);
379 EXPECT_TRUE(drag_drop_controller_
->drop_received_
);
380 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
381 drag_drop_controller_
->drag_string_
);
383 EXPECT_EQ(1, drag_view
->num_drag_enters_
);
384 EXPECT_EQ(num_drags
- 1 - drag_view
->VerticalDragThreshold(),
385 drag_view
->num_drag_updates_
);
386 EXPECT_EQ(1, drag_view
->num_drops_
);
387 EXPECT_EQ(0, drag_view
->num_drag_exits_
);
388 EXPECT_TRUE(drag_view
->drag_done_received_
);
391 TEST_F(DragDropControllerTest
, DragDropWithZeroDragUpdates
) {
392 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
393 DragTestView
* drag_view
= new DragTestView
;
394 AddViewToWidgetAndResize(widget
.get(), drag_view
);
395 ui::OSExchangeData data
;
396 data
.SetString(base::UTF8ToUTF16("I am being dragged"));
397 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
398 widget
->GetNativeView());
399 generator
.PressLeftButton();
401 int num_drags
= drag_view
->VerticalDragThreshold() + 1;
402 for (int i
= 0; i
< num_drags
; ++i
) {
403 // Because we are not doing a blocking drag and drop, the original
404 // OSDragExchangeData object is lost as soon as we return from the drag
405 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
406 // drag_data_ to a fake drag data object that we created.
408 UpdateDragData(&data
);
409 generator
.MoveMouseBy(0, 1);
412 UpdateDragData(&data
);
414 generator
.ReleaseLeftButton();
416 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
417 EXPECT_EQ(num_drags
- 1 - drag_view
->VerticalDragThreshold() + 1,
418 drag_drop_controller_
->num_drag_updates_
);
419 EXPECT_TRUE(drag_drop_controller_
->drop_received_
);
421 EXPECT_EQ(1, drag_view
->num_drag_enters_
);
422 EXPECT_EQ(num_drags
- 1 - drag_view
->VerticalDragThreshold() + 1,
423 drag_view
->num_drag_updates_
);
424 EXPECT_EQ(1, drag_view
->num_drops_
);
425 EXPECT_EQ(0, drag_view
->num_drag_exits_
);
426 EXPECT_TRUE(drag_view
->drag_done_received_
);
429 // TODO(win_aura) http://crbug.com/154081
431 #define MAYBE_DragDropInMultipleViewsSingleWidgetTest DISABLED_DragDropInMultipleViewsSingleWidgetTest
433 #define MAYBE_DragDropInMultipleViewsSingleWidgetTest DragDropInMultipleViewsSingleWidgetTest
435 TEST_F(DragDropControllerTest
, MAYBE_DragDropInMultipleViewsSingleWidgetTest
) {
436 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
437 DragTestView
* drag_view1
= new DragTestView
;
438 AddViewToWidgetAndResize(widget
.get(), drag_view1
);
439 DragTestView
* drag_view2
= new DragTestView
;
440 AddViewToWidgetAndResize(widget
.get(), drag_view2
);
442 ui::OSExchangeData data
;
443 data
.SetString(base::UTF8ToUTF16("I am being dragged"));
445 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow());
446 generator
.MoveMouseRelativeTo(widget
->GetNativeView(),
447 drag_view1
->bounds().CenterPoint());
448 generator
.PressLeftButton();
450 int num_drags
= drag_view1
->width();
451 for (int i
= 0; i
< num_drags
; ++i
) {
452 // Because we are not doing a blocking drag and drop, the original
453 // OSDragExchangeData object is lost as soon as we return from the drag
454 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
455 // drag_data_ to a fake drag data object that we created.
457 UpdateDragData(&data
);
458 generator
.MoveMouseBy(1, 0);
460 // Execute any scheduled draws to process deferred mouse events.
461 RunAllPendingInMessageLoop();
464 generator
.ReleaseLeftButton();
466 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
467 EXPECT_EQ(num_drags
- 1 - drag_view1
->HorizontalDragThreshold(),
468 drag_drop_controller_
->num_drag_updates_
);
469 EXPECT_TRUE(drag_drop_controller_
->drop_received_
);
470 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
471 drag_drop_controller_
->drag_string_
);
473 EXPECT_EQ(1, drag_view1
->num_drag_enters_
);
474 int num_expected_updates
= drag_view1
->bounds().width() -
475 drag_view1
->bounds().CenterPoint().x() - 2;
476 EXPECT_EQ(num_expected_updates
- drag_view1
->HorizontalDragThreshold(),
477 drag_view1
->num_drag_updates_
);
478 EXPECT_EQ(0, drag_view1
->num_drops_
);
479 EXPECT_EQ(1, drag_view1
->num_drag_exits_
);
480 EXPECT_TRUE(drag_view1
->drag_done_received_
);
482 EXPECT_EQ(1, drag_view2
->num_drag_enters_
);
483 num_expected_updates
= num_drags
- num_expected_updates
- 1;
484 EXPECT_EQ(num_expected_updates
, drag_view2
->num_drag_updates_
);
485 EXPECT_EQ(1, drag_view2
->num_drops_
);
486 EXPECT_EQ(0, drag_view2
->num_drag_exits_
);
487 EXPECT_FALSE(drag_view2
->drag_done_received_
);
490 // TODO(win_aura) http://crbug.com/154081
492 #define MAYBE_DragDropInMultipleViewsMultipleWidgetsTest DISABLED_DragDropInMultipleViewsMultipleWidgetsTest
494 #define MAYBE_DragDropInMultipleViewsMultipleWidgetsTest DragDropInMultipleViewsMultipleWidgetsTest
496 TEST_F(DragDropControllerTest
, MAYBE_DragDropInMultipleViewsMultipleWidgetsTest
) {
497 scoped_ptr
<views::Widget
> widget1(CreateNewWidget());
498 DragTestView
* drag_view1
= new DragTestView
;
499 AddViewToWidgetAndResize(widget1
.get(), drag_view1
);
500 scoped_ptr
<views::Widget
> widget2(CreateNewWidget());
501 DragTestView
* drag_view2
= new DragTestView
;
502 AddViewToWidgetAndResize(widget2
.get(), drag_view2
);
503 gfx::Rect widget1_bounds
= widget1
->GetClientAreaBoundsInScreen();
504 gfx::Rect widget2_bounds
= widget2
->GetClientAreaBoundsInScreen();
505 widget2
->SetBounds(gfx::Rect(widget1_bounds
.width(), 0,
506 widget2_bounds
.width(), widget2_bounds
.height()));
508 ui::OSExchangeData data
;
509 data
.SetString(base::UTF8ToUTF16("I am being dragged"));
511 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
512 widget1
->GetNativeView());
513 generator
.PressLeftButton();
515 int num_drags
= drag_view1
->width();
516 for (int i
= 0; i
< num_drags
; ++i
) {
517 // Because we are not doing a blocking drag and drop, the original
518 // OSDragExchangeData object is lost as soon as we return from the drag
519 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
520 // drag_data_ to a fake drag data object that we created.
522 UpdateDragData(&data
);
523 generator
.MoveMouseBy(1, 0);
525 // Execute any scheduled draws to process deferred mouse events.
526 RunAllPendingInMessageLoop();
529 generator
.ReleaseLeftButton();
531 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
532 EXPECT_EQ(num_drags
- 1 - drag_view1
->HorizontalDragThreshold(),
533 drag_drop_controller_
->num_drag_updates_
);
534 EXPECT_TRUE(drag_drop_controller_
->drop_received_
);
535 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
536 drag_drop_controller_
->drag_string_
);
538 EXPECT_EQ(1, drag_view1
->num_drag_enters_
);
539 int num_expected_updates
= drag_view1
->bounds().width() -
540 drag_view1
->bounds().CenterPoint().x() - 2;
541 EXPECT_EQ(num_expected_updates
- drag_view1
->HorizontalDragThreshold(),
542 drag_view1
->num_drag_updates_
);
543 EXPECT_EQ(0, drag_view1
->num_drops_
);
544 EXPECT_EQ(1, drag_view1
->num_drag_exits_
);
545 EXPECT_TRUE(drag_view1
->drag_done_received_
);
547 EXPECT_EQ(1, drag_view2
->num_drag_enters_
);
548 num_expected_updates
= num_drags
- num_expected_updates
- 1;
549 EXPECT_EQ(num_expected_updates
, drag_view2
->num_drag_updates_
);
550 EXPECT_EQ(1, drag_view2
->num_drops_
);
551 EXPECT_EQ(0, drag_view2
->num_drag_exits_
);
552 EXPECT_FALSE(drag_view2
->drag_done_received_
);
555 // TODO(win_aura) http://crbug.com/154081
557 #define MAYBE_ViewRemovedWhileInDragDropTest DISABLED_ViewRemovedWhileInDragDropTest
559 #define MAYBE_ViewRemovedWhileInDragDropTest ViewRemovedWhileInDragDropTest
561 TEST_F(DragDropControllerTest
, MAYBE_ViewRemovedWhileInDragDropTest
) {
562 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
563 scoped_ptr
<DragTestView
> drag_view(new DragTestView
);
564 AddViewToWidgetAndResize(widget
.get(), drag_view
.get());
565 gfx::Point point
= gfx::Rect(drag_view
->bounds()).CenterPoint();
566 ui::OSExchangeData data
;
567 data
.SetString(base::UTF8ToUTF16("I am being dragged"));
569 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow());
570 generator
.MoveMouseToCenterOf(widget
->GetNativeView());
571 generator
.PressLeftButton();
573 int num_drags_1
= 17;
574 for (int i
= 0; i
< num_drags_1
; ++i
) {
575 // Because we are not doing a blocking drag and drop, the original
576 // OSDragExchangeData object is lost as soon as we return from the drag
577 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
578 // drag_data_ to a fake drag data object that we created.
580 UpdateDragData(&data
);
581 generator
.MoveMouseBy(0, 1);
583 // Execute any scheduled draws to process deferred mouse events.
584 RunAllPendingInMessageLoop();
587 drag_view
->parent()->RemoveChildView(drag_view
.get());
588 // View has been removed. We will not get any of the following drag updates.
589 int num_drags_2
= 23;
590 for (int i
= 0; i
< num_drags_2
; ++i
) {
591 UpdateDragData(&data
);
592 generator
.MoveMouseBy(0, 1);
594 // Execute any scheduled draws to process deferred mouse events.
595 RunAllPendingInMessageLoop();
598 generator
.ReleaseLeftButton();
600 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
601 EXPECT_EQ(num_drags_1
+ num_drags_2
- 1 - drag_view
->VerticalDragThreshold(),
602 drag_drop_controller_
->num_drag_updates_
);
603 EXPECT_TRUE(drag_drop_controller_
->drop_received_
);
604 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
605 drag_drop_controller_
->drag_string_
);
607 EXPECT_EQ(1, drag_view
->num_drag_enters_
);
608 EXPECT_EQ(num_drags_1
- 1 - drag_view
->VerticalDragThreshold(),
609 drag_view
->num_drag_updates_
);
610 EXPECT_EQ(0, drag_view
->num_drops_
);
611 EXPECT_EQ(0, drag_view
->num_drag_exits_
);
612 EXPECT_TRUE(drag_view
->drag_done_received_
);
615 TEST_F(DragDropControllerTest
, DragLeavesClipboardAloneTest
) {
616 ui::Clipboard
* cb
= ui::Clipboard::GetForCurrentThread();
617 std::string
clip_str("I am on the clipboard");
619 // We first copy some text to the clipboard.
620 ui::ScopedClipboardWriter
scw(ui::CLIPBOARD_TYPE_COPY_PASTE
);
621 scw
.WriteText(base::ASCIIToUTF16(clip_str
));
623 EXPECT_TRUE(cb
->IsFormatAvailable(ui::Clipboard::GetPlainTextFormatType(),
624 ui::CLIPBOARD_TYPE_COPY_PASTE
));
626 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
627 DragTestView
* drag_view
= new DragTestView
;
628 AddViewToWidgetAndResize(widget
.get(), drag_view
);
630 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
631 widget
->GetNativeView());
632 ui::OSExchangeData data
;
633 std::string
data_str("I am being dragged");
634 data
.SetString(base::ASCIIToUTF16(data_str
));
636 generator
.PressLeftButton();
637 generator
.MoveMouseBy(0, drag_view
->VerticalDragThreshold() + 1);
639 // Execute any scheduled draws to process deferred mouse events.
640 RunAllPendingInMessageLoop();
642 // Verify the clipboard contents haven't changed
644 EXPECT_TRUE(cb
->IsFormatAvailable(ui::Clipboard::GetPlainTextFormatType(),
645 ui::CLIPBOARD_TYPE_COPY_PASTE
));
646 cb
->ReadAsciiText(ui::CLIPBOARD_TYPE_COPY_PASTE
, &result
);
647 EXPECT_EQ(clip_str
, result
);
648 // Destory the clipboard here because ash doesn't delete it.
650 ui::Clipboard::DestroyClipboardForCurrentThread();
653 TEST_F(DragDropControllerTest
, WindowDestroyedDuringDragDrop
) {
654 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
655 DragTestView
* drag_view
= new DragTestView
;
656 AddViewToWidgetAndResize(widget
.get(), drag_view
);
657 aura::Window
* window
= widget
->GetNativeView();
659 ui::OSExchangeData data
;
660 data
.SetString(base::UTF8ToUTF16("I am being dragged"));
661 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
662 widget
->GetNativeView());
663 generator
.PressLeftButton();
666 for (int i
= 0; i
< num_drags
; ++i
) {
667 // Because we are not doing a blocking drag and drop, the original
668 // OSDragExchangeData object is lost as soon as we return from the drag
669 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
670 // drag_data_ to a fake drag data object that we created.
672 UpdateDragData(&data
);
673 generator
.MoveMouseBy(0, 1);
675 // Execute any scheduled draws to process deferred mouse events.
676 RunAllPendingInMessageLoop();
678 if (i
> drag_view
->VerticalDragThreshold())
679 EXPECT_EQ(window
, GetDragWindow());
683 EXPECT_FALSE(GetDragWindow());
686 for (int i
= 0; i
< num_drags
; ++i
) {
688 UpdateDragData(&data
);
689 generator
.MoveMouseBy(0, 1);
690 // We should not crash here.
693 generator
.ReleaseLeftButton();
695 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
696 EXPECT_TRUE(drag_drop_controller_
->drop_received_
);
699 TEST_F(DragDropControllerTest
, SyntheticEventsDuringDragDrop
) {
700 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
701 DragTestView
* drag_view
= new DragTestView
;
702 AddViewToWidgetAndResize(widget
.get(), drag_view
);
703 ui::OSExchangeData data
;
704 data
.SetString(base::UTF8ToUTF16("I am being dragged"));
705 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
706 widget
->GetNativeView());
707 generator
.PressLeftButton();
710 for (int i
= 0; i
< num_drags
; ++i
) {
711 // Because we are not doing a blocking drag and drop, the original
712 // OSDragExchangeData object is lost as soon as we return from the drag
713 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
714 // drag_data_ to a fake drag data object that we created.
716 UpdateDragData(&data
);
717 generator
.MoveMouseBy(0, 1);
719 // We send a unexpected mouse move event. Note that we cannot use
720 // EventGenerator since it implicitly turns these into mouse drag events.
721 // The DragDropController should simply ignore these events.
722 gfx::Point mouse_move_location
= drag_view
->bounds().CenterPoint();
723 ui::MouseEvent
mouse_move(ui::ET_MOUSE_MOVED
, mouse_move_location
,
724 mouse_move_location
, ui::EventTimeForNow(), 0, 0);
725 ui::EventDispatchDetails details
= Shell::GetPrimaryRootWindow()->
726 GetHost()->event_processor()->OnEventFromSource(&mouse_move
);
727 ASSERT_FALSE(details
.dispatcher_destroyed
);
730 generator
.ReleaseLeftButton();
732 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
733 EXPECT_EQ(num_drags
- 1 - drag_view
->VerticalDragThreshold(),
734 drag_drop_controller_
->num_drag_updates_
);
735 EXPECT_TRUE(drag_drop_controller_
->drop_received_
);
736 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
737 drag_drop_controller_
->drag_string_
);
739 EXPECT_EQ(1, drag_view
->num_drag_enters_
);
740 EXPECT_EQ(num_drags
- 1 - drag_view
->VerticalDragThreshold(),
741 drag_view
->num_drag_updates_
);
742 EXPECT_EQ(1, drag_view
->num_drops_
);
743 EXPECT_EQ(0, drag_view
->num_drag_exits_
);
744 EXPECT_TRUE(drag_view
->drag_done_received_
);
747 // TODO(win_aura) http://crbug.com/154081
749 #define MAYBE_PressingEscapeCancelsDragDrop DISABLED_PressingEscapeCancelsDragDrop
750 #define MAYBE_CaptureLostCancelsDragDrop DISABLED_CaptureLostCancelsDragDrop
752 #define MAYBE_PressingEscapeCancelsDragDrop PressingEscapeCancelsDragDrop
753 #define MAYBE_CaptureLostCancelsDragDrop CaptureLostCancelsDragDrop
755 TEST_F(DragDropControllerTest
, MAYBE_PressingEscapeCancelsDragDrop
) {
756 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
757 DragTestView
* drag_view
= new DragTestView
;
758 AddViewToWidgetAndResize(widget
.get(), drag_view
);
759 ui::OSExchangeData data
;
760 data
.SetString(base::UTF8ToUTF16("I am being dragged"));
761 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
762 widget
->GetNativeView());
763 generator
.PressLeftButton();
766 for (int i
= 0; i
< num_drags
; ++i
) {
767 // Because we are not doing a blocking drag and drop, the original
768 // OSDragExchangeData object is lost as soon as we return from the drag
769 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
770 // drag_data_ to a fake drag data object that we created.
772 UpdateDragData(&data
);
773 generator
.MoveMouseBy(0, 1);
775 // Execute any scheduled draws to process deferred mouse events.
776 RunAllPendingInMessageLoop();
779 generator
.PressKey(ui::VKEY_ESCAPE
, 0);
781 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
782 EXPECT_EQ(num_drags
- 1 - drag_view
->VerticalDragThreshold(),
783 drag_drop_controller_
->num_drag_updates_
);
784 EXPECT_FALSE(drag_drop_controller_
->drop_received_
);
785 EXPECT_TRUE(drag_drop_controller_
->drag_canceled_
);
786 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
787 drag_drop_controller_
->drag_string_
);
789 EXPECT_EQ(1, drag_view
->num_drag_enters_
);
790 EXPECT_EQ(num_drags
- 1 - drag_view
->VerticalDragThreshold(),
791 drag_view
->num_drag_updates_
);
792 EXPECT_EQ(0, drag_view
->num_drops_
);
793 EXPECT_EQ(1, drag_view
->num_drag_exits_
);
794 EXPECT_TRUE(drag_view
->drag_done_received_
);
797 TEST_F(DragDropControllerTest
, MAYBE_CaptureLostCancelsDragDrop
) {
798 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
799 DragTestView
* drag_view
= new DragTestView
;
800 AddViewToWidgetAndResize(widget
.get(), drag_view
);
801 ui::OSExchangeData data
;
802 data
.SetString(base::UTF8ToUTF16("I am being dragged"));
803 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
804 widget
->GetNativeView());
805 generator
.PressLeftButton();
808 for (int i
= 0; i
< num_drags
; ++i
) {
809 // Because we are not doing a blocking drag and drop, the original
810 // OSDragExchangeData object is lost as soon as we return from the drag
811 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
812 // drag_data_ to a fake drag data object that we created.
814 UpdateDragData(&data
);
815 generator
.MoveMouseBy(0, 1);
817 // Execute any scheduled draws to process deferred mouse events.
818 RunAllPendingInMessageLoop();
820 // Make sure the capture window won't handle mouse events.
821 aura::Window
* capture_window
= drag_drop_tracker()->capture_window();
822 ASSERT_TRUE(capture_window
);
823 EXPECT_EQ("0x0", capture_window
->bounds().size().ToString());
825 capture_window
->GetEventHandlerForPoint(gfx::Point()));
827 capture_window
->GetTopWindowContainingPoint(gfx::Point()));
829 aura::client::GetCaptureClient(widget
->GetNativeView()->GetRootWindow())->
832 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
833 EXPECT_EQ(num_drags
- 1 - drag_view
->VerticalDragThreshold(),
834 drag_drop_controller_
->num_drag_updates_
);
835 EXPECT_FALSE(drag_drop_controller_
->drop_received_
);
836 EXPECT_TRUE(drag_drop_controller_
->drag_canceled_
);
837 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
838 drag_drop_controller_
->drag_string_
);
840 EXPECT_EQ(1, drag_view
->num_drag_enters_
);
841 EXPECT_EQ(num_drags
- 1 - drag_view
->VerticalDragThreshold(),
842 drag_view
->num_drag_updates_
);
843 EXPECT_EQ(0, drag_view
->num_drops_
);
844 EXPECT_EQ(1, drag_view
->num_drag_exits_
);
845 EXPECT_TRUE(drag_view
->drag_done_received_
);
848 TEST_F(DragDropControllerTest
, TouchDragDropInMultipleWindows
) {
849 base::CommandLine::ForCurrentProcess()->AppendSwitch(
850 switches::kEnableTouchDragDrop
);
851 scoped_ptr
<views::Widget
> widget1(CreateNewWidget());
852 DragTestView
* drag_view1
= new DragTestView
;
853 AddViewToWidgetAndResize(widget1
.get(), drag_view1
);
854 scoped_ptr
<views::Widget
> widget2(CreateNewWidget());
855 DragTestView
* drag_view2
= new DragTestView
;
856 AddViewToWidgetAndResize(widget2
.get(), drag_view2
);
857 gfx::Rect widget1_bounds
= widget1
->GetClientAreaBoundsInScreen();
858 gfx::Rect widget2_bounds
= widget2
->GetClientAreaBoundsInScreen();
859 widget2
->SetBounds(gfx::Rect(widget1_bounds
.width(), 0,
860 widget2_bounds
.width(), widget2_bounds
.height()));
862 ui::OSExchangeData data
;
863 data
.SetString(base::UTF8ToUTF16("I am being dragged"));
865 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
866 widget1
->GetNativeView());
867 generator
.PressTouch();
868 gfx::Point point
= gfx::Rect(drag_view1
->bounds()).CenterPoint();
869 DispatchGesture(ui::ET_GESTURE_LONG_PRESS
, point
);
870 // Because we are not doing a blocking drag and drop, the original
871 // OSDragExchangeData object is lost as soon as we return from the drag
872 // initiation in DragDropController::StartDragAndDrop(). Hence we set the
873 // drag_data_ to a fake drag data object that we created.
874 UpdateDragData(&data
);
875 gfx::Point gesture_location
= point
;
876 int num_drags
= drag_view1
->width();
877 for (int i
= 0; i
< num_drags
; ++i
) {
878 gesture_location
.Offset(1, 0);
879 DispatchGesture(ui::ET_GESTURE_SCROLL_UPDATE
, gesture_location
);
881 // Execute any scheduled draws to process deferred mouse events.
882 RunAllPendingInMessageLoop();
885 DispatchGesture(ui::ET_GESTURE_SCROLL_END
, gesture_location
);
887 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
888 EXPECT_EQ(num_drags
, drag_drop_controller_
->num_drag_updates_
);
889 EXPECT_TRUE(drag_drop_controller_
->drop_received_
);
890 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
891 drag_drop_controller_
->drag_string_
);
893 EXPECT_EQ(1, drag_view1
->num_drag_enters_
);
894 int num_expected_updates
= drag_view1
->bounds().width() -
895 drag_view1
->bounds().CenterPoint().x() - 1;
896 EXPECT_EQ(num_expected_updates
, drag_view1
->num_drag_updates_
);
897 EXPECT_EQ(0, drag_view1
->num_drops_
);
898 EXPECT_EQ(1, drag_view1
->num_drag_exits_
);
899 EXPECT_TRUE(drag_view1
->drag_done_received_
);
901 EXPECT_EQ(1, drag_view2
->num_drag_enters_
);
902 num_expected_updates
= num_drags
- num_expected_updates
;
903 EXPECT_EQ(num_expected_updates
, drag_view2
->num_drag_updates_
);
904 EXPECT_EQ(1, drag_view2
->num_drops_
);
905 EXPECT_EQ(0, drag_view2
->num_drag_exits_
);
906 EXPECT_FALSE(drag_view2
->drag_done_received_
);
909 TEST_F(DragDropControllerTest
, TouchDragDropCancelsOnLongTap
) {
910 base::CommandLine::ForCurrentProcess()->AppendSwitch(
911 switches::kEnableTouchDragDrop
);
912 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
913 DragTestView
* drag_view
= new DragTestView
;
914 AddViewToWidgetAndResize(widget
.get(), drag_view
);
915 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
916 widget
->GetNativeView());
918 generator
.PressTouch();
919 gfx::Point point
= gfx::Rect(drag_view
->bounds()).CenterPoint();
920 DispatchGesture(ui::ET_GESTURE_LONG_PRESS
, point
);
921 DispatchGesture(ui::ET_GESTURE_LONG_TAP
, point
);
923 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
924 EXPECT_TRUE(drag_drop_controller_
->drag_canceled_
);
925 EXPECT_EQ(0, drag_drop_controller_
->num_drag_updates_
);
926 EXPECT_FALSE(drag_drop_controller_
->drop_received_
);
927 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
928 drag_drop_controller_
->drag_string_
);
929 EXPECT_EQ(0, drag_view
->num_drag_enters_
);
930 EXPECT_EQ(0, drag_view
->num_drops_
);
931 EXPECT_EQ(0, drag_view
->num_drag_exits_
);
932 EXPECT_TRUE(drag_view
->drag_done_received_
);
935 TEST_F(DragDropControllerTest
, TouchDragDropLongTapGestureIsForwarded
) {
936 base::CommandLine::ForCurrentProcess()->AppendSwitch(
937 switches::kEnableTouchDragDrop
);
938 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
939 DragTestView
* drag_view
= new DragTestView
;
940 AddViewToWidgetAndResize(widget
.get(), drag_view
);
941 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
942 widget
->GetNativeView());
944 generator
.PressTouch();
945 gfx::Point point
= gfx::Rect(drag_view
->bounds()).CenterPoint();
946 DispatchGesture(ui::ET_GESTURE_LONG_PRESS
, point
);
948 // Since we are not running inside a nested loop, the |drag_source_window_|
949 // will get destroyed immediately. Hence we reassign it.
950 EXPECT_EQ(NULL
, GetDragSourceWindow());
951 SetDragSourceWindow(widget
->GetNativeView());
952 EXPECT_FALSE(drag_view
->long_tap_received_
);
953 DispatchGesture(ui::ET_GESTURE_LONG_TAP
, point
);
954 CompleteCancelAnimation();
955 EXPECT_TRUE(drag_view
->long_tap_received_
);
960 class DragImageWindowObserver
: public aura::WindowObserver
{
962 void OnWindowDestroying(aura::Window
* window
) override
{
963 window_location_on_destroying_
= window
->GetBoundsInScreen().origin();
966 gfx::Point
window_location_on_destroying() const {
967 return window_location_on_destroying_
;
971 gfx::Point window_location_on_destroying_
;
976 // Verifies the drag image moves back to the position where drag is started
977 // across displays when drag is cancelled.
978 TEST_F(DragDropControllerTest
, DragCancelAcrossDisplays
) {
979 if (!SupportsMultipleDisplays())
982 UpdateDisplay("400x400,400x400");
983 aura::Window::Windows root_windows
=
984 Shell::GetInstance()->GetAllRootWindows();
985 for (aura::Window::Windows::iterator iter
= root_windows
.begin();
986 iter
!= root_windows
.end(); ++iter
) {
987 aura::client::SetDragDropClient(*iter
, drag_drop_controller_
.get());
990 ui::OSExchangeData data
;
991 data
.SetString(base::UTF8ToUTF16("I am being dragged"));
993 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
994 aura::Window
* window
= widget
->GetNativeWindow();
995 drag_drop_controller_
->StartDragAndDrop(
997 window
->GetRootWindow(),
1000 ui::DragDropTypes::DRAG_MOVE
,
1001 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE
);
1003 DragImageWindowObserver observer
;
1004 ASSERT_TRUE(GetDragImageWindow());
1005 GetDragImageWindow()->AddObserver(&observer
);
1008 ui::MouseEvent
e(ui::ET_MOUSE_DRAGGED
, gfx::Point(200, 0),
1009 gfx::Point(200, 0), ui::EventTimeForNow(), ui::EF_NONE
,
1011 drag_drop_controller_
->DragUpdate(window
, e
);
1014 ui::MouseEvent
e(ui::ET_MOUSE_DRAGGED
, gfx::Point(600, 0),
1015 gfx::Point(600, 0), ui::EventTimeForNow(), ui::EF_NONE
,
1017 drag_drop_controller_
->DragUpdate(window
, e
);
1020 drag_drop_controller_
->DragCancel();
1021 CompleteCancelAnimation();
1023 EXPECT_EQ("5,5", observer
.window_location_on_destroying().ToString());
1027 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
1028 aura::Window
* window
= widget
->GetNativeWindow();
1029 drag_drop_controller_
->StartDragAndDrop(
1031 window
->GetRootWindow(),
1033 gfx::Point(405, 405),
1034 ui::DragDropTypes::DRAG_MOVE
,
1035 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE
);
1036 DragImageWindowObserver observer
;
1037 ASSERT_TRUE(GetDragImageWindow());
1038 GetDragImageWindow()->AddObserver(&observer
);
1041 ui::MouseEvent
e(ui::ET_MOUSE_DRAGGED
, gfx::Point(600, 0),
1042 gfx::Point(600, 0), ui::EventTimeForNow(), ui::EF_NONE
,
1044 drag_drop_controller_
->DragUpdate(window
, e
);
1047 ui::MouseEvent
e(ui::ET_MOUSE_DRAGGED
, gfx::Point(200, 0),
1048 gfx::Point(200, 0), ui::EventTimeForNow(), ui::EF_NONE
,
1050 drag_drop_controller_
->DragUpdate(window
, e
);
1053 drag_drop_controller_
->DragCancel();
1054 CompleteCancelAnimation();
1056 EXPECT_EQ("405,405", observer
.window_location_on_destroying().ToString());
1058 for (aura::Window::Windows::iterator iter
= root_windows
.begin();
1059 iter
!= root_windows
.end(); ++iter
) {
1060 aura::client::SetDragDropClient(*iter
, NULL
);
1064 TEST_F(DragDropControllerTest
, TouchDragDropCompletesOnFling
) {
1065 base::CommandLine::ForCurrentProcess()->AppendSwitch(
1066 switches::kEnableTouchDragDrop
);
1067 ui::GestureConfiguration::GetInstance()
1068 ->set_max_touch_move_in_pixels_for_click(1);
1069 scoped_ptr
<views::Widget
> widget(CreateNewWidget());
1070 DragTestView
* drag_view
= new DragTestView
;
1071 AddViewToWidgetAndResize(widget
.get(), drag_view
);
1072 ui::OSExchangeData data
;
1073 data
.SetString(base::UTF8ToUTF16("I am being dragged"));
1074 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
1075 widget
->GetNativeView());
1077 gfx::Point start
= gfx::Rect(drag_view
->bounds()).CenterPoint();
1078 gfx::Point mid
= start
+ gfx::Vector2d(drag_view
->bounds().width() / 6, 0);
1079 gfx::Point end
= start
+ gfx::Vector2d(drag_view
->bounds().width() / 3, 0);
1081 base::TimeDelta timestamp
= ui::EventTimeForNow();
1082 ui::TouchEvent
press(ui::ET_TOUCH_PRESSED
, start
, 0, timestamp
);
1083 generator
.Dispatch(&press
);
1085 DispatchGesture(ui::ET_GESTURE_LONG_PRESS
, start
);
1086 UpdateDragData(&data
);
1087 timestamp
+= base::TimeDelta::FromMilliseconds(10);
1088 ui::TouchEvent
move1(ui::ET_TOUCH_MOVED
, mid
, 0, timestamp
);
1089 generator
.Dispatch(&move1
);
1090 // Doing two moves instead of one will guarantee to generate a fling at the
1092 timestamp
+= base::TimeDelta::FromMilliseconds(10);
1093 ui::TouchEvent
move2(ui::ET_TOUCH_MOVED
, end
, 0, timestamp
);
1094 generator
.Dispatch(&move2
);
1095 ui::TouchEvent
release(ui::ET_TOUCH_RELEASED
, end
, 0, timestamp
);
1096 generator
.Dispatch(&release
);
1098 EXPECT_TRUE(drag_drop_controller_
->drag_start_received_
);
1099 EXPECT_FALSE(drag_drop_controller_
->drag_canceled_
);
1100 EXPECT_EQ(2, drag_drop_controller_
->num_drag_updates_
);
1101 EXPECT_TRUE(drag_drop_controller_
->drop_received_
);
1102 EXPECT_EQ(base::UTF8ToUTF16("I am being dragged"),
1103 drag_drop_controller_
->drag_string_
);
1104 EXPECT_EQ(1, drag_view
->num_drag_enters_
);
1105 EXPECT_EQ(2, drag_view
->num_drag_updates_
);
1106 EXPECT_EQ(1, drag_view
->num_drops_
);
1107 EXPECT_EQ(0, drag_view
->num_drag_exits_
);
1108 EXPECT_TRUE(drag_view
->drag_done_received_
);