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