tab_drag_controller_interactive_uitest.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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/window_state.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/tabs/tab_strip_model.h" 20#include "chrome/browser/ui/views/frame/browser_view.h" 21#include "chrome/browser/ui/views/frame/native_browser_frame_factory.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_AURA) && !defined(OS_CHROMEOS) 40#include "chrome/browser/ui/views/frame/desktop_browser_frame_aura.h" 41#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h" 42#endif 43 44#if defined(USE_ASH) 45#include "ash/ash_switches.h" 46#include "ash/display/display_controller.h" 47#include "ash/display/display_manager.h" 48#include "ash/shell.h" 49#include "ash/test/cursor_manager_test_api.h" 50#include "ash/wm/coordinate_conversion.h" 51#include "ash/wm/window_state.h" 52#include "ash/wm/window_util.h" 53#include "chrome/browser/ui/views/frame/immersive_mode_controller.h" 54#include "ui/aura/client/screen_position_client.h" 55#include "ui/aura/root_window.h" 56#include "ui/aura/test/event_generator.h" 57#endif 58 59using content::WebContents; 60 61namespace test { 62 63namespace { 64 65const char kTabDragControllerInteractiveUITestUserDataKey[] = 66 "TabDragControllerInteractiveUITestUserData"; 67 68class TabDragControllerInteractiveUITestUserData 69 : public base::SupportsUserData::Data { 70 public: 71 explicit TabDragControllerInteractiveUITestUserData(int id) : id_(id) {} 72 virtual ~TabDragControllerInteractiveUITestUserData() {} 73 int id() { return id_; } 74 75 private: 76 int id_; 77}; 78 79} // namespace 80 81class QuitDraggingObserver : public content::NotificationObserver { 82 public: 83 QuitDraggingObserver() { 84 registrar_.Add(this, chrome::NOTIFICATION_TAB_DRAG_LOOP_DONE, 85 content::NotificationService::AllSources()); 86 } 87 88 virtual void Observe(int type, 89 const content::NotificationSource& source, 90 const content::NotificationDetails& details) OVERRIDE { 91 DCHECK_EQ(chrome::NOTIFICATION_TAB_DRAG_LOOP_DONE, type); 92 base::MessageLoopForUI::current()->Quit(); 93 delete this; 94 } 95 96 private: 97 virtual ~QuitDraggingObserver() {} 98 99 content::NotificationRegistrar registrar_; 100 101 DISALLOW_COPY_AND_ASSIGN(QuitDraggingObserver); 102}; 103 104gfx::Point GetCenterInScreenCoordinates(const views::View* view) { 105 gfx::Point center(view->width() / 2, view->height() / 2); 106 views::View::ConvertPointToScreen(view, ¢er); 107 return center; 108} 109 110void SetID(WebContents* web_contents, int id) { 111 web_contents->SetUserData(&kTabDragControllerInteractiveUITestUserDataKey, 112 new TabDragControllerInteractiveUITestUserData(id)); 113} 114 115void ResetIDs(TabStripModel* model, int start) { 116 for (int i = 0; i < model->count(); ++i) 117 SetID(model->GetWebContentsAt(i), start + i); 118} 119 120std::string IDString(TabStripModel* model) { 121 std::string result; 122 for (int i = 0; i < model->count(); ++i) { 123 if (i != 0) 124 result += " "; 125 WebContents* contents = model->GetWebContentsAt(i); 126 TabDragControllerInteractiveUITestUserData* user_data = 127 static_cast<TabDragControllerInteractiveUITestUserData*>( 128 contents->GetUserData( 129 &kTabDragControllerInteractiveUITestUserDataKey)); 130 if (user_data) 131 result += base::IntToString(user_data->id()); 132 else 133 result += "?"; 134 } 135 return result; 136} 137 138// Creates a listener that quits the message loop when no longer dragging. 139void QuitWhenNotDraggingImpl() { 140 new QuitDraggingObserver(); // QuitDraggingObserver deletes itself. 141} 142 143TabStrip* GetTabStripForBrowser(Browser* browser) { 144 BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser); 145 return static_cast<TabStrip*>(browser_view->tabstrip()); 146} 147 148} // namespace test 149 150using test::GetCenterInScreenCoordinates; 151using test::SetID; 152using test::ResetIDs; 153using test::IDString; 154using test::GetTabStripForBrowser; 155 156TabDragControllerTest::TabDragControllerTest() 157 : native_browser_list(BrowserList::GetInstance( 158 chrome::HOST_DESKTOP_TYPE_NATIVE)) { 159} 160 161TabDragControllerTest::~TabDragControllerTest() { 162} 163 164void TabDragControllerTest::StopAnimating(TabStrip* tab_strip) { 165 tab_strip->StopAnimating(true); 166} 167 168void TabDragControllerTest::AddTabAndResetBrowser(Browser* browser) { 169 AddBlankTabAndShow(browser); 170 StopAnimating(GetTabStripForBrowser(browser)); 171 ResetIDs(browser->tab_strip_model(), 0); 172} 173 174Browser* TabDragControllerTest::CreateAnotherWindowBrowserAndRelayout() { 175 // Create another browser. 176 Browser* browser2 = CreateBrowser(browser()->profile()); 177 ResetIDs(browser2->tab_strip_model(), 100); 178 179 // Resize the two windows so they're right next to each other. 180 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow( 181 browser()->window()->GetNativeWindow()).work_area(); 182 gfx::Size half_size = 183 gfx::Size(work_area.width() / 3 - 10, work_area.height() / 2 - 10); 184 browser()->window()->SetBounds(gfx::Rect(work_area.origin(), half_size)); 185 browser2->window()->SetBounds(gfx::Rect( 186 work_area.x() + half_size.width(), work_area.y(), 187 half_size.width(), half_size.height())); 188 return browser2; 189} 190 191namespace { 192 193enum InputSource { 194 INPUT_SOURCE_MOUSE = 0, 195 INPUT_SOURCE_TOUCH = 1 196}; 197 198int GetDetachY(TabStrip* tab_strip) { 199 return std::max(TabDragController::kTouchVerticalDetachMagnetism, 200 TabDragController::kVerticalDetachMagnetism) + 201 tab_strip->height() + 1; 202} 203 204bool GetIsDragged(Browser* browser) { 205#if !defined(USE_ASH) || defined(OS_WIN) // TODO(win_ash) 206 return false; 207#else 208 return ash::wm::GetWindowState(browser->window()->GetNativeWindow())-> 209 is_dragged(); 210#endif 211} 212 213} // namespace 214 215#if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash) 216class ScreenEventGeneratorDelegate : public aura::test::EventGeneratorDelegate { 217 public: 218 explicit ScreenEventGeneratorDelegate(aura::Window* root_window) 219 : root_window_(root_window) {} 220 virtual ~ScreenEventGeneratorDelegate() {} 221 222 // EventGeneratorDelegate overrides: 223 virtual aura::RootWindow* GetRootWindowAt( 224 const gfx::Point& point) const OVERRIDE { 225 return root_window_->GetDispatcher(); 226 } 227 228 virtual aura::client::ScreenPositionClient* GetScreenPositionClient( 229 const aura::Window* window) const OVERRIDE { 230 return aura::client::GetScreenPositionClient(root_window_); 231 } 232 233 private: 234 aura::Window* root_window_; 235 236 DISALLOW_COPY_AND_ASSIGN(ScreenEventGeneratorDelegate); 237}; 238 239#endif 240 241#if defined(USE_AURA) && !defined(OS_CHROMEOS) 242 243// Following classes verify a crash scenario. Specifically on Windows when focus 244// changes it can trigger capture being lost. This was causing a crash in tab 245// dragging as it wasn't set up to handle this scenario. These classes 246// synthesize this scenario. 247 248// Allows making ClearNativeFocus() invoke ReleaseCapture(). 249class TestDesktopBrowserFrameAura : public DesktopBrowserFrameAura { 250 public: 251 TestDesktopBrowserFrameAura( 252 BrowserFrame* browser_frame, 253 BrowserView* browser_view) 254 : DesktopBrowserFrameAura(browser_frame, browser_view), 255 release_capture_(false) {} 256 virtual ~TestDesktopBrowserFrameAura() {} 257 258 void ReleaseCaptureOnNextClear() { 259 release_capture_ = true; 260 } 261 262 virtual void ClearNativeFocus() OVERRIDE { 263 views::DesktopNativeWidgetAura::ClearNativeFocus(); 264 if (release_capture_) { 265 release_capture_ = false; 266 GetWidget()->ReleaseCapture(); 267 } 268 } 269 270 private: 271 // If true ReleaseCapture() is invoked in ClearNativeFocus(). 272 bool release_capture_; 273 274 DISALLOW_COPY_AND_ASSIGN(TestDesktopBrowserFrameAura); 275}; 276 277// Factory for creating a TestDesktopBrowserFrameAura. 278class TestNativeBrowserFrameFactory : public NativeBrowserFrameFactory { 279 public: 280 TestNativeBrowserFrameFactory() {} 281 virtual ~TestNativeBrowserFrameFactory() {} 282 283 virtual NativeBrowserFrame* Create( 284 BrowserFrame* browser_frame, 285 BrowserView* browser_view) OVERRIDE { 286 return new TestDesktopBrowserFrameAura(browser_frame, browser_view); 287 } 288 289 private: 290 DISALLOW_COPY_AND_ASSIGN(TestNativeBrowserFrameFactory); 291}; 292 293class TabDragCaptureLostTest : public TabDragControllerTest { 294 public: 295 TabDragCaptureLostTest() { 296 NativeBrowserFrameFactory::Set(new TestNativeBrowserFrameFactory); 297 } 298 299 private: 300 DISALLOW_COPY_AND_ASSIGN(TabDragCaptureLostTest); 301}; 302 303// See description above for details. 304IN_PROC_BROWSER_TEST_F(TabDragCaptureLostTest, ReleaseCaptureOnDrag) { 305 AddTabAndResetBrowser(browser()); 306 307 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 308 gfx::Point tab_1_center(GetCenterInScreenCoordinates(tab_strip->tab_at(1))); 309 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_1_center) && 310 ui_test_utils::SendMouseEventsSync( 311 ui_controls::LEFT, ui_controls::DOWN)); 312 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 313 TestDesktopBrowserFrameAura* frame = 314 static_cast<TestDesktopBrowserFrameAura*>( 315 BrowserView::GetBrowserViewForBrowser(browser())->GetWidget()-> 316 native_widget_private()); 317 // Invoke ReleaseCaptureOnDrag() so that when the drag happens and focus 318 // changes capture is released and the drag cancels. 319 frame->ReleaseCaptureOnNextClear(); 320 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center)); 321 EXPECT_FALSE(tab_strip->IsDragSessionActive()); 322} 323 324IN_PROC_BROWSER_TEST_F(TabDragControllerTest, GestureEndShouldEndDragTest) { 325 AddTabAndResetBrowser(browser()); 326 327 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 328 TabStripModel* model = browser()->tab_strip_model(); 329 330 Tab* tab1 = tab_strip->tab_at(1); 331 gfx::Point tab_1_center(tab1->width() / 2, tab1->height() / 2); 332 333 ui::GestureEvent gesture_begin(ui::ET_GESTURE_BEGIN, tab_1_center.x(), 334 tab_1_center.x(), 0, base::TimeDelta(), 335 ui::GestureEventDetails(ui::ET_GESTURE_BEGIN, 0.0f, 0.0f), 0); 336 tab_strip->MaybeStartDrag(tab1, gesture_begin, 337 tab_strip->GetSelectionModel()); 338 //tab_strip->tab_at(1)->OnGestureEvent(&gesture_begin); 339 EXPECT_TRUE(TabDragController::IsActive()); 340 341 ui::GestureEvent gesture_end(ui::ET_GESTURE_END, tab_1_center.x(), 342 tab_1_center.x(), 0, base::TimeDelta(), 343 ui::GestureEventDetails(ui::ET_GESTURE_END, 0.0f, 0.0f), 0); 344 tab_strip->OnGestureEvent(&gesture_end); 345 EXPECT_FALSE(TabDragController::IsActive()); 346 EXPECT_FALSE(tab_strip->IsDragSessionActive()); 347} 348 349#endif 350 351class DetachToBrowserTabDragControllerTest 352 : public TabDragControllerTest, 353 public ::testing::WithParamInterface<const char*> { 354 public: 355 DetachToBrowserTabDragControllerTest() {} 356 357 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 358#if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash) 359 if (!docked_windows_enabled()) { 360 CommandLine::ForCurrentProcess()->AppendSwitch( 361 ash::switches::kAshDisableDockedWindows); 362 } 363#endif 364 } 365 366 virtual void SetUpOnMainThread() OVERRIDE { 367#if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash) 368 event_generator_.reset(new aura::test::EventGenerator( 369 ash::Shell::GetPrimaryRootWindow())); 370#endif 371 } 372 373 InputSource input_source() const { 374 return strstr(GetParam(), "mouse") ? 375 INPUT_SOURCE_MOUSE : INPUT_SOURCE_TOUCH; 376 } 377 378 bool docked_windows_enabled() const { 379 return (strstr(GetParam(), "docked") != NULL); 380 } 381 382 // Set root window from a point in screen coordinates 383 void SetEventGeneratorRootWindow(const gfx::Point& point) { 384 if (input_source() == INPUT_SOURCE_MOUSE) 385 return; 386#if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash) 387 event_generator_.reset(new aura::test::EventGenerator( 388 new ScreenEventGeneratorDelegate(ash::wm::GetRootWindowAt(point)))); 389#endif 390 } 391 392 // The following methods update one of the mouse or touch input depending upon 393 // the InputSource. 394 bool PressInput(const gfx::Point& location) { 395 if (input_source() == INPUT_SOURCE_MOUSE) { 396 return ui_test_utils::SendMouseMoveSync(location) && 397 ui_test_utils::SendMouseEventsSync( 398 ui_controls::LEFT, ui_controls::DOWN); 399 } 400#if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash) 401 event_generator_->set_current_location(location); 402 event_generator_->PressTouch(); 403#else 404 NOTREACHED(); 405#endif 406 return true; 407 } 408 409 bool PressInput2() { 410 // Second touch input is only used for touch sequence tests. 411 EXPECT_EQ(INPUT_SOURCE_TOUCH, input_source()); 412#if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash) 413 event_generator_->set_current_location( 414 event_generator_->current_location()); 415 event_generator_->PressTouchId(1); 416#else 417 NOTREACHED(); 418#endif 419 return true; 420 } 421 422 bool DragInputTo(const gfx::Point& location) { 423 if (input_source() == INPUT_SOURCE_MOUSE) 424 return ui_test_utils::SendMouseMoveSync(location); 425#if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash) 426 event_generator_->MoveTouch(location); 427#else 428 NOTREACHED(); 429#endif 430 return true; 431 } 432 433 bool DragInputToAsync(const gfx::Point& location) { 434 if (input_source() == INPUT_SOURCE_MOUSE) 435 return ui_controls::SendMouseMove(location.x(), location.y()); 436#if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash) 437 event_generator_->MoveTouch(location); 438#else 439 NOTREACHED(); 440#endif 441 return true; 442 } 443 444 bool DragInputToNotifyWhenDone(int x, 445 int y, 446 const base::Closure& task) { 447 if (input_source() == INPUT_SOURCE_MOUSE) 448 return ui_controls::SendMouseMoveNotifyWhenDone(x, y, task); 449#if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash) 450 base::MessageLoop::current()->PostTask(FROM_HERE, task); 451 event_generator_->MoveTouch(gfx::Point(x, y)); 452#else 453 NOTREACHED(); 454#endif 455 return true; 456 } 457 458 bool DragInputToDelayedNotifyWhenDone(int x, 459 int y, 460 const base::Closure& task, 461 base::TimeDelta delay) { 462 if (input_source() == INPUT_SOURCE_MOUSE) 463 return ui_controls::SendMouseMoveNotifyWhenDone(x, y, task); 464#if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash) 465 base::MessageLoop::current()->PostDelayedTask(FROM_HERE, task, delay); 466 event_generator_->MoveTouch(gfx::Point(x, y)); 467#else 468 NOTREACHED(); 469#endif 470 return true; 471 } 472 473 bool DragInput2ToNotifyWhenDone(int x, 474 int y, 475 const base::Closure& task) { 476 if (input_source() == INPUT_SOURCE_MOUSE) 477 return ui_controls::SendMouseMoveNotifyWhenDone(x, y, task); 478#if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash) 479 base::MessageLoop::current()->PostTask(FROM_HERE, task); 480 event_generator_->MoveTouchId(gfx::Point(x, y), 1); 481#else 482 NOTREACHED(); 483#endif 484 return true; 485 } 486 487 bool ReleaseInput() { 488 if (input_source() == INPUT_SOURCE_MOUSE) { 489 return ui_test_utils::SendMouseEventsSync( 490 ui_controls::LEFT, ui_controls::UP); 491 } 492#if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash) 493 event_generator_->ReleaseTouch(); 494#else 495 NOTREACHED(); 496#endif 497 return true; 498 } 499 500 bool ReleaseInput2() { 501 if (input_source() == INPUT_SOURCE_MOUSE) { 502 return ui_test_utils::SendMouseEventsSync( 503 ui_controls::LEFT, ui_controls::UP); 504 } 505#if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash) 506 event_generator_->ReleaseTouchId(1); 507#else 508 NOTREACHED(); 509#endif 510 return true; 511 } 512 513 bool ReleaseMouseAsync() { 514 return input_source() == INPUT_SOURCE_MOUSE && 515 ui_controls::SendMouseEvents(ui_controls::LEFT, ui_controls::UP); 516 } 517 518 void QuitWhenNotDragging() { 519 if (input_source() == INPUT_SOURCE_MOUSE) { 520 // Schedule observer to quit message loop when done dragging. This has to 521 // be async so the message loop can run. 522 test::QuitWhenNotDraggingImpl(); 523 base::MessageLoop::current()->Run(); 524 } else { 525 // Touch events are sync, so we know we're not in a drag session. But some 526 // tests rely on the browser fully closing, which is async. So, run all 527 // pending tasks. 528 base::RunLoop run_loop; 529 run_loop.RunUntilIdle(); 530 } 531 } 532 533 void AddBlankTabAndShow(Browser* browser) { 534 InProcessBrowserTest::AddBlankTabAndShow(browser); 535 } 536 537 Browser* browser() const { return InProcessBrowserTest::browser(); } 538 539 private: 540#if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash) 541 scoped_ptr<aura::test::EventGenerator> event_generator_; 542#endif 543 544 DISALLOW_COPY_AND_ASSIGN(DetachToBrowserTabDragControllerTest); 545}; 546 547// Creates a browser with two tabs, drags the second to the first. 548IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, DragInSameWindow) { 549 // TODO(sky): this won't work with touch as it requires a long press. 550 if (input_source() == INPUT_SOURCE_TOUCH) { 551 VLOG(1) << "Test is DISABLED for touch input."; 552 return; 553 } 554 555 AddTabAndResetBrowser(browser()); 556 557 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 558 TabStripModel* model = browser()->tab_strip_model(); 559 560 gfx::Point tab_1_center(GetCenterInScreenCoordinates(tab_strip->tab_at(1))); 561 ASSERT_TRUE(PressInput(tab_1_center)); 562 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 563 ASSERT_TRUE(DragInputTo(tab_0_center)); 564 ASSERT_TRUE(ReleaseInput()); 565 EXPECT_EQ("1 0", IDString(model)); 566 EXPECT_FALSE(TabDragController::IsActive()); 567 EXPECT_FALSE(tab_strip->IsDragSessionActive()); 568 569 // The tab strip should no longer have capture because the drag was ended and 570 // mouse/touch was released. 571 EXPECT_FALSE(tab_strip->GetWidget()->HasCapture()); 572} 573 574namespace { 575 576// Invoked from the nested message loop. 577void DragToSeparateWindowStep2(DetachToBrowserTabDragControllerTest* test, 578 TabStrip* not_attached_tab_strip, 579 TabStrip* target_tab_strip) { 580 ASSERT_FALSE(not_attached_tab_strip->IsDragSessionActive()); 581 ASSERT_FALSE(target_tab_strip->IsDragSessionActive()); 582 ASSERT_TRUE(TabDragController::IsActive()); 583 584 // Drag to target_tab_strip. This should stop the nested loop from dragging 585 // the window. 586 gfx::Point target_point(target_tab_strip->width() -1, 587 target_tab_strip->height() / 2); 588 views::View::ConvertPointToScreen(target_tab_strip, &target_point); 589 ASSERT_TRUE(test->DragInputToAsync(target_point)); 590} 591 592} // namespace 593 594#if defined(OS_CHROMEOS) 595// TODO(sky,sad): Disabled as it fails due to resize locks with a real 596// compositor. crbug.com/331924 597#define MAYBE_DragToSeparateWindow DISABLED_DragToSeparateWindow 598#else 599#define MAYBE_DragToSeparateWindow DragToSeparateWindow 600#endif 601// Creates two browsers, drags from first into second. 602IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, 603 MAYBE_DragToSeparateWindow) { 604 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 605 606 // Add another tab to browser(). 607 AddTabAndResetBrowser(browser()); 608 609 // Create another browser. 610 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout(); 611 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2); 612 613 // Move to the first tab and drag it enough so that it detaches, but not 614 // enough that it attaches to browser2. 615 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 616 ASSERT_TRUE(PressInput(tab_0_center)); 617 ASSERT_TRUE(DragInputToNotifyWhenDone( 618 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip), 619 base::Bind(&DragToSeparateWindowStep2, 620 this, tab_strip, tab_strip2))); 621 QuitWhenNotDragging(); 622 623 // Should now be attached to tab_strip2. 624 ASSERT_TRUE(tab_strip2->IsDragSessionActive()); 625 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 626 ASSERT_TRUE(TabDragController::IsActive()); 627 EXPECT_FALSE(GetIsDragged(browser())); 628 629 // Release mouse or touch, stopping the drag session. 630 ASSERT_TRUE(ReleaseInput()); 631 ASSERT_FALSE(tab_strip2->IsDragSessionActive()); 632 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 633 ASSERT_FALSE(TabDragController::IsActive()); 634 EXPECT_EQ("100 0", IDString(browser2->tab_strip_model())); 635 EXPECT_EQ("1", IDString(browser()->tab_strip_model())); 636 EXPECT_FALSE(GetIsDragged(browser2)); 637 638 // Both windows should not be maximized 639 EXPECT_FALSE(browser()->window()->IsMaximized()); 640 EXPECT_FALSE(browser2->window()->IsMaximized()); 641 642 // The tab strip should no longer have capture because the drag was ended and 643 // mouse/touch was released. 644 EXPECT_FALSE(tab_strip->GetWidget()->HasCapture()); 645 EXPECT_FALSE(tab_strip2->GetWidget()->HasCapture()); 646} 647 648namespace { 649 650void DetachToOwnWindowStep2(DetachToBrowserTabDragControllerTest* test) { 651 if (test->input_source() == INPUT_SOURCE_TOUCH) 652 ASSERT_TRUE(test->ReleaseInput()); 653} 654 655#if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash) 656bool IsWindowPositionManaged(aura::Window* window) { 657 return ash::wm::GetWindowState(window)->window_position_managed(); 658} 659bool HasUserChangedWindowPositionOrSize(aura::Window* window) { 660 return ash::wm::GetWindowState(window)->bounds_changed_by_user(); 661} 662#else 663bool IsWindowPositionManaged(gfx::NativeWindow window) { 664 return true; 665} 666bool HasUserChangedWindowPositionOrSize(gfx::NativeWindow window) { 667 return false; 668} 669#endif 670 671} // namespace 672 673#if defined(OS_CHROMEOS) 674// TODO(sky,sad): Disabled as it fails due to resize locks with a real 675// compositor. crbug.com/331924 676#define MAYBE_DetachToOwnWindow DISABLED_DetachToOwnWindow 677#else 678#define MAYBE_DetachToOwnWindow DetachToOwnWindow 679#endif 680// Drags from browser to separate window and releases mouse. 681IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, 682 MAYBE_DetachToOwnWindow) { 683 const gfx::Rect initial_bounds(browser()->window()->GetBounds()); 684 // Add another tab. 685 AddTabAndResetBrowser(browser()); 686 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 687 688 // Move to the first tab and drag it enough so that it detaches. 689 gfx::Point tab_0_center( 690 GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 691 ASSERT_TRUE(PressInput(tab_0_center)); 692 ASSERT_TRUE(DragInputToNotifyWhenDone( 693 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip), 694 base::Bind(&DetachToOwnWindowStep2, this))); 695 if (input_source() == INPUT_SOURCE_MOUSE) { 696 ASSERT_TRUE(ReleaseMouseAsync()); 697 QuitWhenNotDragging(); 698 } 699 700 // Should no longer be dragging. 701 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 702 ASSERT_FALSE(TabDragController::IsActive()); 703 704 // There should now be another browser. 705 ASSERT_EQ(2u, native_browser_list->size()); 706 Browser* new_browser = native_browser_list->get(1); 707 ASSERT_TRUE(new_browser->window()->IsActive()); 708 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser); 709 ASSERT_FALSE(tab_strip2->IsDragSessionActive()); 710 711 EXPECT_EQ("0", IDString(new_browser->tab_strip_model())); 712 EXPECT_EQ("1", IDString(browser()->tab_strip_model())); 713 714 // The bounds of the initial window should not have changed. 715 EXPECT_EQ(initial_bounds.ToString(), 716 browser()->window()->GetBounds().ToString()); 717 718 EXPECT_FALSE(GetIsDragged(browser())); 719 EXPECT_FALSE(GetIsDragged(new_browser)); 720 // After this both windows should still be manageable. 721 EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow())); 722 EXPECT_TRUE(IsWindowPositionManaged( 723 new_browser->window()->GetNativeWindow())); 724 725 // Both windows should not be maximized 726 EXPECT_FALSE(browser()->window()->IsMaximized()); 727 EXPECT_FALSE(new_browser->window()->IsMaximized()); 728 729 // The tab strip should no longer have capture because the drag was ended and 730 // mouse/touch was released. 731 EXPECT_FALSE(tab_strip->GetWidget()->HasCapture()); 732 EXPECT_FALSE(tab_strip2->GetWidget()->HasCapture()); 733} 734 735#if defined(OS_CHROMEOS) 736// TODO(sky,sad): Disabled as it fails due to resize locks with a real 737// compositor. crbug.com/331924 738#define MAYBE_DetachToOwnWindowFromMaximizedWindow \ 739 DISABLED_DetachToOwnWindowFromMaximizedWindow 740#else 741#define MAYBE_DetachToOwnWindowFromMaximizedWindow \ 742 DetachToOwnWindowFromMaximizedWindow 743#endif 744// Drags from browser to a separate window and releases mouse. 745IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, 746 MAYBE_DetachToOwnWindowFromMaximizedWindow) { 747 // Maximize the initial browser window. 748 browser()->window()->Maximize(); 749 ASSERT_TRUE(browser()->window()->IsMaximized()); 750 751 // Add another tab. 752 AddTabAndResetBrowser(browser()); 753 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 754 755 // Move to the first tab and drag it enough so that it detaches. 756 gfx::Point tab_0_center( 757 GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 758 ASSERT_TRUE(PressInput(tab_0_center)); 759 ASSERT_TRUE(DragInputToNotifyWhenDone( 760 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip), 761 base::Bind(&DetachToOwnWindowStep2, this))); 762 if (input_source() == INPUT_SOURCE_MOUSE) { 763 ASSERT_TRUE(ReleaseMouseAsync()); 764 QuitWhenNotDragging(); 765 } 766 767 // Should no longer be dragging. 768 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 769 ASSERT_FALSE(TabDragController::IsActive()); 770 771 // There should now be another browser. 772 ASSERT_EQ(2u, native_browser_list->size()); 773 Browser* new_browser = native_browser_list->get(1); 774 ASSERT_TRUE(new_browser->window()->IsActive()); 775 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser); 776 ASSERT_FALSE(tab_strip2->IsDragSessionActive()); 777 778 EXPECT_EQ("0", IDString(new_browser->tab_strip_model())); 779 EXPECT_EQ("1", IDString(browser()->tab_strip_model())); 780 781 // The bounds of the initial window should not have changed. 782 EXPECT_TRUE(browser()->window()->IsMaximized()); 783 784 EXPECT_FALSE(GetIsDragged(browser())); 785 EXPECT_FALSE(GetIsDragged(new_browser)); 786 // After this both windows should still be manageable. 787 EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow())); 788 EXPECT_TRUE(IsWindowPositionManaged( 789 new_browser->window()->GetNativeWindow())); 790 791 // The new window should be maximized. 792 EXPECT_TRUE(new_browser->window()->IsMaximized()); 793} 794 795// Deletes a tab being dragged before the user moved enough to start a drag. 796IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, 797 DeleteBeforeStartedDragging) { 798 // Add another tab. 799 AddTabAndResetBrowser(browser()); 800 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 801 802 // Click on the first tab, but don't move it. 803 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 804 ASSERT_TRUE(PressInput(tab_0_center)); 805 806 // Should be dragging. 807 ASSERT_TRUE(tab_strip->IsDragSessionActive()); 808 ASSERT_TRUE(TabDragController::IsActive()); 809 810 // Delete the tab being dragged. 811 delete browser()->tab_strip_model()->GetWebContentsAt(0); 812 813 // Should have canceled dragging. 814 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 815 ASSERT_FALSE(TabDragController::IsActive()); 816 817 EXPECT_EQ("1", IDString(browser()->tab_strip_model())); 818 EXPECT_FALSE(GetIsDragged(browser())); 819} 820 821#if defined(OS_CHROMEOS) 822// TODO(sky,sad): Disabled as it fails due to resize locks with a real 823// compositor. crbug.com/331924 824#define MAYBE_DeleteTabWhileAttached DISABLED_DeleteTabWhileAttached 825#else 826#define MAYBE_DeleteTabWhileAttached DeleteTabWhileAttached 827#endif 828// Deletes a tab being dragged while still attached. 829IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, 830 MAYBE_DeleteTabWhileAttached) { 831 // TODO(sky,sad): Disabled as it fails due to resize locks with a real 832 // compositor. crbug.com/331924 833 if (input_source() == INPUT_SOURCE_MOUSE) { 834 VLOG(1) << "Test is DISABLED for mouse input."; 835 return; 836 } 837 838 // Add another tab. 839 AddTabAndResetBrowser(browser()); 840 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 841 842 // Click on the first tab and move it enough so that it starts dragging but is 843 // still attached. 844 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 845 ASSERT_TRUE(PressInput(tab_0_center)); 846 ASSERT_TRUE(DragInputTo( 847 gfx::Point(tab_0_center.x() + 20, tab_0_center.y()))); 848 849 // Should be dragging. 850 ASSERT_TRUE(tab_strip->IsDragSessionActive()); 851 ASSERT_TRUE(TabDragController::IsActive()); 852 853 // Delete the tab being dragged. 854 delete browser()->tab_strip_model()->GetWebContentsAt(0); 855 856 // Should have canceled dragging. 857 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 858 ASSERT_FALSE(TabDragController::IsActive()); 859 860 EXPECT_EQ("1", IDString(browser()->tab_strip_model())); 861 862 EXPECT_FALSE(GetIsDragged(browser())); 863} 864 865namespace { 866 867void DeleteWhileDetachedStep2(WebContents* tab) { 868 delete tab; 869} 870 871} // namespace 872 873#if defined(OS_CHROMEOS) 874// TODO(sky,sad): Disabled as it fails due to resize locks with a real 875// compositor. crbug.com/331924 876#define MAYBE_DeleteTabWhileDetached DISABLED_DeleteTabWhileDetached 877#else 878#define MAYBE_DeleteTabWhileDetached DeleteTabWhileDetached 879#endif 880// Deletes a tab being dragged after dragging a tab so that a new window is 881// created. 882IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, 883 MAYBE_DeleteTabWhileDetached) { 884 // Add another tab. 885 AddTabAndResetBrowser(browser()); 886 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 887 888 // Move to the first tab and drag it enough so that it detaches. 889 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 890 WebContents* to_delete = 891 browser()->tab_strip_model()->GetWebContentsAt(0); 892 ASSERT_TRUE(PressInput(tab_0_center)); 893 ASSERT_TRUE(DragInputToNotifyWhenDone( 894 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip), 895 base::Bind(&DeleteWhileDetachedStep2, to_delete))); 896 QuitWhenNotDragging(); 897 898 // Should not be dragging. 899 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 900 ASSERT_FALSE(TabDragController::IsActive()); 901 902 EXPECT_EQ("1", IDString(browser()->tab_strip_model())); 903 904 EXPECT_FALSE(GetIsDragged(browser())); 905} 906 907namespace { 908 909void DeleteSourceDetachedStep2(WebContents* tab, 910 const BrowserList* browser_list) { 911 ASSERT_EQ(2u, browser_list->size()); 912 Browser* new_browser = browser_list->get(1); 913 // This ends up closing the source window. 914 delete tab; 915 // Cancel the drag. 916 ui_controls::SendKeyPress(new_browser->window()->GetNativeWindow(), 917 ui::VKEY_ESCAPE, false, false, false, false); 918} 919 920} // namespace 921 922#if defined(OS_CHROMEOS) 923// TODO(sky,sad): Disabled as it fails due to resize locks with a real 924// compositor. crbug.com/331924 925#define MAYBE_DeleteSourceDetached DISABLED_DeleteSourceDetached 926#else 927#define MAYBE_DeleteSourceDetached DeleteSourceDetached 928#endif 929// Detaches a tab and while detached deletes a tab from the source so that the 930// source window closes then presses escape to cancel the drag. 931IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, 932 MAYBE_DeleteSourceDetached) { 933 // Add another tab. 934 AddTabAndResetBrowser(browser()); 935 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 936 937 // Move to the first tab and drag it enough so that it detaches. 938 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 939 WebContents* to_delete = browser()->tab_strip_model()->GetWebContentsAt(1); 940 ASSERT_TRUE(PressInput(tab_0_center)); 941 ASSERT_TRUE(DragInputToNotifyWhenDone( 942 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip), 943 base::Bind(&DeleteSourceDetachedStep2, to_delete, native_browser_list))); 944 QuitWhenNotDragging(); 945 946 // Should not be dragging. 947 ASSERT_EQ(1u, native_browser_list->size()); 948 Browser* new_browser = native_browser_list->get(0); 949 ASSERT_FALSE(GetTabStripForBrowser(new_browser)->IsDragSessionActive()); 950 ASSERT_FALSE(TabDragController::IsActive()); 951 952 EXPECT_EQ("0", IDString(new_browser->tab_strip_model())); 953 954 EXPECT_FALSE(GetIsDragged(new_browser)); 955 956 // Remaining browser window should not be maximized 957 EXPECT_FALSE(new_browser->window()->IsMaximized()); 958} 959 960namespace { 961 962void PressEscapeWhileDetachedStep2(const BrowserList* browser_list) { 963 ASSERT_EQ(2u, browser_list->size()); 964 Browser* new_browser = browser_list->get(1); 965 ui_controls::SendKeyPress( 966 new_browser->window()->GetNativeWindow(), ui::VKEY_ESCAPE, false, false, 967 false, false); 968} 969 970} // namespace 971 972#if defined(OS_CHROMEOS) 973// TODO(sky,sad): Disabled as it fails due to resize locks with a real 974// compositor. crbug.com/331924 975#define MAYBE_PressEscapeWhileDetached DISABLED_PressEscapeWhileDetached 976#else 977#define MAYBE_PressEscapeWhileDetached PressEscapeWhileDetached 978#endif 979// This is disabled until NativeViewHost::Detach really detaches. 980// Detaches a tab and while detached presses escape to revert the drag. 981IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, 982 MAYBE_PressEscapeWhileDetached) { 983 // Add another tab. 984 AddTabAndResetBrowser(browser()); 985 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 986 987 // Move to the first tab and drag it enough so that it detaches. 988 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 989 ASSERT_TRUE(PressInput(tab_0_center)); 990 ASSERT_TRUE(DragInputToNotifyWhenDone( 991 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip), 992 base::Bind(&PressEscapeWhileDetachedStep2, native_browser_list))); 993 QuitWhenNotDragging(); 994 995 // Should not be dragging. 996 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 997 ASSERT_FALSE(TabDragController::IsActive()); 998 999 // And there should only be one window. 1000 EXPECT_EQ(1u, native_browser_list->size()); 1001 1002 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model())); 1003 1004 // Remaining browser window should not be maximized 1005 EXPECT_FALSE(browser()->window()->IsMaximized()); 1006 1007 // The tab strip should no longer have capture because the drag was ended and 1008 // mouse/touch was released. 1009 EXPECT_FALSE(tab_strip->GetWidget()->HasCapture()); 1010} 1011 1012namespace { 1013 1014void DragAllStep2(DetachToBrowserTabDragControllerTest* test, 1015 const BrowserList* browser_list) { 1016 // Should only be one window. 1017 ASSERT_EQ(1u, browser_list->size()); 1018 if (test->input_source() == INPUT_SOURCE_TOUCH) { 1019 ASSERT_TRUE(test->ReleaseInput()); 1020 } else { 1021 ASSERT_TRUE(test->ReleaseMouseAsync()); 1022 } 1023} 1024 1025} // namespace 1026 1027#if defined(OS_CHROMEOS) 1028// TODO(sky,sad): Disabled as it fails due to resize locks with a real 1029// compositor. crbug.com/331924 1030#define MAYBE_DragAll DISABLED_DragAll 1031#else 1032#define MAYBE_DragAll DragAll 1033#endif 1034// Selects multiple tabs and starts dragging the window. 1035IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, MAYBE_DragAll) { 1036 // Add another tab. 1037 AddTabAndResetBrowser(browser()); 1038 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 1039 browser()->tab_strip_model()->AddTabAtToSelection(0); 1040 browser()->tab_strip_model()->AddTabAtToSelection(1); 1041 1042 // Move to the first tab and drag it enough so that it would normally 1043 // detach. 1044 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 1045 ASSERT_TRUE(PressInput(tab_0_center)); 1046 ASSERT_TRUE(DragInputToNotifyWhenDone( 1047 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip), 1048 base::Bind(&DragAllStep2, this, native_browser_list))); 1049 QuitWhenNotDragging(); 1050 1051 // Should not be dragging. 1052 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 1053 ASSERT_FALSE(TabDragController::IsActive()); 1054 1055 // And there should only be one window. 1056 EXPECT_EQ(1u, native_browser_list->size()); 1057 1058 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model())); 1059 1060 EXPECT_FALSE(GetIsDragged(browser())); 1061 1062 // Remaining browser window should not be maximized 1063 EXPECT_FALSE(browser()->window()->IsMaximized()); 1064} 1065 1066namespace { 1067 1068// Invoked from the nested message loop. 1069void DragAllToSeparateWindowStep2(DetachToBrowserTabDragControllerTest* test, 1070 TabStrip* attached_tab_strip, 1071 TabStrip* target_tab_strip, 1072 const BrowserList* browser_list) { 1073 ASSERT_TRUE(attached_tab_strip->IsDragSessionActive()); 1074 ASSERT_FALSE(target_tab_strip->IsDragSessionActive()); 1075 ASSERT_TRUE(TabDragController::IsActive()); 1076 ASSERT_EQ(2u, browser_list->size()); 1077 1078 // Drag to target_tab_strip. This should stop the nested loop from dragging 1079 // the window. 1080 gfx::Point target_point(target_tab_strip->width() - 1, 1081 target_tab_strip->height() / 2); 1082 views::View::ConvertPointToScreen(target_tab_strip, &target_point); 1083 ASSERT_TRUE(test->DragInputToAsync(target_point)); 1084} 1085 1086} // namespace 1087 1088#if defined(OS_CHROMEOS) 1089// TODO(sky,sad): Disabled as it fails due to resize locks with a real 1090// compositor. crbug.com/331924 1091#define MAYBE_DragAllToSeparateWindow DISABLED_DragAllToSeparateWindow 1092#else 1093#define MAYBE_DragAllToSeparateWindow DragAllToSeparateWindow 1094#endif 1095// Creates two browsers, selects all tabs in first and drags into second. 1096IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, 1097 MAYBE_DragAllToSeparateWindow) { 1098 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 1099 1100 // Add another tab to browser(). 1101 AddTabAndResetBrowser(browser()); 1102 1103 // Create another browser. 1104 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout(); 1105 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2); 1106 1107 browser()->tab_strip_model()->AddTabAtToSelection(0); 1108 browser()->tab_strip_model()->AddTabAtToSelection(1); 1109 1110 // Move to the first tab and drag it enough so that it detaches, but not 1111 // enough that it attaches to browser2. 1112 gfx::Point tab_0_center( 1113 GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 1114 ASSERT_TRUE(PressInput(tab_0_center)); 1115 ASSERT_TRUE(DragInputToNotifyWhenDone( 1116 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip), 1117 base::Bind(&DragAllToSeparateWindowStep2, this, tab_strip, tab_strip2, 1118 native_browser_list))); 1119 QuitWhenNotDragging(); 1120 1121 // Should now be attached to tab_strip2. 1122 ASSERT_TRUE(tab_strip2->IsDragSessionActive()); 1123 ASSERT_TRUE(TabDragController::IsActive()); 1124 ASSERT_EQ(1u, native_browser_list->size()); 1125 1126 // Release the mouse, stopping the drag session. 1127 ASSERT_TRUE(ReleaseInput()); 1128 ASSERT_FALSE(tab_strip2->IsDragSessionActive()); 1129 ASSERT_FALSE(TabDragController::IsActive()); 1130 EXPECT_EQ("100 0 1", IDString(browser2->tab_strip_model())); 1131 1132 EXPECT_FALSE(GetIsDragged(browser2)); 1133 1134 // Remaining browser window should not be maximized 1135 EXPECT_FALSE(browser2->window()->IsMaximized()); 1136} 1137 1138namespace { 1139 1140// Invoked from the nested message loop. 1141void DragAllToSeparateWindowAndCancelStep2( 1142 DetachToBrowserTabDragControllerTest* test, 1143 TabStrip* attached_tab_strip, 1144 TabStrip* target_tab_strip, 1145 const BrowserList* browser_list) { 1146 ASSERT_TRUE(attached_tab_strip->IsDragSessionActive()); 1147 ASSERT_FALSE(target_tab_strip->IsDragSessionActive()); 1148 ASSERT_TRUE(TabDragController::IsActive()); 1149 ASSERT_EQ(2u, browser_list->size()); 1150 1151 // Drag to target_tab_strip. This should stop the nested loop from dragging 1152 // the window. 1153 gfx::Point target_point(target_tab_strip->width() - 1, 1154 target_tab_strip->height() / 2); 1155 views::View::ConvertPointToScreen(target_tab_strip, &target_point); 1156 ASSERT_TRUE(test->DragInputToAsync(target_point)); 1157} 1158 1159} // namespace 1160 1161#if defined(OS_CHROMEOS) 1162// TODO(sky,sad): Disabled as it fails due to resize locks with a real 1163// compositor. crbug.com/331924 1164#define MAYBE_DragAllToSeparateWindowAndCancel \ 1165 DISABLED_DragAllToSeparateWindowAndCancel 1166#else 1167#define MAYBE_DragAllToSeparateWindowAndCancel DragAllToSeparateWindowAndCancel 1168#endif 1169// Creates two browsers, selects all tabs in first, drags into second, then hits 1170// escape. 1171IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, 1172 MAYBE_DragAllToSeparateWindowAndCancel) { 1173 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 1174 1175 // Add another tab to browser(). 1176 AddTabAndResetBrowser(browser()); 1177 1178 // Create another browser. 1179 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout(); 1180 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2); 1181 1182 browser()->tab_strip_model()->AddTabAtToSelection(0); 1183 browser()->tab_strip_model()->AddTabAtToSelection(1); 1184 1185 // Move to the first tab and drag it enough so that it detaches, but not 1186 // enough that it attaches to browser2. 1187 gfx::Point tab_0_center( 1188 GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 1189 ASSERT_TRUE(PressInput(tab_0_center)); 1190 ASSERT_TRUE(DragInputToNotifyWhenDone( 1191 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip), 1192 base::Bind(&DragAllToSeparateWindowAndCancelStep2, this, 1193 tab_strip, tab_strip2, native_browser_list))); 1194 QuitWhenNotDragging(); 1195 1196 // Should now be attached to tab_strip2. 1197 ASSERT_TRUE(tab_strip2->IsDragSessionActive()); 1198 ASSERT_TRUE(TabDragController::IsActive()); 1199 ASSERT_EQ(1u, native_browser_list->size()); 1200 1201 // Cancel the drag. 1202 ASSERT_TRUE(ui_test_utils::SendKeyPressSync( 1203 browser2, ui::VKEY_ESCAPE, false, false, false, false)); 1204 1205 ASSERT_FALSE(tab_strip2->IsDragSessionActive()); 1206 ASSERT_FALSE(TabDragController::IsActive()); 1207 EXPECT_EQ("100 0 1", IDString(browser2->tab_strip_model())); 1208 1209 // browser() will have been destroyed, but browser2 should remain. 1210 ASSERT_EQ(1u, native_browser_list->size()); 1211 1212 EXPECT_FALSE(GetIsDragged(browser2)); 1213 1214 // Remaining browser window should not be maximized 1215 EXPECT_FALSE(browser2->window()->IsMaximized()); 1216} 1217 1218#if defined(OS_CHROMEOS) 1219// TODO(sky,sad): Disabled as it fails due to resize locks with a real 1220// compositor. crbug.com/331924 1221#define MAYBE_DragDirectlyToSecondWindow DISABLED_DragDirectlyToSecondWindow 1222#else 1223#define MAYBE_DragDirectlyToSecondWindow DragDirectlyToSecondWindow 1224#endif 1225// Creates two browsers, drags from first into the second in such a way that 1226// no detaching should happen. 1227IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, 1228 MAYBE_DragDirectlyToSecondWindow) { 1229 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 1230 1231 // Add another tab to browser(). 1232 AddTabAndResetBrowser(browser()); 1233 1234 // Create another browser. 1235 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout(); 1236 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2); 1237 1238 // Move the tabstrip down enough so that we can detach. 1239 gfx::Rect bounds(browser2->window()->GetBounds()); 1240 bounds.Offset(0, 100); 1241 browser2->window()->SetBounds(bounds); 1242 1243 // Move to the first tab and drag it enough so that it detaches, but not 1244 // enough that it attaches to browser2. 1245 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 1246 ASSERT_TRUE(PressInput(tab_0_center)); 1247 1248 gfx::Point b2_location(5, 0); 1249 views::View::ConvertPointToScreen(tab_strip2, &b2_location); 1250 ASSERT_TRUE(DragInputTo(b2_location)); 1251 1252 // Should now be attached to tab_strip2. 1253 ASSERT_TRUE(tab_strip2->IsDragSessionActive()); 1254 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 1255 ASSERT_TRUE(TabDragController::IsActive()); 1256 1257 // Release the mouse, stopping the drag session. 1258 ASSERT_TRUE(ReleaseInput()); 1259 ASSERT_FALSE(tab_strip2->IsDragSessionActive()); 1260 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 1261 ASSERT_FALSE(TabDragController::IsActive()); 1262 EXPECT_EQ("0 100", IDString(browser2->tab_strip_model())); 1263 EXPECT_EQ("1", IDString(browser()->tab_strip_model())); 1264 1265 EXPECT_FALSE(GetIsDragged(browser())); 1266 EXPECT_FALSE(GetIsDragged(browser2)); 1267 1268 // Both windows should not be maximized 1269 EXPECT_FALSE(browser()->window()->IsMaximized()); 1270 EXPECT_FALSE(browser2->window()->IsMaximized()); 1271} 1272 1273#if defined(OS_CHROMEOS) 1274// TODO(sky,sad): Disabled as it fails due to resize locks with a real 1275// compositor. crbug.com/331924 1276#define MAYBE_DragSingleTabToSeparateWindow \ 1277 DISABLED_DragSingleTabToSeparateWindow 1278#else 1279#define MAYBE_DragSingleTabToSeparateWindow DragSingleTabToSeparateWindow 1280#endif 1281// Creates two browsers, the first browser has a single tab and drags into the 1282// second browser. 1283IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, 1284 MAYBE_DragSingleTabToSeparateWindow) { 1285 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 1286 1287 ResetIDs(browser()->tab_strip_model(), 0); 1288 1289 // Create another browser. 1290 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout(); 1291 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2); 1292 const gfx::Rect initial_bounds(browser2->window()->GetBounds()); 1293 1294 // Move to the first tab and drag it enough so that it detaches, but not 1295 // enough that it attaches to browser2. 1296 gfx::Point tab_0_center( 1297 GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 1298 ASSERT_TRUE(PressInput(tab_0_center)); 1299 ASSERT_TRUE(DragInputToNotifyWhenDone( 1300 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip), 1301 base::Bind(&DragAllToSeparateWindowStep2, this, tab_strip, tab_strip2, 1302 native_browser_list))); 1303 QuitWhenNotDragging(); 1304 1305 // Should now be attached to tab_strip2. 1306 ASSERT_TRUE(tab_strip2->IsDragSessionActive()); 1307 ASSERT_TRUE(TabDragController::IsActive()); 1308 ASSERT_EQ(1u, native_browser_list->size()); 1309 1310 // Release the mouse, stopping the drag session. 1311 ASSERT_TRUE(ReleaseInput()); 1312 ASSERT_FALSE(tab_strip2->IsDragSessionActive()); 1313 ASSERT_FALSE(TabDragController::IsActive()); 1314 EXPECT_EQ("100 0", IDString(browser2->tab_strip_model())); 1315 1316 EXPECT_FALSE(GetIsDragged(browser2)); 1317 1318 // Remaining browser window should not be maximized 1319 EXPECT_FALSE(browser2->window()->IsMaximized()); 1320 1321 // Make sure that the window is still managed and not user moved. 1322 EXPECT_TRUE(IsWindowPositionManaged(browser2->window()->GetNativeWindow())); 1323 EXPECT_FALSE(HasUserChangedWindowPositionOrSize( 1324 browser2->window()->GetNativeWindow())); 1325 // Also make sure that the drag to window position has not changed. 1326 EXPECT_EQ(initial_bounds.ToString(), 1327 browser2->window()->GetBounds().ToString()); 1328} 1329 1330namespace { 1331 1332// Invoked from the nested message loop. 1333void CancelOnNewTabWhenDraggingStep2( 1334 DetachToBrowserTabDragControllerTest* test, 1335 const BrowserList* browser_list) { 1336 ASSERT_TRUE(TabDragController::IsActive()); 1337 ASSERT_EQ(2u, browser_list->size()); 1338 1339 // Add another tab. This should trigger exiting the nested loop. 1340 test->AddBlankTabAndShow(browser_list->GetLastActive()); 1341} 1342 1343} // namespace 1344 1345#if defined(OS_CHROMEOS) 1346// TODO(sky,sad): Disabled as it fails due to resize locks with a real 1347// compositor. crbug.com/331924 1348#define MAYBE_CancelOnNewTabWhenDragging DISABLED_CancelOnNewTabWhenDragging 1349#else 1350#define MAYBE_CancelOnNewTabWhenDragging CancelOnNewTabWhenDragging 1351#endif 1352// Adds another tab, detaches into separate window, adds another tab and 1353// verifies the run loop ends. 1354IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, 1355 MAYBE_CancelOnNewTabWhenDragging) { 1356 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 1357 1358 // Add another tab to browser(). 1359 AddTabAndResetBrowser(browser()); 1360 1361 // Move to the first tab and drag it enough so that it detaches. 1362 gfx::Point tab_0_center( 1363 GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 1364 ASSERT_TRUE(PressInput(tab_0_center)); 1365 ASSERT_TRUE(DragInputToNotifyWhenDone( 1366 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip), 1367 base::Bind(&CancelOnNewTabWhenDraggingStep2, this, native_browser_list))); 1368 QuitWhenNotDragging(); 1369 1370 // Should be two windows and not dragging. 1371 ASSERT_FALSE(TabDragController::IsActive()); 1372 ASSERT_EQ(2u, native_browser_list->size()); 1373 for (chrome::BrowserIterator it; !it.done(); it.Next()) { 1374 EXPECT_FALSE(GetIsDragged(*it)); 1375 // Should not be maximized 1376 EXPECT_FALSE(it->window()->IsMaximized()); 1377 } 1378} 1379 1380#if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash) 1381 1382namespace { 1383 1384void DragInMaximizedWindowStep2(DetachToBrowserTabDragControllerTest* test, 1385 Browser* browser, 1386 TabStrip* tab_strip, 1387 const BrowserList* browser_list) { 1388 // There should be another browser. 1389 ASSERT_EQ(2u, browser_list->size()); 1390 Browser* new_browser = browser_list->get(1); 1391 EXPECT_NE(browser, new_browser); 1392 ASSERT_TRUE(new_browser->window()->IsActive()); 1393 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser); 1394 1395 ASSERT_TRUE(tab_strip2->IsDragSessionActive()); 1396 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 1397 1398 // Both windows should be visible. 1399 EXPECT_TRUE(tab_strip->GetWidget()->IsVisible()); 1400 EXPECT_TRUE(tab_strip2->GetWidget()->IsVisible()); 1401 1402 // Stops dragging. 1403 ASSERT_TRUE(test->ReleaseInput()); 1404} 1405 1406} // namespace 1407 1408#if defined(OS_CHROMEOS) 1409// TODO(sky,sad): Disabled as it fails due to resize locks with a real 1410// compositor. crbug.com/331924 1411#define MAYBE_DragInMaximizedWindow DISABLED_DragInMaximizedWindow 1412#else 1413#define MAYBE_DragInMaximizedWindow DragInMaximizedWindow 1414#endif 1415// Creates a browser with two tabs, maximizes it, drags the tab out. 1416IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, 1417 MAYBE_DragInMaximizedWindow) { 1418 AddTabAndResetBrowser(browser()); 1419 browser()->window()->Maximize(); 1420 1421 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 1422 1423 // Move to the first tab and drag it enough so that it detaches. 1424 gfx::Point tab_0_center( 1425 GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 1426 ASSERT_TRUE(PressInput(tab_0_center)); 1427 ASSERT_TRUE(DragInputToNotifyWhenDone( 1428 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip), 1429 base::Bind(&DragInMaximizedWindowStep2, this, browser(), tab_strip, 1430 native_browser_list))); 1431 QuitWhenNotDragging(); 1432 1433 ASSERT_FALSE(TabDragController::IsActive()); 1434 1435 // Should be two browsers. 1436 ASSERT_EQ(2u, native_browser_list->size()); 1437 Browser* new_browser = native_browser_list->get(1); 1438 ASSERT_TRUE(new_browser->window()->IsActive()); 1439 1440 EXPECT_TRUE(browser()->window()->GetNativeWindow()->IsVisible()); 1441 EXPECT_TRUE(new_browser->window()->GetNativeWindow()->IsVisible()); 1442 1443 EXPECT_FALSE(GetIsDragged(browser())); 1444 EXPECT_FALSE(GetIsDragged(new_browser)); 1445 1446 // The source window should be maximized. 1447 EXPECT_TRUE(browser()->window()->IsMaximized()); 1448 // The new window should be maximized. 1449 EXPECT_TRUE(new_browser->window()->IsMaximized()); 1450} 1451 1452// Subclass of DetachToBrowserTabDragControllerTest that 1453// creates multiple displays. 1454class DetachToBrowserInSeparateDisplayTabDragControllerTest 1455 : public DetachToBrowserTabDragControllerTest { 1456 public: 1457 DetachToBrowserInSeparateDisplayTabDragControllerTest() {} 1458 virtual ~DetachToBrowserInSeparateDisplayTabDragControllerTest() {} 1459 1460 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 1461 DetachToBrowserTabDragControllerTest::SetUpCommandLine(command_line); 1462 // Make screens sufficiently wide to host 2 browsers side by side. 1463 command_line->AppendSwitchASCII("ash-host-window-bounds", 1464 "0+0-600x600,601+0-600x600"); 1465 } 1466 1467 private: 1468 DISALLOW_COPY_AND_ASSIGN( 1469 DetachToBrowserInSeparateDisplayTabDragControllerTest); 1470}; 1471 1472// Subclass of DetachToBrowserTabDragControllerTest that runs tests only with 1473// touch input. 1474class DetachToBrowserTabDragControllerTestTouch 1475 : public DetachToBrowserTabDragControllerTest { 1476 public: 1477 DetachToBrowserTabDragControllerTestTouch() {} 1478 virtual ~DetachToBrowserTabDragControllerTestTouch() {} 1479 1480 private: 1481 DISALLOW_COPY_AND_ASSIGN(DetachToBrowserTabDragControllerTestTouch); 1482}; 1483 1484namespace { 1485 1486void DragSingleTabToSeparateWindowInSecondDisplayStep3( 1487 DetachToBrowserTabDragControllerTest* test) { 1488 ASSERT_TRUE(test->ReleaseInput()); 1489} 1490 1491void DragSingleTabToSeparateWindowInSecondDisplayStep2( 1492 DetachToBrowserTabDragControllerTest* test, 1493 const gfx::Point& target_point) { 1494 ASSERT_TRUE(test->DragInputToNotifyWhenDone( 1495 target_point.x(), target_point.y(), 1496 base::Bind(&DragSingleTabToSeparateWindowInSecondDisplayStep3, test))); 1497} 1498 1499} // namespace 1500 1501#if defined(OS_CHROMEOS) 1502// TODO(sky,sad): Disabled as it fails due to resize locks with a real 1503// compositor. crbug.com/331924 1504#define MAYBE_DragSingleTabToSeparateWindowInSecondDisplay \ 1505 DISABLED_DragSingleTabToSeparateWindowInSecondDisplay 1506#else 1507#define MAYBE_DragSingleTabToSeparateWindow \ 1508 DragSingleTabToSeparateWindowInSecondDisplay 1509#endif 1510// Drags from browser to a second display and releases input. 1511IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest, 1512 MAYBE_DragSingleTabToSeparateWindowInSecondDisplay) { 1513 // Add another tab. 1514 AddTabAndResetBrowser(browser()); 1515 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 1516 1517 // Move to the first tab and drag it enough so that it detaches. 1518 // Then drag it to the final destination on the second screen. 1519 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 1520 ASSERT_TRUE(PressInput(tab_0_center)); 1521 ASSERT_TRUE(DragInputToNotifyWhenDone( 1522 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip), 1523 base::Bind(&DragSingleTabToSeparateWindowInSecondDisplayStep2, 1524 this, gfx::Point(600 + tab_0_center.x(), 1525 tab_0_center.y() 1526 + GetDetachY(tab_strip))))); 1527 QuitWhenNotDragging(); 1528 1529 // Should no longer be dragging. 1530 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 1531 ASSERT_FALSE(TabDragController::IsActive()); 1532 1533 // There should now be another browser. 1534 ASSERT_EQ(2u, native_browser_list->size()); 1535 Browser* new_browser = native_browser_list->get(1); 1536 ASSERT_TRUE(new_browser->window()->IsActive()); 1537 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser); 1538 ASSERT_FALSE(tab_strip2->IsDragSessionActive()); 1539 1540 // This other browser should be on the second screen (with mouse drag) 1541 // With the touch input the browser cannot be dragged from one screen 1542 // to another and the window stays on the first screen. 1543 if (input_source() == INPUT_SOURCE_MOUSE) { 1544 aura::Window::Windows roots = ash::Shell::GetAllRootWindows(); 1545 ASSERT_EQ(2u, roots.size()); 1546 aura::Window* second_root = roots[1]; 1547 EXPECT_EQ(second_root, 1548 new_browser->window()->GetNativeWindow()->GetRootWindow()); 1549 } 1550 1551 EXPECT_EQ("0", IDString(new_browser->tab_strip_model())); 1552 EXPECT_EQ("1", IDString(browser()->tab_strip_model())); 1553 1554 // Both windows should not be maximized 1555 EXPECT_FALSE(browser()->window()->IsMaximized()); 1556 EXPECT_FALSE(new_browser->window()->IsMaximized()); 1557} 1558 1559namespace { 1560 1561// Invoked from the nested message loop. 1562void DragTabToWindowInSeparateDisplayStep2( 1563 DetachToBrowserTabDragControllerTest* test, 1564 TabStrip* not_attached_tab_strip, 1565 TabStrip* target_tab_strip) { 1566 ASSERT_FALSE(not_attached_tab_strip->IsDragSessionActive()); 1567 ASSERT_FALSE(target_tab_strip->IsDragSessionActive()); 1568 ASSERT_TRUE(TabDragController::IsActive()); 1569 1570 // Drag to target_tab_strip. This should stop the nested loop from dragging 1571 // the window. 1572 gfx::Point target_point( 1573 GetCenterInScreenCoordinates(target_tab_strip->tab_at(0))); 1574 1575 // Move it close to the beginning of the target tabstrip. 1576 target_point.set_x( 1577 target_point.x() - target_tab_strip->tab_at(0)->width() / 2 + 10); 1578 ASSERT_TRUE(test->DragInputToAsync(target_point)); 1579} 1580 1581} // namespace 1582 1583#if defined(OS_CHROMEOS) 1584// TODO(sky,sad): Disabled as it fails due to resize locks with a real 1585// compositor. crbug.com/331924 1586#define MAYBE_DragTabToWindowInSeparateDisplay \ 1587 DISABLED_DragTabToWindowInSeparateDisplay 1588#else 1589#define MAYBE_DragTabToWindowInSeparateDisplay DragTabToWindowInSeparateDisplay 1590#endif 1591// Drags from browser to another browser on a second display and releases input. 1592IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest, 1593 MAYBE_DragTabToWindowInSeparateDisplay) { 1594 // Add another tab. 1595 AddTabAndResetBrowser(browser()); 1596 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 1597 1598 // Create another browser. 1599 Browser* browser2 = CreateBrowser(browser()->profile()); 1600 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2); 1601 ResetIDs(browser2->tab_strip_model(), 100); 1602 1603 // Move the second browser to the second display. 1604 aura::Window::Windows roots = ash::Shell::GetAllRootWindows(); 1605 ASSERT_EQ(2u, roots.size()); 1606 aura::Window* second_root = roots[1]; 1607 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow( 1608 second_root).work_area(); 1609 browser2->window()->SetBounds(work_area); 1610 EXPECT_EQ(second_root, 1611 browser2->window()->GetNativeWindow()->GetRootWindow()); 1612 1613 // Move to the first tab and drag it enough so that it detaches, but not 1614 // enough that it attaches to browser2. 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(&DragTabToWindowInSeparateDisplayStep2, 1620 this, tab_strip, tab_strip2))); 1621 QuitWhenNotDragging(); 1622 1623 // Should now be attached to tab_strip2. 1624 ASSERT_TRUE(tab_strip2->IsDragSessionActive()); 1625 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 1626 ASSERT_TRUE(TabDragController::IsActive()); 1627 1628 // Release the mouse, stopping the drag session. 1629 ASSERT_TRUE(ReleaseInput()); 1630 ASSERT_FALSE(tab_strip2->IsDragSessionActive()); 1631 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 1632 ASSERT_FALSE(TabDragController::IsActive()); 1633 EXPECT_EQ("0 100", IDString(browser2->tab_strip_model())); 1634 EXPECT_EQ("1", IDString(browser()->tab_strip_model())); 1635 1636 // Both windows should not be maximized 1637 EXPECT_FALSE(browser()->window()->IsMaximized()); 1638 EXPECT_FALSE(browser2->window()->IsMaximized()); 1639} 1640 1641#if defined(OS_CHROMEOS) 1642// TODO(sky,sad): Disabled as it fails due to resize locks with a real 1643// compositor. crbug.com/331924 1644#define MAYBE_DragTabToWindowOnSecondDisplay \ 1645 DISABLED_DragTabToWindowOnSecondDisplay 1646#else 1647#define MAYBE_DragTabToWindowOnSecondDisplay DragTabToWindowOnSecondDisplay 1648#endif 1649// Drags from browser to another browser on a second display and releases input. 1650IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest, 1651 MAYBE_DragTabToWindowOnSecondDisplay) { 1652 // Add another tab. 1653 AddTabAndResetBrowser(browser()); 1654 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 1655 1656 // Create another browser. 1657 Browser* browser2 = CreateBrowser(browser()->profile()); 1658 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2); 1659 ResetIDs(browser2->tab_strip_model(), 100); 1660 1661 // Move both browsers to the second display. 1662 aura::Window::Windows roots = ash::Shell::GetAllRootWindows(); 1663 ASSERT_EQ(2u, roots.size()); 1664 aura::Window* second_root = roots[1]; 1665 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow( 1666 second_root).work_area(); 1667 browser()->window()->SetBounds(work_area); 1668 1669 // position both browser windows side by side on the second screen. 1670 gfx::Rect work_area2(work_area); 1671 work_area.set_width(work_area.width()/2); 1672 browser()->window()->SetBounds(work_area); 1673 work_area2.set_x(work_area2.x() + work_area2.width()/2); 1674 work_area2.set_width(work_area2.width()/2); 1675 browser2->window()->SetBounds(work_area2); 1676 EXPECT_EQ(second_root, 1677 browser()->window()->GetNativeWindow()->GetRootWindow()); 1678 EXPECT_EQ(second_root, 1679 browser2->window()->GetNativeWindow()->GetRootWindow()); 1680 1681 // Move to the first tab and drag it enough so that it detaches, but not 1682 // enough that it attaches to browser2. 1683 // SetEventGeneratorRootWindow sets correct (second) RootWindow 1684 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 1685 SetEventGeneratorRootWindow(tab_0_center); 1686 ASSERT_TRUE(PressInput(tab_0_center)); 1687 ASSERT_TRUE(DragInputToNotifyWhenDone( 1688 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip), 1689 base::Bind(&DragTabToWindowInSeparateDisplayStep2, 1690 this, tab_strip, tab_strip2))); 1691 QuitWhenNotDragging(); 1692 1693 // Should now be attached to tab_strip2. 1694 ASSERT_TRUE(tab_strip2->IsDragSessionActive()); 1695 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 1696 ASSERT_TRUE(TabDragController::IsActive()); 1697 1698 // Release the mouse, stopping the drag session. 1699 ASSERT_TRUE(ReleaseInput()); 1700 ASSERT_FALSE(tab_strip2->IsDragSessionActive()); 1701 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 1702 ASSERT_FALSE(TabDragController::IsActive()); 1703 EXPECT_EQ("0 100", IDString(browser2->tab_strip_model())); 1704 EXPECT_EQ("1", IDString(browser()->tab_strip_model())); 1705 1706 // Both windows should not be maximized 1707 EXPECT_FALSE(browser()->window()->IsMaximized()); 1708 EXPECT_FALSE(browser2->window()->IsMaximized()); 1709} 1710 1711#if defined(OS_CHROMEOS) 1712// TODO(sky,sad): Disabled as it fails due to resize locks with a real 1713// compositor. crbug.com/331924 1714#define MAYBE_DragMaxTabToNonMaxWindowInSeparateDisplay \ 1715 DISABLED_DragMaxTabToNonMaxWindowInSeparateDisplay 1716#else 1717#define MAYBE_DragMaxTabToNonMaxWindowInSeparateDisplay \ 1718 DragMaxTabToNonMaxWindowInSeparateDisplay 1719#endif 1720// Drags from a maximized browser to another non-maximized browser on a second 1721// display and releases input. 1722IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest, 1723 MAYBE_DragMaxTabToNonMaxWindowInSeparateDisplay) { 1724 // Add another tab. 1725 AddTabAndResetBrowser(browser()); 1726 browser()->window()->Maximize(); 1727 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 1728 1729 // Create another browser on the second display. 1730 aura::Window::Windows roots = ash::Shell::GetAllRootWindows(); 1731 ASSERT_EQ(2u, roots.size()); 1732 aura::Window* first_root = roots[0]; 1733 aura::Window* second_root = roots[1]; 1734 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow( 1735 second_root).work_area(); 1736 work_area.Inset(20,20,20,60); 1737 Browser::CreateParams params(browser()->profile(), 1738 browser()->host_desktop_type()); 1739 params.initial_show_state = ui::SHOW_STATE_NORMAL; 1740 params.initial_bounds = work_area; 1741 Browser* browser2 = new Browser(params); 1742 AddBlankTabAndShow(browser2); 1743 1744 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2); 1745 ResetIDs(browser2->tab_strip_model(), 100); 1746 1747 EXPECT_EQ(second_root, 1748 browser2->window()->GetNativeWindow()->GetRootWindow()); 1749 EXPECT_EQ(first_root, 1750 browser()->window()->GetNativeWindow()->GetRootWindow()); 1751 EXPECT_EQ(2, tab_strip->tab_count()); 1752 EXPECT_EQ(1, tab_strip2->tab_count()); 1753 1754 // Move to the first tab and drag it enough so that it detaches, but not 1755 // enough that it attaches to browser2. 1756 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 1757 ASSERT_TRUE(PressInput(tab_0_center)); 1758 ASSERT_TRUE(DragInputToNotifyWhenDone( 1759 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip), 1760 base::Bind(&DragTabToWindowInSeparateDisplayStep2, 1761 this, tab_strip, tab_strip2))); 1762 QuitWhenNotDragging(); 1763 1764 // Should now be attached to tab_strip2. 1765 ASSERT_TRUE(tab_strip2->IsDragSessionActive()); 1766 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 1767 ASSERT_TRUE(TabDragController::IsActive()); 1768 1769 // Release the mouse, stopping the drag session. 1770 ASSERT_TRUE(ReleaseInput()); 1771 1772 // tab should have moved 1773 EXPECT_EQ(1, tab_strip->tab_count()); 1774 EXPECT_EQ(2, tab_strip2->tab_count()); 1775 1776 ASSERT_FALSE(tab_strip2->IsDragSessionActive()); 1777 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 1778 ASSERT_FALSE(TabDragController::IsActive()); 1779 EXPECT_EQ("0 100", IDString(browser2->tab_strip_model())); 1780 EXPECT_EQ("1", IDString(browser()->tab_strip_model())); 1781 1782 // Source browser should still be maximized, target should not 1783 EXPECT_TRUE(browser()->window()->IsMaximized()); 1784 EXPECT_FALSE(browser2->window()->IsMaximized()); 1785} 1786 1787// Immersive fullscreen is ChromeOS only. 1788#if defined(OS_CHROMEOS) 1789// TODO(sky,sad): Disabled as it fails due to resize locks with a real 1790// compositor. crbug.com/331924 1791#define MAYBE_DragTabToImmersiveBrowserOnSeparateDisplay \ 1792 DISABLED_DragTabToImmersiveBrowserOnSeparateDisplay 1793// Drags from a restored browser to an immersive fullscreen browser on a 1794// second display and releases input. 1795IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest, 1796 MAYBE_DragTabToImmersiveBrowserOnSeparateDisplay) { 1797 // Add another tab. 1798 AddTabAndResetBrowser(browser()); 1799 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 1800 1801 // Create another browser. 1802 Browser* browser2 = CreateBrowser(browser()->profile()); 1803 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2); 1804 ResetIDs(browser2->tab_strip_model(), 100); 1805 1806 // Move the second browser to the second display. 1807 aura::Window::Windows roots = ash::Shell::GetAllRootWindows(); 1808 ASSERT_EQ(2u, roots.size()); 1809 aura::Window* second_root = roots[1]; 1810 gfx::Rect work_area = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow( 1811 second_root).work_area(); 1812 browser2->window()->SetBounds(work_area); 1813 EXPECT_EQ(second_root, 1814 browser2->window()->GetNativeWindow()->GetRootWindow()); 1815 1816 // Put the second browser into immersive fullscreen. 1817 BrowserView* browser_view2 = BrowserView::GetBrowserViewForBrowser(browser2); 1818 ImmersiveModeController* immersive_controller2 = 1819 browser_view2->immersive_mode_controller(); 1820 immersive_controller2->SetupForTest(); 1821 chrome::ToggleFullscreenMode(browser2); 1822 ASSERT_TRUE(immersive_controller2->IsEnabled()); 1823 ASSERT_FALSE(immersive_controller2->IsRevealed()); 1824 ASSERT_TRUE(tab_strip2->IsImmersiveStyle()); 1825 1826 // Move to the first tab and drag it enough so that it detaches, but not 1827 // enough that it attaches to browser2. 1828 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 1829 ASSERT_TRUE(PressInput(tab_0_center)); 1830 ASSERT_TRUE(DragInputToNotifyWhenDone( 1831 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip), 1832 base::Bind(&DragTabToWindowInSeparateDisplayStep2, 1833 this, tab_strip, tab_strip2))); 1834 QuitWhenNotDragging(); 1835 1836 // Should now be attached to tab_strip2. 1837 ASSERT_TRUE(tab_strip2->IsDragSessionActive()); 1838 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 1839 ASSERT_TRUE(TabDragController::IsActive()); 1840 1841 // browser2's top chrome should be revealed and the tab strip should be 1842 // at normal height while user is tragging tabs_strip2's tabs. 1843 ASSERT_TRUE(immersive_controller2->IsRevealed()); 1844 ASSERT_FALSE(tab_strip2->IsImmersiveStyle()); 1845 1846 // Release the mouse, stopping the drag session. 1847 ASSERT_TRUE(ReleaseInput()); 1848 ASSERT_FALSE(tab_strip2->IsDragSessionActive()); 1849 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 1850 ASSERT_FALSE(TabDragController::IsActive()); 1851 EXPECT_EQ("0 100", IDString(browser2->tab_strip_model())); 1852 EXPECT_EQ("1", IDString(browser()->tab_strip_model())); 1853 1854 // Move the mouse off of browser2's top chrome. 1855 aura::Window* primary_root = roots[0]; 1856 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync( 1857 primary_root->GetBoundsInScreen().CenterPoint())); 1858 1859 // The first browser window should not be in immersive fullscreen. 1860 // browser2 should still be in immersive fullscreen, but the top chrome should 1861 // no longer be revealed. 1862 BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser()); 1863 EXPECT_FALSE(browser_view->immersive_mode_controller()->IsEnabled()); 1864 1865 EXPECT_TRUE(immersive_controller2->IsEnabled()); 1866 EXPECT_FALSE(immersive_controller2->IsRevealed()); 1867 EXPECT_TRUE(tab_strip2->IsImmersiveStyle()); 1868} 1869#endif // OS_CHROMEOS 1870 1871// Subclass of DetachToBrowserTabDragControllerTest that 1872// creates multiple displays with different device scale factors. 1873class DifferentDeviceScaleFactorDisplayTabDragControllerTest 1874 : public DetachToBrowserTabDragControllerTest { 1875 public: 1876 DifferentDeviceScaleFactorDisplayTabDragControllerTest() {} 1877 virtual ~DifferentDeviceScaleFactorDisplayTabDragControllerTest() {} 1878 1879 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 1880 DetachToBrowserTabDragControllerTest::SetUpCommandLine(command_line); 1881 command_line->AppendSwitchASCII("ash-host-window-bounds", 1882 "400x400,0+400-800x800*2"); 1883 } 1884 1885 float GetCursorDeviceScaleFactor() const { 1886 ash::test::CursorManagerTestApi cursor_test_api( 1887 ash::Shell::GetInstance()->cursor_manager()); 1888 return cursor_test_api.GetDisplay().device_scale_factor(); 1889 } 1890 1891 private: 1892 DISALLOW_COPY_AND_ASSIGN( 1893 DifferentDeviceScaleFactorDisplayTabDragControllerTest); 1894}; 1895 1896namespace { 1897 1898// The points where a tab is dragged in CursorDeviceScaleFactorStep. 1899const struct DragPoint { 1900 int x; 1901 int y; 1902} kDragPoints[] = { 1903 {300, 200}, 1904 {399, 200}, 1905 {500, 200}, 1906 {400, 200}, 1907 {300, 200}, 1908}; 1909 1910// The expected device scale factors before the cursor is moved to the 1911// corresponding kDragPoints in CursorDeviceScaleFactorStep. 1912const float kDeviceScaleFactorExpectations[] = { 1913 1.0f, 1914 1.0f, 1915 2.0f, 1916 2.0f, 1917 1.0f, 1918}; 1919 1920COMPILE_ASSERT( 1921 arraysize(kDragPoints) == arraysize(kDeviceScaleFactorExpectations), 1922 kDragPoints_and_kDeviceScaleFactorExpectations_must_have_same_size); 1923 1924// Drags tab to |kDragPoints[index]|, then calls the next step function. 1925void CursorDeviceScaleFactorStep( 1926 DifferentDeviceScaleFactorDisplayTabDragControllerTest* test, 1927 TabStrip* not_attached_tab_strip, 1928 size_t index) { 1929 ASSERT_FALSE(not_attached_tab_strip->IsDragSessionActive()); 1930 ASSERT_TRUE(TabDragController::IsActive()); 1931 1932 if (index < arraysize(kDragPoints)) { 1933 EXPECT_EQ(kDeviceScaleFactorExpectations[index], 1934 test->GetCursorDeviceScaleFactor()); 1935 const DragPoint p = kDragPoints[index]; 1936 ASSERT_TRUE(test->DragInputToNotifyWhenDone( 1937 p.x, p.y, base::Bind(&CursorDeviceScaleFactorStep, 1938 test, not_attached_tab_strip, index + 1))); 1939 } else { 1940 // Finishes a serise of CursorDeviceScaleFactorStep calls and ends drag. 1941 EXPECT_EQ(1.0f, test->GetCursorDeviceScaleFactor()); 1942 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( 1943 ui_controls::LEFT, ui_controls::UP)); 1944 } 1945} 1946 1947} // namespace 1948 1949#if defined(OS_CHROMEOS) 1950// TODO(sky,sad): Disabled as it fails due to resize locks with a real 1951// compositor. crbug.com/331924 1952#define MAYBE_CursorDeviceScaleFactor DISABLED_CursorDeviceScaleFactor 1953#else 1954#define MAYBE_CursorDeviceScaleFactor CursorDeviceScaleFactor 1955#endif 1956// Verifies cursor's device scale factor is updated when a tab is moved across 1957// displays with different device scale factors (http://crbug.com/154183). 1958IN_PROC_BROWSER_TEST_P(DifferentDeviceScaleFactorDisplayTabDragControllerTest, 1959 MAYBE_CursorDeviceScaleFactor) { 1960 // Add another tab. 1961 AddTabAndResetBrowser(browser()); 1962 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 1963 1964 // Move the second browser to the second display. 1965 aura::Window::Windows roots = ash::Shell::GetAllRootWindows(); 1966 ASSERT_EQ(2u, roots.size()); 1967 1968 // Move to the first tab and drag it enough so that it detaches. 1969 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 1970 ASSERT_TRUE(PressInput(tab_0_center)); 1971 ASSERT_TRUE(DragInputToNotifyWhenDone( 1972 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip), 1973 base::Bind(&CursorDeviceScaleFactorStep, 1974 this, tab_strip, 0))); 1975 QuitWhenNotDragging(); 1976} 1977 1978namespace { 1979 1980class DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest 1981 : public TabDragControllerTest { 1982 public: 1983 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest() {} 1984 1985 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 1986 TabDragControllerTest::SetUpCommandLine(command_line); 1987 command_line->AppendSwitchASCII("ash-host-window-bounds", 1988 "0+0-250x250,251+0-250x250"); 1989 } 1990 1991 bool Press(const gfx::Point& position) { 1992 return ui_test_utils::SendMouseMoveSync(position) && 1993 ui_test_utils::SendMouseEventsSync(ui_controls::LEFT, 1994 ui_controls::DOWN); 1995 } 1996 1997 bool DragTabAndExecuteTaskWhenDone(const gfx::Point& position, 1998 const base::Closure& task) { 1999 return ui_controls::SendMouseMoveNotifyWhenDone( 2000 position.x(), position.y(), task); 2001 } 2002 2003 void QuitWhenNotDragging() { 2004 test::QuitWhenNotDraggingImpl(); 2005 base::MessageLoop::current()->Run(); 2006 } 2007 2008 private: 2009 DISALLOW_COPY_AND_ASSIGN( 2010 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest); 2011}; 2012 2013// Invoked from the nested message loop. 2014void CancelDragTabToWindowInSeparateDisplayStep3( 2015 TabStrip* tab_strip, 2016 const BrowserList* browser_list) { 2017 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 2018 ASSERT_TRUE(TabDragController::IsActive()); 2019 ASSERT_EQ(2u, browser_list->size()); 2020 2021 // Switching display mode should cancel the drag operation. 2022 ash::internal::DisplayManager* display_manager = 2023 ash::Shell::GetInstance()->display_manager(); 2024 display_manager->AddRemoveDisplay(); 2025} 2026 2027// Invoked from the nested message loop. 2028void CancelDragTabToWindowInSeparateDisplayStep2( 2029 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest* test, 2030 TabStrip* tab_strip, 2031 aura::Window* current_root, 2032 gfx::Point final_destination, 2033 const BrowserList* browser_list) { 2034 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 2035 ASSERT_TRUE(TabDragController::IsActive()); 2036 ASSERT_EQ(2u, browser_list->size()); 2037 2038 Browser* new_browser = browser_list->get(1); 2039 EXPECT_EQ(current_root, 2040 new_browser->window()->GetNativeWindow()->GetRootWindow()); 2041 2042 ASSERT_TRUE(test->DragTabAndExecuteTaskWhenDone( 2043 final_destination, 2044 base::Bind(&CancelDragTabToWindowInSeparateDisplayStep3, 2045 tab_strip, browser_list))); 2046} 2047 2048} // namespace 2049 2050#if defined(OS_CHROMEOS) 2051// TODO(sky,sad): Disabled as it fails due to resize locks with a real 2052// compositor. crbug.com/331924 2053#define MAYBE_CancelDragTabToWindowIn2ndDisplay \ 2054 DISABLED_CancelDragTabToWindowIn2ndDisplay 2055#else 2056#define MAYBE_CancelDragTabToWindowIn2ndDisplay \ 2057 CancelDragTabToWindowIn2ndDisplay 2058#endif 2059// Drags from browser to a second display and releases input. 2060IN_PROC_BROWSER_TEST_F( 2061 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest, 2062 MAYBE_CancelDragTabToWindowIn2ndDisplay) { 2063 // Add another tab. 2064 AddTabAndResetBrowser(browser()); 2065 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 2066 2067 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model())); 2068 2069 // Move the second browser to the second display. 2070 aura::Window::Windows roots = ash::Shell::GetAllRootWindows(); 2071 ASSERT_EQ(2u, roots.size()); 2072 gfx::Point final_destination = 2073 gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow( 2074 roots[1]).work_area().CenterPoint(); 2075 2076 // Move to the first tab and drag it enough so that it detaches, but not 2077 // enough to move to another display. 2078 gfx::Point tab_0_dst(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 2079 ASSERT_TRUE(Press(tab_0_dst)); 2080 tab_0_dst.Offset(0, GetDetachY(tab_strip)); 2081 ASSERT_TRUE(DragTabAndExecuteTaskWhenDone( 2082 tab_0_dst, base::Bind(&CancelDragTabToWindowInSeparateDisplayStep2, 2083 this, tab_strip, roots[0], final_destination, 2084 native_browser_list))); 2085 QuitWhenNotDragging(); 2086 2087 ASSERT_EQ(1u, native_browser_list->size()); 2088 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 2089 ASSERT_FALSE(TabDragController::IsActive()); 2090 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model())); 2091 2092 // Release the mouse 2093 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( 2094 ui_controls::LEFT, ui_controls::UP)); 2095} 2096 2097#if defined(OS_CHROMEOS) 2098// TODO(sky,sad): Disabled as it fails due to resize locks with a real 2099// compositor. crbug.com/331924 2100#define MAYBE_CancelDragTabToWindowIn1stDisplay \ 2101 DISABLED_CancelDragTabToWindowIn1stDisplay 2102#else 2103#define MAYBE_CancelDragTabToWindowIn1stDisplay \ 2104 CancelDragTabToWindowIn1stDisplay 2105#endif 2106// Drags from browser from a second display to primary and releases input. 2107IN_PROC_BROWSER_TEST_F( 2108 DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest, 2109 MAYBE_CancelDragTabToWindowIn1stDisplay) { 2110 aura::Window::Windows roots = ash::Shell::GetAllRootWindows(); 2111 ASSERT_EQ(2u, roots.size()); 2112 2113 // Add another tab. 2114 AddTabAndResetBrowser(browser()); 2115 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 2116 2117 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model())); 2118 EXPECT_EQ(roots[0], browser()->window()->GetNativeWindow()->GetRootWindow()); 2119 2120 gfx::Rect work_area = gfx::Screen::GetNativeScreen()-> 2121 GetDisplayNearestWindow(roots[1]).work_area(); 2122 browser()->window()->SetBounds(work_area); 2123 EXPECT_EQ(roots[1], browser()->window()->GetNativeWindow()->GetRootWindow()); 2124 2125 // Move the second browser to the display. 2126 gfx::Point final_destination = 2127 gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow( 2128 roots[0]).work_area().CenterPoint(); 2129 2130 // Move to the first tab and drag it enough so that it detaches, but not 2131 // enough to move to another display. 2132 gfx::Point tab_0_dst(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 2133 ASSERT_TRUE(Press(tab_0_dst)); 2134 tab_0_dst.Offset(0, GetDetachY(tab_strip)); 2135 ASSERT_TRUE(DragTabAndExecuteTaskWhenDone( 2136 tab_0_dst, base::Bind(&CancelDragTabToWindowInSeparateDisplayStep2, 2137 this, tab_strip, roots[1], final_destination, 2138 native_browser_list))); 2139 QuitWhenNotDragging(); 2140 2141 ASSERT_EQ(1u, native_browser_list->size()); 2142 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 2143 ASSERT_FALSE(TabDragController::IsActive()); 2144 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model())); 2145 2146 // Release the mouse 2147 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( 2148 ui_controls::LEFT, ui_controls::UP)); 2149} 2150 2151namespace { 2152 2153void PressSecondFingerWhileDetachedStep2( 2154 DetachToBrowserTabDragControllerTest* test) { 2155 ASSERT_TRUE(TabDragController::IsActive()); 2156 ASSERT_EQ(2u, test->native_browser_list->size()); 2157 Browser* new_browser = test->native_browser_list->get(1); 2158 ASSERT_TRUE(new_browser->window()->IsActive()); 2159 2160 ASSERT_TRUE(test->PressInput2()); 2161} 2162 2163} // namespace 2164 2165#if defined(OS_CHROMEOS) 2166// TODO(sky,sad): Disabled as it fails due to resize locks with a real 2167// compositor. crbug.com/331924 2168#define MAYBE_PressSecondFingerWhileDetached DISABLED_PressSecondFingerWhileDetached 2169#else 2170#define MAYBE_PressSecondFingerWhileDetached PressSecondFingerWhileDetached 2171#endif 2172// Detaches a tab and while detached presses a second finger. 2173IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestTouch, 2174 MAYBE_PressSecondFingerWhileDetached) { 2175 gfx::Rect bounds(browser()->window()->GetBounds()); 2176 // Add another tab. 2177 AddTabAndResetBrowser(browser()); 2178 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 2179 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model())); 2180 2181 // Move to the first tab and drag it enough so that it detaches. 2182 gfx::Point tab_0_center( 2183 GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 2184 ASSERT_TRUE(PressInput(tab_0_center)); 2185 ASSERT_TRUE(DragInputToDelayedNotifyWhenDone( 2186 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip), 2187 base::Bind(&PressSecondFingerWhileDetachedStep2, this), 2188 base::TimeDelta::FromMilliseconds(60))); 2189 QuitWhenNotDragging(); 2190 2191 // The drag should have been reverted. 2192 ASSERT_EQ(1u, native_browser_list->size()); 2193 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 2194 ASSERT_FALSE(TabDragController::IsActive()); 2195 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model())); 2196 2197 ASSERT_TRUE(ReleaseInput()); 2198 ASSERT_TRUE(ReleaseInput2()); 2199} 2200 2201// Subclass of DetachToBrowserTabDragControllerTest that runs tests with 2202// docked windows enabled and disabled. 2203class DetachToDockedTabDragControllerTest 2204 : public DetachToBrowserTabDragControllerTest { 2205 public: 2206 DetachToDockedTabDragControllerTest() {} 2207 virtual ~DetachToDockedTabDragControllerTest() {} 2208 2209 private: 2210 DISALLOW_COPY_AND_ASSIGN(DetachToDockedTabDragControllerTest); 2211}; 2212 2213namespace { 2214 2215void DetachToDockedWindowNextStep( 2216 DetachToDockedTabDragControllerTest* test, 2217 const gfx::Point& target_point, 2218 int iteration) { 2219 ASSERT_EQ(2u, test->native_browser_list->size()); 2220 Browser* new_browser = test->native_browser_list->get(1); 2221 ASSERT_TRUE(new_browser->window()->IsActive()); 2222 2223 if (!iteration) { 2224 ASSERT_TRUE(test->ReleaseInput()); 2225 return; 2226 } 2227 ASSERT_TRUE(test->DragInputToNotifyWhenDone( 2228 target_point.x(), target_point.y(), 2229 base::Bind(&DetachToDockedWindowNextStep, 2230 test, 2231 gfx::Point(target_point.x(), 1 + target_point.y()), 2232 iteration - 1))); 2233} 2234 2235} // namespace 2236 2237#if defined(OS_CHROMEOS) 2238// TODO(sky,sad): Disabled as it fails due to resize locks with a real 2239// compositor. crbug.com/331924 2240#define MAYBE_DetachToDockedWindowFromMaximizedWindow \ 2241 DISABLED_DetachToDockedWindowFromMaximizedWindow 2242#else 2243#define MAYBE_DetachToDockedWindowFromMaximizedWindow \ 2244 DetachToDockedWindowFromMaximizedWindow 2245#endif 2246// Drags from browser to separate window, docks that window and releases mouse. 2247IN_PROC_BROWSER_TEST_P(DetachToDockedTabDragControllerTest, 2248 MAYBE_DetachToDockedWindowFromMaximizedWindow) { 2249 // TODO(sky,sad): Disabled as it fails due to resize locks with a real 2250 // compositor. crbug.com/331924 2251 if (docked_windows_enabled()) { 2252 VLOG(1) << "Test is DISABLED for docked windows."; 2253 return; 2254 } 2255 2256 // Maximize the initial browser window. 2257 browser()->window()->Maximize(); 2258 ASSERT_TRUE(browser()->window()->IsMaximized()); 2259 2260 // Add another tab. 2261 AddTabAndResetBrowser(browser()); 2262 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 2263 2264 // Move to the first tab and drag it enough so that it detaches. 2265 gfx::Point tab_0_center( 2266 GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 2267 ASSERT_TRUE(PressInput(tab_0_center)); 2268 2269 // The following matches kMovesBeforeAdjust in snap_sizer.cc 2270 const int kNumIterations = 25 * 5 + 10; 2271 ASSERT_TRUE(DragInputToNotifyWhenDone( 2272 tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip), 2273 base::Bind(&DetachToDockedWindowNextStep, this, 2274 gfx::Point(0, tab_0_center.y() + GetDetachY(tab_strip)), 2275 kNumIterations))); 2276 // Continue dragging enough times to go through snapping sequence and dock 2277 // the window. 2278 QuitWhenNotDragging(); 2279 // Should no longer be dragging. 2280 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 2281 ASSERT_FALSE(TabDragController::IsActive()); 2282 2283 // There should now be another browser. 2284 ASSERT_EQ(2u, native_browser_list->size()); 2285 Browser* new_browser = native_browser_list->get(1); 2286 ASSERT_TRUE(new_browser->window()->IsActive()); 2287 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser); 2288 ASSERT_FALSE(tab_strip2->IsDragSessionActive()); 2289 2290 EXPECT_EQ("0", IDString(new_browser->tab_strip_model())); 2291 EXPECT_EQ("1", IDString(browser()->tab_strip_model())); 2292 2293 // The bounds of the initial window should not have changed. 2294 EXPECT_TRUE(browser()->window()->IsMaximized()); 2295 2296 EXPECT_FALSE(GetIsDragged(browser())); 2297 EXPECT_FALSE(GetIsDragged(new_browser)); 2298 // After this both windows should still be manageable. 2299 EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow())); 2300 EXPECT_TRUE(IsWindowPositionManaged( 2301 new_browser->window()->GetNativeWindow())); 2302 2303 ash::wm::WindowState* window_state = 2304 ash::wm::GetWindowState(new_browser->window()->GetNativeWindow()); 2305 // The new window should not be maximized because it gets docked or snapped. 2306 EXPECT_FALSE(new_browser->window()->IsMaximized()); 2307 if (docked_windows_enabled()) { 2308 // The new window should be docked and not snapped if docking is allowed. 2309 EXPECT_TRUE(window_state->IsDocked()); 2310 EXPECT_FALSE(window_state->IsSnapped()); 2311 } else { 2312 // The new window should be snapped and not docked if docking is disabled. 2313 EXPECT_FALSE(window_state->IsDocked()); 2314 EXPECT_TRUE(window_state->IsSnapped()); 2315 } 2316} 2317 2318 2319#endif 2320 2321#if defined(USE_ASH) && !defined(OS_WIN) // TODO(win_ash) 2322INSTANTIATE_TEST_CASE_P(TabDragging, 2323 DetachToBrowserInSeparateDisplayTabDragControllerTest, 2324 ::testing::Values("mouse", "touch")); 2325INSTANTIATE_TEST_CASE_P(TabDragging, 2326 DifferentDeviceScaleFactorDisplayTabDragControllerTest, 2327 ::testing::Values("mouse")); 2328INSTANTIATE_TEST_CASE_P(TabDragging, 2329 DetachToBrowserTabDragControllerTest, 2330 ::testing::Values("mouse", "touch")); 2331INSTANTIATE_TEST_CASE_P(TabDragging, 2332 DetachToDockedTabDragControllerTest, 2333 ::testing::Values("mouse", "mouse docked")); 2334INSTANTIATE_TEST_CASE_P(TabDragging, 2335 DetachToBrowserTabDragControllerTestTouch, 2336 ::testing::Values("touch", "touch docked")); 2337#else 2338INSTANTIATE_TEST_CASE_P(TabDragging, 2339 DetachToBrowserTabDragControllerTest, 2340 ::testing::Values("mouse")); 2341#endif 2342