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 "chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.h"
6
7 #include <algorithm>
8
9 #include "ash/wm/window_state.h"
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "base/command_line.h"
13 #include "base/run_loop.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "chrome/browser/chrome_notification_types.h"
16 #include "chrome/browser/ui/browser.h"
17 #include "chrome/browser/ui/browser_commands.h"
18 #include "chrome/browser/ui/browser_iterator.h"
19 #include "chrome/browser/ui/browser_list.h"
20 #include "chrome/browser/ui/host_desktop.h"
21 #include "chrome/browser/ui/tabs/tab_strip_model.h"
22 #include "chrome/browser/ui/views/frame/browser_view.h"
23 #include "chrome/browser/ui/views/frame/native_browser_frame_factory.h"
24 #include "chrome/browser/ui/views/tabs/tab.h"
25 #include "chrome/browser/ui/views/tabs/tab_drag_controller.h"
26 #include "chrome/browser/ui/views/tabs/tab_strip.h"
27 #include "chrome/test/base/in_process_browser_test.h"
28 #include "chrome/test/base/interactive_test_utils.h"
29 #include "chrome/test/base/ui_test_utils.h"
30 #include "content/public/browser/notification_details.h"
31 #include "content/public/browser/notification_observer.h"
32 #include "content/public/browser/notification_service.h"
33 #include "content/public/browser/notification_source.h"
34 #include "content/public/browser/web_contents.h"
35 #include "ui/base/test/ui_controls.h"
36 #include "ui/gfx/screen.h"
37 #include "ui/views/view.h"
38 #include "ui/views/widget/widget.h"
39
40 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
41 #include "chrome/browser/ui/views/frame/desktop_browser_frame_aura.h"
42 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
43 #endif
44
45 #if defined(USE_ASH)
46 #include "ash/display/display_controller.h"
47 #include "ash/display/display_manager.h"
48 #include "ash/shell.h"
49 #include "ash/test/cursor_manager_test_api.h"
50 #include "ash/wm/coordinate_conversion.h"
51 #include "ash/wm/window_util.h"
52 #include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
53 #include "ui/aura/client/screen_position_client.h"
54 #include "ui/aura/test/event_generator.h"
55 #include "ui/aura/window_event_dispatcher.h"
56 #endif
57
58 using content::WebContents;
59
60 namespace test {
61
62 namespace {
63
64 const char kTabDragControllerInteractiveUITestUserDataKey[] =
65 "TabDragControllerInteractiveUITestUserData";
66
67 class TabDragControllerInteractiveUITestUserData
68 : public base::SupportsUserData::Data {
69 public:
TabDragControllerInteractiveUITestUserData(int id)70 explicit TabDragControllerInteractiveUITestUserData(int id) : id_(id) {}
~TabDragControllerInteractiveUITestUserData()71 virtual ~TabDragControllerInteractiveUITestUserData() {}
id()72 int id() { return id_; }
73
74 private:
75 int id_;
76 };
77
78 } // namespace
79
80 class QuitDraggingObserver : public content::NotificationObserver {
81 public:
QuitDraggingObserver()82 QuitDraggingObserver() {
83 registrar_.Add(this, chrome::NOTIFICATION_TAB_DRAG_LOOP_DONE,
84 content::NotificationService::AllSources());
85 }
86
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)87 virtual void Observe(int type,
88 const content::NotificationSource& source,
89 const content::NotificationDetails& details) OVERRIDE {
90 DCHECK_EQ(chrome::NOTIFICATION_TAB_DRAG_LOOP_DONE, type);
91 base::MessageLoopForUI::current()->Quit();
92 delete this;
93 }
94
95 private:
~QuitDraggingObserver()96 virtual ~QuitDraggingObserver() {}
97
98 content::NotificationRegistrar registrar_;
99
100 DISALLOW_COPY_AND_ASSIGN(QuitDraggingObserver);
101 };
102
GetCenterInScreenCoordinates(const views::View * view)103 gfx::Point GetCenterInScreenCoordinates(const views::View* view) {
104 gfx::Point center(view->width() / 2, view->height() / 2);
105 views::View::ConvertPointToScreen(view, ¢er);
106 return center;
107 }
108
SetID(WebContents * web_contents,int id)109 void SetID(WebContents* web_contents, int id) {
110 web_contents->SetUserData(&kTabDragControllerInteractiveUITestUserDataKey,
111 new TabDragControllerInteractiveUITestUserData(id));
112 }
113
ResetIDs(TabStripModel * model,int start)114 void ResetIDs(TabStripModel* model, int start) {
115 for (int i = 0; i < model->count(); ++i)
116 SetID(model->GetWebContentsAt(i), start + i);
117 }
118
IDString(TabStripModel * model)119 std::string IDString(TabStripModel* model) {
120 std::string result;
121 for (int i = 0; i < model->count(); ++i) {
122 if (i != 0)
123 result += " ";
124 WebContents* contents = model->GetWebContentsAt(i);
125 TabDragControllerInteractiveUITestUserData* user_data =
126 static_cast<TabDragControllerInteractiveUITestUserData*>(
127 contents->GetUserData(
128 &kTabDragControllerInteractiveUITestUserDataKey));
129 if (user_data)
130 result += base::IntToString(user_data->id());
131 else
132 result += "?";
133 }
134 return result;
135 }
136
137 // Creates a listener that quits the message loop when no longer dragging.
QuitWhenNotDraggingImpl()138 void QuitWhenNotDraggingImpl() {
139 new QuitDraggingObserver(); // QuitDraggingObserver deletes itself.
140 }
141
GetTabStripForBrowser(Browser * browser)142 TabStrip* GetTabStripForBrowser(Browser* browser) {
143 BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
144 return static_cast<TabStrip*>(browser_view->tabstrip());
145 }
146
147 } // namespace test
148
149 using test::GetCenterInScreenCoordinates;
150 using test::SetID;
151 using test::ResetIDs;
152 using test::IDString;
153 using test::GetTabStripForBrowser;
154
TabDragControllerTest()155 TabDragControllerTest::TabDragControllerTest()
156 : native_browser_list(BrowserList::GetInstance(
157 chrome::HOST_DESKTOP_TYPE_NATIVE)) {
158 }
159
~TabDragControllerTest()160 TabDragControllerTest::~TabDragControllerTest() {
161 }
162
StopAnimating(TabStrip * tab_strip)163 void TabDragControllerTest::StopAnimating(TabStrip* tab_strip) {
164 tab_strip->StopAnimating(true);
165 }
166
AddTabAndResetBrowser(Browser * browser)167 void TabDragControllerTest::AddTabAndResetBrowser(Browser* browser) {
168 AddBlankTabAndShow(browser);
169 StopAnimating(GetTabStripForBrowser(browser));
170 ResetIDs(browser->tab_strip_model(), 0);
171 }
172
CreateAnotherWindowBrowserAndRelayout()173 Browser* TabDragControllerTest::CreateAnotherWindowBrowserAndRelayout() {
174 // Create another browser.
175 Browser* browser2 = CreateBrowser(browser()->profile());
176 ResetIDs(browser2->tab_strip_model(), 100);
177
178 // Resize the two windows so they're right next to each other.
179 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
180 browser()->window()->GetNativeWindow()).work_area();
181 gfx::Size half_size =
182 gfx::Size(work_area.width() / 3 - 10, work_area.height() / 2 - 10);
183 browser()->window()->SetBounds(gfx::Rect(work_area.origin(), half_size));
184 browser2->window()->SetBounds(gfx::Rect(
185 work_area.x() + half_size.width(), work_area.y(),
186 half_size.width(), half_size.height()));
187 return browser2;
188 }
189
190 namespace {
191
192 enum InputSource {
193 INPUT_SOURCE_MOUSE = 0,
194 INPUT_SOURCE_TOUCH = 1
195 };
196
GetDetachY(TabStrip * tab_strip)197 int GetDetachY(TabStrip* tab_strip) {
198 return std::max(TabDragController::kTouchVerticalDetachMagnetism,
199 TabDragController::kVerticalDetachMagnetism) +
200 tab_strip->height() + 1;
201 }
202
GetIsDragged(Browser * browser)203 bool GetIsDragged(Browser* browser) {
204 #if !defined(USE_ASH) || defined(OS_WIN) // TODO(win_ash)
205 return false;
206 #else
207 return ash::wm::GetWindowState(browser->window()->GetNativeWindow())->
208 is_dragged();
209 #endif
210 }
211
212 } // namespace
213
214 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
215 class ScreenEventGeneratorDelegate : public aura::test::EventGeneratorDelegate {
216 public:
ScreenEventGeneratorDelegate(aura::Window * root_window)217 explicit ScreenEventGeneratorDelegate(aura::Window* root_window)
218 : root_window_(root_window) {}
~ScreenEventGeneratorDelegate()219 virtual ~ScreenEventGeneratorDelegate() {}
220
221 // EventGeneratorDelegate overrides:
GetHostAt(const gfx::Point & point) const222 virtual aura::WindowTreeHost* GetHostAt(
223 const gfx::Point& point) const OVERRIDE {
224 return root_window_->GetHost();
225 }
226
GetScreenPositionClient(const aura::Window * window) const227 virtual aura::client::ScreenPositionClient* GetScreenPositionClient(
228 const aura::Window* window) const OVERRIDE {
229 return aura::client::GetScreenPositionClient(root_window_);
230 }
231
232 private:
233 aura::Window* root_window_;
234
235 DISALLOW_COPY_AND_ASSIGN(ScreenEventGeneratorDelegate);
236 };
237
238 #endif
239
240 #if !defined(OS_CHROMEOS)
241
242 // Following classes verify a crash scenario. Specifically on Windows when focus
243 // changes it can trigger capture being lost. This was causing a crash in tab
244 // dragging as it wasn't set up to handle this scenario. These classes
245 // synthesize this scenario.
246
247 // Allows making ClearNativeFocus() invoke ReleaseCapture().
248 class TestDesktopBrowserFrameAura : public DesktopBrowserFrameAura {
249 public:
TestDesktopBrowserFrameAura(BrowserFrame * browser_frame,BrowserView * browser_view)250 TestDesktopBrowserFrameAura(
251 BrowserFrame* browser_frame,
252 BrowserView* browser_view)
253 : DesktopBrowserFrameAura(browser_frame, browser_view),
254 release_capture_(false) {}
~TestDesktopBrowserFrameAura()255 virtual ~TestDesktopBrowserFrameAura() {}
256
ReleaseCaptureOnNextClear()257 void ReleaseCaptureOnNextClear() {
258 release_capture_ = true;
259 }
260
ClearNativeFocus()261 virtual void ClearNativeFocus() OVERRIDE {
262 views::DesktopNativeWidgetAura::ClearNativeFocus();
263 if (release_capture_) {
264 release_capture_ = false;
265 GetWidget()->ReleaseCapture();
266 }
267 }
268
269 private:
270 // If true ReleaseCapture() is invoked in ClearNativeFocus().
271 bool release_capture_;
272
273 DISALLOW_COPY_AND_ASSIGN(TestDesktopBrowserFrameAura);
274 };
275
276 // Factory for creating a TestDesktopBrowserFrameAura.
277 class TestNativeBrowserFrameFactory : public NativeBrowserFrameFactory {
278 public:
TestNativeBrowserFrameFactory()279 TestNativeBrowserFrameFactory() {}
~TestNativeBrowserFrameFactory()280 virtual ~TestNativeBrowserFrameFactory() {}
281
Create(BrowserFrame * browser_frame,BrowserView * browser_view)282 virtual NativeBrowserFrame* Create(
283 BrowserFrame* browser_frame,
284 BrowserView* browser_view) OVERRIDE {
285 return new TestDesktopBrowserFrameAura(browser_frame, browser_view);
286 }
287
288 private:
289 DISALLOW_COPY_AND_ASSIGN(TestNativeBrowserFrameFactory);
290 };
291
292 class TabDragCaptureLostTest : public TabDragControllerTest {
293 public:
TabDragCaptureLostTest()294 TabDragCaptureLostTest() {
295 NativeBrowserFrameFactory::Set(new TestNativeBrowserFrameFactory);
296 }
297
298 private:
299 DISALLOW_COPY_AND_ASSIGN(TabDragCaptureLostTest);
300 };
301
302 // See description above for details.
IN_PROC_BROWSER_TEST_F(TabDragCaptureLostTest,ReleaseCaptureOnDrag)303 IN_PROC_BROWSER_TEST_F(TabDragCaptureLostTest, ReleaseCaptureOnDrag) {
304 AddTabAndResetBrowser(browser());
305
306 TabStrip* tab_strip = GetTabStripForBrowser(browser());
307 gfx::Point tab_1_center(GetCenterInScreenCoordinates(tab_strip->tab_at(1)));
308 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_1_center) &&
309 ui_test_utils::SendMouseEventsSync(
310 ui_controls::LEFT, ui_controls::DOWN));
311 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
312 TestDesktopBrowserFrameAura* frame =
313 static_cast<TestDesktopBrowserFrameAura*>(
314 BrowserView::GetBrowserViewForBrowser(browser())->GetWidget()->
315 native_widget_private());
316 // Invoke ReleaseCaptureOnDrag() so that when the drag happens and focus
317 // changes capture is released and the drag cancels.
318 frame->ReleaseCaptureOnNextClear();
319 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center));
320 EXPECT_FALSE(tab_strip->IsDragSessionActive());
321 }
322
IN_PROC_BROWSER_TEST_F(TabDragControllerTest,GestureEndShouldEndDragTest)323 IN_PROC_BROWSER_TEST_F(TabDragControllerTest, GestureEndShouldEndDragTest) {
324 AddTabAndResetBrowser(browser());
325
326 TabStrip* tab_strip = GetTabStripForBrowser(browser());
327
328 Tab* tab1 = tab_strip->tab_at(1);
329 gfx::Point tab_1_center(tab1->width() / 2, tab1->height() / 2);
330
331 ui::GestureEvent gesture_begin(ui::ET_GESTURE_BEGIN, tab_1_center.x(),
332 tab_1_center.x(), 0, base::TimeDelta(),
333 ui::GestureEventDetails(ui::ET_GESTURE_BEGIN, 0.0f, 0.0f), 0);
334 tab_strip->MaybeStartDrag(tab1, gesture_begin,
335 tab_strip->GetSelectionModel());
336 EXPECT_TRUE(TabDragController::IsActive());
337
338 ui::GestureEvent gesture_end(ui::ET_GESTURE_END, tab_1_center.x(),
339 tab_1_center.x(), 0, base::TimeDelta(),
340 ui::GestureEventDetails(ui::ET_GESTURE_END, 0.0f, 0.0f), 0);
341 tab_strip->OnGestureEvent(&gesture_end);
342 EXPECT_FALSE(TabDragController::IsActive());
343 EXPECT_FALSE(tab_strip->IsDragSessionActive());
344 }
345
346 #endif
347
348 class DetachToBrowserTabDragControllerTest
349 : public TabDragControllerTest,
350 public ::testing::WithParamInterface<const char*> {
351 public:
DetachToBrowserTabDragControllerTest()352 DetachToBrowserTabDragControllerTest() {}
353
SetUpOnMainThread()354 virtual void SetUpOnMainThread() OVERRIDE {
355 #if defined(OS_CHROMEOS)
356 event_generator_.reset(new aura::test::EventGenerator(
357 ash::Shell::GetPrimaryRootWindow()));
358 #endif
359 }
360
input_source() const361 InputSource input_source() const {
362 return strstr(GetParam(), "mouse") ?
363 INPUT_SOURCE_MOUSE : INPUT_SOURCE_TOUCH;
364 }
365
366 // Set root window from a point in screen coordinates
SetEventGeneratorRootWindow(const gfx::Point & point)367 void SetEventGeneratorRootWindow(const gfx::Point& point) {
368 if (input_source() == INPUT_SOURCE_MOUSE)
369 return;
370 #if defined(OS_CHROMEOS)
371 event_generator_.reset(new aura::test::EventGenerator(
372 new ScreenEventGeneratorDelegate(ash::wm::GetRootWindowAt(point))));
373 #endif
374 }
375
376 // The following methods update one of the mouse or touch input depending upon
377 // the InputSource.
PressInput(const gfx::Point & location)378 bool PressInput(const gfx::Point& location) {
379 if (input_source() == INPUT_SOURCE_MOUSE) {
380 return ui_test_utils::SendMouseMoveSync(location) &&
381 ui_test_utils::SendMouseEventsSync(
382 ui_controls::LEFT, ui_controls::DOWN);
383 }
384 #if defined(OS_CHROMEOS)
385 event_generator_->set_current_location(location);
386 event_generator_->PressTouch();
387 #else
388 NOTREACHED();
389 #endif
390 return true;
391 }
392
PressInput2()393 bool PressInput2() {
394 // Second touch input is only used for touch sequence tests.
395 EXPECT_EQ(INPUT_SOURCE_TOUCH, input_source());
396 #if defined(OS_CHROMEOS)
397 event_generator_->set_current_location(
398 event_generator_->current_location());
399 event_generator_->PressTouchId(1);
400 #else
401 NOTREACHED();
402 #endif
403 return true;
404 }
405
DragInputTo(const gfx::Point & location)406 bool DragInputTo(const gfx::Point& location) {
407 if (input_source() == INPUT_SOURCE_MOUSE)
408 return ui_test_utils::SendMouseMoveSync(location);
409 #if defined(OS_CHROMEOS)
410 event_generator_->MoveTouch(location);
411 #else
412 NOTREACHED();
413 #endif
414 return true;
415 }
416
DragInputToAsync(const gfx::Point & location)417 bool DragInputToAsync(const gfx::Point& location) {
418 if (input_source() == INPUT_SOURCE_MOUSE)
419 return ui_controls::SendMouseMove(location.x(), location.y());
420 #if defined(OS_CHROMEOS)
421 event_generator_->MoveTouch(location);
422 #else
423 NOTREACHED();
424 #endif
425 return true;
426 }
427
DragInputToNotifyWhenDone(int x,int y,const base::Closure & task)428 bool DragInputToNotifyWhenDone(int x,
429 int y,
430 const base::Closure& task) {
431 if (input_source() == INPUT_SOURCE_MOUSE)
432 return ui_controls::SendMouseMoveNotifyWhenDone(x, y, task);
433 #if defined(OS_CHROMEOS)
434 base::MessageLoop::current()->PostTask(FROM_HERE, task);
435 event_generator_->MoveTouch(gfx::Point(x, y));
436 #else
437 NOTREACHED();
438 #endif
439 return true;
440 }
441
DragInputToDelayedNotifyWhenDone(int x,int y,const base::Closure & task,base::TimeDelta delay)442 bool DragInputToDelayedNotifyWhenDone(int x,
443 int y,
444 const base::Closure& task,
445 base::TimeDelta delay) {
446 if (input_source() == INPUT_SOURCE_MOUSE)
447 return ui_controls::SendMouseMoveNotifyWhenDone(x, y, task);
448 #if defined(OS_CHROMEOS)
449 base::MessageLoop::current()->PostDelayedTask(FROM_HERE, task, delay);
450 event_generator_->MoveTouch(gfx::Point(x, y));
451 #else
452 NOTREACHED();
453 #endif
454 return true;
455 }
456
DragInput2ToNotifyWhenDone(int x,int y,const base::Closure & task)457 bool DragInput2ToNotifyWhenDone(int x,
458 int y,
459 const base::Closure& task) {
460 if (input_source() == INPUT_SOURCE_MOUSE)
461 return ui_controls::SendMouseMoveNotifyWhenDone(x, y, task);
462 #if defined(OS_CHROMEOS)
463 base::MessageLoop::current()->PostTask(FROM_HERE, task);
464 event_generator_->MoveTouchId(gfx::Point(x, y), 1);
465 #else
466 NOTREACHED();
467 #endif
468 return true;
469 }
470
ReleaseInput()471 bool ReleaseInput() {
472 if (input_source() == INPUT_SOURCE_MOUSE) {
473 return ui_test_utils::SendMouseEventsSync(
474 ui_controls::LEFT, ui_controls::UP);
475 }
476 #if defined(OS_CHROMEOS)
477 event_generator_->ReleaseTouch();
478 #else
479 NOTREACHED();
480 #endif
481 return true;
482 }
483
ReleaseInput2()484 bool ReleaseInput2() {
485 if (input_source() == INPUT_SOURCE_MOUSE) {
486 return ui_test_utils::SendMouseEventsSync(
487 ui_controls::LEFT, ui_controls::UP);
488 }
489 #if defined(OS_CHROMEOS)
490 event_generator_->ReleaseTouchId(1);
491 #else
492 NOTREACHED();
493 #endif
494 return true;
495 }
496
ReleaseMouseAsync()497 bool ReleaseMouseAsync() {
498 return input_source() == INPUT_SOURCE_MOUSE &&
499 ui_controls::SendMouseEvents(ui_controls::LEFT, ui_controls::UP);
500 }
501
QuitWhenNotDragging()502 void QuitWhenNotDragging() {
503 if (input_source() == INPUT_SOURCE_MOUSE) {
504 // Schedule observer to quit message loop when done dragging. This has to
505 // be async so the message loop can run.
506 test::QuitWhenNotDraggingImpl();
507 base::MessageLoop::current()->Run();
508 } else {
509 // Touch events are sync, so we know we're not in a drag session. But some
510 // tests rely on the browser fully closing, which is async. So, run all
511 // pending tasks.
512 base::RunLoop run_loop;
513 run_loop.RunUntilIdle();
514 }
515 }
516
AddBlankTabAndShow(Browser * browser)517 void AddBlankTabAndShow(Browser* browser) {
518 InProcessBrowserTest::AddBlankTabAndShow(browser);
519 }
520
browser() const521 Browser* browser() const { return InProcessBrowserTest::browser(); }
522
523 private:
524 #if defined(OS_CHROMEOS)
525 scoped_ptr<aura::test::EventGenerator> event_generator_;
526 #endif
527
528 DISALLOW_COPY_AND_ASSIGN(DetachToBrowserTabDragControllerTest);
529 };
530
531 // Creates a browser with two tabs, drags the second to the first.
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,DragInSameWindow)532 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, DragInSameWindow) {
533 // TODO(sky): this won't work with touch as it requires a long press.
534 if (input_source() == INPUT_SOURCE_TOUCH) {
535 VLOG(1) << "Test is DISABLED for touch input.";
536 return;
537 }
538
539 AddTabAndResetBrowser(browser());
540
541 TabStrip* tab_strip = GetTabStripForBrowser(browser());
542 TabStripModel* model = browser()->tab_strip_model();
543
544 gfx::Point tab_1_center(GetCenterInScreenCoordinates(tab_strip->tab_at(1)));
545 ASSERT_TRUE(PressInput(tab_1_center));
546 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
547 ASSERT_TRUE(DragInputTo(tab_0_center));
548 ASSERT_TRUE(ReleaseInput());
549 EXPECT_EQ("1 0", IDString(model));
550 EXPECT_FALSE(TabDragController::IsActive());
551 EXPECT_FALSE(tab_strip->IsDragSessionActive());
552
553 // The tab strip should no longer have capture because the drag was ended and
554 // mouse/touch was released.
555 EXPECT_FALSE(tab_strip->GetWidget()->HasCapture());
556 }
557
558 namespace {
559
560 // Invoked from the nested message loop.
DragToSeparateWindowStep2(DetachToBrowserTabDragControllerTest * test,TabStrip * not_attached_tab_strip,TabStrip * target_tab_strip)561 void DragToSeparateWindowStep2(DetachToBrowserTabDragControllerTest* test,
562 TabStrip* not_attached_tab_strip,
563 TabStrip* target_tab_strip) {
564 ASSERT_FALSE(not_attached_tab_strip->IsDragSessionActive());
565 ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
566 ASSERT_TRUE(TabDragController::IsActive());
567
568 // Drag to target_tab_strip. This should stop the nested loop from dragging
569 // the window.
570 gfx::Point target_point(target_tab_strip->width() -1,
571 target_tab_strip->height() / 2);
572 views::View::ConvertPointToScreen(target_tab_strip, &target_point);
573 ASSERT_TRUE(test->DragInputToAsync(target_point));
574 }
575
576 } // namespace
577
578 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
579 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
580 // compositor. crbug.com/331924
581 #define MAYBE_DragToSeparateWindow DISABLED_DragToSeparateWindow
582 #else
583 #define MAYBE_DragToSeparateWindow DragToSeparateWindow
584 #endif
585 // Creates two browsers, drags from first into second.
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,MAYBE_DragToSeparateWindow)586 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
587 MAYBE_DragToSeparateWindow) {
588 TabStrip* tab_strip = GetTabStripForBrowser(browser());
589
590 // Add another tab to browser().
591 AddTabAndResetBrowser(browser());
592
593 // Create another browser.
594 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
595 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
596
597 // Move to the first tab and drag it enough so that it detaches, but not
598 // enough that it attaches to browser2.
599 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
600 ASSERT_TRUE(PressInput(tab_0_center));
601 ASSERT_TRUE(DragInputToNotifyWhenDone(
602 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
603 base::Bind(&DragToSeparateWindowStep2,
604 this, tab_strip, tab_strip2)));
605 QuitWhenNotDragging();
606
607 // Should now be attached to tab_strip2.
608 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
609 ASSERT_FALSE(tab_strip->IsDragSessionActive());
610 ASSERT_TRUE(TabDragController::IsActive());
611 EXPECT_FALSE(GetIsDragged(browser()));
612
613 // Release mouse or touch, stopping the drag session.
614 ASSERT_TRUE(ReleaseInput());
615 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
616 ASSERT_FALSE(tab_strip->IsDragSessionActive());
617 ASSERT_FALSE(TabDragController::IsActive());
618 EXPECT_EQ("100 0", IDString(browser2->tab_strip_model()));
619 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
620 EXPECT_FALSE(GetIsDragged(browser2));
621
622 // Both windows should not be maximized
623 EXPECT_FALSE(browser()->window()->IsMaximized());
624 EXPECT_FALSE(browser2->window()->IsMaximized());
625
626 // The tab strip should no longer have capture because the drag was ended and
627 // mouse/touch was released.
628 EXPECT_FALSE(tab_strip->GetWidget()->HasCapture());
629 EXPECT_FALSE(tab_strip2->GetWidget()->HasCapture());
630 }
631
632 namespace {
633
DetachToOwnWindowStep2(DetachToBrowserTabDragControllerTest * test)634 void DetachToOwnWindowStep2(DetachToBrowserTabDragControllerTest* test) {
635 if (test->input_source() == INPUT_SOURCE_TOUCH)
636 ASSERT_TRUE(test->ReleaseInput());
637 }
638
639 #if defined(OS_CHROMEOS)
IsWindowPositionManaged(aura::Window * window)640 bool IsWindowPositionManaged(aura::Window* window) {
641 return ash::wm::GetWindowState(window)->window_position_managed();
642 }
HasUserChangedWindowPositionOrSize(aura::Window * window)643 bool HasUserChangedWindowPositionOrSize(aura::Window* window) {
644 return ash::wm::GetWindowState(window)->bounds_changed_by_user();
645 }
646 #else
IsWindowPositionManaged(gfx::NativeWindow window)647 bool IsWindowPositionManaged(gfx::NativeWindow window) {
648 return true;
649 }
HasUserChangedWindowPositionOrSize(gfx::NativeWindow window)650 bool HasUserChangedWindowPositionOrSize(gfx::NativeWindow window) {
651 return false;
652 }
653 #endif
654
655 } // namespace
656
657 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
658 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
659 // compositor. crbug.com/331924
660 #define MAYBE_DetachToOwnWindow DISABLED_DetachToOwnWindow
661 #else
662 #define MAYBE_DetachToOwnWindow DetachToOwnWindow
663 #endif
664 // Drags from browser to separate window and releases mouse.
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,MAYBE_DetachToOwnWindow)665 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
666 MAYBE_DetachToOwnWindow) {
667 const gfx::Rect initial_bounds(browser()->window()->GetBounds());
668 // Add another tab.
669 AddTabAndResetBrowser(browser());
670 TabStrip* tab_strip = GetTabStripForBrowser(browser());
671
672 // Move to the first tab and drag it enough so that it detaches.
673 gfx::Point tab_0_center(
674 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
675 ASSERT_TRUE(PressInput(tab_0_center));
676 ASSERT_TRUE(DragInputToNotifyWhenDone(
677 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
678 base::Bind(&DetachToOwnWindowStep2, this)));
679 if (input_source() == INPUT_SOURCE_MOUSE) {
680 ASSERT_TRUE(ReleaseMouseAsync());
681 QuitWhenNotDragging();
682 }
683
684 // Should no longer be dragging.
685 ASSERT_FALSE(tab_strip->IsDragSessionActive());
686 ASSERT_FALSE(TabDragController::IsActive());
687
688 // There should now be another browser.
689 ASSERT_EQ(2u, native_browser_list->size());
690 Browser* new_browser = native_browser_list->get(1);
691 ASSERT_TRUE(new_browser->window()->IsActive());
692 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
693 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
694
695 EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
696 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
697
698 // The bounds of the initial window should not have changed.
699 EXPECT_EQ(initial_bounds.ToString(),
700 browser()->window()->GetBounds().ToString());
701
702 EXPECT_FALSE(GetIsDragged(browser()));
703 EXPECT_FALSE(GetIsDragged(new_browser));
704 // After this both windows should still be manageable.
705 EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
706 EXPECT_TRUE(IsWindowPositionManaged(
707 new_browser->window()->GetNativeWindow()));
708
709 // Both windows should not be maximized
710 EXPECT_FALSE(browser()->window()->IsMaximized());
711 EXPECT_FALSE(new_browser->window()->IsMaximized());
712
713 // The tab strip should no longer have capture because the drag was ended and
714 // mouse/touch was released.
715 EXPECT_FALSE(tab_strip->GetWidget()->HasCapture());
716 EXPECT_FALSE(tab_strip2->GetWidget()->HasCapture());
717 }
718
719 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
720 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
721 // compositor. crbug.com/331924
722 #define MAYBE_DetachToOwnWindowFromMaximizedWindow \
723 DISABLED_DetachToOwnWindowFromMaximizedWindow
724 #else
725 #define MAYBE_DetachToOwnWindowFromMaximizedWindow \
726 DetachToOwnWindowFromMaximizedWindow
727 #endif
728 // Drags from browser to a separate window and releases mouse.
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,MAYBE_DetachToOwnWindowFromMaximizedWindow)729 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
730 MAYBE_DetachToOwnWindowFromMaximizedWindow) {
731 // Maximize the initial browser window.
732 browser()->window()->Maximize();
733 ASSERT_TRUE(browser()->window()->IsMaximized());
734
735 // Add another tab.
736 AddTabAndResetBrowser(browser());
737 TabStrip* tab_strip = GetTabStripForBrowser(browser());
738
739 // Move to the first tab and drag it enough so that it detaches.
740 gfx::Point tab_0_center(
741 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
742 ASSERT_TRUE(PressInput(tab_0_center));
743 ASSERT_TRUE(DragInputToNotifyWhenDone(
744 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
745 base::Bind(&DetachToOwnWindowStep2, this)));
746 if (input_source() == INPUT_SOURCE_MOUSE) {
747 ASSERT_TRUE(ReleaseMouseAsync());
748 QuitWhenNotDragging();
749 }
750
751 // Should no longer be dragging.
752 ASSERT_FALSE(tab_strip->IsDragSessionActive());
753 ASSERT_FALSE(TabDragController::IsActive());
754
755 // There should now be another browser.
756 ASSERT_EQ(2u, native_browser_list->size());
757 Browser* new_browser = native_browser_list->get(1);
758 ASSERT_TRUE(new_browser->window()->IsActive());
759 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
760 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
761
762 EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
763 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
764
765 // The bounds of the initial window should not have changed.
766 EXPECT_TRUE(browser()->window()->IsMaximized());
767
768 EXPECT_FALSE(GetIsDragged(browser()));
769 EXPECT_FALSE(GetIsDragged(new_browser));
770 // After this both windows should still be manageable.
771 EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
772 EXPECT_TRUE(IsWindowPositionManaged(
773 new_browser->window()->GetNativeWindow()));
774
775 // The new window should be maximized.
776 EXPECT_TRUE(new_browser->window()->IsMaximized());
777 }
778
779 // Deletes a tab being dragged before the user moved enough to start a drag.
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,DeleteBeforeStartedDragging)780 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
781 DeleteBeforeStartedDragging) {
782 // Add another tab.
783 AddTabAndResetBrowser(browser());
784 TabStrip* tab_strip = GetTabStripForBrowser(browser());
785
786 // Click on the first tab, but don't move it.
787 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
788 ASSERT_TRUE(PressInput(tab_0_center));
789
790 // Should be dragging.
791 ASSERT_TRUE(tab_strip->IsDragSessionActive());
792 ASSERT_TRUE(TabDragController::IsActive());
793
794 // Delete the tab being dragged.
795 delete browser()->tab_strip_model()->GetWebContentsAt(0);
796
797 // Should have canceled dragging.
798 ASSERT_FALSE(tab_strip->IsDragSessionActive());
799 ASSERT_FALSE(TabDragController::IsActive());
800
801 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
802 EXPECT_FALSE(GetIsDragged(browser()));
803 }
804
805 #if defined(OS_CHROMEOS)
806 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
807 // compositor. crbug.com/331924
808 #define MAYBE_DeleteTabWhileAttached DISABLED_DeleteTabWhileAttached
809 #else
810 #define MAYBE_DeleteTabWhileAttached DeleteTabWhileAttached
811 #endif
812 // Deletes a tab being dragged while still attached.
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,MAYBE_DeleteTabWhileAttached)813 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
814 MAYBE_DeleteTabWhileAttached) {
815 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
816 // compositor. crbug.com/331924
817 if (input_source() == INPUT_SOURCE_MOUSE) {
818 VLOG(1) << "Test is DISABLED for mouse input.";
819 return;
820 }
821
822 // Add another tab.
823 AddTabAndResetBrowser(browser());
824 TabStrip* tab_strip = GetTabStripForBrowser(browser());
825
826 // Click on the first tab and move it enough so that it starts dragging but is
827 // still attached.
828 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
829 ASSERT_TRUE(PressInput(tab_0_center));
830 ASSERT_TRUE(DragInputTo(
831 gfx::Point(tab_0_center.x() + 20, tab_0_center.y())));
832
833 // Should be dragging.
834 ASSERT_TRUE(tab_strip->IsDragSessionActive());
835 ASSERT_TRUE(TabDragController::IsActive());
836
837 // Delete the tab being dragged.
838 delete browser()->tab_strip_model()->GetWebContentsAt(0);
839
840 // Should have canceled dragging.
841 ASSERT_FALSE(tab_strip->IsDragSessionActive());
842 ASSERT_FALSE(TabDragController::IsActive());
843
844 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
845
846 EXPECT_FALSE(GetIsDragged(browser()));
847 }
848
849 namespace {
850
DeleteWhileDetachedStep2(WebContents * tab)851 void DeleteWhileDetachedStep2(WebContents* tab) {
852 delete tab;
853 }
854
855 } // namespace
856
857 #if defined(OS_CHROMEOS)
858 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
859 // compositor. crbug.com/331924
860 #define MAYBE_DeleteTabWhileDetached DISABLED_DeleteTabWhileDetached
861 #else
862 #define MAYBE_DeleteTabWhileDetached DeleteTabWhileDetached
863 #endif
864 // Deletes a tab being dragged after dragging a tab so that a new window is
865 // created.
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,MAYBE_DeleteTabWhileDetached)866 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
867 MAYBE_DeleteTabWhileDetached) {
868 // Add another tab.
869 AddTabAndResetBrowser(browser());
870 TabStrip* tab_strip = GetTabStripForBrowser(browser());
871
872 // Move to the first tab and drag it enough so that it detaches.
873 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
874 WebContents* to_delete =
875 browser()->tab_strip_model()->GetWebContentsAt(0);
876 ASSERT_TRUE(PressInput(tab_0_center));
877 ASSERT_TRUE(DragInputToNotifyWhenDone(
878 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
879 base::Bind(&DeleteWhileDetachedStep2, to_delete)));
880 QuitWhenNotDragging();
881
882 // Should not be dragging.
883 ASSERT_FALSE(tab_strip->IsDragSessionActive());
884 ASSERT_FALSE(TabDragController::IsActive());
885
886 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
887
888 EXPECT_FALSE(GetIsDragged(browser()));
889 }
890
891 namespace {
892
DeleteSourceDetachedStep2(WebContents * tab,const BrowserList * browser_list)893 void DeleteSourceDetachedStep2(WebContents* tab,
894 const BrowserList* browser_list) {
895 ASSERT_EQ(2u, browser_list->size());
896 Browser* new_browser = browser_list->get(1);
897 // This ends up closing the source window.
898 delete tab;
899 // Cancel the drag.
900 ui_controls::SendKeyPress(new_browser->window()->GetNativeWindow(),
901 ui::VKEY_ESCAPE, false, false, false, false);
902 }
903
904 } // namespace
905
906 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
907 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
908 // compositor. crbug.com/331924
909 #define MAYBE_DeleteSourceDetached DISABLED_DeleteSourceDetached
910 #else
911 #define MAYBE_DeleteSourceDetached DeleteSourceDetached
912 #endif
913 // Detaches a tab and while detached deletes a tab from the source so that the
914 // source window closes then presses escape to cancel the drag.
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,MAYBE_DeleteSourceDetached)915 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
916 MAYBE_DeleteSourceDetached) {
917 // Add another tab.
918 AddTabAndResetBrowser(browser());
919 TabStrip* tab_strip = GetTabStripForBrowser(browser());
920
921 // Move to the first tab and drag it enough so that it detaches.
922 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
923 WebContents* to_delete = browser()->tab_strip_model()->GetWebContentsAt(1);
924 ASSERT_TRUE(PressInput(tab_0_center));
925 ASSERT_TRUE(DragInputToNotifyWhenDone(
926 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
927 base::Bind(&DeleteSourceDetachedStep2, to_delete, native_browser_list)));
928 QuitWhenNotDragging();
929
930 // Should not be dragging.
931 ASSERT_EQ(1u, native_browser_list->size());
932 Browser* new_browser = native_browser_list->get(0);
933 ASSERT_FALSE(GetTabStripForBrowser(new_browser)->IsDragSessionActive());
934 ASSERT_FALSE(TabDragController::IsActive());
935
936 EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
937
938 EXPECT_FALSE(GetIsDragged(new_browser));
939
940 // Remaining browser window should not be maximized
941 EXPECT_FALSE(new_browser->window()->IsMaximized());
942 }
943
944 namespace {
945
PressEscapeWhileDetachedStep2(const BrowserList * browser_list)946 void PressEscapeWhileDetachedStep2(const BrowserList* browser_list) {
947 ASSERT_EQ(2u, browser_list->size());
948 Browser* new_browser = browser_list->get(1);
949 ui_controls::SendKeyPress(
950 new_browser->window()->GetNativeWindow(), ui::VKEY_ESCAPE, false, false,
951 false, false);
952 }
953
954 } // namespace
955
956 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
957 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
958 // compositor. crbug.com/331924
959 #define MAYBE_PressEscapeWhileDetached DISABLED_PressEscapeWhileDetached
960 #else
961 #define MAYBE_PressEscapeWhileDetached PressEscapeWhileDetached
962 #endif
963 // This is disabled until NativeViewHost::Detach really detaches.
964 // Detaches a tab and while detached presses escape to revert the drag.
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,MAYBE_PressEscapeWhileDetached)965 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
966 MAYBE_PressEscapeWhileDetached) {
967 // Add another tab.
968 AddTabAndResetBrowser(browser());
969 TabStrip* tab_strip = GetTabStripForBrowser(browser());
970
971 // Move to the first tab and drag it enough so that it detaches.
972 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
973 ASSERT_TRUE(PressInput(tab_0_center));
974 ASSERT_TRUE(DragInputToNotifyWhenDone(
975 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
976 base::Bind(&PressEscapeWhileDetachedStep2, native_browser_list)));
977 QuitWhenNotDragging();
978
979 // Should not be dragging.
980 ASSERT_FALSE(tab_strip->IsDragSessionActive());
981 ASSERT_FALSE(TabDragController::IsActive());
982
983 // And there should only be one window.
984 EXPECT_EQ(1u, native_browser_list->size());
985
986 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
987
988 // Remaining browser window should not be maximized
989 EXPECT_FALSE(browser()->window()->IsMaximized());
990
991 // The tab strip should no longer have capture because the drag was ended and
992 // mouse/touch was released.
993 EXPECT_FALSE(tab_strip->GetWidget()->HasCapture());
994 }
995
996 namespace {
997
DragAllStep2(DetachToBrowserTabDragControllerTest * test,const BrowserList * browser_list)998 void DragAllStep2(DetachToBrowserTabDragControllerTest* test,
999 const BrowserList* browser_list) {
1000 // Should only be one window.
1001 ASSERT_EQ(1u, browser_list->size());
1002 if (test->input_source() == INPUT_SOURCE_TOUCH) {
1003 ASSERT_TRUE(test->ReleaseInput());
1004 } else {
1005 ASSERT_TRUE(test->ReleaseMouseAsync());
1006 }
1007 }
1008
1009 } // namespace
1010
1011 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1012 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1013 // compositor. crbug.com/331924
1014 #define MAYBE_DragAll DISABLED_DragAll
1015 #else
1016 #define MAYBE_DragAll DragAll
1017 #endif
1018 // Selects multiple tabs and starts dragging the window.
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,MAYBE_DragAll)1019 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, MAYBE_DragAll) {
1020 // Add another tab.
1021 AddTabAndResetBrowser(browser());
1022 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1023 browser()->tab_strip_model()->AddTabAtToSelection(0);
1024 browser()->tab_strip_model()->AddTabAtToSelection(1);
1025
1026 // Move to the first tab and drag it enough so that it would normally
1027 // detach.
1028 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1029 ASSERT_TRUE(PressInput(tab_0_center));
1030 ASSERT_TRUE(DragInputToNotifyWhenDone(
1031 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1032 base::Bind(&DragAllStep2, this, native_browser_list)));
1033 QuitWhenNotDragging();
1034
1035 // Should not be dragging.
1036 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1037 ASSERT_FALSE(TabDragController::IsActive());
1038
1039 // And there should only be one window.
1040 EXPECT_EQ(1u, native_browser_list->size());
1041
1042 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
1043
1044 EXPECT_FALSE(GetIsDragged(browser()));
1045
1046 // Remaining browser window should not be maximized
1047 EXPECT_FALSE(browser()->window()->IsMaximized());
1048 }
1049
1050 namespace {
1051
1052 // Invoked from the nested message loop.
DragAllToSeparateWindowStep2(DetachToBrowserTabDragControllerTest * test,TabStrip * attached_tab_strip,TabStrip * target_tab_strip,const BrowserList * browser_list)1053 void DragAllToSeparateWindowStep2(DetachToBrowserTabDragControllerTest* test,
1054 TabStrip* attached_tab_strip,
1055 TabStrip* target_tab_strip,
1056 const BrowserList* browser_list) {
1057 ASSERT_TRUE(attached_tab_strip->IsDragSessionActive());
1058 ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
1059 ASSERT_TRUE(TabDragController::IsActive());
1060 ASSERT_EQ(2u, browser_list->size());
1061
1062 // Drag to target_tab_strip. This should stop the nested loop from dragging
1063 // the window.
1064 gfx::Point target_point(target_tab_strip->width() - 1,
1065 target_tab_strip->height() / 2);
1066 views::View::ConvertPointToScreen(target_tab_strip, &target_point);
1067 ASSERT_TRUE(test->DragInputToAsync(target_point));
1068 }
1069
1070 } // namespace
1071
1072 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1073 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1074 // compositor. crbug.com/331924
1075 #define MAYBE_DragAllToSeparateWindow DISABLED_DragAllToSeparateWindow
1076 #else
1077 #define MAYBE_DragAllToSeparateWindow DragAllToSeparateWindow
1078 #endif
1079 // Creates two browsers, selects all tabs in first and drags into second.
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,MAYBE_DragAllToSeparateWindow)1080 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1081 MAYBE_DragAllToSeparateWindow) {
1082 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1083
1084 // Add another tab to browser().
1085 AddTabAndResetBrowser(browser());
1086
1087 // Create another browser.
1088 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
1089 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1090
1091 browser()->tab_strip_model()->AddTabAtToSelection(0);
1092 browser()->tab_strip_model()->AddTabAtToSelection(1);
1093
1094 // Move to the first tab and drag it enough so that it detaches, but not
1095 // enough that it attaches to browser2.
1096 gfx::Point tab_0_center(
1097 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1098 ASSERT_TRUE(PressInput(tab_0_center));
1099 ASSERT_TRUE(DragInputToNotifyWhenDone(
1100 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1101 base::Bind(&DragAllToSeparateWindowStep2, this, tab_strip, tab_strip2,
1102 native_browser_list)));
1103 QuitWhenNotDragging();
1104
1105 // Should now be attached to tab_strip2.
1106 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1107 ASSERT_TRUE(TabDragController::IsActive());
1108 ASSERT_EQ(1u, native_browser_list->size());
1109
1110 // Release the mouse, stopping the drag session.
1111 ASSERT_TRUE(ReleaseInput());
1112 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1113 ASSERT_FALSE(TabDragController::IsActive());
1114 EXPECT_EQ("100 0 1", IDString(browser2->tab_strip_model()));
1115
1116 EXPECT_FALSE(GetIsDragged(browser2));
1117
1118 // Remaining browser window should not be maximized
1119 EXPECT_FALSE(browser2->window()->IsMaximized());
1120 }
1121
1122 namespace {
1123
1124 // Invoked from the nested message loop.
DragAllToSeparateWindowAndCancelStep2(DetachToBrowserTabDragControllerTest * test,TabStrip * attached_tab_strip,TabStrip * target_tab_strip,const BrowserList * browser_list)1125 void DragAllToSeparateWindowAndCancelStep2(
1126 DetachToBrowserTabDragControllerTest* test,
1127 TabStrip* attached_tab_strip,
1128 TabStrip* target_tab_strip,
1129 const BrowserList* browser_list) {
1130 ASSERT_TRUE(attached_tab_strip->IsDragSessionActive());
1131 ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
1132 ASSERT_TRUE(TabDragController::IsActive());
1133 ASSERT_EQ(2u, browser_list->size());
1134
1135 // Drag to target_tab_strip. This should stop the nested loop from dragging
1136 // the window.
1137 gfx::Point target_point(target_tab_strip->width() - 1,
1138 target_tab_strip->height() / 2);
1139 views::View::ConvertPointToScreen(target_tab_strip, &target_point);
1140 ASSERT_TRUE(test->DragInputToAsync(target_point));
1141 }
1142
1143 } // namespace
1144
1145 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1146 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1147 // compositor. crbug.com/331924
1148 #define MAYBE_DragAllToSeparateWindowAndCancel \
1149 DISABLED_DragAllToSeparateWindowAndCancel
1150 #else
1151 #define MAYBE_DragAllToSeparateWindowAndCancel DragAllToSeparateWindowAndCancel
1152 #endif
1153 // Creates two browsers, selects all tabs in first, drags into second, then hits
1154 // escape.
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,MAYBE_DragAllToSeparateWindowAndCancel)1155 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1156 MAYBE_DragAllToSeparateWindowAndCancel) {
1157 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1158
1159 // Add another tab to browser().
1160 AddTabAndResetBrowser(browser());
1161
1162 // Create another browser.
1163 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
1164 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1165
1166 browser()->tab_strip_model()->AddTabAtToSelection(0);
1167 browser()->tab_strip_model()->AddTabAtToSelection(1);
1168
1169 // Move to the first tab and drag it enough so that it detaches, but not
1170 // enough that it attaches to browser2.
1171 gfx::Point tab_0_center(
1172 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1173 ASSERT_TRUE(PressInput(tab_0_center));
1174 ASSERT_TRUE(DragInputToNotifyWhenDone(
1175 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1176 base::Bind(&DragAllToSeparateWindowAndCancelStep2, this,
1177 tab_strip, tab_strip2, native_browser_list)));
1178 QuitWhenNotDragging();
1179
1180 // Should now be attached to tab_strip2.
1181 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1182 ASSERT_TRUE(TabDragController::IsActive());
1183 ASSERT_EQ(1u, native_browser_list->size());
1184
1185 // Cancel the drag.
1186 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
1187 browser2, ui::VKEY_ESCAPE, false, false, false, false));
1188
1189 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1190 ASSERT_FALSE(TabDragController::IsActive());
1191 EXPECT_EQ("100 0 1", IDString(browser2->tab_strip_model()));
1192
1193 // browser() will have been destroyed, but browser2 should remain.
1194 ASSERT_EQ(1u, native_browser_list->size());
1195
1196 EXPECT_FALSE(GetIsDragged(browser2));
1197
1198 // Remaining browser window should not be maximized
1199 EXPECT_FALSE(browser2->window()->IsMaximized());
1200 }
1201
1202 #if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_WIN)
1203 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1204 // compositor. crbug.com/331924
1205 #define MAYBE_DragDirectlyToSecondWindow DISABLED_DragDirectlyToSecondWindow
1206 #else
1207 #define MAYBE_DragDirectlyToSecondWindow DragDirectlyToSecondWindow
1208 #endif
1209 // Creates two browsers, drags from first into the second in such a way that
1210 // no detaching should happen.
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,MAYBE_DragDirectlyToSecondWindow)1211 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1212 MAYBE_DragDirectlyToSecondWindow) {
1213 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1214
1215 // Add another tab to browser().
1216 AddTabAndResetBrowser(browser());
1217
1218 // Create another browser.
1219 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
1220 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1221
1222 // Move the tabstrip down enough so that we can detach.
1223 gfx::Rect bounds(browser2->window()->GetBounds());
1224 bounds.Offset(0, 100);
1225 browser2->window()->SetBounds(bounds);
1226
1227 // Move to the first tab and drag it enough so that it detaches, but not
1228 // enough that it attaches to browser2.
1229 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1230 ASSERT_TRUE(PressInput(tab_0_center));
1231
1232 gfx::Point b2_location(5, 0);
1233 views::View::ConvertPointToScreen(tab_strip2, &b2_location);
1234 ASSERT_TRUE(DragInputTo(b2_location));
1235
1236 // Should now be attached to tab_strip2.
1237 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1238 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1239 ASSERT_TRUE(TabDragController::IsActive());
1240
1241 // Release the mouse, stopping the drag session.
1242 ASSERT_TRUE(ReleaseInput());
1243 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1244 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1245 ASSERT_FALSE(TabDragController::IsActive());
1246 EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1247 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1248
1249 EXPECT_FALSE(GetIsDragged(browser()));
1250 EXPECT_FALSE(GetIsDragged(browser2));
1251
1252 // Both windows should not be maximized
1253 EXPECT_FALSE(browser()->window()->IsMaximized());
1254 EXPECT_FALSE(browser2->window()->IsMaximized());
1255 }
1256
1257 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1258 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1259 // compositor. crbug.com/331924
1260 #define MAYBE_DragSingleTabToSeparateWindow \
1261 DISABLED_DragSingleTabToSeparateWindow
1262 #else
1263 #define MAYBE_DragSingleTabToSeparateWindow DragSingleTabToSeparateWindow
1264 #endif
1265 // Creates two browsers, the first browser has a single tab and drags into the
1266 // second browser.
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,MAYBE_DragSingleTabToSeparateWindow)1267 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1268 MAYBE_DragSingleTabToSeparateWindow) {
1269 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1270
1271 ResetIDs(browser()->tab_strip_model(), 0);
1272
1273 // Create another browser.
1274 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
1275 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1276 const gfx::Rect initial_bounds(browser2->window()->GetBounds());
1277
1278 // Move to the first tab and drag it enough so that it detaches, but not
1279 // enough that it attaches to browser2.
1280 gfx::Point tab_0_center(
1281 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1282 ASSERT_TRUE(PressInput(tab_0_center));
1283 ASSERT_TRUE(DragInputToNotifyWhenDone(
1284 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1285 base::Bind(&DragAllToSeparateWindowStep2, this, tab_strip, tab_strip2,
1286 native_browser_list)));
1287 QuitWhenNotDragging();
1288
1289 // Should now be attached to tab_strip2.
1290 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1291 ASSERT_TRUE(TabDragController::IsActive());
1292 ASSERT_EQ(1u, native_browser_list->size());
1293
1294 // Release the mouse, stopping the drag session.
1295 ASSERT_TRUE(ReleaseInput());
1296 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1297 ASSERT_FALSE(TabDragController::IsActive());
1298 EXPECT_EQ("100 0", IDString(browser2->tab_strip_model()));
1299
1300 EXPECT_FALSE(GetIsDragged(browser2));
1301
1302 // Remaining browser window should not be maximized
1303 EXPECT_FALSE(browser2->window()->IsMaximized());
1304
1305 // Make sure that the window is still managed and not user moved.
1306 EXPECT_TRUE(IsWindowPositionManaged(browser2->window()->GetNativeWindow()));
1307 EXPECT_FALSE(HasUserChangedWindowPositionOrSize(
1308 browser2->window()->GetNativeWindow()));
1309 // Also make sure that the drag to window position has not changed.
1310 EXPECT_EQ(initial_bounds.ToString(),
1311 browser2->window()->GetBounds().ToString());
1312 }
1313
1314 namespace {
1315
1316 // Invoked from the nested message loop.
CancelOnNewTabWhenDraggingStep2(DetachToBrowserTabDragControllerTest * test,const BrowserList * browser_list)1317 void CancelOnNewTabWhenDraggingStep2(
1318 DetachToBrowserTabDragControllerTest* test,
1319 const BrowserList* browser_list) {
1320 ASSERT_TRUE(TabDragController::IsActive());
1321 ASSERT_EQ(2u, browser_list->size());
1322
1323 // Add another tab. This should trigger exiting the nested loop.
1324 test->AddBlankTabAndShow(browser_list->GetLastActive());
1325 }
1326
1327 } // namespace
1328
1329 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1330 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1331 // compositor. crbug.com/331924
1332 #define MAYBE_CancelOnNewTabWhenDragging DISABLED_CancelOnNewTabWhenDragging
1333 #else
1334 #define MAYBE_CancelOnNewTabWhenDragging CancelOnNewTabWhenDragging
1335 #endif
1336 // Adds another tab, detaches into separate window, adds another tab and
1337 // verifies the run loop ends.
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,MAYBE_CancelOnNewTabWhenDragging)1338 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1339 MAYBE_CancelOnNewTabWhenDragging) {
1340 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1341
1342 // Add another tab to browser().
1343 AddTabAndResetBrowser(browser());
1344
1345 // Move to the first tab and drag it enough so that it detaches.
1346 gfx::Point tab_0_center(
1347 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1348 ASSERT_TRUE(PressInput(tab_0_center));
1349 ASSERT_TRUE(DragInputToNotifyWhenDone(
1350 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1351 base::Bind(&CancelOnNewTabWhenDraggingStep2, this, native_browser_list)));
1352 QuitWhenNotDragging();
1353
1354 // Should be two windows and not dragging.
1355 ASSERT_FALSE(TabDragController::IsActive());
1356 ASSERT_EQ(2u, native_browser_list->size());
1357 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
1358 EXPECT_FALSE(GetIsDragged(*it));
1359 // Should not be maximized
1360 EXPECT_FALSE(it->window()->IsMaximized());
1361 }
1362 }
1363
1364 #if defined(OS_CHROMEOS)
1365 // TODO(sky,sad): A number of tests below are disabled as they fail due to
1366 // resize locks with a real compositor. crbug.com/331924
1367 namespace {
1368
DragInMaximizedWindowStep2(DetachToBrowserTabDragControllerTest * test,Browser * browser,TabStrip * tab_strip,const BrowserList * browser_list)1369 void DragInMaximizedWindowStep2(DetachToBrowserTabDragControllerTest* test,
1370 Browser* browser,
1371 TabStrip* tab_strip,
1372 const BrowserList* browser_list) {
1373 // There should be another browser.
1374 ASSERT_EQ(2u, browser_list->size());
1375 Browser* new_browser = browser_list->get(1);
1376 EXPECT_NE(browser, new_browser);
1377 ASSERT_TRUE(new_browser->window()->IsActive());
1378 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
1379
1380 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1381 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1382
1383 // Both windows should be visible.
1384 EXPECT_TRUE(tab_strip->GetWidget()->IsVisible());
1385 EXPECT_TRUE(tab_strip2->GetWidget()->IsVisible());
1386
1387 // Stops dragging.
1388 ASSERT_TRUE(test->ReleaseInput());
1389 }
1390
1391 } // namespace
1392
1393 // Creates a browser with two tabs, maximizes it, drags the tab out.
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,DISABLED_DragInMaximizedWindow)1394 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1395 DISABLED_DragInMaximizedWindow) {
1396 AddTabAndResetBrowser(browser());
1397 browser()->window()->Maximize();
1398
1399 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1400
1401 // Move to the first tab and drag it enough so that it detaches.
1402 gfx::Point tab_0_center(
1403 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1404 ASSERT_TRUE(PressInput(tab_0_center));
1405 ASSERT_TRUE(DragInputToNotifyWhenDone(
1406 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1407 base::Bind(&DragInMaximizedWindowStep2, this, browser(), tab_strip,
1408 native_browser_list)));
1409 QuitWhenNotDragging();
1410
1411 ASSERT_FALSE(TabDragController::IsActive());
1412
1413 // Should be two browsers.
1414 ASSERT_EQ(2u, native_browser_list->size());
1415 Browser* new_browser = native_browser_list->get(1);
1416 ASSERT_TRUE(new_browser->window()->IsActive());
1417
1418 EXPECT_TRUE(browser()->window()->GetNativeWindow()->IsVisible());
1419 EXPECT_TRUE(new_browser->window()->GetNativeWindow()->IsVisible());
1420
1421 EXPECT_FALSE(GetIsDragged(browser()));
1422 EXPECT_FALSE(GetIsDragged(new_browser));
1423
1424 // The source window should be maximized.
1425 EXPECT_TRUE(browser()->window()->IsMaximized());
1426 // The new window should be maximized.
1427 EXPECT_TRUE(new_browser->window()->IsMaximized());
1428 }
1429
1430 // Subclass of DetachToBrowserTabDragControllerTest that
1431 // creates multiple displays.
1432 class DetachToBrowserInSeparateDisplayTabDragControllerTest
1433 : public DetachToBrowserTabDragControllerTest {
1434 public:
DetachToBrowserInSeparateDisplayTabDragControllerTest()1435 DetachToBrowserInSeparateDisplayTabDragControllerTest() {}
~DetachToBrowserInSeparateDisplayTabDragControllerTest()1436 virtual ~DetachToBrowserInSeparateDisplayTabDragControllerTest() {}
1437
SetUpCommandLine(CommandLine * command_line)1438 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
1439 DetachToBrowserTabDragControllerTest::SetUpCommandLine(command_line);
1440 // Make screens sufficiently wide to host 2 browsers side by side.
1441 command_line->AppendSwitchASCII("ash-host-window-bounds",
1442 "0+0-600x600,601+0-600x600");
1443 }
1444
1445 private:
1446 DISALLOW_COPY_AND_ASSIGN(
1447 DetachToBrowserInSeparateDisplayTabDragControllerTest);
1448 };
1449
1450 // Subclass of DetachToBrowserTabDragControllerTest that runs tests only with
1451 // touch input.
1452 class DetachToBrowserTabDragControllerTestTouch
1453 : public DetachToBrowserTabDragControllerTest {
1454 public:
DetachToBrowserTabDragControllerTestTouch()1455 DetachToBrowserTabDragControllerTestTouch() {}
~DetachToBrowserTabDragControllerTestTouch()1456 virtual ~DetachToBrowserTabDragControllerTestTouch() {}
1457
1458 private:
1459 DISALLOW_COPY_AND_ASSIGN(DetachToBrowserTabDragControllerTestTouch);
1460 };
1461
1462 namespace {
1463
DragSingleTabToSeparateWindowInSecondDisplayStep3(DetachToBrowserTabDragControllerTest * test)1464 void DragSingleTabToSeparateWindowInSecondDisplayStep3(
1465 DetachToBrowserTabDragControllerTest* test) {
1466 ASSERT_TRUE(test->ReleaseInput());
1467 }
1468
DragSingleTabToSeparateWindowInSecondDisplayStep2(DetachToBrowserTabDragControllerTest * test,const gfx::Point & target_point)1469 void DragSingleTabToSeparateWindowInSecondDisplayStep2(
1470 DetachToBrowserTabDragControllerTest* test,
1471 const gfx::Point& target_point) {
1472 ASSERT_TRUE(test->DragInputToNotifyWhenDone(
1473 target_point.x(), target_point.y(),
1474 base::Bind(&DragSingleTabToSeparateWindowInSecondDisplayStep3, test)));
1475 }
1476
1477 } // namespace
1478
1479 // Drags from browser to a second display and releases input.
IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,DISABLED_DragSingleTabToSeparateWindowInSecondDisplay)1480 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1481 DISABLED_DragSingleTabToSeparateWindowInSecondDisplay) {
1482 // Add another tab.
1483 AddTabAndResetBrowser(browser());
1484 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1485
1486 // Move to the first tab and drag it enough so that it detaches.
1487 // Then drag it to the final destination on the second screen.
1488 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1489 ASSERT_TRUE(PressInput(tab_0_center));
1490 ASSERT_TRUE(DragInputToNotifyWhenDone(
1491 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1492 base::Bind(&DragSingleTabToSeparateWindowInSecondDisplayStep2,
1493 this, gfx::Point(600 + tab_0_center.x(),
1494 tab_0_center.y()
1495 + GetDetachY(tab_strip)))));
1496 QuitWhenNotDragging();
1497
1498 // Should no longer be dragging.
1499 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1500 ASSERT_FALSE(TabDragController::IsActive());
1501
1502 // There should now be another browser.
1503 ASSERT_EQ(2u, native_browser_list->size());
1504 Browser* new_browser = native_browser_list->get(1);
1505 ASSERT_TRUE(new_browser->window()->IsActive());
1506 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
1507 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1508
1509 // This other browser should be on the second screen (with mouse drag)
1510 // With the touch input the browser cannot be dragged from one screen
1511 // to another and the window stays on the first screen.
1512 if (input_source() == INPUT_SOURCE_MOUSE) {
1513 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1514 ASSERT_EQ(2u, roots.size());
1515 aura::Window* second_root = roots[1];
1516 EXPECT_EQ(second_root,
1517 new_browser->window()->GetNativeWindow()->GetRootWindow());
1518 }
1519
1520 EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
1521 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1522
1523 // Both windows should not be maximized
1524 EXPECT_FALSE(browser()->window()->IsMaximized());
1525 EXPECT_FALSE(new_browser->window()->IsMaximized());
1526 }
1527
1528 namespace {
1529
1530 // Invoked from the nested message loop.
DragTabToWindowInSeparateDisplayStep2(DetachToBrowserTabDragControllerTest * test,TabStrip * not_attached_tab_strip,TabStrip * target_tab_strip)1531 void DragTabToWindowInSeparateDisplayStep2(
1532 DetachToBrowserTabDragControllerTest* test,
1533 TabStrip* not_attached_tab_strip,
1534 TabStrip* target_tab_strip) {
1535 ASSERT_FALSE(not_attached_tab_strip->IsDragSessionActive());
1536 ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
1537 ASSERT_TRUE(TabDragController::IsActive());
1538
1539 // Drag to target_tab_strip. This should stop the nested loop from dragging
1540 // the window.
1541 gfx::Point target_point(
1542 GetCenterInScreenCoordinates(target_tab_strip->tab_at(0)));
1543
1544 // Move it close to the beginning of the target tabstrip.
1545 target_point.set_x(
1546 target_point.x() - target_tab_strip->tab_at(0)->width() / 2 + 10);
1547 ASSERT_TRUE(test->DragInputToAsync(target_point));
1548 }
1549
1550 } // namespace
1551
1552 // Drags from browser to another browser on a second display and releases input.
IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,DISABLED_DragTabToWindowInSeparateDisplay)1553 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1554 DISABLED_DragTabToWindowInSeparateDisplay) {
1555 // Add another tab.
1556 AddTabAndResetBrowser(browser());
1557 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1558
1559 // Create another browser.
1560 Browser* browser2 = CreateBrowser(browser()->profile());
1561 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1562 ResetIDs(browser2->tab_strip_model(), 100);
1563
1564 // Move the second browser to the second display.
1565 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1566 ASSERT_EQ(2u, roots.size());
1567 aura::Window* second_root = roots[1];
1568 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1569 second_root).work_area();
1570 browser2->window()->SetBounds(work_area);
1571 EXPECT_EQ(second_root,
1572 browser2->window()->GetNativeWindow()->GetRootWindow());
1573
1574 // Move to the first tab and drag it enough so that it detaches, but not
1575 // enough that it attaches to browser2.
1576 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1577 ASSERT_TRUE(PressInput(tab_0_center));
1578 ASSERT_TRUE(DragInputToNotifyWhenDone(
1579 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1580 base::Bind(&DragTabToWindowInSeparateDisplayStep2,
1581 this, tab_strip, tab_strip2)));
1582 QuitWhenNotDragging();
1583
1584 // Should now be attached to tab_strip2.
1585 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1586 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1587 ASSERT_TRUE(TabDragController::IsActive());
1588
1589 // Release the mouse, stopping the drag session.
1590 ASSERT_TRUE(ReleaseInput());
1591 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1592 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1593 ASSERT_FALSE(TabDragController::IsActive());
1594 EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1595 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1596
1597 // Both windows should not be maximized
1598 EXPECT_FALSE(browser()->window()->IsMaximized());
1599 EXPECT_FALSE(browser2->window()->IsMaximized());
1600 }
1601
1602 // Drags from browser to another browser on a second display and releases input.
IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,DISABLED_DragTabToWindowOnSecondDisplay)1603 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1604 DISABLED_DragTabToWindowOnSecondDisplay) {
1605 // Add another tab.
1606 AddTabAndResetBrowser(browser());
1607 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1608
1609 // Create another browser.
1610 Browser* browser2 = CreateBrowser(browser()->profile());
1611 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1612 ResetIDs(browser2->tab_strip_model(), 100);
1613
1614 // Move both browsers to the second display.
1615 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1616 ASSERT_EQ(2u, roots.size());
1617 aura::Window* second_root = roots[1];
1618 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1619 second_root).work_area();
1620 browser()->window()->SetBounds(work_area);
1621
1622 // position both browser windows side by side on the second screen.
1623 gfx::Rect work_area2(work_area);
1624 work_area.set_width(work_area.width()/2);
1625 browser()->window()->SetBounds(work_area);
1626 work_area2.set_x(work_area2.x() + work_area2.width()/2);
1627 work_area2.set_width(work_area2.width()/2);
1628 browser2->window()->SetBounds(work_area2);
1629 EXPECT_EQ(second_root,
1630 browser()->window()->GetNativeWindow()->GetRootWindow());
1631 EXPECT_EQ(second_root,
1632 browser2->window()->GetNativeWindow()->GetRootWindow());
1633
1634 // Move to the first tab and drag it enough so that it detaches, but not
1635 // enough that it attaches to browser2.
1636 // SetEventGeneratorRootWindow sets correct (second) RootWindow
1637 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1638 SetEventGeneratorRootWindow(tab_0_center);
1639 ASSERT_TRUE(PressInput(tab_0_center));
1640 ASSERT_TRUE(DragInputToNotifyWhenDone(
1641 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1642 base::Bind(&DragTabToWindowInSeparateDisplayStep2,
1643 this, tab_strip, tab_strip2)));
1644 QuitWhenNotDragging();
1645
1646 // Should now be attached to tab_strip2.
1647 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1648 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1649 ASSERT_TRUE(TabDragController::IsActive());
1650
1651 // Release the mouse, stopping the drag session.
1652 ASSERT_TRUE(ReleaseInput());
1653 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1654 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1655 ASSERT_FALSE(TabDragController::IsActive());
1656 EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1657 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1658
1659 // Both windows should not be maximized
1660 EXPECT_FALSE(browser()->window()->IsMaximized());
1661 EXPECT_FALSE(browser2->window()->IsMaximized());
1662 }
1663
1664 // Drags from a maximized browser to another non-maximized browser on a second
1665 // display and releases input.
IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,DISABLED_DragMaxTabToNonMaxWindowInSeparateDisplay)1666 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1667 DISABLED_DragMaxTabToNonMaxWindowInSeparateDisplay) {
1668 // Add another tab.
1669 AddTabAndResetBrowser(browser());
1670 browser()->window()->Maximize();
1671 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1672
1673 // Create another browser on the second display.
1674 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1675 ASSERT_EQ(2u, roots.size());
1676 aura::Window* first_root = roots[0];
1677 aura::Window* second_root = roots[1];
1678 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1679 second_root).work_area();
1680 work_area.Inset(20, 20, 20, 60);
1681 Browser::CreateParams params(browser()->profile(),
1682 browser()->host_desktop_type());
1683 params.initial_show_state = ui::SHOW_STATE_NORMAL;
1684 params.initial_bounds = work_area;
1685 Browser* browser2 = new Browser(params);
1686 AddBlankTabAndShow(browser2);
1687
1688 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1689 ResetIDs(browser2->tab_strip_model(), 100);
1690
1691 EXPECT_EQ(second_root,
1692 browser2->window()->GetNativeWindow()->GetRootWindow());
1693 EXPECT_EQ(first_root,
1694 browser()->window()->GetNativeWindow()->GetRootWindow());
1695 EXPECT_EQ(2, tab_strip->tab_count());
1696 EXPECT_EQ(1, tab_strip2->tab_count());
1697
1698 // Move to the first tab and drag it enough so that it detaches, but not
1699 // enough that it attaches to browser2.
1700 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1701 ASSERT_TRUE(PressInput(tab_0_center));
1702 ASSERT_TRUE(DragInputToNotifyWhenDone(
1703 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1704 base::Bind(&DragTabToWindowInSeparateDisplayStep2,
1705 this, tab_strip, tab_strip2)));
1706 QuitWhenNotDragging();
1707
1708 // Should now be attached to tab_strip2.
1709 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1710 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1711 ASSERT_TRUE(TabDragController::IsActive());
1712
1713 // Release the mouse, stopping the drag session.
1714 ASSERT_TRUE(ReleaseInput());
1715
1716 // tab should have moved
1717 EXPECT_EQ(1, tab_strip->tab_count());
1718 EXPECT_EQ(2, tab_strip2->tab_count());
1719
1720 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1721 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1722 ASSERT_FALSE(TabDragController::IsActive());
1723 EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1724 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1725
1726 // Source browser should still be maximized, target should not
1727 EXPECT_TRUE(browser()->window()->IsMaximized());
1728 EXPECT_FALSE(browser2->window()->IsMaximized());
1729 }
1730
1731 // Drags from a restored browser to an immersive fullscreen browser on a
1732 // second display and releases input.
IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,DISABLED_DragTabToImmersiveBrowserOnSeparateDisplay)1733 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1734 DISABLED_DragTabToImmersiveBrowserOnSeparateDisplay) {
1735 // Add another tab.
1736 AddTabAndResetBrowser(browser());
1737 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1738
1739 // Create another browser.
1740 Browser* browser2 = CreateBrowser(browser()->profile());
1741 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1742 ResetIDs(browser2->tab_strip_model(), 100);
1743
1744 // Move the second browser to the second display.
1745 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1746 ASSERT_EQ(2u, roots.size());
1747 aura::Window* second_root = roots[1];
1748 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1749 second_root).work_area();
1750 browser2->window()->SetBounds(work_area);
1751 EXPECT_EQ(second_root,
1752 browser2->window()->GetNativeWindow()->GetRootWindow());
1753
1754 // Put the second browser into immersive fullscreen.
1755 BrowserView* browser_view2 = BrowserView::GetBrowserViewForBrowser(browser2);
1756 ImmersiveModeController* immersive_controller2 =
1757 browser_view2->immersive_mode_controller();
1758 immersive_controller2->SetupForTest();
1759 chrome::ToggleFullscreenMode(browser2);
1760 ASSERT_TRUE(immersive_controller2->IsEnabled());
1761 ASSERT_FALSE(immersive_controller2->IsRevealed());
1762 ASSERT_TRUE(tab_strip2->IsImmersiveStyle());
1763
1764 // Move to the first tab and drag it enough so that it detaches, but not
1765 // enough that it attaches to browser2.
1766 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1767 ASSERT_TRUE(PressInput(tab_0_center));
1768 ASSERT_TRUE(DragInputToNotifyWhenDone(
1769 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1770 base::Bind(&DragTabToWindowInSeparateDisplayStep2,
1771 this, tab_strip, tab_strip2)));
1772 QuitWhenNotDragging();
1773
1774 // Should now be attached to tab_strip2.
1775 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1776 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1777 ASSERT_TRUE(TabDragController::IsActive());
1778
1779 // browser2's top chrome should be revealed and the tab strip should be
1780 // at normal height while user is tragging tabs_strip2's tabs.
1781 ASSERT_TRUE(immersive_controller2->IsRevealed());
1782 ASSERT_FALSE(tab_strip2->IsImmersiveStyle());
1783
1784 // Release the mouse, stopping the drag session.
1785 ASSERT_TRUE(ReleaseInput());
1786 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1787 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1788 ASSERT_FALSE(TabDragController::IsActive());
1789 EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1790 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1791
1792 // Move the mouse off of browser2's top chrome.
1793 aura::Window* primary_root = roots[0];
1794 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
1795 primary_root->GetBoundsInScreen().CenterPoint()));
1796
1797 // The first browser window should not be in immersive fullscreen.
1798 // browser2 should still be in immersive fullscreen, but the top chrome should
1799 // no longer be revealed.
1800 BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
1801 EXPECT_FALSE(browser_view->immersive_mode_controller()->IsEnabled());
1802
1803 EXPECT_TRUE(immersive_controller2->IsEnabled());
1804 EXPECT_FALSE(immersive_controller2->IsRevealed());
1805 EXPECT_TRUE(tab_strip2->IsImmersiveStyle());
1806 }
1807
1808 // Subclass of DetachToBrowserTabDragControllerTest that
1809 // creates multiple displays with different device scale factors.
1810 class DifferentDeviceScaleFactorDisplayTabDragControllerTest
1811 : public DetachToBrowserTabDragControllerTest {
1812 public:
DifferentDeviceScaleFactorDisplayTabDragControllerTest()1813 DifferentDeviceScaleFactorDisplayTabDragControllerTest() {}
~DifferentDeviceScaleFactorDisplayTabDragControllerTest()1814 virtual ~DifferentDeviceScaleFactorDisplayTabDragControllerTest() {}
1815
SetUpCommandLine(CommandLine * command_line)1816 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
1817 DetachToBrowserTabDragControllerTest::SetUpCommandLine(command_line);
1818 command_line->AppendSwitchASCII("ash-host-window-bounds",
1819 "400x400,0+400-800x800*2");
1820 }
1821
GetCursorDeviceScaleFactor() const1822 float GetCursorDeviceScaleFactor() const {
1823 ash::test::CursorManagerTestApi cursor_test_api(
1824 ash::Shell::GetInstance()->cursor_manager());
1825 return cursor_test_api.GetCurrentCursor().device_scale_factor();
1826 }
1827
1828 private:
1829 DISALLOW_COPY_AND_ASSIGN(
1830 DifferentDeviceScaleFactorDisplayTabDragControllerTest);
1831 };
1832
1833 namespace {
1834
1835 // The points where a tab is dragged in CursorDeviceScaleFactorStep.
1836 const struct DragPoint {
1837 int x;
1838 int y;
1839 } kDragPoints[] = {
1840 {300, 200},
1841 {399, 200},
1842 {500, 200},
1843 {400, 200},
1844 {300, 200},
1845 };
1846
1847 // The expected device scale factors before the cursor is moved to the
1848 // corresponding kDragPoints in CursorDeviceScaleFactorStep.
1849 const float kDeviceScaleFactorExpectations[] = {
1850 1.0f,
1851 1.0f,
1852 2.0f,
1853 2.0f,
1854 1.0f,
1855 };
1856
1857 COMPILE_ASSERT(
1858 arraysize(kDragPoints) == arraysize(kDeviceScaleFactorExpectations),
1859 kDragPoints_and_kDeviceScaleFactorExpectations_must_have_same_size);
1860
1861 // Drags tab to |kDragPoints[index]|, then calls the next step function.
CursorDeviceScaleFactorStep(DifferentDeviceScaleFactorDisplayTabDragControllerTest * test,TabStrip * not_attached_tab_strip,size_t index)1862 void CursorDeviceScaleFactorStep(
1863 DifferentDeviceScaleFactorDisplayTabDragControllerTest* test,
1864 TabStrip* not_attached_tab_strip,
1865 size_t index) {
1866 ASSERT_FALSE(not_attached_tab_strip->IsDragSessionActive());
1867 ASSERT_TRUE(TabDragController::IsActive());
1868
1869 if (index < arraysize(kDragPoints)) {
1870 EXPECT_EQ(kDeviceScaleFactorExpectations[index],
1871 test->GetCursorDeviceScaleFactor());
1872 const DragPoint p = kDragPoints[index];
1873 ASSERT_TRUE(test->DragInputToNotifyWhenDone(
1874 p.x, p.y, base::Bind(&CursorDeviceScaleFactorStep,
1875 test, not_attached_tab_strip, index + 1)));
1876 } else {
1877 // Finishes a serise of CursorDeviceScaleFactorStep calls and ends drag.
1878 EXPECT_EQ(1.0f, test->GetCursorDeviceScaleFactor());
1879 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
1880 ui_controls::LEFT, ui_controls::UP));
1881 }
1882 }
1883
1884 } // namespace
1885
1886 // Verifies cursor's device scale factor is updated when a tab is moved across
1887 // displays with different device scale factors (http://crbug.com/154183).
IN_PROC_BROWSER_TEST_P(DifferentDeviceScaleFactorDisplayTabDragControllerTest,DISABLED_CursorDeviceScaleFactor)1888 IN_PROC_BROWSER_TEST_P(DifferentDeviceScaleFactorDisplayTabDragControllerTest,
1889 DISABLED_CursorDeviceScaleFactor) {
1890 // Add another tab.
1891 AddTabAndResetBrowser(browser());
1892 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1893
1894 // Move the second browser to the second display.
1895 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1896 ASSERT_EQ(2u, roots.size());
1897
1898 // Move to the first tab and drag it enough so that it detaches.
1899 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1900 ASSERT_TRUE(PressInput(tab_0_center));
1901 ASSERT_TRUE(DragInputToNotifyWhenDone(
1902 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1903 base::Bind(&CursorDeviceScaleFactorStep,
1904 this, tab_strip, 0)));
1905 QuitWhenNotDragging();
1906 }
1907
1908 namespace {
1909
1910 class DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest
1911 : public TabDragControllerTest {
1912 public:
DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest()1913 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest() {}
1914
SetUpCommandLine(CommandLine * command_line)1915 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
1916 TabDragControllerTest::SetUpCommandLine(command_line);
1917 command_line->AppendSwitchASCII("ash-host-window-bounds",
1918 "0+0-250x250,251+0-250x250");
1919 }
1920
Press(const gfx::Point & position)1921 bool Press(const gfx::Point& position) {
1922 return ui_test_utils::SendMouseMoveSync(position) &&
1923 ui_test_utils::SendMouseEventsSync(ui_controls::LEFT,
1924 ui_controls::DOWN);
1925 }
1926
DragTabAndExecuteTaskWhenDone(const gfx::Point & position,const base::Closure & task)1927 bool DragTabAndExecuteTaskWhenDone(const gfx::Point& position,
1928 const base::Closure& task) {
1929 return ui_controls::SendMouseMoveNotifyWhenDone(
1930 position.x(), position.y(), task);
1931 }
1932
QuitWhenNotDragging()1933 void QuitWhenNotDragging() {
1934 test::QuitWhenNotDraggingImpl();
1935 base::MessageLoop::current()->Run();
1936 }
1937
1938 private:
1939 DISALLOW_COPY_AND_ASSIGN(
1940 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest);
1941 };
1942
1943 // Invoked from the nested message loop.
CancelDragTabToWindowInSeparateDisplayStep3(TabStrip * tab_strip,const BrowserList * browser_list)1944 void CancelDragTabToWindowInSeparateDisplayStep3(
1945 TabStrip* tab_strip,
1946 const BrowserList* browser_list) {
1947 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1948 ASSERT_TRUE(TabDragController::IsActive());
1949 ASSERT_EQ(2u, browser_list->size());
1950
1951 // Switching display mode should cancel the drag operation.
1952 ash::DisplayManager* display_manager =
1953 ash::Shell::GetInstance()->display_manager();
1954 display_manager->AddRemoveDisplay();
1955 }
1956
1957 // Invoked from the nested message loop.
CancelDragTabToWindowInSeparateDisplayStep2(DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest * test,TabStrip * tab_strip,aura::Window * current_root,gfx::Point final_destination,const BrowserList * browser_list)1958 void CancelDragTabToWindowInSeparateDisplayStep2(
1959 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest* test,
1960 TabStrip* tab_strip,
1961 aura::Window* current_root,
1962 gfx::Point final_destination,
1963 const BrowserList* browser_list) {
1964 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1965 ASSERT_TRUE(TabDragController::IsActive());
1966 ASSERT_EQ(2u, browser_list->size());
1967
1968 Browser* new_browser = browser_list->get(1);
1969 EXPECT_EQ(current_root,
1970 new_browser->window()->GetNativeWindow()->GetRootWindow());
1971
1972 ASSERT_TRUE(test->DragTabAndExecuteTaskWhenDone(
1973 final_destination,
1974 base::Bind(&CancelDragTabToWindowInSeparateDisplayStep3,
1975 tab_strip, browser_list)));
1976 }
1977
1978 } // namespace
1979
1980 // Drags from browser to a second display and releases input.
IN_PROC_BROWSER_TEST_F(DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest,DISABLED_CancelDragTabToWindowIn2ndDisplay)1981 IN_PROC_BROWSER_TEST_F(
1982 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest,
1983 DISABLED_CancelDragTabToWindowIn2ndDisplay) {
1984 // Add another tab.
1985 AddTabAndResetBrowser(browser());
1986 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1987
1988 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
1989
1990 // Move the second browser to the second display.
1991 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1992 ASSERT_EQ(2u, roots.size());
1993 gfx::Point final_destination =
1994 gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1995 roots[1]).work_area().CenterPoint();
1996
1997 // Move to the first tab and drag it enough so that it detaches, but not
1998 // enough to move to another display.
1999 gfx::Point tab_0_dst(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
2000 ASSERT_TRUE(Press(tab_0_dst));
2001 tab_0_dst.Offset(0, GetDetachY(tab_strip));
2002 ASSERT_TRUE(DragTabAndExecuteTaskWhenDone(
2003 tab_0_dst, base::Bind(&CancelDragTabToWindowInSeparateDisplayStep2,
2004 this, tab_strip, roots[0], final_destination,
2005 native_browser_list)));
2006 QuitWhenNotDragging();
2007
2008 ASSERT_EQ(1u, native_browser_list->size());
2009 ASSERT_FALSE(tab_strip->IsDragSessionActive());
2010 ASSERT_FALSE(TabDragController::IsActive());
2011 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2012
2013 // Release the mouse
2014 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
2015 ui_controls::LEFT, ui_controls::UP));
2016 }
2017
2018 // Drags from browser from a second display to primary and releases input.
IN_PROC_BROWSER_TEST_F(DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest,DISABLED_CancelDragTabToWindowIn1stDisplay)2019 IN_PROC_BROWSER_TEST_F(
2020 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest,
2021 DISABLED_CancelDragTabToWindowIn1stDisplay) {
2022 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
2023 ASSERT_EQ(2u, roots.size());
2024
2025 // Add another tab.
2026 AddTabAndResetBrowser(browser());
2027 TabStrip* tab_strip = GetTabStripForBrowser(browser());
2028
2029 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2030 EXPECT_EQ(roots[0], browser()->window()->GetNativeWindow()->GetRootWindow());
2031
2032 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->
2033 GetDisplayNearestWindow(roots[1]).work_area();
2034 browser()->window()->SetBounds(work_area);
2035 EXPECT_EQ(roots[1], browser()->window()->GetNativeWindow()->GetRootWindow());
2036
2037 // Move the second browser to the display.
2038 gfx::Point final_destination =
2039 gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
2040 roots[0]).work_area().CenterPoint();
2041
2042 // Move to the first tab and drag it enough so that it detaches, but not
2043 // enough to move to another display.
2044 gfx::Point tab_0_dst(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
2045 ASSERT_TRUE(Press(tab_0_dst));
2046 tab_0_dst.Offset(0, GetDetachY(tab_strip));
2047 ASSERT_TRUE(DragTabAndExecuteTaskWhenDone(
2048 tab_0_dst, base::Bind(&CancelDragTabToWindowInSeparateDisplayStep2,
2049 this, tab_strip, roots[1], final_destination,
2050 native_browser_list)));
2051 QuitWhenNotDragging();
2052
2053 ASSERT_EQ(1u, native_browser_list->size());
2054 ASSERT_FALSE(tab_strip->IsDragSessionActive());
2055 ASSERT_FALSE(TabDragController::IsActive());
2056 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2057
2058 // Release the mouse
2059 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
2060 ui_controls::LEFT, ui_controls::UP));
2061 }
2062
2063 namespace {
2064
PressSecondFingerWhileDetachedStep2(DetachToBrowserTabDragControllerTest * test)2065 void PressSecondFingerWhileDetachedStep2(
2066 DetachToBrowserTabDragControllerTest* test) {
2067 ASSERT_TRUE(TabDragController::IsActive());
2068 ASSERT_EQ(2u, test->native_browser_list->size());
2069 Browser* new_browser = test->native_browser_list->get(1);
2070 ASSERT_TRUE(new_browser->window()->IsActive());
2071
2072 ASSERT_TRUE(test->PressInput2());
2073 }
2074
2075 } // namespace
2076
2077 // Detaches a tab and while detached presses a second finger.
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestTouch,DISABLED_PressSecondFingerWhileDetached)2078 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestTouch,
2079 DISABLED_PressSecondFingerWhileDetached) {
2080 gfx::Rect bounds(browser()->window()->GetBounds());
2081 // Add another tab.
2082 AddTabAndResetBrowser(browser());
2083 TabStrip* tab_strip = GetTabStripForBrowser(browser());
2084 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2085
2086 // Move to the first tab and drag it enough so that it detaches.
2087 gfx::Point tab_0_center(
2088 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
2089 ASSERT_TRUE(PressInput(tab_0_center));
2090 ASSERT_TRUE(DragInputToDelayedNotifyWhenDone(
2091 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
2092 base::Bind(&PressSecondFingerWhileDetachedStep2, this),
2093 base::TimeDelta::FromMilliseconds(60)));
2094 QuitWhenNotDragging();
2095
2096 // The drag should have been reverted.
2097 ASSERT_EQ(1u, native_browser_list->size());
2098 ASSERT_FALSE(tab_strip->IsDragSessionActive());
2099 ASSERT_FALSE(TabDragController::IsActive());
2100 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2101
2102 ASSERT_TRUE(ReleaseInput());
2103 ASSERT_TRUE(ReleaseInput2());
2104 }
2105
2106 #if defined(OS_CHROMEOS)
2107
2108 namespace {
2109
DetachToDockedWindowNextStep(DetachToBrowserTabDragControllerTest * test,const gfx::Point & target_point,int iteration)2110 void DetachToDockedWindowNextStep(
2111 DetachToBrowserTabDragControllerTest* test,
2112 const gfx::Point& target_point,
2113 int iteration) {
2114 ASSERT_EQ(2u, test->native_browser_list->size());
2115 Browser* new_browser = test->native_browser_list->get(1);
2116 ASSERT_TRUE(new_browser->window()->IsActive());
2117
2118 if (!iteration) {
2119 ASSERT_TRUE(test->ReleaseInput());
2120 return;
2121 }
2122 ASSERT_TRUE(test->DragInputToNotifyWhenDone(
2123 target_point.x(), target_point.y(),
2124 base::Bind(&DetachToDockedWindowNextStep,
2125 test,
2126 gfx::Point(target_point.x(), 1 + target_point.y()),
2127 iteration - 1)));
2128 }
2129
2130 } // namespace
2131
2132 // Drags from browser to separate window, docks that window and releases mouse.
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,DISABLED_DetachToDockedWindowFromMaximizedWindow)2133 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
2134 DISABLED_DetachToDockedWindowFromMaximizedWindow) {
2135 // Maximize the initial browser window.
2136 browser()->window()->Maximize();
2137 ASSERT_TRUE(browser()->window()->IsMaximized());
2138
2139 // Add another tab.
2140 AddTabAndResetBrowser(browser());
2141 TabStrip* tab_strip = GetTabStripForBrowser(browser());
2142
2143 // Move to the first tab and drag it enough so that it detaches.
2144 gfx::Point tab_0_center(
2145 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
2146 ASSERT_TRUE(PressInput(tab_0_center));
2147
2148 // The following matches kMovesBeforeAdjust in snap_sizer.cc
2149 const int kNumIterations = 25 * 5 + 10;
2150 ASSERT_TRUE(DragInputToNotifyWhenDone(
2151 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
2152 base::Bind(&DetachToDockedWindowNextStep, this,
2153 gfx::Point(0, tab_0_center.y() + GetDetachY(tab_strip)),
2154 kNumIterations)));
2155 // Continue dragging enough times to go through snapping sequence and dock
2156 // the window.
2157 QuitWhenNotDragging();
2158 // Should no longer be dragging.
2159 ASSERT_FALSE(tab_strip->IsDragSessionActive());
2160 ASSERT_FALSE(TabDragController::IsActive());
2161
2162 // There should now be another browser.
2163 ASSERT_EQ(2u, native_browser_list->size());
2164 Browser* new_browser = native_browser_list->get(1);
2165 ASSERT_TRUE(new_browser->window()->IsActive());
2166 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
2167 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
2168
2169 EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
2170 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
2171
2172 // The bounds of the initial window should not have changed.
2173 EXPECT_TRUE(browser()->window()->IsMaximized());
2174
2175 EXPECT_FALSE(GetIsDragged(browser()));
2176 EXPECT_FALSE(GetIsDragged(new_browser));
2177 // After this both windows should still be manageable.
2178 EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
2179 EXPECT_TRUE(IsWindowPositionManaged(
2180 new_browser->window()->GetNativeWindow()));
2181
2182 ash::wm::WindowState* window_state =
2183 ash::wm::GetWindowState(new_browser->window()->GetNativeWindow());
2184 // The new window should not be maximized because it gets docked or snapped.
2185 EXPECT_FALSE(new_browser->window()->IsMaximized());
2186 // The new window should be docked and not snapped.
2187 EXPECT_TRUE(window_state->IsDocked());
2188 EXPECT_FALSE(window_state->IsSnapped());
2189 }
2190
2191 #endif // OS_CHROMEOS
2192
2193 #endif
2194
2195 #if defined(USE_ASH) && defined(OS_CHROMEOS) // TODO(win_ash,linux_ash)
2196 INSTANTIATE_TEST_CASE_P(TabDragging,
2197 DetachToBrowserInSeparateDisplayTabDragControllerTest,
2198 ::testing::Values("mouse", "touch"));
2199 INSTANTIATE_TEST_CASE_P(TabDragging,
2200 DifferentDeviceScaleFactorDisplayTabDragControllerTest,
2201 ::testing::Values("mouse"));
2202 INSTANTIATE_TEST_CASE_P(TabDragging,
2203 DetachToBrowserTabDragControllerTest,
2204 ::testing::Values("mouse", "touch"));
2205 INSTANTIATE_TEST_CASE_P(TabDragging,
2206 DetachToBrowserTabDragControllerTestTouch,
2207 ::testing::Values("touch"));
2208 #elif defined(USE_ASH)
2209 INSTANTIATE_TEST_CASE_P(TabDragging,
2210 DetachToBrowserTabDragControllerTest,
2211 ::testing::Values("mouse"));
2212 #endif
2213