Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(22)

Side by Side Diff: chrome/browser/profiles/profile_shortcut_manager_win.cc

Issue 14137032: Create profile .ico file on profile creation (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rework Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/browser/profiles/profile_shortcut_manager_win.h ('k') | chrome/common/pref_names.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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"
24 #include "chrome/browser/profiles/profile_info_cache_observer.h" 25 #include "chrome/browser/profiles/profile_info_cache_observer.h"
25 #include "chrome/browser/profiles/profile_info_util.h" 26 #include "chrome/browser/profiles/profile_info_util.h"
26 #include "chrome/browser/profiles/profile_manager.h" 27 #include "chrome/browser/profiles/profile_manager.h"
27 #include "chrome/browser/shell_integration.h" 28 #include "chrome/browser/shell_integration.h"
29 #include "chrome/common/chrome_notification_types.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
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));
150 scoped_ptr<SkBitmap> app_icon_bitmap(GetAppIconForSize(kShortcutIconSize)); 166 scoped_ptr<SkBitmap> app_icon_bitmap(GetAppIconForSize(kShortcutIconSize));
151 if (!app_icon_bitmap) 167 if (!app_icon_bitmap)
152 return base::FilePath(); 168 return base::FilePath();
153 169
154 gfx::ImageFamily badged_bitmaps; 170 gfx::ImageFamily badged_bitmaps;
155 badged_bitmaps.Add(gfx::Image::CreateFrom1xBitmap( 171 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( 172 badged_bitmaps.Add(gfx::Image::CreateFrom1xBitmap(
161 BadgeIcon(*app_icon_bitmap, avatar_bitmap_2x, 2))); 173 BadgeIcon(*app_icon_bitmap, avatar_bitmap_1x, 1)));
162 } 174 }
163 175
176 scoped_ptr<SkBitmap> large_app_icon_bitmap(
177 GetAppIconForSize(IconUtil::kLargeIconSize));
178 if (large_app_icon_bitmap && !avatar_bitmap_2x.empty()) {
179 badged_bitmaps.Add(gfx::Image::CreateFrom1xBitmap(
180 BadgeIcon(*large_app_icon_bitmap, avatar_bitmap_2x, 2)));
181 }
182
183 // If we have no badged bitmaps, we should just use the default chrome icon.
184 if (badged_bitmaps.empty()) {
185 badged_bitmaps.Add(gfx::Image::CreateFrom1xBitmap(*app_icon_bitmap));
186 if (large_app_icon_bitmap) {
187 badged_bitmaps.Add(
188 gfx::Image::CreateFrom1xBitmap(*large_app_icon_bitmap));
189 }
190 }
164 // Finally, write the .ico file containing this new bitmap. 191 // Finally, write the .ico file containing this new bitmap.
165 const base::FilePath icon_path = 192 const base::FilePath icon_path =
166 profile_path.AppendASCII(profiles::internal::kProfileIconFileName); 193 profiles::internal::GetProfileIconPath(profile_path);
167 if (!IconUtil::CreateIconFileFromImageFamily(badged_bitmaps, icon_path)) 194 const bool had_icon = file_util::PathExists(icon_path);
195
196 if (!IconUtil::CreateIconFileFromImageFamily(badged_bitmaps, icon_path)) {
197 NOTREACHED();
168 return base::FilePath(); 198 return base::FilePath();
199 }
169 200
201 if (had_icon) {
202 // This invalidates the Windows icon cache and causes the icon changes to
203 // register with the taskbar and desktop. SHCNE_ASSOCCHANGED will cause a
204 // desktop flash and we would like to avoid that if possible.
205 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
206 } else {
207 SHChangeNotify(SHCNE_CREATE, SHCNF_PATH, icon_path.value().c_str(), NULL);
208 }
209 if (!callback.is_null())
210 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
170 return icon_path; 211 return icon_path;
171 } 212 }
172 213
214 // Updates the preferences with the current icon version on icon creation
215 // success.
216 void OnProfileIconCreateSuccess(Profile* profile) {
217 profile->GetPrefs()->SetInteger(prefs::kProfileIconVersion,
218 kCurrentProfileIconVersion);
219 }
220
221 void UpdateProfileIconIfNecessary(
222 Profile* profile,
223 ProfileShortcutManager* profile_shortcut_manager) {
gab 2013/06/27 14:18:56 Make this is a private method of ProfileShortcutMa
Alexei Svitkine (slow) 2013/06/27 15:53:08 Good point. How about making both this and OnProfi
gab 2013/06/27 17:55:44 Making both private methods SGTM.
calamity 2013/07/05 08:04:33 Since everything's in this file now, I can probabl
gab 2013/07/05 13:47:24 I think that could work, however I don't think you
Alexei Svitkine (slow) 2013/07/05 15:14:24 This function is a UI thread function (and needs t
gab 2013/07/05 15:35:42 Ah my bad, hadn't noticed that OnProfileIconCreate
Alexei Svitkine (slow) 2013/07/05 15:56:17 Ah, you're right CreateOrUpdateShortcutsForProfile
224 if (profile->GetPrefs()->GetInteger(prefs::kProfileIconVersion) <
225 kCurrentProfileIconVersion) {
226 // Ensure the profile's icon file has been created.
227 profile_shortcut_manager->CreateOrUpdateProfileIcon(
228 profile->GetPath(),
229 base::Bind(&OnProfileIconCreateSuccess, profile));
230 }
231 }
232
173 // Gets the user and system directories for desktop shortcuts. Parameters may 233 // 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. 234 // be NULL if a directory type is not needed. Returns true on success.
175 bool GetDesktopShortcutsDirectories( 235 bool GetDesktopShortcutsDirectories(
176 base::FilePath* user_shortcuts_directory, 236 base::FilePath* user_shortcuts_directory,
177 base::FilePath* system_shortcuts_directory) { 237 base::FilePath* system_shortcuts_directory) {
178 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); 238 BrowserDistribution* distribution = BrowserDistribution::GetDistribution();
179 if (user_shortcuts_directory && 239 if (user_shortcuts_directory &&
180 !ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_DESKTOP, 240 !ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
181 distribution, ShellUtil::CURRENT_USER, 241 distribution, ShellUtil::CURRENT_USER,
182 user_shortcuts_directory)) { 242 user_shortcuts_directory)) {
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
294 if (file_util::PathExists(possible_new_system_shortcut)) 354 if (file_util::PathExists(possible_new_system_shortcut))
295 file_util::Delete(old_shortcut_path, false); 355 file_util::Delete(old_shortcut_path, false);
296 else if (!RenameDesktopShortcut(old_shortcut_path, new_shortcut_path)) 356 else if (!RenameDesktopShortcut(old_shortcut_path, new_shortcut_path))
297 DLOG(ERROR) << "Could not rename Windows profile desktop shortcut."; 357 DLOG(ERROR) << "Could not rename Windows profile desktop shortcut.";
298 } else { 358 } else {
299 // If the shortcut does not exist, it may have been renamed by the user. In 359 // If the shortcut does not exist, it may have been renamed by the user. In
300 // that case, its name should not be changed. 360 // that case, its name should not be changed.
301 // It's also possible that a system-level shortcut exists instead - this 361 // 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 362 // 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 363 // installation. If that's the case, copy that one over - it will get its
304 // properties updated by |CreateOrUpdateDesktopShortcutsForProfile()|. 364 // properties updated by
365 // |CreateOrUpdateDesktopShortcutsAndIconForProfile()|.
305 const base::FilePath possible_old_system_shortcut = 366 const base::FilePath possible_old_system_shortcut =
306 system_shortcuts_directory.Append(old_shortcut_filename); 367 system_shortcuts_directory.Append(old_shortcut_filename);
307 if (file_util::PathExists(possible_old_system_shortcut)) 368 if (file_util::PathExists(possible_old_system_shortcut))
308 file_util::CopyFile(possible_old_system_shortcut, new_shortcut_path); 369 file_util::CopyFile(possible_old_system_shortcut, new_shortcut_path);
309 } 370 }
310 } 371 }
311 372
373 struct CreateOrUpdateShortcutsParams {
374 CreateOrUpdateShortcutsParams(
375 base::FilePath profile_path,
376 ProfileShortcutManagerWin::CreateOrUpdateMode create_mode,
377 ProfileShortcutManagerWin::NonProfileShortcutAction action)
378 : profile_path(profile_path), create_mode(create_mode), action(action) {}
379 ~CreateOrUpdateShortcutsParams() {}
380
381 ProfileShortcutManagerWin::CreateOrUpdateMode create_mode;
382 ProfileShortcutManagerWin::NonProfileShortcutAction action;
383
384 // The path for this profile.
385 base::FilePath profile_path;
386 // The profile name before this update. Empty on create.
387 string16 old_profile_name;
388 // The new profile name.
389 string16 profile_name;
390 // Avatar images for this profile.
391 SkBitmap avatar_image_1x;
392 SkBitmap avatar_image_2x;
393 };
394
312 // Updates all desktop shortcuts for the given profile to have the specified 395 // 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 396 // 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 397 // 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. 398 // should be updated is specified by |params.action|. Must be called on the FILE
316 void CreateOrUpdateDesktopShortcutsForProfile( 399 // thread. |callback| is called on successful icon creation.
317 const base::FilePath& profile_path, 400 void CreateOrUpdateDesktopShortcutsAndIconForProfile(
318 const string16& old_profile_name, 401 const CreateOrUpdateShortcutsParams& params,
319 const string16& profile_name, 402 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)); 403 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
325 404
405 const base::FilePath shortcut_icon =
406 CreateOrUpdateShortcutIconForProfile(params.profile_path,
407 params.avatar_image_1x,
408 params.avatar_image_2x,
409 callback);
410 if (shortcut_icon.empty()) {
411 NOTREACHED();
412 return;
413 }
414 if (params.create_mode ==
415 ProfileShortcutManagerWin::CREATE_OR_UPDATE_ICON_ONLY) {
416 return;
417 }
418
326 base::FilePath chrome_exe; 419 base::FilePath chrome_exe;
327 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { 420 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
328 NOTREACHED(); 421 NOTREACHED();
329 return; 422 return;
330 } 423 }
331 424
332 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); 425 BrowserDistribution* distribution = BrowserDistribution::GetDistribution();
333 // Ensure that the distribution supports creating shortcuts. If it doesn't, 426 // Ensure that the distribution supports creating shortcuts. If it doesn't,
334 // the following code may result in NOTREACHED() being hit. 427 // the following code may result in NOTREACHED() being hit.
335 DCHECK(distribution->CanCreateDesktopShortcuts()); 428 DCHECK(distribution->CanCreateDesktopShortcuts());
336 429
337 if (old_profile_name != profile_name) { 430 if (params.old_profile_name != params.profile_name) {
338 const string16 old_shortcut_filename = 431 const string16 old_shortcut_filename =
339 profiles::internal::GetShortcutFilenameForProfile(old_profile_name, 432 profiles::internal::GetShortcutFilenameForProfile(
340 distribution); 433 params.old_profile_name,
434 distribution);
341 const string16 new_shortcut_filename = 435 const string16 new_shortcut_filename =
342 profiles::internal::GetShortcutFilenameForProfile(profile_name, 436 profiles::internal::GetShortcutFilenameForProfile(params.profile_name,
343 distribution); 437 distribution);
344 RenameChromeDesktopShortcutForProfile(old_shortcut_filename, 438 RenameChromeDesktopShortcutForProfile(old_shortcut_filename,
345 new_shortcut_filename); 439 new_shortcut_filename);
346 } 440 }
347 441
348 ShellUtil::ShortcutProperties properties(ShellUtil::CURRENT_USER); 442 ShellUtil::ShortcutProperties properties(ShellUtil::CURRENT_USER);
349 installer::Product product(distribution); 443 installer::Product product(distribution);
350 product.AddDefaultShortcutProperties(chrome_exe, &properties); 444 product.AddDefaultShortcutProperties(chrome_exe, &properties);
351 445
352 const string16 command_line = 446 const string16 command_line =
353 profiles::internal::CreateProfileShortcutFlags(profile_path); 447 profiles::internal::CreateProfileShortcutFlags(params.profile_path);
354 448
355 // Only set the profile-specific properties when |profile_name| is non empty. 449 // 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, 450 // If it is empty, it means the shortcut being created should be a regular,
357 // non-profile Chrome shortcut. 451 // non-profile Chrome shortcut.
358 if (!profile_name.empty()) { 452 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); 453 properties.set_arguments(command_line);
454 properties.set_icon(shortcut_icon, 0);
366 } else { 455 } else {
367 // Set the arguments explicitly to the empty string to ensure that 456 // Set the arguments explicitly to the empty string to ensure that
368 // |ShellUtil::CreateOrUpdateShortcut| updates that part of the shortcut. 457 // |ShellUtil::CreateOrUpdateShortcut| updates that part of the shortcut.
369 properties.set_arguments(string16()); 458 properties.set_arguments(string16());
370 } 459 }
371 460
372 properties.set_app_id( 461 properties.set_app_id(
373 ShellIntegration::GetChromiumModelIdForProfile(profile_path)); 462 ShellIntegration::GetChromiumModelIdForProfile(params.profile_path));
374 463
375 ShellUtil::ShortcutOperation operation = 464 ShellUtil::ShortcutOperation operation =
376 ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING; 465 ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING;
377 466
378 std::vector<base::FilePath> shortcuts; 467 std::vector<base::FilePath> shortcuts;
379 ListDesktopShortcutsWithCommandLine(chrome_exe, command_line, 468 ListDesktopShortcutsWithCommandLine(chrome_exe, command_line,
380 action == ProfileShortcutManagerWin::UPDATE_NON_PROFILE_SHORTCUTS, 469 params.action == ProfileShortcutManagerWin::UPDATE_NON_PROFILE_SHORTCUTS,
381 &shortcuts); 470 &shortcuts);
382 if (create_mode == ProfileShortcutManagerWin::CREATE_WHEN_NONE_FOUND && 471 if (params.create_mode == ProfileShortcutManagerWin::CREATE_WHEN_NONE_FOUND &&
383 shortcuts.empty()) { 472 shortcuts.empty()) {
384 const string16 shortcut_name = 473 const string16 shortcut_name =
385 profiles::internal::GetShortcutFilenameForProfile(profile_name, 474 profiles::internal::GetShortcutFilenameForProfile(params.profile_name,
386 distribution); 475 distribution);
387 shortcuts.push_back(base::FilePath(shortcut_name)); 476 shortcuts.push_back(base::FilePath(shortcut_name));
388 operation = ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL; 477 operation = ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL;
389 } 478 }
390 479
391 for (size_t i = 0; i < shortcuts.size(); ++i) { 480 for (size_t i = 0; i < shortcuts.size(); ++i) {
392 const base::FilePath shortcut_name = 481 const base::FilePath shortcut_name =
393 shortcuts[i].BaseName().RemoveExtension(); 482 shortcuts[i].BaseName().RemoveExtension();
394 properties.set_shortcut_name(shortcut_name.value()); 483 properties.set_shortcut_name(shortcut_name.value());
395 ShellUtil::CreateOrUpdateShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, 484 ShellUtil::CreateOrUpdateShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
(...skipping 12 matching lines...) Expand all
408 base::FileEnumerator::FILES); 497 base::FileEnumerator::FILES);
409 for (base::FilePath path = enumerator.Next(); !path.empty(); 498 for (base::FilePath path = enumerator.Next(); !path.empty();
410 path = enumerator.Next()) { 499 path = enumerator.Next()) {
411 if (IsChromeShortcut(path, chrome_exe, NULL)) 500 if (IsChromeShortcut(path, chrome_exe, NULL))
412 return true; 501 return true;
413 } 502 }
414 503
415 return false; 504 return false;
416 } 505 }
417 506
418 // Deletes all desktop shortcuts for the specified profile and also removes the 507 // Deletes all desktop shortcuts for the specified profile. If
419 // corresponding icon file. If |ensure_shortcuts_remain| is true, then a regular 508 // |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 509 // 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. 510 // shortcut(s). Must be called on the FILE thread.
422 void DeleteDesktopShortcutsAndIconFile(const base::FilePath& profile_path, 511 void DeleteDesktopShortcuts(const base::FilePath& profile_path,
423 bool ensure_shortcuts_remain) { 512 bool ensure_shortcuts_remain) {
424 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 513 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
425 514
426 base::FilePath chrome_exe; 515 base::FilePath chrome_exe;
427 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { 516 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
428 NOTREACHED(); 517 NOTREACHED();
429 return; 518 return;
430 } 519 }
431 520
432 const string16 command_line = 521 const string16 command_line =
433 profiles::internal::CreateProfileShortcutFlags(profile_path); 522 profiles::internal::CreateProfileShortcutFlags(profile_path);
434 std::vector<base::FilePath> shortcuts; 523 std::vector<base::FilePath> shortcuts;
435 ListDesktopShortcutsWithCommandLine(chrome_exe, command_line, false, 524 ListDesktopShortcutsWithCommandLine(chrome_exe, command_line, false,
436 &shortcuts); 525 &shortcuts);
437 526
438 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); 527 BrowserDistribution* distribution = BrowserDistribution::GetDistribution();
439 for (size_t i = 0; i < shortcuts.size(); ++i) { 528 for (size_t i = 0; i < shortcuts.size(); ++i) {
440 // Use file_util::Delete() instead of ShellUtil::RemoveShortcut(), as the 529 // Use file_util::Delete() instead of ShellUtil::RemoveShortcut(), as the
441 // latter causes non-profile taskbar shortcuts to be unpinned. 530 // latter causes non-profile taskbar shortcuts to be unpinned.
442 file_util::Delete(shortcuts[i], false); 531 file_util::Delete(shortcuts[i], false);
443 // Notify the shell that the shortcut was deleted to ensure desktop refresh. 532 // Notify the shell that the shortcut was deleted to ensure desktop refresh.
444 SHChangeNotify(SHCNE_DELETE, SHCNF_PATH, shortcuts[i].value().c_str(), 533 SHChangeNotify(SHCNE_DELETE, SHCNF_PATH, shortcuts[i].value().c_str(),
445 NULL); 534 NULL);
446 } 535 }
447 536
448 const base::FilePath icon_path =
449 profile_path.AppendASCII(profiles::internal::kProfileIconFileName);
450 file_util::Delete(icon_path, false);
451
452 // If |ensure_shortcuts_remain| is true and deleting this profile caused the 537 // 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. 538 // last shortcuts to be removed, re-create a regular non-profile shortcut.
454 const bool had_shortcuts = !shortcuts.empty(); 539 const bool had_shortcuts = !shortcuts.empty();
455 if (ensure_shortcuts_remain && had_shortcuts && 540 if (ensure_shortcuts_remain && had_shortcuts &&
456 !ChromeDesktopShortcutsExist(chrome_exe)) { 541 !ChromeDesktopShortcutsExist(chrome_exe)) {
457 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); 542 BrowserDistribution* distribution = BrowserDistribution::GetDistribution();
458 // Ensure that the distribution supports creating shortcuts. If it doesn't, 543 // Ensure that the distribution supports creating shortcuts. If it doesn't,
459 // the following code may result in NOTREACHED() being hit. 544 // the following code may result in NOTREACHED() being hit.
460 DCHECK(distribution->CanCreateDesktopShortcuts()); 545 DCHECK(distribution->CanCreateDesktopShortcuts());
461 installer::Product product(distribution); 546 installer::Product product(distribution);
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
523 SkBitmap bitmap_copy; 608 SkBitmap bitmap_copy;
524 image_bitmap->deepCopyTo(&bitmap_copy, image_bitmap->getConfig()); 609 image_bitmap->deepCopyTo(&bitmap_copy, image_bitmap->getConfig());
525 return bitmap_copy; 610 return bitmap_copy;
526 } 611 }
527 612
528 } // namespace 613 } // namespace
529 614
530 namespace profiles { 615 namespace profiles {
531 namespace internal { 616 namespace internal {
532 617
533 const char kProfileIconFileName[] = "Google Profile.ico"; 618 base::FilePath GetProfileIconPath(const base::FilePath& profile_path) {
619 return profile_path.AppendASCII(kProfileIconFileName);
620 }
534 621
535 string16 GetShortcutFilenameForProfile(const string16& profile_name, 622 string16 GetShortcutFilenameForProfile(const string16& profile_name,
536 BrowserDistribution* distribution) { 623 BrowserDistribution* distribution) {
537 string16 shortcut_name; 624 string16 shortcut_name;
538 if (!profile_name.empty()) { 625 if (!profile_name.empty()) {
539 shortcut_name.append(SanitizeShortcutProfileNameString(profile_name)); 626 shortcut_name.append(SanitizeShortcutProfileNameString(profile_name));
540 shortcut_name.append(L" - "); 627 shortcut_name.append(L" - ");
541 shortcut_name.append(l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)); 628 shortcut_name.append(l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME));
542 } else { 629 } else {
543 shortcut_name.append(distribution->GetAppShortCutName()); 630 shortcut_name.append(distribution->GetAppShortCutName());
(...skipping 22 matching lines...) Expand all
566 ProfileManager* manager) { 653 ProfileManager* manager) {
567 return new ProfileShortcutManagerWin(manager); 654 return new ProfileShortcutManagerWin(manager);
568 } 655 }
569 656
570 ProfileShortcutManagerWin::ProfileShortcutManagerWin(ProfileManager* manager) 657 ProfileShortcutManagerWin::ProfileShortcutManagerWin(ProfileManager* manager)
571 : profile_manager_(manager) { 658 : profile_manager_(manager) {
572 DCHECK_EQ( 659 DCHECK_EQ(
573 arraysize(kProfileAvatarIconResources2x), 660 arraysize(kProfileAvatarIconResources2x),
574 profile_manager_->GetProfileInfoCache().GetDefaultAvatarIconCount()); 661 profile_manager_->GetProfileInfoCache().GetDefaultAvatarIconCount());
575 662
663 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED,
664 content::NotificationService::AllSources());
665
576 profile_manager_->GetProfileInfoCache().AddObserver(this); 666 profile_manager_->GetProfileInfoCache().AddObserver(this);
577 } 667 }
578 668
579 ProfileShortcutManagerWin::~ProfileShortcutManagerWin() { 669 ProfileShortcutManagerWin::~ProfileShortcutManagerWin() {
580 profile_manager_->GetProfileInfoCache().RemoveObserver(this); 670 profile_manager_->GetProfileInfoCache().RemoveObserver(this);
581 } 671 }
582 672
673 void ProfileShortcutManagerWin::CreateOrUpdateProfileIcon(
674 const base::FilePath& profile_path,
675 const base::Closure& callback) {
676 CreateOrUpdateShortcutsForProfileAtPath(profile_path,
677 CREATE_OR_UPDATE_ICON_ONLY,
678 IGNORE_NON_PROFILE_SHORTCUTS,
679 callback);
680 }
681
583 void ProfileShortcutManagerWin::CreateProfileShortcut( 682 void ProfileShortcutManagerWin::CreateProfileShortcut(
584 const base::FilePath& profile_path) { 683 const base::FilePath& profile_path) {
585 CreateOrUpdateShortcutsForProfileAtPath(profile_path, CREATE_WHEN_NONE_FOUND, 684 CreateOrUpdateShortcutsForProfileAtPath(profile_path, CREATE_WHEN_NONE_FOUND,
586 IGNORE_NON_PROFILE_SHORTCUTS); 685 IGNORE_NON_PROFILE_SHORTCUTS,
686 base::Closure());
587 } 687 }
588 688
589 void ProfileShortcutManagerWin::RemoveProfileShortcuts( 689 void ProfileShortcutManagerWin::RemoveProfileShortcuts(
590 const base::FilePath& profile_path) { 690 const base::FilePath& profile_path) {
591 BrowserThread::PostTask( 691 BrowserThread::PostTask(
592 BrowserThread::FILE, FROM_HERE, 692 BrowserThread::FILE, FROM_HERE,
593 base::Bind(&DeleteDesktopShortcutsAndIconFile, profile_path, false)); 693 base::Bind(&DeleteDesktopShortcuts, profile_path, false));
594 } 694 }
595 695
596 void ProfileShortcutManagerWin::HasProfileShortcuts( 696 void ProfileShortcutManagerWin::HasProfileShortcuts(
597 const base::FilePath& profile_path, 697 const base::FilePath& profile_path,
598 const base::Callback<void(bool)>& callback) { 698 const base::Callback<void(bool)>& callback) {
599 BrowserThread::PostTaskAndReplyWithResult( 699 BrowserThread::PostTaskAndReplyWithResult(
600 BrowserThread::FILE, FROM_HERE, 700 BrowserThread::FILE, FROM_HERE,
601 base::Bind(&HasAnyProfileShortcuts, profile_path), callback); 701 base::Bind(&HasAnyProfileShortcuts, profile_path), callback);
602 } 702 }
603 703
604 void ProfileShortcutManagerWin::OnProfileAdded( 704 void ProfileShortcutManagerWin::OnProfileAdded(
605 const base::FilePath& profile_path) { 705 const base::FilePath& profile_path) {
706 CreateOrUpdateProfileIcon(profile_path, base::Closure());
606 if (profile_manager_->GetProfileInfoCache().GetNumberOfProfiles() == 2) { 707 if (profile_manager_->GetProfileInfoCache().GetNumberOfProfiles() == 2) {
607 // When the second profile is added, make existing non-profile shortcuts 708 // When the second profile is added, make existing non-profile shortcuts
608 // point to the first profile and be badged/named appropriately. 709 // point to the first profile and be badged/named appropriately.
609 CreateOrUpdateShortcutsForProfileAtPath(GetOtherProfilePath(profile_path), 710 CreateOrUpdateShortcutsForProfileAtPath(GetOtherProfilePath(profile_path),
610 UPDATE_EXISTING_ONLY, 711 UPDATE_EXISTING_ONLY,
611 UPDATE_NON_PROFILE_SHORTCUTS); 712 UPDATE_NON_PROFILE_SHORTCUTS,
713 base::Closure());
612 } 714 }
613 } 715 }
614 716
615 void ProfileShortcutManagerWin::OnProfileWasRemoved( 717 void ProfileShortcutManagerWin::OnProfileWasRemoved(
616 const base::FilePath& profile_path, 718 const base::FilePath& profile_path,
617 const string16& profile_name) { 719 const string16& profile_name) {
618 const ProfileInfoCache& cache = profile_manager_->GetProfileInfoCache(); 720 const ProfileInfoCache& cache = profile_manager_->GetProfileInfoCache();
619 // If there is only one profile remaining, remove the badging information 721 // If there is only one profile remaining, remove the badging information
620 // from an existing shortcut. 722 // from an existing shortcut.
621 const bool deleting_down_to_last_profile = (cache.GetNumberOfProfiles() == 1); 723 const bool deleting_down_to_last_profile = (cache.GetNumberOfProfiles() == 1);
622 if (deleting_down_to_last_profile) { 724 if (deleting_down_to_last_profile) {
725 // This is needed to unbadge the icon.
623 CreateOrUpdateShortcutsForProfileAtPath(cache.GetPathOfProfileAtIndex(0), 726 CreateOrUpdateShortcutsForProfileAtPath(cache.GetPathOfProfileAtIndex(0),
624 UPDATE_EXISTING_ONLY, 727 UPDATE_EXISTING_ONLY,
625 IGNORE_NON_PROFILE_SHORTCUTS); 728 IGNORE_NON_PROFILE_SHORTCUTS,
729 base::Closure());
626 } 730 }
627 731
628 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 732 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
629 base::Bind(&DeleteDesktopShortcutsAndIconFile, 733 base::Bind(&DeleteDesktopShortcuts,
630 profile_path, 734 profile_path,
631 deleting_down_to_last_profile)); 735 deleting_down_to_last_profile));
632 } 736 }
633 737
634 void ProfileShortcutManagerWin::OnProfileNameChanged( 738 void ProfileShortcutManagerWin::OnProfileNameChanged(
635 const base::FilePath& profile_path, 739 const base::FilePath& profile_path,
636 const string16& old_profile_name) { 740 const string16& old_profile_name) {
637 CreateOrUpdateShortcutsForProfileAtPath(profile_path, UPDATE_EXISTING_ONLY, 741 CreateOrUpdateShortcutsForProfileAtPath(profile_path, UPDATE_EXISTING_ONLY,
638 IGNORE_NON_PROFILE_SHORTCUTS); 742 IGNORE_NON_PROFILE_SHORTCUTS,
743 base::Closure());
639 } 744 }
640 745
641 void ProfileShortcutManagerWin::OnProfileAvatarChanged( 746 void ProfileShortcutManagerWin::OnProfileAvatarChanged(
642 const base::FilePath& profile_path) { 747 const base::FilePath& profile_path) {
643 CreateOrUpdateShortcutsForProfileAtPath(profile_path, UPDATE_EXISTING_ONLY, 748 CreateOrUpdateProfileIcon(profile_path, base::Closure());
644 IGNORE_NON_PROFILE_SHORTCUTS);
645 } 749 }
646 750
647 base::FilePath ProfileShortcutManagerWin::GetOtherProfilePath( 751 base::FilePath ProfileShortcutManagerWin::GetOtherProfilePath(
648 const base::FilePath& profile_path) { 752 const base::FilePath& profile_path) {
649 const ProfileInfoCache& cache = profile_manager_->GetProfileInfoCache(); 753 const ProfileInfoCache& cache = profile_manager_->GetProfileInfoCache();
650 DCHECK_EQ(2U, cache.GetNumberOfProfiles()); 754 DCHECK_EQ(2U, cache.GetNumberOfProfiles());
651 // Get the index of the current profile, in order to find the index of the 755 // Get the index of the current profile, in order to find the index of the
652 // other profile. 756 // other profile.
653 size_t current_profile_index = cache.GetIndexOfProfileWithPath(profile_path); 757 size_t current_profile_index = cache.GetIndexOfProfileWithPath(profile_path);
654 size_t other_profile_index = (current_profile_index == 0) ? 1 : 0; 758 size_t other_profile_index = (current_profile_index == 0) ? 1 : 0;
655 return cache.GetPathOfProfileAtIndex(other_profile_index); 759 return cache.GetPathOfProfileAtIndex(other_profile_index);
656 } 760 }
657 761
658 void ProfileShortcutManagerWin::CreateOrUpdateShortcutsForProfileAtPath( 762 void ProfileShortcutManagerWin::CreateOrUpdateShortcutsForProfileAtPath(
659 const base::FilePath& profile_path, 763 const base::FilePath& profile_path,
660 CreateOrUpdateMode create_mode, 764 CreateOrUpdateMode create_mode,
661 NonProfileShortcutAction action) { 765 NonProfileShortcutAction action,
766 const base::Closure& callback) {
767 CreateOrUpdateShortcutsParams params(profile_path, create_mode, action);
768
662 ProfileInfoCache* cache = &profile_manager_->GetProfileInfoCache(); 769 ProfileInfoCache* cache = &profile_manager_->GetProfileInfoCache();
663 size_t profile_index = cache->GetIndexOfProfileWithPath(profile_path); 770 size_t profile_index = cache->GetIndexOfProfileWithPath(profile_path);
664 if (profile_index == std::string::npos) 771 if (profile_index == std::string::npos)
665 return; 772 return;
666 bool remove_badging = cache->GetNumberOfProfiles() == 1; 773 bool remove_badging = cache->GetNumberOfProfiles() == 1;
667 774
668 string16 old_shortcut_appended_name = 775 params.old_profile_name =
669 cache->GetShortcutNameOfProfileAtIndex(profile_index); 776 cache->GetShortcutNameOfProfileAtIndex(profile_index);
670 777
671 // Exit early if the mode is to update existing profile shortcuts only and 778 // Exit early if the mode is to update existing profile shortcuts only and
672 // none were ever created for this profile, per the shortcut name not being 779 // none were ever created for this profile, per the shortcut name not being
673 // set in the profile info cache. 780 // set in the profile info cache.
674 if (old_shortcut_appended_name.empty() && 781 if (params.old_profile_name.empty() &&
675 create_mode == UPDATE_EXISTING_ONLY && 782 create_mode == UPDATE_EXISTING_ONLY &&
676 action == IGNORE_NON_PROFILE_SHORTCUTS) { 783 action == IGNORE_NON_PROFILE_SHORTCUTS) {
677 return; 784 return;
678 } 785 }
679 786
680 string16 new_shortcut_appended_name; 787 if (!remove_badging) {
681 if (!remove_badging) 788 params.profile_name = cache->GetNameOfProfileAtIndex(profile_index);
682 new_shortcut_appended_name = cache->GetNameOfProfileAtIndex(profile_index);
683 789
684 SkBitmap avatar_bitmap_copy_1x;
685 SkBitmap avatar_bitmap_copy_2x;
686 if (!remove_badging) {
687 const size_t icon_index = 790 const size_t icon_index =
688 cache->GetAvatarIconIndexOfProfileAtIndex(profile_index); 791 cache->GetAvatarIconIndexOfProfileAtIndex(profile_index);
689 const int resource_id_1x = 792 const int resource_id_1x =
690 cache->GetDefaultAvatarIconResourceIDAtIndex(icon_index); 793 cache->GetDefaultAvatarIconResourceIDAtIndex(icon_index);
691 const int resource_id_2x = kProfileAvatarIconResources2x[icon_index]; 794 const int resource_id_2x = kProfileAvatarIconResources2x[icon_index];
692 // Make a copy of the SkBitmaps to ensure that we can safely use the image 795 // Make a copy of the SkBitmaps to ensure that we can safely use the image
693 // data on the FILE thread. 796 // data on the FILE thread.
694 avatar_bitmap_copy_1x = GetImageResourceSkBitmapCopy(resource_id_1x); 797 params.avatar_image_1x = GetImageResourceSkBitmapCopy(resource_id_1x);
695 avatar_bitmap_copy_2x = GetImageResourceSkBitmapCopy(resource_id_2x); 798 params.avatar_image_2x = GetImageResourceSkBitmapCopy(resource_id_2x);
696 } 799 }
697 BrowserThread::PostTask( 800 BrowserThread::PostTask(
698 BrowserThread::FILE, FROM_HERE, 801 BrowserThread::FILE, FROM_HERE,
699 base::Bind(&CreateOrUpdateDesktopShortcutsForProfile, profile_path, 802 base::Bind(&CreateOrUpdateDesktopShortcutsAndIconForProfile, params,
700 old_shortcut_appended_name, new_shortcut_appended_name, 803 callback));
701 avatar_bitmap_copy_1x, avatar_bitmap_copy_2x, create_mode,
702 action));
703 804
704 cache->SetShortcutNameOfProfileAtIndex(profile_index, 805 cache->SetShortcutNameOfProfileAtIndex(profile_index,
705 new_shortcut_appended_name); 806 params.profile_name);
706 } 807 }
808
809 void ProfileShortcutManagerWin::Observe(
810 int type,
811 const content::NotificationSource& source,
812 const content::NotificationDetails& details) {
813 switch (type) {
814 case chrome::NOTIFICATION_PROFILE_CREATED: {
815 Profile* profile =
816 content::Source<Profile>(source).ptr()->GetOriginalProfile();
817 UpdateProfileIconIfNecessary(profile, this);
818 break;
819 }
820 default:
821 NOTREACHED();
822 break;
823 }
824 }
OLDNEW
« no previous file with comments | « chrome/browser/profiles/profile_shortcut_manager_win.h ('k') | chrome/common/pref_names.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698