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 52using content::WebContents; 53 54namespace test { 55 56namespace { 57 58const char kTabDragControllerInteractiveUITestUserDataKey[] = 59 "TabDragControllerInteractiveUITestUserData"; 60 61class 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 74class 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 97gfx::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 103void SetID(WebContents* web_contents, int id) { 104 web_contents->SetUserData(&kTabDragControllerInteractiveUITestUserDataKey, 105 new TabDragControllerInteractiveUITestUserData(id)); 106} 107 108void ResetIDs(TabStripModel* model, int start) { 109 for (int i = 0; i < model->count(); ++i) 110 SetID(model->GetWebContentsAt(i), start + i); 111} 112 113std::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. 132void QuitWhenNotDraggingImpl() { 133 new QuitDraggingObserver(); // QuitDraggingObserver deletes itself. 134} 135 136TabStrip* GetTabStripForBrowser(Browser* browser) { 137 BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser); 138 return static_cast<TabStrip*>(browser_view->tabstrip()); 139} 140 141} // namespace test 142 143using test::GetCenterInScreenCoordinates; 144using test::SetID; 145using test::ResetIDs; 146using test::IDString; 147using test::GetTabStripForBrowser; 148 149TabDragControllerTest::TabDragControllerTest() 150 : native_browser_list(BrowserList::GetInstance( 151 chrome::HOST_DESKTOP_TYPE_NATIVE)) { 152} 153 154TabDragControllerTest::~TabDragControllerTest() { 155} 156 157void 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 166void TabDragControllerTest::StopAnimating(TabStrip* tab_strip) { 167 tab_strip->StopAnimating(true); 168} 169 170void TabDragControllerTest::AddTabAndResetBrowser(Browser* browser) { 171 AddBlankTabAndShow(browser); 172 StopAnimating(GetTabStripForBrowser(browser)); 173 ResetIDs(browser->tab_strip_model(), 0); 174} 175 176Browser* 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 193namespace { 194 195enum InputSource { 196 INPUT_SOURCE_MOUSE = 0, 197 INPUT_SOURCE_TOUCH = 1 198}; 199 200int GetDetachY(TabStrip* tab_strip) { 201 return std::max(TabDragController::kTouchVerticalDetachMagnetism, 202 TabDragController::kVerticalDetachMagnetism) + 203 tab_strip->height() + 1; 204} 205 206bool 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) 217class 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 242class 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. 376IN_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 393namespace { 394 395// Invoked from the nested message loop. 396void 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. 420IN_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 461namespace { 462 463void 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) 469bool IsWindowPositionManaged(aura::Window* window) { 470 return ash::wm::IsWindowPositionManaged(window); 471} 472bool HasUserChangedWindowPositionOrSize(aura::Window* window) { 473 return ash::wm::HasUserChangedWindowPositionOrSize(window); 474} 475#else 476bool IsWindowPositionManaged(gfx::NativeWindow window) { 477 return true; 478} 479bool HasUserChangedWindowPositionOrSize(gfx::NativeWindow window) { 480 return false; 481} 482#endif 483 484} // namespace 485 486// Drags from browser to separate window and releases mouse. 487IN_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. 537IN_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. 594IN_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. 620IN_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 649namespace { 650 651void 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. 659IN_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 684namespace { 685 686void 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. 701IN_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 730namespace { 731 732void 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. 744IN_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 771namespace { 772 773void 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. 787IN_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 818namespace { 819 820// Invoked from the nested message loop. 821void 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. 841IN_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 883namespace { 884 885// Invoked from the nested message loop. 886void 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. 908IN_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. 957IN_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. 1005IN_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 1052namespace { 1053 1054// Invoked from the nested message loop. 1055void 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. 1069IN_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 1097namespace { 1098 1099void 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. 1124IN_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. 1162class 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 1179namespace { 1180 1181void DragSingleTabToSeparateWindowInSecondDisplayStep3( 1182 DetachToBrowserTabDragControllerTest* test) { 1183 ASSERT_TRUE(test->ReleaseInput()); 1184} 1185 1186void 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. 1197IN_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 1245namespace { 1246 1247// Invoked from the nested message loop. 1248void 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. 1270IN_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. 1320IN_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. 1383IN_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. 1452IN_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 1527class 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 1549namespace { 1550 1551// The points where a tab is dragged in CursorDeviceScaleFactorStep. 1552const 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. 1565const float kDeviceScaleFactorExpectations[] = { 1566 1.0f, 1567 1.0f, 1568 2.0f, 1569 2.0f, 1570 1.0f, 1571}; 1572 1573COMPILE_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. 1578void 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). 1604IN_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 1624namespace { 1625 1626class 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. 1660void 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. 1674void 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. 1697IN_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. 1735IN_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) 1782INSTANTIATE_TEST_CASE_P(TabDragging, 1783 DetachToBrowserInSeparateDisplayTabDragControllerTest, 1784 ::testing::Values("mouse", "touch")); 1785INSTANTIATE_TEST_CASE_P(TabDragging, 1786 DifferentDeviceScaleFactorDisplayTabDragControllerTest, 1787 ::testing::Values("mouse")); 1788INSTANTIATE_TEST_CASE_P(TabDragging, 1789 DetachToBrowserTabDragControllerTest, 1790 ::testing::Values("mouse", "touch")); 1791#else 1792INSTANTIATE_TEST_CASE_P(TabDragging, 1793 DetachToBrowserTabDragControllerTest, 1794 ::testing::Values("mouse")); 1795#endif 1796