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"
7 #include "ash/wm/window_state.h"
9 #include "base/callback.h"
10 #include "base/command_line.h"
11 #include "base/run_loop.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "chrome/browser/chrome_notification_types.h"
14 #include "chrome/browser/ui/browser.h"
15 #include "chrome/browser/ui/browser_commands.h"
16 #include "chrome/browser/ui/browser_iterator.h"
17 #include "chrome/browser/ui/browser_list.h"
18 #include "chrome/browser/ui/host_desktop.h"
19 #include "chrome/browser/ui/tabs/tab_strip_model.h"
20 #include "chrome/browser/ui/views/frame/browser_view.h"
21 #include "chrome/browser/ui/views/frame/native_browser_frame_factory.h"
22 #include "chrome/browser/ui/views/tabs/tab.h"
23 #include "chrome/browser/ui/views/tabs/tab_drag_controller.h"
24 #include "chrome/browser/ui/views/tabs/tab_strip.h"
25 #include "chrome/common/chrome_switches.h"
26 #include "chrome/test/base/in_process_browser_test.h"
27 #include "chrome/test/base/interactive_test_utils.h"
28 #include "chrome/test/base/ui_test_utils.h"
29 #include "content/public/browser/notification_details.h"
30 #include "content/public/browser/notification_observer.h"
31 #include "content/public/browser/notification_service.h"
32 #include "content/public/browser/notification_source.h"
33 #include "content/public/browser/web_contents.h"
34 #include "ui/base/test/ui_controls.h"
35 #include "ui/gfx/screen.h"
36 #include "ui/views/view.h"
37 #include "ui/views/widget/widget.h"
39 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
40 #include "chrome/browser/ui/views/frame/desktop_browser_frame_aura.h"
41 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
45 #include "ash/ash_switches.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_state.h"
52 #include "ash/wm/window_util.h"
53 #include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
54 #include "ui/aura/client/screen_position_client.h"
55 #include "ui/aura/root_window.h"
56 #include "ui/aura/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::SetUp() {
165 // TODO(danakj): Remove this when the tests are not flaky (crbug.com/270065)
166 // or we use test contexts in the renderer to keep things fast enough to
167 // avoid the flake (crbug.com/270918).
170 InProcessBrowserTest::SetUp();
173 void TabDragControllerTest::StopAnimating(TabStrip
* tab_strip
) {
174 tab_strip
->StopAnimating(true);
177 void TabDragControllerTest::AddTabAndResetBrowser(Browser
* browser
) {
178 AddBlankTabAndShow(browser
);
179 StopAnimating(GetTabStripForBrowser(browser
));
180 ResetIDs(browser
->tab_strip_model(), 0);
183 Browser
* TabDragControllerTest::CreateAnotherWindowBrowserAndRelayout() {
184 // Create another browser.
185 Browser
* browser2
= CreateBrowser(browser()->profile());
186 ResetIDs(browser2
->tab_strip_model(), 100);
188 // Resize the two windows so they're right next to each other.
189 gfx::Rect work_area
= gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
190 browser()->window()->GetNativeWindow()).work_area();
191 gfx::Size half_size
=
192 gfx::Size(work_area
.width() / 3 - 10, work_area
.height() / 2 - 10);
193 browser()->window()->SetBounds(gfx::Rect(work_area
.origin(), half_size
));
194 browser2
->window()->SetBounds(gfx::Rect(
195 work_area
.x() + half_size
.width(), work_area
.y(),
196 half_size
.width(), half_size
.height()));
203 INPUT_SOURCE_MOUSE
= 0,
204 INPUT_SOURCE_TOUCH
= 1
207 int GetDetachY(TabStrip
* tab_strip
) {
208 return std::max(TabDragController::kTouchVerticalDetachMagnetism
,
209 TabDragController::kVerticalDetachMagnetism
) +
210 tab_strip
->height() + 1;
213 bool GetIsDragged(Browser
* browser
) {
214 #if !defined(USE_ASH) || defined(OS_WIN) // TODO(win_ash)
217 return ash::wm::GetWindowState(browser
->window()->GetNativeWindow())->
224 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
225 class ScreenEventGeneratorDelegate
: public aura::test::EventGeneratorDelegate
{
227 explicit ScreenEventGeneratorDelegate(aura::Window
* root_window
)
228 : root_window_(root_window
) {}
229 virtual ~ScreenEventGeneratorDelegate() {}
231 // EventGeneratorDelegate overrides:
232 virtual aura::RootWindow
* GetRootWindowAt(
233 const gfx::Point
& point
) const OVERRIDE
{
234 return root_window_
->GetDispatcher();
237 virtual aura::client::ScreenPositionClient
* GetScreenPositionClient(
238 const aura::Window
* window
) const OVERRIDE
{
239 return aura::client::GetScreenPositionClient(root_window_
);
243 aura::Window
* root_window_
;
245 DISALLOW_COPY_AND_ASSIGN(ScreenEventGeneratorDelegate
);
250 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
252 // Following classes verify a crash scenario. Specifically on Windows when focus
253 // changes it can trigger capture being lost. This was causing a crash in tab
254 // dragging as it wasn't set up to handle this scenario. These classes
255 // synthesize this scenario.
257 // Allows making ClearNativeFocus() invoke ReleaseCapture().
258 class TestDesktopBrowserFrameAura
: public DesktopBrowserFrameAura
{
260 TestDesktopBrowserFrameAura(
261 BrowserFrame
* browser_frame
,
262 BrowserView
* browser_view
)
263 : DesktopBrowserFrameAura(browser_frame
, browser_view
),
264 release_capture_(false) {}
265 virtual ~TestDesktopBrowserFrameAura() {}
267 void ReleaseCaptureOnNextClear() {
268 release_capture_
= true;
271 virtual void ClearNativeFocus() OVERRIDE
{
272 views::DesktopNativeWidgetAura::ClearNativeFocus();
273 if (release_capture_
) {
274 release_capture_
= false;
275 GetWidget()->ReleaseCapture();
280 // If true ReleaseCapture() is invoked in ClearNativeFocus().
281 bool release_capture_
;
283 DISALLOW_COPY_AND_ASSIGN(TestDesktopBrowserFrameAura
);
286 // Factory for creating a TestDesktopBrowserFrameAura.
287 class TestNativeBrowserFrameFactory
: public NativeBrowserFrameFactory
{
289 TestNativeBrowserFrameFactory() {}
290 virtual ~TestNativeBrowserFrameFactory() {}
292 virtual NativeBrowserFrame
* Create(
293 BrowserFrame
* browser_frame
,
294 BrowserView
* browser_view
) OVERRIDE
{
295 return new TestDesktopBrowserFrameAura(browser_frame
, browser_view
);
299 DISALLOW_COPY_AND_ASSIGN(TestNativeBrowserFrameFactory
);
302 class TabDragCaptureLostTest
: public TabDragControllerTest
{
304 TabDragCaptureLostTest() {
305 NativeBrowserFrameFactory::Set(new TestNativeBrowserFrameFactory
);
309 DISALLOW_COPY_AND_ASSIGN(TabDragCaptureLostTest
);
312 // See description above for details.
313 IN_PROC_BROWSER_TEST_F(TabDragCaptureLostTest
, ReleaseCaptureOnDrag
) {
314 AddTabAndResetBrowser(browser());
316 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
317 gfx::Point
tab_1_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(1)));
318 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_1_center
) &&
319 ui_test_utils::SendMouseEventsSync(
320 ui_controls::LEFT
, ui_controls::DOWN
));
321 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
322 TestDesktopBrowserFrameAura
* frame
=
323 static_cast<TestDesktopBrowserFrameAura
*>(
324 BrowserView::GetBrowserViewForBrowser(browser())->GetWidget()->
325 native_widget_private());
326 // Invoke ReleaseCaptureOnDrag() so that when the drag happens and focus
327 // changes capture is released and the drag cancels.
328 frame
->ReleaseCaptureOnNextClear();
329 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center
));
330 EXPECT_FALSE(tab_strip
->IsDragSessionActive());
333 IN_PROC_BROWSER_TEST_F(TabDragControllerTest
, GestureEndShouldEndDragTest
) {
334 AddTabAndResetBrowser(browser());
336 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
337 TabStripModel
* model
= browser()->tab_strip_model();
339 Tab
* tab1
= tab_strip
->tab_at(1);
340 gfx::Point
tab_1_center(tab1
->width() / 2, tab1
->height() / 2);
342 ui::GestureEvent
gesture_begin(ui::ET_GESTURE_BEGIN
, tab_1_center
.x(),
343 tab_1_center
.x(), 0, base::TimeDelta(),
344 ui::GestureEventDetails(ui::ET_GESTURE_BEGIN
, 0.0f
, 0.0f
), 0);
345 tab_strip
->MaybeStartDrag(tab1
, gesture_begin
,
346 tab_strip
->GetSelectionModel());
347 //tab_strip->tab_at(1)->OnGestureEvent(&gesture_begin);
348 EXPECT_TRUE(TabDragController::IsActive());
350 ui::GestureEvent
gesture_end(ui::ET_GESTURE_END
, tab_1_center
.x(),
351 tab_1_center
.x(), 0, base::TimeDelta(),
352 ui::GestureEventDetails(ui::ET_GESTURE_END
, 0.0f
, 0.0f
), 0);
353 tab_strip
->OnGestureEvent(&gesture_end
);
354 EXPECT_FALSE(TabDragController::IsActive());
355 EXPECT_FALSE(tab_strip
->IsDragSessionActive());
360 class DetachToBrowserTabDragControllerTest
361 : public TabDragControllerTest
,
362 public ::testing::WithParamInterface
<const char*> {
364 DetachToBrowserTabDragControllerTest() {}
366 virtual void SetUpCommandLine(CommandLine
* command_line
) OVERRIDE
{
367 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
368 if (!docked_windows_enabled()) {
369 CommandLine::ForCurrentProcess()->AppendSwitch(
370 ash::switches::kAshDisableDockedWindows
);
375 virtual void SetUpOnMainThread() OVERRIDE
{
376 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
377 event_generator_
.reset(new aura::test::EventGenerator(
378 ash::Shell::GetPrimaryRootWindow()));
382 InputSource
input_source() const {
383 return strstr(GetParam(), "mouse") ?
384 INPUT_SOURCE_MOUSE
: INPUT_SOURCE_TOUCH
;
387 bool docked_windows_enabled() const {
388 return (strstr(GetParam(), "docked") != NULL
);
391 // Set root window from a point in screen coordinates
392 void SetEventGeneratorRootWindow(const gfx::Point
& point
) {
393 if (input_source() == INPUT_SOURCE_MOUSE
)
395 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
396 event_generator_
.reset(new aura::test::EventGenerator(
397 new ScreenEventGeneratorDelegate(ash::wm::GetRootWindowAt(point
))));
401 // The following methods update one of the mouse or touch input depending upon
403 bool PressInput(const gfx::Point
& location
) {
404 if (input_source() == INPUT_SOURCE_MOUSE
) {
405 return ui_test_utils::SendMouseMoveSync(location
) &&
406 ui_test_utils::SendMouseEventsSync(
407 ui_controls::LEFT
, ui_controls::DOWN
);
409 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
410 event_generator_
->set_current_location(location
);
411 event_generator_
->PressTouch();
419 // Second touch input is only used for touch sequence tests.
420 EXPECT_EQ(INPUT_SOURCE_TOUCH
, input_source());
421 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
422 event_generator_
->set_current_location(
423 event_generator_
->current_location());
424 event_generator_
->PressTouchId(1);
431 bool DragInputTo(const gfx::Point
& location
) {
432 if (input_source() == INPUT_SOURCE_MOUSE
)
433 return ui_test_utils::SendMouseMoveSync(location
);
434 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
435 event_generator_
->MoveTouch(location
);
442 bool DragInputToAsync(const gfx::Point
& location
) {
443 if (input_source() == INPUT_SOURCE_MOUSE
)
444 return ui_controls::SendMouseMove(location
.x(), location
.y());
445 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
446 event_generator_
->MoveTouch(location
);
453 bool DragInputToNotifyWhenDone(int x
,
455 const base::Closure
& task
) {
456 if (input_source() == INPUT_SOURCE_MOUSE
)
457 return ui_controls::SendMouseMoveNotifyWhenDone(x
, y
, task
);
458 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
459 base::MessageLoop::current()->PostTask(FROM_HERE
, task
);
460 event_generator_
->MoveTouch(gfx::Point(x
, y
));
467 bool DragInputToDelayedNotifyWhenDone(int x
,
469 const base::Closure
& task
,
470 base::TimeDelta delay
) {
471 if (input_source() == INPUT_SOURCE_MOUSE
)
472 return ui_controls::SendMouseMoveNotifyWhenDone(x
, y
, task
);
473 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
474 base::MessageLoop::current()->PostDelayedTask(FROM_HERE
, task
, delay
);
475 event_generator_
->MoveTouch(gfx::Point(x
, y
));
482 bool DragInput2ToNotifyWhenDone(int x
,
484 const base::Closure
& task
) {
485 if (input_source() == INPUT_SOURCE_MOUSE
)
486 return ui_controls::SendMouseMoveNotifyWhenDone(x
, y
, task
);
487 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
488 base::MessageLoop::current()->PostTask(FROM_HERE
, task
);
489 event_generator_
->MoveTouchId(gfx::Point(x
, y
), 1);
496 bool ReleaseInput() {
497 if (input_source() == INPUT_SOURCE_MOUSE
) {
498 return ui_test_utils::SendMouseEventsSync(
499 ui_controls::LEFT
, ui_controls::UP
);
501 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
502 event_generator_
->ReleaseTouch();
509 bool ReleaseInput2() {
510 if (input_source() == INPUT_SOURCE_MOUSE
) {
511 return ui_test_utils::SendMouseEventsSync(
512 ui_controls::LEFT
, ui_controls::UP
);
514 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
515 event_generator_
->ReleaseTouchId(1);
522 bool ReleaseMouseAsync() {
523 return input_source() == INPUT_SOURCE_MOUSE
&&
524 ui_controls::SendMouseEvents(ui_controls::LEFT
, ui_controls::UP
);
527 void QuitWhenNotDragging() {
528 if (input_source() == INPUT_SOURCE_MOUSE
) {
529 // Schedule observer to quit message loop when done dragging. This has to
530 // be async so the message loop can run.
531 test::QuitWhenNotDraggingImpl();
532 base::MessageLoop::current()->Run();
534 // Touch events are sync, so we know we're not in a drag session. But some
535 // tests rely on the browser fully closing, which is async. So, run all
537 base::RunLoop run_loop
;
538 run_loop
.RunUntilIdle();
542 void AddBlankTabAndShow(Browser
* browser
) {
543 InProcessBrowserTest::AddBlankTabAndShow(browser
);
546 Browser
* browser() const { return InProcessBrowserTest::browser(); }
549 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
550 scoped_ptr
<aura::test::EventGenerator
> event_generator_
;
553 DISALLOW_COPY_AND_ASSIGN(DetachToBrowserTabDragControllerTest
);
556 // Creates a browser with two tabs, drags the second to the first.
557 // TODO(sky): this won't work with touch as it requires a long press.
558 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
559 DISABLED_DragInSameWindow
) {
560 AddTabAndResetBrowser(browser());
562 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
563 TabStripModel
* model
= browser()->tab_strip_model();
565 gfx::Point
tab_1_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(1)));
566 ASSERT_TRUE(PressInput(tab_1_center
));
567 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
568 ASSERT_TRUE(DragInputTo(tab_0_center
));
569 ASSERT_TRUE(ReleaseInput());
570 EXPECT_EQ("1 0", IDString(model
));
571 EXPECT_FALSE(TabDragController::IsActive());
572 EXPECT_FALSE(tab_strip
->IsDragSessionActive());
577 // Invoked from the nested message loop.
578 void DragToSeparateWindowStep2(DetachToBrowserTabDragControllerTest
* test
,
579 TabStrip
* not_attached_tab_strip
,
580 TabStrip
* target_tab_strip
) {
581 ASSERT_FALSE(not_attached_tab_strip
->IsDragSessionActive());
582 ASSERT_FALSE(target_tab_strip
->IsDragSessionActive());
583 ASSERT_TRUE(TabDragController::IsActive());
585 // Drag to target_tab_strip. This should stop the nested loop from dragging
587 gfx::Point
target_point(target_tab_strip
->width() -1,
588 target_tab_strip
->height() / 2);
589 views::View::ConvertPointToScreen(target_tab_strip
, &target_point
);
590 ASSERT_TRUE(test
->DragInputToAsync(target_point
));
595 // Creates two browsers, drags from first into second.
596 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
597 DragToSeparateWindow
) {
598 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
600 // Add another tab to browser().
601 AddTabAndResetBrowser(browser());
603 // Create another browser.
604 Browser
* browser2
= CreateAnotherWindowBrowserAndRelayout();
605 TabStrip
* tab_strip2
= GetTabStripForBrowser(browser2
);
607 // Move to the first tab and drag it enough so that it detaches, but not
608 // enough that it attaches to browser2.
609 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
610 ASSERT_TRUE(PressInput(tab_0_center
));
611 ASSERT_TRUE(DragInputToNotifyWhenDone(
612 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
613 base::Bind(&DragToSeparateWindowStep2
,
614 this, tab_strip
, tab_strip2
)));
615 QuitWhenNotDragging();
617 // Should now be attached to tab_strip2.
618 ASSERT_TRUE(tab_strip2
->IsDragSessionActive());
619 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
620 ASSERT_TRUE(TabDragController::IsActive());
621 EXPECT_FALSE(GetIsDragged(browser()));
623 // Release the mouse, stopping the drag session.
624 ASSERT_TRUE(ReleaseInput());
625 ASSERT_FALSE(tab_strip2
->IsDragSessionActive());
626 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
627 ASSERT_FALSE(TabDragController::IsActive());
628 EXPECT_EQ("100 0", IDString(browser2
->tab_strip_model()));
629 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
630 EXPECT_FALSE(GetIsDragged(browser2
));
632 // Both windows should not be maximized
633 EXPECT_FALSE(browser()->window()->IsMaximized());
634 EXPECT_FALSE(browser2
->window()->IsMaximized());
639 void DetachToOwnWindowStep2(DetachToBrowserTabDragControllerTest
* test
) {
640 if (test
->input_source() == INPUT_SOURCE_TOUCH
)
641 ASSERT_TRUE(test
->ReleaseInput());
644 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
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 // Drags from browser to separate window and releases mouse.
663 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
665 const gfx::Rect
initial_bounds(browser()->window()->GetBounds());
667 AddTabAndResetBrowser(browser());
668 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
670 // Move to the first tab and drag it enough so that it detaches.
671 gfx::Point
tab_0_center(
672 GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
673 ASSERT_TRUE(PressInput(tab_0_center
));
674 ASSERT_TRUE(DragInputToNotifyWhenDone(
675 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
676 base::Bind(&DetachToOwnWindowStep2
, this)));
677 if (input_source() == INPUT_SOURCE_MOUSE
) {
678 ASSERT_TRUE(ReleaseMouseAsync());
679 QuitWhenNotDragging();
682 // Should no longer be dragging.
683 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
684 ASSERT_FALSE(TabDragController::IsActive());
686 // There should now be another browser.
687 ASSERT_EQ(2u, native_browser_list
->size());
688 Browser
* new_browser
= native_browser_list
->get(1);
689 ASSERT_TRUE(new_browser
->window()->IsActive());
690 TabStrip
* tab_strip2
= GetTabStripForBrowser(new_browser
);
691 ASSERT_FALSE(tab_strip2
->IsDragSessionActive());
693 EXPECT_EQ("0", IDString(new_browser
->tab_strip_model()));
694 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
696 // The bounds of the initial window should not have changed.
697 EXPECT_EQ(initial_bounds
.ToString(),
698 browser()->window()->GetBounds().ToString());
700 EXPECT_FALSE(GetIsDragged(browser()));
701 EXPECT_FALSE(GetIsDragged(new_browser
));
702 // After this both windows should still be manageable.
703 EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
704 EXPECT_TRUE(IsWindowPositionManaged(
705 new_browser
->window()->GetNativeWindow()));
707 // Both windows should not be maximized
708 EXPECT_FALSE(browser()->window()->IsMaximized());
709 EXPECT_FALSE(new_browser
->window()->IsMaximized());
712 // Drags from browser to separate window and releases mouse.
713 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
714 DetachToOwnWindowFromMaximizedWindow
) {
715 // Maximize the initial browser window.
716 browser()->window()->Maximize();
717 ASSERT_TRUE(browser()->window()->IsMaximized());
720 AddTabAndResetBrowser(browser());
721 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
723 // Move to the first tab and drag it enough so that it detaches.
724 gfx::Point
tab_0_center(
725 GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
726 ASSERT_TRUE(PressInput(tab_0_center
));
727 ASSERT_TRUE(DragInputToNotifyWhenDone(
728 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
729 base::Bind(&DetachToOwnWindowStep2
, this)));
730 if (input_source() == INPUT_SOURCE_MOUSE
) {
731 ASSERT_TRUE(ReleaseMouseAsync());
732 QuitWhenNotDragging();
735 // Should no longer be dragging.
736 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
737 ASSERT_FALSE(TabDragController::IsActive());
739 // There should now be another browser.
740 ASSERT_EQ(2u, native_browser_list
->size());
741 Browser
* new_browser
= native_browser_list
->get(1);
742 ASSERT_TRUE(new_browser
->window()->IsActive());
743 TabStrip
* tab_strip2
= GetTabStripForBrowser(new_browser
);
744 ASSERT_FALSE(tab_strip2
->IsDragSessionActive());
746 EXPECT_EQ("0", IDString(new_browser
->tab_strip_model()));
747 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
749 // The bounds of the initial window should not have changed.
750 EXPECT_TRUE(browser()->window()->IsMaximized());
752 EXPECT_FALSE(GetIsDragged(browser()));
753 EXPECT_FALSE(GetIsDragged(new_browser
));
754 // After this both windows should still be manageable.
755 EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
756 EXPECT_TRUE(IsWindowPositionManaged(
757 new_browser
->window()->GetNativeWindow()));
759 // The new window should be maximized.
760 EXPECT_TRUE(new_browser
->window()->IsMaximized());
763 // Deletes a tab being dragged before the user moved enough to start a drag.
764 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
765 DeleteBeforeStartedDragging
) {
767 AddTabAndResetBrowser(browser());
768 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
770 // Click on the first tab, but don't move it.
771 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
772 ASSERT_TRUE(PressInput(tab_0_center
));
774 // Should be dragging.
775 ASSERT_TRUE(tab_strip
->IsDragSessionActive());
776 ASSERT_TRUE(TabDragController::IsActive());
778 // Delete the tab being dragged.
779 delete browser()->tab_strip_model()->GetWebContentsAt(0);
781 // Should have canceled dragging.
782 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
783 ASSERT_FALSE(TabDragController::IsActive());
785 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
786 EXPECT_FALSE(GetIsDragged(browser()));
789 // Deletes a tab being dragged while still attached.
790 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
791 DeleteTabWhileAttached
) {
793 AddTabAndResetBrowser(browser());
794 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
796 // Click on the first tab and move it enough so that it starts dragging but is
798 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
799 ASSERT_TRUE(PressInput(tab_0_center
));
800 ASSERT_TRUE(DragInputTo(
801 gfx::Point(tab_0_center
.x() + 20, tab_0_center
.y())));
803 // Should be dragging.
804 ASSERT_TRUE(tab_strip
->IsDragSessionActive());
805 ASSERT_TRUE(TabDragController::IsActive());
807 // Delete the tab being dragged.
808 delete browser()->tab_strip_model()->GetWebContentsAt(0);
810 // Should have canceled dragging.
811 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
812 ASSERT_FALSE(TabDragController::IsActive());
814 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
816 EXPECT_FALSE(GetIsDragged(browser()));
821 void DeleteWhileDetachedStep2(WebContents
* tab
) {
827 // Deletes a tab being dragged after dragging a tab so that a new window is
829 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
830 DeleteTabWhileDetached
) {
832 AddTabAndResetBrowser(browser());
833 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
835 // Move to the first tab and drag it enough so that it detaches.
836 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
837 WebContents
* to_delete
=
838 browser()->tab_strip_model()->GetWebContentsAt(0);
839 ASSERT_TRUE(PressInput(tab_0_center
));
840 ASSERT_TRUE(DragInputToNotifyWhenDone(
841 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
842 base::Bind(&DeleteWhileDetachedStep2
, to_delete
)));
843 QuitWhenNotDragging();
845 // Should not be 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 DeleteSourceDetachedStep2(WebContents
* tab
,
857 const BrowserList
* browser_list
) {
858 ASSERT_EQ(2u, browser_list
->size());
859 Browser
* new_browser
= browser_list
->get(1);
860 // This ends up closing the source window.
863 ui_controls::SendKeyPress(new_browser
->window()->GetNativeWindow(),
864 ui::VKEY_ESCAPE
, false, false, false, false);
869 // Detaches a tab and while detached deletes a tab from the source so that the
870 // source window closes then presses escape to cancel the drag.
871 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
872 DeleteSourceDetached
) {
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
= browser()->tab_strip_model()->GetWebContentsAt(1);
880 ASSERT_TRUE(PressInput(tab_0_center
));
881 ASSERT_TRUE(DragInputToNotifyWhenDone(
882 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
883 base::Bind(&DeleteSourceDetachedStep2
, to_delete
, native_browser_list
)));
884 QuitWhenNotDragging();
886 // Should not be dragging.
887 ASSERT_EQ(1u, native_browser_list
->size());
888 Browser
* new_browser
= native_browser_list
->get(0);
889 ASSERT_FALSE(GetTabStripForBrowser(new_browser
)->IsDragSessionActive());
890 ASSERT_FALSE(TabDragController::IsActive());
892 EXPECT_EQ("0", IDString(new_browser
->tab_strip_model()));
894 EXPECT_FALSE(GetIsDragged(new_browser
));
896 // Remaining browser window should not be maximized
897 EXPECT_FALSE(new_browser
->window()->IsMaximized());
902 void PressEscapeWhileDetachedStep2(const BrowserList
* browser_list
) {
903 ASSERT_EQ(2u, browser_list
->size());
904 Browser
* new_browser
= browser_list
->get(1);
905 ui_controls::SendKeyPress(
906 new_browser
->window()->GetNativeWindow(), ui::VKEY_ESCAPE
, false, false,
912 // This is disabled until NativeViewHost::Detach really detaches.
913 // Detaches a tab and while detached presses escape to revert the drag.
914 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
915 PressEscapeWhileDetached
) {
917 AddTabAndResetBrowser(browser());
918 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
920 // Move to the first tab and drag it enough so that it detaches.
921 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
922 ASSERT_TRUE(PressInput(tab_0_center
));
923 ASSERT_TRUE(DragInputToNotifyWhenDone(
924 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
925 base::Bind(&PressEscapeWhileDetachedStep2
, native_browser_list
)));
926 QuitWhenNotDragging();
928 // Should not be dragging.
929 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
930 ASSERT_FALSE(TabDragController::IsActive());
932 // And there should only be one window.
933 EXPECT_EQ(1u, native_browser_list
->size());
935 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
937 // Remaining browser window should not be maximized
938 EXPECT_FALSE(browser()->window()->IsMaximized());
943 void DragAllStep2(DetachToBrowserTabDragControllerTest
* test
,
944 const BrowserList
* browser_list
) {
945 // Should only be one window.
946 ASSERT_EQ(1u, browser_list
->size());
947 if (test
->input_source() == INPUT_SOURCE_TOUCH
) {
948 ASSERT_TRUE(test
->ReleaseInput());
950 ASSERT_TRUE(test
->ReleaseMouseAsync());
956 // Selects multiple tabs and starts dragging the window.
957 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
, DragAll
) {
959 AddTabAndResetBrowser(browser());
960 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
961 browser()->tab_strip_model()->AddTabAtToSelection(0);
962 browser()->tab_strip_model()->AddTabAtToSelection(1);
964 // Move to the first tab and drag it enough so that it would normally
966 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
967 ASSERT_TRUE(PressInput(tab_0_center
));
968 ASSERT_TRUE(DragInputToNotifyWhenDone(
969 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
970 base::Bind(&DragAllStep2
, this, native_browser_list
)));
971 QuitWhenNotDragging();
973 // Should not be dragging.
974 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
975 ASSERT_FALSE(TabDragController::IsActive());
977 // And there should only be one window.
978 EXPECT_EQ(1u, native_browser_list
->size());
980 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
982 EXPECT_FALSE(GetIsDragged(browser()));
984 // Remaining browser window should not be maximized
985 EXPECT_FALSE(browser()->window()->IsMaximized());
990 // Invoked from the nested message loop.
991 void DragAllToSeparateWindowStep2(DetachToBrowserTabDragControllerTest
* test
,
992 TabStrip
* attached_tab_strip
,
993 TabStrip
* target_tab_strip
,
994 const BrowserList
* browser_list
) {
995 ASSERT_TRUE(attached_tab_strip
->IsDragSessionActive());
996 ASSERT_FALSE(target_tab_strip
->IsDragSessionActive());
997 ASSERT_TRUE(TabDragController::IsActive());
998 ASSERT_EQ(2u, browser_list
->size());
1000 // Drag to target_tab_strip. This should stop the nested loop from dragging
1002 gfx::Point
target_point(target_tab_strip
->width() - 1,
1003 target_tab_strip
->height() / 2);
1004 views::View::ConvertPointToScreen(target_tab_strip
, &target_point
);
1005 ASSERT_TRUE(test
->DragInputToAsync(target_point
));
1010 // Creates two browsers, selects all tabs in first and drags into second.
1011 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
1012 DragAllToSeparateWindow
) {
1013 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
1015 // Add another tab to browser().
1016 AddTabAndResetBrowser(browser());
1018 // Create another browser.
1019 Browser
* browser2
= CreateAnotherWindowBrowserAndRelayout();
1020 TabStrip
* tab_strip2
= GetTabStripForBrowser(browser2
);
1022 browser()->tab_strip_model()->AddTabAtToSelection(0);
1023 browser()->tab_strip_model()->AddTabAtToSelection(1);
1025 // Move to the first tab and drag it enough so that it detaches, but not
1026 // enough that it attaches to browser2.
1027 gfx::Point
tab_0_center(
1028 GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
1029 ASSERT_TRUE(PressInput(tab_0_center
));
1030 ASSERT_TRUE(DragInputToNotifyWhenDone(
1031 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
1032 base::Bind(&DragAllToSeparateWindowStep2
, this, tab_strip
, tab_strip2
,
1033 native_browser_list
)));
1034 QuitWhenNotDragging();
1036 // Should now be attached to tab_strip2.
1037 ASSERT_TRUE(tab_strip2
->IsDragSessionActive());
1038 ASSERT_TRUE(TabDragController::IsActive());
1039 ASSERT_EQ(1u, native_browser_list
->size());
1041 // Release the mouse, stopping the drag session.
1042 ASSERT_TRUE(ReleaseInput());
1043 ASSERT_FALSE(tab_strip2
->IsDragSessionActive());
1044 ASSERT_FALSE(TabDragController::IsActive());
1045 EXPECT_EQ("100 0 1", IDString(browser2
->tab_strip_model()));
1047 EXPECT_FALSE(GetIsDragged(browser2
));
1049 // Remaining browser window should not be maximized
1050 EXPECT_FALSE(browser2
->window()->IsMaximized());
1055 // Invoked from the nested message loop.
1056 void DragAllToSeparateWindowAndCancelStep2(
1057 DetachToBrowserTabDragControllerTest
* test
,
1058 TabStrip
* attached_tab_strip
,
1059 TabStrip
* target_tab_strip
,
1060 const BrowserList
* browser_list
) {
1061 ASSERT_TRUE(attached_tab_strip
->IsDragSessionActive());
1062 ASSERT_FALSE(target_tab_strip
->IsDragSessionActive());
1063 ASSERT_TRUE(TabDragController::IsActive());
1064 ASSERT_EQ(2u, browser_list
->size());
1066 // Drag to target_tab_strip. This should stop the nested loop from dragging
1068 gfx::Point
target_point(target_tab_strip
->width() - 1,
1069 target_tab_strip
->height() / 2);
1070 views::View::ConvertPointToScreen(target_tab_strip
, &target_point
);
1071 ASSERT_TRUE(test
->DragInputToAsync(target_point
));
1076 // Creates two browsers, selects all tabs in first, drags into second, then hits
1078 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
1079 DragAllToSeparateWindowAndCancel
) {
1080 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
1082 // Add another tab to browser().
1083 AddTabAndResetBrowser(browser());
1085 // Create another browser.
1086 Browser
* browser2
= CreateAnotherWindowBrowserAndRelayout();
1087 TabStrip
* tab_strip2
= GetTabStripForBrowser(browser2
);
1089 browser()->tab_strip_model()->AddTabAtToSelection(0);
1090 browser()->tab_strip_model()->AddTabAtToSelection(1);
1092 // Move to the first tab and drag it enough so that it detaches, but not
1093 // enough that it attaches to browser2.
1094 gfx::Point
tab_0_center(
1095 GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
1096 ASSERT_TRUE(PressInput(tab_0_center
));
1097 ASSERT_TRUE(DragInputToNotifyWhenDone(
1098 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
1099 base::Bind(&DragAllToSeparateWindowAndCancelStep2
, this,
1100 tab_strip
, tab_strip2
, native_browser_list
)));
1101 QuitWhenNotDragging();
1103 // Should now be attached to tab_strip2.
1104 ASSERT_TRUE(tab_strip2
->IsDragSessionActive());
1105 ASSERT_TRUE(TabDragController::IsActive());
1106 ASSERT_EQ(1u, native_browser_list
->size());
1109 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
1110 browser2
, ui::VKEY_ESCAPE
, false, false, false, false));
1112 ASSERT_FALSE(tab_strip2
->IsDragSessionActive());
1113 ASSERT_FALSE(TabDragController::IsActive());
1114 EXPECT_EQ("100 0 1", IDString(browser2
->tab_strip_model()));
1116 // browser() will have been destroyed, but browser2 should remain.
1117 ASSERT_EQ(1u, native_browser_list
->size());
1119 EXPECT_FALSE(GetIsDragged(browser2
));
1121 // Remaining browser window should not be maximized
1122 EXPECT_FALSE(browser2
->window()->IsMaximized());
1125 // Creates two browsers, drags from first into the second in such a way that
1126 // no detaching should happen.
1127 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
1128 DragDirectlyToSecondWindow
) {
1129 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
1131 // Add another tab to browser().
1132 AddTabAndResetBrowser(browser());
1134 // Create another browser.
1135 Browser
* browser2
= CreateAnotherWindowBrowserAndRelayout();
1136 TabStrip
* tab_strip2
= GetTabStripForBrowser(browser2
);
1138 // Move the tabstrip down enough so that we can detach.
1139 gfx::Rect
bounds(browser2
->window()->GetBounds());
1140 bounds
.Offset(0, 100);
1141 browser2
->window()->SetBounds(bounds
);
1143 // Move to the first tab and drag it enough so that it detaches, but not
1144 // enough that it attaches to browser2.
1145 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
1146 ASSERT_TRUE(PressInput(tab_0_center
));
1148 gfx::Point
b2_location(5, 0);
1149 views::View::ConvertPointToScreen(tab_strip2
, &b2_location
);
1150 ASSERT_TRUE(DragInputTo(b2_location
));
1152 // Should now be attached to tab_strip2.
1153 ASSERT_TRUE(tab_strip2
->IsDragSessionActive());
1154 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1155 ASSERT_TRUE(TabDragController::IsActive());
1157 // Release the mouse, stopping the drag session.
1158 ASSERT_TRUE(ReleaseInput());
1159 ASSERT_FALSE(tab_strip2
->IsDragSessionActive());
1160 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1161 ASSERT_FALSE(TabDragController::IsActive());
1162 EXPECT_EQ("0 100", IDString(browser2
->tab_strip_model()));
1163 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1165 EXPECT_FALSE(GetIsDragged(browser()));
1166 EXPECT_FALSE(GetIsDragged(browser2
));
1168 // Both windows should not be maximized
1169 EXPECT_FALSE(browser()->window()->IsMaximized());
1170 EXPECT_FALSE(browser2
->window()->IsMaximized());
1173 // Creates two browsers, the first browser has a single tab and drags into the
1175 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
1176 DragSingleTabToSeparateWindow
) {
1177 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
1179 ResetIDs(browser()->tab_strip_model(), 0);
1181 // Create another browser.
1182 Browser
* browser2
= CreateAnotherWindowBrowserAndRelayout();
1183 TabStrip
* tab_strip2
= GetTabStripForBrowser(browser2
);
1184 const gfx::Rect
initial_bounds(browser2
->window()->GetBounds());
1186 // Move to the first tab and drag it enough so that it detaches, but not
1187 // enough that it attaches to browser2.
1188 gfx::Point
tab_0_center(
1189 GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
1190 ASSERT_TRUE(PressInput(tab_0_center
));
1191 ASSERT_TRUE(DragInputToNotifyWhenDone(
1192 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
1193 base::Bind(&DragAllToSeparateWindowStep2
, this, tab_strip
, tab_strip2
,
1194 native_browser_list
)));
1195 QuitWhenNotDragging();
1197 // Should now be attached to tab_strip2.
1198 ASSERT_TRUE(tab_strip2
->IsDragSessionActive());
1199 ASSERT_TRUE(TabDragController::IsActive());
1200 ASSERT_EQ(1u, native_browser_list
->size());
1202 // Release the mouse, stopping the drag session.
1203 ASSERT_TRUE(ReleaseInput());
1204 ASSERT_FALSE(tab_strip2
->IsDragSessionActive());
1205 ASSERT_FALSE(TabDragController::IsActive());
1206 EXPECT_EQ("100 0", IDString(browser2
->tab_strip_model()));
1208 EXPECT_FALSE(GetIsDragged(browser2
));
1210 // Remaining browser window should not be maximized
1211 EXPECT_FALSE(browser2
->window()->IsMaximized());
1213 // Make sure that the window is still managed and not user moved.
1214 EXPECT_TRUE(IsWindowPositionManaged(browser2
->window()->GetNativeWindow()));
1215 EXPECT_FALSE(HasUserChangedWindowPositionOrSize(
1216 browser2
->window()->GetNativeWindow()));
1217 // Also make sure that the drag to window position has not changed.
1218 EXPECT_EQ(initial_bounds
.ToString(),
1219 browser2
->window()->GetBounds().ToString());
1224 // Invoked from the nested message loop.
1225 void CancelOnNewTabWhenDraggingStep2(
1226 DetachToBrowserTabDragControllerTest
* test
,
1227 const BrowserList
* browser_list
) {
1228 ASSERT_TRUE(TabDragController::IsActive());
1229 ASSERT_EQ(2u, browser_list
->size());
1231 // Add another tab. This should trigger exiting the nested loop.
1232 test
->AddBlankTabAndShow(browser_list
->GetLastActive());
1237 // Adds another tab, detaches into separate window, adds another tab and
1238 // verifies the run loop ends.
1239 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
1240 CancelOnNewTabWhenDragging
) {
1241 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
1243 // Add another tab to browser().
1244 AddTabAndResetBrowser(browser());
1246 // Move to the first tab and drag it enough so that it detaches.
1247 gfx::Point
tab_0_center(
1248 GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
1249 ASSERT_TRUE(PressInput(tab_0_center
));
1250 ASSERT_TRUE(DragInputToNotifyWhenDone(
1251 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
1252 base::Bind(&CancelOnNewTabWhenDraggingStep2
, this, native_browser_list
)));
1253 QuitWhenNotDragging();
1255 // Should be two windows and not dragging.
1256 ASSERT_FALSE(TabDragController::IsActive());
1257 ASSERT_EQ(2u, native_browser_list
->size());
1258 for (chrome::BrowserIterator it
; !it
.done(); it
.Next()) {
1259 EXPECT_FALSE(GetIsDragged(*it
));
1260 // Should not be maximized
1261 EXPECT_FALSE(it
->window()->IsMaximized());
1265 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
1269 void DragInMaximizedWindowStep2(DetachToBrowserTabDragControllerTest
* test
,
1271 TabStrip
* tab_strip
,
1272 const BrowserList
* browser_list
) {
1273 // There should be another browser.
1274 ASSERT_EQ(2u, browser_list
->size());
1275 Browser
* new_browser
= browser_list
->get(1);
1276 EXPECT_NE(browser
, new_browser
);
1277 ASSERT_TRUE(new_browser
->window()->IsActive());
1278 TabStrip
* tab_strip2
= GetTabStripForBrowser(new_browser
);
1280 ASSERT_TRUE(tab_strip2
->IsDragSessionActive());
1281 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1283 // Both windows should be visible.
1284 EXPECT_TRUE(tab_strip
->GetWidget()->IsVisible());
1285 EXPECT_TRUE(tab_strip2
->GetWidget()->IsVisible());
1288 ASSERT_TRUE(test
->ReleaseInput());
1293 // Creates a browser with two tabs, maximizes it, drags the tab out.
1294 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
1295 DragInMaximizedWindow
) {
1296 AddTabAndResetBrowser(browser());
1297 browser()->window()->Maximize();
1299 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
1301 // Move to the first tab and drag it enough so that it detaches.
1302 gfx::Point
tab_0_center(
1303 GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
1304 ASSERT_TRUE(PressInput(tab_0_center
));
1305 ASSERT_TRUE(DragInputToNotifyWhenDone(
1306 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
1307 base::Bind(&DragInMaximizedWindowStep2
, this, browser(), tab_strip
,
1308 native_browser_list
)));
1309 QuitWhenNotDragging();
1311 ASSERT_FALSE(TabDragController::IsActive());
1313 // Should be two browsers.
1314 ASSERT_EQ(2u, native_browser_list
->size());
1315 Browser
* new_browser
= native_browser_list
->get(1);
1316 ASSERT_TRUE(new_browser
->window()->IsActive());
1318 EXPECT_TRUE(browser()->window()->GetNativeWindow()->IsVisible());
1319 EXPECT_TRUE(new_browser
->window()->GetNativeWindow()->IsVisible());
1321 EXPECT_FALSE(GetIsDragged(browser()));
1322 EXPECT_FALSE(GetIsDragged(new_browser
));
1324 // The source window should be maximized.
1325 EXPECT_TRUE(browser()->window()->IsMaximized());
1326 // The new window should be maximized.
1327 EXPECT_TRUE(new_browser
->window()->IsMaximized());
1330 // Subclass of DetachToBrowserTabDragControllerTest that
1331 // creates multiple displays.
1332 class DetachToBrowserInSeparateDisplayTabDragControllerTest
1333 : public DetachToBrowserTabDragControllerTest
{
1335 DetachToBrowserInSeparateDisplayTabDragControllerTest() {}
1336 virtual ~DetachToBrowserInSeparateDisplayTabDragControllerTest() {}
1338 virtual void SetUpCommandLine(CommandLine
* command_line
) OVERRIDE
{
1339 DetachToBrowserTabDragControllerTest::SetUpCommandLine(command_line
);
1340 // Make screens sufficiently wide to host 2 browsers side by side.
1341 command_line
->AppendSwitchASCII("ash-host-window-bounds",
1342 "0+0-600x600,601+0-600x600");
1346 DISALLOW_COPY_AND_ASSIGN(
1347 DetachToBrowserInSeparateDisplayTabDragControllerTest
);
1350 // Subclass of DetachToBrowserTabDragControllerTest that runs tests only with
1352 class DetachToBrowserTabDragControllerTestTouch
1353 : public DetachToBrowserTabDragControllerTest
{
1355 DetachToBrowserTabDragControllerTestTouch() {}
1356 virtual ~DetachToBrowserTabDragControllerTestTouch() {}
1359 DISALLOW_COPY_AND_ASSIGN(DetachToBrowserTabDragControllerTestTouch
);
1364 void DragSingleTabToSeparateWindowInSecondDisplayStep3(
1365 DetachToBrowserTabDragControllerTest
* test
) {
1366 ASSERT_TRUE(test
->ReleaseInput());
1369 void DragSingleTabToSeparateWindowInSecondDisplayStep2(
1370 DetachToBrowserTabDragControllerTest
* test
,
1371 const gfx::Point
& target_point
) {
1372 ASSERT_TRUE(test
->DragInputToNotifyWhenDone(
1373 target_point
.x(), target_point
.y(),
1374 base::Bind(&DragSingleTabToSeparateWindowInSecondDisplayStep3
, test
)));
1379 // Drags from browser to a second display and releases input.
1380 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest
,
1381 DragSingleTabToSeparateWindowInSecondDisplay
) {
1383 AddTabAndResetBrowser(browser());
1384 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
1386 // Move to the first tab and drag it enough so that it detaches.
1387 // Then drag it to the final destination on the second screen.
1388 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
1389 ASSERT_TRUE(PressInput(tab_0_center
));
1390 ASSERT_TRUE(DragInputToNotifyWhenDone(
1391 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
1392 base::Bind(&DragSingleTabToSeparateWindowInSecondDisplayStep2
,
1393 this, gfx::Point(600 + tab_0_center
.x(),
1395 + GetDetachY(tab_strip
)))));
1396 QuitWhenNotDragging();
1398 // Should no longer be dragging.
1399 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1400 ASSERT_FALSE(TabDragController::IsActive());
1402 // There should now be another browser.
1403 ASSERT_EQ(2u, native_browser_list
->size());
1404 Browser
* new_browser
= native_browser_list
->get(1);
1405 ASSERT_TRUE(new_browser
->window()->IsActive());
1406 TabStrip
* tab_strip2
= GetTabStripForBrowser(new_browser
);
1407 ASSERT_FALSE(tab_strip2
->IsDragSessionActive());
1409 // This other browser should be on the second screen (with mouse drag)
1410 // With the touch input the browser cannot be dragged from one screen
1411 // to another and the window stays on the first screen.
1412 if (input_source() == INPUT_SOURCE_MOUSE
) {
1413 aura::Window::Windows roots
= ash::Shell::GetAllRootWindows();
1414 ASSERT_EQ(2u, roots
.size());
1415 aura::Window
* second_root
= roots
[1];
1416 EXPECT_EQ(second_root
,
1417 new_browser
->window()->GetNativeWindow()->GetRootWindow());
1420 EXPECT_EQ("0", IDString(new_browser
->tab_strip_model()));
1421 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1423 // Both windows should not be maximized
1424 EXPECT_FALSE(browser()->window()->IsMaximized());
1425 EXPECT_FALSE(new_browser
->window()->IsMaximized());
1430 // Invoked from the nested message loop.
1431 void DragTabToWindowInSeparateDisplayStep2(
1432 DetachToBrowserTabDragControllerTest
* test
,
1433 TabStrip
* not_attached_tab_strip
,
1434 TabStrip
* target_tab_strip
) {
1435 ASSERT_FALSE(not_attached_tab_strip
->IsDragSessionActive());
1436 ASSERT_FALSE(target_tab_strip
->IsDragSessionActive());
1437 ASSERT_TRUE(TabDragController::IsActive());
1439 // Drag to target_tab_strip. This should stop the nested loop from dragging
1441 gfx::Point
target_point(
1442 GetCenterInScreenCoordinates(target_tab_strip
->tab_at(0)));
1444 // Move it close to the beginning of the target tabstrip.
1446 target_point
.x() - target_tab_strip
->tab_at(0)->width() / 2 + 10);
1447 ASSERT_TRUE(test
->DragInputToAsync(target_point
));
1452 // Drags from browser to another browser on a second display and releases input.
1453 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest
,
1454 DragTabToWindowInSeparateDisplay
) {
1456 AddTabAndResetBrowser(browser());
1457 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
1459 // Create another browser.
1460 Browser
* browser2
= CreateBrowser(browser()->profile());
1461 TabStrip
* tab_strip2
= GetTabStripForBrowser(browser2
);
1462 ResetIDs(browser2
->tab_strip_model(), 100);
1464 // Move the second browser to the second display.
1465 aura::Window::Windows roots
= ash::Shell::GetAllRootWindows();
1466 ASSERT_EQ(2u, roots
.size());
1467 aura::Window
* second_root
= roots
[1];
1468 gfx::Rect work_area
= gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1469 second_root
).work_area();
1470 browser2
->window()->SetBounds(work_area
);
1471 EXPECT_EQ(second_root
,
1472 browser2
->window()->GetNativeWindow()->GetRootWindow());
1474 // Move to the first tab and drag it enough so that it detaches, but not
1475 // enough that it attaches to browser2.
1476 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
1477 ASSERT_TRUE(PressInput(tab_0_center
));
1478 ASSERT_TRUE(DragInputToNotifyWhenDone(
1479 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
1480 base::Bind(&DragTabToWindowInSeparateDisplayStep2
,
1481 this, tab_strip
, tab_strip2
)));
1482 QuitWhenNotDragging();
1484 // Should now be attached to tab_strip2.
1485 ASSERT_TRUE(tab_strip2
->IsDragSessionActive());
1486 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1487 ASSERT_TRUE(TabDragController::IsActive());
1489 // Release the mouse, stopping the drag session.
1490 ASSERT_TRUE(ReleaseInput());
1491 ASSERT_FALSE(tab_strip2
->IsDragSessionActive());
1492 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1493 ASSERT_FALSE(TabDragController::IsActive());
1494 EXPECT_EQ("0 100", IDString(browser2
->tab_strip_model()));
1495 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1497 // Both windows should not be maximized
1498 EXPECT_FALSE(browser()->window()->IsMaximized());
1499 EXPECT_FALSE(browser2
->window()->IsMaximized());
1502 // Drags from browser to another browser on a second display and releases input.
1503 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest
,
1504 DragTabToWindowOnSecondDisplay
) {
1506 AddTabAndResetBrowser(browser());
1507 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
1509 // Create another browser.
1510 Browser
* browser2
= CreateBrowser(browser()->profile());
1511 TabStrip
* tab_strip2
= GetTabStripForBrowser(browser2
);
1512 ResetIDs(browser2
->tab_strip_model(), 100);
1514 // Move both browsers to the second display.
1515 aura::Window::Windows roots
= ash::Shell::GetAllRootWindows();
1516 ASSERT_EQ(2u, roots
.size());
1517 aura::Window
* second_root
= roots
[1];
1518 gfx::Rect work_area
= gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1519 second_root
).work_area();
1520 browser()->window()->SetBounds(work_area
);
1522 // position both browser windows side by side on the second screen.
1523 gfx::Rect
work_area2(work_area
);
1524 work_area
.set_width(work_area
.width()/2);
1525 browser()->window()->SetBounds(work_area
);
1526 work_area2
.set_x(work_area2
.x() + work_area2
.width()/2);
1527 work_area2
.set_width(work_area2
.width()/2);
1528 browser2
->window()->SetBounds(work_area2
);
1529 EXPECT_EQ(second_root
,
1530 browser()->window()->GetNativeWindow()->GetRootWindow());
1531 EXPECT_EQ(second_root
,
1532 browser2
->window()->GetNativeWindow()->GetRootWindow());
1534 // Move to the first tab and drag it enough so that it detaches, but not
1535 // enough that it attaches to browser2.
1536 // SetEventGeneratorRootWindow sets correct (second) RootWindow
1537 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
1538 SetEventGeneratorRootWindow(tab_0_center
);
1539 ASSERT_TRUE(PressInput(tab_0_center
));
1540 ASSERT_TRUE(DragInputToNotifyWhenDone(
1541 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
1542 base::Bind(&DragTabToWindowInSeparateDisplayStep2
,
1543 this, tab_strip
, tab_strip2
)));
1544 QuitWhenNotDragging();
1546 // Should now be attached to tab_strip2.
1547 ASSERT_TRUE(tab_strip2
->IsDragSessionActive());
1548 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1549 ASSERT_TRUE(TabDragController::IsActive());
1551 // Release the mouse, stopping the drag session.
1552 ASSERT_TRUE(ReleaseInput());
1553 ASSERT_FALSE(tab_strip2
->IsDragSessionActive());
1554 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1555 ASSERT_FALSE(TabDragController::IsActive());
1556 EXPECT_EQ("0 100", IDString(browser2
->tab_strip_model()));
1557 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1559 // Both windows should not be maximized
1560 EXPECT_FALSE(browser()->window()->IsMaximized());
1561 EXPECT_FALSE(browser2
->window()->IsMaximized());
1564 // Drags from a maximized browser to another non-maximized browser on a second
1565 // display and releases input.
1566 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest
,
1567 DragMaxTabToNonMaxWindowInSeparateDisplay
) {
1569 AddTabAndResetBrowser(browser());
1570 browser()->window()->Maximize();
1571 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
1573 // Create another browser on the second display.
1574 aura::Window::Windows roots
= ash::Shell::GetAllRootWindows();
1575 ASSERT_EQ(2u, roots
.size());
1576 aura::Window
* first_root
= roots
[0];
1577 aura::Window
* second_root
= roots
[1];
1578 gfx::Rect work_area
= gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1579 second_root
).work_area();
1580 work_area
.Inset(20,20,20,60);
1581 Browser::CreateParams
params(browser()->profile(),
1582 browser()->host_desktop_type());
1583 params
.initial_show_state
= ui::SHOW_STATE_NORMAL
;
1584 params
.initial_bounds
= work_area
;
1585 Browser
* browser2
= new Browser(params
);
1586 AddBlankTabAndShow(browser2
);
1588 TabStrip
* tab_strip2
= GetTabStripForBrowser(browser2
);
1589 ResetIDs(browser2
->tab_strip_model(), 100);
1591 EXPECT_EQ(second_root
,
1592 browser2
->window()->GetNativeWindow()->GetRootWindow());
1593 EXPECT_EQ(first_root
,
1594 browser()->window()->GetNativeWindow()->GetRootWindow());
1595 EXPECT_EQ(2, tab_strip
->tab_count());
1596 EXPECT_EQ(1, tab_strip2
->tab_count());
1598 // Move to the first tab and drag it enough so that it detaches, but not
1599 // enough that it attaches to browser2.
1600 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
1601 ASSERT_TRUE(PressInput(tab_0_center
));
1602 ASSERT_TRUE(DragInputToNotifyWhenDone(
1603 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
1604 base::Bind(&DragTabToWindowInSeparateDisplayStep2
,
1605 this, tab_strip
, tab_strip2
)));
1606 QuitWhenNotDragging();
1608 // Should now be attached to tab_strip2.
1609 ASSERT_TRUE(tab_strip2
->IsDragSessionActive());
1610 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1611 ASSERT_TRUE(TabDragController::IsActive());
1613 // Release the mouse, stopping the drag session.
1614 ASSERT_TRUE(ReleaseInput());
1616 // tab should have moved
1617 EXPECT_EQ(1, tab_strip
->tab_count());
1618 EXPECT_EQ(2, tab_strip2
->tab_count());
1620 ASSERT_FALSE(tab_strip2
->IsDragSessionActive());
1621 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1622 ASSERT_FALSE(TabDragController::IsActive());
1623 EXPECT_EQ("0 100", IDString(browser2
->tab_strip_model()));
1624 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1626 // Source browser should still be maximized, target should not
1627 EXPECT_TRUE(browser()->window()->IsMaximized());
1628 EXPECT_FALSE(browser2
->window()->IsMaximized());
1631 // Immersive fullscreen is ChromeOS only.
1632 #if defined(OS_CHROMEOS)
1633 // Drags from a restored browser to an immersive fullscreen browser on a
1634 // second display and releases input.
1635 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest
,
1636 DragTabToImmersiveBrowserOnSeparateDisplay
) {
1638 AddTabAndResetBrowser(browser());
1639 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
1641 // Create another browser.
1642 Browser
* browser2
= CreateBrowser(browser()->profile());
1643 TabStrip
* tab_strip2
= GetTabStripForBrowser(browser2
);
1644 ResetIDs(browser2
->tab_strip_model(), 100);
1646 // Move the second browser to the second display.
1647 aura::Window::Windows roots
= ash::Shell::GetAllRootWindows();
1648 ASSERT_EQ(2u, roots
.size());
1649 aura::Window
* second_root
= roots
[1];
1650 gfx::Rect work_area
= gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1651 second_root
).work_area();
1652 browser2
->window()->SetBounds(work_area
);
1653 EXPECT_EQ(second_root
,
1654 browser2
->window()->GetNativeWindow()->GetRootWindow());
1656 // Put the second browser into immersive fullscreen.
1657 BrowserView
* browser_view2
= BrowserView::GetBrowserViewForBrowser(browser2
);
1658 ImmersiveModeController
* immersive_controller2
=
1659 browser_view2
->immersive_mode_controller();
1660 immersive_controller2
->SetupForTest();
1661 chrome::ToggleFullscreenMode(browser2
);
1662 ASSERT_TRUE(immersive_controller2
->IsEnabled());
1663 ASSERT_FALSE(immersive_controller2
->IsRevealed());
1664 ASSERT_TRUE(tab_strip2
->IsImmersiveStyle());
1666 // Move to the first tab and drag it enough so that it detaches, but not
1667 // enough that it attaches to browser2.
1668 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
1669 ASSERT_TRUE(PressInput(tab_0_center
));
1670 ASSERT_TRUE(DragInputToNotifyWhenDone(
1671 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
1672 base::Bind(&DragTabToWindowInSeparateDisplayStep2
,
1673 this, tab_strip
, tab_strip2
)));
1674 QuitWhenNotDragging();
1676 // Should now be attached to tab_strip2.
1677 ASSERT_TRUE(tab_strip2
->IsDragSessionActive());
1678 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1679 ASSERT_TRUE(TabDragController::IsActive());
1681 // browser2's top chrome should be revealed and the tab strip should be
1682 // at normal height while user is tragging tabs_strip2's tabs.
1683 ASSERT_TRUE(immersive_controller2
->IsRevealed());
1684 ASSERT_FALSE(tab_strip2
->IsImmersiveStyle());
1686 // Release the mouse, stopping the drag session.
1687 ASSERT_TRUE(ReleaseInput());
1688 ASSERT_FALSE(tab_strip2
->IsDragSessionActive());
1689 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1690 ASSERT_FALSE(TabDragController::IsActive());
1691 EXPECT_EQ("0 100", IDString(browser2
->tab_strip_model()));
1692 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1694 // Move the mouse off of browser2's top chrome.
1695 aura::Window
* primary_root
= roots
[0];
1696 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
1697 primary_root
->GetBoundsInScreen().CenterPoint()));
1699 // The first browser window should not be in immersive fullscreen.
1700 // browser2 should still be in immersive fullscreen, but the top chrome should
1701 // no longer be revealed.
1702 BrowserView
* browser_view
= BrowserView::GetBrowserViewForBrowser(browser());
1703 EXPECT_FALSE(browser_view
->immersive_mode_controller()->IsEnabled());
1705 EXPECT_TRUE(immersive_controller2
->IsEnabled());
1706 EXPECT_FALSE(immersive_controller2
->IsRevealed());
1707 EXPECT_TRUE(tab_strip2
->IsImmersiveStyle());
1709 #endif // OS_CHROMEOS
1711 // Subclass of DetachToBrowserTabDragControllerTest that
1712 // creates multiple displays with different device scale factors.
1713 class DifferentDeviceScaleFactorDisplayTabDragControllerTest
1714 : public DetachToBrowserTabDragControllerTest
{
1716 DifferentDeviceScaleFactorDisplayTabDragControllerTest() {}
1717 virtual ~DifferentDeviceScaleFactorDisplayTabDragControllerTest() {}
1719 virtual void SetUpCommandLine(CommandLine
* command_line
) OVERRIDE
{
1720 DetachToBrowserTabDragControllerTest::SetUpCommandLine(command_line
);
1721 command_line
->AppendSwitchASCII("ash-host-window-bounds",
1722 "400x400,0+400-800x800*2");
1725 float GetCursorDeviceScaleFactor() const {
1726 ash::test::CursorManagerTestApi
cursor_test_api(
1727 ash::Shell::GetInstance()->cursor_manager());
1728 return cursor_test_api
.GetDisplay().device_scale_factor();
1732 DISALLOW_COPY_AND_ASSIGN(
1733 DifferentDeviceScaleFactorDisplayTabDragControllerTest
);
1738 // The points where a tab is dragged in CursorDeviceScaleFactorStep.
1739 const struct DragPoint
{
1750 // The expected device scale factors before the cursor is moved to the
1751 // corresponding kDragPoints in CursorDeviceScaleFactorStep.
1752 const float kDeviceScaleFactorExpectations
[] = {
1761 arraysize(kDragPoints
) == arraysize(kDeviceScaleFactorExpectations
),
1762 kDragPoints_and_kDeviceScaleFactorExpectations_must_have_same_size
);
1764 // Drags tab to |kDragPoints[index]|, then calls the next step function.
1765 void CursorDeviceScaleFactorStep(
1766 DifferentDeviceScaleFactorDisplayTabDragControllerTest
* test
,
1767 TabStrip
* not_attached_tab_strip
,
1769 ASSERT_FALSE(not_attached_tab_strip
->IsDragSessionActive());
1770 ASSERT_TRUE(TabDragController::IsActive());
1772 if (index
< arraysize(kDragPoints
)) {
1773 EXPECT_EQ(kDeviceScaleFactorExpectations
[index
],
1774 test
->GetCursorDeviceScaleFactor());
1775 const DragPoint p
= kDragPoints
[index
];
1776 ASSERT_TRUE(test
->DragInputToNotifyWhenDone(
1777 p
.x
, p
.y
, base::Bind(&CursorDeviceScaleFactorStep
,
1778 test
, not_attached_tab_strip
, index
+ 1)));
1780 // Finishes a serise of CursorDeviceScaleFactorStep calls and ends drag.
1781 EXPECT_EQ(1.0f
, test
->GetCursorDeviceScaleFactor());
1782 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
1783 ui_controls::LEFT
, ui_controls::UP
));
1789 // Verifies cursor's device scale factor is updated when a tab is moved across
1790 // displays with different device scale factors (http://crbug.com/154183).
1791 IN_PROC_BROWSER_TEST_P(DifferentDeviceScaleFactorDisplayTabDragControllerTest
,
1792 CursorDeviceScaleFactor
) {
1794 AddTabAndResetBrowser(browser());
1795 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
1797 // Move the second browser to the second display.
1798 aura::Window::Windows roots
= ash::Shell::GetAllRootWindows();
1799 ASSERT_EQ(2u, roots
.size());
1801 // Move to the first tab and drag it enough so that it detaches.
1802 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
1803 ASSERT_TRUE(PressInput(tab_0_center
));
1804 ASSERT_TRUE(DragInputToNotifyWhenDone(
1805 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
1806 base::Bind(&CursorDeviceScaleFactorStep
,
1807 this, tab_strip
, 0)));
1808 QuitWhenNotDragging();
1813 class DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest
1814 : public TabDragControllerTest
{
1816 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest() {}
1818 virtual void SetUpCommandLine(CommandLine
* command_line
) OVERRIDE
{
1819 TabDragControllerTest::SetUpCommandLine(command_line
);
1820 command_line
->AppendSwitchASCII("ash-host-window-bounds",
1821 "0+0-250x250,251+0-250x250");
1824 bool Press(const gfx::Point
& position
) {
1825 return ui_test_utils::SendMouseMoveSync(position
) &&
1826 ui_test_utils::SendMouseEventsSync(ui_controls::LEFT
,
1830 bool DragTabAndExecuteTaskWhenDone(const gfx::Point
& position
,
1831 const base::Closure
& task
) {
1832 return ui_controls::SendMouseMoveNotifyWhenDone(
1833 position
.x(), position
.y(), task
);
1836 void QuitWhenNotDragging() {
1837 test::QuitWhenNotDraggingImpl();
1838 base::MessageLoop::current()->Run();
1842 DISALLOW_COPY_AND_ASSIGN(
1843 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest
);
1846 // Invoked from the nested message loop.
1847 void CancelDragTabToWindowInSeparateDisplayStep3(
1848 TabStrip
* tab_strip
,
1849 const BrowserList
* browser_list
) {
1850 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1851 ASSERT_TRUE(TabDragController::IsActive());
1852 ASSERT_EQ(2u, browser_list
->size());
1854 // Switching display mode should cancel the drag operation.
1855 ash::internal::DisplayManager
* display_manager
=
1856 ash::Shell::GetInstance()->display_manager();
1857 display_manager
->AddRemoveDisplay();
1860 // Invoked from the nested message loop.
1861 void CancelDragTabToWindowInSeparateDisplayStep2(
1862 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest
* test
,
1863 TabStrip
* tab_strip
,
1864 aura::Window
* current_root
,
1865 gfx::Point final_destination
,
1866 const BrowserList
* browser_list
) {
1867 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1868 ASSERT_TRUE(TabDragController::IsActive());
1869 ASSERT_EQ(2u, browser_list
->size());
1871 Browser
* new_browser
= browser_list
->get(1);
1872 EXPECT_EQ(current_root
,
1873 new_browser
->window()->GetNativeWindow()->GetRootWindow());
1875 ASSERT_TRUE(test
->DragTabAndExecuteTaskWhenDone(
1877 base::Bind(&CancelDragTabToWindowInSeparateDisplayStep3
,
1878 tab_strip
, browser_list
)));
1883 // Drags from browser to a second display and releases input.
1884 IN_PROC_BROWSER_TEST_F(
1885 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest
,
1886 CancelDragTabToWindowIn2ndDisplay
) {
1888 AddTabAndResetBrowser(browser());
1889 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
1891 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
1893 // Move the second browser to the second display.
1894 aura::Window::Windows roots
= ash::Shell::GetAllRootWindows();
1895 ASSERT_EQ(2u, roots
.size());
1896 gfx::Point final_destination
=
1897 gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1898 roots
[1]).work_area().CenterPoint();
1900 // Move to the first tab and drag it enough so that it detaches, but not
1901 // enough to move to another display.
1902 gfx::Point
tab_0_dst(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
1903 ASSERT_TRUE(Press(tab_0_dst
));
1904 tab_0_dst
.Offset(0, GetDetachY(tab_strip
));
1905 ASSERT_TRUE(DragTabAndExecuteTaskWhenDone(
1906 tab_0_dst
, base::Bind(&CancelDragTabToWindowInSeparateDisplayStep2
,
1907 this, tab_strip
, roots
[0], final_destination
,
1908 native_browser_list
)));
1909 QuitWhenNotDragging();
1911 ASSERT_EQ(1u, native_browser_list
->size());
1912 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1913 ASSERT_FALSE(TabDragController::IsActive());
1914 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
1916 // Release the mouse
1917 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
1918 ui_controls::LEFT
, ui_controls::UP
));
1921 // Drags from browser from a second display to primary and releases input.
1922 IN_PROC_BROWSER_TEST_F(
1923 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest
,
1924 CancelDragTabToWindowIn1stDisplay
) {
1925 aura::Window::Windows roots
= ash::Shell::GetAllRootWindows();
1926 ASSERT_EQ(2u, roots
.size());
1929 AddTabAndResetBrowser(browser());
1930 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
1932 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
1933 EXPECT_EQ(roots
[0], browser()->window()->GetNativeWindow()->GetRootWindow());
1935 gfx::Rect work_area
= gfx::Screen::GetNativeScreen()->
1936 GetDisplayNearestWindow(roots
[1]).work_area();
1937 browser()->window()->SetBounds(work_area
);
1938 EXPECT_EQ(roots
[1], browser()->window()->GetNativeWindow()->GetRootWindow());
1940 // Move the second browser to the display.
1941 gfx::Point final_destination
=
1942 gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1943 roots
[0]).work_area().CenterPoint();
1945 // Move to the first tab and drag it enough so that it detaches, but not
1946 // enough to move to another display.
1947 gfx::Point
tab_0_dst(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
1948 ASSERT_TRUE(Press(tab_0_dst
));
1949 tab_0_dst
.Offset(0, GetDetachY(tab_strip
));
1950 ASSERT_TRUE(DragTabAndExecuteTaskWhenDone(
1951 tab_0_dst
, base::Bind(&CancelDragTabToWindowInSeparateDisplayStep2
,
1952 this, tab_strip
, roots
[1], final_destination
,
1953 native_browser_list
)));
1954 QuitWhenNotDragging();
1956 ASSERT_EQ(1u, native_browser_list
->size());
1957 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1958 ASSERT_FALSE(TabDragController::IsActive());
1959 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
1961 // Release the mouse
1962 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
1963 ui_controls::LEFT
, ui_controls::UP
));
1968 void DetachToOwnWindowTwoFingersDragStep5(
1969 DetachToBrowserTabDragControllerTest
* test
) {
1970 ASSERT_EQ(2u, test
->native_browser_list
->size());
1971 Browser
* new_browser
= test
->native_browser_list
->get(1);
1972 ASSERT_TRUE(new_browser
->window()->IsActive());
1974 ASSERT_TRUE(test
->ReleaseInput());
1975 ASSERT_TRUE(test
->ReleaseInput2());
1976 ASSERT_TRUE(new_browser
->window()->IsActive());
1979 void DetachToOwnWindowTwoFingersDragStep4(
1980 DetachToBrowserTabDragControllerTest
* test
,
1981 const gfx::Point
& target_point
) {
1982 ASSERT_EQ(2u, test
->native_browser_list
->size());
1983 Browser
* new_browser
= test
->native_browser_list
->get(1);
1984 ASSERT_TRUE(new_browser
->window()->IsActive());
1986 ASSERT_TRUE(test
->DragInput2ToNotifyWhenDone(
1987 target_point
.x(), target_point
.y(),
1988 base::Bind(&DetachToOwnWindowTwoFingersDragStep5
, test
)));
1991 void DetachToOwnWindowTwoFingersDragStep3(
1992 DetachToBrowserTabDragControllerTest
* test
,
1993 const gfx::Point
& target_point
) {
1994 ASSERT_TRUE(test
->PressInput2());
1996 ASSERT_EQ(2u, test
->native_browser_list
->size());
1997 Browser
* new_browser
= test
->native_browser_list
->get(1);
1998 ASSERT_TRUE(new_browser
->window()->IsActive());
2000 ASSERT_TRUE(test
->DragInputToDelayedNotifyWhenDone(
2001 target_point
.x(), target_point
.y(),
2002 base::Bind(&DetachToOwnWindowTwoFingersDragStep4
,
2005 base::TimeDelta::FromMilliseconds(60)));
2008 void DetachToOwnWindowTwoFingersDragStep2(
2009 DetachToBrowserTabDragControllerTest
* test
,
2010 const gfx::Point
& target_point
) {
2011 ASSERT_EQ(2u, test
->native_browser_list
->size());
2012 Browser
* new_browser
= test
->native_browser_list
->get(1);
2013 ASSERT_TRUE(new_browser
->window()->IsActive());
2015 ASSERT_TRUE(test
->DragInputToDelayedNotifyWhenDone(
2016 target_point
.x(), target_point
.y(),
2017 base::Bind(&DetachToOwnWindowTwoFingersDragStep3
,
2019 target_point
+ gfx::Vector2d(-2, 1)),
2020 base::TimeDelta::FromMilliseconds(60)));
2025 // Drags from browser to separate window starting with one finger and
2026 // then continuing with two fingers.
2027 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestTouch
,
2028 DetachToOwnWindowTwoFingers
) {
2029 gfx::Rect
bounds(browser()->window()->GetBounds());
2031 AddTabAndResetBrowser(browser());
2032 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
2034 // Move to the first tab and drag it enough so that it detaches.
2035 gfx::Point
tab_0_center(
2036 GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
2037 ASSERT_TRUE(PressInput(tab_0_center
));
2038 // Drags in this test are very short to avoid fling.
2039 ASSERT_TRUE(DragInputToDelayedNotifyWhenDone(
2040 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
2041 base::Bind(&DetachToOwnWindowTwoFingersDragStep2
,
2042 this, gfx::Point(5 + tab_0_center
.x(),
2043 1 + tab_0_center
.y()
2044 + GetDetachY(tab_strip
))),
2045 base::TimeDelta::FromMilliseconds(60)));
2046 // Continue dragging, first with one finger, then with two fingers.
2047 QuitWhenNotDragging();
2049 // There should now be another browser.
2050 ASSERT_EQ(2u, native_browser_list
->size());
2051 Browser
* new_browser
= native_browser_list
->get(1);
2052 ASSERT_TRUE(new_browser
->window()->IsActive());
2053 // The sequence of drags should successfully move the browser window.
2054 bounds
+= gfx::Vector2d(5 - 2, 1 + 1 + GetDetachY(tab_strip
));
2055 EXPECT_EQ(bounds
.ToString(),
2056 new_browser
->window()->GetNativeWindow()->bounds().ToString());
2059 // Subclass of DetachToBrowserTabDragControllerTest that runs tests with
2060 // docked windows enabled and disabled.
2061 class DetachToDockedTabDragControllerTest
2062 : public DetachToBrowserTabDragControllerTest
{
2064 DetachToDockedTabDragControllerTest() {}
2065 virtual ~DetachToDockedTabDragControllerTest() {}
2068 DISALLOW_COPY_AND_ASSIGN(DetachToDockedTabDragControllerTest
);
2073 void DetachToDockedWindowNextStep(
2074 DetachToDockedTabDragControllerTest
* test
,
2075 const gfx::Point
& target_point
,
2077 ASSERT_EQ(2u, test
->native_browser_list
->size());
2078 Browser
* new_browser
= test
->native_browser_list
->get(1);
2079 ASSERT_TRUE(new_browser
->window()->IsActive());
2082 ASSERT_TRUE(test
->ReleaseInput());
2085 ASSERT_TRUE(test
->DragInputToNotifyWhenDone(
2086 target_point
.x(), target_point
.y(),
2087 base::Bind(&DetachToDockedWindowNextStep
,
2089 gfx::Point(target_point
.x(), 1 + target_point
.y()),
2095 // Drags from browser to separate window, docks that window and releases mouse.
2096 IN_PROC_BROWSER_TEST_P(DetachToDockedTabDragControllerTest
,
2097 DetachToDockedWindowFromMaximizedWindow
) {
2098 // Maximize the initial browser window.
2099 browser()->window()->Maximize();
2100 ASSERT_TRUE(browser()->window()->IsMaximized());
2103 AddTabAndResetBrowser(browser());
2104 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
2106 // Move to the first tab and drag it enough so that it detaches.
2107 gfx::Point
tab_0_center(
2108 GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
2109 ASSERT_TRUE(PressInput(tab_0_center
));
2111 // The following matches kMovesBeforeAdjust in snap_sizer.cc
2112 const int kNumIterations
= 25 * 5 + 10;
2113 ASSERT_TRUE(DragInputToNotifyWhenDone(
2114 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
2115 base::Bind(&DetachToDockedWindowNextStep
, this,
2116 gfx::Point(0, tab_0_center
.y() + GetDetachY(tab_strip
)),
2118 // Continue dragging enough times to go through snapping sequence and dock
2120 QuitWhenNotDragging();
2121 // Should no longer be dragging.
2122 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
2123 ASSERT_FALSE(TabDragController::IsActive());
2125 // There should now be another browser.
2126 ASSERT_EQ(2u, native_browser_list
->size());
2127 Browser
* new_browser
= native_browser_list
->get(1);
2128 ASSERT_TRUE(new_browser
->window()->IsActive());
2129 TabStrip
* tab_strip2
= GetTabStripForBrowser(new_browser
);
2130 ASSERT_FALSE(tab_strip2
->IsDragSessionActive());
2132 EXPECT_EQ("0", IDString(new_browser
->tab_strip_model()));
2133 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
2135 // The bounds of the initial window should not have changed.
2136 EXPECT_TRUE(browser()->window()->IsMaximized());
2138 EXPECT_FALSE(GetIsDragged(browser()));
2139 EXPECT_FALSE(GetIsDragged(new_browser
));
2140 // After this both windows should still be manageable.
2141 EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
2142 EXPECT_TRUE(IsWindowPositionManaged(
2143 new_browser
->window()->GetNativeWindow()));
2145 ash::wm::WindowState
* window_state
=
2146 ash::wm::GetWindowState(new_browser
->window()->GetNativeWindow());
2147 // The new window should not be maximized because it gets docked or snapped.
2148 EXPECT_FALSE(new_browser
->window()->IsMaximized());
2149 if (docked_windows_enabled()) {
2150 // The new window should be docked and not snapped if docking is allowed.
2151 EXPECT_TRUE(window_state
->IsDocked());
2152 EXPECT_FALSE(window_state
->IsSnapped());
2154 // The new window should be snapped and not docked if docking is disabled.
2155 EXPECT_FALSE(window_state
->IsDocked());
2156 EXPECT_TRUE(window_state
->IsSnapped());
2163 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
2164 INSTANTIATE_TEST_CASE_P(TabDragging
,
2165 DetachToBrowserInSeparateDisplayTabDragControllerTest
,
2166 ::testing::Values("mouse", "touch"));
2167 INSTANTIATE_TEST_CASE_P(TabDragging
,
2168 DifferentDeviceScaleFactorDisplayTabDragControllerTest
,
2169 ::testing::Values("mouse"));
2170 INSTANTIATE_TEST_CASE_P(TabDragging
,
2171 DetachToBrowserTabDragControllerTest
,
2172 ::testing::Values("mouse", "touch"));
2173 INSTANTIATE_TEST_CASE_P(TabDragging
,
2174 DetachToDockedTabDragControllerTest
,
2175 ::testing::Values("mouse", "mouse docked"));
2176 INSTANTIATE_TEST_CASE_P(TabDragging
,
2177 DetachToBrowserTabDragControllerTestTouch
,
2178 ::testing::Values("touch", "touch docked"));
2180 INSTANTIATE_TEST_CASE_P(TabDragging
,
2181 DetachToBrowserTabDragControllerTest
,
2182 ::testing::Values("mouse"));