OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 "components/ntp_snippets/ntp_snippets_service.h" | 5 #include "components/ntp_snippets/ntp_snippets_service.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <iterator> | 8 #include <iterator> |
9 #include <utility> | 9 #include <utility> |
10 | 10 |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
205 suggestions_service_(suggestions_service), | 205 suggestions_service_(suggestions_service), |
206 application_language_code_(application_language_code), | 206 application_language_code_(application_language_code), |
207 scheduler_(scheduler), | 207 scheduler_(scheduler), |
208 snippets_fetcher_(std::move(snippets_fetcher)), | 208 snippets_fetcher_(std::move(snippets_fetcher)), |
209 image_fetcher_(std::move(image_fetcher)), | 209 image_fetcher_(std::move(image_fetcher)), |
210 image_decoder_(std::move(image_decoder)), | 210 image_decoder_(std::move(image_decoder)), |
211 database_(std::move(database)), | 211 database_(std::move(database)), |
212 snippets_status_service_(std::move(status_service)), | 212 snippets_status_service_(std::move(status_service)), |
213 fetch_after_load_(false), | 213 fetch_after_load_(false), |
214 provided_category_( | 214 provided_category_( |
215 category_factory->FromKnownCategory(KnownCategories::ARTICLES)) { | 215 category_factory->FromKnownCategory(KnownCategories::ARTICLES)), |
| 216 thumbnail_requests_throttler_( |
| 217 pref_service, |
| 218 RequestThrottler::RequestType::CONTENT_SUGGESTION_THUMBNAIL) { |
216 if (database_->IsErrorState()) { | 219 if (database_->IsErrorState()) { |
217 EnterState(State::ERROR_OCCURRED, CategoryStatus::LOADING_ERROR); | 220 EnterState(State::ERROR_OCCURRED, CategoryStatus::LOADING_ERROR); |
218 return; | 221 return; |
219 } | 222 } |
220 | 223 |
221 database_->SetErrorCallback(base::Bind(&NTPSnippetsService::OnDatabaseError, | 224 database_->SetErrorCallback(base::Bind(&NTPSnippetsService::OnDatabaseError, |
222 base::Unretained(this))); | 225 base::Unretained(this))); |
223 | 226 |
224 // We transition to other states while finalizing the initialization, when the | 227 // We transition to other states while finalizing the initialization, when the |
225 // database is done loading. | 228 // database is done loading. |
226 database_->LoadSnippets(base::Bind(&NTPSnippetsService::OnDatabaseLoaded, | 229 database_->LoadSnippets(base::Bind(&NTPSnippetsService::OnDatabaseLoaded, |
227 base::Unretained(this))); | 230 base::Unretained(this))); |
228 } | 231 } |
229 | 232 |
230 NTPSnippetsService::~NTPSnippetsService() { | 233 NTPSnippetsService::~NTPSnippetsService() { |
231 } | 234 } |
232 | 235 |
233 // static | 236 // static |
234 void NTPSnippetsService::RegisterProfilePrefs(PrefRegistrySimple* registry) { | 237 void NTPSnippetsService::RegisterProfilePrefs(PrefRegistrySimple* registry) { |
235 registry->RegisterListPref(prefs::kSnippetHosts); | 238 registry->RegisterListPref(prefs::kSnippetHosts); |
236 | 239 |
237 NTPSnippetsStatusService::RegisterProfilePrefs(registry); | 240 NTPSnippetsStatusService::RegisterProfilePrefs(registry); |
238 } | 241 } |
239 | 242 |
240 void NTPSnippetsService::FetchSnippets(bool force_request) { | 243 void NTPSnippetsService::FetchSnippets(bool interactive_request) { |
241 if (ready()) | 244 if (ready()) |
242 FetchSnippetsFromHosts(GetSuggestionsHosts(), force_request); | 245 FetchSnippetsFromHosts(GetSuggestionsHosts(), interactive_request); |
243 else | 246 else |
244 fetch_after_load_ = true; | 247 fetch_after_load_ = true; |
245 } | 248 } |
246 | 249 |
247 void NTPSnippetsService::FetchSnippetsFromHosts( | 250 void NTPSnippetsService::FetchSnippetsFromHosts( |
248 const std::set<std::string>& hosts, | 251 const std::set<std::string>& hosts, |
249 bool force_request) { | 252 bool interactive_request) { |
250 if (!ready()) | 253 if (!ready()) |
251 return; | 254 return; |
252 | 255 |
253 if (snippets_.empty()) | 256 if (snippets_.empty()) |
254 UpdateCategoryStatus(CategoryStatus::AVAILABLE_LOADING); | 257 UpdateCategoryStatus(CategoryStatus::AVAILABLE_LOADING); |
255 | 258 |
256 snippets_fetcher_->FetchSnippetsFromHosts(hosts, application_language_code_, | 259 snippets_fetcher_->FetchSnippetsFromHosts( |
257 kMaxSnippetCount, force_request); | 260 hosts, application_language_code_, kMaxSnippetCount, interactive_request); |
258 } | 261 } |
259 | 262 |
260 void NTPSnippetsService::RescheduleFetching() { | 263 void NTPSnippetsService::RescheduleFetching() { |
261 // The scheduler only exists on Android so far, it's null on other platforms. | 264 // The scheduler only exists on Android so far, it's null on other platforms. |
262 if (!scheduler_) | 265 if (!scheduler_) |
263 return; | 266 return; |
264 | 267 |
265 if (ready()) { | 268 if (ready()) { |
266 base::Time now = base::Time::Now(); | 269 base::Time now = base::Time::Now(); |
267 scheduler_->Schedule( | 270 scheduler_->Schedule( |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
310 snippets_.erase(it); | 313 snippets_.erase(it); |
311 } | 314 } |
312 | 315 |
313 void NTPSnippetsService::FetchSuggestionImage( | 316 void NTPSnippetsService::FetchSuggestionImage( |
314 const std::string& suggestion_id, | 317 const std::string& suggestion_id, |
315 const ImageFetchedCallback& callback) { | 318 const ImageFetchedCallback& callback) { |
316 std::string snippet_id = GetWithinCategoryIDFromUniqueID(suggestion_id); | 319 std::string snippet_id = GetWithinCategoryIDFromUniqueID(suggestion_id); |
317 database_->LoadImage( | 320 database_->LoadImage( |
318 snippet_id, | 321 snippet_id, |
319 base::Bind(&NTPSnippetsService::OnSnippetImageFetchedFromDatabase, | 322 base::Bind(&NTPSnippetsService::OnSnippetImageFetchedFromDatabase, |
320 base::Unretained(this), snippet_id, callback)); | 323 base::Unretained(this), callback, snippet_id)); |
321 } | 324 } |
322 | 325 |
323 void NTPSnippetsService::ClearCachedSuggestionsForDebugging(Category category) { | 326 void NTPSnippetsService::ClearCachedSuggestionsForDebugging(Category category) { |
324 DCHECK_EQ(category, provided_category_); | 327 DCHECK_EQ(category, provided_category_); |
325 if (!initialized()) | 328 if (!initialized()) |
326 return; | 329 return; |
327 | 330 |
328 if (snippets_.empty()) | 331 if (snippets_.empty()) |
329 return; | 332 return; |
330 | 333 |
(...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
620 if (snippet->expiry_date() < next_expiry) | 623 if (snippet->expiry_date() < next_expiry) |
621 next_expiry = snippet->expiry_date(); | 624 next_expiry = snippet->expiry_date(); |
622 } | 625 } |
623 DCHECK_GT(next_expiry, expiry); | 626 DCHECK_GT(next_expiry, expiry); |
624 expiry_timer_.Start(FROM_HERE, next_expiry - expiry, | 627 expiry_timer_.Start(FROM_HERE, next_expiry - expiry, |
625 base::Bind(&NTPSnippetsService::ClearExpiredSnippets, | 628 base::Bind(&NTPSnippetsService::ClearExpiredSnippets, |
626 base::Unretained(this))); | 629 base::Unretained(this))); |
627 } | 630 } |
628 | 631 |
629 void NTPSnippetsService::OnSnippetImageFetchedFromDatabase( | 632 void NTPSnippetsService::OnSnippetImageFetchedFromDatabase( |
| 633 const ImageFetchedCallback& callback, |
630 const std::string& snippet_id, | 634 const std::string& snippet_id, |
631 const ImageFetchedCallback& callback, | |
632 std::string data) { | 635 std::string data) { |
633 // |image_decoder_| is null in tests. | 636 // |image_decoder_| is null in tests. |
634 if (image_decoder_ && !data.empty()) { | 637 if (image_decoder_ && !data.empty()) { |
635 image_decoder_->DecodeImage( | 638 image_decoder_->DecodeImage( |
636 std::move(data), | 639 std::move(data), |
637 base::Bind(&NTPSnippetsService::OnSnippetImageDecoded, | 640 base::Bind(&NTPSnippetsService::OnSnippetImageDecodedFromDatabase, |
638 base::Unretained(this), snippet_id, callback)); | 641 base::Unretained(this), callback, snippet_id)); |
639 return; | 642 return; |
640 } | 643 } |
641 | 644 |
642 // Fetching from the DB failed; start a network fetch. | 645 // Fetching from the DB failed; start a network fetch. |
643 FetchSnippetImageFromNetwork(snippet_id, callback); | 646 FetchSnippetImageFromNetwork(snippet_id, callback); |
644 } | 647 } |
645 | 648 |
646 void NTPSnippetsService::OnSnippetImageDecoded( | 649 void NTPSnippetsService::OnSnippetImageDecodedFromDatabase( |
| 650 const ImageFetchedCallback& callback, |
647 const std::string& snippet_id, | 651 const std::string& snippet_id, |
648 const ImageFetchedCallback& callback, | |
649 const gfx::Image& image) { | 652 const gfx::Image& image) { |
650 if (!image.IsEmpty()) { | 653 if (!image.IsEmpty()) { |
651 callback.Run(MakeUniqueID(provided_category_, snippet_id), image); | 654 callback.Run(MakeUniqueID(provided_category_, snippet_id), image); |
652 return; | 655 return; |
653 } | 656 } |
654 | 657 |
655 // If decoding the image failed, delete the DB entry. | 658 // If decoding the image failed, delete the DB entry. |
656 database_->DeleteImage(snippet_id); | 659 database_->DeleteImage(snippet_id); |
657 | 660 |
658 FetchSnippetImageFromNetwork(snippet_id, callback); | 661 FetchSnippetImageFromNetwork(snippet_id, callback); |
659 } | 662 } |
660 | 663 |
661 void NTPSnippetsService::FetchSnippetImageFromNetwork( | 664 void NTPSnippetsService::FetchSnippetImageFromNetwork( |
662 const std::string& snippet_id, | 665 const std::string& snippet_id, |
663 const ImageFetchedCallback& callback) { | 666 const ImageFetchedCallback& callback) { |
664 auto it = | 667 auto it = |
665 std::find_if(snippets_.begin(), snippets_.end(), | 668 std::find_if(snippets_.begin(), snippets_.end(), |
666 [&snippet_id](const std::unique_ptr<NTPSnippet>& snippet) { | 669 [&snippet_id](const std::unique_ptr<NTPSnippet>& snippet) { |
667 return snippet->id() == snippet_id; | 670 return snippet->id() == snippet_id; |
668 }); | 671 }); |
669 if (it == snippets_.end()) { | 672 |
670 callback.Run(MakeUniqueID(provided_category_, snippet_id), gfx::Image()); | 673 if (it == snippets_.end() || |
| 674 !thumbnail_requests_throttler_.DemandQuotaForRequest( |
| 675 /*interactive_request=*/true)) { |
| 676 // Return an empty image. Directly, this is never synchronous with the |
| 677 // original FetchSuggestionImage() call - an asynchronous database query has |
| 678 // happened in the meantime. |
| 679 OnSnippetImageDecodedFromNetwork(callback, snippet_id, gfx::Image()); |
671 return; | 680 return; |
672 } | 681 } |
673 | 682 |
674 const NTPSnippet& snippet = *it->get(); | 683 const NTPSnippet& snippet = *it->get(); |
| 684 |
| 685 // The image fetcher calls OnImageDataFetched() with the raw data (this object |
| 686 // is an ImageFetcherDelegate) and then also |
| 687 // OnSnippetImageDecodedFromNetwork() after the raw data gets decoded. |
675 image_fetcher_->StartOrQueueNetworkRequest( | 688 image_fetcher_->StartOrQueueNetworkRequest( |
676 snippet.id(), snippet.salient_image_url(), callback); | 689 snippet.id(), snippet.salient_image_url(), |
| 690 base::Bind(&NTPSnippetsService::OnSnippetImageDecodedFromNetwork, |
| 691 base::Unretained(this), callback)); |
| 692 } |
| 693 |
| 694 void NTPSnippetsService::OnSnippetImageDecodedFromNetwork( |
| 695 const ImageFetchedCallback& callback, |
| 696 const std::string& snippet_id, |
| 697 const gfx::Image& image) { |
| 698 callback.Run(MakeUniqueID(provided_category_, snippet_id), image); |
677 } | 699 } |
678 | 700 |
679 void NTPSnippetsService::EnterStateEnabled(bool fetch_snippets) { | 701 void NTPSnippetsService::EnterStateEnabled(bool fetch_snippets) { |
680 if (fetch_snippets) | 702 if (fetch_snippets) |
681 FetchSnippets(/*force_request=*/false); | 703 FetchSnippets(/*force_request=*/false); |
682 | 704 |
683 // FetchSnippets should set the status to |AVAILABLE_LOADING| if relevant, | 705 // FetchSnippets should set the status to |AVAILABLE_LOADING| if relevant, |
684 // otherwise we transition to |AVAILABLE| here. | 706 // otherwise we transition to |AVAILABLE| here. |
685 if (category_status_ != CategoryStatus::AVAILABLE_LOADING) | 707 if (category_status_ != CategoryStatus::AVAILABLE_LOADING) |
686 UpdateCategoryStatus(CategoryStatus::AVAILABLE); | 708 UpdateCategoryStatus(CategoryStatus::AVAILABLE); |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
813 void NTPSnippetsService::UpdateCategoryStatus(CategoryStatus status) { | 835 void NTPSnippetsService::UpdateCategoryStatus(CategoryStatus status) { |
814 if (status == category_status_) | 836 if (status == category_status_) |
815 return; | 837 return; |
816 | 838 |
817 category_status_ = status; | 839 category_status_ = status; |
818 observer()->OnCategoryStatusChanged(this, provided_category_, | 840 observer()->OnCategoryStatusChanged(this, provided_category_, |
819 category_status_); | 841 category_status_); |
820 } | 842 } |
821 | 843 |
822 } // namespace ntp_snippets | 844 } // namespace ntp_snippets |
OLD | NEW |