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