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.h" | 5 #include "chrome/browser/profiles/profile_shortcut_manager.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
11 #include "base/file_util.h" | 11 #include "base/file_util.h" |
12 #include "base/path_service.h" | 12 #include "base/path_service.h" |
13 #include "base/stringprintf.h" | 13 #include "base/stringprintf.h" |
14 #include "base/utf_string_conversions.h" | 14 #include "base/utf_string_conversions.h" |
15 #include "chrome/browser/app_icon_win.h" | 15 #include "chrome/browser/app_icon_win.h" |
16 #include "chrome/browser/browser_process.h" | 16 #include "chrome/browser/browser_process.h" |
17 #include "chrome/browser/prefs/pref_service.h" | 17 #include "chrome/browser/prefs/pref_service.h" |
18 #include "chrome/browser/profiles/profile_info_cache.h" | 18 #include "chrome/browser/profiles/profile_info_cache_observer.h" |
19 #include "chrome/browser/profiles/profile_info_util.h" | 19 #include "chrome/browser/profiles/profile_info_util.h" |
20 #include "chrome/browser/profiles/profile_manager.h" | 20 #include "chrome/browser/profiles/profile_manager.h" |
21 #include "chrome/common/chrome_constants.h" | 21 #include "chrome/common/chrome_constants.h" |
22 #include "chrome/common/chrome_switches.h" | 22 #include "chrome/common/chrome_switches.h" |
23 #include "chrome/common/pref_names.h" | 23 #include "chrome/common/pref_names.h" |
24 #include "chrome/installer/util/auto_launch_util.h" | 24 #include "chrome/installer/util/auto_launch_util.h" |
25 #include "chrome/installer/util/browser_distribution.h" | 25 #include "chrome/installer/util/browser_distribution.h" |
26 #include "chrome/installer/util/shell_util.h" | 26 #include "chrome/installer/util/shell_util.h" |
27 #include "content/public/browser/browser_thread.h" | 27 #include "content/public/browser/browser_thread.h" |
28 #include "grit/generated_resources.h" | 28 #include "grit/generated_resources.h" |
(...skipping 12 matching lines...) Expand all Loading... | |
41 const int kProfileAvatarShortcutBadgeHeight = 28; | 41 const int kProfileAvatarShortcutBadgeHeight = 28; |
42 const int kShortcutIconSize = 48; | 42 const int kShortcutIconSize = 48; |
43 | 43 |
44 // Creates a desktop shortcut icon file (.ico) on the disk for a given profile, | 44 // Creates a desktop shortcut icon file (.ico) on the disk for a given profile, |
45 // badging the browser distribution icon with the profile avatar. | 45 // badging the browser distribution icon with the profile avatar. |
46 // |profile_base_dir| is the base directory (and key) of the profile. Returns | 46 // |profile_base_dir| is the base directory (and key) of the profile. Returns |
47 // a path to the shortcut icon file on disk, which is empty if this fails. | 47 // a path to the shortcut icon file on disk, which is empty if this fails. |
48 // Use index 0 when assigning the resulting file as the icon. | 48 // Use index 0 when assigning the resulting file as the icon. |
49 FilePath CreateChromeDesktopShortcutIconForProfile( | 49 FilePath CreateChromeDesktopShortcutIconForProfile( |
50 const FilePath& profile_path, | 50 const FilePath& profile_path, |
51 const gfx::Image& avatar_image) { | 51 const SkBitmap& avatar_bitmap) { |
52 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 52 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
53 const SkBitmap* avatar_bitmap = avatar_image.ToSkBitmap(); | |
54 HICON app_icon_handle = GetAppIconForSize(kShortcutIconSize); | 53 HICON app_icon_handle = GetAppIconForSize(kShortcutIconSize); |
55 scoped_ptr<SkBitmap> app_icon_bitmap( | 54 scoped_ptr<SkBitmap> app_icon_bitmap( |
56 IconUtil::CreateSkBitmapFromHICON(app_icon_handle)); | 55 IconUtil::CreateSkBitmapFromHICON(app_icon_handle)); |
57 DestroyIcon(app_icon_handle); | 56 DestroyIcon(app_icon_handle); |
58 if (!app_icon_bitmap.get()) | 57 if (!app_icon_bitmap.get()) |
59 return FilePath(); | 58 return FilePath(); |
60 | 59 |
61 // TODO(hallielaine): Share this chunk of code with | 60 // TODO(hallielaine): Share this chunk of code with |
62 // avatar_menu_button::DrawTaskBarDecoration. | 61 // avatar_menu_button::DrawTaskBarDecoration. |
63 const SkBitmap* source_bitmap = NULL; | 62 const SkBitmap* source_bitmap = NULL; |
64 SkBitmap squarer_bitmap; | 63 SkBitmap squarer_bitmap; |
65 if ((avatar_bitmap->width() == profiles::kAvatarIconWidth) && | 64 if ((avatar_bitmap.width() == profiles::kAvatarIconWidth) && |
66 (avatar_bitmap->height() == profiles::kAvatarIconHeight)) { | 65 (avatar_bitmap.height() == profiles::kAvatarIconHeight)) { |
67 // Shave a couple of columns so the bitmap is more square. So when | 66 // Shave a couple of columns so the bitmap is more square. So when |
68 // resized to a square aspect ratio it looks pretty. | 67 // resized to a square aspect ratio it looks pretty. |
69 int x = 2; | 68 int x = 2; |
70 avatar_bitmap->extractSubset(&squarer_bitmap, SkIRect::MakeXYWH(x, 0, | 69 avatar_bitmap.extractSubset(&squarer_bitmap, SkIRect::MakeXYWH(x, 0, |
71 profiles::kAvatarIconWidth - x * 2, profiles::kAvatarIconHeight)); | 70 profiles::kAvatarIconWidth - x * 2, profiles::kAvatarIconHeight)); |
72 source_bitmap = &squarer_bitmap; | 71 source_bitmap = &squarer_bitmap; |
73 } else { | 72 } else { |
74 source_bitmap = avatar_bitmap; | 73 source_bitmap = &avatar_bitmap; |
75 } | 74 } |
76 SkBitmap sk_icon = skia::ImageOperations::Resize( | 75 SkBitmap sk_icon = skia::ImageOperations::Resize( |
77 *source_bitmap, | 76 *source_bitmap, |
78 skia::ImageOperations::RESIZE_LANCZOS3, | 77 skia::ImageOperations::RESIZE_LANCZOS3, |
79 kProfileAvatarShortcutBadgeWidth, | 78 kProfileAvatarShortcutBadgeWidth, |
80 kProfileAvatarShortcutBadgeHeight); | 79 kProfileAvatarShortcutBadgeHeight); |
81 | 80 |
82 // Overlay the avatar on the icon, anchoring it to the bottom-right of the | 81 // Overlay the avatar on the icon, anchoring it to the bottom-right of the |
83 // icon. | 82 // icon. |
84 scoped_ptr<SkCanvas> offscreen_canvas( | 83 scoped_ptr<SkCanvas> offscreen_canvas( |
(...skipping 16 matching lines...) Expand all Loading... | |
101 | 100 |
102 return icon_path; | 101 return icon_path; |
103 } | 102 } |
104 | 103 |
105 string16 CreateProfileShortcutFlags(const FilePath& profile_path) { | 104 string16 CreateProfileShortcutFlags(const FilePath& profile_path) { |
106 return base::StringPrintf(L"--%ls=\"%ls\"", | 105 return base::StringPrintf(L"--%ls=\"%ls\"", |
107 ASCIIToUTF16(switches::kProfileDirectory).c_str(), | 106 ASCIIToUTF16(switches::kProfileDirectory).c_str(), |
108 profile_path.BaseName().value().c_str()); | 107 profile_path.BaseName().value().c_str()); |
109 } | 108 } |
110 | 109 |
111 // Wrap a ShellUtil function that returns a bool so it can be posted in a | 110 // Wrap a ShellUtil/FileUtil function that returns a bool so it can be posted |
112 // task to the FILE thread. | 111 // in a task to the FILE thread. |
113 void CallShellUtilBoolFunction( | 112 void CallBoolFunction( |
114 const base::Callback<bool(void)>& bool_function) { | 113 const base::Callback<bool(void)>& bool_function) { |
115 bool_function.Run(); | 114 bool_function.Run(); |
116 } | 115 } |
117 | 116 |
117 // Renames an existing Chrome desktop profile shortcut. Must be called on the | |
118 // FILE thread. | |
119 void RenameChromeDesktopShortcutForProfile( | |
120 const string16& old_shortcut_file, | |
121 const string16& new_shortcut_file) { | |
122 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
123 FilePath shortcut_path; | |
124 if (ShellUtil::GetDesktopPath(false, // User's directory instead of system. | |
125 &shortcut_path)) { | |
126 FilePath old_shortcut_path = shortcut_path.Append(old_shortcut_file); | |
127 FilePath new_shortcut_path = shortcut_path.Append(new_shortcut_file); | |
128 if (!file_util::Move(old_shortcut_path, new_shortcut_path)) | |
129 LOG(ERROR) << "Could not rename Windows profile desktop shortcut."; | |
130 } | |
131 } | |
132 | |
133 // Create or update a profile desktop shortcut. Must be called on the FILE | |
134 // thread. | |
135 void CreateOrUpdateProfileDesktopShortcut( | |
136 const FilePath& profile_path, | |
137 const string16& profile_name, | |
138 const SkBitmap& avatar_image, | |
139 bool create) { | |
140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
141 FilePath shortcut_icon = CreateChromeDesktopShortcutIconForProfile( | |
142 profile_path, avatar_image); | |
143 | |
144 FilePath chrome_exe; | |
145 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) | |
146 return; | |
147 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); | |
148 if (!dist) | |
149 return; | |
150 string16 description(WideToUTF16(dist->GetAppDescription())); | |
gab
2012/08/24 19:28:16
dist->GetAppDescription() does return a string16,
Halli
2012/08/24 19:54:24
Done.
| |
151 | |
152 uint32 options = create ? ShellUtil::SHORTCUT_CREATE_ALWAYS : | |
153 ShellUtil::SHORTCUT_NO_OPTIONS; | |
gab
2012/08/24 19:28:16
optional nit: Align with ShellUtil::SHORTCUT_CREAT
Halli
2012/08/24 19:54:24
Done.
| |
154 ShellUtil::CreateChromeDesktopShortcut( | |
155 dist, | |
156 chrome_exe.value(), | |
157 description, | |
158 profile_name, | |
159 CreateProfileShortcutFlags(profile_path), | |
160 shortcut_icon.empty() ? chrome_exe.value() : shortcut_icon.value(), | |
161 shortcut_icon.empty() ? dist->GetIconIndex() : 0, | |
162 ShellUtil::CURRENT_USER, | |
163 options); | |
164 } | |
165 | |
118 } // namespace | 166 } // namespace |
119 | 167 |
120 class ProfileShortcutManagerWin : public ProfileShortcutManager { | 168 class ProfileShortcutManagerWin : public ProfileShortcutManager, |
169 public ProfileInfoCacheObserver { | |
121 public: | 170 public: |
122 ProfileShortcutManagerWin(); | 171 explicit ProfileShortcutManagerWin(ProfileInfoCache& cache); |
123 virtual ~ProfileShortcutManagerWin(); | 172 virtual ~ProfileShortcutManagerWin(); |
124 | 173 |
125 virtual void CreateChromeDesktopShortcut( | 174 virtual void StartProfileDesktopShortcutCreation( |
126 const FilePath& profile_path, const string16& profile_name, | 175 const FilePath& profile_path, const string16& profile_name, |
127 const gfx::Image& avatar_image) OVERRIDE; | 176 const gfx::Image& avatar_image) OVERRIDE; |
128 virtual void DeleteChromeDesktopShortcut(const FilePath& profile_path) | 177 virtual void DeleteProfileDesktopShortcut(const FilePath& profile_path, |
129 OVERRIDE; | 178 const string16& profile_name) OVERRIDE; |
179 | |
180 virtual void OnProfileAdded(const FilePath& profile_path) OVERRIDE; | |
181 virtual void OnProfileWillBeRemoved(const FilePath& profile_path) OVERRIDE; | |
182 virtual void OnProfileWasRemoved(const FilePath& profile_path, | |
183 const string16& profile_name) OVERRIDE; | |
184 virtual void OnProfileNameChanged(const FilePath& profile_path, | |
185 const string16& old_profile_name) OVERRIDE; | |
186 virtual void OnProfileAvatarChanged(const FilePath& profile_path) OVERRIDE; | |
130 | 187 |
131 private: | 188 private: |
132 struct ProfileShortcutInfo { | 189 ProfileInfoCache& profile_info_cache_; |
133 string16 flags; | |
134 string16 profile_name; | |
135 gfx::Image avatar_image; | |
136 | |
137 ProfileShortcutInfo() | |
138 : flags(string16()), | |
139 profile_name(string16()), | |
140 avatar_image(gfx::Image()) { | |
141 } | |
142 | |
143 ProfileShortcutInfo( | |
144 string16 p_flags, | |
145 string16 p_profile_name, | |
146 gfx::Image p_avatar_image) | |
147 : flags(p_flags), | |
148 profile_name(p_profile_name), | |
149 avatar_image(p_avatar_image) { | |
150 } | |
151 }; | |
152 | |
153 // TODO(hallielaine): Repopulate this map on chrome session startup | |
154 typedef std::map<FilePath, ProfileShortcutInfo> ProfileShortcutsMap; | |
155 ProfileShortcutsMap profile_shortcuts_; | |
156 }; | 190 }; |
157 | 191 |
158 // static | 192 // static |
159 bool ProfileShortcutManager::IsFeatureEnabled() { | 193 bool ProfileShortcutManager::IsFeatureEnabled() { |
160 if (CommandLine::ForCurrentProcess()->HasSwitch( | 194 if (CommandLine::ForCurrentProcess()->HasSwitch( |
161 switches::kProfileDesktopShortcuts)) { | 195 switches::kProfileDesktopShortcuts)) { |
162 return true; | 196 return true; |
163 } | 197 } |
164 return false; | 198 return false; |
165 } | 199 } |
166 | 200 |
167 // static | 201 // static |
168 ProfileShortcutManager* ProfileShortcutManager::Create() { | 202 ProfileShortcutManager* ProfileShortcutManager::Create( |
169 return new ProfileShortcutManagerWin(); | 203 ProfileInfoCache& cache) { |
204 return new ProfileShortcutManagerWin(cache); | |
170 } | 205 } |
171 | 206 |
172 ProfileShortcutManagerWin::ProfileShortcutManagerWin() { | 207 ProfileShortcutManagerWin::ProfileShortcutManagerWin(ProfileInfoCache& cache) |
208 : profile_info_cache_(cache) { | |
209 cache.AddObserver(this); | |
173 } | 210 } |
174 | 211 |
175 ProfileShortcutManagerWin::~ProfileShortcutManagerWin() { | 212 ProfileShortcutManagerWin::~ProfileShortcutManagerWin() { |
213 profile_info_cache_.RemoveObserver(this); | |
176 } | 214 } |
177 | 215 |
178 void ProfileShortcutManagerWin::CreateChromeDesktopShortcut( | 216 void ProfileShortcutManagerWin::StartProfileDesktopShortcutCreation( |
179 const FilePath& profile_path, const string16& profile_name, | 217 const FilePath& profile_path, const string16& profile_name, |
180 const gfx::Image& avatar_image) { | 218 const gfx::Image& avatar_image) { |
181 FilePath shortcut_icon = CreateChromeDesktopShortcutIconForProfile( | 219 DCHECK(!avatar_image.IsEmpty()); |
182 profile_path, avatar_image); | 220 const SkBitmap* avatar_bitmap = avatar_image.ToSkBitmap(); |
183 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
184 FilePath chrome_exe; | |
185 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) | |
186 return; | |
187 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); | |
188 string16 description; | |
189 if (!dist) | |
190 return; | |
191 description = WideToUTF16(dist->GetAppDescription()); | |
192 | 221 |
193 // Add the profile to the map if it doesn't exist already | 222 // Make a copy of the SkBitmap to ensure that we can safely use the image |
194 if (!profile_shortcuts_.count(profile_path)) { | 223 // data on the FILE thread. |
195 string16 flags = CreateProfileShortcutFlags(profile_path); | 224 SkBitmap avatar_bitmap_copy; |
196 profile_shortcuts_.insert(std::make_pair(profile_path, | 225 DCHECK(avatar_bitmap->deepCopyTo(&avatar_bitmap_copy, |
197 ProfileShortcutInfo(flags, profile_name, | 226 avatar_bitmap->getConfig())); |
198 avatar_image))); | 227 BrowserThread::PostTask( |
199 } | 228 BrowserThread::FILE, FROM_HERE, |
200 | 229 base::Bind(&CreateOrUpdateProfileDesktopShortcut, |
201 ShellUtil::CreateChromeDesktopShortcut( | 230 profile_path, profile_name, avatar_bitmap_copy, true)); |
202 dist, | |
203 chrome_exe.value(), | |
204 description, | |
205 profile_shortcuts_[profile_path].profile_name, | |
206 profile_shortcuts_[profile_path].flags, | |
207 shortcut_icon.empty() ? chrome_exe.value() : shortcut_icon.value(), | |
208 shortcut_icon.empty() ? dist->GetIconIndex() : 0, | |
209 ShellUtil::CURRENT_USER, | |
210 ShellUtil::SHORTCUT_CREATE_ALWAYS); | |
211 } | 231 } |
212 | 232 |
213 void ProfileShortcutManagerWin::DeleteChromeDesktopShortcut( | 233 void ProfileShortcutManagerWin::DeleteProfileDesktopShortcut( |
214 const FilePath& profile_path) { | 234 const FilePath& profile_path, const string16& profile_name) { |
215 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); | 235 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); |
216 string16 shortcut; | 236 string16 shortcut; |
217 // If we can find the shortcut, delete it | 237 // If we can find the shortcut, delete it |
218 if (ShellUtil::GetChromeShortcutName(dist, false, | 238 if (ShellUtil::GetChromeShortcutName(dist, false, |
219 profile_shortcuts_[profile_path].profile_name, &shortcut)) { | 239 profile_name, &shortcut)) { |
220 std::vector<string16> appended_names(1, shortcut); | 240 std::vector<string16> appended_names(1, shortcut); |
221 BrowserThread::PostTask( | 241 BrowserThread::PostTask( |
222 BrowserThread::FILE, FROM_HERE, | 242 BrowserThread::FILE, FROM_HERE, |
223 base::Bind(&CallShellUtilBoolFunction, base::Bind( | 243 base::Bind(&CallBoolFunction, base::Bind( |
224 &ShellUtil::RemoveChromeDesktopShortcutsWithAppendedNames, | 244 &ShellUtil::RemoveChromeDesktopShortcutsWithAppendedNames, |
gab
2012/08/24 19:17:33
Is RemoveChromeDesktopShortcutsWithAppendedNames()
Halli
2012/08/24 19:54:24
This will be used soon to remove all Profile short
| |
225 appended_names))); | 245 appended_names))); |
226 profile_shortcuts_.erase(profile_path); | 246 } |
247 FilePath icon_path = profile_path.AppendASCII(kProfileIconFileName); | |
248 BrowserThread::PostTask( | |
249 BrowserThread::FILE, FROM_HERE, | |
250 base::Bind(&CallBoolFunction, base::Bind( | |
251 &file_util::Delete, icon_path, false))); | |
252 } | |
253 | |
254 void ProfileShortcutManagerWin::OnProfileAdded(const FilePath& profile_path) { | |
255 } | |
256 | |
257 void ProfileShortcutManagerWin::OnProfileWillBeRemoved( | |
258 const FilePath& profile_path) { | |
259 } | |
260 | |
261 void ProfileShortcutManagerWin::OnProfileWasRemoved( | |
262 const FilePath& profile_path, | |
263 const string16& profile_name) { | |
264 } | |
265 | |
266 void ProfileShortcutManagerWin::OnProfileNameChanged( | |
267 const FilePath& profile_path, | |
268 const string16& old_profile_name) { | |
269 size_t profile_index = profile_info_cache_.GetIndexOfProfileWithPath( | |
270 profile_path); | |
271 if (profile_index == std::string::npos) | |
272 return; | |
273 | |
274 string16 new_profile_name = | |
275 profile_info_cache_.GetNameOfProfileAtIndex(profile_index); | |
276 | |
277 string16 old_shortcut_file; | |
278 string16 new_shortcut_file; | |
279 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); | |
280 if (ShellUtil::GetChromeShortcutName( | |
281 dist, false, old_profile_name, &old_shortcut_file) && | |
282 ShellUtil::GetChromeShortcutName( | |
283 dist, false, new_profile_name, &new_shortcut_file)) { | |
284 BrowserThread::PostTask( | |
285 BrowserThread::FILE, FROM_HERE, | |
286 base::Bind(&RenameChromeDesktopShortcutForProfile, | |
287 old_shortcut_file, | |
288 new_shortcut_file)); | |
227 } | 289 } |
228 } | 290 } |
229 | 291 |
292 void ProfileShortcutManagerWin::OnProfileAvatarChanged( | |
293 const FilePath& profile_path) { | |
294 size_t profile_index = profile_info_cache_.GetIndexOfProfileWithPath( | |
295 profile_path); | |
296 if (profile_index == std::string::npos) | |
297 return; | |
298 | |
299 string16 profile_name = | |
300 profile_info_cache_.GetNameOfProfileAtIndex(profile_index); | |
301 string16 shortcut; | |
302 | |
303 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); | |
304 if (ShellUtil::GetChromeShortcutName( | |
305 dist, false, profile_name, &shortcut)) { | |
306 size_t new_icon_index = profile_info_cache_. | |
307 GetAvatarIconIndexOfProfileAtIndex(profile_index); | |
308 gfx::Image avatar_image = | |
309 ResourceBundle::GetSharedInstance().GetNativeImageNamed( | |
310 profile_info_cache_.GetDefaultAvatarIconResourceIDAtIndex( | |
311 new_icon_index)); | |
312 | |
313 DCHECK(!avatar_image.IsEmpty()); | |
314 const SkBitmap* avatar_bitmap = avatar_image.ToSkBitmap(); | |
315 | |
316 // Make a copy of the SkBitmap to ensure that we can safely use the image | |
317 // data on the FILE thread. | |
318 SkBitmap avatar_bitmap_copy; | |
319 DCHECK(avatar_bitmap->deepCopyTo(&avatar_bitmap_copy, | |
320 avatar_bitmap->getConfig())); | |
321 BrowserThread::PostTask( | |
322 BrowserThread::FILE, FROM_HERE, | |
323 base::Bind(&CreateOrUpdateProfileDesktopShortcut, | |
324 profile_path, profile_name, avatar_bitmap_copy, false)); | |
325 } | |
326 } | |
327 | |
OLD | NEW |