| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/history/top_sites.h" | 5 #include "chrome/browser/history/top_sites.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "app/l10n_util.h" | 9 #include "app/l10n_util.h" |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 44 static const int64 kMinUpdateIntervalMinutes = 1; | 44 static const int64 kMinUpdateIntervalMinutes = 1; |
| 45 static const int64 kMaxUpdateIntervalMinutes = 60; | 45 static const int64 kMaxUpdateIntervalMinutes = 60; |
| 46 | 46 |
| 47 | 47 |
| 48 TopSites::TopSites(Profile* profile) : profile_(profile), | 48 TopSites::TopSites(Profile* profile) : profile_(profile), |
| 49 mock_history_service_(NULL), | 49 mock_history_service_(NULL), |
| 50 last_num_urls_changed_(0), | 50 last_num_urls_changed_(0), |
| 51 migration_in_progress_(false), | 51 migration_in_progress_(false), |
| 52 waiting_for_results_(true), | 52 waiting_for_results_(true), |
| 53 blacklist_(NULL), | 53 blacklist_(NULL), |
| 54 pinned_urls_(NULL) { | 54 pinned_urls_(NULL), |
| 55 handle_to_wait_for_(NULL) { |
| 55 if (!profile_) | 56 if (!profile_) |
| 56 return; | 57 return; |
| 57 | 58 |
| 58 if (NotificationService::current()) { | 59 if (NotificationService::current()) { |
| 59 registrar_.Add(this, NotificationType::HISTORY_URLS_DELETED, | 60 registrar_.Add(this, NotificationType::HISTORY_URLS_DELETED, |
| 60 Source<Profile>(profile_)); | 61 Source<Profile>(profile_)); |
| 61 registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED, | 62 registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED, |
| 62 NotificationService::AllSources()); | 63 NotificationService::AllSources()); |
| 63 } | 64 } |
| 64 | 65 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 83 if (!db_->Init(db_name)) { | 84 if (!db_->Init(db_name)) { |
| 84 NOTREACHED() << "Failed to initialize database."; | 85 NOTREACHED() << "Failed to initialize database."; |
| 85 return; | 86 return; |
| 86 } | 87 } |
| 87 | 88 |
| 88 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, NewRunnableMethod( | 89 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, NewRunnableMethod( |
| 89 this, &TopSites::ReadDatabase)); | 90 this, &TopSites::ReadDatabase)); |
| 90 | 91 |
| 91 // Start the one-shot timer. | 92 // Start the one-shot timer. |
| 92 timer_.Start(base::TimeDelta::FromSeconds(kUpdateIntervalSecs), this, | 93 timer_.Start(base::TimeDelta::FromSeconds(kUpdateIntervalSecs), this, |
| 93 &TopSites::StartQueryForMostVisited); | 94 &TopSites::TimerFired); |
| 94 } | 95 } |
| 95 | 96 |
| 96 void TopSites::ReadDatabase() { | 97 void TopSites::ReadDatabase() { |
| 97 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); | 98 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); |
| 98 std::map<GURL, Images> thumbnails; | 99 std::map<GURL, Images> thumbnails; |
| 99 | 100 |
| 100 DCHECK(db_.get()); | 101 DCHECK(db_.get()); |
| 101 MostVisitedURLList top_urls; | 102 MostVisitedURLList top_urls; |
| 102 db_->GetPageThumbnails(&top_urls, &thumbnails); | 103 db_->GetPageThumbnails(&top_urls, &thumbnails); |
| 103 MostVisitedURLList copy(top_urls); // StoreMostVisited destroys the list. | 104 MostVisitedURLList copy(top_urls); // StoreMostVisited destroys the list. |
| (...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 442 } | 443 } |
| 443 } | 444 } |
| 444 } | 445 } |
| 445 | 446 |
| 446 // If we are not expecting any thumbnails, migration is done. | 447 // If we are not expecting any thumbnails, migration is done. |
| 447 if (migration_in_progress_ && migration_pending_urls_.empty()) | 448 if (migration_in_progress_ && migration_pending_urls_.empty()) |
| 448 OnMigrationDone(); | 449 OnMigrationDone(); |
| 449 | 450 |
| 450 timer_.Stop(); | 451 timer_.Stop(); |
| 451 timer_.Start(GetUpdateDelay(), this, | 452 timer_.Start(GetUpdateDelay(), this, |
| 452 &TopSites::StartQueryForMostVisited); | 453 &TopSites::TimerFired); |
| 453 } | 454 } |
| 454 | 455 |
| 455 void TopSites::OnMigrationDone() { | 456 void TopSites::OnMigrationDone() { |
| 456 migration_in_progress_ = false; | 457 migration_in_progress_ = false; |
| 457 if (!profile_) | 458 if (!profile_) |
| 458 return; | 459 return; |
| 459 | 460 |
| 460 HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); | 461 HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); |
| 461 // |hs| may be null during unit tests. | 462 // |hs| may be null during unit tests. |
| 462 if (!hs) | 463 if (!hs) |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 631 | 632 |
| 632 // Any member without the special marker in the all_old_urls list means that | 633 // Any member without the special marker in the all_old_urls list means that |
| 633 // there wasn't a "new" URL that mapped to it, so it was deleted. | 634 // there wasn't a "new" URL that mapped to it, so it was deleted. |
| 634 for (std::map<GURL, size_t>::const_iterator i = all_old_urls.begin(); | 635 for (std::map<GURL, size_t>::const_iterator i = all_old_urls.begin(); |
| 635 i != all_old_urls.end(); ++i) { | 636 i != all_old_urls.end(); ++i) { |
| 636 if (i->second != kAlreadyFoundMarker) | 637 if (i->second != kAlreadyFoundMarker) |
| 637 deleted_urls->push_back(i->second); | 638 deleted_urls->push_back(i->second); |
| 638 } | 639 } |
| 639 } | 640 } |
| 640 | 641 |
| 641 void TopSites::StartQueryForMostVisited() { | 642 CancelableRequestProvider::Handle TopSites::StartQueryForMostVisited() { |
| 643 CancelableRequestProvider::Handle request_handle = NULL; |
| 642 if (mock_history_service_) { | 644 if (mock_history_service_) { |
| 643 // Testing with a mockup. | 645 // Testing with a mockup. |
| 644 // QueryMostVisitedURLs is not virtual, so we have to duplicate the code. | 646 // QueryMostVisitedURLs is not virtual, so we have to duplicate the code. |
| 645 mock_history_service_->QueryMostVisitedURLs( | 647 request_handle = mock_history_service_->QueryMostVisitedURLs( |
| 646 kTopSitesNumber + blacklist_->size(), | 648 kTopSitesNumber + blacklist_->size(), |
| 647 kDaysOfHistory, | 649 kDaysOfHistory, |
| 648 &cancelable_consumer_, | 650 &cancelable_consumer_, |
| 649 NewCallback(this, &TopSites::OnTopSitesAvailable)); | 651 NewCallback(this, &TopSites::OnTopSitesAvailable)); |
| 650 } else { | 652 } else if (profile_) { |
| 651 if (!profile_) | |
| 652 return; | |
| 653 | |
| 654 HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); | 653 HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); |
| 655 // |hs| may be null during unit tests. | 654 // |hs| may be null during unit tests. |
| 656 if (hs) { | 655 if (hs) { |
| 657 hs->QueryMostVisitedURLs( | 656 request_handle = hs->QueryMostVisitedURLs( |
| 658 kTopSitesNumber + blacklist_->size(), | 657 kTopSitesNumber + blacklist_->size(), |
| 659 kDaysOfHistory, | 658 kDaysOfHistory, |
| 660 &cancelable_consumer_, | 659 &cancelable_consumer_, |
| 661 NewCallback(this, &TopSites::OnTopSitesAvailable)); | 660 NewCallback(this, &TopSites::OnTopSitesAvailable)); |
| 662 } else { | 661 } else { |
| 663 LOG(INFO) << "History Service not available."; | 662 LOG(INFO) << "History Service not available."; |
| 664 } | 663 } |
| 665 } | 664 } |
| 665 return request_handle; |
| 666 } |
| 667 |
| 668 void TopSites::TimerFired() { |
| 669 StartQueryForMostVisited(); |
| 666 } | 670 } |
| 667 | 671 |
| 668 void TopSites::StartMigration() { | 672 void TopSites::StartMigration() { |
| 669 LOG(INFO) << "Starting migration to TopSites."; | 673 LOG(INFO) << "Starting migration to TopSites."; |
| 670 migration_in_progress_ = true; | 674 migration_in_progress_ = true; |
| 671 StartQueryForMostVisited(); | 675 StartQueryForMostVisited(); |
| 672 MigratePinnedURLs(); | 676 MigratePinnedURLs(); |
| 673 } | 677 } |
| 674 | 678 |
| 675 bool TopSites::HasBlacklistedItems() const { | 679 bool TopSites::HasBlacklistedItems() const { |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 753 if (ChromeThread::IsWellKnownThread(ChromeThread::UI)) { | 757 if (ChromeThread::IsWellKnownThread(ChromeThread::UI)) { |
| 754 ptr = NULL; | 758 ptr = NULL; |
| 755 } else { | 759 } else { |
| 756 // Need to roll our own UI thread. | 760 // Need to roll our own UI thread. |
| 757 ChromeThread ui_loop(ChromeThread::UI, MessageLoop::current()); | 761 ChromeThread ui_loop(ChromeThread::UI, MessageLoop::current()); |
| 758 ptr = NULL; | 762 ptr = NULL; |
| 759 MessageLoop::current()->RunAllPending(); | 763 MessageLoop::current()->RunAllPending(); |
| 760 } | 764 } |
| 761 } | 765 } |
| 762 | 766 |
| 767 void TopSites::RefreshAndCallback(CancelableRequestConsumer* consumer, |
| 768 Callback0::Type* callback) { |
| 769 if (refresh_callback_) { |
| 770 DLOG(ERROR) << "Waiting for refresh before previous refresh finished"; |
| 771 return; |
| 772 } |
| 773 scoped_refptr<CancelableRequest<Callback0::Type> > request( |
| 774 new CancelableRequest<Callback0::Type>(callback)); |
| 775 AddRequest(request, consumer); |
| 776 refresh_callback_ = request; |
| 777 handle_to_wait_for_ = StartQueryForMostVisited(); |
| 778 } |
| 779 |
| 763 void TopSites::ClearProfile() { | 780 void TopSites::ClearProfile() { |
| 764 profile_ = NULL; | 781 profile_ = NULL; |
| 765 } | 782 } |
| 766 | 783 |
| 767 base::TimeDelta TopSites::GetUpdateDelay() { | 784 base::TimeDelta TopSites::GetUpdateDelay() { |
| 768 AutoLock lock(lock_); | 785 AutoLock lock(lock_); |
| 769 if (top_sites_.size() == 0) | 786 if (top_sites_.size() == 0) |
| 770 return base::TimeDelta::FromSeconds(30); | 787 return base::TimeDelta::FromSeconds(30); |
| 771 | 788 |
| 772 int64 range = kMaxUpdateIntervalMinutes - kMinUpdateIntervalMinutes; | 789 int64 range = kMaxUpdateIntervalMinutes - kMinUpdateIntervalMinutes; |
| 773 int64 minutes = kMaxUpdateIntervalMinutes - | 790 int64 minutes = kMaxUpdateIntervalMinutes - |
| 774 last_num_urls_changed_ * range / top_sites_.size(); | 791 last_num_urls_changed_ * range / top_sites_.size(); |
| 775 return base::TimeDelta::FromMinutes(minutes); | 792 return base::TimeDelta::FromMinutes(minutes); |
| 776 } | 793 } |
| 777 | 794 |
| 778 void TopSites::OnTopSitesAvailable( | 795 void TopSites::OnTopSitesAvailable( |
| 779 CancelableRequestProvider::Handle handle, | 796 CancelableRequestProvider::Handle handle, |
| 780 MostVisitedURLList pages) { | 797 MostVisitedURLList pages) { |
| 781 AddPrepopulatedPages(&pages); | 798 AddPrepopulatedPages(&pages); |
| 782 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, NewRunnableMethod( | 799 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, NewRunnableMethod( |
| 783 this, &TopSites::UpdateMostVisited, pages)); | 800 this, &TopSites::UpdateMostVisited, pages)); |
| 801 |
| 802 if (handle == handle_to_wait_for_) { |
| 803 if (ChromeThread::IsWellKnownThread(ChromeThread::UI)) { |
| 804 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 805 // Posting this task after the one above should guarantee that |
| 806 // |top_sites_| is completely refreshed. |
| 807 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, NewRunnableMethod( |
| 808 this, &TopSites::InvokeRefreshCallback)); |
| 809 } else { |
| 810 // This will happen in unit tests when we don't have a real UI thread. |
| 811 InvokeRefreshCallbackOnUIThread(); |
| 812 } |
| 813 } |
| 784 } | 814 } |
| 785 | 815 |
| 786 // static | 816 // static |
| 787 void TopSites::ProcessPendingCallbacks(PendingCallbackSet pending_callbacks, | 817 void TopSites::ProcessPendingCallbacks(PendingCallbackSet pending_callbacks, |
| 788 const MostVisitedURLList& urls) { | 818 const MostVisitedURLList& urls) { |
| 789 PendingCallbackSet::iterator i; | 819 PendingCallbackSet::iterator i; |
| 790 for (i = pending_callbacks.begin(); | 820 for (i = pending_callbacks.begin(); |
| 791 i != pending_callbacks.end(); ++i) { | 821 i != pending_callbacks.end(); ++i) { |
| 792 scoped_refptr<CancelableRequest<GetTopSitesCallback> > request = *i; | 822 scoped_refptr<CancelableRequest<GetTopSitesCallback> > request = *i; |
| 793 if (!request->canceled()) | 823 if (!request->canceled()) |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 886 void TopSites::ResetDatabase() { | 916 void TopSites::ResetDatabase() { |
| 887 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); | 917 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); |
| 888 db_.reset(new TopSitesDatabaseImpl()); | 918 db_.reset(new TopSitesDatabaseImpl()); |
| 889 file_util::Delete(db_path_, false); | 919 file_util::Delete(db_path_, false); |
| 890 if (!db_->Init(db_path_)) { | 920 if (!db_->Init(db_path_)) { |
| 891 NOTREACHED() << "Failed to initialize database."; | 921 NOTREACHED() << "Failed to initialize database."; |
| 892 return; | 922 return; |
| 893 } | 923 } |
| 894 } | 924 } |
| 895 | 925 |
| 926 void TopSites::InvokeRefreshCallback() { |
| 927 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, |
| 928 NewRunnableMethod(this, &TopSites::InvokeRefreshCallbackOnUIThread)); |
| 929 } |
| 930 |
| 931 void TopSites::InvokeRefreshCallbackOnUIThread() { |
| 932 if (refresh_callback_) { |
| 933 if (!refresh_callback_->canceled()) |
| 934 refresh_callback_->ForwardResult(Callback0::Type::TupleType()); |
| 935 refresh_callback_.release(); |
| 936 } else { |
| 937 LOG(DFATAL) << "No refresh callback was set."; |
| 938 } |
| 939 } |
| 940 |
| 896 } // namespace history | 941 } // namespace history |
| OLD | NEW |