Chromium Code Reviews| OLD | NEW | 
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "chrome/browser/profiles/profile_shortcut_manager_win.h" | 5 #include "chrome/browser/profiles/profile_shortcut_manager_win.h" | 
| 6 | 6 | 
| 7 #include <shlobj.h> // For SHChangeNotify(). | 7 #include <shlobj.h> // For SHChangeNotify(). | 
| 8 | 8 | 
| 9 #include <string> | 9 #include <string> | 
| 10 #include <vector> | 10 #include <vector> | 
| 11 | 11 | 
| 12 #include "base/bind.h" | 12 #include "base/bind.h" | 
| 13 #include "base/command_line.h" | 13 #include "base/command_line.h" | 
| 14 #include "base/file_util.h" | 14 #include "base/file_util.h" | 
| 15 #include "base/files/file_enumerator.h" | 15 #include "base/files/file_enumerator.h" | 
| 16 #include "base/path_service.h" | 16 #include "base/path_service.h" | 
| 17 #include "base/prefs/pref_service.h" | |
| 17 #include "base/strings/string16.h" | 18 #include "base/strings/string16.h" | 
| 18 #include "base/strings/string_util.h" | 19 #include "base/strings/string_util.h" | 
| 19 #include "base/strings/stringprintf.h" | 20 #include "base/strings/stringprintf.h" | 
| 20 #include "base/strings/utf_string_conversions.h" | 21 #include "base/strings/utf_string_conversions.h" | 
| 21 #include "base/win/shortcut.h" | 22 #include "base/win/shortcut.h" | 
| 22 #include "chrome/browser/app_icon_win.h" | 23 #include "chrome/browser/app_icon_win.h" | 
| 23 #include "chrome/browser/browser_process.h" | 24 #include "chrome/browser/browser_process.h" | 
| 25 #include "chrome/browser/chrome_notification_types.h" | |
| 24 #include "chrome/browser/profiles/profile_info_cache_observer.h" | 26 #include "chrome/browser/profiles/profile_info_cache_observer.h" | 
| 25 #include "chrome/browser/profiles/profile_info_util.h" | 27 #include "chrome/browser/profiles/profile_info_util.h" | 
| 26 #include "chrome/browser/profiles/profile_manager.h" | 28 #include "chrome/browser/profiles/profile_manager.h" | 
| 27 #include "chrome/browser/shell_integration.h" | 29 #include "chrome/browser/shell_integration.h" | 
| 28 #include "chrome/common/chrome_switches.h" | 30 #include "chrome/common/chrome_switches.h" | 
| 31 #include "chrome/common/pref_names.h" | |
| 29 #include "chrome/installer/util/browser_distribution.h" | 32 #include "chrome/installer/util/browser_distribution.h" | 
| 30 #include "chrome/installer/util/product.h" | 33 #include "chrome/installer/util/product.h" | 
| 31 #include "chrome/installer/util/shell_util.h" | 34 #include "chrome/installer/util/shell_util.h" | 
| 32 #include "content/public/browser/browser_thread.h" | 35 #include "content/public/browser/browser_thread.h" | 
| 36 #include "content/public/browser/notification_service.h" | |
| 33 #include "grit/chrome_unscaled_resources.h" | 37 #include "grit/chrome_unscaled_resources.h" | 
| 34 #include "grit/chromium_strings.h" | 38 #include "grit/chromium_strings.h" | 
| 35 #include "skia/ext/image_operations.h" | 39 #include "skia/ext/image_operations.h" | 
| 36 #include "skia/ext/platform_canvas.h" | 40 #include "skia/ext/platform_canvas.h" | 
| 37 #include "ui/base/l10n/l10n_util.h" | 41 #include "ui/base/l10n/l10n_util.h" | 
| 38 #include "ui/base/resource/resource_bundle.h" | 42 #include "ui/base/resource/resource_bundle.h" | 
| 39 #include "ui/gfx/icon_util.h" | 43 #include "ui/gfx/icon_util.h" | 
| 40 #include "ui/gfx/image/image.h" | 44 #include "ui/gfx/image/image.h" | 
| 41 #include "ui/gfx/image/image_family.h" | 45 #include "ui/gfx/image/image_family.h" | 
| 42 #include "ui/gfx/rect.h" | 46 #include "ui/gfx/rect.h" | 
| 43 #include "ui/gfx/skia_util.h" | 47 #include "ui/gfx/skia_util.h" | 
| 44 | 48 | 
| 45 using content::BrowserThread; | 49 using content::BrowserThread; | 
| 46 | 50 | 
| 47 namespace { | 51 namespace { | 
| 48 | 52 | 
| 53 // Name of the badged icon file generated for a given profile. | |
| 54 const char kProfileIconFileName[] = "Google Profile.ico"; | |
| 55 | |
| 49 // Characters that are not allowed in Windows filenames. Taken from | 56 // Characters that are not allowed in Windows filenames. Taken from | 
| 50 // http://msdn.microsoft.com/en-us/library/aa365247.aspx | 57 // http://msdn.microsoft.com/en-us/library/aa365247.aspx | 
| 51 const char16 kReservedCharacters[] = L"<>:\"/\\|?*\x01\x02\x03\x04\x05\x06\x07" | 58 const char16 kReservedCharacters[] = L"<>:\"/\\|?*\x01\x02\x03\x04\x05\x06\x07" | 
| 52 L"\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19" | 59 L"\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19" | 
| 53 L"\x1A\x1B\x1C\x1D\x1E\x1F"; | 60 L"\x1A\x1B\x1C\x1D\x1E\x1F"; | 
| 54 | 61 | 
| 55 // The maximum number of characters allowed in profile shortcuts' file names. | 62 // The maximum number of characters allowed in profile shortcuts' file names. | 
| 56 // Warning: migration code will be needed if this is changed later, since | 63 // Warning: migration code will be needed if this is changed later, since | 
| 57 // existing shortcuts might no longer be found if the name is generated | 64 // existing shortcuts might no longer be found if the name is generated | 
| 58 // differently than it was when a shortcut was originally created. | 65 // differently than it was when a shortcut was originally created. | 
| 59 const int kMaxProfileShortcutFileNameLength = 64; | 66 const int kMaxProfileShortcutFileNameLength = 64; | 
| 60 | 67 | 
| 61 const int kProfileAvatarBadgeSize = 28; | 68 const int kProfileAvatarBadgeSize = 28; | 
| 62 const int kShortcutIconSize = 48; | 69 const int kShortcutIconSize = 48; | 
| 63 | 70 | 
| 71 const int kCurrentProfileIconVersion = 1; | |
| 72 | |
| 64 // 2x sized profile avatar icons. Mirrors |kDefaultAvatarIconResources| in | 73 // 2x sized profile avatar icons. Mirrors |kDefaultAvatarIconResources| in | 
| 65 // profile_info_cache.cc. | 74 // profile_info_cache.cc. | 
| 66 const int kProfileAvatarIconResources2x[] = { | 75 const int kProfileAvatarIconResources2x[] = { | 
| 67 IDR_PROFILE_AVATAR_2X_0, | 76 IDR_PROFILE_AVATAR_2X_0, | 
| 68 IDR_PROFILE_AVATAR_2X_1, | 77 IDR_PROFILE_AVATAR_2X_1, | 
| 69 IDR_PROFILE_AVATAR_2X_2, | 78 IDR_PROFILE_AVATAR_2X_2, | 
| 70 IDR_PROFILE_AVATAR_2X_3, | 79 IDR_PROFILE_AVATAR_2X_3, | 
| 71 IDR_PROFILE_AVATAR_2X_4, | 80 IDR_PROFILE_AVATAR_2X_4, | 
| 72 IDR_PROFILE_AVATAR_2X_5, | 81 IDR_PROFILE_AVATAR_2X_5, | 
| 73 IDR_PROFILE_AVATAR_2X_6, | 82 IDR_PROFILE_AVATAR_2X_6, | 
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 134 const SkBitmap& badged_bitmap = | 143 const SkBitmap& badged_bitmap = | 
| 135 offscreen_canvas->getDevice()->accessBitmap(false); | 144 offscreen_canvas->getDevice()->accessBitmap(false); | 
| 136 SkBitmap badged_bitmap_copy; | 145 SkBitmap badged_bitmap_copy; | 
| 137 badged_bitmap.deepCopyTo(&badged_bitmap_copy, badged_bitmap.getConfig()); | 146 badged_bitmap.deepCopyTo(&badged_bitmap_copy, badged_bitmap.getConfig()); | 
| 138 return badged_bitmap_copy; | 147 return badged_bitmap_copy; | 
| 139 } | 148 } | 
| 140 | 149 | 
| 141 // Creates a desktop shortcut icon file (.ico) on the disk for a given profile, | 150 // Creates a desktop shortcut icon file (.ico) on the disk for a given profile, | 
| 142 // badging the browser distribution icon with the profile avatar. | 151 // badging the browser distribution icon with the profile avatar. | 
| 143 // Returns a path to the shortcut icon file on disk, which is empty if this | 152 // Returns a path to the shortcut icon file on disk, which is empty if this | 
| 144 // fails. Use index 0 when assigning the resulting file as the icon. | 153 // fails. Use index 0 when assigning the resulting file as the icon. If both | 
| 145 base::FilePath CreateChromeDesktopShortcutIconForProfile( | 154 // given bitmaps are empty, an unbadged icon is created. | 
| 155 // |callback| will be run on successful icon creation. | |
| 156 // Returns the path to the created icon on success and an empty base::FilePath | |
| 157 // on failure. | |
| 158 // TODO(calamity): Ideally we'd just copy the app icon verbatim from the exe's | |
| 159 // resources in the case of an unbadged icon. | |
| 160 base::FilePath CreateOrUpdateShortcutIconForProfile( | |
| 146 const base::FilePath& profile_path, | 161 const base::FilePath& profile_path, | 
| 147 const SkBitmap& avatar_bitmap_1x, | 162 const SkBitmap& avatar_bitmap_1x, | 
| 148 const SkBitmap& avatar_bitmap_2x) { | 163 const SkBitmap& avatar_bitmap_2x, | 
| 164 const base::Closure& callback) { | |
| 149 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 165 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 
| 166 | |
| 150 scoped_ptr<SkBitmap> app_icon_bitmap(GetAppIconForSize(kShortcutIconSize)); | 167 scoped_ptr<SkBitmap> app_icon_bitmap(GetAppIconForSize(kShortcutIconSize)); | 
| 151 if (!app_icon_bitmap) | 168 if (!app_icon_bitmap) | 
| 152 return base::FilePath(); | 169 return base::FilePath(); | 
| 153 | 170 | 
| 154 gfx::ImageFamily badged_bitmaps; | 171 gfx::ImageFamily badged_bitmaps; | 
| 155 badged_bitmaps.Add(gfx::Image::CreateFrom1xBitmap( | 172 if (!avatar_bitmap_1x.empty()) { | 
| 156 BadgeIcon(*app_icon_bitmap, avatar_bitmap_1x, 1))); | |
| 157 | |
| 158 app_icon_bitmap = GetAppIconForSize(IconUtil::kLargeIconSize); | |
| 159 if (app_icon_bitmap) { | |
| 160 badged_bitmaps.Add(gfx::Image::CreateFrom1xBitmap( | 173 badged_bitmaps.Add(gfx::Image::CreateFrom1xBitmap( | 
| 161 BadgeIcon(*app_icon_bitmap, avatar_bitmap_2x, 2))); | 174 BadgeIcon(*app_icon_bitmap, avatar_bitmap_1x, 1))); | 
| 162 } | 175 } | 
| 163 | 176 | 
| 177 scoped_ptr<SkBitmap> large_app_icon_bitmap( | |
| 178 GetAppIconForSize(IconUtil::kLargeIconSize)); | |
| 179 if (large_app_icon_bitmap && !avatar_bitmap_2x.empty()) { | |
| 180 badged_bitmaps.Add(gfx::Image::CreateFrom1xBitmap( | |
| 181 BadgeIcon(*large_app_icon_bitmap, avatar_bitmap_2x, 2))); | |
| 182 } | |
| 183 | |
| 184 // If we have no badged bitmaps, we should just use the default chrome icon. | |
| 185 if (badged_bitmaps.empty()) { | |
| 186 badged_bitmaps.Add(gfx::Image::CreateFrom1xBitmap(*app_icon_bitmap)); | |
| 187 if (large_app_icon_bitmap) { | |
| 188 badged_bitmaps.Add( | |
| 189 gfx::Image::CreateFrom1xBitmap(*large_app_icon_bitmap)); | |
| 190 } | |
| 191 } | |
| 164 // Finally, write the .ico file containing this new bitmap. | 192 // Finally, write the .ico file containing this new bitmap. | 
| 165 const base::FilePath icon_path = | 193 const base::FilePath icon_path = | 
| 166 profile_path.AppendASCII(profiles::internal::kProfileIconFileName); | 194 profiles::internal::GetProfileIconPath(profile_path); | 
| 167 if (!IconUtil::CreateIconFileFromImageFamily(badged_bitmaps, icon_path)) | 195 const bool had_icon = base::PathExists(icon_path); | 
| 196 | |
| 197 if (!base::PathExists(icon_path.DirName()) || | |
| 198 !IconUtil::CreateIconFileFromImageFamily(badged_bitmaps, icon_path)) { | |
| 199 DLOG(WARNING) << "Could not write profile icon file to " | |
| 200 << icon_path.value(); | |
| 
 
gab
2013/07/16 14:10:38
If the suggested test fixes work, I think I still
 
calamity
2013/07/18 08:39:08
It's reachable because the OS can do anything anyt
 
 | |
| 168 return base::FilePath(); | 201 return base::FilePath(); | 
| 202 } | |
| 169 | 203 | 
| 204 if (had_icon) { | |
| 205 // This invalidates the Windows icon cache and causes the icon changes to | |
| 206 // register with the taskbar and desktop. SHCNE_ASSOCCHANGED will cause a | |
| 207 // desktop flash and we would like to avoid that if possible. | |
| 208 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); | |
| 209 } else { | |
| 210 SHChangeNotify(SHCNE_CREATE, SHCNF_PATH, icon_path.value().c_str(), NULL); | |
| 211 } | |
| 212 if (!callback.is_null()) | |
| 213 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback); | |
| 170 return icon_path; | 214 return icon_path; | 
| 171 } | 215 } | 
| 172 | 216 | 
| 217 // Updates the preferences with the current icon version on icon creation | |
| 218 // success. | |
| 219 void OnProfileIconCreateSuccess(base::FilePath profile_path) { | |
| 220 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 221 if (!g_browser_process->profile_manager()) | |
| 222 return; | |
| 223 Profile* profile = | |
| 224 g_browser_process->profile_manager()->GetProfileByPath(profile_path); | |
| 225 if (profile) { | |
| 226 profile->GetPrefs()->SetInteger(prefs::kProfileIconVersion, | |
| 227 kCurrentProfileIconVersion); | |
| 228 } | |
| 229 } | |
| 230 | |
| 173 // Gets the user and system directories for desktop shortcuts. Parameters may | 231 // Gets the user and system directories for desktop shortcuts. Parameters may | 
| 174 // be NULL if a directory type is not needed. Returns true on success. | 232 // be NULL if a directory type is not needed. Returns true on success. | 
| 175 bool GetDesktopShortcutsDirectories( | 233 bool GetDesktopShortcutsDirectories( | 
| 176 base::FilePath* user_shortcuts_directory, | 234 base::FilePath* user_shortcuts_directory, | 
| 177 base::FilePath* system_shortcuts_directory) { | 235 base::FilePath* system_shortcuts_directory) { | 
| 178 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); | 236 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); | 
| 179 if (user_shortcuts_directory && | 237 if (user_shortcuts_directory && | 
| 180 !ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_DESKTOP, | 238 !ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_DESKTOP, | 
| 181 distribution, ShellUtil::CURRENT_USER, | 239 distribution, ShellUtil::CURRENT_USER, | 
| 182 user_shortcuts_directory)) { | 240 user_shortcuts_directory)) { | 
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 294 if (base::PathExists(possible_new_system_shortcut)) | 352 if (base::PathExists(possible_new_system_shortcut)) | 
| 295 base::Delete(old_shortcut_path, false); | 353 base::Delete(old_shortcut_path, false); | 
| 296 else if (!RenameDesktopShortcut(old_shortcut_path, new_shortcut_path)) | 354 else if (!RenameDesktopShortcut(old_shortcut_path, new_shortcut_path)) | 
| 297 DLOG(ERROR) << "Could not rename Windows profile desktop shortcut."; | 355 DLOG(ERROR) << "Could not rename Windows profile desktop shortcut."; | 
| 298 } else { | 356 } else { | 
| 299 // If the shortcut does not exist, it may have been renamed by the user. In | 357 // If the shortcut does not exist, it may have been renamed by the user. In | 
| 300 // that case, its name should not be changed. | 358 // that case, its name should not be changed. | 
| 301 // It's also possible that a system-level shortcut exists instead - this | 359 // It's also possible that a system-level shortcut exists instead - this | 
| 302 // should only be the case for the original Chrome shortcut from an | 360 // should only be the case for the original Chrome shortcut from an | 
| 303 // installation. If that's the case, copy that one over - it will get its | 361 // installation. If that's the case, copy that one over - it will get its | 
| 304 // properties updated by |CreateOrUpdateDesktopShortcutsForProfile()|. | 362 // properties updated by | 
| 363 // |CreateOrUpdateDesktopShortcutsAndIconForProfile()|. | |
| 305 const base::FilePath possible_old_system_shortcut = | 364 const base::FilePath possible_old_system_shortcut = | 
| 306 system_shortcuts_directory.Append(old_shortcut_filename); | 365 system_shortcuts_directory.Append(old_shortcut_filename); | 
| 307 if (base::PathExists(possible_old_system_shortcut)) | 366 if (base::PathExists(possible_old_system_shortcut)) | 
| 308 base::CopyFile(possible_old_system_shortcut, new_shortcut_path); | 367 base::CopyFile(possible_old_system_shortcut, new_shortcut_path); | 
| 309 } | 368 } | 
| 310 } | 369 } | 
| 311 | 370 | 
| 371 struct CreateOrUpdateShortcutsParams { | |
| 372 CreateOrUpdateShortcutsParams( | |
| 373 base::FilePath profile_path, | |
| 374 ProfileShortcutManagerWin::CreateOrUpdateMode create_mode, | |
| 375 ProfileShortcutManagerWin::NonProfileShortcutAction action) | |
| 376 : profile_path(profile_path), create_mode(create_mode), action(action) {} | |
| 377 ~CreateOrUpdateShortcutsParams() {} | |
| 378 | |
| 379 ProfileShortcutManagerWin::CreateOrUpdateMode create_mode; | |
| 380 ProfileShortcutManagerWin::NonProfileShortcutAction action; | |
| 381 | |
| 382 // The path for this profile. | |
| 383 base::FilePath profile_path; | |
| 384 // The profile name before this update. Empty on create. | |
| 385 string16 old_profile_name; | |
| 386 // The new profile name. | |
| 387 string16 profile_name; | |
| 388 // Avatar images for this profile. | |
| 389 SkBitmap avatar_image_1x; | |
| 390 SkBitmap avatar_image_2x; | |
| 391 }; | |
| 392 | |
| 312 // Updates all desktop shortcuts for the given profile to have the specified | 393 // Updates all desktop shortcuts for the given profile to have the specified | 
| 313 // parameters. If |create_mode| is CREATE_WHEN_NONE_FOUND, a new shortcut is | 394 // parameters. If |params.create_mode| is CREATE_WHEN_NONE_FOUND, a new shortcut | 
| 314 // created if no existing ones were found. Whether non-profile shortcuts should | 395 // is created if no existing ones were found. Whether non-profile shortcuts | 
| 315 // be updated is specified by |action|. Must be called on the FILE thread. | 396 // should be updated is specified by |params.action|. Must be called on the FILE | 
| 316 void CreateOrUpdateDesktopShortcutsForProfile( | 397 // thread. |callback| is called on successful icon creation. | 
| 317 const base::FilePath& profile_path, | 398 void CreateOrUpdateDesktopShortcutsAndIconForProfile( | 
| 318 const string16& old_profile_name, | 399 const CreateOrUpdateShortcutsParams& params, | 
| 319 const string16& profile_name, | 400 const base::Closure& callback) { | 
| 320 const SkBitmap& avatar_image_1x, | |
| 321 const SkBitmap& avatar_image_2x, | |
| 322 ProfileShortcutManagerWin::CreateOrUpdateMode create_mode, | |
| 323 ProfileShortcutManagerWin::NonProfileShortcutAction action) { | |
| 324 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 401 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 
| 402 const base::FilePath shortcut_icon = | |
| 403 CreateOrUpdateShortcutIconForProfile(params.profile_path, | |
| 404 params.avatar_image_1x, | |
| 405 params.avatar_image_2x, | |
| 406 callback); | |
| 407 if (shortcut_icon.empty() || | |
| 408 params.create_mode == | |
| 409 ProfileShortcutManagerWin::CREATE_OR_UPDATE_ICON_ONLY) { | |
| 410 return; | |
| 411 } | |
| 325 | 412 | 
| 326 base::FilePath chrome_exe; | 413 base::FilePath chrome_exe; | 
| 327 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { | 414 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { | 
| 328 NOTREACHED(); | 415 NOTREACHED(); | 
| 329 return; | 416 return; | 
| 330 } | 417 } | 
| 331 | 418 | 
| 332 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); | 419 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); | 
| 333 // Ensure that the distribution supports creating shortcuts. If it doesn't, | 420 // Ensure that the distribution supports creating shortcuts. If it doesn't, | 
| 334 // the following code may result in NOTREACHED() being hit. | 421 // the following code may result in NOTREACHED() being hit. | 
| 335 DCHECK(distribution->CanCreateDesktopShortcuts()); | 422 DCHECK(distribution->CanCreateDesktopShortcuts()); | 
| 336 | 423 | 
| 337 if (old_profile_name != profile_name) { | 424 if (params.old_profile_name != params.profile_name) { | 
| 338 const string16 old_shortcut_filename = | 425 const string16 old_shortcut_filename = | 
| 339 profiles::internal::GetShortcutFilenameForProfile(old_profile_name, | 426 profiles::internal::GetShortcutFilenameForProfile( | 
| 340 distribution); | 427 params.old_profile_name, | 
| 428 distribution); | |
| 341 const string16 new_shortcut_filename = | 429 const string16 new_shortcut_filename = | 
| 342 profiles::internal::GetShortcutFilenameForProfile(profile_name, | 430 profiles::internal::GetShortcutFilenameForProfile(params.profile_name, | 
| 343 distribution); | 431 distribution); | 
| 344 RenameChromeDesktopShortcutForProfile(old_shortcut_filename, | 432 RenameChromeDesktopShortcutForProfile(old_shortcut_filename, | 
| 345 new_shortcut_filename); | 433 new_shortcut_filename); | 
| 346 } | 434 } | 
| 347 | 435 | 
| 348 ShellUtil::ShortcutProperties properties(ShellUtil::CURRENT_USER); | 436 ShellUtil::ShortcutProperties properties(ShellUtil::CURRENT_USER); | 
| 349 installer::Product product(distribution); | 437 installer::Product product(distribution); | 
| 350 product.AddDefaultShortcutProperties(chrome_exe, &properties); | 438 product.AddDefaultShortcutProperties(chrome_exe, &properties); | 
| 351 | 439 | 
| 352 const string16 command_line = | 440 const string16 command_line = | 
| 353 profiles::internal::CreateProfileShortcutFlags(profile_path); | 441 profiles::internal::CreateProfileShortcutFlags(params.profile_path); | 
| 354 | 442 | 
| 355 // Only set the profile-specific properties when |profile_name| is non empty. | 443 // Only set the profile-specific properties when |profile_name| is non empty. | 
| 356 // If it is empty, it means the shortcut being created should be a regular, | 444 // If it is empty, it means the shortcut being created should be a regular, | 
| 357 // non-profile Chrome shortcut. | 445 // non-profile Chrome shortcut. | 
| 358 if (!profile_name.empty()) { | 446 if (!params.profile_name.empty()) { | 
| 359 const base::FilePath shortcut_icon = | |
| 360 CreateChromeDesktopShortcutIconForProfile(profile_path, | |
| 361 avatar_image_1x, | |
| 362 avatar_image_2x); | |
| 363 if (!shortcut_icon.empty()) | |
| 364 properties.set_icon(shortcut_icon, 0); | |
| 365 properties.set_arguments(command_line); | 447 properties.set_arguments(command_line); | 
| 448 properties.set_icon(shortcut_icon, 0); | |
| 366 } else { | 449 } else { | 
| 367 // Set the arguments explicitly to the empty string to ensure that | 450 // Set the arguments explicitly to the empty string to ensure that | 
| 368 // |ShellUtil::CreateOrUpdateShortcut| updates that part of the shortcut. | 451 // |ShellUtil::CreateOrUpdateShortcut| updates that part of the shortcut. | 
| 369 properties.set_arguments(string16()); | 452 properties.set_arguments(string16()); | 
| 370 } | 453 } | 
| 371 | 454 | 
| 372 properties.set_app_id( | 455 properties.set_app_id( | 
| 373 ShellIntegration::GetChromiumModelIdForProfile(profile_path)); | 456 ShellIntegration::GetChromiumModelIdForProfile(params.profile_path)); | 
| 374 | 457 | 
| 375 ShellUtil::ShortcutOperation operation = | 458 ShellUtil::ShortcutOperation operation = | 
| 376 ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING; | 459 ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING; | 
| 377 | 460 | 
| 378 std::vector<base::FilePath> shortcuts; | 461 std::vector<base::FilePath> shortcuts; | 
| 379 ListDesktopShortcutsWithCommandLine(chrome_exe, command_line, | 462 ListDesktopShortcutsWithCommandLine(chrome_exe, command_line, | 
| 380 action == ProfileShortcutManagerWin::UPDATE_NON_PROFILE_SHORTCUTS, | 463 params.action == ProfileShortcutManagerWin::UPDATE_NON_PROFILE_SHORTCUTS, | 
| 381 &shortcuts); | 464 &shortcuts); | 
| 382 if (create_mode == ProfileShortcutManagerWin::CREATE_WHEN_NONE_FOUND && | 465 if (params.create_mode == ProfileShortcutManagerWin::CREATE_WHEN_NONE_FOUND && | 
| 383 shortcuts.empty()) { | 466 shortcuts.empty()) { | 
| 384 const string16 shortcut_name = | 467 const string16 shortcut_name = | 
| 385 profiles::internal::GetShortcutFilenameForProfile(profile_name, | 468 profiles::internal::GetShortcutFilenameForProfile(params.profile_name, | 
| 386 distribution); | 469 distribution); | 
| 387 shortcuts.push_back(base::FilePath(shortcut_name)); | 470 shortcuts.push_back(base::FilePath(shortcut_name)); | 
| 388 operation = ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL; | 471 operation = ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL; | 
| 389 } | 472 } | 
| 390 | 473 | 
| 391 for (size_t i = 0; i < shortcuts.size(); ++i) { | 474 for (size_t i = 0; i < shortcuts.size(); ++i) { | 
| 392 const base::FilePath shortcut_name = | 475 const base::FilePath shortcut_name = | 
| 393 shortcuts[i].BaseName().RemoveExtension(); | 476 shortcuts[i].BaseName().RemoveExtension(); | 
| 394 properties.set_shortcut_name(shortcut_name.value()); | 477 properties.set_shortcut_name(shortcut_name.value()); | 
| 395 ShellUtil::CreateOrUpdateShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, | 478 ShellUtil::CreateOrUpdateShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, | 
| (...skipping 12 matching lines...) Expand all Loading... | |
| 408 base::FileEnumerator::FILES); | 491 base::FileEnumerator::FILES); | 
| 409 for (base::FilePath path = enumerator.Next(); !path.empty(); | 492 for (base::FilePath path = enumerator.Next(); !path.empty(); | 
| 410 path = enumerator.Next()) { | 493 path = enumerator.Next()) { | 
| 411 if (IsChromeShortcut(path, chrome_exe, NULL)) | 494 if (IsChromeShortcut(path, chrome_exe, NULL)) | 
| 412 return true; | 495 return true; | 
| 413 } | 496 } | 
| 414 | 497 | 
| 415 return false; | 498 return false; | 
| 416 } | 499 } | 
| 417 | 500 | 
| 418 // Deletes all desktop shortcuts for the specified profile and also removes the | 501 // Deletes all desktop shortcuts for the specified profile. If | 
| 419 // corresponding icon file. If |ensure_shortcuts_remain| is true, then a regular | 502 // |ensure_shortcuts_remain| is true, then a regular non-profile shortcut will | 
| 420 // non-profile shortcut will be created if this function would otherwise delete | 503 // be created if this function would otherwise delete the last Chrome desktop | 
| 421 // the last Chrome desktop shortcut(s). Must be called on the FILE thread. | 504 // shortcut(s). Must be called on the FILE thread. | 
| 422 void DeleteDesktopShortcutsAndIconFile(const base::FilePath& profile_path, | 505 void DeleteDesktopShortcuts(const base::FilePath& profile_path, | 
| 423 bool ensure_shortcuts_remain) { | 506 bool ensure_shortcuts_remain) { | 
| 424 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 507 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 
| 425 | 508 | 
| 426 base::FilePath chrome_exe; | 509 base::FilePath chrome_exe; | 
| 427 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { | 510 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { | 
| 428 NOTREACHED(); | 511 NOTREACHED(); | 
| 429 return; | 512 return; | 
| 430 } | 513 } | 
| 431 | 514 | 
| 432 const string16 command_line = | 515 const string16 command_line = | 
| 433 profiles::internal::CreateProfileShortcutFlags(profile_path); | 516 profiles::internal::CreateProfileShortcutFlags(profile_path); | 
| 434 std::vector<base::FilePath> shortcuts; | 517 std::vector<base::FilePath> shortcuts; | 
| 435 ListDesktopShortcutsWithCommandLine(chrome_exe, command_line, false, | 518 ListDesktopShortcutsWithCommandLine(chrome_exe, command_line, false, | 
| 436 &shortcuts); | 519 &shortcuts); | 
| 437 | 520 | 
| 438 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); | 521 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); | 
| 439 for (size_t i = 0; i < shortcuts.size(); ++i) { | 522 for (size_t i = 0; i < shortcuts.size(); ++i) { | 
| 440 // Use base::Delete() instead of ShellUtil::RemoveShortcut(), as the | 523 // Use base::Delete() instead of ShellUtil::RemoveShortcut(), as the | 
| 441 // latter causes non-profile taskbar shortcuts to be unpinned. | 524 // latter causes non-profile taskbar shortcuts to be unpinned. | 
| 442 base::Delete(shortcuts[i], false); | 525 base::Delete(shortcuts[i], false); | 
| 443 // Notify the shell that the shortcut was deleted to ensure desktop refresh. | 526 // Notify the shell that the shortcut was deleted to ensure desktop refresh. | 
| 444 SHChangeNotify(SHCNE_DELETE, SHCNF_PATH, shortcuts[i].value().c_str(), | 527 SHChangeNotify(SHCNE_DELETE, SHCNF_PATH, shortcuts[i].value().c_str(), | 
| 445 NULL); | 528 NULL); | 
| 446 } | 529 } | 
| 447 | 530 | 
| 448 const base::FilePath icon_path = | |
| 449 profile_path.AppendASCII(profiles::internal::kProfileIconFileName); | |
| 450 base::Delete(icon_path, false); | |
| 451 | |
| 452 // If |ensure_shortcuts_remain| is true and deleting this profile caused the | 531 // If |ensure_shortcuts_remain| is true and deleting this profile caused the | 
| 453 // last shortcuts to be removed, re-create a regular non-profile shortcut. | 532 // last shortcuts to be removed, re-create a regular non-profile shortcut. | 
| 454 const bool had_shortcuts = !shortcuts.empty(); | 533 const bool had_shortcuts = !shortcuts.empty(); | 
| 455 if (ensure_shortcuts_remain && had_shortcuts && | 534 if (ensure_shortcuts_remain && had_shortcuts && | 
| 456 !ChromeDesktopShortcutsExist(chrome_exe)) { | 535 !ChromeDesktopShortcutsExist(chrome_exe)) { | 
| 457 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); | 536 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); | 
| 458 // Ensure that the distribution supports creating shortcuts. If it doesn't, | 537 // Ensure that the distribution supports creating shortcuts. If it doesn't, | 
| 459 // the following code may result in NOTREACHED() being hit. | 538 // the following code may result in NOTREACHED() being hit. | 
| 460 DCHECK(distribution->CanCreateDesktopShortcuts()); | 539 DCHECK(distribution->CanCreateDesktopShortcuts()); | 
| 461 installer::Product product(distribution); | 540 installer::Product product(distribution); | 
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 523 SkBitmap bitmap_copy; | 602 SkBitmap bitmap_copy; | 
| 524 image_bitmap->deepCopyTo(&bitmap_copy, image_bitmap->getConfig()); | 603 image_bitmap->deepCopyTo(&bitmap_copy, image_bitmap->getConfig()); | 
| 525 return bitmap_copy; | 604 return bitmap_copy; | 
| 526 } | 605 } | 
| 527 | 606 | 
| 528 } // namespace | 607 } // namespace | 
| 529 | 608 | 
| 530 namespace profiles { | 609 namespace profiles { | 
| 531 namespace internal { | 610 namespace internal { | 
| 532 | 611 | 
| 533 const char kProfileIconFileName[] = "Google Profile.ico"; | 612 base::FilePath GetProfileIconPath(const base::FilePath& profile_path) { | 
| 613 return profile_path.AppendASCII(kProfileIconFileName); | |
| 614 } | |
| 534 | 615 | 
| 535 string16 GetShortcutFilenameForProfile(const string16& profile_name, | 616 string16 GetShortcutFilenameForProfile(const string16& profile_name, | 
| 536 BrowserDistribution* distribution) { | 617 BrowserDistribution* distribution) { | 
| 537 string16 shortcut_name; | 618 string16 shortcut_name; | 
| 538 if (!profile_name.empty()) { | 619 if (!profile_name.empty()) { | 
| 539 shortcut_name.append(SanitizeShortcutProfileNameString(profile_name)); | 620 shortcut_name.append(SanitizeShortcutProfileNameString(profile_name)); | 
| 540 shortcut_name.append(L" - "); | 621 shortcut_name.append(L" - "); | 
| 541 shortcut_name.append(l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)); | 622 shortcut_name.append(l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)); | 
| 542 } else { | 623 } else { | 
| 543 shortcut_name.append(distribution->GetAppShortCutName()); | 624 shortcut_name.append(distribution->GetAppShortCutName()); | 
| (...skipping 21 matching lines...) Expand all Loading... | |
| 565 ProfileManager* manager) { | 646 ProfileManager* manager) { | 
| 566 return new ProfileShortcutManagerWin(manager); | 647 return new ProfileShortcutManagerWin(manager); | 
| 567 } | 648 } | 
| 568 | 649 | 
| 569 ProfileShortcutManagerWin::ProfileShortcutManagerWin(ProfileManager* manager) | 650 ProfileShortcutManagerWin::ProfileShortcutManagerWin(ProfileManager* manager) | 
| 570 : profile_manager_(manager) { | 651 : profile_manager_(manager) { | 
| 571 DCHECK_EQ( | 652 DCHECK_EQ( | 
| 572 arraysize(kProfileAvatarIconResources2x), | 653 arraysize(kProfileAvatarIconResources2x), | 
| 573 profile_manager_->GetProfileInfoCache().GetDefaultAvatarIconCount()); | 654 profile_manager_->GetProfileInfoCache().GetDefaultAvatarIconCount()); | 
| 574 | 655 | 
| 656 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED, | |
| 657 content::NotificationService::AllSources()); | |
| 658 | |
| 575 profile_manager_->GetProfileInfoCache().AddObserver(this); | 659 profile_manager_->GetProfileInfoCache().AddObserver(this); | 
| 576 } | 660 } | 
| 577 | 661 | 
| 578 ProfileShortcutManagerWin::~ProfileShortcutManagerWin() { | 662 ProfileShortcutManagerWin::~ProfileShortcutManagerWin() { | 
| 579 profile_manager_->GetProfileInfoCache().RemoveObserver(this); | 663 profile_manager_->GetProfileInfoCache().RemoveObserver(this); | 
| 580 } | 664 } | 
| 581 | 665 | 
| 666 void ProfileShortcutManagerWin::CreateOrUpdateProfileIcon( | |
| 667 const base::FilePath& profile_path, | |
| 668 const base::Closure& callback) { | |
| 669 CreateOrUpdateShortcutsForProfileAtPath(profile_path, | |
| 670 CREATE_OR_UPDATE_ICON_ONLY, | |
| 671 IGNORE_NON_PROFILE_SHORTCUTS, | |
| 672 callback); | |
| 673 } | |
| 674 | |
| 582 void ProfileShortcutManagerWin::CreateProfileShortcut( | 675 void ProfileShortcutManagerWin::CreateProfileShortcut( | 
| 583 const base::FilePath& profile_path) { | 676 const base::FilePath& profile_path) { | 
| 584 CreateOrUpdateShortcutsForProfileAtPath(profile_path, CREATE_WHEN_NONE_FOUND, | 677 CreateOrUpdateShortcutsForProfileAtPath(profile_path, CREATE_WHEN_NONE_FOUND, | 
| 585 IGNORE_NON_PROFILE_SHORTCUTS); | 678 IGNORE_NON_PROFILE_SHORTCUTS, | 
| 679 base::Closure()); | |
| 586 } | 680 } | 
| 587 | 681 | 
| 588 void ProfileShortcutManagerWin::RemoveProfileShortcuts( | 682 void ProfileShortcutManagerWin::RemoveProfileShortcuts( | 
| 589 const base::FilePath& profile_path) { | 683 const base::FilePath& profile_path) { | 
| 590 BrowserThread::PostTask( | 684 BrowserThread::PostTask( | 
| 591 BrowserThread::FILE, FROM_HERE, | 685 BrowserThread::FILE, FROM_HERE, | 
| 592 base::Bind(&DeleteDesktopShortcutsAndIconFile, profile_path, false)); | 686 base::Bind(&DeleteDesktopShortcuts, profile_path, false)); | 
| 593 } | 687 } | 
| 594 | 688 | 
| 595 void ProfileShortcutManagerWin::HasProfileShortcuts( | 689 void ProfileShortcutManagerWin::HasProfileShortcuts( | 
| 596 const base::FilePath& profile_path, | 690 const base::FilePath& profile_path, | 
| 597 const base::Callback<void(bool)>& callback) { | 691 const base::Callback<void(bool)>& callback) { | 
| 598 BrowserThread::PostTaskAndReplyWithResult( | 692 BrowserThread::PostTaskAndReplyWithResult( | 
| 599 BrowserThread::FILE, FROM_HERE, | 693 BrowserThread::FILE, FROM_HERE, | 
| 600 base::Bind(&HasAnyProfileShortcuts, profile_path), callback); | 694 base::Bind(&HasAnyProfileShortcuts, profile_path), callback); | 
| 601 } | 695 } | 
| 602 | 696 | 
| 603 void ProfileShortcutManagerWin::OnProfileAdded( | 697 void ProfileShortcutManagerWin::OnProfileAdded( | 
| 604 const base::FilePath& profile_path) { | 698 const base::FilePath& profile_path) { | 
| 699 CreateOrUpdateProfileIcon(profile_path, base::Closure()); | |
| 605 if (profile_manager_->GetProfileInfoCache().GetNumberOfProfiles() == 2) { | 700 if (profile_manager_->GetProfileInfoCache().GetNumberOfProfiles() == 2) { | 
| 606 // When the second profile is added, make existing non-profile shortcuts | 701 // When the second profile is added, make existing non-profile shortcuts | 
| 607 // point to the first profile and be badged/named appropriately. | 702 // point to the first profile and be badged/named appropriately. | 
| 608 CreateOrUpdateShortcutsForProfileAtPath(GetOtherProfilePath(profile_path), | 703 CreateOrUpdateShortcutsForProfileAtPath(GetOtherProfilePath(profile_path), | 
| 609 UPDATE_EXISTING_ONLY, | 704 UPDATE_EXISTING_ONLY, | 
| 610 UPDATE_NON_PROFILE_SHORTCUTS); | 705 UPDATE_NON_PROFILE_SHORTCUTS, | 
| 706 base::Closure()); | |
| 611 } | 707 } | 
| 612 } | 708 } | 
| 613 | 709 | 
| 614 void ProfileShortcutManagerWin::OnProfileWasRemoved( | 710 void ProfileShortcutManagerWin::OnProfileWasRemoved( | 
| 615 const base::FilePath& profile_path, | 711 const base::FilePath& profile_path, | 
| 616 const string16& profile_name) { | 712 const string16& profile_name) { | 
| 617 const ProfileInfoCache& cache = profile_manager_->GetProfileInfoCache(); | 713 const ProfileInfoCache& cache = profile_manager_->GetProfileInfoCache(); | 
| 618 // If there is only one profile remaining, remove the badging information | 714 // If there is only one profile remaining, remove the badging information | 
| 619 // from an existing shortcut. | 715 // from an existing shortcut. | 
| 620 const bool deleting_down_to_last_profile = (cache.GetNumberOfProfiles() == 1); | 716 const bool deleting_down_to_last_profile = (cache.GetNumberOfProfiles() == 1); | 
| 621 if (deleting_down_to_last_profile) { | 717 if (deleting_down_to_last_profile) { | 
| 718 // This is needed to unbadge the icon. | |
| 622 CreateOrUpdateShortcutsForProfileAtPath(cache.GetPathOfProfileAtIndex(0), | 719 CreateOrUpdateShortcutsForProfileAtPath(cache.GetPathOfProfileAtIndex(0), | 
| 623 UPDATE_EXISTING_ONLY, | 720 UPDATE_EXISTING_ONLY, | 
| 624 IGNORE_NON_PROFILE_SHORTCUTS); | 721 IGNORE_NON_PROFILE_SHORTCUTS, | 
| 722 base::Closure()); | |
| 625 } | 723 } | 
| 626 | 724 | 
| 627 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, | 725 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, | 
| 628 base::Bind(&DeleteDesktopShortcutsAndIconFile, | 726 base::Bind(&DeleteDesktopShortcuts, | 
| 629 profile_path, | 727 profile_path, | 
| 630 deleting_down_to_last_profile)); | 728 deleting_down_to_last_profile)); | 
| 631 } | 729 } | 
| 632 | 730 | 
| 633 void ProfileShortcutManagerWin::OnProfileNameChanged( | 731 void ProfileShortcutManagerWin::OnProfileNameChanged( | 
| 634 const base::FilePath& profile_path, | 732 const base::FilePath& profile_path, | 
| 635 const string16& old_profile_name) { | 733 const string16& old_profile_name) { | 
| 636 CreateOrUpdateShortcutsForProfileAtPath(profile_path, UPDATE_EXISTING_ONLY, | 734 CreateOrUpdateShortcutsForProfileAtPath(profile_path, UPDATE_EXISTING_ONLY, | 
| 637 IGNORE_NON_PROFILE_SHORTCUTS); | 735 IGNORE_NON_PROFILE_SHORTCUTS, | 
| 736 base::Closure()); | |
| 638 } | 737 } | 
| 639 | 738 | 
| 640 void ProfileShortcutManagerWin::OnProfileAvatarChanged( | 739 void ProfileShortcutManagerWin::OnProfileAvatarChanged( | 
| 641 const base::FilePath& profile_path) { | 740 const base::FilePath& profile_path) { | 
| 642 CreateOrUpdateShortcutsForProfileAtPath(profile_path, UPDATE_EXISTING_ONLY, | 741 CreateOrUpdateProfileIcon(profile_path, base::Closure()); | 
| 643 IGNORE_NON_PROFILE_SHORTCUTS); | |
| 644 } | 742 } | 
| 645 | 743 | 
| 646 base::FilePath ProfileShortcutManagerWin::GetOtherProfilePath( | 744 base::FilePath ProfileShortcutManagerWin::GetOtherProfilePath( | 
| 647 const base::FilePath& profile_path) { | 745 const base::FilePath& profile_path) { | 
| 648 const ProfileInfoCache& cache = profile_manager_->GetProfileInfoCache(); | 746 const ProfileInfoCache& cache = profile_manager_->GetProfileInfoCache(); | 
| 649 DCHECK_EQ(2U, cache.GetNumberOfProfiles()); | 747 DCHECK_EQ(2U, cache.GetNumberOfProfiles()); | 
| 650 // Get the index of the current profile, in order to find the index of the | 748 // Get the index of the current profile, in order to find the index of the | 
| 651 // other profile. | 749 // other profile. | 
| 652 size_t current_profile_index = cache.GetIndexOfProfileWithPath(profile_path); | 750 size_t current_profile_index = cache.GetIndexOfProfileWithPath(profile_path); | 
| 653 size_t other_profile_index = (current_profile_index == 0) ? 1 : 0; | 751 size_t other_profile_index = (current_profile_index == 0) ? 1 : 0; | 
| 654 return cache.GetPathOfProfileAtIndex(other_profile_index); | 752 return cache.GetPathOfProfileAtIndex(other_profile_index); | 
| 655 } | 753 } | 
| 656 | 754 | 
| 657 void ProfileShortcutManagerWin::CreateOrUpdateShortcutsForProfileAtPath( | 755 void ProfileShortcutManagerWin::CreateOrUpdateShortcutsForProfileAtPath( | 
| 658 const base::FilePath& profile_path, | 756 const base::FilePath& profile_path, | 
| 659 CreateOrUpdateMode create_mode, | 757 CreateOrUpdateMode create_mode, | 
| 660 NonProfileShortcutAction action) { | 758 NonProfileShortcutAction action, | 
| 759 const base::Closure& callback) { | |
| 760 DCHECK(!BrowserThread::IsWellKnownThread(BrowserThread::UI) || | |
| 761 BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 762 CreateOrUpdateShortcutsParams params(profile_path, create_mode, action); | |
| 763 | |
| 661 ProfileInfoCache* cache = &profile_manager_->GetProfileInfoCache(); | 764 ProfileInfoCache* cache = &profile_manager_->GetProfileInfoCache(); | 
| 662 size_t profile_index = cache->GetIndexOfProfileWithPath(profile_path); | 765 size_t profile_index = cache->GetIndexOfProfileWithPath(profile_path); | 
| 663 if (profile_index == std::string::npos) | 766 if (profile_index == std::string::npos) | 
| 664 return; | 767 return; | 
| 665 bool remove_badging = cache->GetNumberOfProfiles() == 1; | 768 bool remove_badging = cache->GetNumberOfProfiles() == 1; | 
| 666 | 769 | 
| 667 string16 old_shortcut_appended_name = | 770 params.old_profile_name = | 
| 668 cache->GetShortcutNameOfProfileAtIndex(profile_index); | 771 cache->GetShortcutNameOfProfileAtIndex(profile_index); | 
| 669 | 772 | 
| 670 // Exit early if the mode is to update existing profile shortcuts only and | 773 // Exit early if the mode is to update existing profile shortcuts only and | 
| 671 // none were ever created for this profile, per the shortcut name not being | 774 // none were ever created for this profile, per the shortcut name not being | 
| 672 // set in the profile info cache. | 775 // set in the profile info cache. | 
| 673 if (old_shortcut_appended_name.empty() && | 776 if (params.old_profile_name.empty() && | 
| 674 create_mode == UPDATE_EXISTING_ONLY && | 777 create_mode == UPDATE_EXISTING_ONLY && | 
| 675 action == IGNORE_NON_PROFILE_SHORTCUTS) { | 778 action == IGNORE_NON_PROFILE_SHORTCUTS) { | 
| 676 return; | 779 return; | 
| 677 } | 780 } | 
| 678 | 781 | 
| 679 string16 new_shortcut_appended_name; | 782 if (!remove_badging) { | 
| 680 if (!remove_badging) | 783 params.profile_name = cache->GetNameOfProfileAtIndex(profile_index); | 
| 681 new_shortcut_appended_name = cache->GetNameOfProfileAtIndex(profile_index); | |
| 682 | 784 | 
| 683 SkBitmap avatar_bitmap_copy_1x; | |
| 684 SkBitmap avatar_bitmap_copy_2x; | |
| 685 if (!remove_badging) { | |
| 686 const size_t icon_index = | 785 const size_t icon_index = | 
| 687 cache->GetAvatarIconIndexOfProfileAtIndex(profile_index); | 786 cache->GetAvatarIconIndexOfProfileAtIndex(profile_index); | 
| 688 const int resource_id_1x = | 787 const int resource_id_1x = | 
| 689 cache->GetDefaultAvatarIconResourceIDAtIndex(icon_index); | 788 cache->GetDefaultAvatarIconResourceIDAtIndex(icon_index); | 
| 690 const int resource_id_2x = kProfileAvatarIconResources2x[icon_index]; | 789 const int resource_id_2x = kProfileAvatarIconResources2x[icon_index]; | 
| 691 // Make a copy of the SkBitmaps to ensure that we can safely use the image | 790 // Make a copy of the SkBitmaps to ensure that we can safely use the image | 
| 692 // data on the FILE thread. | 791 // data on the FILE thread. | 
| 693 avatar_bitmap_copy_1x = GetImageResourceSkBitmapCopy(resource_id_1x); | 792 params.avatar_image_1x = GetImageResourceSkBitmapCopy(resource_id_1x); | 
| 694 avatar_bitmap_copy_2x = GetImageResourceSkBitmapCopy(resource_id_2x); | 793 params.avatar_image_2x = GetImageResourceSkBitmapCopy(resource_id_2x); | 
| 695 } | 794 } | 
| 696 BrowserThread::PostTask( | 795 BrowserThread::PostTask( | 
| 697 BrowserThread::FILE, FROM_HERE, | 796 BrowserThread::FILE, FROM_HERE, | 
| 698 base::Bind(&CreateOrUpdateDesktopShortcutsForProfile, profile_path, | 797 base::Bind(&CreateOrUpdateDesktopShortcutsAndIconForProfile, params, | 
| 699 old_shortcut_appended_name, new_shortcut_appended_name, | 798 callback)); | 
| 700 avatar_bitmap_copy_1x, avatar_bitmap_copy_2x, create_mode, | |
| 701 action)); | |
| 702 | 799 | 
| 703 cache->SetShortcutNameOfProfileAtIndex(profile_index, | 800 cache->SetShortcutNameOfProfileAtIndex(profile_index, | 
| 704 new_shortcut_appended_name); | 801 params.profile_name); | 
| 705 } | 802 } | 
| 803 | |
| 804 void ProfileShortcutManagerWin::Observe( | |
| 805 int type, | |
| 806 const content::NotificationSource& source, | |
| 807 const content::NotificationDetails& details) { | |
| 808 switch (type) { | |
| 809 // This notification is triggered when a profile is loaded. | |
| 810 case chrome::NOTIFICATION_PROFILE_CREATED: { | |
| 811 Profile* profile = | |
| 812 content::Source<Profile>(source).ptr()->GetOriginalProfile(); | |
| 813 if (profile->GetPrefs()->GetInteger(prefs::kProfileIconVersion) < | |
| 814 kCurrentProfileIconVersion) { | |
| 815 // Ensure the profile's icon file has been created. | |
| 816 CreateOrUpdateProfileIcon( | |
| 817 profile->GetPath(), | |
| 818 base::Bind(&OnProfileIconCreateSuccess, profile->GetPath())); | |
| 819 } | |
| 820 break; | |
| 821 } | |
| 822 default: | |
| 823 NOTREACHED(); | |
| 824 break; | |
| 825 } | |
| 826 } | |
| OLD | NEW |