// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ash/test/ash_test_base.h" #include <string> #include <vector> #include "ash/ash_switches.h" #include "ash/display/display_controller.h" #include "ash/screen_ash.h" #include "ash/shell.h" #include "ash/shell/toplevel_window.h" #include "ash/test/ash_test_helper.h" #include "ash/test/display_manager_test_api.h" #include "ash/test/test_session_state_delegate.h" #include "ash/test/test_shell_delegate.h" #include "ash/test/test_system_tray_delegate.h" #include "ash/wm/coordinate_conversion.h" #include "ash/wm/window_positioner.h" #include "base/command_line.h" #include "content/public/test/web_contents_tester.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/client/screen_position_client.h" #include "ui/aura/client/window_tree_client.h" #include "ui/aura/root_window.h" #include "ui/aura/test/event_generator.h" #include "ui/aura/test/test_window_delegate.h" #include "ui/aura/window.h" #include "ui/aura/window_delegate.h" #include "ui/base/ime/input_method_initializer.h" #include "ui/gfx/display.h" #include "ui/gfx/point.h" #include "ui/gfx/screen.h" #if defined(OS_CHROMEOS) #include "ash/system/chromeos/tray_display.h" #endif #if defined(OS_WIN) #include "ash/test/test_metro_viewer_process_host.h" #include "base/test/test_process_killer_win.h" #include "base/win/metro.h" #include "base/win/windows_version.h" #include "ui/aura/remote_root_window_host_win.h" #include "ui/aura/root_window_host_win.h" #include "win8/test/test_registrar_constants.h" #endif namespace ash { namespace test { namespace { class AshEventGeneratorDelegate : public aura::test::EventGeneratorDelegate { public: AshEventGeneratorDelegate() {} virtual ~AshEventGeneratorDelegate() {} // aura::test::EventGeneratorDelegate overrides: virtual aura::RootWindow* GetRootWindowAt( const gfx::Point& point_in_screen) const OVERRIDE { gfx::Screen* screen = Shell::GetScreen(); gfx::Display display = screen->GetDisplayNearestPoint(point_in_screen); return Shell::GetInstance()->display_controller()-> GetRootWindowForDisplayId(display.id())->GetDispatcher(); } virtual aura::client::ScreenPositionClient* GetScreenPositionClient( const aura::Window* window) const OVERRIDE { return aura::client::GetScreenPositionClient(window->GetRootWindow()); } private: DISALLOW_COPY_AND_ASSIGN(AshEventGeneratorDelegate); }; } // namespace content::WebContents* AshTestViewsDelegate::CreateWebContents( content::BrowserContext* browser_context, content::SiteInstance* site_instance) { return content::WebContentsTester::CreateTestWebContents(browser_context, site_instance); } ///////////////////////////////////////////////////////////////////////////// AshTestBase::AshTestBase() : setup_called_(false), teardown_called_(false), start_session_(true) { // Must initialize |ash_test_helper_| here because some tests rely on // AshTestBase methods before they call AshTestBase::SetUp(). ash_test_helper_.reset(new AshTestHelper(base::MessageLoopForUI::current())); } AshTestBase::~AshTestBase() { CHECK(setup_called_) << "You have overridden SetUp but never called AshTestBase::SetUp"; CHECK(teardown_called_) << "You have overridden TearDown but never called AshTestBase::TearDown"; } void AshTestBase::SetUp() { setup_called_ = true; // Clears the saved state so that test doesn't use on the wrong // default state. shell::ToplevelWindow::ClearSavedStateForTest(); // TODO(jamescook): Can we do this without changing command line? // Use the origin (1,1) so that it doesn't over // lap with the native mouse cursor. CommandLine* command_line = CommandLine::ForCurrentProcess(); if (!command_line->HasSwitch(switches::kAshHostWindowBounds)) { command_line->AppendSwitchASCII( switches::kAshHostWindowBounds, "1+1-800x600"); } #if defined(OS_WIN) aura::test::SetUsePopupAsRootWindowForTest(true); #endif ash_test_helper_->SetUp(start_session_); Shell::GetPrimaryRootWindow()->Show(); Shell::GetPrimaryRootWindow()->GetDispatcher()->host()->Show(); // Move the mouse cursor to far away so that native events doesn't // interfere test expectations. Shell::GetPrimaryRootWindow()->MoveCursorTo(gfx::Point(-1000, -1000)); ash::Shell::GetInstance()->cursor_manager()->EnableMouseEvents(); #if defined(OS_WIN) if (!command_line->HasSwitch(ash::switches::kForceAshToDesktop)) { if (base::win::GetVersion() >= base::win::VERSION_WIN8) { ipc_thread_.reset(new base::Thread("test_metro_viewer_ipc_thread")); base::Thread::Options options; options.message_loop_type = base::MessageLoop::TYPE_IO; ipc_thread_->StartWithOptions(options); metro_viewer_host_.reset( new TestMetroViewerProcessHost(ipc_thread_->message_loop_proxy())); CHECK(metro_viewer_host_->LaunchViewerAndWaitForConnection( win8::test::kDefaultTestAppUserModelId)); aura::RemoteRootWindowHostWin* root_window_host = aura::RemoteRootWindowHostWin::Instance(); CHECK(root_window_host != NULL); } ash::WindowPositioner::SetMaximizeFirstWindow(true); } #endif } void AshTestBase::TearDown() { teardown_called_ = true; // Flush the message loop to finish pending release tasks. RunAllPendingInMessageLoop(); #if defined(OS_WIN) if (base::win::GetVersion() >= base::win::VERSION_WIN8 && !CommandLine::ForCurrentProcess()->HasSwitch( ash::switches::kForceAshToDesktop)) { // Check that our viewer connection is still established. CHECK(!metro_viewer_host_->closed_unexpectedly()); } #endif ash_test_helper_->TearDown(); #if defined(OS_WIN) aura::test::SetUsePopupAsRootWindowForTest(false); // Kill the viewer process if we spun one up. metro_viewer_host_.reset(); // Clean up any dangling viewer processes as the metro APIs sometimes leave // zombies behind. A default browser process in metro will have the // following command line arg so use that to avoid killing all processes named // win8::test::kDefaultTestExePath. const wchar_t kViewerProcessArgument[] = L"DefaultBrowserServer"; base::KillAllNamedProcessesWithArgument(win8::test::kDefaultTestExePath, kViewerProcessArgument); #endif event_generator_.reset(); // Some tests set an internal display id, // reset it here, so other tests will continue in a clean environment. gfx::Display::SetInternalDisplayId(gfx::Display::kInvalidDisplayID); } aura::test::EventGenerator& AshTestBase::GetEventGenerator() { if (!event_generator_) { event_generator_.reset( new aura::test::EventGenerator(new AshEventGeneratorDelegate())); } return *event_generator_.get(); } // static bool AshTestBase::SupportsMultipleDisplays() { #if defined(OS_WIN) return base::win::GetVersion() < base::win::VERSION_WIN8; #else return true; #endif } // static bool AshTestBase::SupportsHostWindowResize() { #if defined(OS_WIN) return base::win::GetVersion() < base::win::VERSION_WIN8; #else return true; #endif } void AshTestBase::UpdateDisplay(const std::string& display_specs) { DisplayManagerTestApi display_manager_test_api( Shell::GetInstance()->display_manager()); display_manager_test_api.UpdateDisplay(display_specs); } aura::Window* AshTestBase::CurrentContext() { return ash_test_helper_->CurrentContext(); } aura::Window* AshTestBase::CreateTestWindowInShellWithId(int id) { return CreateTestWindowInShellWithDelegate(NULL, id, gfx::Rect()); } aura::Window* AshTestBase::CreateTestWindowInShellWithBounds( const gfx::Rect& bounds) { return CreateTestWindowInShellWithDelegate(NULL, 0, bounds); } aura::Window* AshTestBase::CreateTestWindowInShell(SkColor color, int id, const gfx::Rect& bounds) { return CreateTestWindowInShellWithDelegate( new aura::test::ColorTestWindowDelegate(color), id, bounds); } aura::Window* AshTestBase::CreateTestWindowInShellWithDelegate( aura::WindowDelegate* delegate, int id, const gfx::Rect& bounds) { return CreateTestWindowInShellWithDelegateAndType( delegate, aura::client::WINDOW_TYPE_NORMAL, id, bounds); } aura::Window* AshTestBase::CreateTestWindowInShellWithDelegateAndType( aura::WindowDelegate* delegate, aura::client::WindowType type, int id, const gfx::Rect& bounds) { aura::Window* window = new aura::Window(delegate); window->set_id(id); window->SetType(type); window->Init(ui::LAYER_TEXTURED); window->Show(); if (bounds.IsEmpty()) { ParentWindowInPrimaryRootWindow(window); } else { gfx::Display display = Shell::GetScreen()->GetDisplayMatching(bounds); aura::Window* root = ash::Shell::GetInstance()->display_controller()-> GetRootWindowForDisplayId(display.id()); gfx::Point origin = bounds.origin(); wm::ConvertPointFromScreen(root, &origin); window->SetBounds(gfx::Rect(origin, bounds.size())); aura::client::ParentWindowWithContext(window, root, bounds); } window->SetProperty(aura::client::kCanMaximizeKey, true); return window; } void AshTestBase::ParentWindowInPrimaryRootWindow(aura::Window* window) { aura::client::ParentWindowWithContext( window, Shell::GetPrimaryRootWindow(), gfx::Rect()); } void AshTestBase::RunAllPendingInMessageLoop() { ash_test_helper_->RunAllPendingInMessageLoop(); } TestScreenshotDelegate* AshTestBase::GetScreenshotDelegate() { return ash_test_helper_->test_screenshot_delegate(); } TestSystemTrayDelegate* AshTestBase::GetSystemTrayDelegate() { return static_cast<TestSystemTrayDelegate*>( Shell::GetInstance()->system_tray_delegate()); } void AshTestBase::SetSessionStarted(bool session_started) { ash_test_helper_->test_shell_delegate()->test_session_state_delegate()-> SetActiveUserSessionStarted(session_started); } void AshTestBase::SetUserLoggedIn(bool user_logged_in) { ash_test_helper_->test_shell_delegate()->test_session_state_delegate()-> SetHasActiveUser(user_logged_in); } void AshTestBase::SetCanLockScreen(bool can_lock_screen) { ash_test_helper_->test_shell_delegate()->test_session_state_delegate()-> SetCanLockScreen(can_lock_screen); } void AshTestBase::SetShouldLockScreenBeforeSuspending(bool should_lock) { ash_test_helper_->test_shell_delegate()->test_session_state_delegate()-> SetShouldLockScreenBeforeSuspending(should_lock); } void AshTestBase::SetUserAddingScreenRunning(bool user_adding_screen_running) { ash_test_helper_->test_shell_delegate()->test_session_state_delegate()-> SetUserAddingScreenRunning(user_adding_screen_running); } void AshTestBase::BlockUserSession(UserSessionBlockReason block_reason) { switch (block_reason) { case BLOCKED_BY_LOCK_SCREEN: SetSessionStarted(true); SetUserAddingScreenRunning(false); Shell::GetInstance()->session_state_delegate()->LockScreen(); break; case BLOCKED_BY_LOGIN_SCREEN: SetUserAddingScreenRunning(false); SetSessionStarted(false); break; case BLOCKED_BY_USER_ADDING_SCREEN: SetUserAddingScreenRunning(true); SetSessionStarted(true); break; default: NOTREACHED(); break; } } void AshTestBase::UnblockUserSession() { Shell::GetInstance()->session_state_delegate()->UnlockScreen(); SetSessionStarted(true); SetUserAddingScreenRunning(false); } } // namespace test } // namespace ash