Desktop PWA: Adding prototype for Run PWA on user OS login
This is part 1 of 3 of the prototype to configure PWAS to run on
OS login.
Updates for the prototype include:
- Added feature flag "Desktop PWAs run on OS login", disabled by default.
- Added Startup folder to Windows base paths and shell util.
- Added "in_startup" entry to Web App Shortcut locations.
- If feature flag is enabled, show a checkbox in the PWA install dialog.
- If checked, PWA install task creates an additional shortcut in
Windows Startup folder by setting "in_startup" location to true.
Additional parts for the feature to come in next CLs.
Explainer: https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/master/RunOnLogin/Explainer.md
I2P: https://groups.google.com/a/chromium.org/forum/#!msg/blink-dev/T6d2zqF_jpw/76TP7Bc2DwAJ
Bug: 897302
Change-Id: I0870e5a26e94e8e60001b78c95e53da134388f0a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2026256
Commit-Queue: Carlos Frias <carlos.frias@microsoft.com>
Reviewed-by: Alexey Baskakov <loyso@chromium.org>
Reviewed-by: Greg Thompson <grt@chromium.org>
Reviewed-by: Alan Cutter <alancutter@chromium.org>
Cr-Commit-Position: refs/heads/master@{#772460}
diff --git a/base/base_paths_win.cc b/base/base_paths_win.cc
index 453b249c..1fe49b61 100644
--- a/base/base_paths_win.cc
+++ b/base/base_paths_win.cc
@@ -107,6 +107,18 @@
return false;
cur = FilePath(system_buffer);
break;
+ case base::DIR_COMMON_STARTUP:
+ if (FAILED(SHGetFolderPath(nullptr, CSIDL_COMMON_STARTUP, nullptr,
+ SHGFP_TYPE_CURRENT, system_buffer)))
+ return false;
+ cur = FilePath(system_buffer);
+ break;
+ case base::DIR_USER_STARTUP:
+ if (FAILED(SHGetFolderPath(nullptr, CSIDL_STARTUP, nullptr,
+ SHGFP_TYPE_CURRENT, system_buffer)))
+ return false;
+ cur = FilePath(system_buffer);
+ break;
case base::DIR_APP_DATA:
if (FAILED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT,
system_buffer)))
diff --git a/base/base_paths_win.h b/base/base_paths_win.h
index 2db16a6..df1991c 100644
--- a/base/base_paths_win.h
+++ b/base/base_paths_win.h
@@ -30,6 +30,10 @@
// Start Menu\Programs"
DIR_START_MENU, // Usually "C:\Users\<user>\AppData\Roaming\
// Microsoft\Windows\Start Menu\Programs"
+ DIR_COMMON_STARTUP, // Usually "C:\ProgramData\Microsoft\Windows\
+ // Start Menu\Programs\Startup"
+ DIR_USER_STARTUP, // Usually "C:\Users\<user>\AppData\Roaming\
+ // Microsoft\Windows\Start Menu\Programs\Startup"
DIR_APP_DATA, // Application Data directory under the user
// profile.
DIR_LOCAL_APP_DATA, // "Local Settings\Application Data" directory
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 84f1ae1..c07ec50d 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -2297,6 +2297,12 @@
<message name="IDS_INSTALL_PWA_BUTTON_LABEL" desc="Text for button that installs a web app to the operating system.">
Install
</message>
+ <message name="IDS_INSTALL_PWA_RUN_ON_OS_LOGIN_LABEL" desc="Text for checkbox label for auto starting the web app with user login to the operating system session.">
+ {0, select,
+ tablet {Start app when you sign in to your tablet}
+ computer {Start app when you sign in to your computer}
+ other {Start app when you sign in to your device}}
+ </message>
<message name="IDS_BOOKMARK_APP_AX_BUBBLE_NAME_LABEL" desc="Text preceding the name of a bookmark app, read by spoken feedback.">
Shortcut name
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index d0e0107..02196125 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2734,6 +2734,10 @@
flag_descriptions::kDesktopPWAsWithoutExtensionsName,
flag_descriptions::kDesktopPWAsWithoutExtensionsDescription, kOsDesktop,
FEATURE_VALUE_TYPE(features::kDesktopPWAsWithoutExtensions)},
+ {"enable-desktop-pwas-run-on-os-login",
+ flag_descriptions::kDesktopPWAsRunOnOsLoginName,
+ flag_descriptions::kDesktopPWAsRunOnOsLoginDescription, kOsDesktop,
+ FEATURE_VALUE_TYPE(features::kDesktopPWAsRunOnOsLogin)},
{"enable-system-webapps", flag_descriptions::kEnableSystemWebAppsName,
flag_descriptions::kEnableSystemWebAppsDescription, kOsDesktop,
FEATURE_VALUE_TYPE(features::kSystemWebApps)},
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 58af1ca..281969d8 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1453,6 +1453,11 @@
"expiry_milestone": 88
},
{
+ "name": "enable-desktop-pwas-run-on-os-login",
+ "owners": [ "cafrias@microsoft.com", "desktop-pwas-team@google.com" ],
+ "expiry_milestone": 85
+ },
+ {
"name": "enable-desktop-pwas-tab-strip",
"owners": [ "desktop-pwas-team@google.com" ],
"expiry_milestone": 88
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 054822a2..bff329c 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -634,6 +634,11 @@
"is incomplete and may corrupt your synced Chrome profile. Test accounts "
"only are advised.";
+const char kDesktopPWAsRunOnOsLoginName[] = "Desktop PWAs run on OS login";
+const char kDesktopPWAsRunOnOsLoginDescription[] =
+ "Enable installed PWAs to be configured to automatically start when the OS "
+ "user logs in.";
+
const char kEnableSystemWebAppsName[] = "System Web Apps";
const char kEnableSystemWebAppsDescription[] =
"Experimental system for using the Desktop PWA framework for running System"
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index e024d558..352316d 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -385,6 +385,9 @@
extern const char kDesktopPWAsWithoutExtensionsName[];
extern const char kDesktopPWAsWithoutExtensionsDescription[];
+extern const char kDesktopPWAsRunOnOsLoginName[];
+extern const char kDesktopPWAsRunOnOsLoginDescription[];
+
extern const char kEnableSystemWebAppsName[];
extern const char kEnableSystemWebAppsDescription[];
diff --git a/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.cc b/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.cc
index abf2070..717fbbb 100644
--- a/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.cc
+++ b/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.cc
@@ -4,8 +4,12 @@
#include "chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.h"
+#include <utility>
+
+#include "base/i18n/message_formatter.h"
#include "base/strings/string16.h"
#include "base/strings/string_util.h"
+#include "build/build_config.h"
#include "chrome/browser/ui/browser_dialogs.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/views/chrome_layout_provider.h"
@@ -29,6 +33,12 @@
namespace {
+#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
+constexpr char kDeviceTypeForCheckbox[] = "computer";
+#else
+constexpr char kDeviceTypeForCheckbox[] = "other";
+#endif
+
PWAConfirmationBubbleView* g_bubble_ = nullptr;
bool g_auto_accept_pwa_for_testing = false;
@@ -79,6 +89,11 @@
return g_bubble_;
}
+// static
+PWAConfirmationBubbleView* PWAConfirmationBubbleView::GetBubbleForTesting() {
+ return g_bubble_;
+}
+
PWAConfirmationBubbleView::PWAConfirmationBubbleView(
views::View* anchor_view,
views::Button* highlight_button,
@@ -86,7 +101,8 @@
chrome::AppInstallationAcceptanceCallback callback)
: LocationBarBubbleDelegateView(anchor_view, nullptr),
web_app_info_(std::move(web_app_info)),
- callback_(std::move(callback)) {
+ callback_(std::move(callback)),
+ run_on_os_login_(nullptr) {
DCHECK(web_app_info_);
WidgetDelegate::SetShowCloseButton(true);
@@ -136,6 +152,17 @@
web_app_info_->enable_experimental_tabbed_window);
}
+ // TODO(crbug.com/897302): This is an experimental UI added to prototype
+ // The PWA Run on OS Login feature, final design is yet to be decided.
+ if (base::FeatureList::IsEnabled(features::kDesktopPWAsRunOnOsLogin)) {
+ // TODO(crbug.com/897302): Detect the type of device and supply the proper
+ // constant for the string.
+ run_on_os_login_ = labels->AddChildView(std::make_unique<views::Checkbox>(
+ base::i18n::MessageFormatter::FormatWithNumberedArgs(
+ l10n_util::GetStringUTF16(IDS_INSTALL_PWA_RUN_ON_OS_LOGIN_LABEL),
+ kDeviceTypeForCheckbox)));
+ }
+
chrome::RecordDialogCreation(chrome::DialogIdentifier::PWA_CONFIRMATION);
SetHighlightedButton(highlight_button);
@@ -162,10 +189,23 @@
web_app_info_->enable_experimental_tabbed_window =
tabbed_window_checkbox_->GetChecked();
}
+
+ // User opt-in in checkbox is passed via the web_app_info structure to the
+ // underlying PWA install code.
+ // The definition of run_on_os_login_ is dependent on
+ // features::kDesktopPWAsRunOnOsLogin being enabled.
+ if (run_on_os_login_)
+ web_app_info_->run_on_os_login = run_on_os_login_->GetChecked();
+
std::move(callback_).Run(true, std::move(web_app_info_));
return true;
}
+views::Checkbox*
+PWAConfirmationBubbleView::GetRunOnOsLoginCheckboxForTesting() {
+ return run_on_os_login_;
+}
+
namespace chrome {
void ShowPWAInstallBubble(content::WebContents* web_contents,
diff --git a/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.h b/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.h
index f63db32a..d32b360 100644
--- a/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.h
+++ b/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.h
@@ -5,6 +5,8 @@
#ifndef CHROME_BROWSER_UI_VIEWS_WEB_APPS_PWA_CONFIRMATION_BUBBLE_VIEW_H_
#define CHROME_BROWSER_UI_VIEWS_WEB_APPS_PWA_CONFIRMATION_BUBBLE_VIEW_H_
+#include <memory>
+
#include "chrome/browser/ui/browser_dialogs.h"
#include "chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.h"
#include "chrome/common/web_application_info.h"
@@ -20,6 +22,7 @@
class PWAConfirmationBubbleView : public LocationBarBubbleDelegateView {
public:
static bool IsShowing();
+ static PWAConfirmationBubbleView* GetBubbleForTesting();
PWAConfirmationBubbleView(views::View* anchor_view,
views::Button* highlight_button,
@@ -31,10 +34,12 @@
views::View* GetInitiallyFocusedView() override;
void WindowClosing() override;
bool Accept() override;
+ views::Checkbox* GetRunOnOsLoginCheckboxForTesting();
private:
std::unique_ptr<WebApplicationInfo> web_app_info_;
chrome::AppInstallationAcceptanceCallback callback_;
+ views::Checkbox* run_on_os_login_ = nullptr;
// Checkbox to launch window with tab strip.
views::Checkbox* tabbed_window_checkbox_ = nullptr;
diff --git a/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view_browsertest.cc b/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view_browsertest.cc
index cd6912c..09a8204c 100644
--- a/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view_browsertest.cc
@@ -2,18 +2,78 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <memory>
+#include <utility>
+
#include "base/bind_helpers.h"
#include "base/macros.h"
+#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/bind_test_util.h"
+#include "base/test/scoped_feature_list.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_dialogs.h"
+#include "chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.h"
#include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
#include "chrome/browser/web_applications/components/web_app_id.h"
+#include "chrome/common/chrome_features.h"
#include "chrome/common/web_application_info.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "content/public/test/browser_test.h"
+#include "ui/views/controls/button/checkbox.h"
-using PWAConfirmationBubbleViewBrowserTest = InProcessBrowserTest;
+class PWAConfirmationBubbleViewBrowserTest : public InProcessBrowserTest {
+ public:
+ PWAConfirmationBubbleViewBrowserTest() {
+ // Tests will crash if kDesktopPWAsRunOnOsLogin feature flag is not enabled.
+ // AcceptBubbleInPWAWindowRunOnOsLoginChecked and
+ // AcceptBubbleInPWAWindowRunOnOsLoginUnchecked tests interact with the
+ // checkbox which is only added if feature flag is enabled.
+ scoped_feature_list_.InitAndEnableFeature(
+ features::kDesktopPWAsRunOnOsLogin);
+ }
+ ~PWAConfirmationBubbleViewBrowserTest() override = default;
+
+ std::unique_ptr<WebApplicationInfo> GetAppInfo() {
+ auto app_info = std::make_unique<WebApplicationInfo>();
+ app_info->title = base::UTF8ToUTF16("Test app 2");
+ app_info->app_url = GURL("https://example2.com");
+ app_info->open_as_window = true;
+ return app_info;
+ }
+
+ std::unique_ptr<WebApplicationInfo> GetCallbackAppInfoFromDialog(
+ bool run_on_os_login_checked) {
+ std::unique_ptr<WebApplicationInfo> resulting_app_info = nullptr;
+ auto app_info = GetAppInfo();
+
+ base::RunLoop loop;
+ // Show the PWA install dialog.
+ chrome::ShowPWAInstallBubble(
+ browser()->tab_strip_model()->GetActiveWebContents(),
+ std::move(app_info),
+ base::BindLambdaForTesting(
+ [&](bool accepted,
+ std::unique_ptr<WebApplicationInfo> app_info_callback) {
+ resulting_app_info = std::move(app_info_callback);
+ loop.Quit();
+ }));
+
+ // Get bubble dialog, set checkbox and accept.
+ PWAConfirmationBubbleView* bubble_dialog =
+ PWAConfirmationBubbleView::GetBubbleForTesting();
+ bubble_dialog->GetRunOnOsLoginCheckboxForTesting()->SetChecked(
+ run_on_os_login_checked);
+ bubble_dialog->Accept();
+
+ loop.Run();
+
+ return resulting_app_info;
+ }
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
+};
IN_PROC_BROWSER_TEST_F(PWAConfirmationBubbleViewBrowserTest,
ShowBubbleInPWAWindow) {
@@ -24,10 +84,7 @@
web_app::AppId app_id = web_app::InstallWebApp(profile, std::move(app_info));
Browser* browser = web_app::LaunchWebAppBrowser(profile, app_id);
- app_info = std::make_unique<WebApplicationInfo>();
- app_info->title = base::UTF8ToUTF16("Test app 2");
- app_info->app_url = GURL("https://example2.com");
- app_info->open_as_window = true;
+ app_info = GetAppInfo();
// Tests that we don't crash when showing the install prompt in a PWA window.
chrome::ShowPWAInstallBubble(
browser->tab_strip_model()->GetActiveWebContents(), std::move(app_info),
@@ -43,3 +100,17 @@
browser->tab_strip_model()->GetActiveWebContents(), std::move(app_info),
base::DoNothing());
}
+
+IN_PROC_BROWSER_TEST_F(PWAConfirmationBubbleViewBrowserTest,
+ AcceptBubbleInPWAWindowRunOnOsLoginChecked) {
+ auto resulting_app_info =
+ GetCallbackAppInfoFromDialog(/*run_on_os_login_checked=*/true);
+ EXPECT_TRUE(resulting_app_info->run_on_os_login);
+}
+
+IN_PROC_BROWSER_TEST_F(PWAConfirmationBubbleViewBrowserTest,
+ AcceptBubbleInPWAWindowRunOnOsLoginUnchecked) {
+ auto resulting_app_info =
+ GetCallbackAppInfoFromDialog(/*run_on_os_login_checked=*/false);
+ EXPECT_FALSE(resulting_app_info->run_on_os_login);
+}
diff --git a/chrome/browser/ui/web_applications/web_app_menu_model.cc b/chrome/browser/ui/web_applications/web_app_menu_model.cc
index c6c3195..9dcf974e 100644
--- a/chrome/browser/ui/web_applications/web_app_menu_model.cc
+++ b/chrome/browser/ui/web_applications/web_app_menu_model.cc
@@ -42,6 +42,9 @@
}
void WebAppMenuModel::Build() {
+ // TODO(crbug.com/897302): Expose UI for user opt out and reenable for the Run
+ // on OS Login feature.
+
if (CreateActionToolbarOverflowMenu())
AddSeparator(ui::UPPER_SEPARATOR);
AddItemWithStringId(IDC_WEB_APP_MENU_APP_INFO,
diff --git a/chrome/browser/web_applications/components/app_shortcut_manager.cc b/chrome/browser/web_applications/components/app_shortcut_manager.cc
index 93975b5..8c00475 100644
--- a/chrome/browser/web_applications/components/app_shortcut_manager.cc
+++ b/chrome/browser/web_applications/components/app_shortcut_manager.cc
@@ -79,6 +79,13 @@
base::FilePath shortcut_data_dir =
internals::GetShortcutDataDir(*shortcut_info);
+ if (base::FeatureList::IsEnabled(features::kDesktopPWAsRunOnOsLogin)) {
+ internals::GetShortcutIOTaskRunner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&internals::UnregisterRunOnOsLogin,
+ shortcut_info->profile_path, shortcut_info->title));
+ }
+
internals::PostShortcutIOTask(
base::BindOnce(&internals::DeletePlatformShortcuts, shortcut_data_dir),
std::move(shortcut_info));
@@ -183,4 +190,22 @@
std::move(info), std::move(callback));
}
+void AppShortcutManager::RegisterRunOnOsLogin(
+ const AppId& app_id,
+ RegisterRunOnOsLoginCallback callback) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ GetShortcutInfoForApp(
+ app_id,
+ base::BindOnce(
+ &AppShortcutManager::OnShortcutInfoRetrievedRegisterRunOnOsLogin,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void AppShortcutManager::OnShortcutInfoRetrievedRegisterRunOnOsLogin(
+ RegisterRunOnOsLoginCallback callback,
+ std::unique_ptr<ShortcutInfo> info) {
+ internals::ScheduleRegisterRunOnOsLogin(std::move(info), std::move(callback));
+}
+
} // namespace web_app
diff --git a/chrome/browser/web_applications/components/app_shortcut_manager.h b/chrome/browser/web_applications/components/app_shortcut_manager.h
index 36cc07d..2c50355 100644
--- a/chrome/browser/web_applications/components/app_shortcut_manager.h
+++ b/chrome/browser/web_applications/components/app_shortcut_manager.h
@@ -58,6 +58,8 @@
virtual void CreateShortcuts(const AppId& app_id,
bool add_to_desktop,
CreateShortcutsCallback callback);
+ virtual void RegisterRunOnOsLogin(const AppId& app_id,
+ RegisterRunOnOsLoginCallback callback);
// Registers a shortcuts menu for the web app's icon with the OS.
void RegisterShortcutsMenuWithOs(
@@ -95,6 +97,10 @@
CreateShortcutsCallback callback,
std::unique_ptr<ShortcutInfo> info);
+ void OnShortcutInfoRetrievedRegisterRunOnOsLogin(
+ RegisterRunOnOsLoginCallback callback,
+ std::unique_ptr<ShortcutInfo> info);
+
ScopedObserver<AppRegistrar, AppRegistrarObserver> app_registrar_observer_{
this};
diff --git a/chrome/browser/web_applications/components/external_install_options.cc b/chrome/browser/web_applications/components/external_install_options.cc
index 38907264..2d5b6b4 100644
--- a/chrome/browser/web_applications/components/external_install_options.cc
+++ b/chrome/browser/web_applications/components/external_install_options.cc
@@ -97,6 +97,7 @@
params.add_to_applications_menu = install_options.add_to_applications_menu;
params.add_to_desktop = install_options.add_to_desktop;
params.add_to_quick_launch_bar = install_options.add_to_quick_launch_bar;
+ params.run_on_os_login = install_options.run_on_os_login;
params.add_to_search = install_options.add_to_search;
params.add_to_management = install_options.add_to_management;
params.is_disabled = install_options.is_disabled;
diff --git a/chrome/browser/web_applications/components/external_install_options.h b/chrome/browser/web_applications/components/external_install_options.h
index 11983df..82627a37 100644
--- a/chrome/browser/web_applications/components/external_install_options.h
+++ b/chrome/browser/web_applications/components/external_install_options.h
@@ -58,6 +58,12 @@
// other platforms.
bool add_to_management = true;
+ // Whether the app should be registered to run on OS login.
+ // Currently this only works on Windows by adding a shortcut to the
+ // Startup Folder.
+ // TODO(crbug.com/897302): Enable for other platforms.
+ bool run_on_os_login = false;
+
// If true, the app icon is displayed on Chrome OS with a blocked logo on
// top, and the user cannot launch the app. Has no effect on other platforms.
bool is_disabled = false;
diff --git a/chrome/browser/web_applications/components/install_manager.h b/chrome/browser/web_applications/components/install_manager.h
index ddcddec7..2613285 100644
--- a/chrome/browser/web_applications/components/install_manager.h
+++ b/chrome/browser/web_applications/components/install_manager.h
@@ -121,6 +121,7 @@
bool add_to_applications_menu = true;
bool add_to_desktop = true;
bool add_to_quick_launch_bar = true;
+ bool run_on_os_login = false;
// These have no effect outside of Chrome OS.
bool add_to_search = true;
diff --git a/chrome/browser/web_applications/components/web_app_shortcut.cc b/chrome/browser/web_applications/components/web_app_shortcut.cc
index 099c69d8..9cd64a1b 100644
--- a/chrome/browser/web_applications/components/web_app_shortcut.cc
+++ b/chrome/browser/web_applications/components/web_app_shortcut.cc
@@ -71,6 +71,15 @@
FROM_HERE, base::BindOnce(std::move(callback), shortcut_created));
}
+void RegisterRunOnOsLoginAndPostCallback(RegisterRunOnOsLoginCallback callback,
+ const ShortcutInfo& shortcut_info) {
+ bool run_on_os_login_registered =
+ internals::RegisterRunOnOsLogin(shortcut_info);
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE,
+ base::BindOnce(std::move(callback), run_on_os_login_registered));
+}
+
} // namespace
ShortcutInfo::ShortcutInfo() = default;
@@ -82,7 +91,8 @@
ShortcutLocations::ShortcutLocations()
: on_desktop(false),
applications_menu_location(APP_MENU_LOCATION_NONE),
- in_quick_launch_bar(false) {}
+ in_quick_launch_bar(false),
+ in_startup(false) {}
std::string GenerateApplicationNameFromInfo(const ShortcutInfo& shortcut_info) {
// TODO(loyso): Remove this empty()/non-empty difference.
@@ -165,6 +175,28 @@
std::move(shortcut_info));
}
+void ScheduleRegisterRunOnOsLogin(std::unique_ptr<ShortcutInfo> shortcut_info,
+ RegisterRunOnOsLoginCallback callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ PostShortcutIOTask(
+ base::BindOnce(&RegisterRunOnOsLoginAndPostCallback, std::move(callback)),
+ std::move(shortcut_info));
+}
+
+#if !defined(OS_WIN)
+// TODO(crbug.com/897302): This boilerplate function is used for platforms
+// other than Windows, currently the feature is only supported in Windows.
+bool RegisterRunOnOsLogin(const ShortcutInfo& shortcut_info) {
+ return false;
+}
+
+// TODO(crbug.com/897302): This boilerplate function is used for platforms
+// other than Windows, currently the feature is only supported in Windows.
+void UnregisterRunOnOsLogin(const base::FilePath& profile_path,
+ const base::string16& shortcut_title) {}
+#endif
+
void PostShortcutIOTaskAndReply(
base::OnceCallback<void(const ShortcutInfo&)> task,
std::unique_ptr<ShortcutInfo> shortcut_info,
diff --git a/chrome/browser/web_applications/components/web_app_shortcut.h b/chrome/browser/web_applications/components/web_app_shortcut.h
index ff6cb284..7ec765638 100644
--- a/chrome/browser/web_applications/components/web_app_shortcut.h
+++ b/chrome/browser/web_applications/components/web_app_shortcut.h
@@ -87,6 +87,10 @@
// Mac dock or the gnome/kde application launcher. However, those are not
// implemented yet.
bool in_quick_launch_bar;
+
+ // For Windows, this refers to the Startup folder.
+ // TODO(crbug.com/897302): where to create shortcuts in other OS.
+ bool in_startup;
};
// This encodes the cause of shortcut creation as the correct behavior in each
@@ -115,6 +119,12 @@
// created.
using CreateShortcutsCallback = base::OnceCallback<void(bool shortcut_created)>;
+// Callback made when RegisterRunOnOsLogin has finished trying to register the
+// app to the OS Startup indicating whether or not it was successfully
+// registered.
+using RegisterRunOnOsLoginCallback =
+ base::OnceCallback<void(bool registered_successfully)>;
+
// Returns an array of desired icon sizes (in px) to be contained in an app OS
// shortcut, sorted in ascending order (biggest desired icon size is last).
base::span<const int> GetDesiredIconSizesForShortcut();
@@ -146,6 +156,23 @@
std::unique_ptr<ShortcutInfo> shortcut_info,
CreateShortcutsCallback callback);
+// Schedules a call to |RegisterRunOnOsLogin| on the Shortcut IO thread and
+// invokes |callback| when complete. This function must be called from the UI
+// thread.
+void ScheduleRegisterRunOnOsLogin(std::unique_ptr<ShortcutInfo> shortcut_info,
+ RegisterRunOnOsLoginCallback callback);
+
+// Registers the app with the OS to run on OS login. Platform specific
+// implementations are required for this.
+// See web_app_shortcut_win.cc for Windows.
+bool RegisterRunOnOsLogin(const ShortcutInfo& shortcut_info);
+
+// Unregisters the app with the OS from running on startup. Platform specific
+// implementations are required for this.
+// See web_app_shortcut_win.cc for Windows.
+void UnregisterRunOnOsLogin(const base::FilePath& profile_path,
+ const base::string16& shortcut_title);
+
// Delete all the shortcuts we have added for this extension. This is the
// platform specific implementation of the DeleteAllShortcuts function, and
// is executed on the FILE thread.
diff --git a/chrome/browser/web_applications/components/web_app_shortcut_win.cc b/chrome/browser/web_applications/components/web_app_shortcut_win.cc
index 6a8a1c49..f2d68d3b 100644
--- a/chrome/browser/web_applications/components/web_app_shortcut_win.cc
+++ b/chrome/browser/web_applications/components/web_app_shortcut_win.cc
@@ -393,6 +393,35 @@
return true;
}
+bool RegisterRunOnOsLogin(const ShortcutInfo& shortcut_info) {
+ base::FilePath shortcut_data_dir =
+ internals::GetShortcutDataDir(shortcut_info);
+
+ ShortcutLocations locations;
+ locations.in_startup = true;
+
+ return CreatePlatformShortcuts(shortcut_data_dir, locations,
+ SHORTCUT_CREATION_BY_USER, shortcut_info);
+}
+
+void UnregisterRunOnOsLogin(const base::FilePath& profile_path,
+ const base::string16& shortcut_title) {
+ web_app::ShortcutLocations all_shortcut_locations;
+ all_shortcut_locations.in_startup = true;
+ std::vector<base::FilePath> all_paths =
+ web_app::internals::GetShortcutPaths(all_shortcut_locations);
+
+ // Only Startup folder is the expected path to be returned in all_paths.
+ for (const auto& path : all_paths) {
+ // Find all app's shortcuts in Startup folder to delete.
+ std::vector<base::FilePath> shortcut_files =
+ FindAppShortcutsByProfileAndTitle(path, profile_path, shortcut_title);
+ for (const auto& shortcut_file : shortcut_files) {
+ base::DeleteFile(shortcut_file, /*recursive=*/false);
+ }
+ }
+}
+
bool CreatePlatformShortcuts(const base::FilePath& web_app_path,
const ShortcutLocations& creation_locations,
ShortcutCreationReason creation_reason,
@@ -526,7 +555,8 @@
// taskbar. This needs to be handled by callers.
creation_locations.in_quick_launch_bar &&
base::win::CanPinShortcutToTaskbar(),
- ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH}};
+ ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH},
+ {creation_locations.in_startup, ShellUtil::SHORTCUT_LOCATION_STARTUP}};
// Populate shortcut_paths.
for (size_t i = 0; i < base::size(locations); ++i) {
diff --git a/chrome/browser/web_applications/extensions/pending_app_install_task_unittest.cc b/chrome/browser/web_applications/extensions/pending_app_install_task_unittest.cc
index a4b420b..0312d90 100644
--- a/chrome/browser/web_applications/extensions/pending_app_install_task_unittest.cc
+++ b/chrome/browser/web_applications/extensions/pending_app_install_task_unittest.cc
@@ -388,6 +388,19 @@
DISALLOW_COPY_AND_ASSIGN(PendingAppInstallTaskTest);
};
+class PendingAppInstallTaskWithRunOnOsLoginTest
+ : public PendingAppInstallTaskTest {
+ public:
+ void SetUp() override {
+ scoped_feature_list_.InitWithFeatures({features::kDesktopPWAsRunOnOsLogin},
+ {});
+ PendingAppInstallTaskTest::SetUp();
+ }
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
+};
+
TEST_F(PendingAppInstallTaskTest,
WebAppOrShortcutFromContents_InstallationSucceeds) {
auto task = GetInstallationTaskWithTestMocks(
@@ -916,4 +929,65 @@
base::RunLoop().RunUntilIdle();
}
+TEST_F(PendingAppInstallTaskWithRunOnOsLoginTest,
+ WebAppOrShortcutFromContents_RunOnOsLogin) {
+ ExternalInstallOptions install_options(
+ WebAppUrl(), DisplayMode::kStandalone,
+ ExternalInstallSource::kInternalDefault);
+ install_options.run_on_os_login = true;
+
+ auto task = GetInstallationTaskWithTestMocks(std::move(install_options));
+
+ base::RunLoop run_loop;
+
+ task->Install(
+ web_contents(), WebAppUrlLoader::Result::kUrlLoaded,
+ base::BindLambdaForTesting([&](PendingAppInstallTask::Result result) {
+ EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result.code);
+ EXPECT_TRUE(result.app_id.has_value());
+
+ EXPECT_EQ(1u, shortcut_manager()->num_create_shortcuts_calls());
+ EXPECT_TRUE(shortcut_manager()->did_add_to_desktop().value());
+
+ EXPECT_EQ(1u, shortcut_manager()->num_register_run_on_os_login_calls());
+
+ EXPECT_EQ(1u, finalizer()->num_add_app_to_quick_launch_bar_calls());
+ EXPECT_EQ(0u, finalizer()->num_reparent_tab_calls());
+
+ run_loop.Quit();
+ }));
+
+ run_loop.Run();
+}
+
+TEST_F(PendingAppInstallTaskWithRunOnOsLoginTest,
+ WebAppOrShortcutFromContents_NoRunOnOsLogin) {
+ ExternalInstallOptions install_options(
+ WebAppUrl(), DisplayMode::kStandalone,
+ ExternalInstallSource::kInternalDefault);
+ install_options.run_on_os_login = false;
+ auto task = GetInstallationTaskWithTestMocks(std::move(install_options));
+
+ base::RunLoop run_loop;
+
+ task->Install(
+ web_contents(), WebAppUrlLoader::Result::kUrlLoaded,
+ base::BindLambdaForTesting([&](PendingAppInstallTask::Result result) {
+ EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result.code);
+ EXPECT_TRUE(result.app_id.has_value());
+
+ EXPECT_EQ(1u, shortcut_manager()->num_create_shortcuts_calls());
+ EXPECT_TRUE(shortcut_manager()->did_add_to_desktop().value());
+
+ EXPECT_EQ(0u, shortcut_manager()->num_register_run_on_os_login_calls());
+
+ EXPECT_EQ(1u, finalizer()->num_add_app_to_quick_launch_bar_calls());
+ EXPECT_EQ(0u, finalizer()->num_reparent_tab_calls());
+
+ run_loop.Quit();
+ }));
+
+ run_loop.Run();
+}
+
} // namespace web_app
diff --git a/chrome/browser/web_applications/test/test_app_shortcut_manager.cc b/chrome/browser/web_applications/test/test_app_shortcut_manager.cc
index 7b64e91..5a5686c 100644
--- a/chrome/browser/web_applications/test/test_app_shortcut_manager.cc
+++ b/chrome/browser/web_applications/test/test_app_shortcut_manager.cc
@@ -56,4 +56,11 @@
NOTIMPLEMENTED();
}
+void TestAppShortcutManager::RegisterRunOnOsLogin(
+ const AppId& app_id,
+ RegisterRunOnOsLoginCallback callback) {
+ ++num_register_run_on_os_login_calls_;
+ std::move(callback).Run(true);
+}
+
} // namespace web_app
diff --git a/chrome/browser/web_applications/test/test_app_shortcut_manager.h b/chrome/browser/web_applications/test/test_app_shortcut_manager.h
index e9132e5..517fd0c 100644
--- a/chrome/browser/web_applications/test/test_app_shortcut_manager.h
+++ b/chrome/browser/web_applications/test/test_app_shortcut_manager.h
@@ -25,6 +25,10 @@
return num_create_shortcuts_calls_;
}
+ size_t num_register_run_on_os_login_calls() const {
+ return num_register_run_on_os_login_calls_;
+ }
+
void set_can_create_shortcuts(bool can_create_shortcuts) {
can_create_shortcuts_ = can_create_shortcuts;
}
@@ -34,7 +38,7 @@
}
void SetNextCreateShortcutsResult(const AppId& app_id, bool success);
-
+ void SetNextRegisterRunOnOsLoginResult(const AppId& app_id, bool success);
// AppShortcutManager:
bool CanCreateShortcuts() const override;
void CreateShortcuts(const AppId& app_id,
@@ -43,9 +47,12 @@
std::unique_ptr<ShortcutInfo> BuildShortcutInfo(const AppId& app_id) override;
void GetShortcutInfoForApp(const AppId& app_id,
GetShortcutInfoCallback callback) override;
+ void RegisterRunOnOsLogin(const AppId& app_id,
+ RegisterRunOnOsLoginCallback callback) override;
private:
size_t num_create_shortcuts_calls_ = 0;
+ size_t num_register_run_on_os_login_calls_ = 0;
base::Optional<bool> did_add_to_desktop_;
bool can_create_shortcuts_ = true;
diff --git a/chrome/browser/web_applications/web_app_install_task.cc b/chrome/browser/web_applications/web_app_install_task.cc
index 0415c54..1886daa 100644
--- a/chrome/browser/web_applications/web_app_install_task.cc
+++ b/chrome/browser/web_applications/web_app_install_task.cc
@@ -810,6 +810,30 @@
shortcut_manager_->RegisterShortcutsMenuWithOs(web_app_info->shortcut_infos,
app_id);
}
+
+ if (base::FeatureList::IsEnabled(features::kDesktopPWAsRunOnOsLogin)) {
+ // TODO(crbug.com/897302): Add run on OS login dev activation from
+ // manifest, for now it is on by default if feature flag is enabled
+ bool run_on_os_login = web_app_info->run_on_os_login;
+
+ if (install_params_)
+ run_on_os_login = install_params_->run_on_os_login;
+
+ if (run_on_os_login) {
+ shortcut_manager_->RegisterRunOnOsLogin(
+ app_id, base::BindOnce(&WebAppInstallTask::OnRegisteredRunOnOsLogin,
+ weak_ptr_factory_.GetWeakPtr(), app_id));
+ } else {
+ CallInstallCallback(app_id, InstallResultCode::kSuccessNewInstall);
+ }
+ } else {
+ CallInstallCallback(app_id, InstallResultCode::kSuccessNewInstall);
+ }
+}
+
+void WebAppInstallTask::OnRegisteredRunOnOsLogin(
+ const AppId& app_id,
+ bool registered_run_on_os_login) {
CallInstallCallback(app_id, InstallResultCode::kSuccessNewInstall);
}
diff --git a/chrome/browser/web_applications/web_app_install_task.h b/chrome/browser/web_applications/web_app_install_task.h
index 8d866db..bfee580b 100644
--- a/chrome/browser/web_applications/web_app_install_task.h
+++ b/chrome/browser/web_applications/web_app_install_task.h
@@ -217,6 +217,8 @@
void OnShortcutsCreated(std::unique_ptr<WebApplicationInfo> web_app_info,
const AppId& app_id,
bool shortcut_created);
+ void OnRegisteredRunOnOsLogin(const AppId& app_id,
+ bool registered_run_on_os_login);
// Whether we should just obtain WebApplicationInfo instead of the actual
// installation.
diff --git a/chrome/browser/web_applications/web_app_install_task_unittest.cc b/chrome/browser/web_applications/web_app_install_task_unittest.cc
index 162f8cc..7546de13 100644
--- a/chrome/browser/web_applications/web_app_install_task_unittest.cc
+++ b/chrome/browser/web_applications/web_app_install_task_unittest.cc
@@ -345,6 +345,39 @@
TestInstallFinalizer* test_install_finalizer_ = nullptr;
};
+class WebAppInstallTaskWithRunOnOsLoginTest : public WebAppInstallTaskTest {
+ public:
+ WebAppInstallTaskWithRunOnOsLoginTest() {
+ scoped_feature_list_.InitWithFeatures({features::kDesktopPWAsRunOnOsLogin},
+ {});
+ }
+
+ ~WebAppInstallTaskWithRunOnOsLoginTest() override = default;
+
+ void CreateRendererAppInfo(const GURL& url,
+ const std::string name,
+ const std::string description,
+ const GURL& scope,
+ base::Optional<SkColor> theme_color,
+ bool open_as_window,
+ bool run_on_os_login) {
+ auto web_app_info = std::make_unique<WebApplicationInfo>();
+
+ web_app_info->app_url = url;
+ web_app_info->title = base::UTF8ToUTF16(name);
+ web_app_info->description = base::UTF8ToUTF16(description);
+ web_app_info->scope = scope;
+ web_app_info->theme_color = theme_color;
+ web_app_info->open_as_window = open_as_window;
+ web_app_info->run_on_os_login = run_on_os_login;
+
+ data_retriever_->SetRendererWebApplicationInfo(std::move(web_app_info));
+ }
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
+};
+
TEST_F(WebAppInstallTaskTest, InstallFromWebContents) {
EXPECT_TRUE(AreWebAppsUserInstallable(profile()));
@@ -1173,4 +1206,98 @@
}
}
+TEST_F(WebAppInstallTaskWithRunOnOsLoginTest,
+ InstallFromWebContentsRunOnOsLogin) {
+ EXPECT_TRUE(AreWebAppsUserInstallable(profile()));
+
+ const GURL url = GURL("https://example.com/scope/path");
+ const std::string name = "Name";
+ const std::string description = "Description";
+ const GURL scope = GURL("https://example.com/scope");
+ const base::Optional<SkColor> theme_color = 0xAABBCCDD;
+ const base::Optional<SkColor> expected_theme_color = 0xFFBBCCDD; // Opaque.
+
+ const AppId app_id = GenerateAppIdFromURL(url);
+
+ CreateDefaultDataToRetrieve(url, scope);
+ CreateRendererAppInfo(url, name, description, /*scope=*/GURL{}, theme_color,
+ /*open_as_window=*/true, /*run_on_os_login=*/true);
+
+ base::RunLoop run_loop;
+ bool callback_called = false;
+ const bool force_shortcut_app = false;
+
+ install_task_->InstallWebAppFromManifestWithFallback(
+ web_contents(), force_shortcut_app, WebappInstallSource::MENU_BROWSER_TAB,
+ base::BindOnce(TestAcceptDialogCallback),
+ base::BindLambdaForTesting(
+ [&](const AppId& installed_app_id, InstallResultCode code) {
+ EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
+ EXPECT_EQ(app_id, installed_app_id);
+ callback_called = true;
+ run_loop.Quit();
+ }));
+ run_loop.Run();
+
+ EXPECT_TRUE(callback_called);
+
+ const 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, web_app->launch_url());
+ EXPECT_EQ(scope, web_app->scope());
+ EXPECT_EQ(expected_theme_color, web_app->theme_color());
+ EXPECT_EQ(1u, test_shortcut_manager().num_register_run_on_os_login_calls());
+}
+
+TEST_F(WebAppInstallTaskWithRunOnOsLoginTest,
+ InstallFromWebContentsNoRunOnOsLogin) {
+ EXPECT_TRUE(AreWebAppsUserInstallable(profile()));
+
+ const GURL url = GURL("https://example.com/scope/path");
+ const std::string name = "Name";
+ const std::string description = "Description";
+ const GURL scope = GURL("https://example.com/scope");
+ const base::Optional<SkColor> theme_color = 0xAABBCCDD;
+ const base::Optional<SkColor> expected_theme_color = 0xFFBBCCDD; // Opaque.
+
+ const AppId app_id = GenerateAppIdFromURL(url);
+
+ CreateDefaultDataToRetrieve(url, scope);
+ CreateRendererAppInfo(url, name, description, /*scope=*/GURL{}, theme_color,
+ /*open_as_window=*/true, /*run_on_os_login=*/false);
+
+ base::RunLoop run_loop;
+ bool callback_called = false;
+ const bool force_shortcut_app = false;
+
+ install_task_->InstallWebAppFromManifestWithFallback(
+ web_contents(), force_shortcut_app, WebappInstallSource::MENU_BROWSER_TAB,
+ base::BindOnce(TestAcceptDialogCallback),
+ base::BindLambdaForTesting(
+ [&](const AppId& installed_app_id, InstallResultCode code) {
+ EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
+ EXPECT_EQ(app_id, installed_app_id);
+ callback_called = true;
+ run_loop.Quit();
+ }));
+ run_loop.Run();
+
+ EXPECT_TRUE(callback_called);
+
+ const 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, web_app->launch_url());
+ EXPECT_EQ(scope, web_app->scope());
+ EXPECT_EQ(expected_theme_color, web_app->theme_color());
+ EXPECT_EQ(0u, test_shortcut_manager().num_register_run_on_os_login_calls());
+}
+
} // namespace web_app
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 95e07c46..e723eb05 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -261,6 +261,10 @@
"DefaultWebAppInstallation", base::FEATURE_ENABLED_BY_DEFAULT};
#endif
+// Enables or disables Desktop PWAs to be auto-started on OS login.
+const base::Feature kDesktopPWAsRunOnOsLogin{"DesktopPWAsRunOnOsLogin",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// Enable DNS over HTTPS (DoH).
const base::Feature kDnsOverHttps{"DnsOverHttps",
base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 2ca6f2d..700c807c 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -155,6 +155,9 @@
#endif
COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kDesktopPWAsRunOnOsLogin;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
extern const base::Feature kDnsOverHttps;
COMPONENT_EXPORT(CHROME_FEATURES)
extern const base::FeatureParam<bool> kDnsOverHttpsFallbackParam;
diff --git a/chrome/common/web_application_info.h b/chrome/common/web_application_info.h
index 6cfde5a..78f6dd6 100644
--- a/chrome/common/web_application_info.h
+++ b/chrome/common/web_application_info.h
@@ -121,6 +121,10 @@
// Set of shortcut infos populated using shortcuts specified in the manifest.
std::vector<WebApplicationShortcutInfo> shortcut_infos;
+
+ // User preference as to whether to auto run the app on OS login.
+ // Currently only supported in Windows platform.
+ bool run_on_os_login = false;
};
std::ostream& operator<<(std::ostream& out,
diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc
index 502fc4f..7152775 100644
--- a/chrome/installer/util/shell_util.cc
+++ b/chrome/installer/util/shell_util.cc
@@ -1560,7 +1560,8 @@
case SHORTCUT_LOCATION_QUICK_LAUNCH: // Falls through.
case SHORTCUT_LOCATION_START_MENU_ROOT: // Falls through.
case SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED: // Falls through.
- case SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR:
+ case SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR: // Falls through.
+ case SHORTCUT_LOCATION_STARTUP:
return true;
case SHORTCUT_LOCATION_TASKBAR_PINS:
return base::win::GetVersion() >= base::win::Version::WIN7;
@@ -1608,6 +1609,10 @@
case SHORTCUT_LOCATION_APP_SHORTCUTS:
// TODO(huangs): Move GetAppShortcutsFolder() logic into base_paths_win.
return GetAppShortcutsFolder(level, path);
+ case SHORTCUT_LOCATION_STARTUP:
+ dir_key = (level == CURRENT_USER) ? base::DIR_USER_STARTUP
+ : base::DIR_COMMON_STARTUP;
+ break;
default:
NOTREACHED();
diff --git a/chrome/installer/util/shell_util.h b/chrome/installer/util/shell_util.h
index 9cc69fa..0676683 100644
--- a/chrome/installer/util/shell_util.h
+++ b/chrome/installer/util/shell_util.h
@@ -72,6 +72,7 @@
SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR,
SHORTCUT_LOCATION_TASKBAR_PINS, // base::win::Version::WIN7 +
SHORTCUT_LOCATION_APP_SHORTCUTS, // base::win::Version::WIN8 +
+ SHORTCUT_LOCATION_STARTUP,
NUM_SHORTCUT_LOCATIONS
};
diff --git a/chrome/installer/util/shell_util_unittest.cc b/chrome/installer/util/shell_util_unittest.cc
index d6a5b5d..e384dcb 100644
--- a/chrome/installer/util/shell_util_unittest.cc
+++ b/chrome/installer/util/shell_util_unittest.cc
@@ -76,6 +76,8 @@
ASSERT_TRUE(fake_default_user_quick_launch_.CreateUniqueTempDir());
ASSERT_TRUE(fake_start_menu_.CreateUniqueTempDir());
ASSERT_TRUE(fake_common_start_menu_.CreateUniqueTempDir());
+ ASSERT_TRUE(fake_user_startup_.CreateUniqueTempDir());
+ ASSERT_TRUE(fake_common_startup_.CreateUniqueTempDir());
user_desktop_override_.reset(new base::ScopedPathOverride(
base::DIR_USER_DESKTOP, fake_user_desktop_.GetPath()));
common_desktop_override_.reset(new base::ScopedPathOverride(
@@ -86,6 +88,10 @@
base::DIR_START_MENU, fake_start_menu_.GetPath()));
common_start_menu_override_.reset(new base::ScopedPathOverride(
base::DIR_COMMON_START_MENU, fake_common_start_menu_.GetPath()));
+ common_startup_override_.reset(new base::ScopedPathOverride(
+ base::DIR_COMMON_STARTUP, fake_common_startup_.GetPath()));
+ user_startup_override_.reset(new base::ScopedPathOverride(
+ base::DIR_USER_STARTUP, fake_user_startup_.GetPath()));
base::FilePath icon_path;
base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &icon_path);
@@ -205,11 +211,15 @@
base::ScopedTempDir fake_default_user_quick_launch_;
base::ScopedTempDir fake_start_menu_;
base::ScopedTempDir fake_common_start_menu_;
+ base::ScopedTempDir fake_user_startup_;
+ base::ScopedTempDir fake_common_startup_;
std::unique_ptr<base::ScopedPathOverride> user_desktop_override_;
std::unique_ptr<base::ScopedPathOverride> common_desktop_override_;
std::unique_ptr<base::ScopedPathOverride> user_quick_launch_override_;
std::unique_ptr<base::ScopedPathOverride> start_menu_override_;
std::unique_ptr<base::ScopedPathOverride> common_start_menu_override_;
+ std::unique_ptr<base::ScopedPathOverride> user_startup_override_;
+ std::unique_ptr<base::ScopedPathOverride> common_startup_override_;
base::FilePath chrome_exe_;
base::FilePath manganese_exe_;
@@ -246,6 +256,14 @@
ShellUtil::SYSTEM_LEVEL, &path);
EXPECT_EQ(fake_common_start_menu_.GetPath().Append(start_menu_subfolder),
path);
+
+ ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_STARTUP,
+ ShellUtil::SYSTEM_LEVEL, &path);
+ EXPECT_EQ(fake_common_startup_.GetPath(), path);
+
+ ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_STARTUP,
+ ShellUtil::CURRENT_USER, &path);
+ EXPECT_EQ(fake_user_startup_.GetPath(), path);
}
TEST_F(ShellUtilShortcutTest, MoveExistingShortcut) {
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 12e5a46..44586fde 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -40990,6 +40990,7 @@
<int value="746765012" label="AutofillEnableToolbarStatusChip:disabled"/>
<int value="746944193" label="enable-automatic-password-saving:disabled"/>
<int value="747076955" label="MobileIdentityConsistency:enabled"/>
+ <int value="747391377" label="DesktopPWAsRunOnOsLogin:disabled"/>
<int value="747847237" label="PhysicalWeb:enabled"/>
<int value="749312701" label="ChromeOSAccountManager:disabled"/>
<int value="749516419" label="DragToSnapInClamshellMode:disabled"/>
@@ -41955,6 +41956,7 @@
label="enable-message-center-always-scroll-up-upon-notification-removal"/>
<int value="1861521561" label="OmniboxLocalEntitySuggestions:enabled"/>
<int value="1861954820" label="HighResolutionMouseScrolling:enabled"/>
+ <int value="1862126613" label="DesktopPWAsRunOnOsLogin:enabled"/>
<int value="1862207743" label="enable-android-spellchecker"/>
<int value="1863622457" label="WebAuthentication:enabled"/>
<int value="1865068568" label="disable-audio-support-for-desktop-share"/>