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