1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.h"
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"
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"
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_delegate_aura.h"
55 #include "ui/aura/window_event_dispatcher.h"
56 #include "ui/events/test/event_generator.h"
59 using content::WebContents;
65 const char kTabDragControllerInteractiveUITestUserDataKey[] =
66 "TabDragControllerInteractiveUITestUserData";
68 class TabDragControllerInteractiveUITestUserData
69 : public base::SupportsUserData::Data {
71 explicit TabDragControllerInteractiveUITestUserData(int id) : id_(id) {}
72 virtual ~TabDragControllerInteractiveUITestUserData() {}
73 int id() { return id_; }
81 class QuitDraggingObserver : public content::NotificationObserver {
83 QuitDraggingObserver() {
84 registrar_.Add(this, chrome::NOTIFICATION_TAB_DRAG_LOOP_DONE,
85 content::NotificationService::AllSources());
88 virtual void Observe(int type,
89 const content::NotificationSource& source,
90 const content::NotificationDetails& details) OVERRIDE {
91 DCHECK_EQ(chrome::NOTIFICATION_TAB_DRAG_LOOP_DONE, type);
92 base::MessageLoopForUI::current()->Quit();
97 virtual ~QuitDraggingObserver() {}
99 content::NotificationRegistrar registrar_;
101 DISALLOW_COPY_AND_ASSIGN(QuitDraggingObserver);
104 gfx::Point GetCenterInScreenCoordinates(const views::View* view) {
105 gfx::Point center(view->width() / 2, view->height() / 2);
106 views::View::ConvertPointToScreen(view, ¢er);
110 void SetID(WebContents* web_contents, int id) {
111 web_contents->SetUserData(&kTabDragControllerInteractiveUITestUserDataKey,
112 new TabDragControllerInteractiveUITestUserData(id));
115 void ResetIDs(TabStripModel* model, int start) {
116 for (int i = 0; i < model->count(); ++i)
117 SetID(model->GetWebContentsAt(i), start + i);
120 std::string IDString(TabStripModel* model) {
122 for (int i = 0; i < model->count(); ++i) {
125 WebContents* contents = model->GetWebContentsAt(i);
126 TabDragControllerInteractiveUITestUserData* user_data =
127 static_cast<TabDragControllerInteractiveUITestUserData*>(
128 contents->GetUserData(
129 &kTabDragControllerInteractiveUITestUserDataKey));
131 result += base::IntToString(user_data->id());
138 // Creates a listener that quits the message loop when no longer dragging.
139 void QuitWhenNotDraggingImpl() {
140 new QuitDraggingObserver(); // QuitDraggingObserver deletes itself.
143 TabStrip* GetTabStripForBrowser(Browser* browser) {
144 BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
145 return static_cast<TabStrip*>(browser_view->tabstrip());
150 using test::GetCenterInScreenCoordinates;
152 using test::ResetIDs;
153 using test::IDString;
154 using test::GetTabStripForBrowser;
156 TabDragControllerTest::TabDragControllerTest()
157 : native_browser_list(BrowserList::GetInstance(
158 chrome::HOST_DESKTOP_TYPE_NATIVE)) {
161 TabDragControllerTest::~TabDragControllerTest() {
164 void TabDragControllerTest::StopAnimating(TabStrip* tab_strip) {
165 tab_strip->StopAnimating(true);
168 void TabDragControllerTest::AddTabAndResetBrowser(Browser* browser) {
169 AddBlankTabAndShow(browser);
170 StopAnimating(GetTabStripForBrowser(browser));
171 ResetIDs(browser->tab_strip_model(), 0);
174 Browser* TabDragControllerTest::CreateAnotherWindowBrowserAndRelayout() {
175 // Create another browser.
176 Browser* browser2 = CreateBrowser(browser()->profile());
177 ResetIDs(browser2->tab_strip_model(), 100);
179 // Resize the two windows so they're right next to each other.
180 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
181 browser()->window()->GetNativeWindow()).work_area();
182 gfx::Size half_size =
183 gfx::Size(work_area.width() / 3 - 10, work_area.height() / 2 - 10);
184 browser()->window()->SetBounds(gfx::Rect(work_area.origin(), half_size));
185 browser2->window()->SetBounds(gfx::Rect(
186 work_area.x() + half_size.width(), work_area.y(),
187 half_size.width(), half_size.height()));
194 INPUT_SOURCE_MOUSE = 0,
195 INPUT_SOURCE_TOUCH = 1
198 int GetDetachY(TabStrip* tab_strip) {
199 return std::max(TabDragController::kTouchVerticalDetachMagnetism,
200 TabDragController::kVerticalDetachMagnetism) +
201 tab_strip->height() + 1;
204 bool GetIsDragged(Browser* browser) {
205 #if !defined(USE_ASH) || defined(OS_WIN) // TODO(win_ash)
208 return ash::wm::GetWindowState(browser->window()->GetNativeWindow())->
215 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
216 class ScreenEventGeneratorDelegate
217 : public aura::test::EventGeneratorDelegateAura {
219 explicit ScreenEventGeneratorDelegate(aura::Window* root_window)
220 : root_window_(root_window) {}
221 virtual ~ScreenEventGeneratorDelegate() {}
223 // EventGeneratorDelegateAura overrides:
224 virtual aura::WindowTreeHost* GetHostAt(
225 const gfx::Point& point) const OVERRIDE {
226 return root_window_->GetHost();
229 virtual aura::client::ScreenPositionClient* GetScreenPositionClient(
230 const aura::Window* window) const OVERRIDE {
231 return aura::client::GetScreenPositionClient(root_window_);
235 aura::Window* root_window_;
237 DISALLOW_COPY_AND_ASSIGN(ScreenEventGeneratorDelegate);
242 #if !defined(OS_CHROMEOS)
244 // Following classes verify a crash scenario. Specifically on Windows when focus
245 // changes it can trigger capture being lost. This was causing a crash in tab
246 // dragging as it wasn't set up to handle this scenario. These classes
247 // synthesize this scenario.
249 // Allows making ClearNativeFocus() invoke ReleaseCapture().
250 class TestDesktopBrowserFrameAura : public DesktopBrowserFrameAura {
252 TestDesktopBrowserFrameAura(
253 BrowserFrame* browser_frame,
254 BrowserView* browser_view)
255 : DesktopBrowserFrameAura(browser_frame, browser_view),
256 release_capture_(false) {}
257 virtual ~TestDesktopBrowserFrameAura() {}
259 void ReleaseCaptureOnNextClear() {
260 release_capture_ = true;
263 virtual void ClearNativeFocus() OVERRIDE {
264 views::DesktopNativeWidgetAura::ClearNativeFocus();
265 if (release_capture_) {
266 release_capture_ = false;
267 GetWidget()->ReleaseCapture();
272 // If true ReleaseCapture() is invoked in ClearNativeFocus().
273 bool release_capture_;
275 DISALLOW_COPY_AND_ASSIGN(TestDesktopBrowserFrameAura);
278 // Factory for creating a TestDesktopBrowserFrameAura.
279 class TestNativeBrowserFrameFactory : public NativeBrowserFrameFactory {
281 TestNativeBrowserFrameFactory() {}
282 virtual ~TestNativeBrowserFrameFactory() {}
284 virtual NativeBrowserFrame* Create(
285 BrowserFrame* browser_frame,
286 BrowserView* browser_view) OVERRIDE {
287 return new TestDesktopBrowserFrameAura(browser_frame, browser_view);
291 DISALLOW_COPY_AND_ASSIGN(TestNativeBrowserFrameFactory);
294 class TabDragCaptureLostTest : public TabDragControllerTest {
296 TabDragCaptureLostTest() {
297 NativeBrowserFrameFactory::Set(new TestNativeBrowserFrameFactory);
301 DISALLOW_COPY_AND_ASSIGN(TabDragCaptureLostTest);
304 // See description above for details.
305 IN_PROC_BROWSER_TEST_F(TabDragCaptureLostTest, ReleaseCaptureOnDrag) {
306 AddTabAndResetBrowser(browser());
308 TabStrip* tab_strip = GetTabStripForBrowser(browser());
309 gfx::Point tab_1_center(GetCenterInScreenCoordinates(tab_strip->tab_at(1)));
310 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_1_center) &&
311 ui_test_utils::SendMouseEventsSync(
312 ui_controls::LEFT, ui_controls::DOWN));
313 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
314 TestDesktopBrowserFrameAura* frame =
315 static_cast<TestDesktopBrowserFrameAura*>(
316 BrowserView::GetBrowserViewForBrowser(browser())->GetWidget()->
317 native_widget_private());
318 // Invoke ReleaseCaptureOnDrag() so that when the drag happens and focus
319 // changes capture is released and the drag cancels.
320 frame->ReleaseCaptureOnNextClear();
321 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center));
322 EXPECT_FALSE(tab_strip->IsDragSessionActive());
325 IN_PROC_BROWSER_TEST_F(TabDragControllerTest, GestureEndShouldEndDragTest) {
326 AddTabAndResetBrowser(browser());
328 TabStrip* tab_strip = GetTabStripForBrowser(browser());
330 Tab* tab1 = tab_strip->tab_at(1);
331 gfx::Point tab_1_center(tab1->width() / 2, tab1->height() / 2);
333 ui::GestureEvent gesture_tap_down(
338 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
339 tab_strip->MaybeStartDrag(tab1, gesture_tap_down,
340 tab_strip->GetSelectionModel());
341 EXPECT_TRUE(TabDragController::IsActive());
343 ui::GestureEvent gesture_end(tab_1_center.x(),
347 ui::GestureEventDetails(ui::ET_GESTURE_END));
348 tab_strip->OnGestureEvent(&gesture_end);
349 EXPECT_FALSE(TabDragController::IsActive());
350 EXPECT_FALSE(tab_strip->IsDragSessionActive());
355 class DetachToBrowserTabDragControllerTest
356 : public TabDragControllerTest,
357 public ::testing::WithParamInterface<const char*> {
359 DetachToBrowserTabDragControllerTest() {}
361 virtual void SetUpOnMainThread() OVERRIDE {
362 #if defined(OS_CHROMEOS)
363 event_generator_.reset(
364 new ui::test::EventGenerator(ash::Shell::GetPrimaryRootWindow()));
368 InputSource input_source() const {
369 return strstr(GetParam(), "mouse") ?
370 INPUT_SOURCE_MOUSE : INPUT_SOURCE_TOUCH;
373 // Set root window from a point in screen coordinates
374 void SetEventGeneratorRootWindow(const gfx::Point& point) {
375 if (input_source() == INPUT_SOURCE_MOUSE)
377 #if defined(OS_CHROMEOS)
378 event_generator_.reset(new ui::test::EventGenerator(
379 new ScreenEventGeneratorDelegate(ash::wm::GetRootWindowAt(point))));
383 // The following methods update one of the mouse or touch input depending upon
385 bool PressInput(const gfx::Point& location) {
386 if (input_source() == INPUT_SOURCE_MOUSE) {
387 return ui_test_utils::SendMouseMoveSync(location) &&
388 ui_test_utils::SendMouseEventsSync(
389 ui_controls::LEFT, ui_controls::DOWN);
391 #if defined(OS_CHROMEOS)
392 event_generator_->set_current_location(location);
393 event_generator_->PressTouch();
401 // Second touch input is only used for touch sequence tests.
402 EXPECT_EQ(INPUT_SOURCE_TOUCH, input_source());
403 #if defined(OS_CHROMEOS)
404 event_generator_->set_current_location(
405 event_generator_->current_location());
406 event_generator_->PressTouchId(1);
413 bool DragInputTo(const gfx::Point& location) {
414 if (input_source() == INPUT_SOURCE_MOUSE)
415 return ui_test_utils::SendMouseMoveSync(location);
416 #if defined(OS_CHROMEOS)
417 event_generator_->MoveTouch(location);
424 bool DragInputToAsync(const gfx::Point& location) {
425 if (input_source() == INPUT_SOURCE_MOUSE)
426 return ui_controls::SendMouseMove(location.x(), location.y());
427 #if defined(OS_CHROMEOS)
428 event_generator_->MoveTouch(location);
435 bool DragInputToNotifyWhenDone(int x,
437 const base::Closure& task) {
438 if (input_source() == INPUT_SOURCE_MOUSE)
439 return ui_controls::SendMouseMoveNotifyWhenDone(x, y, task);
440 #if defined(OS_CHROMEOS)
441 base::MessageLoop::current()->PostTask(FROM_HERE, task);
442 event_generator_->MoveTouch(gfx::Point(x, y));
449 bool DragInputToDelayedNotifyWhenDone(int x,
451 const base::Closure& task,
452 base::TimeDelta delay) {
453 if (input_source() == INPUT_SOURCE_MOUSE)
454 return ui_controls::SendMouseMoveNotifyWhenDone(x, y, task);
455 #if defined(OS_CHROMEOS)
456 base::MessageLoop::current()->PostDelayedTask(FROM_HERE, task, delay);
457 event_generator_->MoveTouch(gfx::Point(x, y));
464 bool DragInput2ToNotifyWhenDone(int x,
466 const base::Closure& task) {
467 if (input_source() == INPUT_SOURCE_MOUSE)
468 return ui_controls::SendMouseMoveNotifyWhenDone(x, y, task);
469 #if defined(OS_CHROMEOS)
470 base::MessageLoop::current()->PostTask(FROM_HERE, task);
471 event_generator_->MoveTouchId(gfx::Point(x, y), 1);
478 bool ReleaseInput() {
479 if (input_source() == INPUT_SOURCE_MOUSE) {
480 return ui_test_utils::SendMouseEventsSync(
481 ui_controls::LEFT, ui_controls::UP);
483 #if defined(OS_CHROMEOS)
484 event_generator_->ReleaseTouch();
491 bool ReleaseInput2() {
492 if (input_source() == INPUT_SOURCE_MOUSE) {
493 return ui_test_utils::SendMouseEventsSync(
494 ui_controls::LEFT, ui_controls::UP);
496 #if defined(OS_CHROMEOS)
497 event_generator_->ReleaseTouchId(1);
504 bool ReleaseMouseAsync() {
505 return input_source() == INPUT_SOURCE_MOUSE &&
506 ui_controls::SendMouseEvents(ui_controls::LEFT, ui_controls::UP);
509 void QuitWhenNotDragging() {
510 if (input_source() == INPUT_SOURCE_MOUSE) {
511 // Schedule observer to quit message loop when done dragging. This has to
512 // be async so the message loop can run.
513 test::QuitWhenNotDraggingImpl();
514 base::MessageLoop::current()->Run();
516 // Touch events are sync, so we know we're not in a drag session. But some
517 // tests rely on the browser fully closing, which is async. So, run all
519 base::RunLoop run_loop;
520 run_loop.RunUntilIdle();
524 void AddBlankTabAndShow(Browser* browser) {
525 InProcessBrowserTest::AddBlankTabAndShow(browser);
528 Browser* browser() const { return InProcessBrowserTest::browser(); }
531 #if defined(OS_CHROMEOS)
532 scoped_ptr<ui::test::EventGenerator> event_generator_;
535 DISALLOW_COPY_AND_ASSIGN(DetachToBrowserTabDragControllerTest);
538 // Creates a browser with two tabs, drags the second to the first.
539 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, DragInSameWindow) {
540 // TODO(sky): this won't work with touch as it requires a long press.
541 if (input_source() == INPUT_SOURCE_TOUCH) {
542 VLOG(1) << "Test is DISABLED for touch input.";
546 AddTabAndResetBrowser(browser());
548 TabStrip* tab_strip = GetTabStripForBrowser(browser());
549 TabStripModel* model = browser()->tab_strip_model();
551 gfx::Point tab_1_center(GetCenterInScreenCoordinates(tab_strip->tab_at(1)));
552 ASSERT_TRUE(PressInput(tab_1_center));
553 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
554 ASSERT_TRUE(DragInputTo(tab_0_center));
555 ASSERT_TRUE(ReleaseInput());
556 EXPECT_EQ("1 0", IDString(model));
557 EXPECT_FALSE(TabDragController::IsActive());
558 EXPECT_FALSE(tab_strip->IsDragSessionActive());
560 // The tab strip should no longer have capture because the drag was ended and
561 // mouse/touch was released.
562 EXPECT_FALSE(tab_strip->GetWidget()->HasCapture());
567 // Invoked from the nested message loop.
568 void DragToSeparateWindowStep2(DetachToBrowserTabDragControllerTest* test,
569 TabStrip* not_attached_tab_strip,
570 TabStrip* target_tab_strip) {
571 ASSERT_FALSE(not_attached_tab_strip->IsDragSessionActive());
572 ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
573 ASSERT_TRUE(TabDragController::IsActive());
575 // Drag to target_tab_strip. This should stop the nested loop from dragging
577 gfx::Point target_point(target_tab_strip->width() -1,
578 target_tab_strip->height() / 2);
579 views::View::ConvertPointToScreen(target_tab_strip, &target_point);
580 ASSERT_TRUE(test->DragInputToAsync(target_point));
585 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
586 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
587 // compositor. crbug.com/331924
588 #define MAYBE_DragToSeparateWindow DISABLED_DragToSeparateWindow
590 #define MAYBE_DragToSeparateWindow DragToSeparateWindow
592 // Creates two browsers, drags from first into second.
593 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
594 MAYBE_DragToSeparateWindow) {
595 TabStrip* tab_strip = GetTabStripForBrowser(browser());
597 // Add another tab to browser().
598 AddTabAndResetBrowser(browser());
600 // Create another browser.
601 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
602 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
604 // Move to the first tab and drag it enough so that it detaches, but not
605 // enough that it attaches to browser2.
606 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
607 ASSERT_TRUE(PressInput(tab_0_center));
608 ASSERT_TRUE(DragInputToNotifyWhenDone(
609 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
610 base::Bind(&DragToSeparateWindowStep2,
611 this, tab_strip, tab_strip2)));
612 QuitWhenNotDragging();
614 // Should now be attached to tab_strip2.
615 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
616 ASSERT_FALSE(tab_strip->IsDragSessionActive());
617 ASSERT_TRUE(TabDragController::IsActive());
618 EXPECT_FALSE(GetIsDragged(browser()));
620 // Release mouse or touch, stopping the drag session.
621 ASSERT_TRUE(ReleaseInput());
622 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
623 ASSERT_FALSE(tab_strip->IsDragSessionActive());
624 ASSERT_FALSE(TabDragController::IsActive());
625 EXPECT_EQ("100 0", IDString(browser2->tab_strip_model()));
626 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
627 EXPECT_FALSE(GetIsDragged(browser2));
629 // Both windows should not be maximized
630 EXPECT_FALSE(browser()->window()->IsMaximized());
631 EXPECT_FALSE(browser2->window()->IsMaximized());
633 // The tab strip should no longer have capture because the drag was ended and
634 // mouse/touch was released.
635 EXPECT_FALSE(tab_strip->GetWidget()->HasCapture());
636 EXPECT_FALSE(tab_strip2->GetWidget()->HasCapture());
641 void DetachToOwnWindowStep2(DetachToBrowserTabDragControllerTest* test) {
642 if (test->input_source() == INPUT_SOURCE_TOUCH)
643 ASSERT_TRUE(test->ReleaseInput());
646 #if defined(OS_CHROMEOS)
647 bool IsWindowPositionManaged(aura::Window* window) {
648 return ash::wm::GetWindowState(window)->window_position_managed();
650 bool HasUserChangedWindowPositionOrSize(aura::Window* window) {
651 return ash::wm::GetWindowState(window)->bounds_changed_by_user();
654 bool IsWindowPositionManaged(gfx::NativeWindow window) {
657 bool HasUserChangedWindowPositionOrSize(gfx::NativeWindow window) {
664 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
665 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
666 // compositor. crbug.com/331924
667 #define MAYBE_DetachToOwnWindow DISABLED_DetachToOwnWindow
669 #define MAYBE_DetachToOwnWindow DetachToOwnWindow
671 // Drags from browser to separate window and releases mouse.
672 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
673 MAYBE_DetachToOwnWindow) {
674 const gfx::Rect initial_bounds(browser()->window()->GetBounds());
676 AddTabAndResetBrowser(browser());
677 TabStrip* tab_strip = GetTabStripForBrowser(browser());
679 // Move to the first tab and drag it enough so that it detaches.
680 gfx::Point tab_0_center(
681 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
682 ASSERT_TRUE(PressInput(tab_0_center));
683 ASSERT_TRUE(DragInputToNotifyWhenDone(
684 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
685 base::Bind(&DetachToOwnWindowStep2, this)));
686 if (input_source() == INPUT_SOURCE_MOUSE) {
687 ASSERT_TRUE(ReleaseMouseAsync());
688 QuitWhenNotDragging();
691 // Should no longer be dragging.
692 ASSERT_FALSE(tab_strip->IsDragSessionActive());
693 ASSERT_FALSE(TabDragController::IsActive());
695 // There should now be another browser.
696 ASSERT_EQ(2u, native_browser_list->size());
697 Browser* new_browser = native_browser_list->get(1);
698 ASSERT_TRUE(new_browser->window()->IsActive());
699 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
700 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
702 EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
703 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
705 // The bounds of the initial window should not have changed.
706 EXPECT_EQ(initial_bounds.ToString(),
707 browser()->window()->GetBounds().ToString());
709 EXPECT_FALSE(GetIsDragged(browser()));
710 EXPECT_FALSE(GetIsDragged(new_browser));
711 // After this both windows should still be manageable.
712 EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
713 EXPECT_TRUE(IsWindowPositionManaged(
714 new_browser->window()->GetNativeWindow()));
716 // Both windows should not be maximized
717 EXPECT_FALSE(browser()->window()->IsMaximized());
718 EXPECT_FALSE(new_browser->window()->IsMaximized());
720 // The tab strip should no longer have capture because the drag was ended and
721 // mouse/touch was released.
722 EXPECT_FALSE(tab_strip->GetWidget()->HasCapture());
723 EXPECT_FALSE(tab_strip2->GetWidget()->HasCapture());
726 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
727 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
728 // compositor. crbug.com/331924
729 #define MAYBE_DetachToOwnWindowFromMaximizedWindow \
730 DISABLED_DetachToOwnWindowFromMaximizedWindow
732 #define MAYBE_DetachToOwnWindowFromMaximizedWindow \
733 DetachToOwnWindowFromMaximizedWindow
735 // Drags from browser to a separate window and releases mouse.
736 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
737 MAYBE_DetachToOwnWindowFromMaximizedWindow) {
738 // Maximize the initial browser window.
739 browser()->window()->Maximize();
740 ASSERT_TRUE(browser()->window()->IsMaximized());
743 AddTabAndResetBrowser(browser());
744 TabStrip* tab_strip = GetTabStripForBrowser(browser());
746 // Move to the first tab and drag it enough so that it detaches.
747 gfx::Point tab_0_center(
748 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
749 ASSERT_TRUE(PressInput(tab_0_center));
750 ASSERT_TRUE(DragInputToNotifyWhenDone(
751 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
752 base::Bind(&DetachToOwnWindowStep2, this)));
753 if (input_source() == INPUT_SOURCE_MOUSE) {
754 ASSERT_TRUE(ReleaseMouseAsync());
755 QuitWhenNotDragging();
758 // Should no longer be dragging.
759 ASSERT_FALSE(tab_strip->IsDragSessionActive());
760 ASSERT_FALSE(TabDragController::IsActive());
762 // There should now be another browser.
763 ASSERT_EQ(2u, native_browser_list->size());
764 Browser* new_browser = native_browser_list->get(1);
765 ASSERT_TRUE(new_browser->window()->IsActive());
766 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
767 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
769 EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
770 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
772 // The bounds of the initial window should not have changed.
773 EXPECT_TRUE(browser()->window()->IsMaximized());
775 EXPECT_FALSE(GetIsDragged(browser()));
776 EXPECT_FALSE(GetIsDragged(new_browser));
777 // After this both windows should still be manageable.
778 EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
779 EXPECT_TRUE(IsWindowPositionManaged(
780 new_browser->window()->GetNativeWindow()));
782 // The new window should be maximized.
783 EXPECT_TRUE(new_browser->window()->IsMaximized());
786 // Deletes a tab being dragged before the user moved enough to start a drag.
787 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
788 DeleteBeforeStartedDragging) {
790 AddTabAndResetBrowser(browser());
791 TabStrip* tab_strip = GetTabStripForBrowser(browser());
793 // Click on the first tab, but don't move it.
794 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
795 ASSERT_TRUE(PressInput(tab_0_center));
797 // Should be dragging.
798 ASSERT_TRUE(tab_strip->IsDragSessionActive());
799 ASSERT_TRUE(TabDragController::IsActive());
801 // Delete the tab being dragged.
802 delete browser()->tab_strip_model()->GetWebContentsAt(0);
804 // Should have canceled dragging.
805 ASSERT_FALSE(tab_strip->IsDragSessionActive());
806 ASSERT_FALSE(TabDragController::IsActive());
808 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
809 EXPECT_FALSE(GetIsDragged(browser()));
812 #if defined(OS_CHROMEOS)
813 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
814 // compositor. crbug.com/331924
815 #define MAYBE_DeleteTabWhileAttached DISABLED_DeleteTabWhileAttached
817 #define MAYBE_DeleteTabWhileAttached DeleteTabWhileAttached
819 // Deletes a tab being dragged while still attached.
820 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
821 MAYBE_DeleteTabWhileAttached) {
822 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
823 // compositor. crbug.com/331924
824 if (input_source() == INPUT_SOURCE_MOUSE) {
825 VLOG(1) << "Test is DISABLED for mouse input.";
830 AddTabAndResetBrowser(browser());
831 TabStrip* tab_strip = GetTabStripForBrowser(browser());
833 // Click on the first tab and move it enough so that it starts dragging but is
835 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
836 ASSERT_TRUE(PressInput(tab_0_center));
837 ASSERT_TRUE(DragInputTo(
838 gfx::Point(tab_0_center.x() + 20, tab_0_center.y())));
840 // Should be dragging.
841 ASSERT_TRUE(tab_strip->IsDragSessionActive());
842 ASSERT_TRUE(TabDragController::IsActive());
844 // Delete the tab being dragged.
845 delete browser()->tab_strip_model()->GetWebContentsAt(0);
847 // Should have canceled dragging.
848 ASSERT_FALSE(tab_strip->IsDragSessionActive());
849 ASSERT_FALSE(TabDragController::IsActive());
851 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
853 EXPECT_FALSE(GetIsDragged(browser()));
858 void DeleteWhileDetachedStep2(WebContents* tab) {
864 #if defined(OS_CHROMEOS)
865 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
866 // compositor. crbug.com/331924
867 #define MAYBE_DeleteTabWhileDetached DISABLED_DeleteTabWhileDetached
869 #define MAYBE_DeleteTabWhileDetached DeleteTabWhileDetached
871 // Deletes a tab being dragged after dragging a tab so that a new window is
873 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
874 MAYBE_DeleteTabWhileDetached) {
876 AddTabAndResetBrowser(browser());
877 TabStrip* tab_strip = GetTabStripForBrowser(browser());
879 // Move to the first tab and drag it enough so that it detaches.
880 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
881 WebContents* to_delete =
882 browser()->tab_strip_model()->GetWebContentsAt(0);
883 ASSERT_TRUE(PressInput(tab_0_center));
884 ASSERT_TRUE(DragInputToNotifyWhenDone(
885 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
886 base::Bind(&DeleteWhileDetachedStep2, to_delete)));
887 QuitWhenNotDragging();
889 // Should not be dragging.
890 ASSERT_FALSE(tab_strip->IsDragSessionActive());
891 ASSERT_FALSE(TabDragController::IsActive());
893 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
895 EXPECT_FALSE(GetIsDragged(browser()));
900 void DeleteSourceDetachedStep2(WebContents* tab,
901 const BrowserList* browser_list) {
902 ASSERT_EQ(2u, browser_list->size());
903 Browser* new_browser = browser_list->get(1);
904 // This ends up closing the source window.
907 ui_controls::SendKeyPress(new_browser->window()->GetNativeWindow(),
908 ui::VKEY_ESCAPE, false, false, false, false);
913 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
914 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
915 // compositor. crbug.com/331924
916 #define MAYBE_DeleteSourceDetached DISABLED_DeleteSourceDetached
918 #define MAYBE_DeleteSourceDetached DeleteSourceDetached
920 // Detaches a tab and while detached deletes a tab from the source so that the
921 // source window closes then presses escape to cancel the drag.
922 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
923 MAYBE_DeleteSourceDetached) {
925 AddTabAndResetBrowser(browser());
926 TabStrip* tab_strip = GetTabStripForBrowser(browser());
928 // Move to the first tab and drag it enough so that it detaches.
929 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
930 WebContents* to_delete = browser()->tab_strip_model()->GetWebContentsAt(1);
931 ASSERT_TRUE(PressInput(tab_0_center));
932 ASSERT_TRUE(DragInputToNotifyWhenDone(
933 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
934 base::Bind(&DeleteSourceDetachedStep2, to_delete, native_browser_list)));
935 QuitWhenNotDragging();
937 // Should not be dragging.
938 ASSERT_EQ(1u, native_browser_list->size());
939 Browser* new_browser = native_browser_list->get(0);
940 ASSERT_FALSE(GetTabStripForBrowser(new_browser)->IsDragSessionActive());
941 ASSERT_FALSE(TabDragController::IsActive());
943 EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
945 EXPECT_FALSE(GetIsDragged(new_browser));
947 // Remaining browser window should not be maximized
948 EXPECT_FALSE(new_browser->window()->IsMaximized());
953 void PressEscapeWhileDetachedStep2(const BrowserList* browser_list) {
954 ASSERT_EQ(2u, browser_list->size());
955 Browser* new_browser = browser_list->get(1);
956 ui_controls::SendKeyPress(
957 new_browser->window()->GetNativeWindow(), ui::VKEY_ESCAPE, false, false,
963 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
964 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
965 // compositor. crbug.com/331924
966 #define MAYBE_PressEscapeWhileDetached DISABLED_PressEscapeWhileDetached
968 #define MAYBE_PressEscapeWhileDetached PressEscapeWhileDetached
970 // This is disabled until NativeViewHost::Detach really detaches.
971 // Detaches a tab and while detached presses escape to revert the drag.
972 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
973 MAYBE_PressEscapeWhileDetached) {
975 AddTabAndResetBrowser(browser());
976 TabStrip* tab_strip = GetTabStripForBrowser(browser());
978 // Move to the first tab and drag it enough so that it detaches.
979 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
980 ASSERT_TRUE(PressInput(tab_0_center));
981 ASSERT_TRUE(DragInputToNotifyWhenDone(
982 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
983 base::Bind(&PressEscapeWhileDetachedStep2, native_browser_list)));
984 QuitWhenNotDragging();
986 // Should not be dragging.
987 ASSERT_FALSE(tab_strip->IsDragSessionActive());
988 ASSERT_FALSE(TabDragController::IsActive());
990 // And there should only be one window.
991 EXPECT_EQ(1u, native_browser_list->size());
993 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
995 // Remaining browser window should not be maximized
996 EXPECT_FALSE(browser()->window()->IsMaximized());
998 // The tab strip should no longer have capture because the drag was ended and
999 // mouse/touch was released.
1000 EXPECT_FALSE(tab_strip->GetWidget()->HasCapture());
1005 void DragAllStep2(DetachToBrowserTabDragControllerTest* test,
1006 const BrowserList* browser_list) {
1007 // Should only be one window.
1008 ASSERT_EQ(1u, browser_list->size());
1009 if (test->input_source() == INPUT_SOURCE_TOUCH) {
1010 ASSERT_TRUE(test->ReleaseInput());
1012 ASSERT_TRUE(test->ReleaseMouseAsync());
1018 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1019 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1020 // compositor. crbug.com/331924
1021 #define MAYBE_DragAll DISABLED_DragAll
1023 #define MAYBE_DragAll DragAll
1025 // Selects multiple tabs and starts dragging the window.
1026 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, MAYBE_DragAll) {
1028 AddTabAndResetBrowser(browser());
1029 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1030 browser()->tab_strip_model()->AddTabAtToSelection(0);
1031 browser()->tab_strip_model()->AddTabAtToSelection(1);
1033 // Move to the first tab and drag it enough so that it would normally
1035 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1036 ASSERT_TRUE(PressInput(tab_0_center));
1037 ASSERT_TRUE(DragInputToNotifyWhenDone(
1038 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1039 base::Bind(&DragAllStep2, this, native_browser_list)));
1040 QuitWhenNotDragging();
1042 // Should not be dragging.
1043 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1044 ASSERT_FALSE(TabDragController::IsActive());
1046 // And there should only be one window.
1047 EXPECT_EQ(1u, native_browser_list->size());
1049 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
1051 EXPECT_FALSE(GetIsDragged(browser()));
1053 // Remaining browser window should not be maximized
1054 EXPECT_FALSE(browser()->window()->IsMaximized());
1059 // Invoked from the nested message loop.
1060 void DragAllToSeparateWindowStep2(DetachToBrowserTabDragControllerTest* test,
1061 TabStrip* attached_tab_strip,
1062 TabStrip* target_tab_strip,
1063 const BrowserList* browser_list) {
1064 ASSERT_TRUE(attached_tab_strip->IsDragSessionActive());
1065 ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
1066 ASSERT_TRUE(TabDragController::IsActive());
1067 ASSERT_EQ(2u, browser_list->size());
1069 // Drag to target_tab_strip. This should stop the nested loop from dragging
1071 gfx::Point target_point(target_tab_strip->width() - 1,
1072 target_tab_strip->height() / 2);
1073 views::View::ConvertPointToScreen(target_tab_strip, &target_point);
1074 ASSERT_TRUE(test->DragInputToAsync(target_point));
1079 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1080 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1081 // compositor. crbug.com/331924
1082 #define MAYBE_DragAllToSeparateWindow DISABLED_DragAllToSeparateWindow
1084 #define MAYBE_DragAllToSeparateWindow DragAllToSeparateWindow
1086 // Creates two browsers, selects all tabs in first and drags into second.
1087 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1088 MAYBE_DragAllToSeparateWindow) {
1089 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1091 // Add another tab to browser().
1092 AddTabAndResetBrowser(browser());
1094 // Create another browser.
1095 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
1096 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1098 browser()->tab_strip_model()->AddTabAtToSelection(0);
1099 browser()->tab_strip_model()->AddTabAtToSelection(1);
1101 // Move to the first tab and drag it enough so that it detaches, but not
1102 // enough that it attaches to browser2.
1103 gfx::Point tab_0_center(
1104 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1105 ASSERT_TRUE(PressInput(tab_0_center));
1106 ASSERT_TRUE(DragInputToNotifyWhenDone(
1107 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1108 base::Bind(&DragAllToSeparateWindowStep2, this, tab_strip, tab_strip2,
1109 native_browser_list)));
1110 QuitWhenNotDragging();
1112 // Should now be attached to tab_strip2.
1113 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1114 ASSERT_TRUE(TabDragController::IsActive());
1115 ASSERT_EQ(1u, native_browser_list->size());
1117 // Release the mouse, stopping the drag session.
1118 ASSERT_TRUE(ReleaseInput());
1119 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1120 ASSERT_FALSE(TabDragController::IsActive());
1121 EXPECT_EQ("100 0 1", IDString(browser2->tab_strip_model()));
1123 EXPECT_FALSE(GetIsDragged(browser2));
1125 // Remaining browser window should not be maximized
1126 EXPECT_FALSE(browser2->window()->IsMaximized());
1131 // Invoked from the nested message loop.
1132 void DragAllToSeparateWindowAndCancelStep2(
1133 DetachToBrowserTabDragControllerTest* test,
1134 TabStrip* attached_tab_strip,
1135 TabStrip* target_tab_strip,
1136 const BrowserList* browser_list) {
1137 ASSERT_TRUE(attached_tab_strip->IsDragSessionActive());
1138 ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
1139 ASSERT_TRUE(TabDragController::IsActive());
1140 ASSERT_EQ(2u, browser_list->size());
1142 // Drag to target_tab_strip. This should stop the nested loop from dragging
1144 gfx::Point target_point(target_tab_strip->width() - 1,
1145 target_tab_strip->height() / 2);
1146 views::View::ConvertPointToScreen(target_tab_strip, &target_point);
1147 ASSERT_TRUE(test->DragInputToAsync(target_point));
1152 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1153 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1154 // compositor. crbug.com/331924
1155 #define MAYBE_DragAllToSeparateWindowAndCancel \
1156 DISABLED_DragAllToSeparateWindowAndCancel
1158 #define MAYBE_DragAllToSeparateWindowAndCancel DragAllToSeparateWindowAndCancel
1160 // Creates two browsers, selects all tabs in first, drags into second, then hits
1162 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1163 MAYBE_DragAllToSeparateWindowAndCancel) {
1164 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1166 // Add another tab to browser().
1167 AddTabAndResetBrowser(browser());
1169 // Create another browser.
1170 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
1171 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1173 browser()->tab_strip_model()->AddTabAtToSelection(0);
1174 browser()->tab_strip_model()->AddTabAtToSelection(1);
1176 // Move to the first tab and drag it enough so that it detaches, but not
1177 // enough that it attaches to browser2.
1178 gfx::Point tab_0_center(
1179 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1180 ASSERT_TRUE(PressInput(tab_0_center));
1181 ASSERT_TRUE(DragInputToNotifyWhenDone(
1182 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1183 base::Bind(&DragAllToSeparateWindowAndCancelStep2, this,
1184 tab_strip, tab_strip2, native_browser_list)));
1185 QuitWhenNotDragging();
1187 // Should now be attached to tab_strip2.
1188 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1189 ASSERT_TRUE(TabDragController::IsActive());
1190 ASSERT_EQ(1u, native_browser_list->size());
1193 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
1194 browser2, ui::VKEY_ESCAPE, false, false, false, false));
1196 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1197 ASSERT_FALSE(TabDragController::IsActive());
1198 EXPECT_EQ("100 0 1", IDString(browser2->tab_strip_model()));
1200 // browser() will have been destroyed, but browser2 should remain.
1201 ASSERT_EQ(1u, native_browser_list->size());
1203 EXPECT_FALSE(GetIsDragged(browser2));
1205 // Remaining browser window should not be maximized
1206 EXPECT_FALSE(browser2->window()->IsMaximized());
1209 #if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_WIN)
1210 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1211 // compositor. crbug.com/331924
1212 #define MAYBE_DragDirectlyToSecondWindow DISABLED_DragDirectlyToSecondWindow
1214 #define MAYBE_DragDirectlyToSecondWindow DragDirectlyToSecondWindow
1216 // Creates two browsers, drags from first into the second in such a way that
1217 // no detaching should happen.
1218 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1219 MAYBE_DragDirectlyToSecondWindow) {
1220 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1222 // Add another tab to browser().
1223 AddTabAndResetBrowser(browser());
1225 // Create another browser.
1226 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
1227 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1229 // Move the tabstrip down enough so that we can detach.
1230 gfx::Rect bounds(browser2->window()->GetBounds());
1231 bounds.Offset(0, 100);
1232 browser2->window()->SetBounds(bounds);
1234 // Move to the first tab and drag it enough so that it detaches, but not
1235 // enough that it attaches to browser2.
1236 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1237 ASSERT_TRUE(PressInput(tab_0_center));
1239 gfx::Point b2_location(5, 0);
1240 views::View::ConvertPointToScreen(tab_strip2, &b2_location);
1241 ASSERT_TRUE(DragInputTo(b2_location));
1243 // Should now be attached to tab_strip2.
1244 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1245 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1246 ASSERT_TRUE(TabDragController::IsActive());
1248 // Release the mouse, stopping the drag session.
1249 ASSERT_TRUE(ReleaseInput());
1250 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1251 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1252 ASSERT_FALSE(TabDragController::IsActive());
1253 EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1254 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1256 EXPECT_FALSE(GetIsDragged(browser()));
1257 EXPECT_FALSE(GetIsDragged(browser2));
1259 // Both windows should not be maximized
1260 EXPECT_FALSE(browser()->window()->IsMaximized());
1261 EXPECT_FALSE(browser2->window()->IsMaximized());
1264 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1265 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1266 // compositor. crbug.com/331924
1267 #define MAYBE_DragSingleTabToSeparateWindow \
1268 DISABLED_DragSingleTabToSeparateWindow
1270 #define MAYBE_DragSingleTabToSeparateWindow DragSingleTabToSeparateWindow
1272 // Creates two browsers, the first browser has a single tab and drags into the
1274 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1275 MAYBE_DragSingleTabToSeparateWindow) {
1276 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1278 ResetIDs(browser()->tab_strip_model(), 0);
1280 // Create another browser.
1281 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
1282 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1283 const gfx::Rect initial_bounds(browser2->window()->GetBounds());
1285 // Move to the first tab and drag it enough so that it detaches, but not
1286 // enough that it attaches to browser2.
1287 gfx::Point tab_0_center(
1288 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1289 ASSERT_TRUE(PressInput(tab_0_center));
1290 ASSERT_TRUE(DragInputToNotifyWhenDone(
1291 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1292 base::Bind(&DragAllToSeparateWindowStep2, this, tab_strip, tab_strip2,
1293 native_browser_list)));
1294 QuitWhenNotDragging();
1296 // Should now be attached to tab_strip2.
1297 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1298 ASSERT_TRUE(TabDragController::IsActive());
1299 ASSERT_EQ(1u, native_browser_list->size());
1301 // Release the mouse, stopping the drag session.
1302 ASSERT_TRUE(ReleaseInput());
1303 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1304 ASSERT_FALSE(TabDragController::IsActive());
1305 EXPECT_EQ("100 0", IDString(browser2->tab_strip_model()));
1307 EXPECT_FALSE(GetIsDragged(browser2));
1309 // Remaining browser window should not be maximized
1310 EXPECT_FALSE(browser2->window()->IsMaximized());
1312 // Make sure that the window is still managed and not user moved.
1313 EXPECT_TRUE(IsWindowPositionManaged(browser2->window()->GetNativeWindow()));
1314 EXPECT_FALSE(HasUserChangedWindowPositionOrSize(
1315 browser2->window()->GetNativeWindow()));
1316 // Also make sure that the drag to window position has not changed.
1317 EXPECT_EQ(initial_bounds.ToString(),
1318 browser2->window()->GetBounds().ToString());
1323 // Invoked from the nested message loop.
1324 void CancelOnNewTabWhenDraggingStep2(
1325 DetachToBrowserTabDragControllerTest* test,
1326 const BrowserList* browser_list) {
1327 ASSERT_TRUE(TabDragController::IsActive());
1328 ASSERT_EQ(2u, browser_list->size());
1330 // Add another tab. This should trigger exiting the nested loop.
1331 test->AddBlankTabAndShow(browser_list->GetLastActive());
1336 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1337 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1338 // compositor. crbug.com/331924
1339 #define MAYBE_CancelOnNewTabWhenDragging DISABLED_CancelOnNewTabWhenDragging
1341 #define MAYBE_CancelOnNewTabWhenDragging CancelOnNewTabWhenDragging
1343 // Adds another tab, detaches into separate window, adds another tab and
1344 // verifies the run loop ends.
1345 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1346 MAYBE_CancelOnNewTabWhenDragging) {
1347 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1349 // Add another tab to browser().
1350 AddTabAndResetBrowser(browser());
1352 // Move to the first tab and drag it enough so that it detaches.
1353 gfx::Point tab_0_center(
1354 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1355 ASSERT_TRUE(PressInput(tab_0_center));
1356 ASSERT_TRUE(DragInputToNotifyWhenDone(
1357 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1358 base::Bind(&CancelOnNewTabWhenDraggingStep2, this, native_browser_list)));
1359 QuitWhenNotDragging();
1361 // Should be two windows and not dragging.
1362 ASSERT_FALSE(TabDragController::IsActive());
1363 ASSERT_EQ(2u, native_browser_list->size());
1364 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
1365 EXPECT_FALSE(GetIsDragged(*it));
1366 // Should not be maximized
1367 EXPECT_FALSE(it->window()->IsMaximized());
1371 #if defined(OS_CHROMEOS)
1372 // TODO(sky,sad): A number of tests below are disabled as they fail due to
1373 // resize locks with a real compositor. crbug.com/331924
1376 void DragInMaximizedWindowStep2(DetachToBrowserTabDragControllerTest* test,
1378 TabStrip* tab_strip,
1379 const BrowserList* browser_list) {
1380 // There should be another browser.
1381 ASSERT_EQ(2u, browser_list->size());
1382 Browser* new_browser = browser_list->get(1);
1383 EXPECT_NE(browser, new_browser);
1384 ASSERT_TRUE(new_browser->window()->IsActive());
1385 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
1387 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1388 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1390 // Both windows should be visible.
1391 EXPECT_TRUE(tab_strip->GetWidget()->IsVisible());
1392 EXPECT_TRUE(tab_strip2->GetWidget()->IsVisible());
1395 ASSERT_TRUE(test->ReleaseInput());
1400 // Creates a browser with two tabs, maximizes it, drags the tab out.
1401 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1402 DISABLED_DragInMaximizedWindow) {
1403 AddTabAndResetBrowser(browser());
1404 browser()->window()->Maximize();
1406 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1408 // Move to the first tab and drag it enough so that it detaches.
1409 gfx::Point tab_0_center(
1410 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1411 ASSERT_TRUE(PressInput(tab_0_center));
1412 ASSERT_TRUE(DragInputToNotifyWhenDone(
1413 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1414 base::Bind(&DragInMaximizedWindowStep2, this, browser(), tab_strip,
1415 native_browser_list)));
1416 QuitWhenNotDragging();
1418 ASSERT_FALSE(TabDragController::IsActive());
1420 // Should be two browsers.
1421 ASSERT_EQ(2u, native_browser_list->size());
1422 Browser* new_browser = native_browser_list->get(1);
1423 ASSERT_TRUE(new_browser->window()->IsActive());
1425 EXPECT_TRUE(browser()->window()->GetNativeWindow()->IsVisible());
1426 EXPECT_TRUE(new_browser->window()->GetNativeWindow()->IsVisible());
1428 EXPECT_FALSE(GetIsDragged(browser()));
1429 EXPECT_FALSE(GetIsDragged(new_browser));
1431 // The source window should be maximized.
1432 EXPECT_TRUE(browser()->window()->IsMaximized());
1433 // The new window should be maximized.
1434 EXPECT_TRUE(new_browser->window()->IsMaximized());
1437 // Subclass of DetachToBrowserTabDragControllerTest that
1438 // creates multiple displays.
1439 class DetachToBrowserInSeparateDisplayTabDragControllerTest
1440 : public DetachToBrowserTabDragControllerTest {
1442 DetachToBrowserInSeparateDisplayTabDragControllerTest() {}
1443 virtual ~DetachToBrowserInSeparateDisplayTabDragControllerTest() {}
1445 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
1446 DetachToBrowserTabDragControllerTest::SetUpCommandLine(command_line);
1447 // Make screens sufficiently wide to host 2 browsers side by side.
1448 command_line->AppendSwitchASCII("ash-host-window-bounds",
1449 "0+0-600x600,601+0-600x600");
1453 DISALLOW_COPY_AND_ASSIGN(
1454 DetachToBrowserInSeparateDisplayTabDragControllerTest);
1457 // Subclass of DetachToBrowserTabDragControllerTest that runs tests only with
1459 class DetachToBrowserTabDragControllerTestTouch
1460 : public DetachToBrowserTabDragControllerTest {
1462 DetachToBrowserTabDragControllerTestTouch() {}
1463 virtual ~DetachToBrowserTabDragControllerTestTouch() {}
1466 DISALLOW_COPY_AND_ASSIGN(DetachToBrowserTabDragControllerTestTouch);
1471 void DragSingleTabToSeparateWindowInSecondDisplayStep3(
1472 DetachToBrowserTabDragControllerTest* test) {
1473 ASSERT_TRUE(test->ReleaseInput());
1476 void DragSingleTabToSeparateWindowInSecondDisplayStep2(
1477 DetachToBrowserTabDragControllerTest* test,
1478 const gfx::Point& target_point) {
1479 ASSERT_TRUE(test->DragInputToNotifyWhenDone(
1480 target_point.x(), target_point.y(),
1481 base::Bind(&DragSingleTabToSeparateWindowInSecondDisplayStep3, test)));
1486 // Drags from browser to a second display and releases input.
1487 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1488 DISABLED_DragSingleTabToSeparateWindowInSecondDisplay) {
1490 AddTabAndResetBrowser(browser());
1491 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1493 // Move to the first tab and drag it enough so that it detaches.
1494 // Then drag it to the final destination on the second screen.
1495 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1496 ASSERT_TRUE(PressInput(tab_0_center));
1497 ASSERT_TRUE(DragInputToNotifyWhenDone(
1498 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1499 base::Bind(&DragSingleTabToSeparateWindowInSecondDisplayStep2,
1500 this, gfx::Point(600 + tab_0_center.x(),
1502 + GetDetachY(tab_strip)))));
1503 QuitWhenNotDragging();
1505 // Should no longer be dragging.
1506 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1507 ASSERT_FALSE(TabDragController::IsActive());
1509 // There should now be another browser.
1510 ASSERT_EQ(2u, native_browser_list->size());
1511 Browser* new_browser = native_browser_list->get(1);
1512 ASSERT_TRUE(new_browser->window()->IsActive());
1513 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
1514 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1516 // This other browser should be on the second screen (with mouse drag)
1517 // With the touch input the browser cannot be dragged from one screen
1518 // to another and the window stays on the first screen.
1519 if (input_source() == INPUT_SOURCE_MOUSE) {
1520 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1521 ASSERT_EQ(2u, roots.size());
1522 aura::Window* second_root = roots[1];
1523 EXPECT_EQ(second_root,
1524 new_browser->window()->GetNativeWindow()->GetRootWindow());
1527 EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
1528 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1530 // Both windows should not be maximized
1531 EXPECT_FALSE(browser()->window()->IsMaximized());
1532 EXPECT_FALSE(new_browser->window()->IsMaximized());
1537 // Invoked from the nested message loop.
1538 void DragTabToWindowInSeparateDisplayStep2(
1539 DetachToBrowserTabDragControllerTest* test,
1540 TabStrip* not_attached_tab_strip,
1541 TabStrip* target_tab_strip) {
1542 ASSERT_FALSE(not_attached_tab_strip->IsDragSessionActive());
1543 ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
1544 ASSERT_TRUE(TabDragController::IsActive());
1546 // Drag to target_tab_strip. This should stop the nested loop from dragging
1548 gfx::Point target_point(
1549 GetCenterInScreenCoordinates(target_tab_strip->tab_at(0)));
1551 // Move it close to the beginning of the target tabstrip.
1553 target_point.x() - target_tab_strip->tab_at(0)->width() / 2 + 10);
1554 ASSERT_TRUE(test->DragInputToAsync(target_point));
1559 // Drags from browser to another browser on a second display and releases input.
1560 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1561 DISABLED_DragTabToWindowInSeparateDisplay) {
1563 AddTabAndResetBrowser(browser());
1564 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1566 // Create another browser.
1567 Browser* browser2 = CreateBrowser(browser()->profile());
1568 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1569 ResetIDs(browser2->tab_strip_model(), 100);
1571 // Move the second browser to the second display.
1572 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1573 ASSERT_EQ(2u, roots.size());
1574 aura::Window* second_root = roots[1];
1575 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1576 second_root).work_area();
1577 browser2->window()->SetBounds(work_area);
1578 EXPECT_EQ(second_root,
1579 browser2->window()->GetNativeWindow()->GetRootWindow());
1581 // Move to the first tab and drag it enough so that it detaches, but not
1582 // enough that it attaches to browser2.
1583 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1584 ASSERT_TRUE(PressInput(tab_0_center));
1585 ASSERT_TRUE(DragInputToNotifyWhenDone(
1586 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1587 base::Bind(&DragTabToWindowInSeparateDisplayStep2,
1588 this, tab_strip, tab_strip2)));
1589 QuitWhenNotDragging();
1591 // Should now be attached to tab_strip2.
1592 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1593 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1594 ASSERT_TRUE(TabDragController::IsActive());
1596 // Release the mouse, stopping the drag session.
1597 ASSERT_TRUE(ReleaseInput());
1598 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1599 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1600 ASSERT_FALSE(TabDragController::IsActive());
1601 EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1602 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1604 // Both windows should not be maximized
1605 EXPECT_FALSE(browser()->window()->IsMaximized());
1606 EXPECT_FALSE(browser2->window()->IsMaximized());
1609 // Drags from browser to another browser on a second display and releases input.
1610 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1611 DISABLED_DragTabToWindowOnSecondDisplay) {
1613 AddTabAndResetBrowser(browser());
1614 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1616 // Create another browser.
1617 Browser* browser2 = CreateBrowser(browser()->profile());
1618 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1619 ResetIDs(browser2->tab_strip_model(), 100);
1621 // Move both browsers to the second display.
1622 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1623 ASSERT_EQ(2u, roots.size());
1624 aura::Window* second_root = roots[1];
1625 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1626 second_root).work_area();
1627 browser()->window()->SetBounds(work_area);
1629 // position both browser windows side by side on the second screen.
1630 gfx::Rect work_area2(work_area);
1631 work_area.set_width(work_area.width()/2);
1632 browser()->window()->SetBounds(work_area);
1633 work_area2.set_x(work_area2.x() + work_area2.width()/2);
1634 work_area2.set_width(work_area2.width()/2);
1635 browser2->window()->SetBounds(work_area2);
1636 EXPECT_EQ(second_root,
1637 browser()->window()->GetNativeWindow()->GetRootWindow());
1638 EXPECT_EQ(second_root,
1639 browser2->window()->GetNativeWindow()->GetRootWindow());
1641 // Move to the first tab and drag it enough so that it detaches, but not
1642 // enough that it attaches to browser2.
1643 // SetEventGeneratorRootWindow sets correct (second) RootWindow
1644 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1645 SetEventGeneratorRootWindow(tab_0_center);
1646 ASSERT_TRUE(PressInput(tab_0_center));
1647 ASSERT_TRUE(DragInputToNotifyWhenDone(
1648 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1649 base::Bind(&DragTabToWindowInSeparateDisplayStep2,
1650 this, tab_strip, tab_strip2)));
1651 QuitWhenNotDragging();
1653 // Should now be attached to tab_strip2.
1654 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1655 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1656 ASSERT_TRUE(TabDragController::IsActive());
1658 // Release the mouse, stopping the drag session.
1659 ASSERT_TRUE(ReleaseInput());
1660 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1661 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1662 ASSERT_FALSE(TabDragController::IsActive());
1663 EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1664 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1666 // Both windows should not be maximized
1667 EXPECT_FALSE(browser()->window()->IsMaximized());
1668 EXPECT_FALSE(browser2->window()->IsMaximized());
1671 // Drags from a maximized browser to another non-maximized browser on a second
1672 // display and releases input.
1673 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1674 DISABLED_DragMaxTabToNonMaxWindowInSeparateDisplay) {
1676 AddTabAndResetBrowser(browser());
1677 browser()->window()->Maximize();
1678 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1680 // Create another browser on the second display.
1681 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1682 ASSERT_EQ(2u, roots.size());
1683 aura::Window* first_root = roots[0];
1684 aura::Window* second_root = roots[1];
1685 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1686 second_root).work_area();
1687 work_area.Inset(20, 20, 20, 60);
1688 Browser::CreateParams params(browser()->profile(),
1689 browser()->host_desktop_type());
1690 params.initial_show_state = ui::SHOW_STATE_NORMAL;
1691 params.initial_bounds = work_area;
1692 Browser* browser2 = new Browser(params);
1693 AddBlankTabAndShow(browser2);
1695 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1696 ResetIDs(browser2->tab_strip_model(), 100);
1698 EXPECT_EQ(second_root,
1699 browser2->window()->GetNativeWindow()->GetRootWindow());
1700 EXPECT_EQ(first_root,
1701 browser()->window()->GetNativeWindow()->GetRootWindow());
1702 EXPECT_EQ(2, tab_strip->tab_count());
1703 EXPECT_EQ(1, tab_strip2->tab_count());
1705 // Move to the first tab and drag it enough so that it detaches, but not
1706 // enough that it attaches to browser2.
1707 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1708 ASSERT_TRUE(PressInput(tab_0_center));
1709 ASSERT_TRUE(DragInputToNotifyWhenDone(
1710 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1711 base::Bind(&DragTabToWindowInSeparateDisplayStep2,
1712 this, tab_strip, tab_strip2)));
1713 QuitWhenNotDragging();
1715 // Should now be attached to tab_strip2.
1716 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1717 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1718 ASSERT_TRUE(TabDragController::IsActive());
1720 // Release the mouse, stopping the drag session.
1721 ASSERT_TRUE(ReleaseInput());
1723 // tab should have moved
1724 EXPECT_EQ(1, tab_strip->tab_count());
1725 EXPECT_EQ(2, tab_strip2->tab_count());
1727 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1728 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1729 ASSERT_FALSE(TabDragController::IsActive());
1730 EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1731 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1733 // Source browser should still be maximized, target should not
1734 EXPECT_TRUE(browser()->window()->IsMaximized());
1735 EXPECT_FALSE(browser2->window()->IsMaximized());
1738 // Drags from a restored browser to an immersive fullscreen browser on a
1739 // second display and releases input.
1740 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1741 DISABLED_DragTabToImmersiveBrowserOnSeparateDisplay) {
1743 AddTabAndResetBrowser(browser());
1744 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1746 // Create another browser.
1747 Browser* browser2 = CreateBrowser(browser()->profile());
1748 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1749 ResetIDs(browser2->tab_strip_model(), 100);
1751 // Move the second browser to the second display.
1752 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1753 ASSERT_EQ(2u, roots.size());
1754 aura::Window* second_root = roots[1];
1755 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1756 second_root).work_area();
1757 browser2->window()->SetBounds(work_area);
1758 EXPECT_EQ(second_root,
1759 browser2->window()->GetNativeWindow()->GetRootWindow());
1761 // Put the second browser into immersive fullscreen.
1762 BrowserView* browser_view2 = BrowserView::GetBrowserViewForBrowser(browser2);
1763 ImmersiveModeController* immersive_controller2 =
1764 browser_view2->immersive_mode_controller();
1765 immersive_controller2->SetupForTest();
1766 chrome::ToggleFullscreenMode(browser2);
1767 ASSERT_TRUE(immersive_controller2->IsEnabled());
1768 ASSERT_FALSE(immersive_controller2->IsRevealed());
1769 ASSERT_TRUE(tab_strip2->IsImmersiveStyle());
1771 // Move to the first tab and drag it enough so that it detaches, but not
1772 // enough that it attaches to browser2.
1773 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1774 ASSERT_TRUE(PressInput(tab_0_center));
1775 ASSERT_TRUE(DragInputToNotifyWhenDone(
1776 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1777 base::Bind(&DragTabToWindowInSeparateDisplayStep2,
1778 this, tab_strip, tab_strip2)));
1779 QuitWhenNotDragging();
1781 // Should now be attached to tab_strip2.
1782 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1783 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1784 ASSERT_TRUE(TabDragController::IsActive());
1786 // browser2's top chrome should be revealed and the tab strip should be
1787 // at normal height while user is tragging tabs_strip2's tabs.
1788 ASSERT_TRUE(immersive_controller2->IsRevealed());
1789 ASSERT_FALSE(tab_strip2->IsImmersiveStyle());
1791 // Release the mouse, stopping the drag session.
1792 ASSERT_TRUE(ReleaseInput());
1793 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1794 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1795 ASSERT_FALSE(TabDragController::IsActive());
1796 EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1797 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1799 // Move the mouse off of browser2's top chrome.
1800 aura::Window* primary_root = roots[0];
1801 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
1802 primary_root->GetBoundsInScreen().CenterPoint()));
1804 // The first browser window should not be in immersive fullscreen.
1805 // browser2 should still be in immersive fullscreen, but the top chrome should
1806 // no longer be revealed.
1807 BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
1808 EXPECT_FALSE(browser_view->immersive_mode_controller()->IsEnabled());
1810 EXPECT_TRUE(immersive_controller2->IsEnabled());
1811 EXPECT_FALSE(immersive_controller2->IsRevealed());
1812 EXPECT_TRUE(tab_strip2->IsImmersiveStyle());
1815 // Subclass of DetachToBrowserTabDragControllerTest that
1816 // creates multiple displays with different device scale factors.
1817 class DifferentDeviceScaleFactorDisplayTabDragControllerTest
1818 : public DetachToBrowserTabDragControllerTest {
1820 DifferentDeviceScaleFactorDisplayTabDragControllerTest() {}
1821 virtual ~DifferentDeviceScaleFactorDisplayTabDragControllerTest() {}
1823 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
1824 DetachToBrowserTabDragControllerTest::SetUpCommandLine(command_line);
1825 command_line->AppendSwitchASCII("ash-host-window-bounds",
1826 "400x400,0+400-800x800*2");
1829 float GetCursorDeviceScaleFactor() const {
1830 ash::test::CursorManagerTestApi cursor_test_api(
1831 ash::Shell::GetInstance()->cursor_manager());
1832 return cursor_test_api.GetCurrentCursor().device_scale_factor();
1836 DISALLOW_COPY_AND_ASSIGN(
1837 DifferentDeviceScaleFactorDisplayTabDragControllerTest);
1842 // The points where a tab is dragged in CursorDeviceScaleFactorStep.
1843 const struct DragPoint {
1854 // The expected device scale factors before the cursor is moved to the
1855 // corresponding kDragPoints in CursorDeviceScaleFactorStep.
1856 const float kDeviceScaleFactorExpectations[] = {
1865 arraysize(kDragPoints) == arraysize(kDeviceScaleFactorExpectations),
1866 kDragPoints_and_kDeviceScaleFactorExpectations_must_have_same_size);
1868 // Drags tab to |kDragPoints[index]|, then calls the next step function.
1869 void CursorDeviceScaleFactorStep(
1870 DifferentDeviceScaleFactorDisplayTabDragControllerTest* test,
1871 TabStrip* not_attached_tab_strip,
1873 ASSERT_FALSE(not_attached_tab_strip->IsDragSessionActive());
1874 ASSERT_TRUE(TabDragController::IsActive());
1876 if (index < arraysize(kDragPoints)) {
1877 EXPECT_EQ(kDeviceScaleFactorExpectations[index],
1878 test->GetCursorDeviceScaleFactor());
1879 const DragPoint p = kDragPoints[index];
1880 ASSERT_TRUE(test->DragInputToNotifyWhenDone(
1881 p.x, p.y, base::Bind(&CursorDeviceScaleFactorStep,
1882 test, not_attached_tab_strip, index + 1)));
1884 // Finishes a serise of CursorDeviceScaleFactorStep calls and ends drag.
1885 EXPECT_EQ(1.0f, test->GetCursorDeviceScaleFactor());
1886 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
1887 ui_controls::LEFT, ui_controls::UP));
1893 // Verifies cursor's device scale factor is updated when a tab is moved across
1894 // displays with different device scale factors (http://crbug.com/154183).
1895 IN_PROC_BROWSER_TEST_P(DifferentDeviceScaleFactorDisplayTabDragControllerTest,
1896 DISABLED_CursorDeviceScaleFactor) {
1898 AddTabAndResetBrowser(browser());
1899 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1901 // Move the second browser to the second display.
1902 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1903 ASSERT_EQ(2u, roots.size());
1905 // Move to the first tab and drag it enough so that it detaches.
1906 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1907 ASSERT_TRUE(PressInput(tab_0_center));
1908 ASSERT_TRUE(DragInputToNotifyWhenDone(
1909 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1910 base::Bind(&CursorDeviceScaleFactorStep,
1911 this, tab_strip, 0)));
1912 QuitWhenNotDragging();
1917 class DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest
1918 : public TabDragControllerTest {
1920 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest() {}
1922 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
1923 TabDragControllerTest::SetUpCommandLine(command_line);
1924 command_line->AppendSwitchASCII("ash-host-window-bounds",
1925 "0+0-250x250,251+0-250x250");
1928 bool Press(const gfx::Point& position) {
1929 return ui_test_utils::SendMouseMoveSync(position) &&
1930 ui_test_utils::SendMouseEventsSync(ui_controls::LEFT,
1934 bool DragTabAndExecuteTaskWhenDone(const gfx::Point& position,
1935 const base::Closure& task) {
1936 return ui_controls::SendMouseMoveNotifyWhenDone(
1937 position.x(), position.y(), task);
1940 void QuitWhenNotDragging() {
1941 test::QuitWhenNotDraggingImpl();
1942 base::MessageLoop::current()->Run();
1946 DISALLOW_COPY_AND_ASSIGN(
1947 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest);
1950 // Invoked from the nested message loop.
1951 void CancelDragTabToWindowInSeparateDisplayStep3(
1952 TabStrip* tab_strip,
1953 const BrowserList* browser_list) {
1954 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1955 ASSERT_TRUE(TabDragController::IsActive());
1956 ASSERT_EQ(2u, browser_list->size());
1958 // Switching display mode should cancel the drag operation.
1959 ash::DisplayManager* display_manager =
1960 ash::Shell::GetInstance()->display_manager();
1961 display_manager->AddRemoveDisplay();
1964 // Invoked from the nested message loop.
1965 void CancelDragTabToWindowInSeparateDisplayStep2(
1966 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest* test,
1967 TabStrip* tab_strip,
1968 aura::Window* current_root,
1969 gfx::Point final_destination,
1970 const BrowserList* browser_list) {
1971 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1972 ASSERT_TRUE(TabDragController::IsActive());
1973 ASSERT_EQ(2u, browser_list->size());
1975 Browser* new_browser = browser_list->get(1);
1976 EXPECT_EQ(current_root,
1977 new_browser->window()->GetNativeWindow()->GetRootWindow());
1979 ASSERT_TRUE(test->DragTabAndExecuteTaskWhenDone(
1981 base::Bind(&CancelDragTabToWindowInSeparateDisplayStep3,
1982 tab_strip, browser_list)));
1987 // Drags from browser to a second display and releases input.
1988 IN_PROC_BROWSER_TEST_F(
1989 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest,
1990 DISABLED_CancelDragTabToWindowIn2ndDisplay) {
1992 AddTabAndResetBrowser(browser());
1993 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1995 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
1997 // Move the second browser to the second display.
1998 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1999 ASSERT_EQ(2u, roots.size());
2000 gfx::Point final_destination =
2001 gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
2002 roots[1]).work_area().CenterPoint();
2004 // Move to the first tab and drag it enough so that it detaches, but not
2005 // enough to move to another display.
2006 gfx::Point tab_0_dst(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
2007 ASSERT_TRUE(Press(tab_0_dst));
2008 tab_0_dst.Offset(0, GetDetachY(tab_strip));
2009 ASSERT_TRUE(DragTabAndExecuteTaskWhenDone(
2010 tab_0_dst, base::Bind(&CancelDragTabToWindowInSeparateDisplayStep2,
2011 this, tab_strip, roots[0], final_destination,
2012 native_browser_list)));
2013 QuitWhenNotDragging();
2015 ASSERT_EQ(1u, native_browser_list->size());
2016 ASSERT_FALSE(tab_strip->IsDragSessionActive());
2017 ASSERT_FALSE(TabDragController::IsActive());
2018 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2020 // Release the mouse
2021 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
2022 ui_controls::LEFT, ui_controls::UP));
2025 // Drags from browser from a second display to primary and releases input.
2026 IN_PROC_BROWSER_TEST_F(
2027 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest,
2028 DISABLED_CancelDragTabToWindowIn1stDisplay) {
2029 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
2030 ASSERT_EQ(2u, roots.size());
2033 AddTabAndResetBrowser(browser());
2034 TabStrip* tab_strip = GetTabStripForBrowser(browser());
2036 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2037 EXPECT_EQ(roots[0], browser()->window()->GetNativeWindow()->GetRootWindow());
2039 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->
2040 GetDisplayNearestWindow(roots[1]).work_area();
2041 browser()->window()->SetBounds(work_area);
2042 EXPECT_EQ(roots[1], browser()->window()->GetNativeWindow()->GetRootWindow());
2044 // Move the second browser to the display.
2045 gfx::Point final_destination =
2046 gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
2047 roots[0]).work_area().CenterPoint();
2049 // Move to the first tab and drag it enough so that it detaches, but not
2050 // enough to move to another display.
2051 gfx::Point tab_0_dst(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
2052 ASSERT_TRUE(Press(tab_0_dst));
2053 tab_0_dst.Offset(0, GetDetachY(tab_strip));
2054 ASSERT_TRUE(DragTabAndExecuteTaskWhenDone(
2055 tab_0_dst, base::Bind(&CancelDragTabToWindowInSeparateDisplayStep2,
2056 this, tab_strip, roots[1], final_destination,
2057 native_browser_list)));
2058 QuitWhenNotDragging();
2060 ASSERT_EQ(1u, native_browser_list->size());
2061 ASSERT_FALSE(tab_strip->IsDragSessionActive());
2062 ASSERT_FALSE(TabDragController::IsActive());
2063 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2065 // Release the mouse
2066 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
2067 ui_controls::LEFT, ui_controls::UP));
2072 void PressSecondFingerWhileDetachedStep2(
2073 DetachToBrowserTabDragControllerTest* test) {
2074 ASSERT_TRUE(TabDragController::IsActive());
2075 ASSERT_EQ(2u, test->native_browser_list->size());
2076 Browser* new_browser = test->native_browser_list->get(1);
2077 ASSERT_TRUE(new_browser->window()->IsActive());
2079 ASSERT_TRUE(test->PressInput2());
2084 // Detaches a tab and while detached presses a second finger.
2085 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestTouch,
2086 DISABLED_PressSecondFingerWhileDetached) {
2087 gfx::Rect bounds(browser()->window()->GetBounds());
2089 AddTabAndResetBrowser(browser());
2090 TabStrip* tab_strip = GetTabStripForBrowser(browser());
2091 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2093 // Move to the first tab and drag it enough so that it detaches.
2094 gfx::Point tab_0_center(
2095 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
2096 ASSERT_TRUE(PressInput(tab_0_center));
2097 ASSERT_TRUE(DragInputToDelayedNotifyWhenDone(
2098 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
2099 base::Bind(&PressSecondFingerWhileDetachedStep2, this),
2100 base::TimeDelta::FromMilliseconds(60)));
2101 QuitWhenNotDragging();
2103 // The drag should have been reverted.
2104 ASSERT_EQ(1u, native_browser_list->size());
2105 ASSERT_FALSE(tab_strip->IsDragSessionActive());
2106 ASSERT_FALSE(TabDragController::IsActive());
2107 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2109 ASSERT_TRUE(ReleaseInput());
2110 ASSERT_TRUE(ReleaseInput2());
2113 #if defined(OS_CHROMEOS)
2117 void DetachToDockedWindowNextStep(
2118 DetachToBrowserTabDragControllerTest* test,
2119 const gfx::Point& target_point,
2121 ASSERT_EQ(2u, test->native_browser_list->size());
2122 Browser* new_browser = test->native_browser_list->get(1);
2123 ASSERT_TRUE(new_browser->window()->IsActive());
2126 ASSERT_TRUE(test->ReleaseInput());
2129 ASSERT_TRUE(test->DragInputToNotifyWhenDone(
2130 target_point.x(), target_point.y(),
2131 base::Bind(&DetachToDockedWindowNextStep,
2133 gfx::Point(target_point.x(), 1 + target_point.y()),
2139 // Drags from browser to separate window, docks that window and releases mouse.
2140 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
2141 DISABLED_DetachToDockedWindowFromMaximizedWindow) {
2142 // Maximize the initial browser window.
2143 browser()->window()->Maximize();
2144 ASSERT_TRUE(browser()->window()->IsMaximized());
2147 AddTabAndResetBrowser(browser());
2148 TabStrip* tab_strip = GetTabStripForBrowser(browser());
2150 // Move to the first tab and drag it enough so that it detaches.
2151 gfx::Point tab_0_center(
2152 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
2153 ASSERT_TRUE(PressInput(tab_0_center));
2155 // The following matches kMovesBeforeAdjust in snap_sizer.cc
2156 const int kNumIterations = 25 * 5 + 10;
2157 ASSERT_TRUE(DragInputToNotifyWhenDone(
2158 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
2159 base::Bind(&DetachToDockedWindowNextStep, this,
2160 gfx::Point(0, tab_0_center.y() + GetDetachY(tab_strip)),
2162 // Continue dragging enough times to go through snapping sequence and dock
2164 QuitWhenNotDragging();
2165 // Should no longer be dragging.
2166 ASSERT_FALSE(tab_strip->IsDragSessionActive());
2167 ASSERT_FALSE(TabDragController::IsActive());
2169 // There should now be another browser.
2170 ASSERT_EQ(2u, native_browser_list->size());
2171 Browser* new_browser = native_browser_list->get(1);
2172 ASSERT_TRUE(new_browser->window()->IsActive());
2173 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
2174 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
2176 EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
2177 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
2179 // The bounds of the initial window should not have changed.
2180 EXPECT_TRUE(browser()->window()->IsMaximized());
2182 EXPECT_FALSE(GetIsDragged(browser()));
2183 EXPECT_FALSE(GetIsDragged(new_browser));
2184 // After this both windows should still be manageable.
2185 EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
2186 EXPECT_TRUE(IsWindowPositionManaged(
2187 new_browser->window()->GetNativeWindow()));
2189 ash::wm::WindowState* window_state =
2190 ash::wm::GetWindowState(new_browser->window()->GetNativeWindow());
2191 // The new window should not be maximized because it gets docked or snapped.
2192 EXPECT_FALSE(new_browser->window()->IsMaximized());
2193 // The new window should be docked and not snapped.
2194 EXPECT_TRUE(window_state->IsDocked());
2195 EXPECT_FALSE(window_state->IsSnapped());
2198 #endif // OS_CHROMEOS
2202 #if defined(USE_ASH) && defined(OS_CHROMEOS) // TODO(win_ash,linux_ash)
2203 INSTANTIATE_TEST_CASE_P(TabDragging,
2204 DetachToBrowserInSeparateDisplayTabDragControllerTest,
2205 ::testing::Values("mouse", "touch"));
2206 INSTANTIATE_TEST_CASE_P(TabDragging,
2207 DifferentDeviceScaleFactorDisplayTabDragControllerTest,
2208 ::testing::Values("mouse"));
2209 INSTANTIATE_TEST_CASE_P(TabDragging,
2210 DetachToBrowserTabDragControllerTest,
2211 ::testing::Values("mouse", "touch"));
2212 INSTANTIATE_TEST_CASE_P(TabDragging,
2213 DetachToBrowserTabDragControllerTestTouch,
2214 ::testing::Values("touch"));
2215 #elif defined(USE_ASH)
2216 INSTANTIATE_TEST_CASE_P(TabDragging,
2217 DetachToBrowserTabDragControllerTest,
2218 ::testing::Values("mouse"));