Commit c176d79e authored by Michael Giuffrida's avatar Michael Giuffrida Committed by Commit Bot

AppShell: Enable chrome.runtime.reload()

Allow apps to reload themselves, and ensure the ShellDesktopControllerAura
keeps app_shell alive long enough for the app to come back up.

Add browser tests for ShellDesktopControllerAura and
chrome.runtime.reload() in AppShell.

Bug: 762642,759867
Change-Id: If09ad83e6d3073461ebf8b53afa69a6c2aab7e15
Reviewed-on: https://chromium-review.googlesource.com/912752Reviewed-by: default avatarJames Cook <jamescook@chromium.org>
Commit-Queue: Michael Giuffrida <michaelpg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#542261}
parent 4720a9cf
...@@ -95,6 +95,8 @@ source_set("app_shell_lib") { ...@@ -95,6 +95,8 @@ source_set("app_shell_lib") {
"browser/api/feedback_private/shell_feedback_private_delegate.h", "browser/api/feedback_private/shell_feedback_private_delegate.h",
"browser/api/identity/identity_api.cc", "browser/api/identity/identity_api.cc",
"browser/api/identity/identity_api.h", "browser/api/identity/identity_api.h",
"browser/api/runtime/shell_runtime_api_delegate.cc",
"browser/api/runtime/shell_runtime_api_delegate.h",
"browser/default_shell_browser_main_delegate.cc", "browser/default_shell_browser_main_delegate.cc",
"browser/default_shell_browser_main_delegate.h", "browser/default_shell_browser_main_delegate.h",
"browser/delegates/shell_kiosk_delegate.cc", "browser/delegates/shell_kiosk_delegate.cc",
...@@ -161,8 +163,6 @@ source_set("app_shell_lib") { ...@@ -161,8 +163,6 @@ source_set("app_shell_lib") {
"browser/shell_oauth2_token_service_delegate.h", "browser/shell_oauth2_token_service_delegate.h",
"browser/shell_prefs.cc", "browser/shell_prefs.cc",
"browser/shell_prefs.h", "browser/shell_prefs.h",
"browser/shell_runtime_api_delegate.cc",
"browser/shell_runtime_api_delegate.h",
"browser/shell_special_storage_policy.cc", "browser/shell_special_storage_policy.cc",
"browser/shell_special_storage_policy.h", "browser/shell_special_storage_policy.h",
"browser/shell_speech_recognition_manager_delegate.cc", "browser/shell_speech_recognition_manager_delegate.cc",
...@@ -456,6 +456,7 @@ if (is_mac) { ...@@ -456,6 +456,7 @@ if (is_mac) {
source_set("browser_tests") { source_set("browser_tests") {
testonly = true testonly = true
sources = [ sources = [
"browser/api/runtime/runtime_apitest.cc",
"browser/geolocation/geolocation_apitest.cc", "browser/geolocation/geolocation_apitest.cc",
"browser/shell_browsertest.cc", "browser/shell_browsertest.cc",
"test/shell_apitest.cc", "test/shell_apitest.cc",
...@@ -473,15 +474,18 @@ source_set("browser_tests") { ...@@ -473,15 +474,18 @@ source_set("browser_tests") {
":app_shell_lib", ":app_shell_lib",
"//base", "//base",
"//base/test:test_support", "//base/test:test_support",
"//components/keep_alive_registry",
"//components/version_info", "//components/version_info",
"//content/shell:content_shell_lib", "//content/shell:content_shell_lib",
"//content/test:test_support", "//content/test:test_support",
"//extensions:test_support", "//extensions:test_support",
"//extensions/browser", "//extensions/browser",
"//extensions/browser:test_support",
"//extensions/common", "//extensions/common",
] ]
if (use_aura) { if (use_aura) {
sources += [ "browser/shell_desktop_controller_aura_browsertest.cc" ]
deps += [ "//ui/aura" ] deps += [ "//ui/aura" ]
} }
} }
......
// Copyright 2018 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 "extensions/browser/browsertest_util.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/test_extension_registry_observer.h"
#include "extensions/common/extension_id.h"
#include "extensions/shell/browser/shell_extension_system.h"
#include "extensions/shell/test/shell_apitest.h"
#include "extensions/test/result_catcher.h"
namespace extensions {
using ShellRuntimeApiTest = ShellApiTest;
IN_PROC_BROWSER_TEST_F(ShellRuntimeApiTest, RuntimeReload) {
const Extension* extension = nullptr;
// Load the extension and wait for it to be ready.
{
ResultCatcher catcher;
ASSERT_TRUE(extension = LoadExtension("extension"));
ASSERT_TRUE(catcher.GetNextResult());
}
const ExtensionId extension_id = extension->id();
ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context());
// Reload the extension and wait for a pair of
// ExtensionRegistry::OnExtensionUnloaded()/Loaded() calls.
TestExtensionRegistryObserver registry_observer(registry, extension_id);
ASSERT_TRUE(browsertest_util::ExecuteScriptInBackgroundPageNoWait(
browser_context(), extension_id, "chrome.runtime.reload();"));
ASSERT_EQ(extension, registry_observer.WaitForExtensionUnloaded());
EXPECT_TRUE(registry->disabled_extensions().Contains(extension_id));
ASSERT_TRUE(extension = registry_observer.WaitForExtensionLoaded());
ASSERT_EQ(extension->id(), extension_id);
EXPECT_TRUE(registry->enabled_extensions().Contains(extension_id));
// Wait for the background page to load.
{
ResultCatcher catcher;
ASSERT_TRUE(catcher.GetNextResult());
}
}
IN_PROC_BROWSER_TEST_F(ShellRuntimeApiTest, RuntimeReloadApp) {
const Extension* extension = nullptr;
// Load and launch the app and wait for it to create a window.
{
ResultCatcher catcher;
extension = LoadApp("platform_app");
ASSERT_TRUE(catcher.GetNextResult());
}
const ExtensionId extension_id = extension->id();
ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context());
// Reload the extension and wait for a pair of
// ExtensionRegistry::OnExtensionUnloaded()/Loaded() calls.
TestExtensionRegistryObserver registry_observer(registry, extension_id);
ASSERT_TRUE(browsertest_util::ExecuteScriptInBackgroundPageNoWait(
browser_context(), extension_id, "chrome.runtime.reload();"));
ASSERT_EQ(extension, registry_observer.WaitForExtensionUnloaded());
EXPECT_TRUE(registry->disabled_extensions().Contains(extension_id));
ASSERT_TRUE(extension = registry_observer.WaitForExtensionLoaded());
ASSERT_EQ(extension->id(), extension_id);
EXPECT_TRUE(registry->enabled_extensions().Contains(extension_id));
// Reloading the app should launch it again automatically.
// Wait for the app to create a new window.
{
ResultCatcher catcher;
ASSERT_TRUE(catcher.GetNextResult());
}
}
} // namespace extensions
...@@ -2,10 +2,11 @@ ...@@ -2,10 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "extensions/shell/browser/shell_runtime_api_delegate.h" #include "extensions/shell/browser/api/runtime/shell_runtime_api_delegate.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "extensions/common/api/runtime.h" #include "extensions/common/api/runtime.h"
#include "extensions/shell/browser/shell_extension_system.h"
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
#include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/dbus_thread_manager.h"
...@@ -17,19 +18,21 @@ using extensions::api::runtime::PlatformInfo; ...@@ -17,19 +18,21 @@ using extensions::api::runtime::PlatformInfo;
namespace extensions { namespace extensions {
ShellRuntimeAPIDelegate::ShellRuntimeAPIDelegate() { ShellRuntimeAPIDelegate::ShellRuntimeAPIDelegate(
content::BrowserContext* browser_context)
: browser_context_(browser_context) {
DCHECK(browser_context_);
} }
ShellRuntimeAPIDelegate::~ShellRuntimeAPIDelegate() { ShellRuntimeAPIDelegate::~ShellRuntimeAPIDelegate() = default;
}
void ShellRuntimeAPIDelegate::AddUpdateObserver(UpdateObserver* observer) { void ShellRuntimeAPIDelegate::AddUpdateObserver(UpdateObserver* observer) {}
}
void ShellRuntimeAPIDelegate::RemoveUpdateObserver(UpdateObserver* observer) { void ShellRuntimeAPIDelegate::RemoveUpdateObserver(UpdateObserver* observer) {}
}
void ShellRuntimeAPIDelegate::ReloadExtension(const std::string& extension_id) { void ShellRuntimeAPIDelegate::ReloadExtension(const std::string& extension_id) {
static_cast<ShellExtensionSystem*>(ExtensionSystem::Get(browser_context_))
->ReloadExtension(extension_id);
} }
bool ShellRuntimeAPIDelegate::CheckForUpdates( bool ShellRuntimeAPIDelegate::CheckForUpdates(
...@@ -38,8 +41,7 @@ bool ShellRuntimeAPIDelegate::CheckForUpdates( ...@@ -38,8 +41,7 @@ bool ShellRuntimeAPIDelegate::CheckForUpdates(
return false; return false;
} }
void ShellRuntimeAPIDelegate::OpenURL(const GURL& uninstall_url) { void ShellRuntimeAPIDelegate::OpenURL(const GURL& uninstall_url) {}
}
bool ShellRuntimeAPIDelegate::GetPlatformInfo(PlatformInfo* info) { bool ShellRuntimeAPIDelegate::GetPlatformInfo(PlatformInfo* info) {
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
......
...@@ -2,17 +2,21 @@ ...@@ -2,17 +2,21 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifndef EXTENSIONS_SHELL_BROWSER_SHELL_RUNTIME_API_DELEGATE_H_ #ifndef EXTENSIONS_SHELL_BROWSER_API_RUNTIME_SHELL_RUNTIME_API_DELEGATE_H_
#define EXTENSIONS_SHELL_BROWSER_SHELL_RUNTIME_API_DELEGATE_H_ #define EXTENSIONS_SHELL_BROWSER_API_RUNTIME_SHELL_RUNTIME_API_DELEGATE_H_
#include "base/macros.h" #include "base/macros.h"
#include "extensions/browser/api/runtime/runtime_api_delegate.h" #include "extensions/browser/api/runtime/runtime_api_delegate.h"
namespace content {
class BrowserContext;
} // namespace content
namespace extensions { namespace extensions {
class ShellRuntimeAPIDelegate : public RuntimeAPIDelegate { class ShellRuntimeAPIDelegate : public RuntimeAPIDelegate {
public: public:
ShellRuntimeAPIDelegate(); explicit ShellRuntimeAPIDelegate(content::BrowserContext* browser_context);
~ShellRuntimeAPIDelegate() override; ~ShellRuntimeAPIDelegate() override;
// RuntimeAPIDelegate implementation. // RuntimeAPIDelegate implementation.
...@@ -26,9 +30,11 @@ class ShellRuntimeAPIDelegate : public RuntimeAPIDelegate { ...@@ -26,9 +30,11 @@ class ShellRuntimeAPIDelegate : public RuntimeAPIDelegate {
bool RestartDevice(std::string* error_message) override; bool RestartDevice(std::string* error_message) override;
private: private:
content::BrowserContext* browser_context_;
DISALLOW_COPY_AND_ASSIGN(ShellRuntimeAPIDelegate); DISALLOW_COPY_AND_ASSIGN(ShellRuntimeAPIDelegate);
}; };
} // namespace extensions } // namespace extensions
#endif // EXTENSIONS_SHELL_BROWSER_SHELL_RUNTIME_API_DELEGATE_H_ #endif // EXTENSIONS_SHELL_BROWSER_API_RUNTIME_SHELL_RUNTIME_API_DELEGATE_H_
...@@ -2,10 +2,8 @@ ...@@ -2,10 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "base/logging.h"
#include "content/public/browser/notification_service.h" #include "content/public/browser/notification_service.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "content/public/test/test_utils.h"
#include "extensions/browser/app_window/app_window.h" #include "extensions/browser/app_window/app_window.h"
#include "extensions/browser/app_window/app_window_registry.h" #include "extensions/browser/app_window/app_window_registry.h"
#include "extensions/browser/notification_types.h" #include "extensions/browser/notification_types.h"
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "components/keep_alive_registry/keep_alive_registry.h"
#include "extensions/shell/browser/shell_app_window_client.h" #include "extensions/shell/browser/shell_app_window_client.h"
#include "ui/aura/client/cursor_client.h" #include "ui/aura/client/cursor_client.h"
#include "ui/aura/window.h" #include "ui/aura/window.h"
...@@ -161,10 +162,15 @@ ShellDesktopControllerAura::~ShellDesktopControllerAura() { ...@@ -161,10 +162,15 @@ ShellDesktopControllerAura::~ShellDesktopControllerAura() {
} }
void ShellDesktopControllerAura::Run() { void ShellDesktopControllerAura::Run() {
KeepAliveRegistry::GetInstance()->AddObserver(this);
base::RunLoop run_loop; base::RunLoop run_loop;
run_loop_ = &run_loop; run_loop_ = &run_loop;
run_loop.Run(); run_loop.Run();
run_loop_ = nullptr; run_loop_ = nullptr;
KeepAliveRegistry::GetInstance()->SetIsShuttingDown(true);
KeepAliveRegistry::GetInstance()->RemoveObserver(this);
} }
void ShellDesktopControllerAura::AddAppWindow(AppWindow* app_window, void ShellDesktopControllerAura::AddAppWindow(AppWindow* app_window,
...@@ -198,9 +204,7 @@ void ShellDesktopControllerAura::CloseRootWindowController( ...@@ -198,9 +204,7 @@ void ShellDesktopControllerAura::CloseRootWindowController(
TearDownRootWindowController(it->second.get()); TearDownRootWindowController(it->second.get());
root_window_controllers_.erase(it); root_window_controllers_.erase(it);
// run_loop_ may be null in tests. MaybeQuit();
if (run_loop_ && root_window_controllers_.empty())
run_loop_->QuitWhenIdle();
} }
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
...@@ -234,6 +238,15 @@ ui::EventDispatchDetails ShellDesktopControllerAura::DispatchKeyEventPostIME( ...@@ -234,6 +238,15 @@ ui::EventDispatchDetails ShellDesktopControllerAura::DispatchKeyEventPostIME(
return GetPrimaryHost()->DispatchKeyEventPostIME(key_event); return GetPrimaryHost()->DispatchKeyEventPostIME(key_event);
} }
void ShellDesktopControllerAura::OnKeepAliveStateChanged(
bool is_keeping_alive) {
if (!is_keeping_alive)
MaybeQuit();
}
void ShellDesktopControllerAura::OnKeepAliveRestartStateChanged(
bool can_restart) {}
aura::WindowTreeHost* ShellDesktopControllerAura::GetPrimaryHost() { aura::WindowTreeHost* ShellDesktopControllerAura::GetPrimaryHost() {
if (root_window_controllers_.empty()) if (root_window_controllers_.empty())
return nullptr; return nullptr;
...@@ -337,6 +350,19 @@ void ShellDesktopControllerAura::TearDownRootWindowController( ...@@ -337,6 +350,19 @@ void ShellDesktopControllerAura::TearDownRootWindowController(
root->host()->window()->RemovePreTargetHandler(focus_controller_.get()); root->host()->window()->RemovePreTargetHandler(focus_controller_.get());
} }
void ShellDesktopControllerAura::MaybeQuit() {
// run_loop_ may be null in tests.
if (!run_loop_)
return;
// Quit if there are no app windows open and no keep-alives waiting for apps
// to relaunch.
if (root_window_controllers_.empty() &&
!KeepAliveRegistry::GetInstance()->IsKeepingAlive()) {
run_loop_->QuitWhenIdle();
}
}
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
gfx::Size ShellDesktopControllerAura::GetStartingWindowSize() { gfx::Size ShellDesktopControllerAura::GetStartingWindowSize() {
gfx::Size size; gfx::Size size;
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/macros.h" #include "base/macros.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "components/keep_alive_registry/keep_alive_state_observer.h"
#include "extensions/shell/browser/desktop_controller.h" #include "extensions/shell/browser/desktop_controller.h"
#include "extensions/shell/browser/root_window_controller.h" #include "extensions/shell/browser/root_window_controller.h"
#include "ui/aura/window.h" #include "ui/aura/window.h"
...@@ -69,7 +70,8 @@ class ShellDesktopControllerAura ...@@ -69,7 +70,8 @@ class ShellDesktopControllerAura
public chromeos::PowerManagerClient::Observer, public chromeos::PowerManagerClient::Observer,
public display::DisplayConfigurator::Observer, public display::DisplayConfigurator::Observer,
#endif #endif
public ui::internal::InputMethodDelegate { public ui::internal::InputMethodDelegate,
public KeepAliveStateObserver {
public: public:
explicit ShellDesktopControllerAura(content::BrowserContext* browser_context); explicit ShellDesktopControllerAura(content::BrowserContext* browser_context);
~ShellDesktopControllerAura() override; ~ShellDesktopControllerAura() override;
...@@ -84,19 +86,23 @@ class ShellDesktopControllerAura ...@@ -84,19 +86,23 @@ class ShellDesktopControllerAura
RootWindowController* root_window_controller) override; RootWindowController* root_window_controller) override;
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
// chromeos::PowerManagerClient::Observer overrides: // chromeos::PowerManagerClient::Observer:
void PowerButtonEventReceived(bool down, void PowerButtonEventReceived(bool down,
const base::TimeTicks& timestamp) override; const base::TimeTicks& timestamp) override;
// display::DisplayConfigurator::Observer overrides. // display::DisplayConfigurator::Observer:
void OnDisplayModeChanged( void OnDisplayModeChanged(
const display::DisplayConfigurator::DisplayStateList& displays) override; const display::DisplayConfigurator::DisplayStateList& displays) override;
#endif #endif
// ui::internal::InputMethodDelegate overrides: // ui::internal::InputMethodDelegate:
ui::EventDispatchDetails DispatchKeyEventPostIME( ui::EventDispatchDetails DispatchKeyEventPostIME(
ui::KeyEvent* key_event) override; ui::KeyEvent* key_event) override;
// KeepAliveStateObserver:
void OnKeepAliveStateChanged(bool is_keeping_alive) override;
void OnKeepAliveRestartStateChanged(bool can_restart) override;
// Returns the WindowTreeHost for the primary display. // Returns the WindowTreeHost for the primary display.
aura::WindowTreeHost* GetPrimaryHost(); aura::WindowTreeHost* GetPrimaryHost();
...@@ -119,6 +125,10 @@ class ShellDesktopControllerAura ...@@ -119,6 +125,10 @@ class ShellDesktopControllerAura
// Removes handlers from the RootWindowController so it can be destroyed. // Removes handlers from the RootWindowController so it can be destroyed.
void TearDownRootWindowController(RootWindowController* root); void TearDownRootWindowController(RootWindowController* root);
// Quits if there are no app windows, and no keep-alives waiting for apps to
// relaunch.
void MaybeQuit();
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
// Returns the desired dimensions of the RootWindowController from the command // Returns the desired dimensions of the RootWindowController from the command
// line, or falls back to a default size. // line, or falls back to a default size.
......
// Copyright 2018 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 "extensions/shell/browser/shell_desktop_controller_aura.h"
#include "base/macros.h"
#include "base/task_scheduler/post_task.h"
#include "base/test/bind_test_util.h"
#include "base/time/time.h"
#include "components/keep_alive_registry/keep_alive_registry.h"
#include "extensions/browser/app_window/app_window.h"
#include "extensions/browser/app_window/app_window_registry.h"
#include "extensions/browser/browsertest_util.h"
#include "extensions/shell/browser/desktop_controller.h"
#include "extensions/shell/test/shell_apitest.h"
#include "extensions/test/result_catcher.h"
namespace extensions {
// Tests that spin up the ShellDesktopControllerAura and run async tasks like
// launching and reloading apps.
class ShellDesktopControllerAuraBrowserTest : public ShellApiTest {
public:
ShellDesktopControllerAuraBrowserTest() = default;
~ShellDesktopControllerAuraBrowserTest() override = default;
// Loads and launches a platform app that opens an app window.
void LoadAndLaunchApp() {
ASSERT_FALSE(app_);
app_ = LoadApp("platform_app");
ASSERT_TRUE(app_);
// Wait for app window to load.
ResultCatcher catcher;
EXPECT_TRUE(catcher.GetNextResult());
// A window was created.
EXPECT_EQ(1u,
AppWindowRegistry::Get(browser_context())->app_windows().size());
}
protected:
// Returns an open app window.
AppWindow* GetAppWindow() {
EXPECT_GT(AppWindowRegistry::Get(browser_context())->app_windows().size(),
0u);
return AppWindowRegistry::Get(browser_context())->app_windows().front();
}
// ShellApiTest:
void SetUpOnMainThread() override {
ShellApiTest::SetUpOnMainThread();
desktop_controller_ =
static_cast<ShellDesktopControllerAura*>(DesktopController::instance());
ASSERT_TRUE(desktop_controller_);
}
void TearDownOnMainThread() override {
EXPECT_FALSE(KeepAliveRegistry::GetInstance()->IsKeepingAlive());
ShellApiTest::TearDownOnMainThread();
}
ShellDesktopControllerAura* desktop_controller_ = nullptr;
scoped_refptr<const Extension> app_;
private:
DISALLOW_COPY_AND_ASSIGN(ShellDesktopControllerAuraBrowserTest);
};
// Test that closing the app window stops the DesktopController.
IN_PROC_BROWSER_TEST_F(ShellDesktopControllerAuraBrowserTest, CloseAppWindow) {
bool test_succeeded = false;
// Post a task so everything runs after the DesktopController starts.
base::ThreadTaskRunnerHandle::Get()->PostTaskAndReply(
FROM_HERE,
// Asynchronously launch the app.
base::BindOnce(&ShellDesktopControllerAuraBrowserTest::LoadAndLaunchApp,
base::Unretained(this)),
// Once the app launches, run the test.
base::BindLambdaForTesting([this, &test_succeeded]() {
// Close the app window so DesktopController quits.
GetAppWindow()->OnNativeClose();
test_succeeded = true;
}));
// Start DesktopController. It should run until the last app window closes.
desktop_controller_->Run();
EXPECT_TRUE(test_succeeded)
<< "DesktopController quit before test completed.";
}
// Test that the DesktopController runs until all app windows close.
IN_PROC_BROWSER_TEST_F(ShellDesktopControllerAuraBrowserTest, TwoAppWindows) {
bool test_succeeded = false;
// Post a task so everything runs after the DesktopController starts.
base::ThreadTaskRunnerHandle::Get()->PostTaskAndReply(
FROM_HERE,
// Asynchronously launch the app.
base::BindOnce(&ShellDesktopControllerAuraBrowserTest::LoadAndLaunchApp,
base::Unretained(this)),
// Once the app launches, run the test.
base::BindLambdaForTesting([this, &test_succeeded]() {
// Create a second app window.
ASSERT_TRUE(browsertest_util::ExecuteScriptInBackgroundPageNoWait(
browser_context(), app_->id(),
"chrome.app.window.create('/hello.html');"));
ResultCatcher catcher;
catcher.GetNextResult();
// Close the first app window.
GetAppWindow()->OnNativeClose();
// One window is still open, so the DesktopController should still be
// running. Post a task to close the last window.
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, base::BindLambdaForTesting([this, &test_succeeded]() {
GetAppWindow()->OnNativeClose();
test_succeeded = true;
}),
// A regression might cause DesktopController to quit before the
// last window closes. To ensure we catch this, wait a while before
// closing the last window. If DesktopController::Run() finishes
// before we close the last window and update |test_succeeded|, the
// test fails.
base::TimeDelta::FromMilliseconds(500));
}));
desktop_controller_->Run();
EXPECT_TRUE(test_succeeded)
<< "DesktopController quit before test completed.";
}
// Test that the DesktopController stays open while an app reloads, even though
// the app window closes.
IN_PROC_BROWSER_TEST_F(ShellDesktopControllerAuraBrowserTest, ReloadApp) {
bool test_succeeded = false;
// Post a task so everything runs after the DesktopController starts.
base::ThreadTaskRunnerHandle::Get()->PostTaskAndReply(
FROM_HERE,
// Asynchronously launch the app.
base::BindOnce(&ShellDesktopControllerAuraBrowserTest::LoadAndLaunchApp,
base::Unretained(this)),
// Once the app launches, run the test.
base::BindLambdaForTesting([this, &test_succeeded]() {
// Reload the app.
ASSERT_TRUE(browsertest_util::ExecuteScriptInBackgroundPageNoWait(
browser_context(), app_->id(), "chrome.runtime.reload();"));
// Wait for the app window to re-open.
ResultCatcher catcher;
ASSERT_TRUE(catcher.GetNextResult());
// Close the new window after a delay. DesktopController should remain
// open until the window closes.
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, base::BindLambdaForTesting([this, &test_succeeded]() {
AppWindow* app_window = AppWindowRegistry::Get(browser_context())
->app_windows()
.front();
app_window->OnNativeClose();
test_succeeded = true;
}),
base::TimeDelta::FromMilliseconds(500));
}));
desktop_controller_->Run();
EXPECT_TRUE(test_succeeded)
<< "DesktopController quit before test completed.";
}
} // namespace extensions
...@@ -70,6 +70,10 @@ void ShellExtensionSystem::LaunchApp(const ExtensionId& extension_id) { ...@@ -70,6 +70,10 @@ void ShellExtensionSystem::LaunchApp(const ExtensionId& extension_id) {
apps::LaunchPlatformApp(browser_context_, extension, SOURCE_UNTRACKED); apps::LaunchPlatformApp(browser_context_, extension, SOURCE_UNTRACKED);
} }
void ShellExtensionSystem::ReloadExtension(const ExtensionId& extension_id) {
extension_loader_->ReloadExtension(extension_id);
}
void ShellExtensionSystem::Shutdown() { void ShellExtensionSystem::Shutdown() {
extension_loader_.reset(); extension_loader_.reset();
} }
......
...@@ -52,6 +52,9 @@ class ShellExtensionSystem : public ExtensionSystem { ...@@ -52,6 +52,9 @@ class ShellExtensionSystem : public ExtensionSystem {
// Launch the app with id |extension_id|. // Launch the app with id |extension_id|.
void LaunchApp(const ExtensionId& extension_id); void LaunchApp(const ExtensionId& extension_id);
// Reloads the extension with id |extension_id|.
void ReloadExtension(const ExtensionId& extension_id);
// KeyedService implementation: // KeyedService implementation:
void Shutdown() override; void Shutdown() override;
......
...@@ -23,13 +23,13 @@ ...@@ -23,13 +23,13 @@
#include "extensions/browser/url_request_util.h" #include "extensions/browser/url_request_util.h"
#include "extensions/common/features/feature_channel.h" #include "extensions/common/features/feature_channel.h"
#include "extensions/shell/browser/api/generated_api_registration.h" #include "extensions/shell/browser/api/generated_api_registration.h"
#include "extensions/shell/browser/api/runtime/shell_runtime_api_delegate.h"
#include "extensions/shell/browser/delegates/shell_kiosk_delegate.h" #include "extensions/shell/browser/delegates/shell_kiosk_delegate.h"
#include "extensions/shell/browser/shell_extension_host_delegate.h" #include "extensions/shell/browser/shell_extension_host_delegate.h"
#include "extensions/shell/browser/shell_extension_system_factory.h" #include "extensions/shell/browser/shell_extension_system_factory.h"
#include "extensions/shell/browser/shell_extension_web_contents_observer.h" #include "extensions/shell/browser/shell_extension_web_contents_observer.h"
#include "extensions/shell/browser/shell_extensions_api_client.h" #include "extensions/shell/browser/shell_extensions_api_client.h"
#include "extensions/shell/browser/shell_navigation_ui_data.h" #include "extensions/shell/browser/shell_navigation_ui_data.h"
#include "extensions/shell/browser/shell_runtime_api_delegate.h"
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
#include "chromeos/login/login_state.h" #include "chromeos/login/login_state.h"
...@@ -229,7 +229,7 @@ void ShellExtensionsBrowserClient::RegisterExtensionInterfaces( ...@@ -229,7 +229,7 @@ void ShellExtensionsBrowserClient::RegisterExtensionInterfaces(
std::unique_ptr<RuntimeAPIDelegate> std::unique_ptr<RuntimeAPIDelegate>
ShellExtensionsBrowserClient::CreateRuntimeAPIDelegate( ShellExtensionsBrowserClient::CreateRuntimeAPIDelegate(
content::BrowserContext* context) const { content::BrowserContext* context) const {
return std::make_unique<ShellRuntimeAPIDelegate>(); return std::make_unique<ShellRuntimeAPIDelegate>(context);
} }
const ComponentExtensionResourceManager* const ComponentExtensionResourceManager*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment