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