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, ¢er); 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