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