#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_buffers
#endif
#include "chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.h"
#include <stddef.h>
#include <algorithm>
#include <limits>
#include <memory>
#include <optional>
#include <set>
#include <utility>
#include "base/command_line.h"
#include "base/dcheck_is_on.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/location.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/bind.h"
#include "base/test/run_until.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/tabs/features.h"
#include "chrome/browser/ui/tabs/tab_group.h"
#include "chrome/browser/ui/tabs/tab_group_model.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
#include "chrome/browser/ui/tabs/tab_style.h"
#include "chrome/browser/ui/ui_features.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/frame/native_browser_frame_factory.h"
#include "chrome/browser/ui/views/frame/tab_strip_region_view.h"
#include "chrome/browser/ui/views/tabs/tab.h"
#include "chrome/browser/ui/views/tabs/tab_drag_controller.h"
#include "chrome/browser/ui/views/tabs/tab_strip.h"
#include "chrome/browser/ui/views/tabs/window_finder.h"
#include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
#include "chrome/browser/web_applications/test/os_integration_test_override_impl.h"
#include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/browser/web_applications/web_app_registrar.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/interactive_test_utils.h"
#include "chrome/test/base/ui_test_utils.h"
#include "chromeos/ui/base/window_properties.h"
#include "components/constrained_window/constrained_window_views.h"
#include "components/tab_groups/tab_group_color.h"
#include "components/tab_groups/tab_group_id.h"
#include "components/tab_groups/tab_group_visual_data.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "third_party/blink/public/common/features.h"
#include "ui/aura/env.h"
#include "ui/base/mojom/ui_base_types.mojom-shared.h"
#include "ui/base/test/ui_controls.h"
#include "ui/compositor/layer.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/gfx/animation/animation_test_api.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/controls/native/native_view_host.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
#include "ui/views/window/dialog_delegate.h"
#if defined(USE_AURA)
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura/test/test_windows.h"
#include "ui/aura/window_targeter.h"
#endif
#if defined(USE_AURA) && !BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/ui/views/frame/desktop_browser_frame_aura.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
#endif
#if BUILDFLAG(IS_CHROMEOS)
#include "base/test/simple_test_tick_clock.h"
#include "ui/events/base_event_utils.h"
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/public/cpp/split_view_test_api.h"
#include "ash/public/cpp/test/shell_test_api.h"
#include "ash/public/cpp/window_properties.h"
#include "ash/shell.h"
#include "ash/wm/window_state.h"
#include "chrome/browser/ash/system_web_apps/test_support/test_system_web_app_installation.h"
#include "chrome/browser/ui/views/frame/browser_view_layout.h"
#include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
#include "chrome/browser/ui/views/frame/immersive_mode_controller_chromeos.h"
#include "chromeos/ui/frame/immersive/immersive_fullscreen_controller_test_api.h"
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/client/cursor_shape_client.h"
#include "ui/aura/client/screen_position_client.h"
#include "ui/aura/window_event_dispatcher.h"
#include "ui/base/cursor/cursor.h"
#include "ui/display/manager/display_manager.h"
#include "ui/display/test/display_manager_test_api.h"
#include "ui/events/gesture_detection/gesture_configuration.h"
#endif
#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chrome/browser/ui/views/frame/desktop_browser_frame_lacros.h"
#include "chromeos/crosapi/mojom/test_controller.mojom-test-utils.h"
#include "chromeos/lacros/lacros_service.h"
#include "ui/aura/window_tree_host_platform.h"
#include "ui/platform_window/extensions/wayland_extension.h"
#define DESKTOP_BROWSER_FRAME_AURA …
#elif BUILDFLAG(IS_LINUX)
#include "chrome/browser/ui/views/frame/desktop_browser_frame_aura_linux.h"
#include "ui/ozone/public/ozone_platform.h"
#define DESKTOP_BROWSER_FRAME_AURA …
#else
#define DESKTOP_BROWSER_FRAME_AURA …
#endif
#if BUILDFLAG(IS_WIN)
#include "ui/base/ui_base_features.h"
#endif
WebContents;
Display;
GetDisplays;
namespace test {
namespace {
const char kTabDragControllerInteractiveUITestUserDataKey[] = …;
class TabDragControllerInteractiveUITestUserData
: public base::SupportsUserData::Data { … };
#if BUILDFLAG(IS_CHROMEOS_ASH)
aura::Window* GetWindowForTabStrip(TabStrip* tab_strip) {
return tab_strip ? tab_strip->GetWidget()->GetNativeWindow() : nullptr;
}
#endif
gfx::Point GetLeftCenterInScreenCoordinates(const views::View* view) { … }
gfx::Point GetRightCenterInScreenCoordinates(const views::View* view) { … }
}
class QuitDraggingObserver { … };
void SetID(WebContents* web_contents, int id) { … }
void ResetIDs(TabStripModel* model, int start) { … }
std::string IDString(TabStripModel* model) { … }
TabStrip* GetTabStripForBrowser(Browser* browser) { … }
TabDragController* GetTabDragController(TabStrip* tab_strip) { … }
void ResizeUsingMouseEmulation(Browser* browser,
const gfx::Rect& target_bounds) { … }
bool CanUseSetBounds() { … }
}
GetTabDragController;
GetTabStripForBrowser;
IDString;
ResetIDs;
SetID;
GetCenterInScreenCoordinates;
TabDragControllerTest::TabDragControllerTest()
: … { … }
TabDragControllerTest::~TabDragControllerTest() = default;
void TabDragControllerTest::StopAnimating(TabStrip* tab_strip) { … }
void TabDragControllerTest::AddTabsAndResetBrowser(Browser* browser,
int additional_tabs,
const GURL& url) { … }
Browser* TabDragControllerTest::CreateAnotherBrowserAndResize() { … }
void TabDragControllerTest::SetWindowFinderForTabStrip(
TabStrip* tab_strip,
std::unique_ptr<WindowFinder> window_finder) { … }
void TabDragControllerTest::HandleGestureEvent(TabStrip* tab_strip,
ui::GestureEvent* event) { … }
bool TabDragControllerTest::HasDragStarted(TabStrip* tab_strip) const { … }
void TabDragControllerTest::SetUp() { … }
namespace {
enum InputSource { … };
int GetDetachY(TabStrip* tab_strip) { … }
bool GetIsDragged(Browser* browser) { … }
}
#if !BUILDFLAG(IS_CHROMEOS_ASH) && defined(USE_AURA)
class TestDesktopBrowserFrameAura : public DESKTOP_BROWSER_FRAME_AURA { … };
class TestNativeBrowserFrameFactory : public NativeBrowserFrameFactory { … };
class TabDragCaptureLostTest : public TabDragControllerTest { … };
IN_PROC_BROWSER_TEST_F(TabDragCaptureLostTest, ReleaseCaptureOnDrag) { … }
#endif
IN_PROC_BROWSER_TEST_F(TabDragControllerTest, GestureEndShouldEndDragTest) { … }
class DetachToBrowserTabDragControllerTest
: public TabDragControllerTest,
public ::testing::WithParamInterface<
#if !BUILDFLAG(IS_CHROMEOS)
testing::tuple<bool, bool, const char*, bool>> { … };
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DragRightToUngroupTab) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DragLeftToUngroupTab) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DragTabWithinGroupDoesNotModifyGroup) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DragOnlyTabInGroupRemovesGroup) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DragSingleTabLeftIntoGroup) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DragSingleTabRightIntoGroup) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DragSingleTabRightOfRightmostGroup) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DragMultipleTabsRightIntoGroup) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DragMultipleTabsLeftIntoGroup) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DragUngroupedTabGroupedTabOutsideGroup) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
RevertDragSingleTabIntoGroup) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
RevertDragSingleTabGroupIntoGroup) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DragGroupHeaderDragsGroup) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DragGroupHeaderRightAvoidsOtherGroups) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DragGroupHeaderLeftAvoidsOtherGroups) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DragPinnedTabDoesNotGroup) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
KeyPressShouldEndDragTest) { … }
#if BUILDFLAG(IS_CHROMEOS)
#define MAYBE_StartDragWhileEndingPreviousDragDoesNothingTest …
#else
#define MAYBE_StartDragWhileEndingPreviousDragDoesNothingTest …
#endif
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
MAYBE_StartDragWhileEndingPreviousDragDoesNothingTest) { … }
#if defined(USE_AURA)
bool SubtreeShouldBeExplored(aura::Window* window,
const gfx::Point& local_point) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DragWithMaskedWindows) { … }
#endif
namespace {
void DragToSeparateWindowStep2(DetachToBrowserTabDragControllerTest* test,
TabStrip* not_attached_tab_strip,
TabStrip* target_tab_strip) { … }
}
#if (BUILDFLAG(IS_MAC) && defined(ARCH_CPU_ARM64)) || BUILDFLAG(IS_LINUX)
#define MAYBE_DragToSeparateWindow …
#else
#define MAYBE_DragToSeparateWindow …
#endif
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
MAYBE_DragToSeparateWindow) { … }
#if (BUILDFLAG(IS_MAC) && defined(ARCH_CPU_ARM64)) || BUILDFLAG(IS_LINUX) || \
BUILDFLAG(IS_CHROMEOS)
#define MAYBE_DragToSeparateWindowDuringDragEnd …
#else
#define MAYBE_DragToSeparateWindowDuringDragEnd …
#endif
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
MAYBE_DragToSeparateWindowDuringDragEnd) { … }
#if BUILDFLAG(IS_WIN)
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DragToOccludedWindow) {
TabStrip* tab_strip = GetTabStripForBrowser(browser());
AddTabsAndResetBrowser(browser(), 1);
Browser* browser2 = CreateAnotherBrowserAndResize();
TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
browser2->window()
->GetNativeWindow()
->GetHost()
->SetNativeWindowOcclusionState(aura::Window::OcclusionState::OCCLUDED,
{});
ASSERT_TRUE(PressInput(GetCenterInScreenCoordinates(tab_strip->tab_at(1))));
ASSERT_TRUE(
DragInputToAsync(GetCenterInScreenCoordinates(tab_strip2->tab_at(0))));
ASSERT_TRUE(ReleaseInput());
EXPECT_EQ(3u, browser_list()->size());
}
#endif
namespace {
class CaptureLoseWindowFinder : public WindowFinder { … };
}
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
CaptureLostDuringDrag) { … }
namespace {
#if BUILDFLAG(IS_CHROMEOS_ASH)
bool IsWindowPositionManaged(aura::Window* window) {
return window->GetProperty(ash::kWindowPositionManagedTypeKey);
}
bool HasUserChangedWindowPositionOrSize(aura::Window* window) {
return ash::WindowState::Get(window)->bounds_changed_by_user();
}
#else
bool IsWindowPositionManaged(gfx::NativeWindow window) { … }
bool HasUserChangedWindowPositionOrSize(gfx::NativeWindow window) { … }
#endif
}
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DetachToOwnWindow) { … }
class TestDialog : public views::DialogDelegateView { … };
#if BUILDFLAG(IS_WIN)
#define MAYBE_DetachToOwnWindowWithDialog …
#else
#define MAYBE_DetachToOwnWindowWithDialog …
#endif
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
MAYBE_DetachToOwnWindowWithDialog) { … }
#if BUILDFLAG(IS_CHROMEOS_ASH)
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DetachToOwnWindowWithNonVisibleOnAllWorkspaceState) {
ASSERT_EQ(1u, browser_list()->size());
Browser* source_browser = browser_list()->get(0);
auto* source_window = source_browser->window()->GetNativeWindow();
source_window->SetProperty(
aura::client::kWindowWorkspaceKey,
aura::client::kWindowWorkspaceVisibleOnAllWorkspaces);
AddTabsAndResetBrowser(browser(), 1);
TabStrip* tab_strip = GetTabStripForBrowser(browser());
int tab_0_width = tab_strip->tab_at(0)->width();
DragTabAndNotify(tab_strip,
base::BindOnce(&DetachToBrowserTabDragControllerTest::
ReleaseInputAfterWindowDetached,
base::Unretained(this), tab_0_width));
ASSERT_FALSE(tab_strip->GetDragContext()->IsDragSessionActive());
ASSERT_FALSE(TabDragController::IsActive());
ASSERT_EQ(2u, browser_list()->size());
Browser* new_browser = browser_list()->get(1);
EXPECT_TRUE(new_browser->window()->IsActive());
TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
EXPECT_FALSE(tab_strip2->GetDragContext()->IsDragSessionActive());
EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
EXPECT_FALSE(GetIsDragged(browser()));
EXPECT_FALSE(GetIsDragged(new_browser));
EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
EXPECT_TRUE(
IsWindowPositionManaged(new_browser->window()->GetNativeWindow()));
auto* new_window = new_browser->window()->GetNativeWindow();
ASSERT_FALSE(new_window->GetProperty(aura::client::kWindowWorkspaceKey) ==
aura::client::kWindowWorkspaceVisibleOnAllWorkspaces);
}
#endif
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DetachFromFullsizeWindow) { … }
#if !BUILDFLAG(IS_MAC)
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DetachToOwnWindowFromMaximizedWindow) { … }
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DetachToOwnWindowWhileInImmersiveFullscreenMode) {
chrome::ToggleFullscreenMode(browser());
ImmersiveModeController* controller =
BrowserView::GetBrowserViewForBrowser(browser())
->immersive_mode_controller();
ASSERT_TRUE(controller->IsEnabled());
std::unique_ptr<ImmersiveRevealedLock> lock =
controller->GetRevealedLock(ImmersiveModeController::ANIMATE_REVEAL_NO);
AddTabsAndResetBrowser(browser(), 1);
TabStrip* tab_strip = GetTabStripForBrowser(browser());
int tab_0_width = tab_strip->tab_at(0)->width();
DragTabAndNotify(tab_strip,
base::BindOnce(&DetachToBrowserTabDragControllerTest::
ReleaseInputAfterWindowDetached,
base::Unretained(this), tab_0_width));
ASSERT_FALSE(tab_strip->GetDragContext()->IsDragSessionActive());
ASSERT_FALSE(TabDragController::IsActive());
ASSERT_EQ(2u, browser_list()->size());
Browser* new_browser = browser_list()->get(1);
ASSERT_TRUE(new_browser->window()->IsActive());
TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
ASSERT_FALSE(tab_strip2->GetDragContext()->IsDragSessionActive());
EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
EXPECT_TRUE(browser()->window()->IsFullscreen());
ASSERT_TRUE(BrowserView::GetBrowserViewForBrowser(browser())
->immersive_mode_controller()
->IsEnabled());
EXPECT_FALSE(GetIsDragged(browser()));
EXPECT_FALSE(GetIsDragged(new_browser));
EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
EXPECT_TRUE(
IsWindowPositionManaged(new_browser->window()->GetNativeWindow()));
ASSERT_TRUE(BrowserView::GetBrowserViewForBrowser(new_browser)
->immersive_mode_controller()
->IsEnabled());
EXPECT_TRUE(new_browser->window()->IsFullscreen());
}
#endif
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DeleteBeforeStartedDragging) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
ReplaceBeforeStartedDragging) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DragDoesntStartFromClick) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DeleteTabWhileAttached) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DeleteTabsWhileDetached) { … }
namespace {
void PressEscapeWhileDetachedStep2(DetachToBrowserTabDragControllerTest* test) { … }
}
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
RevertDragWhileDetached) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, DragInSameWindow) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
TabDragContextOwnsDraggedTabs) { … }
#if BUILDFLAG(IS_LINUX)
#define MAYBE_TabDragContextOwnsClosingDraggedTabs …
#else
#define MAYBE_TabDragContextOwnsClosingDraggedTabs …
#endif
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
MAYBE_TabDragContextOwnsClosingDraggedTabs) { … }
namespace {
void DragAllStep2(DetachToBrowserTabDragControllerTest* test) { … }
}
#if BUILDFLAG(IS_WIN)
#define MAYBE_DragAll …
#else
#define MAYBE_DragAll …
#endif
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, MAYBE_DragAll) { … }
namespace {
void DragAllToSeparateWindowStep2(DetachToBrowserTabDragControllerTest* test,
TabStrip* attached_tab_strip,
TabStrip* target_tab_strip) { … }
}
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX)
#define MAYBE_DragAllToSeparateWindow …
#else
#define MAYBE_DragAllToSeparateWindow …
#endif
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
MAYBE_DragAllToSeparateWindow) { … }
namespace {
void DoubleNestedRunLoopStep2(DetachToBrowserTabDragControllerTest* test,
TabStrip* attached_tab_strip,
TabStrip* target_tab_strip) { … }
}
#if BUILDFLAG(IS_CHROMEOS_LACROS)
#define MAYBE_DragToSeparateWindowAttemptToSpawnDoubleNestedRunLoop …
#else
#define MAYBE_DragToSeparateWindowAttemptToSpawnDoubleNestedRunLoop …
#endif
IN_PROC_BROWSER_TEST_P(
DetachToBrowserTabDragControllerTest,
MAYBE_DragToSeparateWindowAttemptToSpawnDoubleNestedRunLoop) { … }
#if BUILDFLAG(IS_MAC) && defined(ARCH_CPU_ARM64)
#define MAYBE_DragWindowIntoGroup …
#else
#define MAYBE_DragWindowIntoGroup …
#endif
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
MAYBE_DragWindowIntoGroup) { … }
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
#define MAYBE_DragGroupHeaderToSeparateWindow …
#else
#define MAYBE_DragGroupHeaderToSeparateWindow …
#endif
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
MAYBE_DragGroupHeaderToSeparateWindow) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
RevertHeaderDragRight) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
RevertHeaderDragLeft) { … }
namespace {
void PressEscapeWhileDetachedHeaderStep2(
DetachToBrowserTabDragControllerTest* test) { … }
}
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
RevertHeaderDragWhileDetached) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DragTabLeftPastCollapsedGroupHeader) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DragTabRightPastCollapsedGroupHeader) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
RevertCollapsedHeaderDragWhileDetached) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DragCollapsedGroupHeaderExpandsGroup) { … }
#if BUILDFLAG(IS_MAC) || (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
#define MAYBE_DragCollapsedGroupHeaderToSeparateWindow …
#else
#define MAYBE_DragCollapsedGroupHeaderToSeparateWindow …
#endif
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
MAYBE_DragCollapsedGroupHeaderToSeparateWindow) { … }
DetachTabWithUrlControlledByWebApp;
IN_PROC_BROWSER_TEST_P(DetachTabWithUrlControlledByWebApp, TearOffWebApp) { … }
#if !BUILDFLAG(IS_MAC)
class DetachToBrowserTabDragControllerTestWithTabbedWebApp
: public DetachToBrowserTabDragControllerTest { … };
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestWithTabbedWebApp,
HomeTabAddedToEveryWindow) { … }
#if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
#define MAYBE_CantDragHomeTab …
#else
#define MAYBE_CantDragHomeTab …
#endif
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestWithTabbedWebApp,
MAYBE_CantDragHomeTab) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestWithTabbedWebApp,
NoHomeTab) { … }
#endif
class DetachToBrowserTabDragControllerTestWithScrollableTabStripEnabled
: public DetachToBrowserTabDragControllerTest { … };
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) || \
(BUILDFLAG(IS_MAC) && DCHECK_IS_ON())
#define MAYBE_DraggingRightExpandsTabStripSize …
#else
#define MAYBE_DraggingRightExpandsTabStripSize …
#endif
IN_PROC_BROWSER_TEST_P(
DetachToBrowserTabDragControllerTestWithScrollableTabStripEnabled,
MAYBE_DraggingRightExpandsTabStripSize) { … }
namespace {
void DragAllToSeparateWindowAndCancelStep2(
DetachToBrowserTabDragControllerTest* test,
TabStrip* attached_tab_strip,
TabStrip* target_tab_strip) { … }
}
#if BUILDFLAG(IS_MAC)
#define MAYBE_DragAllToSeparateWindowAndCancel …
#else
#define MAYBE_DragAllToSeparateWindowAndCancel …
#endif
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
MAYBE_DragAllToSeparateWindowAndCancel) { … }
#if BUILDFLAG(IS_MAC)
#define MAYBE_DragAllToSeparateWindowWithPinnedTabs …
#else
#define MAYBE_DragAllToSeparateWindowWithPinnedTabs …
#endif
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
MAYBE_DragAllToSeparateWindowWithPinnedTabs) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DISABLED_DragDirectlyToSecondWindow) { … }
#if (BUILDFLAG(IS_MAC) && defined(ARCH_CPU_ARM64)) || BUILDFLAG(IS_LINUX)
#define MAYBE_DragSingleTabToSeparateWindow …
#else
#define MAYBE_DragSingleTabToSeparateWindow …
#endif
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
MAYBE_DragSingleTabToSeparateWindow) { … }
#if !BUILDFLAG(IS_MAC)
namespace {
void CancelOnNewTabWhenDraggingStep2(DetachToBrowserTabDragControllerTest* test,
const Browser* default_browser,
base::OnceClosure quit_closure,
WebContents** contents_out) { … }
}
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
CancelOnNewTabWhenDragging) { … }
#endif
namespace {
TabStrip* GetAttachedTabstrip() { … }
void DragWindowAndVerifyOffset(DetachToBrowserTabDragControllerTest* test,
TabStrip* tab_strip,
int tab_index) { … }
}
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC)
#define MAYBE_OffsetForDraggingTab …
#else
#define MAYBE_OffsetForDraggingTab …
#endif
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
MAYBE_OffsetForDraggingTab) { … }
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DISABLED_OffsetForDraggingDetachedTab) { … }
#if BUILDFLAG(IS_CHROMEOS)
namespace {
void DragInMaximizedWindowStep2(DetachToBrowserTabDragControllerTest* test,
Browser* browser,
TabStrip* tab_strip) {
size_t num_browsers = test->browser_list()->size();
EXPECT_EQ(2u, num_browsers);
Browser* new_browser = test->browser_list()->get(num_browsers - 1);
EXPECT_NE(browser, new_browser);
ui_test_utils::BrowserActivationWaiter activation_waiter(new_browser);
activation_waiter.WaitForActivation();
EXPECT_TRUE(new_browser->window()->IsActive());
TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
EXPECT_TRUE(tab_strip2->GetDragContext()->IsDragSessionActive());
EXPECT_FALSE(tab_strip->GetDragContext()->IsDragSessionActive());
EXPECT_TRUE(tab_strip->GetWidget()->IsVisible());
EXPECT_TRUE(tab_strip2->GetWidget()->IsVisible());
EXPECT_TRUE(test->ReleaseInput());
}
}
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DragInMaximizedWindow) {
{
auto waiter = ui_test_utils::CreateAsyncWidgetRequestWaiter(*browser());
browser()->window()->Maximize();
waiter.Wait();
}
ASSERT_TRUE(browser()->window()->IsMaximized());
AddTabsAndResetBrowser(browser(), 1);
TabStrip* tab_strip = GetTabStripForBrowser(browser());
DragTabAndNotify(tab_strip, base::BindOnce(&DragInMaximizedWindowStep2, this,
browser(), tab_strip));
ASSERT_FALSE(TabDragController::IsActive());
ASSERT_EQ(2u, browser_list()->size());
Browser* new_browser = browser_list()->get(1);
ASSERT_TRUE(new_browser->window()->IsActive());
EXPECT_TRUE(browser()->window()->GetNativeWindow()->IsVisible());
EXPECT_TRUE(new_browser->window()->GetNativeWindow()->IsVisible());
EXPECT_FALSE(GetIsDragged(browser()));
EXPECT_FALSE(GetIsDragged(new_browser));
EXPECT_TRUE(browser()->window()->IsMaximized());
EXPECT_TRUE(new_browser->window()->IsMaximized());
}
#endif
#if BUILDFLAG(IS_CHROMEOS)
namespace {
void NewBrowserWindowStateStep2(DetachToBrowserTabDragControllerTest* test,
TabStrip* tab_strip) {
EXPECT_EQ(3u, test->browser_list()->size());
Browser* new_browser = test->browser_list()->get(2);
aura::Window* window = new_browser->window()->GetNativeWindow();
EXPECT_NE(window->GetProperty(aura::client::kShowStateKey),
ui::SHOW_STATE_MAXIMIZED);
EXPECT_EQ(window->GetProperty(aura::client::kShowStateKey),
ui::SHOW_STATE_DEFAULT);
EXPECT_TRUE(test->ReleaseInput());
}
}
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
NewBrowserWindowState) {
Browser::CreateParams params(browser()->profile(), false);
params.initial_show_state = ui::SHOW_STATE_MAXIMIZED;
Browser* browser = Browser::Create(params);
AddBlankTabAndShow(browser);
TabStrip* tab_strip = GetTabStripForBrowser(browser);
AddTabsAndResetBrowser(browser, 1);
browser->window()->Maximize();
EXPECT_EQ(browser->window()->GetNativeWindow()->GetProperty(
aura::client::kShowStateKey),
ui::SHOW_STATE_MAXIMIZED);
DragTabAndNotify(
tab_strip, base::BindOnce(&NewBrowserWindowStateStep2, this, tab_strip));
}
#endif
#if BUILDFLAG(IS_CHROMEOS)
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
OffsetForDraggingInMaximizedWindow) {
AddTabsAndResetBrowser(browser(), 1);
browser()->window()->SetBounds(browser()->window()->GetBounds() +
gfx::Vector2d(100, 50));
browser()->window()->Maximize();
DragWindowAndVerifyOffset(this, GetTabStripForBrowser(browser()), 0);
ASSERT_FALSE(TabDragController::IsActive());
}
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
namespace {
class DraggedWindowObserver : public aura::WindowObserver {
public:
DraggedWindowObserver(DetachToBrowserTabDragControllerTest* test,
aura::Window* window,
const gfx::Rect& bounds,
const gfx::Point& end_point)
: test_(test), end_bounds_(bounds), end_point_(end_point) {}
DraggedWindowObserver(const DraggedWindowObserver&) = delete;
DraggedWindowObserver& operator=(const DraggedWindowObserver&) = delete;
~DraggedWindowObserver() override {
if (window_)
window_->RemoveObserver(this);
}
void StartObserving(aura::Window* window) {
DCHECK(!window_);
window_ = window;
window_->AddObserver(this);
}
void OnWindowDestroying(aura::Window* window) override {
DCHECK_EQ(window_, window);
window_->RemoveObserver(this);
window_ = nullptr;
}
void OnWindowPropertyChanged(aura::Window* window,
const void* key,
intptr_t old) override {
DCHECK_EQ(window_, window);
if (key == ash::kIsDraggingTabsKey) {
if (!window_->GetProperty(ash::kIsDraggingTabsKey)) {
test_->MoveInputTo(end_point_);
window_->SetBounds(end_bounds_);
}
}
}
private:
raw_ptr<DetachToBrowserTabDragControllerTest> test_;
raw_ptr<aura::Window> window_ = nullptr;
gfx::Rect end_bounds_;
gfx::Point end_point_;
};
void DoNotObserveDraggedWidgetAfterDragEndsStep2(
DetachToBrowserTabDragControllerTest* test,
DraggedWindowObserver* observer,
TabStrip* attached_tab_strip) {
EXPECT_TRUE(attached_tab_strip->GetDragContext()->IsDragSessionActive());
EXPECT_TRUE(TabDragController::IsActive());
observer->StartObserving(attached_tab_strip->GetWidget()->GetNativeWindow());
EXPECT_TRUE(test->ReleaseInput());
}
}
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
DoNotObserveDraggedWidgetAfterDragEnds) {
TabStrip* tab_strip = GetTabStripForBrowser(browser());
Browser* browser2 = CreateAnotherBrowserAndResize();
TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
EXPECT_EQ(2u, browser_list()->size());
std::unique_ptr<DraggedWindowObserver> observer(new DraggedWindowObserver(
this, test::GetWindowForTabStrip(tab_strip),
tab_strip2->GetWidget()->GetNativeWindow()->bounds(),
GetCenterInScreenCoordinates(tab_strip2)));
DragTabAndNotify(tab_strip,
base::BindOnce(&DoNotObserveDraggedWidgetAfterDragEndsStep2,
this, observer.get(), tab_strip));
EXPECT_EQ(2u, browser_list()->size());
ASSERT_FALSE(TabDragController::IsActive());
}
#endif
#if BUILDFLAG(IS_CHROMEOS)
namespace {
bool WebContentsIsFastResized(Browser* browser) {
BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
ContentsWebView* contents_web_view =
static_cast<ContentsWebView*>(browser_view->GetContentsView());
return contents_web_view->holder()->fast_resize();
}
void FastResizeDuringDraggingStep2(DetachToBrowserTabDragControllerTest* test,
TabStrip* not_attached_tab_strip,
TabStrip* target_tab_strip) {
size_t num_browsers = test->browser_list()->size();
EXPECT_EQ(3u, num_browsers);
#if !(BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
Browser* new_browser = test->browser_list()->get(num_browsers - 1);
EXPECT_TRUE(WebContentsIsFastResized(new_browser));
EXPECT_TRUE(WebContentsIsFastResized(test->browser()));
#endif
EXPECT_TRUE(
test->DragInputTo(GetCenterInScreenCoordinates(target_tab_strip)));
EXPECT_TRUE(test->ReleaseInput());
}
}
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
FastResizeDuringDragging) {
TabStrip* tab_strip = GetTabStripForBrowser(browser());
AddTabsAndResetBrowser(browser(), 1);
Browser* browser2 = CreateAnotherBrowserAndResize();
TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
EXPECT_EQ(2u, browser_list()->size());
EXPECT_FALSE(WebContentsIsFastResized(browser()));
EXPECT_FALSE(WebContentsIsFastResized(browser2));
DragTabAndNotify(tab_strip, base::BindOnce(&FastResizeDuringDraggingStep2,
this, tab_strip, tab_strip2));
EXPECT_FALSE(WebContentsIsFastResized(browser()));
EXPECT_FALSE(WebContentsIsFastResized(browser2));
}
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
class DetachToBrowserTabDragControllerTestWithTabbedSystemApp
: public DetachToBrowserTabDragControllerTest {
public:
DetachToBrowserTabDragControllerTestWithTabbedSystemApp()
: test_system_web_app_installation_(
ash::TestSystemWebAppInstallation::SetUpTabbedMultiWindowApp()) {}
webapps::AppId InstallMockApp() {
test_system_web_app_installation_->WaitForAppInstall();
return test_system_web_app_installation_->GetAppId();
}
Browser* LaunchWebAppBrowser(webapps::AppId app_id) {
return web_app::LaunchWebAppBrowser(browser()->profile(), app_id);
}
const GURL& GetAppUrl() {
return test_system_web_app_installation_->GetAppUrl();
}
private:
std::unique_ptr<ash::TestSystemWebAppInstallation>
test_system_web_app_installation_;
};
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestWithTabbedSystemApp,
DragAppToOwnWindow) {
webapps::AppId tabbed_app_id = InstallMockApp();
Browser* app_browser = LaunchWebAppBrowser(tabbed_app_id);
ASSERT_EQ(2u, browser_list()->size());
CloseBrowserSynchronously(browser());
ASSERT_EQ(1u, browser_list()->size());
SelectFirstBrowser();
ASSERT_EQ(app_browser, browser());
EXPECT_EQ(Browser::Type::TYPE_APP, browser_list()->get(0)->type());
AddTabsAndResetBrowser(browser(), 1, GetAppUrl());
TabStrip* tab_strip = GetTabStripForBrowser(browser());
int tab_0_width = tab_strip->tab_at(0)->width();
DragTabAndNotify(tab_strip,
base::BindOnce(&DetachToBrowserTabDragControllerTest::
ReleaseInputAfterWindowDetached,
base::Unretained(this), tab_0_width));
ASSERT_EQ(2u, browser_list()->size());
EXPECT_EQ(Browser::Type::TYPE_APP, browser_list()->get(1)->type());
}
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestWithTabbedSystemApp,
DISABLED_DragAppToAppWindow) {
webapps::AppId tabbed_app_id = InstallMockApp();
Browser* app_browser1 = LaunchWebAppBrowser(tabbed_app_id);
Browser* app_browser2 = LaunchWebAppBrowser(tabbed_app_id);
ASSERT_EQ(3u, browser_list()->size());
ResetIDs(app_browser2->tab_strip_model(), 100);
gfx::Rect work_area =
display::Screen::GetScreen()
->GetDisplayNearestWindow(app_browser1->window()->GetNativeWindow())
.work_area();
const gfx::Size size(work_area.width() / 3, work_area.height() / 2);
gfx::Rect browser_rect(work_area.origin(), size);
app_browser1->window()->SetBounds(browser_rect);
browser_rect.set_x(browser_rect.right());
app_browser2->window()->SetBounds(browser_rect);
CloseBrowserSynchronously(browser());
ASSERT_EQ(2u, browser_list()->size());
SelectFirstBrowser();
ASSERT_EQ(app_browser1, browser());
AddTabsAndResetBrowser(browser(), 1, GetAppUrl());
TabStrip* tab_strip1 = GetTabStripForBrowser(app_browser1);
TabStrip* tab_strip2 = GetTabStripForBrowser(app_browser2);
DragTabAndNotify(tab_strip1, base::BindOnce(&DragToSeparateWindowStep2, this,
tab_strip1, tab_strip2));
ASSERT_TRUE(ReleaseInput());
EXPECT_EQ("100 0", IDString(app_browser2->tab_strip_model()));
EXPECT_EQ("1", IDString(app_browser1->tab_strip_model()));
}
#endif
#if BUILDFLAG(IS_CHROMEOS)
class DetachToBrowserInSeparateDisplayTabDragControllerTest
: public DetachToBrowserTabDragControllerTest {
public:
DetachToBrowserInSeparateDisplayTabDragControllerTest() {}
DetachToBrowserInSeparateDisplayTabDragControllerTest(
const DetachToBrowserInSeparateDisplayTabDragControllerTest&) = delete;
DetachToBrowserInSeparateDisplayTabDragControllerTest& operator=(
const DetachToBrowserInSeparateDisplayTabDragControllerTest&) = delete;
virtual ~DetachToBrowserInSeparateDisplayTabDragControllerTest() {}
void SetUpOnMainThread() override {
DetachToBrowserTabDragControllerTest::SetUpOnMainThread();
const std::string display_specs = "1280x800,1280x800";
#if BUILDFLAG(IS_CHROMEOS_LACROS)
ui_controls::UpdateDisplaySync(display_specs);
#else
display::test::DisplayManagerTestApi(ash::Shell::Get()->display_manager())
.UpdateDisplay(display_specs);
#endif
}
};
namespace {
void DragSingleTabToSeparateWindowInSecondDisplayStep3(
DetachToBrowserTabDragControllerTest* test) {
EXPECT_TRUE(test->ReleaseInput());
}
void DragSingleTabToSeparateWindowInSecondDisplayStep2(
DetachToBrowserTabDragControllerTest* test,
const gfx::Point& target_point) {
EXPECT_TRUE(test->DragInputToNotifyWhenDone(
target_point,
base::BindOnce(&DragSingleTabToSeparateWindowInSecondDisplayStep3,
test)));
}
}
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
DISABLED_DragSingleTabToSeparateWindowInSecondDisplay) {
AddTabsAndResetBrowser(browser(), 1);
TabStrip* tab_strip = GetTabStripForBrowser(browser());
display::Screen* const screen = display::Screen::GetScreen();
display::Display second_display = ui_test_utils::GetSecondaryDisplay(screen);
const gfx::Point start = GetCenterInScreenCoordinates(tab_strip->tab_at(0));
ASSERT_FALSE(second_display.bounds().Contains(start));
const gfx::Point target(second_display.bounds().x() + 1,
start.y() + GetDetachY(tab_strip));
ASSERT_TRUE(second_display.bounds().Contains(target));
ash::Shell::Get()->cursor_manager()->SetDisplay(second_display);
DragTabAndNotify(
tab_strip,
base::BindOnce(&DragSingleTabToSeparateWindowInSecondDisplayStep2, this,
target));
ASSERT_FALSE(tab_strip->GetDragContext()->IsDragSessionActive());
ASSERT_FALSE(TabDragController::IsActive());
ASSERT_EQ(2u, browser_list()->size());
Browser* new_browser = browser_list()->get(1);
ASSERT_TRUE(new_browser->window()->IsActive());
TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
ASSERT_FALSE(tab_strip2->GetDragContext()->IsDragSessionActive());
if (input_source() == INPUT_SOURCE_MOUSE) {
EXPECT_EQ(
ui_test_utils::GetSecondaryDisplay(screen).id(),
screen
->GetDisplayNearestWindow(new_browser->window()->GetNativeWindow())
.id());
}
EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
EXPECT_FALSE(browser()->window()->IsMaximized());
EXPECT_FALSE(new_browser->window()->IsMaximized());
}
#endif
#if BUILDFLAG(IS_CHROMEOS)
namespace {
void DragTabToWindowInSeparateDisplayStep2(
DetachToBrowserTabDragControllerTest* test,
TabStrip* not_attached_tab_strip,
TabStrip* target_tab_strip) {
EXPECT_FALSE(not_attached_tab_strip->GetDragContext()->IsDragSessionActive());
EXPECT_FALSE(target_tab_strip->GetDragContext()->IsDragSessionActive());
EXPECT_TRUE(TabDragController::IsActive());
gfx::Point target_point(
GetCenterInScreenCoordinates(target_tab_strip->tab_at(0)));
target_point.Offset(-20, 0);
EXPECT_TRUE(test->DragInputToAsync(target_point));
}
}
#if BUILDFLAG(IS_CHROMEOS_ASH) && defined(MEMORY_SANITIZER)
#define MAYBE_DragTabToWindowInSeparateDisplay …
#else
#define MAYBE_DragTabToWindowInSeparateDisplay …
#endif
IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
MAYBE_DragTabToWindowInSeparateDisplay) {
AddTabsAndResetBrowser(browser(), 1);
TabStrip* tab_strip = GetTabStripForBrowser(browser());
Browser* browser2 = CreateBrowser(browser()->profile());
TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
ResetIDs(browser2->tab_strip_model(), 100);
display::Screen* screen = display::Screen::GetScreen();
Display second_display = ui_test_utils::GetSecondaryDisplay(screen);
ui_test_utils::SetAndWaitForBounds(*browser2, second_display.work_area());
EXPECT_EQ(
second_display.id(),
screen->GetDisplayNearestWindow(browser2->window()->GetNativeWindow())
.id());
DragTabAndNotify(tab_strip,
base::BindOnce(&DragTabToWindowInSeparateDisplayStep2, this,
tab_strip, tab_strip2));
ASSERT_TRUE(tab_strip2->GetDragContext()->IsDragSessionActive());
ASSERT_FALSE(tab_strip->GetDragContext()->IsDragSessionActive());
ASSERT_TRUE(TabDragController::IsActive());
ASSERT_TRUE(ReleaseInput());
ASSERT_FALSE(tab_strip2->GetDragContext()->IsDragSessionActive());
ASSERT_FALSE(tab_strip->GetDragContext()->IsDragSessionActive());
ASSERT_FALSE(TabDragController::IsActive());
EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
EXPECT_FALSE(browser()->window()->IsMaximized());
EXPECT_FALSE(browser2->window()->IsMaximized());
}
IN_PROC_BROWSER_TEST_P(
DetachToBrowserInSeparateDisplayTabDragControllerTest,
DISABLED_DragBrowserWindowWhenMajorityOfBoundsInSecondDisplay) {
const std::pair<Display, Display> displays =
GetDisplays(display::Screen::GetScreen());
TabStrip* tab_strip = GetTabStripForBrowser(browser());
{
int target_x = displays.first.bounds().right() -
browser()->window()->GetBounds().width() / 2 + 20;
const gfx::Point target_point =
GetCenterInScreenCoordinates(tab_strip->tab_at(0)) +
gfx::Vector2d(target_x - browser()->window()->GetBounds().x(),
GetDetachY(tab_strip));
DragTabAndNotify(
tab_strip,
base::BindOnce(&DragSingleTabToSeparateWindowInSecondDisplayStep2, this,
target_point));
StopAnimating(tab_strip);
}
EXPECT_EQ(displays.first.id(),
browser()->window()->GetNativeWindow()->GetHost()->GetDisplayId());
const gfx::Point tab_0_center =
GetCenterInScreenCoordinates(tab_strip->tab_at(0));
const int offset_x = tab_0_center.x() - browser()->window()->GetBounds().x();
const int detach_y = tab_0_center.y() + GetDetachY(tab_strip);
const int first_display_warp_edge_x = displays.first.bounds().right() - 1;
const gfx::Point warped_point(displays.second.bounds().x() + 1, detach_y);
DragTabAndNotify(
tab_strip, base::BindLambdaForTesting([&]() {
ASSERT_TRUE(DragInputToNotifyWhenDone(
gfx::Point(first_display_warp_edge_x, detach_y),
base::BindOnce(&DragSingleTabToSeparateWindowInSecondDisplayStep2,
this, warped_point)));
}));
ASSERT_FALSE(tab_strip->GetDragContext()->IsDragSessionActive());
ASSERT_FALSE(TabDragController::IsActive());
ASSERT_EQ(1u, browser_list()->size());
ASSERT_EQ(browser(), browser_list()->get(0));
ASSERT_TRUE(browser()->window()->IsActive());
ASSERT_FALSE(tab_strip->GetDragContext()->IsDragSessionActive());
EXPECT_EQ(warped_point.x() - offset_x, browser()->window()->GetBounds().x());
EXPECT_EQ(displays.second.id(),
browser()->window()->GetNativeWindow()->GetHost()->GetDisplayId());
}
#if BUILDFLAG(IS_CHROMEOS) && defined(MEMORY_SANITIZER)
#define MAYBE_DragTabToWindowOnSecondDisplay …
#else
#define MAYBE_DragTabToWindowOnSecondDisplay …
#endif
IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
MAYBE_DragTabToWindowOnSecondDisplay) {
AddTabsAndResetBrowser(browser(), 1);
TabStrip* tab_strip = GetTabStripForBrowser(browser());
Browser* browser2 = CreateBrowser(browser()->profile());
TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
ResetIDs(browser2->tab_strip_model(), 100);
display::Screen* screen = display::Screen::GetScreen();
Display second_display = ui_test_utils::GetSecondaryDisplay(screen);
gfx::Rect work_area = second_display.work_area();
work_area.set_width(work_area.width() / 2);
ui_test_utils::SetAndWaitForBounds(*browser(), work_area);
work_area.set_x(browser()->window()->GetBounds().right());
ASSERT_LT(work_area.x(), second_display.work_area().right());
ui_test_utils::SetAndWaitForBounds(*browser2, work_area);
EXPECT_EQ(
second_display.id(),
screen->GetDisplayNearestWindow(browser()->window()->GetNativeWindow())
.id());
EXPECT_EQ(
second_display.id(),
screen->GetDisplayNearestWindow(browser2->window()->GetNativeWindow())
.id());
ASSERT_LT(GetCenterInScreenCoordinates(tab_strip2->tab_at(0)).x(),
second_display.work_area().right());
DragTabAndNotify(tab_strip,
base::BindOnce(&DragTabToWindowInSeparateDisplayStep2, this,
tab_strip, tab_strip2));
ASSERT_TRUE(tab_strip2->GetDragContext()->IsDragSessionActive());
ASSERT_FALSE(tab_strip->GetDragContext()->IsDragSessionActive());
ASSERT_TRUE(TabDragController::IsActive());
ASSERT_TRUE(ReleaseInput());
ASSERT_FALSE(tab_strip2->GetDragContext()->IsDragSessionActive());
ASSERT_FALSE(tab_strip->GetDragContext()->IsDragSessionActive());
ASSERT_FALSE(TabDragController::IsActive());
EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
EXPECT_FALSE(browser()->window()->IsMaximized());
EXPECT_FALSE(browser2->window()->IsMaximized());
}
#if BUILDFLAG(IS_CHROMEOS) && defined(MEMORY_SANITIZER)
#define MAYBE_DragMaxTabToNonMaxWindowInSeparateDisplay …
#else
#define MAYBE_DragMaxTabToNonMaxWindowInSeparateDisplay …
#endif
IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
MAYBE_DragMaxTabToNonMaxWindowInSeparateDisplay) {
AddTabsAndResetBrowser(browser(), 1);
ASSERT_TRUE(ui_test_utils::MaximizeAndWaitUntilUIUpdateDone(*browser()));
TabStrip* tab_strip = GetTabStripForBrowser(browser());
display::Screen* screen = display::Screen::GetScreen();
ASSERT_EQ(2, screen->GetNumDisplays());
const std::pair<Display, Display> displays = GetDisplays(screen);
gfx::Rect work_area = displays.second.work_area();
work_area.Inset(gfx::Insets::TLBR(20, 20, 60, 20));
Browser::CreateParams params(browser()->profile(), true);
params.initial_show_state = ui::SHOW_STATE_NORMAL;
params.initial_bounds = work_area;
Browser* browser2 = Browser::Create(params);
AddBlankTabAndShow(browser2);
TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
ResetIDs(browser2->tab_strip_model(), 100);
EXPECT_EQ(
displays.second.id(),
screen->GetDisplayNearestWindow(browser2->window()->GetNativeWindow())
.id());
EXPECT_EQ(
displays.first.id(),
screen->GetDisplayNearestWindow(browser()->window()->GetNativeWindow())
.id());
EXPECT_EQ(2, tab_strip->GetTabCount());
EXPECT_EQ(1, tab_strip2->GetTabCount());
DragTabAndNotify(tab_strip,
base::BindOnce(&DragTabToWindowInSeparateDisplayStep2, this,
tab_strip, tab_strip2));
ASSERT_TRUE(tab_strip2->GetDragContext()->IsDragSessionActive());
ASSERT_FALSE(tab_strip->GetDragContext()->IsDragSessionActive());
ASSERT_TRUE(TabDragController::IsActive());
ASSERT_TRUE(ReleaseInput());
EXPECT_EQ(1, tab_strip->GetTabCount());
EXPECT_EQ(2, tab_strip2->GetTabCount());
ASSERT_FALSE(tab_strip2->GetDragContext()->IsDragSessionActive());
ASSERT_FALSE(tab_strip->GetDragContext()->IsDragSessionActive());
ASSERT_FALSE(TabDragController::IsActive());
EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
EXPECT_TRUE(browser()->window()->IsMaximized());
EXPECT_FALSE(browser2->window()->IsMaximized());
}
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
DISABLED_DragTabToImmersiveBrowserOnSeparateDisplay) {
AddTabsAndResetBrowser(browser(), 1);
TabStrip* tab_strip = GetTabStripForBrowser(browser());
Browser* browser2 = CreateBrowser(browser()->profile());
TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
ResetIDs(browser2->tab_strip_model(), 100);
display::Screen* screen = display::Screen::GetScreen();
const std::pair<Display, Display> displays = GetDisplays(screen);
ui_test_utils::SetAndWaitForBounds(*browser2, displays.second.work_area());
EXPECT_EQ(
displays.second.id(),
screen->GetDisplayNearestWindow(browser2->window()->GetNativeWindow())
.id());
BrowserView* browser_view2 = BrowserView::GetBrowserViewForBrowser(browser2);
ImmersiveModeController* immersive_controller2 =
browser_view2->immersive_mode_controller();
chromeos::ImmersiveFullscreenControllerTestApi(
static_cast<ImmersiveModeControllerChromeos*>(immersive_controller2)
->controller())
.SetupForTest();
chrome::ToggleFullscreenMode(browser2);
ASSERT_TRUE(immersive_controller2->IsEnabled());
ASSERT_FALSE(immersive_controller2->IsRevealed());
ASSERT_TRUE(tab_strip2->GetVisible());
DragTabAndNotify(tab_strip,
base::BindOnce(&DragTabToWindowInSeparateDisplayStep2, this,
tab_strip, tab_strip2));
ASSERT_TRUE(tab_strip2->GetDragContext()->IsDragSessionActive());
ASSERT_FALSE(tab_strip->GetDragContext()->IsDragSessionActive());
ASSERT_TRUE(TabDragController::IsActive());
ASSERT_TRUE(immersive_controller2->IsRevealed());
ASSERT_TRUE(tab_strip2->GetVisible());
ASSERT_TRUE(ReleaseInput());
ASSERT_FALSE(tab_strip2->GetDragContext()->IsDragSessionActive());
ASSERT_FALSE(tab_strip->GetDragContext()->IsDragSessionActive());
ASSERT_FALSE(TabDragController::IsActive());
EXPECT_EQ("0 100", IDString(browser2->tab_strip_model()));
EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
ASSERT_TRUE(
ui_test_utils::SendMouseMoveSync(displays.first.bounds().CenterPoint()));
BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
EXPECT_FALSE(browser_view->immersive_mode_controller()->IsEnabled());
EXPECT_TRUE(immersive_controller2->IsEnabled());
EXPECT_FALSE(immersive_controller2->IsRevealed());
EXPECT_TRUE(tab_strip2->GetVisible());
}
class DifferentDeviceScaleFactorDisplayTabDragControllerTest
: public DetachToBrowserTabDragControllerTest {
public:
DifferentDeviceScaleFactorDisplayTabDragControllerTest() {}
DifferentDeviceScaleFactorDisplayTabDragControllerTest(
const DifferentDeviceScaleFactorDisplayTabDragControllerTest&) = delete;
DifferentDeviceScaleFactorDisplayTabDragControllerTest& operator=(
const DifferentDeviceScaleFactorDisplayTabDragControllerTest&) = delete;
virtual ~DifferentDeviceScaleFactorDisplayTabDragControllerTest() {}
void SetUpOnMainThread() override {
DetachToBrowserTabDragControllerTest::SetUpOnMainThread();
display::test::DisplayManagerTestApi(ash::Shell::Get()->display_manager())
.UpdateDisplay("1280x800,1280x800*2");
}
float GetCursorDeviceScaleFactor() const {
auto* cursor_client = aura::client::GetCursorClient(
browser()->window()->GetNativeWindow()->GetRootWindow());
const auto& cursor_shape_client = aura::client::GetCursorShapeClient();
return cursor_shape_client.GetCursorData(cursor_client->GetCursor())
->scale_factor;
}
};
namespace {
constexpr gfx::Point kDragPoints[] = {
{300, 200}, {399, 200}, {500, 200}, {400, 200}, {300, 200},
};
constexpr float kDeviceScaleFactorExpectations[] = {
1.0f, 1.0f, 2.0f, 2.0f, 1.0f,
};
static_assert(
std::size(kDragPoints) == std::size(kDeviceScaleFactorExpectations),
"kDragPoints and kDeviceScaleFactorExpectations must have the same "
"number of elements");
void CursorDeviceScaleFactorStep(
DifferentDeviceScaleFactorDisplayTabDragControllerTest* test,
TabStrip* not_attached_tab_strip,
size_t index) {
SCOPED_TRACE(index);
ASSERT_FALSE(not_attached_tab_strip->GetDragContext()->IsDragSessionActive());
ASSERT_TRUE(TabDragController::IsActive());
if (index > 0) {
EXPECT_EQ(kDragPoints[index - 1],
aura::Env::GetInstance()->last_mouse_location());
EXPECT_EQ(kDeviceScaleFactorExpectations[index - 1],
test->GetCursorDeviceScaleFactor());
}
if (index < std::size(kDragPoints)) {
ASSERT_TRUE(test->DragInputToNotifyWhenDone(
kDragPoints[index], base::BindOnce(&CursorDeviceScaleFactorStep, test,
not_attached_tab_strip, index + 1)));
} else {
ASSERT_TRUE(
ui_test_utils::SendMouseEventsSync(ui_controls::LEFT, ui_controls::UP));
}
}
}
IN_PROC_BROWSER_TEST_P(DifferentDeviceScaleFactorDisplayTabDragControllerTest,
DISABLED_CursorDeviceScaleFactor) {
AddTabsAndResetBrowser(browser(), 1);
TabStrip* tab_strip = GetTabStripForBrowser(browser());
ASSERT_EQ(2, display::Screen::GetScreen()->GetNumDisplays());
DragTabAndNotify(tab_strip, base::BindOnce(&CursorDeviceScaleFactorStep, this,
tab_strip, 0));
}
class DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest
: public DetachToBrowserTabDragControllerTest {
public:
DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest() {}
DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest(
const DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest&) =
delete;
DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest& operator=(
const DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest&) =
delete;
void SetUpOnMainThread() override {
DetachToBrowserTabDragControllerTest::SetUpOnMainThread();
display::test::DisplayManagerTestApi(ash::Shell::Get()->display_manager())
.UpdateDisplay("1280x800,1280x800");
}
};
namespace {
void CancelDragTabToWindowInSeparateDisplayStep3(
DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest* test,
TabStrip* tab_strip) {
ASSERT_FALSE(tab_strip->GetDragContext()->IsDragSessionActive());
ASSERT_TRUE(TabDragController::IsActive());
ASSERT_EQ(2u, test->browser_list()->size());
ash::ShellTestApi().AddRemoveDisplay();
}
void CancelDragTabToWindowInSeparateDisplayStep2(
DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest* test,
TabStrip* tab_strip,
Display current_display,
gfx::Point final_destination) {
EXPECT_FALSE(tab_strip->GetDragContext()->IsDragSessionActive());
EXPECT_TRUE(TabDragController::IsActive());
size_t num_browsers = test->browser_list()->size();
EXPECT_EQ(2u, num_browsers);
Browser* new_browser = test->browser_list()->get(num_browsers - 1);
EXPECT_EQ(
current_display.id(),
display::Screen::GetScreen()
->GetDisplayNearestWindow(new_browser->window()->GetNativeWindow())
.id());
EXPECT_TRUE(test->DragInputToNotifyWhenDone(
final_destination,
base::BindOnce(&CancelDragTabToWindowInSeparateDisplayStep3, test,
tab_strip)));
}
}
#if BUILDFLAG(IS_CHROMEOS)
#define MAYBE_CancelDragTabToWindowIn2ndDisplay …
#else
#define MAYBE_CancelDragTabToWindowIn2ndDisplay …
#endif
IN_PROC_BROWSER_TEST_P(
DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest,
MAYBE_CancelDragTabToWindowIn2ndDisplay) {
AddTabsAndResetBrowser(browser(), 1);
TabStrip* tab_strip = GetTabStripForBrowser(browser());
EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
const std::pair<Display, Display> displays =
GetDisplays(display::Screen::GetScreen());
gfx::Point final_destination = displays.second.work_area().CenterPoint();
DragTabAndNotify(
tab_strip,
base::BindOnce(&CancelDragTabToWindowInSeparateDisplayStep2, this,
tab_strip, displays.first, final_destination));
ASSERT_EQ(1u, browser_list()->size());
ASSERT_FALSE(tab_strip->GetDragContext()->IsDragSessionActive());
ASSERT_FALSE(TabDragController::IsActive());
EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
ASSERT_TRUE(
ui_test_utils::SendMouseEventsSync(ui_controls::LEFT, ui_controls::UP));
}
#if BUILDFLAG(IS_CHROMEOS)
#define MAYBE_CancelDragTabToWindowIn1stDisplay …
#else
#define MAYBE_CancelDragTabToWindowIn1stDisplay …
#endif
IN_PROC_BROWSER_TEST_P(
DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest,
MAYBE_CancelDragTabToWindowIn1stDisplay) {
display::Screen* screen = display::Screen::GetScreen();
const std::pair<Display, Display> displays = GetDisplays(screen);
AddTabsAndResetBrowser(browser(), 1);
TabStrip* tab_strip = GetTabStripForBrowser(browser());
EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
EXPECT_EQ(
displays.first.id(),
screen->GetDisplayNearestWindow(browser()->window()->GetNativeWindow())
.id());
browser()->window()->SetBounds(displays.second.work_area());
EXPECT_EQ(
displays.second.id(),
screen->GetDisplayNearestWindow(browser()->window()->GetNativeWindow())
.id());
gfx::Point final_destination = displays.first.work_area().CenterPoint();
DragTabAndNotify(
tab_strip,
base::BindOnce(&CancelDragTabToWindowInSeparateDisplayStep2, this,
tab_strip, displays.second, final_destination));
ASSERT_EQ(1u, browser_list()->size());
ASSERT_FALSE(tab_strip->GetDragContext()->IsDragSessionActive());
ASSERT_FALSE(TabDragController::IsActive());
EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
ASSERT_TRUE(
ui_test_utils::SendMouseEventsSync(ui_controls::LEFT, ui_controls::UP));
}
#endif
#if BUILDFLAG(IS_CHROMEOS)
class DetachToBrowserTabDragControllerTestTouch
: public DetachToBrowserTabDragControllerTest {
public:
DetachToBrowserTabDragControllerTestTouch() {}
DetachToBrowserTabDragControllerTestTouch(
const DetachToBrowserTabDragControllerTestTouch&) = delete;
DetachToBrowserTabDragControllerTestTouch& operator=(
const DetachToBrowserTabDragControllerTestTouch&) = delete;
virtual ~DetachToBrowserTabDragControllerTestTouch() {}
void TearDown() override {
ui::SetEventTickClockForTesting(nullptr);
clock_.reset();
}
protected:
std::unique_ptr<base::SimpleTestTickClock> clock_;
};
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
namespace {
void PressSecondFingerWhileDetachedStep3(
DetachToBrowserTabDragControllerTest* test) {
EXPECT_TRUE(TabDragController::IsActive());
EXPECT_EQ(2u, test->browser_list()->size());
EXPECT_TRUE(test->browser_list()->get(1)->window()->IsActive());
EXPECT_TRUE(test->ReleaseInput());
EXPECT_TRUE(test->ReleaseInput(1));
}
void PressSecondFingerWhileDetachedStep2(
DetachToBrowserTabDragControllerTest* test,
const gfx::Point& target_point) {
EXPECT_TRUE(TabDragController::IsActive());
size_t num_browsers = test->browser_list()->size();
EXPECT_EQ(2u, num_browsers);
EXPECT_TRUE(
test->browser_list()->get(num_browsers - 1)->window()->IsActive());
EXPECT_TRUE(test->PressInput(gfx::Point(), 1));
EXPECT_TRUE(test->DragInputToNotifyWhenDone(
target_point,
base::BindOnce(&PressSecondFingerWhileDetachedStep3, test)));
}
}
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestTouch,
PressSecondFingerWhileDetached) {
AddTabsAndResetBrowser(browser(), 1);
TabStrip* tab_strip = GetTabStripForBrowser(browser());
EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
const int touch_move_delta = GetDetachY(tab_strip);
const gfx::Point target = GetCenterInScreenCoordinates(tab_strip->tab_at(0)) +
gfx::Vector2d(0, 2 * touch_move_delta);
DragTabAndNotify(
tab_strip,
base::BindOnce(&PressSecondFingerWhileDetachedStep2, this, target), 0,
touch_move_delta + 5);
ASSERT_FALSE(tab_strip->GetDragContext()->IsDragSessionActive());
ASSERT_FALSE(TabDragController::IsActive());
ASSERT_EQ(2u, browser_list()->size());
Browser* new_browser = browser_list()->get(1);
ASSERT_TRUE(new_browser->window()->IsActive());
TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
ASSERT_FALSE(tab_strip2->GetDragContext()->IsDragSessionActive());
EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
}
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestTouch,
LeftSnapShouldntCauseMergeAtEnd) {
TabStrip* tab_strip = GetTabStripForBrowser(browser());
AddTabsAndResetBrowser(browser(), 1);
gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
base::RunLoop run_loop;
ui_controls::SendMouseMoveNotifyWhenDone(tab_0_center.x(), tab_0_center.y(),
run_loop.QuitClosure());
run_loop.Run();
DragTabAndNotify(
tab_strip, base::BindLambdaForTesting([&]() {
const gfx::Rect display_bounds =
display::Screen::GetScreen()->GetPrimaryDisplay().bounds();
const gfx::Point target(display_bounds.x(),
display_bounds.CenterPoint().y());
ASSERT_TRUE(
DragInputToNotifyWhenDone(target, base::BindLambdaForTesting([&]() {
ASSERT_TRUE(ReleaseInput());
})));
}),
1);
ASSERT_FALSE(TabDragController::IsActive());
EXPECT_EQ(2u, browser_list()->size());
}
#endif
#if BUILDFLAG(IS_CHROMEOS)
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestTouch,
FlingDownAtEndOfDrag) {
SetMinFlingVelocity(1);
TabStrip* tab_strip = GetTabStripForBrowser(browser());
test::QuitDraggingObserver observer(tab_strip);
const gfx::Point tab_0_center =
GetCenterInScreenCoordinates(tab_strip->tab_at(0));
const gfx::Vector2d detach(0, GetDetachY(tab_strip));
clock_ = std::make_unique<base::SimpleTestTickClock>();
clock_->SetNowTicks(base::TimeTicks::Now());
ui::SetEventTickClockForTesting(clock_.get());
ASSERT_TRUE(PressInput(tab_0_center));
clock_->Advance(base::Milliseconds(5));
ASSERT_TRUE(DragInputToNotifyWhenDone(
tab_0_center + detach, base::BindLambdaForTesting([&]() {
clock_->Advance(base::Milliseconds(5));
ASSERT_TRUE(DragInputToNotifyWhenDone(
tab_0_center + detach + detach, base::BindLambdaForTesting([&]() {
clock_->Advance(base::Milliseconds(5));
ASSERT_TRUE(ReleaseInput());
})));
})));
observer.Wait();
ASSERT_FALSE(tab_strip->GetDragContext()->IsDragSessionActive());
ASSERT_FALSE(TabDragController::IsActive());
EXPECT_TRUE(browser()->window()->IsMinimized());
EXPECT_FALSE(browser()->window()->IsVisible());
}
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestTouch,
DISABLED_FlingOnStartingDrag) {
SetMinFlingVelocity(1);
AddTabsAndResetBrowser(browser(), 1);
TabStrip* tab_strip = GetTabStripForBrowser(browser());
const gfx::Point tab_0_center =
GetCenterInScreenCoordinates(tab_strip->tab_at(0));
const gfx::Vector2d detach(0, GetDetachY(tab_strip));
test::QuitDraggingObserver observer(tab_strip);
clock_ = std::make_unique<base::SimpleTestTickClock>();
clock_->SetNowTicks(base::TimeTicks::Now());
ui::SetEventTickClockForTesting(clock_.get());
ASSERT_TRUE(PressInput(tab_0_center));
clock_->Advance(base::Milliseconds(5));
ASSERT_TRUE(DragInputToAsync(tab_0_center + detach));
clock_->Advance(base::Milliseconds(5));
ASSERT_TRUE(DragInputToAsync(tab_0_center + detach + detach));
clock_->Advance(base::Milliseconds(2));
ASSERT_TRUE(ReleaseInput());
observer.Wait();
ASSERT_FALSE(tab_strip->GetDragContext()->IsDragSessionActive());
ASSERT_FALSE(TabDragController::IsActive());
EXPECT_EQ(2u, browser_list()->size());
auto* browser2 = browser_list()->get(1);
EXPECT_TRUE(browser2->window()->IsMinimized());
EXPECT_FALSE(browser2->window()->IsVisible());
}
#endif
namespace {
class SelectTabDuringDragObserver : public TabStripModelObserver { … };
}
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
SelectTabDuringDrag) { … }
#if BUILDFLAG(IS_CHROMEOS_ASH)
using DetachToBrowserTabDragControllerTestWithOnTaskLocked =
DetachToBrowserTabDragControllerTestWithTabbedSystemApp;
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestWithOnTaskLocked,
MoveTabOnDrag) {
const webapps::AppId tabbed_app_id = InstallMockApp();
Browser* const app_browser = LaunchWebAppBrowser(tabbed_app_id);
ASSERT_EQ(2u, browser_list()->size());
CloseBrowserSynchronously(browser());
ASSERT_EQ(1u, browser_list()->size());
SelectFirstBrowser();
ASSERT_EQ(app_browser, browser());
EXPECT_EQ(Browser::Type::TYPE_APP, browser_list()->get(0)->type());
browser()->SetLockedForOnTask(true);
AddTabsAndResetBrowser(browser(), 3, GetAppUrl());
TabStripModel* const tab_strip_model = browser()->tab_strip_model();
ASSERT_EQ("0 1 2 3", IDString(tab_strip_model));
TabStrip* const tab_strip = GetTabStripForBrowser(browser());
ASSERT_TRUE(PressInput(GetCenterInScreenCoordinates(tab_strip->tab_at(1))));
ASSERT_TRUE(DragInputTo(GetCenterInScreenCoordinates(tab_strip->tab_at(2))));
ASSERT_TRUE(ReleaseInput());
StopAnimating(tab_strip);
ASSERT_EQ(1u, browser_list()->size());
EXPECT_EQ("0 2 1 3", IDString(tab_strip_model));
}
IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestWithOnTaskLocked,
TabDoesNotDetachOnDrag) {
const webapps::AppId tabbed_app_id = InstallMockApp();
Browser* const app_browser = LaunchWebAppBrowser(tabbed_app_id);
ASSERT_EQ(2u, browser_list()->size());
CloseBrowserSynchronously(browser());
ASSERT_EQ(1u, browser_list()->size());
SelectFirstBrowser();
ASSERT_EQ(app_browser, browser());
EXPECT_EQ(Browser::Type::TYPE_APP, browser_list()->get(0)->type());
browser()->SetLockedForOnTask(true);
AddTabsAndResetBrowser(browser(), 3, GetAppUrl());
TabStrip* const tab_strip = GetTabStripForBrowser(browser());
const gfx::Point initial_drag_position =
GetCenterInScreenCoordinates(tab_strip->tab_at(1));
ASSERT_TRUE(PressInput(initial_drag_position));
ASSERT_TRUE(DragInputTo(initial_drag_position +
gfx::Vector2d(0, GetDetachY(tab_strip) + 1)));
ASSERT_TRUE(ReleaseInput());
StopAnimating(tab_strip);
EXPECT_EQ(1u, browser_list()->size());
}
#endif
#if BUILDFLAG(IS_CHROMEOS)
INSTANTIATE_TEST_SUITE_P(
TabDragging,
DetachToBrowserTabDragControllerTest,
::testing::Combine(
::testing::Bool(),
::testing::Values(false),
::testing::Values("mouse", "touch")));
INSTANTIATE_TEST_SUITE_P(
TabDragging,
DetachToBrowserTabDragControllerTestWithScrollableTabStripEnabled,
::testing::Combine(
::testing::Bool(),
::testing::Values(false),
::testing::Values("mouse", "touch")));
#else
INSTANTIATE_TEST_SUITE_P(…);
INSTANTIATE_TEST_SUITE_P(…);
#endif
#if BUILDFLAG(IS_CHROMEOS)
INSTANTIATE_TEST_SUITE_P(
TabDragging,
DetachToBrowserInSeparateDisplayTabDragControllerTest,
::testing::Combine(
::testing::Bool(),
::testing::Values(false),
::testing::Values("mouse")));
INSTANTIATE_TEST_SUITE_P(
TabDragging,
DetachToBrowserTabDragControllerTestTouch,
::testing::Combine(
::testing::Bool(),
::testing::Values(false),
::testing::Values("touch")));
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
INSTANTIATE_TEST_SUITE_P(
TabDragging,
DifferentDeviceScaleFactorDisplayTabDragControllerTest,
::testing::Combine(
::testing::Bool(),
::testing::Values(false),
::testing::Values("mouse")));
INSTANTIATE_TEST_SUITE_P(
TabDragging,
DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest,
::testing::Combine(
::testing::Bool(),
::testing::Values(false),
::testing::Values("mouse")));
INSTANTIATE_TEST_SUITE_P(
TabDragging,
DetachToBrowserTabDragControllerTestWithTabbedSystemApp,
::testing::Combine(
::testing::Bool(),
::testing::Values(false),
::testing::Values("mouse", "touch")));
INSTANTIATE_TEST_SUITE_P(
TabDragging,
DetachToBrowserTabDragControllerTestWithOnTaskLocked,
::testing::Combine(
::testing::Bool(),
::testing::Values(false),
::testing::Values("mouse", "touch")));
#endif
#if BUILDFLAG(IS_CHROMEOS)
INSTANTIATE_TEST_SUITE_P(
TabDragging,
DetachToBrowserTabDragControllerTestWithTabbedWebApp,
::testing::Combine(
::testing::Bool(),
::testing::Values(false),
::testing::Values("mouse", "touch")));
#elif !BUILDFLAG(IS_MAC)
INSTANTIATE_TEST_SUITE_P(…);
#endif
#if BUILDFLAG(IS_CHROMEOS)
INSTANTIATE_TEST_SUITE_P(
TabDragging,
DetachTabWithUrlControlledByWebApp,
::testing::Combine(
::testing::Bool(),
::testing::Bool(),
::testing::Values("mouse")));
#else
INSTANTIATE_TEST_SUITE_P(…);
#endif