drag_drop_controller_unittest.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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.
4
5#include "ash/drag_drop/drag_drop_controller.h"
6
7#include "ash/drag_drop/drag_drop_tracker.h"
8#include "ash/drag_drop/drag_image_view.h"
9#include "ash/shell.h"
10#include "ash/test/ash_test_base.h"
11#include "base/command_line.h"
12#include "base/location.h"
13#include "base/strings/utf_string_conversions.h"
14#include "ui/aura/client/capture_client.h"
15#include "ui/aura/root_window.h"
16#include "ui/aura/test/event_generator.h"
17#include "ui/base/clipboard/clipboard.h"
18#include "ui/base/clipboard/scoped_clipboard_writer.h"
19#include "ui/base/dragdrop/drag_drop_types.h"
20#include "ui/base/dragdrop/drag_utils.h"
21#include "ui/base/dragdrop/os_exchange_data.h"
22#include "ui/base/ui_base_switches.h"
23#include "ui/events/event.h"
24#include "ui/events/event_utils.h"
25#include "ui/events/gestures/gesture_types.h"
26#include "ui/gfx/animation/linear_animation.h"
27#include "ui/gfx/image/image_skia_rep.h"
28#include "ui/views/test/test_views_delegate.h"
29#include "ui/views/view.h"
30#include "ui/views/views_delegate.h"
31#include "ui/views/widget/native_widget_aura.h"
32#include "ui/views/widget/native_widget_delegate.h"
33#include "ui/views/widget/widget.h"
34
35namespace ash {
36namespace test {
37
38namespace {
39
40// A simple view that makes sure RunShellDrag is invoked on mouse drag.
41class DragTestView : public views::View {
42 public:
43  DragTestView() : views::View() {
44    Reset();
45  }
46
47  void Reset() {
48    num_drag_enters_ = 0;
49    num_drag_exits_ = 0;
50    num_drag_updates_ = 0;
51    num_drops_ = 0;
52    drag_done_received_ = false;
53    long_tap_received_ = false;
54  }
55
56  int VerticalDragThreshold() {
57    return views::View::GetVerticalDragThreshold();
58  }
59
60  int HorizontalDragThreshold() {
61    return views::View::GetHorizontalDragThreshold();
62  }
63
64  int num_drag_enters_;
65  int num_drag_exits_;
66  int num_drag_updates_;
67  int num_drops_;
68  bool drag_done_received_;
69  bool long_tap_received_;
70
71 private:
72  // View overrides:
73  virtual int GetDragOperations(const gfx::Point& press_pt) OVERRIDE {
74    return ui::DragDropTypes::DRAG_COPY;
75  }
76
77  virtual void WriteDragData(const gfx::Point& p,
78                             OSExchangeData* data) OVERRIDE {
79    data->SetString(UTF8ToUTF16("I am being dragged"));
80    gfx::ImageSkiaRep image_rep(gfx::Size(10, 20), 1.0f);
81    gfx::ImageSkia image_skia(image_rep);
82
83    drag_utils::SetDragImageOnDataObject(
84        image_skia, image_skia.size(), gfx::Vector2d(), data);
85  }
86
87  virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
88    return true;
89  }
90
91  virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
92    if (event->type() == ui::ET_GESTURE_LONG_TAP)
93      long_tap_received_ = true;
94    return;
95  }
96
97  virtual bool GetDropFormats(
98      int* formats,
99      std::set<OSExchangeData::CustomFormat>* custom_formats) OVERRIDE {
100    *formats = ui::OSExchangeData::STRING;
101    return true;
102  }
103
104  virtual bool CanDrop(const OSExchangeData& data) OVERRIDE {
105    return true;
106  }
107
108  virtual void OnDragEntered(const ui::DropTargetEvent& event) OVERRIDE {
109    num_drag_enters_++;
110  }
111
112  virtual int OnDragUpdated(const ui::DropTargetEvent& event) OVERRIDE {
113    num_drag_updates_++;
114    return ui::DragDropTypes::DRAG_COPY;
115  }
116
117  virtual void OnDragExited() OVERRIDE {
118    num_drag_exits_++;
119  }
120
121  virtual int OnPerformDrop(const ui::DropTargetEvent& event) OVERRIDE {
122    num_drops_++;
123    return ui::DragDropTypes::DRAG_COPY;
124  }
125
126  virtual void OnDragDone() OVERRIDE {
127    drag_done_received_ = true;
128  }
129
130  DISALLOW_COPY_AND_ASSIGN(DragTestView);
131};
132
133class CompletableLinearAnimation : public gfx::LinearAnimation {
134 public:
135  CompletableLinearAnimation(int duration,
136                             int frame_rate,
137                             gfx::AnimationDelegate* delegate)
138      : gfx::LinearAnimation(duration, frame_rate, delegate),
139        duration_(duration) {
140  }
141
142  void Complete() {
143    Step(start_time() + base::TimeDelta::FromMilliseconds(duration_));
144  }
145
146 private:
147  int duration_;
148};
149
150class TestDragDropController : public internal::DragDropController {
151 public:
152  TestDragDropController() : internal::DragDropController() {
153    Reset();
154  }
155
156  void Reset() {
157    drag_start_received_ = false;
158    num_drag_updates_ = 0;
159    drop_received_ = false;
160    drag_canceled_ = false;
161    drag_string_.clear();
162  }
163
164  virtual int StartDragAndDrop(
165      const ui::OSExchangeData& data,
166      aura::RootWindow* root_window,
167      aura::Window* source_window,
168      const gfx::Point& location,
169      int operation,
170      ui::DragDropTypes::DragEventSource source) OVERRIDE {
171    drag_start_received_ = true;
172    data.GetString(&drag_string_);
173    return DragDropController::StartDragAndDrop(
174        data, root_window, source_window, location, operation, source);
175  }
176
177  virtual void DragUpdate(aura::Window* target,
178                          const ui::LocatedEvent& event) OVERRIDE {
179    DragDropController::DragUpdate(target, event);
180    num_drag_updates_++;
181  }
182
183  virtual void Drop(aura::Window* target,
184                    const ui::LocatedEvent& event) OVERRIDE {
185    DragDropController::Drop(target, event);
186    drop_received_ = true;
187  }
188
189  virtual void DragCancel() OVERRIDE {
190    DragDropController::DragCancel();
191    drag_canceled_ = true;
192  }
193
194  virtual gfx::LinearAnimation* CreateCancelAnimation(
195      int duration,
196      int frame_rate,
197      gfx::AnimationDelegate* delegate) OVERRIDE {
198    return new CompletableLinearAnimation(duration, frame_rate, delegate);
199  }
200
201  virtual void DoDragCancel(int animation_duration_ms) OVERRIDE {
202    DragDropController::DoDragCancel(animation_duration_ms);
203    drag_canceled_ = true;
204  }
205
206  bool drag_start_received_;
207  int num_drag_updates_;
208  bool drop_received_;
209  bool drag_canceled_;
210  base::string16 drag_string_;
211
212 private:
213  DISALLOW_COPY_AND_ASSIGN(TestDragDropController);
214};
215
216class TestNativeWidgetAura : public views::NativeWidgetAura {
217 public:
218  explicit TestNativeWidgetAura(views::internal::NativeWidgetDelegate* delegate)
219      : NativeWidgetAura(delegate),
220        check_if_capture_lost_(false) {
221  }
222
223  void set_check_if_capture_lost(bool value) {
224    check_if_capture_lost_ = value;
225  }
226
227  virtual void OnCaptureLost() OVERRIDE {
228    DCHECK(!check_if_capture_lost_);
229    views::NativeWidgetAura::OnCaptureLost();
230  }
231
232 private:
233  bool check_if_capture_lost_;
234
235  DISALLOW_COPY_AND_ASSIGN(TestNativeWidgetAura);
236};
237
238// TODO(sky): this is for debugging, remove when track down failure.
239void SetCheckIfCaptureLost(views::Widget* widget, bool value) {
240  // On Windows, the DCHECK triggers when running on bot or locally through RDP,
241  // but not when logged in locally.
242#if !defined(OS_WIN)
243  static_cast<TestNativeWidgetAura*>(widget->native_widget())->
244      set_check_if_capture_lost(value);
245#endif
246}
247
248views::Widget* CreateNewWidget() {
249  views::Widget* widget = new views::Widget;
250  views::Widget::InitParams params;
251  params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
252  params.accept_events = true;
253  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
254  params.parent = Shell::GetPrimaryRootWindow();
255  params.child = true;
256  params.native_widget = new TestNativeWidgetAura(widget);
257  widget->Init(params);
258  widget->Show();
259  return widget;
260}
261
262void AddViewToWidgetAndResize(views::Widget* widget, views::View* view) {
263  if (!widget->GetContentsView()) {
264    views::View* contents_view = new views::View;
265    widget->SetContentsView(contents_view);
266  }
267
268  views::View* contents_view = widget->GetContentsView();
269  contents_view->AddChildView(view);
270  view->SetBounds(contents_view->width(), 0, 100, 100);
271  gfx::Rect contents_view_bounds = contents_view->bounds();
272  contents_view_bounds.Union(view->bounds());
273  contents_view->SetBoundsRect(contents_view_bounds);
274  widget->SetBounds(contents_view_bounds);
275}
276
277void DispatchGesture(ui::EventType gesture_type, gfx::Point location) {
278  ui::GestureEvent gesture_event(
279      gesture_type,
280      location.x(),
281      location.y(),
282      0,
283      ui::EventTimeForNow(),
284      ui::GestureEventDetails(gesture_type, 0, 0),
285      1);
286  Shell::GetPrimaryRootWindow()->DispatchGestureEvent(&gesture_event);
287}
288
289bool IsGestureEventType(ui::EventType type) {
290  switch (type) {
291    case ui::ET_GESTURE_SCROLL_BEGIN:
292    case ui::ET_GESTURE_SCROLL_END:
293    case ui::ET_GESTURE_SCROLL_UPDATE:
294    case ui::ET_GESTURE_TAP:
295    case ui::ET_GESTURE_TAP_CANCEL:
296    case ui::ET_GESTURE_TAP_DOWN:
297    case ui::ET_GESTURE_BEGIN:
298    case ui::ET_GESTURE_END:
299    case ui::ET_GESTURE_TWO_FINGER_TAP:
300    case ui::ET_GESTURE_PINCH_BEGIN:
301    case ui::ET_GESTURE_PINCH_END:
302    case ui::ET_GESTURE_PINCH_UPDATE:
303    case ui::ET_GESTURE_LONG_PRESS:
304    case ui::ET_GESTURE_LONG_TAP:
305    case ui::ET_GESTURE_MULTIFINGER_SWIPE:
306    case ui::ET_SCROLL_FLING_CANCEL:
307    case ui::ET_SCROLL_FLING_START:
308      return true;
309    default:
310      break;
311  }
312  return false;
313}
314
315}  // namespace
316
317class DragDropControllerTest : public AshTestBase {
318 public:
319  DragDropControllerTest() : AshTestBase() {}
320  virtual ~DragDropControllerTest() {}
321
322  virtual void SetUp() OVERRIDE {
323    AshTestBase::SetUp();
324    drag_drop_controller_.reset(new TestDragDropController);
325    drag_drop_controller_->set_should_block_during_drag_drop(false);
326    aura::client::SetDragDropClient(Shell::GetPrimaryRootWindow(),
327                                    drag_drop_controller_.get());
328    views_delegate_.reset(new views::TestViewsDelegate);
329  }
330
331  virtual void TearDown() OVERRIDE {
332    aura::client::SetDragDropClient(Shell::GetPrimaryRootWindow(), NULL);
333    drag_drop_controller_.reset();
334    AshTestBase::TearDown();
335  }
336
337  void UpdateDragData(ui::OSExchangeData* data) {
338    drag_drop_controller_->drag_data_ = data;
339  }
340
341  aura::Window* GetDragWindow() {
342    return drag_drop_controller_->drag_window_;
343  }
344
345  aura::Window* GetDragSourceWindow() {
346    return drag_drop_controller_->drag_source_window_;
347  }
348
349  void SetDragSourceWindow(aura::Window* drag_source_window) {
350    drag_drop_controller_->drag_source_window_ = drag_source_window;
351    drag_source_window->AddObserver(drag_drop_controller_.get());
352  }
353
354  aura::Window* GetDragImageWindow() {
355    return drag_drop_controller_->drag_image_.get() ?
356        drag_drop_controller_->drag_image_->GetWidget()->GetNativeWindow() :
357        NULL;
358  }
359
360  internal::DragDropTracker* drag_drop_tracker() {
361    return drag_drop_controller_->drag_drop_tracker_.get();
362  }
363
364  void CompleteCancelAnimation() {
365    CompletableLinearAnimation* animation =
366        static_cast<CompletableLinearAnimation*>(
367            drag_drop_controller_->cancel_animation_.get());
368    animation->Complete();
369  }
370
371 protected:
372  scoped_ptr<TestDragDropController> drag_drop_controller_;
373  scoped_ptr<views::TestViewsDelegate> views_delegate_;
374
375 private:
376  DISALLOW_COPY_AND_ASSIGN(DragDropControllerTest);
377};
378
379// TODO(win_aura) http://crbug.com/154081
380#if defined(OS_WIN)
381#define MAYBE_DragDropInSingleViewTest DISABLED_DragDropInSingleViewTest
382#else
383#define MAYBE_DragDropInSingleViewTest DragDropInSingleViewTest
384#endif
385TEST_F(DragDropControllerTest, MAYBE_DragDropInSingleViewTest) {
386  scoped_ptr<views::Widget> widget(CreateNewWidget());
387  DragTestView* drag_view = new DragTestView;
388  AddViewToWidgetAndResize(widget.get(), drag_view);
389  ui::OSExchangeData data;
390  data.SetString(UTF8ToUTF16("I am being dragged"));
391  aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
392                                       widget->GetNativeView());
393  generator.PressLeftButton();
394
395  int num_drags = 17;
396  SetCheckIfCaptureLost(widget.get(), true);
397  for (int i = 0; i < num_drags; ++i) {
398    // Because we are not doing a blocking drag and drop, the original
399    // OSDragExchangeData object is lost as soon as we return from the drag
400    // initiation in DragDropController::StartDragAndDrop(). Hence we set the
401    // drag_data_ to a fake drag data object that we created.
402    if (i > 0)
403      UpdateDragData(&data);
404    // 7 comes from views::View::GetVerticalDragThreshold()).
405    if (i >= 7)
406      SetCheckIfCaptureLost(widget.get(), false);
407
408    generator.MoveMouseBy(0, 1);
409
410    // Execute any scheduled draws to process deferred mouse events.
411    RunAllPendingInMessageLoop();
412  }
413
414  generator.ReleaseLeftButton();
415
416  EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
417  EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
418      drag_drop_controller_->num_drag_updates_);
419  EXPECT_TRUE(drag_drop_controller_->drop_received_);
420  EXPECT_EQ(UTF8ToUTF16("I am being dragged"),
421      drag_drop_controller_->drag_string_);
422
423  EXPECT_EQ(1, drag_view->num_drag_enters_);
424  EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
425      drag_view->num_drag_updates_);
426  EXPECT_EQ(1, drag_view->num_drops_);
427  EXPECT_EQ(0, drag_view->num_drag_exits_);
428  EXPECT_TRUE(drag_view->drag_done_received_);
429}
430
431TEST_F(DragDropControllerTest, DragDropWithZeroDragUpdates) {
432  scoped_ptr<views::Widget> widget(CreateNewWidget());
433  DragTestView* drag_view = new DragTestView;
434  AddViewToWidgetAndResize(widget.get(), drag_view);
435  ui::OSExchangeData data;
436  data.SetString(UTF8ToUTF16("I am being dragged"));
437  aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
438                                       widget->GetNativeView());
439  generator.PressLeftButton();
440
441  int num_drags = drag_view->VerticalDragThreshold() + 1;
442  for (int i = 0; i < num_drags; ++i) {
443    // Because we are not doing a blocking drag and drop, the original
444    // OSDragExchangeData object is lost as soon as we return from the drag
445    // initiation in DragDropController::StartDragAndDrop(). Hence we set the
446    // drag_data_ to a fake drag data object that we created.
447    if (i > 0)
448      UpdateDragData(&data);
449    generator.MoveMouseBy(0, 1);
450  }
451
452  UpdateDragData(&data);
453
454  generator.ReleaseLeftButton();
455
456  EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
457  EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold() + 1,
458      drag_drop_controller_->num_drag_updates_);
459  EXPECT_TRUE(drag_drop_controller_->drop_received_);
460
461  EXPECT_EQ(1, drag_view->num_drag_enters_);
462  EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold() + 1,
463      drag_view->num_drag_updates_);
464  EXPECT_EQ(1, drag_view->num_drops_);
465  EXPECT_EQ(0, drag_view->num_drag_exits_);
466  EXPECT_TRUE(drag_view->drag_done_received_);
467}
468
469// TODO(win_aura) http://crbug.com/154081
470#if defined(OS_WIN)
471#define MAYBE_DragDropInMultipleViewsSingleWidgetTest DISABLED_DragDropInMultipleViewsSingleWidgetTest
472#else
473#define MAYBE_DragDropInMultipleViewsSingleWidgetTest DragDropInMultipleViewsSingleWidgetTest
474#endif
475TEST_F(DragDropControllerTest, MAYBE_DragDropInMultipleViewsSingleWidgetTest) {
476  scoped_ptr<views::Widget> widget(CreateNewWidget());
477  DragTestView* drag_view1 = new DragTestView;
478  AddViewToWidgetAndResize(widget.get(), drag_view1);
479  DragTestView* drag_view2 = new DragTestView;
480  AddViewToWidgetAndResize(widget.get(), drag_view2);
481
482  ui::OSExchangeData data;
483  data.SetString(UTF8ToUTF16("I am being dragged"));
484
485  aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
486  generator.MoveMouseRelativeTo(widget->GetNativeView(),
487                                drag_view1->bounds().CenterPoint());
488  generator.PressLeftButton();
489
490  int num_drags = drag_view1->width();
491  for (int i = 0; i < num_drags; ++i) {
492    // Because we are not doing a blocking drag and drop, the original
493    // OSDragExchangeData object is lost as soon as we return from the drag
494    // initiation in DragDropController::StartDragAndDrop(). Hence we set the
495    // drag_data_ to a fake drag data object that we created.
496    if (i > 0)
497      UpdateDragData(&data);
498    generator.MoveMouseBy(1, 0);
499
500    // Execute any scheduled draws to process deferred mouse events.
501    RunAllPendingInMessageLoop();
502  }
503
504  generator.ReleaseLeftButton();
505
506  EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
507  EXPECT_EQ(num_drags - 1 - drag_view1->HorizontalDragThreshold(),
508      drag_drop_controller_->num_drag_updates_);
509  EXPECT_TRUE(drag_drop_controller_->drop_received_);
510  EXPECT_EQ(UTF8ToUTF16("I am being dragged"),
511      drag_drop_controller_->drag_string_);
512
513  EXPECT_EQ(1, drag_view1->num_drag_enters_);
514  int num_expected_updates = drag_view1->bounds().width() -
515      drag_view1->bounds().CenterPoint().x() - 2;
516  EXPECT_EQ(num_expected_updates - drag_view1->HorizontalDragThreshold(),
517      drag_view1->num_drag_updates_);
518  EXPECT_EQ(0, drag_view1->num_drops_);
519  EXPECT_EQ(1, drag_view1->num_drag_exits_);
520  EXPECT_TRUE(drag_view1->drag_done_received_);
521
522  EXPECT_EQ(1, drag_view2->num_drag_enters_);
523  num_expected_updates = num_drags - num_expected_updates - 1;
524  EXPECT_EQ(num_expected_updates, drag_view2->num_drag_updates_);
525  EXPECT_EQ(1, drag_view2->num_drops_);
526  EXPECT_EQ(0, drag_view2->num_drag_exits_);
527  EXPECT_FALSE(drag_view2->drag_done_received_);
528}
529
530// TODO(win_aura) http://crbug.com/154081
531#if defined(OS_WIN)
532#define MAYBE_DragDropInMultipleViewsMultipleWidgetsTest DISABLED_DragDropInMultipleViewsMultipleWidgetsTest
533#else
534#define MAYBE_DragDropInMultipleViewsMultipleWidgetsTest DragDropInMultipleViewsMultipleWidgetsTest
535#endif
536TEST_F(DragDropControllerTest, MAYBE_DragDropInMultipleViewsMultipleWidgetsTest) {
537  scoped_ptr<views::Widget> widget1(CreateNewWidget());
538  DragTestView* drag_view1 = new DragTestView;
539  AddViewToWidgetAndResize(widget1.get(), drag_view1);
540  scoped_ptr<views::Widget> widget2(CreateNewWidget());
541  DragTestView* drag_view2 = new DragTestView;
542  AddViewToWidgetAndResize(widget2.get(), drag_view2);
543  gfx::Rect widget1_bounds = widget1->GetClientAreaBoundsInScreen();
544  gfx::Rect widget2_bounds = widget2->GetClientAreaBoundsInScreen();
545  widget2->SetBounds(gfx::Rect(widget1_bounds.width(), 0,
546      widget2_bounds.width(), widget2_bounds.height()));
547
548  ui::OSExchangeData data;
549  data.SetString(UTF8ToUTF16("I am being dragged"));
550
551  aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
552                                       widget1->GetNativeView());
553  generator.PressLeftButton();
554
555  int num_drags = drag_view1->width();
556  for (int i = 0; i < num_drags; ++i) {
557    // Because we are not doing a blocking drag and drop, the original
558    // OSDragExchangeData object is lost as soon as we return from the drag
559    // initiation in DragDropController::StartDragAndDrop(). Hence we set the
560    // drag_data_ to a fake drag data object that we created.
561    if (i > 0)
562      UpdateDragData(&data);
563    generator.MoveMouseBy(1, 0);
564
565    // Execute any scheduled draws to process deferred mouse events.
566    RunAllPendingInMessageLoop();
567  }
568
569  generator.ReleaseLeftButton();
570
571  EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
572  EXPECT_EQ(num_drags - 1 - drag_view1->HorizontalDragThreshold(),
573      drag_drop_controller_->num_drag_updates_);
574  EXPECT_TRUE(drag_drop_controller_->drop_received_);
575  EXPECT_EQ(UTF8ToUTF16("I am being dragged"),
576      drag_drop_controller_->drag_string_);
577
578  EXPECT_EQ(1, drag_view1->num_drag_enters_);
579  int num_expected_updates = drag_view1->bounds().width() -
580      drag_view1->bounds().CenterPoint().x() - 2;
581  EXPECT_EQ(num_expected_updates - drag_view1->HorizontalDragThreshold(),
582      drag_view1->num_drag_updates_);
583  EXPECT_EQ(0, drag_view1->num_drops_);
584  EXPECT_EQ(1, drag_view1->num_drag_exits_);
585  EXPECT_TRUE(drag_view1->drag_done_received_);
586
587  EXPECT_EQ(1, drag_view2->num_drag_enters_);
588  num_expected_updates = num_drags - num_expected_updates - 1;
589  EXPECT_EQ(num_expected_updates, drag_view2->num_drag_updates_);
590  EXPECT_EQ(1, drag_view2->num_drops_);
591  EXPECT_EQ(0, drag_view2->num_drag_exits_);
592  EXPECT_FALSE(drag_view2->drag_done_received_);
593}
594
595// TODO(win_aura) http://crbug.com/154081
596#if defined(OS_WIN)
597#define MAYBE_ViewRemovedWhileInDragDropTest DISABLED_ViewRemovedWhileInDragDropTest
598#else
599#define MAYBE_ViewRemovedWhileInDragDropTest ViewRemovedWhileInDragDropTest
600#endif
601TEST_F(DragDropControllerTest, MAYBE_ViewRemovedWhileInDragDropTest) {
602  scoped_ptr<views::Widget> widget(CreateNewWidget());
603  scoped_ptr<DragTestView> drag_view(new DragTestView);
604  AddViewToWidgetAndResize(widget.get(), drag_view.get());
605  gfx::Point point = gfx::Rect(drag_view->bounds()).CenterPoint();
606  ui::OSExchangeData data;
607  data.SetString(UTF8ToUTF16("I am being dragged"));
608
609  aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
610  generator.MoveMouseToCenterOf(widget->GetNativeView());
611  generator.PressLeftButton();
612
613  int num_drags_1 = 17;
614  for (int i = 0; i < num_drags_1; ++i) {
615    // Because we are not doing a blocking drag and drop, the original
616    // OSDragExchangeData object is lost as soon as we return from the drag
617    // initiation in DragDropController::StartDragAndDrop(). Hence we set the
618    // drag_data_ to a fake drag data object that we created.
619    if (i > 0)
620      UpdateDragData(&data);
621    generator.MoveMouseBy(0, 1);
622
623    // Execute any scheduled draws to process deferred mouse events.
624    RunAllPendingInMessageLoop();
625  }
626
627  drag_view->parent()->RemoveChildView(drag_view.get());
628  // View has been removed. We will not get any of the following drag updates.
629  int num_drags_2 = 23;
630  for (int i = 0; i < num_drags_2; ++i) {
631    UpdateDragData(&data);
632    generator.MoveMouseBy(0, 1);
633
634    // Execute any scheduled draws to process deferred mouse events.
635    RunAllPendingInMessageLoop();
636  }
637
638  generator.ReleaseLeftButton();
639
640  EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
641  EXPECT_EQ(num_drags_1 + num_drags_2 - 1 - drag_view->VerticalDragThreshold(),
642      drag_drop_controller_->num_drag_updates_);
643  EXPECT_TRUE(drag_drop_controller_->drop_received_);
644  EXPECT_EQ(UTF8ToUTF16("I am being dragged"),
645      drag_drop_controller_->drag_string_);
646
647  EXPECT_EQ(1, drag_view->num_drag_enters_);
648  EXPECT_EQ(num_drags_1 - 1 - drag_view->VerticalDragThreshold(),
649      drag_view->num_drag_updates_);
650  EXPECT_EQ(0, drag_view->num_drops_);
651  EXPECT_EQ(0, drag_view->num_drag_exits_);
652  EXPECT_TRUE(drag_view->drag_done_received_);
653}
654
655TEST_F(DragDropControllerTest, DragLeavesClipboardAloneTest) {
656  ui::Clipboard* cb = ui::Clipboard::GetForCurrentThread();
657  std::string clip_str("I am on the clipboard");
658  {
659    // We first copy some text to the clipboard.
660    ui::ScopedClipboardWriter scw(cb, ui::CLIPBOARD_TYPE_COPY_PASTE);
661    scw.WriteText(ASCIIToUTF16(clip_str));
662  }
663  EXPECT_TRUE(cb->IsFormatAvailable(ui::Clipboard::GetPlainTextFormatType(),
664      ui::CLIPBOARD_TYPE_COPY_PASTE));
665
666  scoped_ptr<views::Widget> widget(CreateNewWidget());
667  DragTestView* drag_view = new DragTestView;
668  AddViewToWidgetAndResize(widget.get(), drag_view);
669
670  aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
671                                       widget->GetNativeView());
672  ui::OSExchangeData data;
673  std::string data_str("I am being dragged");
674  data.SetString(ASCIIToUTF16(data_str));
675
676  generator.PressLeftButton();
677  generator.MoveMouseBy(0, drag_view->VerticalDragThreshold() + 1);
678
679  // Execute any scheduled draws to process deferred mouse events.
680  RunAllPendingInMessageLoop();
681
682  // Verify the clipboard contents haven't changed
683  std::string result;
684  EXPECT_TRUE(cb->IsFormatAvailable(ui::Clipboard::GetPlainTextFormatType(),
685      ui::CLIPBOARD_TYPE_COPY_PASTE));
686  cb->ReadAsciiText(ui::CLIPBOARD_TYPE_COPY_PASTE, &result);
687  EXPECT_EQ(clip_str, result);
688  // Destory the clipboard here because ash doesn't delete it.
689  // crbug.com/158150.
690  ui::Clipboard::DestroyClipboardForCurrentThread();
691}
692
693TEST_F(DragDropControllerTest, WindowDestroyedDuringDragDrop) {
694  scoped_ptr<views::Widget> widget(CreateNewWidget());
695  DragTestView* drag_view = new DragTestView;
696  AddViewToWidgetAndResize(widget.get(), drag_view);
697  aura::Window* window = widget->GetNativeView();
698
699  ui::OSExchangeData data;
700  data.SetString(UTF8ToUTF16("I am being dragged"));
701  aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
702                                       widget->GetNativeView());
703  generator.PressLeftButton();
704
705  int num_drags = 17;
706  for (int i = 0; i < num_drags; ++i) {
707    // Because we are not doing a blocking drag and drop, the original
708    // OSDragExchangeData object is lost as soon as we return from the drag
709    // initiation in DragDropController::StartDragAndDrop(). Hence we set the
710    // drag_data_ to a fake drag data object that we created.
711    if (i > 0)
712      UpdateDragData(&data);
713    generator.MoveMouseBy(0, 1);
714
715    // Execute any scheduled draws to process deferred mouse events.
716    RunAllPendingInMessageLoop();
717
718    if (i > drag_view->VerticalDragThreshold())
719      EXPECT_EQ(window, GetDragWindow());
720  }
721
722  widget->CloseNow();
723  EXPECT_FALSE(GetDragWindow());
724
725  num_drags = 23;
726  for (int i = 0; i < num_drags; ++i) {
727    if (i > 0)
728      UpdateDragData(&data);
729    generator.MoveMouseBy(0, 1);
730    // We should not crash here.
731  }
732
733  generator.ReleaseLeftButton();
734
735  EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
736  EXPECT_TRUE(drag_drop_controller_->drop_received_);
737}
738
739TEST_F(DragDropControllerTest, SyntheticEventsDuringDragDrop) {
740  scoped_ptr<views::Widget> widget(CreateNewWidget());
741  DragTestView* drag_view = new DragTestView;
742  AddViewToWidgetAndResize(widget.get(), drag_view);
743  ui::OSExchangeData data;
744  data.SetString(UTF8ToUTF16("I am being dragged"));
745  aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
746                                       widget->GetNativeView());
747  generator.PressLeftButton();
748
749  int num_drags = 17;
750  for (int i = 0; i < num_drags; ++i) {
751    // Because we are not doing a blocking drag and drop, the original
752    // OSDragExchangeData object is lost as soon as we return from the drag
753    // initiation in DragDropController::StartDragAndDrop(). Hence we set the
754    // drag_data_ to a fake drag data object that we created.
755    if (i > 0)
756      UpdateDragData(&data);
757    generator.MoveMouseBy(0, 1);
758
759    // We send a unexpected mouse move event. Note that we cannot use
760    // EventGenerator since it implicitly turns these into mouse drag events.
761    // The DragDropController should simply ignore these events.
762    gfx::Point mouse_move_location = drag_view->bounds().CenterPoint();
763    ui::MouseEvent mouse_move(ui::ET_MOUSE_MOVED, mouse_move_location,
764                              mouse_move_location, 0);
765    Shell::GetPrimaryRootWindow()->AsRootWindowHostDelegate()->OnHostMouseEvent(
766        &mouse_move);
767  }
768
769  generator.ReleaseLeftButton();
770
771  EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
772  EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
773      drag_drop_controller_->num_drag_updates_);
774  EXPECT_TRUE(drag_drop_controller_->drop_received_);
775  EXPECT_EQ(UTF8ToUTF16("I am being dragged"),
776      drag_drop_controller_->drag_string_);
777
778  EXPECT_EQ(1, drag_view->num_drag_enters_);
779  EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
780      drag_view->num_drag_updates_);
781  EXPECT_EQ(1, drag_view->num_drops_);
782  EXPECT_EQ(0, drag_view->num_drag_exits_);
783  EXPECT_TRUE(drag_view->drag_done_received_);
784}
785
786// TODO(win_aura) http://crbug.com/154081
787#if defined(OS_WIN)
788#define MAYBE_PressingEscapeCancelsDragDrop DISABLED_PressingEscapeCancelsDragDrop
789#define MAYBE_CaptureLostCancelsDragDrop DISABLED_CaptureLostCancelsDragDrop
790#else
791#define MAYBE_PressingEscapeCancelsDragDrop PressingEscapeCancelsDragDrop
792#define MAYBE_CaptureLostCancelsDragDrop CaptureLostCancelsDragDrop
793#endif
794TEST_F(DragDropControllerTest, MAYBE_PressingEscapeCancelsDragDrop) {
795  scoped_ptr<views::Widget> widget(CreateNewWidget());
796  DragTestView* drag_view = new DragTestView;
797  AddViewToWidgetAndResize(widget.get(), drag_view);
798  ui::OSExchangeData data;
799  data.SetString(UTF8ToUTF16("I am being dragged"));
800  aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
801                                       widget->GetNativeView());
802  generator.PressLeftButton();
803
804  int num_drags = 17;
805  for (int i = 0; i < num_drags; ++i) {
806    // Because we are not doing a blocking drag and drop, the original
807    // OSDragExchangeData object is lost as soon as we return from the drag
808    // initiation in DragDropController::StartDragAndDrop(). Hence we set the
809    // drag_data_ to a fake drag data object that we created.
810    if (i > 0)
811      UpdateDragData(&data);
812    generator.MoveMouseBy(0, 1);
813
814    // Execute any scheduled draws to process deferred mouse events.
815    RunAllPendingInMessageLoop();
816  }
817
818  generator.PressKey(ui::VKEY_ESCAPE, 0);
819
820  EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
821  EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
822      drag_drop_controller_->num_drag_updates_);
823  EXPECT_FALSE(drag_drop_controller_->drop_received_);
824  EXPECT_TRUE(drag_drop_controller_->drag_canceled_);
825  EXPECT_EQ(UTF8ToUTF16("I am being dragged"),
826      drag_drop_controller_->drag_string_);
827
828  EXPECT_EQ(1, drag_view->num_drag_enters_);
829  EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
830      drag_view->num_drag_updates_);
831  EXPECT_EQ(0, drag_view->num_drops_);
832  EXPECT_EQ(1, drag_view->num_drag_exits_);
833  EXPECT_TRUE(drag_view->drag_done_received_);
834}
835
836TEST_F(DragDropControllerTest, MAYBE_CaptureLostCancelsDragDrop) {
837  scoped_ptr<views::Widget> widget(CreateNewWidget());
838  DragTestView* drag_view = new DragTestView;
839  AddViewToWidgetAndResize(widget.get(), drag_view);
840  ui::OSExchangeData data;
841  data.SetString(UTF8ToUTF16("I am being dragged"));
842  aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
843                                       widget->GetNativeView());
844  generator.PressLeftButton();
845
846  int num_drags = 17;
847  for (int i = 0; i < num_drags; ++i) {
848    // Because we are not doing a blocking drag and drop, the original
849    // OSDragExchangeData object is lost as soon as we return from the drag
850    // initiation in DragDropController::StartDragAndDrop(). Hence we set the
851    // drag_data_ to a fake drag data object that we created.
852    if (i > 0)
853      UpdateDragData(&data);
854    generator.MoveMouseBy(0, 1);
855
856    // Execute any scheduled draws to process deferred mouse events.
857    RunAllPendingInMessageLoop();
858  }
859  // Make sure the capture window won't handle mouse events.
860  aura::Window* capture_window = drag_drop_tracker()->capture_window();
861  ASSERT_TRUE(!!capture_window);
862  EXPECT_EQ("0x0", capture_window->bounds().size().ToString());
863  EXPECT_EQ(NULL,
864            capture_window->GetEventHandlerForPoint(gfx::Point()));
865  EXPECT_EQ(NULL,
866            capture_window->GetTopWindowContainingPoint(gfx::Point()));
867
868  aura::client::GetCaptureClient(widget->GetNativeView()->GetRootWindow())->
869      SetCapture(NULL);
870
871  EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
872  EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
873      drag_drop_controller_->num_drag_updates_);
874  EXPECT_FALSE(drag_drop_controller_->drop_received_);
875  EXPECT_TRUE(drag_drop_controller_->drag_canceled_);
876  EXPECT_EQ(UTF8ToUTF16("I am being dragged"),
877      drag_drop_controller_->drag_string_);
878
879  EXPECT_EQ(1, drag_view->num_drag_enters_);
880  EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
881      drag_view->num_drag_updates_);
882  EXPECT_EQ(0, drag_view->num_drops_);
883  EXPECT_EQ(1, drag_view->num_drag_exits_);
884  EXPECT_TRUE(drag_view->drag_done_received_);
885}
886
887TEST_F(DragDropControllerTest, TouchDragDropInMultipleWindows) {
888  CommandLine::ForCurrentProcess()->AppendSwitch(
889      switches::kEnableTouchDragDrop);
890  scoped_ptr<views::Widget> widget1(CreateNewWidget());
891  DragTestView* drag_view1 = new DragTestView;
892  AddViewToWidgetAndResize(widget1.get(), drag_view1);
893  scoped_ptr<views::Widget> widget2(CreateNewWidget());
894  DragTestView* drag_view2 = new DragTestView;
895  AddViewToWidgetAndResize(widget2.get(), drag_view2);
896  gfx::Rect widget1_bounds = widget1->GetClientAreaBoundsInScreen();
897  gfx::Rect widget2_bounds = widget2->GetClientAreaBoundsInScreen();
898  widget2->SetBounds(gfx::Rect(widget1_bounds.width(), 0,
899      widget2_bounds.width(), widget2_bounds.height()));
900
901  ui::OSExchangeData data;
902  data.SetString(UTF8ToUTF16("I am being dragged"));
903
904  aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
905                                       widget1->GetNativeView());
906  generator.PressTouch();
907  gfx::Point point = gfx::Rect(drag_view1->bounds()).CenterPoint();
908  DispatchGesture(ui::ET_GESTURE_LONG_PRESS, point);
909  // Because we are not doing a blocking drag and drop, the original
910  // OSDragExchangeData object is lost as soon as we return from the drag
911  // initiation in DragDropController::StartDragAndDrop(). Hence we set the
912  // drag_data_ to a fake drag data object that we created.
913  UpdateDragData(&data);
914  gfx::Point gesture_location = point;
915  int num_drags = drag_view1->width();
916  for (int i = 0; i < num_drags; ++i) {
917    gesture_location.Offset(1, 0);
918    DispatchGesture(ui::ET_GESTURE_SCROLL_UPDATE, gesture_location);
919
920    // Execute any scheduled draws to process deferred mouse events.
921    RunAllPendingInMessageLoop();
922  }
923
924  DispatchGesture(ui::ET_GESTURE_SCROLL_END, gesture_location);
925
926  EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
927  EXPECT_EQ(num_drags, drag_drop_controller_->num_drag_updates_);
928  EXPECT_TRUE(drag_drop_controller_->drop_received_);
929  EXPECT_EQ(UTF8ToUTF16("I am being dragged"),
930      drag_drop_controller_->drag_string_);
931
932  EXPECT_EQ(1, drag_view1->num_drag_enters_);
933  int num_expected_updates = drag_view1->bounds().width() -
934      drag_view1->bounds().CenterPoint().x() - 1;
935  EXPECT_EQ(num_expected_updates, drag_view1->num_drag_updates_);
936  EXPECT_EQ(0, drag_view1->num_drops_);
937  EXPECT_EQ(1, drag_view1->num_drag_exits_);
938  EXPECT_TRUE(drag_view1->drag_done_received_);
939
940  EXPECT_EQ(1, drag_view2->num_drag_enters_);
941  num_expected_updates = num_drags - num_expected_updates;
942  EXPECT_EQ(num_expected_updates, drag_view2->num_drag_updates_);
943  EXPECT_EQ(1, drag_view2->num_drops_);
944  EXPECT_EQ(0, drag_view2->num_drag_exits_);
945  EXPECT_FALSE(drag_view2->drag_done_received_);
946}
947
948TEST_F(DragDropControllerTest, TouchDragDropCancelsOnLongTap) {
949  CommandLine::ForCurrentProcess()->AppendSwitch(
950      switches::kEnableTouchDragDrop);
951  scoped_ptr<views::Widget> widget(CreateNewWidget());
952  DragTestView* drag_view = new DragTestView;
953  AddViewToWidgetAndResize(widget.get(), drag_view);
954  aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
955                                       widget->GetNativeView());
956
957  generator.PressTouch();
958  gfx::Point point = gfx::Rect(drag_view->bounds()).CenterPoint();
959  DispatchGesture(ui::ET_GESTURE_LONG_PRESS, point);
960  DispatchGesture(ui::ET_GESTURE_LONG_TAP, point);
961
962  EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
963  EXPECT_TRUE(drag_drop_controller_->drag_canceled_);
964  EXPECT_EQ(0, drag_drop_controller_->num_drag_updates_);
965  EXPECT_FALSE(drag_drop_controller_->drop_received_);
966  EXPECT_EQ(UTF8ToUTF16("I am being dragged"),
967            drag_drop_controller_->drag_string_);
968  EXPECT_EQ(0, drag_view->num_drag_enters_);
969  EXPECT_EQ(0, drag_view->num_drops_);
970  EXPECT_EQ(0, drag_view->num_drag_exits_);
971  EXPECT_TRUE(drag_view->drag_done_received_);
972}
973
974TEST_F(DragDropControllerTest, TouchDragDropLongTapGestureIsForwarded) {
975  CommandLine::ForCurrentProcess()->AppendSwitch(
976      switches::kEnableTouchDragDrop);
977  scoped_ptr<views::Widget> widget(CreateNewWidget());
978  DragTestView* drag_view = new DragTestView;
979  AddViewToWidgetAndResize(widget.get(), drag_view);
980  aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
981                                       widget->GetNativeView());
982
983  generator.PressTouch();
984  gfx::Point point = gfx::Rect(drag_view->bounds()).CenterPoint();
985  DispatchGesture(ui::ET_GESTURE_LONG_PRESS, point);
986
987  // Since we are not running inside a nested loop, the |drag_source_window_|
988  // will get destroyed immediately. Hence we reassign it.
989  EXPECT_EQ(NULL, GetDragSourceWindow());
990  SetDragSourceWindow(widget->GetNativeView());
991  EXPECT_FALSE(drag_view->long_tap_received_);
992  DispatchGesture(ui::ET_GESTURE_LONG_TAP, point);
993  CompleteCancelAnimation();
994  EXPECT_TRUE(drag_view->long_tap_received_);
995}
996
997namespace {
998
999class DragImageWindowObserver : public aura::WindowObserver {
1000 public:
1001  virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
1002    window_location_on_destroying_ = window->GetBoundsInScreen().origin();
1003  }
1004
1005  gfx::Point window_location_on_destroying() const {
1006    return window_location_on_destroying_;
1007  }
1008
1009 public:
1010  gfx::Point window_location_on_destroying_;
1011};
1012
1013}
1014
1015// Verifies the drag image moves back to the position where drag is started
1016// across displays when drag is cancelled.
1017TEST_F(DragDropControllerTest, DragCancelAcrossDisplays) {
1018  if (!SupportsMultipleDisplays())
1019    return;
1020
1021  UpdateDisplay("400x400,400x400");
1022  Shell::RootWindowList root_windows =
1023      Shell::GetInstance()->GetAllRootWindows();
1024  for (Shell::RootWindowList::iterator iter = root_windows.begin();
1025       iter != root_windows.end(); ++iter) {
1026    aura::client::SetDragDropClient(*iter, drag_drop_controller_.get());
1027  }
1028
1029  ui::OSExchangeData data;
1030  data.SetString(UTF8ToUTF16("I am being dragged"));
1031  {
1032    scoped_ptr<views::Widget> widget(CreateNewWidget());
1033    aura::Window* window = widget->GetNativeWindow();
1034    drag_drop_controller_->StartDragAndDrop(
1035        data,
1036        window->GetRootWindow(),
1037        window,
1038        gfx::Point(5, 5),
1039        ui::DragDropTypes::DRAG_MOVE,
1040        ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
1041
1042    DragImageWindowObserver observer;
1043    ASSERT_TRUE(GetDragImageWindow());
1044    GetDragImageWindow()->AddObserver(&observer);
1045
1046    {
1047      ui::MouseEvent e(ui::ET_MOUSE_DRAGGED,
1048                       gfx::Point(200, 0),
1049                       gfx::Point(200, 0),
1050                       ui::EF_NONE);
1051      drag_drop_controller_->DragUpdate(window, e);
1052    }
1053    {
1054      ui::MouseEvent e(ui::ET_MOUSE_DRAGGED,
1055                       gfx::Point(600, 0),
1056                       gfx::Point(600, 0),
1057                       ui::EF_NONE);
1058      drag_drop_controller_->DragUpdate(window, e);
1059    }
1060
1061    drag_drop_controller_->DragCancel();
1062    CompleteCancelAnimation();
1063
1064    EXPECT_EQ("5,5", observer.window_location_on_destroying().ToString());
1065  }
1066
1067  {
1068    scoped_ptr<views::Widget> widget(CreateNewWidget());
1069    aura::Window* window = widget->GetNativeWindow();
1070    drag_drop_controller_->StartDragAndDrop(
1071        data,
1072        window->GetRootWindow(),
1073        window,
1074        gfx::Point(405, 405),
1075        ui::DragDropTypes::DRAG_MOVE,
1076        ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
1077    DragImageWindowObserver observer;
1078    ASSERT_TRUE(GetDragImageWindow());
1079    GetDragImageWindow()->AddObserver(&observer);
1080
1081    {
1082      ui::MouseEvent e(ui::ET_MOUSE_DRAGGED,
1083                       gfx::Point(600, 0),
1084                       gfx::Point(600, 0),
1085                       ui::EF_NONE);
1086      drag_drop_controller_->DragUpdate(window, e);
1087    }
1088    {
1089      ui::MouseEvent e(ui::ET_MOUSE_DRAGGED,
1090                       gfx::Point(200, 0),
1091                       gfx::Point(200, 0),
1092                       ui::EF_NONE);
1093      drag_drop_controller_->DragUpdate(window, e);
1094    }
1095
1096    drag_drop_controller_->DragCancel();
1097    CompleteCancelAnimation();
1098
1099    EXPECT_EQ("405,405", observer.window_location_on_destroying().ToString());
1100  }
1101  for (Shell::RootWindowList::iterator iter = root_windows.begin();
1102       iter != root_windows.end(); ++iter) {
1103    aura::client::SetDragDropClient(*iter, NULL);
1104  }
1105}
1106
1107}  // namespace test
1108}  // namespace aura
1109