1 // Copyright (c) 2013 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/shell.h" 8 #include "ash/test/ash_test_base.h" 9 #include "base/bind.h" 10 #include "base/message_loop/message_loop.h" 11 #include "base/path_service.h" 12 #include "base/strings/utf_string_conversions.h" 13 #include "ui/aura/window_event_dispatcher.h" 14 #include "ui/base/dragdrop/drag_drop_types.h" 15 #include "ui/base/resource/resource_bundle.h" 16 #include "ui/base/test/ui_controls.h" 17 #include "ui/base/ui_base_paths.h" 18 #include "ui/gl/gl_surface.h" 19 #include "ui/views/view.h" 20 #include "ui/views/widget/widget.h" 21 22 namespace ash { 23 namespace { 24 25 class DraggableView : public views::View { 26 public: 27 DraggableView() {} 28 virtual ~DraggableView() {} 29 30 // views::View overrides: 31 virtual int GetDragOperations(const gfx::Point& press_pt) OVERRIDE { 32 return ui::DragDropTypes::DRAG_MOVE; 33 } 34 virtual void WriteDragData(const gfx::Point& press_pt, 35 OSExchangeData* data)OVERRIDE { 36 data->SetString(base::UTF8ToUTF16("test")); 37 } 38 39 private: 40 DISALLOW_COPY_AND_ASSIGN(DraggableView); 41 }; 42 43 class TargetView : public views::View { 44 public: 45 TargetView() : dropped_(false) {} 46 virtual ~TargetView() {} 47 48 // views::View overrides: 49 virtual bool GetDropFormats( 50 int* formats, 51 std::set<OSExchangeData::CustomFormat>* custom_formats) OVERRIDE { 52 *formats = ui::OSExchangeData::STRING; 53 return true; 54 } 55 virtual bool AreDropTypesRequired() OVERRIDE { 56 return false; 57 } 58 virtual bool CanDrop(const OSExchangeData& data) OVERRIDE { 59 return true; 60 } 61 virtual int OnDragUpdated(const ui::DropTargetEvent& event) OVERRIDE { 62 return ui::DragDropTypes::DRAG_MOVE; 63 } 64 virtual int OnPerformDrop(const ui::DropTargetEvent& event) OVERRIDE { 65 dropped_ = true; 66 return ui::DragDropTypes::DRAG_MOVE; 67 } 68 69 bool dropped() const { return dropped_; } 70 71 private: 72 bool dropped_; 73 74 DISALLOW_COPY_AND_ASSIGN(TargetView); 75 }; 76 77 views::Widget* CreateWidget(views::View* contents_view, 78 const gfx::Rect& bounds) { 79 views::Widget* widget = new views::Widget; 80 views::Widget::InitParams params; 81 params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS; 82 params.accept_events = true; 83 params.context = Shell::GetPrimaryRootWindow(); 84 params.bounds = bounds; 85 widget->Init(params); 86 87 widget->SetContentsView(contents_view); 88 widget->Show(); 89 return widget; 90 } 91 92 void QuitLoop() { 93 base::MessageLoop::current()->Quit(); 94 } 95 96 void DragDropAcrossMultiDisplay_Step4() { 97 ui_controls::SendMouseEventsNotifyWhenDone( 98 ui_controls::LEFT, ui_controls::UP, 99 base::Bind(&QuitLoop)); 100 } 101 102 void DragDropAcrossMultiDisplay_Step3() { 103 // Move to the edge of the 1st display so that the mouse 104 // is moved to 2nd display by ash. 105 ui_controls::SendMouseMoveNotifyWhenDone( 106 399, 10, 107 base::Bind(&DragDropAcrossMultiDisplay_Step4)); 108 } 109 110 void DragDropAcrossMultiDisplay_Step2() { 111 ui_controls::SendMouseMoveNotifyWhenDone( 112 20, 10, 113 base::Bind(&DragDropAcrossMultiDisplay_Step3)); 114 } 115 116 void DragDropAcrossMultiDisplay_Step1() { 117 ui_controls::SendMouseEventsNotifyWhenDone( 118 ui_controls::LEFT, ui_controls::DOWN, 119 base::Bind(&DragDropAcrossMultiDisplay_Step2)); 120 } 121 122 } // namespace 123 124 class DragDropTest : public test::AshTestBase { 125 public: 126 DragDropTest() {} 127 virtual ~DragDropTest() {} 128 129 virtual void SetUp() OVERRIDE { 130 gfx::GLSurface::InitializeOneOffForTests(); 131 132 ui::RegisterPathProvider(); 133 ui::ResourceBundle::InitSharedInstanceWithLocale( 134 "en-US", NULL, ui::ResourceBundle::LOAD_COMMON_RESOURCES); 135 base::FilePath resources_pack_path; 136 PathService::Get(base::DIR_MODULE, &resources_pack_path); 137 resources_pack_path = 138 resources_pack_path.Append(FILE_PATH_LITERAL("resources.pak")); 139 ResourceBundle::GetSharedInstance().AddDataPackFromPath( 140 resources_pack_path, ui::SCALE_FACTOR_NONE); 141 142 test::AshTestBase::SetUp(); 143 } 144 }; 145 146 #if !defined(OS_CHROMEOS) 147 #define MAYBE_DragDropAcrossMultiDisplay DISABLED_DragDropAcrossMultiDisplay 148 #else 149 #define MAYBE_DragDropAcrossMultiDisplay DragDropAcrossMultiDisplay 150 #endif 151 152 // Test if the mouse gets moved properly to another display 153 // during drag & drop operation. 154 TEST_F(DragDropTest, MAYBE_DragDropAcrossMultiDisplay) { 155 if (!SupportsMultipleDisplays()) 156 return; 157 158 UpdateDisplay("400x400,400x400"); 159 aura::Window::Windows root_windows = 160 Shell::GetInstance()->GetAllRootWindows(); 161 views::View* draggable_view = new DraggableView(); 162 draggable_view->set_drag_controller(NULL); 163 draggable_view->SetBounds(0, 0, 100, 100); 164 views::Widget* source = 165 CreateWidget(draggable_view, gfx::Rect(0, 0, 100, 100)); 166 167 TargetView* target_view = new TargetView(); 168 target_view->SetBounds(0, 0, 100, 100); 169 views::Widget* target = 170 CreateWidget(target_view, gfx::Rect(400, 0, 100, 100)); 171 172 // Make sure they're on the different root windows. 173 EXPECT_EQ(root_windows[0], source->GetNativeView()->GetRootWindow()); 174 EXPECT_EQ(root_windows[1], target->GetNativeView()->GetRootWindow()); 175 176 ui_controls::SendMouseMoveNotifyWhenDone( 177 10, 10, base::Bind(&DragDropAcrossMultiDisplay_Step1)); 178 179 base::MessageLoop::current()->Run(); 180 181 EXPECT_TRUE(target_view->dropped()); 182 183 source->Close(); 184 target->Close(); 185 } 186 187 } // namespace ash 188