diff options
-rw-r--r-- | chrome/browser/chrome_browser_main_win.cc | 13 | ||||
-rw-r--r-- | chrome/browser/first_run/first_run_win.cc | 2 | ||||
-rw-r--r-- | chrome/browser/profiles/profile_info_cache.cc | 73 | ||||
-rw-r--r-- | chrome/browser/profiles/profile_info_cache.h | 16 | ||||
-rw-r--r-- | chrome/browser/profiles/profile_info_cache_observer.h | 30 | ||||
-rw-r--r-- | chrome/browser/profiles/profile_manager.cc | 13 | ||||
-rw-r--r-- | chrome/browser/profiles/profile_manager.h | 26 | ||||
-rw-r--r-- | chrome/browser/profiles/profile_manager_unittest.cc | 6 | ||||
-rw-r--r-- | chrome/browser/profiles/profile_shortcut_manager_win.cc | 216 | ||||
-rw-r--r-- | chrome/browser/profiles/profile_shortcut_manager_win.h | 62 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 3 | ||||
-rw-r--r-- | chrome/installer/setup/install.cc | 8 | ||||
-rw-r--r-- | chrome/installer/util/browser_distribution_unittest.cc | 15 | ||||
-rw-r--r-- | chrome/installer/util/shell_util.cc | 62 | ||||
-rw-r--r-- | chrome/installer/util/shell_util.h | 53 | ||||
-rw-r--r-- | chrome/installer/util/shell_util_unittest.cc | 86 |
16 files changed, 622 insertions, 62 deletions
diff --git a/chrome/browser/chrome_browser_main_win.cc b/chrome/browser/chrome_browser_main_win.cc index 928315b..3965c1d 100644 --- a/chrome/browser/chrome_browser_main_win.cc +++ b/chrome/browser/chrome_browser_main_win.cc @@ -22,6 +22,8 @@ #include "chrome/browser/browser_util_win.h" #include "chrome/browser/first_run/first_run.h" #include "chrome/browser/metrics/metrics_service.h" +#include "chrome/browser/profiles/profile_info_cache.h" +#include "chrome/browser/profiles/profile_shortcut_manager_win.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/views/uninstall_view.h" #include "chrome/common/chrome_constants.h" @@ -141,11 +143,18 @@ int DoUninstallTasks(bool chrome_still_running) { // created by us and not by the installer so |alternate| is false. BrowserDistribution* dist = BrowserDistribution::GetDistribution(); if (!ShellUtil::RemoveChromeDesktopShortcut(dist, ShellUtil::CURRENT_USER, - false)) + false)) { VLOG(1) << "Failed to delete desktop shortcut."; + } + if (!ShellUtil::RemoveChromeDesktopShortcutsWithAppendedNames( + ProfileShortcutManagerWin::GenerateShortcutsFromProfiles( + ProfileInfoCache::GetProfileNames()))) { + VLOG(1) << "Failed to delete desktop profiles shortcuts."; + } if (!ShellUtil::RemoveChromeQuickLaunchShortcut(dist, - ShellUtil::CURRENT_USER)) + ShellUtil::CURRENT_USER)) { VLOG(1) << "Failed to delete quick launch shortcut."; + } } return ret; } diff --git a/chrome/browser/first_run/first_run_win.cc b/chrome/browser/first_run/first_run_win.cc index 6d343c9..9a0c675 100644 --- a/chrome/browser/first_run/first_run_win.cc +++ b/chrome/browser/first_run/first_run_win.cc @@ -108,6 +108,8 @@ bool CreateChromeDesktopShortcut() { dist, chrome_exe.value(), dist->GetAppDescription(), + L"", + L"", ShellUtil::CURRENT_USER, false, true); // create if doesn't exist. diff --git a/chrome/browser/profiles/profile_info_cache.cc b/chrome/browser/profiles/profile_info_cache.cc index c0966da..c3b20e0 100644 --- a/chrome/browser/profiles/profile_info_cache.cc +++ b/chrome/browser/profiles/profile_info_cache.cc @@ -12,6 +12,7 @@ #include "base/stringprintf.h" #include "base/utf_string_conversions.h" #include "base/values.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/prefs/scoped_user_pref_update.h" #include "chrome/common/chrome_notification_types.h" @@ -86,7 +87,7 @@ const int kDefaultNames[] = { IDS_DEFAULT_AVATAR_NAME_25 }; -} // namespace +} // namespace ProfileInfoCache::ProfileInfoCache(PrefService* prefs, const FilePath& user_data_dir) @@ -127,10 +128,22 @@ void ProfileInfoCache::AddProfileToCache(const FilePath& profile_path, sorted_keys_.insert(FindPositionForProfile(key, name), key); + FOR_EACH_OBSERVER(ProfileInfoCacheObserver, + observer_list_, + OnProfileAdded(name, UTF8ToUTF16(key))); + content::NotificationService::current()->Notify( - chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED, - content::NotificationService::AllSources(), - content::NotificationService::NoDetails()); + chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED, + content::NotificationService::AllSources(), + content::NotificationService::NoDetails()); +} + +void ProfileInfoCache::AddObserver(ProfileInfoCacheObserver* obs) { + observer_list_.AddObserver(obs); +} + +void ProfileInfoCache::RemoveObserver(ProfileInfoCacheObserver* obs) { + observer_list_.RemoveObserver(obs); } void ProfileInfoCache::DeleteProfileFromCache(const FilePath& profile_path) { @@ -138,13 +151,22 @@ void ProfileInfoCache::DeleteProfileFromCache(const FilePath& profile_path) { DictionaryValue* cache = update.Get(); std::string key = CacheKeyFromProfilePath(profile_path); + DictionaryValue* info = NULL; + cache->GetDictionary(key, &info); + string16 name; + info->GetString(kNameKey, &name); + + FOR_EACH_OBSERVER(ProfileInfoCacheObserver, + observer_list_, + OnProfileRemoved(name)); + cache->Remove(key, NULL); sorted_keys_.erase(std::find(sorted_keys_.begin(), sorted_keys_.end(), key)); content::NotificationService::current()->Notify( - chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED, - content::NotificationService::AllSources(), - content::NotificationService::NoDetails()); + chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED, + content::NotificationService::AllSources(), + content::NotificationService::NoDetails()); } size_t ProfileInfoCache::GetNumberOfProfiles() const { @@ -215,6 +237,8 @@ size_t ProfileInfoCache::GetAvatarIconIndexOfProfileAtIndex(size_t index) void ProfileInfoCache::SetNameOfProfileAtIndex(size_t index, const string16& name) { scoped_ptr<DictionaryValue> info(GetInfoForProfileAtIndex(index)->DeepCopy()); + string16 old_name; + info->GetString(kNameKey, &old_name); info->SetString(kNameKey, name); // This takes ownership of |info|. SetInfoForProfileAtIndex(index, info.release()); @@ -227,10 +251,14 @@ void ProfileInfoCache::SetNameOfProfileAtIndex(size_t index, sorted_keys_.erase(key_it); sorted_keys_.insert(FindPositionForProfile(key, name), key); + FOR_EACH_OBSERVER(ProfileInfoCacheObserver, + observer_list_, + OnProfileNameChanged(old_name, name)); + content::NotificationService::current()->Notify( - chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED, - content::NotificationService::AllSources(), - content::NotificationService::NoDetails()); + chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED, + content::NotificationService::AllSources(), + content::NotificationService::NoDetails()); } void ProfileInfoCache::SetUserNameOfProfileAtIndex(size_t index, @@ -395,9 +423,9 @@ void ProfileInfoCache::SetInfoForProfileAtIndex(size_t index, cache->Set(sorted_keys_[index], info); content::NotificationService::current()->Notify( - chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED, - content::NotificationService::AllSources(), - content::NotificationService::NoDetails()); + chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED, + content::NotificationService::AllSources(), + content::NotificationService::NoDetails()); } std::string ProfileInfoCache::CacheKeyFromProfilePath( @@ -423,6 +451,25 @@ std::vector<std::string>::iterator ProfileInfoCache::FindPositionForProfile( return sorted_keys_.end(); } +// static +std::vector<string16> ProfileInfoCache::GetProfileNames() { + std::vector<string16> names; + PrefService* local_state = g_browser_process->local_state(); + const DictionaryValue* cache = local_state->GetDictionary( + prefs::kProfileInfoCache); + string16 name; + for (base::DictionaryValue::key_iterator it = cache->begin_keys(); + it != cache->end_keys(); + ++it) { + base::DictionaryValue* info = NULL; + cache->GetDictionary(*it, &info); + info->GetString(kNameKey, &name); + names.push_back(name); + } + return names; +} + +// static void ProfileInfoCache::RegisterPrefs(PrefService* prefs) { prefs->RegisterDictionaryPref(prefs::kProfileInfoCache); } diff --git a/chrome/browser/profiles/profile_info_cache.h b/chrome/browser/profiles/profile_info_cache.h index 345503c..63e08ff 100644 --- a/chrome/browser/profiles/profile_info_cache.h +++ b/chrome/browser/profiles/profile_info_cache.h @@ -12,7 +12,9 @@ #include "base/basictypes.h" #include "base/compiler_specific.h" #include "base/file_path.h" +#include "base/observer_list.h" #include "base/string16.h" +#include "chrome/browser/profiles/profile_info_cache_observer.h" #include "chrome/browser/profiles/profile_info_interface.h" namespace gfx { @@ -25,7 +27,6 @@ class DictionaryValue; class PrefService; - // This class saves various information about profiles to local preferences. // This cache can be used to display a list of profiles without having to // actually load the profiles from disk. @@ -83,13 +84,22 @@ class ProfileInfoCache : public ProfileInfoInterface { static bool IsDefaultAvatarIconUrl(const std::string& icon_url, size_t *icon_index); + // Gets all names of profiles associated with this instance of Chrome. + // Because this method will be called during uninstall, before the creation + // of the ProfileManager, it reads directly from the local state preferences, + // rather than going through the ProfileInfoCache object. + static std::vector<string16> GetProfileNames(); + // Register cache related preferences in Local State. static void RegisterPrefs(PrefService* prefs); + void AddObserver(ProfileInfoCacheObserver* obs); + void RemoveObserver(ProfileInfoCacheObserver* obs); + private: const base::DictionaryValue* GetInfoForProfileAtIndex(size_t index) const; // Saves the profile info to a cache and takes ownership of |info|. - // Currently the only information that is cached is the profiles name, + // Currently the only information that is cached is the profile's name, // user name, and avatar icon. void SetInfoForProfileAtIndex(size_t index, base::DictionaryValue* info); std::string CacheKeyFromProfilePath(const FilePath& profile_path) const; @@ -110,6 +120,8 @@ class ProfileInfoCache : public ProfileInfoInterface { std::vector<std::string> sorted_keys_; FilePath user_data_dir_; + ObserverList<ProfileInfoCacheObserver> observer_list_; + DISALLOW_COPY_AND_ASSIGN(ProfileInfoCache); }; diff --git a/chrome/browser/profiles/profile_info_cache_observer.h b/chrome/browser/profiles/profile_info_cache_observer.h new file mode 100644 index 0000000..43beaef7 --- /dev/null +++ b/chrome/browser/profiles/profile_info_cache_observer.h @@ -0,0 +1,30 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_PROFILES_PROFILE_INFO_CACHE_OBSERVER_H_ +#define CHROME_BROWSER_PROFILES_PROFILE_INFO_CACHE_OBSERVER_H_ +#pragma once + +// This class provides an Observer interface to watch for changes to the +// ProfileInfoCache. +class ProfileInfoCacheObserver { + public: + virtual ~ProfileInfoCacheObserver() {} + + virtual void OnProfileAdded( + const string16& profile_name, + const string16& profile_base_dir) = 0; + virtual void OnProfileRemoved( + const string16& profile_name) = 0; + virtual void OnProfileNameChanged( + const string16& old_profile_name, + const string16& new_profile_name) = 0; + + protected: + ProfileInfoCacheObserver() {} + + DISALLOW_COPY_AND_ASSIGN(ProfileInfoCacheObserver); +}; + +#endif // CHROME_BROWSER_PROFILES_PROFILE_INFO_CACHE_OBSERVER_H_ diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc index 26d38b6..6836041 100644 --- a/chrome/browser/profiles/profile_manager.cc +++ b/chrome/browser/profiles/profile_manager.cc @@ -213,6 +213,9 @@ ProfileManager::ProfileManager(const FilePath& user_data_dir) ProfileManager::~ProfileManager() { BrowserList::RemoveObserver(this); +#if defined(OS_WIN) + profile_info_cache_->RemoveObserver(profile_shortcut_manager_.get()); +#endif } FilePath ProfileManager::GetDefaultProfileDir( @@ -589,6 +592,10 @@ ProfileInfoCache& ProfileManager::GetProfileInfoCache() { if (!profile_info_cache_.get()) { profile_info_cache_.reset(new ProfileInfoCache( g_browser_process->local_state(), user_data_dir_)); +#if defined(OS_WIN) + profile_shortcut_manager_.reset(new ProfileShortcutManagerWin()); + profile_info_cache_->AddObserver(profile_shortcut_manager_.get()); +#endif } return *profile_info_cache_.get(); } @@ -699,3 +706,9 @@ void ProfileManager::RegisterTestingProfile(Profile* profile, if (add_to_cache) AddProfileToCache(profile); } + +#if defined(OS_WIN) +void ProfileManager::RemoveProfileShortcutManagerForTesting() { + profile_info_cache_->RemoveObserver(profile_shortcut_manager_.get()); +} +#endif diff --git a/chrome/browser/profiles/profile_manager.h b/chrome/browser/profiles/profile_manager.h index 12c5d99..b353b0a 100644 --- a/chrome/browser/profiles/profile_manager.h +++ b/chrome/browser/profiles/profile_manager.h @@ -24,13 +24,17 @@ #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" +#if defined(OS_WIN) +#include "chrome/browser/profiles/profile_shortcut_manager_win.h" +#endif + class NewProfileLauncher; class ProfileInfoCache; class ProfileManagerObserver { public: enum Status { - // So epic. + // Asynchronous Profile services were not created. STATUS_FAIL, // Profile created but before initializing extensions and promo resources. STATUS_CREATED, @@ -190,6 +194,11 @@ class ProfileManager : public base::NonThreadSafe, // for testing. If |addToCache|, add to ProfileInfoCache as well. void RegisterTestingProfile(Profile* profile, bool addToCache); +#if defined(OS_WIN) + // Remove the shortcut manager for testing. + void RemoveProfileShortcutManagerForTesting(); +#endif + const FilePath& user_data_dir() const { return user_data_dir_; } protected: @@ -243,7 +252,7 @@ class ProfileManager : public base::NonThreadSafe, const ProfileManager::ProfilePathAndName& pair1, const ProfileManager::ProfilePathAndName& pair2); - // Adds |profile| to the profile info cache if it's not already there. + // Adds |profile| to the profile info cache if it hasn't been added yet. void AddProfileToCache(Profile* profile); // For ChromeOS, determines if profile should be otr. @@ -270,13 +279,22 @@ class ProfileManager : public base::NonThreadSafe, bool will_import_; // Maps profile path to ProfileInfo (if profile has been created). Use - // RegisterProfile() to add into this map. + // RegisterProfile() to add into this map. This map owns all loaded profile + // objects in a running instance of Chrome. typedef std::map<FilePath, linked_ptr<ProfileInfo> > ProfilesInfoMap; ProfilesInfoMap profiles_info_; - // Object to cache various information about profiles. + // Object to cache various information about profiles. Contains information + // about every profile which has been created for this instance of Chrome, + // if it has not been explicitly deleted. scoped_ptr<ProfileInfoCache> profile_info_cache_; +#if defined(OS_WIN) + // Manages the creation, deletion, and renaming of Windows shortcuts by + // observing the ProfileInfoCache. + scoped_ptr<ProfileShortcutManagerWin> profile_shortcut_manager_; +#endif + DISALLOW_COPY_AND_ASSIGN(ProfileManager); }; diff --git a/chrome/browser/profiles/profile_manager_unittest.cc b/chrome/browser/profiles/profile_manager_unittest.cc index 0392b4d..4f91e70 100644 --- a/chrome/browser/profiles/profile_manager_unittest.cc +++ b/chrome/browser/profiles/profile_manager_unittest.cc @@ -66,6 +66,12 @@ class ProfileManagerTest : public testing::Test { // Create a new temporary directory, and store the path ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); profile_manager_.reset(new ProfileManagerWithoutInit(temp_dir_.path())); +#if defined(OS_WIN) + // Force the ProfileInfoCache to be created immediately, so we can + // remove the shortcut manager for testing. + profile_manager_->GetProfileInfoCache(); + profile_manager_->RemoveProfileShortcutManagerForTesting(); +#endif } virtual void TearDown() { diff --git a/chrome/browser/profiles/profile_shortcut_manager_win.cc b/chrome/browser/profiles/profile_shortcut_manager_win.cc new file mode 100644 index 0000000..8258ef5 --- /dev/null +++ b/chrome/browser/profiles/profile_shortcut_manager_win.cc @@ -0,0 +1,216 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/profiles/profile_shortcut_manager_win.h" + +#include "base/bind.h" +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/path_service.h" +#include "base/stringprintf.h" +#include "base/utf_string_conversions.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/profiles/profile_info_cache.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/common/chrome_constants.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/pref_names.h" +#include "chrome/installer/util/browser_distribution.h" +#include "chrome/installer/util/shell_util.h" +#include "content/public/browser/browser_thread.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" + +using content::BrowserThread; + +namespace { + +// Creates the argument to pass to the Windows executable that launches Chrome +// with the profile in |profile_base_dir|. +// For example: --profile-directory="Profile 2" +string16 CreateProfileShortcutSwitch(string16 profile_base_dir) { + string16 profile_directory = base::StringPrintf(L"--%ls=\"%ls\"", + ASCIIToUTF16(switches::kProfileDirectory).c_str(), + profile_base_dir.c_str()); + return profile_directory; +} + +// Wrap a ShellUtil function that returns a bool so it can be posted in a +// task to the FILE thread. +void CallShellUtilBoolFunction( + const base::Callback<bool(void)>& bool_function) { + bool_function.Run(); +} + +} // namespace + +ProfileShortcutManagerWin::ProfileShortcutManagerWin() { +} + +ProfileShortcutManagerWin::~ProfileShortcutManagerWin() { +} + +void ProfileShortcutManagerWin::OnProfileAdded( + const string16& profile_name, + const string16& profile_base_dir) { + // Launch task to add shortcut to desktop on Windows. If this is the very + // first profile created, don't add the user name to the shortcut. + // TODO(mirandac): respect master_preferences choice to create no shortcuts + // (see http://crbug.com/104463) + if (g_browser_process->profile_manager()->GetNumberOfProfiles() > 1) { + string16 profile_directory = + CreateProfileShortcutSwitch(profile_base_dir); + BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, + base::Bind(&CreateChromeDesktopShortcutForProfile, + profile_name, profile_directory, true)); + + // If this is the very first multi-user account created, change the + // original shortcut to launch with the First User profile. + PrefService* local_state = g_browser_process->local_state(); + if (local_state->GetInteger(prefs::kProfilesNumCreated) == 2) { + string16 default_name = l10n_util::GetStringUTF16( + IDS_DEFAULT_PROFILE_NAME); + string16 default_directory = + CreateProfileShortcutSwitch(UTF8ToUTF16(chrome::kInitialProfile)); + BrowserDistribution* dist = BrowserDistribution::GetDistribution(); + + string16 old_shortcut; + string16 new_shortcut; + if (ShellUtil::GetChromeShortcutName(dist, false, L"", &old_shortcut) && + ShellUtil::GetChromeShortcutName(dist, false, default_name, + &new_shortcut)) { + // Update doesn't allow changing the target, so rename first. + BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, + base::Bind(&RenameChromeDesktopShortcutForProfile, + old_shortcut, new_shortcut)); + BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, + base::Bind(&UpdateChromeDesktopShortcutForProfile, + new_shortcut, default_directory)); + } + } + } else { // Only one profile, so create original shortcut. + BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, + base::Bind(&CreateChromeDesktopShortcutForProfile, + L"", L"", true)); + } +} + +void ProfileShortcutManagerWin::OnProfileRemoved( + const string16& profile_name) { + BrowserDistribution* dist = BrowserDistribution::GetDistribution(); + string16 shortcut; + if (ShellUtil::GetChromeShortcutName(dist, false, profile_name, &shortcut)) { + std::vector<string16> shortcuts(1, shortcut); + BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, + base::Bind(&CallShellUtilBoolFunction, + base::Bind( + &ShellUtil::RemoveChromeDesktopShortcutsWithAppendedNames, + shortcuts))); + } +} + +void ProfileShortcutManagerWin::OnProfileNameChanged( + const string16& old_profile_name, + const string16& new_profile_name) { + // Launch task to change name of desktop shortcut on Windows. + // TODO(mirandac): respect master_preferences choice to create no shortcuts + // (see http://crbug.com/104463) + string16 old_shortcut; + string16 new_shortcut; + BrowserDistribution* dist = BrowserDistribution::GetDistribution(); + if (ShellUtil::GetChromeShortcutName( + dist, false, old_profile_name, &old_shortcut) && + ShellUtil::GetChromeShortcutName( + dist, false, new_profile_name, &new_shortcut)) { + BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, + base::Bind(&RenameChromeDesktopShortcutForProfile, + old_shortcut, + new_shortcut)); + } +} + +// static +std::vector<string16> ProfileShortcutManagerWin::GenerateShortcutsFromProfiles( + const std::vector<string16>& profile_names) { + BrowserDistribution* dist = BrowserDistribution::GetDistribution(); + std::vector<string16> shortcuts; + shortcuts.reserve(profile_names.size()); + for (std::vector<string16>::const_iterator it = profile_names.begin(); + it != profile_names.end(); + ++it) { + string16 shortcut; + if (ShellUtil::GetChromeShortcutName(dist, false, *it, &shortcut)) + shortcuts.push_back(shortcut); + } + return shortcuts; +} + +// static +void ProfileShortcutManagerWin::CreateChromeDesktopShortcutForProfile( + const string16& profile_name, + const string16& directory, + bool create) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + FilePath chrome_exe; + if (!PathService::Get(base::FILE_EXE, &chrome_exe)) + return; + BrowserDistribution* dist = BrowserDistribution::GetDistribution(); + string16 description; + if (!dist) + return; + else + description = WideToUTF16(dist->GetAppDescription()); + ShellUtil::CreateChromeDesktopShortcut( + dist, + chrome_exe.value(), + description, + profile_name, + directory, + ShellUtil::CURRENT_USER, + false, // Use alternate text. + create); // Create if it doesn't already exist. +} + +// static +void ProfileShortcutManagerWin::RenameChromeDesktopShortcutForProfile( + const string16& old_shortcut, + const string16& new_shortcut) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + FilePath shortcut_path; + if (ShellUtil::GetDesktopPath(false, // User's directory instead of system. + &shortcut_path)) { + FilePath old_profile = shortcut_path.Append(old_shortcut); + FilePath new_profile = shortcut_path.Append(new_shortcut); + file_util::Move(old_profile, new_profile); + } +} + +// static +void ProfileShortcutManagerWin::UpdateChromeDesktopShortcutForProfile( + const string16& shortcut, + const string16& arguments) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + FilePath shortcut_path; + if (!ShellUtil::GetDesktopPath(false, &shortcut_path)) + return; + + shortcut_path = shortcut_path.Append(shortcut); + FilePath chrome_exe; + if (!PathService::Get(base::FILE_EXE, &chrome_exe)) + return; + BrowserDistribution* dist = BrowserDistribution::GetDistribution(); + string16 description; + if (!dist) + return; + else + description = WideToUTF16(dist->GetAppDescription()); + ShellUtil::UpdateChromeShortcut( + dist, + chrome_exe.value(), + shortcut_path.value(), + arguments, + description, + false); +} diff --git a/chrome/browser/profiles/profile_shortcut_manager_win.h b/chrome/browser/profiles/profile_shortcut_manager_win.h new file mode 100644 index 0000000..938bcbe --- /dev/null +++ b/chrome/browser/profiles/profile_shortcut_manager_win.h @@ -0,0 +1,62 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_PROFILES_PROFILE_SHORTCUT_MANAGER_WIN_H_ +#define CHROME_BROWSER_PROFILES_PROFILE_SHORTCUT_MANAGER_WIN_H_ +#pragma once + +#include <vector> + +#include "base/callback.h" +#include "base/compiler_specific.h" +#include "base/string16.h" +#include "chrome/browser/profiles/profile_info_cache_observer.h" + +// This class observes the ProfileInfoCache, and makes corresponding changes +// to shortcuts on the user's desktop in Windows systems. +class ProfileShortcutManagerWin : public ProfileInfoCacheObserver { + public: + ProfileShortcutManagerWin(); + virtual ~ProfileShortcutManagerWin(); + + // ProfileInfoCacheObserver: + virtual void OnProfileAdded( + const string16& profile_name, + const string16& profile_base_dir) OVERRIDE; + virtual void OnProfileRemoved( + const string16& profile_name) OVERRIDE; + virtual void OnProfileNameChanged( + const string16& old_profile_name, + const string16& new_profile_name) OVERRIDE; + + // Takes a vector of profile names (for example: "Sparky") and generates a + // vector of shortcut link names (for example: "Chromium (Sparky).lnk"). + static std::vector<string16> GenerateShortcutsFromProfiles( + const std::vector<string16>& profile_names); + + private: + // Creates a desktop shortcut to open Chrome with the given profile name and + // directory. Iff |create|, create shortcut if it doesn't already exist. Must + // be called on the FILE thread. + static void CreateChromeDesktopShortcutForProfile( + const string16& profile_name, + const string16& directory, + bool create); + + // Renames an existing Chrome desktop profile shortcut. Must be called on the + // FILE thread. + static void RenameChromeDesktopShortcutForProfile( + const string16& old_profile_name, + const string16& new_profile_name); + + // Updates the arguments to a Chrome desktop shortcut for a profile. Must be + // called on the FILE thread. + static void UpdateChromeDesktopShortcutForProfile( + const string16& shortcut, + const string16& arguments); + + DISALLOW_COPY_AND_ASSIGN(ProfileShortcutManagerWin); +}; + +#endif // CHROME_BROWSER_PROFILES_PROFILE_SHORTCUT_MANAGER_WIN_H_ diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 9b01954..2f01db7 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1965,6 +1965,7 @@ 'browser/profiles/profile_impl_io_data.h', 'browser/profiles/profile_info_cache.cc', 'browser/profiles/profile_info_cache.h', + 'browser/profiles/profile_info_cache_observer.h', 'browser/profiles/profile_info_interface.h', 'browser/profiles/profile_io_data.cc', 'browser/profiles/profile_io_data.h', @@ -1974,6 +1975,8 @@ 'browser/profiles/profile_manager.h', 'browser/profiles/profile_metrics.cc', 'browser/profiles/profile_metrics.h', + 'browser/profiles/profile_shortcut_manager_win.cc', + 'browser/profiles/profile_shortcut_manager_win.h', 'browser/protector/base_setting_change.cc', 'browser/protector/base_setting_change.h', 'browser/protector/default_search_provider_change.cc', diff --git a/chrome/installer/setup/install.cc b/chrome/installer/setup/install.cc index d817c48..36c24ca 100644 --- a/chrome/installer/setup/install.cc +++ b/chrome/installer/setup/install.cc @@ -131,12 +131,12 @@ bool CreateOrUpdateChromeShortcuts(const InstallerState& installer_state, VLOG(1) << "Creating shortcut to " << chrome_exe.value() << " at " << chrome_link.value(); ret = ShellUtil::UpdateChromeShortcut(browser_dist, chrome_exe.value(), - chrome_link.value(), product_desc, true); + chrome_link.value(), L"", product_desc, true); } else if (file_util::PathExists(chrome_link)) { VLOG(1) << "Updating shortcut at " << chrome_link.value() << " to point to " << chrome_exe.value(); ret = ShellUtil::UpdateChromeShortcut(browser_dist, chrome_exe.value(), - chrome_link.value(), product_desc, false); + chrome_link.value(), L"", product_desc, false); } else { VLOG(1) << "not first or repaired install, link file doesn't exist. status: " @@ -181,7 +181,7 @@ bool CreateOrUpdateChromeShortcuts(const InstallerState& installer_state, if (ret) { if (installer_state.system_install()) { ret = ShellUtil::CreateChromeDesktopShortcut(product.distribution(), - chrome_exe.value(), product_desc, ShellUtil::SYSTEM_LEVEL, + chrome_exe.value(), product_desc, L"", L"", ShellUtil::SYSTEM_LEVEL, alt_shortcut, create_all_shortcut); if (ret) { ret = ShellUtil::CreateChromeQuickLaunchShortcut( @@ -191,7 +191,7 @@ bool CreateOrUpdateChromeShortcuts(const InstallerState& installer_state, } } else { ret = ShellUtil::CreateChromeDesktopShortcut(product.distribution(), - chrome_exe.value(), product_desc, ShellUtil::CURRENT_USER, + chrome_exe.value(), product_desc, L"", L"", ShellUtil::CURRENT_USER, alt_shortcut, create_all_shortcut); if (ret) { ret = ShellUtil::CreateChromeQuickLaunchShortcut( diff --git a/chrome/installer/util/browser_distribution_unittest.cc b/chrome/installer/util/browser_distribution_unittest.cc index 942f62c..6a09443 100644 --- a/chrome/installer/util/browser_distribution_unittest.cc +++ b/chrome/installer/util/browser_distribution_unittest.cc @@ -43,10 +43,21 @@ TEST(BrowserDistributionTest, StringsTest) { TEST(BrowserDistributionTest, AlternateAndNormalShortcutName) { std::wstring normal_name; std::wstring alternate_name; + std::wstring appended_name_one; + std::wstring appended_name_two; BrowserDistribution* dist = BrowserDistribution::GetDistribution(); - EXPECT_TRUE(ShellUtil::GetChromeShortcutName(dist, &normal_name, false)); - EXPECT_TRUE(ShellUtil::GetChromeShortcutName(dist, &alternate_name, true)); + EXPECT_TRUE(ShellUtil::GetChromeShortcutName(dist, false, L"", + &normal_name)); + EXPECT_TRUE(ShellUtil::GetChromeShortcutName(dist, true, L"", + &alternate_name)); + EXPECT_TRUE(ShellUtil::GetChromeShortcutName(dist, true, L"Sparky", + &appended_name_one)); + EXPECT_TRUE(ShellUtil::GetChromeShortcutName(dist, true, L"Sparkles", + &appended_name_two)); EXPECT_NE(normal_name, alternate_name); + EXPECT_NE(appended_name_one, appended_name_two); EXPECT_FALSE(normal_name.empty()); EXPECT_FALSE(alternate_name.empty()); + EXPECT_FALSE(appended_name_one.empty()); + EXPECT_FALSE(appended_name_two.empty()); } diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc index 3b56f82..ab6622d 100644 --- a/chrome/installer/util/shell_util.cc +++ b/chrome/installer/util/shell_util.cc @@ -545,11 +545,14 @@ bool ShellUtil::AdminNeededForRegistryCleanup(BrowserDistribution* dist, bool ShellUtil::CreateChromeDesktopShortcut(BrowserDistribution* dist, const std::wstring& chrome_exe, const std::wstring& description, + const std::wstring& appended_name, + const std::wstring& arguments, ShellChange shell_change, bool alternate, bool create_new) { std::wstring shortcut_name; - if (!ShellUtil::GetChromeShortcutName(dist, &shortcut_name, alternate)) + if (!ShellUtil::GetChromeShortcutName(dist, alternate, appended_name, + &shortcut_name)) return false; bool ret = false; @@ -565,18 +568,24 @@ bool ShellUtil::CreateChromeDesktopShortcut(BrowserDistribution* dist, // nothing in it, so let's continue. if (ShellUtil::GetDesktopPath(false, &shortcut_path)) { shortcut = shortcut_path.Append(shortcut_name); - ret = ShellUtil::UpdateChromeShortcut(dist, chrome_exe, + ret = ShellUtil::UpdateChromeShortcut(dist, + chrome_exe, shortcut.value(), - description, create_new); + arguments, + description, + create_new); } } } else if (shell_change == ShellUtil::SYSTEM_LEVEL) { FilePath shortcut_path; if (ShellUtil::GetDesktopPath(true, &shortcut_path)) { FilePath shortcut = shortcut_path.Append(shortcut_name); - ret = ShellUtil::UpdateChromeShortcut(dist, chrome_exe, + ret = ShellUtil::UpdateChromeShortcut(dist, + chrome_exe, shortcut.value(), - description, create_new); + arguments, + description, + create_new); } } else { NOTREACHED(); @@ -589,7 +598,7 @@ bool ShellUtil::CreateChromeQuickLaunchShortcut(BrowserDistribution* dist, int shell_change, bool create_new) { std::wstring shortcut_name; - if (!ShellUtil::GetChromeShortcutName(dist, &shortcut_name, false)) + if (!ShellUtil::GetChromeShortcutName(dist, false, L"", &shortcut_name)) return false; bool ret = true; @@ -599,7 +608,7 @@ bool ShellUtil::CreateChromeQuickLaunchShortcut(BrowserDistribution* dist, if (ShellUtil::GetQuickLaunchPath(false, &user_ql_path)) { file_util::AppendToPath(&user_ql_path, shortcut_name); ret = ShellUtil::UpdateChromeShortcut(dist, chrome_exe, user_ql_path, - L"", create_new); + L"", L"", create_new); } else { ret = false; } @@ -612,7 +621,7 @@ bool ShellUtil::CreateChromeQuickLaunchShortcut(BrowserDistribution* dist, if (ShellUtil::GetQuickLaunchPath(true, &default_ql_path)) { file_util::AppendToPath(&default_ql_path, shortcut_name); ret = ShellUtil::UpdateChromeShortcut(dist, chrome_exe, default_ql_path, - L"", create_new) && ret; + L"", L"", create_new) && ret; } else { ret = false; } @@ -634,9 +643,16 @@ std::wstring ShellUtil::GetChromeShellOpenCmd(const std::wstring& chrome_exe) { } bool ShellUtil::GetChromeShortcutName(BrowserDistribution* dist, - std::wstring* shortcut, bool alternate) { + bool alternate, + const std::wstring& appended_name, + std::wstring* shortcut) { shortcut->assign(alternate ? dist->GetAlternateApplicationName() : dist->GetAppShortCutName()); + if (!appended_name.empty()) { + shortcut->append(L" ("); + shortcut->append(appended_name); + shortcut->append(L")"); + } shortcut->append(L".lnk"); return true; } @@ -954,7 +970,8 @@ bool ShellUtil::RegisterChromeForProtocol(BrowserDistribution* dist, bool ShellUtil::RemoveChromeDesktopShortcut(BrowserDistribution* dist, int shell_change, bool alternate) { std::wstring shortcut_name; - if (!ShellUtil::GetChromeShortcutName(dist, &shortcut_name, alternate)) + if (!ShellUtil::GetChromeShortcutName(dist, alternate, L"", + &shortcut_name)) return false; bool ret = true; @@ -980,10 +997,28 @@ bool ShellUtil::RemoveChromeDesktopShortcut(BrowserDistribution* dist, return ret; } +bool ShellUtil::RemoveChromeDesktopShortcutsWithAppendedNames( + const std::vector<std::wstring>& appended_names) { + FilePath shortcut_path; + bool ret = true; + if (ShellUtil::GetDesktopPath(false, &shortcut_path)) { + for (std::vector<std::wstring>::const_iterator it = + appended_names.begin(); + it != appended_names.end(); + ++it) { + FilePath delete_shortcut = shortcut_path.Append(*it); + ret = ret && file_util::Delete(delete_shortcut, false); + } + } else { + ret = false; + } + return ret; +} + bool ShellUtil::RemoveChromeQuickLaunchShortcut(BrowserDistribution* dist, int shell_change) { std::wstring shortcut_name; - if (!ShellUtil::GetChromeShortcutName(dist, &shortcut_name, false)) + if (!ShellUtil::GetChromeShortcutName(dist, false, L"", &shortcut_name)) return false; bool ret = true; @@ -1015,6 +1050,7 @@ bool ShellUtil::RemoveChromeQuickLaunchShortcut(BrowserDistribution* dist, bool ShellUtil::UpdateChromeShortcut(BrowserDistribution* dist, const std::wstring& chrome_exe, const std::wstring& shortcut, + const std::wstring& arguments, const std::wstring& description, bool create_new) { std::wstring chrome_path = FilePath(chrome_exe).DirName().value(); @@ -1030,7 +1066,7 @@ bool ShellUtil::UpdateChromeShortcut(BrowserDistribution* dist, chrome_exe.c_str(), // target shortcut.c_str(), // shortcut chrome_path.c_str(), // working dir - NULL, // arguments + arguments.c_str(), // arguments description.c_str(), // description chrome_exe.c_str(), // icon file icon_index, // icon index @@ -1040,7 +1076,7 @@ bool ShellUtil::UpdateChromeShortcut(BrowserDistribution* dist, chrome_exe.c_str(), // target shortcut.c_str(), // shortcut chrome_path.c_str(), // working dir - NULL, // arguments + arguments.c_str(), // arguments description.c_str(), // description chrome_exe.c_str(), // icon file icon_index, // icon index diff --git a/chrome/installer/util/shell_util.h b/chrome/installer/util/shell_util.h index fcb0fb8..9b0524a 100644 --- a/chrome/installer/util/shell_util.h +++ b/chrome/installer/util/shell_util.h @@ -20,6 +20,10 @@ class BrowserDistribution; class FilePath; +namespace base { +class DictionaryValue; +} + // This is a utility class that provides common shell integration methods // that can be used by installer as well as Chrome. class ShellUtil { @@ -87,18 +91,26 @@ class ShellUtil { static bool AdminNeededForRegistryCleanup(BrowserDistribution* dist, const std::wstring& suffix); - // Create Chrome shortcut on Desktop - // If shell_change is CURRENT_USER, the shortcut is created in the - // Desktop folder of current user's profile. - // If shell_change is SYSTEM_LEVEL, the shortcut is created in the - // Desktop folder of "All Users" profile. - // If alternate is true, an alternate text for the shortcut is used. - // create_new: If false, will only update the shortcut. If true, the function - // will create a new shortcut if it doesn't exist already. + // Creates Chrome shortcut on the Desktop. + // |dist| gives the type of browser distribution currently in use. + // |chrome_exe| provides the target path information. + // |description| provides the shortcut's "comment" property. + // |appended_name| provides a string to be appended to the distribution name, + // and can be the empty string. + // |arguments| gives a set of arguments to be passed to the executable. + // If |shell_change| is CURRENT_USER, the shortcut is created in the + // Desktop folder of current user's profile. + // If |shell_change| is SYSTEM_LEVEL, the shortcut is created in the + // Desktop folder of the "All Users" profile. + // If |alternate| is true, an alternate text for the shortcut is used. + // If |create_new| is false, an existing shortcut will be updated, but if + // no shortcut exists, it will not be created. // Returns true iff the method causes a shortcut to be created / updated. static bool CreateChromeDesktopShortcut(BrowserDistribution* dist, const std::wstring& chrome_exe, const std::wstring& description, + const std::wstring& appended_name, + const std::wstring& arguments, ShellChange shell_change, bool alternate, bool create_new); @@ -129,11 +141,14 @@ class ShellUtil { // chrome_exe: the full path to chrome.exe static std::wstring GetChromeShellOpenCmd(const std::wstring& chrome_exe); - // Returns the localized name of Chrome shortcut. If |alternate| is true - // it returns a second localized text that is better suited for certain - // scenarios. + // Returns the localized name of Chrome shortcut in |shortcut|. If + // |appended_name| is not empty, it is included in the shortcut name. If + // |alternate| is true, a second localized text that is better suited for + // certain scenarios is used. static bool GetChromeShortcutName(BrowserDistribution* dist, - std::wstring* shortcut, bool alternate); + bool alternate, + const std::wstring& appended_name, + std::wstring* shortcut); // Gets the desktop path for the current user or all users (if system_level // is true) and returns it in 'path' argument. Return true if successful, @@ -250,7 +265,14 @@ class ShellUtil { // If alternate is true, the shortcut with the alternate name is removed. See // CreateChromeDesktopShortcut() for more information. static bool RemoveChromeDesktopShortcut(BrowserDistribution* dist, - int shell_change, bool alternate); + int shell_change, + bool alternate); + + // Removes a set of existing Chrome desktop shortcuts. |appended_names| is a + // list of shortcut file names as obtained from + // ShellUtil::GetChromeShortcutName. + static bool RemoveChromeDesktopShortcutsWithAppendedNames( + const std::vector<std::wstring>& appended_names); // Remove Chrome shortcut from Quick Launch Bar. // If shell_change is CURRENT_USER, the shortcut is removed from @@ -261,13 +283,14 @@ class ShellUtil { int shell_change); // Updates shortcut (or creates a new shortcut) at destination given by - // shortcut to a target given by chrome_exe. The arguments is left NULL - // for the target and icon is set as icon at index 0 from exe. + // shortcut to a target given by chrome_exe. The arguments are given by + // |arguments| for the target and icon is set as icon at index 0 from exe. // If create_new is set to true, the function will create a new shortcut if // if doesn't exist. static bool UpdateChromeShortcut(BrowserDistribution* dist, const std::wstring& chrome_exe, const std::wstring& shortcut, + const std::wstring& arguments, const std::wstring& description, bool create_new); diff --git a/chrome/installer/util/shell_util_unittest.cc b/chrome/installer/util/shell_util_unittest.cc index f6d3dd1..625010e 100644 --- a/chrome/installer/util/shell_util_unittest.cc +++ b/chrome/installer/util/shell_util_unittest.cc @@ -109,9 +109,12 @@ TEST_F(ShellUtilTest, UpdateChromeShortcutTest) { FilePath shortcut_path = temp_dir_.path().AppendASCII("shortcut.lnk"); const std::wstring description(L"dummy description"); - EXPECT_TRUE(ShellUtil::UpdateChromeShortcut(dist, exe_path.value(), + EXPECT_TRUE(ShellUtil::UpdateChromeShortcut(dist, + exe_path.value(), shortcut_path.value(), - description, true)); + L"", + description, + true)); EXPECT_TRUE(VerifyChromeShortcut(exe_path.value(), shortcut_path.value(), description, 0)); @@ -130,9 +133,12 @@ TEST_F(ShellUtilTest, UpdateChromeShortcutTest) { "}"; file.close(); ASSERT_TRUE(file_util::Delete(shortcut_path, false)); - EXPECT_TRUE(ShellUtil::UpdateChromeShortcut(dist, exe_path.value(), + EXPECT_TRUE(ShellUtil::UpdateChromeShortcut(dist, + exe_path.value(), shortcut_path.value(), - description, true)); + L"", + description, + true)); EXPECT_TRUE(VerifyChromeShortcut(exe_path.value(), shortcut_path.value(), description, 1)); @@ -140,9 +146,12 @@ TEST_F(ShellUtilTest, UpdateChromeShortcutTest) { // Now change only description to update shortcut and make sure icon index // doesn't change. const std::wstring description2(L"dummy description 2"); - EXPECT_TRUE(ShellUtil::UpdateChromeShortcut(dist, exe_path.value(), + EXPECT_TRUE(ShellUtil::UpdateChromeShortcut(dist, + exe_path.value(), shortcut_path.value(), - description2, false)); + L"", + description2, + false)); EXPECT_TRUE(VerifyChromeShortcut(exe_path.value(), shortcut_path.value(), description2, 1)); @@ -173,15 +182,34 @@ TEST_F(ShellUtilTest, CreateChromeDesktopShortcutTest) { EXPECT_TRUE(ShellUtil::GetDesktopPath(true, &system_desktop_path)); std::wstring shortcut_name; - EXPECT_TRUE(ShellUtil::GetChromeShortcutName(dist, &shortcut_name, false)); + EXPECT_TRUE(ShellUtil::GetChromeShortcutName(dist, false, L"", + &shortcut_name)); + + std::wstring default_profile_shortcut_name; + const std::wstring default_profile_user_name = L"Minsk"; + EXPECT_TRUE(ShellUtil::GetChromeShortcutName(dist, false, + default_profile_user_name, + &default_profile_shortcut_name)); + + std::wstring second_profile_shortcut_name; + const std::wstring second_profile_user_name = L"Pinsk"; + EXPECT_TRUE(ShellUtil::GetChromeShortcutName(dist, false, + second_profile_user_name, + &second_profile_shortcut_name)); FilePath user_shortcut_path = user_desktop_path.Append(shortcut_name); FilePath system_shortcut_path = system_desktop_path.Append(shortcut_name); + FilePath default_profile_shortcut_path = user_desktop_path.Append( + default_profile_shortcut_name); + FilePath second_profile_shortcut_path = user_desktop_path.Append( + second_profile_shortcut_name); // Test simple creation of a user-level shortcut. EXPECT_TRUE(ShellUtil::CreateChromeDesktopShortcut(dist, exe_path.value(), description, + L"", + L"", ShellUtil::CURRENT_USER, false, true)); @@ -197,6 +225,8 @@ TEST_F(ShellUtilTest, CreateChromeDesktopShortcutTest) { EXPECT_TRUE(ShellUtil::CreateChromeDesktopShortcut(dist, exe_path.value(), description, + L"", + L"", ShellUtil::SYSTEM_LEVEL, false, true)); @@ -213,12 +243,16 @@ TEST_F(ShellUtilTest, CreateChromeDesktopShortcutTest) { EXPECT_TRUE(ShellUtil::CreateChromeDesktopShortcut(dist, exe_path.value(), description, + L"", + L"", ShellUtil::SYSTEM_LEVEL, false, true)); EXPECT_FALSE(ShellUtil::CreateChromeDesktopShortcut(dist, exe_path.value(), description, + L"", + L"", ShellUtil::CURRENT_USER, false, true)); @@ -236,12 +270,16 @@ TEST_F(ShellUtilTest, CreateChromeDesktopShortcutTest) { EXPECT_TRUE(ShellUtil::CreateChromeDesktopShortcut(dist, exe_path.value(), description, + L"", + L"", ShellUtil::CURRENT_USER, false, true)); EXPECT_TRUE(ShellUtil::CreateChromeDesktopShortcut(dist, exe_path.value(), description, + L"", + L"", ShellUtil::SYSTEM_LEVEL, false, true)); @@ -259,4 +297,38 @@ TEST_F(ShellUtilTest, CreateChromeDesktopShortcutTest) { EXPECT_TRUE(ShellUtil::RemoveChromeDesktopShortcut(dist, ShellUtil::SYSTEM_LEVEL, false)); + + // Test creation of two profile-specific shortcuts (these are always + // user-level). + EXPECT_TRUE(ShellUtil::CreateChromeDesktopShortcut( + dist, + exe_path.value(), + description, + default_profile_user_name, + L"--profile-directory=\"Default\"", + ShellUtil::CURRENT_USER, + false, + true)); + EXPECT_TRUE(VerifyChromeShortcut(exe_path.value(), + default_profile_shortcut_path.value(), + description, + 0)); + EXPECT_TRUE(ShellUtil::CreateChromeDesktopShortcut( + dist, + exe_path.value(), + description, + second_profile_user_name, + L"--profile-directory=\"Profile 1\"", + ShellUtil::CURRENT_USER, + false, + true)); + EXPECT_TRUE(VerifyChromeShortcut(exe_path.value(), + second_profile_shortcut_path.value(), + description, + 0)); + std::vector<string16> profile_names; + profile_names.push_back(default_profile_shortcut_name); + profile_names.push_back(second_profile_shortcut_name); + EXPECT_TRUE(ShellUtil::RemoveChromeDesktopShortcutsWithAppendedNames( + profile_names)); } |