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