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/browser_tabstrip.h"
21 #include "chrome/browser/ui/host_desktop.h"
22 #include "chrome/browser/ui/tabs/tab_strip_model.h"
23 #include "chrome/browser/ui/views/frame/browser_view.h"
24 #include "chrome/browser/ui/views/frame/native_browser_frame_factory.h"
25 #include "chrome/browser/ui/views/tabs/tab.h"
26 #include "chrome/browser/ui/views/tabs/tab_drag_controller.h"
27 #include "chrome/browser/ui/views/tabs/tab_strip.h"
28 #include "chrome/test/base/in_process_browser_test.h"
29 #include "chrome/test/base/interactive_test_utils.h"
30 #include "chrome/test/base/ui_test_utils.h"
31 #include "content/public/browser/notification_details.h"
32 #include "content/public/browser/notification_observer.h"
33 #include "content/public/browser/notification_service.h"
34 #include "content/public/browser/notification_source.h"
35 #include "content/public/browser/web_contents.h"
36 #include "ui/base/test/ui_controls.h"
37 #include "ui/gfx/screen.h"
38 #include "ui/views/view.h"
39 #include "ui/views/widget/widget.h"
42 #include "ui/aura/client/aura_constants.h"
43 #include "ui/aura/test/test_window_delegate.h"
44 #include "ui/aura/test/test_windows.h"
45 #include "ui/aura/window_targeter.h"
48 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
49 #include "chrome/browser/ui/views/frame/desktop_browser_frame_aura.h"
50 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
54 #include "ash/display/display_controller.h"
55 #include "ash/display/display_manager.h"
56 #include "ash/shell.h"
57 #include "ash/test/cursor_manager_test_api.h"
58 #include "ash/wm/coordinate_conversion.h"
59 #include "ash/wm/window_util.h"
60 #include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
61 #include "ui/aura/client/screen_position_client.h"
62 #include "ui/aura/test/event_generator_delegate_aura.h"
63 #include "ui/aura/window_event_dispatcher.h"
64 #include "ui/events/test/event_generator.h"
67 using content::WebContents
;
73 const char kTabDragControllerInteractiveUITestUserDataKey
[] =
74 "TabDragControllerInteractiveUITestUserData";
76 class TabDragControllerInteractiveUITestUserData
77 : public base::SupportsUserData::Data
{
79 explicit TabDragControllerInteractiveUITestUserData(int id
) : id_(id
) {}
80 ~TabDragControllerInteractiveUITestUserData() override
{}
81 int id() { return id_
; }
89 class QuitDraggingObserver
: public content::NotificationObserver
{
91 QuitDraggingObserver() {
92 registrar_
.Add(this, chrome::NOTIFICATION_TAB_DRAG_LOOP_DONE
,
93 content::NotificationService::AllSources());
96 void Observe(int type
,
97 const content::NotificationSource
& source
,
98 const content::NotificationDetails
& details
) override
{
99 DCHECK_EQ(chrome::NOTIFICATION_TAB_DRAG_LOOP_DONE
, type
);
100 base::MessageLoopForUI::current()->Quit();
105 ~QuitDraggingObserver() override
{}
107 content::NotificationRegistrar registrar_
;
109 DISALLOW_COPY_AND_ASSIGN(QuitDraggingObserver
);
112 gfx::Point
GetCenterInScreenCoordinates(const views::View
* view
) {
113 gfx::Point
center(view
->width() / 2, view
->height() / 2);
114 views::View::ConvertPointToScreen(view
, ¢er
);
118 void SetID(WebContents
* web_contents
, int id
) {
119 web_contents
->SetUserData(&kTabDragControllerInteractiveUITestUserDataKey
,
120 new TabDragControllerInteractiveUITestUserData(id
));
123 void ResetIDs(TabStripModel
* model
, int start
) {
124 for (int i
= 0; i
< model
->count(); ++i
)
125 SetID(model
->GetWebContentsAt(i
), start
+ i
);
128 std::string
IDString(TabStripModel
* model
) {
130 for (int i
= 0; i
< model
->count(); ++i
) {
133 WebContents
* contents
= model
->GetWebContentsAt(i
);
134 TabDragControllerInteractiveUITestUserData
* user_data
=
135 static_cast<TabDragControllerInteractiveUITestUserData
*>(
136 contents
->GetUserData(
137 &kTabDragControllerInteractiveUITestUserDataKey
));
139 result
+= base::IntToString(user_data
->id());
146 // Creates a listener that quits the message loop when no longer dragging.
147 void QuitWhenNotDraggingImpl() {
148 new QuitDraggingObserver(); // QuitDraggingObserver deletes itself.
151 TabStrip
* GetTabStripForBrowser(Browser
* browser
) {
152 BrowserView
* browser_view
= BrowserView::GetBrowserViewForBrowser(browser
);
153 return static_cast<TabStrip
*>(browser_view
->tabstrip());
158 using test::GetCenterInScreenCoordinates
;
160 using test::ResetIDs
;
161 using test::IDString
;
162 using test::GetTabStripForBrowser
;
164 TabDragControllerTest::TabDragControllerTest()
165 : native_browser_list(BrowserList::GetInstance(
166 chrome::HOST_DESKTOP_TYPE_NATIVE
)) {
169 TabDragControllerTest::~TabDragControllerTest() {
172 void TabDragControllerTest::StopAnimating(TabStrip
* tab_strip
) {
173 tab_strip
->StopAnimating(true);
176 void TabDragControllerTest::AddTabAndResetBrowser(Browser
* browser
) {
177 AddBlankTabAndShow(browser
);
178 StopAnimating(GetTabStripForBrowser(browser
));
179 ResetIDs(browser
->tab_strip_model(), 0);
182 Browser
* TabDragControllerTest::CreateAnotherWindowBrowserAndRelayout() {
183 // Create another browser.
184 Browser
* browser2
= CreateBrowser(browser()->profile());
185 ResetIDs(browser2
->tab_strip_model(), 100);
187 // Resize the two windows so they're right next to each other.
188 gfx::Rect work_area
= gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
189 browser()->window()->GetNativeWindow()).work_area();
190 gfx::Size half_size
=
191 gfx::Size(work_area
.width() / 3 - 10, work_area
.height() / 2 - 10);
192 browser()->window()->SetBounds(gfx::Rect(work_area
.origin(), half_size
));
193 browser2
->window()->SetBounds(gfx::Rect(
194 work_area
.x() + half_size
.width(), work_area
.y(),
195 half_size
.width(), half_size
.height()));
202 INPUT_SOURCE_MOUSE
= 0,
203 INPUT_SOURCE_TOUCH
= 1
206 int GetDetachY(TabStrip
* tab_strip
) {
207 return std::max(TabDragController::kTouchVerticalDetachMagnetism
,
208 TabDragController::kVerticalDetachMagnetism
) +
209 tab_strip
->height() + 1;
212 bool GetIsDragged(Browser
* browser
) {
213 #if !defined(USE_ASH) || defined(OS_WIN) // TODO(win_ash)
216 return ash::wm::GetWindowState(browser
->window()->GetNativeWindow())->
223 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
224 class ScreenEventGeneratorDelegate
225 : public aura::test::EventGeneratorDelegateAura
{
227 explicit ScreenEventGeneratorDelegate(aura::Window
* root_window
)
228 : root_window_(root_window
) {}
229 ~ScreenEventGeneratorDelegate() override
{}
231 // EventGeneratorDelegateAura overrides:
232 aura::WindowTreeHost
* GetHostAt(const gfx::Point
& point
) const override
{
233 return root_window_
->GetHost();
236 aura::client::ScreenPositionClient
* GetScreenPositionClient(
237 const aura::Window
* window
) const override
{
238 return aura::client::GetScreenPositionClient(root_window_
);
242 aura::Window
* root_window_
;
244 DISALLOW_COPY_AND_ASSIGN(ScreenEventGeneratorDelegate
);
249 #if !defined(OS_CHROMEOS)
251 // Following classes verify a crash scenario. Specifically on Windows when focus
252 // changes it can trigger capture being lost. This was causing a crash in tab
253 // dragging as it wasn't set up to handle this scenario. These classes
254 // synthesize this scenario.
256 // Allows making ClearNativeFocus() invoke ReleaseCapture().
257 class TestDesktopBrowserFrameAura
: public DesktopBrowserFrameAura
{
259 TestDesktopBrowserFrameAura(
260 BrowserFrame
* browser_frame
,
261 BrowserView
* browser_view
)
262 : DesktopBrowserFrameAura(browser_frame
, browser_view
),
263 release_capture_(false) {}
264 ~TestDesktopBrowserFrameAura() override
{}
266 void ReleaseCaptureOnNextClear() {
267 release_capture_
= true;
270 void ClearNativeFocus() override
{
271 views::DesktopNativeWidgetAura::ClearNativeFocus();
272 if (release_capture_
) {
273 release_capture_
= false;
274 GetWidget()->ReleaseCapture();
279 // If true ReleaseCapture() is invoked in ClearNativeFocus().
280 bool release_capture_
;
282 DISALLOW_COPY_AND_ASSIGN(TestDesktopBrowserFrameAura
);
285 // Factory for creating a TestDesktopBrowserFrameAura.
286 class TestNativeBrowserFrameFactory
: public NativeBrowserFrameFactory
{
288 TestNativeBrowserFrameFactory() {}
289 ~TestNativeBrowserFrameFactory() override
{}
291 NativeBrowserFrame
* Create(BrowserFrame
* browser_frame
,
292 BrowserView
* browser_view
) override
{
293 return new TestDesktopBrowserFrameAura(browser_frame
, browser_view
);
297 DISALLOW_COPY_AND_ASSIGN(TestNativeBrowserFrameFactory
);
300 class TabDragCaptureLostTest
: public TabDragControllerTest
{
302 TabDragCaptureLostTest() {
303 NativeBrowserFrameFactory::Set(new TestNativeBrowserFrameFactory
);
307 DISALLOW_COPY_AND_ASSIGN(TabDragCaptureLostTest
);
310 // See description above for details.
311 IN_PROC_BROWSER_TEST_F(TabDragCaptureLostTest
, ReleaseCaptureOnDrag
) {
312 AddTabAndResetBrowser(browser());
314 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
315 gfx::Point
tab_1_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(1)));
316 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_1_center
) &&
317 ui_test_utils::SendMouseEventsSync(
318 ui_controls::LEFT
, ui_controls::DOWN
));
319 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
320 TestDesktopBrowserFrameAura
* frame
=
321 static_cast<TestDesktopBrowserFrameAura
*>(
322 BrowserView::GetBrowserViewForBrowser(browser())->GetWidget()->
323 native_widget_private());
324 // Invoke ReleaseCaptureOnDrag() so that when the drag happens and focus
325 // changes capture is released and the drag cancels.
326 frame
->ReleaseCaptureOnNextClear();
327 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center
));
328 EXPECT_FALSE(tab_strip
->IsDragSessionActive());
331 IN_PROC_BROWSER_TEST_F(TabDragControllerTest
, GestureEndShouldEndDragTest
) {
332 AddTabAndResetBrowser(browser());
334 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
336 Tab
* tab1
= tab_strip
->tab_at(1);
337 gfx::Point
tab_1_center(tab1
->width() / 2, tab1
->height() / 2);
339 ui::GestureEvent
gesture_tap_down(
344 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN
));
345 tab_strip
->MaybeStartDrag(tab1
, gesture_tap_down
,
346 tab_strip
->GetSelectionModel());
347 EXPECT_TRUE(TabDragController::IsActive());
349 ui::GestureEvent
gesture_end(tab_1_center
.x(),
353 ui::GestureEventDetails(ui::ET_GESTURE_END
));
354 tab_strip
->OnGestureEvent(&gesture_end
);
355 EXPECT_FALSE(TabDragController::IsActive());
356 EXPECT_FALSE(tab_strip
->IsDragSessionActive());
361 class DetachToBrowserTabDragControllerTest
362 : public TabDragControllerTest
,
363 public ::testing::WithParamInterface
<const char*> {
365 DetachToBrowserTabDragControllerTest() {}
367 void SetUpOnMainThread() override
{
368 #if defined(OS_CHROMEOS)
369 event_generator_
.reset(
370 new ui::test::EventGenerator(ash::Shell::GetPrimaryRootWindow()));
374 InputSource
input_source() const {
375 return strstr(GetParam(), "mouse") ?
376 INPUT_SOURCE_MOUSE
: INPUT_SOURCE_TOUCH
;
379 // Set root window from a point in screen coordinates
380 void SetEventGeneratorRootWindow(const gfx::Point
& point
) {
381 if (input_source() == INPUT_SOURCE_MOUSE
)
383 #if defined(OS_CHROMEOS)
384 event_generator_
.reset(new ui::test::EventGenerator(
385 new ScreenEventGeneratorDelegate(ash::wm::GetRootWindowAt(point
))));
389 // The following methods update one of the mouse or touch input depending upon
391 bool PressInput(const gfx::Point
& location
) {
392 if (input_source() == INPUT_SOURCE_MOUSE
) {
393 return ui_test_utils::SendMouseMoveSync(location
) &&
394 ui_test_utils::SendMouseEventsSync(
395 ui_controls::LEFT
, ui_controls::DOWN
);
397 #if defined(OS_CHROMEOS)
398 event_generator_
->set_current_location(location
);
399 event_generator_
->PressTouch();
407 // Second touch input is only used for touch sequence tests.
408 EXPECT_EQ(INPUT_SOURCE_TOUCH
, input_source());
409 #if defined(OS_CHROMEOS)
410 event_generator_
->set_current_location(
411 event_generator_
->current_location());
412 event_generator_
->PressTouchId(1);
419 bool DragInputTo(const gfx::Point
& location
) {
420 if (input_source() == INPUT_SOURCE_MOUSE
)
421 return ui_test_utils::SendMouseMoveSync(location
);
422 #if defined(OS_CHROMEOS)
423 event_generator_
->MoveTouch(location
);
430 bool DragInputToAsync(const gfx::Point
& location
) {
431 if (input_source() == INPUT_SOURCE_MOUSE
)
432 return ui_controls::SendMouseMove(location
.x(), location
.y());
433 #if defined(OS_CHROMEOS)
434 event_generator_
->MoveTouch(location
);
441 bool DragInputToNotifyWhenDone(int x
,
443 const base::Closure
& task
) {
444 if (input_source() == INPUT_SOURCE_MOUSE
)
445 return ui_controls::SendMouseMoveNotifyWhenDone(x
, y
, task
);
446 #if defined(OS_CHROMEOS)
447 base::MessageLoop::current()->PostTask(FROM_HERE
, task
);
448 event_generator_
->MoveTouch(gfx::Point(x
, y
));
455 bool DragInputToDelayedNotifyWhenDone(int x
,
457 const base::Closure
& task
,
458 base::TimeDelta delay
) {
459 if (input_source() == INPUT_SOURCE_MOUSE
)
460 return ui_controls::SendMouseMoveNotifyWhenDone(x
, y
, task
);
461 #if defined(OS_CHROMEOS)
462 base::MessageLoop::current()->PostDelayedTask(FROM_HERE
, task
, delay
);
463 event_generator_
->MoveTouch(gfx::Point(x
, y
));
470 bool DragInput2ToNotifyWhenDone(int x
,
472 const base::Closure
& task
) {
473 if (input_source() == INPUT_SOURCE_MOUSE
)
474 return ui_controls::SendMouseMoveNotifyWhenDone(x
, y
, task
);
475 #if defined(OS_CHROMEOS)
476 base::MessageLoop::current()->PostTask(FROM_HERE
, task
);
477 event_generator_
->MoveTouchId(gfx::Point(x
, y
), 1);
484 bool ReleaseInput() {
485 if (input_source() == INPUT_SOURCE_MOUSE
) {
486 return ui_test_utils::SendMouseEventsSync(
487 ui_controls::LEFT
, ui_controls::UP
);
489 #if defined(OS_CHROMEOS)
490 event_generator_
->ReleaseTouch();
497 bool ReleaseInput2() {
498 if (input_source() == INPUT_SOURCE_MOUSE
) {
499 return ui_test_utils::SendMouseEventsSync(
500 ui_controls::LEFT
, ui_controls::UP
);
502 #if defined(OS_CHROMEOS)
503 event_generator_
->ReleaseTouchId(1);
510 bool ReleaseMouseAsync() {
511 return input_source() == INPUT_SOURCE_MOUSE
&&
512 ui_controls::SendMouseEvents(ui_controls::LEFT
, ui_controls::UP
);
515 void QuitWhenNotDragging() {
516 if (input_source() == INPUT_SOURCE_MOUSE
) {
517 // Schedule observer to quit message loop when done dragging. This has to
518 // be async so the message loop can run.
519 test::QuitWhenNotDraggingImpl();
520 base::MessageLoop::current()->Run();
522 // Touch events are sync, so we know we're not in a drag session. But some
523 // tests rely on the browser fully closing, which is async. So, run all
525 base::RunLoop run_loop
;
526 run_loop
.RunUntilIdle();
530 void AddBlankTabAndShow(Browser
* browser
) {
531 InProcessBrowserTest::AddBlankTabAndShow(browser
);
534 Browser
* browser() const { return InProcessBrowserTest::browser(); }
537 #if defined(OS_CHROMEOS)
538 scoped_ptr
<ui::test::EventGenerator
> event_generator_
;
541 DISALLOW_COPY_AND_ASSIGN(DetachToBrowserTabDragControllerTest
);
544 // Creates a browser with two tabs, drags the second to the first.
545 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
, DragInSameWindow
) {
546 // TODO(sky): this won't work with touch as it requires a long press.
547 if (input_source() == INPUT_SOURCE_TOUCH
) {
548 VLOG(1) << "Test is DISABLED for touch input.";
552 AddTabAndResetBrowser(browser());
554 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
555 TabStripModel
* model
= browser()->tab_strip_model();
557 gfx::Point
tab_1_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(1)));
558 ASSERT_TRUE(PressInput(tab_1_center
));
559 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
560 ASSERT_TRUE(DragInputTo(tab_0_center
));
561 ASSERT_TRUE(ReleaseInput());
562 EXPECT_EQ("1 0", IDString(model
));
563 EXPECT_FALSE(TabDragController::IsActive());
564 EXPECT_FALSE(tab_strip
->IsDragSessionActive());
566 // The tab strip should no longer have capture because the drag was ended and
567 // mouse/touch was released.
568 EXPECT_FALSE(tab_strip
->GetWidget()->HasCapture());
571 #if defined(USE_AURA)
574 // We need both MaskedWindowTargeter and MaskedWindowDelegate as they
575 // are used in two different pathes. crbug.com/493354.
576 class MaskedWindowTargeter
: public aura::WindowTargeter
{
578 MaskedWindowTargeter() {}
579 ~MaskedWindowTargeter() override
{}
581 // aura::WindowTargeter:
582 bool EventLocationInsideBounds(aura::Window
* target
,
583 const ui::LocatedEvent
& event
) const override
{
584 aura::Window
* window
= static_cast<aura::Window
*>(target
);
585 gfx::Point local_point
= event
.location();
586 if (window
->parent())
587 aura::Window::ConvertPointToTarget(window
->parent(), window
,
589 return window
->GetEventHandlerForPoint(local_point
);
593 DISALLOW_COPY_AND_ASSIGN(MaskedWindowTargeter
);
598 // The logic to find the target tabstrip should take the window mask into
599 // account. This test hangs without the fix. crbug.com/473080.
600 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
601 DragWithMaskedWindows
) {
602 AddTabAndResetBrowser(browser());
604 aura::Window
* browser_window
= browser()->window()->GetNativeWindow();
605 const gfx::Rect bounds
= browser_window
->GetBoundsInScreen();
606 aura::test::MaskedWindowDelegate
masked_window_delegate(
607 gfx::Rect(bounds
.width() - 10, 0, 10, bounds
.height()));
608 gfx::Rect
test(bounds
);
609 masked_window_delegate
.set_can_focus(false);
610 scoped_ptr
<aura::Window
> masked_window(
611 aura::test::CreateTestWindowWithDelegate(&masked_window_delegate
, 10,
612 test
, browser_window
->parent()));
613 masked_window
->SetEventTargeter(
614 scoped_ptr
<ui::EventTargeter
>(new MaskedWindowTargeter()));
616 ASSERT_FALSE(masked_window
->GetEventHandlerForPoint(
617 gfx::Point(bounds
.width() - 11, 0)));
618 ASSERT_TRUE(masked_window
->GetEventHandlerForPoint(
619 gfx::Point(bounds
.width() - 9, 0)));
620 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
621 TabStripModel
* model
= browser()->tab_strip_model();
623 gfx::Point
tab_1_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(1)));
624 ASSERT_TRUE(PressInput(tab_1_center
));
625 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
626 ASSERT_TRUE(DragInputTo(tab_0_center
));
627 ASSERT_TRUE(ReleaseInput());
628 EXPECT_EQ("1 0", IDString(model
));
629 EXPECT_FALSE(TabDragController::IsActive());
630 EXPECT_FALSE(tab_strip
->IsDragSessionActive());
636 // Invoked from the nested message loop.
637 void DragToSeparateWindowStep2(DetachToBrowserTabDragControllerTest
* test
,
638 TabStrip
* not_attached_tab_strip
,
639 TabStrip
* target_tab_strip
) {
640 ASSERT_FALSE(not_attached_tab_strip
->IsDragSessionActive());
641 ASSERT_FALSE(target_tab_strip
->IsDragSessionActive());
642 ASSERT_TRUE(TabDragController::IsActive());
644 // Drag to target_tab_strip. This should stop the nested loop from dragging
646 gfx::Point
target_point(target_tab_strip
->width() -1,
647 target_tab_strip
->height() / 2);
648 views::View::ConvertPointToScreen(target_tab_strip
, &target_point
);
649 ASSERT_TRUE(test
->DragInputToAsync(target_point
));
654 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
655 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
656 // compositor. crbug.com/331924
657 #define MAYBE_DragToSeparateWindow DISABLED_DragToSeparateWindow
659 #define MAYBE_DragToSeparateWindow DragToSeparateWindow
661 // Creates two browsers, drags from first into second.
662 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
663 MAYBE_DragToSeparateWindow
) {
664 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
666 // Add another tab to browser().
667 AddTabAndResetBrowser(browser());
669 // Create another browser.
670 Browser
* browser2
= CreateAnotherWindowBrowserAndRelayout();
671 TabStrip
* tab_strip2
= GetTabStripForBrowser(browser2
);
673 // Move to the first tab and drag it enough so that it detaches, but not
674 // enough that it attaches to browser2.
675 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
676 ASSERT_TRUE(PressInput(tab_0_center
));
677 ASSERT_TRUE(DragInputToNotifyWhenDone(
678 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
679 base::Bind(&DragToSeparateWindowStep2
,
680 this, tab_strip
, tab_strip2
)));
681 QuitWhenNotDragging();
683 // Should now be attached to tab_strip2.
684 ASSERT_TRUE(tab_strip2
->IsDragSessionActive());
685 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
686 ASSERT_TRUE(TabDragController::IsActive());
687 EXPECT_FALSE(GetIsDragged(browser()));
689 // Release mouse or touch, stopping the drag session.
690 ASSERT_TRUE(ReleaseInput());
691 ASSERT_FALSE(tab_strip2
->IsDragSessionActive());
692 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
693 ASSERT_FALSE(TabDragController::IsActive());
694 EXPECT_EQ("100 0", IDString(browser2
->tab_strip_model()));
695 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
696 EXPECT_FALSE(GetIsDragged(browser2
));
698 // Both windows should not be maximized
699 EXPECT_FALSE(browser()->window()->IsMaximized());
700 EXPECT_FALSE(browser2
->window()->IsMaximized());
702 // The tab strip should no longer have capture because the drag was ended and
703 // mouse/touch was released.
704 EXPECT_FALSE(tab_strip
->GetWidget()->HasCapture());
705 EXPECT_FALSE(tab_strip2
->GetWidget()->HasCapture());
710 void DetachToOwnWindowStep2(DetachToBrowserTabDragControllerTest
* test
) {
711 if (test
->input_source() == INPUT_SOURCE_TOUCH
)
712 ASSERT_TRUE(test
->ReleaseInput());
715 #if defined(OS_CHROMEOS)
716 bool IsWindowPositionManaged(aura::Window
* window
) {
717 return ash::wm::GetWindowState(window
)->window_position_managed();
719 bool HasUserChangedWindowPositionOrSize(aura::Window
* window
) {
720 return ash::wm::GetWindowState(window
)->bounds_changed_by_user();
723 bool IsWindowPositionManaged(gfx::NativeWindow window
) {
726 bool HasUserChangedWindowPositionOrSize(gfx::NativeWindow window
) {
733 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
734 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
735 // compositor. crbug.com/331924
736 #define MAYBE_DetachToOwnWindow DISABLED_DetachToOwnWindow
738 #define MAYBE_DetachToOwnWindow DetachToOwnWindow
740 // Drags from browser to separate window and releases mouse.
741 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
742 MAYBE_DetachToOwnWindow
) {
743 const gfx::Rect
initial_bounds(browser()->window()->GetBounds());
745 AddTabAndResetBrowser(browser());
746 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
748 // Move to the first tab and drag it enough so that it detaches.
749 gfx::Point
tab_0_center(
750 GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
751 ASSERT_TRUE(PressInput(tab_0_center
));
752 ASSERT_TRUE(DragInputToNotifyWhenDone(
753 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
754 base::Bind(&DetachToOwnWindowStep2
, this)));
755 if (input_source() == INPUT_SOURCE_MOUSE
) {
756 ASSERT_TRUE(ReleaseMouseAsync());
757 QuitWhenNotDragging();
760 // Should no longer be dragging.
761 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
762 ASSERT_FALSE(TabDragController::IsActive());
764 // There should now be another browser.
765 ASSERT_EQ(2u, native_browser_list
->size());
766 Browser
* new_browser
= native_browser_list
->get(1);
767 ASSERT_TRUE(new_browser
->window()->IsActive());
768 TabStrip
* tab_strip2
= GetTabStripForBrowser(new_browser
);
769 ASSERT_FALSE(tab_strip2
->IsDragSessionActive());
771 EXPECT_EQ("0", IDString(new_browser
->tab_strip_model()));
772 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
774 // The bounds of the initial window should not have changed.
775 EXPECT_EQ(initial_bounds
.ToString(),
776 browser()->window()->GetBounds().ToString());
778 EXPECT_FALSE(GetIsDragged(browser()));
779 EXPECT_FALSE(GetIsDragged(new_browser
));
780 // After this both windows should still be manageable.
781 EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
782 EXPECT_TRUE(IsWindowPositionManaged(
783 new_browser
->window()->GetNativeWindow()));
785 // Both windows should not be maximized
786 EXPECT_FALSE(browser()->window()->IsMaximized());
787 EXPECT_FALSE(new_browser
->window()->IsMaximized());
789 // The tab strip should no longer have capture because the drag was ended and
790 // mouse/touch was released.
791 EXPECT_FALSE(tab_strip
->GetWidget()->HasCapture());
792 EXPECT_FALSE(tab_strip2
->GetWidget()->HasCapture());
795 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
796 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
797 // compositor. crbug.com/331924
798 #define MAYBE_DetachFromFullsizeWindow DISABLED_DetachFromFullsizeWindow
800 #define MAYBE_DetachFromFullsizeWindow DetachFromFullsizeWindow
802 // Tests that a tab can be dragged from a browser window that is resized to full
804 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
805 MAYBE_DetachFromFullsizeWindow
) {
806 // Resize the browser window so that it is as big as the work area.
807 gfx::Rect work_area
=
808 gfx::Screen::GetNativeScreen()
809 ->GetDisplayNearestWindow(browser()->window()->GetNativeWindow())
811 browser()->window()->SetBounds(work_area
);
812 const gfx::Rect
initial_bounds(browser()->window()->GetBounds());
814 AddTabAndResetBrowser(browser());
815 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
817 // Move to the first tab and drag it enough so that it detaches.
818 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
819 ASSERT_TRUE(PressInput(tab_0_center
));
820 ASSERT_TRUE(DragInputToNotifyWhenDone(
821 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
822 base::Bind(&DetachToOwnWindowStep2
, this)));
823 if (input_source() == INPUT_SOURCE_MOUSE
) {
824 ASSERT_TRUE(ReleaseMouseAsync());
825 QuitWhenNotDragging();
828 // Should no longer be dragging.
829 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
830 ASSERT_FALSE(TabDragController::IsActive());
832 // There should now be another browser.
833 ASSERT_EQ(2u, native_browser_list
->size());
834 Browser
* new_browser
= native_browser_list
->get(1);
835 ASSERT_TRUE(new_browser
->window()->IsActive());
836 TabStrip
* tab_strip2
= GetTabStripForBrowser(new_browser
);
837 ASSERT_FALSE(tab_strip2
->IsDragSessionActive());
839 EXPECT_EQ("0", IDString(new_browser
->tab_strip_model()));
840 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
842 // The bounds of the initial window should not have changed.
843 EXPECT_EQ(initial_bounds
.ToString(),
844 browser()->window()->GetBounds().ToString());
846 EXPECT_FALSE(GetIsDragged(browser()));
847 EXPECT_FALSE(GetIsDragged(new_browser
));
848 // After this both windows should still be manageable.
849 EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
851 IsWindowPositionManaged(new_browser
->window()->GetNativeWindow()));
853 // Only second window should be maximized.
854 EXPECT_FALSE(browser()->window()->IsMaximized());
855 EXPECT_TRUE(new_browser
->window()->IsMaximized());
857 // The tab strip should no longer have capture because the drag was ended and
858 // mouse/touch was released.
859 EXPECT_FALSE(tab_strip
->GetWidget()->HasCapture());
860 EXPECT_FALSE(tab_strip2
->GetWidget()->HasCapture());
863 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
864 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
865 // compositor. crbug.com/331924
866 #define MAYBE_DetachToOwnWindowFromMaximizedWindow \
867 DISABLED_DetachToOwnWindowFromMaximizedWindow
869 #define MAYBE_DetachToOwnWindowFromMaximizedWindow \
870 DetachToOwnWindowFromMaximizedWindow
872 // Drags from browser to a separate window and releases mouse.
873 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
874 MAYBE_DetachToOwnWindowFromMaximizedWindow
) {
875 // Maximize the initial browser window.
876 browser()->window()->Maximize();
877 ASSERT_TRUE(browser()->window()->IsMaximized());
880 AddTabAndResetBrowser(browser());
881 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
883 // Move to the first tab and drag it enough so that it detaches.
884 gfx::Point
tab_0_center(
885 GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
886 ASSERT_TRUE(PressInput(tab_0_center
));
887 ASSERT_TRUE(DragInputToNotifyWhenDone(
888 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
889 base::Bind(&DetachToOwnWindowStep2
, this)));
890 if (input_source() == INPUT_SOURCE_MOUSE
) {
891 ASSERT_TRUE(ReleaseMouseAsync());
892 QuitWhenNotDragging();
895 // Should no longer be dragging.
896 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
897 ASSERT_FALSE(TabDragController::IsActive());
899 // There should now be another browser.
900 ASSERT_EQ(2u, native_browser_list
->size());
901 Browser
* new_browser
= native_browser_list
->get(1);
902 ASSERT_TRUE(new_browser
->window()->IsActive());
903 TabStrip
* tab_strip2
= GetTabStripForBrowser(new_browser
);
904 ASSERT_FALSE(tab_strip2
->IsDragSessionActive());
906 EXPECT_EQ("0", IDString(new_browser
->tab_strip_model()));
907 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
909 // The bounds of the initial window should not have changed.
910 EXPECT_TRUE(browser()->window()->IsMaximized());
912 EXPECT_FALSE(GetIsDragged(browser()));
913 EXPECT_FALSE(GetIsDragged(new_browser
));
914 // After this both windows should still be manageable.
915 EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
916 EXPECT_TRUE(IsWindowPositionManaged(
917 new_browser
->window()->GetNativeWindow()));
919 // The new window should be maximized.
920 EXPECT_TRUE(new_browser
->window()->IsMaximized());
923 // Deletes a tab being dragged before the user moved enough to start a drag.
924 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
925 DeleteBeforeStartedDragging
) {
927 AddTabAndResetBrowser(browser());
928 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
930 // Click on the first tab, but don't move it.
931 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
932 ASSERT_TRUE(PressInput(tab_0_center
));
934 // Should be dragging.
935 ASSERT_TRUE(tab_strip
->IsDragSessionActive());
936 ASSERT_TRUE(TabDragController::IsActive());
938 // Delete the tab being dragged.
939 delete browser()->tab_strip_model()->GetWebContentsAt(0);
941 // Should have canceled dragging.
942 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
943 ASSERT_FALSE(TabDragController::IsActive());
945 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
946 EXPECT_FALSE(GetIsDragged(browser()));
949 #if defined(OS_CHROMEOS)
950 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
951 // compositor. crbug.com/331924
952 #define MAYBE_DeleteTabWhileAttached DISABLED_DeleteTabWhileAttached
954 #define MAYBE_DeleteTabWhileAttached DeleteTabWhileAttached
956 // Deletes a tab being dragged while still attached.
957 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
958 MAYBE_DeleteTabWhileAttached
) {
959 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
960 // compositor. crbug.com/331924
961 if (input_source() == INPUT_SOURCE_MOUSE
) {
962 VLOG(1) << "Test is DISABLED for mouse input.";
967 AddTabAndResetBrowser(browser());
968 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
970 // Click on the first tab and move it enough so that it starts dragging but is
972 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
973 ASSERT_TRUE(PressInput(tab_0_center
));
974 ASSERT_TRUE(DragInputTo(
975 gfx::Point(tab_0_center
.x() + 20, tab_0_center
.y())));
977 // Should be dragging.
978 ASSERT_TRUE(tab_strip
->IsDragSessionActive());
979 ASSERT_TRUE(TabDragController::IsActive());
981 // Delete the tab being dragged.
982 delete browser()->tab_strip_model()->GetWebContentsAt(0);
984 // Should have canceled dragging.
985 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
986 ASSERT_FALSE(TabDragController::IsActive());
988 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
990 EXPECT_FALSE(GetIsDragged(browser()));
995 void DeleteWhileDetachedStep2(WebContents
* tab
) {
1001 #if defined(OS_CHROMEOS)
1002 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1003 // compositor. crbug.com/331924
1004 #define MAYBE_DeleteTabWhileDetached DISABLED_DeleteTabWhileDetached
1006 #define MAYBE_DeleteTabWhileDetached DeleteTabWhileDetached
1008 // Deletes a tab being dragged after dragging a tab so that a new window is
1010 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
1011 MAYBE_DeleteTabWhileDetached
) {
1013 AddTabAndResetBrowser(browser());
1014 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
1016 // Move to the first tab and drag it enough so that it detaches.
1017 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
1018 WebContents
* to_delete
=
1019 browser()->tab_strip_model()->GetWebContentsAt(0);
1020 ASSERT_TRUE(PressInput(tab_0_center
));
1021 ASSERT_TRUE(DragInputToNotifyWhenDone(
1022 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
1023 base::Bind(&DeleteWhileDetachedStep2
, to_delete
)));
1024 QuitWhenNotDragging();
1026 // Should not be dragging.
1027 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1028 ASSERT_FALSE(TabDragController::IsActive());
1030 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1032 EXPECT_FALSE(GetIsDragged(browser()));
1037 void DeleteSourceDetachedStep2(WebContents
* tab
,
1038 const BrowserList
* browser_list
) {
1039 ASSERT_EQ(2u, browser_list
->size());
1040 Browser
* new_browser
= browser_list
->get(1);
1041 // This ends up closing the source window.
1044 ui_controls::SendKeyPress(new_browser
->window()->GetNativeWindow(),
1045 ui::VKEY_ESCAPE
, false, false, false, false);
1050 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1051 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1052 // compositor. crbug.com/331924
1053 #define MAYBE_DeleteSourceDetached DISABLED_DeleteSourceDetached
1055 #define MAYBE_DeleteSourceDetached DeleteSourceDetached
1057 // Detaches a tab and while detached deletes a tab from the source so that the
1058 // source window closes then presses escape to cancel the drag.
1059 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
1060 MAYBE_DeleteSourceDetached
) {
1062 AddTabAndResetBrowser(browser());
1063 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
1065 // Move to the first tab and drag it enough so that it detaches.
1066 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
1067 WebContents
* to_delete
= browser()->tab_strip_model()->GetWebContentsAt(1);
1068 ASSERT_TRUE(PressInput(tab_0_center
));
1069 ASSERT_TRUE(DragInputToNotifyWhenDone(
1070 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
1071 base::Bind(&DeleteSourceDetachedStep2
, to_delete
, native_browser_list
)));
1072 QuitWhenNotDragging();
1074 // Should not be dragging.
1075 ASSERT_EQ(1u, native_browser_list
->size());
1076 Browser
* new_browser
= native_browser_list
->get(0);
1077 ASSERT_FALSE(GetTabStripForBrowser(new_browser
)->IsDragSessionActive());
1078 ASSERT_FALSE(TabDragController::IsActive());
1080 EXPECT_EQ("0", IDString(new_browser
->tab_strip_model()));
1082 EXPECT_FALSE(GetIsDragged(new_browser
));
1084 // Remaining browser window should not be maximized
1085 EXPECT_FALSE(new_browser
->window()->IsMaximized());
1090 void PressEscapeWhileDetachedStep2(const BrowserList
* browser_list
) {
1091 ASSERT_EQ(2u, browser_list
->size());
1092 Browser
* new_browser
= browser_list
->get(1);
1093 ui_controls::SendKeyPress(
1094 new_browser
->window()->GetNativeWindow(), ui::VKEY_ESCAPE
, false, false,
1100 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1101 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1102 // compositor. crbug.com/331924
1103 #define MAYBE_PressEscapeWhileDetached DISABLED_PressEscapeWhileDetached
1105 #define MAYBE_PressEscapeWhileDetached PressEscapeWhileDetached
1107 // This is disabled until NativeViewHost::Detach really detaches.
1108 // Detaches a tab and while detached presses escape to revert the drag.
1109 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
1110 MAYBE_PressEscapeWhileDetached
) {
1112 AddTabAndResetBrowser(browser());
1113 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
1115 // Move to the first tab and drag it enough so that it detaches.
1116 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
1117 ASSERT_TRUE(PressInput(tab_0_center
));
1118 ASSERT_TRUE(DragInputToNotifyWhenDone(
1119 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
1120 base::Bind(&PressEscapeWhileDetachedStep2
, native_browser_list
)));
1121 QuitWhenNotDragging();
1123 // Should not be dragging.
1124 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1125 ASSERT_FALSE(TabDragController::IsActive());
1127 // And there should only be one window.
1128 EXPECT_EQ(1u, native_browser_list
->size());
1130 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
1132 // Remaining browser window should not be maximized
1133 EXPECT_FALSE(browser()->window()->IsMaximized());
1135 // The tab strip should no longer have capture because the drag was ended and
1136 // mouse/touch was released.
1137 EXPECT_FALSE(tab_strip
->GetWidget()->HasCapture());
1142 void DragAllStep2(DetachToBrowserTabDragControllerTest
* test
,
1143 const BrowserList
* browser_list
) {
1144 // Should only be one window.
1145 ASSERT_EQ(1u, browser_list
->size());
1146 if (test
->input_source() == INPUT_SOURCE_TOUCH
) {
1147 ASSERT_TRUE(test
->ReleaseInput());
1149 ASSERT_TRUE(test
->ReleaseMouseAsync());
1155 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1156 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1157 // compositor. crbug.com/331924
1158 #define MAYBE_DragAll DISABLED_DragAll
1160 #define MAYBE_DragAll DragAll
1162 // Selects multiple tabs and starts dragging the window.
1163 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
, MAYBE_DragAll
) {
1165 AddTabAndResetBrowser(browser());
1166 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
1167 browser()->tab_strip_model()->AddTabAtToSelection(0);
1168 browser()->tab_strip_model()->AddTabAtToSelection(1);
1170 // Move to the first tab and drag it enough so that it would normally
1172 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
1173 ASSERT_TRUE(PressInput(tab_0_center
));
1174 ASSERT_TRUE(DragInputToNotifyWhenDone(
1175 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
1176 base::Bind(&DragAllStep2
, this, native_browser_list
)));
1177 QuitWhenNotDragging();
1179 // Should not be dragging.
1180 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1181 ASSERT_FALSE(TabDragController::IsActive());
1183 // And there should only be one window.
1184 EXPECT_EQ(1u, native_browser_list
->size());
1186 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
1188 EXPECT_FALSE(GetIsDragged(browser()));
1190 // Remaining browser window should not be maximized
1191 EXPECT_FALSE(browser()->window()->IsMaximized());
1196 // Invoked from the nested message loop.
1197 void DragAllToSeparateWindowStep2(DetachToBrowserTabDragControllerTest
* test
,
1198 TabStrip
* attached_tab_strip
,
1199 TabStrip
* target_tab_strip
,
1200 const BrowserList
* browser_list
) {
1201 ASSERT_TRUE(attached_tab_strip
->IsDragSessionActive());
1202 ASSERT_FALSE(target_tab_strip
->IsDragSessionActive());
1203 ASSERT_TRUE(TabDragController::IsActive());
1204 ASSERT_EQ(2u, browser_list
->size());
1206 // Drag to target_tab_strip. This should stop the nested loop from dragging
1208 gfx::Point
target_point(target_tab_strip
->width() - 1,
1209 target_tab_strip
->height() / 2);
1210 views::View::ConvertPointToScreen(target_tab_strip
, &target_point
);
1211 ASSERT_TRUE(test
->DragInputToAsync(target_point
));
1216 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1217 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1218 // compositor. crbug.com/331924
1219 #define MAYBE_DragAllToSeparateWindow DISABLED_DragAllToSeparateWindow
1221 #define MAYBE_DragAllToSeparateWindow DragAllToSeparateWindow
1223 // Creates two browsers, selects all tabs in first and drags into second.
1224 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
1225 MAYBE_DragAllToSeparateWindow
) {
1226 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
1228 // Add another tab to browser().
1229 AddTabAndResetBrowser(browser());
1231 // Create another browser.
1232 Browser
* browser2
= CreateAnotherWindowBrowserAndRelayout();
1233 TabStrip
* tab_strip2
= GetTabStripForBrowser(browser2
);
1235 browser()->tab_strip_model()->AddTabAtToSelection(0);
1236 browser()->tab_strip_model()->AddTabAtToSelection(1);
1238 // Move to the first tab and drag it enough so that it detaches, but not
1239 // enough that it attaches to browser2.
1240 gfx::Point
tab_0_center(
1241 GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
1242 ASSERT_TRUE(PressInput(tab_0_center
));
1243 ASSERT_TRUE(DragInputToNotifyWhenDone(
1244 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
1245 base::Bind(&DragAllToSeparateWindowStep2
, this, tab_strip
, tab_strip2
,
1246 native_browser_list
)));
1247 QuitWhenNotDragging();
1249 // Should now be attached to tab_strip2.
1250 ASSERT_TRUE(tab_strip2
->IsDragSessionActive());
1251 ASSERT_TRUE(TabDragController::IsActive());
1252 ASSERT_EQ(1u, native_browser_list
->size());
1254 // Release the mouse, stopping the drag session.
1255 ASSERT_TRUE(ReleaseInput());
1256 ASSERT_FALSE(tab_strip2
->IsDragSessionActive());
1257 ASSERT_FALSE(TabDragController::IsActive());
1258 EXPECT_EQ("100 0 1", IDString(browser2
->tab_strip_model()));
1260 EXPECT_FALSE(GetIsDragged(browser2
));
1262 // Remaining browser window should not be maximized
1263 EXPECT_FALSE(browser2
->window()->IsMaximized());
1268 // Invoked from the nested message loop.
1269 void DragAllToSeparateWindowAndCancelStep2(
1270 DetachToBrowserTabDragControllerTest
* test
,
1271 TabStrip
* attached_tab_strip
,
1272 TabStrip
* target_tab_strip
,
1273 const BrowserList
* browser_list
) {
1274 ASSERT_TRUE(attached_tab_strip
->IsDragSessionActive());
1275 ASSERT_FALSE(target_tab_strip
->IsDragSessionActive());
1276 ASSERT_TRUE(TabDragController::IsActive());
1277 ASSERT_EQ(2u, browser_list
->size());
1279 // Drag to target_tab_strip. This should stop the nested loop from dragging
1281 gfx::Point
target_point(target_tab_strip
->width() - 1,
1282 target_tab_strip
->height() / 2);
1283 views::View::ConvertPointToScreen(target_tab_strip
, &target_point
);
1284 ASSERT_TRUE(test
->DragInputToAsync(target_point
));
1289 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1290 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1291 // compositor. crbug.com/331924
1292 #define MAYBE_DragAllToSeparateWindowAndCancel \
1293 DISABLED_DragAllToSeparateWindowAndCancel
1295 #define MAYBE_DragAllToSeparateWindowAndCancel DragAllToSeparateWindowAndCancel
1297 // Creates two browsers, selects all tabs in first, drags into second, then hits
1299 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
1300 MAYBE_DragAllToSeparateWindowAndCancel
) {
1301 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
1303 // Add another tab to browser().
1304 AddTabAndResetBrowser(browser());
1306 // Create another browser.
1307 Browser
* browser2
= CreateAnotherWindowBrowserAndRelayout();
1308 TabStrip
* tab_strip2
= GetTabStripForBrowser(browser2
);
1310 browser()->tab_strip_model()->AddTabAtToSelection(0);
1311 browser()->tab_strip_model()->AddTabAtToSelection(1);
1313 // Move to the first tab and drag it enough so that it detaches, but not
1314 // enough that it attaches to browser2.
1315 gfx::Point
tab_0_center(
1316 GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
1317 ASSERT_TRUE(PressInput(tab_0_center
));
1318 ASSERT_TRUE(DragInputToNotifyWhenDone(
1319 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
1320 base::Bind(&DragAllToSeparateWindowAndCancelStep2
, this,
1321 tab_strip
, tab_strip2
, native_browser_list
)));
1322 QuitWhenNotDragging();
1324 // Should now be attached to tab_strip2.
1325 ASSERT_TRUE(tab_strip2
->IsDragSessionActive());
1326 ASSERT_TRUE(TabDragController::IsActive());
1327 ASSERT_EQ(1u, native_browser_list
->size());
1330 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
1331 browser2
, ui::VKEY_ESCAPE
, false, false, false, false));
1333 ASSERT_FALSE(tab_strip2
->IsDragSessionActive());
1334 ASSERT_FALSE(TabDragController::IsActive());
1335 EXPECT_EQ("100 0 1", IDString(browser2
->tab_strip_model()));
1337 // browser() will have been destroyed, but browser2 should remain.
1338 ASSERT_EQ(1u, native_browser_list
->size());
1340 EXPECT_FALSE(GetIsDragged(browser2
));
1342 // Remaining browser window should not be maximized
1343 EXPECT_FALSE(browser2
->window()->IsMaximized());
1346 #if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_WIN)
1347 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1348 // compositor. crbug.com/331924
1349 #define MAYBE_DragDirectlyToSecondWindow DISABLED_DragDirectlyToSecondWindow
1351 #define MAYBE_DragDirectlyToSecondWindow DragDirectlyToSecondWindow
1353 // Creates two browsers, drags from first into the second in such a way that
1354 // no detaching should happen.
1355 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
1356 MAYBE_DragDirectlyToSecondWindow
) {
1357 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
1359 // Add another tab to browser().
1360 AddTabAndResetBrowser(browser());
1362 // Create another browser.
1363 Browser
* browser2
= CreateAnotherWindowBrowserAndRelayout();
1364 TabStrip
* tab_strip2
= GetTabStripForBrowser(browser2
);
1366 // Move the tabstrip down enough so that we can detach.
1367 gfx::Rect
bounds(browser2
->window()->GetBounds());
1368 bounds
.Offset(0, 100);
1369 browser2
->window()->SetBounds(bounds
);
1371 // Move to the first tab and drag it enough so that it detaches, but not
1372 // enough that it attaches to browser2.
1373 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
1374 ASSERT_TRUE(PressInput(tab_0_center
));
1376 gfx::Point
b2_location(5, 0);
1377 views::View::ConvertPointToScreen(tab_strip2
, &b2_location
);
1378 ASSERT_TRUE(DragInputTo(b2_location
));
1380 // Should now be attached to tab_strip2.
1381 ASSERT_TRUE(tab_strip2
->IsDragSessionActive());
1382 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1383 ASSERT_TRUE(TabDragController::IsActive());
1385 // Release the mouse, stopping the drag session.
1386 ASSERT_TRUE(ReleaseInput());
1387 ASSERT_FALSE(tab_strip2
->IsDragSessionActive());
1388 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1389 ASSERT_FALSE(TabDragController::IsActive());
1390 EXPECT_EQ("0 100", IDString(browser2
->tab_strip_model()));
1391 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1393 EXPECT_FALSE(GetIsDragged(browser()));
1394 EXPECT_FALSE(GetIsDragged(browser2
));
1396 // Both windows should not be maximized
1397 EXPECT_FALSE(browser()->window()->IsMaximized());
1398 EXPECT_FALSE(browser2
->window()->IsMaximized());
1401 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1402 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1403 // compositor. crbug.com/331924
1404 #define MAYBE_DragSingleTabToSeparateWindow \
1405 DISABLED_DragSingleTabToSeparateWindow
1407 #define MAYBE_DragSingleTabToSeparateWindow DragSingleTabToSeparateWindow
1409 // Creates two browsers, the first browser has a single tab and drags into the
1411 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
1412 MAYBE_DragSingleTabToSeparateWindow
) {
1413 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
1415 ResetIDs(browser()->tab_strip_model(), 0);
1417 // Create another browser.
1418 Browser
* browser2
= CreateAnotherWindowBrowserAndRelayout();
1419 TabStrip
* tab_strip2
= GetTabStripForBrowser(browser2
);
1420 const gfx::Rect
initial_bounds(browser2
->window()->GetBounds());
1422 // Move to the first tab and drag it enough so that it detaches, but not
1423 // enough that it attaches to browser2.
1424 gfx::Point
tab_0_center(
1425 GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
1426 ASSERT_TRUE(PressInput(tab_0_center
));
1427 ASSERT_TRUE(DragInputToNotifyWhenDone(
1428 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
1429 base::Bind(&DragAllToSeparateWindowStep2
, this, tab_strip
, tab_strip2
,
1430 native_browser_list
)));
1431 QuitWhenNotDragging();
1433 // Should now be attached to tab_strip2.
1434 ASSERT_TRUE(tab_strip2
->IsDragSessionActive());
1435 ASSERT_TRUE(TabDragController::IsActive());
1436 ASSERT_EQ(1u, native_browser_list
->size());
1438 // Release the mouse, stopping the drag session.
1439 ASSERT_TRUE(ReleaseInput());
1440 ASSERT_FALSE(tab_strip2
->IsDragSessionActive());
1441 ASSERT_FALSE(TabDragController::IsActive());
1442 EXPECT_EQ("100 0", IDString(browser2
->tab_strip_model()));
1444 EXPECT_FALSE(GetIsDragged(browser2
));
1446 // Remaining browser window should not be maximized
1447 EXPECT_FALSE(browser2
->window()->IsMaximized());
1449 // Make sure that the window is still managed and not user moved.
1450 EXPECT_TRUE(IsWindowPositionManaged(browser2
->window()->GetNativeWindow()));
1451 EXPECT_FALSE(HasUserChangedWindowPositionOrSize(
1452 browser2
->window()->GetNativeWindow()));
1453 // Also make sure that the drag to window position has not changed.
1454 EXPECT_EQ(initial_bounds
.ToString(),
1455 browser2
->window()->GetBounds().ToString());
1460 // Invoked from the nested message loop.
1461 void CancelOnNewTabWhenDraggingStep2(
1462 DetachToBrowserTabDragControllerTest
* test
,
1463 const BrowserList
* browser_list
) {
1464 ASSERT_TRUE(TabDragController::IsActive());
1465 ASSERT_EQ(2u, browser_list
->size());
1467 // Add another tab. This should trigger exiting the nested loop. Add at the
1468 // to exercise past crash when model/tabstrip got out of sync (474082).
1469 content::WindowedNotificationObserver
observer(
1470 content::NOTIFICATION_LOAD_STOP
,
1471 content::NotificationService::AllSources());
1472 chrome::AddTabAt(browser_list
->GetLastActive(), GURL(url::kAboutBlankURL
),
1479 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1480 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1481 // compositor. crbug.com/331924
1482 #define MAYBE_CancelOnNewTabWhenDragging DISABLED_CancelOnNewTabWhenDragging
1484 #define MAYBE_CancelOnNewTabWhenDragging CancelOnNewTabWhenDragging
1486 // Adds another tab, detaches into separate window, adds another tab and
1487 // verifies the run loop ends.
1488 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
1489 MAYBE_CancelOnNewTabWhenDragging
) {
1490 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
1492 // Add another tab to browser().
1493 AddTabAndResetBrowser(browser());
1495 // Move to the first tab and drag it enough so that it detaches.
1496 gfx::Point
tab_0_center(
1497 GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
1498 ASSERT_TRUE(PressInput(tab_0_center
));
1499 ASSERT_TRUE(DragInputToNotifyWhenDone(
1500 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
1501 base::Bind(&CancelOnNewTabWhenDraggingStep2
, this, native_browser_list
)));
1502 QuitWhenNotDragging();
1504 // Should be two windows and not dragging.
1505 ASSERT_FALSE(TabDragController::IsActive());
1506 ASSERT_EQ(2u, native_browser_list
->size());
1507 for (chrome::BrowserIterator it
; !it
.done(); it
.Next()) {
1508 EXPECT_FALSE(GetIsDragged(*it
));
1509 // Should not be maximized
1510 EXPECT_FALSE(it
->window()->IsMaximized());
1514 #if defined(OS_CHROMEOS)
1515 // TODO(sky,sad): A number of tests below are disabled as they fail due to
1516 // resize locks with a real compositor. crbug.com/331924
1519 void DragInMaximizedWindowStep2(DetachToBrowserTabDragControllerTest
* test
,
1521 TabStrip
* tab_strip
,
1522 const BrowserList
* browser_list
) {
1523 // There should be another browser.
1524 ASSERT_EQ(2u, browser_list
->size());
1525 Browser
* new_browser
= browser_list
->get(1);
1526 EXPECT_NE(browser
, new_browser
);
1527 ASSERT_TRUE(new_browser
->window()->IsActive());
1528 TabStrip
* tab_strip2
= GetTabStripForBrowser(new_browser
);
1530 ASSERT_TRUE(tab_strip2
->IsDragSessionActive());
1531 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1533 // Both windows should be visible.
1534 EXPECT_TRUE(tab_strip
->GetWidget()->IsVisible());
1535 EXPECT_TRUE(tab_strip2
->GetWidget()->IsVisible());
1538 ASSERT_TRUE(test
->ReleaseInput());
1543 // Creates a browser with two tabs, maximizes it, drags the tab out.
1544 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
1545 DISABLED_DragInMaximizedWindow
) {
1546 AddTabAndResetBrowser(browser());
1547 browser()->window()->Maximize();
1549 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
1551 // Move to the first tab and drag it enough so that it detaches.
1552 gfx::Point
tab_0_center(
1553 GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
1554 ASSERT_TRUE(PressInput(tab_0_center
));
1555 ASSERT_TRUE(DragInputToNotifyWhenDone(
1556 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
1557 base::Bind(&DragInMaximizedWindowStep2
, this, browser(), tab_strip
,
1558 native_browser_list
)));
1559 QuitWhenNotDragging();
1561 ASSERT_FALSE(TabDragController::IsActive());
1563 // Should be two browsers.
1564 ASSERT_EQ(2u, native_browser_list
->size());
1565 Browser
* new_browser
= native_browser_list
->get(1);
1566 ASSERT_TRUE(new_browser
->window()->IsActive());
1568 EXPECT_TRUE(browser()->window()->GetNativeWindow()->IsVisible());
1569 EXPECT_TRUE(new_browser
->window()->GetNativeWindow()->IsVisible());
1571 EXPECT_FALSE(GetIsDragged(browser()));
1572 EXPECT_FALSE(GetIsDragged(new_browser
));
1574 // The source window should be maximized.
1575 EXPECT_TRUE(browser()->window()->IsMaximized());
1576 // The new window should be maximized.
1577 EXPECT_TRUE(new_browser
->window()->IsMaximized());
1580 // Subclass of DetachToBrowserTabDragControllerTest that
1581 // creates multiple displays.
1582 class DetachToBrowserInSeparateDisplayTabDragControllerTest
1583 : public DetachToBrowserTabDragControllerTest
{
1585 DetachToBrowserInSeparateDisplayTabDragControllerTest() {}
1586 virtual ~DetachToBrowserInSeparateDisplayTabDragControllerTest() {}
1588 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
1589 DetachToBrowserTabDragControllerTest::SetUpCommandLine(command_line
);
1590 // Make screens sufficiently wide to host 2 browsers side by side.
1591 command_line
->AppendSwitchASCII("ash-host-window-bounds",
1592 "0+0-600x600,601+0-600x600");
1596 DISALLOW_COPY_AND_ASSIGN(
1597 DetachToBrowserInSeparateDisplayTabDragControllerTest
);
1600 // Subclass of DetachToBrowserTabDragControllerTest that runs tests only with
1602 class DetachToBrowserTabDragControllerTestTouch
1603 : public DetachToBrowserTabDragControllerTest
{
1605 DetachToBrowserTabDragControllerTestTouch() {}
1606 virtual ~DetachToBrowserTabDragControllerTestTouch() {}
1609 DISALLOW_COPY_AND_ASSIGN(DetachToBrowserTabDragControllerTestTouch
);
1614 void DragSingleTabToSeparateWindowInSecondDisplayStep3(
1615 DetachToBrowserTabDragControllerTest
* test
) {
1616 ASSERT_TRUE(test
->ReleaseInput());
1619 void DragSingleTabToSeparateWindowInSecondDisplayStep2(
1620 DetachToBrowserTabDragControllerTest
* test
,
1621 const gfx::Point
& target_point
) {
1622 ASSERT_TRUE(test
->DragInputToNotifyWhenDone(
1623 target_point
.x(), target_point
.y(),
1624 base::Bind(&DragSingleTabToSeparateWindowInSecondDisplayStep3
, test
)));
1629 // Drags from browser to a second display and releases input.
1630 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest
,
1631 DISABLED_DragSingleTabToSeparateWindowInSecondDisplay
) {
1633 AddTabAndResetBrowser(browser());
1634 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
1636 // Move to the first tab and drag it enough so that it detaches.
1637 // Then drag it to the final destination on the second screen.
1638 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
1639 ASSERT_TRUE(PressInput(tab_0_center
));
1640 ASSERT_TRUE(DragInputToNotifyWhenDone(
1641 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
1642 base::Bind(&DragSingleTabToSeparateWindowInSecondDisplayStep2
,
1643 this, gfx::Point(600 + tab_0_center
.x(),
1645 + GetDetachY(tab_strip
)))));
1646 QuitWhenNotDragging();
1648 // Should no longer be dragging.
1649 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1650 ASSERT_FALSE(TabDragController::IsActive());
1652 // There should now be another browser.
1653 ASSERT_EQ(2u, native_browser_list
->size());
1654 Browser
* new_browser
= native_browser_list
->get(1);
1655 ASSERT_TRUE(new_browser
->window()->IsActive());
1656 TabStrip
* tab_strip2
= GetTabStripForBrowser(new_browser
);
1657 ASSERT_FALSE(tab_strip2
->IsDragSessionActive());
1659 // This other browser should be on the second screen (with mouse drag)
1660 // With the touch input the browser cannot be dragged from one screen
1661 // to another and the window stays on the first screen.
1662 if (input_source() == INPUT_SOURCE_MOUSE
) {
1663 aura::Window::Windows roots
= ash::Shell::GetAllRootWindows();
1664 ASSERT_EQ(2u, roots
.size());
1665 aura::Window
* second_root
= roots
[1];
1666 EXPECT_EQ(second_root
,
1667 new_browser
->window()->GetNativeWindow()->GetRootWindow());
1670 EXPECT_EQ("0", IDString(new_browser
->tab_strip_model()));
1671 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1673 // Both windows should not be maximized
1674 EXPECT_FALSE(browser()->window()->IsMaximized());
1675 EXPECT_FALSE(new_browser
->window()->IsMaximized());
1680 // Invoked from the nested message loop.
1681 void DragTabToWindowInSeparateDisplayStep2(
1682 DetachToBrowserTabDragControllerTest
* test
,
1683 TabStrip
* not_attached_tab_strip
,
1684 TabStrip
* target_tab_strip
) {
1685 ASSERT_FALSE(not_attached_tab_strip
->IsDragSessionActive());
1686 ASSERT_FALSE(target_tab_strip
->IsDragSessionActive());
1687 ASSERT_TRUE(TabDragController::IsActive());
1689 // Drag to target_tab_strip. This should stop the nested loop from dragging
1691 gfx::Point
target_point(
1692 GetCenterInScreenCoordinates(target_tab_strip
->tab_at(0)));
1694 // Move it close to the beginning of the target tabstrip.
1696 target_point
.x() - target_tab_strip
->tab_at(0)->width() / 2 + 10);
1697 ASSERT_TRUE(test
->DragInputToAsync(target_point
));
1702 // Drags from browser to another browser on a second display and releases input.
1703 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest
,
1704 DISABLED_DragTabToWindowInSeparateDisplay
) {
1706 AddTabAndResetBrowser(browser());
1707 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
1709 // Create another browser.
1710 Browser
* browser2
= CreateBrowser(browser()->profile());
1711 TabStrip
* tab_strip2
= GetTabStripForBrowser(browser2
);
1712 ResetIDs(browser2
->tab_strip_model(), 100);
1714 // Move the second browser to the second display.
1715 aura::Window::Windows roots
= ash::Shell::GetAllRootWindows();
1716 ASSERT_EQ(2u, roots
.size());
1717 aura::Window
* second_root
= roots
[1];
1718 gfx::Rect work_area
= gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1719 second_root
).work_area();
1720 browser2
->window()->SetBounds(work_area
);
1721 EXPECT_EQ(second_root
,
1722 browser2
->window()->GetNativeWindow()->GetRootWindow());
1724 // Move to the first tab and drag it enough so that it detaches, but not
1725 // enough that it attaches to browser2.
1726 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
1727 ASSERT_TRUE(PressInput(tab_0_center
));
1728 ASSERT_TRUE(DragInputToNotifyWhenDone(
1729 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
1730 base::Bind(&DragTabToWindowInSeparateDisplayStep2
,
1731 this, tab_strip
, tab_strip2
)));
1732 QuitWhenNotDragging();
1734 // Should now be attached to tab_strip2.
1735 ASSERT_TRUE(tab_strip2
->IsDragSessionActive());
1736 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1737 ASSERT_TRUE(TabDragController::IsActive());
1739 // Release the mouse, stopping the drag session.
1740 ASSERT_TRUE(ReleaseInput());
1741 ASSERT_FALSE(tab_strip2
->IsDragSessionActive());
1742 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1743 ASSERT_FALSE(TabDragController::IsActive());
1744 EXPECT_EQ("0 100", IDString(browser2
->tab_strip_model()));
1745 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1747 // Both windows should not be maximized
1748 EXPECT_FALSE(browser()->window()->IsMaximized());
1749 EXPECT_FALSE(browser2
->window()->IsMaximized());
1752 // Drags from browser to another browser on a second display and releases input.
1753 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest
,
1754 DISABLED_DragTabToWindowOnSecondDisplay
) {
1756 AddTabAndResetBrowser(browser());
1757 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
1759 // Create another browser.
1760 Browser
* browser2
= CreateBrowser(browser()->profile());
1761 TabStrip
* tab_strip2
= GetTabStripForBrowser(browser2
);
1762 ResetIDs(browser2
->tab_strip_model(), 100);
1764 // Move both browsers to the second display.
1765 aura::Window::Windows roots
= ash::Shell::GetAllRootWindows();
1766 ASSERT_EQ(2u, roots
.size());
1767 aura::Window
* second_root
= roots
[1];
1768 gfx::Rect work_area
= gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1769 second_root
).work_area();
1770 browser()->window()->SetBounds(work_area
);
1772 // position both browser windows side by side on the second screen.
1773 gfx::Rect
work_area2(work_area
);
1774 work_area
.set_width(work_area
.width()/2);
1775 browser()->window()->SetBounds(work_area
);
1776 work_area2
.set_x(work_area2
.x() + work_area2
.width()/2);
1777 work_area2
.set_width(work_area2
.width()/2);
1778 browser2
->window()->SetBounds(work_area2
);
1779 EXPECT_EQ(second_root
,
1780 browser()->window()->GetNativeWindow()->GetRootWindow());
1781 EXPECT_EQ(second_root
,
1782 browser2
->window()->GetNativeWindow()->GetRootWindow());
1784 // Move to the first tab and drag it enough so that it detaches, but not
1785 // enough that it attaches to browser2.
1786 // SetEventGeneratorRootWindow sets correct (second) RootWindow
1787 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
1788 SetEventGeneratorRootWindow(tab_0_center
);
1789 ASSERT_TRUE(PressInput(tab_0_center
));
1790 ASSERT_TRUE(DragInputToNotifyWhenDone(
1791 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
1792 base::Bind(&DragTabToWindowInSeparateDisplayStep2
,
1793 this, tab_strip
, tab_strip2
)));
1794 QuitWhenNotDragging();
1796 // Should now be attached to tab_strip2.
1797 ASSERT_TRUE(tab_strip2
->IsDragSessionActive());
1798 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1799 ASSERT_TRUE(TabDragController::IsActive());
1801 // Release the mouse, stopping the drag session.
1802 ASSERT_TRUE(ReleaseInput());
1803 ASSERT_FALSE(tab_strip2
->IsDragSessionActive());
1804 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1805 ASSERT_FALSE(TabDragController::IsActive());
1806 EXPECT_EQ("0 100", IDString(browser2
->tab_strip_model()));
1807 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1809 // Both windows should not be maximized
1810 EXPECT_FALSE(browser()->window()->IsMaximized());
1811 EXPECT_FALSE(browser2
->window()->IsMaximized());
1814 // Drags from a maximized browser to another non-maximized browser on a second
1815 // display and releases input.
1816 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest
,
1817 DISABLED_DragMaxTabToNonMaxWindowInSeparateDisplay
) {
1819 AddTabAndResetBrowser(browser());
1820 browser()->window()->Maximize();
1821 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
1823 // Create another browser on the second display.
1824 aura::Window::Windows roots
= ash::Shell::GetAllRootWindows();
1825 ASSERT_EQ(2u, roots
.size());
1826 aura::Window
* first_root
= roots
[0];
1827 aura::Window
* second_root
= roots
[1];
1828 gfx::Rect work_area
= gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1829 second_root
).work_area();
1830 work_area
.Inset(20, 20, 20, 60);
1831 Browser::CreateParams
params(browser()->profile(),
1832 browser()->host_desktop_type());
1833 params
.initial_show_state
= ui::SHOW_STATE_NORMAL
;
1834 params
.initial_bounds
= work_area
;
1835 Browser
* browser2
= new Browser(params
);
1836 AddBlankTabAndShow(browser2
);
1838 TabStrip
* tab_strip2
= GetTabStripForBrowser(browser2
);
1839 ResetIDs(browser2
->tab_strip_model(), 100);
1841 EXPECT_EQ(second_root
,
1842 browser2
->window()->GetNativeWindow()->GetRootWindow());
1843 EXPECT_EQ(first_root
,
1844 browser()->window()->GetNativeWindow()->GetRootWindow());
1845 EXPECT_EQ(2, tab_strip
->tab_count());
1846 EXPECT_EQ(1, tab_strip2
->tab_count());
1848 // Move to the first tab and drag it enough so that it detaches, but not
1849 // enough that it attaches to browser2.
1850 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
1851 ASSERT_TRUE(PressInput(tab_0_center
));
1852 ASSERT_TRUE(DragInputToNotifyWhenDone(
1853 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
1854 base::Bind(&DragTabToWindowInSeparateDisplayStep2
,
1855 this, tab_strip
, tab_strip2
)));
1856 QuitWhenNotDragging();
1858 // Should now be attached to tab_strip2.
1859 ASSERT_TRUE(tab_strip2
->IsDragSessionActive());
1860 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1861 ASSERT_TRUE(TabDragController::IsActive());
1863 // Release the mouse, stopping the drag session.
1864 ASSERT_TRUE(ReleaseInput());
1866 // tab should have moved
1867 EXPECT_EQ(1, tab_strip
->tab_count());
1868 EXPECT_EQ(2, tab_strip2
->tab_count());
1870 ASSERT_FALSE(tab_strip2
->IsDragSessionActive());
1871 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1872 ASSERT_FALSE(TabDragController::IsActive());
1873 EXPECT_EQ("0 100", IDString(browser2
->tab_strip_model()));
1874 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1876 // Source browser should still be maximized, target should not
1877 EXPECT_TRUE(browser()->window()->IsMaximized());
1878 EXPECT_FALSE(browser2
->window()->IsMaximized());
1881 // Drags from a restored browser to an immersive fullscreen browser on a
1882 // second display and releases input.
1883 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest
,
1884 DISABLED_DragTabToImmersiveBrowserOnSeparateDisplay
) {
1886 AddTabAndResetBrowser(browser());
1887 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
1889 // Create another browser.
1890 Browser
* browser2
= CreateBrowser(browser()->profile());
1891 TabStrip
* tab_strip2
= GetTabStripForBrowser(browser2
);
1892 ResetIDs(browser2
->tab_strip_model(), 100);
1894 // Move the second browser to the second display.
1895 aura::Window::Windows roots
= ash::Shell::GetAllRootWindows();
1896 ASSERT_EQ(2u, roots
.size());
1897 aura::Window
* second_root
= roots
[1];
1898 gfx::Rect work_area
= gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1899 second_root
).work_area();
1900 browser2
->window()->SetBounds(work_area
);
1901 EXPECT_EQ(second_root
,
1902 browser2
->window()->GetNativeWindow()->GetRootWindow());
1904 // Put the second browser into immersive fullscreen.
1905 BrowserView
* browser_view2
= BrowserView::GetBrowserViewForBrowser(browser2
);
1906 ImmersiveModeController
* immersive_controller2
=
1907 browser_view2
->immersive_mode_controller();
1908 immersive_controller2
->SetupForTest();
1909 chrome::ToggleFullscreenMode(browser2
);
1910 ASSERT_TRUE(immersive_controller2
->IsEnabled());
1911 ASSERT_FALSE(immersive_controller2
->IsRevealed());
1912 ASSERT_TRUE(tab_strip2
->IsImmersiveStyle());
1914 // Move to the first tab and drag it enough so that it detaches, but not
1915 // enough that it attaches to browser2.
1916 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
1917 ASSERT_TRUE(PressInput(tab_0_center
));
1918 ASSERT_TRUE(DragInputToNotifyWhenDone(
1919 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
1920 base::Bind(&DragTabToWindowInSeparateDisplayStep2
,
1921 this, tab_strip
, tab_strip2
)));
1922 QuitWhenNotDragging();
1924 // Should now be attached to tab_strip2.
1925 ASSERT_TRUE(tab_strip2
->IsDragSessionActive());
1926 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1927 ASSERT_TRUE(TabDragController::IsActive());
1929 // browser2's top chrome should be revealed and the tab strip should be
1930 // at normal height while user is tragging tabs_strip2's tabs.
1931 ASSERT_TRUE(immersive_controller2
->IsRevealed());
1932 ASSERT_FALSE(tab_strip2
->IsImmersiveStyle());
1934 // Release the mouse, stopping the drag session.
1935 ASSERT_TRUE(ReleaseInput());
1936 ASSERT_FALSE(tab_strip2
->IsDragSessionActive());
1937 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
1938 ASSERT_FALSE(TabDragController::IsActive());
1939 EXPECT_EQ("0 100", IDString(browser2
->tab_strip_model()));
1940 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1942 // Move the mouse off of browser2's top chrome.
1943 aura::Window
* primary_root
= roots
[0];
1944 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
1945 primary_root
->GetBoundsInScreen().CenterPoint()));
1947 // The first browser window should not be in immersive fullscreen.
1948 // browser2 should still be in immersive fullscreen, but the top chrome should
1949 // no longer be revealed.
1950 BrowserView
* browser_view
= BrowserView::GetBrowserViewForBrowser(browser());
1951 EXPECT_FALSE(browser_view
->immersive_mode_controller()->IsEnabled());
1953 EXPECT_TRUE(immersive_controller2
->IsEnabled());
1954 EXPECT_FALSE(immersive_controller2
->IsRevealed());
1955 EXPECT_TRUE(tab_strip2
->IsImmersiveStyle());
1958 // Subclass of DetachToBrowserTabDragControllerTest that
1959 // creates multiple displays with different device scale factors.
1960 class DifferentDeviceScaleFactorDisplayTabDragControllerTest
1961 : public DetachToBrowserTabDragControllerTest
{
1963 DifferentDeviceScaleFactorDisplayTabDragControllerTest() {}
1964 virtual ~DifferentDeviceScaleFactorDisplayTabDragControllerTest() {}
1966 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
1967 DetachToBrowserTabDragControllerTest::SetUpCommandLine(command_line
);
1968 command_line
->AppendSwitchASCII("ash-host-window-bounds",
1969 "400x400,0+400-800x800*2");
1972 float GetCursorDeviceScaleFactor() const {
1973 ash::test::CursorManagerTestApi
cursor_test_api(
1974 ash::Shell::GetInstance()->cursor_manager());
1975 return cursor_test_api
.GetCurrentCursor().device_scale_factor();
1979 DISALLOW_COPY_AND_ASSIGN(
1980 DifferentDeviceScaleFactorDisplayTabDragControllerTest
);
1985 // The points where a tab is dragged in CursorDeviceScaleFactorStep.
1986 const struct DragPoint
{
1997 // The expected device scale factors before the cursor is moved to the
1998 // corresponding kDragPoints in CursorDeviceScaleFactorStep.
1999 const float kDeviceScaleFactorExpectations
[] = {
2008 arraysize(kDragPoints
) == arraysize(kDeviceScaleFactorExpectations
),
2009 "kDragPoints and kDeviceScaleFactorExpectations must have the same "
2010 "number of elements");
2012 // Drags tab to |kDragPoints[index]|, then calls the next step function.
2013 void CursorDeviceScaleFactorStep(
2014 DifferentDeviceScaleFactorDisplayTabDragControllerTest
* test
,
2015 TabStrip
* not_attached_tab_strip
,
2017 ASSERT_FALSE(not_attached_tab_strip
->IsDragSessionActive());
2018 ASSERT_TRUE(TabDragController::IsActive());
2020 if (index
< arraysize(kDragPoints
)) {
2021 EXPECT_EQ(kDeviceScaleFactorExpectations
[index
],
2022 test
->GetCursorDeviceScaleFactor());
2023 const DragPoint p
= kDragPoints
[index
];
2024 ASSERT_TRUE(test
->DragInputToNotifyWhenDone(
2025 p
.x
, p
.y
, base::Bind(&CursorDeviceScaleFactorStep
,
2026 test
, not_attached_tab_strip
, index
+ 1)));
2028 // Finishes a serise of CursorDeviceScaleFactorStep calls and ends drag.
2029 EXPECT_EQ(1.0f
, test
->GetCursorDeviceScaleFactor());
2030 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
2031 ui_controls::LEFT
, ui_controls::UP
));
2037 // Verifies cursor's device scale factor is updated when a tab is moved across
2038 // displays with different device scale factors (http://crbug.com/154183).
2039 IN_PROC_BROWSER_TEST_P(DifferentDeviceScaleFactorDisplayTabDragControllerTest
,
2040 DISABLED_CursorDeviceScaleFactor
) {
2042 AddTabAndResetBrowser(browser());
2043 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
2045 // Move the second browser to the second display.
2046 aura::Window::Windows roots
= ash::Shell::GetAllRootWindows();
2047 ASSERT_EQ(2u, roots
.size());
2049 // Move to the first tab and drag it enough so that it detaches.
2050 gfx::Point
tab_0_center(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
2051 ASSERT_TRUE(PressInput(tab_0_center
));
2052 ASSERT_TRUE(DragInputToNotifyWhenDone(
2053 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
2054 base::Bind(&CursorDeviceScaleFactorStep
,
2055 this, tab_strip
, 0)));
2056 QuitWhenNotDragging();
2061 class DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest
2062 : public TabDragControllerTest
{
2064 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest() {}
2066 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
2067 TabDragControllerTest::SetUpCommandLine(command_line
);
2068 command_line
->AppendSwitchASCII("ash-host-window-bounds",
2069 "0+0-250x250,251+0-250x250");
2072 bool Press(const gfx::Point
& position
) {
2073 return ui_test_utils::SendMouseMoveSync(position
) &&
2074 ui_test_utils::SendMouseEventsSync(ui_controls::LEFT
,
2078 bool DragTabAndExecuteTaskWhenDone(const gfx::Point
& position
,
2079 const base::Closure
& task
) {
2080 return ui_controls::SendMouseMoveNotifyWhenDone(
2081 position
.x(), position
.y(), task
);
2084 void QuitWhenNotDragging() {
2085 test::QuitWhenNotDraggingImpl();
2086 base::MessageLoop::current()->Run();
2090 DISALLOW_COPY_AND_ASSIGN(
2091 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest
);
2094 // Invoked from the nested message loop.
2095 void CancelDragTabToWindowInSeparateDisplayStep3(
2096 TabStrip
* tab_strip
,
2097 const BrowserList
* browser_list
) {
2098 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
2099 ASSERT_TRUE(TabDragController::IsActive());
2100 ASSERT_EQ(2u, browser_list
->size());
2102 // Switching display mode should cancel the drag operation.
2103 ash::DisplayManager
* display_manager
=
2104 ash::Shell::GetInstance()->display_manager();
2105 display_manager
->AddRemoveDisplay();
2108 // Invoked from the nested message loop.
2109 void CancelDragTabToWindowInSeparateDisplayStep2(
2110 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest
* test
,
2111 TabStrip
* tab_strip
,
2112 aura::Window
* current_root
,
2113 gfx::Point final_destination
,
2114 const BrowserList
* browser_list
) {
2115 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
2116 ASSERT_TRUE(TabDragController::IsActive());
2117 ASSERT_EQ(2u, browser_list
->size());
2119 Browser
* new_browser
= browser_list
->get(1);
2120 EXPECT_EQ(current_root
,
2121 new_browser
->window()->GetNativeWindow()->GetRootWindow());
2123 ASSERT_TRUE(test
->DragTabAndExecuteTaskWhenDone(
2125 base::Bind(&CancelDragTabToWindowInSeparateDisplayStep3
,
2126 tab_strip
, browser_list
)));
2131 // Drags from browser to a second display and releases input.
2132 IN_PROC_BROWSER_TEST_F(
2133 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest
,
2134 DISABLED_CancelDragTabToWindowIn2ndDisplay
) {
2136 AddTabAndResetBrowser(browser());
2137 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
2139 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2141 // Move the second browser to the second display.
2142 aura::Window::Windows roots
= ash::Shell::GetAllRootWindows();
2143 ASSERT_EQ(2u, roots
.size());
2144 gfx::Point final_destination
=
2145 gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
2146 roots
[1]).work_area().CenterPoint();
2148 // Move to the first tab and drag it enough so that it detaches, but not
2149 // enough to move to another display.
2150 gfx::Point
tab_0_dst(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
2151 ASSERT_TRUE(Press(tab_0_dst
));
2152 tab_0_dst
.Offset(0, GetDetachY(tab_strip
));
2153 ASSERT_TRUE(DragTabAndExecuteTaskWhenDone(
2154 tab_0_dst
, base::Bind(&CancelDragTabToWindowInSeparateDisplayStep2
,
2155 this, tab_strip
, roots
[0], final_destination
,
2156 native_browser_list
)));
2157 QuitWhenNotDragging();
2159 ASSERT_EQ(1u, native_browser_list
->size());
2160 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
2161 ASSERT_FALSE(TabDragController::IsActive());
2162 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2164 // Release the mouse
2165 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
2166 ui_controls::LEFT
, ui_controls::UP
));
2169 // Drags from browser from a second display to primary and releases input.
2170 IN_PROC_BROWSER_TEST_F(
2171 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest
,
2172 DISABLED_CancelDragTabToWindowIn1stDisplay
) {
2173 aura::Window::Windows roots
= ash::Shell::GetAllRootWindows();
2174 ASSERT_EQ(2u, roots
.size());
2177 AddTabAndResetBrowser(browser());
2178 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
2180 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2181 EXPECT_EQ(roots
[0], browser()->window()->GetNativeWindow()->GetRootWindow());
2183 gfx::Rect work_area
= gfx::Screen::GetNativeScreen()->
2184 GetDisplayNearestWindow(roots
[1]).work_area();
2185 browser()->window()->SetBounds(work_area
);
2186 EXPECT_EQ(roots
[1], browser()->window()->GetNativeWindow()->GetRootWindow());
2188 // Move the second browser to the display.
2189 gfx::Point final_destination
=
2190 gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
2191 roots
[0]).work_area().CenterPoint();
2193 // Move to the first tab and drag it enough so that it detaches, but not
2194 // enough to move to another display.
2195 gfx::Point
tab_0_dst(GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
2196 ASSERT_TRUE(Press(tab_0_dst
));
2197 tab_0_dst
.Offset(0, GetDetachY(tab_strip
));
2198 ASSERT_TRUE(DragTabAndExecuteTaskWhenDone(
2199 tab_0_dst
, base::Bind(&CancelDragTabToWindowInSeparateDisplayStep2
,
2200 this, tab_strip
, roots
[1], final_destination
,
2201 native_browser_list
)));
2202 QuitWhenNotDragging();
2204 ASSERT_EQ(1u, native_browser_list
->size());
2205 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
2206 ASSERT_FALSE(TabDragController::IsActive());
2207 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2209 // Release the mouse
2210 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
2211 ui_controls::LEFT
, ui_controls::UP
));
2216 void PressSecondFingerWhileDetachedStep2(
2217 DetachToBrowserTabDragControllerTest
* test
) {
2218 ASSERT_TRUE(TabDragController::IsActive());
2219 ASSERT_EQ(2u, test
->native_browser_list
->size());
2220 Browser
* new_browser
= test
->native_browser_list
->get(1);
2221 ASSERT_TRUE(new_browser
->window()->IsActive());
2223 ASSERT_TRUE(test
->PressInput2());
2228 // Detaches a tab and while detached presses a second finger.
2229 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestTouch
,
2230 DISABLED_PressSecondFingerWhileDetached
) {
2231 gfx::Rect
bounds(browser()->window()->GetBounds());
2233 AddTabAndResetBrowser(browser());
2234 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
2235 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2237 // Move to the first tab and drag it enough so that it detaches.
2238 gfx::Point
tab_0_center(
2239 GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
2240 ASSERT_TRUE(PressInput(tab_0_center
));
2241 ASSERT_TRUE(DragInputToDelayedNotifyWhenDone(
2242 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
2243 base::Bind(&PressSecondFingerWhileDetachedStep2
, this),
2244 base::TimeDelta::FromMilliseconds(60)));
2245 QuitWhenNotDragging();
2247 // The drag should have been reverted.
2248 ASSERT_EQ(1u, native_browser_list
->size());
2249 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
2250 ASSERT_FALSE(TabDragController::IsActive());
2251 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2253 ASSERT_TRUE(ReleaseInput());
2254 ASSERT_TRUE(ReleaseInput2());
2257 #if defined(OS_CHROMEOS)
2261 void DetachToDockedWindowNextStep(
2262 DetachToBrowserTabDragControllerTest
* test
,
2263 const gfx::Point
& target_point
,
2265 ASSERT_EQ(2u, test
->native_browser_list
->size());
2266 Browser
* new_browser
= test
->native_browser_list
->get(1);
2267 ASSERT_TRUE(new_browser
->window()->IsActive());
2270 ASSERT_TRUE(test
->ReleaseInput());
2273 ASSERT_TRUE(test
->DragInputToNotifyWhenDone(
2274 target_point
.x(), target_point
.y(),
2275 base::Bind(&DetachToDockedWindowNextStep
,
2277 gfx::Point(target_point
.x(), 1 + target_point
.y()),
2283 // Drags from browser to separate window, docks that window and releases mouse.
2284 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest
,
2285 DISABLED_DetachToDockedWindowFromMaximizedWindow
) {
2286 // Maximize the initial browser window.
2287 browser()->window()->Maximize();
2288 ASSERT_TRUE(browser()->window()->IsMaximized());
2291 AddTabAndResetBrowser(browser());
2292 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
2294 // Move to the first tab and drag it enough so that it detaches.
2295 gfx::Point
tab_0_center(
2296 GetCenterInScreenCoordinates(tab_strip
->tab_at(0)));
2297 ASSERT_TRUE(PressInput(tab_0_center
));
2299 // The following matches kMovesBeforeAdjust in snap_sizer.cc
2300 const int kNumIterations
= 25 * 5 + 10;
2301 ASSERT_TRUE(DragInputToNotifyWhenDone(
2302 tab_0_center
.x(), tab_0_center
.y() + GetDetachY(tab_strip
),
2303 base::Bind(&DetachToDockedWindowNextStep
, this,
2304 gfx::Point(0, tab_0_center
.y() + GetDetachY(tab_strip
)),
2306 // Continue dragging enough times to go through snapping sequence and dock
2308 QuitWhenNotDragging();
2309 // Should no longer be dragging.
2310 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
2311 ASSERT_FALSE(TabDragController::IsActive());
2313 // There should now be another browser.
2314 ASSERT_EQ(2u, native_browser_list
->size());
2315 Browser
* new_browser
= native_browser_list
->get(1);
2316 ASSERT_TRUE(new_browser
->window()->IsActive());
2317 TabStrip
* tab_strip2
= GetTabStripForBrowser(new_browser
);
2318 ASSERT_FALSE(tab_strip2
->IsDragSessionActive());
2320 EXPECT_EQ("0", IDString(new_browser
->tab_strip_model()));
2321 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
2323 // The bounds of the initial window should not have changed.
2324 EXPECT_TRUE(browser()->window()->IsMaximized());
2326 EXPECT_FALSE(GetIsDragged(browser()));
2327 EXPECT_FALSE(GetIsDragged(new_browser
));
2328 // After this both windows should still be manageable.
2329 EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
2330 EXPECT_TRUE(IsWindowPositionManaged(
2331 new_browser
->window()->GetNativeWindow()));
2333 ash::wm::WindowState
* window_state
=
2334 ash::wm::GetWindowState(new_browser
->window()->GetNativeWindow());
2335 // The new window should not be maximized because it gets docked or snapped.
2336 EXPECT_FALSE(new_browser
->window()->IsMaximized());
2337 // The new window should be docked and not snapped.
2338 EXPECT_TRUE(window_state
->IsDocked());
2339 EXPECT_FALSE(window_state
->IsSnapped());
2342 #endif // OS_CHROMEOS
2346 #if defined(USE_ASH) && defined(OS_CHROMEOS) // TODO(win_ash,linux_ash)
2347 INSTANTIATE_TEST_CASE_P(TabDragging
,
2348 DetachToBrowserInSeparateDisplayTabDragControllerTest
,
2349 ::testing::Values("mouse", "touch"));
2350 INSTANTIATE_TEST_CASE_P(TabDragging
,
2351 DifferentDeviceScaleFactorDisplayTabDragControllerTest
,
2352 ::testing::Values("mouse"));
2353 INSTANTIATE_TEST_CASE_P(TabDragging
,
2354 DetachToBrowserTabDragControllerTest
,
2355 ::testing::Values("mouse", "touch"));
2356 INSTANTIATE_TEST_CASE_P(TabDragging
,
2357 DetachToBrowserTabDragControllerTestTouch
,
2358 ::testing::Values("touch"));
2359 #elif defined(USE_ASH)
2360 INSTANTIATE_TEST_CASE_P(TabDragging
,
2361 DetachToBrowserTabDragControllerTest
,
2362 ::testing::Values("mouse"));