Revert 168224 - Update V8 to version 3.15.4.
[chromium-blink-merge.git] / chrome / browser / profiles / profile_shortcut_manager_win.cc
blob9a7c304a070a24771d1272ba2b08f433568a5e46
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
3 // found in the LICENSE file.
5 #include "chrome/browser/profiles/profile_shortcut_manager.h"
7 #include <map>
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/file_util.h"
12 #include "base/path_service.h"
13 #include "base/string16.h"
14 #include "base/stringprintf.h"
15 #include "base/utf_string_conversions.h"
16 #include "chrome/browser/app_icon_win.h"
17 #include "chrome/browser/browser_process.h"
18 #include "chrome/browser/prefs/pref_service.h"
19 #include "chrome/browser/profiles/profile_info_cache_observer.h"
20 #include "chrome/browser/profiles/profile_info_util.h"
21 #include "chrome/browser/profiles/profile_manager.h"
22 #include "chrome/common/chrome_constants.h"
23 #include "chrome/common/chrome_switches.h"
24 #include "chrome/common/pref_names.h"
25 #include "chrome/installer/util/auto_launch_util.h"
26 #include "chrome/installer/util/browser_distribution.h"
27 #include "chrome/installer/util/product.h"
28 #include "chrome/installer/util/shell_util.h"
29 #include "content/public/browser/browser_thread.h"
30 #include "grit/generated_resources.h"
31 #include "skia/ext/image_operations.h"
32 #include "skia/ext/platform_canvas.h"
33 #include "ui/base/l10n/l10n_util.h"
34 #include "ui/base/resource/resource_bundle.h"
35 #include "ui/gfx/icon_util.h"
36 #include "ui/gfx/image/image.h"
38 using content::BrowserThread;
40 namespace {
42 const char kProfileIconFileName[] = "Google Profile.ico";
43 const int kProfileAvatarShortcutBadgeWidth = 28;
44 const int kProfileAvatarShortcutBadgeHeight = 28;
45 const int kShortcutIconSize = 48;
47 // Creates a desktop shortcut icon file (.ico) on the disk for a given profile,
48 // badging the browser distribution icon with the profile avatar.
49 // Returns a path to the shortcut icon file on disk, which is empty if this
50 // fails. Use index 0 when assigning the resulting file as the icon.
51 FilePath CreateChromeDesktopShortcutIconForProfile(
52 const FilePath& profile_path,
53 const SkBitmap& avatar_bitmap) {
54 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
55 HICON app_icon_handle = GetAppIconForSize(kShortcutIconSize);
56 scoped_ptr<SkBitmap> app_icon_bitmap(
57 IconUtil::CreateSkBitmapFromHICON(app_icon_handle));
58 DestroyIcon(app_icon_handle);
59 if (!app_icon_bitmap.get())
60 return FilePath();
62 // TODO(rlp): Share this chunk of code with
63 // avatar_menu_button::DrawTaskBarDecoration.
64 const SkBitmap* source_bitmap = NULL;
65 SkBitmap squarer_bitmap;
66 if ((avatar_bitmap.width() == profiles::kAvatarIconWidth) &&
67 (avatar_bitmap.height() == profiles::kAvatarIconHeight)) {
68 // Shave a couple of columns so the bitmap is more square. So when
69 // resized to a square aspect ratio it looks pretty.
70 int x = 2;
71 avatar_bitmap.extractSubset(&squarer_bitmap, SkIRect::MakeXYWH(x, 0,
72 profiles::kAvatarIconWidth - x * 2, profiles::kAvatarIconHeight));
73 source_bitmap = &squarer_bitmap;
74 } else {
75 source_bitmap = &avatar_bitmap;
77 SkBitmap sk_icon = skia::ImageOperations::Resize(
78 *source_bitmap,
79 skia::ImageOperations::RESIZE_LANCZOS3,
80 kProfileAvatarShortcutBadgeWidth,
81 kProfileAvatarShortcutBadgeHeight);
83 // Overlay the avatar on the icon, anchoring it to the bottom-right of the
84 // icon.
85 scoped_ptr<SkCanvas> offscreen_canvas(
86 skia::CreateBitmapCanvas(app_icon_bitmap->width(),
87 app_icon_bitmap->height(),
88 false));
89 DCHECK(offscreen_canvas.get());
90 offscreen_canvas->drawBitmap(*app_icon_bitmap, 0, 0);
91 offscreen_canvas->drawBitmap(
92 sk_icon,
93 app_icon_bitmap->width() - kProfileAvatarShortcutBadgeWidth,
94 app_icon_bitmap->height() - kProfileAvatarShortcutBadgeHeight);
95 const SkBitmap& final_bitmap =
96 offscreen_canvas->getDevice()->accessBitmap(false);
98 // Finally, write the .ico file containing this new bitmap.
99 FilePath icon_path = profile_path.AppendASCII(kProfileIconFileName);
100 if (!IconUtil::CreateIconFileFromSkBitmap(final_bitmap, icon_path))
101 return FilePath();
103 return icon_path;
106 string16 CreateProfileShortcutFlags(const FilePath& profile_path) {
107 return base::StringPrintf(L"--%ls=\"%ls\"",
108 ASCIIToUTF16(switches::kProfileDirectory).c_str(),
109 profile_path.BaseName().value().c_str());
112 // Renames an existing Chrome desktop profile shortcut. Must be called on the
113 // FILE thread.
114 void RenameChromeDesktopShortcutForProfile(
115 const string16& old_shortcut_file,
116 const string16& new_shortcut_file) {
117 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
118 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
119 FilePath shortcut_path;
120 if (ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist,
121 ShellUtil::CURRENT_USER, &shortcut_path)) {
122 FilePath old_shortcut_path = shortcut_path.Append(old_shortcut_file);
123 FilePath new_shortcut_path = shortcut_path.Append(new_shortcut_file);
124 if (!file_util::Move(old_shortcut_path, new_shortcut_path))
125 LOG(ERROR) << "Could not rename Windows profile desktop shortcut.";
129 // Create or update a profile desktop shortcut. Must be called on the FILE
130 // thread.
131 void CreateOrUpdateProfileDesktopShortcut(
132 const FilePath& profile_path,
133 const string16& profile_name,
134 const SkBitmap& avatar_image,
135 bool create) {
136 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
137 FilePath shortcut_icon =
138 CreateChromeDesktopShortcutIconForProfile(profile_path, avatar_image);
140 FilePath chrome_exe;
141 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
142 NOTREACHED();
143 return;
145 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
146 installer::Product product(dist);
148 ShellUtil::ShortcutProperties properties(ShellUtil::CURRENT_USER);
149 product.AddDefaultShortcutProperties(chrome_exe, &properties);
150 properties.set_arguments(CreateProfileShortcutFlags(profile_path));
151 if (!shortcut_icon.empty())
152 properties.set_icon(shortcut_icon, 0);
153 properties.set_shortcut_name(
154 ProfileShortcutManager::GetShortcutNameForProfile(profile_name));
155 ShellUtil::ShortcutOperation operation =
156 create ? ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS :
157 ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING;
158 ShellUtil::CreateOrUpdateShortcut(
159 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist, properties, operation);
162 // Deletes the specified desktop shortcut and corresponding icon file. Must be
163 // called on the FILE thread.
164 void DeleteDesktopShortcutAndIconFile(const string16& shortcut_name,
165 const FilePath& icon_path) {
166 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
168 FilePath chrome_exe;
169 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
170 NOTREACHED();
171 return;
174 ShellUtil::RemoveShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
175 BrowserDistribution::GetDistribution(),
176 chrome_exe.value(), ShellUtil::CURRENT_USER,
177 &shortcut_name);
178 file_util::Delete(icon_path, false);
181 } // namespace
183 class ProfileShortcutManagerWin : public ProfileShortcutManager,
184 public ProfileInfoCacheObserver {
185 public:
186 explicit ProfileShortcutManagerWin(ProfileManager* manager);
187 virtual ~ProfileShortcutManagerWin();
189 virtual void CreateProfileShortcut(const FilePath& profile_path) OVERRIDE;
191 // ProfileInfoCacheObserver:
192 virtual void OnProfileAdded(const FilePath& profile_path) OVERRIDE;
193 virtual void OnProfileWillBeRemoved(const FilePath& profile_path) OVERRIDE;
194 virtual void OnProfileWasRemoved(const FilePath& profile_path,
195 const string16& profile_name) OVERRIDE;
196 virtual void OnProfileNameChanged(const FilePath& profile_path,
197 const string16& old_profile_name) OVERRIDE;
198 virtual void OnProfileAvatarChanged(const FilePath& profile_path) OVERRIDE;
200 private:
201 void StartProfileShortcutNameChange(const FilePath& profile_path,
202 const string16& old_profile_name);
203 // Gives the profile path of an alternate profile than |profile_path|.
204 // Must only be called when the number profiles is 2.
205 FilePath GetOtherProfilePath(const FilePath& profile_path);
206 void UpdateShortcutForProfileAtPath(const FilePath& profile_path,
207 bool create_always);
209 ProfileManager* profile_manager_;
211 DISALLOW_COPY_AND_ASSIGN(ProfileShortcutManagerWin);
214 // static
215 bool ProfileShortcutManager::IsFeatureEnabled() {
216 return false;
219 // static
220 ProfileShortcutManager* ProfileShortcutManager::Create(
221 ProfileManager* manager) {
222 return new ProfileShortcutManagerWin(manager);
225 // static
226 string16 ProfileShortcutManager::GetShortcutNameForProfile(
227 const string16& profile_name) {
228 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
229 string16 shortcut_name(dist->GetAppShortCutName());
230 shortcut_name.append(L" (");
231 shortcut_name.append(profile_name);
232 shortcut_name.append(L")");
233 return shortcut_name;
236 ProfileShortcutManagerWin::ProfileShortcutManagerWin(ProfileManager* manager)
237 : profile_manager_(manager) {
238 profile_manager_->GetProfileInfoCache().AddObserver(this);
241 ProfileShortcutManagerWin::~ProfileShortcutManagerWin() {
242 profile_manager_->GetProfileInfoCache().RemoveObserver(this);
245 void ProfileShortcutManagerWin::CreateProfileShortcut(
246 const FilePath& profile_path) {
247 UpdateShortcutForProfileAtPath(profile_path, true);
250 void ProfileShortcutManagerWin::OnProfileAdded(const FilePath& profile_path) {
251 const size_t profile_count =
252 profile_manager_->GetProfileInfoCache().GetNumberOfProfiles();
253 if (profile_count == 1) {
254 UpdateShortcutForProfileAtPath(profile_path, true);
255 } else if (profile_count == 2) {
256 UpdateShortcutForProfileAtPath(GetOtherProfilePath(profile_path), false);
260 void ProfileShortcutManagerWin::OnProfileWillBeRemoved(
261 const FilePath& profile_path) {
264 void ProfileShortcutManagerWin::OnProfileWasRemoved(
265 const FilePath& profile_path,
266 const string16& profile_name) {
267 const ProfileInfoCache& cache = profile_manager_->GetProfileInfoCache();
268 // If there is only one profile remaining, remove the badging information
269 // from an existing shortcut.
270 if (cache.GetNumberOfProfiles() == 1)
271 UpdateShortcutForProfileAtPath(cache.GetPathOfProfileAtIndex(0), false);
273 string16 profile_name_updated;
274 if (cache.GetNumberOfProfiles() != 0)
275 profile_name_updated = profile_name;
277 string16 shortcut_name = GetShortcutNameForProfile(profile_name_updated);
278 FilePath icon_path = profile_path.AppendASCII(kProfileIconFileName);
279 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
280 base::Bind(&DeleteDesktopShortcutAndIconFile,
281 shortcut_name, icon_path));
284 void ProfileShortcutManagerWin::OnProfileNameChanged(
285 const FilePath& profile_path,
286 const string16& old_profile_name) {
287 UpdateShortcutForProfileAtPath(profile_path, false);
290 void ProfileShortcutManagerWin::OnProfileAvatarChanged(
291 const FilePath& profile_path) {
292 UpdateShortcutForProfileAtPath(profile_path, false);
295 void ProfileShortcutManagerWin::StartProfileShortcutNameChange(
296 const FilePath& profile_path,
297 const string16& old_profile_name) {
298 const ProfileInfoCache& cache = profile_manager_->GetProfileInfoCache();
299 size_t profile_index = cache.GetIndexOfProfileWithPath(profile_path);
300 if (profile_index == std::string::npos)
301 return;
302 // If the shortcut will have an appended name, get the profile name.
303 string16 new_profile_name;
304 if (cache.GetNumberOfProfiles() != 1)
305 new_profile_name = cache.GetNameOfProfileAtIndex(profile_index);
307 string16 old_shortcut_file(GetShortcutNameForProfile(old_profile_name));
308 string16 new_shortcut_file(GetShortcutNameForProfile(new_profile_name));
309 BrowserThread::PostTask(
310 BrowserThread::FILE, FROM_HERE,
311 base::Bind(&RenameChromeDesktopShortcutForProfile,
312 old_shortcut_file,
313 new_shortcut_file));
316 FilePath ProfileShortcutManagerWin::GetOtherProfilePath(
317 const FilePath& profile_path) {
318 const ProfileInfoCache& cache = profile_manager_->GetProfileInfoCache();
319 DCHECK_EQ(2U, cache.GetNumberOfProfiles());
320 // Get the index of the current profile, in order to find the index of the
321 // other profile.
322 size_t current_profile_index = cache.GetIndexOfProfileWithPath(profile_path);
323 size_t other_profile_index = (current_profile_index == 0) ? 1 : 0;
324 return profile_manager_->GetProfileInfoCache().
325 GetPathOfProfileAtIndex(other_profile_index);
328 void ProfileShortcutManagerWin::UpdateShortcutForProfileAtPath(
329 const FilePath& profile_path,
330 bool create_always) {
331 ProfileInfoCache* cache = &profile_manager_->GetProfileInfoCache();
332 size_t profile_index = cache->GetIndexOfProfileWithPath(profile_path);
333 if (profile_index == std::string::npos)
334 return;
335 bool remove_badging = cache->GetNumberOfProfiles() == 1;
337 string16 old_shortcut_appended_name =
338 cache->GetShortcutNameOfProfileAtIndex(profile_index);
340 string16 new_shortcut_appended_name;
341 if (!remove_badging)
342 new_shortcut_appended_name = cache->GetNameOfProfileAtIndex(profile_index);
344 if (!create_always &&
345 new_shortcut_appended_name != old_shortcut_appended_name) {
346 StartProfileShortcutNameChange(profile_path, old_shortcut_appended_name);
349 SkBitmap profile_avatar_bitmap_copy;
350 if (!remove_badging) {
351 size_t profile_icon_index =
352 cache->GetAvatarIconIndexOfProfileAtIndex(profile_index);
353 gfx::Image profile_avatar_image = ResourceBundle::GetSharedInstance().
354 GetNativeImageNamed(
355 cache->GetDefaultAvatarIconResourceIDAtIndex(profile_icon_index));
357 DCHECK(!profile_avatar_image.IsEmpty());
358 const SkBitmap* profile_avatar_bitmap = profile_avatar_image.ToSkBitmap();
359 // Make a copy of the SkBitmap to ensure that we can safely use the image
360 // data on the FILE thread.
361 profile_avatar_bitmap->deepCopyTo(&profile_avatar_bitmap_copy,
362 profile_avatar_bitmap->getConfig());
364 BrowserThread::PostTask(
365 BrowserThread::FILE, FROM_HERE,
366 base::Bind(&CreateOrUpdateProfileDesktopShortcut,
367 profile_path, new_shortcut_appended_name,
368 profile_avatar_bitmap_copy, create_always));
370 cache->SetShortcutNameOfProfileAtIndex(profile_index,
371 new_shortcut_appended_name);