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 ~TabDragControllerInteractiveUITestUserData() override {}
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 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 ~QuitDraggingObserver() override {}
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 ~ScreenEventGeneratorDelegate() override {}
223 // EventGeneratorDelegateAura overrides:
224 aura::WindowTreeHost* GetHostAt(const gfx::Point& point) const override {
225 return root_window_->GetHost();
228 aura::client::ScreenPositionClient* GetScreenPositionClient(
229 const aura::Window* window) const override {
230 return aura::client::GetScreenPositionClient(root_window_);
234 aura::Window* root_window_;
236 DISALLOW_COPY_AND_ASSIGN(ScreenEventGeneratorDelegate);
241 #if !defined(OS_CHROMEOS)
243 // Following classes verify a crash scenario. Specifically on Windows when focus
244 // changes it can trigger capture being lost. This was causing a crash in tab
245 // dragging as it wasn't set up to handle this scenario. These classes
246 // synthesize this scenario.
248 // Allows making ClearNativeFocus() invoke ReleaseCapture().
249 class TestDesktopBrowserFrameAura : public DesktopBrowserFrameAura {
251 TestDesktopBrowserFrameAura(
252 BrowserFrame* browser_frame,
253 BrowserView* browser_view)
254 : DesktopBrowserFrameAura(browser_frame, browser_view),
255 release_capture_(false) {}
256 ~TestDesktopBrowserFrameAura() override {}
258 void ReleaseCaptureOnNextClear() {
259 release_capture_ = true;
262 void ClearNativeFocus() override {
263 views::DesktopNativeWidgetAura::ClearNativeFocus();
264 if (release_capture_) {
265 release_capture_ = false;
266 GetWidget()->ReleaseCapture();
271 // If true ReleaseCapture() is invoked in ClearNativeFocus().
272 bool release_capture_;
274 DISALLOW_COPY_AND_ASSIGN(TestDesktopBrowserFrameAura);
277 // Factory for creating a TestDesktopBrowserFrameAura.
278 class TestNativeBrowserFrameFactory : public NativeBrowserFrameFactory {
280 TestNativeBrowserFrameFactory() {}
281 ~TestNativeBrowserFrameFactory() override {}
283 NativeBrowserFrame* Create(BrowserFrame* browser_frame,
284 BrowserView* browser_view) override {
285 return new TestDesktopBrowserFrameAura(browser_frame, browser_view);
289 DISALLOW_COPY_AND_ASSIGN(TestNativeBrowserFrameFactory);
292 class TabDragCaptureLostTest : public TabDragControllerTest {
294 TabDragCaptureLostTest() {
295 NativeBrowserFrameFactory::Set(new TestNativeBrowserFrameFactory);
299 DISALLOW_COPY_AND_ASSIGN(TabDragCaptureLostTest);
302 // See description above for details.
303 IN_PROC_BROWSER_TEST_F(TabDragCaptureLostTest, ReleaseCaptureOnDrag) {
304 AddTabAndResetBrowser(browser());
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());
323 IN_PROC_BROWSER_TEST_F(TabDragControllerTest, GestureEndShouldEndDragTest) {
324 AddTabAndResetBrowser(browser());
326 TabStrip* tab_strip = GetTabStripForBrowser(browser());
328 Tab* tab1 = tab_strip->tab_at(1);
329 gfx::Point tab_1_center(tab1->width() / 2, tab1->height() / 2);
331 ui::GestureEvent gesture_tap_down(
336 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
337 tab_strip->MaybeStartDrag(tab1, gesture_tap_down,
338 tab_strip->GetSelectionModel());
339 EXPECT_TRUE(TabDragController::IsActive());
341 ui::GestureEvent gesture_end(tab_1_center.x(),
345 ui::GestureEventDetails(ui::ET_GESTURE_END));
346 tab_strip->OnGestureEvent(&gesture_end);
347 EXPECT_FALSE(TabDragController::IsActive());
348 EXPECT_FALSE(tab_strip->IsDragSessionActive());
353 class DetachToBrowserTabDragControllerTest
354 : public TabDragControllerTest,
355 public ::testing::WithParamInterface<const char*> {
357 DetachToBrowserTabDragControllerTest() {}
359 void SetUpOnMainThread() override {
360 #if defined(OS_CHROMEOS)
361 event_generator_.reset(
362 new ui::test::EventGenerator(ash::Shell::GetPrimaryRootWindow()));
366 InputSource input_source() const {
367 return strstr(GetParam(), "mouse") ?
368 INPUT_SOURCE_MOUSE : INPUT_SOURCE_TOUCH;
371 // Set root window from a point in screen coordinates
372 void SetEventGeneratorRootWindow(const gfx::Point& point) {
373 if (input_source() == INPUT_SOURCE_MOUSE)
375 #if defined(OS_CHROMEOS)
376 event_generator_.reset(new ui::test::EventGenerator(
377 new ScreenEventGeneratorDelegate(ash::wm::GetRootWindowAt(point))));
381 // The following methods update one of the mouse or touch input depending upon
383 bool PressInput(const gfx::Point& location) {
384 if (input_source() == INPUT_SOURCE_MOUSE) {
385 return ui_test_utils::SendMouseMoveSync(location) &&
386 ui_test_utils::SendMouseEventsSync(
387 ui_controls::LEFT, ui_controls::DOWN);
389 #if defined(OS_CHROMEOS)
390 event_generator_->set_current_location(location);
391 event_generator_->PressTouch();
399 // Second touch input is only used for touch sequence tests.
400 EXPECT_EQ(INPUT_SOURCE_TOUCH, input_source());
401 #if defined(OS_CHROMEOS)
402 event_generator_->set_current_location(
403 event_generator_->current_location());
404 event_generator_->PressTouchId(1);
411 bool DragInputTo(const gfx::Point& location) {
412 if (input_source() == INPUT_SOURCE_MOUSE)
413 return ui_test_utils::SendMouseMoveSync(location);
414 #if defined(OS_CHROMEOS)
415 event_generator_->MoveTouch(location);
422 bool DragInputToAsync(const gfx::Point& location) {
423 if (input_source() == INPUT_SOURCE_MOUSE)
424 return ui_controls::SendMouseMove(location.x(), location.y());
425 #if defined(OS_CHROMEOS)
426 event_generator_->MoveTouch(location);
433 bool DragInputToNotifyWhenDone(int x,
435 const base::Closure& task) {
436 if (input_source() == INPUT_SOURCE_MOUSE)
437 return ui_controls::SendMouseMoveNotifyWhenDone(x, y, task);
438 #if defined(OS_CHROMEOS)
439 base::MessageLoop::current()->PostTask(FROM_HERE, task);
440 event_generator_->MoveTouch(gfx::Point(x, y));
447 bool DragInputToDelayedNotifyWhenDone(int x,
449 const base::Closure& task,
450 base::TimeDelta delay) {
451 if (input_source() == INPUT_SOURCE_MOUSE)
452 return ui_controls::SendMouseMoveNotifyWhenDone(x, y, task);
453 #if defined(OS_CHROMEOS)
454 base::MessageLoop::current()->PostDelayedTask(FROM_HERE, task, delay);
455 event_generator_->MoveTouch(gfx::Point(x, y));
462 bool DragInput2ToNotifyWhenDone(int x,
464 const base::Closure& task) {
465 if (input_source() == INPUT_SOURCE_MOUSE)
466 return ui_controls::SendMouseMoveNotifyWhenDone(x, y, task);
467 #if defined(OS_CHROMEOS)
468 base::MessageLoop::current()->PostTask(FROM_HERE, task);
469 event_generator_->MoveTouchId(gfx::Point(x, y), 1);
476 bool ReleaseInput() {
477 if (input_source() == INPUT_SOURCE_MOUSE) {
478 return ui_test_utils::SendMouseEventsSync(
479 ui_controls::LEFT, ui_controls::UP);
481 #if defined(OS_CHROMEOS)
482 event_generator_->ReleaseTouch();
489 bool ReleaseInput2() {
490 if (input_source() == INPUT_SOURCE_MOUSE) {
491 return ui_test_utils::SendMouseEventsSync(
492 ui_controls::LEFT, ui_controls::UP);
494 #if defined(OS_CHROMEOS)
495 event_generator_->ReleaseTouchId(1);
502 bool ReleaseMouseAsync() {
503 return input_source() == INPUT_SOURCE_MOUSE &&
504 ui_controls::SendMouseEvents(ui_controls::LEFT, ui_controls::UP);
507 void QuitWhenNotDragging() {
508 if (input_source() == INPUT_SOURCE_MOUSE) {
509 // Schedule observer to quit message loop when done dragging. This has to
510 // be async so the message loop can run.
511 test::QuitWhenNotDraggingImpl();
512 base::MessageLoop::current()->Run();
514 // Touch events are sync, so we know we're not in a drag session. But some
515 // tests rely on the browser fully closing, which is async. So, run all
517 base::RunLoop run_loop;
518 run_loop.RunUntilIdle();
522 void AddBlankTabAndShow(Browser* browser) {
523 InProcessBrowserTest::AddBlankTabAndShow(browser);
526 Browser* browser() const { return InProcessBrowserTest::browser(); }
529 #if defined(OS_CHROMEOS)
530 scoped_ptr<ui::test::EventGenerator> event_generator_;
533 DISALLOW_COPY_AND_ASSIGN(DetachToBrowserTabDragControllerTest);
536 // Creates a browser with two tabs, drags the second to the first.
537 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, DragInSameWindow) {
538 // TODO(sky): this won't work with touch as it requires a long press.
539 if (input_source() == INPUT_SOURCE_TOUCH) {
540 VLOG(1) << "Test is DISABLED for touch input.";
544 AddTabAndResetBrowser(browser());
546 TabStrip* tab_strip = GetTabStripForBrowser(browser());
547 TabStripModel* model = browser()->tab_strip_model();
549 gfx::Point tab_1_center(GetCenterInScreenCoordinates(tab_strip->tab_at(1)));
550 ASSERT_TRUE(PressInput(tab_1_center));
551 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
552 ASSERT_TRUE(DragInputTo(tab_0_center));
553 ASSERT_TRUE(ReleaseInput());
554 EXPECT_EQ("1 0", IDString(model));
555 EXPECT_FALSE(TabDragController::IsActive());
556 EXPECT_FALSE(tab_strip->IsDragSessionActive());
558 // The tab strip should no longer have capture because the drag was ended and
559 // mouse/touch was released.
560 EXPECT_FALSE(tab_strip->GetWidget()->HasCapture());
565 // Invoked from the nested message loop.
566 void DragToSeparateWindowStep2(DetachToBrowserTabDragControllerTest* test,
567 TabStrip* not_attached_tab_strip,
568 TabStrip* target_tab_strip) {
569 ASSERT_FALSE(not_attached_tab_strip->IsDragSessionActive());
570 ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
571 ASSERT_TRUE(TabDragController::IsActive());
573 // Drag to target_tab_strip. This should stop the nested loop from dragging
575 gfx::Point target_point(target_tab_strip->width() -1,
576 target_tab_strip->height() / 2);
577 views::View::ConvertPointToScreen(target_tab_strip, &target_point);
578 ASSERT_TRUE(test->DragInputToAsync(target_point));
583 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
584 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
585 // compositor. crbug.com/331924
586 #define MAYBE_DragToSeparateWindow DISABLED_DragToSeparateWindow
588 #define MAYBE_DragToSeparateWindow DragToSeparateWindow
590 // Creates two browsers, drags from first into second.
591 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
592 MAYBE_DragToSeparateWindow) {
593 TabStrip* tab_strip = GetTabStripForBrowser(browser());
595 // Add another tab to browser().
596 AddTabAndResetBrowser(browser());
598 // Create another browser.
599 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
600 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
602 // Move to the first tab and drag it enough so that it detaches, but not
603 // enough that it attaches to browser2.
604 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
605 ASSERT_TRUE(PressInput(tab_0_center));
606 ASSERT_TRUE(DragInputToNotifyWhenDone(
607 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
608 base::Bind(&DragToSeparateWindowStep2,
609 this, tab_strip, tab_strip2)));
610 QuitWhenNotDragging();
612 // Should now be attached to tab_strip2.
613 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
614 ASSERT_FALSE(tab_strip->IsDragSessionActive());
615 ASSERT_TRUE(TabDragController::IsActive());
616 EXPECT_FALSE(GetIsDragged(browser()));
618 // Release mouse or touch, stopping the drag session.
619 ASSERT_TRUE(ReleaseInput());
620 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
621 ASSERT_FALSE(tab_strip->IsDragSessionActive());
622 ASSERT_FALSE(TabDragController::IsActive());
623 EXPECT_EQ("100 0", IDString(browser2->tab_strip_model()));
624 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
625 EXPECT_FALSE(GetIsDragged(browser2));
627 // Both windows should not be maximized
628 EXPECT_FALSE(browser()->window()->IsMaximized());
629 EXPECT_FALSE(browser2->window()->IsMaximized());
631 // The tab strip should no longer have capture because the drag was ended and
632 // mouse/touch was released.
633 EXPECT_FALSE(tab_strip->GetWidget()->HasCapture());
634 EXPECT_FALSE(tab_strip2->GetWidget()->HasCapture());
639 void DetachToOwnWindowStep2(DetachToBrowserTabDragControllerTest* test) {
640 if (test->input_source() == INPUT_SOURCE_TOUCH)
641 ASSERT_TRUE(test->ReleaseInput());
644 #if defined(OS_CHROMEOS)
645 bool IsWindowPositionManaged(aura::Window* window) {
646 return ash::wm::GetWindowState(window)->window_position_managed();
648 bool HasUserChangedWindowPositionOrSize(aura::Window* window) {
649 return ash::wm::GetWindowState(window)->bounds_changed_by_user();
652 bool IsWindowPositionManaged(gfx::NativeWindow window) {
655 bool HasUserChangedWindowPositionOrSize(gfx::NativeWindow window) {
662 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
663 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
664 // compositor. crbug.com/331924
665 #define MAYBE_DetachToOwnWindow DISABLED_DetachToOwnWindow
667 #define MAYBE_DetachToOwnWindow DetachToOwnWindow
669 // Drags from browser to separate window and releases mouse.
670 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
671 MAYBE_DetachToOwnWindow) {
672 const gfx::Rect initial_bounds(browser()->window()->GetBounds());
674 AddTabAndResetBrowser(browser());
675 TabStrip* tab_strip = GetTabStripForBrowser(browser());
677 // Move to the first tab and drag it enough so that it detaches.
678 gfx::Point tab_0_center(
679 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
680 ASSERT_TRUE(PressInput(tab_0_center));
681 ASSERT_TRUE(DragInputToNotifyWhenDone(
682 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
683 base::Bind(&DetachToOwnWindowStep2, this)));
684 if (input_source() == INPUT_SOURCE_MOUSE) {
685 ASSERT_TRUE(ReleaseMouseAsync());
686 QuitWhenNotDragging();
689 // Should no longer be dragging.
690 ASSERT_FALSE(tab_strip->IsDragSessionActive());
691 ASSERT_FALSE(TabDragController::IsActive());
693 // There should now be another browser.
694 ASSERT_EQ(2u, native_browser_list->size());
695 Browser* new_browser = native_browser_list->get(1);
696 ASSERT_TRUE(new_browser->window()->IsActive());
697 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
698 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
700 EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
701 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
703 // The bounds of the initial window should not have changed.
704 EXPECT_EQ(initial_bounds.ToString(),
705 browser()->window()->GetBounds().ToString());
707 EXPECT_FALSE(GetIsDragged(browser()));
708 EXPECT_FALSE(GetIsDragged(new_browser));
709 // After this both windows should still be manageable.
710 EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
711 EXPECT_TRUE(IsWindowPositionManaged(
712 new_browser->window()->GetNativeWindow()));
714 // Both windows should not be maximized
715 EXPECT_FALSE(browser()->window()->IsMaximized());
716 EXPECT_FALSE(new_browser->window()->IsMaximized());
718 // The tab strip should no longer have capture because the drag was ended and
719 // mouse/touch was released.
720 EXPECT_FALSE(tab_strip->GetWidget()->HasCapture());
721 EXPECT_FALSE(tab_strip2->GetWidget()->HasCapture());
724 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
725 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
726 // compositor. crbug.com/331924
727 #define MAYBE_DetachToOwnWindowFromMaximizedWindow \
728 DISABLED_DetachToOwnWindowFromMaximizedWindow
730 #define MAYBE_DetachToOwnWindowFromMaximizedWindow \
731 DetachToOwnWindowFromMaximizedWindow
733 // Drags from browser to a separate window and releases mouse.
734 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
735 MAYBE_DetachToOwnWindowFromMaximizedWindow) {
736 // Maximize the initial browser window.
737 browser()->window()->Maximize();
738 ASSERT_TRUE(browser()->window()->IsMaximized());
741 AddTabAndResetBrowser(browser());
742 TabStrip* tab_strip = GetTabStripForBrowser(browser());
744 // Move to the first tab and drag it enough so that it detaches.
745 gfx::Point tab_0_center(
746 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
747 ASSERT_TRUE(PressInput(tab_0_center));
748 ASSERT_TRUE(DragInputToNotifyWhenDone(
749 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
750 base::Bind(&DetachToOwnWindowStep2, this)));
751 if (input_source() == INPUT_SOURCE_MOUSE) {
752 ASSERT_TRUE(ReleaseMouseAsync());
753 QuitWhenNotDragging();
756 // Should no longer be dragging.
757 ASSERT_FALSE(tab_strip->IsDragSessionActive());
758 ASSERT_FALSE(TabDragController::IsActive());
760 // There should now be another browser.
761 ASSERT_EQ(2u, native_browser_list->size());
762 Browser* new_browser = native_browser_list->get(1);
763 ASSERT_TRUE(new_browser->window()->IsActive());
764 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
765 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
767 EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
768 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
770 // The bounds of the initial window should not have changed.
771 EXPECT_TRUE(browser()->window()->IsMaximized());
773 EXPECT_FALSE(GetIsDragged(browser()));
774 EXPECT_FALSE(GetIsDragged(new_browser));
775 // After this both windows should still be manageable.
776 EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
777 EXPECT_TRUE(IsWindowPositionManaged(
778 new_browser->window()->GetNativeWindow()));
780 // The new window should be maximized.
781 EXPECT_TRUE(new_browser->window()->IsMaximized());
784 // Deletes a tab being dragged before the user moved enough to start a drag.
785 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
786 DeleteBeforeStartedDragging) {
788 AddTabAndResetBrowser(browser());
789 TabStrip* tab_strip = GetTabStripForBrowser(browser());
791 // Click on the first tab, but don't move it.
792 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
793 ASSERT_TRUE(PressInput(tab_0_center));
795 // Should be dragging.
796 ASSERT_TRUE(tab_strip->IsDragSessionActive());
797 ASSERT_TRUE(TabDragController::IsActive());
799 // Delete the tab being dragged.
800 delete browser()->tab_strip_model()->GetWebContentsAt(0);
802 // Should have canceled dragging.
803 ASSERT_FALSE(tab_strip->IsDragSessionActive());
804 ASSERT_FALSE(TabDragController::IsActive());
806 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
807 EXPECT_FALSE(GetIsDragged(browser()));
810 #if defined(OS_CHROMEOS)
811 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
812 // compositor. crbug.com/331924
813 #define MAYBE_DeleteTabWhileAttached DISABLED_DeleteTabWhileAttached
815 #define MAYBE_DeleteTabWhileAttached DeleteTabWhileAttached
817 // Deletes a tab being dragged while still attached.
818 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
819 MAYBE_DeleteTabWhileAttached) {
820 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
821 // compositor. crbug.com/331924
822 if (input_source() == INPUT_SOURCE_MOUSE) {
823 VLOG(1) << "Test is DISABLED for mouse input.";
828 AddTabAndResetBrowser(browser());
829 TabStrip* tab_strip = GetTabStripForBrowser(browser());
831 // Click on the first tab and move it enough so that it starts dragging but is
833 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
834 ASSERT_TRUE(PressInput(tab_0_center));
835 ASSERT_TRUE(DragInputTo(
836 gfx::Point(tab_0_center.x() + 20, tab_0_center.y())));
838 // Should be dragging.
839 ASSERT_TRUE(tab_strip->IsDragSessionActive());
840 ASSERT_TRUE(TabDragController::IsActive());
842 // Delete the tab being dragged.
843 delete browser()->tab_strip_model()->GetWebContentsAt(0);
845 // Should have canceled dragging.
846 ASSERT_FALSE(tab_strip->IsDragSessionActive());
847 ASSERT_FALSE(TabDragController::IsActive());
849 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
851 EXPECT_FALSE(GetIsDragged(browser()));
856 void DeleteWhileDetachedStep2(WebContents* tab) {
862 #if defined(OS_CHROMEOS)
863 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
864 // compositor. crbug.com/331924
865 #define MAYBE_DeleteTabWhileDetached DISABLED_DeleteTabWhileDetached
867 #define MAYBE_DeleteTabWhileDetached DeleteTabWhileDetached
869 // Deletes a tab being dragged after dragging a tab so that a new window is
871 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
872 MAYBE_DeleteTabWhileDetached) {
874 AddTabAndResetBrowser(browser());
875 TabStrip* tab_strip = GetTabStripForBrowser(browser());
877 // Move to the first tab and drag it enough so that it detaches.
878 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
879 WebContents* to_delete =
880 browser()->tab_strip_model()->GetWebContentsAt(0);
881 ASSERT_TRUE(PressInput(tab_0_center));
882 ASSERT_TRUE(DragInputToNotifyWhenDone(
883 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
884 base::Bind(&DeleteWhileDetachedStep2, to_delete)));
885 QuitWhenNotDragging();
887 // Should not be dragging.
888 ASSERT_FALSE(tab_strip->IsDragSessionActive());
889 ASSERT_FALSE(TabDragController::IsActive());
891 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
893 EXPECT_FALSE(GetIsDragged(browser()));
898 void DeleteSourceDetachedStep2(WebContents* tab,
899 const BrowserList* browser_list) {
900 ASSERT_EQ(2u, browser_list->size());
901 Browser* new_browser = browser_list->get(1);
902 // This ends up closing the source window.
905 ui_controls::SendKeyPress(new_browser->window()->GetNativeWindow(),
906 ui::VKEY_ESCAPE, false, false, false, false);
911 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
912 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
913 // compositor. crbug.com/331924
914 #define MAYBE_DeleteSourceDetached DISABLED_DeleteSourceDetached
916 #define MAYBE_DeleteSourceDetached DeleteSourceDetached
918 // Detaches a tab and while detached deletes a tab from the source so that the
919 // source window closes then presses escape to cancel the drag.
920 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
921 MAYBE_DeleteSourceDetached) {
923 AddTabAndResetBrowser(browser());
924 TabStrip* tab_strip = GetTabStripForBrowser(browser());
926 // Move to the first tab and drag it enough so that it detaches.
927 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
928 WebContents* to_delete = browser()->tab_strip_model()->GetWebContentsAt(1);
929 ASSERT_TRUE(PressInput(tab_0_center));
930 ASSERT_TRUE(DragInputToNotifyWhenDone(
931 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
932 base::Bind(&DeleteSourceDetachedStep2, to_delete, native_browser_list)));
933 QuitWhenNotDragging();
935 // Should not be dragging.
936 ASSERT_EQ(1u, native_browser_list->size());
937 Browser* new_browser = native_browser_list->get(0);
938 ASSERT_FALSE(GetTabStripForBrowser(new_browser)->IsDragSessionActive());
939 ASSERT_FALSE(TabDragController::IsActive());
941 EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
943 EXPECT_FALSE(GetIsDragged(new_browser));
945 // Remaining browser window should not be maximized
946 EXPECT_FALSE(new_browser->window()->IsMaximized());
951 void PressEscapeWhileDetachedStep2(const BrowserList* browser_list) {
952 ASSERT_EQ(2u, browser_list->size());
953 Browser* new_browser = browser_list->get(1);
954 ui_controls::SendKeyPress(
955 new_browser->window()->GetNativeWindow(), ui::VKEY_ESCAPE, false, false,
961 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
962 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
963 // compositor. crbug.com/331924
964 #define MAYBE_PressEscapeWhileDetached DISABLED_PressEscapeWhileDetached
966 #define MAYBE_PressEscapeWhileDetached PressEscapeWhileDetached
968 // This is disabled until NativeViewHost::Detach really detaches.
969 // Detaches a tab and while detached presses escape to revert the drag.
970 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
971 MAYBE_PressEscapeWhileDetached) {
973 AddTabAndResetBrowser(browser());
974 TabStrip* tab_strip = GetTabStripForBrowser(browser());
976 // Move to the first tab and drag it enough so that it detaches.
977 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
978 ASSERT_TRUE(PressInput(tab_0_center));
979 ASSERT_TRUE(DragInputToNotifyWhenDone(
980 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
981 base::Bind(&PressEscapeWhileDetachedStep2, native_browser_list)));
982 QuitWhenNotDragging();
984 // Should not be dragging.
985 ASSERT_FALSE(tab_strip->IsDragSessionActive());
986 ASSERT_FALSE(TabDragController::IsActive());
988 // And there should only be one window.
989 EXPECT_EQ(1u, native_browser_list->size());
991 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
993 // Remaining browser window should not be maximized
994 EXPECT_FALSE(browser()->window()->IsMaximized());
996 // The tab strip should no longer have capture because the drag was ended and
997 // mouse/touch was released.
998 EXPECT_FALSE(tab_strip->GetWidget()->HasCapture());
1003 void DragAllStep2(DetachToBrowserTabDragControllerTest* test,
1004 const BrowserList* browser_list) {
1005 // Should only be one window.
1006 ASSERT_EQ(1u, browser_list->size());
1007 if (test->input_source() == INPUT_SOURCE_TOUCH) {
1008 ASSERT_TRUE(test->ReleaseInput());
1010 ASSERT_TRUE(test->ReleaseMouseAsync());
1016 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1017 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1018 // compositor. crbug.com/331924
1019 #define MAYBE_DragAll DISABLED_DragAll
1021 #define MAYBE_DragAll DragAll
1023 // Selects multiple tabs and starts dragging the window.
1024 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, MAYBE_DragAll) {
1026 AddTabAndResetBrowser(browser());
1027 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1028 browser()->tab_strip_model()->AddTabAtToSelection(0);
1029 browser()->tab_strip_model()->AddTabAtToSelection(1);
1031 // Move to the first tab and drag it enough so that it would normally
1033 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1034 ASSERT_TRUE(PressInput(tab_0_center));
1035 ASSERT_TRUE(DragInputToNotifyWhenDone(
1036 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1037 base::Bind(&DragAllStep2, this, native_browser_list)));
1038 QuitWhenNotDragging();
1040 // Should not be dragging.
1041 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1042 ASSERT_FALSE(TabDragController::IsActive());
1044 // And there should only be one window.
1045 EXPECT_EQ(1u, native_browser_list->size());
1047 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
1049 EXPECT_FALSE(GetIsDragged(browser()));
1051 // Remaining browser window should not be maximized
1052 EXPECT_FALSE(browser()->window()->IsMaximized());
1057 // Invoked from the nested message loop.
1058 void DragAllToSeparateWindowStep2(DetachToBrowserTabDragControllerTest* test,
1059 TabStrip* attached_tab_strip,
1060 TabStrip* target_tab_strip,
1061 const BrowserList* browser_list) {
1062 ASSERT_TRUE(attached_tab_strip->IsDragSessionActive());
1063 ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
1064 ASSERT_TRUE(TabDragController::IsActive());
1065 ASSERT_EQ(2u, browser_list->size());
1067 // Drag to target_tab_strip. This should stop the nested loop from dragging
1069 gfx::Point target_point(target_tab_strip->width() - 1,
1070 target_tab_strip->height() / 2);
1071 views::View::ConvertPointToScreen(target_tab_strip, &target_point);
1072 ASSERT_TRUE(test->DragInputToAsync(target_point));
1077 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1078 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1079 // compositor. crbug.com/331924
1080 #define MAYBE_DragAllToSeparateWindow DISABLED_DragAllToSeparateWindow
1082 #define MAYBE_DragAllToSeparateWindow DragAllToSeparateWindow
1084 // Creates two browsers, selects all tabs in first and drags into second.
1085 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1086 MAYBE_DragAllToSeparateWindow) {
1087 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1089 // Add another tab to browser().
1090 AddTabAndResetBrowser(browser());
1092 // Create another browser.
1093 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
1094 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1096 browser()->tab_strip_model()->AddTabAtToSelection(0);
1097 browser()->tab_strip_model()->AddTabAtToSelection(1);
1099 // Move to the first tab and drag it enough so that it detaches, but not
1100 // enough that it attaches to browser2.
1101 gfx::Point tab_0_center(
1102 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1103 ASSERT_TRUE(PressInput(tab_0_center));
1104 ASSERT_TRUE(DragInputToNotifyWhenDone(
1105 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1106 base::Bind(&DragAllToSeparateWindowStep2, this, tab_strip, tab_strip2,
1107 native_browser_list)));
1108 QuitWhenNotDragging();
1110 // Should now be attached to tab_strip2.
1111 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1112 ASSERT_TRUE(TabDragController::IsActive());
1113 ASSERT_EQ(1u, native_browser_list->size());
1115 // Release the mouse, stopping the drag session.
1116 ASSERT_TRUE(ReleaseInput());
1117 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1118 ASSERT_FALSE(TabDragController::IsActive());
1119 EXPECT_EQ("100 0 1", IDString(browser2->tab_strip_model()));
1121 EXPECT_FALSE(GetIsDragged(browser2));
1123 // Remaining browser window should not be maximized
1124 EXPECT_FALSE(browser2->window()->IsMaximized());
1129 // Invoked from the nested message loop.
1130 void DragAllToSeparateWindowAndCancelStep2(
1131 DetachToBrowserTabDragControllerTest* test,
1132 TabStrip* attached_tab_strip,
1133 TabStrip* target_tab_strip,
1134 const BrowserList* browser_list) {
1135 ASSERT_TRUE(attached_tab_strip->IsDragSessionActive());
1136 ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
1137 ASSERT_TRUE(TabDragController::IsActive());
1138 ASSERT_EQ(2u, browser_list->size());
1140 // Drag to target_tab_strip. This should stop the nested loop from dragging
1142 gfx::Point target_point(target_tab_strip->width() - 1,
1143 target_tab_strip->height() / 2);
1144 views::View::ConvertPointToScreen(target_tab_strip, &target_point);
1145 ASSERT_TRUE(test->DragInputToAsync(target_point));
1150 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1151 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1152 // compositor. crbug.com/331924
1153 #define MAYBE_DragAllToSeparateWindowAndCancel \
1154 DISABLED_DragAllToSeparateWindowAndCancel
1156 #define MAYBE_DragAllToSeparateWindowAndCancel DragAllToSeparateWindowAndCancel
1158 // Creates two browsers, selects all tabs in first, drags into second, then hits
1160 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1161 MAYBE_DragAllToSeparateWindowAndCancel) {
1162 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1164 // Add another tab to browser().
1165 AddTabAndResetBrowser(browser());
1167 // Create another browser.
1168 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
1169 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1171 browser()->tab_strip_model()->AddTabAtToSelection(0);
1172 browser()->tab_strip_model()->AddTabAtToSelection(1);
1174 // Move to the first tab and drag it enough so that it detaches, but not
1175 // enough that it attaches to browser2.
1176 gfx::Point tab_0_center(
1177 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1178 ASSERT_TRUE(PressInput(tab_0_center));
1179 ASSERT_TRUE(DragInputToNotifyWhenDone(
1180 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1181 base::Bind(&DragAllToSeparateWindowAndCancelStep2, this,
1182 tab_strip, tab_strip2, native_browser_list)));
1183 QuitWhenNotDragging();
1185 // Should now be attached to tab_strip2.
1186 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1187 ASSERT_TRUE(TabDragController::IsActive());
1188 ASSERT_EQ(1u, native_browser_list->size());
1191 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
1192 browser2, ui::VKEY_ESCAPE, false, false, false, false));
1194 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1195 ASSERT_FALSE(TabDragController::IsActive());
1196 EXPECT_EQ("100 0 1", IDString(browser2->tab_strip_model()));
1198 // browser() will have been destroyed, but browser2 should remain.
1199 ASSERT_EQ(1u, native_browser_list->size());
1201 EXPECT_FALSE(GetIsDragged(browser2));
1203 // Remaining browser window should not be maximized
1204 EXPECT_FALSE(browser2->window()->IsMaximized());
1207 #if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_WIN)
1208 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1209 // compositor. crbug.com/331924
1210 #define MAYBE_DragDirectlyToSecondWindow DISABLED_DragDirectlyToSecondWindow
1212 #define MAYBE_DragDirectlyToSecondWindow DragDirectlyToSecondWindow
1214 // Creates two browsers, drags from first into the second in such a way that
1215 // no detaching should happen.
1216 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1217 MAYBE_DragDirectlyToSecondWindow) {
1218 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1220 // Add another tab to browser().
1221 AddTabAndResetBrowser(browser());
1223 // Create another browser.
1224 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
1225 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1227 // Move the tabstrip down enough so that we can detach.
1228 gfx::Rect bounds(browser2->window()->GetBounds());
1229 bounds.Offset(0, 100);
1230 browser2->window()->SetBounds(bounds);
1232 // Move to the first tab and drag it enough so that it detaches, but not
1233 // enough that it attaches to browser2.
1234 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1235 ASSERT_TRUE(PressInput(tab_0_center));
1237 gfx::Point b2_location(5, 0);
1238 views::View::ConvertPointToScreen(tab_strip2, &b2_location);
1239 ASSERT_TRUE(DragInputTo(b2_location));
1241 // Should now be attached to tab_strip2.
1242 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1243 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1244 ASSERT_TRUE(TabDragController::IsActive());
1246 // Release the mouse, stopping the drag session.
1247 ASSERT_TRUE(ReleaseInput());
1248 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1249 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1250 ASSERT_FALSE(TabDragController::IsActive());
1251 EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1252 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1254 EXPECT_FALSE(GetIsDragged(browser()));
1255 EXPECT_FALSE(GetIsDragged(browser2));
1257 // Both windows should not be maximized
1258 EXPECT_FALSE(browser()->window()->IsMaximized());
1259 EXPECT_FALSE(browser2->window()->IsMaximized());
1262 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1263 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1264 // compositor. crbug.com/331924
1265 #define MAYBE_DragSingleTabToSeparateWindow \
1266 DISABLED_DragSingleTabToSeparateWindow
1268 #define MAYBE_DragSingleTabToSeparateWindow DragSingleTabToSeparateWindow
1270 // Creates two browsers, the first browser has a single tab and drags into the
1272 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1273 MAYBE_DragSingleTabToSeparateWindow) {
1274 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1276 ResetIDs(browser()->tab_strip_model(), 0);
1278 // Create another browser.
1279 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
1280 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1281 const gfx::Rect initial_bounds(browser2->window()->GetBounds());
1283 // Move to the first tab and drag it enough so that it detaches, but not
1284 // enough that it attaches to browser2.
1285 gfx::Point tab_0_center(
1286 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1287 ASSERT_TRUE(PressInput(tab_0_center));
1288 ASSERT_TRUE(DragInputToNotifyWhenDone(
1289 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1290 base::Bind(&DragAllToSeparateWindowStep2, this, tab_strip, tab_strip2,
1291 native_browser_list)));
1292 QuitWhenNotDragging();
1294 // Should now be attached to tab_strip2.
1295 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1296 ASSERT_TRUE(TabDragController::IsActive());
1297 ASSERT_EQ(1u, native_browser_list->size());
1299 // Release the mouse, stopping the drag session.
1300 ASSERT_TRUE(ReleaseInput());
1301 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1302 ASSERT_FALSE(TabDragController::IsActive());
1303 EXPECT_EQ("100 0", IDString(browser2->tab_strip_model()));
1305 EXPECT_FALSE(GetIsDragged(browser2));
1307 // Remaining browser window should not be maximized
1308 EXPECT_FALSE(browser2->window()->IsMaximized());
1310 // Make sure that the window is still managed and not user moved.
1311 EXPECT_TRUE(IsWindowPositionManaged(browser2->window()->GetNativeWindow()));
1312 EXPECT_FALSE(HasUserChangedWindowPositionOrSize(
1313 browser2->window()->GetNativeWindow()));
1314 // Also make sure that the drag to window position has not changed.
1315 EXPECT_EQ(initial_bounds.ToString(),
1316 browser2->window()->GetBounds().ToString());
1321 // Invoked from the nested message loop.
1322 void CancelOnNewTabWhenDraggingStep2(
1323 DetachToBrowserTabDragControllerTest* test,
1324 const BrowserList* browser_list) {
1325 ASSERT_TRUE(TabDragController::IsActive());
1326 ASSERT_EQ(2u, browser_list->size());
1328 // Add another tab. This should trigger exiting the nested loop.
1329 test->AddBlankTabAndShow(browser_list->GetLastActive());
1334 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1335 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1336 // compositor. crbug.com/331924
1337 #define MAYBE_CancelOnNewTabWhenDragging DISABLED_CancelOnNewTabWhenDragging
1339 #define MAYBE_CancelOnNewTabWhenDragging CancelOnNewTabWhenDragging
1341 // Adds another tab, detaches into separate window, adds another tab and
1342 // verifies the run loop ends.
1343 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1344 MAYBE_CancelOnNewTabWhenDragging) {
1345 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1347 // Add another tab to browser().
1348 AddTabAndResetBrowser(browser());
1350 // Move to the first tab and drag it enough so that it detaches.
1351 gfx::Point tab_0_center(
1352 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1353 ASSERT_TRUE(PressInput(tab_0_center));
1354 ASSERT_TRUE(DragInputToNotifyWhenDone(
1355 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1356 base::Bind(&CancelOnNewTabWhenDraggingStep2, this, native_browser_list)));
1357 QuitWhenNotDragging();
1359 // Should be two windows and not dragging.
1360 ASSERT_FALSE(TabDragController::IsActive());
1361 ASSERT_EQ(2u, native_browser_list->size());
1362 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
1363 EXPECT_FALSE(GetIsDragged(*it));
1364 // Should not be maximized
1365 EXPECT_FALSE(it->window()->IsMaximized());
1369 #if defined(OS_CHROMEOS)
1370 // TODO(sky,sad): A number of tests below are disabled as they fail due to
1371 // resize locks with a real compositor. crbug.com/331924
1374 void DragInMaximizedWindowStep2(DetachToBrowserTabDragControllerTest* test,
1376 TabStrip* tab_strip,
1377 const BrowserList* browser_list) {
1378 // There should be another browser.
1379 ASSERT_EQ(2u, browser_list->size());
1380 Browser* new_browser = browser_list->get(1);
1381 EXPECT_NE(browser, new_browser);
1382 ASSERT_TRUE(new_browser->window()->IsActive());
1383 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
1385 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1386 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1388 // Both windows should be visible.
1389 EXPECT_TRUE(tab_strip->GetWidget()->IsVisible());
1390 EXPECT_TRUE(tab_strip2->GetWidget()->IsVisible());
1393 ASSERT_TRUE(test->ReleaseInput());
1398 // Creates a browser with two tabs, maximizes it, drags the tab out.
1399 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1400 DISABLED_DragInMaximizedWindow) {
1401 AddTabAndResetBrowser(browser());
1402 browser()->window()->Maximize();
1404 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1406 // Move to the first tab and drag it enough so that it detaches.
1407 gfx::Point tab_0_center(
1408 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1409 ASSERT_TRUE(PressInput(tab_0_center));
1410 ASSERT_TRUE(DragInputToNotifyWhenDone(
1411 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1412 base::Bind(&DragInMaximizedWindowStep2, this, browser(), tab_strip,
1413 native_browser_list)));
1414 QuitWhenNotDragging();
1416 ASSERT_FALSE(TabDragController::IsActive());
1418 // Should be two browsers.
1419 ASSERT_EQ(2u, native_browser_list->size());
1420 Browser* new_browser = native_browser_list->get(1);
1421 ASSERT_TRUE(new_browser->window()->IsActive());
1423 EXPECT_TRUE(browser()->window()->GetNativeWindow()->IsVisible());
1424 EXPECT_TRUE(new_browser->window()->GetNativeWindow()->IsVisible());
1426 EXPECT_FALSE(GetIsDragged(browser()));
1427 EXPECT_FALSE(GetIsDragged(new_browser));
1429 // The source window should be maximized.
1430 EXPECT_TRUE(browser()->window()->IsMaximized());
1431 // The new window should be maximized.
1432 EXPECT_TRUE(new_browser->window()->IsMaximized());
1435 // Subclass of DetachToBrowserTabDragControllerTest that
1436 // creates multiple displays.
1437 class DetachToBrowserInSeparateDisplayTabDragControllerTest
1438 : public DetachToBrowserTabDragControllerTest {
1440 DetachToBrowserInSeparateDisplayTabDragControllerTest() {}
1441 virtual ~DetachToBrowserInSeparateDisplayTabDragControllerTest() {}
1443 virtual void SetUpCommandLine(CommandLine* command_line) override {
1444 DetachToBrowserTabDragControllerTest::SetUpCommandLine(command_line);
1445 // Make screens sufficiently wide to host 2 browsers side by side.
1446 command_line->AppendSwitchASCII("ash-host-window-bounds",
1447 "0+0-600x600,601+0-600x600");
1451 DISALLOW_COPY_AND_ASSIGN(
1452 DetachToBrowserInSeparateDisplayTabDragControllerTest);
1455 // Subclass of DetachToBrowserTabDragControllerTest that runs tests only with
1457 class DetachToBrowserTabDragControllerTestTouch
1458 : public DetachToBrowserTabDragControllerTest {
1460 DetachToBrowserTabDragControllerTestTouch() {}
1461 virtual ~DetachToBrowserTabDragControllerTestTouch() {}
1464 DISALLOW_COPY_AND_ASSIGN(DetachToBrowserTabDragControllerTestTouch);
1469 void DragSingleTabToSeparateWindowInSecondDisplayStep3(
1470 DetachToBrowserTabDragControllerTest* test) {
1471 ASSERT_TRUE(test->ReleaseInput());
1474 void DragSingleTabToSeparateWindowInSecondDisplayStep2(
1475 DetachToBrowserTabDragControllerTest* test,
1476 const gfx::Point& target_point) {
1477 ASSERT_TRUE(test->DragInputToNotifyWhenDone(
1478 target_point.x(), target_point.y(),
1479 base::Bind(&DragSingleTabToSeparateWindowInSecondDisplayStep3, test)));
1484 // Drags from browser to a second display and releases input.
1485 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1486 DISABLED_DragSingleTabToSeparateWindowInSecondDisplay) {
1488 AddTabAndResetBrowser(browser());
1489 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1491 // Move to the first tab and drag it enough so that it detaches.
1492 // Then drag it to the final destination on the second screen.
1493 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1494 ASSERT_TRUE(PressInput(tab_0_center));
1495 ASSERT_TRUE(DragInputToNotifyWhenDone(
1496 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1497 base::Bind(&DragSingleTabToSeparateWindowInSecondDisplayStep2,
1498 this, gfx::Point(600 + tab_0_center.x(),
1500 + GetDetachY(tab_strip)))));
1501 QuitWhenNotDragging();
1503 // Should no longer be dragging.
1504 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1505 ASSERT_FALSE(TabDragController::IsActive());
1507 // There should now be another browser.
1508 ASSERT_EQ(2u, native_browser_list->size());
1509 Browser* new_browser = native_browser_list->get(1);
1510 ASSERT_TRUE(new_browser->window()->IsActive());
1511 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
1512 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1514 // This other browser should be on the second screen (with mouse drag)
1515 // With the touch input the browser cannot be dragged from one screen
1516 // to another and the window stays on the first screen.
1517 if (input_source() == INPUT_SOURCE_MOUSE) {
1518 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1519 ASSERT_EQ(2u, roots.size());
1520 aura::Window* second_root = roots[1];
1521 EXPECT_EQ(second_root,
1522 new_browser->window()->GetNativeWindow()->GetRootWindow());
1525 EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
1526 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1528 // Both windows should not be maximized
1529 EXPECT_FALSE(browser()->window()->IsMaximized());
1530 EXPECT_FALSE(new_browser->window()->IsMaximized());
1535 // Invoked from the nested message loop.
1536 void DragTabToWindowInSeparateDisplayStep2(
1537 DetachToBrowserTabDragControllerTest* test,
1538 TabStrip* not_attached_tab_strip,
1539 TabStrip* target_tab_strip) {
1540 ASSERT_FALSE(not_attached_tab_strip->IsDragSessionActive());
1541 ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
1542 ASSERT_TRUE(TabDragController::IsActive());
1544 // Drag to target_tab_strip. This should stop the nested loop from dragging
1546 gfx::Point target_point(
1547 GetCenterInScreenCoordinates(target_tab_strip->tab_at(0)));
1549 // Move it close to the beginning of the target tabstrip.
1551 target_point.x() - target_tab_strip->tab_at(0)->width() / 2 + 10);
1552 ASSERT_TRUE(test->DragInputToAsync(target_point));
1557 // Drags from browser to another browser on a second display and releases input.
1558 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1559 DISABLED_DragTabToWindowInSeparateDisplay) {
1561 AddTabAndResetBrowser(browser());
1562 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1564 // Create another browser.
1565 Browser* browser2 = CreateBrowser(browser()->profile());
1566 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1567 ResetIDs(browser2->tab_strip_model(), 100);
1569 // Move the second browser to the second display.
1570 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1571 ASSERT_EQ(2u, roots.size());
1572 aura::Window* second_root = roots[1];
1573 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1574 second_root).work_area();
1575 browser2->window()->SetBounds(work_area);
1576 EXPECT_EQ(second_root,
1577 browser2->window()->GetNativeWindow()->GetRootWindow());
1579 // Move to the first tab and drag it enough so that it detaches, but not
1580 // enough that it attaches to browser2.
1581 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1582 ASSERT_TRUE(PressInput(tab_0_center));
1583 ASSERT_TRUE(DragInputToNotifyWhenDone(
1584 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1585 base::Bind(&DragTabToWindowInSeparateDisplayStep2,
1586 this, tab_strip, tab_strip2)));
1587 QuitWhenNotDragging();
1589 // Should now be attached to tab_strip2.
1590 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1591 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1592 ASSERT_TRUE(TabDragController::IsActive());
1594 // Release the mouse, stopping the drag session.
1595 ASSERT_TRUE(ReleaseInput());
1596 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1597 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1598 ASSERT_FALSE(TabDragController::IsActive());
1599 EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1600 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1602 // Both windows should not be maximized
1603 EXPECT_FALSE(browser()->window()->IsMaximized());
1604 EXPECT_FALSE(browser2->window()->IsMaximized());
1607 // Drags from browser to another browser on a second display and releases input.
1608 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1609 DISABLED_DragTabToWindowOnSecondDisplay) {
1611 AddTabAndResetBrowser(browser());
1612 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1614 // Create another browser.
1615 Browser* browser2 = CreateBrowser(browser()->profile());
1616 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1617 ResetIDs(browser2->tab_strip_model(), 100);
1619 // Move both browsers to the second display.
1620 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1621 ASSERT_EQ(2u, roots.size());
1622 aura::Window* second_root = roots[1];
1623 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1624 second_root).work_area();
1625 browser()->window()->SetBounds(work_area);
1627 // position both browser windows side by side on the second screen.
1628 gfx::Rect work_area2(work_area);
1629 work_area.set_width(work_area.width()/2);
1630 browser()->window()->SetBounds(work_area);
1631 work_area2.set_x(work_area2.x() + work_area2.width()/2);
1632 work_area2.set_width(work_area2.width()/2);
1633 browser2->window()->SetBounds(work_area2);
1634 EXPECT_EQ(second_root,
1635 browser()->window()->GetNativeWindow()->GetRootWindow());
1636 EXPECT_EQ(second_root,
1637 browser2->window()->GetNativeWindow()->GetRootWindow());
1639 // Move to the first tab and drag it enough so that it detaches, but not
1640 // enough that it attaches to browser2.
1641 // SetEventGeneratorRootWindow sets correct (second) RootWindow
1642 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1643 SetEventGeneratorRootWindow(tab_0_center);
1644 ASSERT_TRUE(PressInput(tab_0_center));
1645 ASSERT_TRUE(DragInputToNotifyWhenDone(
1646 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1647 base::Bind(&DragTabToWindowInSeparateDisplayStep2,
1648 this, tab_strip, tab_strip2)));
1649 QuitWhenNotDragging();
1651 // Should now be attached to tab_strip2.
1652 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1653 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1654 ASSERT_TRUE(TabDragController::IsActive());
1656 // Release the mouse, stopping the drag session.
1657 ASSERT_TRUE(ReleaseInput());
1658 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1659 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1660 ASSERT_FALSE(TabDragController::IsActive());
1661 EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1662 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1664 // Both windows should not be maximized
1665 EXPECT_FALSE(browser()->window()->IsMaximized());
1666 EXPECT_FALSE(browser2->window()->IsMaximized());
1669 // Drags from a maximized browser to another non-maximized browser on a second
1670 // display and releases input.
1671 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1672 DISABLED_DragMaxTabToNonMaxWindowInSeparateDisplay) {
1674 AddTabAndResetBrowser(browser());
1675 browser()->window()->Maximize();
1676 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1678 // Create another browser on the second display.
1679 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1680 ASSERT_EQ(2u, roots.size());
1681 aura::Window* first_root = roots[0];
1682 aura::Window* second_root = roots[1];
1683 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1684 second_root).work_area();
1685 work_area.Inset(20, 20, 20, 60);
1686 Browser::CreateParams params(browser()->profile(),
1687 browser()->host_desktop_type());
1688 params.initial_show_state = ui::SHOW_STATE_NORMAL;
1689 params.initial_bounds = work_area;
1690 Browser* browser2 = new Browser(params);
1691 AddBlankTabAndShow(browser2);
1693 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1694 ResetIDs(browser2->tab_strip_model(), 100);
1696 EXPECT_EQ(second_root,
1697 browser2->window()->GetNativeWindow()->GetRootWindow());
1698 EXPECT_EQ(first_root,
1699 browser()->window()->GetNativeWindow()->GetRootWindow());
1700 EXPECT_EQ(2, tab_strip->tab_count());
1701 EXPECT_EQ(1, tab_strip2->tab_count());
1703 // Move to the first tab and drag it enough so that it detaches, but not
1704 // enough that it attaches to browser2.
1705 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1706 ASSERT_TRUE(PressInput(tab_0_center));
1707 ASSERT_TRUE(DragInputToNotifyWhenDone(
1708 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1709 base::Bind(&DragTabToWindowInSeparateDisplayStep2,
1710 this, tab_strip, tab_strip2)));
1711 QuitWhenNotDragging();
1713 // Should now be attached to tab_strip2.
1714 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1715 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1716 ASSERT_TRUE(TabDragController::IsActive());
1718 // Release the mouse, stopping the drag session.
1719 ASSERT_TRUE(ReleaseInput());
1721 // tab should have moved
1722 EXPECT_EQ(1, tab_strip->tab_count());
1723 EXPECT_EQ(2, tab_strip2->tab_count());
1725 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1726 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1727 ASSERT_FALSE(TabDragController::IsActive());
1728 EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1729 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1731 // Source browser should still be maximized, target should not
1732 EXPECT_TRUE(browser()->window()->IsMaximized());
1733 EXPECT_FALSE(browser2->window()->IsMaximized());
1736 // Drags from a restored browser to an immersive fullscreen browser on a
1737 // second display and releases input.
1738 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1739 DISABLED_DragTabToImmersiveBrowserOnSeparateDisplay) {
1741 AddTabAndResetBrowser(browser());
1742 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1744 // Create another browser.
1745 Browser* browser2 = CreateBrowser(browser()->profile());
1746 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1747 ResetIDs(browser2->tab_strip_model(), 100);
1749 // Move the second browser to the second display.
1750 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1751 ASSERT_EQ(2u, roots.size());
1752 aura::Window* second_root = roots[1];
1753 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1754 second_root).work_area();
1755 browser2->window()->SetBounds(work_area);
1756 EXPECT_EQ(second_root,
1757 browser2->window()->GetNativeWindow()->GetRootWindow());
1759 // Put the second browser into immersive fullscreen.
1760 BrowserView* browser_view2 = BrowserView::GetBrowserViewForBrowser(browser2);
1761 ImmersiveModeController* immersive_controller2 =
1762 browser_view2->immersive_mode_controller();
1763 immersive_controller2->SetupForTest();
1764 chrome::ToggleFullscreenMode(browser2);
1765 ASSERT_TRUE(immersive_controller2->IsEnabled());
1766 ASSERT_FALSE(immersive_controller2->IsRevealed());
1767 ASSERT_TRUE(tab_strip2->IsImmersiveStyle());
1769 // Move to the first tab and drag it enough so that it detaches, but not
1770 // enough that it attaches to browser2.
1771 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1772 ASSERT_TRUE(PressInput(tab_0_center));
1773 ASSERT_TRUE(DragInputToNotifyWhenDone(
1774 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1775 base::Bind(&DragTabToWindowInSeparateDisplayStep2,
1776 this, tab_strip, tab_strip2)));
1777 QuitWhenNotDragging();
1779 // Should now be attached to tab_strip2.
1780 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1781 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1782 ASSERT_TRUE(TabDragController::IsActive());
1784 // browser2's top chrome should be revealed and the tab strip should be
1785 // at normal height while user is tragging tabs_strip2's tabs.
1786 ASSERT_TRUE(immersive_controller2->IsRevealed());
1787 ASSERT_FALSE(tab_strip2->IsImmersiveStyle());
1789 // Release the mouse, stopping the drag session.
1790 ASSERT_TRUE(ReleaseInput());
1791 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1792 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1793 ASSERT_FALSE(TabDragController::IsActive());
1794 EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1795 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1797 // Move the mouse off of browser2's top chrome.
1798 aura::Window* primary_root = roots[0];
1799 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
1800 primary_root->GetBoundsInScreen().CenterPoint()));
1802 // The first browser window should not be in immersive fullscreen.
1803 // browser2 should still be in immersive fullscreen, but the top chrome should
1804 // no longer be revealed.
1805 BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
1806 EXPECT_FALSE(browser_view->immersive_mode_controller()->IsEnabled());
1808 EXPECT_TRUE(immersive_controller2->IsEnabled());
1809 EXPECT_FALSE(immersive_controller2->IsRevealed());
1810 EXPECT_TRUE(tab_strip2->IsImmersiveStyle());
1813 // Subclass of DetachToBrowserTabDragControllerTest that
1814 // creates multiple displays with different device scale factors.
1815 class DifferentDeviceScaleFactorDisplayTabDragControllerTest
1816 : public DetachToBrowserTabDragControllerTest {
1818 DifferentDeviceScaleFactorDisplayTabDragControllerTest() {}
1819 virtual ~DifferentDeviceScaleFactorDisplayTabDragControllerTest() {}
1821 virtual void SetUpCommandLine(CommandLine* command_line) override {
1822 DetachToBrowserTabDragControllerTest::SetUpCommandLine(command_line);
1823 command_line->AppendSwitchASCII("ash-host-window-bounds",
1824 "400x400,0+400-800x800*2");
1827 float GetCursorDeviceScaleFactor() const {
1828 ash::test::CursorManagerTestApi cursor_test_api(
1829 ash::Shell::GetInstance()->cursor_manager());
1830 return cursor_test_api.GetCurrentCursor().device_scale_factor();
1834 DISALLOW_COPY_AND_ASSIGN(
1835 DifferentDeviceScaleFactorDisplayTabDragControllerTest);
1840 // The points where a tab is dragged in CursorDeviceScaleFactorStep.
1841 const struct DragPoint {
1852 // The expected device scale factors before the cursor is moved to the
1853 // corresponding kDragPoints in CursorDeviceScaleFactorStep.
1854 const float kDeviceScaleFactorExpectations[] = {
1863 arraysize(kDragPoints) == arraysize(kDeviceScaleFactorExpectations),
1864 kDragPoints_and_kDeviceScaleFactorExpectations_must_have_same_size);
1866 // Drags tab to |kDragPoints[index]|, then calls the next step function.
1867 void CursorDeviceScaleFactorStep(
1868 DifferentDeviceScaleFactorDisplayTabDragControllerTest* test,
1869 TabStrip* not_attached_tab_strip,
1871 ASSERT_FALSE(not_attached_tab_strip->IsDragSessionActive());
1872 ASSERT_TRUE(TabDragController::IsActive());
1874 if (index < arraysize(kDragPoints)) {
1875 EXPECT_EQ(kDeviceScaleFactorExpectations[index],
1876 test->GetCursorDeviceScaleFactor());
1877 const DragPoint p = kDragPoints[index];
1878 ASSERT_TRUE(test->DragInputToNotifyWhenDone(
1879 p.x, p.y, base::Bind(&CursorDeviceScaleFactorStep,
1880 test, not_attached_tab_strip, index + 1)));
1882 // Finishes a serise of CursorDeviceScaleFactorStep calls and ends drag.
1883 EXPECT_EQ(1.0f, test->GetCursorDeviceScaleFactor());
1884 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
1885 ui_controls::LEFT, ui_controls::UP));
1891 // Verifies cursor's device scale factor is updated when a tab is moved across
1892 // displays with different device scale factors (http://crbug.com/154183).
1893 IN_PROC_BROWSER_TEST_P(DifferentDeviceScaleFactorDisplayTabDragControllerTest,
1894 DISABLED_CursorDeviceScaleFactor) {
1896 AddTabAndResetBrowser(browser());
1897 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1899 // Move the second browser to the second display.
1900 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1901 ASSERT_EQ(2u, roots.size());
1903 // Move to the first tab and drag it enough so that it detaches.
1904 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1905 ASSERT_TRUE(PressInput(tab_0_center));
1906 ASSERT_TRUE(DragInputToNotifyWhenDone(
1907 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1908 base::Bind(&CursorDeviceScaleFactorStep,
1909 this, tab_strip, 0)));
1910 QuitWhenNotDragging();
1915 class DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest
1916 : public TabDragControllerTest {
1918 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest() {}
1920 virtual void SetUpCommandLine(CommandLine* command_line) override {
1921 TabDragControllerTest::SetUpCommandLine(command_line);
1922 command_line->AppendSwitchASCII("ash-host-window-bounds",
1923 "0+0-250x250,251+0-250x250");
1926 bool Press(const gfx::Point& position) {
1927 return ui_test_utils::SendMouseMoveSync(position) &&
1928 ui_test_utils::SendMouseEventsSync(ui_controls::LEFT,
1932 bool DragTabAndExecuteTaskWhenDone(const gfx::Point& position,
1933 const base::Closure& task) {
1934 return ui_controls::SendMouseMoveNotifyWhenDone(
1935 position.x(), position.y(), task);
1938 void QuitWhenNotDragging() {
1939 test::QuitWhenNotDraggingImpl();
1940 base::MessageLoop::current()->Run();
1944 DISALLOW_COPY_AND_ASSIGN(
1945 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest);
1948 // Invoked from the nested message loop.
1949 void CancelDragTabToWindowInSeparateDisplayStep3(
1950 TabStrip* tab_strip,
1951 const BrowserList* browser_list) {
1952 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1953 ASSERT_TRUE(TabDragController::IsActive());
1954 ASSERT_EQ(2u, browser_list->size());
1956 // Switching display mode should cancel the drag operation.
1957 ash::DisplayManager* display_manager =
1958 ash::Shell::GetInstance()->display_manager();
1959 display_manager->AddRemoveDisplay();
1962 // Invoked from the nested message loop.
1963 void CancelDragTabToWindowInSeparateDisplayStep2(
1964 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest* test,
1965 TabStrip* tab_strip,
1966 aura::Window* current_root,
1967 gfx::Point final_destination,
1968 const BrowserList* browser_list) {
1969 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1970 ASSERT_TRUE(TabDragController::IsActive());
1971 ASSERT_EQ(2u, browser_list->size());
1973 Browser* new_browser = browser_list->get(1);
1974 EXPECT_EQ(current_root,
1975 new_browser->window()->GetNativeWindow()->GetRootWindow());
1977 ASSERT_TRUE(test->DragTabAndExecuteTaskWhenDone(
1979 base::Bind(&CancelDragTabToWindowInSeparateDisplayStep3,
1980 tab_strip, browser_list)));
1985 // Drags from browser to a second display and releases input.
1986 IN_PROC_BROWSER_TEST_F(
1987 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest,
1988 DISABLED_CancelDragTabToWindowIn2ndDisplay) {
1990 AddTabAndResetBrowser(browser());
1991 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1993 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
1995 // Move the second browser to the second display.
1996 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1997 ASSERT_EQ(2u, roots.size());
1998 gfx::Point final_destination =
1999 gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
2000 roots[1]).work_area().CenterPoint();
2002 // Move to the first tab and drag it enough so that it detaches, but not
2003 // enough to move to another display.
2004 gfx::Point tab_0_dst(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
2005 ASSERT_TRUE(Press(tab_0_dst));
2006 tab_0_dst.Offset(0, GetDetachY(tab_strip));
2007 ASSERT_TRUE(DragTabAndExecuteTaskWhenDone(
2008 tab_0_dst, base::Bind(&CancelDragTabToWindowInSeparateDisplayStep2,
2009 this, tab_strip, roots[0], final_destination,
2010 native_browser_list)));
2011 QuitWhenNotDragging();
2013 ASSERT_EQ(1u, native_browser_list->size());
2014 ASSERT_FALSE(tab_strip->IsDragSessionActive());
2015 ASSERT_FALSE(TabDragController::IsActive());
2016 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2018 // Release the mouse
2019 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
2020 ui_controls::LEFT, ui_controls::UP));
2023 // Drags from browser from a second display to primary and releases input.
2024 IN_PROC_BROWSER_TEST_F(
2025 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest,
2026 DISABLED_CancelDragTabToWindowIn1stDisplay) {
2027 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
2028 ASSERT_EQ(2u, roots.size());
2031 AddTabAndResetBrowser(browser());
2032 TabStrip* tab_strip = GetTabStripForBrowser(browser());
2034 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2035 EXPECT_EQ(roots[0], browser()->window()->GetNativeWindow()->GetRootWindow());
2037 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->
2038 GetDisplayNearestWindow(roots[1]).work_area();
2039 browser()->window()->SetBounds(work_area);
2040 EXPECT_EQ(roots[1], browser()->window()->GetNativeWindow()->GetRootWindow());
2042 // Move the second browser to the display.
2043 gfx::Point final_destination =
2044 gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
2045 roots[0]).work_area().CenterPoint();
2047 // Move to the first tab and drag it enough so that it detaches, but not
2048 // enough to move to another display.
2049 gfx::Point tab_0_dst(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
2050 ASSERT_TRUE(Press(tab_0_dst));
2051 tab_0_dst.Offset(0, GetDetachY(tab_strip));
2052 ASSERT_TRUE(DragTabAndExecuteTaskWhenDone(
2053 tab_0_dst, base::Bind(&CancelDragTabToWindowInSeparateDisplayStep2,
2054 this, tab_strip, roots[1], final_destination,
2055 native_browser_list)));
2056 QuitWhenNotDragging();
2058 ASSERT_EQ(1u, native_browser_list->size());
2059 ASSERT_FALSE(tab_strip->IsDragSessionActive());
2060 ASSERT_FALSE(TabDragController::IsActive());
2061 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2063 // Release the mouse
2064 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
2065 ui_controls::LEFT, ui_controls::UP));
2070 void PressSecondFingerWhileDetachedStep2(
2071 DetachToBrowserTabDragControllerTest* test) {
2072 ASSERT_TRUE(TabDragController::IsActive());
2073 ASSERT_EQ(2u, test->native_browser_list->size());
2074 Browser* new_browser = test->native_browser_list->get(1);
2075 ASSERT_TRUE(new_browser->window()->IsActive());
2077 ASSERT_TRUE(test->PressInput2());
2082 // Detaches a tab and while detached presses a second finger.
2083 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestTouch,
2084 DISABLED_PressSecondFingerWhileDetached) {
2085 gfx::Rect bounds(browser()->window()->GetBounds());
2087 AddTabAndResetBrowser(browser());
2088 TabStrip* tab_strip = GetTabStripForBrowser(browser());
2089 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2091 // Move to the first tab and drag it enough so that it detaches.
2092 gfx::Point tab_0_center(
2093 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
2094 ASSERT_TRUE(PressInput(tab_0_center));
2095 ASSERT_TRUE(DragInputToDelayedNotifyWhenDone(
2096 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
2097 base::Bind(&PressSecondFingerWhileDetachedStep2, this),
2098 base::TimeDelta::FromMilliseconds(60)));
2099 QuitWhenNotDragging();
2101 // The drag should have been reverted.
2102 ASSERT_EQ(1u, native_browser_list->size());
2103 ASSERT_FALSE(tab_strip->IsDragSessionActive());
2104 ASSERT_FALSE(TabDragController::IsActive());
2105 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2107 ASSERT_TRUE(ReleaseInput());
2108 ASSERT_TRUE(ReleaseInput2());
2111 #if defined(OS_CHROMEOS)
2115 void DetachToDockedWindowNextStep(
2116 DetachToBrowserTabDragControllerTest* test,
2117 const gfx::Point& target_point,
2119 ASSERT_EQ(2u, test->native_browser_list->size());
2120 Browser* new_browser = test->native_browser_list->get(1);
2121 ASSERT_TRUE(new_browser->window()->IsActive());
2124 ASSERT_TRUE(test->ReleaseInput());
2127 ASSERT_TRUE(test->DragInputToNotifyWhenDone(
2128 target_point.x(), target_point.y(),
2129 base::Bind(&DetachToDockedWindowNextStep,
2131 gfx::Point(target_point.x(), 1 + target_point.y()),
2137 // Drags from browser to separate window, docks that window and releases mouse.
2138 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
2139 DISABLED_DetachToDockedWindowFromMaximizedWindow) {
2140 // Maximize the initial browser window.
2141 browser()->window()->Maximize();
2142 ASSERT_TRUE(browser()->window()->IsMaximized());
2145 AddTabAndResetBrowser(browser());
2146 TabStrip* tab_strip = GetTabStripForBrowser(browser());
2148 // Move to the first tab and drag it enough so that it detaches.
2149 gfx::Point tab_0_center(
2150 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
2151 ASSERT_TRUE(PressInput(tab_0_center));
2153 // The following matches kMovesBeforeAdjust in snap_sizer.cc
2154 const int kNumIterations = 25 * 5 + 10;
2155 ASSERT_TRUE(DragInputToNotifyWhenDone(
2156 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
2157 base::Bind(&DetachToDockedWindowNextStep, this,
2158 gfx::Point(0, tab_0_center.y() + GetDetachY(tab_strip)),
2160 // Continue dragging enough times to go through snapping sequence and dock
2162 QuitWhenNotDragging();
2163 // Should no longer be dragging.
2164 ASSERT_FALSE(tab_strip->IsDragSessionActive());
2165 ASSERT_FALSE(TabDragController::IsActive());
2167 // There should now be another browser.
2168 ASSERT_EQ(2u, native_browser_list->size());
2169 Browser* new_browser = native_browser_list->get(1);
2170 ASSERT_TRUE(new_browser->window()->IsActive());
2171 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
2172 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
2174 EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
2175 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
2177 // The bounds of the initial window should not have changed.
2178 EXPECT_TRUE(browser()->window()->IsMaximized());
2180 EXPECT_FALSE(GetIsDragged(browser()));
2181 EXPECT_FALSE(GetIsDragged(new_browser));
2182 // After this both windows should still be manageable.
2183 EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
2184 EXPECT_TRUE(IsWindowPositionManaged(
2185 new_browser->window()->GetNativeWindow()));
2187 ash::wm::WindowState* window_state =
2188 ash::wm::GetWindowState(new_browser->window()->GetNativeWindow());
2189 // The new window should not be maximized because it gets docked or snapped.
2190 EXPECT_FALSE(new_browser->window()->IsMaximized());
2191 // The new window should be docked and not snapped.
2192 EXPECT_TRUE(window_state->IsDocked());
2193 EXPECT_FALSE(window_state->IsSnapped());
2196 #endif // OS_CHROMEOS
2200 #if defined(USE_ASH) && defined(OS_CHROMEOS) // TODO(win_ash,linux_ash)
2201 INSTANTIATE_TEST_CASE_P(TabDragging,
2202 DetachToBrowserInSeparateDisplayTabDragControllerTest,
2203 ::testing::Values("mouse", "touch"));
2204 INSTANTIATE_TEST_CASE_P(TabDragging,
2205 DifferentDeviceScaleFactorDisplayTabDragControllerTest,
2206 ::testing::Values("mouse"));
2207 INSTANTIATE_TEST_CASE_P(TabDragging,
2208 DetachToBrowserTabDragControllerTest,
2209 ::testing::Values("mouse", "touch"));
2210 INSTANTIATE_TEST_CASE_P(TabDragging,
2211 DetachToBrowserTabDragControllerTestTouch,
2212 ::testing::Values("touch"));
2213 #elif defined(USE_ASH)
2214 INSTANTIATE_TEST_CASE_P(TabDragging,
2215 DetachToBrowserTabDragControllerTest,
2216 ::testing::Values("mouse"));