| 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 "base/base_paths.h" | 7 #include "base/base_paths.h" |
| 8 #include "base/bind.h" | 8 #include "base/bind.h" |
| 9 #include "base/bind_helpers.h" | 9 #include "base/bind_helpers.h" |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 187 base::FilePath GenerateJumplistIconDirName( | 187 base::FilePath GenerateJumplistIconDirName( |
| 188 const base::FilePath& profile_dir, | 188 const base::FilePath& profile_dir, |
| 189 const base::FilePath::StringPieceType& suffix) { | 189 const base::FilePath::StringPieceType& suffix) { |
| 190 base::FilePath::StringType dir_name(chrome::kJumpListIconDirname); | 190 base::FilePath::StringType dir_name(chrome::kJumpListIconDirname); |
| 191 suffix.AppendToString(&dir_name); | 191 suffix.AppendToString(&dir_name); |
| 192 return profile_dir.Append(dir_name); | 192 return profile_dir.Append(dir_name); |
| 193 } | 193 } |
| 194 | 194 |
| 195 } // namespace | 195 } // namespace |
| 196 | 196 |
| 197 JumpList::UpdateResults::UpdateResults() {} | 197 JumpList::UpdateTransaction::UpdateTransaction() {} |
| 198 | 198 |
| 199 JumpList::UpdateResults::~UpdateResults() {} | 199 JumpList::UpdateTransaction::~UpdateTransaction() {} |
| 200 | 200 |
| 201 // static | 201 // static |
| 202 bool JumpList::Enabled() { | 202 bool JumpList::Enabled() { |
| 203 return JumpListUpdater::IsEnabled(); | 203 return JumpListUpdater::IsEnabled(); |
| 204 } | 204 } |
| 205 | 205 |
| 206 void JumpList::Shutdown() { | 206 void JumpList::Shutdown() { |
| 207 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 207 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 208 Terminate(); | 208 Terminate(); |
| 209 } | 209 } |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 299 sessions::TabRestoreService* service) {} | 299 sessions::TabRestoreService* service) {} |
| 300 | 300 |
| 301 void JumpList::OnIncognitoAvailabilityChanged() { | 301 void JumpList::OnIncognitoAvailabilityChanged() { |
| 302 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 302 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 303 | 303 |
| 304 if (icon_urls_.empty()) | 304 if (icon_urls_.empty()) |
| 305 PostRunUpdate(); | 305 PostRunUpdate(); |
| 306 } | 306 } |
| 307 | 307 |
| 308 void JumpList::InitializeTimerForUpdate() { | 308 void JumpList::InitializeTimerForUpdate() { |
| 309 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 310 |
| 309 if (timer_.IsRunning()) { | 311 if (timer_.IsRunning()) { |
| 310 timer_.Reset(); | 312 timer_.Reset(); |
| 311 } else { | 313 } else { |
| 312 // base::Unretained is safe since |this| is guaranteed to outlive timer_. | 314 // base::Unretained is safe since |this| is guaranteed to outlive timer_. |
| 313 timer_.Start(FROM_HERE, kDelayForJumplistUpdate, | 315 timer_.Start(FROM_HERE, kDelayForJumplistUpdate, |
| 314 base::Bind(&JumpList::OnDelayTimer, base::Unretained(this))); | 316 base::Bind(&JumpList::OnDelayTimer, base::Unretained(this))); |
| 315 } | 317 } |
| 316 } | 318 } |
| 317 | 319 |
| 318 void JumpList::OnDelayTimer() { | 320 void JumpList::OnDelayTimer() { |
| 319 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 321 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 322 DCHECK(!update_in_progress_); |
| 320 | 323 |
| 321 if (updates_to_skip_ > 0) { | 324 if (updates_to_skip_ > 0) { |
| 322 --updates_to_skip_; | 325 --updates_to_skip_; |
| 323 return; | 326 return; |
| 324 } | 327 } |
| 325 | 328 |
| 326 // Retrieve the recently closed URLs synchronously. | 329 // Retrieve the recently closed URLs synchronously. |
| 327 if (tab_restore_has_pending_notification_) { | 330 if (tab_restore_has_pending_notification_) { |
| 328 tab_restore_has_pending_notification_ = false; | 331 tab_restore_has_pending_notification_ = false; |
| 329 ProcessTabRestoreServiceNotification(); | 332 ProcessTabRestoreServiceNotification(); |
| 330 } | 333 } |
| 331 | 334 |
| 332 // If TopSites has updates, retrieve the URLs asynchronously, and on its | 335 // If TopSites has updates, retrieve the URLs asynchronously, and on its |
| 333 // completion, trigger favicon loading. | 336 // completion, trigger favicon loading. |
| 334 // Otherwise, call StartLoadingFavicon directly to start favicon loading. | 337 // Otherwise, call StartLoadingFavicon directly to start favicon loading. |
| 335 if (top_sites_has_pending_notification_) | 338 if (top_sites_has_pending_notification_) |
| 336 ProcessTopSitesNotification(); | 339 ProcessTopSitesNotification(); |
| 337 else | 340 else |
| 338 StartLoadingFavicon(); | 341 StartLoadingFavicon(); |
| 339 } | 342 } |
| 340 | 343 |
| 341 void JumpList::ProcessTopSitesNotification() { | 344 void JumpList::ProcessTopSitesNotification() { |
| 342 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 345 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 346 DCHECK(!update_in_progress_); |
| 343 | 347 |
| 344 // Opening the first tab in one session triggers a TopSite history sync. | 348 // Opening the first tab in one session triggers a TopSite history sync. |
| 345 // Delay this sync till the first tab is closed to allow the "recently closed" | 349 // Delay this sync till the first tab is closed to allow the "recently closed" |
| 346 // category from last session to stay longer. All previous pending | 350 // category from last session to stay longer. All previous pending |
| 347 // notifications from TopSites are ignored. | 351 // notifications from TopSites are ignored. |
| 348 if (!has_tab_closed_) { | 352 if (!has_tab_closed_) { |
| 349 top_sites_has_pending_notification_ = false; | 353 top_sites_has_pending_notification_ = false; |
| 350 return; | 354 return; |
| 351 } | 355 } |
| 352 | 356 |
| 353 scoped_refptr<history::TopSites> top_sites = | 357 scoped_refptr<history::TopSites> top_sites = |
| 354 TopSitesFactory::GetForProfile(profile_); | 358 TopSitesFactory::GetForProfile(profile_); |
| 355 if (top_sites) { | 359 if (top_sites) { |
| 356 top_sites->GetMostVisitedURLs( | 360 top_sites->GetMostVisitedURLs( |
| 357 base::Bind(&JumpList::OnMostVisitedURLsAvailable, | 361 base::Bind(&JumpList::OnMostVisitedURLsAvailable, |
| 358 weak_ptr_factory_.GetWeakPtr()), | 362 weak_ptr_factory_.GetWeakPtr()), |
| 359 false); | 363 false); |
| 360 } | 364 } |
| 361 } | 365 } |
| 362 | 366 |
| 363 void JumpList::ProcessTabRestoreServiceNotification() { | 367 void JumpList::ProcessTabRestoreServiceNotification() { |
| 364 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 368 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 369 DCHECK(!update_in_progress_); |
| 365 | 370 |
| 366 // Create a list of ShellLinkItems from the "Recently Closed" pages. | 371 // Create a list of ShellLinkItems from the "Recently Closed" pages. |
| 367 // As noted above, we create a ShellLinkItem objects with the following | 372 // As noted above, we create a ShellLinkItem objects with the following |
| 368 // parameters. | 373 // parameters. |
| 369 // * arguments | 374 // * arguments |
| 370 // The last URL of the tab object. | 375 // The last URL of the tab object. |
| 371 // * title | 376 // * title |
| 372 // The title of the last URL. | 377 // The title of the last URL. |
| 373 // * icon | 378 // * icon |
| 374 // An empty string. This value is to be updated in OnFaviconDataAvailable(). | 379 // An empty string. This value is to be updated in OnFaviconDataAvailable(). |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 542 TRACE_EVENT0("browser", "JumpList::PostRunUpdate"); | 547 TRACE_EVENT0("browser", "JumpList::PostRunUpdate"); |
| 543 | 548 |
| 544 update_in_progress_ = true; | 549 update_in_progress_ = true; |
| 545 | 550 |
| 546 base::FilePath profile_dir = profile_->GetPath(); | 551 base::FilePath profile_dir = profile_->GetPath(); |
| 547 | 552 |
| 548 // Check if incognito windows (or normal windows) are disabled by policy. | 553 // Check if incognito windows (or normal windows) are disabled by policy. |
| 549 IncognitoModePrefs::Availability incognito_availability = | 554 IncognitoModePrefs::Availability incognito_availability = |
| 550 IncognitoModePrefs::GetAvailability(profile_->GetPrefs()); | 555 IncognitoModePrefs::GetAvailability(profile_->GetPrefs()); |
| 551 | 556 |
| 552 // Make local copies of JumpList member variables and use them for an update. | 557 auto update_transaction = base::MakeUnique<UpdateTransaction>(); |
| 553 ShellLinkItemList local_most_visited_pages = most_visited_pages_; | 558 if (most_visited_should_update_) |
| 554 ShellLinkItemList local_recently_closed_pages = recently_closed_pages_; | 559 update_transaction->most_visited_icons = std::move(most_visited_icons_); |
| 560 if (recently_closed_should_update_) { |
| 561 update_transaction->recently_closed_icons = |
| 562 std::move(recently_closed_icons_); |
| 563 } |
| 555 | 564 |
| 556 bool most_visited_should_update = most_visited_should_update_; | 565 // Parameter evaluation order is unspecified in C++. Do the first bind and |
| 557 bool recently_closed_should_update = recently_closed_should_update_; | 566 // then move it into PostTaskAndReply to ensure the pointer value is obtained |
| 558 | 567 // before base::Passed() is called. |
| 559 auto update_results = base::MakeUnique<UpdateResults>(); | 568 auto run_update = |
| 560 update_results->most_visited_icons_in_update = most_visited_icons_; | 569 base::Bind(&JumpList::RunUpdateJumpList, app_id_, profile_dir, |
| 561 update_results->recently_closed_icons_in_update = recently_closed_icons_; | 570 most_visited_pages_, recently_closed_pages_, |
| 562 | 571 most_visited_should_update_, recently_closed_should_update_, |
| 563 // Parameter evaluation order is unspecified in C++. Ensure the pointer value | 572 incognito_availability, update_transaction.get()); |
| 564 // is obtained before base::Passed() is called. | |
| 565 auto* update_results_raw = update_results.get(); | |
| 566 | 573 |
| 567 // Post a task to update the JumpList, which consists of 1) create new icons, | 574 // Post a task to update the JumpList, which consists of 1) create new icons, |
| 568 // 2) delete old icons, 3) notify the OS. | 575 // 2) notify the OS, 3) delete old icons. |
| 569 if (!update_jumplist_task_runner_->PostTaskAndReply( | 576 if (!update_jumplist_task_runner_->PostTaskAndReply( |
| 570 FROM_HERE, | 577 FROM_HERE, std::move(run_update), |
| 571 base::Bind(&JumpList::RunUpdateJumpList, app_id_, profile_dir, | |
| 572 local_most_visited_pages, local_recently_closed_pages, | |
| 573 most_visited_should_update, recently_closed_should_update, | |
| 574 incognito_availability, update_results_raw), | |
| 575 base::Bind(&JumpList::OnRunUpdateCompletion, | 578 base::Bind(&JumpList::OnRunUpdateCompletion, |
| 576 weak_ptr_factory_.GetWeakPtr(), | 579 weak_ptr_factory_.GetWeakPtr(), |
| 577 base::Passed(std::move(update_results))))) { | 580 base::Passed(std::move(update_transaction))))) { |
| 578 OnRunUpdateCompletion(base::MakeUnique<UpdateResults>()); | 581 OnRunUpdateCompletion(base::MakeUnique<UpdateTransaction>()); |
| 579 } | 582 } |
| 580 } | 583 } |
| 581 | 584 |
| 582 void JumpList::OnRunUpdateCompletion( | 585 void JumpList::OnRunUpdateCompletion( |
| 583 std::unique_ptr<UpdateResults> update_results) { | 586 std::unique_ptr<UpdateTransaction> update_transaction) { |
| 584 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 587 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 585 | 588 |
| 586 // Update JumpList member variables based on the results from the update run | 589 // Update JumpList member variables based on the results from the update run |
| 587 // just finished. | 590 // just finished. |
| 588 if (update_results->update_timeout) | 591 if (update_transaction->update_timeout) |
| 589 updates_to_skip_ = kUpdatesToSkipUnderHeavyLoad; | 592 updates_to_skip_ = kUpdatesToSkipUnderHeavyLoad; |
| 590 | 593 |
| 591 if (update_results->update_success) { | 594 if (update_transaction->update_success) { |
| 592 most_visited_icons_.swap(update_results->most_visited_icons_in_update); | 595 if (most_visited_should_update_) { |
| 593 recently_closed_icons_.swap( | 596 most_visited_icons_ = std::move(update_transaction->most_visited_icons); |
| 594 update_results->recently_closed_icons_in_update); | 597 most_visited_should_update_ = false; |
| 595 most_visited_should_update_ = false; | 598 } |
| 596 recently_closed_should_update_ = false; | 599 if (recently_closed_should_update_) { |
| 600 recently_closed_icons_ = |
| 601 std::move(update_transaction->recently_closed_icons); |
| 602 recently_closed_should_update_ = false; |
| 603 } |
| 597 } | 604 } |
| 598 | 605 |
| 599 update_in_progress_ = false; | 606 update_in_progress_ = false; |
| 600 | 607 |
| 601 // If there is any new notification during the update run just finished, start | 608 // If there is any new notification during the update run just finished, start |
| 602 // another JumpList update. | 609 // another JumpList update. |
| 603 // Otherwise, post tasks to delete the JumpListIcons and JumpListIconsOld | 610 // Otherwise, post tasks to delete the JumpListIcons and JumpListIconsOld |
| 604 // folders as they are no longer needed. Now we have the | 611 // folders as they are no longer needed. Now we have the |
| 605 // JumpListIcons{MostVisited, RecentClosed} folders instead. | 612 // JumpListIcons{MostVisited, RecentClosed} folders instead. |
| 606 if (top_sites_has_pending_notification_ || | 613 if (top_sites_has_pending_notification_ || |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 656 | 663 |
| 657 // static | 664 // static |
| 658 void JumpList::RunUpdateJumpList( | 665 void JumpList::RunUpdateJumpList( |
| 659 const base::string16& app_id, | 666 const base::string16& app_id, |
| 660 const base::FilePath& profile_dir, | 667 const base::FilePath& profile_dir, |
| 661 const ShellLinkItemList& most_visited_pages, | 668 const ShellLinkItemList& most_visited_pages, |
| 662 const ShellLinkItemList& recently_closed_pages, | 669 const ShellLinkItemList& recently_closed_pages, |
| 663 bool most_visited_should_update, | 670 bool most_visited_should_update, |
| 664 bool recently_closed_should_update, | 671 bool recently_closed_should_update, |
| 665 IncognitoModePrefs::Availability incognito_availability, | 672 IncognitoModePrefs::Availability incognito_availability, |
| 666 UpdateResults* update_results) { | 673 UpdateTransaction* update_transaction) { |
| 667 if (!JumpListUpdater::IsEnabled()) | 674 if (!JumpListUpdater::IsEnabled()) |
| 668 return; | 675 return; |
| 669 | 676 |
| 670 DCHECK(update_results); | 677 DCHECK(update_transaction); |
| 678 |
| 679 base::FilePath most_visited_icon_dir = GenerateJumplistIconDirName( |
| 680 profile_dir, FILE_PATH_LITERAL("MostVisited")); |
| 681 base::FilePath recently_closed_icon_dir = GenerateJumplistIconDirName( |
| 682 profile_dir, FILE_PATH_LITERAL("RecentClosed")); |
| 683 |
| 684 CreateNewJumpListAndNotifyOS( |
| 685 app_id, most_visited_icon_dir, recently_closed_icon_dir, |
| 686 most_visited_pages, recently_closed_pages, most_visited_should_update, |
| 687 recently_closed_should_update, incognito_availability, |
| 688 update_transaction); |
| 689 |
| 690 // Delete any obsolete icon files. |
| 691 if (most_visited_should_update) { |
| 692 DeleteIconFiles(most_visited_icon_dir, |
| 693 update_transaction->most_visited_icons); |
| 694 } |
| 695 if (recently_closed_should_update) { |
| 696 DeleteIconFiles(recently_closed_icon_dir, |
| 697 update_transaction->recently_closed_icons); |
| 698 } |
| 699 } |
| 700 |
| 701 // static |
| 702 void JumpList::CreateNewJumpListAndNotifyOS( |
| 703 const base::string16& app_id, |
| 704 const base::FilePath& most_visited_icon_dir, |
| 705 const base::FilePath& recently_closed_icon_dir, |
| 706 const ShellLinkItemList& most_visited_pages, |
| 707 const ShellLinkItemList& recently_closed_pages, |
| 708 bool most_visited_should_update, |
| 709 bool recently_closed_should_update, |
| 710 IncognitoModePrefs::Availability incognito_availability, |
| 711 UpdateTransaction* update_transaction) { |
| 712 DCHECK(update_transaction); |
| 671 | 713 |
| 672 JumpListUpdater jumplist_updater(app_id); | 714 JumpListUpdater jumplist_updater(app_id); |
| 673 | 715 |
| 674 base::ElapsedTimer begin_update_timer; | 716 base::ElapsedTimer begin_update_timer; |
| 675 | 717 |
| 676 if (!jumplist_updater.BeginUpdate()) | 718 if (!jumplist_updater.BeginUpdate()) |
| 677 return; | 719 return; |
| 678 | 720 |
| 679 // Discard this JumpList update if JumpListUpdater::BeginUpdate takes longer | 721 // Discard this JumpList update if JumpListUpdater::BeginUpdate takes longer |
| 680 // than the maximum allowed time, as it's very likely the following update | 722 // than the maximum allowed time, as it's very likely the following update |
| 681 // steps will also take a long time. As we've not updated the icons on the | 723 // steps will also take a long time. |
| 682 // disk, discarding this update wont't affect the current JumpList used by OS. | |
| 683 if (begin_update_timer.Elapsed() >= kTimeOutForJumplistBeginUpdate) { | 724 if (begin_update_timer.Elapsed() >= kTimeOutForJumplistBeginUpdate) { |
| 684 update_results->update_timeout = true; | 725 update_transaction->update_timeout = true; |
| 685 return; | 726 return; |
| 686 } | 727 } |
| 687 | 728 |
| 688 // Record the desired number of icons created in this JumpList update. | 729 // Record the desired number of icons created in this JumpList update. |
| 689 int icons_created = 0; | 730 int icons_created = 0; |
| 690 | 731 |
| 732 URLIconCache most_visited_icons_next; |
| 733 URLIconCache recently_closed_icons_next; |
| 734 |
| 691 // Update the icons for "Most Visisted" category of the JumpList if needed. | 735 // Update the icons for "Most Visisted" category of the JumpList if needed. |
| 692 if (most_visited_should_update) { | 736 if (most_visited_should_update) { |
| 693 base::FilePath icon_dir_most_visited = GenerateJumplistIconDirName( | |
| 694 profile_dir, FILE_PATH_LITERAL("MostVisited")); | |
| 695 | |
| 696 icons_created += UpdateIconFiles( | 737 icons_created += UpdateIconFiles( |
| 697 icon_dir_most_visited, most_visited_pages, kMostVisitedItems, | 738 most_visited_icon_dir, most_visited_pages, kMostVisitedItems, |
| 698 &update_results->most_visited_icons_in_update); | 739 &update_transaction->most_visited_icons, &most_visited_icons_next); |
| 699 } | 740 } |
| 700 | 741 |
| 701 // Update the icons for "Recently Closed" category of the JumpList if needed. | 742 // Update the icons for "Recently Closed" category of the JumpList if needed. |
| 702 if (recently_closed_should_update) { | 743 if (recently_closed_should_update) { |
| 703 base::FilePath icon_dir_recent_closed = GenerateJumplistIconDirName( | |
| 704 profile_dir, FILE_PATH_LITERAL("RecentClosed")); | |
| 705 | |
| 706 icons_created += UpdateIconFiles( | 744 icons_created += UpdateIconFiles( |
| 707 icon_dir_recent_closed, recently_closed_pages, kRecentlyClosedItems, | 745 recently_closed_icon_dir, recently_closed_pages, kRecentlyClosedItems, |
| 708 &update_results->recently_closed_icons_in_update); | 746 &update_transaction->recently_closed_icons, |
| 747 &recently_closed_icons_next); |
| 709 } | 748 } |
| 710 | 749 |
| 711 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. | 750 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. |
| 712 UMA_HISTOGRAM_COUNTS_100("WinJumplist.CreateIconFilesCount", icons_created); | 751 UMA_HISTOGRAM_COUNTS_100("WinJumplist.CreateIconFilesCount", icons_created); |
| 713 | 752 |
| 714 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. | 753 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. |
| 715 SCOPED_UMA_HISTOGRAM_TIMER("WinJumplist.UpdateJumpListDuration"); | 754 SCOPED_UMA_HISTOGRAM_TIMER("WinJumplist.UpdateJumpListDuration"); |
| 716 | 755 |
| 717 base::ElapsedTimer add_custom_category_timer; | 756 base::ElapsedTimer add_custom_category_timer; |
| 718 | 757 |
| 719 // Update the "Most Visited" category of the JumpList if it exists. | 758 // Update the "Most Visited" category of the JumpList if it exists. |
| 720 // This update request is applied into the JumpList when we commit this | 759 // This update request is applied into the JumpList when we commit this |
| 721 // transaction. | 760 // transaction. |
| 722 if (!jumplist_updater.AddCustomCategory( | 761 if (!jumplist_updater.AddCustomCategory( |
| 723 l10n_util::GetStringUTF16(IDS_NEW_TAB_MOST_VISITED), | 762 l10n_util::GetStringUTF16(IDS_NEW_TAB_MOST_VISITED), |
| 724 most_visited_pages, kMostVisitedItems)) { | 763 most_visited_pages, kMostVisitedItems)) { |
| 725 return; | 764 return; |
| 726 } | 765 } |
| 727 | 766 |
| 728 // Update the "Recently Closed" category of the JumpList. | 767 // Update the "Recently Closed" category of the JumpList. |
| 729 if (!jumplist_updater.AddCustomCategory( | 768 if (!jumplist_updater.AddCustomCategory( |
| 730 l10n_util::GetStringUTF16(IDS_RECENTLY_CLOSED), recently_closed_pages, | 769 l10n_util::GetStringUTF16(IDS_RECENTLY_CLOSED), recently_closed_pages, |
| 731 kRecentlyClosedItems)) { | 770 kRecentlyClosedItems)) { |
| 732 return; | 771 return; |
| 733 } | 772 } |
| 734 | 773 |
| 735 // If JumpListUpdater::AddCustomCategory or JumpListUpdater::CommitUpdate | 774 // If AddCustomCategory takes longer than the maximum allowed time, abort the |
| 736 // takes longer than the maximum allowed time, skip the next | 775 // current update and skip the next |kUpdatesToSkipUnderHeavyLoad| updates. |
| 737 // |kUpdatesToSkipUnderHeavyLoad| updates. This update should be finished | 776 if (add_custom_category_timer.Elapsed() >= kTimeOutForAddCustomCategory) { |
| 738 // because we've already updated the icons on the disk. If discarding this | 777 update_transaction->update_timeout = true; |
| 739 // update from here, some items in the current JumpList may not have icons | 778 return; |
| 740 // as they've been delete from the disk. In this case, the background color of | 779 } |
| 741 // the JumpList panel is used instead, which doesn't look nice. | |
| 742 | |
| 743 if (add_custom_category_timer.Elapsed() >= kTimeOutForAddCustomCategory) | |
| 744 update_results->update_timeout = true; | |
| 745 | 780 |
| 746 // Update the "Tasks" category of the JumpList. | 781 // Update the "Tasks" category of the JumpList. |
| 747 if (!UpdateTaskCategory(&jumplist_updater, incognito_availability)) | 782 if (!UpdateTaskCategory(&jumplist_updater, incognito_availability)) |
| 748 return; | 783 return; |
| 749 | 784 |
| 750 base::ElapsedTimer commit_update_timer; | 785 base::ElapsedTimer commit_update_timer; |
| 751 | 786 |
| 752 // Commit this transaction and send the updated JumpList to Windows. | 787 // Commit this transaction and send the updated JumpList to Windows. |
| 753 if (jumplist_updater.CommitUpdate()) | 788 bool commit_success = jumplist_updater.CommitUpdate(); |
| 754 update_results->update_success = true; | |
| 755 | 789 |
| 790 // If CommitUpdate call takes longer than the maximum allowed time, skip the |
| 791 // next |kUpdatesToSkipUnderHeavyLoad| updates. |
| 756 if (commit_update_timer.Elapsed() >= kTimeOutForJumplistCommitUpdate) | 792 if (commit_update_timer.Elapsed() >= kTimeOutForJumplistCommitUpdate) |
| 757 update_results->update_timeout = true; | 793 update_transaction->update_timeout = true; |
| 794 |
| 795 if (commit_success) { |
| 796 update_transaction->update_success = true; |
| 797 |
| 798 // The move assignments below ensure update_transaction always has the icons |
| 799 // to keep. |
| 800 if (most_visited_should_update) { |
| 801 update_transaction->most_visited_icons = |
| 802 std::move(most_visited_icons_next); |
| 803 } |
| 804 if (recently_closed_should_update) { |
| 805 update_transaction->recently_closed_icons = |
| 806 std::move(recently_closed_icons_next); |
| 807 } |
| 808 } |
| 758 } | 809 } |
| 759 | 810 |
| 760 // static | 811 // static |
| 761 int JumpList::UpdateIconFiles(const base::FilePath& icon_dir, | 812 int JumpList::UpdateIconFiles(const base::FilePath& icon_dir, |
| 762 const ShellLinkItemList& page_list, | 813 const ShellLinkItemList& item_list, |
| 763 size_t slot_limit, | 814 size_t max_items, |
| 764 URLIconCache* icon_cache) { | 815 URLIconCache* icon_cur, |
| 816 URLIconCache* icon_next) { |
| 817 DCHECK(icon_cur); |
| 818 DCHECK(icon_next); |
| 819 |
| 820 // Clear the JumpList icon folder at |icon_dir| and the caches when |
| 821 // 1) |icon_cur| is empty. This happens when "Most visited" or "Recently |
| 822 // closed" category updates for the 1st time after Chrome is launched. |
| 823 // 2) The number of icons in |icon_dir| has exceeded the limit. |
| 824 if (icon_cur->empty() || FilesExceedLimitInDir(icon_dir, max_items * 2)) { |
| 825 DeleteDirectoryContentAndLogRuntime(icon_dir, kFileDeleteLimit); |
| 826 icon_cur->clear(); |
| 827 icon_next->clear(); |
| 828 // Create new icons only when the directory exists and is empty. |
| 829 if (!base::CreateDirectory(icon_dir) || !base::IsDirectoryEmpty(icon_dir)) |
| 830 return 0; |
| 831 } else if (!base::CreateDirectory(icon_dir)) { |
| 832 return 0; |
| 833 } |
| 834 |
| 835 return CreateIconFiles(icon_dir, item_list, max_items, *icon_cur, icon_next); |
| 836 } |
| 837 |
| 838 // static |
| 839 int JumpList::CreateIconFiles(const base::FilePath& icon_dir, |
| 840 const ShellLinkItemList& item_list, |
| 841 size_t max_items, |
| 842 const URLIconCache& icon_cur, |
| 843 URLIconCache* icon_next) { |
| 844 DCHECK(icon_next); |
| 845 |
| 846 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. |
| 847 SCOPED_UMA_HISTOGRAM_TIMER("WinJumplist.CreateIconFilesDuration"); |
| 848 |
| 765 int icons_created = 0; | 849 int icons_created = 0; |
| 766 | 850 |
| 767 // Clear the JumpList icon folder at |icon_dir| and the cache when | 851 // Reuse icons for urls that already present in the current JumpList. |
| 768 // 1) |icon_cache| is empty. This happens when "Most visited" or "Recently | 852 for (ShellLinkItemList::const_iterator iter = item_list.begin(); |
| 769 // closed" category updates for the 1st time after Chrome is launched. | 853 iter != item_list.end() && max_items > 0; ++iter, --max_items) { |
| 770 // 2) The number of icons in |icon_dir| has exceeded the limit. | 854 ShellLinkItem* item = iter->get(); |
| 771 if (icon_cache->empty() || FilesExceedLimitInDir(icon_dir, slot_limit * 2)) { | 855 auto cache_iter = icon_cur.find(item->url()); |
| 772 DeleteDirectoryContentAndLogRuntime(icon_dir, kFileDeleteLimit); | 856 if (cache_iter != icon_cur.end()) { |
| 773 icon_cache->clear(); | 857 item->set_icon(cache_iter->second.value(), 0); |
| 774 // Create new icons only when the directory exists and is empty. | 858 (*icon_next)[item->url()] = cache_iter->second; |
| 775 if (base::CreateDirectory(icon_dir) && base::IsDirectoryEmpty(icon_dir)) | 859 } else { |
| 776 icons_created += | 860 base::FilePath icon_path; |
| 777 CreateIconFiles(icon_dir, page_list, slot_limit, icon_cache); | 861 if (CreateIconFile(item->icon_image(), icon_dir, &icon_path)) { |
| 778 } else if (base::CreateDirectory(icon_dir)) { | 862 ++icons_created; |
| 779 icons_created += | 863 item->set_icon(icon_path.value(), 0); |
| 780 CreateIconFiles(icon_dir, page_list, slot_limit, icon_cache); | 864 (*icon_next)[item->url()] = icon_path; |
| 781 DeleteIconFiles(icon_dir, icon_cache); | 865 } |
| 866 } |
| 782 } | 867 } |
| 783 | 868 |
| 784 return icons_created; | 869 return icons_created; |
| 785 } | 870 } |
| 786 | 871 |
| 787 // static | 872 // static |
| 788 int JumpList::CreateIconFiles(const base::FilePath& icon_dir, | |
| 789 const ShellLinkItemList& item_list, | |
| 790 size_t max_items, | |
| 791 URLIconCache* icon_cache) { | |
| 792 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. | |
| 793 SCOPED_UMA_HISTOGRAM_TIMER("WinJumplist.CreateIconFilesDuration"); | |
| 794 | |
| 795 int icons_created = 0; | |
| 796 | |
| 797 // Reuse icons for urls that already present in the current JumpList. | |
| 798 URLIconCache updated_map; | |
| 799 for (ShellLinkItemList::const_iterator iter = item_list.begin(); | |
| 800 iter != item_list.end() && max_items > 0; ++iter, --max_items) { | |
| 801 ShellLinkItem* item = iter->get(); | |
| 802 auto cache_iter = icon_cache->find(item->url()); | |
| 803 if (cache_iter != icon_cache->end()) { | |
| 804 item->set_icon(cache_iter->second.value(), 0); | |
| 805 updated_map[item->url()] = cache_iter->second; | |
| 806 } else { | |
| 807 base::FilePath icon_path; | |
| 808 if (CreateIconFile(item->icon_image(), icon_dir, &icon_path)) { | |
| 809 ++icons_created; | |
| 810 item->set_icon(icon_path.value(), 0); | |
| 811 updated_map[item->url()] = icon_path; | |
| 812 } | |
| 813 } | |
| 814 } | |
| 815 icon_cache->swap(updated_map); | |
| 816 | |
| 817 return icons_created; | |
| 818 } | |
| 819 | |
| 820 // static | |
| 821 void JumpList::DeleteIconFiles(const base::FilePath& icon_dir, | 873 void JumpList::DeleteIconFiles(const base::FilePath& icon_dir, |
| 822 URLIconCache* icon_cache) { | 874 const URLIconCache& icons_cache) { |
| 823 // Put all cached icon file paths into a set. | 875 // Put all cached icon file paths into a set. |
| 824 base::flat_set<base::FilePath> cached_files; | 876 base::flat_set<base::FilePath> cached_files; |
| 825 cached_files.reserve(icon_cache->size()); | 877 cached_files.reserve(icons_cache.size()); |
| 826 | 878 |
| 827 for (const auto& url_path_pair : *icon_cache) | 879 for (const auto& url_path_pair : icons_cache) |
| 828 cached_files.insert(url_path_pair.second); | 880 cached_files.insert(url_path_pair.second); |
| 829 | 881 |
| 830 DeleteNonCachedFiles(icon_dir, cached_files); | 882 DeleteNonCachedFiles(icon_dir, cached_files); |
| 831 } | 883 } |
| OLD | NEW |