| OLD | NEW |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 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/win/jumplist.h" | 5 #include "chrome/browser/win/jumplist.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 120 base::DeleteFile(path, false); | 120 base::DeleteFile(path, false); |
| 121 return false; | 121 return false; |
| 122 } | 122 } |
| 123 | 123 |
| 124 // Add this icon file to the list and return its absolute path. | 124 // Add this icon file to the list and return its absolute path. |
| 125 // The IShellLink::SetIcon() function needs the absolute path to an icon. | 125 // The IShellLink::SetIcon() function needs the absolute path to an icon. |
| 126 *icon_path = path; | 126 *icon_path = path; |
| 127 return true; | 127 return true; |
| 128 } | 128 } |
| 129 | 129 |
| 130 // Creates icon files for the asynchrounously loaded icons. | |
| 131 void CreateIconFiles(const base::FilePath& icon_dir, | |
| 132 const ShellLinkItemList& item_list, | |
| 133 size_t max_items) { | |
| 134 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. | |
| 135 SCOPED_UMA_HISTOGRAM_TIMER("WinJumplist.CreateIconFilesDuration"); | |
| 136 | |
| 137 for (ShellLinkItemList::const_iterator item = item_list.begin(); | |
| 138 item != item_list.end() && max_items > 0; ++item, --max_items) { | |
| 139 base::FilePath icon_path; | |
| 140 if (CreateIconFile((*item)->icon_image(), icon_dir, &icon_path)) | |
| 141 (*item)->set_icon(icon_path.value(), 0); | |
| 142 } | |
| 143 } | |
| 144 | |
| 145 // Updates icon files in |icon_dir|, which includes deleting old icons and | |
| 146 // creating at most |slot_limit| new icons for |page_list|. | |
| 147 void UpdateIconFiles(const base::FilePath& icon_dir, | |
| 148 const ShellLinkItemList& page_list, | |
| 149 size_t slot_limit) { | |
| 150 DeleteDirectoryContentAndLogRuntime(icon_dir, kFileDeleteLimit); | |
| 151 | |
| 152 // Create new icons only when the directory exists and is empty. | |
| 153 if (base::CreateDirectory(icon_dir) && base::IsDirectoryEmpty(icon_dir)) | |
| 154 CreateIconFiles(icon_dir, page_list, slot_limit); | |
| 155 } | |
| 156 | |
| 157 // Updates the "Tasks" category of the JumpList. | 130 // Updates the "Tasks" category of the JumpList. |
| 158 bool UpdateTaskCategory( | 131 bool UpdateTaskCategory( |
| 159 JumpListUpdater* jumplist_updater, | 132 JumpListUpdater* jumplist_updater, |
| 160 IncognitoModePrefs::Availability incognito_availability) { | 133 IncognitoModePrefs::Availability incognito_availability) { |
| 161 base::FilePath chrome_path; | 134 base::FilePath chrome_path; |
| 162 if (!PathService::Get(base::FILE_EXE, &chrome_path)) | 135 if (!PathService::Get(base::FILE_EXE, &chrome_path)) |
| 163 return false; | 136 return false; |
| 164 | 137 |
| 165 int icon_index = install_static::GetIconResourceIndex(); | 138 int icon_index = install_static::GetIconResourceIndex(); |
| 166 | 139 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 200 // Returns the full path of the JumpListIcons[|suffix|] directory in | 173 // Returns the full path of the JumpListIcons[|suffix|] directory in |
| 201 // |profile_dir|. | 174 // |profile_dir|. |
| 202 base::FilePath GenerateJumplistIconDirName( | 175 base::FilePath GenerateJumplistIconDirName( |
| 203 const base::FilePath& profile_dir, | 176 const base::FilePath& profile_dir, |
| 204 const base::FilePath::StringPieceType& suffix) { | 177 const base::FilePath::StringPieceType& suffix) { |
| 205 base::FilePath::StringType dir_name(chrome::kJumpListIconDirname); | 178 base::FilePath::StringType dir_name(chrome::kJumpListIconDirname); |
| 206 suffix.AppendToString(&dir_name); | 179 suffix.AppendToString(&dir_name); |
| 207 return profile_dir.Append(dir_name); | 180 return profile_dir.Append(dir_name); |
| 208 } | 181 } |
| 209 | 182 |
| 210 // Updates the application JumpList, which consists of 1) delete old icon files; | |
| 211 // 2) create new icon files; 3) notify the OS. | |
| 212 // Note that any timeout error along the way results in the old jumplist being | |
| 213 // left as-is, while any non-timeout error results in the old jumplist being | |
| 214 // left as-is, but without icon files. | |
| 215 bool UpdateJumpList(const wchar_t* app_id, | |
| 216 const base::FilePath& profile_dir, | |
| 217 const ShellLinkItemList& most_visited_pages, | |
| 218 const ShellLinkItemList& recently_closed_pages, | |
| 219 bool most_visited_pages_have_updates, | |
| 220 bool recently_closed_pages_have_updates, | |
| 221 IncognitoModePrefs::Availability incognito_availability) { | |
| 222 if (!JumpListUpdater::IsEnabled()) | |
| 223 return true; | |
| 224 | |
| 225 JumpListUpdater jumplist_updater(app_id); | |
| 226 | |
| 227 base::ElapsedTimer begin_update_timer; | |
| 228 | |
| 229 if (!jumplist_updater.BeginUpdate()) | |
| 230 return false; | |
| 231 | |
| 232 // Discard this JumpList update if JumpListUpdater::BeginUpdate takes longer | |
| 233 // than the maximum allowed time, as it's very likely the following update | |
| 234 // steps will also take a long time. | |
| 235 if (begin_update_timer.Elapsed() >= kTimeOutForJumplistUpdate) | |
| 236 return false; | |
| 237 | |
| 238 // The default maximum number of items to display in JumpList is 10. | |
| 239 // https://msdn.microsoft.com/library/windows/desktop/dd378398.aspx | |
| 240 // The "Most visited" category title always takes 1 of the JumpList slots if | |
| 241 // |most_visited_pages| isn't empty. | |
| 242 // The "Recently closed" category title will also take 1 if | |
| 243 // |recently_closed_pages| isn't empty. | |
| 244 // For the remaining slots, we allocate 5/8 (i.e., 5 slots if both categories | |
| 245 // present) to "most-visited" items and 3/8 (i.e., 3 slots if both categories | |
| 246 // present) to "recently-closed" items, respectively. | |
| 247 // Nevertheless, if there are not so many items in |recently_closed_pages|, | |
| 248 // we give the remaining slots to "most-visited" items. | |
| 249 | |
| 250 const int kMostVisited = 50; | |
| 251 const int kRecentlyClosed = 30; | |
| 252 const int kTotal = kMostVisited + kRecentlyClosed; | |
| 253 | |
| 254 // Adjust the available jumplist slots to account for the category titles. | |
| 255 size_t user_max_items_adjusted = jumplist_updater.user_max_items(); | |
| 256 if (!most_visited_pages.empty()) | |
| 257 --user_max_items_adjusted; | |
| 258 if (!recently_closed_pages.empty()) | |
| 259 --user_max_items_adjusted; | |
| 260 | |
| 261 size_t most_visited_items = | |
| 262 MulDiv(user_max_items_adjusted, kMostVisited, kTotal); | |
| 263 size_t recently_closed_items = user_max_items_adjusted - most_visited_items; | |
| 264 if (recently_closed_pages.size() < recently_closed_items) { | |
| 265 most_visited_items += recently_closed_items - recently_closed_pages.size(); | |
| 266 recently_closed_items = recently_closed_pages.size(); | |
| 267 } | |
| 268 | |
| 269 // Record the desired number of icons to create in this JumpList update. | |
| 270 int icons_to_create = 0; | |
| 271 | |
| 272 // Update the icons for "Most Visisted" category of the JumpList if needed. | |
| 273 if (most_visited_pages_have_updates) { | |
| 274 base::FilePath icon_dir_most_visited = GenerateJumplistIconDirName( | |
| 275 profile_dir, FILE_PATH_LITERAL("MostVisited")); | |
| 276 | |
| 277 UpdateIconFiles(icon_dir_most_visited, most_visited_pages, | |
| 278 most_visited_items); | |
| 279 | |
| 280 icons_to_create += std::min(most_visited_pages.size(), most_visited_items); | |
| 281 } | |
| 282 | |
| 283 // Update the icons for "Recently Closed" category of the JumpList if needed. | |
| 284 if (recently_closed_pages_have_updates) { | |
| 285 base::FilePath icon_dir_recent_closed = GenerateJumplistIconDirName( | |
| 286 profile_dir, FILE_PATH_LITERAL("RecentClosed")); | |
| 287 | |
| 288 UpdateIconFiles(icon_dir_recent_closed, recently_closed_pages, | |
| 289 recently_closed_items); | |
| 290 | |
| 291 icons_to_create += | |
| 292 std::min(recently_closed_pages.size(), recently_closed_items); | |
| 293 } | |
| 294 | |
| 295 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. | |
| 296 UMA_HISTOGRAM_COUNTS_100("WinJumplist.CreateIconFilesCount", icons_to_create); | |
| 297 | |
| 298 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. | |
| 299 SCOPED_UMA_HISTOGRAM_TIMER("WinJumplist.UpdateJumpListDuration"); | |
| 300 | |
| 301 // Update the "Most Visited" category of the JumpList if it exists. | |
| 302 // This update request is applied into the JumpList when we commit this | |
| 303 // transaction. | |
| 304 if (!jumplist_updater.AddCustomCategory( | |
| 305 l10n_util::GetStringUTF16(IDS_NEW_TAB_MOST_VISITED), | |
| 306 most_visited_pages, most_visited_items)) { | |
| 307 return false; | |
| 308 } | |
| 309 | |
| 310 // Update the "Recently Closed" category of the JumpList. | |
| 311 if (!jumplist_updater.AddCustomCategory( | |
| 312 l10n_util::GetStringUTF16(IDS_RECENTLY_CLOSED), | |
| 313 recently_closed_pages, recently_closed_items)) { | |
| 314 return false; | |
| 315 } | |
| 316 | |
| 317 // Update the "Tasks" category of the JumpList. | |
| 318 if (!UpdateTaskCategory(&jumplist_updater, incognito_availability)) | |
| 319 return false; | |
| 320 | |
| 321 // Commit this transaction and send the updated JumpList to Windows. | |
| 322 return jumplist_updater.CommitUpdate(); | |
| 323 } | |
| 324 | |
| 325 // Updates the jumplist, once all the data has been fetched. | |
| 326 void RunUpdateJumpList(IncognitoModePrefs::Availability incognito_availability, | |
| 327 const std::wstring& app_id, | |
| 328 const base::FilePath& profile_dir, | |
| 329 base::RefCountedData<JumpListData>* ref_counted_data) { | |
| 330 JumpListData* data = &ref_counted_data->data; | |
| 331 ShellLinkItemList local_most_visited_pages; | |
| 332 ShellLinkItemList local_recently_closed_pages; | |
| 333 bool most_visited_pages_have_updates; | |
| 334 bool recently_closed_pages_have_updates; | |
| 335 | |
| 336 { | |
| 337 base::AutoLock auto_lock(data->list_lock_); | |
| 338 // Make sure we are not out of date: if icon_urls_ is not empty, then | |
| 339 // another notification has been received since we processed this one | |
| 340 if (!data->icon_urls_.empty()) | |
| 341 return; | |
| 342 | |
| 343 // Make local copies of lists and flags so we can release the lock. | |
| 344 local_most_visited_pages = data->most_visited_pages_; | |
| 345 local_recently_closed_pages = data->recently_closed_pages_; | |
| 346 | |
| 347 most_visited_pages_have_updates = data->most_visited_pages_have_updates_; | |
| 348 recently_closed_pages_have_updates = | |
| 349 data->recently_closed_pages_have_updates_; | |
| 350 | |
| 351 // Clear the flags to reflect that we'll take actions on these updates. | |
| 352 data->most_visited_pages_have_updates_ = false; | |
| 353 data->recently_closed_pages_have_updates_ = false; | |
| 354 } | |
| 355 | |
| 356 if (!most_visited_pages_have_updates && !recently_closed_pages_have_updates) | |
| 357 return; | |
| 358 | |
| 359 // Update the application JumpList. If it fails, reset the flags to true if | |
| 360 // they were so that the corresponding JumpList categories will be tried to | |
| 361 // update again in the next run. | |
| 362 if (!UpdateJumpList( | |
| 363 app_id.c_str(), profile_dir, local_most_visited_pages, | |
| 364 local_recently_closed_pages, most_visited_pages_have_updates, | |
| 365 recently_closed_pages_have_updates, incognito_availability)) { | |
| 366 base::AutoLock auto_lock(data->list_lock_); | |
| 367 if (most_visited_pages_have_updates) | |
| 368 data->most_visited_pages_have_updates_ = true; | |
| 369 if (recently_closed_pages_have_updates) | |
| 370 data->recently_closed_pages_have_updates_ = true; | |
| 371 } | |
| 372 } | |
| 373 | |
| 374 } // namespace | 183 } // namespace |
| 375 | 184 |
| 376 JumpList::JumpListData::JumpListData() {} | 185 JumpList::JumpListData::JumpListData() {} |
| 377 | 186 |
| 378 JumpList::JumpListData::~JumpListData() {} | 187 JumpList::JumpListData::~JumpListData() {} |
| 379 | 188 |
| 380 JumpList::JumpList(Profile* profile) | 189 JumpList::JumpList(Profile* profile) |
| 381 : RefcountedKeyedService(content::BrowserThread::GetTaskRunnerForThread( | 190 : RefcountedKeyedService(content::BrowserThread::GetTaskRunnerForThread( |
| 382 content::BrowserThread::UI)), | 191 content::BrowserThread::UI)), |
| 383 profile_(profile), | 192 profile_(profile), |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 475 const int kMostVistedCount = 9; | 284 const int kMostVistedCount = 9; |
| 476 { | 285 { |
| 477 JumpListData* data = &jumplist_data_->data; | 286 JumpListData* data = &jumplist_data_->data; |
| 478 base::AutoLock auto_lock(data->list_lock_); | 287 base::AutoLock auto_lock(data->list_lock_); |
| 479 data->most_visited_pages_.clear(); | 288 data->most_visited_pages_.clear(); |
| 480 | 289 |
| 481 for (size_t i = 0; i < urls.size() && i < kMostVistedCount; i++) { | 290 for (size_t i = 0; i < urls.size() && i < kMostVistedCount; i++) { |
| 482 const history::MostVisitedURL& url = urls[i]; | 291 const history::MostVisitedURL& url = urls[i]; |
| 483 scoped_refptr<ShellLinkItem> link = CreateShellLink(); | 292 scoped_refptr<ShellLinkItem> link = CreateShellLink(); |
| 484 std::string url_string = url.url.spec(); | 293 std::string url_string = url.url.spec(); |
| 485 std::wstring url_string_wide = base::UTF8ToWide(url_string); | 294 base::string16 url_string_wide = base::UTF8ToUTF16(url_string); |
| 486 link->GetCommandLine()->AppendArgNative(url_string_wide); | 295 link->GetCommandLine()->AppendArgNative(url_string_wide); |
| 487 link->GetCommandLine()->AppendSwitchASCII( | 296 link->GetCommandLine()->AppendSwitchASCII( |
| 488 switches::kWinJumplistAction, jumplist::kMostVisitedCategory); | 297 switches::kWinJumplistAction, jumplist::kMostVisitedCategory); |
| 489 link->set_title(!url.title.empty() ? url.title : url_string_wide); | 298 link->set_title(!url.title.empty() ? url.title : url_string_wide); |
| 490 data->most_visited_pages_.push_back(link); | 299 data->most_visited_pages_.push_back(link); |
| 491 data->icon_urls_.push_back(std::make_pair(url_string, link)); | 300 data->icon_urls_.push_back(std::make_pair(url_string, link)); |
| 492 } | 301 } |
| 493 data->most_visited_pages_have_updates_ = true; | 302 data->most_visited_pages_have_updates_ = true; |
| 494 } | 303 } |
| 495 | 304 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 528 data->list_lock_.AssertAcquired(); | 337 data->list_lock_.AssertAcquired(); |
| 529 | 338 |
| 530 // This code adds the URL and the title strings of the given tab to |data|. | 339 // This code adds the URL and the title strings of the given tab to |data|. |
| 531 if (data->recently_closed_pages_.size() >= max_items) | 340 if (data->recently_closed_pages_.size() >= max_items) |
| 532 return false; | 341 return false; |
| 533 | 342 |
| 534 scoped_refptr<ShellLinkItem> link = CreateShellLink(); | 343 scoped_refptr<ShellLinkItem> link = CreateShellLink(); |
| 535 const sessions::SerializedNavigationEntry& current_navigation = | 344 const sessions::SerializedNavigationEntry& current_navigation = |
| 536 tab.navigations.at(tab.current_navigation_index); | 345 tab.navigations.at(tab.current_navigation_index); |
| 537 std::string url = current_navigation.virtual_url().spec(); | 346 std::string url = current_navigation.virtual_url().spec(); |
| 538 link->GetCommandLine()->AppendArgNative(base::UTF8ToWide(url)); | 347 link->GetCommandLine()->AppendArgNative(base::UTF8ToUTF16(url)); |
| 539 link->GetCommandLine()->AppendSwitchASCII(switches::kWinJumplistAction, | 348 link->GetCommandLine()->AppendSwitchASCII(switches::kWinJumplistAction, |
| 540 jumplist::kRecentlyClosedCategory); | 349 jumplist::kRecentlyClosedCategory); |
| 541 link->set_title(current_navigation.title()); | 350 link->set_title(current_navigation.title()); |
| 542 data->recently_closed_pages_.push_back(link); | 351 data->recently_closed_pages_.push_back(link); |
| 543 data->icon_urls_.push_back(std::make_pair(std::move(url), std::move(link))); | 352 data->icon_urls_.push_back(std::make_pair(std::move(url), std::move(link))); |
| 544 | 353 |
| 545 return true; | 354 return true; |
| 546 } | 355 } |
| 547 | 356 |
| 548 void JumpList::AddWindow(const sessions::TabRestoreService::Window& window, | 357 void JumpList::AddWindow(const sessions::TabRestoreService::Window& window, |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 661 | 470 |
| 662 base::FilePath profile_dir = profile_->GetPath(); | 471 base::FilePath profile_dir = profile_->GetPath(); |
| 663 | 472 |
| 664 // Check if incognito windows (or normal windows) are disabled by policy. | 473 // Check if incognito windows (or normal windows) are disabled by policy. |
| 665 IncognitoModePrefs::Availability incognito_availability = | 474 IncognitoModePrefs::Availability incognito_availability = |
| 666 IncognitoModePrefs::GetAvailability(profile_->GetPrefs()); | 475 IncognitoModePrefs::GetAvailability(profile_->GetPrefs()); |
| 667 | 476 |
| 668 // Post a task to update the JumpList, which consists of 1) delete old icons, | 477 // Post a task to update the JumpList, which consists of 1) delete old icons, |
| 669 // 2) create new icons, 3) notify the OS. | 478 // 2) create new icons, 3) notify the OS. |
| 670 update_jumplist_task_runner_->PostTask( | 479 update_jumplist_task_runner_->PostTask( |
| 671 FROM_HERE, base::Bind(&RunUpdateJumpList, incognito_availability, app_id_, | 480 FROM_HERE, |
| 672 profile_dir, base::RetainedRef(jumplist_data_))); | 481 base::Bind(&JumpList::RunUpdateJumpList, this, incognito_availability, |
| 482 app_id_, profile_dir, base::RetainedRef(jumplist_data_))); |
| 673 | 483 |
| 674 // Post a task to delete JumpListIcons folder as it's no longer needed. | 484 // Post a task to delete JumpListIcons folder as it's no longer needed. |
| 675 // Now we have JumpListIconsMostVisited folder and JumpListIconsRecentClosed | 485 // Now we have JumpListIconsMostVisited folder and JumpListIconsRecentClosed |
| 676 // folder instead. | 486 // folder instead. |
| 677 base::FilePath icon_dir = | 487 base::FilePath icon_dir = |
| 678 GenerateJumplistIconDirName(profile_dir, FILE_PATH_LITERAL("")); | 488 GenerateJumplistIconDirName(profile_dir, FILE_PATH_LITERAL("")); |
| 679 | 489 |
| 680 delete_jumplisticons_task_runner_->PostTask( | 490 delete_jumplisticons_task_runner_->PostTask( |
| 681 FROM_HERE, | 491 FROM_HERE, |
| 682 base::Bind(&DeleteDirectory, std::move(icon_dir), kFileDeleteLimit)); | 492 base::Bind(&DeleteDirectory, std::move(icon_dir), kFileDeleteLimit)); |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 757 break; | 567 break; |
| 758 } | 568 } |
| 759 } | 569 } |
| 760 | 570 |
| 761 data->recently_closed_pages_have_updates_ = true; | 571 data->recently_closed_pages_have_updates_ = true; |
| 762 } | 572 } |
| 763 | 573 |
| 764 // Send a query that retrieves the first favicon. | 574 // Send a query that retrieves the first favicon. |
| 765 StartLoadingFavicon(); | 575 StartLoadingFavicon(); |
| 766 } | 576 } |
| 577 |
| 578 void JumpList::CreateIconFiles(const base::FilePath& icon_dir, |
| 579 const ShellLinkItemList& item_list, |
| 580 size_t max_items) { |
| 581 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. |
| 582 SCOPED_UMA_HISTOGRAM_TIMER("WinJumplist.CreateIconFilesDuration"); |
| 583 |
| 584 for (ShellLinkItemList::const_iterator item = item_list.begin(); |
| 585 item != item_list.end() && max_items > 0; ++item, --max_items) { |
| 586 base::FilePath icon_path; |
| 587 if (CreateIconFile((*item)->icon_image(), icon_dir, &icon_path)) |
| 588 (*item)->set_icon(icon_path.value(), 0); |
| 589 } |
| 590 } |
| 591 |
| 592 void JumpList::UpdateIconFiles(const base::FilePath& icon_dir, |
| 593 const ShellLinkItemList& page_list, |
| 594 size_t slot_limit) { |
| 595 DeleteDirectoryContentAndLogRuntime(icon_dir, kFileDeleteLimit); |
| 596 |
| 597 // Create new icons only when the directory exists and is empty. |
| 598 if (base::CreateDirectory(icon_dir) && base::IsDirectoryEmpty(icon_dir)) |
| 599 CreateIconFiles(icon_dir, page_list, slot_limit); |
| 600 } |
| 601 |
| 602 bool JumpList::UpdateJumpList( |
| 603 const base::string16& app_id, |
| 604 const base::FilePath& profile_dir, |
| 605 const ShellLinkItemList& most_visited_pages, |
| 606 const ShellLinkItemList& recently_closed_pages, |
| 607 bool most_visited_pages_have_updates, |
| 608 bool recently_closed_pages_have_updates, |
| 609 IncognitoModePrefs::Availability incognito_availability) { |
| 610 if (!JumpListUpdater::IsEnabled()) |
| 611 return true; |
| 612 |
| 613 JumpListUpdater jumplist_updater(app_id); |
| 614 |
| 615 base::ElapsedTimer begin_update_timer; |
| 616 |
| 617 if (!jumplist_updater.BeginUpdate()) |
| 618 return false; |
| 619 |
| 620 // Discard this JumpList update if JumpListUpdater::BeginUpdate takes longer |
| 621 // than the maximum allowed time, as it's very likely the following update |
| 622 // steps will also take a long time. |
| 623 if (begin_update_timer.Elapsed() >= kTimeOutForJumplistUpdate) |
| 624 return false; |
| 625 |
| 626 // The default maximum number of items to display in JumpList is 10. |
| 627 // https://msdn.microsoft.com/library/windows/desktop/dd378398.aspx |
| 628 // The "Most visited" category title always takes 1 of the JumpList slots if |
| 629 // |most_visited_pages| isn't empty. |
| 630 // The "Recently closed" category title will also take 1 if |
| 631 // |recently_closed_pages| isn't empty. |
| 632 // For the remaining slots, we allocate 5/8 (i.e., 5 slots if both categories |
| 633 // present) to "most-visited" items and 3/8 (i.e., 3 slots if both categories |
| 634 // present) to "recently-closed" items, respectively. |
| 635 // Nevertheless, if there are not so many items in |recently_closed_pages|, |
| 636 // we give the remaining slots to "most-visited" items. |
| 637 |
| 638 const int kMostVisited = 50; |
| 639 const int kRecentlyClosed = 30; |
| 640 const int kTotal = kMostVisited + kRecentlyClosed; |
| 641 |
| 642 // Adjust the available jumplist slots to account for the category titles. |
| 643 size_t user_max_items_adjusted = jumplist_updater.user_max_items(); |
| 644 if (!most_visited_pages.empty()) |
| 645 --user_max_items_adjusted; |
| 646 if (!recently_closed_pages.empty()) |
| 647 --user_max_items_adjusted; |
| 648 |
| 649 size_t most_visited_items = |
| 650 MulDiv(user_max_items_adjusted, kMostVisited, kTotal); |
| 651 size_t recently_closed_items = user_max_items_adjusted - most_visited_items; |
| 652 if (recently_closed_pages.size() < recently_closed_items) { |
| 653 most_visited_items += recently_closed_items - recently_closed_pages.size(); |
| 654 recently_closed_items = recently_closed_pages.size(); |
| 655 } |
| 656 |
| 657 // Record the desired number of icons to create in this JumpList update. |
| 658 int icons_to_create = 0; |
| 659 |
| 660 // Update the icons for "Most Visisted" category of the JumpList if needed. |
| 661 if (most_visited_pages_have_updates) { |
| 662 base::FilePath icon_dir_most_visited = GenerateJumplistIconDirName( |
| 663 profile_dir, FILE_PATH_LITERAL("MostVisited")); |
| 664 |
| 665 UpdateIconFiles(icon_dir_most_visited, most_visited_pages, |
| 666 most_visited_items); |
| 667 |
| 668 icons_to_create += std::min(most_visited_pages.size(), most_visited_items); |
| 669 } |
| 670 |
| 671 // Update the icons for "Recently Closed" category of the JumpList if needed. |
| 672 if (recently_closed_pages_have_updates) { |
| 673 base::FilePath icon_dir_recent_closed = GenerateJumplistIconDirName( |
| 674 profile_dir, FILE_PATH_LITERAL("RecentClosed")); |
| 675 |
| 676 UpdateIconFiles(icon_dir_recent_closed, recently_closed_pages, |
| 677 recently_closed_items); |
| 678 |
| 679 icons_to_create += |
| 680 std::min(recently_closed_pages.size(), recently_closed_items); |
| 681 } |
| 682 |
| 683 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. |
| 684 UMA_HISTOGRAM_COUNTS_100("WinJumplist.CreateIconFilesCount", icons_to_create); |
| 685 |
| 686 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. |
| 687 SCOPED_UMA_HISTOGRAM_TIMER("WinJumplist.UpdateJumpListDuration"); |
| 688 |
| 689 // Update the "Most Visited" category of the JumpList if it exists. |
| 690 // This update request is applied into the JumpList when we commit this |
| 691 // transaction. |
| 692 if (!jumplist_updater.AddCustomCategory( |
| 693 l10n_util::GetStringUTF16(IDS_NEW_TAB_MOST_VISITED), |
| 694 most_visited_pages, most_visited_items)) { |
| 695 return false; |
| 696 } |
| 697 |
| 698 // Update the "Recently Closed" category of the JumpList. |
| 699 if (!jumplist_updater.AddCustomCategory( |
| 700 l10n_util::GetStringUTF16(IDS_RECENTLY_CLOSED), recently_closed_pages, |
| 701 recently_closed_items)) { |
| 702 return false; |
| 703 } |
| 704 |
| 705 // Update the "Tasks" category of the JumpList. |
| 706 if (!UpdateTaskCategory(&jumplist_updater, incognito_availability)) |
| 707 return false; |
| 708 |
| 709 // Commit this transaction and send the updated JumpList to Windows. |
| 710 return jumplist_updater.CommitUpdate(); |
| 711 } |
| 712 |
| 713 void JumpList::RunUpdateJumpList( |
| 714 IncognitoModePrefs::Availability incognito_availability, |
| 715 const base::string16& app_id, |
| 716 const base::FilePath& profile_dir, |
| 717 base::RefCountedData<JumpListData>* ref_counted_data) { |
| 718 JumpListData* data = &ref_counted_data->data; |
| 719 ShellLinkItemList local_most_visited_pages; |
| 720 ShellLinkItemList local_recently_closed_pages; |
| 721 bool most_visited_pages_have_updates; |
| 722 bool recently_closed_pages_have_updates; |
| 723 |
| 724 { |
| 725 base::AutoLock auto_lock(data->list_lock_); |
| 726 // Make sure we are not out of date: if icon_urls_ is not empty, then |
| 727 // another notification has been received since we processed this one |
| 728 if (!data->icon_urls_.empty()) |
| 729 return; |
| 730 |
| 731 // Make local copies of lists and flags so we can release the lock. |
| 732 local_most_visited_pages = data->most_visited_pages_; |
| 733 local_recently_closed_pages = data->recently_closed_pages_; |
| 734 |
| 735 most_visited_pages_have_updates = data->most_visited_pages_have_updates_; |
| 736 recently_closed_pages_have_updates = |
| 737 data->recently_closed_pages_have_updates_; |
| 738 |
| 739 // Clear the flags to reflect that we'll take actions on these updates. |
| 740 data->most_visited_pages_have_updates_ = false; |
| 741 data->recently_closed_pages_have_updates_ = false; |
| 742 } |
| 743 |
| 744 if (!most_visited_pages_have_updates && !recently_closed_pages_have_updates) |
| 745 return; |
| 746 |
| 747 // Update the application JumpList. If it fails, reset the flags to true if |
| 748 // they were so that the corresponding JumpList categories will be tried to |
| 749 // update again in the next run. |
| 750 if (!UpdateJumpList( |
| 751 app_id, profile_dir, local_most_visited_pages, |
| 752 local_recently_closed_pages, most_visited_pages_have_updates, |
| 753 recently_closed_pages_have_updates, incognito_availability)) { |
| 754 base::AutoLock auto_lock(data->list_lock_); |
| 755 if (most_visited_pages_have_updates) |
| 756 data->most_visited_pages_have_updates_ = true; |
| 757 if (recently_closed_pages_have_updates) |
| 758 data->recently_closed_pages_have_updates_ = true; |
| 759 } |
| 760 } |
| OLD | NEW |