diff options
-rw-r--r-- | chrome/browser/shell_integration.h | 1 | ||||
-rw-r--r-- | chrome/browser/ui/web_applications/web_app_ui.cc | 4 | ||||
-rw-r--r-- | chrome/browser/web_applications/web_app_mac.h | 4 | ||||
-rw-r--r-- | chrome/browser/web_applications/web_app_mac.mm | 97 | ||||
-rw-r--r-- | chrome/browser/web_applications/web_app_mac_unittest.mm | 30 | ||||
-rw-r--r-- | chrome/common/mac/app_mode_common.h | 12 | ||||
-rw-r--r-- | chrome/common/mac/app_mode_common.mm | 3 |
7 files changed, 106 insertions, 45 deletions
diff --git a/chrome/browser/shell_integration.h b/chrome/browser/shell_integration.h index 1306027..f781b00 100644 --- a/chrome/browser/shell_integration.h +++ b/chrome/browser/shell_integration.h @@ -103,6 +103,7 @@ class ShellIntegration { base::FilePath extension_path; gfx::ImageFamily favicon; base::FilePath profile_path; + std::string profile_name; }; // Info about which locations to create app shortcuts in. diff --git a/chrome/browser/ui/web_applications/web_app_ui.cc b/chrome/browser/ui/web_applications/web_app_ui.cc index b807bc7..c185bfd 100644 --- a/chrome/browser/ui/web_applications/web_app_ui.cc +++ b/chrome/browser/ui/web_applications/web_app_ui.cc @@ -8,6 +8,7 @@ #include "base/bind_helpers.h" #include "base/file_util.h" #include "base/path_service.h" +#include "base/prefs/pref_service.h" #include "base/string16.h" #include "base/utf_string_conversions.h" #include "chrome/browser/extensions/image_loader.h" @@ -20,6 +21,7 @@ #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" #include "chrome/common/extensions/manifest_handlers/icons_handler.h" +#include "chrome/common/pref_names.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/notification_details.h" #include "content/public/browser/notification_registrar.h" @@ -423,6 +425,8 @@ void UpdateShortcutInfoForApp(const extensions::Extension& app, shortcut_info->description = UTF8ToUTF16(app.description()); shortcut_info->extension_path = app.path(); shortcut_info->profile_path = profile->GetPath(); + shortcut_info->profile_name = + profile->GetPrefs()->GetString(prefs::kProfileName); } void UpdateShortcutInfoAndIconForApp( diff --git a/chrome/browser/web_applications/web_app_mac.h b/chrome/browser/web_applications/web_app_mac.h index 91d46d7..d20aa22 100644 --- a/chrome/browser/web_applications/web_app_mac.h +++ b/chrome/browser/web_applications/web_app_mac.h @@ -65,6 +65,10 @@ class WebAppShortcutCreator { private: FRIEND_TEST_ALL_PREFIXES(WebAppShortcutCreatorTest, UpdateIcon); + // Updates the InfoPlist.string inside |app_path| with the display name for + // the app. + bool UpdateDisplayName(const base::FilePath& app_path) const; + // Path to the app's user data directory. For example: // ~/Library/Application Support/Chromium/Default/Web Applications/_crx_abc/ // Note, the user data directory is the parent of the profile directory. diff --git a/chrome/browser/web_applications/web_app_mac.mm b/chrome/browser/web_applications/web_app_mac.mm index a884e84..64caabd 100644 --- a/chrome/browser/web_applications/web_app_mac.mm +++ b/chrome/browser/web_applications/web_app_mac.mm @@ -18,6 +18,7 @@ #include "base/mac/scoped_cftyperef.h" #include "base/memory/scoped_nsobject.h" #include "base/strings/sys_string_conversions.h" +#include "base/string_util.h" #include "base/utf_string_conversions.h" #include "chrome/browser/ui/web_applications/web_app_ui.h" #include "chrome/browser/web_applications/web_app.h" @@ -132,6 +133,31 @@ base::FilePath GetWritableApplicationsDirectory() { return base::FilePath(); } +// Given the path to an app bundle, return the resources directory. +base::FilePath GetResourcesPath(const base::FilePath& app_path) { + return app_path.Append("Contents").Append("Resources"); +} + +bool HasExistingExtensionShim(const base::FilePath& destination_directory, + const std::string& extension_id, + const base::FilePath& own_basename) { + // Check if there any any other shims for the same extension. + file_util::FileEnumerator enumerator(destination_directory, + false /* recursive */, + file_util::FileEnumerator::DIRECTORIES); + for (base::FilePath shim_path = enumerator.Next(); + !shim_path.empty(); shim_path = enumerator.Next()) { + if (shim_path.BaseName() != own_basename && + EndsWith(shim_path.RemoveExtension().value(), + extension_id, + true /* case_sensitive */)) { + return true; + } + } + + return false; +} + } // namespace namespace web_app { @@ -155,15 +181,16 @@ base::FilePath WebAppShortcutCreator::GetShortcutPath() const { if (dst_path.empty()) return dst_path; - base::FilePath app_name = internals::GetSanitizedFileName(info_.title); + base::FilePath app_name = internals::GetSanitizedFileName(UTF8ToUTF16( + info_.profile_path.BaseName().value() + " " + info_.extension_id)); return dst_path.Append(app_name.ReplaceExtension("app")); } bool WebAppShortcutCreator::CreateShortcut() { - base::FilePath app_name = internals::GetSanitizedFileName(info_.title); - base::FilePath app_file_name = app_name.ReplaceExtension("app"); - base::FilePath dst_path = GetDestinationPath(); - if (dst_path.empty() || !file_util::DirectoryExists(dst_path.DirName())) { + base::FilePath app_path = GetShortcutPath(); + base::FilePath app_name = app_path.BaseName(); + base::FilePath dst_path = app_path.DirName(); + if (app_path.empty() || !file_util::DirectoryExists(dst_path.DirName())) { LOG(ERROR) << "Couldn't find an Applications directory to copy app to."; return false; } @@ -172,19 +199,10 @@ bool WebAppShortcutCreator::CreateShortcut() { return false; } - base::FilePath app_path = dst_path.Append(app_file_name); - app_path = file_util::MakeUniqueDirectory(app_path); - if (app_path.empty()) { - LOG(ERROR) << "Couldn't create a unique directory for app path: " - << app_path.value(); - return false; - } - app_file_name = app_path.BaseName(); - base::ScopedTempDir scoped_temp_dir; if (!scoped_temp_dir.CreateUniqueTempDir()) return false; - base::FilePath staging_path = scoped_temp_dir.path().Append(app_file_name); + base::FilePath staging_path = scoped_temp_dir.path().Append(app_name); // Update the app's plist and icon in a temp directory. This works around // a Finder bug where the app's icon doesn't properly update. @@ -197,6 +215,9 @@ bool WebAppShortcutCreator::CreateShortcut() { if (!UpdatePlist(staging_path)) return false; + if (!UpdateDisplayName(staging_path)) + return false; + if (!UpdateIcon(staging_path)) return false; @@ -224,9 +245,6 @@ base::FilePath WebAppShortcutCreator::GetDestinationPath() const { } bool WebAppShortcutCreator::UpdatePlist(const base::FilePath& app_path) const { - NSString* plist_path = base::mac::FilePathToNSString( - app_path.Append("Contents").Append("Info.plist")); - NSString* extension_id = base::SysUTF8ToNSString(info_.extension_id); NSString* extension_title = base::SysUTF16ToNSString(info_.title); NSString* extension_url = base::SysUTF8ToNSString(info_.url.spec()); @@ -239,6 +257,8 @@ bool WebAppShortcutCreator::UpdatePlist(const base::FilePath& app_path) const { chrome_bundle_id, app_mode::kShortcutBrowserBundleIDPlaceholder, nil]; + NSString* plist_path = base::mac::FilePathToNSString( + app_path.Append("Contents").Append("Info.plist")); NSMutableDictionary* plist = [NSMutableDictionary dictionaryWithContentsOfFile:plist_path]; NSArray* keys = [plist allKeys]; @@ -265,9 +285,47 @@ bool WebAppShortcutCreator::UpdatePlist(const base::FilePath& app_path) const { forKey:app_mode::kCrAppModeUserDataDirKey]; [plist setObject:base::mac::FilePathToNSString(info_.profile_path.BaseName()) forKey:app_mode::kCrAppModeProfileDirKey]; + [plist setObject:base::SysUTF8ToNSString(info_.profile_name) + forKey:app_mode::kCrAppModeProfileNameKey]; + [plist setObject:[NSNumber numberWithBool:YES] + forKey:app_mode::kLSHasLocalizedDisplayNameKey]; + + base::FilePath app_name = app_path.BaseName().RemoveExtension(); + [plist setObject:base::mac::FilePathToNSString(app_name) + forKey:base::mac::CFToNSCast(kCFBundleNameKey)]; + return [plist writeToFile:plist_path atomically:YES]; } +bool WebAppShortcutCreator::UpdateDisplayName( + const base::FilePath& app_path) const { + // OSX searches for the best language in the order of preferred languages. + // Since we only have one localization directory, it will choose this one. + base::FilePath localized_dir = GetResourcesPath(app_path).Append("en.lproj"); + if (!file_util::CreateDirectory(localized_dir)) + return false; + + NSString* bundle_name = base::SysUTF16ToNSString(info_.title); + NSString* display_name = base::SysUTF16ToNSString(info_.title); + if (HasExistingExtensionShim(GetDestinationPath(), + info_.extension_id, + app_path.BaseName())) { + display_name = [bundle_name + stringByAppendingString:base::SysUTF8ToNSString( + " (" + info_.profile_name + ")")]; + } + + NSDictionary* strings_plist = @{ + base::mac::CFToNSCast(kCFBundleNameKey) : bundle_name, + app_mode::kCFBundleDisplayNameKey : display_name + }; + + NSString* localized_path = base::mac::FilePathToNSString( + localized_dir.Append("InfoPlist.strings")); + return [strings_plist writeToFile:localized_path + atomically:YES]; +} + bool WebAppShortcutCreator::UpdateIcon(const base::FilePath& app_path) const { if (info_.favicon.empty()) return true; @@ -290,8 +348,7 @@ bool WebAppShortcutCreator::UpdateIcon(const base::FilePath& app_path) const { if (!image_added) return false; - base::FilePath resources_path = - app_path.Append("Contents").Append("Resources"); + base::FilePath resources_path = GetResourcesPath(app_path); if (!file_util::CreateDirectory(resources_path)) return false; diff --git a/chrome/browser/web_applications/web_app_mac_unittest.mm b/chrome/browser/web_applications/web_app_mac_unittest.mm index 0c08366..653bbb5 100644 --- a/chrome/browser/web_applications/web_app_mac_unittest.mm +++ b/chrome/browser/web_applications/web_app_mac_unittest.mm @@ -50,6 +50,7 @@ ShellIntegration::ShortcutInfo GetShortcutInfo() { info.title = ASCIIToUTF16("Shortcut Title"); info.url = GURL("http://example.com/"); info.profile_path = base::FilePath("Default"); + info.profile_name = "profile name"; return info; } @@ -64,7 +65,8 @@ TEST(WebAppShortcutCreatorTest, CreateShortcut) { ShellIntegration::ShortcutInfo info = GetShortcutInfo(); base::FilePath dst_folder = scoped_temp_dir.path(); - base::FilePath dst_path = dst_folder.Append(UTF16ToUTF8(info.title) + ".app"); + base::FilePath dst_path = dst_folder.Append( + info.profile_path.value() + " " + info.extension_id + ".app"); NiceMock<WebAppShortcutCreatorMock> shortcut_creator(info); EXPECT_CALL(shortcut_creator, GetDestinationPath()) @@ -103,7 +105,8 @@ TEST(WebAppShortcutCreatorTest, RunShortcut) { ShellIntegration::ShortcutInfo info = GetShortcutInfo(); base::FilePath dst_folder = scoped_temp_dir.path(); - base::FilePath dst_path = dst_folder.Append(UTF16ToUTF8(info.title) + ".app"); + base::FilePath dst_path = dst_folder.Append( + info.profile_path.value() + " " + info.extension_id + ".app"); NiceMock<WebAppShortcutCreatorMock> shortcut_creator(info); EXPECT_CALL(shortcut_creator, GetDestinationPath()) @@ -132,29 +135,6 @@ TEST(WebAppShortcutCreatorTest, CreateFailure) { EXPECT_FALSE(shortcut_creator.CreateShortcut()); } -TEST(WebAppShortcutCreatorTest, CreateUnique) { - base::ScopedTempDir scoped_temp_dir; - EXPECT_TRUE(scoped_temp_dir.CreateUniqueTempDir()); - - ShellIntegration::ShortcutInfo info = GetShortcutInfo(); - - base::FilePath dst_folder = scoped_temp_dir.path(); - base::FilePath dst_path = dst_folder.Append(UTF16ToUTF8(info.title) + ".app"); - - file_util::CreateDirectory(dst_path); - base::FilePath expected_app_path = - dst_path.InsertBeforeExtensionASCII(" (1)"); - - NiceMock<WebAppShortcutCreatorMock> shortcut_creator(info); - EXPECT_CALL(shortcut_creator, GetDestinationPath()) - .WillRepeatedly(Return(dst_folder)); - EXPECT_CALL(shortcut_creator, - RevealGeneratedBundleInFinder(expected_app_path)); - - EXPECT_TRUE(shortcut_creator.CreateShortcut()); - EXPECT_TRUE(file_util::PathExists(expected_app_path)); -} - TEST(WebAppShortcutCreatorTest, UpdateIcon) { base::ScopedTempDir scoped_temp_dir; ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir()); diff --git a/chrome/common/mac/app_mode_common.h b/chrome/common/mac/app_mode_common.h index 8bb114f..b9045a6 100644 --- a/chrome/common/mac/app_mode_common.h +++ b/chrome/common/mac/app_mode_common.h @@ -33,6 +33,15 @@ extern const char kAppListModeId[]; // associates the shim without launching the app. extern const char kNoLaunchApp[]; +// The display name of the bundle as shown in Finder and the Dock. For localized +// bundles, this overrides the bundle's file name. +extern NSString* const kCFBundleDisplayNameKey; + +// The key specifying whether the display name should be localized. This makes +// Finder look in localization folders in the app bundle for a display name. +// (e.g. Content/Resources/en.lproj/) +extern NSString* const kLSHasLocalizedDisplayNameKey; + // The key under which the browser's bundle ID will be stored in the // app mode launcher bundle's Info.plist. extern NSString* const kBrowserBundleIDKey; @@ -52,6 +61,9 @@ extern NSString* const kCrAppModeUserDataDirKey; // Key for the app's extension path. extern NSString* const kCrAppModeProfileDirKey; +// Key for the app's profile display name. +extern NSString* const kCrAppModeProfileNameKey; + // When the Chrome browser is run, it stores its location in the defaults // system using this key. extern NSString* const kLastRunAppBundlePathPrefsKey; diff --git a/chrome/common/mac/app_mode_common.mm b/chrome/common/mac/app_mode_common.mm index ae5e2f7..f67eb2f 100644 --- a/chrome/common/mac/app_mode_common.mm +++ b/chrome/common/mac/app_mode_common.mm @@ -12,12 +12,15 @@ const char kAppListModeId[] = "app_list"; const char kNoLaunchApp[] = "no-launch-app"; +NSString* const kCFBundleDisplayNameKey = @"CFBundleDisplayName"; +NSString* const kLSHasLocalizedDisplayNameKey = @"LSHasLocalizedDisplayName"; NSString* const kBrowserBundleIDKey = @"CrBundleIdentifier"; NSString* const kCrAppModeShortcutIDKey = @"CrAppModeShortcutID"; NSString* const kCrAppModeShortcutNameKey = @"CrAppModeShortcutName"; NSString* const kCrAppModeShortcutURLKey = @"CrAppModeShortcutURL"; NSString* const kCrAppModeUserDataDirKey = @"CrAppModeUserDataDir"; NSString* const kCrAppModeProfileDirKey = @"CrAppModeProfileDir"; +NSString* const kCrAppModeProfileNameKey = @"CrAppModeProfileName"; NSString* const kLastRunAppBundlePathPrefsKey = @"LastRunAppBundlePath"; |