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/jumplist_win.h" | 5 #include "chrome/browser/jumplist_win.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
10 #include "base/files/file_util.h" | 10 #include "base/files/file_util.h" |
| 11 #include "base/metrics/field_trial.h" |
11 #include "base/path_service.h" | 12 #include "base/path_service.h" |
12 #include "base/prefs/pref_change_registrar.h" | 13 #include "base/prefs/pref_change_registrar.h" |
13 #include "base/strings/string_util.h" | 14 #include "base/strings/string_util.h" |
14 #include "base/strings/utf_string_conversions.h" | 15 #include "base/strings/utf_string_conversions.h" |
15 #include "base/threading/thread.h" | 16 #include "base/threading/thread.h" |
| 17 #include "chrome/browser/browser_process.h" |
16 #include "chrome/browser/chrome_notification_types.h" | 18 #include "chrome/browser/chrome_notification_types.h" |
17 #include "chrome/browser/favicon/favicon_service.h" | 19 #include "chrome/browser/favicon/favicon_service.h" |
18 #include "chrome/browser/favicon/favicon_service_factory.h" | 20 #include "chrome/browser/favicon/favicon_service_factory.h" |
19 #include "chrome/browser/history/history_service.h" | 21 #include "chrome/browser/history/history_service.h" |
20 #include "chrome/browser/history/top_sites.h" | 22 #include "chrome/browser/history/top_sites.h" |
| 23 #include "chrome/browser/metrics/jumplist_metrics_win.h" |
21 #include "chrome/browser/profiles/profile.h" | 24 #include "chrome/browser/profiles/profile.h" |
| 25 #include "chrome/browser/profiles/profile_avatar_icon_util.h" |
| 26 #include "chrome/browser/profiles/profile_info_cache.h" |
| 27 #include "chrome/browser/profiles/profile_manager.h" |
22 #include "chrome/browser/sessions/session_types.h" | 28 #include "chrome/browser/sessions/session_types.h" |
23 #include "chrome/browser/sessions/tab_restore_service.h" | 29 #include "chrome/browser/sessions/tab_restore_service.h" |
24 #include "chrome/browser/sessions/tab_restore_service_factory.h" | 30 #include "chrome/browser/sessions/tab_restore_service_factory.h" |
25 #include "chrome/browser/shell_integration.h" | 31 #include "chrome/browser/shell_integration.h" |
26 #include "chrome/common/chrome_constants.h" | 32 #include "chrome/common/chrome_constants.h" |
27 #include "chrome/common/chrome_switches.h" | 33 #include "chrome/common/chrome_switches.h" |
28 #include "chrome/common/pref_names.h" | 34 #include "chrome/common/pref_names.h" |
29 #include "chrome/common/url_constants.h" | 35 #include "chrome/common/url_constants.h" |
30 #include "chrome/grit/generated_resources.h" | 36 #include "chrome/grit/generated_resources.h" |
31 #include "components/favicon_base/favicon_types.h" | 37 #include "components/favicon_base/favicon_types.h" |
32 #include "components/history/core/browser/page_usage_data.h" | 38 #include "components/history/core/browser/page_usage_data.h" |
| 39 #include "components/signin/core/common/profile_management_switches.h" |
33 #include "content/public/browser/browser_thread.h" | 40 #include "content/public/browser/browser_thread.h" |
34 #include "content/public/browser/notification_source.h" | 41 #include "content/public/browser/notification_source.h" |
35 #include "ui/base/l10n/l10n_util.h" | 42 #include "ui/base/l10n/l10n_util.h" |
36 #include "ui/gfx/codec/png_codec.h" | 43 #include "ui/gfx/codec/png_codec.h" |
37 #include "ui/gfx/favicon_size.h" | 44 #include "ui/gfx/favicon_size.h" |
38 #include "ui/gfx/icon_util.h" | 45 #include "ui/gfx/icon_util.h" |
39 #include "ui/gfx/image/image_family.h" | 46 #include "ui/gfx/image/image_family.h" |
40 #include "url/gurl.h" | 47 #include "url/gurl.h" |
41 | 48 |
42 using content::BrowserThread; | 49 using content::BrowserThread; |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
120 items.push_back(incognito); | 127 items.push_back(incognito); |
121 } | 128 } |
122 | 129 |
123 return jumplist_updater->AddTasks(items); | 130 return jumplist_updater->AddTasks(items); |
124 } | 131 } |
125 | 132 |
126 // Updates the application JumpList. | 133 // Updates the application JumpList. |
127 bool UpdateJumpList(const wchar_t* app_id, | 134 bool UpdateJumpList(const wchar_t* app_id, |
128 const ShellLinkItemList& most_visited_pages, | 135 const ShellLinkItemList& most_visited_pages, |
129 const ShellLinkItemList& recently_closed_pages, | 136 const ShellLinkItemList& recently_closed_pages, |
130 IncognitoModePrefs::Availability incognito_availability) { | 137 const ShellLinkItemList& profile_switcher, |
| 138 IncognitoModePrefs::Availability incognito_availability, |
| 139 bool use_profiles_category) { |
131 // JumpList is implemented only on Windows 7 or later. | 140 // JumpList is implemented only on Windows 7 or later. |
132 // So, we should return now when this function is called on earlier versions | 141 // So, we should return now when this function is called on earlier versions |
133 // of Windows. | 142 // of Windows. |
134 if (!JumpListUpdater::IsEnabled()) | 143 if (!JumpListUpdater::IsEnabled()) |
135 return true; | 144 return true; |
136 | 145 |
137 JumpListUpdater jumplist_updater(app_id); | 146 JumpListUpdater jumplist_updater(app_id); |
138 if (!jumplist_updater.BeginUpdate()) | 147 if (!jumplist_updater.BeginUpdate()) |
139 return false; | 148 return false; |
140 | 149 |
141 // We allocate 60% of the given JumpList slots to "most-visited" items | 150 size_t recently_closed_items; |
142 // and 40% to "recently-closed" items, respectively. | 151 size_t profiles_or_most_visited_items; |
143 // Nevertheless, if there are not so many items in |recently_closed_pages|, | 152 |
144 // we give the remaining slots to "most-visited" items. | 153 // Depending on the experiment, we are either showing the "Most-Visited" or |
145 const int kMostVisited = 60; | 154 // "People" categories. |
146 const int kRecentlyClosed = 40; | 155 if (use_profiles_category) { |
147 const int kTotal = kMostVisited + kRecentlyClosed; | 156 // Show at most 8 profiles, and fill the rest of the slots with the |
148 size_t most_visited_items = | 157 // "recently-closed" items. |
149 MulDiv(jumplist_updater.user_max_items(), kMostVisited, kTotal); | 158 const size_t kMaxProfiles = 8; |
150 size_t recently_closed_items = | 159 size_t max_displayed_items = std::min(kMaxProfiles, |
151 jumplist_updater.user_max_items() - most_visited_items; | 160 jumplist_updater.user_max_items()); |
152 if (recently_closed_pages.size() < recently_closed_items) { | 161 profiles_or_most_visited_items = std::min(max_displayed_items, |
153 most_visited_items += recently_closed_items - recently_closed_pages.size(); | 162 profile_switcher.size()); |
154 recently_closed_items = recently_closed_pages.size(); | 163 recently_closed_items = |
| 164 jumplist_updater.user_max_items() - profiles_or_most_visited_items; |
| 165 } else { |
| 166 // We allocate 60% of the given JumpList slots to "most-visited" items |
| 167 // and 40% to "recently-closed" items, respectively. |
| 168 // Nevertheless, if there are not so many items in |recently_closed_pages|, |
| 169 // we give the remaining slots to "most-visited" items. |
| 170 const int kMostVisited = 60; |
| 171 const int kRecentlyClosed = 40; |
| 172 const int kTotal = kMostVisited + kRecentlyClosed; |
| 173 profiles_or_most_visited_items = |
| 174 MulDiv(jumplist_updater.user_max_items(), kMostVisited, kTotal); |
| 175 recently_closed_items = |
| 176 jumplist_updater.user_max_items() - profiles_or_most_visited_items; |
| 177 if (recently_closed_pages.size() < recently_closed_items) { |
| 178 profiles_or_most_visited_items += |
| 179 recently_closed_items - recently_closed_pages.size(); |
| 180 recently_closed_items = recently_closed_pages.size(); |
| 181 } |
155 } | 182 } |
156 | 183 |
157 // Update the "Most Visited" category of the JumpList. | 184 // Update the "Most Visited" category of the JumpList if it exists. |
158 // This update request is applied into the JumpList when we commit this | 185 // This update request is applied into the JumpList when we commit this |
159 // transaction. | 186 // transaction. |
160 if (!jumplist_updater.AddCustomCategory( | 187 if (!use_profiles_category && !jumplist_updater.AddCustomCategory( |
161 base::UTF16ToWide( | 188 base::UTF16ToWide( |
162 l10n_util::GetStringUTF16(IDS_NEW_TAB_MOST_VISITED)), | 189 l10n_util::GetStringUTF16(IDS_NEW_TAB_MOST_VISITED)), |
163 most_visited_pages, most_visited_items)) { | 190 most_visited_pages, profiles_or_most_visited_items)) { |
164 return false; | 191 return false; |
165 } | 192 } |
166 | 193 |
167 // Update the "Recently Closed" category of the JumpList. | 194 // Update the "Recently Closed" category of the JumpList. |
168 if (!jumplist_updater.AddCustomCategory( | 195 if (!jumplist_updater.AddCustomCategory( |
169 base::UTF16ToWide( | 196 base::UTF16ToWide( |
170 l10n_util::GetStringUTF16(IDS_NEW_TAB_RECENTLY_CLOSED)), | 197 l10n_util::GetStringUTF16(IDS_NEW_TAB_RECENTLY_CLOSED)), |
171 recently_closed_pages, recently_closed_items)) { | 198 recently_closed_pages, recently_closed_items)) { |
172 return false; | 199 return false; |
173 } | 200 } |
174 | 201 |
| 202 // Update the "People" category of the JumpList if it exists. Only display it |
| 203 // if there's more than one profile available. |
| 204 if (use_profiles_category && profile_switcher.size() > 1 && |
| 205 !jumplist_updater.AddCustomCategory( |
| 206 l10n_util::GetStringUTF16(IDS_PROFILES_OPTIONS_GROUP_NAME), |
| 207 profile_switcher, profiles_or_most_visited_items)) { |
| 208 return false; |
| 209 } |
| 210 |
175 // Update the "Tasks" category of the JumpList. | 211 // Update the "Tasks" category of the JumpList. |
176 if (!UpdateTaskCategory(&jumplist_updater, incognito_availability)) | 212 if (!UpdateTaskCategory(&jumplist_updater, incognito_availability)) |
177 return false; | 213 return false; |
178 | 214 |
179 // Commit this transaction and send the updated JumpList to Windows. | 215 // Commit this transaction and send the updated JumpList to Windows. |
180 if (!jumplist_updater.CommitUpdate()) | 216 if (!jumplist_updater.CommitUpdate()) |
181 return false; | 217 return false; |
182 | 218 |
183 return true; | 219 return true; |
184 } | 220 } |
185 | 221 |
| 222 // Checks whether the experiment that replaces the Most Visited category |
| 223 // with a Profiles list exists. |
| 224 bool HasProfilesJumplistExperiment() { |
| 225 const std::string group_name = |
| 226 base::FieldTrialList::FindFullName("WindowsJumplistProfiles"); |
| 227 return group_name == "UseProfiles"; |
| 228 } |
| 229 |
186 } // namespace | 230 } // namespace |
187 | 231 |
188 JumpList::JumpList(Profile* profile) | 232 JumpList::JumpList(Profile* profile) |
189 : profile_(profile), | 233 : profile_(profile), |
190 task_id_(base::CancelableTaskTracker::kBadTaskId), | 234 task_id_(base::CancelableTaskTracker::kBadTaskId), |
191 weak_ptr_factory_(this) { | 235 weak_ptr_factory_(this), |
| 236 use_profiles_category_(false) { |
192 DCHECK(Enabled()); | 237 DCHECK(Enabled()); |
193 // To update JumpList when a tab is added or removed, we add this object to | 238 // To update JumpList when a tab is added or removed, we add this object to |
194 // the observer list of the TabRestoreService class. | 239 // the observer list of the TabRestoreService class. |
195 // When we add this object to the observer list, we save the pointer to this | 240 // When we add this object to the observer list, we save the pointer to this |
196 // TabRestoreService object. This pointer is used when we remove this object | 241 // TabRestoreService object. This pointer is used when we remove this object |
197 // from the observer list. | 242 // from the observer list. |
198 TabRestoreService* tab_restore_service = | 243 TabRestoreService* tab_restore_service = |
199 TabRestoreServiceFactory::GetForProfile(profile_); | 244 TabRestoreServiceFactory::GetForProfile(profile_); |
200 if (!tab_restore_service) | 245 if (!tab_restore_service) |
201 return; | 246 return; |
202 | 247 |
203 app_id_ = ShellIntegration::GetChromiumModelIdForProfile(profile_->GetPath()); | 248 app_id_ = ShellIntegration::GetChromiumModelIdForProfile(profile_->GetPath()); |
204 icon_dir_ = profile_->GetPath().Append(chrome::kJumpListIconDirname); | 249 icon_dir_ = profile_->GetPath().Append(chrome::kJumpListIconDirname); |
| 250 use_profiles_category_ = HasProfilesJumplistExperiment(); |
| 251 |
205 history::TopSites* top_sites = profile_->GetTopSites(); | 252 history::TopSites* top_sites = profile_->GetTopSites(); |
206 if (top_sites) { | 253 if (top_sites) { |
207 // TopSites updates itself after a delay. This is especially noticable when | 254 // TopSites updates itself after a delay. This is especially noticable when |
208 // your profile is empty. Ask TopSites to update itself when jumplist is | 255 // your profile is empty. Ask TopSites to update itself when jumplist is |
209 // initialized. | 256 // initialized. |
210 top_sites->SyncWithHistory(); | 257 top_sites->SyncWithHistory(); |
211 registrar_.reset(new content::NotificationRegistrar); | 258 registrar_.reset(new content::NotificationRegistrar); |
212 // Register for notification when TopSites changes so that we can update | 259 // Register for notification when TopSites changes so that we can update |
213 // ourself. | 260 // ourself. |
214 registrar_->Add(this, chrome::NOTIFICATION_TOP_SITES_CHANGED, | 261 registrar_->Add(this, chrome::NOTIFICATION_TOP_SITES_CHANGED, |
215 content::Source<history::TopSites>(top_sites)); | 262 content::Source<history::TopSites>(top_sites)); |
216 // Register for notification when profile is destroyed to ensure that all | 263 // Register for notification when profile is destroyed to ensure that all |
217 // observers are detatched at that time. | 264 // observers are detatched at that time. |
218 registrar_->Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, | 265 registrar_->Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, |
219 content::Source<Profile>(profile_)); | 266 content::Source<Profile>(profile_)); |
220 } | 267 } |
221 tab_restore_service->AddObserver(this); | 268 tab_restore_service->AddObserver(this); |
222 pref_change_registrar_.reset(new PrefChangeRegistrar); | 269 pref_change_registrar_.reset(new PrefChangeRegistrar); |
223 pref_change_registrar_->Init(profile_->GetPrefs()); | 270 pref_change_registrar_->Init(profile_->GetPrefs()); |
224 pref_change_registrar_->Add( | 271 pref_change_registrar_->Add( |
225 prefs::kIncognitoModeAvailability, | 272 prefs::kIncognitoModeAvailability, |
226 base::Bind(&JumpList::OnIncognitoAvailabilityChanged, this)); | 273 base::Bind(&JumpList::OnIncognitoAvailabilityChanged, this)); |
| 274 |
| 275 ProfileManager* profile_manager = g_browser_process->profile_manager(); |
| 276 avatar_menu_.reset(new AvatarMenu( |
| 277 &profile_manager->GetProfileInfoCache(), this, NULL)); |
| 278 avatar_menu_->RebuildMenu(); |
| 279 UpdateProfileSwitcher(); |
227 } | 280 } |
228 | 281 |
229 JumpList::~JumpList() { | 282 JumpList::~JumpList() { |
230 Terminate(); | 283 Terminate(); |
231 } | 284 } |
232 | 285 |
233 // static | 286 // static |
234 bool JumpList::Enabled() { | 287 bool JumpList::Enabled() { |
235 return JumpListUpdater::IsEnabled(); | 288 return JumpListUpdater::IsEnabled(); |
236 } | 289 } |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
274 if (tab_restore_service) | 327 if (tab_restore_service) |
275 tab_restore_service->RemoveObserver(this); | 328 tab_restore_service->RemoveObserver(this); |
276 registrar_.reset(); | 329 registrar_.reset(); |
277 pref_change_registrar_.reset(); | 330 pref_change_registrar_.reset(); |
278 } | 331 } |
279 profile_ = NULL; | 332 profile_ = NULL; |
280 } | 333 } |
281 | 334 |
282 void JumpList::OnMostVisitedURLsAvailable( | 335 void JumpList::OnMostVisitedURLsAvailable( |
283 const history::MostVisitedURLList& data) { | 336 const history::MostVisitedURLList& data) { |
284 | |
285 // If we have a pending favicon request, cancel it here (it is out of date). | 337 // If we have a pending favicon request, cancel it here (it is out of date). |
286 CancelPendingUpdate(); | 338 CancelPendingUpdate(); |
287 | 339 |
288 { | 340 { |
289 base::AutoLock auto_lock(list_lock_); | 341 base::AutoLock auto_lock(list_lock_); |
290 most_visited_pages_.clear(); | 342 most_visited_pages_.clear(); |
291 for (size_t i = 0; i < data.size(); i++) { | 343 for (size_t i = 0; i < data.size(); i++) { |
292 const history::MostVisitedURL& url = data[i]; | 344 const history::MostVisitedURL& url = data[i]; |
293 scoped_refptr<ShellLinkItem> link = CreateShellLink(); | 345 scoped_refptr<ShellLinkItem> link = CreateShellLink(); |
294 std::string url_string = url.url.spec(); | 346 std::string url_string = url.url.spec(); |
295 std::wstring url_string_wide = base::UTF8ToWide(url_string); | 347 std::wstring url_string_wide = base::UTF8ToWide(url_string); |
296 link->GetCommandLine()->AppendArgNative(url_string_wide); | 348 link->GetCommandLine()->AppendArgNative(url_string_wide); |
| 349 link->GetCommandLine()->AppendSwitchASCII( |
| 350 switches::kWinJumplistAction, jumplist::kMostVisitedCategory); |
297 link->set_title(!url.title.empty()? url.title : url_string_wide); | 351 link->set_title(!url.title.empty()? url.title : url_string_wide); |
298 most_visited_pages_.push_back(link); | 352 most_visited_pages_.push_back(link); |
299 icon_urls_.push_back(make_pair(url_string, link)); | 353 icon_urls_.push_back(make_pair(url_string, link)); |
300 } | 354 } |
301 } | 355 } |
302 | 356 |
303 // Send a query that retrieves the first favicon. | 357 // Send a query that retrieves the first favicon. |
304 StartLoadingFavicon(); | 358 StartLoadingFavicon(); |
305 } | 359 } |
306 | 360 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
343 recently_closed_pages_ = temp_list; | 397 recently_closed_pages_ = temp_list; |
344 } | 398 } |
345 | 399 |
346 // Send a query that retrieves the first favicon. | 400 // Send a query that retrieves the first favicon. |
347 StartLoadingFavicon(); | 401 StartLoadingFavicon(); |
348 } | 402 } |
349 | 403 |
350 void JumpList::TabRestoreServiceDestroyed(TabRestoreService* service) { | 404 void JumpList::TabRestoreServiceDestroyed(TabRestoreService* service) { |
351 } | 405 } |
352 | 406 |
| 407 void JumpList::OnAvatarMenuChanged(AvatarMenu* avatar_menu) { |
| 408 UpdateProfileSwitcher(); |
| 409 PostRunUpdate(); |
| 410 } |
| 411 |
353 bool JumpList::AddTab(const TabRestoreService::Tab* tab, | 412 bool JumpList::AddTab(const TabRestoreService::Tab* tab, |
354 ShellLinkItemList* list, | 413 ShellLinkItemList* list, |
355 size_t max_items) { | 414 size_t max_items) { |
356 // This code adds the URL and the title strings of the given tab to the | 415 // This code adds the URL and the title strings of the given tab to the |
357 // specified list. | 416 // specified list. |
358 if (list->size() >= max_items) | 417 if (list->size() >= max_items) |
359 return false; | 418 return false; |
360 | 419 |
361 scoped_refptr<ShellLinkItem> link = CreateShellLink(); | 420 scoped_refptr<ShellLinkItem> link = CreateShellLink(); |
362 const sessions::SerializedNavigationEntry& current_navigation = | 421 const sessions::SerializedNavigationEntry& current_navigation = |
363 tab->navigations.at(tab->current_navigation_index); | 422 tab->navigations.at(tab->current_navigation_index); |
364 std::string url = current_navigation.virtual_url().spec(); | 423 std::string url = current_navigation.virtual_url().spec(); |
365 link->GetCommandLine()->AppendArgNative(base::UTF8ToWide(url)); | 424 link->GetCommandLine()->AppendArgNative(base::UTF8ToWide(url)); |
| 425 link->GetCommandLine()->AppendSwitchASCII( |
| 426 switches::kWinJumplistAction, jumplist::kRecentlyClosedCategory); |
366 link->set_title(current_navigation.title()); | 427 link->set_title(current_navigation.title()); |
367 list->push_back(link); | 428 list->push_back(link); |
368 icon_urls_.push_back(make_pair(url, link)); | 429 icon_urls_.push_back(make_pair(url, link)); |
369 return true; | 430 return true; |
370 } | 431 } |
371 | 432 |
372 void JumpList::AddWindow(const TabRestoreService::Window* window, | 433 void JumpList::AddWindow(const TabRestoreService::Window* window, |
373 ShellLinkItemList* list, | 434 ShellLinkItemList* list, |
374 size_t max_items) { | 435 size_t max_items) { |
375 // This code enumerates al the tabs in the given window object and add their | 436 // This code enumerates al the tabs in the given window object and add their |
(...skipping 14 matching lines...) Expand all Loading... |
390 waiting_for_icons = !icon_urls_.empty(); | 451 waiting_for_icons = !icon_urls_.empty(); |
391 if (waiting_for_icons) { | 452 if (waiting_for_icons) { |
392 // Ask FaviconService if it has a favicon of a URL. | 453 // Ask FaviconService if it has a favicon of a URL. |
393 // When FaviconService has one, it will call OnFaviconDataAvailable(). | 454 // When FaviconService has one, it will call OnFaviconDataAvailable(). |
394 url = GURL(icon_urls_.front().first); | 455 url = GURL(icon_urls_.front().first); |
395 } | 456 } |
396 } | 457 } |
397 | 458 |
398 if (!waiting_for_icons) { | 459 if (!waiting_for_icons) { |
399 // No more favicons are needed by the application JumpList. Schedule a | 460 // No more favicons are needed by the application JumpList. Schedule a |
400 // RunUpdate call. | 461 // RunUpdateOnFileThread call. |
401 PostRunUpdate(); | 462 PostRunUpdate(); |
402 return; | 463 return; |
403 } | 464 } |
404 | 465 |
405 FaviconService* favicon_service = | 466 FaviconService* favicon_service = |
406 FaviconServiceFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS); | 467 FaviconServiceFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS); |
407 task_id_ = favicon_service->GetFaviconImageForPageURL( | 468 task_id_ = favicon_service->GetFaviconImageForPageURL( |
408 url, | 469 url, |
409 base::Bind(&JumpList::OnFaviconDataAvailable, base::Unretained(this)), | 470 base::Bind(&JumpList::OnFaviconDataAvailable, base::Unretained(this)), |
410 &cancelable_task_tracker_); | 471 &cancelable_task_tracker_); |
411 } | 472 } |
412 | 473 |
413 void JumpList::OnFaviconDataAvailable( | 474 void JumpList::OnFaviconDataAvailable( |
414 const favicon_base::FaviconImageResult& image_result) { | 475 const favicon_base::FaviconImageResult& image_result) { |
415 // If there is currently a favicon request in progress, it is now outdated, | 476 // If there is currently a favicon request in progress, it is now outdated, |
416 // as we have received another, so nullify the handle from the old request. | 477 // as we have received another, so nullify the handle from the old request. |
417 task_id_ = base::CancelableTaskTracker::kBadTaskId; | 478 task_id_ = base::CancelableTaskTracker::kBadTaskId; |
418 // lock the list to set icon data and pop the url | 479 // Lock the list to set icon data and pop the url. |
419 { | 480 { |
420 base::AutoLock auto_lock(list_lock_); | 481 base::AutoLock auto_lock(list_lock_); |
421 // Attach the received data to the ShellLinkItem object. | 482 // Attach the received data to the ShellLinkItem object. |
422 // This data will be decoded by the RunUpdate method. | 483 // This data will be decoded by the RunUpdateOnFileThread method. |
423 if (!image_result.image.IsEmpty()) { | 484 if (!image_result.image.IsEmpty()) { |
424 if (!icon_urls_.empty() && icon_urls_.front().second) | 485 if (!icon_urls_.empty() && icon_urls_.front().second) |
425 icon_urls_.front().second->set_icon_data(image_result.image.AsBitmap()); | 486 icon_urls_.front().second->set_icon_data(image_result.image.AsBitmap()); |
426 } | 487 } |
427 | 488 |
428 if (!icon_urls_.empty()) | 489 if (!icon_urls_.empty()) |
429 icon_urls_.pop_front(); | 490 icon_urls_.pop_front(); |
430 } | 491 } |
431 // Check whether we need to load more favicons. | 492 // Check whether we need to load more favicons. |
432 StartLoadingFavicon(); | 493 StartLoadingFavicon(); |
(...skipping 12 matching lines...) Expand all Loading... |
445 } | 506 } |
446 | 507 |
447 void JumpList::PostRunUpdate() { | 508 void JumpList::PostRunUpdate() { |
448 // Check if incognito windows (or normal windows) are disabled by policy. | 509 // Check if incognito windows (or normal windows) are disabled by policy. |
449 IncognitoModePrefs::Availability incognito_availability = | 510 IncognitoModePrefs::Availability incognito_availability = |
450 profile_ ? IncognitoModePrefs::GetAvailability(profile_->GetPrefs()) | 511 profile_ ? IncognitoModePrefs::GetAvailability(profile_->GetPrefs()) |
451 : IncognitoModePrefs::ENABLED; | 512 : IncognitoModePrefs::ENABLED; |
452 | 513 |
453 BrowserThread::PostTask( | 514 BrowserThread::PostTask( |
454 BrowserThread::FILE, FROM_HERE, | 515 BrowserThread::FILE, FROM_HERE, |
455 base::Bind(&JumpList::RunUpdate, this, incognito_availability)); | 516 base::Bind(&JumpList::RunUpdateOnFileThread, |
| 517 this, |
| 518 incognito_availability)); |
456 } | 519 } |
457 | 520 |
458 void JumpList::RunUpdate( | 521 void JumpList::RunUpdateOnFileThread( |
459 IncognitoModePrefs::Availability incognito_availability) { | 522 IncognitoModePrefs::Availability incognito_availability) { |
460 ShellLinkItemList local_most_visited_pages; | 523 ShellLinkItemList local_most_visited_pages; |
461 ShellLinkItemList local_recently_closed_pages; | 524 ShellLinkItemList local_recently_closed_pages; |
| 525 ShellLinkItemList local_profile_switcher; |
462 | 526 |
463 { | 527 { |
464 base::AutoLock auto_lock(list_lock_); | 528 base::AutoLock auto_lock(list_lock_); |
465 // Make sure we are not out of date: if icon_urls_ is not empty, then | 529 // Make sure we are not out of date: if icon_urls_ is not empty, then |
466 // another notification has been received since we processed this one | 530 // another notification has been received since we processed this one |
467 if (!icon_urls_.empty()) | 531 if (!icon_urls_.empty()) |
468 return; | 532 return; |
469 | 533 |
470 // Make local copies of lists so we can release the lock. | 534 // Make local copies of lists so we can release the lock. |
471 local_most_visited_pages = most_visited_pages_; | 535 local_most_visited_pages = most_visited_pages_; |
472 local_recently_closed_pages = recently_closed_pages_; | 536 local_recently_closed_pages = recently_closed_pages_; |
| 537 local_profile_switcher = profile_switcher_; |
473 } | 538 } |
474 | 539 |
475 // Delete the directory which contains old icon files, rename the current | 540 // Delete the directory which contains old icon files, rename the current |
476 // icon directory, and create a new directory which contains new JumpList | 541 // icon directory, and create a new directory which contains new JumpList |
477 // icon files. | 542 // icon files. |
478 base::FilePath icon_dir_old(icon_dir_.value() + L"Old"); | 543 base::FilePath icon_dir_old(icon_dir_.value() + L"Old"); |
479 if (base::PathExists(icon_dir_old)) | 544 if (base::PathExists(icon_dir_old)) |
480 base::DeleteFile(icon_dir_old, true); | 545 base::DeleteFile(icon_dir_old, true); |
481 base::Move(icon_dir_, icon_dir_old); | 546 base::Move(icon_dir_, icon_dir_old); |
482 base::CreateDirectory(icon_dir_); | 547 base::CreateDirectory(icon_dir_); |
483 | 548 |
484 // Create temporary icon files for shortcuts in the "Most Visited" category. | 549 // Create temporary icon files for shortcuts in the "Most Visited" category. |
485 CreateIconFiles(local_most_visited_pages); | 550 CreateIconFiles(local_most_visited_pages); |
486 | 551 |
487 // Create temporary icon files for shortcuts in the "Recently Closed" | 552 // Create temporary icon files for shortcuts in the "Recently Closed" |
488 // category. | 553 // category. |
489 CreateIconFiles(local_recently_closed_pages); | 554 CreateIconFiles(local_recently_closed_pages); |
490 | 555 |
| 556 // Create temporary icon files for the profile avatars in the "People" |
| 557 // category. |
| 558 CreateIconFiles(local_profile_switcher); |
| 559 |
491 // We finished collecting all resources needed for updating an application | 560 // We finished collecting all resources needed for updating an application |
492 // JumpList. So, create a new JumpList and replace the current JumpList | 561 // JumpList. So, create a new JumpList and replace the current JumpList |
493 // with it. | 562 // with it. |
494 UpdateJumpList(app_id_.c_str(), local_most_visited_pages, | 563 UpdateJumpList(app_id_.c_str(), |
495 local_recently_closed_pages, incognito_availability); | 564 local_most_visited_pages, |
| 565 local_recently_closed_pages, |
| 566 local_profile_switcher, |
| 567 incognito_availability, |
| 568 use_profiles_category_); |
496 } | 569 } |
497 | 570 |
498 void JumpList::CreateIconFiles(const ShellLinkItemList& item_list) { | 571 void JumpList::CreateIconFiles(const ShellLinkItemList& item_list) { |
499 for (ShellLinkItemList::const_iterator item = item_list.begin(); | 572 for (ShellLinkItemList::const_iterator item = item_list.begin(); |
500 item != item_list.end(); ++item) { | 573 item != item_list.end(); ++item) { |
501 base::FilePath icon_path; | 574 base::FilePath icon_path; |
502 if (CreateIconFile((*item)->icon_data(), icon_dir_, &icon_path)) | 575 if (CreateIconFile((*item)->icon_data(), icon_dir_, &icon_path)) |
503 (*item)->set_icon(icon_path.value(), 0); | 576 (*item)->set_icon(icon_path.value(), 0); |
504 } | 577 } |
505 } | 578 } |
| 579 |
| 580 void JumpList::UpdateProfileSwitcher() { |
| 581 ShellLinkItemList new_profile_switcher; |
| 582 |
| 583 // Don't display a menu in the single profile case. |
| 584 if (avatar_menu_->GetNumberOfItems() > 1) { |
| 585 for (size_t i = 0; i < avatar_menu_->GetNumberOfItems(); ++i) { |
| 586 scoped_refptr<ShellLinkItem> link = CreateShellLink(); |
| 587 const AvatarMenu::Item& item = avatar_menu_->GetItemAt(i); |
| 588 |
| 589 link->set_title(item.name); |
| 590 link->GetCommandLine()->AppendSwitchPath( |
| 591 switches::kProfileDirectory, item.profile_path.BaseName()); |
| 592 link->GetCommandLine()->AppendSwitch( |
| 593 switches::kActivateExistingProfileBrowser); |
| 594 link->GetCommandLine()->AppendSwitchASCII( |
| 595 switches::kWinJumplistAction, jumplist::kProfilesCategory); |
| 596 |
| 597 gfx::Image avatar; |
| 598 bool is_rectangle; |
| 599 profiles::GetTransparentBackgroundProfileAvatar( |
| 600 item.profile_path, &avatar, &is_rectangle); |
| 601 link->set_icon_data(avatar.AsBitmap()); |
| 602 new_profile_switcher.push_back(link); |
| 603 } |
| 604 } |
| 605 |
| 606 { |
| 607 base::AutoLock auto_lock(list_lock_); |
| 608 new_profile_switcher.swap(profile_switcher_); |
| 609 } |
| 610 } |
OLD | NEW |