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