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> |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 37 #include "ui/gfx/icon_util.h" | 37 #include "ui/gfx/icon_util.h" |
| 38 #include "ui/gfx/image/image.h" | 38 #include "ui/gfx/image/image.h" |
| 39 #include "ui/gfx/image/image_family.h" | 39 #include "ui/gfx/image/image_family.h" |
| 40 #include "ui/gfx/rect.h" | 40 #include "ui/gfx/rect.h" |
| 41 #include "ui/gfx/skia_util.h" | 41 #include "ui/gfx/skia_util.h" |
| 42 | 42 |
| 43 using content::BrowserThread; | 43 using content::BrowserThread; |
| 44 | 44 |
| 45 namespace { | 45 namespace { |
| 46 | 46 |
| 47 // Name of the badged icon file generated for a given profile. | |
| 48 const char kProfileIconFileName[] = "Google Profile.ico"; | |
| 49 | |
| 47 // Characters that are not allowed in Windows filenames. Taken from | 50 // Characters that are not allowed in Windows filenames. Taken from |
| 48 // http://msdn.microsoft.com/en-us/library/aa365247.aspx | 51 // http://msdn.microsoft.com/en-us/library/aa365247.aspx |
| 49 const char16 kReservedCharacters[] = L"<>:\"/\\|?*\x01\x02\x03\x04\x05\x06\x07" | 52 const char16 kReservedCharacters[] = L"<>:\"/\\|?*\x01\x02\x03\x04\x05\x06\x07" |
| 50 L"\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19" | 53 L"\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19" |
| 51 L"\x1A\x1B\x1C\x1D\x1E\x1F"; | 54 L"\x1A\x1B\x1C\x1D\x1E\x1F"; |
| 52 | 55 |
| 53 // The maximum number of characters allowed in profile shortcuts' file names. | 56 // The maximum number of characters allowed in profile shortcuts' file names. |
| 54 // Warning: migration code will be needed if this is changed later, since | 57 // Warning: migration code will be needed if this is changed later, since |
| 55 // existing shortcuts might no longer be found if the name is generated | 58 // existing shortcuts might no longer be found if the name is generated |
| 56 // differently than it was when a shortcut was originally created. | 59 // differently than it was when a shortcut was originally created. |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 132 const SkBitmap& badged_bitmap = | 135 const SkBitmap& badged_bitmap = |
| 133 offscreen_canvas->getDevice()->accessBitmap(false); | 136 offscreen_canvas->getDevice()->accessBitmap(false); |
| 134 SkBitmap badged_bitmap_copy; | 137 SkBitmap badged_bitmap_copy; |
| 135 badged_bitmap.deepCopyTo(&badged_bitmap_copy, badged_bitmap.getConfig()); | 138 badged_bitmap.deepCopyTo(&badged_bitmap_copy, badged_bitmap.getConfig()); |
| 136 return badged_bitmap_copy; | 139 return badged_bitmap_copy; |
| 137 } | 140 } |
| 138 | 141 |
| 139 // Creates a desktop shortcut icon file (.ico) on the disk for a given profile, | 142 // Creates a desktop shortcut icon file (.ico) on the disk for a given profile, |
| 140 // badging the browser distribution icon with the profile avatar. | 143 // badging the browser distribution icon with the profile avatar. |
| 141 // Returns a path to the shortcut icon file on disk, which is empty if this | 144 // Returns a path to the shortcut icon file on disk, which is empty if this |
| 142 // fails. Use index 0 when assigning the resulting file as the icon. | 145 // fails. Use index 0 when assigning the resulting file as the icon. If both |
| 143 base::FilePath CreateChromeDesktopShortcutIconForProfile( | 146 // given bitmaps are empty, an unbadged icon is created. |
| 147 // |is_create| should be true if we are creating the icon at a time when it | |
| 148 // is not possibly already in use. If it is false, we will refresh the Windows | |
| 149 // icon cache. | |
| 150 // TODO(calamity): Ideally we'd just copy the app icon verbatim from the exe's | |
| 151 // resources in the case of an unbadged icon. | |
| 152 base::FilePath CreateOrUpdateShortcutIconForProfile( | |
| 144 const base::FilePath& profile_path, | 153 const base::FilePath& profile_path, |
| 145 const SkBitmap& avatar_bitmap_1x, | 154 const SkBitmap& avatar_bitmap_1x, |
| 146 const SkBitmap& avatar_bitmap_2x) { | 155 const SkBitmap& avatar_bitmap_2x, |
| 156 bool is_icon_create) { | |
|
Alexei Svitkine (slow)
2013/05/24 14:43:51
Instead of passing this parameter, can this just c
calamity
2013/05/31 04:07:27
Done.
| |
| 147 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 157 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 148 scoped_ptr<SkBitmap> app_icon_bitmap(GetAppIconForSize(kShortcutIconSize)); | 158 scoped_ptr<SkBitmap> app_icon_bitmap(GetAppIconForSize(kShortcutIconSize)); |
| 149 if (!app_icon_bitmap) | 159 if (!app_icon_bitmap) |
| 150 return base::FilePath(); | 160 return base::FilePath(); |
| 151 | 161 |
| 152 gfx::ImageFamily badged_bitmaps; | 162 gfx::ImageFamily badged_bitmaps; |
| 153 badged_bitmaps.Add(gfx::Image::CreateFrom1xBitmap( | 163 if (!avatar_bitmap_1x.empty()) { |
| 154 BadgeIcon(*app_icon_bitmap, avatar_bitmap_1x, 1))); | |
| 155 | |
| 156 app_icon_bitmap = GetAppIconForSize(IconUtil::kLargeIconSize); | |
| 157 if (app_icon_bitmap) { | |
| 158 badged_bitmaps.Add(gfx::Image::CreateFrom1xBitmap( | 164 badged_bitmaps.Add(gfx::Image::CreateFrom1xBitmap( |
| 159 BadgeIcon(*app_icon_bitmap, avatar_bitmap_2x, 2))); | 165 BadgeIcon(*app_icon_bitmap, avatar_bitmap_1x, 1))); |
| 160 } | 166 } |
| 161 | 167 |
| 168 scoped_ptr<SkBitmap> large_app_icon_bitmap( | |
| 169 GetAppIconForSize(IconUtil::kLargeIconSize)); | |
| 170 if (large_app_icon_bitmap && !avatar_bitmap_2x.empty()) { | |
| 171 badged_bitmaps.Add(gfx::Image::CreateFrom1xBitmap( | |
| 172 BadgeIcon(*large_app_icon_bitmap, avatar_bitmap_2x, 2))); | |
| 173 } | |
| 174 | |
| 175 // If we have no badged bitmaps, we should just use the default chrome icon. | |
| 176 if (badged_bitmaps.empty()) { | |
| 177 badged_bitmaps.Add(gfx::Image::CreateFrom1xBitmap(*app_icon_bitmap)); | |
| 178 if (large_app_icon_bitmap) { | |
| 179 badged_bitmaps.Add( | |
| 180 gfx::Image::CreateFrom1xBitmap(*large_app_icon_bitmap)); | |
| 181 } | |
| 182 } | |
| 162 // Finally, write the .ico file containing this new bitmap. | 183 // Finally, write the .ico file containing this new bitmap. |
| 163 const base::FilePath icon_path = | 184 const base::FilePath icon_path = |
| 164 profile_path.AppendASCII(profiles::internal::kProfileIconFileName); | 185 profiles::internal::GetProfileIconPath(profile_path); |
| 165 if (!IconUtil::CreateIconFileFromImageFamily(badged_bitmaps, icon_path)) | 186 |
| 187 if (!IconUtil::CreateIconFileFromImageFamily(badged_bitmaps, icon_path)) { | |
| 188 NOTREACHED(); | |
| 166 return base::FilePath(); | 189 return base::FilePath(); |
| 190 } | |
| 167 | 191 |
| 192 if (is_icon_create) { | |
| 193 SHChangeNotify(SHCNE_CREATE, SHCNF_PATH, icon_path.value().c_str(), NULL); | |
| 194 } else { | |
| 195 // This invalidates the Windows icon cache and causes the icon changes to | |
| 196 // register with the taskbar and desktop. | |
| 197 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST | SHCNF_FLUSHNOWAIT, | |
| 198 NULL, NULL); | |
| 199 } | |
| 168 return icon_path; | 200 return icon_path; |
| 169 } | 201 } |
| 170 | 202 |
| 171 // Gets the user and system directories for desktop shortcuts. Parameters may | 203 // Gets the user and system directories for desktop shortcuts. Parameters may |
| 172 // be NULL if a directory type is not needed. Returns true on success. | 204 // be NULL if a directory type is not needed. Returns true on success. |
| 173 bool GetDesktopShortcutsDirectories( | 205 bool GetDesktopShortcutsDirectories( |
| 174 base::FilePath* user_shortcuts_directory, | 206 base::FilePath* user_shortcuts_directory, |
| 175 base::FilePath* system_shortcuts_directory) { | 207 base::FilePath* system_shortcuts_directory) { |
| 176 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); | 208 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); |
| 177 if (user_shortcuts_directory && | 209 if (user_shortcuts_directory && |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 292 if (file_util::PathExists(possible_new_system_shortcut)) | 324 if (file_util::PathExists(possible_new_system_shortcut)) |
| 293 file_util::Delete(old_shortcut_path, false); | 325 file_util::Delete(old_shortcut_path, false); |
| 294 else if (!RenameDesktopShortcut(old_shortcut_path, new_shortcut_path)) | 326 else if (!RenameDesktopShortcut(old_shortcut_path, new_shortcut_path)) |
| 295 DLOG(ERROR) << "Could not rename Windows profile desktop shortcut."; | 327 DLOG(ERROR) << "Could not rename Windows profile desktop shortcut."; |
| 296 } else { | 328 } else { |
| 297 // If the shortcut does not exist, it may have been renamed by the user. In | 329 // If the shortcut does not exist, it may have been renamed by the user. In |
| 298 // that case, its name should not be changed. | 330 // that case, its name should not be changed. |
| 299 // It's also possible that a system-level shortcut exists instead - this | 331 // It's also possible that a system-level shortcut exists instead - this |
| 300 // should only be the case for the original Chrome shortcut from an | 332 // should only be the case for the original Chrome shortcut from an |
| 301 // installation. If that's the case, copy that one over - it will get its | 333 // installation. If that's the case, copy that one over - it will get its |
| 302 // properties updated by |CreateOrUpdateDesktopShortcutsForProfile()|. | 334 // properties updated by |
| 335 // |CreateOrUpdateDesktopShortcutsAndIconForProfile()|. | |
| 303 const base::FilePath possible_old_system_shortcut = | 336 const base::FilePath possible_old_system_shortcut = |
| 304 system_shortcuts_directory.Append(old_shortcut_filename); | 337 system_shortcuts_directory.Append(old_shortcut_filename); |
| 305 if (file_util::PathExists(possible_old_system_shortcut)) | 338 if (file_util::PathExists(possible_old_system_shortcut)) |
| 306 file_util::CopyFile(possible_old_system_shortcut, new_shortcut_path); | 339 file_util::CopyFile(possible_old_system_shortcut, new_shortcut_path); |
| 307 } | 340 } |
| 308 } | 341 } |
| 309 | 342 |
| 343 struct CreateOrUpdateShortcutsParams { | |
| 344 CreateOrUpdateShortcutsParams() {} | |
| 345 ~CreateOrUpdateShortcutsParams() {} | |
| 346 | |
| 347 base::FilePath profile_path; | |
| 348 string16 old_profile_name; | |
| 349 string16 profile_name; | |
| 350 SkBitmap avatar_image_1x; | |
| 351 SkBitmap avatar_image_2x; | |
| 352 ProfileShortcutManagerWin::CreateOrUpdateMode create_mode; | |
| 353 ProfileShortcutManagerWin::NonProfileShortcutAction action; | |
| 354 bool is_icon_create; | |
| 355 }; | |
| 356 | |
| 310 // Updates all desktop shortcuts for the given profile to have the specified | 357 // Updates all desktop shortcuts for the given profile to have the specified |
| 311 // parameters. If |create_mode| is CREATE_WHEN_NONE_FOUND, a new shortcut is | 358 // parameters. If |create_mode| is CREATE_WHEN_NONE_FOUND, a new shortcut is |
| 312 // created if no existing ones were found. Whether non-profile shortcuts should | 359 // created if no existing ones were found. Whether non-profile shortcuts should |
| 313 // be updated is specified by |action|. Must be called on the FILE thread. | 360 // be updated is specified by |action|. Must be called on the FILE thread. |
| 314 void CreateOrUpdateDesktopShortcutsForProfile( | 361 void CreateOrUpdateDesktopShortcutsAndIconForProfile( |
| 315 const base::FilePath& profile_path, | 362 const CreateOrUpdateShortcutsParams& params) { |
| 316 const string16& old_profile_name, | |
| 317 const string16& profile_name, | |
| 318 const SkBitmap& avatar_image_1x, | |
| 319 const SkBitmap& avatar_image_2x, | |
| 320 ProfileShortcutManagerWin::CreateOrUpdateMode create_mode, | |
| 321 ProfileShortcutManagerWin::NonProfileShortcutAction action) { | |
| 322 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 363 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 323 | 364 |
| 365 base::FilePath shortcut_icon = | |
| 366 CreateOrUpdateShortcutIconForProfile(params.profile_path, | |
| 367 params.avatar_image_1x, | |
| 368 params.avatar_image_2x, | |
| 369 params.is_icon_create); | |
| 370 if (shortcut_icon.empty()) { | |
| 371 NOTREACHED(); | |
| 372 return; | |
| 373 } | |
| 374 if (params.create_mode == ProfileShortcutManagerWin::CREATE_ICON_ONLY) | |
| 375 return; | |
| 376 | |
| 324 base::FilePath chrome_exe; | 377 base::FilePath chrome_exe; |
| 325 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { | 378 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { |
| 326 NOTREACHED(); | 379 NOTREACHED(); |
| 327 return; | 380 return; |
| 328 } | 381 } |
| 329 | 382 |
| 330 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); | 383 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); |
| 331 // Ensure that the distribution supports creating shortcuts. If it doesn't, | 384 // Ensure that the distribution supports creating shortcuts. If it doesn't, |
| 332 // the following code may result in NOTREACHED() being hit. | 385 // the following code may result in NOTREACHED() being hit. |
| 333 DCHECK(distribution->CanCreateDesktopShortcuts()); | 386 DCHECK(distribution->CanCreateDesktopShortcuts()); |
| 334 | 387 |
| 335 if (old_profile_name != profile_name) { | 388 if (params.old_profile_name != params.profile_name) { |
| 336 const string16 old_shortcut_filename = | 389 const string16 old_shortcut_filename = |
| 337 profiles::internal::GetShortcutFilenameForProfile(old_profile_name, | 390 profiles::internal::GetShortcutFilenameForProfile( |
| 338 distribution); | 391 params.old_profile_name, |
| 392 distribution); | |
| 339 const string16 new_shortcut_filename = | 393 const string16 new_shortcut_filename = |
| 340 profiles::internal::GetShortcutFilenameForProfile(profile_name, | 394 profiles::internal::GetShortcutFilenameForProfile(params.profile_name, |
| 341 distribution); | 395 distribution); |
| 342 RenameChromeDesktopShortcutForProfile(old_shortcut_filename, | 396 RenameChromeDesktopShortcutForProfile(old_shortcut_filename, |
| 343 new_shortcut_filename); | 397 new_shortcut_filename); |
| 344 } | 398 } |
| 345 | 399 |
| 346 ShellUtil::ShortcutProperties properties(ShellUtil::CURRENT_USER); | 400 ShellUtil::ShortcutProperties properties(ShellUtil::CURRENT_USER); |
| 347 installer::Product product(distribution); | 401 installer::Product product(distribution); |
| 348 product.AddDefaultShortcutProperties(chrome_exe, &properties); | 402 product.AddDefaultShortcutProperties(chrome_exe, &properties); |
| 349 | 403 |
| 350 const string16 command_line = | 404 const string16 command_line = |
| 351 profiles::internal::CreateProfileShortcutFlags(profile_path); | 405 profiles::internal::CreateProfileShortcutFlags(params.profile_path); |
| 352 | 406 |
| 353 // Only set the profile-specific properties when |profile_name| is non empty. | 407 // Only set the profile-specific properties when |profile_name| is non empty. |
| 354 // If it is empty, it means the shortcut being created should be a regular, | 408 // If it is empty, it means the shortcut being created should be a regular, |
| 355 // non-profile Chrome shortcut. | 409 // non-profile Chrome shortcut. |
| 356 if (!profile_name.empty()) { | 410 if (!params.profile_name.empty()) { |
| 357 const base::FilePath shortcut_icon = | |
| 358 CreateChromeDesktopShortcutIconForProfile(profile_path, | |
| 359 avatar_image_1x, | |
| 360 avatar_image_2x); | |
| 361 if (!shortcut_icon.empty()) | 411 if (!shortcut_icon.empty()) |
| 362 properties.set_icon(shortcut_icon, 0); | 412 properties.set_icon(shortcut_icon, 0); |
| 363 properties.set_arguments(command_line); | 413 properties.set_arguments(command_line); |
| 364 } else { | 414 } else { |
| 365 // Set the arguments explicitly to the empty string to ensure that | 415 // Set the arguments explicitly to the empty string to ensure that |
| 366 // |ShellUtil::CreateOrUpdateShortcut| updates that part of the shortcut. | 416 // |ShellUtil::CreateOrUpdateShortcut| updates that part of the shortcut. |
| 367 properties.set_arguments(string16()); | 417 properties.set_arguments(string16()); |
| 368 } | 418 } |
| 369 | 419 |
| 370 ShellUtil::ShortcutOperation operation = | 420 ShellUtil::ShortcutOperation operation = |
| 371 ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING; | 421 ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING; |
| 372 | 422 |
| 373 std::vector<base::FilePath> shortcuts; | 423 std::vector<base::FilePath> shortcuts; |
| 374 ListDesktopShortcutsWithCommandLine(chrome_exe, command_line, | 424 ListDesktopShortcutsWithCommandLine(chrome_exe, command_line, |
| 375 action == ProfileShortcutManagerWin::UPDATE_NON_PROFILE_SHORTCUTS, | 425 params.action == ProfileShortcutManagerWin::UPDATE_NON_PROFILE_SHORTCUTS, |
| 376 &shortcuts); | 426 &shortcuts); |
| 377 if (create_mode == ProfileShortcutManagerWin::CREATE_WHEN_NONE_FOUND && | 427 if (params.create_mode == ProfileShortcutManagerWin::CREATE_WHEN_NONE_FOUND && |
| 378 shortcuts.empty()) { | 428 shortcuts.empty()) { |
| 379 const string16 shortcut_name = | 429 const string16 shortcut_name = |
| 380 profiles::internal::GetShortcutFilenameForProfile(profile_name, | 430 profiles::internal::GetShortcutFilenameForProfile(params.profile_name, |
| 381 distribution); | 431 distribution); |
| 382 shortcuts.push_back(base::FilePath(shortcut_name)); | 432 shortcuts.push_back(base::FilePath(shortcut_name)); |
| 383 operation = ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL; | 433 operation = ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL; |
| 384 } | 434 } |
| 385 | 435 |
| 386 for (size_t i = 0; i < shortcuts.size(); ++i) { | 436 for (size_t i = 0; i < shortcuts.size(); ++i) { |
| 387 const base::FilePath shortcut_name = | 437 const base::FilePath shortcut_name = |
| 388 shortcuts[i].BaseName().RemoveExtension(); | 438 shortcuts[i].BaseName().RemoveExtension(); |
| 389 properties.set_shortcut_name(shortcut_name.value()); | 439 properties.set_shortcut_name(shortcut_name.value()); |
| 390 ShellUtil::CreateOrUpdateShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, | 440 ShellUtil::CreateOrUpdateShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 403 file_util::FileEnumerator::FILES); | 453 file_util::FileEnumerator::FILES); |
| 404 for (base::FilePath path = enumerator.Next(); !path.empty(); | 454 for (base::FilePath path = enumerator.Next(); !path.empty(); |
| 405 path = enumerator.Next()) { | 455 path = enumerator.Next()) { |
| 406 if (IsChromeShortcut(path, chrome_exe, NULL)) | 456 if (IsChromeShortcut(path, chrome_exe, NULL)) |
| 407 return true; | 457 return true; |
| 408 } | 458 } |
| 409 | 459 |
| 410 return false; | 460 return false; |
| 411 } | 461 } |
| 412 | 462 |
| 413 // Deletes all desktop shortcuts for the specified profile and also removes the | 463 // Deletes all desktop shortcuts for the specified profile. If |
| 414 // corresponding icon file. If |ensure_shortcuts_remain| is true, then a regular | 464 // |ensure_shortcuts_remain| is true, then a regular non-profile shortcut will |
| 415 // non-profile shortcut will be created if this function would otherwise delete | 465 // be created if this function would otherwise delete the last Chrome desktop |
| 416 // the last Chrome desktop shortcut(s). Must be called on the FILE thread. | 466 // shortcut(s). Must be called on the FILE thread. |
| 417 void DeleteDesktopShortcutsAndIconFile(const base::FilePath& profile_path, | 467 void DeleteDesktopShortcuts(const base::FilePath& profile_path, |
| 418 bool ensure_shortcuts_remain) { | 468 bool ensure_shortcuts_remain) { |
| 419 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 469 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 420 | 470 |
| 421 base::FilePath chrome_exe; | 471 base::FilePath chrome_exe; |
| 422 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { | 472 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { |
| 423 NOTREACHED(); | 473 NOTREACHED(); |
| 424 return; | 474 return; |
| 425 } | 475 } |
| 426 | 476 |
| 427 const string16 command_line = | 477 const string16 command_line = |
| 428 profiles::internal::CreateProfileShortcutFlags(profile_path); | 478 profiles::internal::CreateProfileShortcutFlags(profile_path); |
| 429 std::vector<base::FilePath> shortcuts; | 479 std::vector<base::FilePath> shortcuts; |
| 430 ListDesktopShortcutsWithCommandLine(chrome_exe, command_line, false, | 480 ListDesktopShortcutsWithCommandLine(chrome_exe, command_line, false, |
| 431 &shortcuts); | 481 &shortcuts); |
| 432 | 482 |
| 433 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); | 483 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); |
| 434 for (size_t i = 0; i < shortcuts.size(); ++i) { | 484 for (size_t i = 0; i < shortcuts.size(); ++i) { |
| 435 // Use file_util::Delete() instead of ShellUtil::RemoveShortcut(), as the | 485 // Use file_util::Delete() instead of ShellUtil::RemoveShortcut(), as the |
| 436 // latter causes non-profile taskbar shortcuts to be unpinned. | 486 // latter causes non-profile taskbar shortcuts to be unpinned. |
| 437 file_util::Delete(shortcuts[i], false); | 487 file_util::Delete(shortcuts[i], false); |
| 438 // Notify the shell that the shortcut was deleted to ensure desktop refresh. | 488 // Notify the shell that the shortcut was deleted to ensure desktop refresh. |
| 439 SHChangeNotify(SHCNE_DELETE, SHCNF_PATH, shortcuts[i].value().c_str(), | 489 SHChangeNotify(SHCNE_DELETE, SHCNF_PATH, shortcuts[i].value().c_str(), |
| 440 NULL); | 490 NULL); |
| 441 } | 491 } |
| 442 | 492 |
| 443 const base::FilePath icon_path = | |
| 444 profile_path.AppendASCII(profiles::internal::kProfileIconFileName); | |
| 445 file_util::Delete(icon_path, false); | |
| 446 | |
| 447 // If |ensure_shortcuts_remain| is true and deleting this profile caused the | 493 // If |ensure_shortcuts_remain| is true and deleting this profile caused the |
| 448 // last shortcuts to be removed, re-create a regular non-profile shortcut. | 494 // last shortcuts to be removed, re-create a regular non-profile shortcut. |
| 449 const bool had_shortcuts = !shortcuts.empty(); | 495 const bool had_shortcuts = !shortcuts.empty(); |
| 450 if (ensure_shortcuts_remain && had_shortcuts && | 496 if (ensure_shortcuts_remain && had_shortcuts && |
| 451 !ChromeDesktopShortcutsExist(chrome_exe)) { | 497 !ChromeDesktopShortcutsExist(chrome_exe)) { |
| 452 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); | 498 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); |
| 453 // Ensure that the distribution supports creating shortcuts. If it doesn't, | 499 // Ensure that the distribution supports creating shortcuts. If it doesn't, |
| 454 // the following code may result in NOTREACHED() being hit. | 500 // the following code may result in NOTREACHED() being hit. |
| 455 DCHECK(distribution->CanCreateDesktopShortcuts()); | 501 DCHECK(distribution->CanCreateDesktopShortcuts()); |
| 456 installer::Product product(distribution); | 502 installer::Product product(distribution); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 518 SkBitmap bitmap_copy; | 564 SkBitmap bitmap_copy; |
| 519 image_bitmap->deepCopyTo(&bitmap_copy, image_bitmap->getConfig()); | 565 image_bitmap->deepCopyTo(&bitmap_copy, image_bitmap->getConfig()); |
| 520 return bitmap_copy; | 566 return bitmap_copy; |
| 521 } | 567 } |
| 522 | 568 |
| 523 } // namespace | 569 } // namespace |
| 524 | 570 |
| 525 namespace profiles { | 571 namespace profiles { |
| 526 namespace internal { | 572 namespace internal { |
| 527 | 573 |
| 528 const char kProfileIconFileName[] = "Google Profile.ico"; | 574 base::FilePath GetProfileIconPath(const base::FilePath& profile_path) { |
| 575 return profile_path.AppendASCII(kProfileIconFileName); | |
| 576 } | |
| 529 | 577 |
| 530 string16 GetShortcutFilenameForProfile(const string16& profile_name, | 578 string16 GetShortcutFilenameForProfile(const string16& profile_name, |
| 531 BrowserDistribution* distribution) { | 579 BrowserDistribution* distribution) { |
| 532 string16 shortcut_name; | 580 string16 shortcut_name; |
| 533 if (!profile_name.empty()) { | 581 if (!profile_name.empty()) { |
| 534 shortcut_name.append(SanitizeShortcutProfileNameString(profile_name)); | 582 shortcut_name.append(SanitizeShortcutProfileNameString(profile_name)); |
| 535 shortcut_name.append(L" - "); | 583 shortcut_name.append(L" - "); |
| 536 shortcut_name.append(l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)); | 584 shortcut_name.append(l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)); |
| 537 } else { | 585 } else { |
| 538 shortcut_name.append(distribution->GetAppShortCutName()); | 586 shortcut_name.append(distribution->GetAppShortCutName()); |
| 539 } | 587 } |
| 540 return shortcut_name + installer::kLnkExt; | 588 return shortcut_name + installer::kLnkExt; |
| 541 } | 589 } |
| 542 | 590 |
| 543 string16 CreateProfileShortcutFlags(const base::FilePath& profile_path) { | 591 string16 CreateProfileShortcutFlags(const base::FilePath& profile_path) { |
| 544 return base::StringPrintf(L"--%ls=\"%ls\"", | 592 return base::StringPrintf(L"--%ls=\"%ls\"", |
| 545 ASCIIToUTF16(switches::kProfileDirectory).c_str(), | 593 ASCIIToUTF16(switches::kProfileDirectory).c_str(), |
| 546 profile_path.BaseName().value().c_str()); | 594 profile_path.BaseName().value().c_str()); |
| 547 } | 595 } |
| 548 | 596 |
| 549 } // namespace internal | 597 } // namespace internal |
| 550 } // namespace profiles | 598 } // namespace profiles |
| 551 | 599 |
| 552 // static | 600 // static |
| 553 bool ProfileShortcutManager::IsFeatureEnabled() { | 601 bool ProfileShortcutManager::IsFeatureEnabled() { |
| 554 return BrowserDistribution::GetDistribution()->CanCreateDesktopShortcuts() && | 602 return BrowserDistribution::GetDistribution()->CanCreateDesktopShortcuts() && |
| 555 !CommandLine::ForCurrentProcess()->HasSwitch(switches::kUserDataDir) && | 603 !CommandLine::ForCurrentProcess()->HasSwitch(switches::kUserDataDir); |
| 556 !CommandLine::ForCurrentProcess()->HasSwitch(switches::kShowAppList); | |
| 557 } | 604 } |
| 558 | 605 |
| 559 // static | 606 // static |
| 560 ProfileShortcutManager* ProfileShortcutManager::Create( | 607 ProfileShortcutManager* ProfileShortcutManager::Create( |
| 561 ProfileManager* manager) { | 608 ProfileManager* manager) { |
| 562 return new ProfileShortcutManagerWin(manager); | 609 return new ProfileShortcutManagerWin(manager); |
| 563 } | 610 } |
| 564 | 611 |
| 565 ProfileShortcutManagerWin::ProfileShortcutManagerWin(ProfileManager* manager) | 612 ProfileShortcutManagerWin::ProfileShortcutManagerWin(ProfileManager* manager) |
| 566 : profile_manager_(manager) { | 613 : profile_manager_(manager) { |
| 567 DCHECK_EQ( | 614 DCHECK_EQ( |
| 568 arraysize(kProfileAvatarIconResources2x), | 615 arraysize(kProfileAvatarIconResources2x), |
| 569 profile_manager_->GetProfileInfoCache().GetDefaultAvatarIconCount()); | 616 profile_manager_->GetProfileInfoCache().GetDefaultAvatarIconCount()); |
| 570 | 617 |
| 571 profile_manager_->GetProfileInfoCache().AddObserver(this); | 618 profile_manager_->GetProfileInfoCache().AddObserver(this); |
| 572 } | 619 } |
| 573 | 620 |
| 574 ProfileShortcutManagerWin::~ProfileShortcutManagerWin() { | 621 ProfileShortcutManagerWin::~ProfileShortcutManagerWin() { |
| 575 profile_manager_->GetProfileInfoCache().RemoveObserver(this); | 622 profile_manager_->GetProfileInfoCache().RemoveObserver(this); |
| 576 } | 623 } |
| 577 | 624 |
| 625 void ProfileShortcutManagerWin::CreateProfileIcon( | |
| 626 const base::FilePath& profile_path) { | |
| 627 CreateOrUpdateShortcutsForProfileAtPath(profile_path, CREATE_ICON_ONLY, | |
| 628 IGNORE_NON_PROFILE_SHORTCUTS, true); | |
| 629 } | |
| 630 | |
| 631 void ProfileShortcutManagerWin::UpdateProfileIcon( | |
| 632 const base::FilePath& profile_path) { | |
| 633 CreateOrUpdateShortcutsForProfileAtPath(profile_path, CREATE_ICON_ONLY, | |
| 634 IGNORE_NON_PROFILE_SHORTCUTS, false); | |
| 635 } | |
| 636 | |
| 578 void ProfileShortcutManagerWin::CreateProfileShortcut( | 637 void ProfileShortcutManagerWin::CreateProfileShortcut( |
| 579 const base::FilePath& profile_path) { | 638 const base::FilePath& profile_path) { |
| 580 CreateOrUpdateShortcutsForProfileAtPath(profile_path, CREATE_WHEN_NONE_FOUND, | 639 CreateOrUpdateShortcutsForProfileAtPath(profile_path, CREATE_WHEN_NONE_FOUND, |
| 581 IGNORE_NON_PROFILE_SHORTCUTS); | 640 IGNORE_NON_PROFILE_SHORTCUTS, true); |
| 582 } | 641 } |
| 583 | 642 |
| 584 void ProfileShortcutManagerWin::RemoveProfileShortcuts( | 643 void ProfileShortcutManagerWin::RemoveProfileShortcuts( |
| 585 const base::FilePath& profile_path) { | 644 const base::FilePath& profile_path) { |
| 586 BrowserThread::PostTask( | 645 BrowserThread::PostTask( |
| 587 BrowserThread::FILE, FROM_HERE, | 646 BrowserThread::FILE, FROM_HERE, |
| 588 base::Bind(&DeleteDesktopShortcutsAndIconFile, profile_path, false)); | 647 base::Bind(&DeleteDesktopShortcuts, profile_path, false)); |
| 589 } | 648 } |
| 590 | 649 |
| 591 void ProfileShortcutManagerWin::HasProfileShortcuts( | 650 void ProfileShortcutManagerWin::HasProfileShortcuts( |
| 592 const base::FilePath& profile_path, | 651 const base::FilePath& profile_path, |
| 593 const base::Callback<void(bool)>& callback) { | 652 const base::Callback<void(bool)>& callback) { |
| 594 BrowserThread::PostTaskAndReplyWithResult( | 653 BrowserThread::PostTaskAndReplyWithResult( |
| 595 BrowserThread::FILE, FROM_HERE, | 654 BrowserThread::FILE, FROM_HERE, |
| 596 base::Bind(&HasAnyProfileShortcuts, profile_path), callback); | 655 base::Bind(&HasAnyProfileShortcuts, profile_path), callback); |
| 597 } | 656 } |
| 598 | 657 |
| 599 void ProfileShortcutManagerWin::OnProfileAdded( | 658 void ProfileShortcutManagerWin::OnProfileAdded( |
| 600 const base::FilePath& profile_path) { | 659 const base::FilePath& profile_path) { |
| 601 const size_t profile_count = | 660 const size_t profile_count = |
| 602 profile_manager_->GetProfileInfoCache().GetNumberOfProfiles(); | 661 profile_manager_->GetProfileInfoCache().GetNumberOfProfiles(); |
| 603 if (profile_count == 1) { | 662 if (profile_count == 1) { |
| 604 CreateOrUpdateShortcutsForProfileAtPath(profile_path, | 663 CreateOrUpdateShortcutsForProfileAtPath(profile_path, |
| 605 CREATE_WHEN_NONE_FOUND, | 664 CREATE_WHEN_NONE_FOUND, |
| 606 UPDATE_NON_PROFILE_SHORTCUTS); | 665 UPDATE_NON_PROFILE_SHORTCUTS, |
| 607 } else if (profile_count == 2) { | 666 false); |
| 608 CreateOrUpdateShortcutsForProfileAtPath(GetOtherProfilePath(profile_path), | 667 } else { |
| 609 UPDATE_EXISTING_ONLY, | 668 CreateProfileIcon(profile_path); |
| 610 UPDATE_NON_PROFILE_SHORTCUTS); | 669 if (profile_count == 2) { |
| 670 CreateOrUpdateShortcutsForProfileAtPath(GetOtherProfilePath(profile_path), | |
| 671 UPDATE_EXISTING_ONLY, | |
| 672 UPDATE_NON_PROFILE_SHORTCUTS, | |
| 673 true); | |
| 674 } | |
| 611 } | 675 } |
| 612 } | 676 } |
| 613 | 677 |
| 614 void ProfileShortcutManagerWin::OnProfileWillBeRemoved( | 678 void ProfileShortcutManagerWin::OnProfileWillBeRemoved( |
| 615 const base::FilePath& profile_path) { | 679 const base::FilePath& profile_path) { |
| 616 } | 680 } |
| 617 | 681 |
| 618 void ProfileShortcutManagerWin::OnProfileWasRemoved( | 682 void ProfileShortcutManagerWin::OnProfileWasRemoved( |
| 619 const base::FilePath& profile_path, | 683 const base::FilePath& profile_path, |
| 620 const string16& profile_name) { | 684 const string16& profile_name) { |
| 621 const ProfileInfoCache& cache = profile_manager_->GetProfileInfoCache(); | 685 const ProfileInfoCache& cache = profile_manager_->GetProfileInfoCache(); |
| 622 // If there is only one profile remaining, remove the badging information | 686 // If there is only one profile remaining, remove the badging information |
| 623 // from an existing shortcut. | 687 // from an existing shortcut. |
| 624 const bool deleting_down_to_last_profile = (cache.GetNumberOfProfiles() == 1); | 688 const bool deleting_down_to_last_profile = (cache.GetNumberOfProfiles() == 1); |
| 625 if (deleting_down_to_last_profile) { | 689 if (deleting_down_to_last_profile) { |
| 690 // This is needed to unbadge the icon. | |
| 626 CreateOrUpdateShortcutsForProfileAtPath(cache.GetPathOfProfileAtIndex(0), | 691 CreateOrUpdateShortcutsForProfileAtPath(cache.GetPathOfProfileAtIndex(0), |
| 627 UPDATE_EXISTING_ONLY, | 692 UPDATE_EXISTING_ONLY, |
| 628 IGNORE_NON_PROFILE_SHORTCUTS); | 693 IGNORE_NON_PROFILE_SHORTCUTS, |
| 694 false); | |
| 629 } | 695 } |
| 630 | 696 |
| 631 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, | 697 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
| 632 base::Bind(&DeleteDesktopShortcutsAndIconFile, | 698 base::Bind(&DeleteDesktopShortcuts, |
| 633 profile_path, | 699 profile_path, |
| 634 deleting_down_to_last_profile)); | 700 deleting_down_to_last_profile)); |
| 635 } | 701 } |
| 636 | 702 |
| 637 void ProfileShortcutManagerWin::OnProfileNameChanged( | 703 void ProfileShortcutManagerWin::OnProfileNameChanged( |
| 638 const base::FilePath& profile_path, | 704 const base::FilePath& profile_path, |
| 639 const string16& old_profile_name) { | 705 const string16& old_profile_name) { |
| 640 CreateOrUpdateShortcutsForProfileAtPath(profile_path, UPDATE_EXISTING_ONLY, | 706 CreateOrUpdateShortcutsForProfileAtPath(profile_path, UPDATE_EXISTING_ONLY, |
| 641 IGNORE_NON_PROFILE_SHORTCUTS); | 707 IGNORE_NON_PROFILE_SHORTCUTS, false); |
| 642 } | 708 } |
| 643 | 709 |
| 644 void ProfileShortcutManagerWin::OnProfileAvatarChanged( | 710 void ProfileShortcutManagerWin::OnProfileAvatarChanged( |
| 645 const base::FilePath& profile_path) { | 711 const base::FilePath& profile_path) { |
| 646 CreateOrUpdateShortcutsForProfileAtPath(profile_path, UPDATE_EXISTING_ONLY, | 712 UpdateProfileIcon(profile_path); |
| 647 IGNORE_NON_PROFILE_SHORTCUTS); | |
| 648 } | 713 } |
| 649 | 714 |
| 650 base::FilePath ProfileShortcutManagerWin::GetOtherProfilePath( | 715 base::FilePath ProfileShortcutManagerWin::GetOtherProfilePath( |
| 651 const base::FilePath& profile_path) { | 716 const base::FilePath& profile_path) { |
| 652 const ProfileInfoCache& cache = profile_manager_->GetProfileInfoCache(); | 717 const ProfileInfoCache& cache = profile_manager_->GetProfileInfoCache(); |
| 653 DCHECK_EQ(2U, cache.GetNumberOfProfiles()); | 718 DCHECK_EQ(2U, cache.GetNumberOfProfiles()); |
| 654 // Get the index of the current profile, in order to find the index of the | 719 // Get the index of the current profile, in order to find the index of the |
| 655 // other profile. | 720 // other profile. |
| 656 size_t current_profile_index = cache.GetIndexOfProfileWithPath(profile_path); | 721 size_t current_profile_index = cache.GetIndexOfProfileWithPath(profile_path); |
| 657 size_t other_profile_index = (current_profile_index == 0) ? 1 : 0; | 722 size_t other_profile_index = (current_profile_index == 0) ? 1 : 0; |
| 658 return cache.GetPathOfProfileAtIndex(other_profile_index); | 723 return cache.GetPathOfProfileAtIndex(other_profile_index); |
| 659 } | 724 } |
| 660 | 725 |
| 661 void ProfileShortcutManagerWin::CreateOrUpdateShortcutsForProfileAtPath( | 726 void ProfileShortcutManagerWin::CreateOrUpdateShortcutsForProfileAtPath( |
| 662 const base::FilePath& profile_path, | 727 const base::FilePath& profile_path, |
| 663 CreateOrUpdateMode create_mode, | 728 CreateOrUpdateMode create_mode, |
| 664 NonProfileShortcutAction action) { | 729 NonProfileShortcutAction action, |
| 730 bool is_icon_create) { | |
| 731 CreateOrUpdateShortcutsParams params; | |
| 732 params.profile_path = profile_path; | |
| 733 params.create_mode = create_mode; | |
| 734 params.action = action; | |
| 735 params.is_icon_create = is_icon_create; | |
| 736 | |
| 665 ProfileInfoCache* cache = &profile_manager_->GetProfileInfoCache(); | 737 ProfileInfoCache* cache = &profile_manager_->GetProfileInfoCache(); |
| 666 size_t profile_index = cache->GetIndexOfProfileWithPath(profile_path); | 738 size_t profile_index = cache->GetIndexOfProfileWithPath(profile_path); |
| 667 if (profile_index == std::string::npos) | 739 if (profile_index == std::string::npos) |
| 668 return; | 740 return; |
| 669 bool remove_badging = cache->GetNumberOfProfiles() == 1; | 741 bool remove_badging = cache->GetNumberOfProfiles() == 1; |
| 670 | 742 |
| 671 string16 old_shortcut_appended_name = | 743 params.old_profile_name = |
| 672 cache->GetShortcutNameOfProfileAtIndex(profile_index); | 744 cache->GetShortcutNameOfProfileAtIndex(profile_index); |
| 673 | 745 |
| 674 // Exit early if the mode is to update existing profile shortcuts only and | 746 // Exit early if the mode is to update existing profile shortcuts only and |
| 675 // none were ever created for this profile, per the shortcut name not being | 747 // none were ever created for this profile, per the shortcut name not being |
| 676 // set in the profile info cache. | 748 // set in the profile info cache. |
| 677 if (old_shortcut_appended_name.empty() && | 749 if (params.old_profile_name.empty() && |
| 678 create_mode == UPDATE_EXISTING_ONLY && | 750 create_mode == UPDATE_EXISTING_ONLY && |
| 679 action == IGNORE_NON_PROFILE_SHORTCUTS) { | 751 action == IGNORE_NON_PROFILE_SHORTCUTS) { |
| 680 return; | 752 return; |
| 681 } | 753 } |
| 682 | 754 |
| 683 string16 new_shortcut_appended_name; | |
| 684 if (!remove_badging) | 755 if (!remove_badging) |
| 685 new_shortcut_appended_name = cache->GetNameOfProfileAtIndex(profile_index); | 756 params.profile_name = cache->GetNameOfProfileAtIndex(profile_index); |
| 686 | 757 |
| 687 SkBitmap avatar_bitmap_copy_1x; | |
| 688 SkBitmap avatar_bitmap_copy_2x; | |
| 689 if (!remove_badging) { | 758 if (!remove_badging) { |
| 690 const size_t icon_index = | 759 const size_t icon_index = |
| 691 cache->GetAvatarIconIndexOfProfileAtIndex(profile_index); | 760 cache->GetAvatarIconIndexOfProfileAtIndex(profile_index); |
| 692 const int resource_id_1x = | 761 const int resource_id_1x = |
| 693 cache->GetDefaultAvatarIconResourceIDAtIndex(icon_index); | 762 cache->GetDefaultAvatarIconResourceIDAtIndex(icon_index); |
| 694 const int resource_id_2x = kProfileAvatarIconResources2x[icon_index]; | 763 const int resource_id_2x = kProfileAvatarIconResources2x[icon_index]; |
| 695 // Make a copy of the SkBitmaps to ensure that we can safely use the image | 764 // Make a copy of the SkBitmaps to ensure that we can safely use the image |
| 696 // data on the FILE thread. | 765 // data on the FILE thread. |
| 697 avatar_bitmap_copy_1x = GetImageResourceSkBitmapCopy(resource_id_1x); | 766 params.avatar_image_1x = GetImageResourceSkBitmapCopy(resource_id_1x); |
| 698 avatar_bitmap_copy_2x = GetImageResourceSkBitmapCopy(resource_id_2x); | 767 params.avatar_image_2x = GetImageResourceSkBitmapCopy(resource_id_2x); |
| 699 } | 768 } |
| 700 BrowserThread::PostTask( | 769 BrowserThread::PostTask( |
| 701 BrowserThread::FILE, FROM_HERE, | 770 BrowserThread::FILE, FROM_HERE, |
| 702 base::Bind(&CreateOrUpdateDesktopShortcutsForProfile, profile_path, | 771 base::Bind(&CreateOrUpdateDesktopShortcutsAndIconForProfile, params)); |
| 703 old_shortcut_appended_name, new_shortcut_appended_name, | |
| 704 avatar_bitmap_copy_1x, avatar_bitmap_copy_2x, create_mode, | |
| 705 action)); | |
| 706 | 772 |
| 707 cache->SetShortcutNameOfProfileAtIndex(profile_index, | 773 cache->SetShortcutNameOfProfileAtIndex(profile_index, |
| 708 new_shortcut_appended_name); | 774 params.profile_name); |
| 709 } | 775 } |
| OLD | NEW |