Home | History | Annotate | Download | only in tabs
      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
   2220