WebApp: Introduce WebApp, WebAppRegistrar and InstallManager entities.
Introduce DesktopPWAsWithoutExtensions command line switch.
A WebApp represents single web app.
WebApp objects are owned by WebAppRegistrar.
WebAppRegistrar is a root entity which is able to add/remove new apps.
Later WebAppRegistrar will be able:
- to iterate over all the registered apps.
- to iterate over various subsets of all registered apps (shortcut apps)
- to survive the browser (and ChromeOS) relaunch (persistence)
InstallManager is an abstract manager to plumb 3-dot menu user installation.
We will evolve its WebAppInstallManager implementation
into comprehensive install manager later.
--enable-features=DesktopPWAsWithoutExtensions will enable off-extensions
implementation for Desktop PWAs.
Bug: 891172, 871116
Change-Id: Iebcbd93cf08eec0f11c7c22dce57ded81a2a2e94
Reviewed-on: https://chromium-review.googlesource.com/c/1275468
Reviewed-by: Ben Wells <[email protected]>
Reviewed-by: Trent Apted <[email protected]>
Commit-Queue: Alexey Baskakov <[email protected]>
Cr-Commit-Position: refs/heads/master@{#599887}
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index e2701d5..ae9a346 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -3970,6 +3970,9 @@
"//chrome/browser/extensions",
"//chrome/browser/web_applications",
+
+ # TODO(loyso): Erase these. crbug.com/877898.
+ "//chrome/browser/web_applications:web_applications_on_extensions",
"//chrome/browser/web_applications/bookmark_apps",
"//chrome/browser/web_applications/components",
"//chrome/browser/web_applications/extensions",
@@ -3978,6 +3981,7 @@
"//apps",
"//chrome/browser/sync_file_system/drive_backend:sync_file_system_drive_proto",
"//chrome/browser/web_applications",
+ "//chrome/browser/web_applications:web_applications_on_extensions",
"//chrome/browser/web_applications/bookmark_apps",
"//chrome/browser/web_applications/components",
"//chrome/browser/web_applications/extensions",
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 873b29ac..cadddbf 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -69,7 +69,7 @@
"//chrome/browser/extensions",
"//chrome/browser/resource_coordinator:tab_metrics_event_proto",
"//chrome/browser/ssl:proto",
- "//chrome/browser/web_applications",
+ "//chrome/browser/web_applications:web_applications_on_extensions",
"//chrome/browser/web_applications/bookmark_apps",
"//chrome/browser/web_applications/components",
"//chrome/common",
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 67eab0a..cbeab15f 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1258,6 +1258,10 @@
if (enable_extensions) {
deps += [
+ "//chrome/browser/web_applications",
+
+ # TODO(loyso): Erase these. crbug.com/877898.
+ "//chrome/browser/web_applications:web_applications_on_extensions",
"//chrome/browser/web_applications/components",
"//chrome/browser/web_applications/extensions",
]
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc
index 1b80948..fe98ecab 100644
--- a/chrome/browser/ui/browser_commands.cc
+++ b/chrome/browser/ui/browser_commands.cc
@@ -99,9 +99,9 @@
#if BUILDFLAG(ENABLE_EXTENSIONS)
#include "chrome/browser/extensions/api/commands/command_service.h"
#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
-#include "chrome/browser/extensions/tab_helper.h"
#include "chrome/browser/ui/extensions/settings_api_bubble_helpers.h"
#include "chrome/browser/web_applications/components/web_app_helpers.h"
+#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/common/extensions/extension_metrics.h"
#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
#include "extensions/browser/extension_registry.h"
@@ -1256,15 +1256,13 @@
void CreateBookmarkAppFromCurrentWebContents(Browser* browser,
bool force_shortcut_app) {
base::RecordAction(UserMetricsAction("CreateHostedApp"));
- extensions::TabHelper::FromWebContents(
- browser->tab_strip_model()->GetActiveWebContents())
- ->CreateHostedAppFromWebContents(force_shortcut_app);
+ web_app::WebAppProvider::InstallWebApp(
+ browser->tab_strip_model()->GetActiveWebContents(), force_shortcut_app);
}
bool CanCreateBookmarkApp(const Browser* browser) {
- return extensions::TabHelper::FromWebContents(
- browser->tab_strip_model()->GetActiveWebContents())
- ->CanCreateBookmarkApp();
+ return web_app::WebAppProvider::CanInstallWebApp(
+ browser->tab_strip_model()->GetActiveWebContents());
}
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn
index 621fc64..509d0e8 100644
--- a/chrome/browser/web_applications/BUILD.gn
+++ b/chrome/browser/web_applications/BUILD.gn
@@ -8,6 +8,71 @@
source_set("web_applications") {
sources = [
+ "web_app.cc",
+ "web_app.h",
+ "web_app_install_manager.cc",
+ "web_app_install_manager.h",
+ "web_app_registrar.cc",
+ "web_app_registrar.h",
+ "web_app_utils.cc",
+ "web_app_utils.h",
+ ]
+
+ deps = [
+ ":web_app_group",
+ "//chrome/browser/web_applications/components",
+ "//chrome/common",
+ "//content/public/browser",
+ "//skia",
+ ]
+}
+
+source_set("web_applications_test_support") {
+ testonly = true
+
+ sources = [
+ "test/test_data_retriever.cc",
+ "test/test_data_retriever.h",
+ "test/web_app_test.cc",
+ "test/web_app_test.h",
+ ]
+
+ deps = [
+ ":web_app_group",
+ ":web_applications",
+ "//chrome/browser/web_applications/components",
+ "//chrome/test:test_support",
+ "//testing/gtest",
+ ]
+}
+
+source_set("web_applications_unit_tests") {
+ testonly = true
+
+ sources = [
+ "web_app_install_manager_unittest.cc",
+ "web_app_registrar_unittest.cc",
+ ]
+
+ deps = [
+ ":web_app_group",
+ ":web_applications",
+ ":web_applications_test_support",
+ "//base/test:test_support",
+ "//chrome/browser",
+ "//chrome/browser/web_applications/components",
+ "//chrome/common",
+ "//chrome/test:test_support",
+ "//content/public/browser",
+ "//content/test:test_support",
+ "//skia",
+ ]
+}
+
+# TODO(loyso): Erase this and move WebAppProvider into web_applications set.
+# crbug.com/877898
+source_set("web_applications_on_extensions") {
+ sources = [
"web_app_provider.cc",
"web_app_provider.h",
"web_app_provider_factory.cc",
@@ -16,6 +81,7 @@
deps = [
":web_app_group",
+ ":web_applications",
"//chrome/browser/web_applications/bookmark_apps",
"//chrome/browser/web_applications/components",
"//chrome/browser/web_applications/extensions",
@@ -30,6 +96,7 @@
deps = [
":web_app_group",
+ ":web_applications_unit_tests",
"//chrome/browser/web_applications/bookmark_apps:unit_tests",
"//chrome/browser/web_applications/components:unit_tests",
"//chrome/browser/web_applications/extensions:unit_tests",
diff --git a/chrome/browser/web_applications/bookmark_apps/BUILD.gn b/chrome/browser/web_applications/bookmark_apps/BUILD.gn
index 8cb2b08d..a6fc8cf 100644
--- a/chrome/browser/web_applications/bookmark_apps/BUILD.gn
+++ b/chrome/browser/web_applications/bookmark_apps/BUILD.gn
@@ -8,6 +8,8 @@
source_set("bookmark_apps") {
sources = [
+ "bookmark_app_install_manager.cc",
+ "bookmark_app_install_manager.h",
"external_web_apps.cc",
"external_web_apps.h",
"policy/web_app_policy_constants.cc",
@@ -44,7 +46,7 @@
"//base",
"//chrome/browser",
"//chrome/browser/web_applications:web_app_group",
- "//chrome/browser/web_applications:web_applications",
+ "//chrome/browser/web_applications:web_applications_on_extensions",
"//chrome/browser/web_applications/components",
"//chrome/browser/web_applications/components:test_support",
"//chrome/browser/web_applications/extensions",
diff --git a/chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager.cc b/chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager.cc
new file mode 100644
index 0000000..db8b379
--- /dev/null
+++ b/chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager.cc
@@ -0,0 +1,30 @@
+// 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 "chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager.h"
+
+#include "chrome/browser/extensions/tab_helper.h"
+#include "chrome/browser/profiles/profile.h"
+#include "content/public/browser/web_contents.h"
+
+namespace extensions {
+
+BookmarkAppInstallManager::BookmarkAppInstallManager() = default;
+
+BookmarkAppInstallManager::~BookmarkAppInstallManager() = default;
+
+bool BookmarkAppInstallManager::CanInstallWebApp(
+ const content::WebContents* web_contents) {
+ return extensions::TabHelper::FromWebContents(web_contents)
+ ->CanCreateBookmarkApp();
+}
+
+void BookmarkAppInstallManager::InstallWebApp(
+ content::WebContents* web_contents,
+ bool force_shortcut_app) {
+ extensions::TabHelper::FromWebContents(web_contents)
+ ->CreateHostedAppFromWebContents(force_shortcut_app);
+}
+
+} // namespace extensions
diff --git a/chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager.h b/chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager.h
new file mode 100644
index 0000000..2b033414
--- /dev/null
+++ b/chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager.h
@@ -0,0 +1,29 @@
+// 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.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_BOOKMARK_APPS_BOOKMARK_APP_INSTALL_MANAGER_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_BOOKMARK_APPS_BOOKMARK_APP_INSTALL_MANAGER_H_
+
+#include "base/macros.h"
+#include "chrome/browser/web_applications/components/install_manager.h"
+
+namespace extensions {
+
+class BookmarkAppInstallManager final : public web_app::InstallManager {
+ public:
+ BookmarkAppInstallManager();
+ ~BookmarkAppInstallManager() override;
+
+ // InstallManager interface implementation.
+ bool CanInstallWebApp(const content::WebContents* web_contents) override;
+ void InstallWebApp(content::WebContents* web_contents,
+ bool force_shortcut_app) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BookmarkAppInstallManager);
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_WEB_APPLICATIONS_BOOKMARK_APPS_BOOKMARK_APP_INSTALL_MANAGER_H_
diff --git a/chrome/browser/web_applications/components/BUILD.gn b/chrome/browser/web_applications/components/BUILD.gn
index 584f6b5..16d3fd3 100644
--- a/chrome/browser/web_applications/components/BUILD.gn
+++ b/chrome/browser/web_applications/components/BUILD.gn
@@ -4,6 +4,7 @@
source_set("components") {
sources = [
+ "install_manager.h",
"install_result_code.h",
"pending_app_manager.cc",
"pending_app_manager.h",
diff --git a/chrome/browser/web_applications/components/install_manager.h b/chrome/browser/web_applications/components/install_manager.h
new file mode 100644
index 0000000..7b70fa21
--- /dev/null
+++ b/chrome/browser/web_applications/components/install_manager.h
@@ -0,0 +1,28 @@
+// 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.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_INSTALL_MANAGER_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_INSTALL_MANAGER_H_
+
+namespace content {
+class WebContents;
+}
+
+namespace web_app {
+
+class InstallManager {
+ public:
+ // Returns true if a web app can be installed for a given |web_contents|.
+ virtual bool CanInstallWebApp(const content::WebContents* web_contents) = 0;
+
+ // Starts a web app installation process for a given |web_contents|.
+ virtual void InstallWebApp(content::WebContents* web_contents,
+ bool force_shortcut_app) = 0;
+
+ virtual ~InstallManager() = default;
+};
+
+} // namespace web_app
+
+#endif // CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_INSTALL_MANAGER_H_
diff --git a/chrome/browser/web_applications/components/install_result_code.h b/chrome/browser/web_applications/components/install_result_code.h
index b557fa6..33616d6 100644
--- a/chrome/browser/web_applications/components/install_result_code.h
+++ b/chrome/browser/web_applications/components/install_result_code.h
@@ -19,6 +19,7 @@
kAlreadyInstalled,
// Catch-all failure category. More-specific failure categories are below.
kFailedUnknownReason,
+ kGetWebApplicationInfoFailed,
kPreviouslyUninstalled,
};
diff --git a/chrome/browser/web_applications/extensions/BUILD.gn b/chrome/browser/web_applications/extensions/BUILD.gn
index 689ffbe..920160c 100644
--- a/chrome/browser/web_applications/extensions/BUILD.gn
+++ b/chrome/browser/web_applications/extensions/BUILD.gn
@@ -42,9 +42,6 @@
testonly = true
sources = [
- # TODO(loyso): Extract it into web_applications_test_support set.
- "../test/test_data_retriever.cc",
- "../test/test_data_retriever.h",
"bookmark_app_installation_task_unittest.cc",
"bookmark_app_installer_unittest.cc",
"pending_bookmark_app_manager_unittest.cc",
@@ -55,6 +52,7 @@
":extensions",
"//chrome/browser",
"//chrome/browser/web_applications:web_app_group",
+ "//chrome/browser/web_applications:web_applications_test_support",
"//chrome/browser/web_applications/components",
"//chrome/common",
"//chrome/test:test_support",
@@ -82,8 +80,8 @@
"//base/test:test_support",
"//chrome/browser",
"//chrome/browser/ui",
- "//chrome/browser/web_applications",
"//chrome/browser/web_applications:web_app_group",
+ "//chrome/browser/web_applications:web_applications_on_extensions",
"//chrome/browser/web_applications/components",
"//chrome/test:test_support_ui",
"//extensions/browser",
diff --git a/chrome/browser/web_applications/test/web_app_test.cc b/chrome/browser/web_applications/test/web_app_test.cc
new file mode 100644
index 0000000..d1c0140
--- /dev/null
+++ b/chrome/browser/web_applications/test/web_app_test.cc
@@ -0,0 +1,13 @@
+// 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 "chrome/browser/web_applications/test/web_app_test.h"
+
+namespace web_app {
+
+WebAppTest::WebAppTest() = default;
+
+WebAppTest::~WebAppTest() = default;
+
+} // namespace web_app
diff --git a/chrome/browser/web_applications/test/web_app_test.h b/chrome/browser/web_applications/test/web_app_test.h
new file mode 100644
index 0000000..d96606f
--- /dev/null
+++ b/chrome/browser/web_applications/test/web_app_test.h
@@ -0,0 +1,24 @@
+// Copyright (c) 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.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_TEST_WEB_APP_TEST_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_TEST_WEB_APP_TEST_H_
+
+#include "base/macros.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+
+namespace web_app {
+
+class WebAppTest : public ChromeRenderViewHostTestHarness {
+ public:
+ WebAppTest();
+ ~WebAppTest() override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(WebAppTest);
+};
+
+} // namespace web_app
+
+#endif // CHROME_BROWSER_WEB_APPLICATIONS_TEST_WEB_APP_TEST_H_
diff --git a/chrome/browser/web_applications/web_app.cc b/chrome/browser/web_applications/web_app.cc
new file mode 100644
index 0000000..dd2e1a20
--- /dev/null
+++ b/chrome/browser/web_applications/web_app.cc
@@ -0,0 +1,25 @@
+// 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 "chrome/browser/web_applications/web_app.h"
+
+namespace web_app {
+
+WebApp::WebApp(const AppId& app_id) : app_id_(app_id) {}
+
+WebApp::~WebApp() = default;
+
+void WebApp::SetName(const std::string& name) {
+ name_ = name;
+}
+
+void WebApp::SetDescription(const std::string& description) {
+ description_ = description;
+}
+
+void WebApp::SetLaunchUrl(const std::string& launch_url) {
+ launch_url_ = launch_url;
+}
+
+} // namespace web_app
diff --git a/chrome/browser/web_applications/web_app.h b/chrome/browser/web_applications/web_app.h
new file mode 100644
index 0000000..cc592a2b
--- /dev/null
+++ b/chrome/browser/web_applications/web_app.h
@@ -0,0 +1,42 @@
+// 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.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "chrome/browser/web_applications/components/web_app_helpers.h"
+
+namespace web_app {
+
+class WebApp {
+ public:
+ explicit WebApp(const AppId& app_id);
+ ~WebApp();
+
+ const AppId& app_id() const { return app_id_; }
+
+ const std::string& name() const { return name_; }
+ const std::string& description() const { return description_; }
+ const std::string& launch_url() const { return launch_url_; }
+
+ void SetName(const std::string& name);
+ void SetDescription(const std::string& description);
+ void SetLaunchUrl(const std::string& launch_url);
+
+ private:
+ const AppId app_id_;
+
+ std::string name_;
+ std::string description_;
+ std::string launch_url_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebApp);
+};
+
+} // namespace web_app
+
+#endif // CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_H_
diff --git a/chrome/browser/web_applications/web_app_install_manager.cc b/chrome/browser/web_applications/web_app_install_manager.cc
new file mode 100644
index 0000000..ebf7b31
--- /dev/null
+++ b/chrome/browser/web_applications/web_app_install_manager.cc
@@ -0,0 +1,96 @@
+// 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 "chrome/browser/web_applications/web_app_install_manager.h"
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/web_applications/components/install_result_code.h"
+#include "chrome/browser/web_applications/components/web_app_data_retriever.h"
+#include "chrome/browser/web_applications/components/web_app_helpers.h"
+#include "chrome/browser/web_applications/web_app.h"
+#include "chrome/browser/web_applications/web_app_registrar.h"
+#include "chrome/browser/web_applications/web_app_utils.h"
+#include "chrome/common/web_application_info.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/web_contents.h"
+
+namespace web_app {
+
+WebAppInstallManager::WebAppInstallManager(Profile* profile,
+ WebAppRegistrar* registrar)
+ : profile_(profile),
+ registrar_(registrar),
+ data_retriever_(std::make_unique<WebAppDataRetriever>()) {
+ DCHECK(AllowWebAppInstallation(profile_));
+}
+
+WebAppInstallManager::~WebAppInstallManager() = default;
+
+bool WebAppInstallManager::CanInstallWebApp(
+ const content::WebContents* web_contents) {
+ return IsValidWebAppUrl(web_contents->GetURL());
+}
+
+void WebAppInstallManager::InstallWebApp(content::WebContents* web_contents,
+ bool force_shortcut_app) {
+ // TODO(loyso): Use force_shortcut_app flag during installation.
+ InstallFromWebContents(web_contents, base::DoNothing());
+}
+
+void WebAppInstallManager::SetDataRetrieverForTesting(
+ std::unique_ptr<WebAppDataRetriever> data_retriever) {
+ data_retriever_ = std::move(data_retriever);
+}
+
+void WebAppInstallManager::InstallWebAppForTesting(
+ content::WebContents* web_contents,
+ OnceInstallCallback callback) {
+ InstallFromWebContents(web_contents, std::move(callback));
+}
+
+void WebAppInstallManager::InstallFromWebContents(
+ content::WebContents* web_contents,
+ OnceInstallCallback install_callback) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ data_retriever_->GetWebApplicationInfo(
+ web_contents,
+ base::BindOnce(&WebAppInstallManager::OnGetWebApplicationInfo,
+ weak_ptr_factory_.GetWeakPtr(),
+ std::move(install_callback)));
+}
+
+void WebAppInstallManager::OnGetWebApplicationInfo(
+ OnceInstallCallback install_callback,
+ std::unique_ptr<WebApplicationInfo> web_app_info) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ if (!web_app_info) {
+ std::move(install_callback)
+ .Run(AppId(), InstallResultCode::kGetWebApplicationInfoFailed);
+ return;
+ }
+
+ // TODO(loyso): Implement installation logic from BookmarkAppHelper:
+ // - InstallableManager to get InstallableData.
+ // - UpdateWebAppInfoFromManifest.
+ // - UpdateShareTargetInPrefs.
+ // - WebAppIconDownloader.
+ // etc
+
+ const AppId app_id = GenerateAppIdFromURL(web_app_info->app_url);
+ auto web_app = std::make_unique<WebApp>(app_id);
+
+ web_app->SetName(base::UTF16ToUTF8(web_app_info->title));
+ web_app->SetDescription(base::UTF16ToUTF8(web_app_info->description));
+ web_app->SetLaunchUrl(web_app_info->app_url.spec());
+
+ registrar_->RegisterApp(std::move(web_app));
+
+ std::move(install_callback).Run(app_id, InstallResultCode::kSuccess);
+}
+
+} // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_install_manager.h b/chrome/browser/web_applications/web_app_install_manager.h
new file mode 100644
index 0000000..7f8dfd9f
--- /dev/null
+++ b/chrome/browser/web_applications/web_app_install_manager.h
@@ -0,0 +1,60 @@
+// 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.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_INSTALL_MANAGER_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_INSTALL_MANAGER_H_
+
+#include "base/callback_forward.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/web_applications/components/install_manager.h"
+#include "chrome/browser/web_applications/components/web_app_helpers.h"
+
+class Profile;
+struct WebApplicationInfo;
+
+namespace web_app {
+
+enum class InstallResultCode;
+
+class WebAppDataRetriever;
+class WebAppRegistrar;
+
+class WebAppInstallManager final : public InstallManager {
+ public:
+ WebAppInstallManager(Profile* profile, WebAppRegistrar* registrar);
+ ~WebAppInstallManager() override;
+
+ using OnceInstallCallback =
+ base::OnceCallback<void(const AppId& app_id, InstallResultCode code)>;
+
+ // InstallManager interface implementation.
+ bool CanInstallWebApp(const content::WebContents* web_contents) override;
+ void InstallWebApp(content::WebContents* web_contents,
+ bool force_shortcut_app) override;
+
+ void SetDataRetrieverForTesting(
+ std::unique_ptr<WebAppDataRetriever> data_retriever);
+
+ void InstallWebAppForTesting(content::WebContents* web_contents,
+ OnceInstallCallback callback);
+
+ private:
+ void InstallFromWebContents(content::WebContents* web_contents,
+ OnceInstallCallback callback);
+
+ void OnGetWebApplicationInfo(
+ OnceInstallCallback install_callback,
+ std::unique_ptr<WebApplicationInfo> web_app_info);
+
+ Profile* profile_;
+ WebAppRegistrar* registrar_;
+ std::unique_ptr<WebAppDataRetriever> data_retriever_;
+
+ base::WeakPtrFactory<WebAppInstallManager> weak_ptr_factory_{this};
+ DISALLOW_COPY_AND_ASSIGN(WebAppInstallManager);
+};
+
+} // namespace web_app
+
+#endif // CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_INSTALL_MANAGER_H_
diff --git a/chrome/browser/web_applications/web_app_install_manager_unittest.cc b/chrome/browser/web_applications/web_app_install_manager_unittest.cc
new file mode 100644
index 0000000..3dcb48b
--- /dev/null
+++ b/chrome/browser/web_applications/web_app_install_manager_unittest.cc
@@ -0,0 +1,98 @@
+// 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 "chrome/browser/web_applications/web_app_install_manager.h"
+
+#include "base/callback.h"
+#include "base/run_loop.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/bind_test_util.h"
+#include "chrome/browser/web_applications/components/install_result_code.h"
+#include "chrome/browser/web_applications/test/test_data_retriever.h"
+#include "chrome/browser/web_applications/test/web_app_test.h"
+#include "chrome/browser/web_applications/web_app.h"
+#include "chrome/browser/web_applications/web_app_registrar.h"
+#include "chrome/browser/web_applications/web_app_utils.h"
+#include "chrome/test/base/testing_profile.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace web_app {
+
+class WebAppInstallManagerTest : public WebAppTest {};
+
+TEST_F(WebAppInstallManagerTest, InstallFromWebContents) {
+ EXPECT_EQ(true, AllowWebAppInstallation(profile()));
+
+ auto registrar = std::make_unique<WebAppRegistrar>();
+ auto manager =
+ std::make_unique<WebAppInstallManager>(profile(), registrar.get());
+
+ auto web_app_info = std::make_unique<WebApplicationInfo>();
+
+ const GURL url = GURL("https://example.com/path");
+ const std::string name = "Name";
+ const std::string description = "Description";
+
+ const AppId app_id = GenerateAppIdFromURL(url);
+
+ web_app_info->app_url = url;
+ web_app_info->title = base::UTF8ToUTF16(name);
+ web_app_info->description = base::UTF8ToUTF16(description);
+ manager->SetDataRetrieverForTesting(
+ std::make_unique<TestDataRetriever>(std::move(web_app_info)));
+
+ base::RunLoop run_loop;
+ bool callback_called = false;
+
+ manager->InstallWebAppForTesting(
+ web_contents(),
+ base::BindLambdaForTesting(
+ [&](const AppId& installed_app_id, InstallResultCode code) {
+ EXPECT_EQ(InstallResultCode::kSuccess, code);
+ EXPECT_EQ(app_id, installed_app_id);
+ callback_called = true;
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, run_loop.QuitClosure());
+ }));
+ run_loop.Run();
+
+ EXPECT_TRUE(callback_called);
+
+ WebApp* web_app = registrar->GetAppById(app_id);
+ EXPECT_NE(nullptr, web_app);
+
+ EXPECT_EQ(app_id, web_app->app_id());
+ EXPECT_EQ(name, web_app->name());
+ EXPECT_EQ(description, web_app->description());
+ EXPECT_EQ(url.spec(), web_app->launch_url());
+}
+
+TEST_F(WebAppInstallManagerTest, GetWebApplicationInfoFailed) {
+ auto registrar = std::make_unique<WebAppRegistrar>();
+ auto manager =
+ std::make_unique<WebAppInstallManager>(profile(), registrar.get());
+
+ manager->SetDataRetrieverForTesting(std::make_unique<TestDataRetriever>(
+ std::unique_ptr<WebApplicationInfo>()));
+
+ base::RunLoop run_loop;
+ bool callback_called = false;
+
+ manager->InstallWebAppForTesting(
+ web_contents(),
+ base::BindLambdaForTesting(
+ [&](const AppId& installed_app_id, InstallResultCode code) {
+ EXPECT_EQ(InstallResultCode::kGetWebApplicationInfoFailed, code);
+ EXPECT_EQ(AppId(), installed_app_id);
+ callback_called = true;
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, run_loop.QuitClosure());
+ }));
+ run_loop.Run();
+
+ EXPECT_TRUE(callback_called);
+}
+
+} // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_provider.cc b/chrome/browser/web_applications/web_app_provider.cc
index 025b758..e407472 100644
--- a/chrome/browser/web_applications/web_app_provider.cc
+++ b/chrome/browser/web_applications/web_app_provider.cc
@@ -7,16 +7,25 @@
#include <utility>
#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/feature_list.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager.h"
#include "chrome/browser/web_applications/bookmark_apps/external_web_apps.h"
#include "chrome/browser/web_applications/bookmark_apps/policy/web_app_policy_manager.h"
#include "chrome/browser/web_applications/bookmark_apps/system_web_app_manager.h"
#include "chrome/browser/web_applications/components/web_app_constants.h"
+#include "chrome/browser/web_applications/components/web_app_helpers.h"
#include "chrome/browser/web_applications/extensions/pending_bookmark_app_manager.h"
#include "chrome/browser/web_applications/extensions/web_app_extension_ids_map.h"
+#include "chrome/browser/web_applications/web_app_install_manager.h"
#include "chrome/browser/web_applications/web_app_provider_factory.h"
+#include "chrome/browser/web_applications/web_app_registrar.h"
+#include "chrome/browser/web_applications/web_app_utils.h"
+#include "chrome/common/chrome_features.h"
#include "content/public/browser/notification_source.h"
+#include "content/public/browser/web_contents.h"
namespace web_app {
@@ -25,9 +34,39 @@
return WebAppProviderFactory::GetForProfile(profile);
}
-WebAppProvider::WebAppProvider(Profile* profile)
- : pending_app_manager_(
- std::make_unique<extensions::PendingBookmarkAppManager>(profile)) {
+// static
+WebAppProvider* WebAppProvider::GetForWebContents(
+ const content::WebContents* web_contents) {
+ Profile* profile =
+ Profile::FromBrowserContext(web_contents->GetBrowserContext());
+ DCHECK(profile);
+ return WebAppProvider::Get(profile);
+}
+
+WebAppProvider::WebAppProvider(Profile* profile) {
+ if (base::FeatureList::IsEnabled(features::kDesktopPWAsWithoutExtensions))
+ CreateWebAppsSubsystems(profile);
+ else
+ CreateBookmarkAppsSubsystems(profile);
+}
+
+WebAppProvider::~WebAppProvider() = default;
+
+void WebAppProvider::CreateWebAppsSubsystems(Profile* profile) {
+ if (!AllowWebAppInstallation(profile))
+ return;
+
+ registrar_ = std::make_unique<WebAppRegistrar>();
+ install_manager_ =
+ std::make_unique<WebAppInstallManager>(profile, registrar_.get());
+}
+
+void WebAppProvider::CreateBookmarkAppsSubsystems(Profile* profile) {
+ install_manager_ = std::make_unique<extensions::BookmarkAppInstallManager>();
+
+ pending_app_manager_ =
+ std::make_unique<extensions::PendingBookmarkAppManager>(profile);
+
if (WebAppPolicyManager::ShouldEnableForProfile(profile)) {
web_app_policy_manager_ = std::make_unique<WebAppPolicyManager>(
profile, pending_app_manager_.get());
@@ -44,8 +83,6 @@
weak_ptr_factory_.GetWeakPtr()));
}
-WebAppProvider::~WebAppProvider() = default;
-
// static
void WebAppProvider::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* registry) {
@@ -53,12 +90,38 @@
WebAppPolicyManager::RegisterProfilePrefs(registry);
}
+// static
+bool WebAppProvider::CanInstallWebApp(
+ const content::WebContents* web_contents) {
+ auto* provider = WebAppProvider::GetForWebContents(web_contents);
+ if (!provider || !provider->install_manager_)
+ return false;
+ return provider->install_manager_->CanInstallWebApp(web_contents);
+}
+
+// static
+void WebAppProvider::InstallWebApp(content::WebContents* web_contents,
+ bool force_shortcut_app) {
+ auto* provider = WebAppProvider::GetForWebContents(web_contents);
+ if (!provider || !provider->install_manager_)
+ return;
+ provider->install_manager_->InstallWebApp(web_contents, force_shortcut_app);
+}
+
void WebAppProvider::Reset() {
+ // TODO(loyso): Make it independent to the order of destruction via using two
+ // end-to-end passes:
+ // 1) Do Reset() for each subsystem to nullify pointers (detach subsystems).
+ // 2) Destroy subsystems.
+
// PendingAppManager is used by WebAppPolicyManager and therefore should be
// deleted after it.
web_app_policy_manager_.reset();
system_web_app_manager_.reset();
pending_app_manager_.reset();
+
+ install_manager_.reset();
+ registrar_.reset();
}
void WebAppProvider::Observe(int type,
diff --git a/chrome/browser/web_applications/web_app_provider.h b/chrome/browser/web_applications/web_app_provider.h
index fc10a45..9c5ef7d 100644
--- a/chrome/browser/web_applications/web_app_provider.h
+++ b/chrome/browser/web_applications/web_app_provider.h
@@ -17,13 +17,24 @@
class Profile;
+namespace content {
+class WebContents;
+}
+
namespace user_prefs {
class PrefRegistrySyncable;
}
namespace web_app {
+// Forward declarations of generalized interfaces.
class PendingAppManager;
+class InstallManager;
+
+// Forward declarations for new extension-independent subsystems.
+class WebAppRegistrar;
+
+// Forward declarations for legacy extension-based subsystems.
class WebAppPolicyManager;
class SystemWebAppManager;
@@ -34,6 +45,8 @@
public content::NotificationObserver {
public:
static WebAppProvider* Get(Profile* profile);
+ static WebAppProvider* GetForWebContents(
+ const content::WebContents* web_contents);
explicit WebAppProvider(Profile* profile);
@@ -45,6 +58,13 @@
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
+ // Returns true if a bookmark can be installed for a given |web_contents|.
+ static bool CanInstallWebApp(const content::WebContents* web_contents);
+
+ // Starts a bookmark installation process for a given |web_contents|.
+ static void InstallWebApp(content::WebContents* web_contents,
+ bool force_shortcut_app);
+
void Reset();
// content::NotificationObserver
@@ -53,10 +73,22 @@
const content::NotificationDetails& details) override;
private:
+ // Create extension-independent subsystems.
+ void CreateWebAppsSubsystems(Profile* profile);
+ // ... or create legacy extension-based subsystems.
+ void CreateBookmarkAppsSubsystems(Profile* profile);
+
void OnScanForExternalWebApps(
std::vector<web_app::PendingAppManager::AppInfo>);
+ // New extension-independent subsystems:
+ std::unique_ptr<WebAppRegistrar> registrar_;
+
+ // New generalized subsystems:
+ std::unique_ptr<InstallManager> install_manager_;
std::unique_ptr<PendingAppManager> pending_app_manager_;
+
+ // Legacy extension-based subsystems:
std::unique_ptr<WebAppPolicyManager> web_app_policy_manager_;
std::unique_ptr<SystemWebAppManager> system_web_app_manager_;
diff --git a/chrome/browser/web_applications/web_app_registrar.cc b/chrome/browser/web_applications/web_app_registrar.cc
new file mode 100644
index 0000000..47631b9
--- /dev/null
+++ b/chrome/browser/web_applications/web_app_registrar.cc
@@ -0,0 +1,40 @@
+// 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 "chrome/browser/web_applications/web_app_registrar.h"
+
+#include "base/logging.h"
+#include "chrome/browser/web_applications/web_app.h"
+
+namespace web_app {
+
+WebAppRegistrar::WebAppRegistrar() {}
+
+WebAppRegistrar::~WebAppRegistrar() = default;
+
+void WebAppRegistrar::RegisterApp(std::unique_ptr<WebApp> web_app) {
+ const auto app_id = web_app->app_id();
+ DCHECK(!app_id.empty());
+ DCHECK(!GetAppById(app_id));
+
+ registry_.emplace(std::make_pair(app_id, std::move(web_app)));
+}
+
+std::unique_ptr<WebApp> WebAppRegistrar::UnregisterApp(const AppId& app_id) {
+ DCHECK(!app_id.empty());
+
+ auto kv = registry_.find(app_id);
+ DCHECK(kv != registry_.end());
+
+ auto web_app = std::move(kv->second);
+ registry_.erase(kv);
+ return web_app;
+}
+
+WebApp* WebAppRegistrar::GetAppById(const AppId& app_id) {
+ auto kv = registry_.find(app_id);
+ return kv == registry_.end() ? nullptr : kv->second.get();
+}
+
+} // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_registrar.h b/chrome/browser/web_applications/web_app_registrar.h
new file mode 100644
index 0000000..baa57469
--- /dev/null
+++ b/chrome/browser/web_applications/web_app_registrar.h
@@ -0,0 +1,36 @@
+// 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.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_REGISTRAR_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_REGISTRAR_H_
+
+#include <map>
+#include <memory>
+
+#include "base/macros.h"
+#include "chrome/browser/web_applications/components/web_app_helpers.h"
+
+namespace web_app {
+
+class WebApp;
+
+class WebAppRegistrar {
+ public:
+ WebAppRegistrar();
+ ~WebAppRegistrar();
+
+ void RegisterApp(std::unique_ptr<WebApp> web_app);
+ std::unique_ptr<WebApp> UnregisterApp(const AppId& app_id);
+
+ WebApp* GetAppById(const AppId& app_id);
+
+ private:
+ std::map<AppId, std::unique_ptr<WebApp>> registry_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebAppRegistrar);
+};
+
+} // namespace web_app
+
+#endif // CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_REGISTRAR_H_
diff --git a/chrome/browser/web_applications/web_app_registrar_unittest.cc b/chrome/browser/web_applications/web_app_registrar_unittest.cc
new file mode 100644
index 0000000..7791528
--- /dev/null
+++ b/chrome/browser/web_applications/web_app_registrar_unittest.cc
@@ -0,0 +1,76 @@
+// 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 "chrome/browser/web_applications/web_app_registrar.h"
+
+#include "chrome/browser/web_applications/components/web_app_helpers.h"
+#include "chrome/browser/web_applications/web_app.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace web_app {
+
+TEST(WebAppRegistrar, CreateRegisterUnregister) {
+ auto registrar = std::make_unique<WebAppRegistrar>();
+ EXPECT_EQ(nullptr, registrar->GetAppById(AppId()));
+
+ const GURL launch_url = GURL("https://example.com/path");
+ const AppId app_id = GenerateAppIdFromURL(launch_url);
+ const std::string name = "Name";
+ const std::string description = "Description";
+
+ const GURL launch_url2 = GURL("https://example.com/path2");
+ const AppId app_id2 = GenerateAppIdFromURL(launch_url2);
+
+ auto web_app = std::make_unique<WebApp>(app_id);
+ auto web_app2 = std::make_unique<WebApp>(app_id2);
+
+ web_app->SetName(name);
+ web_app->SetDescription(description);
+ web_app->SetLaunchUrl(launch_url.spec());
+
+ EXPECT_EQ(nullptr, registrar->GetAppById(app_id));
+ EXPECT_EQ(nullptr, registrar->GetAppById(app_id2));
+
+ registrar->RegisterApp(std::move(web_app));
+ WebApp* app = registrar->GetAppById(app_id);
+
+ EXPECT_EQ(app_id, app->app_id());
+ EXPECT_EQ(name, app->name());
+ EXPECT_EQ(description, app->description());
+ EXPECT_EQ(launch_url.spec(), app->launch_url());
+
+ EXPECT_EQ(nullptr, registrar->GetAppById(app_id2));
+
+ registrar->RegisterApp(std::move(web_app2));
+ WebApp* app2 = registrar->GetAppById(app_id2);
+ EXPECT_EQ(app_id2, app2->app_id());
+
+ registrar->UnregisterApp(app_id);
+ EXPECT_EQ(nullptr, registrar->GetAppById(app_id));
+
+ // Check that app2 is still registered.
+ app2 = registrar->GetAppById(app_id2);
+ EXPECT_EQ(app_id2, app2->app_id());
+
+ registrar->UnregisterApp(app_id2);
+ EXPECT_EQ(nullptr, registrar->GetAppById(app_id2));
+}
+
+TEST(WebAppRegistrar, DestroyRegistrarOwningRegisteredApps) {
+ auto registrar = std::make_unique<WebAppRegistrar>();
+
+ const AppId app_id = GenerateAppIdFromURL(GURL("https://example.com/path"));
+ const AppId app_id2 = GenerateAppIdFromURL(GURL("https://example.com/path2"));
+
+ auto web_app = std::make_unique<WebApp>(app_id);
+ registrar->RegisterApp(std::move(web_app));
+
+ auto web_app2 = std::make_unique<WebApp>(app_id2);
+ registrar->RegisterApp(std::move(web_app2));
+
+ registrar.reset();
+}
+
+} // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_utils.cc b/chrome/browser/web_applications/web_app_utils.cc
new file mode 100644
index 0000000..6e5bf76
--- /dev/null
+++ b/chrome/browser/web_applications/web_app_utils.cc
@@ -0,0 +1,16 @@
+// 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 "chrome/browser/web_applications/web_app_utils.h"
+
+#include "chrome/browser/profiles/profile.h"
+
+namespace web_app {
+
+bool AllowWebAppInstallation(Profile* profile) {
+ return !profile->IsGuestSession() && !profile->IsOffTheRecord() &&
+ !profile->IsSystemProfile();
+}
+
+} // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_utils.h b/chrome/browser/web_applications/web_app_utils.h
new file mode 100644
index 0000000..e7f0291
--- /dev/null
+++ b/chrome/browser/web_applications/web_app_utils.h
@@ -0,0 +1,16 @@
+// 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.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_UTILS_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_UTILS_H_
+
+class Profile;
+
+namespace web_app {
+
+bool AllowWebAppInstallation(Profile* profile);
+
+} // namespace web_app
+
+#endif // CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_UTILS_H_
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 2e36309..18ec4dc 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -216,6 +216,11 @@
const base::Feature kDesktopPWAsStayInWindow{"DesktopPWAsStayInWindow",
base::FEATURE_ENABLED_BY_DEFAULT};
+// Enables or disables new Desktop PWAs implementation that does not use
+// extensions.
+const base::Feature kDesktopPWAsWithoutExtensions{
+ "DesktopPWAsWithoutExtensions", base::FEATURE_DISABLED_BY_DEFAULT};
+
// Disables downloads of unsafe file types over HTTP.
const base::Feature kDisallowUnsafeHttpDownloads{
"DisallowUnsafeHttpDownloads", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 3961025d..97e2073b 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -134,6 +134,9 @@
extern const base::Feature kDesktopPWAsStayInWindow;
COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kDesktopPWAsWithoutExtensions;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
extern const base::Feature kDisallowUnsafeHttpDownloads;
COMPONENT_EXPORT(CHROME_FEATURES)
extern const char kDisallowUnsafeHttpDownloadsParamName[];