Skip to content

Commit 7c1b95b

Browse files
Clifford ChengChromium LUCI CQ
Clifford Cheng
authored and
Chromium LUCI CQ
committed
Reland "Reland "Adds a way to create app shortcuts in different folder on Mac/Win/Linux.""
This is a reland of 8e311e7 Original change's description: > Reland "Adds a way to create app shortcuts in different folder on Mac/Win/Linux." > > This is a reland of 479f569 > > Original change's description: > > Adds a way to create app shortcuts in different folder on Mac/Win/Linux. > > > > Change-Id: I3c06104c86333cbbd0857085cf7d7dd1fca63616 > > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2906422 > > Commit-Queue: Clifford Cheng <cliffordcheng@chromium.org> > > Reviewed-by: Daniel Murphy <dmurph@chromium.org> > > Cr-Commit-Position: refs/heads/master@{#892494} > > Change-Id: I3d003f1cb644402ffafaa2553d225da42c230081 > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2965263 > Reviewed-by: Daniel Murphy <dmurph@chromium.org> > Commit-Queue: Clifford Cheng <cliffordcheng@chromium.org> > Cr-Commit-Position: refs/heads/master@{#895652} Change-Id: I1291946931f5bc1dab76e0a1339e99b5cd5a2b8a Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2987632 Commit-Queue: Clifford Cheng <cliffordcheng@chromium.org> Reviewed-by: Daniel Murphy <dmurph@chromium.org> Cr-Commit-Position: refs/heads/master@{#896707}
1 parent ff6d801 commit 7c1b95b

10 files changed

+212
-47
lines changed

chrome/browser/ui/web_applications/web_app_browsertest.cc

+92
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
#include <codecvt>
56
#include <string>
67

78
#include "base/feature_list.h"
9+
#include "base/files/file_util.h"
810
#include "base/strings/string_number_conversions.h"
911
#include "base/strings/stringprintf.h"
1012
#include "base/strings/utf_string_conversions.h"
13+
#include "base/test/bind.h"
1114
#include "base/test/metrics/histogram_tester.h"
1215
#include "base/test/metrics/user_action_tester.h"
1316
#include "base/test/scoped_feature_list.h"
@@ -22,6 +25,7 @@
2225
#include "chrome/browser/banners/app_banner_manager_desktop.h"
2326
#include "chrome/browser/browser_features.h"
2427
#include "chrome/browser/browser_process.h"
28+
#include "chrome/browser/chrome_notification_types.h"
2529
#include "chrome/browser/devtools/protocol/browser_handler.h"
2630
#include "chrome/browser/profiles/profile_manager.h"
2731
#include "chrome/browser/sessions/tab_restore_service_factory.h"
@@ -941,6 +945,94 @@ IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, ReparentWebAppForSecureActiveTab) {
941945
ASSERT_EQ(app_browser->app_controller()->GetAppId(), app_id);
942946
}
943947

948+
#if defined(OS_MAC) || defined(OS_WIN) || defined(OS_LINUX)
949+
IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, WebAppCreateAndDeleteShortcut) {
950+
os_hooks_suppress_.reset();
951+
952+
ShortcutOverrideForTesting shortcut_override;
953+
base::ScopedAllowBlockingForTesting allow_blocking;
954+
base::ScopedTempDir desktop_temp_dir;
955+
EXPECT_TRUE(desktop_temp_dir.CreateUniqueTempDir());
956+
base::FilePath desktop_dir = desktop_temp_dir.GetPath();
957+
958+
base::ScopedTempDir application_temp_dir;
959+
EXPECT_TRUE(application_temp_dir.CreateUniqueTempDir());
960+
base::FilePath application_dir = application_temp_dir.GetPath();
961+
962+
#if defined(OS_MAC)
963+
shortcut_override.chrome_apps_folder = application_dir;
964+
#endif
965+
#if defined(OS_WIN)
966+
shortcut_override.application_menu = application_dir;
967+
#endif
968+
#if !defined(OS_MAC)
969+
shortcut_override.desktop = desktop_dir;
970+
#endif
971+
SetShortcutOverrideForTesting(shortcut_override);
972+
973+
auto* provider = WebAppProviderBase::GetProviderBase(profile());
974+
975+
NavigateToURLAndWait(browser(), GetInstallableAppURL());
976+
977+
// Wait for OS hooks and installation to complete and the app to launch.
978+
base::RunLoop run_loop_install;
979+
WebAppInstallObserver observer(profile());
980+
observer.SetWebAppInstalledWithOsHooksDelegate(base::BindLambdaForTesting(
981+
[&](const AppId& installed_app_id) { run_loop_install.Quit(); }));
982+
content::WindowedNotificationObserver app_loaded_observer(
983+
content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
984+
content::NotificationService::AllSources());
985+
const AppId app_id = InstallPwaForCurrentUrl();
986+
run_loop_install.Run();
987+
app_loaded_observer.Wait();
988+
989+
EXPECT_TRUE(provider->registrar().IsInstalled(app_id));
990+
EXPECT_EQ(provider->registrar().GetAppShortName(app_id),
991+
GetInstallableAppName());
992+
993+
#if defined(OS_WIN)
994+
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
995+
std::wstring shortcut_filename = converter.from_bytes(
996+
provider->registrar().GetAppShortName(app_id) + ".lnk");
997+
base::FilePath desktop_shortcut_path = desktop_dir.Append(shortcut_filename);
998+
base::FilePath app_menu_shortcut_path =
999+
application_dir.Append(shortcut_filename);
1000+
EXPECT_TRUE(base::PathExists(desktop_shortcut_path));
1001+
EXPECT_TRUE(base::PathExists(app_menu_shortcut_path));
1002+
#elif defined(OS_MAC)
1003+
std::string shortcut_filename =
1004+
provider->registrar().GetAppShortName(app_id) + ".app";
1005+
base::FilePath app_shortcut_path = application_dir.Append(shortcut_filename);
1006+
EXPECT_TRUE(base::PathExists(app_shortcut_path));
1007+
#elif defined(OS_LINUX)
1008+
std::string shortcut_filename = "chrome-" + app_id + "-Default.desktop";
1009+
base::FilePath desktop_shortcut_path = desktop_dir.Append(shortcut_filename);
1010+
base::FilePath app_menu_shortcut_path =
1011+
application_dir.Append("applications").Append(shortcut_filename);
1012+
EXPECT_TRUE(base::PathExists(desktop_shortcut_path));
1013+
#endif
1014+
1015+
// Unistall the web app
1016+
base::RunLoop run_loop_uninstall;
1017+
provider->install_finalizer().UninstallWebApp(
1018+
app_id, webapps::WebappUninstallSource::kAppMenu,
1019+
base::BindLambdaForTesting([&](bool uninstalled) {
1020+
DCHECK(uninstalled);
1021+
run_loop_uninstall.Quit();
1022+
}));
1023+
run_loop_uninstall.Run();
1024+
1025+
#if defined(OS_WIN)
1026+
EXPECT_FALSE(base::PathExists(desktop_shortcut_path));
1027+
EXPECT_FALSE(base::PathExists(app_menu_shortcut_path));
1028+
#elif defined(OS_MAC)
1029+
EXPECT_FALSE(base::PathExists(app_shortcut_path));
1030+
#elif defined(OS_LINUX)
1031+
EXPECT_FALSE(base::PathExists(desktop_shortcut_path));
1032+
#endif
1033+
} // namespace web_app
1034+
#endif
1035+
9441036
// Tests that reparenting the last browser tab doesn't close the browser window.
9451037
IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, ReparentLastBrowserTab) {
9461038
const GURL app_url = GetSecureAppURL();

chrome/browser/ui/web_applications/web_app_controller_browsertest.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ class WebAppControllerBrowserTest : public WebAppControllerBrowserTestBase {
8383
~WebAppControllerBrowserTest() override = 0;
8484

8585
protected:
86+
ScopedOsHooksSuppress os_hooks_suppress_;
87+
8688
content::WebContents* OpenApplication(const AppId&);
8789

8890
net::EmbeddedTestServer* https_server() { return &https_server_; }
@@ -105,8 +107,6 @@ class WebAppControllerBrowserTest : public WebAppControllerBrowserTestBase {
105107
// used by the NetworkService.
106108
content::ContentMockCertVerifier cert_verifier_;
107109

108-
ScopedOsHooksSuppress os_hooks_suppress_;
109-
110110
DISALLOW_COPY_AND_ASSIGN(WebAppControllerBrowserTest);
111111
};
112112

chrome/browser/web_applications/components/web_app_run_on_os_login_mac_unittest.mm

+5-2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "testing/gmock/include/gmock/gmock.h"
2626
#include "testing/gtest/include/gtest/gtest.h"
2727
#import "testing/gtest_mac.h"
28+
#include "third_party/abseil-cpp/absl/types/optional.h"
2829

2930
namespace web_app {
3031

@@ -96,7 +97,9 @@ void SetUp() override {
9697
user_data_dir_ = base::MakeAbsoluteFilePath(user_data_dir_);
9798
app_data_dir_ = base::MakeAbsoluteFilePath(app_data_dir_);
9899

99-
SetChromeAppsFolderForTesting(destination_dir_);
100+
ShortcutOverrideForTesting shortcut_override;
101+
shortcut_override.chrome_apps_folder = destination_dir_;
102+
web_app::SetShortcutOverrideForTesting(shortcut_override);
100103

101104
info_ = GetShortcutInfo();
102105
base::FilePath shim_base_name =
@@ -109,7 +112,7 @@ void SetUp() override {
109112

110113
void TearDown() override {
111114
WebAppAutoLoginUtil::SetInstanceForTesting(nullptr);
112-
SetChromeAppsFolderForTesting(base::FilePath());
115+
web_app::SetShortcutOverrideForTesting(absl::nullopt);
113116
WebAppShortcutCreator::ResetHaveLocalizedAppDirNameForTesting();
114117
WebAppTest::TearDown();
115118
}

chrome/browser/web_applications/components/web_app_shortcut.cc

+16
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,22 @@ void DeleteMultiProfileShortcutsForAppAndPostCallback(
9090

9191
} // namespace
9292

93+
ShortcutOverrideForTesting::ShortcutOverrideForTesting() = default;
94+
ShortcutOverrideForTesting::ShortcutOverrideForTesting(
95+
const ShortcutOverrideForTesting& other) = default;
96+
ShortcutOverrideForTesting::~ShortcutOverrideForTesting() = default;
97+
98+
absl::optional<ShortcutOverrideForTesting>& GetShortcutOverrideForTesting() {
99+
static base::NoDestructor<absl::optional<ShortcutOverrideForTesting>>
100+
g_shortcut_override;
101+
return *g_shortcut_override;
102+
}
103+
104+
void SetShortcutOverrideForTesting(
105+
absl::optional<ShortcutOverrideForTesting> shortcut_override_for_testing) {
106+
GetShortcutOverrideForTesting() = shortcut_override_for_testing;
107+
}
108+
93109
ShortcutInfo::ShortcutInfo() = default;
94110

95111
ShortcutInfo::~ShortcutInfo() {

chrome/browser/web_applications/components/web_app_shortcut.h

+24
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@
1212
#include "base/callback_forward.h"
1313
#include "base/containers/span.h"
1414
#include "base/files/file_path.h"
15+
#include "base/no_destructor.h"
1516
#include "base/sequence_checker.h"
17+
#include "build/build_config.h"
18+
#include "third_party/abseil-cpp/absl/types/optional.h"
1619
#include "ui/gfx/image/image_family.h"
1720
#include "url/gurl.h"
1821

@@ -26,6 +29,27 @@ class ImageSkia;
2629

2730
namespace web_app {
2831

32+
struct ShortcutOverrideForTesting {
33+
ShortcutOverrideForTesting(const ShortcutOverrideForTesting& other);
34+
ShortcutOverrideForTesting();
35+
~ShortcutOverrideForTesting();
36+
#if defined(OS_WIN)
37+
base::FilePath desktop;
38+
base::FilePath application_menu;
39+
base::FilePath quick_launch;
40+
base::FilePath startup;
41+
#elif defined(OS_MAC)
42+
base::FilePath chrome_apps_folder;
43+
#elif defined(OS_LINUX)
44+
base::FilePath desktop;
45+
#else
46+
#endif
47+
};
48+
49+
absl::optional<ShortcutOverrideForTesting>& GetShortcutOverrideForTesting();
50+
void SetShortcutOverrideForTesting(
51+
absl::optional<ShortcutOverrideForTesting> shortcut_override_for_testing);
52+
2953
// Represents the info required to create a shortcut for an app.
3054
struct ShortcutInfo {
3155
ShortcutInfo();

chrome/browser/web_applications/components/web_app_shortcut_linux.cc

+40-17
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,14 @@ web_app::LaunchXdgUtilityForTesting& GetInstalledLaunchXdgUtilityForTesting() {
4848
return *instance;
4949
}
5050

51+
base::FilePath GetDesktopPath() {
52+
base::FilePath desktop_path;
53+
if (web_app::GetShortcutOverrideForTesting())
54+
return web_app::GetShortcutOverrideForTesting()->desktop;
55+
base::PathService::Get(base::DIR_USER_DESKTOP, &desktop_path);
56+
return desktop_path;
57+
}
58+
5159
// Result of creating app shortcut icon.
5260
// Success is recorded for each icon image, but the first two errors
5361
// are per app, so the success/error ratio might not be very meaningful.
@@ -201,8 +209,8 @@ bool CreateShortcutAtLocation(const base::FilePath location_path,
201209

202210
bool CreateShortcutOnDesktop(const base::FilePath& shortcut_filename,
203211
const std::string& contents) {
204-
base::FilePath desktop_path;
205-
if (!base::PathService::Get(base::DIR_USER_DESKTOP, &desktop_path)) {
212+
base::FilePath desktop_path = GetDesktopPath();
213+
if (desktop_path.empty()) {
206214
RecordCreateShortcut(CreateShortcutResult::kFailToGetDesktopPath);
207215
return false;
208216
}
@@ -213,6 +221,7 @@ bool CreateShortcutOnDesktop(const base::FilePath& shortcut_filename,
213221
bool CreateShortcutInAutoStart(base::Environment* env,
214222
const base::FilePath& shortcut_filename,
215223
const std::string& contents) {
224+
DCHECK(!web_app::GetShortcutOverrideForTesting());
216225
base::FilePath autostart_path = AutoStart::GetAutostartDirectory(env);
217226
if (!base::DirectoryExists(autostart_path) &&
218227
!base::CreateDirectory(autostart_path)) {
@@ -231,6 +240,7 @@ bool CreateShortcutInApplicationsMenu(base::Environment* env,
231240
const std::string& contents,
232241
const base::FilePath& directory_filename,
233242
const std::string& directory_contents) {
243+
DCHECK(!web_app::GetShortcutOverrideForTesting());
234244
base::ScopedTempDir temp_dir;
235245
if (!temp_dir.CreateUniqueTempDir()) {
236246
RecordCreateShortcut(CreateShortcutResult::kFailToCreateTempDir);
@@ -321,9 +331,9 @@ base::FilePath GetAppShortcutFilename(const base::FilePath& profile_path,
321331
}
322332

323333
bool DeleteShortcutOnDesktop(const base::FilePath& shortcut_filename) {
324-
base::FilePath desktop_path;
334+
base::FilePath desktop_path = GetDesktopPath();
325335
bool result = false;
326-
if (base::PathService::Get(base::DIR_USER_DESKTOP, &desktop_path))
336+
if (!desktop_path.empty())
327337
result = base::DeleteFile(desktop_path.Append(shortcut_filename));
328338
return result;
329339
}
@@ -362,6 +372,21 @@ bool CreateDesktopShortcut(base::Environment* env,
362372
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
363373
base::BlockingType::MAY_BLOCK);
364374

375+
bool create_shortcut_in_startup = creation_locations.in_startup;
376+
// Do not create the shortcuts in startup directory when testing because
377+
// xdg-utility (which creates this shortcut) doesn't work well with temp
378+
// directories.
379+
if (web_app::GetShortcutOverrideForTesting())
380+
create_shortcut_in_startup = false;
381+
382+
ApplicationsMenuLocation applications_menu_location =
383+
creation_locations.applications_menu_location;
384+
// Do not create the shortcuts in startup directory when testing because
385+
// xdg-utility (which creates this shortcut) doesn't work well with temp
386+
// directories.
387+
if (web_app::GetShortcutOverrideForTesting())
388+
applications_menu_location = APP_MENU_LOCATION_NONE;
389+
365390
base::FilePath shortcut_filename;
366391
if (!shortcut_info.extension_id.empty()) {
367392
shortcut_filename = GetAppShortcutFilename(shortcut_info.profile_path,
@@ -371,11 +396,11 @@ bool CreateDesktopShortcut(base::Environment* env,
371396
if (creation_locations.on_desktop)
372397
DeleteShortcutOnDesktop(shortcut_filename);
373398

374-
if (creation_locations.in_startup)
399+
if (create_shortcut_in_startup)
400+
// if (creation_locations.in_startup)
375401
DeleteShortcutInAutoStart(env, shortcut_filename);
376402

377-
if (creation_locations.applications_menu_location !=
378-
APP_MENU_LOCATION_NONE) {
403+
if (applications_menu_location != APP_MENU_LOCATION_NONE) {
379404
DeleteShortcutInApplicationsMenu(shortcut_filename, base::FilePath());
380405
}
381406
} else {
@@ -410,7 +435,8 @@ bool CreateDesktopShortcut(base::Environment* env,
410435
success = CreateShortcutOnDesktop(shortcut_filename, contents);
411436
}
412437

413-
if (creation_locations.in_startup) {
438+
if (create_shortcut_in_startup) {
439+
// if (creation_locations.in_startup) {
414440
std::string contents = shell_integration_linux::GetDesktopFileContents(
415441
chrome_exe_path, app_name, shortcut_info.url,
416442
shortcut_info.extension_id, shortcut_info.title, icon_name,
@@ -419,7 +445,7 @@ bool CreateDesktopShortcut(base::Environment* env,
419445
CreateShortcutInAutoStart(env, shortcut_filename, contents) && success;
420446
}
421447

422-
if (creation_locations.applications_menu_location == APP_MENU_LOCATION_NONE) {
448+
if (applications_menu_location == APP_MENU_LOCATION_NONE) {
423449
return success;
424450
}
425451

@@ -479,9 +505,8 @@ ShortcutLocations GetExistingShortcutLocations(
479505
ShortcutLocations locations;
480506

481507
// Determine whether there is a shortcut on desktop.
482-
base::FilePath desktop_path;
483-
// If Get returns false, just leave desktop_path empty.
484-
base::PathService::Get(base::DIR_USER_DESKTOP, &desktop_path);
508+
base::FilePath desktop_path = GetDesktopPath();
509+
485510
if (!desktop_path.empty()) {
486511
locations.on_desktop =
487512
base::PathExists(desktop_path.Append(shortcut_filename));
@@ -542,8 +567,8 @@ bool DeleteAllDesktopShortcuts(base::Environment* env,
542567

543568
bool result = true;
544569
// Delete shortcuts from Desktop.
545-
base::FilePath desktop_path;
546-
if (base::PathService::Get(base::DIR_USER_DESKTOP, &desktop_path)) {
570+
base::FilePath desktop_path = GetDesktopPath();
571+
if (!desktop_path.empty()) {
547572
std::vector<base::FilePath> shortcut_filenames_desktop =
548573
shell_integration_linux::GetExistingProfileShortcutFilenames(
549574
profile_path, desktop_path);
@@ -610,9 +635,7 @@ std::vector<base::FilePath> GetShortcutLocations(
610635
DCHECK(!shortcut_filename.empty());
611636

612637
if (locations.on_desktop) {
613-
base::FilePath desktop_path;
614-
// If Get returns false, just leave |desktop_path| empty.
615-
base::PathService::Get(base::DIR_USER_DESKTOP, &desktop_path);
638+
base::FilePath desktop_path = GetDesktopPath();
616639
if (!desktop_path.empty()) {
617640
base::FilePath desktop_shortcut_path =
618641
desktop_path.Append(shortcut_filename);

chrome/browser/web_applications/components/web_app_shortcut_mac.h

-3
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,6 @@ bool AppShimLaunchDisabled();
5757
// Returns a path to the Chrome Apps folder in ~/Applications.
5858
base::FilePath GetChromeAppsFolder();
5959

60-
// Testing method to override calls to GetChromeAppsFolder.
61-
void SetChromeAppsFolderForTesting(const base::FilePath& path);
62-
6360
// Remove the specified app from the OS login item list.
6461
void RemoveAppShimFromLoginItems(const std::string& app_id);
6562

0 commit comments

Comments
 (0)