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