Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / tabs / tab_drag_controller_interactive_uitest.cc
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.
4
5 #include "chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.h"
6
7 #include <algorithm>
8
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/host_desktop.h"
21 #include "chrome/browser/ui/tabs/tab_strip_model.h"
22 #include "chrome/browser/ui/views/frame/browser_view.h"
23 #include "chrome/browser/ui/views/frame/native_browser_frame_factory.h"
24 #include "chrome/browser/ui/views/tabs/tab.h"
25 #include "chrome/browser/ui/views/tabs/tab_drag_controller.h"
26 #include "chrome/browser/ui/views/tabs/tab_strip.h"
27 #include "chrome/test/base/in_process_browser_test.h"
28 #include "chrome/test/base/interactive_test_utils.h"
29 #include "chrome/test/base/ui_test_utils.h"
30 #include "content/public/browser/notification_details.h"
31 #include "content/public/browser/notification_observer.h"
32 #include "content/public/browser/notification_service.h"
33 #include "content/public/browser/notification_source.h"
34 #include "content/public/browser/web_contents.h"
35 #include "ui/base/test/ui_controls.h"
36 #include "ui/gfx/screen.h"
37 #include "ui/views/view.h"
38 #include "ui/views/widget/widget.h"
39
40 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
41 #include "chrome/browser/ui/views/frame/desktop_browser_frame_aura.h"
42 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
43 #endif
44
45 #if defined(USE_ASH)
46 #include "ash/display/display_controller.h"
47 #include "ash/display/display_manager.h"
48 #include "ash/shell.h"
49 #include "ash/test/cursor_manager_test_api.h"
50 #include "ash/wm/coordinate_conversion.h"
51 #include "ash/wm/window_util.h"
52 #include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
53 #include "ui/aura/client/screen_position_client.h"
54 #include "ui/aura/test/event_generator_delegate_aura.h"
55 #include "ui/aura/window_event_dispatcher.h"
56 #include "ui/events/test/event_generator.h"
57 #endif
58
59 using content::WebContents;
60
61 namespace test {
62
63 namespace {
64
65 const char kTabDragControllerInteractiveUITestUserDataKey[] =
66     "TabDragControllerInteractiveUITestUserData";
67
68 class TabDragControllerInteractiveUITestUserData
69     : public base::SupportsUserData::Data {
70  public:
71   explicit TabDragControllerInteractiveUITestUserData(int id) : id_(id) {}
72   ~TabDragControllerInteractiveUITestUserData() override {}
73   int id() { return id_; }
74
75  private:
76   int id_;
77 };
78
79 }  // namespace
80
81 class QuitDraggingObserver : public content::NotificationObserver {
82  public:
83   QuitDraggingObserver() {
84     registrar_.Add(this, chrome::NOTIFICATION_TAB_DRAG_LOOP_DONE,
85                    content::NotificationService::AllSources());
86   }
87
88   void Observe(int type,
89                const content::NotificationSource& source,
90                const content::NotificationDetails& details) override {
91     DCHECK_EQ(chrome::NOTIFICATION_TAB_DRAG_LOOP_DONE, type);
92     base::MessageLoopForUI::current()->Quit();
93     delete this;
94   }
95
96  private:
97   ~QuitDraggingObserver() override {}
98
99   content::NotificationRegistrar registrar_;
100
101   DISALLOW_COPY_AND_ASSIGN(QuitDraggingObserver);
102 };
103
104 gfx::Point GetCenterInScreenCoordinates(const views::View* view) {
105   gfx::Point center(view->width() / 2, view->height() / 2);
106   views::View::ConvertPointToScreen(view, &center);
107   return center;
108 }
109
110 void SetID(WebContents* web_contents, int id) {
111   web_contents->SetUserData(&kTabDragControllerInteractiveUITestUserDataKey,
112                             new TabDragControllerInteractiveUITestUserData(id));
113 }
114
115 void ResetIDs(TabStripModel* model, int start) {
116   for (int i = 0; i < model->count(); ++i)
117     SetID(model->GetWebContentsAt(i), start + i);
118 }
119
120 std::string IDString(TabStripModel* model) {
121   std::string result;
122   for (int i = 0; i < model->count(); ++i) {
123     if (i != 0)
124       result += " ";
125     WebContents* contents = model->GetWebContentsAt(i);
126     TabDragControllerInteractiveUITestUserData* user_data =
127         static_cast<TabDragControllerInteractiveUITestUserData*>(
128             contents->GetUserData(
129                 &kTabDragControllerInteractiveUITestUserDataKey));
130     if (user_data)
131       result += base::IntToString(user_data->id());
132     else
133       result += "?";
134   }
135   return result;
136 }
137
138 // Creates a listener that quits the message loop when no longer dragging.
139 void QuitWhenNotDraggingImpl() {
140   new QuitDraggingObserver();  // QuitDraggingObserver deletes itself.
141 }
142
143 TabStrip* GetTabStripForBrowser(Browser* browser) {
144   BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
145   return static_cast<TabStrip*>(browser_view->tabstrip());
146 }
147
148 }  // namespace test
149
150 using test::GetCenterInScreenCoordinates;
151 using test::SetID;
152 using test::ResetIDs;
153 using test::IDString;
154 using test::GetTabStripForBrowser;
155
156 TabDragControllerTest::TabDragControllerTest()
157     : native_browser_list(BrowserList::GetInstance(
158                               chrome::HOST_DESKTOP_TYPE_NATIVE)) {
159 }
160
161 TabDragControllerTest::~TabDragControllerTest() {
162 }
163
164 void TabDragControllerTest::StopAnimating(TabStrip* tab_strip) {
165   tab_strip->StopAnimating(true);
166 }
167
168 void TabDragControllerTest::AddTabAndResetBrowser(Browser* browser) {
169   AddBlankTabAndShow(browser);
170   StopAnimating(GetTabStripForBrowser(browser));
171   ResetIDs(browser->tab_strip_model(), 0);
172 }
173
174 Browser* TabDragControllerTest::CreateAnotherWindowBrowserAndRelayout() {
175   // Create another browser.
176   Browser* browser2 = CreateBrowser(browser()->profile());
177   ResetIDs(browser2->tab_strip_model(), 100);
178
179   // Resize the two windows so they're right next to each other.
180   gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
181       browser()->window()->GetNativeWindow()).work_area();
182   gfx::Size half_size =
183       gfx::Size(work_area.width() / 3 - 10, work_area.height() / 2 - 10);
184   browser()->window()->SetBounds(gfx::Rect(work_area.origin(), half_size));
185   browser2->window()->SetBounds(gfx::Rect(
186       work_area.x() + half_size.width(), work_area.y(),
187       half_size.width(), half_size.height()));
188   return browser2;
189 }
190
191 namespace {
192
193 enum InputSource {
194   INPUT_SOURCE_MOUSE = 0,
195   INPUT_SOURCE_TOUCH = 1
196 };
197
198 int GetDetachY(TabStrip* tab_strip) {
199   return std::max(TabDragController::kTouchVerticalDetachMagnetism,
200                   TabDragController::kVerticalDetachMagnetism) +
201       tab_strip->height() + 1;
202 }
203
204 bool GetIsDragged(Browser* browser) {
205 #if !defined(USE_ASH) || defined(OS_WIN)  // TODO(win_ash)
206   return false;
207 #else
208   return ash::wm::GetWindowState(browser->window()->GetNativeWindow())->
209       is_dragged();
210 #endif
211 }
212
213 }  // namespace
214
215 #if defined(USE_ASH) && !defined(OS_WIN)  // TODO(win_ash)
216 class ScreenEventGeneratorDelegate
217     : public aura::test::EventGeneratorDelegateAura {
218  public:
219   explicit ScreenEventGeneratorDelegate(aura::Window* root_window)
220       : root_window_(root_window) {}
221   ~ScreenEventGeneratorDelegate() override {}
222
223   // EventGeneratorDelegateAura overrides:
224   aura::WindowTreeHost* GetHostAt(const gfx::Point& point) const override {
225     return root_window_->GetHost();
226   }
227
228   aura::client::ScreenPositionClient* GetScreenPositionClient(
229       const aura::Window* window) const override {
230     return aura::client::GetScreenPositionClient(root_window_);
231   }
232
233  private:
234   aura::Window* root_window_;
235
236   DISALLOW_COPY_AND_ASSIGN(ScreenEventGeneratorDelegate);
237 };
238
239 #endif
240
241 #if !defined(OS_CHROMEOS)
242
243 // Following classes verify a crash scenario. Specifically on Windows when focus
244 // changes it can trigger capture being lost. This was causing a crash in tab
245 // dragging as it wasn't set up to handle this scenario. These classes
246 // synthesize this scenario.
247
248 // Allows making ClearNativeFocus() invoke ReleaseCapture().
249 class TestDesktopBrowserFrameAura : public DesktopBrowserFrameAura {
250  public:
251   TestDesktopBrowserFrameAura(
252       BrowserFrame* browser_frame,
253       BrowserView* browser_view)
254       : DesktopBrowserFrameAura(browser_frame, browser_view),
255         release_capture_(false) {}
256   ~TestDesktopBrowserFrameAura() override {}
257
258   void ReleaseCaptureOnNextClear() {
259     release_capture_ = true;
260   }
261
262   void ClearNativeFocus() override {
263     views::DesktopNativeWidgetAura::ClearNativeFocus();
264     if (release_capture_) {
265       release_capture_ = false;
266       GetWidget()->ReleaseCapture();
267     }
268   }
269
270  private:
271   // If true ReleaseCapture() is invoked in ClearNativeFocus().
272   bool release_capture_;
273
274   DISALLOW_COPY_AND_ASSIGN(TestDesktopBrowserFrameAura);
275 };
276
277 // Factory for creating a TestDesktopBrowserFrameAura.
278 class TestNativeBrowserFrameFactory : public NativeBrowserFrameFactory {
279  public:
280   TestNativeBrowserFrameFactory() {}
281   ~TestNativeBrowserFrameFactory() override {}
282
283   NativeBrowserFrame* Create(BrowserFrame* browser_frame,
284                              BrowserView* browser_view) override {
285     return new TestDesktopBrowserFrameAura(browser_frame, browser_view);
286   }
287
288  private:
289   DISALLOW_COPY_AND_ASSIGN(TestNativeBrowserFrameFactory);
290 };
291
292 class TabDragCaptureLostTest : public TabDragControllerTest {
293  public:
294   TabDragCaptureLostTest() {
295     NativeBrowserFrameFactory::Set(new TestNativeBrowserFrameFactory);
296   }
297
298  private:
299   DISALLOW_COPY_AND_ASSIGN(TabDragCaptureLostTest);
300 };
301
302 // See description above for details.
303 IN_PROC_BROWSER_TEST_F(TabDragCaptureLostTest, ReleaseCaptureOnDrag) {
304   AddTabAndResetBrowser(browser());
305
306   TabStrip* tab_strip = GetTabStripForBrowser(browser());
307   gfx::Point tab_1_center(GetCenterInScreenCoordinates(tab_strip->tab_at(1)));
308   ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_1_center) &&
309               ui_test_utils::SendMouseEventsSync(
310                   ui_controls::LEFT, ui_controls::DOWN));
311   gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
312   TestDesktopBrowserFrameAura* frame =
313       static_cast<TestDesktopBrowserFrameAura*>(
314           BrowserView::GetBrowserViewForBrowser(browser())->GetWidget()->
315           native_widget_private());
316   // Invoke ReleaseCaptureOnDrag() so that when the drag happens and focus
317   // changes capture is released and the drag cancels.
318   frame->ReleaseCaptureOnNextClear();
319   ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center));
320   EXPECT_FALSE(tab_strip->IsDragSessionActive());
321 }
322
323 IN_PROC_BROWSER_TEST_F(TabDragControllerTest, GestureEndShouldEndDragTest) {
324   AddTabAndResetBrowser(browser());
325
326   TabStrip* tab_strip = GetTabStripForBrowser(browser());
327
328   Tab* tab1 = tab_strip->tab_at(1);
329   gfx::Point tab_1_center(tab1->width() / 2, tab1->height() / 2);
330
331   ui::GestureEvent gesture_tap_down(
332       tab_1_center.x(),
333       tab_1_center.x(),
334       0,
335       base::TimeDelta(),
336       ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
337   tab_strip->MaybeStartDrag(tab1, gesture_tap_down,
338     tab_strip->GetSelectionModel());
339   EXPECT_TRUE(TabDragController::IsActive());
340
341   ui::GestureEvent gesture_end(tab_1_center.x(),
342                                tab_1_center.x(),
343                                0,
344                                base::TimeDelta(),
345                                ui::GestureEventDetails(ui::ET_GESTURE_END));
346   tab_strip->OnGestureEvent(&gesture_end);
347   EXPECT_FALSE(TabDragController::IsActive());
348   EXPECT_FALSE(tab_strip->IsDragSessionActive());
349 }
350
351 #endif
352
353 class DetachToBrowserTabDragControllerTest
354     : public TabDragControllerTest,
355       public ::testing::WithParamInterface<const char*> {
356  public:
357   DetachToBrowserTabDragControllerTest() {}
358
359   void SetUpOnMainThread() override {
360 #if defined(OS_CHROMEOS)
361     event_generator_.reset(
362         new ui::test::EventGenerator(ash::Shell::GetPrimaryRootWindow()));
363 #endif
364   }
365
366   InputSource input_source() const {
367     return strstr(GetParam(), "mouse") ?
368         INPUT_SOURCE_MOUSE : INPUT_SOURCE_TOUCH;
369   }
370
371   // Set root window from a point in screen coordinates
372   void SetEventGeneratorRootWindow(const gfx::Point& point) {
373     if (input_source() == INPUT_SOURCE_MOUSE)
374       return;
375 #if defined(OS_CHROMEOS)
376     event_generator_.reset(new ui::test::EventGenerator(
377         new ScreenEventGeneratorDelegate(ash::wm::GetRootWindowAt(point))));
378 #endif
379   }
380
381   // The following methods update one of the mouse or touch input depending upon
382   // the InputSource.
383   bool PressInput(const gfx::Point& location) {
384     if (input_source() == INPUT_SOURCE_MOUSE) {
385       return ui_test_utils::SendMouseMoveSync(location) &&
386           ui_test_utils::SendMouseEventsSync(
387               ui_controls::LEFT, ui_controls::DOWN);
388     }
389 #if defined(OS_CHROMEOS)
390     event_generator_->set_current_location(location);
391     event_generator_->PressTouch();
392 #else
393     NOTREACHED();
394 #endif
395     return true;
396   }
397
398   bool PressInput2() {
399     // Second touch input is only used for touch sequence tests.
400     EXPECT_EQ(INPUT_SOURCE_TOUCH, input_source());
401 #if defined(OS_CHROMEOS)
402     event_generator_->set_current_location(
403         event_generator_->current_location());
404     event_generator_->PressTouchId(1);
405 #else
406     NOTREACHED();
407 #endif
408     return true;
409   }
410
411   bool DragInputTo(const gfx::Point& location) {
412     if (input_source() == INPUT_SOURCE_MOUSE)
413       return ui_test_utils::SendMouseMoveSync(location);
414 #if defined(OS_CHROMEOS)
415     event_generator_->MoveTouch(location);
416 #else
417     NOTREACHED();
418 #endif
419     return true;
420   }
421
422   bool DragInputToAsync(const gfx::Point& location) {
423     if (input_source() == INPUT_SOURCE_MOUSE)
424       return ui_controls::SendMouseMove(location.x(), location.y());
425 #if defined(OS_CHROMEOS)
426     event_generator_->MoveTouch(location);
427 #else
428     NOTREACHED();
429 #endif
430     return true;
431   }
432
433   bool DragInputToNotifyWhenDone(int x,
434                                  int y,
435                                  const base::Closure& task) {
436     if (input_source() == INPUT_SOURCE_MOUSE)
437       return ui_controls::SendMouseMoveNotifyWhenDone(x, y, task);
438 #if defined(OS_CHROMEOS)
439     base::MessageLoop::current()->PostTask(FROM_HERE, task);
440     event_generator_->MoveTouch(gfx::Point(x, y));
441 #else
442     NOTREACHED();
443 #endif
444     return true;
445   }
446
447   bool DragInputToDelayedNotifyWhenDone(int x,
448                                         int y,
449                                         const base::Closure& task,
450                                         base::TimeDelta delay) {
451     if (input_source() == INPUT_SOURCE_MOUSE)
452       return ui_controls::SendMouseMoveNotifyWhenDone(x, y, task);
453 #if defined(OS_CHROMEOS)
454     base::MessageLoop::current()->PostDelayedTask(FROM_HERE, task, delay);
455     event_generator_->MoveTouch(gfx::Point(x, y));
456 #else
457     NOTREACHED();
458 #endif
459     return true;
460   }
461
462   bool DragInput2ToNotifyWhenDone(int x,
463                                  int y,
464                                  const base::Closure& task) {
465     if (input_source() == INPUT_SOURCE_MOUSE)
466       return ui_controls::SendMouseMoveNotifyWhenDone(x, y, task);
467 #if defined(OS_CHROMEOS)
468     base::MessageLoop::current()->PostTask(FROM_HERE, task);
469     event_generator_->MoveTouchId(gfx::Point(x, y), 1);
470 #else
471     NOTREACHED();
472 #endif
473     return true;
474   }
475
476   bool ReleaseInput() {
477     if (input_source() == INPUT_SOURCE_MOUSE) {
478       return ui_test_utils::SendMouseEventsSync(
479               ui_controls::LEFT, ui_controls::UP);
480     }
481 #if defined(OS_CHROMEOS)
482     event_generator_->ReleaseTouch();
483 #else
484     NOTREACHED();
485 #endif
486     return true;
487   }
488
489   bool ReleaseInput2() {
490     if (input_source() == INPUT_SOURCE_MOUSE) {
491       return ui_test_utils::SendMouseEventsSync(
492               ui_controls::LEFT, ui_controls::UP);
493     }
494 #if defined(OS_CHROMEOS)
495     event_generator_->ReleaseTouchId(1);
496 #else
497     NOTREACHED();
498 #endif
499     return true;
500   }
501
502   bool ReleaseMouseAsync() {
503     return input_source() == INPUT_SOURCE_MOUSE &&
504         ui_controls::SendMouseEvents(ui_controls::LEFT, ui_controls::UP);
505   }
506
507   void QuitWhenNotDragging() {
508     if (input_source() == INPUT_SOURCE_MOUSE) {
509       // Schedule observer to quit message loop when done dragging. This has to
510       // be async so the message loop can run.
511       test::QuitWhenNotDraggingImpl();
512       base::MessageLoop::current()->Run();
513     } else {
514       // Touch events are sync, so we know we're not in a drag session. But some
515       // tests rely on the browser fully closing, which is async. So, run all
516       // pending tasks.
517       base::RunLoop run_loop;
518       run_loop.RunUntilIdle();
519     }
520   }
521
522   void AddBlankTabAndShow(Browser* browser) {
523     InProcessBrowserTest::AddBlankTabAndShow(browser);
524   }
525
526   Browser* browser() const { return InProcessBrowserTest::browser(); }
527
528  private:
529 #if defined(OS_CHROMEOS)
530   scoped_ptr<ui::test::EventGenerator> event_generator_;
531 #endif
532
533   DISALLOW_COPY_AND_ASSIGN(DetachToBrowserTabDragControllerTest);
534 };
535
536 // Creates a browser with two tabs, drags the second to the first.
537 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, DragInSameWindow) {
538   // TODO(sky): this won't work with touch as it requires a long press.
539   if (input_source() == INPUT_SOURCE_TOUCH) {
540     VLOG(1) << "Test is DISABLED for touch input.";
541     return;
542   }
543
544   AddTabAndResetBrowser(browser());
545
546   TabStrip* tab_strip = GetTabStripForBrowser(browser());
547   TabStripModel* model = browser()->tab_strip_model();
548
549   gfx::Point tab_1_center(GetCenterInScreenCoordinates(tab_strip->tab_at(1)));
550   ASSERT_TRUE(PressInput(tab_1_center));
551   gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
552   ASSERT_TRUE(DragInputTo(tab_0_center));
553   ASSERT_TRUE(ReleaseInput());
554   EXPECT_EQ("1 0", IDString(model));
555   EXPECT_FALSE(TabDragController::IsActive());
556   EXPECT_FALSE(tab_strip->IsDragSessionActive());
557
558   // The tab strip should no longer have capture because the drag was ended and
559   // mouse/touch was released.
560   EXPECT_FALSE(tab_strip->GetWidget()->HasCapture());
561 }
562
563 namespace {
564
565 // Invoked from the nested message loop.
566 void DragToSeparateWindowStep2(DetachToBrowserTabDragControllerTest* test,
567                                TabStrip* not_attached_tab_strip,
568                                TabStrip* target_tab_strip) {
569   ASSERT_FALSE(not_attached_tab_strip->IsDragSessionActive());
570   ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
571   ASSERT_TRUE(TabDragController::IsActive());
572
573   // Drag to target_tab_strip. This should stop the nested loop from dragging
574   // the window.
575   gfx::Point target_point(target_tab_strip->width() -1,
576                           target_tab_strip->height() / 2);
577   views::View::ConvertPointToScreen(target_tab_strip, &target_point);
578   ASSERT_TRUE(test->DragInputToAsync(target_point));
579 }
580
581 }  // namespace
582
583 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
584 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
585 // compositor. crbug.com/331924
586 #define MAYBE_DragToSeparateWindow DISABLED_DragToSeparateWindow
587 #else
588 #define MAYBE_DragToSeparateWindow DragToSeparateWindow
589 #endif
590 // Creates two browsers, drags from first into second.
591 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
592                        MAYBE_DragToSeparateWindow) {
593   TabStrip* tab_strip = GetTabStripForBrowser(browser());
594
595   // Add another tab to browser().
596   AddTabAndResetBrowser(browser());
597
598   // Create another browser.
599   Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
600   TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
601
602   // Move to the first tab and drag it enough so that it detaches, but not
603   // enough that it attaches to browser2.
604   gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
605   ASSERT_TRUE(PressInput(tab_0_center));
606   ASSERT_TRUE(DragInputToNotifyWhenDone(
607                   tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
608                   base::Bind(&DragToSeparateWindowStep2,
609                              this, tab_strip, tab_strip2)));
610   QuitWhenNotDragging();
611
612   // Should now be attached to tab_strip2.
613   ASSERT_TRUE(tab_strip2->IsDragSessionActive());
614   ASSERT_FALSE(tab_strip->IsDragSessionActive());
615   ASSERT_TRUE(TabDragController::IsActive());
616   EXPECT_FALSE(GetIsDragged(browser()));
617
618   // Release mouse or touch, stopping the drag session.
619   ASSERT_TRUE(ReleaseInput());
620   ASSERT_FALSE(tab_strip2->IsDragSessionActive());
621   ASSERT_FALSE(tab_strip->IsDragSessionActive());
622   ASSERT_FALSE(TabDragController::IsActive());
623   EXPECT_EQ("100 0", IDString(browser2->tab_strip_model()));
624   EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
625   EXPECT_FALSE(GetIsDragged(browser2));
626
627   // Both windows should not be maximized
628   EXPECT_FALSE(browser()->window()->IsMaximized());
629   EXPECT_FALSE(browser2->window()->IsMaximized());
630
631   // The tab strip should no longer have capture because the drag was ended and
632   // mouse/touch was released.
633   EXPECT_FALSE(tab_strip->GetWidget()->HasCapture());
634   EXPECT_FALSE(tab_strip2->GetWidget()->HasCapture());
635 }
636
637 namespace {
638
639 void DetachToOwnWindowStep2(DetachToBrowserTabDragControllerTest* test) {
640   if (test->input_source() == INPUT_SOURCE_TOUCH)
641     ASSERT_TRUE(test->ReleaseInput());
642 }
643
644 #if defined(OS_CHROMEOS)
645 bool IsWindowPositionManaged(aura::Window* window) {
646   return ash::wm::GetWindowState(window)->window_position_managed();
647 }
648 bool HasUserChangedWindowPositionOrSize(aura::Window* window) {
649   return ash::wm::GetWindowState(window)->bounds_changed_by_user();
650 }
651 #else
652 bool IsWindowPositionManaged(gfx::NativeWindow window) {
653   return true;
654 }
655 bool HasUserChangedWindowPositionOrSize(gfx::NativeWindow window) {
656   return false;
657 }
658 #endif
659
660 }  // namespace
661
662 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
663 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
664 // compositor. crbug.com/331924
665 #define MAYBE_DetachToOwnWindow DISABLED_DetachToOwnWindow
666 #else
667 #define MAYBE_DetachToOwnWindow DetachToOwnWindow
668 #endif
669 // Drags from browser to separate window and releases mouse.
670 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
671                        MAYBE_DetachToOwnWindow) {
672   const gfx::Rect initial_bounds(browser()->window()->GetBounds());
673   // Add another tab.
674   AddTabAndResetBrowser(browser());
675   TabStrip* tab_strip = GetTabStripForBrowser(browser());
676
677   // Move to the first tab and drag it enough so that it detaches.
678   gfx::Point tab_0_center(
679       GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
680   ASSERT_TRUE(PressInput(tab_0_center));
681   ASSERT_TRUE(DragInputToNotifyWhenDone(
682                   tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
683                   base::Bind(&DetachToOwnWindowStep2, this)));
684   if (input_source() == INPUT_SOURCE_MOUSE) {
685     ASSERT_TRUE(ReleaseMouseAsync());
686     QuitWhenNotDragging();
687   }
688
689   // Should no longer be dragging.
690   ASSERT_FALSE(tab_strip->IsDragSessionActive());
691   ASSERT_FALSE(TabDragController::IsActive());
692
693   // There should now be another browser.
694   ASSERT_EQ(2u, native_browser_list->size());
695   Browser* new_browser = native_browser_list->get(1);
696   ASSERT_TRUE(new_browser->window()->IsActive());
697   TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
698   ASSERT_FALSE(tab_strip2->IsDragSessionActive());
699
700   EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
701   EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
702
703   // The bounds of the initial window should not have changed.
704   EXPECT_EQ(initial_bounds.ToString(),
705             browser()->window()->GetBounds().ToString());
706
707   EXPECT_FALSE(GetIsDragged(browser()));
708   EXPECT_FALSE(GetIsDragged(new_browser));
709   // After this both windows should still be manageable.
710   EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
711   EXPECT_TRUE(IsWindowPositionManaged(
712       new_browser->window()->GetNativeWindow()));
713
714   // Both windows should not be maximized
715   EXPECT_FALSE(browser()->window()->IsMaximized());
716   EXPECT_FALSE(new_browser->window()->IsMaximized());
717
718   // The tab strip should no longer have capture because the drag was ended and
719   // mouse/touch was released.
720   EXPECT_FALSE(tab_strip->GetWidget()->HasCapture());
721   EXPECT_FALSE(tab_strip2->GetWidget()->HasCapture());
722 }
723
724 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
725 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
726 // compositor. crbug.com/331924
727 #define MAYBE_DetachToOwnWindowFromMaximizedWindow \
728   DISABLED_DetachToOwnWindowFromMaximizedWindow
729 #else
730 #define MAYBE_DetachToOwnWindowFromMaximizedWindow \
731   DetachToOwnWindowFromMaximizedWindow
732 #endif
733 // Drags from browser to a separate window and releases mouse.
734 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
735                        MAYBE_DetachToOwnWindowFromMaximizedWindow) {
736   // Maximize the initial browser window.
737   browser()->window()->Maximize();
738   ASSERT_TRUE(browser()->window()->IsMaximized());
739
740   // Add another tab.
741   AddTabAndResetBrowser(browser());
742   TabStrip* tab_strip = GetTabStripForBrowser(browser());
743
744   // Move to the first tab and drag it enough so that it detaches.
745   gfx::Point tab_0_center(
746       GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
747   ASSERT_TRUE(PressInput(tab_0_center));
748   ASSERT_TRUE(DragInputToNotifyWhenDone(
749                   tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
750                   base::Bind(&DetachToOwnWindowStep2, this)));
751   if (input_source() == INPUT_SOURCE_MOUSE) {
752     ASSERT_TRUE(ReleaseMouseAsync());
753     QuitWhenNotDragging();
754   }
755
756   // Should no longer be dragging.
757   ASSERT_FALSE(tab_strip->IsDragSessionActive());
758   ASSERT_FALSE(TabDragController::IsActive());
759
760   // There should now be another browser.
761   ASSERT_EQ(2u, native_browser_list->size());
762   Browser* new_browser = native_browser_list->get(1);
763   ASSERT_TRUE(new_browser->window()->IsActive());
764   TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
765   ASSERT_FALSE(tab_strip2->IsDragSessionActive());
766
767   EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
768   EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
769
770   // The bounds of the initial window should not have changed.
771   EXPECT_TRUE(browser()->window()->IsMaximized());
772
773   EXPECT_FALSE(GetIsDragged(browser()));
774   EXPECT_FALSE(GetIsDragged(new_browser));
775   // After this both windows should still be manageable.
776   EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
777   EXPECT_TRUE(IsWindowPositionManaged(
778       new_browser->window()->GetNativeWindow()));
779
780   // The new window should be maximized.
781   EXPECT_TRUE(new_browser->window()->IsMaximized());
782 }
783
784 // Deletes a tab being dragged before the user moved enough to start a drag.
785 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
786                        DeleteBeforeStartedDragging) {
787   // Add another tab.
788   AddTabAndResetBrowser(browser());
789   TabStrip* tab_strip = GetTabStripForBrowser(browser());
790
791   // Click on the first tab, but don't move it.
792   gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
793   ASSERT_TRUE(PressInput(tab_0_center));
794
795   // Should be dragging.
796   ASSERT_TRUE(tab_strip->IsDragSessionActive());
797   ASSERT_TRUE(TabDragController::IsActive());
798
799   // Delete the tab being dragged.
800   delete browser()->tab_strip_model()->GetWebContentsAt(0);
801
802   // Should have canceled dragging.
803   ASSERT_FALSE(tab_strip->IsDragSessionActive());
804   ASSERT_FALSE(TabDragController::IsActive());
805
806   EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
807   EXPECT_FALSE(GetIsDragged(browser()));
808 }
809
810 #if defined(OS_CHROMEOS)
811 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
812 // compositor. crbug.com/331924
813 #define MAYBE_DeleteTabWhileAttached DISABLED_DeleteTabWhileAttached
814 #else
815 #define MAYBE_DeleteTabWhileAttached DeleteTabWhileAttached
816 #endif
817 // Deletes a tab being dragged while still attached.
818 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
819                        MAYBE_DeleteTabWhileAttached) {
820   // TODO(sky,sad): Disabled as it fails due to resize locks with a real
821   // compositor. crbug.com/331924
822   if (input_source() == INPUT_SOURCE_MOUSE) {
823     VLOG(1) << "Test is DISABLED for mouse input.";
824     return;
825   }
826
827   // Add another tab.
828   AddTabAndResetBrowser(browser());
829   TabStrip* tab_strip = GetTabStripForBrowser(browser());
830
831   // Click on the first tab and move it enough so that it starts dragging but is
832   // still attached.
833   gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
834   ASSERT_TRUE(PressInput(tab_0_center));
835   ASSERT_TRUE(DragInputTo(
836                   gfx::Point(tab_0_center.x() + 20, tab_0_center.y())));
837
838   // Should be dragging.
839   ASSERT_TRUE(tab_strip->IsDragSessionActive());
840   ASSERT_TRUE(TabDragController::IsActive());
841
842   // Delete the tab being dragged.
843   delete browser()->tab_strip_model()->GetWebContentsAt(0);
844
845   // Should have canceled dragging.
846   ASSERT_FALSE(tab_strip->IsDragSessionActive());
847   ASSERT_FALSE(TabDragController::IsActive());
848
849   EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
850
851   EXPECT_FALSE(GetIsDragged(browser()));
852 }
853
854 namespace {
855
856 void DeleteWhileDetachedStep2(WebContents* tab) {
857   delete tab;
858 }
859
860 }  // namespace
861
862 #if defined(OS_CHROMEOS)
863 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
864 // compositor. crbug.com/331924
865 #define MAYBE_DeleteTabWhileDetached DISABLED_DeleteTabWhileDetached
866 #else
867 #define MAYBE_DeleteTabWhileDetached DeleteTabWhileDetached
868 #endif
869 // Deletes a tab being dragged after dragging a tab so that a new window is
870 // created.
871 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
872                        MAYBE_DeleteTabWhileDetached) {
873   // Add another tab.
874   AddTabAndResetBrowser(browser());
875   TabStrip* tab_strip = GetTabStripForBrowser(browser());
876
877   // Move to the first tab and drag it enough so that it detaches.
878   gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
879   WebContents* to_delete =
880       browser()->tab_strip_model()->GetWebContentsAt(0);
881   ASSERT_TRUE(PressInput(tab_0_center));
882   ASSERT_TRUE(DragInputToNotifyWhenDone(
883       tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
884       base::Bind(&DeleteWhileDetachedStep2, to_delete)));
885   QuitWhenNotDragging();
886
887   // Should not be dragging.
888   ASSERT_FALSE(tab_strip->IsDragSessionActive());
889   ASSERT_FALSE(TabDragController::IsActive());
890
891   EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
892
893   EXPECT_FALSE(GetIsDragged(browser()));
894 }
895
896 namespace {
897
898 void DeleteSourceDetachedStep2(WebContents* tab,
899                                const BrowserList* browser_list) {
900   ASSERT_EQ(2u, browser_list->size());
901   Browser* new_browser = browser_list->get(1);
902   // This ends up closing the source window.
903   delete tab;
904   // Cancel the drag.
905   ui_controls::SendKeyPress(new_browser->window()->GetNativeWindow(),
906                             ui::VKEY_ESCAPE, false, false, false, false);
907 }
908
909 }  // namespace
910
911 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
912 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
913 // compositor. crbug.com/331924
914 #define MAYBE_DeleteSourceDetached DISABLED_DeleteSourceDetached
915 #else
916 #define MAYBE_DeleteSourceDetached DeleteSourceDetached
917 #endif
918 // Detaches a tab and while detached deletes a tab from the source so that the
919 // source window closes then presses escape to cancel the drag.
920 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
921                        MAYBE_DeleteSourceDetached) {
922   // Add another tab.
923   AddTabAndResetBrowser(browser());
924   TabStrip* tab_strip = GetTabStripForBrowser(browser());
925
926   // Move to the first tab and drag it enough so that it detaches.
927   gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
928   WebContents* to_delete = browser()->tab_strip_model()->GetWebContentsAt(1);
929   ASSERT_TRUE(PressInput(tab_0_center));
930   ASSERT_TRUE(DragInputToNotifyWhenDone(
931       tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
932       base::Bind(&DeleteSourceDetachedStep2, to_delete, native_browser_list)));
933   QuitWhenNotDragging();
934
935   // Should not be dragging.
936   ASSERT_EQ(1u, native_browser_list->size());
937   Browser* new_browser = native_browser_list->get(0);
938   ASSERT_FALSE(GetTabStripForBrowser(new_browser)->IsDragSessionActive());
939   ASSERT_FALSE(TabDragController::IsActive());
940
941   EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
942
943   EXPECT_FALSE(GetIsDragged(new_browser));
944
945   // Remaining browser window should not be maximized
946   EXPECT_FALSE(new_browser->window()->IsMaximized());
947 }
948
949 namespace {
950
951 void PressEscapeWhileDetachedStep2(const BrowserList* browser_list) {
952   ASSERT_EQ(2u, browser_list->size());
953   Browser* new_browser = browser_list->get(1);
954   ui_controls::SendKeyPress(
955       new_browser->window()->GetNativeWindow(), ui::VKEY_ESCAPE, false, false,
956       false, false);
957 }
958
959 }  // namespace
960
961 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
962 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
963 // compositor. crbug.com/331924
964 #define MAYBE_PressEscapeWhileDetached DISABLED_PressEscapeWhileDetached
965 #else
966 #define MAYBE_PressEscapeWhileDetached PressEscapeWhileDetached
967 #endif
968 // This is disabled until NativeViewHost::Detach really detaches.
969 // Detaches a tab and while detached presses escape to revert the drag.
970 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
971                        MAYBE_PressEscapeWhileDetached) {
972   // Add another tab.
973   AddTabAndResetBrowser(browser());
974   TabStrip* tab_strip = GetTabStripForBrowser(browser());
975
976   // Move to the first tab and drag it enough so that it detaches.
977   gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
978   ASSERT_TRUE(PressInput(tab_0_center));
979   ASSERT_TRUE(DragInputToNotifyWhenDone(
980       tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
981       base::Bind(&PressEscapeWhileDetachedStep2, native_browser_list)));
982   QuitWhenNotDragging();
983
984   // Should not be dragging.
985   ASSERT_FALSE(tab_strip->IsDragSessionActive());
986   ASSERT_FALSE(TabDragController::IsActive());
987
988   // And there should only be one window.
989   EXPECT_EQ(1u, native_browser_list->size());
990
991   EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
992
993   // Remaining browser window should not be maximized
994   EXPECT_FALSE(browser()->window()->IsMaximized());
995
996   // The tab strip should no longer have capture because the drag was ended and
997   // mouse/touch was released.
998   EXPECT_FALSE(tab_strip->GetWidget()->HasCapture());
999 }
1000
1001 namespace {
1002
1003 void DragAllStep2(DetachToBrowserTabDragControllerTest* test,
1004                   const BrowserList* browser_list) {
1005   // Should only be one window.
1006   ASSERT_EQ(1u, browser_list->size());
1007   if (test->input_source() == INPUT_SOURCE_TOUCH) {
1008     ASSERT_TRUE(test->ReleaseInput());
1009   } else {
1010     ASSERT_TRUE(test->ReleaseMouseAsync());
1011   }
1012 }
1013
1014 }  // namespace
1015
1016 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1017 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1018 // compositor. crbug.com/331924
1019 #define MAYBE_DragAll DISABLED_DragAll
1020 #else
1021 #define MAYBE_DragAll DragAll
1022 #endif
1023 // Selects multiple tabs and starts dragging the window.
1024 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, MAYBE_DragAll) {
1025   // Add another tab.
1026   AddTabAndResetBrowser(browser());
1027   TabStrip* tab_strip = GetTabStripForBrowser(browser());
1028   browser()->tab_strip_model()->AddTabAtToSelection(0);
1029   browser()->tab_strip_model()->AddTabAtToSelection(1);
1030
1031   // Move to the first tab and drag it enough so that it would normally
1032   // detach.
1033   gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1034   ASSERT_TRUE(PressInput(tab_0_center));
1035   ASSERT_TRUE(DragInputToNotifyWhenDone(
1036       tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1037       base::Bind(&DragAllStep2, this, native_browser_list)));
1038   QuitWhenNotDragging();
1039
1040   // Should not be dragging.
1041   ASSERT_FALSE(tab_strip->IsDragSessionActive());
1042   ASSERT_FALSE(TabDragController::IsActive());
1043
1044   // And there should only be one window.
1045   EXPECT_EQ(1u, native_browser_list->size());
1046
1047   EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
1048
1049   EXPECT_FALSE(GetIsDragged(browser()));
1050
1051   // Remaining browser window should not be maximized
1052   EXPECT_FALSE(browser()->window()->IsMaximized());
1053 }
1054
1055 namespace {
1056
1057 // Invoked from the nested message loop.
1058 void DragAllToSeparateWindowStep2(DetachToBrowserTabDragControllerTest* test,
1059                                   TabStrip* attached_tab_strip,
1060                                   TabStrip* target_tab_strip,
1061                                   const BrowserList* browser_list) {
1062   ASSERT_TRUE(attached_tab_strip->IsDragSessionActive());
1063   ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
1064   ASSERT_TRUE(TabDragController::IsActive());
1065   ASSERT_EQ(2u, browser_list->size());
1066
1067   // Drag to target_tab_strip. This should stop the nested loop from dragging
1068   // the window.
1069   gfx::Point target_point(target_tab_strip->width() - 1,
1070                           target_tab_strip->height() / 2);
1071   views::View::ConvertPointToScreen(target_tab_strip, &target_point);
1072   ASSERT_TRUE(test->DragInputToAsync(target_point));
1073 }
1074
1075 }  // namespace
1076
1077 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1078 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1079 // compositor. crbug.com/331924
1080 #define MAYBE_DragAllToSeparateWindow DISABLED_DragAllToSeparateWindow
1081 #else
1082 #define MAYBE_DragAllToSeparateWindow DragAllToSeparateWindow
1083 #endif
1084 // Creates two browsers, selects all tabs in first and drags into second.
1085 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1086                        MAYBE_DragAllToSeparateWindow) {
1087   TabStrip* tab_strip = GetTabStripForBrowser(browser());
1088
1089   // Add another tab to browser().
1090   AddTabAndResetBrowser(browser());
1091
1092   // Create another browser.
1093   Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
1094   TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1095
1096   browser()->tab_strip_model()->AddTabAtToSelection(0);
1097   browser()->tab_strip_model()->AddTabAtToSelection(1);
1098
1099   // Move to the first tab and drag it enough so that it detaches, but not
1100   // enough that it attaches to browser2.
1101   gfx::Point tab_0_center(
1102       GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1103   ASSERT_TRUE(PressInput(tab_0_center));
1104   ASSERT_TRUE(DragInputToNotifyWhenDone(
1105       tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1106       base::Bind(&DragAllToSeparateWindowStep2, this, tab_strip, tab_strip2,
1107                  native_browser_list)));
1108   QuitWhenNotDragging();
1109
1110   // Should now be attached to tab_strip2.
1111   ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1112   ASSERT_TRUE(TabDragController::IsActive());
1113   ASSERT_EQ(1u, native_browser_list->size());
1114
1115   // Release the mouse, stopping the drag session.
1116   ASSERT_TRUE(ReleaseInput());
1117   ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1118   ASSERT_FALSE(TabDragController::IsActive());
1119   EXPECT_EQ("100 0 1", IDString(browser2->tab_strip_model()));
1120
1121   EXPECT_FALSE(GetIsDragged(browser2));
1122
1123   // Remaining browser window should not be maximized
1124   EXPECT_FALSE(browser2->window()->IsMaximized());
1125 }
1126
1127 namespace {
1128
1129 // Invoked from the nested message loop.
1130 void DragAllToSeparateWindowAndCancelStep2(
1131     DetachToBrowserTabDragControllerTest* test,
1132     TabStrip* attached_tab_strip,
1133     TabStrip* target_tab_strip,
1134     const BrowserList* browser_list) {
1135   ASSERT_TRUE(attached_tab_strip->IsDragSessionActive());
1136   ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
1137   ASSERT_TRUE(TabDragController::IsActive());
1138   ASSERT_EQ(2u, browser_list->size());
1139
1140   // Drag to target_tab_strip. This should stop the nested loop from dragging
1141   // the window.
1142   gfx::Point target_point(target_tab_strip->width() - 1,
1143                           target_tab_strip->height() / 2);
1144   views::View::ConvertPointToScreen(target_tab_strip, &target_point);
1145   ASSERT_TRUE(test->DragInputToAsync(target_point));
1146 }
1147
1148 }  // namespace
1149
1150 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1151 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1152 // compositor. crbug.com/331924
1153 #define MAYBE_DragAllToSeparateWindowAndCancel \
1154   DISABLED_DragAllToSeparateWindowAndCancel
1155 #else
1156 #define MAYBE_DragAllToSeparateWindowAndCancel DragAllToSeparateWindowAndCancel
1157 #endif
1158 // Creates two browsers, selects all tabs in first, drags into second, then hits
1159 // escape.
1160 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1161                        MAYBE_DragAllToSeparateWindowAndCancel) {
1162   TabStrip* tab_strip = GetTabStripForBrowser(browser());
1163
1164   // Add another tab to browser().
1165   AddTabAndResetBrowser(browser());
1166
1167   // Create another browser.
1168   Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
1169   TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1170
1171   browser()->tab_strip_model()->AddTabAtToSelection(0);
1172   browser()->tab_strip_model()->AddTabAtToSelection(1);
1173
1174   // Move to the first tab and drag it enough so that it detaches, but not
1175   // enough that it attaches to browser2.
1176   gfx::Point tab_0_center(
1177       GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1178   ASSERT_TRUE(PressInput(tab_0_center));
1179   ASSERT_TRUE(DragInputToNotifyWhenDone(
1180                   tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1181                   base::Bind(&DragAllToSeparateWindowAndCancelStep2, this,
1182                              tab_strip, tab_strip2, native_browser_list)));
1183   QuitWhenNotDragging();
1184
1185   // Should now be attached to tab_strip2.
1186   ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1187   ASSERT_TRUE(TabDragController::IsActive());
1188   ASSERT_EQ(1u, native_browser_list->size());
1189
1190   // Cancel the drag.
1191   ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
1192       browser2, ui::VKEY_ESCAPE, false, false, false, false));
1193
1194   ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1195   ASSERT_FALSE(TabDragController::IsActive());
1196   EXPECT_EQ("100 0 1", IDString(browser2->tab_strip_model()));
1197
1198   // browser() will have been destroyed, but browser2 should remain.
1199   ASSERT_EQ(1u, native_browser_list->size());
1200
1201   EXPECT_FALSE(GetIsDragged(browser2));
1202
1203   // Remaining browser window should not be maximized
1204   EXPECT_FALSE(browser2->window()->IsMaximized());
1205 }
1206
1207 #if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_WIN)
1208 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1209 // compositor. crbug.com/331924
1210 #define MAYBE_DragDirectlyToSecondWindow DISABLED_DragDirectlyToSecondWindow
1211 #else
1212 #define MAYBE_DragDirectlyToSecondWindow DragDirectlyToSecondWindow
1213 #endif
1214 // Creates two browsers, drags from first into the second in such a way that
1215 // no detaching should happen.
1216 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1217                        MAYBE_DragDirectlyToSecondWindow) {
1218   TabStrip* tab_strip = GetTabStripForBrowser(browser());
1219
1220   // Add another tab to browser().
1221   AddTabAndResetBrowser(browser());
1222
1223   // Create another browser.
1224   Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
1225   TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1226
1227   // Move the tabstrip down enough so that we can detach.
1228   gfx::Rect bounds(browser2->window()->GetBounds());
1229   bounds.Offset(0, 100);
1230   browser2->window()->SetBounds(bounds);
1231
1232   // Move to the first tab and drag it enough so that it detaches, but not
1233   // enough that it attaches to browser2.
1234   gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1235   ASSERT_TRUE(PressInput(tab_0_center));
1236
1237   gfx::Point b2_location(5, 0);
1238   views::View::ConvertPointToScreen(tab_strip2, &b2_location);
1239   ASSERT_TRUE(DragInputTo(b2_location));
1240
1241   // Should now be attached to tab_strip2.
1242   ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1243   ASSERT_FALSE(tab_strip->IsDragSessionActive());
1244   ASSERT_TRUE(TabDragController::IsActive());
1245
1246   // Release the mouse, stopping the drag session.
1247   ASSERT_TRUE(ReleaseInput());
1248   ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1249   ASSERT_FALSE(tab_strip->IsDragSessionActive());
1250   ASSERT_FALSE(TabDragController::IsActive());
1251   EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1252   EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1253
1254   EXPECT_FALSE(GetIsDragged(browser()));
1255   EXPECT_FALSE(GetIsDragged(browser2));
1256
1257   // Both windows should not be maximized
1258   EXPECT_FALSE(browser()->window()->IsMaximized());
1259   EXPECT_FALSE(browser2->window()->IsMaximized());
1260 }
1261
1262 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1263 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1264 // compositor. crbug.com/331924
1265 #define MAYBE_DragSingleTabToSeparateWindow \
1266   DISABLED_DragSingleTabToSeparateWindow
1267 #else
1268 #define MAYBE_DragSingleTabToSeparateWindow DragSingleTabToSeparateWindow
1269 #endif
1270 // Creates two browsers, the first browser has a single tab and drags into the
1271 // second browser.
1272 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1273                        MAYBE_DragSingleTabToSeparateWindow) {
1274   TabStrip* tab_strip = GetTabStripForBrowser(browser());
1275
1276   ResetIDs(browser()->tab_strip_model(), 0);
1277
1278   // Create another browser.
1279   Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
1280   TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1281   const gfx::Rect initial_bounds(browser2->window()->GetBounds());
1282
1283   // Move to the first tab and drag it enough so that it detaches, but not
1284   // enough that it attaches to browser2.
1285   gfx::Point tab_0_center(
1286       GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1287   ASSERT_TRUE(PressInput(tab_0_center));
1288   ASSERT_TRUE(DragInputToNotifyWhenDone(
1289       tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1290       base::Bind(&DragAllToSeparateWindowStep2, this, tab_strip, tab_strip2,
1291                  native_browser_list)));
1292   QuitWhenNotDragging();
1293
1294   // Should now be attached to tab_strip2.
1295   ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1296   ASSERT_TRUE(TabDragController::IsActive());
1297   ASSERT_EQ(1u, native_browser_list->size());
1298
1299   // Release the mouse, stopping the drag session.
1300   ASSERT_TRUE(ReleaseInput());
1301   ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1302   ASSERT_FALSE(TabDragController::IsActive());
1303   EXPECT_EQ("100 0", IDString(browser2->tab_strip_model()));
1304
1305   EXPECT_FALSE(GetIsDragged(browser2));
1306
1307   // Remaining browser window should not be maximized
1308   EXPECT_FALSE(browser2->window()->IsMaximized());
1309
1310   // Make sure that the window is still managed and not user moved.
1311   EXPECT_TRUE(IsWindowPositionManaged(browser2->window()->GetNativeWindow()));
1312   EXPECT_FALSE(HasUserChangedWindowPositionOrSize(
1313       browser2->window()->GetNativeWindow()));
1314   // Also make sure that the drag to window position has not changed.
1315   EXPECT_EQ(initial_bounds.ToString(),
1316             browser2->window()->GetBounds().ToString());
1317 }
1318
1319 namespace {
1320
1321 // Invoked from the nested message loop.
1322 void CancelOnNewTabWhenDraggingStep2(
1323     DetachToBrowserTabDragControllerTest* test,
1324     const BrowserList* browser_list) {
1325   ASSERT_TRUE(TabDragController::IsActive());
1326   ASSERT_EQ(2u, browser_list->size());
1327
1328   // Add another tab. This should trigger exiting the nested loop.
1329   test->AddBlankTabAndShow(browser_list->GetLastActive());
1330 }
1331
1332 }  // namespace
1333
1334 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
1335 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
1336 // compositor. crbug.com/331924
1337 #define MAYBE_CancelOnNewTabWhenDragging DISABLED_CancelOnNewTabWhenDragging
1338 #else
1339 #define MAYBE_CancelOnNewTabWhenDragging CancelOnNewTabWhenDragging
1340 #endif
1341 // Adds another tab, detaches into separate window, adds another tab and
1342 // verifies the run loop ends.
1343 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1344                        MAYBE_CancelOnNewTabWhenDragging) {
1345   TabStrip* tab_strip = GetTabStripForBrowser(browser());
1346
1347   // Add another tab to browser().
1348   AddTabAndResetBrowser(browser());
1349
1350   // Move to the first tab and drag it enough so that it detaches.
1351   gfx::Point tab_0_center(
1352       GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1353   ASSERT_TRUE(PressInput(tab_0_center));
1354   ASSERT_TRUE(DragInputToNotifyWhenDone(
1355       tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1356       base::Bind(&CancelOnNewTabWhenDraggingStep2, this, native_browser_list)));
1357   QuitWhenNotDragging();
1358
1359   // Should be two windows and not dragging.
1360   ASSERT_FALSE(TabDragController::IsActive());
1361   ASSERT_EQ(2u, native_browser_list->size());
1362   for (chrome::BrowserIterator it; !it.done(); it.Next()) {
1363     EXPECT_FALSE(GetIsDragged(*it));
1364     // Should not be maximized
1365     EXPECT_FALSE(it->window()->IsMaximized());
1366   }
1367 }
1368
1369 #if defined(OS_CHROMEOS)
1370 // TODO(sky,sad): A number of tests below are disabled as they fail due to
1371 // resize locks with a real compositor. crbug.com/331924
1372 namespace {
1373
1374 void DragInMaximizedWindowStep2(DetachToBrowserTabDragControllerTest* test,
1375                                 Browser* browser,
1376                                 TabStrip* tab_strip,
1377                                 const BrowserList* browser_list) {
1378   // There should be another browser.
1379   ASSERT_EQ(2u, browser_list->size());
1380   Browser* new_browser = browser_list->get(1);
1381   EXPECT_NE(browser, new_browser);
1382   ASSERT_TRUE(new_browser->window()->IsActive());
1383   TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
1384
1385   ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1386   ASSERT_FALSE(tab_strip->IsDragSessionActive());
1387
1388   // Both windows should be visible.
1389   EXPECT_TRUE(tab_strip->GetWidget()->IsVisible());
1390   EXPECT_TRUE(tab_strip2->GetWidget()->IsVisible());
1391
1392   // Stops dragging.
1393   ASSERT_TRUE(test->ReleaseInput());
1394 }
1395
1396 }  // namespace
1397
1398 // Creates a browser with two tabs, maximizes it, drags the tab out.
1399 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1400                        DISABLED_DragInMaximizedWindow) {
1401   AddTabAndResetBrowser(browser());
1402   browser()->window()->Maximize();
1403
1404   TabStrip* tab_strip = GetTabStripForBrowser(browser());
1405
1406   // Move to the first tab and drag it enough so that it detaches.
1407   gfx::Point tab_0_center(
1408       GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1409   ASSERT_TRUE(PressInput(tab_0_center));
1410   ASSERT_TRUE(DragInputToNotifyWhenDone(
1411       tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1412       base::Bind(&DragInMaximizedWindowStep2, this, browser(), tab_strip,
1413                  native_browser_list)));
1414   QuitWhenNotDragging();
1415
1416   ASSERT_FALSE(TabDragController::IsActive());
1417
1418   // Should be two browsers.
1419   ASSERT_EQ(2u, native_browser_list->size());
1420   Browser* new_browser = native_browser_list->get(1);
1421   ASSERT_TRUE(new_browser->window()->IsActive());
1422
1423   EXPECT_TRUE(browser()->window()->GetNativeWindow()->IsVisible());
1424   EXPECT_TRUE(new_browser->window()->GetNativeWindow()->IsVisible());
1425
1426   EXPECT_FALSE(GetIsDragged(browser()));
1427   EXPECT_FALSE(GetIsDragged(new_browser));
1428
1429   // The source window should be maximized.
1430   EXPECT_TRUE(browser()->window()->IsMaximized());
1431   // The new window should be maximized.
1432   EXPECT_TRUE(new_browser->window()->IsMaximized());
1433 }
1434
1435 // Subclass of DetachToBrowserTabDragControllerTest that
1436 // creates multiple displays.
1437 class DetachToBrowserInSeparateDisplayTabDragControllerTest
1438     : public DetachToBrowserTabDragControllerTest {
1439  public:
1440   DetachToBrowserInSeparateDisplayTabDragControllerTest() {}
1441   virtual ~DetachToBrowserInSeparateDisplayTabDragControllerTest() {}
1442
1443   virtual void SetUpCommandLine(CommandLine* command_line) override {
1444     DetachToBrowserTabDragControllerTest::SetUpCommandLine(command_line);
1445     // Make screens sufficiently wide to host 2 browsers side by side.
1446     command_line->AppendSwitchASCII("ash-host-window-bounds",
1447                                     "0+0-600x600,601+0-600x600");
1448   }
1449
1450  private:
1451   DISALLOW_COPY_AND_ASSIGN(
1452       DetachToBrowserInSeparateDisplayTabDragControllerTest);
1453 };
1454
1455 // Subclass of DetachToBrowserTabDragControllerTest that runs tests only with
1456 // touch input.
1457 class DetachToBrowserTabDragControllerTestTouch
1458     : public DetachToBrowserTabDragControllerTest {
1459  public:
1460   DetachToBrowserTabDragControllerTestTouch() {}
1461   virtual ~DetachToBrowserTabDragControllerTestTouch() {}
1462
1463  private:
1464   DISALLOW_COPY_AND_ASSIGN(DetachToBrowserTabDragControllerTestTouch);
1465 };
1466
1467 namespace {
1468
1469 void DragSingleTabToSeparateWindowInSecondDisplayStep3(
1470     DetachToBrowserTabDragControllerTest* test) {
1471   ASSERT_TRUE(test->ReleaseInput());
1472 }
1473
1474 void DragSingleTabToSeparateWindowInSecondDisplayStep2(
1475     DetachToBrowserTabDragControllerTest* test,
1476     const gfx::Point& target_point) {
1477   ASSERT_TRUE(test->DragInputToNotifyWhenDone(
1478       target_point.x(), target_point.y(),
1479       base::Bind(&DragSingleTabToSeparateWindowInSecondDisplayStep3, test)));
1480 }
1481
1482 }  // namespace
1483
1484 // Drags from browser to a second display and releases input.
1485 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1486                        DISABLED_DragSingleTabToSeparateWindowInSecondDisplay) {
1487   // Add another tab.
1488   AddTabAndResetBrowser(browser());
1489   TabStrip* tab_strip = GetTabStripForBrowser(browser());
1490
1491   // Move to the first tab and drag it enough so that it detaches.
1492   // Then drag it to the final destination on the second screen.
1493   gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1494   ASSERT_TRUE(PressInput(tab_0_center));
1495   ASSERT_TRUE(DragInputToNotifyWhenDone(
1496                   tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1497                   base::Bind(&DragSingleTabToSeparateWindowInSecondDisplayStep2,
1498                              this, gfx::Point(600 + tab_0_center.x(),
1499                                               tab_0_center.y()
1500                                               + GetDetachY(tab_strip)))));
1501   QuitWhenNotDragging();
1502
1503   // Should no longer be dragging.
1504   ASSERT_FALSE(tab_strip->IsDragSessionActive());
1505   ASSERT_FALSE(TabDragController::IsActive());
1506
1507   // There should now be another browser.
1508   ASSERT_EQ(2u, native_browser_list->size());
1509   Browser* new_browser = native_browser_list->get(1);
1510   ASSERT_TRUE(new_browser->window()->IsActive());
1511   TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
1512   ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1513
1514   // This other browser should be on the second screen (with mouse drag)
1515   // With the touch input the browser cannot be dragged from one screen
1516   // to another and the window stays on the first screen.
1517   if (input_source() == INPUT_SOURCE_MOUSE) {
1518     aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1519     ASSERT_EQ(2u, roots.size());
1520     aura::Window* second_root = roots[1];
1521     EXPECT_EQ(second_root,
1522               new_browser->window()->GetNativeWindow()->GetRootWindow());
1523   }
1524
1525   EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
1526   EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1527
1528   // Both windows should not be maximized
1529   EXPECT_FALSE(browser()->window()->IsMaximized());
1530   EXPECT_FALSE(new_browser->window()->IsMaximized());
1531 }
1532
1533 namespace {
1534
1535 // Invoked from the nested message loop.
1536 void DragTabToWindowInSeparateDisplayStep2(
1537     DetachToBrowserTabDragControllerTest* test,
1538     TabStrip* not_attached_tab_strip,
1539     TabStrip* target_tab_strip) {
1540   ASSERT_FALSE(not_attached_tab_strip->IsDragSessionActive());
1541   ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
1542   ASSERT_TRUE(TabDragController::IsActive());
1543
1544   // Drag to target_tab_strip. This should stop the nested loop from dragging
1545   // the window.
1546   gfx::Point target_point(
1547       GetCenterInScreenCoordinates(target_tab_strip->tab_at(0)));
1548
1549   // Move it close to the beginning of the target tabstrip.
1550   target_point.set_x(
1551       target_point.x() - target_tab_strip->tab_at(0)->width() / 2 + 10);
1552   ASSERT_TRUE(test->DragInputToAsync(target_point));
1553 }
1554
1555 }  // namespace
1556
1557 // Drags from browser to another browser on a second display and releases input.
1558 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1559                        DISABLED_DragTabToWindowInSeparateDisplay) {
1560   // Add another tab.
1561   AddTabAndResetBrowser(browser());
1562   TabStrip* tab_strip = GetTabStripForBrowser(browser());
1563
1564   // Create another browser.
1565   Browser* browser2 = CreateBrowser(browser()->profile());
1566   TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1567   ResetIDs(browser2->tab_strip_model(), 100);
1568
1569   // Move the second browser to the second display.
1570   aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1571   ASSERT_EQ(2u, roots.size());
1572   aura::Window* second_root = roots[1];
1573   gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1574       second_root).work_area();
1575   browser2->window()->SetBounds(work_area);
1576   EXPECT_EQ(second_root,
1577             browser2->window()->GetNativeWindow()->GetRootWindow());
1578
1579   // Move to the first tab and drag it enough so that it detaches, but not
1580   // enough that it attaches to browser2.
1581   gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1582   ASSERT_TRUE(PressInput(tab_0_center));
1583   ASSERT_TRUE(DragInputToNotifyWhenDone(
1584                   tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1585                   base::Bind(&DragTabToWindowInSeparateDisplayStep2,
1586                              this, tab_strip, tab_strip2)));
1587   QuitWhenNotDragging();
1588
1589   // Should now be attached to tab_strip2.
1590   ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1591   ASSERT_FALSE(tab_strip->IsDragSessionActive());
1592   ASSERT_TRUE(TabDragController::IsActive());
1593
1594   // Release the mouse, stopping the drag session.
1595   ASSERT_TRUE(ReleaseInput());
1596   ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1597   ASSERT_FALSE(tab_strip->IsDragSessionActive());
1598   ASSERT_FALSE(TabDragController::IsActive());
1599   EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1600   EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1601
1602   // Both windows should not be maximized
1603   EXPECT_FALSE(browser()->window()->IsMaximized());
1604   EXPECT_FALSE(browser2->window()->IsMaximized());
1605 }
1606
1607 // Drags from browser to another browser on a second display and releases input.
1608 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1609                        DISABLED_DragTabToWindowOnSecondDisplay) {
1610   // Add another tab.
1611   AddTabAndResetBrowser(browser());
1612   TabStrip* tab_strip = GetTabStripForBrowser(browser());
1613
1614   // Create another browser.
1615   Browser* browser2 = CreateBrowser(browser()->profile());
1616   TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1617   ResetIDs(browser2->tab_strip_model(), 100);
1618
1619   // Move both browsers to the second display.
1620   aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1621   ASSERT_EQ(2u, roots.size());
1622   aura::Window* second_root = roots[1];
1623   gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1624       second_root).work_area();
1625   browser()->window()->SetBounds(work_area);
1626
1627   // position both browser windows side by side on the second screen.
1628   gfx::Rect work_area2(work_area);
1629   work_area.set_width(work_area.width()/2);
1630   browser()->window()->SetBounds(work_area);
1631   work_area2.set_x(work_area2.x() + work_area2.width()/2);
1632   work_area2.set_width(work_area2.width()/2);
1633   browser2->window()->SetBounds(work_area2);
1634   EXPECT_EQ(second_root,
1635             browser()->window()->GetNativeWindow()->GetRootWindow());
1636   EXPECT_EQ(second_root,
1637             browser2->window()->GetNativeWindow()->GetRootWindow());
1638
1639   // Move to the first tab and drag it enough so that it detaches, but not
1640   // enough that it attaches to browser2.
1641   // SetEventGeneratorRootWindow sets correct (second) RootWindow
1642   gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1643   SetEventGeneratorRootWindow(tab_0_center);
1644   ASSERT_TRUE(PressInput(tab_0_center));
1645   ASSERT_TRUE(DragInputToNotifyWhenDone(
1646                   tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1647                   base::Bind(&DragTabToWindowInSeparateDisplayStep2,
1648                              this, tab_strip, tab_strip2)));
1649   QuitWhenNotDragging();
1650
1651   // Should now be attached to tab_strip2.
1652   ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1653   ASSERT_FALSE(tab_strip->IsDragSessionActive());
1654   ASSERT_TRUE(TabDragController::IsActive());
1655
1656   // Release the mouse, stopping the drag session.
1657   ASSERT_TRUE(ReleaseInput());
1658   ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1659   ASSERT_FALSE(tab_strip->IsDragSessionActive());
1660   ASSERT_FALSE(TabDragController::IsActive());
1661   EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1662   EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1663
1664   // Both windows should not be maximized
1665   EXPECT_FALSE(browser()->window()->IsMaximized());
1666   EXPECT_FALSE(browser2->window()->IsMaximized());
1667 }
1668
1669 // Drags from a maximized browser to another non-maximized browser on a second
1670 // display and releases input.
1671 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1672                        DISABLED_DragMaxTabToNonMaxWindowInSeparateDisplay) {
1673   // Add another tab.
1674   AddTabAndResetBrowser(browser());
1675   browser()->window()->Maximize();
1676   TabStrip* tab_strip = GetTabStripForBrowser(browser());
1677
1678   // Create another browser on the second display.
1679   aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1680   ASSERT_EQ(2u, roots.size());
1681   aura::Window* first_root = roots[0];
1682   aura::Window* second_root = roots[1];
1683   gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1684       second_root).work_area();
1685   work_area.Inset(20, 20, 20, 60);
1686   Browser::CreateParams params(browser()->profile(),
1687                                browser()->host_desktop_type());
1688   params.initial_show_state = ui::SHOW_STATE_NORMAL;
1689   params.initial_bounds = work_area;
1690   Browser* browser2 = new Browser(params);
1691   AddBlankTabAndShow(browser2);
1692
1693   TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1694   ResetIDs(browser2->tab_strip_model(), 100);
1695
1696   EXPECT_EQ(second_root,
1697             browser2->window()->GetNativeWindow()->GetRootWindow());
1698   EXPECT_EQ(first_root,
1699             browser()->window()->GetNativeWindow()->GetRootWindow());
1700   EXPECT_EQ(2, tab_strip->tab_count());
1701   EXPECT_EQ(1, tab_strip2->tab_count());
1702
1703   // Move to the first tab and drag it enough so that it detaches, but not
1704   // enough that it attaches to browser2.
1705   gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1706   ASSERT_TRUE(PressInput(tab_0_center));
1707   ASSERT_TRUE(DragInputToNotifyWhenDone(
1708                   tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1709                   base::Bind(&DragTabToWindowInSeparateDisplayStep2,
1710                              this, tab_strip, tab_strip2)));
1711   QuitWhenNotDragging();
1712
1713   // Should now be attached to tab_strip2.
1714   ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1715   ASSERT_FALSE(tab_strip->IsDragSessionActive());
1716   ASSERT_TRUE(TabDragController::IsActive());
1717
1718   // Release the mouse, stopping the drag session.
1719   ASSERT_TRUE(ReleaseInput());
1720
1721   // tab should have moved
1722   EXPECT_EQ(1, tab_strip->tab_count());
1723   EXPECT_EQ(2, tab_strip2->tab_count());
1724
1725   ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1726   ASSERT_FALSE(tab_strip->IsDragSessionActive());
1727   ASSERT_FALSE(TabDragController::IsActive());
1728   EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1729   EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1730
1731   // Source browser should still be maximized, target should not
1732   EXPECT_TRUE(browser()->window()->IsMaximized());
1733   EXPECT_FALSE(browser2->window()->IsMaximized());
1734 }
1735
1736 // Drags from a restored browser to an immersive fullscreen browser on a
1737 // second display and releases input.
1738 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1739                        DISABLED_DragTabToImmersiveBrowserOnSeparateDisplay) {
1740   // Add another tab.
1741   AddTabAndResetBrowser(browser());
1742   TabStrip* tab_strip = GetTabStripForBrowser(browser());
1743
1744   // Create another browser.
1745   Browser* browser2 = CreateBrowser(browser()->profile());
1746   TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1747   ResetIDs(browser2->tab_strip_model(), 100);
1748
1749   // Move the second browser to the second display.
1750   aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1751   ASSERT_EQ(2u, roots.size());
1752   aura::Window* second_root = roots[1];
1753   gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1754       second_root).work_area();
1755   browser2->window()->SetBounds(work_area);
1756   EXPECT_EQ(second_root,
1757             browser2->window()->GetNativeWindow()->GetRootWindow());
1758
1759   // Put the second browser into immersive fullscreen.
1760   BrowserView* browser_view2 = BrowserView::GetBrowserViewForBrowser(browser2);
1761   ImmersiveModeController* immersive_controller2 =
1762       browser_view2->immersive_mode_controller();
1763   immersive_controller2->SetupForTest();
1764   chrome::ToggleFullscreenMode(browser2);
1765   ASSERT_TRUE(immersive_controller2->IsEnabled());
1766   ASSERT_FALSE(immersive_controller2->IsRevealed());
1767   ASSERT_TRUE(tab_strip2->IsImmersiveStyle());
1768
1769   // Move to the first tab and drag it enough so that it detaches, but not
1770   // enough that it attaches to browser2.
1771   gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1772   ASSERT_TRUE(PressInput(tab_0_center));
1773   ASSERT_TRUE(DragInputToNotifyWhenDone(
1774                   tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1775                   base::Bind(&DragTabToWindowInSeparateDisplayStep2,
1776                              this, tab_strip, tab_strip2)));
1777   QuitWhenNotDragging();
1778
1779   // Should now be attached to tab_strip2.
1780   ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1781   ASSERT_FALSE(tab_strip->IsDragSessionActive());
1782   ASSERT_TRUE(TabDragController::IsActive());
1783
1784   // browser2's top chrome should be revealed and the tab strip should be
1785   // at normal height while user is tragging tabs_strip2's tabs.
1786   ASSERT_TRUE(immersive_controller2->IsRevealed());
1787   ASSERT_FALSE(tab_strip2->IsImmersiveStyle());
1788
1789   // Release the mouse, stopping the drag session.
1790   ASSERT_TRUE(ReleaseInput());
1791   ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1792   ASSERT_FALSE(tab_strip->IsDragSessionActive());
1793   ASSERT_FALSE(TabDragController::IsActive());
1794   EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1795   EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1796
1797   // Move the mouse off of browser2's top chrome.
1798   aura::Window* primary_root = roots[0];
1799   ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
1800                   primary_root->GetBoundsInScreen().CenterPoint()));
1801
1802   // The first browser window should not be in immersive fullscreen.
1803   // browser2 should still be in immersive fullscreen, but the top chrome should
1804   // no longer be revealed.
1805   BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
1806   EXPECT_FALSE(browser_view->immersive_mode_controller()->IsEnabled());
1807
1808   EXPECT_TRUE(immersive_controller2->IsEnabled());
1809   EXPECT_FALSE(immersive_controller2->IsRevealed());
1810   EXPECT_TRUE(tab_strip2->IsImmersiveStyle());
1811 }
1812
1813 // Subclass of DetachToBrowserTabDragControllerTest that
1814 // creates multiple displays with different device scale factors.
1815 class DifferentDeviceScaleFactorDisplayTabDragControllerTest
1816     : public DetachToBrowserTabDragControllerTest {
1817  public:
1818   DifferentDeviceScaleFactorDisplayTabDragControllerTest() {}
1819   virtual ~DifferentDeviceScaleFactorDisplayTabDragControllerTest() {}
1820
1821   virtual void SetUpCommandLine(CommandLine* command_line) override {
1822     DetachToBrowserTabDragControllerTest::SetUpCommandLine(command_line);
1823     command_line->AppendSwitchASCII("ash-host-window-bounds",
1824                                     "400x400,0+400-800x800*2");
1825   }
1826
1827   float GetCursorDeviceScaleFactor() const {
1828     ash::test::CursorManagerTestApi cursor_test_api(
1829         ash::Shell::GetInstance()->cursor_manager());
1830     return cursor_test_api.GetCurrentCursor().device_scale_factor();
1831   }
1832
1833  private:
1834   DISALLOW_COPY_AND_ASSIGN(
1835       DifferentDeviceScaleFactorDisplayTabDragControllerTest);
1836 };
1837
1838 namespace {
1839
1840 // The points where a tab is dragged in CursorDeviceScaleFactorStep.
1841 const struct DragPoint {
1842   int x;
1843   int y;
1844 } kDragPoints[] = {
1845   {300, 200},
1846   {399, 200},
1847   {500, 200},
1848   {400, 200},
1849   {300, 200},
1850 };
1851
1852 // The expected device scale factors before the cursor is moved to the
1853 // corresponding kDragPoints in CursorDeviceScaleFactorStep.
1854 const float kDeviceScaleFactorExpectations[] = {
1855   1.0f,
1856   1.0f,
1857   2.0f,
1858   2.0f,
1859   1.0f,
1860 };
1861
1862 COMPILE_ASSERT(
1863     arraysize(kDragPoints) == arraysize(kDeviceScaleFactorExpectations),
1864     kDragPoints_and_kDeviceScaleFactorExpectations_must_have_same_size);
1865
1866 // Drags tab to |kDragPoints[index]|, then calls the next step function.
1867 void CursorDeviceScaleFactorStep(
1868     DifferentDeviceScaleFactorDisplayTabDragControllerTest* test,
1869     TabStrip* not_attached_tab_strip,
1870     size_t index) {
1871   ASSERT_FALSE(not_attached_tab_strip->IsDragSessionActive());
1872   ASSERT_TRUE(TabDragController::IsActive());
1873
1874   if (index < arraysize(kDragPoints)) {
1875     EXPECT_EQ(kDeviceScaleFactorExpectations[index],
1876               test->GetCursorDeviceScaleFactor());
1877     const DragPoint p = kDragPoints[index];
1878     ASSERT_TRUE(test->DragInputToNotifyWhenDone(
1879         p.x, p.y, base::Bind(&CursorDeviceScaleFactorStep,
1880                              test, not_attached_tab_strip, index + 1)));
1881   } else {
1882     // Finishes a serise of CursorDeviceScaleFactorStep calls and ends drag.
1883     EXPECT_EQ(1.0f, test->GetCursorDeviceScaleFactor());
1884     ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
1885         ui_controls::LEFT, ui_controls::UP));
1886   }
1887 }
1888
1889 }  // namespace
1890
1891 // Verifies cursor's device scale factor is updated when a tab is moved across
1892 // displays with different device scale factors (http://crbug.com/154183).
1893 IN_PROC_BROWSER_TEST_P(DifferentDeviceScaleFactorDisplayTabDragControllerTest,
1894                        DISABLED_CursorDeviceScaleFactor) {
1895   // Add another tab.
1896   AddTabAndResetBrowser(browser());
1897   TabStrip* tab_strip = GetTabStripForBrowser(browser());
1898
1899   // Move the second browser to the second display.
1900   aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1901   ASSERT_EQ(2u, roots.size());
1902
1903   // Move to the first tab and drag it enough so that it detaches.
1904   gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1905   ASSERT_TRUE(PressInput(tab_0_center));
1906   ASSERT_TRUE(DragInputToNotifyWhenDone(
1907                   tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1908                   base::Bind(&CursorDeviceScaleFactorStep,
1909                              this, tab_strip, 0)));
1910   QuitWhenNotDragging();
1911 }
1912
1913 namespace {
1914
1915 class DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest
1916     : public TabDragControllerTest {
1917  public:
1918   DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest() {}
1919
1920   virtual void SetUpCommandLine(CommandLine* command_line) override {
1921     TabDragControllerTest::SetUpCommandLine(command_line);
1922     command_line->AppendSwitchASCII("ash-host-window-bounds",
1923                                     "0+0-250x250,251+0-250x250");
1924   }
1925
1926   bool Press(const gfx::Point& position) {
1927     return ui_test_utils::SendMouseMoveSync(position) &&
1928         ui_test_utils::SendMouseEventsSync(ui_controls::LEFT,
1929                                            ui_controls::DOWN);
1930   }
1931
1932   bool DragTabAndExecuteTaskWhenDone(const gfx::Point& position,
1933                                      const base::Closure& task) {
1934     return ui_controls::SendMouseMoveNotifyWhenDone(
1935         position.x(), position.y(), task);
1936   }
1937
1938   void QuitWhenNotDragging() {
1939     test::QuitWhenNotDraggingImpl();
1940     base::MessageLoop::current()->Run();
1941   }
1942
1943  private:
1944   DISALLOW_COPY_AND_ASSIGN(
1945       DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest);
1946 };
1947
1948 // Invoked from the nested message loop.
1949 void CancelDragTabToWindowInSeparateDisplayStep3(
1950     TabStrip* tab_strip,
1951     const BrowserList* browser_list) {
1952   ASSERT_FALSE(tab_strip->IsDragSessionActive());
1953   ASSERT_TRUE(TabDragController::IsActive());
1954   ASSERT_EQ(2u, browser_list->size());
1955
1956   // Switching display mode should cancel the drag operation.
1957   ash::DisplayManager* display_manager =
1958       ash::Shell::GetInstance()->display_manager();
1959   display_manager->AddRemoveDisplay();
1960 }
1961
1962 // Invoked from the nested message loop.
1963 void CancelDragTabToWindowInSeparateDisplayStep2(
1964     DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest* test,
1965     TabStrip* tab_strip,
1966     aura::Window* current_root,
1967     gfx::Point final_destination,
1968     const BrowserList* browser_list) {
1969   ASSERT_FALSE(tab_strip->IsDragSessionActive());
1970   ASSERT_TRUE(TabDragController::IsActive());
1971   ASSERT_EQ(2u, browser_list->size());
1972
1973   Browser* new_browser = browser_list->get(1);
1974   EXPECT_EQ(current_root,
1975             new_browser->window()->GetNativeWindow()->GetRootWindow());
1976
1977   ASSERT_TRUE(test->DragTabAndExecuteTaskWhenDone(
1978       final_destination,
1979       base::Bind(&CancelDragTabToWindowInSeparateDisplayStep3,
1980                  tab_strip, browser_list)));
1981 }
1982
1983 }  // namespace
1984
1985 // Drags from browser to a second display and releases input.
1986 IN_PROC_BROWSER_TEST_F(
1987     DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest,
1988     DISABLED_CancelDragTabToWindowIn2ndDisplay) {
1989   // Add another tab.
1990   AddTabAndResetBrowser(browser());
1991   TabStrip* tab_strip = GetTabStripForBrowser(browser());
1992
1993   EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
1994
1995   // Move the second browser to the second display.
1996   aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
1997   ASSERT_EQ(2u, roots.size());
1998   gfx::Point final_destination =
1999       gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
2000           roots[1]).work_area().CenterPoint();
2001
2002   // Move to the first tab and drag it enough so that it detaches, but not
2003   // enough to move to another display.
2004   gfx::Point tab_0_dst(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
2005   ASSERT_TRUE(Press(tab_0_dst));
2006   tab_0_dst.Offset(0, GetDetachY(tab_strip));
2007   ASSERT_TRUE(DragTabAndExecuteTaskWhenDone(
2008       tab_0_dst, base::Bind(&CancelDragTabToWindowInSeparateDisplayStep2,
2009                             this, tab_strip, roots[0], final_destination,
2010                             native_browser_list)));
2011   QuitWhenNotDragging();
2012
2013   ASSERT_EQ(1u, native_browser_list->size());
2014   ASSERT_FALSE(tab_strip->IsDragSessionActive());
2015   ASSERT_FALSE(TabDragController::IsActive());
2016   EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2017
2018   // Release the mouse
2019   ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
2020       ui_controls::LEFT, ui_controls::UP));
2021 }
2022
2023 // Drags from browser from a second display to primary and releases input.
2024 IN_PROC_BROWSER_TEST_F(
2025     DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest,
2026     DISABLED_CancelDragTabToWindowIn1stDisplay) {
2027   aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
2028   ASSERT_EQ(2u, roots.size());
2029
2030   // Add another tab.
2031   AddTabAndResetBrowser(browser());
2032   TabStrip* tab_strip = GetTabStripForBrowser(browser());
2033
2034   EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2035   EXPECT_EQ(roots[0], browser()->window()->GetNativeWindow()->GetRootWindow());
2036
2037   gfx::Rect work_area = gfx::Screen::GetNativeScreen()->
2038       GetDisplayNearestWindow(roots[1]).work_area();
2039   browser()->window()->SetBounds(work_area);
2040   EXPECT_EQ(roots[1], browser()->window()->GetNativeWindow()->GetRootWindow());
2041
2042   // Move the second browser to the display.
2043   gfx::Point final_destination =
2044       gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
2045           roots[0]).work_area().CenterPoint();
2046
2047   // Move to the first tab and drag it enough so that it detaches, but not
2048   // enough to move to another display.
2049   gfx::Point tab_0_dst(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
2050   ASSERT_TRUE(Press(tab_0_dst));
2051   tab_0_dst.Offset(0, GetDetachY(tab_strip));
2052   ASSERT_TRUE(DragTabAndExecuteTaskWhenDone(
2053       tab_0_dst, base::Bind(&CancelDragTabToWindowInSeparateDisplayStep2,
2054                             this, tab_strip, roots[1], final_destination,
2055                             native_browser_list)));
2056   QuitWhenNotDragging();
2057
2058   ASSERT_EQ(1u, native_browser_list->size());
2059   ASSERT_FALSE(tab_strip->IsDragSessionActive());
2060   ASSERT_FALSE(TabDragController::IsActive());
2061   EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2062
2063   // Release the mouse
2064   ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
2065       ui_controls::LEFT, ui_controls::UP));
2066 }
2067
2068 namespace {
2069
2070 void PressSecondFingerWhileDetachedStep2(
2071     DetachToBrowserTabDragControllerTest* test) {
2072   ASSERT_TRUE(TabDragController::IsActive());
2073   ASSERT_EQ(2u, test->native_browser_list->size());
2074   Browser* new_browser = test->native_browser_list->get(1);
2075   ASSERT_TRUE(new_browser->window()->IsActive());
2076
2077   ASSERT_TRUE(test->PressInput2());
2078 }
2079
2080 }  // namespace
2081
2082 // Detaches a tab and while detached presses a second finger.
2083 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestTouch,
2084                        DISABLED_PressSecondFingerWhileDetached) {
2085   gfx::Rect bounds(browser()->window()->GetBounds());
2086   // Add another tab.
2087   AddTabAndResetBrowser(browser());
2088   TabStrip* tab_strip = GetTabStripForBrowser(browser());
2089   EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2090
2091   // Move to the first tab and drag it enough so that it detaches.
2092   gfx::Point tab_0_center(
2093       GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
2094   ASSERT_TRUE(PressInput(tab_0_center));
2095   ASSERT_TRUE(DragInputToDelayedNotifyWhenDone(
2096                   tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
2097                   base::Bind(&PressSecondFingerWhileDetachedStep2, this),
2098                   base::TimeDelta::FromMilliseconds(60)));
2099   QuitWhenNotDragging();
2100
2101   // The drag should have been reverted.
2102   ASSERT_EQ(1u, native_browser_list->size());
2103   ASSERT_FALSE(tab_strip->IsDragSessionActive());
2104   ASSERT_FALSE(TabDragController::IsActive());
2105   EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
2106
2107   ASSERT_TRUE(ReleaseInput());
2108   ASSERT_TRUE(ReleaseInput2());
2109 }
2110
2111 #if defined(OS_CHROMEOS)
2112
2113 namespace {
2114
2115 void DetachToDockedWindowNextStep(
2116     DetachToBrowserTabDragControllerTest* test,
2117     const gfx::Point& target_point,
2118     int iteration) {
2119   ASSERT_EQ(2u, test->native_browser_list->size());
2120   Browser* new_browser = test->native_browser_list->get(1);
2121   ASSERT_TRUE(new_browser->window()->IsActive());
2122
2123   if (!iteration) {
2124     ASSERT_TRUE(test->ReleaseInput());
2125     return;
2126   }
2127   ASSERT_TRUE(test->DragInputToNotifyWhenDone(
2128       target_point.x(), target_point.y(),
2129       base::Bind(&DetachToDockedWindowNextStep,
2130                  test,
2131                  gfx::Point(target_point.x(), 1 + target_point.y()),
2132                  iteration - 1)));
2133 }
2134
2135 }  // namespace
2136
2137 // Drags from browser to separate window, docks that window and releases mouse.
2138 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
2139                        DISABLED_DetachToDockedWindowFromMaximizedWindow) {
2140   // Maximize the initial browser window.
2141   browser()->window()->Maximize();
2142   ASSERT_TRUE(browser()->window()->IsMaximized());
2143
2144   // Add another tab.
2145   AddTabAndResetBrowser(browser());
2146   TabStrip* tab_strip = GetTabStripForBrowser(browser());
2147
2148   // Move to the first tab and drag it enough so that it detaches.
2149   gfx::Point tab_0_center(
2150       GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
2151   ASSERT_TRUE(PressInput(tab_0_center));
2152
2153   // The following matches kMovesBeforeAdjust in snap_sizer.cc
2154   const int kNumIterations = 25 * 5 + 10;
2155   ASSERT_TRUE(DragInputToNotifyWhenDone(
2156       tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
2157       base::Bind(&DetachToDockedWindowNextStep, this,
2158                  gfx::Point(0, tab_0_center.y() + GetDetachY(tab_strip)),
2159                  kNumIterations)));
2160   // Continue dragging enough times to go through snapping sequence and dock
2161   // the window.
2162   QuitWhenNotDragging();
2163   // Should no longer be dragging.
2164   ASSERT_FALSE(tab_strip->IsDragSessionActive());
2165   ASSERT_FALSE(TabDragController::IsActive());
2166
2167   // There should now be another browser.
2168   ASSERT_EQ(2u, native_browser_list->size());
2169   Browser* new_browser = native_browser_list->get(1);
2170   ASSERT_TRUE(new_browser->window()->IsActive());
2171   TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
2172   ASSERT_FALSE(tab_strip2->IsDragSessionActive());
2173
2174   EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
2175   EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
2176
2177   // The bounds of the initial window should not have changed.
2178   EXPECT_TRUE(browser()->window()->IsMaximized());
2179
2180   EXPECT_FALSE(GetIsDragged(browser()));
2181   EXPECT_FALSE(GetIsDragged(new_browser));
2182   // After this both windows should still be manageable.
2183   EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
2184   EXPECT_TRUE(IsWindowPositionManaged(
2185       new_browser->window()->GetNativeWindow()));
2186
2187   ash::wm::WindowState* window_state =
2188       ash::wm::GetWindowState(new_browser->window()->GetNativeWindow());
2189   // The new window should not be maximized because it gets docked or snapped.
2190   EXPECT_FALSE(new_browser->window()->IsMaximized());
2191   // The new window should be docked and not snapped.
2192   EXPECT_TRUE(window_state->IsDocked());
2193   EXPECT_FALSE(window_state->IsSnapped());
2194 }
2195
2196 #endif  // OS_CHROMEOS
2197
2198 #endif
2199
2200 #if defined(USE_ASH) && defined(OS_CHROMEOS)  // TODO(win_ash,linux_ash)
2201 INSTANTIATE_TEST_CASE_P(TabDragging,
2202                         DetachToBrowserInSeparateDisplayTabDragControllerTest,
2203                         ::testing::Values("mouse", "touch"));
2204 INSTANTIATE_TEST_CASE_P(TabDragging,
2205                         DifferentDeviceScaleFactorDisplayTabDragControllerTest,
2206                         ::testing::Values("mouse"));
2207 INSTANTIATE_TEST_CASE_P(TabDragging,
2208                         DetachToBrowserTabDragControllerTest,
2209                         ::testing::Values("mouse", "touch"));
2210 INSTANTIATE_TEST_CASE_P(TabDragging,
2211                         DetachToBrowserTabDragControllerTestTouch,
2212                         ::testing::Values("touch"));
2213 #elif defined(USE_ASH)
2214 INSTANTIATE_TEST_CASE_P(TabDragging,
2215                         DetachToBrowserTabDragControllerTest,
2216                         ::testing::Values("mouse"));
2217 #endif