Commit 35be2105 authored by Alan Cutter's avatar Alan Cutter Committed by Commit Bot

Add launch_query_params option to default web app config

This CL adds a "launch_query_params" field to default web app JSON
configs that causes the web app to launch with the specified query
params appended to the app's start_url.

Bug: 1045537
Change-Id: Ib6025ae39eac7a6f710b2817a0f2ad30437e29c2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2377044Reviewed-by: default avatarEric Willigers <ericwilligers@chromium.org>
Commit-Queue: Alan Cutter <alancutter@chromium.org>
Cr-Commit-Position: refs/heads/master@{#811641}
parent d6b532ce
......@@ -84,7 +84,7 @@ Browser* LaunchWebAppBrowser(Profile* profile, const AppId& app_id) {
// Launches the app, waits for the app url to load.
Browser* LaunchWebAppBrowserAndWait(Profile* profile, const AppId& app_id) {
ui_test_utils::UrlLoadObserver url_observer(
WebAppProvider::Get(profile)->registrar().GetAppStartUrl(app_id),
WebAppProvider::Get(profile)->registrar().GetAppLaunchUrl(app_id),
content::NotificationService::AllSources());
Browser* const app_browser = LaunchWebAppBrowser(profile, app_id);
url_observer.Wait();
......
......@@ -131,7 +131,7 @@ content::WebContents* WebAppLaunchManager::OpenApplication(
params.override_url.is_empty()
? os_integration_manager
.GetMatchingFileHandlerURL(params.app_id, params.launch_files)
.value_or(provider_->registrar().GetAppStartUrl(params.app_id))
.value_or(provider_->registrar().GetAppLaunchUrl(params.app_id))
: params.override_url;
// Place new windows on the specified display.
......
......@@ -131,6 +131,23 @@ bool AppRegistrar::HasExternalAppWithInstallSource(
profile()->GetPrefs(), app_id, install_source);
}
GURL AppRegistrar::GetAppLaunchUrl(const AppId& app_id) const {
const GURL& start_url = GetAppStartUrl(app_id);
const std::string* launch_query_params = GetAppLaunchQueryParams(app_id);
if (!start_url.is_valid() || !launch_query_params)
return start_url;
GURL::Replacements replacements;
if (start_url.query_piece().empty()) {
replacements.SetQueryStr(*launch_query_params);
return start_url.ReplaceComponents(replacements);
}
std::string query_params = start_url.query() + "&" + *launch_query_params;
replacements.SetQueryStr(query_params);
return start_url.ReplaceComponents(replacements);
}
extensions::BookmarkAppRegistrar* AppRegistrar::AsBookmarkAppRegistrar() {
return nullptr;
}
......
......@@ -90,6 +90,11 @@ class AppRegistrar {
virtual base::Optional<SkColor> GetAppBackgroundColor(
const AppId& app_id) const = 0;
virtual const GURL& GetAppStartUrl(const AppId& app_id) const = 0;
virtual const std::string* GetAppLaunchQueryParams(
const AppId& app_id) const = 0;
// Returns the start_url with launch_query_params appended to the end if any.
GURL GetAppLaunchUrl(const AppId& app_id) const;
// TODO(crbug.com/910016): Replace uses of this with GetAppScope().
virtual base::Optional<GURL> GetAppScopeInternal(
......
......@@ -120,6 +120,8 @@ InstallManager::InstallParams ConvertExternalInstallOptionsToParams(
params.additional_search_terms = install_options.additional_search_terms;
params.launch_query_params = install_options.launch_query_params;
return params;
}
......
......@@ -103,6 +103,9 @@ struct ExternalInstallOptions {
// it.
bool reinstall_placeholder = false;
// Optional query parameters to add to the start_url when launching the app.
base::Optional<std::string> launch_query_params;
// Whether we should load |service_worker_registration_url| after successful
// installation to allow the site to install its service worker and set up
// offline caching.
......
......@@ -122,6 +122,8 @@ class InstallManager {
bool require_manifest = false;
std::vector<std::string> additional_search_terms;
base::Optional<std::string> launch_query_params;
};
// Starts a background web app installation process for a given
// |web_contents|.
......
......@@ -149,6 +149,12 @@ const GURL& BookmarkAppRegistrar::GetAppStartUrl(
: GURL::EmptyGURL();
}
// Only implemented for WebApp. Bookmark apps are going away.
const std::string* BookmarkAppRegistrar::GetAppLaunchQueryParams(
const web_app::AppId& app_id) const {
return nullptr;
}
base::Optional<GURL> BookmarkAppRegistrar::GetAppScopeInternal(
const web_app::AppId& app_id) const {
const Extension* extension = GetBookmarkAppDchecked(app_id);
......
......@@ -46,6 +46,8 @@ class BookmarkAppRegistrar : public web_app::AppRegistrar,
base::Optional<SkColor> GetAppBackgroundColor(
const web_app::AppId& app_id) const override;
const GURL& GetAppStartUrl(const web_app::AppId& app_id) const override;
const std::string* GetAppLaunchQueryParams(
const web_app::AppId& app_id) const override;
base::Optional<GURL> GetAppScopeInternal(
const web_app::AppId& app_id) const override;
web_app::DisplayMode GetAppDisplayMode(
......
......@@ -81,8 +81,73 @@ class ExternalWebAppManagerBrowserTest
~ExternalWebAppManagerBrowserTest() override = default;
};
// This JSON config functionality is only available on Chrome OS.
#if defined(OS_CHROMEOS)
IN_PROC_BROWSER_TEST_F(ExternalWebAppManagerBrowserTest,
LaunchQueryParamsBasic) {
ASSERT_TRUE(embedded_test_server()->Start());
GURL start_url = embedded_test_server()->GetURL("/web_apps/basic.html");
AppId app_id = GenerateAppIdFromURL(start_url);
EXPECT_FALSE(registrar().IsInstalled(app_id));
InstallResultCode code =
SyncDefaultAppConfig(start_url, base::ReplaceStringPlaceholders(
R"({
"app_url": "$1",
"launch_container": "window",
"user_type": ["unmanaged"],
"launch_query_params": "test_launch_params"
})",
{start_url.spec()}, nullptr));
EXPECT_EQ(code, InstallResultCode::kSuccessNewInstall);
EXPECT_TRUE(registrar().IsInstalled(app_id));
EXPECT_EQ(registrar().GetAppStartUrl(app_id).spec(), start_url);
GURL launch_url =
embedded_test_server()->GetURL("/web_apps/basic.html?test_launch_params");
EXPECT_EQ(registrar().GetAppLaunchUrl(app_id), launch_url);
Browser* app_browser = LaunchWebAppBrowserAndWait(profile(), app_id);
EXPECT_EQ(
app_browser->tab_strip_model()->GetActiveWebContents()->GetVisibleURL(),
launch_url);
}
IN_PROC_BROWSER_TEST_F(ExternalWebAppManagerBrowserTest,
LaunchQueryParamsComplex) {
ASSERT_TRUE(embedded_test_server()->Start());
GURL install_url = embedded_test_server()->GetURL(
"/web_apps/query_params_in_start_url.html");
GURL start_url = embedded_test_server()->GetURL(
"/web_apps/query_params_in_start_url.html?query_params=in&start=url");
AppId app_id = GenerateAppIdFromURL(start_url);
EXPECT_FALSE(registrar().IsInstalled(app_id));
InstallResultCode code =
SyncDefaultAppConfig(install_url, base::ReplaceStringPlaceholders(
R"({
"app_url": "$1",
"launch_container": "window",
"user_type": ["unmanaged"],
"launch_query_params": "!@#$$%^*&)("
})",
{install_url.spec()}, nullptr));
EXPECT_EQ(code, InstallResultCode::kSuccessNewInstall);
EXPECT_TRUE(registrar().IsInstalled(app_id));
EXPECT_EQ(registrar().GetAppStartUrl(app_id).spec(), start_url);
GURL launch_url = embedded_test_server()->GetURL(
"/web_apps/"
"query_params_in_start_url.html?query_params=in&start=url&!@%23$%^*&)(");
EXPECT_EQ(registrar().GetAppLaunchUrl(app_id), launch_url);
Browser* app_browser = LaunchWebAppBrowserAndWait(profile(), app_id);
EXPECT_EQ(
app_browser->tab_strip_model()->GetActiveWebContents()->GetVisibleURL(),
launch_url);
}
IN_PROC_BROWSER_TEST_F(ExternalWebAppManagerBrowserTest, UninstallAndReplace) {
ASSERT_TRUE(embedded_test_server()->Start());
......@@ -117,6 +182,10 @@ IN_PROC_BROWSER_TEST_F(ExternalWebAppManagerBrowserTest, UninstallAndReplace) {
EXPECT_EQ(app, uninstalled_app.get());
}
// The offline manifest JSON config functionality is only available on Chrome
// OS.
#if defined(OS_CHROMEOS)
// Check that offline fallback installs work offline.
IN_PROC_BROWSER_TEST_F(ExternalWebAppManagerBrowserTest,
OfflineFallbackManifestSiteOffline) {
......
......@@ -71,6 +71,10 @@ constexpr char kLaunchContainer[] = "launch_container";
constexpr char kLaunchContainerTab[] = "tab";
constexpr char kLaunchContainerWindow[] = "window";
// kLaunchQueryParams is an optional string which specifies query parameters to
// add to the start_url when launching the app.
constexpr char kLaunchQueryParams[] = "launch_query_params";
// kLoadAndAwaitServiceWorkerRegistration is an optional bool that specifies
// whether to fetch the |kServiceWorkerRegistrationUrl| after installation to
// allow time for the app to register its service worker. This is done as a
......@@ -281,6 +285,16 @@ ExternalConfigParseResult ParseConfig(FileUtilsWrapper& file_utils,
return Result::Error();
}
// launch_query_params
value = app_config.FindKey(kLaunchQueryParams);
if (value) {
if (!value->is_string()) {
LOG(ERROR) << file << " had an invalid " << kLaunchQueryParams;
return Result::Error();
}
options.launch_query_params = value->GetString();
}
// load_and_await_service_worker_registration
value = app_config.FindKey(kLoadAndAwaitServiceWorkerRegistration);
if (value) {
......
......@@ -157,4 +157,6 @@ message WebAppProto {
optional RunOnOsLoginMode user_run_on_os_login_mode = 24;
optional ShareTarget share_target = 25;
optional string launch_query_params = 26;
}
......@@ -112,6 +112,11 @@ const GURL& TestAppRegistrar::GetAppStartUrl(const AppId& app_id) const {
return iterator->second.launch_url;
}
const std::string* TestAppRegistrar::GetAppLaunchQueryParams(
const AppId& app_id) const {
return nullptr;
}
base::Optional<GURL> TestAppRegistrar::GetAppScopeInternal(
const AppId& app_id) const {
const auto& result = installed_apps_.find(app_id);
......
......@@ -60,6 +60,8 @@ class TestAppRegistrar : public AppRegistrar {
base::Optional<SkColor> GetAppBackgroundColor(
const AppId& app_id) const override;
const GURL& GetAppStartUrl(const AppId& app_id) const override;
const std::string* GetAppLaunchQueryParams(
const AppId& app_id) const override;
base::Optional<GURL> GetAppScopeInternal(const AppId& app_id) const override;
DisplayMode GetAppDisplayMode(const AppId& app_id) const override;
DisplayMode GetAppUserDisplayMode(const AppId& app_id) const override;
......
......@@ -263,6 +263,11 @@ void WebApp::SetSyncFallbackData(SyncFallbackData sync_fallback_data) {
sync_fallback_data_ = std::move(sync_fallback_data);
}
void WebApp::SetLaunchQueryParams(
base::Optional<std::string> launch_query_params) {
launch_query_params_ = std::move(launch_query_params);
}
WebApp::SyncFallbackData::SyncFallbackData() = default;
WebApp::SyncFallbackData::~SyncFallbackData() = default;
......@@ -288,6 +293,9 @@ std::ostream& operator<<(std::ostream& out, const WebApp& app) {
out << "app_id: " << app.app_id_ << std::endl
<< " name: " << app.name_ << std::endl
<< " start_url: " << app.start_url_ << std::endl
<< " launch_query_params: "
<< (app.launch_query_params_ ? *app.launch_query_params_ : std::string())
<< std::endl
<< " scope: " << app.scope_ << std::endl
<< " theme_color: " << ColorToString(app.theme_color_) << std::endl
<< " background_color: " << ColorToString(app.background_color_)
......@@ -354,8 +362,8 @@ bool operator!=(const WebApp::SyncFallbackData& sync_fallback_data1,
bool operator==(const WebApp& app1, const WebApp& app2) {
return std::tie(app1.app_id_, app1.sources_, app1.name_, app1.start_url_,
app1.description_, app1.scope_, app1.theme_color_,
app1.background_color_, app1.icon_infos_,
app1.launch_query_params_, app1.description_, app1.scope_,
app1.theme_color_, app1.background_color_, app1.icon_infos_,
app1.downloaded_icon_sizes_any_,
app1.downloaded_icon_sizes_maskable_, app1.is_generated_icon_,
app1.display_mode_, app1.display_mode_override_,
......@@ -367,8 +375,8 @@ bool operator==(const WebApp& app1, const WebApp& app2) {
app1.sync_fallback_data_, app1.last_launch_time_,
app1.install_time_, app1.run_on_os_login_mode_) ==
std::tie(app2.app_id_, app2.sources_, app2.name_, app2.start_url_,
app2.description_, app2.scope_, app2.theme_color_,
app2.background_color_, app2.icon_infos_,
app2.launch_query_params_, app2.description_, app2.scope_,
app2.theme_color_, app2.background_color_, app2.icon_infos_,
app2.downloaded_icon_sizes_any_,
app2.downloaded_icon_sizes_maskable_, app2.is_generated_icon_,
app2.display_mode_, app2.display_mode_override_,
......
......@@ -45,6 +45,11 @@ class WebApp {
const std::string& description() const { return description_; }
const GURL& start_url() const { return start_url_; }
const std::string* launch_query_params() const {
return launch_query_params_ ? &launch_query_params_.value() : nullptr;
}
const GURL& scope() const { return scope_; }
const base::Optional<SkColor>& theme_color() const { return theme_color_; }
......@@ -171,6 +176,7 @@ class WebApp {
void SetName(const std::string& name);
void SetDescription(const std::string& description);
void SetStartUrl(const GURL& launch_url);
void SetLaunchQueryParams(base::Optional<std::string> launch_query_params);
void SetScope(const GURL& scope);
void SetThemeColor(base::Optional<SkColor> theme_color);
void SetBackgroundColor(base::Optional<SkColor> background_color);
......@@ -218,6 +224,7 @@ class WebApp {
std::string name_;
std::string description_;
GURL start_url_;
base::Optional<std::string> launch_query_params_;
// TODO(loyso): Implement IsValid() function that verifies that the start_url
// is within the scope.
GURL scope_;
......
......@@ -157,6 +157,9 @@ std::unique_ptr<WebAppProto> WebAppDatabase::CreateWebAppProto(
local_data->set_is_locally_installed(web_app.is_locally_installed());
// Optional fields:
if (web_app.launch_query_params())
local_data->set_launch_query_params(*web_app.launch_query_params());
if (web_app.display_mode() != DisplayMode::kUndefined) {
local_data->set_display_mode(
ToWebAppProtoDisplayMode(web_app.display_mode()));
......@@ -394,6 +397,9 @@ std::unique_ptr<WebApp> WebAppDatabase::CreateWebApp(
}
// Optional fields:
if (local_data.has_launch_query_params())
web_app->SetLaunchQueryParams(local_data.launch_query_params());
if (local_data.has_display_mode())
web_app->SetDisplayMode(ToMojomDisplayMode(local_data.display_mode()));
......
......@@ -245,6 +245,9 @@ class WebAppDatabaseTest : public WebAppTest {
app->SetDisplayModeOverride(std::vector<DisplayMode>(
display_mode_override.begin(), display_mode_override.end()));
if (random.next_bool())
app->SetLaunchQueryParams(base::NumberToString(random.next_uint()));
const RunOnOsLoginMode run_on_os_login_modes[3] = {
RunOnOsLoginMode::kUndefined, RunOnOsLoginMode::kWindowed,
RunOnOsLoginMode::kMinimized};
......
......@@ -449,6 +449,9 @@ void WebAppInstallTask::OnGetWebApplicationInfo(
if (!search_term.empty())
web_app_info->additional_search_terms.push_back(std::move(search_term));
}
if (install_params_->launch_query_params)
web_app_info->launch_query_params = install_params_->launch_query_params;
}
data_retriever_->CheckInstallabilityAndRetrieveManifest(
......
......@@ -157,6 +157,7 @@ void SetWebAppManifestFields(const WebApplicationInfo& web_app_info,
web_app.SetDisplayModeOverride(web_app_info.display_override);
web_app.SetDescription(base::UTF16ToUTF8(web_app_info.description));
web_app.SetLaunchQueryParams(web_app_info.launch_query_params);
web_app.SetScope(web_app_info.scope);
DCHECK(!web_app_info.theme_color.has_value() ||
SkColorGetA(*web_app_info.theme_color) == SK_AlphaOPAQUE);
......
......@@ -92,6 +92,12 @@ const GURL& WebAppRegistrar::GetAppStartUrl(const AppId& app_id) const {
return web_app ? web_app->start_url() : GURL::EmptyGURL();
}
const std::string* WebAppRegistrar::GetAppLaunchQueryParams(
const AppId& app_id) const {
auto* web_app = GetAppById(app_id);
return web_app ? web_app->launch_query_params() : nullptr;
}
base::Optional<GURL> WebAppRegistrar::GetAppScopeInternal(
const AppId& app_id) const {
auto* web_app = GetAppById(app_id);
......
......@@ -49,6 +49,8 @@ class WebAppRegistrar : public AppRegistrar, public ProfileManagerObserver {
base::Optional<SkColor> GetAppBackgroundColor(
const AppId& app_id) const override;
const GURL& GetAppStartUrl(const AppId& app_id) const override;
const std::string* GetAppLaunchQueryParams(
const AppId& app_id) const override;
base::Optional<GURL> GetAppScopeInternal(const AppId& app_id) const override;
DisplayMode GetAppDisplayMode(const AppId& app_id) const override;
DisplayMode GetAppUserDisplayMode(const AppId& app_id) const override;
......
......@@ -103,6 +103,9 @@ struct WebApplicationInfo {
// https://www.w3.org/TR/appmanifest/#start_url-member
GURL start_url;
// Optional query parameters to add to the start_url when launching the app.
base::Optional<std::string> launch_query_params;
// Scope for the app. Dictates what URLs will be opened in the app.
GURL scope;
......
<!DOCTYPE html>
<html>
<head>
<link rel="manifest" href="query_params_in_start_url.json">
<link rel="icon" href="basic-48.png">
</head>
<body>
<h1>Query params in start_url</h1>
<script>
navigator.serviceWorker.register('/web_apps/service_worker.js');
</script>
</body>
</html>
{
"name": "Query params in start_url",
"icons": [
{
"src": "basic-48.png",
"sizes": "48x48",
"type": "image/png"
},
{
"src": "basic-192.png",
"sizes": "192x192",
"type": "image/png"
}
],
"start_url": "query_params_in_start_url.html?query_params=in&start=url",
"display": "standalone"
}
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