NaCl: Update revision in DEPS, r12770 -> r12773
[chromium-blink-merge.git] / chrome / browser / ui / views / tabs / tab_drag_controller_interactive_uitest.cc
blob26d070a0c40550b49eaaf21c3ab1d841adfaf420
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"
8 #include "base/bind.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"
42 #endif
44 #if defined(USE_ASH)
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"
57 #endif
59 using content::WebContents;
61 namespace test {
63 namespace {
65 const char kTabDragControllerInteractiveUITestUserDataKey[] =
66 "TabDragControllerInteractiveUITestUserData";
68 class TabDragControllerInteractiveUITestUserData
69 : public base::SupportsUserData::Data {
70 public:
71 explicit TabDragControllerInteractiveUITestUserData(int id) : id_(id) {}
72 virtual ~TabDragControllerInteractiveUITestUserData() {}
73 int id() { return id_; }
75 private:
76 int id_;
79 } // namespace
81 class QuitDraggingObserver : public content::NotificationObserver {
82 public:
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();
93 delete this;
96 private:
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, &center);
107 return center;
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) {
121 std::string result;
122 for (int i = 0; i < model->count(); ++i) {
123 if (i != 0)
124 result += " ";
125 WebContents* contents = model->GetWebContentsAt(i);
126 TabDragControllerInteractiveUITestUserData* user_data =
127 static_cast<TabDragControllerInteractiveUITestUserData*>(
128 contents->GetUserData(
129 &kTabDragControllerInteractiveUITestUserDataKey));
130 if (user_data)
131 result += base::IntToString(user_data->id());
132 else
133 result += "?";
135 return result;
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());
148 } // namespace test
150 using test::GetCenterInScreenCoordinates;
151 using test::SetID;
152 using test::ResetIDs;
153 using test::IDString;
154 using test::GetTabStripForBrowser;
156 TabDragControllerTest::TabDragControllerTest()
157 : native_browser_list(BrowserList::GetInstance(
158 chrome::HOST_DESKTOP_TYPE_NATIVE)) {
161 TabDragControllerTest::~TabDragControllerTest() {
164 void TabDragControllerTest::StopAnimating(TabStrip* tab_strip) {
165 tab_strip->StopAnimating(true);
168 void TabDragControllerTest::AddTabAndResetBrowser(Browser* browser) {
169 AddBlankTabAndShow(browser);
170 StopAnimating(GetTabStripForBrowser(browser));
171 ResetIDs(browser->tab_strip_model(), 0);
174 Browser* TabDragControllerTest::CreateAnotherWindowBrowserAndRelayout() {
175 // Create another browser.
176 Browser* browser2 = CreateBrowser(browser()->profile());
177 ResetIDs(browser2->tab_strip_model(), 100);
179 // Resize the two windows so they're right next to each other.
180 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
181 browser()->window()->GetNativeWindow()).work_area();
182 gfx::Size half_size =
183 gfx::Size(work_area.width() / 3 - 10, work_area.height() / 2 - 10);
184 browser()->window()->SetBounds(gfx::Rect(work_area.origin(), half_size));
185 browser2->window()->SetBounds(gfx::Rect(
186 work_area.x() + half_size.width(), work_area.y(),
187 half_size.width(), half_size.height()));
188 return browser2;
191 namespace {
193 enum InputSource {
194 INPUT_SOURCE_MOUSE = 0,
195 INPUT_SOURCE_TOUCH = 1
198 int GetDetachY(TabStrip* tab_strip) {
199 return std::max(TabDragController::kTouchVerticalDetachMagnetism,
200 TabDragController::kVerticalDetachMagnetism) +
201 tab_strip->height() + 1;
204 bool GetIsDragged(Browser* browser) {
205 #if !defined(USE_ASH) || defined(OS_WIN) // TODO(win_ash)
206 return false;
207 #else
208 return ash::wm::GetWindowState(browser->window()->GetNativeWindow())->
209 is_dragged();
210 #endif
213 } // namespace
215 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
216 class ScreenEventGeneratorDelegate : public aura::test::EventGeneratorDelegate {
217 public:
218 explicit ScreenEventGeneratorDelegate(aura::Window* root_window)
219 : root_window_(root_window) {}
220 virtual ~ScreenEventGeneratorDelegate() {}
222 // EventGeneratorDelegate overrides:
223 virtual aura::RootWindow* GetRootWindowAt(
224 const gfx::Point& point) const OVERRIDE {
225 return root_window_->GetDispatcher();
228 virtual aura::client::ScreenPositionClient* GetScreenPositionClient(
229 const aura::Window* window) const OVERRIDE {
230 return aura::client::GetScreenPositionClient(root_window_);
233 private:
234 aura::Window* root_window_;
236 DISALLOW_COPY_AND_ASSIGN(ScreenEventGeneratorDelegate);
239 #endif
241 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
243 // Following classes verify a crash scenario. Specifically on Windows when focus
244 // changes it can trigger capture being lost. This was causing a crash in tab
245 // dragging as it wasn't set up to handle this scenario. These classes
246 // synthesize this scenario.
248 // Allows making ClearNativeFocus() invoke ReleaseCapture().
249 class TestDesktopBrowserFrameAura : public DesktopBrowserFrameAura {
250 public:
251 TestDesktopBrowserFrameAura(
252 BrowserFrame* browser_frame,
253 BrowserView* browser_view)
254 : DesktopBrowserFrameAura(browser_frame, browser_view),
255 release_capture_(false) {}
256 virtual ~TestDesktopBrowserFrameAura() {}
258 void ReleaseCaptureOnNextClear() {
259 release_capture_ = true;
262 virtual void ClearNativeFocus() OVERRIDE {
263 views::DesktopNativeWidgetAura::ClearNativeFocus();
264 if (release_capture_) {
265 release_capture_ = false;
266 GetWidget()->ReleaseCapture();
270 private:
271 // If true ReleaseCapture() is invoked in ClearNativeFocus().
272 bool release_capture_;
274 DISALLOW_COPY_AND_ASSIGN(TestDesktopBrowserFrameAura);
277 // Factory for creating a TestDesktopBrowserFrameAura.
278 class TestNativeBrowserFrameFactory : public NativeBrowserFrameFactory {
279 public:
280 TestNativeBrowserFrameFactory() {}
281 virtual ~TestNativeBrowserFrameFactory() {}
283 virtual NativeBrowserFrame* Create(
284 BrowserFrame* browser_frame,
285 BrowserView* browser_view) OVERRIDE {
286 return new TestDesktopBrowserFrameAura(browser_frame, browser_view);
289 private:
290 DISALLOW_COPY_AND_ASSIGN(TestNativeBrowserFrameFactory);
293 class TabDragCaptureLostTest : public TabDragControllerTest {
294 public:
295 TabDragCaptureLostTest() {
296 NativeBrowserFrameFactory::Set(new TestNativeBrowserFrameFactory);
299 private:
300 DISALLOW_COPY_AND_ASSIGN(TabDragCaptureLostTest);
303 // See description above for details.
304 IN_PROC_BROWSER_TEST_F(TabDragCaptureLostTest, ReleaseCaptureOnDrag) {
305 AddTabAndResetBrowser(browser());
307 TabStrip* tab_strip = GetTabStripForBrowser(browser());
308 gfx::Point tab_1_center(GetCenterInScreenCoordinates(tab_strip->tab_at(1)));
309 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_1_center) &&
310 ui_test_utils::SendMouseEventsSync(
311 ui_controls::LEFT, ui_controls::DOWN));
312 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
313 TestDesktopBrowserFrameAura* frame =
314 static_cast<TestDesktopBrowserFrameAura*>(
315 BrowserView::GetBrowserViewForBrowser(browser())->GetWidget()->
316 native_widget_private());
317 // Invoke ReleaseCaptureOnDrag() so that when the drag happens and focus
318 // changes capture is released and the drag cancels.
319 frame->ReleaseCaptureOnNextClear();
320 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center));
321 EXPECT_FALSE(tab_strip->IsDragSessionActive());
324 IN_PROC_BROWSER_TEST_F(TabDragControllerTest, GestureEndShouldEndDragTest) {
325 AddTabAndResetBrowser(browser());
327 TabStrip* tab_strip = GetTabStripForBrowser(browser());
328 TabStripModel* model = browser()->tab_strip_model();
330 Tab* tab1 = tab_strip->tab_at(1);
331 gfx::Point tab_1_center(tab1->width() / 2, tab1->height() / 2);
333 ui::GestureEvent gesture_begin(ui::ET_GESTURE_BEGIN, tab_1_center.x(),
334 tab_1_center.x(), 0, base::TimeDelta(),
335 ui::GestureEventDetails(ui::ET_GESTURE_BEGIN, 0.0f, 0.0f), 0);
336 tab_strip->MaybeStartDrag(tab1, gesture_begin,
337 tab_strip->GetSelectionModel());
338 //tab_strip->tab_at(1)->OnGestureEvent(&gesture_begin);
339 EXPECT_TRUE(TabDragController::IsActive());
341 ui::GestureEvent gesture_end(ui::ET_GESTURE_END, tab_1_center.x(),
342 tab_1_center.x(), 0, base::TimeDelta(),
343 ui::GestureEventDetails(ui::ET_GESTURE_END, 0.0f, 0.0f), 0);
344 tab_strip->OnGestureEvent(&gesture_end);
345 EXPECT_FALSE(TabDragController::IsActive());
346 EXPECT_FALSE(tab_strip->IsDragSessionActive());
349 #endif
351 class DetachToBrowserTabDragControllerTest
352 : public TabDragControllerTest,
353 public ::testing::WithParamInterface<const char*> {
354 public:
355 DetachToBrowserTabDragControllerTest() {}
357 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
358 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
359 if (!docked_windows_enabled()) {
360 CommandLine::ForCurrentProcess()->AppendSwitch(
361 ash::switches::kAshDisableDockedWindows);
363 #endif
366 virtual void SetUpOnMainThread() OVERRIDE {
367 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
368 event_generator_.reset(new aura::test::EventGenerator(
369 ash::Shell::GetPrimaryRootWindow()));
370 #endif
373 InputSource input_source() const {
374 return strstr(GetParam(), "mouse") ?
375 INPUT_SOURCE_MOUSE : INPUT_SOURCE_TOUCH;
378 bool docked_windows_enabled() const {
379 return (strstr(GetParam(), "docked") != NULL);
382 // Set root window from a point in screen coordinates
383 void SetEventGeneratorRootWindow(const gfx::Point& point) {
384 if (input_source() == INPUT_SOURCE_MOUSE)
385 return;
386 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
387 event_generator_.reset(new aura::test::EventGenerator(
388 new ScreenEventGeneratorDelegate(ash::wm::GetRootWindowAt(point))));
389 #endif
392 // The following methods update one of the mouse or touch input depending upon
393 // the InputSource.
394 bool PressInput(const gfx::Point& location) {
395 if (input_source() == INPUT_SOURCE_MOUSE) {
396 return ui_test_utils::SendMouseMoveSync(location) &&
397 ui_test_utils::SendMouseEventsSync(
398 ui_controls::LEFT, ui_controls::DOWN);
400 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
401 event_generator_->set_current_location(location);
402 event_generator_->PressTouch();
403 #else
404 NOTREACHED();
405 #endif
406 return true;
409 bool PressInput2() {
410 // Second touch input is only used for touch sequence tests.
411 EXPECT_EQ(INPUT_SOURCE_TOUCH, input_source());
412 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
413 event_generator_->set_current_location(
414 event_generator_->current_location());
415 event_generator_->PressTouchId(1);
416 #else
417 NOTREACHED();
418 #endif
419 return true;
422 bool DragInputTo(const gfx::Point& location) {
423 if (input_source() == INPUT_SOURCE_MOUSE)
424 return ui_test_utils::SendMouseMoveSync(location);
425 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
426 event_generator_->MoveTouch(location);
427 #else
428 NOTREACHED();
429 #endif
430 return true;
433 bool DragInputToAsync(const gfx::Point& location) {
434 if (input_source() == INPUT_SOURCE_MOUSE)
435 return ui_controls::SendMouseMove(location.x(), location.y());
436 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
437 event_generator_->MoveTouch(location);
438 #else
439 NOTREACHED();
440 #endif
441 return true;
444 bool DragInputToNotifyWhenDone(int x,
445 int y,
446 const base::Closure& task) {
447 if (input_source() == INPUT_SOURCE_MOUSE)
448 return ui_controls::SendMouseMoveNotifyWhenDone(x, y, task);
449 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
450 base::MessageLoop::current()->PostTask(FROM_HERE, task);
451 event_generator_->MoveTouch(gfx::Point(x, y));
452 #else
453 NOTREACHED();
454 #endif
455 return true;
458 bool DragInputToDelayedNotifyWhenDone(int x,
459 int y,
460 const base::Closure& task,
461 base::TimeDelta delay) {
462 if (input_source() == INPUT_SOURCE_MOUSE)
463 return ui_controls::SendMouseMoveNotifyWhenDone(x, y, task);
464 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
465 base::MessageLoop::current()->PostDelayedTask(FROM_HERE, task, delay);
466 event_generator_->MoveTouch(gfx::Point(x, y));
467 #else
468 NOTREACHED();
469 #endif
470 return true;
473 bool DragInput2ToNotifyWhenDone(int x,
474 int y,
475 const base::Closure& task) {
476 if (input_source() == INPUT_SOURCE_MOUSE)
477 return ui_controls::SendMouseMoveNotifyWhenDone(x, y, task);
478 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
479 base::MessageLoop::current()->PostTask(FROM_HERE, task);
480 event_generator_->MoveTouchId(gfx::Point(x, y), 1);
481 #else
482 NOTREACHED();
483 #endif
484 return true;
487 bool ReleaseInput() {
488 if (input_source() == INPUT_SOURCE_MOUSE) {
489 return ui_test_utils::SendMouseEventsSync(
490 ui_controls::LEFT, ui_controls::UP);
492 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
493 event_generator_->ReleaseTouch();
494 #else
495 NOTREACHED();
496 #endif
497 return true;
500 bool ReleaseInput2() {
501 if (input_source() == INPUT_SOURCE_MOUSE) {
502 return ui_test_utils::SendMouseEventsSync(
503 ui_controls::LEFT, ui_controls::UP);
505 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
506 event_generator_->ReleaseTouchId(1);
507 #else
508 NOTREACHED();
509 #endif
510 return true;
513 bool ReleaseMouseAsync() {
514 return input_source() == INPUT_SOURCE_MOUSE &&
515 ui_controls::SendMouseEvents(ui_controls::LEFT, ui_controls::UP);
518 void QuitWhenNotDragging() {
519 if (input_source() == INPUT_SOURCE_MOUSE) {
520 // Schedule observer to quit message loop when done dragging. This has to
521 // be async so the message loop can run.
522 test::QuitWhenNotDraggingImpl();
523 base::MessageLoop::current()->Run();
524 } else {
525 // Touch events are sync, so we know we're not in a drag session. But some
526 // tests rely on the browser fully closing, which is async. So, run all
527 // pending tasks.
528 base::RunLoop run_loop;
529 run_loop.RunUntilIdle();
533 void AddBlankTabAndShow(Browser* browser) {
534 InProcessBrowserTest::AddBlankTabAndShow(browser);
537 Browser* browser() const { return InProcessBrowserTest::browser(); }
539 private:
540 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
541 scoped_ptr<aura::test::EventGenerator> event_generator_;
542 #endif
544 DISALLOW_COPY_AND_ASSIGN(DetachToBrowserTabDragControllerTest);
547 // Creates a browser with two tabs, drags the second to the first.
548 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, DragInSameWindow) {
549 // TODO(sky): this won't work with touch as it requires a long press.
550 if (input_source() == INPUT_SOURCE_TOUCH) {
551 VLOG(1) << "Test is DISABLED for touch input.";
552 return;
555 AddTabAndResetBrowser(browser());
557 TabStrip* tab_strip = GetTabStripForBrowser(browser());
558 TabStripModel* model = browser()->tab_strip_model();
560 gfx::Point tab_1_center(GetCenterInScreenCoordinates(tab_strip->tab_at(1)));
561 ASSERT_TRUE(PressInput(tab_1_center));
562 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
563 ASSERT_TRUE(DragInputTo(tab_0_center));
564 ASSERT_TRUE(ReleaseInput());
565 EXPECT_EQ("1 0", IDString(model));
566 EXPECT_FALSE(TabDragController::IsActive());
567 EXPECT_FALSE(tab_strip->IsDragSessionActive());
569 // The tab strip should no longer have capture because the drag was ended and
570 // mouse/touch was released.
571 EXPECT_FALSE(tab_strip->GetWidget()->HasCapture());
574 namespace {
576 // Invoked from the nested message loop.
577 void DragToSeparateWindowStep2(DetachToBrowserTabDragControllerTest* test,
578 TabStrip* not_attached_tab_strip,
579 TabStrip* target_tab_strip) {
580 ASSERT_FALSE(not_attached_tab_strip->IsDragSessionActive());
581 ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
582 ASSERT_TRUE(TabDragController::IsActive());
584 // Drag to target_tab_strip. This should stop the nested loop from dragging
585 // the window.
586 gfx::Point target_point(target_tab_strip->width() -1,
587 target_tab_strip->height() / 2);
588 views::View::ConvertPointToScreen(target_tab_strip, &target_point);
589 ASSERT_TRUE(test->DragInputToAsync(target_point));
592 } // namespace
594 #if defined(OS_CHROMEOS)
595 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
596 // compositor. crbug.com/331924
597 #define MAYBE_DragToSeparateWindow DISABLED_DragToSeparateWindow
598 #else
599 #define MAYBE_DragToSeparateWindow DragToSeparateWindow
600 #endif
601 // Creates two browsers, drags from first into second.
602 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
603 MAYBE_DragToSeparateWindow) {
604 TabStrip* tab_strip = GetTabStripForBrowser(browser());
606 // Add another tab to browser().
607 AddTabAndResetBrowser(browser());
609 // Create another browser.
610 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
611 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
613 // Move to the first tab and drag it enough so that it detaches, but not
614 // enough that it attaches to browser2.
615 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
616 ASSERT_TRUE(PressInput(tab_0_center));
617 ASSERT_TRUE(DragInputToNotifyWhenDone(
618 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
619 base::Bind(&DragToSeparateWindowStep2,
620 this, tab_strip, tab_strip2)));
621 QuitWhenNotDragging();
623 // Should now be attached to tab_strip2.
624 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
625 ASSERT_FALSE(tab_strip->IsDragSessionActive());
626 ASSERT_TRUE(TabDragController::IsActive());
627 EXPECT_FALSE(GetIsDragged(browser()));
629 // Release mouse or touch, stopping the drag session.
630 ASSERT_TRUE(ReleaseInput());
631 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
632 ASSERT_FALSE(tab_strip->IsDragSessionActive());
633 ASSERT_FALSE(TabDragController::IsActive());
634 EXPECT_EQ("100 0", IDString(browser2->tab_strip_model()));
635 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
636 EXPECT_FALSE(GetIsDragged(browser2));
638 // Both windows should not be maximized
639 EXPECT_FALSE(browser()->window()->IsMaximized());
640 EXPECT_FALSE(browser2->window()->IsMaximized());
642 // The tab strip should no longer have capture because the drag was ended and
643 // mouse/touch was released.
644 EXPECT_FALSE(tab_strip->GetWidget()->HasCapture());
645 EXPECT_FALSE(tab_strip2->GetWidget()->HasCapture());
648 namespace {
650 void DetachToOwnWindowStep2(DetachToBrowserTabDragControllerTest* test) {
651 if (test->input_source() == INPUT_SOURCE_TOUCH)
652 ASSERT_TRUE(test->ReleaseInput());
655 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
656 bool IsWindowPositionManaged(aura::Window* window) {
657 return ash::wm::GetWindowState(window)->window_position_managed();
659 bool HasUserChangedWindowPositionOrSize(aura::Window* window) {
660 return ash::wm::GetWindowState(window)->bounds_changed_by_user();
662 #else
663 bool IsWindowPositionManaged(gfx::NativeWindow window) {
664 return true;
666 bool HasUserChangedWindowPositionOrSize(gfx::NativeWindow window) {
667 return false;
669 #endif
671 } // namespace
673 #if defined(OS_CHROMEOS)
674 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
675 // compositor. crbug.com/331924
676 #define MAYBE_DetachToOwnWindow DISABLED_DetachToOwnWindow
677 #else
678 #define MAYBE_DetachToOwnWindow DetachToOwnWindow
679 #endif
680 // Drags from browser to separate window and releases mouse.
681 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
682 MAYBE_DetachToOwnWindow) {
683 const gfx::Rect initial_bounds(browser()->window()->GetBounds());
684 // Add another tab.
685 AddTabAndResetBrowser(browser());
686 TabStrip* tab_strip = GetTabStripForBrowser(browser());
688 // Move to the first tab and drag it enough so that it detaches.
689 gfx::Point tab_0_center(
690 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
691 ASSERT_TRUE(PressInput(tab_0_center));
692 ASSERT_TRUE(DragInputToNotifyWhenDone(
693 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
694 base::Bind(&DetachToOwnWindowStep2, this)));
695 if (input_source() == INPUT_SOURCE_MOUSE) {
696 ASSERT_TRUE(ReleaseMouseAsync());
697 QuitWhenNotDragging();
700 // Should no longer be dragging.
701 ASSERT_FALSE(tab_strip->IsDragSessionActive());
702 ASSERT_FALSE(TabDragController::IsActive());
704 // There should now be another browser.
705 ASSERT_EQ(2u, native_browser_list->size());
706 Browser* new_browser = native_browser_list->get(1);
707 ASSERT_TRUE(new_browser->window()->IsActive());
708 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
709 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
711 EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
712 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
714 // The bounds of the initial window should not have changed.
715 EXPECT_EQ(initial_bounds.ToString(),
716 browser()->window()->GetBounds().ToString());
718 EXPECT_FALSE(GetIsDragged(browser()));
719 EXPECT_FALSE(GetIsDragged(new_browser));
720 // After this both windows should still be manageable.
721 EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
722 EXPECT_TRUE(IsWindowPositionManaged(
723 new_browser->window()->GetNativeWindow()));
725 // Both windows should not be maximized
726 EXPECT_FALSE(browser()->window()->IsMaximized());
727 EXPECT_FALSE(new_browser->window()->IsMaximized());
729 // The tab strip should no longer have capture because the drag was ended and
730 // mouse/touch was released.
731 EXPECT_FALSE(tab_strip->GetWidget()->HasCapture());
732 EXPECT_FALSE(tab_strip2->GetWidget()->HasCapture());
735 #if defined(OS_CHROMEOS)
736 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
737 // compositor. crbug.com/331924
738 #define MAYBE_DetachToOwnWindowFromMaximizedWindow \
739 DISABLED_DetachToOwnWindowFromMaximizedWindow
740 #else
741 #define MAYBE_DetachToOwnWindowFromMaximizedWindow \
742 DetachToOwnWindowFromMaximizedWindow
743 #endif
744 // Drags from browser to a separate window and releases mouse.
745 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
746 MAYBE_DetachToOwnWindowFromMaximizedWindow) {
747 // Maximize the initial browser window.
748 browser()->window()->Maximize();
749 ASSERT_TRUE(browser()->window()->IsMaximized());
751 // Add another tab.
752 AddTabAndResetBrowser(browser());
753 TabStrip* tab_strip = GetTabStripForBrowser(browser());
755 // Move to the first tab and drag it enough so that it detaches.
756 gfx::Point tab_0_center(
757 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
758 ASSERT_TRUE(PressInput(tab_0_center));
759 ASSERT_TRUE(DragInputToNotifyWhenDone(
760 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
761 base::Bind(&DetachToOwnWindowStep2, this)));
762 if (input_source() == INPUT_SOURCE_MOUSE) {
763 ASSERT_TRUE(ReleaseMouseAsync());
764 QuitWhenNotDragging();
767 // Should no longer be dragging.
768 ASSERT_FALSE(tab_strip->IsDragSessionActive());
769 ASSERT_FALSE(TabDragController::IsActive());
771 // There should now be another browser.
772 ASSERT_EQ(2u, native_browser_list->size());
773 Browser* new_browser = native_browser_list->get(1);
774 ASSERT_TRUE(new_browser->window()->IsActive());
775 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
776 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
778 EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
779 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
781 // The bounds of the initial window should not have changed.
782 EXPECT_TRUE(browser()->window()->IsMaximized());
784 EXPECT_FALSE(GetIsDragged(browser()));
785 EXPECT_FALSE(GetIsDragged(new_browser));
786 // After this both windows should still be manageable.
787 EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
788 EXPECT_TRUE(IsWindowPositionManaged(
789 new_browser->window()->GetNativeWindow()));
791 // The new window should be maximized.
792 EXPECT_TRUE(new_browser->window()->IsMaximized());
795 // Deletes a tab being dragged before the user moved enough to start a drag.
796 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
797 DeleteBeforeStartedDragging) {
798 // Add another tab.
799 AddTabAndResetBrowser(browser());
800 TabStrip* tab_strip = GetTabStripForBrowser(browser());
802 // Click on the first tab, but don't move it.
803 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
804 ASSERT_TRUE(PressInput(tab_0_center));
806 // Should be dragging.
807 ASSERT_TRUE(tab_strip->IsDragSessionActive());
808 ASSERT_TRUE(TabDragController::IsActive());
810 // Delete the tab being dragged.
811 delete browser()->tab_strip_model()->GetWebContentsAt(0);
813 // Should have canceled dragging.
814 ASSERT_FALSE(tab_strip->IsDragSessionActive());
815 ASSERT_FALSE(TabDragController::IsActive());
817 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
818 EXPECT_FALSE(GetIsDragged(browser()));
821 #if defined(OS_CHROMEOS)
822 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
823 // compositor. crbug.com/331924
824 #define MAYBE_DeleteTabWhileAttached DISABLED_DeleteTabWhileAttached
825 #else
826 #define MAYBE_DeleteTabWhileAttached DeleteTabWhileAttached
827 #endif
828 // Deletes a tab being dragged while still attached.
829 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
830 MAYBE_DeleteTabWhileAttached) {
831 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
832 // compositor. crbug.com/331924
833 if (input_source() == INPUT_SOURCE_MOUSE) {
834 VLOG(1) << "Test is DISABLED for mouse input.";
835 return;
838 // Add another tab.
839 AddTabAndResetBrowser(browser());
840 TabStrip* tab_strip = GetTabStripForBrowser(browser());
842 // Click on the first tab and move it enough so that it starts dragging but is
843 // still attached.
844 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
845 ASSERT_TRUE(PressInput(tab_0_center));
846 ASSERT_TRUE(DragInputTo(
847 gfx::Point(tab_0_center.x() + 20, tab_0_center.y())));
849 // Should be dragging.
850 ASSERT_TRUE(tab_strip->IsDragSessionActive());
851 ASSERT_TRUE(TabDragController::IsActive());
853 // Delete the tab being dragged.
854 delete browser()->tab_strip_model()->GetWebContentsAt(0);
856 // Should have canceled dragging.
857 ASSERT_FALSE(tab_strip->IsDragSessionActive());
858 ASSERT_FALSE(TabDragController::IsActive());
860 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
862 EXPECT_FALSE(GetIsDragged(browser()));
865 namespace {
867 void DeleteWhileDetachedStep2(WebContents* tab) {
868 delete tab;
871 } // namespace
873 #if defined(OS_CHROMEOS)
874 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
875 // compositor. crbug.com/331924
876 #define MAYBE_DeleteTabWhileDetached DISABLED_DeleteTabWhileDetached
877 #else
878 #define MAYBE_DeleteTabWhileDetached DeleteTabWhileDetached
879 #endif
880 // Deletes a tab being dragged after dragging a tab so that a new window is
881 // created.
882 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
883 MAYBE_DeleteTabWhileDetached) {
884 // Add another tab.
885 AddTabAndResetBrowser(browser());
886 TabStrip* tab_strip = GetTabStripForBrowser(browser());
888 // Move to the first tab and drag it enough so that it detaches.
889 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
890 WebContents* to_delete =
891 browser()->tab_strip_model()->GetWebContentsAt(0);
892 ASSERT_TRUE(PressInput(tab_0_center));
893 ASSERT_TRUE(DragInputToNotifyWhenDone(
894 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
895 base::Bind(&DeleteWhileDetachedStep2, to_delete)));
896 QuitWhenNotDragging();
898 // Should not be dragging.
899 ASSERT_FALSE(tab_strip->IsDragSessionActive());
900 ASSERT_FALSE(TabDragController::IsActive());
902 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
904 EXPECT_FALSE(GetIsDragged(browser()));
907 namespace {
909 void DeleteSourceDetachedStep2(WebContents* tab,
910 const BrowserList* browser_list) {
911 ASSERT_EQ(2u, browser_list->size());
912 Browser* new_browser = browser_list->get(1);
913 // This ends up closing the source window.
914 delete tab;
915 // Cancel the drag.
916 ui_controls::SendKeyPress(new_browser->window()->GetNativeWindow(),
917 ui::VKEY_ESCAPE, false, false, false, false);
920 } // namespace
922 #if defined(OS_CHROMEOS)
923 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
924 // compositor. crbug.com/331924
925 #define MAYBE_DeleteSourceDetached DISABLED_DeleteSourceDetached
926 #else
927 #define MAYBE_DeleteSourceDetached DeleteSourceDetached
928 #endif
929 // Detaches a tab and while detached deletes a tab from the source so that the
930 // source window closes then presses escape to cancel the drag.
931 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
932 MAYBE_DeleteSourceDetached) {
933 // Add another tab.
934 AddTabAndResetBrowser(browser());
935 TabStrip* tab_strip = GetTabStripForBrowser(browser());
937 // Move to the first tab and drag it enough so that it detaches.
938 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
939 WebContents* to_delete = browser()->tab_strip_model()->GetWebContentsAt(1);
940 ASSERT_TRUE(PressInput(tab_0_center));
941 ASSERT_TRUE(DragInputToNotifyWhenDone(
942 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
943 base::Bind(&DeleteSourceDetachedStep2, to_delete, native_browser_list)));
944 QuitWhenNotDragging();
946 // Should not be dragging.
947 ASSERT_EQ(1u, native_browser_list->size());
948 Browser* new_browser = native_browser_list->get(0);
949 ASSERT_FALSE(GetTabStripForBrowser(new_browser)->IsDragSessionActive());
950 ASSERT_FALSE(TabDragController::IsActive());
952 EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
954 EXPECT_FALSE(GetIsDragged(new_browser));
956 // Remaining browser window should not be maximized
957 EXPECT_FALSE(new_browser->window()->IsMaximized());
960 namespace {
962 void PressEscapeWhileDetachedStep2(const BrowserList* browser_list) {
963 ASSERT_EQ(2u, browser_list->size());
964 Browser* new_browser = browser_list->get(1);
965 ui_controls::SendKeyPress(
966 new_browser->window()->GetNativeWindow(), ui::VKEY_ESCAPE, false, false,
967 false, false);
970 } // namespace
972 #if defined(OS_CHROMEOS)
973 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
974 // compositor. crbug.com/331924
975 #define MAYBE_PressEscapeWhileDetached DISABLED_PressEscapeWhileDetached
976 #else
977 #define MAYBE_PressEscapeWhileDetached PressEscapeWhileDetached
978 #endif
979 // This is disabled until NativeViewHost::Detach really detaches.
980 // Detaches a tab and while detached presses escape to revert the drag.
981 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
982 MAYBE_PressEscapeWhileDetached) {
983 // Add another tab.
984 AddTabAndResetBrowser(browser());
985 TabStrip* tab_strip = GetTabStripForBrowser(browser());
987 // Move to the first tab and drag it enough so that it detaches.
988 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
989 ASSERT_TRUE(PressInput(tab_0_center));
990 ASSERT_TRUE(DragInputToNotifyWhenDone(
991 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
992 base::Bind(&PressEscapeWhileDetachedStep2, native_browser_list)));
993 QuitWhenNotDragging();
995 // Should not be dragging.
996 ASSERT_FALSE(tab_strip->IsDragSessionActive());
997 ASSERT_FALSE(TabDragController::IsActive());
999 // And there should only be one window.
1000 EXPECT_EQ(1u, native_browser_list->size());
1002 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
1004 // Remaining browser window should not be maximized
1005 EXPECT_FALSE(browser()->window()->IsMaximized());
1007 // The tab strip should no longer have capture because the drag was ended and
1008 // mouse/touch was released.
1009 EXPECT_FALSE(tab_strip->GetWidget()->HasCapture());
1012 namespace {
1014 void DragAllStep2(DetachToBrowserTabDragControllerTest* test,
1015 const BrowserList* browser_list) {
1016 // Should only be one window.
1017 ASSERT_EQ(1u, browser_list->size());
1018 if (test->input_source() == INPUT_SOURCE_TOUCH) {
1019 ASSERT_TRUE(test->ReleaseInput());
1020 } else {
1021 ASSERT_TRUE(test->ReleaseMouseAsync());
1025 } // namespace
1027 #if defined(OS_CHROMEOS)
1028 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1029 // compositor. crbug.com/331924
1030 #define MAYBE_DragAll DISABLED_DragAll
1031 #else
1032 #define MAYBE_DragAll DragAll
1033 #endif
1034 // Selects multiple tabs and starts dragging the window.
1035 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, MAYBE_DragAll) {
1036 // Add another tab.
1037 AddTabAndResetBrowser(browser());
1038 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1039 browser()->tab_strip_model()->AddTabAtToSelection(0);
1040 browser()->tab_strip_model()->AddTabAtToSelection(1);
1042 // Move to the first tab and drag it enough so that it would normally
1043 // detach.
1044 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1045 ASSERT_TRUE(PressInput(tab_0_center));
1046 ASSERT_TRUE(DragInputToNotifyWhenDone(
1047 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1048 base::Bind(&DragAllStep2, this, native_browser_list)));
1049 QuitWhenNotDragging();
1051 // Should not be dragging.
1052 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1053 ASSERT_FALSE(TabDragController::IsActive());
1055 // And there should only be one window.
1056 EXPECT_EQ(1u, native_browser_list->size());
1058 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
1060 EXPECT_FALSE(GetIsDragged(browser()));
1062 // Remaining browser window should not be maximized
1063 EXPECT_FALSE(browser()->window()->IsMaximized());
1066 namespace {
1068 // Invoked from the nested message loop.
1069 void DragAllToSeparateWindowStep2(DetachToBrowserTabDragControllerTest* test,
1070 TabStrip* attached_tab_strip,
1071 TabStrip* target_tab_strip,
1072 const BrowserList* browser_list) {
1073 ASSERT_TRUE(attached_tab_strip->IsDragSessionActive());
1074 ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
1075 ASSERT_TRUE(TabDragController::IsActive());
1076 ASSERT_EQ(2u, browser_list->size());
1078 // Drag to target_tab_strip. This should stop the nested loop from dragging
1079 // the window.
1080 gfx::Point target_point(target_tab_strip->width() - 1,
1081 target_tab_strip->height() / 2);
1082 views::View::ConvertPointToScreen(target_tab_strip, &target_point);
1083 ASSERT_TRUE(test->DragInputToAsync(target_point));
1086 } // namespace
1088 #if defined(OS_CHROMEOS)
1089 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1090 // compositor. crbug.com/331924
1091 #define MAYBE_DragAllToSeparateWindow DISABLED_DragAllToSeparateWindow
1092 #else
1093 #define MAYBE_DragAllToSeparateWindow DragAllToSeparateWindow
1094 #endif
1095 // Creates two browsers, selects all tabs in first and drags into second.
1096 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1097 MAYBE_DragAllToSeparateWindow) {
1098 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1100 // Add another tab to browser().
1101 AddTabAndResetBrowser(browser());
1103 // Create another browser.
1104 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
1105 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1107 browser()->tab_strip_model()->AddTabAtToSelection(0);
1108 browser()->tab_strip_model()->AddTabAtToSelection(1);
1110 // Move to the first tab and drag it enough so that it detaches, but not
1111 // enough that it attaches to browser2.
1112 gfx::Point tab_0_center(
1113 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1114 ASSERT_TRUE(PressInput(tab_0_center));
1115 ASSERT_TRUE(DragInputToNotifyWhenDone(
1116 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1117 base::Bind(&DragAllToSeparateWindowStep2, this, tab_strip, tab_strip2,
1118 native_browser_list)));
1119 QuitWhenNotDragging();
1121 // Should now be attached to tab_strip2.
1122 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1123 ASSERT_TRUE(TabDragController::IsActive());
1124 ASSERT_EQ(1u, native_browser_list->size());
1126 // Release the mouse, stopping the drag session.
1127 ASSERT_TRUE(ReleaseInput());
1128 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1129 ASSERT_FALSE(TabDragController::IsActive());
1130 EXPECT_EQ("100 0 1", IDString(browser2->tab_strip_model()));
1132 EXPECT_FALSE(GetIsDragged(browser2));
1134 // Remaining browser window should not be maximized
1135 EXPECT_FALSE(browser2->window()->IsMaximized());
1138 namespace {
1140 // Invoked from the nested message loop.
1141 void DragAllToSeparateWindowAndCancelStep2(
1142 DetachToBrowserTabDragControllerTest* test,
1143 TabStrip* attached_tab_strip,
1144 TabStrip* target_tab_strip,
1145 const BrowserList* browser_list) {
1146 ASSERT_TRUE(attached_tab_strip->IsDragSessionActive());
1147 ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
1148 ASSERT_TRUE(TabDragController::IsActive());
1149 ASSERT_EQ(2u, browser_list->size());
1151 // Drag to target_tab_strip. This should stop the nested loop from dragging
1152 // the window.
1153 gfx::Point target_point(target_tab_strip->width() - 1,
1154 target_tab_strip->height() / 2);
1155 views::View::ConvertPointToScreen(target_tab_strip, &target_point);
1156 ASSERT_TRUE(test->DragInputToAsync(target_point));
1159 } // namespace
1161 #if defined(OS_CHROMEOS)
1162 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1163 // compositor. crbug.com/331924
1164 #define MAYBE_DragAllToSeparateWindowAndCancel \
1165 DISABLED_DragAllToSeparateWindowAndCancel
1166 #else
1167 #define MAYBE_DragAllToSeparateWindowAndCancel DragAllToSeparateWindowAndCancel
1168 #endif
1169 // Creates two browsers, selects all tabs in first, drags into second, then hits
1170 // escape.
1171 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1172 MAYBE_DragAllToSeparateWindowAndCancel) {
1173 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1175 // Add another tab to browser().
1176 AddTabAndResetBrowser(browser());
1178 // Create another browser.
1179 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
1180 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1182 browser()->tab_strip_model()->AddTabAtToSelection(0);
1183 browser()->tab_strip_model()->AddTabAtToSelection(1);
1185 // Move to the first tab and drag it enough so that it detaches, but not
1186 // enough that it attaches to browser2.
1187 gfx::Point tab_0_center(
1188 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1189 ASSERT_TRUE(PressInput(tab_0_center));
1190 ASSERT_TRUE(DragInputToNotifyWhenDone(
1191 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1192 base::Bind(&DragAllToSeparateWindowAndCancelStep2, this,
1193 tab_strip, tab_strip2, native_browser_list)));
1194 QuitWhenNotDragging();
1196 // Should now be attached to tab_strip2.
1197 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1198 ASSERT_TRUE(TabDragController::IsActive());
1199 ASSERT_EQ(1u, native_browser_list->size());
1201 // Cancel the drag.
1202 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
1203 browser2, ui::VKEY_ESCAPE, false, false, false, false));
1205 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1206 ASSERT_FALSE(TabDragController::IsActive());
1207 EXPECT_EQ("100 0 1", IDString(browser2->tab_strip_model()));
1209 // browser() will have been destroyed, but browser2 should remain.
1210 ASSERT_EQ(1u, native_browser_list->size());
1212 EXPECT_FALSE(GetIsDragged(browser2));
1214 // Remaining browser window should not be maximized
1215 EXPECT_FALSE(browser2->window()->IsMaximized());
1218 #if defined(OS_CHROMEOS)
1219 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1220 // compositor. crbug.com/331924
1221 #define MAYBE_DragDirectlyToSecondWindow DISABLED_DragDirectlyToSecondWindow
1222 #else
1223 #define MAYBE_DragDirectlyToSecondWindow DragDirectlyToSecondWindow
1224 #endif
1225 // Creates two browsers, drags from first into the second in such a way that
1226 // no detaching should happen.
1227 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1228 MAYBE_DragDirectlyToSecondWindow) {
1229 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1231 // Add another tab to browser().
1232 AddTabAndResetBrowser(browser());
1234 // Create another browser.
1235 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
1236 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1238 // Move the tabstrip down enough so that we can detach.
1239 gfx::Rect bounds(browser2->window()->GetBounds());
1240 bounds.Offset(0, 100);
1241 browser2->window()->SetBounds(bounds);
1243 // Move to the first tab and drag it enough so that it detaches, but not
1244 // enough that it attaches to browser2.
1245 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1246 ASSERT_TRUE(PressInput(tab_0_center));
1248 gfx::Point b2_location(5, 0);
1249 views::View::ConvertPointToScreen(tab_strip2, &b2_location);
1250 ASSERT_TRUE(DragInputTo(b2_location));
1252 // Should now be attached to tab_strip2.
1253 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1254 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1255 ASSERT_TRUE(TabDragController::IsActive());
1257 // Release the mouse, stopping the drag session.
1258 ASSERT_TRUE(ReleaseInput());
1259 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1260 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1261 ASSERT_FALSE(TabDragController::IsActive());
1262 EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1263 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1265 EXPECT_FALSE(GetIsDragged(browser()));
1266 EXPECT_FALSE(GetIsDragged(browser2));
1268 // Both windows should not be maximized
1269 EXPECT_FALSE(browser()->window()->IsMaximized());
1270 EXPECT_FALSE(browser2->window()->IsMaximized());
1273 #if defined(OS_CHROMEOS)
1274 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1275 // compositor. crbug.com/331924
1276 #define MAYBE_DragSingleTabToSeparateWindow \
1277 DISABLED_DragSingleTabToSeparateWindow
1278 #else
1279 #define MAYBE_DragSingleTabToSeparateWindow DragSingleTabToSeparateWindow
1280 #endif
1281 // Creates two browsers, the first browser has a single tab and drags into the
1282 // second browser.
1283 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1284 MAYBE_DragSingleTabToSeparateWindow) {
1285 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1287 ResetIDs(browser()->tab_strip_model(), 0);
1289 // Create another browser.
1290 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
1291 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1292 const gfx::Rect initial_bounds(browser2->window()->GetBounds());
1294 // Move to the first tab and drag it enough so that it detaches, but not
1295 // enough that it attaches to browser2.
1296 gfx::Point tab_0_center(
1297 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1298 ASSERT_TRUE(PressInput(tab_0_center));
1299 ASSERT_TRUE(DragInputToNotifyWhenDone(
1300 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1301 base::Bind(&DragAllToSeparateWindowStep2, this, tab_strip, tab_strip2,
1302 native_browser_list)));
1303 QuitWhenNotDragging();
1305 // Should now be attached to tab_strip2.
1306 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1307 ASSERT_TRUE(TabDragController::IsActive());
1308 ASSERT_EQ(1u, native_browser_list->size());
1310 // Release the mouse, stopping the drag session.
1311 ASSERT_TRUE(ReleaseInput());
1312 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1313 ASSERT_FALSE(TabDragController::IsActive());
1314 EXPECT_EQ("100 0", IDString(browser2->tab_strip_model()));
1316 EXPECT_FALSE(GetIsDragged(browser2));
1318 // Remaining browser window should not be maximized
1319 EXPECT_FALSE(browser2->window()->IsMaximized());
1321 // Make sure that the window is still managed and not user moved.
1322 EXPECT_TRUE(IsWindowPositionManaged(browser2->window()->GetNativeWindow()));
1323 EXPECT_FALSE(HasUserChangedWindowPositionOrSize(
1324 browser2->window()->GetNativeWindow()));
1325 // Also make sure that the drag to window position has not changed.
1326 EXPECT_EQ(initial_bounds.ToString(),
1327 browser2->window()->GetBounds().ToString());
1330 namespace {
1332 // Invoked from the nested message loop.
1333 void CancelOnNewTabWhenDraggingStep2(
1334 DetachToBrowserTabDragControllerTest* test,
1335 const BrowserList* browser_list) {
1336 ASSERT_TRUE(TabDragController::IsActive());
1337 ASSERT_EQ(2u, browser_list->size());
1339 // Add another tab. This should trigger exiting the nested loop.
1340 test->AddBlankTabAndShow(browser_list->GetLastActive());
1343 } // namespace
1345 #if defined(OS_CHROMEOS)
1346 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1347 // compositor. crbug.com/331924
1348 #define MAYBE_CancelOnNewTabWhenDragging DISABLED_CancelOnNewTabWhenDragging
1349 #else
1350 #define MAYBE_CancelOnNewTabWhenDragging CancelOnNewTabWhenDragging
1351 #endif
1352 // Adds another tab, detaches into separate window, adds another tab and
1353 // verifies the run loop ends.
1354 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1355 MAYBE_CancelOnNewTabWhenDragging) {
1356 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1358 // Add another tab to browser().
1359 AddTabAndResetBrowser(browser());
1361 // Move to the first tab and drag it enough so that it detaches.
1362 gfx::Point tab_0_center(
1363 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1364 ASSERT_TRUE(PressInput(tab_0_center));
1365 ASSERT_TRUE(DragInputToNotifyWhenDone(
1366 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1367 base::Bind(&CancelOnNewTabWhenDraggingStep2, this, native_browser_list)));
1368 QuitWhenNotDragging();
1370 // Should be two windows and not dragging.
1371 ASSERT_FALSE(TabDragController::IsActive());
1372 ASSERT_EQ(2u, native_browser_list->size());
1373 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
1374 EXPECT_FALSE(GetIsDragged(*it));
1375 // Should not be maximized
1376 EXPECT_FALSE(it->window()->IsMaximized());
1380 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
1382 namespace {
1384 void DragInMaximizedWindowStep2(DetachToBrowserTabDragControllerTest* test,
1385 Browser* browser,
1386 TabStrip* tab_strip,
1387 const BrowserList* browser_list) {
1388 // There should be another browser.
1389 ASSERT_EQ(2u, browser_list->size());
1390 Browser* new_browser = browser_list->get(1);
1391 EXPECT_NE(browser, new_browser);
1392 ASSERT_TRUE(new_browser->window()->IsActive());
1393 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
1395 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1396 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1398 // Both windows should be visible.
1399 EXPECT_TRUE(tab_strip->GetWidget()->IsVisible());
1400 EXPECT_TRUE(tab_strip2->GetWidget()->IsVisible());
1402 // Stops dragging.
1403 ASSERT_TRUE(test->ReleaseInput());
1406 } // namespace
1408 #if defined(OS_CHROMEOS)
1409 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1410 // compositor. crbug.com/331924
1411 #define MAYBE_DragInMaximizedWindow DISABLED_DragInMaximizedWindow
1412 #else
1413 #define MAYBE_DragInMaximizedWindow DragInMaximizedWindow
1414 #endif
1415 // Creates a browser with two tabs, maximizes it, drags the tab out.
1416 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1417 MAYBE_DragInMaximizedWindow) {
1418 AddTabAndResetBrowser(browser());
1419 browser()->window()->Maximize();
1421 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1423 // Move to the first tab and drag it enough so that it detaches.
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(&DragInMaximizedWindowStep2, this, browser(), tab_strip,
1430 native_browser_list)));
1431 QuitWhenNotDragging();
1433 ASSERT_FALSE(TabDragController::IsActive());
1435 // Should be two browsers.
1436 ASSERT_EQ(2u, native_browser_list->size());
1437 Browser* new_browser = native_browser_list->get(1);
1438 ASSERT_TRUE(new_browser->window()->IsActive());
1440 EXPECT_TRUE(browser()->window()->GetNativeWindow()->IsVisible());
1441 EXPECT_TRUE(new_browser->window()->GetNativeWindow()->IsVisible());
1443 EXPECT_FALSE(GetIsDragged(browser()));
1444 EXPECT_FALSE(GetIsDragged(new_browser));
1446 // The source window should be maximized.
1447 EXPECT_TRUE(browser()->window()->IsMaximized());
1448 // The new window should be maximized.
1449 EXPECT_TRUE(new_browser->window()->IsMaximized());
1452 // Subclass of DetachToBrowserTabDragControllerTest that
1453 // creates multiple displays.
1454 class DetachToBrowserInSeparateDisplayTabDragControllerTest
1455 : public DetachToBrowserTabDragControllerTest {
1456 public:
1457 DetachToBrowserInSeparateDisplayTabDragControllerTest() {}
1458 virtual ~DetachToBrowserInSeparateDisplayTabDragControllerTest() {}
1460 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
1461 DetachToBrowserTabDragControllerTest::SetUpCommandLine(command_line);
1462 // Make screens sufficiently wide to host 2 browsers side by side.
1463 command_line->AppendSwitchASCII("ash-host-window-bounds",
1464 "0+0-600x600,601+0-600x600");
1467 private:
1468 DISALLOW_COPY_AND_ASSIGN(
1469 DetachToBrowserInSeparateDisplayTabDragControllerTest);
1472 // Subclass of DetachToBrowserTabDragControllerTest that runs tests only with
1473 // touch input.
1474 class DetachToBrowserTabDragControllerTestTouch
1475 : public DetachToBrowserTabDragControllerTest {
1476 public:
1477 DetachToBrowserTabDragControllerTestTouch() {}
1478 virtual ~DetachToBrowserTabDragControllerTestTouch() {}
1480 private:
1481 DISALLOW_COPY_AND_ASSIGN(DetachToBrowserTabDragControllerTestTouch);
1484 namespace {
1486 void DragSingleTabToSeparateWindowInSecondDisplayStep3(
1487 DetachToBrowserTabDragControllerTest* test) {
1488 ASSERT_TRUE(test->ReleaseInput());
1491 void DragSingleTabToSeparateWindowInSecondDisplayStep2(
1492 DetachToBrowserTabDragControllerTest* test,
1493 const gfx::Point& target_point) {
1494 ASSERT_TRUE(test->DragInputToNotifyWhenDone(
1495 target_point.x(), target_point.y(),
1496 base::Bind(&DragSingleTabToSeparateWindowInSecondDisplayStep3, test)));
1499 } // namespace
1501 #if defined(OS_CHROMEOS)
1502 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1503 // compositor. crbug.com/331924
1504 #define MAYBE_DragSingleTabToSeparateWindowInSecondDisplay \
1505 DISABLED_DragSingleTabToSeparateWindowInSecondDisplay
1506 #else
1507 #define MAYBE_DragSingleTabToSeparateWindow \
1508 DragSingleTabToSeparateWindowInSecondDisplay
1509 #endif
1510 // Drags from browser to a second display and releases input.
1511 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1512 MAYBE_DragSingleTabToSeparateWindowInSecondDisplay) {
1513 // Add another tab.
1514 AddTabAndResetBrowser(browser());
1515 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1517 // Move to the first tab and drag it enough so that it detaches.
1518 // Then drag it to the final destination on the second screen.
1519 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1520 ASSERT_TRUE(PressInput(tab_0_center));
1521 ASSERT_TRUE(DragInputToNotifyWhenDone(
1522 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1523 base::Bind(&DragSingleTabToSeparateWindowInSecondDisplayStep2,
1524 this, gfx::Point(600 + tab_0_center.x(),
1525 tab_0_center.y()
1526 + GetDetachY(tab_strip)))));
1527 QuitWhenNotDragging();
1529 // Should no longer be dragging.
1530 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1531 ASSERT_FALSE(TabDragController::IsActive());
1533 // There should now be another browser.
1534 ASSERT_EQ(2u, native_browser_list->size());
1535 Browser* new_browser = native_browser_list->get(1);
1536 ASSERT_TRUE(new_browser->window()->IsActive());
1537 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
1538 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1540 // This other browser should be on the second screen (with mouse drag)
1541 // With the touch input the browser cannot be dragged from one screen
1542 // to another and the window stays on the first screen.
1543 if (input_source() == INPUT_SOURCE_MOUSE) {
1544 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1545 ASSERT_EQ(2u, roots.size());
1546 aura::Window* second_root = roots[1];
1547 EXPECT_EQ(second_root,
1548 new_browser->window()->GetNativeWindow()->GetRootWindow());
1551 EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
1552 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1554 // Both windows should not be maximized
1555 EXPECT_FALSE(browser()->window()->IsMaximized());
1556 EXPECT_FALSE(new_browser->window()->IsMaximized());
1559 namespace {
1561 // Invoked from the nested message loop.
1562 void DragTabToWindowInSeparateDisplayStep2(
1563 DetachToBrowserTabDragControllerTest* test,
1564 TabStrip* not_attached_tab_strip,
1565 TabStrip* target_tab_strip) {
1566 ASSERT_FALSE(not_attached_tab_strip->IsDragSessionActive());
1567 ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
1568 ASSERT_TRUE(TabDragController::IsActive());
1570 // Drag to target_tab_strip. This should stop the nested loop from dragging
1571 // the window.
1572 gfx::Point target_point(
1573 GetCenterInScreenCoordinates(target_tab_strip->tab_at(0)));
1575 // Move it close to the beginning of the target tabstrip.
1576 target_point.set_x(
1577 target_point.x() - target_tab_strip->tab_at(0)->width() / 2 + 10);
1578 ASSERT_TRUE(test->DragInputToAsync(target_point));
1581 } // namespace
1583 #if defined(OS_CHROMEOS)
1584 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1585 // compositor. crbug.com/331924
1586 #define MAYBE_DragTabToWindowInSeparateDisplay \
1587 DISABLED_DragTabToWindowInSeparateDisplay
1588 #else
1589 #define MAYBE_DragTabToWindowInSeparateDisplay DragTabToWindowInSeparateDisplay
1590 #endif
1591 // Drags from browser to another browser on a second display and releases input.
1592 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1593 MAYBE_DragTabToWindowInSeparateDisplay) {
1594 // Add another tab.
1595 AddTabAndResetBrowser(browser());
1596 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1598 // Create another browser.
1599 Browser* browser2 = CreateBrowser(browser()->profile());
1600 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1601 ResetIDs(browser2->tab_strip_model(), 100);
1603 // Move the second browser to the second display.
1604 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1605 ASSERT_EQ(2u, roots.size());
1606 aura::Window* second_root = roots[1];
1607 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1608 second_root).work_area();
1609 browser2->window()->SetBounds(work_area);
1610 EXPECT_EQ(second_root,
1611 browser2->window()->GetNativeWindow()->GetRootWindow());
1613 // Move to the first tab and drag it enough so that it detaches, but not
1614 // enough that it attaches to browser2.
1615 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1616 ASSERT_TRUE(PressInput(tab_0_center));
1617 ASSERT_TRUE(DragInputToNotifyWhenDone(
1618 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1619 base::Bind(&DragTabToWindowInSeparateDisplayStep2,
1620 this, tab_strip, tab_strip2)));
1621 QuitWhenNotDragging();
1623 // Should now be attached to tab_strip2.
1624 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1625 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1626 ASSERT_TRUE(TabDragController::IsActive());
1628 // Release the mouse, stopping the drag session.
1629 ASSERT_TRUE(ReleaseInput());
1630 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1631 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1632 ASSERT_FALSE(TabDragController::IsActive());
1633 EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1634 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1636 // Both windows should not be maximized
1637 EXPECT_FALSE(browser()->window()->IsMaximized());
1638 EXPECT_FALSE(browser2->window()->IsMaximized());
1641 #if defined(OS_CHROMEOS)
1642 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1643 // compositor. crbug.com/331924
1644 #define MAYBE_DragTabToWindowOnSecondDisplay \
1645 DISABLED_DragTabToWindowOnSecondDisplay
1646 #else
1647 #define MAYBE_DragTabToWindowOnSecondDisplay DragTabToWindowOnSecondDisplay
1648 #endif
1649 // Drags from browser to another browser on a second display and releases input.
1650 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1651 MAYBE_DragTabToWindowOnSecondDisplay) {
1652 // Add another tab.
1653 AddTabAndResetBrowser(browser());
1654 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1656 // Create another browser.
1657 Browser* browser2 = CreateBrowser(browser()->profile());
1658 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1659 ResetIDs(browser2->tab_strip_model(), 100);
1661 // Move both browsers to the second display.
1662 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1663 ASSERT_EQ(2u, roots.size());
1664 aura::Window* second_root = roots[1];
1665 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1666 second_root).work_area();
1667 browser()->window()->SetBounds(work_area);
1669 // position both browser windows side by side on the second screen.
1670 gfx::Rect work_area2(work_area);
1671 work_area.set_width(work_area.width()/2);
1672 browser()->window()->SetBounds(work_area);
1673 work_area2.set_x(work_area2.x() + work_area2.width()/2);
1674 work_area2.set_width(work_area2.width()/2);
1675 browser2->window()->SetBounds(work_area2);
1676 EXPECT_EQ(second_root,
1677 browser()->window()->GetNativeWindow()->GetRootWindow());
1678 EXPECT_EQ(second_root,
1679 browser2->window()->GetNativeWindow()->GetRootWindow());
1681 // Move to the first tab and drag it enough so that it detaches, but not
1682 // enough that it attaches to browser2.
1683 // SetEventGeneratorRootWindow sets correct (second) RootWindow
1684 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1685 SetEventGeneratorRootWindow(tab_0_center);
1686 ASSERT_TRUE(PressInput(tab_0_center));
1687 ASSERT_TRUE(DragInputToNotifyWhenDone(
1688 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1689 base::Bind(&DragTabToWindowInSeparateDisplayStep2,
1690 this, tab_strip, tab_strip2)));
1691 QuitWhenNotDragging();
1693 // Should now be attached to tab_strip2.
1694 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1695 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1696 ASSERT_TRUE(TabDragController::IsActive());
1698 // Release the mouse, stopping the drag session.
1699 ASSERT_TRUE(ReleaseInput());
1700 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1701 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1702 ASSERT_FALSE(TabDragController::IsActive());
1703 EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1704 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1706 // Both windows should not be maximized
1707 EXPECT_FALSE(browser()->window()->IsMaximized());
1708 EXPECT_FALSE(browser2->window()->IsMaximized());
1711 #if defined(OS_CHROMEOS)
1712 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1713 // compositor. crbug.com/331924
1714 #define MAYBE_DragMaxTabToNonMaxWindowInSeparateDisplay \
1715 DISABLED_DragMaxTabToNonMaxWindowInSeparateDisplay
1716 #else
1717 #define MAYBE_DragMaxTabToNonMaxWindowInSeparateDisplay \
1718 DragMaxTabToNonMaxWindowInSeparateDisplay
1719 #endif
1720 // Drags from a maximized browser to another non-maximized browser on a second
1721 // display and releases input.
1722 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1723 MAYBE_DragMaxTabToNonMaxWindowInSeparateDisplay) {
1724 // Add another tab.
1725 AddTabAndResetBrowser(browser());
1726 browser()->window()->Maximize();
1727 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1729 // Create another browser on the second display.
1730 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1731 ASSERT_EQ(2u, roots.size());
1732 aura::Window* first_root = roots[0];
1733 aura::Window* second_root = roots[1];
1734 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1735 second_root).work_area();
1736 work_area.Inset(20,20,20,60);
1737 Browser::CreateParams params(browser()->profile(),
1738 browser()->host_desktop_type());
1739 params.initial_show_state = ui::SHOW_STATE_NORMAL;
1740 params.initial_bounds = work_area;
1741 Browser* browser2 = new Browser(params);
1742 AddBlankTabAndShow(browser2);
1744 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1745 ResetIDs(browser2->tab_strip_model(), 100);
1747 EXPECT_EQ(second_root,
1748 browser2->window()->GetNativeWindow()->GetRootWindow());
1749 EXPECT_EQ(first_root,
1750 browser()->window()->GetNativeWindow()->GetRootWindow());
1751 EXPECT_EQ(2, tab_strip->tab_count());
1752 EXPECT_EQ(1, tab_strip2->tab_count());
1754 // Move to the first tab and drag it enough so that it detaches, but not
1755 // enough that it attaches to browser2.
1756 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1757 ASSERT_TRUE(PressInput(tab_0_center));
1758 ASSERT_TRUE(DragInputToNotifyWhenDone(
1759 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1760 base::Bind(&DragTabToWindowInSeparateDisplayStep2,
1761 this, tab_strip, tab_strip2)));
1762 QuitWhenNotDragging();
1764 // Should now be attached to tab_strip2.
1765 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1766 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1767 ASSERT_TRUE(TabDragController::IsActive());
1769 // Release the mouse, stopping the drag session.
1770 ASSERT_TRUE(ReleaseInput());
1772 // tab should have moved
1773 EXPECT_EQ(1, tab_strip->tab_count());
1774 EXPECT_EQ(2, tab_strip2->tab_count());
1776 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1777 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1778 ASSERT_FALSE(TabDragController::IsActive());
1779 EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1780 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1782 // Source browser should still be maximized, target should not
1783 EXPECT_TRUE(browser()->window()->IsMaximized());
1784 EXPECT_FALSE(browser2->window()->IsMaximized());
1787 // Immersive fullscreen is ChromeOS only.
1788 #if defined(OS_CHROMEOS)
1789 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1790 // compositor. crbug.com/331924
1791 #define MAYBE_DragTabToImmersiveBrowserOnSeparateDisplay \
1792 DISABLED_DragTabToImmersiveBrowserOnSeparateDisplay
1793 // Drags from a restored browser to an immersive fullscreen browser on a
1794 // second display and releases input.
1795 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1796 MAYBE_DragTabToImmersiveBrowserOnSeparateDisplay) {
1797 // Add another tab.
1798 AddTabAndResetBrowser(browser());
1799 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1801 // Create another browser.
1802 Browser* browser2 = CreateBrowser(browser()->profile());
1803 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1804 ResetIDs(browser2->tab_strip_model(), 100);
1806 // Move the second browser to the second display.
1807 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1808 ASSERT_EQ(2u, roots.size());
1809 aura::Window* second_root = roots[1];
1810 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1811 second_root).work_area();
1812 browser2->window()->SetBounds(work_area);
1813 EXPECT_EQ(second_root,
1814 browser2->window()->GetNativeWindow()->GetRootWindow());
1816 // Put the second browser into immersive fullscreen.
1817 BrowserView* browser_view2 = BrowserView::GetBrowserViewForBrowser(browser2);
1818 ImmersiveModeController* immersive_controller2 =
1819 browser_view2->immersive_mode_controller();
1820 immersive_controller2->SetupForTest();
1821 chrome::ToggleFullscreenMode(browser2);
1822 ASSERT_TRUE(immersive_controller2->IsEnabled());
1823 ASSERT_FALSE(immersive_controller2->IsRevealed());
1824 ASSERT_TRUE(tab_strip2->IsImmersiveStyle());
1826 // Move to the first tab and drag it enough so that it detaches, but not
1827 // enough that it attaches to browser2.
1828 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1829 ASSERT_TRUE(PressInput(tab_0_center));
1830 ASSERT_TRUE(DragInputToNotifyWhenDone(
1831 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1832 base::Bind(&DragTabToWindowInSeparateDisplayStep2,
1833 this, tab_strip, tab_strip2)));
1834 QuitWhenNotDragging();
1836 // Should now be attached to tab_strip2.
1837 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1838 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1839 ASSERT_TRUE(TabDragController::IsActive());
1841 // browser2's top chrome should be revealed and the tab strip should be
1842 // at normal height while user is tragging tabs_strip2's tabs.
1843 ASSERT_TRUE(immersive_controller2->IsRevealed());
1844 ASSERT_FALSE(tab_strip2->IsImmersiveStyle());
1846 // Release the mouse, stopping the drag session.
1847 ASSERT_TRUE(ReleaseInput());
1848 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1849 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1850 ASSERT_FALSE(TabDragController::IsActive());
1851 EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1852 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1854 // Move the mouse off of browser2's top chrome.
1855 aura::Window* primary_root = roots[0];
1856 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
1857 primary_root->GetBoundsInScreen().CenterPoint()));
1859 // The first browser window should not be in immersive fullscreen.
1860 // browser2 should still be in immersive fullscreen, but the top chrome should
1861 // no longer be revealed.
1862 BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
1863 EXPECT_FALSE(browser_view->immersive_mode_controller()->IsEnabled());
1865 EXPECT_TRUE(immersive_controller2->IsEnabled());
1866 EXPECT_FALSE(immersive_controller2->IsRevealed());
1867 EXPECT_TRUE(tab_strip2->IsImmersiveStyle());
1869 #endif // OS_CHROMEOS
1871 // Subclass of DetachToBrowserTabDragControllerTest that
1872 // creates multiple displays with different device scale factors.
1873 class DifferentDeviceScaleFactorDisplayTabDragControllerTest
1874 : public DetachToBrowserTabDragControllerTest {
1875 public:
1876 DifferentDeviceScaleFactorDisplayTabDragControllerTest() {}
1877 virtual ~DifferentDeviceScaleFactorDisplayTabDragControllerTest() {}
1879 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
1880 DetachToBrowserTabDragControllerTest::SetUpCommandLine(command_line);
1881 command_line->AppendSwitchASCII("ash-host-window-bounds",
1882 "400x400,0+400-800x800*2");
1885 float GetCursorDeviceScaleFactor() const {
1886 ash::test::CursorManagerTestApi cursor_test_api(
1887 ash::Shell::GetInstance()->cursor_manager());
1888 return cursor_test_api.GetDisplay().device_scale_factor();
1891 private:
1892 DISALLOW_COPY_AND_ASSIGN(
1893 DifferentDeviceScaleFactorDisplayTabDragControllerTest);
1896 namespace {
1898 // The points where a tab is dragged in CursorDeviceScaleFactorStep.
1899 const struct DragPoint {
1900 int x;
1901 int y;
1902 } kDragPoints[] = {
1903 {300, 200},
1904 {399, 200},
1905 {500, 200},
1906 {400, 200},
1907 {300, 200},
1910 // The expected device scale factors before the cursor is moved to the
1911 // corresponding kDragPoints in CursorDeviceScaleFactorStep.
1912 const float kDeviceScaleFactorExpectations[] = {
1913 1.0f,
1914 1.0f,
1915 2.0f,
1916 2.0f,
1917 1.0f,
1920 COMPILE_ASSERT(
1921 arraysize(kDragPoints) == arraysize(kDeviceScaleFactorExpectations),
1922 kDragPoints_and_kDeviceScaleFactorExpectations_must_have_same_size);
1924 // Drags tab to |kDragPoints[index]|, then calls the next step function.
1925 void CursorDeviceScaleFactorStep(
1926 DifferentDeviceScaleFactorDisplayTabDragControllerTest* test,
1927 TabStrip* not_attached_tab_strip,
1928 size_t index) {
1929 ASSERT_FALSE(not_attached_tab_strip->IsDragSessionActive());
1930 ASSERT_TRUE(TabDragController::IsActive());
1932 if (index < arraysize(kDragPoints)) {
1933 EXPECT_EQ(kDeviceScaleFactorExpectations[index],
1934 test->GetCursorDeviceScaleFactor());
1935 const DragPoint p = kDragPoints[index];
1936 ASSERT_TRUE(test->DragInputToNotifyWhenDone(
1937 p.x, p.y, base::Bind(&CursorDeviceScaleFactorStep,
1938 test, not_attached_tab_strip, index + 1)));
1939 } else {
1940 // Finishes a serise of CursorDeviceScaleFactorStep calls and ends drag.
1941 EXPECT_EQ(1.0f, test->GetCursorDeviceScaleFactor());
1942 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
1943 ui_controls::LEFT, ui_controls::UP));
1947 } // namespace
1949 #if defined(OS_CHROMEOS)
1950 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1951 // compositor. crbug.com/331924
1952 #define MAYBE_CursorDeviceScaleFactor DISABLED_CursorDeviceScaleFactor
1953 #else
1954 #define MAYBE_CursorDeviceScaleFactor CursorDeviceScaleFactor
1955 #endif
1956 // Verifies cursor's device scale factor is updated when a tab is moved across
1957 // displays with different device scale factors (http://crbug.com/154183).
1958 IN_PROC_BROWSER_TEST_P(DifferentDeviceScaleFactorDisplayTabDragControllerTest,
1959 MAYBE_CursorDeviceScaleFactor) {
1960 // Add another tab.
1961 AddTabAndResetBrowser(browser());
1962 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1964 // Move the second browser to the second display.
1965 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1966 ASSERT_EQ(2u, roots.size());
1968 // Move to the first tab and drag it enough so that it detaches.
1969 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1970 ASSERT_TRUE(PressInput(tab_0_center));
1971 ASSERT_TRUE(DragInputToNotifyWhenDone(
1972 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1973 base::Bind(&CursorDeviceScaleFactorStep,
1974 this, tab_strip, 0)));
1975 QuitWhenNotDragging();
1978 namespace {
1980 class DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest
1981 : public TabDragControllerTest {
1982 public:
1983 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest() {}
1985 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
1986 TabDragControllerTest::SetUpCommandLine(command_line);
1987 command_line->AppendSwitchASCII("ash-host-window-bounds",
1988 "0+0-250x250,251+0-250x250");
1991 bool Press(const gfx::Point& position) {
1992 return ui_test_utils::SendMouseMoveSync(position) &&
1993 ui_test_utils::SendMouseEventsSync(ui_controls::LEFT,
1994 ui_controls::DOWN);
1997 bool DragTabAndExecuteTaskWhenDone(const gfx::Point& position,
1998 const base::Closure& task) {
1999 return ui_controls::SendMouseMoveNotifyWhenDone(
2000 position.x(), position.y(), task);
2003 void QuitWhenNotDragging() {
2004 test::QuitWhenNotDraggingImpl();
2005 base::MessageLoop::current()->Run();
2008 private:
2009 DISALLOW_COPY_AND_ASSIGN(
2010 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest);
2013 // Invoked from the nested message loop.
2014 void CancelDragTabToWindowInSeparateDisplayStep3(
2015 TabStrip* tab_strip,
2016 const BrowserList* browser_list) {
2017 ASSERT_FALSE(tab_strip->IsDragSessionActive());
2018 ASSERT_TRUE(TabDragController::IsActive());
2019 ASSERT_EQ(2u, browser_list->size());
2021 // Switching display mode should cancel the drag operation.
2022 ash::internal::DisplayManager* display_manager =
2023 ash::Shell::GetInstance()->display_manager();
2024 display_manager->AddRemoveDisplay();
2027 // Invoked from the nested message loop.
2028 void CancelDragTabToWindowInSeparateDisplayStep2(
2029 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest* test,
2030 TabStrip* tab_strip,
2031 aura::Window* current_root,
2032 gfx::Point final_destination,
2033 const BrowserList* browser_list) {
2034 ASSERT_FALSE(tab_strip->IsDragSessionActive());
2035 ASSERT_TRUE(TabDragController::IsActive());
2036 ASSERT_EQ(2u, browser_list->size());
2038 Browser* new_browser = browser_list->get(1);
2039 EXPECT_EQ(current_root,
2040 new_browser->window()->GetNativeWindow()->GetRootWindow());
2042 ASSERT_TRUE(test->DragTabAndExecuteTaskWhenDone(
2043 final_destination,
2044 base::Bind(&CancelDragTabToWindowInSeparateDisplayStep3,
2045 tab_strip, browser_list)));
2048 } // namespace
2050 #if defined(OS_CHROMEOS)
2051 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
2052 // compositor. crbug.com/331924
2053 #define MAYBE_CancelDragTabToWindowIn2ndDisplay \
2054 DISABLED_CancelDragTabToWindowIn2ndDisplay
2055 #else
2056 #define MAYBE_CancelDragTabToWindowIn2ndDisplay \
2057 CancelDragTabToWindowIn2ndDisplay
2058 #endif
2059 // Drags from browser to a second display and releases input.
2060 IN_PROC_BROWSER_TEST_F(
2061 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest,
2062 MAYBE_CancelDragTabToWindowIn2ndDisplay) {
2063 // Add another tab.
2064 AddTabAndResetBrowser(browser());
2065 TabStrip* tab_strip = GetTabStripForBrowser(browser());
2067 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2069 // Move the second browser to the second display.
2070 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
2071 ASSERT_EQ(2u, roots.size());
2072 gfx::Point final_destination =
2073 gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
2074 roots[1]).work_area().CenterPoint();
2076 // Move to the first tab and drag it enough so that it detaches, but not
2077 // enough to move to another display.
2078 gfx::Point tab_0_dst(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
2079 ASSERT_TRUE(Press(tab_0_dst));
2080 tab_0_dst.Offset(0, GetDetachY(tab_strip));
2081 ASSERT_TRUE(DragTabAndExecuteTaskWhenDone(
2082 tab_0_dst, base::Bind(&CancelDragTabToWindowInSeparateDisplayStep2,
2083 this, tab_strip, roots[0], final_destination,
2084 native_browser_list)));
2085 QuitWhenNotDragging();
2087 ASSERT_EQ(1u, native_browser_list->size());
2088 ASSERT_FALSE(tab_strip->IsDragSessionActive());
2089 ASSERT_FALSE(TabDragController::IsActive());
2090 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2092 // Release the mouse
2093 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
2094 ui_controls::LEFT, ui_controls::UP));
2097 #if defined(OS_CHROMEOS)
2098 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
2099 // compositor. crbug.com/331924
2100 #define MAYBE_CancelDragTabToWindowIn1stDisplay \
2101 DISABLED_CancelDragTabToWindowIn1stDisplay
2102 #else
2103 #define MAYBE_CancelDragTabToWindowIn1stDisplay \
2104 CancelDragTabToWindowIn1stDisplay
2105 #endif
2106 // Drags from browser from a second display to primary and releases input.
2107 IN_PROC_BROWSER_TEST_F(
2108 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest,
2109 MAYBE_CancelDragTabToWindowIn1stDisplay) {
2110 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
2111 ASSERT_EQ(2u, roots.size());
2113 // Add another tab.
2114 AddTabAndResetBrowser(browser());
2115 TabStrip* tab_strip = GetTabStripForBrowser(browser());
2117 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2118 EXPECT_EQ(roots[0], browser()->window()->GetNativeWindow()->GetRootWindow());
2120 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->
2121 GetDisplayNearestWindow(roots[1]).work_area();
2122 browser()->window()->SetBounds(work_area);
2123 EXPECT_EQ(roots[1], browser()->window()->GetNativeWindow()->GetRootWindow());
2125 // Move the second browser to the display.
2126 gfx::Point final_destination =
2127 gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
2128 roots[0]).work_area().CenterPoint();
2130 // Move to the first tab and drag it enough so that it detaches, but not
2131 // enough to move to another display.
2132 gfx::Point tab_0_dst(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
2133 ASSERT_TRUE(Press(tab_0_dst));
2134 tab_0_dst.Offset(0, GetDetachY(tab_strip));
2135 ASSERT_TRUE(DragTabAndExecuteTaskWhenDone(
2136 tab_0_dst, base::Bind(&CancelDragTabToWindowInSeparateDisplayStep2,
2137 this, tab_strip, roots[1], final_destination,
2138 native_browser_list)));
2139 QuitWhenNotDragging();
2141 ASSERT_EQ(1u, native_browser_list->size());
2142 ASSERT_FALSE(tab_strip->IsDragSessionActive());
2143 ASSERT_FALSE(TabDragController::IsActive());
2144 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2146 // Release the mouse
2147 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
2148 ui_controls::LEFT, ui_controls::UP));
2151 namespace {
2153 void PressSecondFingerWhileDetachedStep2(
2154 DetachToBrowserTabDragControllerTest* test) {
2155 ASSERT_TRUE(TabDragController::IsActive());
2156 ASSERT_EQ(2u, test->native_browser_list->size());
2157 Browser* new_browser = test->native_browser_list->get(1);
2158 ASSERT_TRUE(new_browser->window()->IsActive());
2160 ASSERT_TRUE(test->PressInput2());
2163 } // namespace
2165 #if defined(OS_CHROMEOS)
2166 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
2167 // compositor. crbug.com/331924
2168 #define MAYBE_PressSecondFingerWhileDetached DISABLED_PressSecondFingerWhileDetached
2169 #else
2170 #define MAYBE_PressSecondFingerWhileDetached PressSecondFingerWhileDetached
2171 #endif
2172 // Detaches a tab and while detached presses a second finger.
2173 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestTouch,
2174 MAYBE_PressSecondFingerWhileDetached) {
2175 gfx::Rect bounds(browser()->window()->GetBounds());
2176 // Add another tab.
2177 AddTabAndResetBrowser(browser());
2178 TabStrip* tab_strip = GetTabStripForBrowser(browser());
2179 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2181 // Move to the first tab and drag it enough so that it detaches.
2182 gfx::Point tab_0_center(
2183 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
2184 ASSERT_TRUE(PressInput(tab_0_center));
2185 ASSERT_TRUE(DragInputToDelayedNotifyWhenDone(
2186 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
2187 base::Bind(&PressSecondFingerWhileDetachedStep2, this),
2188 base::TimeDelta::FromMilliseconds(60)));
2189 QuitWhenNotDragging();
2191 // The drag should have been reverted.
2192 ASSERT_EQ(1u, native_browser_list->size());
2193 ASSERT_FALSE(tab_strip->IsDragSessionActive());
2194 ASSERT_FALSE(TabDragController::IsActive());
2195 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2197 ASSERT_TRUE(ReleaseInput());
2198 ASSERT_TRUE(ReleaseInput2());
2201 // Subclass of DetachToBrowserTabDragControllerTest that runs tests with
2202 // docked windows enabled and disabled.
2203 class DetachToDockedTabDragControllerTest
2204 : public DetachToBrowserTabDragControllerTest {
2205 public:
2206 DetachToDockedTabDragControllerTest() {}
2207 virtual ~DetachToDockedTabDragControllerTest() {}
2209 private:
2210 DISALLOW_COPY_AND_ASSIGN(DetachToDockedTabDragControllerTest);
2213 namespace {
2215 void DetachToDockedWindowNextStep(
2216 DetachToDockedTabDragControllerTest* test,
2217 const gfx::Point& target_point,
2218 int iteration) {
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 if (!iteration) {
2224 ASSERT_TRUE(test->ReleaseInput());
2225 return;
2227 ASSERT_TRUE(test->DragInputToNotifyWhenDone(
2228 target_point.x(), target_point.y(),
2229 base::Bind(&DetachToDockedWindowNextStep,
2230 test,
2231 gfx::Point(target_point.x(), 1 + target_point.y()),
2232 iteration - 1)));
2235 } // namespace
2237 #if defined(OS_CHROMEOS)
2238 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
2239 // compositor. crbug.com/331924
2240 #define MAYBE_DetachToDockedWindowFromMaximizedWindow \
2241 DISABLED_DetachToDockedWindowFromMaximizedWindow
2242 #else
2243 #define MAYBE_DetachToDockedWindowFromMaximizedWindow \
2244 DetachToDockedWindowFromMaximizedWindow
2245 #endif
2246 // Drags from browser to separate window, docks that window and releases mouse.
2247 IN_PROC_BROWSER_TEST_P(DetachToDockedTabDragControllerTest,
2248 MAYBE_DetachToDockedWindowFromMaximizedWindow) {
2249 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
2250 // compositor. crbug.com/331924
2251 if (docked_windows_enabled()) {
2252 VLOG(1) << "Test is DISABLED for docked windows.";
2253 return;
2256 // Maximize the initial browser window.
2257 browser()->window()->Maximize();
2258 ASSERT_TRUE(browser()->window()->IsMaximized());
2260 // Add another tab.
2261 AddTabAndResetBrowser(browser());
2262 TabStrip* tab_strip = GetTabStripForBrowser(browser());
2264 // Move to the first tab and drag it enough so that it detaches.
2265 gfx::Point tab_0_center(
2266 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
2267 ASSERT_TRUE(PressInput(tab_0_center));
2269 // The following matches kMovesBeforeAdjust in snap_sizer.cc
2270 const int kNumIterations = 25 * 5 + 10;
2271 ASSERT_TRUE(DragInputToNotifyWhenDone(
2272 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
2273 base::Bind(&DetachToDockedWindowNextStep, this,
2274 gfx::Point(0, tab_0_center.y() + GetDetachY(tab_strip)),
2275 kNumIterations)));
2276 // Continue dragging enough times to go through snapping sequence and dock
2277 // the window.
2278 QuitWhenNotDragging();
2279 // Should no longer be dragging.
2280 ASSERT_FALSE(tab_strip->IsDragSessionActive());
2281 ASSERT_FALSE(TabDragController::IsActive());
2283 // There should now be another browser.
2284 ASSERT_EQ(2u, native_browser_list->size());
2285 Browser* new_browser = native_browser_list->get(1);
2286 ASSERT_TRUE(new_browser->window()->IsActive());
2287 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
2288 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
2290 EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
2291 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
2293 // The bounds of the initial window should not have changed.
2294 EXPECT_TRUE(browser()->window()->IsMaximized());
2296 EXPECT_FALSE(GetIsDragged(browser()));
2297 EXPECT_FALSE(GetIsDragged(new_browser));
2298 // After this both windows should still be manageable.
2299 EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
2300 EXPECT_TRUE(IsWindowPositionManaged(
2301 new_browser->window()->GetNativeWindow()));
2303 ash::wm::WindowState* window_state =
2304 ash::wm::GetWindowState(new_browser->window()->GetNativeWindow());
2305 // The new window should not be maximized because it gets docked or snapped.
2306 EXPECT_FALSE(new_browser->window()->IsMaximized());
2307 if (docked_windows_enabled()) {
2308 // The new window should be docked and not snapped if docking is allowed.
2309 EXPECT_TRUE(window_state->IsDocked());
2310 EXPECT_FALSE(window_state->IsSnapped());
2311 } else {
2312 // The new window should be snapped and not docked if docking is disabled.
2313 EXPECT_FALSE(window_state->IsDocked());
2314 EXPECT_TRUE(window_state->IsSnapped());
2319 #endif
2321 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
2322 INSTANTIATE_TEST_CASE_P(TabDragging,
2323 DetachToBrowserInSeparateDisplayTabDragControllerTest,
2324 ::testing::Values("mouse", "touch"));
2325 INSTANTIATE_TEST_CASE_P(TabDragging,
2326 DifferentDeviceScaleFactorDisplayTabDragControllerTest,
2327 ::testing::Values("mouse"));
2328 INSTANTIATE_TEST_CASE_P(TabDragging,
2329 DetachToBrowserTabDragControllerTest,
2330 ::testing::Values("mouse", "touch"));
2331 INSTANTIATE_TEST_CASE_P(TabDragging,
2332 DetachToDockedTabDragControllerTest,
2333 ::testing::Values("mouse", "mouse docked"));
2334 INSTANTIATE_TEST_CASE_P(TabDragging,
2335 DetachToBrowserTabDragControllerTestTouch,
2336 ::testing::Values("touch", "touch docked"));
2337 #else
2338 INSTANTIATE_TEST_CASE_P(TabDragging,
2339 DetachToBrowserTabDragControllerTest,
2340 ::testing::Values("mouse"));
2341 #endif