tab_drag_controller_interactive_uitest.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
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/property_util.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/ui/browser.h"
14#include "chrome/browser/ui/browser_iterator.h"
15#include "chrome/browser/ui/browser_list.h"
16#include "chrome/browser/ui/host_desktop.h"
17#include "chrome/browser/ui/tabs/tab_strip_model.h"
18#include "chrome/browser/ui/views/frame/browser_view.h"
19#include "chrome/browser/ui/views/tabs/tab.h"
20#include "chrome/browser/ui/views/tabs/tab_drag_controller.h"
21#include "chrome/browser/ui/views/tabs/tab_strip.h"
22#include "chrome/common/chrome_notification_types.h"
23#include "chrome/common/chrome_switches.h"
24#include "chrome/test/base/in_process_browser_test.h"
25#include "chrome/test/base/interactive_test_utils.h"
26#include "chrome/test/base/ui_controls.h"
27#include "chrome/test/base/ui_test_utils.h"
28#include "content/public/browser/notification_details.h"
29#include "content/public/browser/notification_observer.h"
30#include "content/public/browser/notification_service.h"
31#include "content/public/browser/notification_source.h"
32#include "content/public/browser/web_contents.h"
33#include "ui/gfx/screen.h"
34#include "ui/views/view.h"
35#include "ui/views/widget/widget.h"
36
37#if defined(USE_ASH)
38#include "ash/display/display_controller.h"
39#include "ash/display/display_manager.h"
40#include "ash/shell.h"
41#include "ash/test/cursor_manager_test_api.h"
42#include "ash/wm/coordinate_conversion.h"
43#include "ash/wm/window_util.h"
44#include "ui/aura/client/screen_position_client.h"
45#include "ui/aura/root_window.h"
46#include "ui/aura/test/event_generator.h"
47#endif
48
49using content::WebContents;
50
51namespace test {
52
53namespace {
54
55const char kTabDragControllerInteractiveUITestUserDataKey[] =
56    "TabDragControllerInteractiveUITestUserData";
57
58class TabDragControllerInteractiveUITestUserData
59    : public base::SupportsUserData::Data {
60 public:
61  explicit TabDragControllerInteractiveUITestUserData(int id) : id_(id) {}
62  virtual ~TabDragControllerInteractiveUITestUserData() {}
63  int id() { return id_; }
64
65 private:
66  int id_;
67};
68
69}  // namespace
70
71class QuitDraggingObserver : public content::NotificationObserver {
72 public:
73  QuitDraggingObserver() {
74    registrar_.Add(this, chrome::NOTIFICATION_TAB_DRAG_LOOP_DONE,
75                   content::NotificationService::AllSources());
76  }
77
78  virtual void Observe(int type,
79                       const content::NotificationSource& source,
80                       const content::NotificationDetails& details) OVERRIDE {
81    DCHECK_EQ(chrome::NOTIFICATION_TAB_DRAG_LOOP_DONE, type);
82    base::MessageLoopForUI::current()->Quit();
83    delete this;
84  }
85
86 private:
87  virtual ~QuitDraggingObserver() {}
88
89  content::NotificationRegistrar registrar_;
90
91  DISALLOW_COPY_AND_ASSIGN(QuitDraggingObserver);
92};
93
94gfx::Point GetCenterInScreenCoordinates(const views::View* view) {
95  gfx::Point center(view->width() / 2, view->height() / 2);
96  views::View::ConvertPointToScreen(view, &center);
97  return center;
98}
99
100void SetID(WebContents* web_contents, int id) {
101  web_contents->SetUserData(&kTabDragControllerInteractiveUITestUserDataKey,
102                            new TabDragControllerInteractiveUITestUserData(id));
103}
104
105void ResetIDs(TabStripModel* model, int start) {
106  for (int i = 0; i < model->count(); ++i)
107    SetID(model->GetWebContentsAt(i), start + i);
108}
109
110std::string IDString(TabStripModel* model) {
111  std::string result;
112  for (int i = 0; i < model->count(); ++i) {
113    if (i != 0)
114      result += " ";
115    WebContents* contents = model->GetWebContentsAt(i);
116    TabDragControllerInteractiveUITestUserData* user_data =
117        static_cast<TabDragControllerInteractiveUITestUserData*>(
118            contents->GetUserData(
119                &kTabDragControllerInteractiveUITestUserDataKey));
120    if (user_data)
121      result += base::IntToString(user_data->id());
122    else
123      result += "?";
124  }
125  return result;
126}
127
128// Creates a listener that quits the message loop when no longer dragging.
129void QuitWhenNotDraggingImpl() {
130  new QuitDraggingObserver();  // QuitDraggingObserver deletes itself.
131}
132
133TabStrip* GetTabStripForBrowser(Browser* browser) {
134  BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
135  return static_cast<TabStrip*>(browser_view->tabstrip());
136}
137
138}  // namespace test
139
140using test::GetCenterInScreenCoordinates;
141using test::SetID;
142using test::ResetIDs;
143using test::IDString;
144using test::GetTabStripForBrowser;
145
146TabDragControllerTest::TabDragControllerTest()
147    : native_browser_list(BrowserList::GetInstance(
148                              chrome::HOST_DESKTOP_TYPE_NATIVE)) {
149}
150
151TabDragControllerTest::~TabDragControllerTest() {
152}
153
154void TabDragControllerTest::StopAnimating(TabStrip* tab_strip) {
155  tab_strip->StopAnimating(true);
156}
157
158void TabDragControllerTest::AddTabAndResetBrowser(Browser* browser) {
159  AddBlankTabAndShow(browser);
160  StopAnimating(GetTabStripForBrowser(browser));
161  ResetIDs(browser->tab_strip_model(), 0);
162}
163
164Browser* TabDragControllerTest::CreateAnotherWindowBrowserAndRelayout() {
165  // Create another browser.
166  Browser* browser2 = CreateBrowser(browser()->profile());
167  ResetIDs(browser2->tab_strip_model(), 100);
168
169  // Resize the two windows so they're right next to each other.
170  gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
171      browser()->window()->GetNativeWindow()).work_area();
172  gfx::Size half_size =
173      gfx::Size(work_area.width() / 3 - 10, work_area.height() / 2 - 10);
174  browser()->window()->SetBounds(gfx::Rect(work_area.origin(), half_size));
175  browser2->window()->SetBounds(gfx::Rect(
176      work_area.x() + half_size.width(), work_area.y(),
177      half_size.width(), half_size.height()));
178  return browser2;
179}
180
181namespace {
182
183enum InputSource {
184  INPUT_SOURCE_MOUSE = 0,
185  INPUT_SOURCE_TOUCH = 1
186};
187
188int GetDetachY(TabStrip* tab_strip) {
189  return std::max(TabDragController::kTouchVerticalDetachMagnetism,
190                  TabDragController::kVerticalDetachMagnetism) +
191      tab_strip->height() + 1;
192}
193
194bool GetTrackedByWorkspace(Browser* browser) {
195#if !defined(USE_ASH) || defined(OS_WIN)  // TODO(win_ash)
196  return true;
197#else
198  return ash::GetTrackedByWorkspace(browser->window()->GetNativeWindow());
199#endif
200}
201
202}  // namespace
203
204#if defined(USE_ASH) && !defined(OS_WIN)  // TODO(win_ash)
205class ScreenEventGeneratorDelegate : public aura::test::EventGeneratorDelegate {
206 public:
207  explicit ScreenEventGeneratorDelegate(aura::RootWindow* root_window)
208      : root_window_(root_window) {}
209  virtual ~ScreenEventGeneratorDelegate() {}
210
211  // EventGeneratorDelegate overrides:
212  virtual aura::RootWindow* GetRootWindowAt(
213      const gfx::Point& point) const OVERRIDE {
214    return root_window_;
215  }
216
217  virtual aura::client::ScreenPositionClient* GetScreenPositionClient(
218      const aura::Window* window) const OVERRIDE {
219    return aura::client::GetScreenPositionClient(root_window_);
220  }
221
222 private:
223  aura::RootWindow* root_window_;
224
225  DISALLOW_COPY_AND_ASSIGN(ScreenEventGeneratorDelegate);
226};
227
228#endif
229
230class DetachToBrowserTabDragControllerTest
231    : public TabDragControllerTest,
232      public ::testing::WithParamInterface<const char*> {
233 public:
234  DetachToBrowserTabDragControllerTest() {}
235
236  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
237    command_line->AppendSwitch(switches::kTabBrowserDragging);
238  }
239
240  virtual void SetUpOnMainThread() OVERRIDE {
241#if defined(USE_ASH) && !defined(OS_WIN)  // TODO(win_ash)
242    event_generator_.reset(new aura::test::EventGenerator(
243                               ash::Shell::GetPrimaryRootWindow()));
244#endif
245  }
246
247  InputSource input_source() const {
248    return !strcmp(GetParam(), "mouse") ?
249        INPUT_SOURCE_MOUSE : INPUT_SOURCE_TOUCH;
250  }
251
252  // Set root window from a point in screen coordinates
253  void SetEventGeneratorRootWindow(const gfx::Point& point) {
254    if (input_source() == INPUT_SOURCE_MOUSE)
255      return;
256#if defined(USE_ASH) && !defined(OS_WIN)  // TODO(win_ash)
257    event_generator_.reset(new aura::test::EventGenerator(
258        new ScreenEventGeneratorDelegate(ash::wm::GetRootWindowAt(point))));
259#endif
260  }
261
262  // The following methods update one of the mouse or touch input depending upon
263  // the InputSource.
264  bool PressInput(const gfx::Point& location) {
265    if (input_source() == INPUT_SOURCE_MOUSE) {
266      return ui_test_utils::SendMouseMoveSync(location) &&
267          ui_test_utils::SendMouseEventsSync(
268              ui_controls::LEFT, ui_controls::DOWN);
269    }
270#if defined(USE_ASH)  && !defined(OS_WIN)  // TODO(win_ash)
271    event_generator_->set_current_location(location);
272    event_generator_->PressTouch();
273#else
274    NOTREACHED();
275#endif
276    return true;
277  }
278
279  bool DragInputTo(const gfx::Point& location) {
280    if (input_source() == INPUT_SOURCE_MOUSE)
281      return ui_test_utils::SendMouseMoveSync(location);
282#if defined(USE_ASH) && !defined(OS_WIN)  // TODO(win_ash)
283    event_generator_->MoveTouch(location);
284#else
285    NOTREACHED();
286#endif
287    return true;
288  }
289
290  bool DragInputToAsync(const gfx::Point& location) {
291    if (input_source() == INPUT_SOURCE_MOUSE)
292      return ui_controls::SendMouseMove(location.x(), location.y());
293#if defined(USE_ASH) && !defined(OS_WIN)  // TODO(win_ash)
294    event_generator_->MoveTouch(location);
295#else
296    NOTREACHED();
297#endif
298    return true;
299  }
300
301  bool DragInputToNotifyWhenDone(int x,
302                                 int y,
303                                 const base::Closure& task) {
304    if (input_source() == INPUT_SOURCE_MOUSE)
305      return ui_controls::SendMouseMoveNotifyWhenDone(x, y, task);
306#if defined(USE_ASH) && !defined(OS_WIN)  // TODO(win_ash)
307    base::MessageLoop::current()->PostTask(FROM_HERE, task);
308    event_generator_->MoveTouch(gfx::Point(x, y));
309#else
310    NOTREACHED();
311#endif
312    return true;
313  }
314
315  bool ReleaseInput() {
316    if (input_source() == INPUT_SOURCE_MOUSE) {
317      return ui_test_utils::SendMouseEventsSync(
318              ui_controls::LEFT, ui_controls::UP);
319    }
320#if defined(USE_ASH) && !defined(OS_WIN)  // TODO(win_ash)
321    event_generator_->ReleaseTouch();
322#else
323    NOTREACHED();
324#endif
325    return true;
326  }
327
328  bool ReleaseMouseAsync() {
329    return input_source() == INPUT_SOURCE_MOUSE &&
330        ui_controls::SendMouseEvents(ui_controls::LEFT, ui_controls::UP);
331  }
332
333  void QuitWhenNotDragging() {
334    if (input_source() == INPUT_SOURCE_MOUSE) {
335      // Schedule observer to quit message loop when done dragging. This has to
336      // be async so the message loop can run.
337      test::QuitWhenNotDraggingImpl();
338      base::MessageLoop::current()->Run();
339    } else {
340      // Touch events are sync, so we know we're not in a drag session. But some
341      // tests rely on the browser fully closing, which is async. So, run all
342      // pending tasks.
343      base::RunLoop run_loop;
344      run_loop.RunUntilIdle();
345    }
346  }
347
348  void AddBlankTabAndShow(Browser* browser) {
349    InProcessBrowserTest::AddBlankTabAndShow(browser);
350  }
351
352  Browser* browser() const { return InProcessBrowserTest::browser(); }
353
354 private:
355#if defined(USE_ASH) && !defined(OS_WIN)  // TODO(win_ash)
356  scoped_ptr<aura::test::EventGenerator> event_generator_;
357#endif
358
359  DISALLOW_COPY_AND_ASSIGN(DetachToBrowserTabDragControllerTest);
360};
361
362// Creates a browser with two tabs, drags the second to the first.
363// TODO(sky): this won't work with touch as it requires a long press.
364IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
365                       DISABLED_DragInSameWindow) {
366  AddTabAndResetBrowser(browser());
367
368  TabStrip* tab_strip = GetTabStripForBrowser(browser());
369  TabStripModel* model = browser()->tab_strip_model();
370
371  gfx::Point tab_1_center(GetCenterInScreenCoordinates(tab_strip->tab_at(1)));
372  ASSERT_TRUE(PressInput(tab_1_center));
373  gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
374  ASSERT_TRUE(DragInputTo(tab_0_center));
375  ASSERT_TRUE(ReleaseInput());
376  EXPECT_EQ("1 0", IDString(model));
377  EXPECT_FALSE(TabDragController::IsActive());
378  EXPECT_FALSE(tab_strip->IsDragSessionActive());
379}
380
381namespace {
382
383// Invoked from the nested message loop.
384void DragToSeparateWindowStep2(DetachToBrowserTabDragControllerTest* test,
385                               TabStrip* not_attached_tab_strip,
386                               TabStrip* target_tab_strip) {
387  ASSERT_FALSE(not_attached_tab_strip->IsDragSessionActive());
388  ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
389  ASSERT_TRUE(TabDragController::IsActive());
390
391  // Drag to target_tab_strip. This should stop the nested loop from dragging
392  // the window.
393  gfx::Point target_point(target_tab_strip->width() -1,
394                          target_tab_strip->height() / 2);
395  views::View::ConvertPointToScreen(target_tab_strip, &target_point);
396  ASSERT_TRUE(test->DragInputToAsync(target_point));
397}
398
399}  // namespace
400
401// Creates two browsers, drags from first into second.
402IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
403                       DragToSeparateWindow) {
404  TabStrip* tab_strip = GetTabStripForBrowser(browser());
405
406  // Add another tab to browser().
407  AddTabAndResetBrowser(browser());
408
409  // Create another browser.
410  Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
411  TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
412
413  // Move to the first tab and drag it enough so that it detaches, but not
414  // enough that it attaches to browser2.
415  gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
416  ASSERT_TRUE(PressInput(tab_0_center));
417  ASSERT_TRUE(DragInputToNotifyWhenDone(
418                  tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
419                  base::Bind(&DragToSeparateWindowStep2,
420                             this, tab_strip, tab_strip2)));
421  QuitWhenNotDragging();
422
423  // Should now be attached to tab_strip2.
424  ASSERT_TRUE(tab_strip2->IsDragSessionActive());
425  ASSERT_FALSE(tab_strip->IsDragSessionActive());
426  ASSERT_TRUE(TabDragController::IsActive());
427  EXPECT_TRUE(GetTrackedByWorkspace(browser()));
428
429  // Release the mouse, stopping the drag session.
430  ASSERT_TRUE(ReleaseInput());
431  ASSERT_FALSE(tab_strip2->IsDragSessionActive());
432  ASSERT_FALSE(tab_strip->IsDragSessionActive());
433  ASSERT_FALSE(TabDragController::IsActive());
434  EXPECT_EQ("100 0", IDString(browser2->tab_strip_model()));
435  EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
436  EXPECT_TRUE(GetTrackedByWorkspace(browser2));
437
438  // Both windows should not be maximized
439  EXPECT_FALSE(browser()->window()->IsMaximized());
440  EXPECT_FALSE(browser2->window()->IsMaximized());
441}
442
443namespace {
444
445void DetachToOwnWindowStep2(DetachToBrowserTabDragControllerTest* test) {
446  if (test->input_source() == INPUT_SOURCE_TOUCH)
447    ASSERT_TRUE(test->ReleaseInput());
448}
449
450#if defined(USE_ASH) && !defined(OS_WIN)  // TODO(win_ash)
451bool IsWindowPositionManaged(aura::Window* window) {
452  return ash::wm::IsWindowPositionManaged(window);
453}
454bool HasUserChangedWindowPositionOrSize(aura::Window* window) {
455  return ash::wm::HasUserChangedWindowPositionOrSize(window);
456}
457#else
458bool IsWindowPositionManaged(gfx::NativeWindow window) {
459  return true;
460}
461bool HasUserChangedWindowPositionOrSize(gfx::NativeWindow window) {
462  return false;
463}
464#endif
465
466}  // namespace
467
468// Drags from browser to separate window and releases mouse.
469IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
470                       DetachToOwnWindow) {
471  const gfx::Rect initial_bounds(browser()->window()->GetBounds());
472  // Add another tab.
473  AddTabAndResetBrowser(browser());
474  TabStrip* tab_strip = GetTabStripForBrowser(browser());
475
476  // Move to the first tab and drag it enough so that it detaches.
477  gfx::Point tab_0_center(
478      GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
479  ASSERT_TRUE(PressInput(tab_0_center));
480  ASSERT_TRUE(DragInputToNotifyWhenDone(
481                  tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
482                  base::Bind(&DetachToOwnWindowStep2, this)));
483  if (input_source() == INPUT_SOURCE_MOUSE) {
484    ASSERT_TRUE(ReleaseMouseAsync());
485    QuitWhenNotDragging();
486  }
487
488  // Should no longer be dragging.
489  ASSERT_FALSE(tab_strip->IsDragSessionActive());
490  ASSERT_FALSE(TabDragController::IsActive());
491
492  // There should now be another browser.
493  ASSERT_EQ(2u, native_browser_list->size());
494  Browser* new_browser = native_browser_list->get(1);
495  ASSERT_TRUE(new_browser->window()->IsActive());
496  TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
497  ASSERT_FALSE(tab_strip2->IsDragSessionActive());
498
499  EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
500  EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
501
502  // The bounds of the initial window should not have changed.
503  EXPECT_EQ(initial_bounds.ToString(),
504            browser()->window()->GetBounds().ToString());
505
506  EXPECT_TRUE(GetTrackedByWorkspace(browser()));
507  EXPECT_TRUE(GetTrackedByWorkspace(new_browser));
508  // After this both windows should still be managable.
509  EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
510  EXPECT_TRUE(IsWindowPositionManaged(
511      new_browser->window()->GetNativeWindow()));
512
513  // Both windows should not be maximized
514  EXPECT_FALSE(browser()->window()->IsMaximized());
515  EXPECT_FALSE(new_browser->window()->IsMaximized());
516}
517
518// Deletes a tab being dragged before the user moved enough to start a drag.
519IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
520                       DeleteBeforeStartedDragging) {
521  // Add another tab.
522  AddTabAndResetBrowser(browser());
523  TabStrip* tab_strip = GetTabStripForBrowser(browser());
524
525  // Click on the first tab, but don't move it.
526  gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
527  ASSERT_TRUE(PressInput(tab_0_center));
528
529  // Should be dragging.
530  ASSERT_TRUE(tab_strip->IsDragSessionActive());
531  ASSERT_TRUE(TabDragController::IsActive());
532
533  // Delete the tab being dragged.
534  delete browser()->tab_strip_model()->GetWebContentsAt(0);
535
536  // Should have canceled dragging.
537  ASSERT_FALSE(tab_strip->IsDragSessionActive());
538  ASSERT_FALSE(TabDragController::IsActive());
539
540  EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
541  EXPECT_TRUE(GetTrackedByWorkspace(browser()));
542}
543
544// Deletes a tab being dragged while still attached.
545IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
546                       DeleteTabWhileAttached) {
547  // Add another tab.
548  AddTabAndResetBrowser(browser());
549  TabStrip* tab_strip = GetTabStripForBrowser(browser());
550
551  // Click on the first tab and move it enough so that it starts dragging but is
552  // still attached.
553  gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
554  ASSERT_TRUE(PressInput(tab_0_center));
555  ASSERT_TRUE(DragInputTo(
556                  gfx::Point(tab_0_center.x() + 20, tab_0_center.y())));
557
558  // Should be dragging.
559  ASSERT_TRUE(tab_strip->IsDragSessionActive());
560  ASSERT_TRUE(TabDragController::IsActive());
561
562  // Delete the tab being dragged.
563  delete browser()->tab_strip_model()->GetWebContentsAt(0);
564
565  // Should have canceled dragging.
566  ASSERT_FALSE(tab_strip->IsDragSessionActive());
567  ASSERT_FALSE(TabDragController::IsActive());
568
569  EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
570
571  EXPECT_TRUE(GetTrackedByWorkspace(browser()));
572}
573
574namespace {
575
576void DeleteWhileDetachedStep2(WebContents* tab) {
577  delete tab;
578}
579
580}  // namespace
581
582// Deletes a tab being dragged after dragging a tab so that a new window is
583// created.
584IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
585                       DeleteTabWhileDetached) {
586  // Add another tab.
587  AddTabAndResetBrowser(browser());
588  TabStrip* tab_strip = GetTabStripForBrowser(browser());
589
590  // Move to the first tab and drag it enough so that it detaches.
591  gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
592  WebContents* to_delete =
593      browser()->tab_strip_model()->GetWebContentsAt(0);
594  ASSERT_TRUE(PressInput(tab_0_center));
595  ASSERT_TRUE(DragInputToNotifyWhenDone(
596      tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
597      base::Bind(&DeleteWhileDetachedStep2, to_delete)));
598  QuitWhenNotDragging();
599
600  // Should not be dragging.
601  ASSERT_FALSE(tab_strip->IsDragSessionActive());
602  ASSERT_FALSE(TabDragController::IsActive());
603
604  EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
605
606  EXPECT_TRUE(GetTrackedByWorkspace(browser()));
607}
608
609namespace {
610
611void DeleteSourceDetachedStep2(WebContents* tab,
612                               const BrowserList* browser_list) {
613  ASSERT_EQ(2u, browser_list->size());
614  Browser* new_browser = browser_list->get(1);
615  // This ends up closing the source window.
616  delete tab;
617  // Cancel the drag.
618  ui_controls::SendKeyPress(new_browser->window()->GetNativeWindow(),
619                            ui::VKEY_ESCAPE, false, false, false, false);
620}
621
622}  // namespace
623
624// Detaches a tab and while detached deletes a tab from the source so that the
625// source window closes then presses escape to cancel the drag.
626IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
627                       DeleteSourceDetached) {
628  // Add another tab.
629  AddTabAndResetBrowser(browser());
630  TabStrip* tab_strip = GetTabStripForBrowser(browser());
631
632  // Move to the first tab and drag it enough so that it detaches.
633  gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
634  WebContents* to_delete = browser()->tab_strip_model()->GetWebContentsAt(1);
635  ASSERT_TRUE(PressInput(tab_0_center));
636  ASSERT_TRUE(DragInputToNotifyWhenDone(
637      tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
638      base::Bind(&DeleteSourceDetachedStep2, to_delete, native_browser_list)));
639  QuitWhenNotDragging();
640
641  // Should not be dragging.
642  ASSERT_EQ(1u, native_browser_list->size());
643  Browser* new_browser = native_browser_list->get(0);
644  ASSERT_FALSE(GetTabStripForBrowser(new_browser)->IsDragSessionActive());
645  ASSERT_FALSE(TabDragController::IsActive());
646
647  EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
648
649  EXPECT_TRUE(GetTrackedByWorkspace(new_browser));
650
651  // Remaining browser window should not be maximized
652  EXPECT_FALSE(new_browser->window()->IsMaximized());
653}
654
655namespace {
656
657void PressEscapeWhileDetachedStep2(const BrowserList* browser_list) {
658  ASSERT_EQ(2u, browser_list->size());
659  Browser* new_browser = browser_list->get(1);
660  ui_controls::SendKeyPress(
661      new_browser->window()->GetNativeWindow(), ui::VKEY_ESCAPE, false, false,
662      false, false);
663}
664
665}  // namespace
666
667// This is disabled until NativeViewHost::Detach really detaches.
668// Detaches a tab and while detached presses escape to revert the drag.
669IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
670                       PressEscapeWhileDetached) {
671  // Add another tab.
672  AddTabAndResetBrowser(browser());
673  TabStrip* tab_strip = GetTabStripForBrowser(browser());
674
675  // Move to the first tab and drag it enough so that it detaches.
676  gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
677  ASSERT_TRUE(PressInput(tab_0_center));
678  ASSERT_TRUE(DragInputToNotifyWhenDone(
679      tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
680      base::Bind(&PressEscapeWhileDetachedStep2, native_browser_list)));
681  QuitWhenNotDragging();
682
683  // Should not be dragging.
684  ASSERT_FALSE(tab_strip->IsDragSessionActive());
685  ASSERT_FALSE(TabDragController::IsActive());
686
687  // And there should only be one window.
688  EXPECT_EQ(1u, native_browser_list->size());
689
690  EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
691
692  // Remaining browser window should not be maximized
693  EXPECT_FALSE(browser()->window()->IsMaximized());
694}
695
696namespace {
697
698void DragAllStep2(DetachToBrowserTabDragControllerTest* test,
699                  const BrowserList* browser_list) {
700  // Should only be one window.
701  ASSERT_EQ(1u, browser_list->size());
702  if (test->input_source() == INPUT_SOURCE_TOUCH) {
703    ASSERT_TRUE(test->ReleaseInput());
704  } else {
705    ASSERT_TRUE(test->ReleaseMouseAsync());
706  }
707}
708
709}  // namespace
710
711// Selects multiple tabs and starts dragging the window.
712IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, DragAll) {
713  // Add another tab.
714  AddTabAndResetBrowser(browser());
715  TabStrip* tab_strip = GetTabStripForBrowser(browser());
716  browser()->tab_strip_model()->AddTabAtToSelection(0);
717  browser()->tab_strip_model()->AddTabAtToSelection(1);
718
719  // Move to the first tab and drag it enough so that it would normally
720  // detach.
721  gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
722  ASSERT_TRUE(PressInput(tab_0_center));
723  ASSERT_TRUE(DragInputToNotifyWhenDone(
724      tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
725      base::Bind(&DragAllStep2, this, native_browser_list)));
726  QuitWhenNotDragging();
727
728  // Should not be dragging.
729  ASSERT_FALSE(tab_strip->IsDragSessionActive());
730  ASSERT_FALSE(TabDragController::IsActive());
731
732  // And there should only be one window.
733  EXPECT_EQ(1u, native_browser_list->size());
734
735  EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
736
737  EXPECT_TRUE(GetTrackedByWorkspace(browser()));
738
739  // Remaining browser window should not be maximized
740  EXPECT_FALSE(browser()->window()->IsMaximized());
741}
742
743namespace {
744
745// Invoked from the nested message loop.
746void DragAllToSeparateWindowStep2(DetachToBrowserTabDragControllerTest* test,
747                                  TabStrip* attached_tab_strip,
748                                  TabStrip* target_tab_strip,
749                                  const BrowserList* browser_list) {
750  ASSERT_TRUE(attached_tab_strip->IsDragSessionActive());
751  ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
752  ASSERT_TRUE(TabDragController::IsActive());
753  ASSERT_EQ(2u, browser_list->size());
754
755  // Drag to target_tab_strip. This should stop the nested loop from dragging
756  // the window.
757  gfx::Point target_point(target_tab_strip->width() - 1,
758                          target_tab_strip->height() / 2);
759  views::View::ConvertPointToScreen(target_tab_strip, &target_point);
760  ASSERT_TRUE(test->DragInputToAsync(target_point));
761}
762
763}  // namespace
764
765// Creates two browsers, selects all tabs in first and drags into second.
766IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
767                       DragAllToSeparateWindow) {
768  TabStrip* tab_strip = GetTabStripForBrowser(browser());
769
770  // Add another tab to browser().
771  AddTabAndResetBrowser(browser());
772
773  // Create another browser.
774  Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
775  TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
776
777  browser()->tab_strip_model()->AddTabAtToSelection(0);
778  browser()->tab_strip_model()->AddTabAtToSelection(1);
779
780  // Move to the first tab and drag it enough so that it detaches, but not
781  // enough that it attaches to browser2.
782  gfx::Point tab_0_center(
783      GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
784  ASSERT_TRUE(PressInput(tab_0_center));
785  ASSERT_TRUE(DragInputToNotifyWhenDone(
786      tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
787      base::Bind(&DragAllToSeparateWindowStep2, this, tab_strip, tab_strip2,
788                 native_browser_list)));
789  QuitWhenNotDragging();
790
791  // Should now be attached to tab_strip2.
792  ASSERT_TRUE(tab_strip2->IsDragSessionActive());
793  ASSERT_TRUE(TabDragController::IsActive());
794  ASSERT_EQ(1u, native_browser_list->size());
795
796  // Release the mouse, stopping the drag session.
797  ASSERT_TRUE(ReleaseInput());
798  ASSERT_FALSE(tab_strip2->IsDragSessionActive());
799  ASSERT_FALSE(TabDragController::IsActive());
800  EXPECT_EQ("100 0 1", IDString(browser2->tab_strip_model()));
801
802  EXPECT_TRUE(GetTrackedByWorkspace(browser2));
803
804  // Remaining browser window should not be maximized
805  EXPECT_FALSE(browser2->window()->IsMaximized());
806}
807
808namespace {
809
810// Invoked from the nested message loop.
811void DragAllToSeparateWindowAndCancelStep2(
812    DetachToBrowserTabDragControllerTest* test,
813    TabStrip* attached_tab_strip,
814    TabStrip* target_tab_strip,
815    const BrowserList* browser_list) {
816  ASSERT_TRUE(attached_tab_strip->IsDragSessionActive());
817  ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
818  ASSERT_TRUE(TabDragController::IsActive());
819  ASSERT_EQ(2u, browser_list->size());
820
821  // Drag to target_tab_strip. This should stop the nested loop from dragging
822  // the window.
823  gfx::Point target_point(target_tab_strip->width() - 1,
824                          target_tab_strip->height() / 2);
825  views::View::ConvertPointToScreen(target_tab_strip, &target_point);
826  ASSERT_TRUE(test->DragInputToAsync(target_point));
827}
828
829}  // namespace
830
831// Creates two browsers, selects all tabs in first, drags into second, then hits
832// escape.
833IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
834                       DragAllToSeparateWindowAndCancel) {
835  TabStrip* tab_strip = GetTabStripForBrowser(browser());
836
837  // Add another tab to browser().
838  AddTabAndResetBrowser(browser());
839
840  // Create another browser.
841  Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
842  TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
843
844  browser()->tab_strip_model()->AddTabAtToSelection(0);
845  browser()->tab_strip_model()->AddTabAtToSelection(1);
846
847  // Move to the first tab and drag it enough so that it detaches, but not
848  // enough that it attaches to browser2.
849  gfx::Point tab_0_center(
850      GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
851  ASSERT_TRUE(PressInput(tab_0_center));
852  ASSERT_TRUE(DragInputToNotifyWhenDone(
853                  tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
854                  base::Bind(&DragAllToSeparateWindowAndCancelStep2, this,
855                             tab_strip, tab_strip2, native_browser_list)));
856  QuitWhenNotDragging();
857
858  // Should now be attached to tab_strip2.
859  ASSERT_TRUE(tab_strip2->IsDragSessionActive());
860  ASSERT_TRUE(TabDragController::IsActive());
861  ASSERT_EQ(1u, native_browser_list->size());
862
863  // Cancel the drag.
864  ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
865      browser2, ui::VKEY_ESCAPE, false, false, false, false));
866
867  ASSERT_FALSE(tab_strip2->IsDragSessionActive());
868  ASSERT_FALSE(TabDragController::IsActive());
869  EXPECT_EQ("100 0 1", IDString(browser2->tab_strip_model()));
870
871  // browser() will have been destroyed, but browser2 should remain.
872  ASSERT_EQ(1u, native_browser_list->size());
873
874  EXPECT_TRUE(GetTrackedByWorkspace(browser2));
875
876  // Remaining browser window should not be maximized
877  EXPECT_FALSE(browser2->window()->IsMaximized());
878}
879
880// Creates two browsers, drags from first into the second in such a way that
881// no detaching should happen.
882IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
883                       DragDirectlyToSecondWindow) {
884  TabStrip* tab_strip = GetTabStripForBrowser(browser());
885
886  // Add another tab to browser().
887  AddTabAndResetBrowser(browser());
888
889  // Create another browser.
890  Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
891  TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
892
893  // Move the tabstrip down enough so that we can detach.
894  gfx::Rect bounds(browser2->window()->GetBounds());
895  bounds.Offset(0, 100);
896  browser2->window()->SetBounds(bounds);
897
898  // Move to the first tab and drag it enough so that it detaches, but not
899  // enough that it attaches to browser2.
900  gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
901  ASSERT_TRUE(PressInput(tab_0_center));
902
903  gfx::Point b2_location(5, 0);
904  views::View::ConvertPointToScreen(tab_strip2, &b2_location);
905  ASSERT_TRUE(DragInputTo(b2_location));
906
907  // Should now be attached to tab_strip2.
908  ASSERT_TRUE(tab_strip2->IsDragSessionActive());
909  ASSERT_FALSE(tab_strip->IsDragSessionActive());
910  ASSERT_TRUE(TabDragController::IsActive());
911
912  // Release the mouse, stopping the drag session.
913  ASSERT_TRUE(ReleaseInput());
914  ASSERT_FALSE(tab_strip2->IsDragSessionActive());
915  ASSERT_FALSE(tab_strip->IsDragSessionActive());
916  ASSERT_FALSE(TabDragController::IsActive());
917  EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
918  EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
919
920  EXPECT_TRUE(GetTrackedByWorkspace(browser()));
921  EXPECT_TRUE(GetTrackedByWorkspace(browser2));
922
923  // Both windows should not be maximized
924  EXPECT_FALSE(browser()->window()->IsMaximized());
925  EXPECT_FALSE(browser2->window()->IsMaximized());
926}
927
928// Creates two browsers, the first browser has a single tab and drags into the
929// second browser.
930IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
931                       DragSingleTabToSeparateWindow) {
932  TabStrip* tab_strip = GetTabStripForBrowser(browser());
933
934  ResetIDs(browser()->tab_strip_model(), 0);
935
936  // Create another browser.
937  Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
938  TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
939  const gfx::Rect initial_bounds(browser2->window()->GetBounds());
940
941  // Move to the first tab and drag it enough so that it detaches, but not
942  // enough that it attaches to browser2.
943  gfx::Point tab_0_center(
944      GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
945  ASSERT_TRUE(PressInput(tab_0_center));
946  ASSERT_TRUE(DragInputToNotifyWhenDone(
947      tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
948      base::Bind(&DragAllToSeparateWindowStep2, this, tab_strip, tab_strip2,
949                 native_browser_list)));
950  QuitWhenNotDragging();
951
952  // Should now be attached to tab_strip2.
953  ASSERT_TRUE(tab_strip2->IsDragSessionActive());
954  ASSERT_TRUE(TabDragController::IsActive());
955  ASSERT_EQ(1u, native_browser_list->size());
956
957  // Release the mouse, stopping the drag session.
958  ASSERT_TRUE(ReleaseInput());
959  ASSERT_FALSE(tab_strip2->IsDragSessionActive());
960  ASSERT_FALSE(TabDragController::IsActive());
961  EXPECT_EQ("100 0", IDString(browser2->tab_strip_model()));
962
963  EXPECT_TRUE(GetTrackedByWorkspace(browser2));
964
965  // Remaining browser window should not be maximized
966  EXPECT_FALSE(browser2->window()->IsMaximized());
967
968  // Make sure that the window is still managed and not user moved.
969  EXPECT_TRUE(IsWindowPositionManaged(browser2->window()->GetNativeWindow()));
970  EXPECT_FALSE(HasUserChangedWindowPositionOrSize(
971      browser2->window()->GetNativeWindow()));
972  // Also make sure that the drag to window position has not changed.
973  EXPECT_EQ(initial_bounds.ToString(),
974            browser2->window()->GetBounds().ToString());
975}
976
977namespace {
978
979// Invoked from the nested message loop.
980void CancelOnNewTabWhenDraggingStep2(
981    DetachToBrowserTabDragControllerTest* test,
982    const BrowserList* browser_list) {
983  ASSERT_TRUE(TabDragController::IsActive());
984  ASSERT_EQ(2u, browser_list->size());
985
986  // Add another tab. This should trigger exiting the nested loop.
987  test->AddBlankTabAndShow(browser_list->GetLastActive());
988}
989
990}  // namespace
991
992// Adds another tab, detaches into separate window, adds another tab and
993// verifies the run loop ends.
994IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
995                       CancelOnNewTabWhenDragging) {
996  TabStrip* tab_strip = GetTabStripForBrowser(browser());
997
998  // Add another tab to browser().
999  AddTabAndResetBrowser(browser());
1000
1001  // Move to the first tab and drag it enough so that it detaches.
1002  gfx::Point tab_0_center(
1003      GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1004  ASSERT_TRUE(PressInput(tab_0_center));
1005  ASSERT_TRUE(DragInputToNotifyWhenDone(
1006      tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1007      base::Bind(&CancelOnNewTabWhenDraggingStep2, this, native_browser_list)));
1008  QuitWhenNotDragging();
1009
1010  // Should be two windows and not dragging.
1011  ASSERT_FALSE(TabDragController::IsActive());
1012  ASSERT_EQ(2u, native_browser_list->size());
1013  for (chrome::BrowserIterator it; !it.done(); it.Next()) {
1014    EXPECT_TRUE(GetTrackedByWorkspace(*it));
1015    // Should not be maximized
1016    EXPECT_FALSE(it->window()->IsMaximized());
1017  }
1018}
1019
1020#if defined(USE_ASH) && !defined(OS_WIN)  // TODO(win_ash)
1021
1022namespace {
1023
1024void DragInMaximizedWindowStep2(DetachToBrowserTabDragControllerTest* test,
1025                                Browser* browser,
1026                                TabStrip* tab_strip,
1027                                const BrowserList* browser_list) {
1028  // There should be another browser.
1029  ASSERT_EQ(2u, browser_list->size());
1030  Browser* new_browser = browser_list->get(1);
1031  EXPECT_NE(browser, new_browser);
1032  ASSERT_TRUE(new_browser->window()->IsActive());
1033  TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
1034
1035  ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1036  ASSERT_FALSE(tab_strip->IsDragSessionActive());
1037
1038  // Both windows should be visible.
1039  EXPECT_TRUE(tab_strip->GetWidget()->IsVisible());
1040  EXPECT_TRUE(tab_strip2->GetWidget()->IsVisible());
1041
1042  // Stops dragging.
1043  ASSERT_TRUE(test->ReleaseInput());
1044}
1045
1046}  // namespace
1047
1048// Creates a browser with two tabs, maximizes it, drags the tab out.
1049IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
1050                       DragInMaximizedWindow) {
1051  AddTabAndResetBrowser(browser());
1052  browser()->window()->Maximize();
1053
1054  TabStrip* tab_strip = GetTabStripForBrowser(browser());
1055
1056  // Move to the first tab and drag it enough so that it detaches.
1057  gfx::Point tab_0_center(
1058      GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1059  ASSERT_TRUE(PressInput(tab_0_center));
1060  ASSERT_TRUE(DragInputToNotifyWhenDone(
1061      tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1062      base::Bind(&DragInMaximizedWindowStep2, this, browser(), tab_strip,
1063                 native_browser_list)));
1064  QuitWhenNotDragging();
1065
1066  ASSERT_FALSE(TabDragController::IsActive());
1067
1068  // Should be two browsers.
1069  ASSERT_EQ(2u, native_browser_list->size());
1070  Browser* new_browser = native_browser_list->get(1);
1071  ASSERT_TRUE(new_browser->window()->IsActive());
1072
1073  // Only the new browser should be visible.
1074  EXPECT_FALSE(browser()->window()->GetNativeWindow()->IsVisible());
1075  EXPECT_TRUE(new_browser->window()->GetNativeWindow()->IsVisible());
1076
1077  EXPECT_TRUE(GetTrackedByWorkspace(browser()));
1078  EXPECT_TRUE(GetTrackedByWorkspace(new_browser));
1079
1080  // Both windows should be maximized
1081  EXPECT_TRUE(browser()->window()->IsMaximized());
1082  EXPECT_TRUE(new_browser->window()->IsMaximized());
1083}
1084
1085// Subclass of DetachToBrowserInSeparateDisplayTabDragControllerTest that
1086// creates multiple displays.
1087class DetachToBrowserInSeparateDisplayTabDragControllerTest
1088    : public DetachToBrowserTabDragControllerTest {
1089 public:
1090  DetachToBrowserInSeparateDisplayTabDragControllerTest() {}
1091
1092  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
1093    DetachToBrowserTabDragControllerTest::SetUpCommandLine(command_line);
1094    // Make screens sufficiently wide to host 2 browsers side by side.
1095    command_line->AppendSwitchASCII("ash-host-window-bounds",
1096                                    "0+0-600x600,601+0-600x600");
1097  }
1098
1099 private:
1100  DISALLOW_COPY_AND_ASSIGN(
1101      DetachToBrowserInSeparateDisplayTabDragControllerTest);
1102};
1103
1104namespace {
1105
1106void DragSingleTabToSeparateWindowInSecondDisplayStep3(
1107    DetachToBrowserTabDragControllerTest* test) {
1108  ASSERT_TRUE(test->ReleaseInput());
1109}
1110
1111void DragSingleTabToSeparateWindowInSecondDisplayStep2(
1112    DetachToBrowserTabDragControllerTest* test,
1113    const gfx::Point& target_point) {
1114  ASSERT_TRUE(test->DragInputToNotifyWhenDone(
1115      target_point.x(), target_point.y(),
1116      base::Bind(&DragSingleTabToSeparateWindowInSecondDisplayStep3, test)));
1117}
1118
1119}  // namespace
1120
1121// Drags from browser to a second display and releases input.
1122IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1123                       DragSingleTabToSeparateWindowInSecondDisplay) {
1124  // Add another tab.
1125  AddTabAndResetBrowser(browser());
1126  TabStrip* tab_strip = GetTabStripForBrowser(browser());
1127
1128  // Move to the first tab and drag it enough so that it detaches.
1129  // Then drag it to the final destination on the second screen.
1130  gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1131  ASSERT_TRUE(PressInput(tab_0_center));
1132  ASSERT_TRUE(DragInputToNotifyWhenDone(
1133                  tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1134                  base::Bind(&DragSingleTabToSeparateWindowInSecondDisplayStep2,
1135                             this, gfx::Point(600 + tab_0_center.x(),
1136                                              tab_0_center.y()
1137                                              + GetDetachY(tab_strip)))));
1138  QuitWhenNotDragging();
1139
1140  // Should no longer be dragging.
1141  ASSERT_FALSE(tab_strip->IsDragSessionActive());
1142  ASSERT_FALSE(TabDragController::IsActive());
1143
1144  // There should now be another browser.
1145  ASSERT_EQ(2u, native_browser_list->size());
1146  Browser* new_browser = native_browser_list->get(1);
1147  ASSERT_TRUE(new_browser->window()->IsActive());
1148  TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
1149  ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1150
1151  // This other browser should be on the second screen (with mouse drag)
1152  // With the touch input the browser cannot be dragged from one screen
1153  // to another and the window stays on the first screen.
1154  if (input_source() == INPUT_SOURCE_MOUSE) {
1155    std::vector<aura::RootWindow*> roots(ash::Shell::GetAllRootWindows());
1156    ASSERT_EQ(2u, roots.size());
1157    aura::RootWindow* second_root = roots[1];
1158    EXPECT_EQ(second_root,
1159              new_browser->window()->GetNativeWindow()->GetRootWindow());
1160  }
1161
1162  EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
1163  EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1164
1165  // Both windows should not be maximized
1166  EXPECT_FALSE(browser()->window()->IsMaximized());
1167  EXPECT_FALSE(new_browser->window()->IsMaximized());
1168}
1169
1170namespace {
1171
1172// Invoked from the nested message loop.
1173void DragTabToWindowInSeparateDisplayStep2(
1174    DetachToBrowserTabDragControllerTest* test,
1175    TabStrip* not_attached_tab_strip,
1176    TabStrip* target_tab_strip) {
1177  ASSERT_FALSE(not_attached_tab_strip->IsDragSessionActive());
1178  ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
1179  ASSERT_TRUE(TabDragController::IsActive());
1180
1181  // Drag to target_tab_strip. This should stop the nested loop from dragging
1182  // the window.
1183  gfx::Point target_point(
1184      GetCenterInScreenCoordinates(target_tab_strip->tab_at(0)));
1185
1186  // Move it close to the beginning of the target tabstrip.
1187  target_point.set_x(
1188      target_point.x() - target_tab_strip->tab_at(0)->width() / 2 + 10);
1189  ASSERT_TRUE(test->DragInputToAsync(target_point));
1190}
1191
1192}  // namespace
1193
1194// Drags from browser to another browser on a second display and releases input.
1195IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1196                       DragTabToWindowInSeparateDisplay) {
1197  // Add another tab.
1198  AddTabAndResetBrowser(browser());
1199  TabStrip* tab_strip = GetTabStripForBrowser(browser());
1200
1201  // Create another browser.
1202  Browser* browser2 = CreateBrowser(browser()->profile());
1203  TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1204  ResetIDs(browser2->tab_strip_model(), 100);
1205
1206  // Move the second browser to the second display.
1207  std::vector<aura::RootWindow*> roots(ash::Shell::GetAllRootWindows());
1208  ASSERT_EQ(2u, roots.size());
1209  aura::RootWindow* second_root = roots[1];
1210  gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1211      second_root).work_area();
1212  browser2->window()->SetBounds(work_area);
1213  EXPECT_EQ(second_root,
1214            browser2->window()->GetNativeWindow()->GetRootWindow());
1215
1216  // Move to the first tab and drag it enough so that it detaches, but not
1217  // enough that it attaches to browser2.
1218  gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1219  ASSERT_TRUE(PressInput(tab_0_center));
1220  ASSERT_TRUE(DragInputToNotifyWhenDone(
1221                  tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1222                  base::Bind(&DragTabToWindowInSeparateDisplayStep2,
1223                             this, tab_strip, tab_strip2)));
1224  QuitWhenNotDragging();
1225
1226  // Should now be attached to tab_strip2.
1227  ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1228  ASSERT_FALSE(tab_strip->IsDragSessionActive());
1229  ASSERT_TRUE(TabDragController::IsActive());
1230
1231  // Release the mouse, stopping the drag session.
1232  ASSERT_TRUE(ReleaseInput());
1233  ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1234  ASSERT_FALSE(tab_strip->IsDragSessionActive());
1235  ASSERT_FALSE(TabDragController::IsActive());
1236  EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1237  EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1238
1239  // Both windows should not be maximized
1240  EXPECT_FALSE(browser()->window()->IsMaximized());
1241  EXPECT_FALSE(browser2->window()->IsMaximized());
1242}
1243
1244// Drags from browser to another browser on a second display and releases input.
1245IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1246                       DragTabToWindowOnSecondDisplay) {
1247  // Add another tab.
1248  AddTabAndResetBrowser(browser());
1249  TabStrip* tab_strip = GetTabStripForBrowser(browser());
1250
1251  // Create another browser.
1252  Browser* browser2 = CreateBrowser(browser()->profile());
1253  TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1254  ResetIDs(browser2->tab_strip_model(), 100);
1255
1256  // Move both browsers to the second display.
1257  std::vector<aura::RootWindow*> roots(ash::Shell::GetAllRootWindows());
1258  ASSERT_EQ(2u, roots.size());
1259  aura::RootWindow* second_root = roots[1];
1260  gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1261      second_root).work_area();
1262  browser()->window()->SetBounds(work_area);
1263
1264  // position both browser windows side by side on the second screen.
1265  gfx::Rect work_area2(work_area);
1266  work_area.set_width(work_area.width()/2);
1267  browser()->window()->SetBounds(work_area);
1268  work_area2.set_x(work_area2.x() + work_area2.width()/2);
1269  work_area2.set_width(work_area2.width()/2);
1270  browser2->window()->SetBounds(work_area2);
1271  EXPECT_EQ(second_root,
1272            browser()->window()->GetNativeWindow()->GetRootWindow());
1273  EXPECT_EQ(second_root,
1274            browser2->window()->GetNativeWindow()->GetRootWindow());
1275
1276  // Move to the first tab and drag it enough so that it detaches, but not
1277  // enough that it attaches to browser2.
1278  // SetEventGeneratorRootWindow sets correct (second) RootWindow
1279  gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1280  SetEventGeneratorRootWindow(tab_0_center);
1281  ASSERT_TRUE(PressInput(tab_0_center));
1282  ASSERT_TRUE(DragInputToNotifyWhenDone(
1283                  tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1284                  base::Bind(&DragTabToWindowInSeparateDisplayStep2,
1285                             this, tab_strip, tab_strip2)));
1286  QuitWhenNotDragging();
1287
1288  // Should now be attached to tab_strip2.
1289  ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1290  ASSERT_FALSE(tab_strip->IsDragSessionActive());
1291  ASSERT_TRUE(TabDragController::IsActive());
1292
1293  // Release the mouse, stopping the drag session.
1294  ASSERT_TRUE(ReleaseInput());
1295  ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1296  ASSERT_FALSE(tab_strip->IsDragSessionActive());
1297  ASSERT_FALSE(TabDragController::IsActive());
1298  EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1299  EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1300
1301  // Both windows should not be maximized
1302  EXPECT_FALSE(browser()->window()->IsMaximized());
1303  EXPECT_FALSE(browser2->window()->IsMaximized());
1304}
1305
1306// Drags from a maximized browser to another non-maximized browser on a second
1307// display and releases input.
1308IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
1309                       DragMaxTabToNonMaxWindowInSeparateDisplay) {
1310  // Add another tab.
1311  AddTabAndResetBrowser(browser());
1312  browser()->window()->Maximize();
1313  TabStrip* tab_strip = GetTabStripForBrowser(browser());
1314
1315  // Create another browser on the second display.
1316  std::vector<aura::RootWindow*> roots(ash::Shell::GetAllRootWindows());
1317  ASSERT_EQ(2u, roots.size());
1318  aura::RootWindow* first_root = roots[0];
1319  aura::RootWindow* second_root = roots[1];
1320  gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1321      second_root).work_area();
1322  work_area.Inset(20,20,20,60);
1323  Browser::CreateParams params(browser()->profile(),
1324                               chrome::HOST_DESKTOP_TYPE_NATIVE);
1325  params.initial_show_state = ui::SHOW_STATE_NORMAL;
1326  params.initial_bounds = work_area;
1327  Browser* browser2 = new Browser(params);
1328  AddBlankTabAndShow(browser2);
1329
1330  TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
1331  ResetIDs(browser2->tab_strip_model(), 100);
1332
1333  EXPECT_EQ(second_root,
1334            browser2->window()->GetNativeWindow()->GetRootWindow());
1335  EXPECT_EQ(first_root,
1336            browser()->window()->GetNativeWindow()->GetRootWindow());
1337  EXPECT_EQ(2, tab_strip->tab_count());
1338  EXPECT_EQ(1, tab_strip2->tab_count());
1339
1340  // Move to the first tab and drag it enough so that it detaches, but not
1341  // enough that it attaches to browser2.
1342  gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1343  ASSERT_TRUE(PressInput(tab_0_center));
1344  ASSERT_TRUE(DragInputToNotifyWhenDone(
1345                  tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1346                  base::Bind(&DragTabToWindowInSeparateDisplayStep2,
1347                             this, tab_strip, tab_strip2)));
1348  QuitWhenNotDragging();
1349
1350  // Should now be attached to tab_strip2.
1351  ASSERT_TRUE(tab_strip2->IsDragSessionActive());
1352  ASSERT_FALSE(tab_strip->IsDragSessionActive());
1353  ASSERT_TRUE(TabDragController::IsActive());
1354
1355  // Release the mouse, stopping the drag session.
1356  ASSERT_TRUE(ReleaseInput());
1357
1358  // tab should have moved
1359  EXPECT_EQ(1, tab_strip->tab_count());
1360  EXPECT_EQ(2, tab_strip2->tab_count());
1361
1362  ASSERT_FALSE(tab_strip2->IsDragSessionActive());
1363  ASSERT_FALSE(tab_strip->IsDragSessionActive());
1364  ASSERT_FALSE(TabDragController::IsActive());
1365  EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
1366  EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
1367
1368  // Source browser should still be maximized, target should not
1369  EXPECT_TRUE(browser()->window()->IsMaximized());
1370  EXPECT_FALSE(browser2->window()->IsMaximized());
1371}
1372
1373class DifferentDeviceScaleFactorDisplayTabDragControllerTest
1374    : public DetachToBrowserTabDragControllerTest {
1375 public:
1376  DifferentDeviceScaleFactorDisplayTabDragControllerTest() {}
1377
1378  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
1379    DetachToBrowserTabDragControllerTest::SetUpCommandLine(command_line);
1380    command_line->AppendSwitchASCII("ash-host-window-bounds",
1381                                    "400x400,800x800*2");
1382  }
1383
1384  float GetCursorDeviceScaleFactor() const {
1385    ash::test::CursorManagerTestApi cursor_test_api(
1386        ash::Shell::GetInstance()->cursor_manager());
1387    return cursor_test_api.GetDisplay().device_scale_factor();
1388  }
1389
1390 private:
1391  DISALLOW_COPY_AND_ASSIGN(
1392      DifferentDeviceScaleFactorDisplayTabDragControllerTest);
1393};
1394
1395namespace {
1396
1397// The points where a tab is dragged in CursorDeviceScaleFactorStep.
1398const struct DragPoint {
1399  int x;
1400  int y;
1401} kDragPoints[] = {
1402  {300, 200},
1403  {399, 200},
1404  {500, 200},
1405  {400, 200},
1406  {300, 200},
1407};
1408
1409// The expected device scale factors before the cursor is moved to the
1410// corresponding kDragPoints in CursorDeviceScaleFactorStep.
1411const float kDeviceScaleFactorExpectations[] = {
1412  1.0f,
1413  1.0f,
1414  2.0f,
1415  2.0f,
1416  1.0f,
1417};
1418
1419COMPILE_ASSERT(
1420    arraysize(kDragPoints) == arraysize(kDeviceScaleFactorExpectations),
1421    kDragPoints_and_kDeviceScaleFactorExpectations_must_have_same_size);
1422
1423// Drags tab to |kDragPoints[index]|, then calls the next step function.
1424void CursorDeviceScaleFactorStep(
1425    DifferentDeviceScaleFactorDisplayTabDragControllerTest* test,
1426    TabStrip* not_attached_tab_strip,
1427    size_t index) {
1428  ASSERT_FALSE(not_attached_tab_strip->IsDragSessionActive());
1429  ASSERT_TRUE(TabDragController::IsActive());
1430
1431  if (index < arraysize(kDragPoints)) {
1432    EXPECT_EQ(kDeviceScaleFactorExpectations[index],
1433              test->GetCursorDeviceScaleFactor());
1434    const DragPoint p = kDragPoints[index];
1435    ASSERT_TRUE(test->DragInputToNotifyWhenDone(
1436        p.x, p.y, base::Bind(&CursorDeviceScaleFactorStep,
1437                             test, not_attached_tab_strip, index + 1)));
1438  } else {
1439    // Finishes a serise of CursorDeviceScaleFactorStep calls and ends drag.
1440    EXPECT_EQ(1.0f, test->GetCursorDeviceScaleFactor());
1441    ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
1442        ui_controls::LEFT, ui_controls::UP));
1443  }
1444}
1445
1446}  // namespace
1447
1448// Verifies cursor's device scale factor is updated when a tab is moved across
1449// displays with different device scale factors (http://crbug.com/154183).
1450IN_PROC_BROWSER_TEST_P(DifferentDeviceScaleFactorDisplayTabDragControllerTest,
1451                       CursorDeviceScaleFactor) {
1452  // Add another tab.
1453  AddTabAndResetBrowser(browser());
1454  TabStrip* tab_strip = GetTabStripForBrowser(browser());
1455
1456  // Move the second browser to the second display.
1457  std::vector<aura::RootWindow*> roots(ash::Shell::GetAllRootWindows());
1458  ASSERT_EQ(2u, roots.size());
1459
1460  // Move to the first tab and drag it enough so that it detaches.
1461  gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1462  ASSERT_TRUE(PressInput(tab_0_center));
1463  ASSERT_TRUE(DragInputToNotifyWhenDone(
1464                  tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
1465                  base::Bind(&CursorDeviceScaleFactorStep,
1466                             this, tab_strip, 0)));
1467  QuitWhenNotDragging();
1468}
1469
1470namespace {
1471
1472class DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest
1473    : public TabDragControllerTest {
1474 public:
1475  DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest() {}
1476
1477  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
1478    TabDragControllerTest::SetUpCommandLine(command_line);
1479    command_line->AppendSwitchASCII("ash-host-window-bounds",
1480                                    "0+0-250x250,251+0-250x250");
1481  }
1482
1483  bool Press(const gfx::Point& position) {
1484    return ui_test_utils::SendMouseMoveSync(position) &&
1485        ui_test_utils::SendMouseEventsSync(ui_controls::LEFT,
1486                                           ui_controls::DOWN);
1487  }
1488
1489  bool DragTabAndExecuteTaskWhenDone(const gfx::Point& position,
1490                                     const base::Closure& task) {
1491    return ui_controls::SendMouseMoveNotifyWhenDone(
1492        position.x(), position.y(), task);
1493  }
1494
1495  void QuitWhenNotDragging() {
1496    test::QuitWhenNotDraggingImpl();
1497    base::MessageLoop::current()->Run();
1498  }
1499
1500 private:
1501  DISALLOW_COPY_AND_ASSIGN(
1502      DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest);
1503};
1504
1505// Invoked from the nested message loop.
1506void CancelDragTabToWindowInSeparateDisplayStep3(
1507    TabStrip* tab_strip,
1508    const BrowserList* browser_list) {
1509  ASSERT_FALSE(tab_strip->IsDragSessionActive());
1510  ASSERT_TRUE(TabDragController::IsActive());
1511  ASSERT_EQ(2u, browser_list->size());
1512
1513  // Switching display mode should cancel the drag operation.
1514  ash::internal::DisplayManager* display_manager =
1515      ash::Shell::GetInstance()->display_manager();
1516  display_manager->AddRemoveDisplay();
1517}
1518
1519// Invoked from the nested message loop.
1520void CancelDragTabToWindowInSeparateDisplayStep2(
1521    DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest* test,
1522    TabStrip* tab_strip,
1523    aura::RootWindow* current_root,
1524    gfx::Point final_destination,
1525    const BrowserList* browser_list) {
1526  ASSERT_FALSE(tab_strip->IsDragSessionActive());
1527  ASSERT_TRUE(TabDragController::IsActive());
1528  ASSERT_EQ(2u, browser_list->size());
1529
1530  Browser* new_browser = browser_list->get(1);
1531  EXPECT_EQ(current_root,
1532            new_browser->window()->GetNativeWindow()->GetRootWindow());
1533
1534  ASSERT_TRUE(test->DragTabAndExecuteTaskWhenDone(
1535      final_destination,
1536      base::Bind(&CancelDragTabToWindowInSeparateDisplayStep3,
1537                 tab_strip, browser_list)));
1538}
1539
1540}  // namespace
1541
1542// Drags from browser to a second display and releases input.
1543IN_PROC_BROWSER_TEST_F(
1544    DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest,
1545    CancelDragTabToWindowIn2ndDisplay) {
1546  // Add another tab.
1547  AddTabAndResetBrowser(browser());
1548  TabStrip* tab_strip = GetTabStripForBrowser(browser());
1549
1550  EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
1551
1552  // Move the second browser to the second display.
1553  std::vector<aura::RootWindow*> roots(ash::Shell::GetAllRootWindows());
1554  ASSERT_EQ(2u, roots.size());
1555  gfx::Point final_destination =
1556      gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1557          roots[1]).work_area().CenterPoint();
1558
1559  // Move to the first tab and drag it enough so that it detaches, but not
1560  // enough to move to another display.
1561  gfx::Point tab_0_dst(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1562  ASSERT_TRUE(Press(tab_0_dst));
1563  tab_0_dst.Offset(0, GetDetachY(tab_strip));
1564  ASSERT_TRUE(DragTabAndExecuteTaskWhenDone(
1565      tab_0_dst, base::Bind(&CancelDragTabToWindowInSeparateDisplayStep2,
1566                            this, tab_strip, roots[0], final_destination,
1567                            native_browser_list)));
1568  QuitWhenNotDragging();
1569
1570  ASSERT_EQ(1u, native_browser_list->size());
1571  ASSERT_FALSE(tab_strip->IsDragSessionActive());
1572  ASSERT_FALSE(TabDragController::IsActive());
1573  EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
1574
1575  // Release the mouse
1576  ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
1577      ui_controls::LEFT, ui_controls::UP));
1578}
1579
1580// Drags from browser from a second display to primary and releases input.
1581IN_PROC_BROWSER_TEST_F(
1582    DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest,
1583    CancelDragTabToWindowIn1stDisplay) {
1584  std::vector<aura::RootWindow*> roots(ash::Shell::GetAllRootWindows());
1585  ASSERT_EQ(2u, roots.size());
1586
1587  // Add another tab.
1588  AddTabAndResetBrowser(browser());
1589  TabStrip* tab_strip = GetTabStripForBrowser(browser());
1590
1591  EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
1592  EXPECT_EQ(roots[0], browser()->window()->GetNativeWindow()->GetRootWindow());
1593
1594  gfx::Rect work_area = gfx::Screen::GetNativeScreen()->
1595      GetDisplayNearestWindow(roots[1]).work_area();
1596  browser()->window()->SetBounds(work_area);
1597  EXPECT_EQ(roots[1], browser()->window()->GetNativeWindow()->GetRootWindow());
1598
1599  // Move the second browser to the display.
1600  gfx::Point final_destination =
1601      gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
1602          roots[0]).work_area().CenterPoint();
1603
1604  // Move to the first tab and drag it enough so that it detaches, but not
1605  // enough to move to another display.
1606  gfx::Point tab_0_dst(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
1607  ASSERT_TRUE(Press(tab_0_dst));
1608  tab_0_dst.Offset(0, GetDetachY(tab_strip));
1609  ASSERT_TRUE(DragTabAndExecuteTaskWhenDone(
1610      tab_0_dst, base::Bind(&CancelDragTabToWindowInSeparateDisplayStep2,
1611                            this, tab_strip, roots[1], final_destination,
1612                            native_browser_list)));
1613  QuitWhenNotDragging();
1614
1615  ASSERT_EQ(1u, native_browser_list->size());
1616  ASSERT_FALSE(tab_strip->IsDragSessionActive());
1617  ASSERT_FALSE(TabDragController::IsActive());
1618  EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
1619
1620  // Release the mouse
1621  ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
1622      ui_controls::LEFT, ui_controls::UP));
1623}
1624
1625#endif
1626
1627#if defined(USE_ASH) && !defined(OS_WIN)  // TODO(win_ash)
1628INSTANTIATE_TEST_CASE_P(TabDragging,
1629                        DetachToBrowserInSeparateDisplayTabDragControllerTest,
1630                        ::testing::Values("mouse", "touch"));
1631INSTANTIATE_TEST_CASE_P(TabDragging,
1632                        DifferentDeviceScaleFactorDisplayTabDragControllerTest,
1633                        ::testing::Values("mouse"));
1634INSTANTIATE_TEST_CASE_P(TabDragging,
1635                        DetachToBrowserTabDragControllerTest,
1636                        ::testing::Values("mouse", "touch"));
1637#else
1638INSTANTIATE_TEST_CASE_P(TabDragging,
1639                        DetachToBrowserTabDragControllerTest,
1640                        ::testing::Values("mouse"));
1641#endif
1642