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