Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / ui / views / tabs / tab_drag_controller_interactive_uitest.cc
blob36bca05c57acb0a689fd884797d0217883cfcc95
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_manager.h"
55 #include "ash/shell.h"
56 #include "ash/test/cursor_manager_test_api.h"
57 #include "ash/wm/coordinate_conversion.h"
58 #include "ash/wm/window_util.h"
59 #include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
60 #include "ui/aura/client/screen_position_client.h"
61 #include "ui/aura/test/event_generator_delegate_aura.h"
62 #include "ui/aura/window_event_dispatcher.h"
63 #include "ui/events/test/event_generator.h"
64 #endif
66 using content::WebContents;
68 namespace test {
70 namespace {
72 const char kTabDragControllerInteractiveUITestUserDataKey[] =
73 "TabDragControllerInteractiveUITestUserData";
75 class TabDragControllerInteractiveUITestUserData
76 : public base::SupportsUserData::Data {
77 public:
78 explicit TabDragControllerInteractiveUITestUserData(int id) : id_(id) {}
79 ~TabDragControllerInteractiveUITestUserData() override {}
80 int id() { return id_; }
82 private:
83 int id_;
86 } // namespace
88 class QuitDraggingObserver : public content::NotificationObserver {
89 public:
90 QuitDraggingObserver() {
91 registrar_.Add(this, chrome::NOTIFICATION_TAB_DRAG_LOOP_DONE,
92 content::NotificationService::AllSources());
95 void Observe(int type,
96 const content::NotificationSource& source,
97 const content::NotificationDetails& details) override {
98 DCHECK_EQ(chrome::NOTIFICATION_TAB_DRAG_LOOP_DONE, type);
99 base::MessageLoopForUI::current()->Quit();
100 delete this;
103 private:
104 ~QuitDraggingObserver() override {}
106 content::NotificationRegistrar registrar_;
108 DISALLOW_COPY_AND_ASSIGN(QuitDraggingObserver);
111 gfx::Point GetCenterInScreenCoordinates(const views::View* view) {
112 gfx::Point center(view->width() / 2, view->height() / 2);
113 views::View::ConvertPointToScreen(view, &center);
114 return center;
117 void SetID(WebContents* web_contents, int id) {
118 web_contents->SetUserData(&kTabDragControllerInteractiveUITestUserDataKey,
119 new TabDragControllerInteractiveUITestUserData(id));
122 void ResetIDs(TabStripModel* model, int start) {
123 for (int i = 0; i < model->count(); ++i)
124 SetID(model->GetWebContentsAt(i), start + i);
127 std::string IDString(TabStripModel* model) {
128 std::string result;
129 for (int i = 0; i < model->count(); ++i) {
130 if (i != 0)
131 result += " ";
132 WebContents* contents = model->GetWebContentsAt(i);
133 TabDragControllerInteractiveUITestUserData* user_data =
134 static_cast<TabDragControllerInteractiveUITestUserData*>(
135 contents->GetUserData(
136 &kTabDragControllerInteractiveUITestUserDataKey));
137 if (user_data)
138 result += base::IntToString(user_data->id());
139 else
140 result += "?";
142 return result;
145 // Creates a listener that quits the message loop when no longer dragging.
146 void QuitWhenNotDraggingImpl() {
147 new QuitDraggingObserver(); // QuitDraggingObserver deletes itself.
150 TabStrip* GetTabStripForBrowser(Browser* browser) {
151 BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
152 return static_cast<TabStrip*>(browser_view->tabstrip());
155 } // namespace test
157 using test::GetCenterInScreenCoordinates;
158 using test::SetID;
159 using test::ResetIDs;
160 using test::IDString;
161 using test::GetTabStripForBrowser;
163 TabDragControllerTest::TabDragControllerTest()
164 : native_browser_list(BrowserList::GetInstance(
165 chrome::HOST_DESKTOP_TYPE_NATIVE)) {
168 TabDragControllerTest::~TabDragControllerTest() {
171 void TabDragControllerTest::StopAnimating(TabStrip* tab_strip) {
172 tab_strip->StopAnimating(true);
175 void TabDragControllerTest::AddTabAndResetBrowser(Browser* browser) {
176 AddBlankTabAndShow(browser);
177 StopAnimating(GetTabStripForBrowser(browser));
178 ResetIDs(browser->tab_strip_model(), 0);
181 Browser* TabDragControllerTest::CreateAnotherWindowBrowserAndRelayout() {
182 // Create another browser.
183 Browser* browser2 = CreateBrowser(browser()->profile());
184 ResetIDs(browser2->tab_strip_model(), 100);
186 // Resize the two windows so they're right next to each other.
187 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
188 browser()->window()->GetNativeWindow()).work_area();
189 gfx::Size half_size =
190 gfx::Size(work_area.width() / 3 - 10, work_area.height() / 2 - 10);
191 browser()->window()->SetBounds(gfx::Rect(work_area.origin(), half_size));
192 browser2->window()->SetBounds(gfx::Rect(
193 work_area.x() + half_size.width(), work_area.y(),
194 half_size.width(), half_size.height()));
195 return browser2;
198 namespace {
200 enum InputSource {
201 INPUT_SOURCE_MOUSE = 0,
202 INPUT_SOURCE_TOUCH = 1
205 int GetDetachY(TabStrip* tab_strip) {
206 return std::max(TabDragController::kTouchVerticalDetachMagnetism,
207 TabDragController::kVerticalDetachMagnetism) +
208 tab_strip->height() + 1;
211 bool GetIsDragged(Browser* browser) {
212 #if !defined(USE_ASH) || defined(OS_WIN) // TODO(win_ash)
213 return false;
214 #else
215 return ash::wm::GetWindowState(browser->window()->GetNativeWindow())->
216 is_dragged();
217 #endif
220 } // namespace
222 #if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash)
223 class ScreenEventGeneratorDelegate
224 : public aura::test::EventGeneratorDelegateAura {
225 public:
226 explicit ScreenEventGeneratorDelegate(aura::Window* root_window)
227 : root_window_(root_window) {}
228 ~ScreenEventGeneratorDelegate() override {}
230 // EventGeneratorDelegateAura overrides:
231 aura::WindowTreeHost* GetHostAt(const gfx::Point& point) const override {
232 return root_window_->GetHost();
235 aura::client::ScreenPositionClient* GetScreenPositionClient(
236 const aura::Window* window) const override {
237 return aura::client::GetScreenPositionClient(root_window_);
240 private:
241 aura::Window* root_window_;
243 DISALLOW_COPY_AND_ASSIGN(ScreenEventGeneratorDelegate);
246 #endif
248 #if !defined(OS_CHROMEOS)
250 // Following classes verify a crash scenario. Specifically on Windows when focus
251 // changes it can trigger capture being lost. This was causing a crash in tab
252 // dragging as it wasn't set up to handle this scenario. These classes
253 // synthesize this scenario.
255 // Allows making ClearNativeFocus() invoke ReleaseCapture().
256 class TestDesktopBrowserFrameAura : public DesktopBrowserFrameAura {
257 public:
258 TestDesktopBrowserFrameAura(
259 BrowserFrame* browser_frame,
260 BrowserView* browser_view)
261 : DesktopBrowserFrameAura(browser_frame, browser_view),
262 release_capture_(false) {}
263 ~TestDesktopBrowserFrameAura() override {}
265 void ReleaseCaptureOnNextClear() {
266 release_capture_ = true;
269 void ClearNativeFocus() override {
270 views::DesktopNativeWidgetAura::ClearNativeFocus();
271 if (release_capture_) {
272 release_capture_ = false;
273 GetWidget()->ReleaseCapture();
277 private:
278 // If true ReleaseCapture() is invoked in ClearNativeFocus().
279 bool release_capture_;
281 DISALLOW_COPY_AND_ASSIGN(TestDesktopBrowserFrameAura);
284 // Factory for creating a TestDesktopBrowserFrameAura.
285 class TestNativeBrowserFrameFactory : public NativeBrowserFrameFactory {
286 public:
287 TestNativeBrowserFrameFactory() {}
288 ~TestNativeBrowserFrameFactory() override {}
290 NativeBrowserFrame* Create(BrowserFrame* browser_frame,
291 BrowserView* browser_view) override {
292 return new TestDesktopBrowserFrameAura(browser_frame, browser_view);
295 private:
296 DISALLOW_COPY_AND_ASSIGN(TestNativeBrowserFrameFactory);
299 class TabDragCaptureLostTest : public TabDragControllerTest {
300 public:
301 TabDragCaptureLostTest() {
302 NativeBrowserFrameFactory::Set(new TestNativeBrowserFrameFactory);
305 private:
306 DISALLOW_COPY_AND_ASSIGN(TabDragCaptureLostTest);
309 // See description above for details.
310 IN_PROC_BROWSER_TEST_F(TabDragCaptureLostTest, ReleaseCaptureOnDrag) {
311 AddTabAndResetBrowser(browser());
313 TabStrip* tab_strip = GetTabStripForBrowser(browser());
314 gfx::Point tab_1_center(GetCenterInScreenCoordinates(tab_strip->tab_at(1)));
315 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_1_center) &&
316 ui_test_utils::SendMouseEventsSync(
317 ui_controls::LEFT, ui_controls::DOWN));
318 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
319 TestDesktopBrowserFrameAura* frame =
320 static_cast<TestDesktopBrowserFrameAura*>(
321 BrowserView::GetBrowserViewForBrowser(browser())->GetWidget()->
322 native_widget_private());
323 // Invoke ReleaseCaptureOnDrag() so that when the drag happens and focus
324 // changes capture is released and the drag cancels.
325 frame->ReleaseCaptureOnNextClear();
326 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center));
327 EXPECT_FALSE(tab_strip->IsDragSessionActive());
330 IN_PROC_BROWSER_TEST_F(TabDragControllerTest, GestureEndShouldEndDragTest) {
331 AddTabAndResetBrowser(browser());
333 TabStrip* tab_strip = GetTabStripForBrowser(browser());
335 Tab* tab1 = tab_strip->tab_at(1);
336 gfx::Point tab_1_center(tab1->width() / 2, tab1->height() / 2);
338 ui::GestureEvent gesture_tap_down(
339 tab_1_center.x(),
340 tab_1_center.x(),
342 base::TimeDelta(),
343 ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
344 tab_strip->MaybeStartDrag(tab1, gesture_tap_down,
345 tab_strip->GetSelectionModel());
346 EXPECT_TRUE(TabDragController::IsActive());
348 ui::GestureEvent gesture_end(tab_1_center.x(),
349 tab_1_center.x(),
351 base::TimeDelta(),
352 ui::GestureEventDetails(ui::ET_GESTURE_END));
353 tab_strip->OnGestureEvent(&gesture_end);
354 EXPECT_FALSE(TabDragController::IsActive());
355 EXPECT_FALSE(tab_strip->IsDragSessionActive());
358 #endif
360 class DetachToBrowserTabDragControllerTest
361 : public TabDragControllerTest,
362 public ::testing::WithParamInterface<const char*> {
363 public:
364 DetachToBrowserTabDragControllerTest() {}
366 void SetUpOnMainThread() override {
367 #if defined(OS_CHROMEOS)
368 event_generator_.reset(
369 new ui::test::EventGenerator(ash::Shell::GetPrimaryRootWindow()));
370 #endif
373 InputSource input_source() const {
374 return strstr(GetParam(), "mouse") ?
375 INPUT_SOURCE_MOUSE : INPUT_SOURCE_TOUCH;
378 // Set root window from a point in screen coordinates
379 void SetEventGeneratorRootWindow(const gfx::Point& point) {
380 if (input_source() == INPUT_SOURCE_MOUSE)
381 return;
382 #if defined(OS_CHROMEOS)
383 event_generator_.reset(new ui::test::EventGenerator(
384 new ScreenEventGeneratorDelegate(ash::wm::GetRootWindowAt(point))));
385 #endif
388 // The following methods update one of the mouse or touch input depending upon
389 // the InputSource.
390 bool PressInput(const gfx::Point& location) {
391 if (input_source() == INPUT_SOURCE_MOUSE) {
392 return ui_test_utils::SendMouseMoveSync(location) &&
393 ui_test_utils::SendMouseEventsSync(
394 ui_controls::LEFT, ui_controls::DOWN);
396 #if defined(OS_CHROMEOS)
397 event_generator_->set_current_location(location);
398 event_generator_->PressTouch();
399 #else
400 NOTREACHED();
401 #endif
402 return true;
405 bool PressInput2() {
406 // Second touch input is only used for touch sequence tests.
407 EXPECT_EQ(INPUT_SOURCE_TOUCH, input_source());
408 #if defined(OS_CHROMEOS)
409 event_generator_->set_current_location(
410 event_generator_->current_location());
411 event_generator_->PressTouchId(1);
412 #else
413 NOTREACHED();
414 #endif
415 return true;
418 bool DragInputTo(const gfx::Point& location) {
419 if (input_source() == INPUT_SOURCE_MOUSE)
420 return ui_test_utils::SendMouseMoveSync(location);
421 #if defined(OS_CHROMEOS)
422 event_generator_->MoveTouch(location);
423 #else
424 NOTREACHED();
425 #endif
426 return true;
429 bool DragInputToAsync(const gfx::Point& location) {
430 if (input_source() == INPUT_SOURCE_MOUSE)
431 return ui_controls::SendMouseMove(location.x(), location.y());
432 #if defined(OS_CHROMEOS)
433 event_generator_->MoveTouch(location);
434 #else
435 NOTREACHED();
436 #endif
437 return true;
440 bool DragInputToNotifyWhenDone(int x,
441 int y,
442 const base::Closure& task) {
443 if (input_source() == INPUT_SOURCE_MOUSE)
444 return ui_controls::SendMouseMoveNotifyWhenDone(x, y, task);
445 #if defined(OS_CHROMEOS)
446 base::MessageLoop::current()->PostTask(FROM_HERE, task);
447 event_generator_->MoveTouch(gfx::Point(x, y));
448 #else
449 NOTREACHED();
450 #endif
451 return true;
454 bool DragInputToDelayedNotifyWhenDone(int x,
455 int y,
456 const base::Closure& task,
457 base::TimeDelta delay) {
458 if (input_source() == INPUT_SOURCE_MOUSE)
459 return ui_controls::SendMouseMoveNotifyWhenDone(x, y, task);
460 #if defined(OS_CHROMEOS)
461 base::MessageLoop::current()->PostDelayedTask(FROM_HERE, task, delay);
462 event_generator_->MoveTouch(gfx::Point(x, y));
463 #else
464 NOTREACHED();
465 #endif
466 return true;
469 bool DragInput2ToNotifyWhenDone(int x,
470 int y,
471 const base::Closure& task) {
472 if (input_source() == INPUT_SOURCE_MOUSE)
473 return ui_controls::SendMouseMoveNotifyWhenDone(x, y, task);
474 #if defined(OS_CHROMEOS)
475 base::MessageLoop::current()->PostTask(FROM_HERE, task);
476 event_generator_->MoveTouchId(gfx::Point(x, y), 1);
477 #else
478 NOTREACHED();
479 #endif
480 return true;
483 bool ReleaseInput() {
484 if (input_source() == INPUT_SOURCE_MOUSE) {
485 return ui_test_utils::SendMouseEventsSync(
486 ui_controls::LEFT, ui_controls::UP);
488 #if defined(OS_CHROMEOS)
489 event_generator_->ReleaseTouch();
490 #else
491 NOTREACHED();
492 #endif
493 return true;
496 bool ReleaseInput2() {
497 if (input_source() == INPUT_SOURCE_MOUSE) {
498 return ui_test_utils::SendMouseEventsSync(
499 ui_controls::LEFT, ui_controls::UP);
501 #if defined(OS_CHROMEOS)
502 event_generator_->ReleaseTouchId(1);
503 #else
504 NOTREACHED();
505 #endif
506 return true;
509 bool ReleaseMouseAsync() {
510 return input_source() == INPUT_SOURCE_MOUSE &&
511 ui_controls::SendMouseEvents(ui_controls::LEFT, ui_controls::UP);
514 void QuitWhenNotDragging() {
515 if (input_source() == INPUT_SOURCE_MOUSE) {
516 // Schedule observer to quit message loop when done dragging. This has to
517 // be async so the message loop can run.
518 test::QuitWhenNotDraggingImpl();
519 base::MessageLoop::current()->Run();
520 } else {
521 // Touch events are sync, so we know we're not in a drag session. But some
522 // tests rely on the browser fully closing, which is async. So, run all
523 // pending tasks.
524 base::RunLoop run_loop;
525 run_loop.RunUntilIdle();
529 void AddBlankTabAndShow(Browser* browser) {
530 InProcessBrowserTest::AddBlankTabAndShow(browser);
533 Browser* browser() const { return InProcessBrowserTest::browser(); }
535 private:
536 #if defined(OS_CHROMEOS)
537 scoped_ptr<ui::test::EventGenerator> event_generator_;
538 #endif
540 DISALLOW_COPY_AND_ASSIGN(DetachToBrowserTabDragControllerTest);
543 // Creates a browser with two tabs, drags the second to the first.
544 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, DragInSameWindow) {
545 // TODO(sky): this won't work with touch as it requires a long press.
546 if (input_source() == INPUT_SOURCE_TOUCH) {
547 VLOG(1) << "Test is DISABLED for touch input.";
548 return;
551 AddTabAndResetBrowser(browser());
553 TabStrip* tab_strip = GetTabStripForBrowser(browser());
554 TabStripModel* model = browser()->tab_strip_model();
556 gfx::Point tab_1_center(GetCenterInScreenCoordinates(tab_strip->tab_at(1)));
557 ASSERT_TRUE(PressInput(tab_1_center));
558 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
559 ASSERT_TRUE(DragInputTo(tab_0_center));
560 ASSERT_TRUE(ReleaseInput());
561 EXPECT_EQ("1 0", IDString(model));
562 EXPECT_FALSE(TabDragController::IsActive());
563 EXPECT_FALSE(tab_strip->IsDragSessionActive());
565 // The tab strip should no longer have capture because the drag was ended and
566 // mouse/touch was released.
567 EXPECT_FALSE(tab_strip->GetWidget()->HasCapture());
570 #if defined(USE_AURA)
571 namespace {
573 // We need both MaskedWindowTargeter and MaskedWindowDelegate as they
574 // are used in two different pathes. crbug.com/493354.
575 class MaskedWindowTargeter : public aura::WindowTargeter {
576 public:
577 MaskedWindowTargeter() {}
578 ~MaskedWindowTargeter() override {}
580 // aura::WindowTargeter:
581 bool EventLocationInsideBounds(aura::Window* target,
582 const ui::LocatedEvent& event) const override {
583 aura::Window* window = static_cast<aura::Window*>(target);
584 gfx::Point local_point = event.location();
585 if (window->parent())
586 aura::Window::ConvertPointToTarget(window->parent(), window,
587 &local_point);
588 return window->GetEventHandlerForPoint(local_point);
591 private:
592 DISALLOW_COPY_AND_ASSIGN(MaskedWindowTargeter);
595 } // namespace
597 // The logic to find the target tabstrip should take the window mask into
598 // account. This test hangs without the fix. crbug.com/473080.
599 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
600 DragWithMaskedWindows) {
601 AddTabAndResetBrowser(browser());
603 aura::Window* browser_window = browser()->window()->GetNativeWindow();
604 const gfx::Rect bounds = browser_window->GetBoundsInScreen();
605 aura::test::MaskedWindowDelegate masked_window_delegate(
606 gfx::Rect(bounds.width() - 10, 0, 10, bounds.height()));
607 gfx::Rect test(bounds);
608 masked_window_delegate.set_can_focus(false);
609 scoped_ptr<aura::Window> masked_window(
610 aura::test::CreateTestWindowWithDelegate(&masked_window_delegate, 10,
611 test, browser_window->parent()));
612 masked_window->SetEventTargeter(
613 scoped_ptr<ui::EventTargeter>(new MaskedWindowTargeter()));
615 ASSERT_FALSE(masked_window->GetEventHandlerForPoint(
616 gfx::Point(bounds.width() - 11, 0)));
617 ASSERT_TRUE(masked_window->GetEventHandlerForPoint(
618 gfx::Point(bounds.width() - 9, 0)));
619 TabStrip* tab_strip = GetTabStripForBrowser(browser());
620 TabStripModel* model = browser()->tab_strip_model();
622 gfx::Point tab_1_center(GetCenterInScreenCoordinates(tab_strip->tab_at(1)));
623 ASSERT_TRUE(PressInput(tab_1_center));
624 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
625 ASSERT_TRUE(DragInputTo(tab_0_center));
626 ASSERT_TRUE(ReleaseInput());
627 EXPECT_EQ("1 0", IDString(model));
628 EXPECT_FALSE(TabDragController::IsActive());
629 EXPECT_FALSE(tab_strip->IsDragSessionActive());
631 #endif // USE_AURA
633 namespace {
635 // Invoked from the nested message loop.
636 void DragToSeparateWindowStep2(DetachToBrowserTabDragControllerTest* test,
637 TabStrip* not_attached_tab_strip,
638 TabStrip* target_tab_strip) {
639 ASSERT_FALSE(not_attached_tab_strip->IsDragSessionActive());
640 ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
641 ASSERT_TRUE(TabDragController::IsActive());
643 // Drag to target_tab_strip. This should stop the nested loop from dragging
644 // the window.
645 gfx::Point target_point(target_tab_strip->width() -1,
646 target_tab_strip->height() / 2);
647 views::View::ConvertPointToScreen(target_tab_strip, &target_point);
648 ASSERT_TRUE(test->DragInputToAsync(target_point));
651 } // namespace
653 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
654 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
655 // compositor. crbug.com/331924
656 #define MAYBE_DragToSeparateWindow DISABLED_DragToSeparateWindow
657 #else
658 #define MAYBE_DragToSeparateWindow DragToSeparateWindow
659 #endif
660 // Creates two browsers, drags from first into second.
661 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
662 MAYBE_DragToSeparateWindow) {
663 TabStrip* tab_strip = GetTabStripForBrowser(browser());
665 // Add another tab to browser().
666 AddTabAndResetBrowser(browser());
668 // Create another browser.
669 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
670 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
672 // Move to the first tab and drag it enough so that it detaches, but not
673 // enough that it attaches to browser2.
674 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
675 ASSERT_TRUE(PressInput(tab_0_center));
676 ASSERT_TRUE(DragInputToNotifyWhenDone(
677 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
678 base::Bind(&DragToSeparateWindowStep2,
679 this, tab_strip, tab_strip2)));
680 QuitWhenNotDragging();
682 // Should now be attached to tab_strip2.
683 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
684 ASSERT_FALSE(tab_strip->IsDragSessionActive());
685 ASSERT_TRUE(TabDragController::IsActive());
686 EXPECT_FALSE(GetIsDragged(browser()));
688 // Release mouse or touch, stopping the drag session.
689 ASSERT_TRUE(ReleaseInput());
690 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
691 ASSERT_FALSE(tab_strip->IsDragSessionActive());
692 ASSERT_FALSE(TabDragController::IsActive());
693 EXPECT_EQ("100 0", IDString(browser2->tab_strip_model()));
694 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
695 EXPECT_FALSE(GetIsDragged(browser2));
697 // Both windows should not be maximized
698 EXPECT_FALSE(browser()->window()->IsMaximized());
699 EXPECT_FALSE(browser2->window()->IsMaximized());
701 // The tab strip should no longer have capture because the drag was ended and
702 // mouse/touch was released.
703 EXPECT_FALSE(tab_strip->GetWidget()->HasCapture());
704 EXPECT_FALSE(tab_strip2->GetWidget()->HasCapture());
707 namespace {
709 void DetachToOwnWindowStep2(DetachToBrowserTabDragControllerTest* test) {
710 if (test->input_source() == INPUT_SOURCE_TOUCH)
711 ASSERT_TRUE(test->ReleaseInput());
714 #if defined(OS_CHROMEOS)
715 bool IsWindowPositionManaged(aura::Window* window) {
716 return ash::wm::GetWindowState(window)->window_position_managed();
718 bool HasUserChangedWindowPositionOrSize(aura::Window* window) {
719 return ash::wm::GetWindowState(window)->bounds_changed_by_user();
721 #else
722 bool IsWindowPositionManaged(gfx::NativeWindow window) {
723 return true;
725 bool HasUserChangedWindowPositionOrSize(gfx::NativeWindow window) {
726 return false;
728 #endif
730 } // namespace
732 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
733 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
734 // compositor. crbug.com/331924
735 #define MAYBE_DetachToOwnWindow DISABLED_DetachToOwnWindow
736 #else
737 #define MAYBE_DetachToOwnWindow DetachToOwnWindow
738 #endif
739 // Drags from browser to separate window and releases mouse.
740 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
741 MAYBE_DetachToOwnWindow) {
742 const gfx::Rect initial_bounds(browser()->window()->GetBounds());
743 // Add another tab.
744 AddTabAndResetBrowser(browser());
745 TabStrip* tab_strip = GetTabStripForBrowser(browser());
747 // Move to the first tab and drag it enough so that it detaches.
748 gfx::Point tab_0_center(
749 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
750 ASSERT_TRUE(PressInput(tab_0_center));
751 ASSERT_TRUE(DragInputToNotifyWhenDone(
752 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
753 base::Bind(&DetachToOwnWindowStep2, this)));
754 if (input_source() == INPUT_SOURCE_MOUSE) {
755 ASSERT_TRUE(ReleaseMouseAsync());
756 QuitWhenNotDragging();
759 // Should no longer be dragging.
760 ASSERT_FALSE(tab_strip->IsDragSessionActive());
761 ASSERT_FALSE(TabDragController::IsActive());
763 // There should now be another browser.
764 ASSERT_EQ(2u, native_browser_list->size());
765 Browser* new_browser = native_browser_list->get(1);
766 ASSERT_TRUE(new_browser->window()->IsActive());
767 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
768 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
770 EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
771 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
773 // The bounds of the initial window should not have changed.
774 EXPECT_EQ(initial_bounds.ToString(),
775 browser()->window()->GetBounds().ToString());
777 EXPECT_FALSE(GetIsDragged(browser()));
778 EXPECT_FALSE(GetIsDragged(new_browser));
779 // After this both windows should still be manageable.
780 EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
781 EXPECT_TRUE(IsWindowPositionManaged(
782 new_browser->window()->GetNativeWindow()));
784 // Both windows should not be maximized
785 EXPECT_FALSE(browser()->window()->IsMaximized());
786 EXPECT_FALSE(new_browser->window()->IsMaximized());
788 // The tab strip should no longer have capture because the drag was ended and
789 // mouse/touch was released.
790 EXPECT_FALSE(tab_strip->GetWidget()->HasCapture());
791 EXPECT_FALSE(tab_strip2->GetWidget()->HasCapture());
794 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
795 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
796 // compositor. crbug.com/331924
797 #define MAYBE_DetachFromFullsizeWindow DISABLED_DetachFromFullsizeWindow
798 #else
799 #define MAYBE_DetachFromFullsizeWindow DetachFromFullsizeWindow
800 #endif
801 // Tests that a tab can be dragged from a browser window that is resized to full
802 // screen.
803 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
804 MAYBE_DetachFromFullsizeWindow) {
805 // Resize the browser window so that it is as big as the work area.
806 gfx::Rect work_area =
807 gfx::Screen::GetNativeScreen()
808 ->GetDisplayNearestWindow(browser()->window()->GetNativeWindow())
809 .work_area();
810 browser()->window()->SetBounds(work_area);
811 const gfx::Rect initial_bounds(browser()->window()->GetBounds());
812 // Add another tab.
813 AddTabAndResetBrowser(browser());
814 TabStrip* tab_strip = GetTabStripForBrowser(browser());
816 // Move to the first tab and drag it enough so that it detaches.
817 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
818 ASSERT_TRUE(PressInput(tab_0_center));
819 ASSERT_TRUE(DragInputToNotifyWhenDone(
820 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
821 base::Bind(&DetachToOwnWindowStep2, this)));
822 if (input_source() == INPUT_SOURCE_MOUSE) {
823 ASSERT_TRUE(ReleaseMouseAsync());
824 QuitWhenNotDragging();
827 // Should no longer be dragging.
828 ASSERT_FALSE(tab_strip->IsDragSessionActive());
829 ASSERT_FALSE(TabDragController::IsActive());
831 // There should now be another browser.
832 ASSERT_EQ(2u, native_browser_list->size());
833 Browser* new_browser = native_browser_list->get(1);
834 ASSERT_TRUE(new_browser->window()->IsActive());
835 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
836 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
838 EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
839 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
841 // The bounds of the initial window should not have changed.
842 EXPECT_EQ(initial_bounds.ToString(),
843 browser()->window()->GetBounds().ToString());
845 EXPECT_FALSE(GetIsDragged(browser()));
846 EXPECT_FALSE(GetIsDragged(new_browser));
847 // After this both windows should still be manageable.
848 EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
849 EXPECT_TRUE(
850 IsWindowPositionManaged(new_browser->window()->GetNativeWindow()));
852 // Only second window should be maximized.
853 EXPECT_FALSE(browser()->window()->IsMaximized());
854 EXPECT_TRUE(new_browser->window()->IsMaximized());
856 // The tab strip should no longer have capture because the drag was ended and
857 // mouse/touch was released.
858 EXPECT_FALSE(tab_strip->GetWidget()->HasCapture());
859 EXPECT_FALSE(tab_strip2->GetWidget()->HasCapture());
862 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
863 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
864 // compositor. crbug.com/331924
865 #define MAYBE_DetachToOwnWindowFromMaximizedWindow \
866 DISABLED_DetachToOwnWindowFromMaximizedWindow
867 #else
868 #define MAYBE_DetachToOwnWindowFromMaximizedWindow \
869 DetachToOwnWindowFromMaximizedWindow
870 #endif
871 // Drags from browser to a separate window and releases mouse.
872 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
873 MAYBE_DetachToOwnWindowFromMaximizedWindow) {
874 // Maximize the initial browser window.
875 browser()->window()->Maximize();
876 ASSERT_TRUE(browser()->window()->IsMaximized());
878 // Add another tab.
879 AddTabAndResetBrowser(browser());
880 TabStrip* tab_strip = GetTabStripForBrowser(browser());
882 // Move to the first tab and drag it enough so that it detaches.
883 gfx::Point tab_0_center(
884 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
885 ASSERT_TRUE(PressInput(tab_0_center));
886 ASSERT_TRUE(DragInputToNotifyWhenDone(
887 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
888 base::Bind(&DetachToOwnWindowStep2, this)));
889 if (input_source() == INPUT_SOURCE_MOUSE) {
890 ASSERT_TRUE(ReleaseMouseAsync());
891 QuitWhenNotDragging();
894 // Should no longer be dragging.
895 ASSERT_FALSE(tab_strip->IsDragSessionActive());
896 ASSERT_FALSE(TabDragController::IsActive());
898 // There should now be another browser.
899 ASSERT_EQ(2u, native_browser_list->size());
900 Browser* new_browser = native_browser_list->get(1);
901 ASSERT_TRUE(new_browser->window()->IsActive());
902 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
903 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
905 EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
906 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
908 // The bounds of the initial window should not have changed.
909 EXPECT_TRUE(browser()->window()->IsMaximized());
911 EXPECT_FALSE(GetIsDragged(browser()));
912 EXPECT_FALSE(GetIsDragged(new_browser));
913 // After this both windows should still be manageable.
914 EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
915 EXPECT_TRUE(IsWindowPositionManaged(
916 new_browser->window()->GetNativeWindow()));
918 // The new window should be maximized.
919 EXPECT_TRUE(new_browser->window()->IsMaximized());
922 // Deletes a tab being dragged before the user moved enough to start a drag.
923 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
924 DeleteBeforeStartedDragging) {
925 // Add another tab.
926 AddTabAndResetBrowser(browser());
927 TabStrip* tab_strip = GetTabStripForBrowser(browser());
929 // Click on the first tab, but don't move it.
930 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
931 ASSERT_TRUE(PressInput(tab_0_center));
933 // Should be dragging.
934 ASSERT_TRUE(tab_strip->IsDragSessionActive());
935 ASSERT_TRUE(TabDragController::IsActive());
937 // Delete the tab being dragged.
938 delete browser()->tab_strip_model()->GetWebContentsAt(0);
940 // Should have canceled dragging.
941 ASSERT_FALSE(tab_strip->IsDragSessionActive());
942 ASSERT_FALSE(TabDragController::IsActive());
944 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
945 EXPECT_FALSE(GetIsDragged(browser()));
948 #if defined(OS_CHROMEOS)
949 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
950 // compositor. crbug.com/331924
951 #define MAYBE_DeleteTabWhileAttached DISABLED_DeleteTabWhileAttached
952 #else
953 #define MAYBE_DeleteTabWhileAttached DeleteTabWhileAttached
954 #endif
955 // Deletes a tab being dragged while still attached.
956 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
957 MAYBE_DeleteTabWhileAttached) {
958 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
959 // compositor. crbug.com/331924
960 if (input_source() == INPUT_SOURCE_MOUSE) {
961 VLOG(1) << "Test is DISABLED for mouse input.";
962 return;
965 // Add another tab.
966 AddTabAndResetBrowser(browser());
967 TabStrip* tab_strip = GetTabStripForBrowser(browser());
969 // Click on the first tab and move it enough so that it starts dragging but is
970 // still attached.
971 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
972 ASSERT_TRUE(PressInput(tab_0_center));
973 ASSERT_TRUE(DragInputTo(
974 gfx::Point(tab_0_center.x() + 20, tab_0_center.y())));
976 // Should be dragging.
977 ASSERT_TRUE(tab_strip->IsDragSessionActive());
978 ASSERT_TRUE(TabDragController::IsActive());
980 // Delete the tab being dragged.
981 delete browser()->tab_strip_model()->GetWebContentsAt(0);
983 // Should have canceled dragging.
984 ASSERT_FALSE(tab_strip->IsDragSessionActive());
985 ASSERT_FALSE(TabDragController::IsActive());
987 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
989 EXPECT_FALSE(GetIsDragged(browser()));
992 namespace {
994 void DeleteWhileDetachedStep2(WebContents* tab) {
995 delete tab;
998 } // namespace
1000 #if defined(OS_CHROMEOS)
1001 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1002 // compositor. crbug.com/331924
1003 #define MAYBE_DeleteTabWhileDetached DISABLED_DeleteTabWhileDetached
1004 #else
1005 #define MAYBE_DeleteTabWhileDetached DeleteTabWhileDetached
1006 #endif
1007 // Deletes a tab being dragged after dragging a tab so that a new window is
1008 // created.
1009 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1010 MAYBE_DeleteTabWhileDetached) {
1011 // Add another tab.
1012 AddTabAndResetBrowser(browser());
1013 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1015 // Move to the first tab and drag it enough so that it detaches.
1016 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1017 WebContents* to_delete =
1018 browser()->tab_strip_model()->GetWebContentsAt(0);
1019 ASSERT_TRUE(PressInput(tab_0_center));
1020 ASSERT_TRUE(DragInputToNotifyWhenDone(
1021 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1022 base::Bind(&DeleteWhileDetachedStep2, to_delete)));
1023 QuitWhenNotDragging();
1025 // Should not be dragging.
1026 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1027 ASSERT_FALSE(TabDragController::IsActive());
1029 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1031 EXPECT_FALSE(GetIsDragged(browser()));
1034 namespace {
1036 void DeleteSourceDetachedStep2(WebContents* tab,
1037 const BrowserList* browser_list) {
1038 ASSERT_EQ(2u, browser_list->size());
1039 Browser* new_browser = browser_list->get(1);
1040 // This ends up closing the source window.
1041 delete tab;
1042 // Cancel the drag.
1043 ui_controls::SendKeyPress(new_browser->window()->GetNativeWindow(),
1044 ui::VKEY_ESCAPE, false, false, false, false);
1047 } // namespace
1049 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1050 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1051 // compositor. crbug.com/331924
1052 #define MAYBE_DeleteSourceDetached DISABLED_DeleteSourceDetached
1053 #else
1054 #define MAYBE_DeleteSourceDetached DeleteSourceDetached
1055 #endif
1056 // Detaches a tab and while detached deletes a tab from the source so that the
1057 // source window closes then presses escape to cancel the drag.
1058 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1059 MAYBE_DeleteSourceDetached) {
1060 // Add another tab.
1061 AddTabAndResetBrowser(browser());
1062 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1064 // Move to the first tab and drag it enough so that it detaches.
1065 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1066 WebContents* to_delete = browser()->tab_strip_model()->GetWebContentsAt(1);
1067 ASSERT_TRUE(PressInput(tab_0_center));
1068 ASSERT_TRUE(DragInputToNotifyWhenDone(
1069 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1070 base::Bind(&DeleteSourceDetachedStep2, to_delete, native_browser_list)));
1071 QuitWhenNotDragging();
1073 // Should not be dragging.
1074 ASSERT_EQ(1u, native_browser_list->size());
1075 Browser* new_browser = native_browser_list->get(0);
1076 ASSERT_FALSE(GetTabStripForBrowser(new_browser)->IsDragSessionActive());
1077 ASSERT_FALSE(TabDragController::IsActive());
1079 EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
1081 EXPECT_FALSE(GetIsDragged(new_browser));
1083 // Remaining browser window should not be maximized
1084 EXPECT_FALSE(new_browser->window()->IsMaximized());
1087 namespace {
1089 void PressEscapeWhileDetachedStep2(const BrowserList* browser_list) {
1090 ASSERT_EQ(2u, browser_list->size());
1091 Browser* new_browser = browser_list->get(1);
1092 ui_controls::SendKeyPress(
1093 new_browser->window()->GetNativeWindow(), ui::VKEY_ESCAPE, false, false,
1094 false, false);
1097 } // namespace
1099 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1100 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1101 // compositor. crbug.com/331924
1102 #define MAYBE_PressEscapeWhileDetached DISABLED_PressEscapeWhileDetached
1103 #else
1104 #define MAYBE_PressEscapeWhileDetached PressEscapeWhileDetached
1105 #endif
1106 // This is disabled until NativeViewHost::Detach really detaches.
1107 // Detaches a tab and while detached presses escape to revert the drag.
1108 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1109 MAYBE_PressEscapeWhileDetached) {
1110 // Add another tab.
1111 AddTabAndResetBrowser(browser());
1112 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1114 // Move to the first tab and drag it enough so that it detaches.
1115 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1116 ASSERT_TRUE(PressInput(tab_0_center));
1117 ASSERT_TRUE(DragInputToNotifyWhenDone(
1118 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1119 base::Bind(&PressEscapeWhileDetachedStep2, native_browser_list)));
1120 QuitWhenNotDragging();
1122 // Should not be dragging.
1123 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1124 ASSERT_FALSE(TabDragController::IsActive());
1126 // And there should only be one window.
1127 EXPECT_EQ(1u, native_browser_list->size());
1129 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
1131 // Remaining browser window should not be maximized
1132 EXPECT_FALSE(browser()->window()->IsMaximized());
1134 // The tab strip should no longer have capture because the drag was ended and
1135 // mouse/touch was released.
1136 EXPECT_FALSE(tab_strip->GetWidget()->HasCapture());
1139 namespace {
1141 void DragAllStep2(DetachToBrowserTabDragControllerTest* test,
1142 const BrowserList* browser_list) {
1143 // Should only be one window.
1144 ASSERT_EQ(1u, browser_list->size());
1145 if (test->input_source() == INPUT_SOURCE_TOUCH) {
1146 ASSERT_TRUE(test->ReleaseInput());
1147 } else {
1148 ASSERT_TRUE(test->ReleaseMouseAsync());
1152 } // namespace
1154 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1155 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1156 // compositor. crbug.com/331924
1157 #define MAYBE_DragAll DISABLED_DragAll
1158 #else
1159 #define MAYBE_DragAll DragAll
1160 #endif
1161 // Selects multiple tabs and starts dragging the window.
1162 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, MAYBE_DragAll) {
1163 // Add another tab.
1164 AddTabAndResetBrowser(browser());
1165 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1166 browser()->tab_strip_model()->AddTabAtToSelection(0);
1167 browser()->tab_strip_model()->AddTabAtToSelection(1);
1169 // Move to the first tab and drag it enough so that it would normally
1170 // detach.
1171 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1172 ASSERT_TRUE(PressInput(tab_0_center));
1173 ASSERT_TRUE(DragInputToNotifyWhenDone(
1174 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1175 base::Bind(&DragAllStep2, this, native_browser_list)));
1176 QuitWhenNotDragging();
1178 // Should not be dragging.
1179 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1180 ASSERT_FALSE(TabDragController::IsActive());
1182 // And there should only be one window.
1183 EXPECT_EQ(1u, native_browser_list->size());
1185 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
1187 EXPECT_FALSE(GetIsDragged(browser()));
1189 // Remaining browser window should not be maximized
1190 EXPECT_FALSE(browser()->window()->IsMaximized());
1193 namespace {
1195 // Invoked from the nested message loop.
1196 void DragAllToSeparateWindowStep2(DetachToBrowserTabDragControllerTest* test,
1197 TabStrip* attached_tab_strip,
1198 TabStrip* target_tab_strip,
1199 const BrowserList* browser_list) {
1200 ASSERT_TRUE(attached_tab_strip->IsDragSessionActive());
1201 ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
1202 ASSERT_TRUE(TabDragController::IsActive());
1203 ASSERT_EQ(2u, browser_list->size());
1205 // Drag to target_tab_strip. This should stop the nested loop from dragging
1206 // the window.
1207 gfx::Point target_point(target_tab_strip->width() - 1,
1208 target_tab_strip->height() / 2);
1209 views::View::ConvertPointToScreen(target_tab_strip, &target_point);
1210 ASSERT_TRUE(test->DragInputToAsync(target_point));
1213 } // namespace
1215 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1216 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1217 // compositor. crbug.com/331924
1218 #define MAYBE_DragAllToSeparateWindow DISABLED_DragAllToSeparateWindow
1219 #else
1220 #define MAYBE_DragAllToSeparateWindow DragAllToSeparateWindow
1221 #endif
1222 // Creates two browsers, selects all tabs in first and drags into second.
1223 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1224 MAYBE_DragAllToSeparateWindow) {
1225 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1227 // Add another tab to browser().
1228 AddTabAndResetBrowser(browser());
1230 // Create another browser.
1231 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
1232 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1234 browser()->tab_strip_model()->AddTabAtToSelection(0);
1235 browser()->tab_strip_model()->AddTabAtToSelection(1);
1237 // Move to the first tab and drag it enough so that it detaches, but not
1238 // enough that it attaches to browser2.
1239 gfx::Point tab_0_center(
1240 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1241 ASSERT_TRUE(PressInput(tab_0_center));
1242 ASSERT_TRUE(DragInputToNotifyWhenDone(
1243 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1244 base::Bind(&DragAllToSeparateWindowStep2, this, tab_strip, tab_strip2,
1245 native_browser_list)));
1246 QuitWhenNotDragging();
1248 // Should now be attached to tab_strip2.
1249 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1250 ASSERT_TRUE(TabDragController::IsActive());
1251 ASSERT_EQ(1u, native_browser_list->size());
1253 // Release the mouse, stopping the drag session.
1254 ASSERT_TRUE(ReleaseInput());
1255 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1256 ASSERT_FALSE(TabDragController::IsActive());
1257 EXPECT_EQ("100 0 1", IDString(browser2->tab_strip_model()));
1259 EXPECT_FALSE(GetIsDragged(browser2));
1261 // Remaining browser window should not be maximized
1262 EXPECT_FALSE(browser2->window()->IsMaximized());
1265 namespace {
1267 // Invoked from the nested message loop.
1268 void DragAllToSeparateWindowAndCancelStep2(
1269 DetachToBrowserTabDragControllerTest* test,
1270 TabStrip* attached_tab_strip,
1271 TabStrip* target_tab_strip,
1272 const BrowserList* browser_list) {
1273 ASSERT_TRUE(attached_tab_strip->IsDragSessionActive());
1274 ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
1275 ASSERT_TRUE(TabDragController::IsActive());
1276 ASSERT_EQ(2u, browser_list->size());
1278 // Drag to target_tab_strip. This should stop the nested loop from dragging
1279 // the window.
1280 gfx::Point target_point(target_tab_strip->width() - 1,
1281 target_tab_strip->height() / 2);
1282 views::View::ConvertPointToScreen(target_tab_strip, &target_point);
1283 ASSERT_TRUE(test->DragInputToAsync(target_point));
1286 } // namespace
1288 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1289 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1290 // compositor. crbug.com/331924
1291 #define MAYBE_DragAllToSeparateWindowAndCancel \
1292 DISABLED_DragAllToSeparateWindowAndCancel
1293 #else
1294 #define MAYBE_DragAllToSeparateWindowAndCancel DragAllToSeparateWindowAndCancel
1295 #endif
1296 // Creates two browsers, selects all tabs in first, drags into second, then hits
1297 // escape.
1298 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1299 MAYBE_DragAllToSeparateWindowAndCancel) {
1300 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1302 // Add another tab to browser().
1303 AddTabAndResetBrowser(browser());
1305 // Create another browser.
1306 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
1307 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1309 browser()->tab_strip_model()->AddTabAtToSelection(0);
1310 browser()->tab_strip_model()->AddTabAtToSelection(1);
1312 // Move to the first tab and drag it enough so that it detaches, but not
1313 // enough that it attaches to browser2.
1314 gfx::Point tab_0_center(
1315 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1316 ASSERT_TRUE(PressInput(tab_0_center));
1317 ASSERT_TRUE(DragInputToNotifyWhenDone(
1318 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1319 base::Bind(&DragAllToSeparateWindowAndCancelStep2, this,
1320 tab_strip, tab_strip2, native_browser_list)));
1321 QuitWhenNotDragging();
1323 // Should now be attached to tab_strip2.
1324 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1325 ASSERT_TRUE(TabDragController::IsActive());
1326 ASSERT_EQ(1u, native_browser_list->size());
1328 // Cancel the drag.
1329 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
1330 browser2, ui::VKEY_ESCAPE, false, false, false, false));
1332 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1333 ASSERT_FALSE(TabDragController::IsActive());
1334 EXPECT_EQ("100 0 1", IDString(browser2->tab_strip_model()));
1336 // browser() will have been destroyed, but browser2 should remain.
1337 ASSERT_EQ(1u, native_browser_list->size());
1339 EXPECT_FALSE(GetIsDragged(browser2));
1341 // Remaining browser window should not be maximized
1342 EXPECT_FALSE(browser2->window()->IsMaximized());
1345 #if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_WIN)
1346 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1347 // compositor. crbug.com/331924
1348 #define MAYBE_DragDirectlyToSecondWindow DISABLED_DragDirectlyToSecondWindow
1349 #else
1350 #define MAYBE_DragDirectlyToSecondWindow DragDirectlyToSecondWindow
1351 #endif
1352 // Creates two browsers, drags from first into the second in such a way that
1353 // no detaching should happen.
1354 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1355 MAYBE_DragDirectlyToSecondWindow) {
1356 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1358 // Add another tab to browser().
1359 AddTabAndResetBrowser(browser());
1361 // Create another browser.
1362 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
1363 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1365 // Move the tabstrip down enough so that we can detach.
1366 gfx::Rect bounds(browser2->window()->GetBounds());
1367 bounds.Offset(0, 100);
1368 browser2->window()->SetBounds(bounds);
1370 // Move to the first tab and drag it enough so that it detaches, but not
1371 // enough that it attaches to browser2.
1372 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1373 ASSERT_TRUE(PressInput(tab_0_center));
1375 gfx::Point b2_location(5, 0);
1376 views::View::ConvertPointToScreen(tab_strip2, &b2_location);
1377 ASSERT_TRUE(DragInputTo(b2_location));
1379 // Should now be attached to tab_strip2.
1380 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1381 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1382 ASSERT_TRUE(TabDragController::IsActive());
1384 // Release the mouse, stopping the drag session.
1385 ASSERT_TRUE(ReleaseInput());
1386 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1387 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1388 ASSERT_FALSE(TabDragController::IsActive());
1389 EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1390 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1392 EXPECT_FALSE(GetIsDragged(browser()));
1393 EXPECT_FALSE(GetIsDragged(browser2));
1395 // Both windows should not be maximized
1396 EXPECT_FALSE(browser()->window()->IsMaximized());
1397 EXPECT_FALSE(browser2->window()->IsMaximized());
1400 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1401 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1402 // compositor. crbug.com/331924
1403 #define MAYBE_DragSingleTabToSeparateWindow \
1404 DISABLED_DragSingleTabToSeparateWindow
1405 #else
1406 #define MAYBE_DragSingleTabToSeparateWindow DragSingleTabToSeparateWindow
1407 #endif
1408 // Creates two browsers, the first browser has a single tab and drags into the
1409 // second browser.
1410 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1411 MAYBE_DragSingleTabToSeparateWindow) {
1412 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1414 ResetIDs(browser()->tab_strip_model(), 0);
1416 // Create another browser.
1417 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
1418 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1419 const gfx::Rect initial_bounds(browser2->window()->GetBounds());
1421 // Move to the first tab and drag it enough so that it detaches, but not
1422 // enough that it attaches to browser2.
1423 gfx::Point tab_0_center(
1424 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1425 ASSERT_TRUE(PressInput(tab_0_center));
1426 ASSERT_TRUE(DragInputToNotifyWhenDone(
1427 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1428 base::Bind(&DragAllToSeparateWindowStep2, this, tab_strip, tab_strip2,
1429 native_browser_list)));
1430 QuitWhenNotDragging();
1432 // Should now be attached to tab_strip2.
1433 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1434 ASSERT_TRUE(TabDragController::IsActive());
1435 ASSERT_EQ(1u, native_browser_list->size());
1437 // Release the mouse, stopping the drag session.
1438 ASSERT_TRUE(ReleaseInput());
1439 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1440 ASSERT_FALSE(TabDragController::IsActive());
1441 EXPECT_EQ("100 0", IDString(browser2->tab_strip_model()));
1443 EXPECT_FALSE(GetIsDragged(browser2));
1445 // Remaining browser window should not be maximized
1446 EXPECT_FALSE(browser2->window()->IsMaximized());
1448 // Make sure that the window is still managed and not user moved.
1449 EXPECT_TRUE(IsWindowPositionManaged(browser2->window()->GetNativeWindow()));
1450 EXPECT_FALSE(HasUserChangedWindowPositionOrSize(
1451 browser2->window()->GetNativeWindow()));
1452 // Also make sure that the drag to window position has not changed.
1453 EXPECT_EQ(initial_bounds.ToString(),
1454 browser2->window()->GetBounds().ToString());
1457 namespace {
1459 // Invoked from the nested message loop.
1460 void CancelOnNewTabWhenDraggingStep2(
1461 DetachToBrowserTabDragControllerTest* test,
1462 const BrowserList* browser_list) {
1463 ASSERT_TRUE(TabDragController::IsActive());
1464 ASSERT_EQ(2u, browser_list->size());
1466 // Add another tab. This should trigger exiting the nested loop. Add at the
1467 // to exercise past crash when model/tabstrip got out of sync (474082).
1468 content::WindowedNotificationObserver observer(
1469 content::NOTIFICATION_LOAD_STOP,
1470 content::NotificationService::AllSources());
1471 chrome::AddTabAt(browser_list->GetLastActive(), GURL(url::kAboutBlankURL),
1472 0, false);
1473 observer.Wait();
1476 } // namespace
1478 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1479 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1480 // compositor. crbug.com/331924
1481 #define MAYBE_CancelOnNewTabWhenDragging DISABLED_CancelOnNewTabWhenDragging
1482 #else
1483 #define MAYBE_CancelOnNewTabWhenDragging CancelOnNewTabWhenDragging
1484 #endif
1485 // Adds another tab, detaches into separate window, adds another tab and
1486 // verifies the run loop ends.
1487 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1488 MAYBE_CancelOnNewTabWhenDragging) {
1489 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1491 // Add another tab to browser().
1492 AddTabAndResetBrowser(browser());
1494 // Move to the first tab and drag it enough so that it detaches.
1495 gfx::Point tab_0_center(
1496 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1497 ASSERT_TRUE(PressInput(tab_0_center));
1498 ASSERT_TRUE(DragInputToNotifyWhenDone(
1499 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1500 base::Bind(&CancelOnNewTabWhenDraggingStep2, this, native_browser_list)));
1501 QuitWhenNotDragging();
1503 // Should be two windows and not dragging.
1504 ASSERT_FALSE(TabDragController::IsActive());
1505 ASSERT_EQ(2u, native_browser_list->size());
1506 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
1507 EXPECT_FALSE(GetIsDragged(*it));
1508 // Should not be maximized
1509 EXPECT_FALSE(it->window()->IsMaximized());
1513 #if defined(OS_CHROMEOS)
1514 // TODO(sky,sad): A number of tests below are disabled as they fail due to
1515 // resize locks with a real compositor. crbug.com/331924
1516 namespace {
1518 void DragInMaximizedWindowStep2(DetachToBrowserTabDragControllerTest* test,
1519 Browser* browser,
1520 TabStrip* tab_strip,
1521 const BrowserList* browser_list) {
1522 // There should be another browser.
1523 ASSERT_EQ(2u, browser_list->size());
1524 Browser* new_browser = browser_list->get(1);
1525 EXPECT_NE(browser, new_browser);
1526 ASSERT_TRUE(new_browser->window()->IsActive());
1527 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
1529 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1530 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1532 // Both windows should be visible.
1533 EXPECT_TRUE(tab_strip->GetWidget()->IsVisible());
1534 EXPECT_TRUE(tab_strip2->GetWidget()->IsVisible());
1536 // Stops dragging.
1537 ASSERT_TRUE(test->ReleaseInput());
1540 } // namespace
1542 // Creates a browser with two tabs, maximizes it, drags the tab out.
1543 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1544 DISABLED_DragInMaximizedWindow) {
1545 AddTabAndResetBrowser(browser());
1546 browser()->window()->Maximize();
1548 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1550 // Move to the first tab and drag it enough so that it detaches.
1551 gfx::Point tab_0_center(
1552 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1553 ASSERT_TRUE(PressInput(tab_0_center));
1554 ASSERT_TRUE(DragInputToNotifyWhenDone(
1555 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1556 base::Bind(&DragInMaximizedWindowStep2, this, browser(), tab_strip,
1557 native_browser_list)));
1558 QuitWhenNotDragging();
1560 ASSERT_FALSE(TabDragController::IsActive());
1562 // Should be two browsers.
1563 ASSERT_EQ(2u, native_browser_list->size());
1564 Browser* new_browser = native_browser_list->get(1);
1565 ASSERT_TRUE(new_browser->window()->IsActive());
1567 EXPECT_TRUE(browser()->window()->GetNativeWindow()->IsVisible());
1568 EXPECT_TRUE(new_browser->window()->GetNativeWindow()->IsVisible());
1570 EXPECT_FALSE(GetIsDragged(browser()));
1571 EXPECT_FALSE(GetIsDragged(new_browser));
1573 // The source window should be maximized.
1574 EXPECT_TRUE(browser()->window()->IsMaximized());
1575 // The new window should be maximized.
1576 EXPECT_TRUE(new_browser->window()->IsMaximized());
1579 // Subclass of DetachToBrowserTabDragControllerTest that
1580 // creates multiple displays.
1581 class DetachToBrowserInSeparateDisplayTabDragControllerTest
1582 : public DetachToBrowserTabDragControllerTest {
1583 public:
1584 DetachToBrowserInSeparateDisplayTabDragControllerTest() {}
1585 virtual ~DetachToBrowserInSeparateDisplayTabDragControllerTest() {}
1587 void SetUpCommandLine(base::CommandLine* command_line) override {
1588 DetachToBrowserTabDragControllerTest::SetUpCommandLine(command_line);
1589 // Make screens sufficiently wide to host 2 browsers side by side.
1590 command_line->AppendSwitchASCII("ash-host-window-bounds",
1591 "0+0-600x600,601+0-600x600");
1594 private:
1595 DISALLOW_COPY_AND_ASSIGN(
1596 DetachToBrowserInSeparateDisplayTabDragControllerTest);
1599 // Subclass of DetachToBrowserTabDragControllerTest that runs tests only with
1600 // touch input.
1601 class DetachToBrowserTabDragControllerTestTouch
1602 : public DetachToBrowserTabDragControllerTest {
1603 public:
1604 DetachToBrowserTabDragControllerTestTouch() {}
1605 virtual ~DetachToBrowserTabDragControllerTestTouch() {}
1607 private:
1608 DISALLOW_COPY_AND_ASSIGN(DetachToBrowserTabDragControllerTestTouch);
1611 namespace {
1613 void DragSingleTabToSeparateWindowInSecondDisplayStep3(
1614 DetachToBrowserTabDragControllerTest* test) {
1615 ASSERT_TRUE(test->ReleaseInput());
1618 void DragSingleTabToSeparateWindowInSecondDisplayStep2(
1619 DetachToBrowserTabDragControllerTest* test,
1620 const gfx::Point& target_point) {
1621 ASSERT_TRUE(test->DragInputToNotifyWhenDone(
1622 target_point.x(), target_point.y(),
1623 base::Bind(&DragSingleTabToSeparateWindowInSecondDisplayStep3, test)));
1626 } // namespace
1628 // Drags from browser to a second display and releases input.
1629 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1630 DISABLED_DragSingleTabToSeparateWindowInSecondDisplay) {
1631 // Add another tab.
1632 AddTabAndResetBrowser(browser());
1633 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1635 // Move to the first tab and drag it enough so that it detaches.
1636 // Then drag it to the final destination on the second screen.
1637 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1638 ASSERT_TRUE(PressInput(tab_0_center));
1639 ASSERT_TRUE(DragInputToNotifyWhenDone(
1640 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1641 base::Bind(&DragSingleTabToSeparateWindowInSecondDisplayStep2,
1642 this, gfx::Point(600 + tab_0_center.x(),
1643 tab_0_center.y()
1644 + GetDetachY(tab_strip)))));
1645 QuitWhenNotDragging();
1647 // Should no longer be dragging.
1648 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1649 ASSERT_FALSE(TabDragController::IsActive());
1651 // There should now be another browser.
1652 ASSERT_EQ(2u, native_browser_list->size());
1653 Browser* new_browser = native_browser_list->get(1);
1654 ASSERT_TRUE(new_browser->window()->IsActive());
1655 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
1656 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1658 // This other browser should be on the second screen (with mouse drag)
1659 // With the touch input the browser cannot be dragged from one screen
1660 // to another and the window stays on the first screen.
1661 if (input_source() == INPUT_SOURCE_MOUSE) {
1662 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1663 ASSERT_EQ(2u, roots.size());
1664 aura::Window* second_root = roots[1];
1665 EXPECT_EQ(second_root,
1666 new_browser->window()->GetNativeWindow()->GetRootWindow());
1669 EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
1670 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1672 // Both windows should not be maximized
1673 EXPECT_FALSE(browser()->window()->IsMaximized());
1674 EXPECT_FALSE(new_browser->window()->IsMaximized());
1677 namespace {
1679 // Invoked from the nested message loop.
1680 void DragTabToWindowInSeparateDisplayStep2(
1681 DetachToBrowserTabDragControllerTest* test,
1682 TabStrip* not_attached_tab_strip,
1683 TabStrip* target_tab_strip) {
1684 ASSERT_FALSE(not_attached_tab_strip->IsDragSessionActive());
1685 ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
1686 ASSERT_TRUE(TabDragController::IsActive());
1688 // Drag to target_tab_strip. This should stop the nested loop from dragging
1689 // the window.
1690 gfx::Point target_point(
1691 GetCenterInScreenCoordinates(target_tab_strip->tab_at(0)));
1693 // Move it close to the beginning of the target tabstrip.
1694 target_point.set_x(
1695 target_point.x() - target_tab_strip->tab_at(0)->width() / 2 + 10);
1696 ASSERT_TRUE(test->DragInputToAsync(target_point));
1699 } // namespace
1701 // Drags from browser to another browser on a second display and releases input.
1702 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1703 DISABLED_DragTabToWindowInSeparateDisplay) {
1704 // Add another tab.
1705 AddTabAndResetBrowser(browser());
1706 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1708 // Create another browser.
1709 Browser* browser2 = CreateBrowser(browser()->profile());
1710 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1711 ResetIDs(browser2->tab_strip_model(), 100);
1713 // Move the second browser to the second display.
1714 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1715 ASSERT_EQ(2u, roots.size());
1716 aura::Window* second_root = roots[1];
1717 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1718 second_root).work_area();
1719 browser2->window()->SetBounds(work_area);
1720 EXPECT_EQ(second_root,
1721 browser2->window()->GetNativeWindow()->GetRootWindow());
1723 // Move to the first tab and drag it enough so that it detaches, but not
1724 // enough that it attaches to browser2.
1725 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1726 ASSERT_TRUE(PressInput(tab_0_center));
1727 ASSERT_TRUE(DragInputToNotifyWhenDone(
1728 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1729 base::Bind(&DragTabToWindowInSeparateDisplayStep2,
1730 this, tab_strip, tab_strip2)));
1731 QuitWhenNotDragging();
1733 // Should now be attached to tab_strip2.
1734 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1735 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1736 ASSERT_TRUE(TabDragController::IsActive());
1738 // Release the mouse, stopping the drag session.
1739 ASSERT_TRUE(ReleaseInput());
1740 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1741 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1742 ASSERT_FALSE(TabDragController::IsActive());
1743 EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1744 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1746 // Both windows should not be maximized
1747 EXPECT_FALSE(browser()->window()->IsMaximized());
1748 EXPECT_FALSE(browser2->window()->IsMaximized());
1751 // Drags from browser to another browser on a second display and releases input.
1752 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1753 DISABLED_DragTabToWindowOnSecondDisplay) {
1754 // Add another tab.
1755 AddTabAndResetBrowser(browser());
1756 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1758 // Create another browser.
1759 Browser* browser2 = CreateBrowser(browser()->profile());
1760 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1761 ResetIDs(browser2->tab_strip_model(), 100);
1763 // Move both browsers to the second display.
1764 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1765 ASSERT_EQ(2u, roots.size());
1766 aura::Window* second_root = roots[1];
1767 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1768 second_root).work_area();
1769 browser()->window()->SetBounds(work_area);
1771 // position both browser windows side by side on the second screen.
1772 gfx::Rect work_area2(work_area);
1773 work_area.set_width(work_area.width()/2);
1774 browser()->window()->SetBounds(work_area);
1775 work_area2.set_x(work_area2.x() + work_area2.width()/2);
1776 work_area2.set_width(work_area2.width()/2);
1777 browser2->window()->SetBounds(work_area2);
1778 EXPECT_EQ(second_root,
1779 browser()->window()->GetNativeWindow()->GetRootWindow());
1780 EXPECT_EQ(second_root,
1781 browser2->window()->GetNativeWindow()->GetRootWindow());
1783 // Move to the first tab and drag it enough so that it detaches, but not
1784 // enough that it attaches to browser2.
1785 // SetEventGeneratorRootWindow sets correct (second) RootWindow
1786 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1787 SetEventGeneratorRootWindow(tab_0_center);
1788 ASSERT_TRUE(PressInput(tab_0_center));
1789 ASSERT_TRUE(DragInputToNotifyWhenDone(
1790 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1791 base::Bind(&DragTabToWindowInSeparateDisplayStep2,
1792 this, tab_strip, tab_strip2)));
1793 QuitWhenNotDragging();
1795 // Should now be attached to tab_strip2.
1796 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1797 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1798 ASSERT_TRUE(TabDragController::IsActive());
1800 // Release the mouse, stopping the drag session.
1801 ASSERT_TRUE(ReleaseInput());
1802 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1803 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1804 ASSERT_FALSE(TabDragController::IsActive());
1805 EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1806 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1808 // Both windows should not be maximized
1809 EXPECT_FALSE(browser()->window()->IsMaximized());
1810 EXPECT_FALSE(browser2->window()->IsMaximized());
1813 // Drags from a maximized browser to another non-maximized browser on a second
1814 // display and releases input.
1815 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1816 DISABLED_DragMaxTabToNonMaxWindowInSeparateDisplay) {
1817 // Add another tab.
1818 AddTabAndResetBrowser(browser());
1819 browser()->window()->Maximize();
1820 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1822 // Create another browser on the second display.
1823 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1824 ASSERT_EQ(2u, roots.size());
1825 aura::Window* first_root = roots[0];
1826 aura::Window* second_root = roots[1];
1827 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1828 second_root).work_area();
1829 work_area.Inset(20, 20, 20, 60);
1830 Browser::CreateParams params(browser()->profile(),
1831 browser()->host_desktop_type());
1832 params.initial_show_state = ui::SHOW_STATE_NORMAL;
1833 params.initial_bounds = work_area;
1834 Browser* browser2 = new Browser(params);
1835 AddBlankTabAndShow(browser2);
1837 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1838 ResetIDs(browser2->tab_strip_model(), 100);
1840 EXPECT_EQ(second_root,
1841 browser2->window()->GetNativeWindow()->GetRootWindow());
1842 EXPECT_EQ(first_root,
1843 browser()->window()->GetNativeWindow()->GetRootWindow());
1844 EXPECT_EQ(2, tab_strip->tab_count());
1845 EXPECT_EQ(1, tab_strip2->tab_count());
1847 // Move to the first tab and drag it enough so that it detaches, but not
1848 // enough that it attaches to browser2.
1849 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1850 ASSERT_TRUE(PressInput(tab_0_center));
1851 ASSERT_TRUE(DragInputToNotifyWhenDone(
1852 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1853 base::Bind(&DragTabToWindowInSeparateDisplayStep2,
1854 this, tab_strip, tab_strip2)));
1855 QuitWhenNotDragging();
1857 // Should now be attached to tab_strip2.
1858 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1859 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1860 ASSERT_TRUE(TabDragController::IsActive());
1862 // Release the mouse, stopping the drag session.
1863 ASSERT_TRUE(ReleaseInput());
1865 // tab should have moved
1866 EXPECT_EQ(1, tab_strip->tab_count());
1867 EXPECT_EQ(2, tab_strip2->tab_count());
1869 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1870 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1871 ASSERT_FALSE(TabDragController::IsActive());
1872 EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1873 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1875 // Source browser should still be maximized, target should not
1876 EXPECT_TRUE(browser()->window()->IsMaximized());
1877 EXPECT_FALSE(browser2->window()->IsMaximized());
1880 // Drags from a restored browser to an immersive fullscreen browser on a
1881 // second display and releases input.
1882 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1883 DISABLED_DragTabToImmersiveBrowserOnSeparateDisplay) {
1884 // Add another tab.
1885 AddTabAndResetBrowser(browser());
1886 TabStrip* tab_strip = GetTabStripForBrowser(browser());
1888 // Create another browser.
1889 Browser* browser2 = CreateBrowser(browser()->profile());
1890 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1891 ResetIDs(browser2->tab_strip_model(), 100);
1893 // Move the second browser to the second display.
1894 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1895 ASSERT_EQ(2u, roots.size());
1896 aura::Window* second_root = roots[1];
1897 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1898 second_root).work_area();
1899 browser2->window()->SetBounds(work_area);
1900 EXPECT_EQ(second_root,
1901 browser2->window()->GetNativeWindow()->GetRootWindow());
1903 // Put the second browser into immersive fullscreen.
1904 BrowserView* browser_view2 = BrowserView::GetBrowserViewForBrowser(browser2);
1905 ImmersiveModeController* immersive_controller2 =
1906 browser_view2->immersive_mode_controller();
1907 immersive_controller2->SetupForTest();
1908 chrome::ToggleFullscreenMode(browser2);
1909 ASSERT_TRUE(immersive_controller2->IsEnabled());
1910 ASSERT_FALSE(immersive_controller2->IsRevealed());
1911 ASSERT_TRUE(tab_strip2->IsImmersiveStyle());
1913 // Move to the first tab and drag it enough so that it detaches, but not
1914 // enough that it attaches to browser2.
1915 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1916 ASSERT_TRUE(PressInput(tab_0_center));
1917 ASSERT_TRUE(DragInputToNotifyWhenDone(
1918 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1919 base::Bind(&DragTabToWindowInSeparateDisplayStep2,
1920 this, tab_strip, tab_strip2)));
1921 QuitWhenNotDragging();
1923 // Should now be attached to tab_strip2.
1924 ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1925 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1926 ASSERT_TRUE(TabDragController::IsActive());
1928 // browser2's top chrome should be revealed and the tab strip should be
1929 // at normal height while user is tragging tabs_strip2's tabs.
1930 ASSERT_TRUE(immersive_controller2->IsRevealed());
1931 ASSERT_FALSE(tab_strip2->IsImmersiveStyle());
1933 // Release the mouse, stopping the drag session.
1934 ASSERT_TRUE(ReleaseInput());
1935 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1936 ASSERT_FALSE(tab_strip->IsDragSessionActive());
1937 ASSERT_FALSE(TabDragController::IsActive());
1938 EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1939 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1941 // Move the mouse off of browser2's top chrome.
1942 aura::Window* primary_root = roots[0];
1943 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
1944 primary_root->GetBoundsInScreen().CenterPoint()));
1946 // The first browser window should not be in immersive fullscreen.
1947 // browser2 should still be in immersive fullscreen, but the top chrome should
1948 // no longer be revealed.
1949 BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
1950 EXPECT_FALSE(browser_view->immersive_mode_controller()->IsEnabled());
1952 EXPECT_TRUE(immersive_controller2->IsEnabled());
1953 EXPECT_FALSE(immersive_controller2->IsRevealed());
1954 EXPECT_TRUE(tab_strip2->IsImmersiveStyle());
1957 // Subclass of DetachToBrowserTabDragControllerTest that
1958 // creates multiple displays with different device scale factors.
1959 class DifferentDeviceScaleFactorDisplayTabDragControllerTest
1960 : public DetachToBrowserTabDragControllerTest {
1961 public:
1962 DifferentDeviceScaleFactorDisplayTabDragControllerTest() {}
1963 virtual ~DifferentDeviceScaleFactorDisplayTabDragControllerTest() {}
1965 void SetUpCommandLine(base::CommandLine* command_line) override {
1966 DetachToBrowserTabDragControllerTest::SetUpCommandLine(command_line);
1967 command_line->AppendSwitchASCII("ash-host-window-bounds",
1968 "400x400,0+400-800x800*2");
1971 float GetCursorDeviceScaleFactor() const {
1972 ash::test::CursorManagerTestApi cursor_test_api(
1973 ash::Shell::GetInstance()->cursor_manager());
1974 return cursor_test_api.GetCurrentCursor().device_scale_factor();
1977 private:
1978 DISALLOW_COPY_AND_ASSIGN(
1979 DifferentDeviceScaleFactorDisplayTabDragControllerTest);
1982 namespace {
1984 // The points where a tab is dragged in CursorDeviceScaleFactorStep.
1985 const struct DragPoint {
1986 int x;
1987 int y;
1988 } kDragPoints[] = {
1989 {300, 200},
1990 {399, 200},
1991 {500, 200},
1992 {400, 200},
1993 {300, 200},
1996 // The expected device scale factors before the cursor is moved to the
1997 // corresponding kDragPoints in CursorDeviceScaleFactorStep.
1998 const float kDeviceScaleFactorExpectations[] = {
1999 1.0f,
2000 1.0f,
2001 2.0f,
2002 2.0f,
2003 1.0f,
2006 static_assert(
2007 arraysize(kDragPoints) == arraysize(kDeviceScaleFactorExpectations),
2008 "kDragPoints and kDeviceScaleFactorExpectations must have the same "
2009 "number of elements");
2011 // Drags tab to |kDragPoints[index]|, then calls the next step function.
2012 void CursorDeviceScaleFactorStep(
2013 DifferentDeviceScaleFactorDisplayTabDragControllerTest* test,
2014 TabStrip* not_attached_tab_strip,
2015 size_t index) {
2016 ASSERT_FALSE(not_attached_tab_strip->IsDragSessionActive());
2017 ASSERT_TRUE(TabDragController::IsActive());
2019 if (index < arraysize(kDragPoints)) {
2020 EXPECT_EQ(kDeviceScaleFactorExpectations[index],
2021 test->GetCursorDeviceScaleFactor());
2022 const DragPoint p = kDragPoints[index];
2023 ASSERT_TRUE(test->DragInputToNotifyWhenDone(
2024 p.x, p.y, base::Bind(&CursorDeviceScaleFactorStep,
2025 test, not_attached_tab_strip, index + 1)));
2026 } else {
2027 // Finishes a serise of CursorDeviceScaleFactorStep calls and ends drag.
2028 EXPECT_EQ(1.0f, test->GetCursorDeviceScaleFactor());
2029 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
2030 ui_controls::LEFT, ui_controls::UP));
2034 } // namespace
2036 // Verifies cursor's device scale factor is updated when a tab is moved across
2037 // displays with different device scale factors (http://crbug.com/154183).
2038 IN_PROC_BROWSER_TEST_P(DifferentDeviceScaleFactorDisplayTabDragControllerTest,
2039 DISABLED_CursorDeviceScaleFactor) {
2040 // Add another tab.
2041 AddTabAndResetBrowser(browser());
2042 TabStrip* tab_strip = GetTabStripForBrowser(browser());
2044 // Move the second browser to the second display.
2045 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
2046 ASSERT_EQ(2u, roots.size());
2048 // Move to the first tab and drag it enough so that it detaches.
2049 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
2050 ASSERT_TRUE(PressInput(tab_0_center));
2051 ASSERT_TRUE(DragInputToNotifyWhenDone(
2052 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
2053 base::Bind(&CursorDeviceScaleFactorStep,
2054 this, tab_strip, 0)));
2055 QuitWhenNotDragging();
2058 namespace {
2060 class DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest
2061 : public TabDragControllerTest {
2062 public:
2063 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest() {}
2065 void SetUpCommandLine(base::CommandLine* command_line) override {
2066 TabDragControllerTest::SetUpCommandLine(command_line);
2067 command_line->AppendSwitchASCII("ash-host-window-bounds",
2068 "0+0-250x250,251+0-250x250");
2071 bool Press(const gfx::Point& position) {
2072 return ui_test_utils::SendMouseMoveSync(position) &&
2073 ui_test_utils::SendMouseEventsSync(ui_controls::LEFT,
2074 ui_controls::DOWN);
2077 bool DragTabAndExecuteTaskWhenDone(const gfx::Point& position,
2078 const base::Closure& task) {
2079 return ui_controls::SendMouseMoveNotifyWhenDone(
2080 position.x(), position.y(), task);
2083 void QuitWhenNotDragging() {
2084 test::QuitWhenNotDraggingImpl();
2085 base::MessageLoop::current()->Run();
2088 private:
2089 DISALLOW_COPY_AND_ASSIGN(
2090 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest);
2093 // Invoked from the nested message loop.
2094 void CancelDragTabToWindowInSeparateDisplayStep3(
2095 TabStrip* tab_strip,
2096 const BrowserList* browser_list) {
2097 ASSERT_FALSE(tab_strip->IsDragSessionActive());
2098 ASSERT_TRUE(TabDragController::IsActive());
2099 ASSERT_EQ(2u, browser_list->size());
2101 // Switching display mode should cancel the drag operation.
2102 ash::DisplayManager* display_manager =
2103 ash::Shell::GetInstance()->display_manager();
2104 display_manager->AddRemoveDisplay();
2107 // Invoked from the nested message loop.
2108 void CancelDragTabToWindowInSeparateDisplayStep2(
2109 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest* test,
2110 TabStrip* tab_strip,
2111 aura::Window* current_root,
2112 gfx::Point final_destination,
2113 const BrowserList* browser_list) {
2114 ASSERT_FALSE(tab_strip->IsDragSessionActive());
2115 ASSERT_TRUE(TabDragController::IsActive());
2116 ASSERT_EQ(2u, browser_list->size());
2118 Browser* new_browser = browser_list->get(1);
2119 EXPECT_EQ(current_root,
2120 new_browser->window()->GetNativeWindow()->GetRootWindow());
2122 ASSERT_TRUE(test->DragTabAndExecuteTaskWhenDone(
2123 final_destination,
2124 base::Bind(&CancelDragTabToWindowInSeparateDisplayStep3,
2125 tab_strip, browser_list)));
2128 } // namespace
2130 // Drags from browser to a second display and releases input.
2131 IN_PROC_BROWSER_TEST_F(
2132 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest,
2133 DISABLED_CancelDragTabToWindowIn2ndDisplay) {
2134 // Add another tab.
2135 AddTabAndResetBrowser(browser());
2136 TabStrip* tab_strip = GetTabStripForBrowser(browser());
2138 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2140 // Move the second browser to the second display.
2141 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
2142 ASSERT_EQ(2u, roots.size());
2143 gfx::Point final_destination =
2144 gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
2145 roots[1]).work_area().CenterPoint();
2147 // Move to the first tab and drag it enough so that it detaches, but not
2148 // enough to move to another display.
2149 gfx::Point tab_0_dst(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
2150 ASSERT_TRUE(Press(tab_0_dst));
2151 tab_0_dst.Offset(0, GetDetachY(tab_strip));
2152 ASSERT_TRUE(DragTabAndExecuteTaskWhenDone(
2153 tab_0_dst, base::Bind(&CancelDragTabToWindowInSeparateDisplayStep2,
2154 this, tab_strip, roots[0], final_destination,
2155 native_browser_list)));
2156 QuitWhenNotDragging();
2158 ASSERT_EQ(1u, native_browser_list->size());
2159 ASSERT_FALSE(tab_strip->IsDragSessionActive());
2160 ASSERT_FALSE(TabDragController::IsActive());
2161 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2163 // Release the mouse
2164 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
2165 ui_controls::LEFT, ui_controls::UP));
2168 // Drags from browser from a second display to primary and releases input.
2169 IN_PROC_BROWSER_TEST_F(
2170 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest,
2171 DISABLED_CancelDragTabToWindowIn1stDisplay) {
2172 aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
2173 ASSERT_EQ(2u, roots.size());
2175 // Add another tab.
2176 AddTabAndResetBrowser(browser());
2177 TabStrip* tab_strip = GetTabStripForBrowser(browser());
2179 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2180 EXPECT_EQ(roots[0], browser()->window()->GetNativeWindow()->GetRootWindow());
2182 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->
2183 GetDisplayNearestWindow(roots[1]).work_area();
2184 browser()->window()->SetBounds(work_area);
2185 EXPECT_EQ(roots[1], browser()->window()->GetNativeWindow()->GetRootWindow());
2187 // Move the second browser to the display.
2188 gfx::Point final_destination =
2189 gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
2190 roots[0]).work_area().CenterPoint();
2192 // Move to the first tab and drag it enough so that it detaches, but not
2193 // enough to move to another display.
2194 gfx::Point tab_0_dst(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
2195 ASSERT_TRUE(Press(tab_0_dst));
2196 tab_0_dst.Offset(0, GetDetachY(tab_strip));
2197 ASSERT_TRUE(DragTabAndExecuteTaskWhenDone(
2198 tab_0_dst, base::Bind(&CancelDragTabToWindowInSeparateDisplayStep2,
2199 this, tab_strip, roots[1], final_destination,
2200 native_browser_list)));
2201 QuitWhenNotDragging();
2203 ASSERT_EQ(1u, native_browser_list->size());
2204 ASSERT_FALSE(tab_strip->IsDragSessionActive());
2205 ASSERT_FALSE(TabDragController::IsActive());
2206 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2208 // Release the mouse
2209 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
2210 ui_controls::LEFT, ui_controls::UP));
2213 namespace {
2215 void PressSecondFingerWhileDetachedStep2(
2216 DetachToBrowserTabDragControllerTest* test) {
2217 ASSERT_TRUE(TabDragController::IsActive());
2218 ASSERT_EQ(2u, test->native_browser_list->size());
2219 Browser* new_browser = test->native_browser_list->get(1);
2220 ASSERT_TRUE(new_browser->window()->IsActive());
2222 ASSERT_TRUE(test->PressInput2());
2225 } // namespace
2227 // Detaches a tab and while detached presses a second finger.
2228 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestTouch,
2229 DISABLED_PressSecondFingerWhileDetached) {
2230 gfx::Rect bounds(browser()->window()->GetBounds());
2231 // Add another tab.
2232 AddTabAndResetBrowser(browser());
2233 TabStrip* tab_strip = GetTabStripForBrowser(browser());
2234 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2236 // Move to the first tab and drag it enough so that it detaches.
2237 gfx::Point tab_0_center(
2238 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
2239 ASSERT_TRUE(PressInput(tab_0_center));
2240 ASSERT_TRUE(DragInputToDelayedNotifyWhenDone(
2241 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
2242 base::Bind(&PressSecondFingerWhileDetachedStep2, this),
2243 base::TimeDelta::FromMilliseconds(60)));
2244 QuitWhenNotDragging();
2246 // The drag should have been reverted.
2247 ASSERT_EQ(1u, native_browser_list->size());
2248 ASSERT_FALSE(tab_strip->IsDragSessionActive());
2249 ASSERT_FALSE(TabDragController::IsActive());
2250 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2252 ASSERT_TRUE(ReleaseInput());
2253 ASSERT_TRUE(ReleaseInput2());
2256 #if defined(OS_CHROMEOS)
2258 namespace {
2260 void DetachToDockedWindowNextStep(
2261 DetachToBrowserTabDragControllerTest* test,
2262 const gfx::Point& target_point,
2263 int iteration) {
2264 ASSERT_EQ(2u, test->native_browser_list->size());
2265 Browser* new_browser = test->native_browser_list->get(1);
2266 ASSERT_TRUE(new_browser->window()->IsActive());
2268 if (!iteration) {
2269 ASSERT_TRUE(test->ReleaseInput());
2270 return;
2272 ASSERT_TRUE(test->DragInputToNotifyWhenDone(
2273 target_point.x(), target_point.y(),
2274 base::Bind(&DetachToDockedWindowNextStep,
2275 test,
2276 gfx::Point(target_point.x(), 1 + target_point.y()),
2277 iteration - 1)));
2280 } // namespace
2282 // Drags from browser to separate window, docks that window and releases mouse.
2283 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
2284 DISABLED_DetachToDockedWindowFromMaximizedWindow) {
2285 // Maximize the initial browser window.
2286 browser()->window()->Maximize();
2287 ASSERT_TRUE(browser()->window()->IsMaximized());
2289 // Add another tab.
2290 AddTabAndResetBrowser(browser());
2291 TabStrip* tab_strip = GetTabStripForBrowser(browser());
2293 // Move to the first tab and drag it enough so that it detaches.
2294 gfx::Point tab_0_center(
2295 GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
2296 ASSERT_TRUE(PressInput(tab_0_center));
2298 // The following matches kMovesBeforeAdjust in snap_sizer.cc
2299 const int kNumIterations = 25 * 5 + 10;
2300 ASSERT_TRUE(DragInputToNotifyWhenDone(
2301 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
2302 base::Bind(&DetachToDockedWindowNextStep, this,
2303 gfx::Point(0, tab_0_center.y() + GetDetachY(tab_strip)),
2304 kNumIterations)));
2305 // Continue dragging enough times to go through snapping sequence and dock
2306 // the window.
2307 QuitWhenNotDragging();
2308 // Should no longer be dragging.
2309 ASSERT_FALSE(tab_strip->IsDragSessionActive());
2310 ASSERT_FALSE(TabDragController::IsActive());
2312 // There should now be another browser.
2313 ASSERT_EQ(2u, native_browser_list->size());
2314 Browser* new_browser = native_browser_list->get(1);
2315 ASSERT_TRUE(new_browser->window()->IsActive());
2316 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
2317 ASSERT_FALSE(tab_strip2->IsDragSessionActive());
2319 EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
2320 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
2322 // The bounds of the initial window should not have changed.
2323 EXPECT_TRUE(browser()->window()->IsMaximized());
2325 EXPECT_FALSE(GetIsDragged(browser()));
2326 EXPECT_FALSE(GetIsDragged(new_browser));
2327 // After this both windows should still be manageable.
2328 EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
2329 EXPECT_TRUE(IsWindowPositionManaged(
2330 new_browser->window()->GetNativeWindow()));
2332 ash::wm::WindowState* window_state =
2333 ash::wm::GetWindowState(new_browser->window()->GetNativeWindow());
2334 // The new window should not be maximized because it gets docked or snapped.
2335 EXPECT_FALSE(new_browser->window()->IsMaximized());
2336 // The new window should be docked and not snapped.
2337 EXPECT_TRUE(window_state->IsDocked());
2338 EXPECT_FALSE(window_state->IsSnapped());
2341 #endif // OS_CHROMEOS
2343 #endif
2345 #if defined(USE_ASH) && defined(OS_CHROMEOS) // TODO(win_ash,linux_ash)
2346 INSTANTIATE_TEST_CASE_P(TabDragging,
2347 DetachToBrowserInSeparateDisplayTabDragControllerTest,
2348 ::testing::Values("mouse", "touch"));
2349 INSTANTIATE_TEST_CASE_P(TabDragging,
2350 DifferentDeviceScaleFactorDisplayTabDragControllerTest,
2351 ::testing::Values("mouse"));
2352 INSTANTIATE_TEST_CASE_P(TabDragging,
2353 DetachToBrowserTabDragControllerTest,
2354 ::testing::Values("mouse", "touch"));
2355 INSTANTIATE_TEST_CASE_P(TabDragging,
2356 DetachToBrowserTabDragControllerTestTouch,
2357 ::testing::Values("touch"));
2358 #elif defined(USE_ASH)
2359 INSTANTIATE_TEST_CASE_P(TabDragging,
2360 DetachToBrowserTabDragControllerTest,
2361 ::testing::Values("mouse"));
2362 #endif