| 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 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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::UpdateResults::UpdateResults() {} |
| 198 | 198 |
| 199 JumpList::UpdateResults::~UpdateResults() {} | 199 JumpList::UpdateResults::~UpdateResults() {} |
| 200 | 200 |
| 201 // static |
| 202 bool JumpList::Enabled() { |
| 203 return JumpListUpdater::IsEnabled(); |
| 204 } |
| 205 |
| 206 void JumpList::Shutdown() { |
| 207 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 208 Terminate(); |
| 209 } |
| 210 |
| 201 JumpList::JumpList(Profile* profile) | 211 JumpList::JumpList(Profile* profile) |
| 202 : profile_(profile), | 212 : profile_(profile), |
| 203 update_jumplist_task_runner_(base::CreateCOMSTATaskRunnerWithTraits( | 213 update_jumplist_task_runner_(base::CreateCOMSTATaskRunnerWithTraits( |
| 204 {base::MayBlock(), base::TaskPriority::USER_VISIBLE, | 214 {base::MayBlock(), base::TaskPriority::USER_VISIBLE, |
| 205 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})), | 215 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})), |
| 206 delete_jumplisticons_task_runner_( | 216 delete_jumplisticons_task_runner_( |
| 207 base::CreateSequencedTaskRunnerWithTraits( | 217 base::CreateSequencedTaskRunnerWithTraits( |
| 208 {base::MayBlock(), base::TaskPriority::BACKGROUND, | 218 {base::MayBlock(), base::TaskPriority::BACKGROUND, |
| 209 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})), | 219 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})), |
| 210 weak_ptr_factory_(this) { | 220 weak_ptr_factory_(this) { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 243 prefs::kIncognitoModeAvailability, | 253 prefs::kIncognitoModeAvailability, |
| 244 base::Bind(&JumpList::OnIncognitoAvailabilityChanged, | 254 base::Bind(&JumpList::OnIncognitoAvailabilityChanged, |
| 245 base::Unretained(this))); | 255 base::Unretained(this))); |
| 246 } | 256 } |
| 247 | 257 |
| 248 JumpList::~JumpList() { | 258 JumpList::~JumpList() { |
| 249 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 259 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 250 Terminate(); | 260 Terminate(); |
| 251 } | 261 } |
| 252 | 262 |
| 253 // static | 263 void JumpList::TopSitesLoaded(history::TopSites* top_sites) {} |
| 254 bool JumpList::Enabled() { | 264 |
| 255 return JumpListUpdater::IsEnabled(); | 265 void JumpList::TopSitesChanged(history::TopSites* top_sites, |
| 266 ChangeReason change_reason) { |
| 267 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 268 |
| 269 top_sites_has_pending_notification_ = true; |
| 270 |
| 271 // Postpone handling this notification until a pending update completes. |
| 272 if (update_in_progress_) |
| 273 return; |
| 274 |
| 275 // If we have a pending favicon request, cancel it here as it's out of date. |
| 276 CancelPendingUpdate(); |
| 277 |
| 278 // Initialize the one-shot timer to update the JumpList in a while. |
| 279 InitializeTimerForUpdate(); |
| 256 } | 280 } |
| 257 | 281 |
| 258 void JumpList::CancelPendingUpdate() { | 282 void JumpList::TabRestoreServiceChanged(sessions::TabRestoreService* service) { |
| 259 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 283 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 260 | 284 |
| 261 // Cancel a pending most-visited URL fetch by invalidating the weak pointer. | 285 tab_restore_has_pending_notification_ = true; |
| 262 weak_ptr_factory_.InvalidateWeakPtrs(); | |
| 263 | 286 |
| 264 // Cancel a pending favicon loading by invalidating its task id. | 287 // Postpone handling this notification until a pending update completes. |
| 265 if (task_id_ != base::CancelableTaskTracker::kBadTaskId) { | 288 if (update_in_progress_) |
| 266 cancelable_task_tracker_.TryCancel(task_id_); | 289 return; |
| 267 task_id_ = base::CancelableTaskTracker::kBadTaskId; | 290 |
| 291 // if we have a pending favicon request, cancel it here as it's out of date. |
| 292 CancelPendingUpdate(); |
| 293 |
| 294 // Initialize the one-shot timer to update the JumpList in a while. |
| 295 InitializeTimerForUpdate(); |
| 296 } |
| 297 |
| 298 void JumpList::TabRestoreServiceDestroyed( |
| 299 sessions::TabRestoreService* service) {} |
| 300 |
| 301 void JumpList::OnIncognitoAvailabilityChanged() { |
| 302 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 303 |
| 304 if (icon_urls_.empty()) |
| 305 PostRunUpdate(); |
| 306 } |
| 307 |
| 308 void JumpList::InitializeTimerForUpdate() { |
| 309 if (timer_.IsRunning()) { |
| 310 timer_.Reset(); |
| 311 } else { |
| 312 // base::Unretained is safe since |this| is guaranteed to outlive timer_. |
| 313 timer_.Start(FROM_HERE, kDelayForJumplistUpdate, |
| 314 base::Bind(&JumpList::OnDelayTimer, base::Unretained(this))); |
| 268 } | 315 } |
| 269 } | 316 } |
| 270 | 317 |
| 271 void JumpList::Terminate() { | 318 void JumpList::OnDelayTimer() { |
| 272 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 319 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 273 timer_.Stop(); | 320 |
| 274 CancelPendingUpdate(); | 321 if (updates_to_skip_ > 0) { |
| 275 update_in_progress_ = false; | 322 --updates_to_skip_; |
| 276 if (profile_) { | 323 return; |
| 277 sessions::TabRestoreService* tab_restore_service = | 324 } |
| 278 TabRestoreServiceFactory::GetForProfile(profile_); | 325 |
| 279 if (tab_restore_service) | 326 // Retrieve the recently closed URLs synchronously. |
| 280 tab_restore_service->RemoveObserver(this); | 327 if (tab_restore_has_pending_notification_) { |
| 328 tab_restore_has_pending_notification_ = false; |
| 329 ProcessTabRestoreServiceNotification(); |
| 330 } |
| 331 |
| 332 // If TopSites has updates, retrieve the URLs asynchronously, and on its |
| 333 // completion, trigger favicon loading. |
| 334 // Otherwise, call StartLoadingFavicon directly to start favicon loading. |
| 335 if (top_sites_has_pending_notification_) |
| 336 ProcessTopSitesNotification(); |
| 337 else |
| 338 StartLoadingFavicon(); |
| 339 } |
| 340 |
| 341 void JumpList::ProcessTopSitesNotification() { |
| 342 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 343 |
| 344 // 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" |
| 346 // category from last session to stay longer. All previous pending |
| 347 // notifications from TopSites are ignored. |
| 348 if (!has_tab_closed_) { |
| 349 top_sites_has_pending_notification_ = false; |
| 350 return; |
| 351 } |
| 352 |
| 353 scoped_refptr<history::TopSites> top_sites = |
| 354 TopSitesFactory::GetForProfile(profile_); |
| 355 if (top_sites) { |
| 356 top_sites->GetMostVisitedURLs( |
| 357 base::Bind(&JumpList::OnMostVisitedURLsAvailable, |
| 358 weak_ptr_factory_.GetWeakPtr()), |
| 359 false); |
| 360 } |
| 361 } |
| 362 |
| 363 void JumpList::ProcessTabRestoreServiceNotification() { |
| 364 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 365 |
| 366 // Create a list of ShellLinkItems from the "Recently Closed" pages. |
| 367 // As noted above, we create a ShellLinkItem objects with the following |
| 368 // parameters. |
| 369 // * arguments |
| 370 // The last URL of the tab object. |
| 371 // * title |
| 372 // The title of the last URL. |
| 373 // * icon |
| 374 // An empty string. This value is to be updated in OnFaviconDataAvailable(). |
| 375 |
| 376 sessions::TabRestoreService* tab_restore_service = |
| 377 TabRestoreServiceFactory::GetForProfile(profile_); |
| 378 |
| 379 recently_closed_pages_.clear(); |
| 380 |
| 381 for (const auto& entry : tab_restore_service->entries()) { |
| 382 if (recently_closed_pages_.size() >= kRecentlyClosedItems) |
| 383 break; |
| 384 switch (entry->type) { |
| 385 case sessions::TabRestoreService::TAB: |
| 386 AddTab(static_cast<const sessions::TabRestoreService::Tab&>(*entry), |
| 387 kRecentlyClosedItems); |
| 388 break; |
| 389 case sessions::TabRestoreService::WINDOW: |
| 390 AddWindow( |
| 391 static_cast<const sessions::TabRestoreService::Window&>(*entry), |
| 392 kRecentlyClosedItems); |
| 393 break; |
| 394 } |
| 395 } |
| 396 |
| 397 recently_closed_should_update_ = true; |
| 398 |
| 399 // Force a TopSite history sync when closing a first tab in one session. |
| 400 if (!has_tab_closed_) { |
| 401 has_tab_closed_ = true; |
| 281 scoped_refptr<history::TopSites> top_sites = | 402 scoped_refptr<history::TopSites> top_sites = |
| 282 TopSitesFactory::GetForProfile(profile_); | 403 TopSitesFactory::GetForProfile(profile_); |
| 283 if (top_sites) | 404 if (top_sites) |
| 284 top_sites->RemoveObserver(this); | 405 top_sites->SyncWithHistory(); |
| 285 pref_change_registrar_.reset(); | |
| 286 } | 406 } |
| 287 profile_ = nullptr; | |
| 288 } | |
| 289 | |
| 290 void JumpList::Shutdown() { | |
| 291 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | |
| 292 Terminate(); | |
| 293 } | 407 } |
| 294 | 408 |
| 295 void JumpList::OnMostVisitedURLsAvailable( | 409 void JumpList::OnMostVisitedURLsAvailable( |
| 296 const history::MostVisitedURLList& urls) { | 410 const history::MostVisitedURLList& urls) { |
| 297 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 411 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 298 | 412 |
| 299 top_sites_has_pending_notification_ = false; | 413 top_sites_has_pending_notification_ = false; |
| 300 | 414 |
| 301 // There is no need to update the JumpList if the top most visited sites in | 415 // There is no need to update the JumpList if the top most visited sites in |
| 302 // display have not changed. | 416 // display have not changed. |
| (...skipping 16 matching lines...) Expand all Loading... |
| 319 most_visited_pages_.push_back(link); | 433 most_visited_pages_.push_back(link); |
| 320 icon_urls_.emplace_back(std::move(url_string), std::move(link)); | 434 icon_urls_.emplace_back(std::move(url_string), std::move(link)); |
| 321 } | 435 } |
| 322 | 436 |
| 323 most_visited_should_update_ = true; | 437 most_visited_should_update_ = true; |
| 324 | 438 |
| 325 // Send a query that retrieves the first favicon. | 439 // Send a query that retrieves the first favicon. |
| 326 StartLoadingFavicon(); | 440 StartLoadingFavicon(); |
| 327 } | 441 } |
| 328 | 442 |
| 329 void JumpList::TabRestoreServiceChanged(sessions::TabRestoreService* service) { | |
| 330 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | |
| 331 | |
| 332 tab_restore_has_pending_notification_ = true; | |
| 333 | |
| 334 // Postpone handling this notification until a pending update completes. | |
| 335 if (update_in_progress_) | |
| 336 return; | |
| 337 | |
| 338 // if we have a pending favicon request, cancel it here as it's out of date. | |
| 339 CancelPendingUpdate(); | |
| 340 | |
| 341 // Initialize the one-shot timer to update the JumpList in a while. | |
| 342 InitializeTimerForUpdate(); | |
| 343 } | |
| 344 | |
| 345 void JumpList::TabRestoreServiceDestroyed( | |
| 346 sessions::TabRestoreService* service) {} | |
| 347 | |
| 348 bool JumpList::AddTab(const sessions::TabRestoreService::Tab& tab, | 443 bool JumpList::AddTab(const sessions::TabRestoreService::Tab& tab, |
| 349 size_t max_items) { | 444 size_t max_items) { |
| 350 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 445 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 351 | 446 |
| 352 // This code adds the URL and the title strings of the given tab to the | 447 // This code adds the URL and the title strings of the given tab to the |
| 353 // JumpList variables. | 448 // JumpList variables. |
| 354 if (recently_closed_pages_.size() >= max_items) | 449 if (recently_closed_pages_.size() >= max_items) |
| 355 return false; | 450 return false; |
| 356 | 451 |
| 357 scoped_refptr<ShellLinkItem> link = CreateShellLink(); | 452 scoped_refptr<ShellLinkItem> link = CreateShellLink(); |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 432 } | 527 } |
| 433 | 528 |
| 434 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/717236 | 529 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/717236 |
| 435 UMA_HISTOGRAM_TIMES("WinJumplist.OnFaviconDataAvailableDuration", | 530 UMA_HISTOGRAM_TIMES("WinJumplist.OnFaviconDataAvailableDuration", |
| 436 timer.Elapsed()); | 531 timer.Elapsed()); |
| 437 | 532 |
| 438 // Check whether we need to load more favicons. | 533 // Check whether we need to load more favicons. |
| 439 StartLoadingFavicon(); | 534 StartLoadingFavicon(); |
| 440 } | 535 } |
| 441 | 536 |
| 442 void JumpList::OnIncognitoAvailabilityChanged() { | |
| 443 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | |
| 444 | |
| 445 if (icon_urls_.empty()) | |
| 446 PostRunUpdate(); | |
| 447 } | |
| 448 | |
| 449 void JumpList::PostRunUpdate() { | 537 void JumpList::PostRunUpdate() { |
| 450 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 538 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 451 | 539 |
| 452 TRACE_EVENT0("browser", "JumpList::PostRunUpdate"); | 540 TRACE_EVENT0("browser", "JumpList::PostRunUpdate"); |
| 453 | 541 |
| 454 update_in_progress_ = true; | 542 update_in_progress_ = true; |
| 455 | 543 |
| 456 base::FilePath profile_dir = profile_->GetPath(); | 544 base::FilePath profile_dir = profile_->GetPath(); |
| 457 | 545 |
| 458 // Check if incognito windows (or normal windows) are disabled by policy. | 546 // Check if incognito windows (or normal windows) are disabled by policy. |
| (...skipping 23 matching lines...) Expand all Loading... |
| 482 local_most_visited_pages, local_recently_closed_pages, | 570 local_most_visited_pages, local_recently_closed_pages, |
| 483 most_visited_should_update, recently_closed_should_update, | 571 most_visited_should_update, recently_closed_should_update, |
| 484 incognito_availability, update_results_raw), | 572 incognito_availability, update_results_raw), |
| 485 base::Bind(&JumpList::OnRunUpdateCompletion, | 573 base::Bind(&JumpList::OnRunUpdateCompletion, |
| 486 weak_ptr_factory_.GetWeakPtr(), | 574 weak_ptr_factory_.GetWeakPtr(), |
| 487 base::Passed(std::move(update_results))))) { | 575 base::Passed(std::move(update_results))))) { |
| 488 OnRunUpdateCompletion(base::MakeUnique<UpdateResults>()); | 576 OnRunUpdateCompletion(base::MakeUnique<UpdateResults>()); |
| 489 } | 577 } |
| 490 } | 578 } |
| 491 | 579 |
| 492 void JumpList::TopSitesLoaded(history::TopSites* top_sites) { | 580 void JumpList::OnRunUpdateCompletion( |
| 493 } | 581 std::unique_ptr<UpdateResults> update_results) { |
| 494 | |
| 495 void JumpList::TopSitesChanged(history::TopSites* top_sites, | |
| 496 ChangeReason change_reason) { | |
| 497 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 582 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 498 | 583 |
| 499 top_sites_has_pending_notification_ = true; | 584 // Update JumpList member variables based on the results from the update run |
| 585 // just finished. |
| 586 if (update_results->update_timeout) |
| 587 updates_to_skip_ = kUpdatesToSkipUnderHeavyLoad; |
| 500 | 588 |
| 501 // Postpone handling this notification until a pending update completes. | 589 if (update_results->update_success) { |
| 502 if (update_in_progress_) | 590 most_visited_icons_.swap(update_results->most_visited_icons_in_update); |
| 503 return; | 591 recently_closed_icons_.swap( |
| 592 update_results->recently_closed_icons_in_update); |
| 593 most_visited_should_update_ = false; |
| 594 recently_closed_should_update_ = false; |
| 595 } |
| 504 | 596 |
| 505 // If we have a pending favicon request, cancel it here as it's out of date. | 597 update_in_progress_ = false; |
| 506 CancelPendingUpdate(); | |
| 507 | 598 |
| 508 // Initialize the one-shot timer to update the JumpList in a while. | 599 // If there is any new notification during the update run just finished, start |
| 509 InitializeTimerForUpdate(); | 600 // another JumpList update. |
| 510 } | 601 // Otherwise, post tasks to delete the JumpListIcons and JumpListIconsOld |
| 602 // folders as they are no longer needed. Now we have the |
| 603 // JumpListIcons{MostVisited, RecentClosed} folders instead. |
| 604 if (top_sites_has_pending_notification_ || |
| 605 tab_restore_has_pending_notification_) { |
| 606 InitializeTimerForUpdate(); |
| 607 } else { |
| 608 base::FilePath profile_dir = profile_->GetPath(); |
| 609 base::FilePath icon_dir = |
| 610 GenerateJumplistIconDirName(profile_dir, FILE_PATH_LITERAL("")); |
| 611 delete_jumplisticons_task_runner_->PostTask( |
| 612 FROM_HERE, |
| 613 base::Bind(&DeleteDirectory, std::move(icon_dir), kFileDeleteLimit)); |
| 511 | 614 |
| 512 void JumpList::InitializeTimerForUpdate() { | 615 base::FilePath icon_dir_old = |
| 513 if (timer_.IsRunning()) { | 616 GenerateJumplistIconDirName(profile_dir, FILE_PATH_LITERAL("Old")); |
| 514 timer_.Reset(); | 617 delete_jumplisticons_task_runner_->PostTask( |
| 515 } else { | 618 FROM_HERE, base::Bind(&DeleteDirectory, std::move(icon_dir_old), |
| 516 // base::Unretained is safe since |this| is guaranteed to outlive timer_. | 619 kFileDeleteLimit)); |
| 517 timer_.Start(FROM_HERE, kDelayForJumplistUpdate, | |
| 518 base::Bind(&JumpList::OnDelayTimer, base::Unretained(this))); | |
| 519 } | 620 } |
| 520 } | 621 } |
| 521 | 622 |
| 522 void JumpList::OnDelayTimer() { | 623 void JumpList::CancelPendingUpdate() { |
| 523 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 624 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 524 | 625 |
| 525 if (updates_to_skip_ > 0) { | 626 // Cancel a pending most-visited URL fetch by invalidating the weak pointer. |
| 526 --updates_to_skip_; | 627 weak_ptr_factory_.InvalidateWeakPtrs(); |
| 527 return; | |
| 528 } | |
| 529 | 628 |
| 530 // Retrieve the recently closed URLs synchronously. | 629 // Cancel a pending favicon loading by invalidating its task id. |
| 531 if (tab_restore_has_pending_notification_) { | 630 if (task_id_ != base::CancelableTaskTracker::kBadTaskId) { |
| 532 tab_restore_has_pending_notification_ = false; | 631 cancelable_task_tracker_.TryCancel(task_id_); |
| 533 ProcessTabRestoreServiceNotification(); | 632 task_id_ = base::CancelableTaskTracker::kBadTaskId; |
| 534 } | |
| 535 | |
| 536 // If TopSites has updates, retrieve the URLs asynchronously, and on its | |
| 537 // completion, trigger favicon loading. | |
| 538 // Otherwise, call StartLoadingFavicon directly to start favicon loading. | |
| 539 if (top_sites_has_pending_notification_) | |
| 540 ProcessTopSitesNotification(); | |
| 541 else | |
| 542 StartLoadingFavicon(); | |
| 543 } | |
| 544 | |
| 545 void JumpList::ProcessTopSitesNotification() { | |
| 546 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | |
| 547 | |
| 548 // Opening the first tab in one session triggers a TopSite history sync. | |
| 549 // Delay this sync till the first tab is closed to allow the "recently closed" | |
| 550 // category from last session to stay longer. All previous pending | |
| 551 // notifications from TopSites are ignored. | |
| 552 if (!has_tab_closed_) { | |
| 553 top_sites_has_pending_notification_ = false; | |
| 554 return; | |
| 555 } | |
| 556 | |
| 557 scoped_refptr<history::TopSites> top_sites = | |
| 558 TopSitesFactory::GetForProfile(profile_); | |
| 559 if (top_sites) { | |
| 560 top_sites->GetMostVisitedURLs( | |
| 561 base::Bind(&JumpList::OnMostVisitedURLsAvailable, | |
| 562 weak_ptr_factory_.GetWeakPtr()), | |
| 563 false); | |
| 564 } | 633 } |
| 565 } | 634 } |
| 566 | 635 |
| 567 void JumpList::ProcessTabRestoreServiceNotification() { | 636 void JumpList::Terminate() { |
| 568 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 637 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 569 | 638 timer_.Stop(); |
| 570 // Create a list of ShellLinkItems from the "Recently Closed" pages. | 639 CancelPendingUpdate(); |
| 571 // As noted above, we create a ShellLinkItem objects with the following | 640 update_in_progress_ = false; |
| 572 // parameters. | 641 if (profile_) { |
| 573 // * arguments | 642 sessions::TabRestoreService* tab_restore_service = |
| 574 // The last URL of the tab object. | 643 TabRestoreServiceFactory::GetForProfile(profile_); |
| 575 // * title | 644 if (tab_restore_service) |
| 576 // The title of the last URL. | 645 tab_restore_service->RemoveObserver(this); |
| 577 // * icon | |
| 578 // An empty string. This value is to be updated in OnFaviconDataAvailable(). | |
| 579 | |
| 580 sessions::TabRestoreService* tab_restore_service = | |
| 581 TabRestoreServiceFactory::GetForProfile(profile_); | |
| 582 | |
| 583 recently_closed_pages_.clear(); | |
| 584 | |
| 585 for (const auto& entry : tab_restore_service->entries()) { | |
| 586 if (recently_closed_pages_.size() >= kRecentlyClosedItems) | |
| 587 break; | |
| 588 switch (entry->type) { | |
| 589 case sessions::TabRestoreService::TAB: | |
| 590 AddTab(static_cast<const sessions::TabRestoreService::Tab&>(*entry), | |
| 591 kRecentlyClosedItems); | |
| 592 break; | |
| 593 case sessions::TabRestoreService::WINDOW: | |
| 594 AddWindow( | |
| 595 static_cast<const sessions::TabRestoreService::Window&>(*entry), | |
| 596 kRecentlyClosedItems); | |
| 597 break; | |
| 598 } | |
| 599 } | |
| 600 | |
| 601 recently_closed_should_update_ = true; | |
| 602 | |
| 603 // Force a TopSite history sync when closing a first tab in one session. | |
| 604 if (!has_tab_closed_) { | |
| 605 has_tab_closed_ = true; | |
| 606 scoped_refptr<history::TopSites> top_sites = | 646 scoped_refptr<history::TopSites> top_sites = |
| 607 TopSitesFactory::GetForProfile(profile_); | 647 TopSitesFactory::GetForProfile(profile_); |
| 608 if (top_sites) | 648 if (top_sites) |
| 609 top_sites->SyncWithHistory(); | 649 top_sites->RemoveObserver(this); |
| 650 pref_change_registrar_.reset(); |
| 610 } | 651 } |
| 652 profile_ = nullptr; |
| 611 } | 653 } |
| 612 | 654 |
| 613 // static | 655 // static |
| 614 void JumpList::DeleteIconFiles(const base::FilePath& icon_dir, | |
| 615 URLIconCache* icon_cache) { | |
| 616 DCHECK(icon_cache); | |
| 617 | |
| 618 // Put all cached icon file paths into a set. | |
| 619 base::flat_set<base::FilePath> cached_files; | |
| 620 cached_files.reserve(icon_cache->size()); | |
| 621 | |
| 622 for (const auto& url_path_pair : *icon_cache) | |
| 623 cached_files.insert(url_path_pair.second); | |
| 624 | |
| 625 DeleteNonCachedFiles(icon_dir, cached_files); | |
| 626 } | |
| 627 | |
| 628 // static | |
| 629 int JumpList::CreateIconFiles(const base::FilePath& icon_dir, | |
| 630 const ShellLinkItemList& item_list, | |
| 631 size_t max_items, | |
| 632 URLIconCache* icon_cache) { | |
| 633 DCHECK(icon_cache); | |
| 634 | |
| 635 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. | |
| 636 SCOPED_UMA_HISTOGRAM_TIMER("WinJumplist.CreateIconFilesDuration"); | |
| 637 | |
| 638 int icons_created = 0; | |
| 639 | |
| 640 // Reuse icons for urls that already present in the current JumpList. | |
| 641 URLIconCache updated_map; | |
| 642 for (ShellLinkItemList::const_iterator iter = item_list.begin(); | |
| 643 iter != item_list.end() && max_items > 0; ++iter, --max_items) { | |
| 644 ShellLinkItem* item = iter->get(); | |
| 645 auto cache_iter = icon_cache->find(item->url()); | |
| 646 if (cache_iter != icon_cache->end()) { | |
| 647 item->set_icon(cache_iter->second.value(), 0); | |
| 648 updated_map[item->url()] = cache_iter->second; | |
| 649 } else { | |
| 650 base::FilePath icon_path; | |
| 651 if (CreateIconFile(item->icon_image(), icon_dir, &icon_path)) { | |
| 652 ++icons_created; | |
| 653 item->set_icon(icon_path.value(), 0); | |
| 654 updated_map[item->url()] = icon_path; | |
| 655 } | |
| 656 } | |
| 657 } | |
| 658 icon_cache->swap(updated_map); | |
| 659 | |
| 660 return icons_created; | |
| 661 } | |
| 662 | |
| 663 // static | |
| 664 int JumpList::UpdateIconFiles(const base::FilePath& icon_dir, | |
| 665 const ShellLinkItemList& page_list, | |
| 666 size_t slot_limit, | |
| 667 URLIconCache* icon_cache) { | |
| 668 DCHECK(icon_cache); | |
| 669 | |
| 670 int icons_created = 0; | |
| 671 | |
| 672 // Clear the JumpList icon folder at |icon_dir| and the cache when | |
| 673 // 1) |icon_cache| is empty. This happens when "Most visited" or "Recently | |
| 674 // closed" category updates for the 1st time after Chrome is launched. | |
| 675 // 2) The number of icons in |icon_dir| has exceeded the limit. | |
| 676 if (icon_cache->empty() || FilesExceedLimitInDir(icon_dir, slot_limit * 2)) { | |
| 677 DeleteDirectoryContentAndLogRuntime(icon_dir, kFileDeleteLimit); | |
| 678 icon_cache->clear(); | |
| 679 // Create new icons only when the directory exists and is empty. | |
| 680 if (base::CreateDirectory(icon_dir) && base::IsDirectoryEmpty(icon_dir)) | |
| 681 icons_created += | |
| 682 CreateIconFiles(icon_dir, page_list, slot_limit, icon_cache); | |
| 683 } else if (base::CreateDirectory(icon_dir)) { | |
| 684 icons_created += | |
| 685 CreateIconFiles(icon_dir, page_list, slot_limit, icon_cache); | |
| 686 DeleteIconFiles(icon_dir, icon_cache); | |
| 687 } | |
| 688 | |
| 689 return icons_created; | |
| 690 } | |
| 691 | |
| 692 // static | |
| 693 void JumpList::RunUpdateJumpList( | 656 void JumpList::RunUpdateJumpList( |
| 694 const base::string16& app_id, | 657 const base::string16& app_id, |
| 695 const base::FilePath& profile_dir, | 658 const base::FilePath& profile_dir, |
| 696 const ShellLinkItemList& most_visited_pages, | 659 const ShellLinkItemList& most_visited_pages, |
| 697 const ShellLinkItemList& recently_closed_pages, | 660 const ShellLinkItemList& recently_closed_pages, |
| 698 bool most_visited_should_update, | 661 bool most_visited_should_update, |
| 699 bool recently_closed_should_update, | 662 bool recently_closed_should_update, |
| 700 IncognitoModePrefs::Availability incognito_availability, | 663 IncognitoModePrefs::Availability incognito_availability, |
| 701 UpdateResults* update_results) { | 664 UpdateResults* update_results) { |
| 702 if (!JumpListUpdater::IsEnabled()) | 665 if (!JumpListUpdater::IsEnabled()) |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 785 base::ElapsedTimer commit_update_timer; | 748 base::ElapsedTimer commit_update_timer; |
| 786 | 749 |
| 787 // Commit this transaction and send the updated JumpList to Windows. | 750 // Commit this transaction and send the updated JumpList to Windows. |
| 788 if (jumplist_updater.CommitUpdate()) | 751 if (jumplist_updater.CommitUpdate()) |
| 789 update_results->update_success = true; | 752 update_results->update_success = true; |
| 790 | 753 |
| 791 if (commit_update_timer.Elapsed() >= kTimeOutForJumplistCommitUpdate) | 754 if (commit_update_timer.Elapsed() >= kTimeOutForJumplistCommitUpdate) |
| 792 update_results->update_timeout = true; | 755 update_results->update_timeout = true; |
| 793 } | 756 } |
| 794 | 757 |
| 795 void JumpList::OnRunUpdateCompletion( | 758 // static |
| 796 std::unique_ptr<UpdateResults> update_results) { | 759 int JumpList::UpdateIconFiles(const base::FilePath& icon_dir, |
| 797 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 760 const ShellLinkItemList& page_list, |
| 761 size_t slot_limit, |
| 762 URLIconCache* icon_cache) { |
| 763 int icons_created = 0; |
| 798 | 764 |
| 799 // Update JumpList member variables based on the results from the update run | 765 // Clear the JumpList icon folder at |icon_dir| and the cache when |
| 800 // just finished. | 766 // 1) |icon_cache| is empty. This happens when "Most visited" or "Recently |
| 801 if (update_results->update_timeout) | 767 // closed" category updates for the 1st time after Chrome is launched. |
| 802 updates_to_skip_ = kUpdatesToSkipUnderHeavyLoad; | 768 // 2) The number of icons in |icon_dir| has exceeded the limit. |
| 803 | 769 if (icon_cache->empty() || FilesExceedLimitInDir(icon_dir, slot_limit * 2)) { |
| 804 if (update_results->update_success) { | 770 DeleteDirectoryContentAndLogRuntime(icon_dir, kFileDeleteLimit); |
| 805 most_visited_icons_.swap(update_results->most_visited_icons_in_update); | 771 icon_cache->clear(); |
| 806 recently_closed_icons_.swap( | 772 // Create new icons only when the directory exists and is empty. |
| 807 update_results->recently_closed_icons_in_update); | 773 if (base::CreateDirectory(icon_dir) && base::IsDirectoryEmpty(icon_dir)) |
| 808 most_visited_should_update_ = false; | 774 icons_created += |
| 809 recently_closed_should_update_ = false; | 775 CreateIconFiles(icon_dir, page_list, slot_limit, icon_cache); |
| 776 } else if (base::CreateDirectory(icon_dir)) { |
| 777 icons_created += |
| 778 CreateIconFiles(icon_dir, page_list, slot_limit, icon_cache); |
| 779 DeleteIconFiles(icon_dir, icon_cache); |
| 810 } | 780 } |
| 811 | 781 |
| 812 update_in_progress_ = false; | 782 return icons_created; |
| 783 } |
| 813 | 784 |
| 814 // If there is any new notification during the update run just finished, start | 785 // static |
| 815 // another JumpList update. | 786 int JumpList::CreateIconFiles(const base::FilePath& icon_dir, |
| 816 // Otherwise, post tasks to delete the JumpListIcons and JumpListIconsOld | 787 const ShellLinkItemList& item_list, |
| 817 // folders as they are no longer needed. Now we have the | 788 size_t max_items, |
| 818 // JumpListIcons{MostVisited, RecentClosed} folders instead. | 789 URLIconCache* icon_cache) { |
| 819 if (top_sites_has_pending_notification_ || | 790 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. |
| 820 tab_restore_has_pending_notification_) { | 791 SCOPED_UMA_HISTOGRAM_TIMER("WinJumplist.CreateIconFilesDuration"); |
| 821 InitializeTimerForUpdate(); | |
| 822 } else { | |
| 823 base::FilePath profile_dir = profile_->GetPath(); | |
| 824 base::FilePath icon_dir = | |
| 825 GenerateJumplistIconDirName(profile_dir, FILE_PATH_LITERAL("")); | |
| 826 delete_jumplisticons_task_runner_->PostTask( | |
| 827 FROM_HERE, | |
| 828 base::Bind(&DeleteDirectory, std::move(icon_dir), kFileDeleteLimit)); | |
| 829 | 792 |
| 830 base::FilePath icon_dir_old = | 793 int icons_created = 0; |
| 831 GenerateJumplistIconDirName(profile_dir, FILE_PATH_LITERAL("Old")); | 794 |
| 832 delete_jumplisticons_task_runner_->PostTask( | 795 // Reuse icons for urls that already present in the current JumpList. |
| 833 FROM_HERE, base::Bind(&DeleteDirectory, std::move(icon_dir_old), | 796 URLIconCache updated_map; |
| 834 kFileDeleteLimit)); | 797 for (ShellLinkItemList::const_iterator iter = item_list.begin(); |
| 798 iter != item_list.end() && max_items > 0; ++iter, --max_items) { |
| 799 ShellLinkItem* item = iter->get(); |
| 800 auto cache_iter = icon_cache->find(item->url()); |
| 801 if (cache_iter != icon_cache->end()) { |
| 802 item->set_icon(cache_iter->second.value(), 0); |
| 803 updated_map[item->url()] = cache_iter->second; |
| 804 } else { |
| 805 base::FilePath icon_path; |
| 806 if (CreateIconFile(item->icon_image(), icon_dir, &icon_path)) { |
| 807 ++icons_created; |
| 808 item->set_icon(icon_path.value(), 0); |
| 809 updated_map[item->url()] = icon_path; |
| 810 } |
| 811 } |
| 835 } | 812 } |
| 813 icon_cache->swap(updated_map); |
| 814 |
| 815 return icons_created; |
| 836 } | 816 } |
| 817 |
| 818 // static |
| 819 void JumpList::DeleteIconFiles(const base::FilePath& icon_dir, |
| 820 URLIconCache* icon_cache) { |
| 821 // Put all cached icon file paths into a set. |
| 822 base::flat_set<base::FilePath> cached_files; |
| 823 cached_files.reserve(icon_cache->size()); |
| 824 |
| 825 for (const auto& url_path_pair : *icon_cache) |
| 826 cached_files.insert(url_path_pair.second); |
| 827 |
| 828 DeleteNonCachedFiles(icon_dir, cached_files); |
| 829 } |
| OLD | NEW |