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