MacViews: Use Mac's "Constrained Window Button" style for Button::STYLE_BUTTON LabelB...
[chromium-blink-merge.git] / chrome / browser / ui / views / tabs / tab_drag_controller_interactive_uitest.cc
blob1911f4c3c20df0a9629e2f61e0ef55370fb3a44c
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 <algorithm>
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"
41 #if defined(USE_AURA)
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"
46 #endif
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"
51 #endif
53 #if defined(USE_ASH)
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"
65 #endif
67 using content::WebContents;
69 namespace test {
71 namespace {
73 const char kTabDragControllerInteractiveUITestUserDataKey[] =
74 "TabDragControllerInteractiveUITestUserData";
76 class TabDragControllerInteractiveUITestUserData
77 : public base::SupportsUserData::Data {
78 public:
79 explicit TabDragControllerInteractiveUITestUserData(int id) : id_(id) {}
80 ~TabDragControllerInteractiveUITestUserData() override {}
81 int id() { return id_; }
83 private:
84 int id_;
87 } // namespace
89 class QuitDraggingObserver : public content::NotificationObserver {
90 public:
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();
101 delete this;
104 private:
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, &center);
115 return center;
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) {
129 std::string result;
130 for (int i = 0; i < model->count(); ++i) {
131 if (i != 0)
132 result += " ";
133 WebContents* contents = model->GetWebContentsAt(i);
134 TabDragControllerInteractiveUITestUserData* user_data =
135 static_cast<TabDragControllerInteractiveUITestUserData*>(
136 contents->GetUserData(
137 &kTabDragControllerInteractiveUITestUserDataKey));
138 if (user_data)
139 result += base::IntToString(user_data->id());
140 else
141 result += "?";
143 return result;
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());
156 } // namespace test
158 using test::GetCenterInScreenCoordinates;
159 using test::SetID;
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()));
196 return browser2;
199 namespace {
201 enum InputSource {
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)
214 return false;
215 #else
216 return ash::wm::GetWindowState(browser->window()->GetNativeWindow())->
217 is_dragged();
218 #endif
221 } // namespace
223 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
224 class ScreenEventGeneratorDelegate
225 : public aura::test::EventGeneratorDelegateAura {
226 public:
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_);
241 private:
242 aura::Window* root_window_;
244 DISALLOW_COPY_AND_ASSIGN(ScreenEventGeneratorDelegate);
247 #endif
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 {
258 public:
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();
278 private:
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 {
287 public:
288 TestNativeBrowserFrameFactory() {}
289 ~TestNativeBrowserFrameFactory() override {}
291 NativeBrowserFrame* Create(BrowserFrame* browser_frame,
292 BrowserView* browser_view) override {
293 return new TestDesktopBrowserFrameAura(browser_frame, browser_view);
296 private:
297 DISALLOW_COPY_AND_ASSIGN(TestNativeBrowserFrameFactory);
300 class TabDragCaptureLostTest : public TabDragControllerTest {
301 public:
302 TabDragCaptureLostTest() {
303 NativeBrowserFrameFactory::Set(new TestNativeBrowserFrameFactory);
306 private:
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(
340 tab_1_center.x(),
341 tab_1_center.x(),
343 base::TimeDelta(),
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(),
350 tab_1_center.x(),
352 base::TimeDelta(),
353 ui::GestureEventDetails(ui::ET_GESTURE_END));
354 tab_strip->OnGestureEvent(&gesture_end);
355 EXPECT_FALSE(TabDragController::IsActive());
356 EXPECT_FALSE(tab_strip->IsDragSessionActive());
359 #endif
361 class DetachToBrowserTabDragControllerTest
362 : public TabDragControllerTest,
363 public ::testing::WithParamInterface<const char*> {
364 public:
365 DetachToBrowserTabDragControllerTest() {}
367 void SetUpOnMainThread() override {
368 #if defined(OS_CHROMEOS)
369 event_generator_.reset(
370 new ui::test::EventGenerator(ash::Shell::GetPrimaryRootWindow()));
371 #endif
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)
382 return;
383 #if defined(OS_CHROMEOS)
384 event_generator_.reset(new ui::test::EventGenerator(
385 new ScreenEventGeneratorDelegate(ash::wm::GetRootWindowAt(point))));
386 #endif
389 // The following methods update one of the mouse or touch input depending upon
390 // the InputSource.
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();
400 #else
401 NOTREACHED();
402 #endif
403 return true;
406 bool PressInput2() {
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);
413 #else
414 NOTREACHED();
415 #endif
416 return true;
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);
424 #else
425 NOTREACHED();
426 #endif
427 return true;
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);
435 #else
436 NOTREACHED();
437 #endif
438 return true;
441 bool DragInputToNotifyWhenDone(int x,
442 int y,
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));
449 #else
450 NOTREACHED();
451 #endif
452 return true;
455 bool DragInputToDelayedNotifyWhenDone(int x,
456 int y,
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));
464 #else
465 NOTREACHED();
466 #endif
467 return true;
470 bool DragInput2ToNotifyWhenDone(int x,
471 int y,
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);
478 #else
479 NOTREACHED();
480 #endif
481 return true;
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();
491 #else
492 NOTREACHED();
493 #endif
494 return true;
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);
504 #else
505 NOTREACHED();
506 #endif
507 return true;
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();
521 } else {
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
524 // pending tasks.
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(); }
536 private:
537 #if defined(OS_CHROMEOS)
538 scoped_ptr<ui::test::EventGenerator> event_generator_;
539 #endif
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.";
549 return;
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)
572 namespace {
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 {
577 public:
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,
588 &local_point);
589 return window->GetEventHandlerForPoint(local_point);
592 private:
593 DISALLOW_COPY_AND_ASSIGN(MaskedWindowTargeter);
596 } // namespace
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());
632 #endif // USE_AURA
634 namespace {
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
645 // the window.
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));
652 } // namespace
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
658 #else
659 #define MAYBE_DragToSeparateWindow DragToSeparateWindow
660 #endif
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());
708 namespace {
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();
722 #else
723 bool IsWindowPositionManaged(gfx::NativeWindow window) {
724 return true;
726 bool HasUserChangedWindowPositionOrSize(gfx::NativeWindow window) {
727 return false;
729 #endif
731 } // namespace
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
737 #else
738 #define MAYBE_DetachToOwnWindow DetachToOwnWindow
739 #endif
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());
744 // Add another tab.
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
799 #else
800 #define MAYBE_DetachFromFullsizeWindow DetachFromFullsizeWindow
801 #endif
802 // Tests that a tab can be dragged from a browser window that is resized to full
803 // screen.
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())
810 .work_area();
811 browser()->window()->SetBounds(work_area);
812 const gfx::Rect initial_bounds(browser()->window()->GetBounds());
813 // Add another tab.
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()));
850 EXPECT_TRUE(
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
868 #else
869 #define MAYBE_DetachToOwnWindowFromMaximizedWindow \
870 DetachToOwnWindowFromMaximizedWindow
871 #endif
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());
879 // Add another tab.
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) {
926 // Add another tab.
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
953 #else
954 #define MAYBE_DeleteTabWhileAttached DeleteTabWhileAttached
955 #endif
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.";
963 return;
966 // Add another tab.
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
971 // still attached.
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()));
993 namespace {
995 void DeleteWhileDetachedStep2(WebContents* tab) {
996 delete tab;
999 } // namespace
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
1005 #else
1006 #define MAYBE_DeleteTabWhileDetached DeleteTabWhileDetached
1007 #endif
1008 // Deletes a tab being dragged after dragging a tab so that a new window is
1009 // created.
1010 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1011 MAYBE_DeleteTabWhileDetached) {
1012 // Add another tab.
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()));
1035 namespace {
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.
1042 delete tab;
1043 // Cancel the drag.
1044 ui_controls::SendKeyPress(new_browser->window()->GetNativeWindow(),
1045 ui::VKEY_ESCAPE, false, false, false, false);
1048 } // namespace
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
1054 #else
1055 #define MAYBE_DeleteSourceDetached DeleteSourceDetached
1056 #endif
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) {
1061 // Add another tab.
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());
1088 namespace {
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,
1095 false, false);
1098 } // namespace
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
1104 #else
1105 #define MAYBE_PressEscapeWhileDetached PressEscapeWhileDetached
1106 #endif
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) {
1111 // Add another tab.
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());
1140 namespace {
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());
1148 } else {
1149 ASSERT_TRUE(test->ReleaseMouseAsync());
1153 } // namespace
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
1159 #else
1160 #define MAYBE_DragAll DragAll
1161 #endif
1162 // Selects multiple tabs and starts dragging the window.
1163 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, MAYBE_DragAll) {
1164 // Add another tab.
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
1171 // detach.
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());
1194 namespace {
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
1207 // the window.
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));
1214 } // namespace
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
1220 #else
1221 #define MAYBE_DragAllToSeparateWindow DragAllToSeparateWindow
1222 #endif
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());
1266 namespace {
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
1280 // the window.
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));
1287 } // namespace
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
1294 #else
1295 #define MAYBE_DragAllToSeparateWindowAndCancel DragAllToSeparateWindowAndCancel
1296 #endif
1297 // Creates two browsers, selects all tabs in first, drags into second, then hits
1298 // escape.
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());
1329 // Cancel the drag.
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
1350 #else
1351 #define MAYBE_DragDirectlyToSecondWindow DragDirectlyToSecondWindow
1352 #endif
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
1406 #else
1407 #define MAYBE_DragSingleTabToSeparateWindow DragSingleTabToSeparateWindow
1408 #endif
1409 // Creates two browsers, the first browser has a single tab and drags into the
1410 // second browser.
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());
1458 namespace {
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),
1473 0, false);
1474 observer.Wait();
1477 } // namespace
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
1483 #else
1484 #define MAYBE_CancelOnNewTabWhenDragging CancelOnNewTabWhenDragging
1485 #endif
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
1517 namespace {
1519 void DragInMaximizedWindowStep2(DetachToBrowserTabDragControllerTest* test,
1520 Browser* browser,
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());
1537 // Stops dragging.
1538 ASSERT_TRUE(test->ReleaseInput());
1541 } // namespace
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 {
1584 public:
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");
1595 private:
1596 DISALLOW_COPY_AND_ASSIGN(
1597 DetachToBrowserInSeparateDisplayTabDragControllerTest);
1600 // Subclass of DetachToBrowserTabDragControllerTest that runs tests only with
1601 // touch input.
1602 class DetachToBrowserTabDragControllerTestTouch
1603 : public DetachToBrowserTabDragControllerTest {
1604 public:
1605 DetachToBrowserTabDragControllerTestTouch() {}
1606 virtual ~DetachToBrowserTabDragControllerTestTouch() {}
1608 private:
1609 DISALLOW_COPY_AND_ASSIGN(DetachToBrowserTabDragControllerTestTouch);
1612 namespace {
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)));
1627 } // namespace
1629 // Drags from browser to a second display and releases input.
1630 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1631 DISABLED_DragSingleTabToSeparateWindowInSecondDisplay) {
1632 // Add another tab.
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(),
1644 tab_0_center.y()
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());
1678 namespace {
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
1690 // the window.
1691 gfx::Point target_point(
1692 GetCenterInScreenCoordinates(target_tab_strip->tab_at(0)));
1694 // Move it close to the beginning of the target tabstrip.
1695 target_point.set_x(
1696 target_point.x() - target_tab_strip->tab_at(0)->width() / 2 + 10);
1697 ASSERT_TRUE(test->DragInputToAsync(target_point));
1700 } // namespace
1702 // Drags from browser to another browser on a second display and releases input.
1703 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1704 DISABLED_DragTabToWindowInSeparateDisplay) {
1705 // Add another tab.
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) {
1755 // Add another tab.
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) {
1818 // Add another tab.
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) {
1885 // Add another tab.
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 {
1962 public:
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();
1978 private:
1979 DISALLOW_COPY_AND_ASSIGN(
1980 DifferentDeviceScaleFactorDisplayTabDragControllerTest);
1983 namespace {
1985 // The points where a tab is dragged in CursorDeviceScaleFactorStep.
1986 const struct DragPoint {
1987 int x;
1988 int y;
1989 } kDragPoints[] = {
1990 {300, 200},
1991 {399, 200},
1992 {500, 200},
1993 {400, 200},
1994 {300, 200},
1997 // The expected device scale factors before the cursor is moved to the
1998 // corresponding kDragPoints in CursorDeviceScaleFactorStep.
1999 const float kDeviceScaleFactorExpectations[] = {
2000 1.0f,
2001 1.0f,
2002 2.0f,
2003 2.0f,
2004 1.0f,
2007 static_assert(
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,
2016 size_t index) {
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)));
2027 } else {
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));
2035 } // namespace
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) {
2041 // Add another tab.
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();
2059 namespace {
2061 class DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest
2062 : public TabDragControllerTest {
2063 public:
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,
2075 ui_controls::DOWN);
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();
2089 private:
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(
2124 final_destination,
2125 base::Bind(&CancelDragTabToWindowInSeparateDisplayStep3,
2126 tab_strip, browser_list)));
2129 } // namespace
2131 // Drags from browser to a second display and releases input.
2132 IN_PROC_BROWSER_TEST_F(
2133 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest,
2134 DISABLED_CancelDragTabToWindowIn2ndDisplay) {
2135 // Add another tab.
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());
2176 // Add another tab.
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));
2214 namespace {
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());
2226 } // namespace
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());
2232 // Add another tab.
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)
2259 namespace {
2261 void DetachToDockedWindowNextStep(
2262 DetachToBrowserTabDragControllerTest* test,
2263 const gfx::Point& target_point,
2264 int iteration) {
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());
2269 if (!iteration) {
2270 ASSERT_TRUE(test->ReleaseInput());
2271 return;
2273 ASSERT_TRUE(test->DragInputToNotifyWhenDone(
2274 target_point.x(), target_point.y(),
2275 base::Bind(&DetachToDockedWindowNextStep,
2276 test,
2277 gfx::Point(target_point.x(), 1 + target_point.y()),
2278 iteration - 1)));
2281 } // namespace
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());
2290 // Add another tab.
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)),
2305 kNumIterations)));
2306 // Continue dragging enough times to go through snapping sequence and dock
2307 // the window.
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
2344 #endif
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"));
2363 #endif