Chromium Code Reviews| 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 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 178 snippets->erase( | 178 snippets->erase( |
| 179 std::remove_if( | 179 std::remove_if( |
| 180 snippets->begin(), snippets->end(), | 180 snippets->begin(), snippets->end(), |
| 181 [](const std::unique_ptr<NTPSnippet>& snippet) { return !snippet; }), | 181 [](const std::unique_ptr<NTPSnippet>& snippet) { return !snippet; }), |
| 182 snippets->end()); | 182 snippets->end()); |
| 183 } | 183 } |
| 184 | 184 |
| 185 } // namespace | 185 } // namespace |
| 186 | 186 |
| 187 NTPSnippetsService::NTPSnippetsService( | 187 NTPSnippetsService::NTPSnippetsService( |
| 188 bool enabled, | 188 Observer* observer, |
| 189 CategoryFactory* category_factory, | |
| 189 PrefService* pref_service, | 190 PrefService* pref_service, |
| 190 SuggestionsService* suggestions_service, | 191 SuggestionsService* suggestions_service, |
| 191 CategoryFactory* category_factory, | |
| 192 const std::string& application_language_code, | 192 const std::string& application_language_code, |
| 193 NTPSnippetsScheduler* scheduler, | 193 NTPSnippetsScheduler* scheduler, |
| 194 std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher, | 194 std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher, |
| 195 std::unique_ptr<ImageFetcher> image_fetcher, | 195 std::unique_ptr<ImageFetcher> image_fetcher, |
| 196 std::unique_ptr<ImageDecoder> image_decoder, | 196 std::unique_ptr<ImageDecoder> image_decoder, |
| 197 std::unique_ptr<NTPSnippetsDatabase> database, | 197 std::unique_ptr<NTPSnippetsDatabase> database, |
| 198 std::unique_ptr<NTPSnippetsStatusService> status_service) | 198 std::unique_ptr<NTPSnippetsStatusService> status_service) |
| 199 : ContentSuggestionsProvider(category_factory), | 199 : ContentSuggestionsProvider(observer, category_factory), |
| 200 state_(State::NOT_INITED), | 200 state_(State::NOT_INITED), |
| 201 category_status_(CategoryStatus::INITIALIZING), | 201 category_status_(CategoryStatus::INITIALIZING), |
| 202 pref_service_(pref_service), | 202 pref_service_(pref_service), |
| 203 suggestions_service_(suggestions_service), | 203 suggestions_service_(suggestions_service), |
| 204 application_language_code_(application_language_code), | 204 application_language_code_(application_language_code), |
| 205 observer_(nullptr), | |
| 206 scheduler_(scheduler), | 205 scheduler_(scheduler), |
| 207 snippets_fetcher_(std::move(snippets_fetcher)), | 206 snippets_fetcher_(std::move(snippets_fetcher)), |
| 208 image_fetcher_(std::move(image_fetcher)), | 207 image_fetcher_(std::move(image_fetcher)), |
| 209 image_decoder_(std::move(image_decoder)), | 208 image_decoder_(std::move(image_decoder)), |
| 210 database_(std::move(database)), | 209 database_(std::move(database)), |
| 211 snippets_status_service_(std::move(status_service)), | 210 snippets_status_service_(std::move(status_service)), |
| 212 fetch_after_load_(false), | 211 fetch_after_load_(false), |
| 213 provided_category_( | 212 provided_category_( |
| 214 category_factory->FromKnownCategory(KnownCategories::ARTICLES)) { | 213 category_factory->FromKnownCategory(KnownCategories::ARTICLES)) { |
| 215 // In some cases, don't even bother loading the database. | 214 // In some cases, don't even bother loading the database. |
|
Marc Treib
2016/08/03 11:53:23
Not really appropriate anymore
Philipp Keck
2016/08/03 12:28:24
Done.
| |
| 216 if (!enabled) { | |
| 217 EnterState(State::SHUT_DOWN, CategoryStatus::CATEGORY_EXPLICITLY_DISABLED); | |
| 218 return; | |
| 219 } | |
| 220 if (database_->IsErrorState()) { | 215 if (database_->IsErrorState()) { |
| 221 EnterState(State::SHUT_DOWN, CategoryStatus::LOADING_ERROR); | 216 EnterState(State::ERROR, CategoryStatus::LOADING_ERROR); |
| 222 return; | 217 return; |
| 223 } | 218 } |
| 224 | 219 |
| 225 database_->SetErrorCallback(base::Bind(&NTPSnippetsService::OnDatabaseError, | 220 database_->SetErrorCallback(base::Bind(&NTPSnippetsService::OnDatabaseError, |
| 226 base::Unretained(this))); | 221 base::Unretained(this))); |
| 227 | 222 |
| 228 // TODO(pke): Move this to SetObserver as soon as the UI reads from the | |
| 229 // ContentSuggestionsService directly. | |
| 230 // We transition to other states while finalizing the initialization, when the | 223 // We transition to other states while finalizing the initialization, when the |
| 231 // database is done loading. | 224 // database is done loading. |
| 232 database_->LoadSnippets(base::Bind(&NTPSnippetsService::OnDatabaseLoaded, | 225 database_->LoadSnippets(base::Bind(&NTPSnippetsService::OnDatabaseLoaded, |
| 233 base::Unretained(this))); | 226 base::Unretained(this))); |
| 234 } | 227 } |
| 235 | 228 |
| 236 NTPSnippetsService::~NTPSnippetsService() { | 229 NTPSnippetsService::~NTPSnippetsService() { |
| 237 DCHECK(state_ == State::SHUT_DOWN); | 230 expiry_timer_.Stop(); |
|
Marc Treib
2016/08/03 11:53:23
I think this isn't necessary, the timer will be de
Philipp Keck
2016/08/03 12:28:24
Indeed. Done.
| |
| 231 RescheduleFetching(); | |
|
Marc Treib
2016/08/03 11:53:23
Why is this here? Note that we do NOT want to un-s
Philipp Keck
2016/08/03 12:28:24
Both of these lines are here because they previous
Marc Treib
2016/08/03 12:37:56
Huh, indeed. That line was added by dgn in https:/
Philipp Keck
2016/08/03 12:57:23
Ok. I just noticed that I did change the observabl
Marc Treib
2016/08/03 13:01:18
New plan: I'll land a fix for this first, then may
| |
| 238 } | 232 } |
| 239 | 233 |
| 240 // static | 234 // static |
| 241 void NTPSnippetsService::RegisterProfilePrefs(PrefRegistrySimple* registry) { | 235 void NTPSnippetsService::RegisterProfilePrefs(PrefRegistrySimple* registry) { |
| 242 registry->RegisterListPref(prefs::kSnippetHosts); | 236 registry->RegisterListPref(prefs::kSnippetHosts); |
| 243 | 237 |
| 244 NTPSnippetsStatusService::RegisterProfilePrefs(registry); | 238 NTPSnippetsStatusService::RegisterProfilePrefs(registry); |
| 245 } | 239 } |
| 246 | 240 |
| 247 // Inherited from KeyedService. | |
| 248 void NTPSnippetsService::Shutdown() { | |
| 249 EnterState(State::SHUT_DOWN, CategoryStatus::NOT_PROVIDED); | |
| 250 } | |
| 251 | |
| 252 void NTPSnippetsService::FetchSnippets(bool force_request) { | 241 void NTPSnippetsService::FetchSnippets(bool force_request) { |
| 253 if (ready()) | 242 if (ready()) |
| 254 FetchSnippetsFromHosts(GetSuggestionsHosts(), force_request); | 243 FetchSnippetsFromHosts(GetSuggestionsHosts(), force_request); |
| 255 else | 244 else |
| 256 fetch_after_load_ = true; | 245 fetch_after_load_ = true; |
| 257 } | 246 } |
| 258 | 247 |
| 259 void NTPSnippetsService::FetchSnippetsFromHosts( | 248 void NTPSnippetsService::FetchSnippetsFromHosts( |
| 260 const std::set<std::string>& hosts, | 249 const std::set<std::string>& hosts, |
| 261 bool force_request) { | 250 bool force_request) { |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 348 if (!initialized()) | 337 if (!initialized()) |
| 349 return; | 338 return; |
| 350 | 339 |
| 351 if (dismissed_snippets_.empty()) | 340 if (dismissed_snippets_.empty()) |
| 352 return; | 341 return; |
| 353 | 342 |
| 354 database_->DeleteSnippets(dismissed_snippets_); | 343 database_->DeleteSnippets(dismissed_snippets_); |
| 355 dismissed_snippets_.clear(); | 344 dismissed_snippets_.clear(); |
| 356 } | 345 } |
| 357 | 346 |
| 358 void NTPSnippetsService::SetObserver(Observer* observer) { | |
| 359 observer_ = observer; | |
| 360 } | |
| 361 | |
| 362 CategoryStatus NTPSnippetsService::GetCategoryStatus(Category category) { | 347 CategoryStatus NTPSnippetsService::GetCategoryStatus(Category category) { |
| 363 DCHECK(category.IsKnownCategory(KnownCategories::ARTICLES)); | 348 DCHECK(category.IsKnownCategory(KnownCategories::ARTICLES)); |
| 364 return category_status_; | 349 return category_status_; |
| 365 } | 350 } |
| 366 | 351 |
| 367 void NTPSnippetsService::AddObserver(NTPSnippetsServiceObserver* observer) { | |
| 368 observers_.AddObserver(observer); | |
| 369 } | |
| 370 | |
| 371 void NTPSnippetsService::RemoveObserver(NTPSnippetsServiceObserver* observer) { | |
| 372 observers_.RemoveObserver(observer); | |
| 373 } | |
| 374 | |
| 375 // static | 352 // static |
| 376 int NTPSnippetsService::GetMaxSnippetCountForTesting() { | 353 int NTPSnippetsService::GetMaxSnippetCountForTesting() { |
| 377 return kMaxSnippetCount; | 354 return kMaxSnippetCount; |
| 378 } | 355 } |
| 379 | 356 |
| 380 //////////////////////////////////////////////////////////////////////////////// | 357 //////////////////////////////////////////////////////////////////////////////// |
| 381 // Private methods | 358 // Private methods |
| 382 | 359 |
| 383 // image_fetcher::ImageFetcherDelegate implementation. | 360 // image_fetcher::ImageFetcherDelegate implementation. |
| 384 void NTPSnippetsService::OnImageDataFetched(const std::string& snippet_id, | 361 void NTPSnippetsService::OnImageDataFetched(const std::string& snippet_id, |
| 385 const std::string& image_data) { | 362 const std::string& image_data) { |
| 386 if (image_data.empty()) | 363 if (image_data.empty()) |
| 387 return; | 364 return; |
| 388 | 365 |
| 389 // Only save the image if the corresponding snippet still exists. | 366 // Only save the image if the corresponding snippet still exists. |
| 390 auto it = | 367 auto it = |
| 391 std::find_if(snippets_.begin(), snippets_.end(), | 368 std::find_if(snippets_.begin(), snippets_.end(), |
| 392 [&snippet_id](const std::unique_ptr<NTPSnippet>& snippet) { | 369 [&snippet_id](const std::unique_ptr<NTPSnippet>& snippet) { |
| 393 return snippet->id() == snippet_id; | 370 return snippet->id() == snippet_id; |
| 394 }); | 371 }); |
| 395 if (it == snippets_.end()) | 372 if (it == snippets_.end()) |
| 396 return; | 373 return; |
| 397 | 374 |
| 398 database_->SaveImage(snippet_id, image_data); | 375 database_->SaveImage(snippet_id, image_data); |
| 399 } | 376 } |
| 400 | 377 |
| 401 void NTPSnippetsService::OnDatabaseLoaded(NTPSnippet::PtrVector snippets) { | 378 void NTPSnippetsService::OnDatabaseLoaded(NTPSnippet::PtrVector snippets) { |
| 402 DCHECK(state_ == State::NOT_INITED || state_ == State::SHUT_DOWN); | 379 if (state_ == State::ERROR) |
| 403 if (state_ == State::SHUT_DOWN) | |
| 404 return; | 380 return; |
| 405 | 381 DCHECK(state_ == State::NOT_INITED); |
| 406 DCHECK(snippets_.empty()); | 382 DCHECK(snippets_.empty()); |
| 407 DCHECK(dismissed_snippets_.empty()); | 383 DCHECK(dismissed_snippets_.empty()); |
| 408 for (std::unique_ptr<NTPSnippet>& snippet : snippets) { | 384 for (std::unique_ptr<NTPSnippet>& snippet : snippets) { |
| 409 if (snippet->is_dismissed()) | 385 if (snippet->is_dismissed()) |
| 410 dismissed_snippets_.emplace_back(std::move(snippet)); | 386 dismissed_snippets_.emplace_back(std::move(snippet)); |
| 411 else | 387 else |
| 412 snippets_.emplace_back(std::move(snippet)); | 388 snippets_.emplace_back(std::move(snippet)); |
| 413 } | 389 } |
| 414 std::sort(snippets_.begin(), snippets_.end(), | 390 std::sort(snippets_.begin(), snippets_.end(), |
| 415 [](const std::unique_ptr<NTPSnippet>& lhs, | 391 [](const std::unique_ptr<NTPSnippet>& lhs, |
| 416 const std::unique_ptr<NTPSnippet>& rhs) { | 392 const std::unique_ptr<NTPSnippet>& rhs) { |
| 417 return lhs->score() > rhs->score(); | 393 return lhs->score() > rhs->score(); |
| 418 }); | 394 }); |
| 419 | 395 |
| 420 ClearExpiredSnippets(); | 396 ClearExpiredSnippets(); |
| 421 FinishInitialization(); | 397 FinishInitialization(); |
| 422 } | 398 } |
| 423 | 399 |
| 424 void NTPSnippetsService::OnDatabaseError() { | 400 void NTPSnippetsService::OnDatabaseError() { |
| 425 EnterState(State::SHUT_DOWN, CategoryStatus::LOADING_ERROR); | 401 EnterState(State::ERROR, CategoryStatus::LOADING_ERROR); |
| 426 } | 402 } |
| 427 | 403 |
| 428 // TODO(dgn): name clash between content suggestions and suggestions hosts. | 404 // TODO(dgn): name clash between content suggestions and suggestions hosts. |
| 429 // method name should be changed. | 405 // method name should be changed. |
| 430 void NTPSnippetsService::OnSuggestionsChanged( | 406 void NTPSnippetsService::OnSuggestionsChanged( |
| 431 const SuggestionsProfile& suggestions) { | 407 const SuggestionsProfile& suggestions) { |
| 432 DCHECK(initialized()); | 408 DCHECK(initialized()); |
| 433 | 409 |
| 434 std::set<std::string> hosts = GetSuggestionsHostsImpl(suggestions); | 410 std::set<std::string> hosts = GetSuggestionsHostsImpl(suggestions); |
| 435 if (hosts == GetSnippetHostsFromPrefs()) | 411 if (hosts == GetSnippetHostsFromPrefs()) |
| (...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 692 | 668 |
| 693 void NTPSnippetsService::EnterStateDisabled() { | 669 void NTPSnippetsService::EnterStateDisabled() { |
| 694 ClearCachedSuggestionsForDebugging(); | 670 ClearCachedSuggestionsForDebugging(); |
| 695 ClearDismissedSuggestionsForDebugging(); | 671 ClearDismissedSuggestionsForDebugging(); |
| 696 | 672 |
| 697 expiry_timer_.Stop(); | 673 expiry_timer_.Stop(); |
| 698 suggestions_service_subscription_.reset(); | 674 suggestions_service_subscription_.reset(); |
| 699 RescheduleFetching(); | 675 RescheduleFetching(); |
| 700 } | 676 } |
| 701 | 677 |
| 702 void NTPSnippetsService::EnterStateShutdown() { | 678 void NTPSnippetsService::EnterStateError() { |
| 703 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, | |
| 704 NTPSnippetsServiceShutdown()); | |
| 705 | |
| 706 expiry_timer_.Stop(); | 679 expiry_timer_.Stop(); |
| 707 suggestions_service_subscription_.reset(); | |
| 708 RescheduleFetching(); | 680 RescheduleFetching(); |
| 709 | |
| 710 snippets_status_service_.reset(); | |
|
Marc Treib
2016/08/03 11:53:23
Why did you remove these two lines?
Philipp Keck
2016/08/03 12:28:24
That was unintentional, because I had removed the
| |
| 711 } | 681 } |
| 712 | 682 |
| 713 void NTPSnippetsService::FinishInitialization() { | 683 void NTPSnippetsService::FinishInitialization() { |
| 714 snippets_fetcher_->SetCallback( | 684 snippets_fetcher_->SetCallback( |
| 715 base::Bind(&NTPSnippetsService::OnFetchFinished, base::Unretained(this))); | 685 base::Bind(&NTPSnippetsService::OnFetchFinished, base::Unretained(this))); |
| 716 | 686 |
| 717 // |image_fetcher_| can be null in tests. | 687 // |image_fetcher_| can be null in tests. |
| 718 if (image_fetcher_) { | 688 if (image_fetcher_) { |
| 719 image_fetcher_->SetImageFetcherDelegate(this); | 689 image_fetcher_->SetImageFetcherDelegate(this); |
| 720 image_fetcher_->SetDataUseServiceName( | 690 image_fetcher_->SetDataUseServiceName( |
| 721 data_use_measurement::DataUseUserData::NTP_SNIPPETS); | 691 data_use_measurement::DataUseUserData::NTP_SNIPPETS); |
| 722 } | 692 } |
| 723 | 693 |
| 724 // Note: Initializing the status service will run the callback right away with | 694 // Note: Initializing the status service will run the callback right away with |
| 725 // the current state. | 695 // the current state. |
| 726 snippets_status_service_->Init(base::Bind( | 696 snippets_status_service_->Init(base::Bind( |
| 727 &NTPSnippetsService::OnDisabledReasonChanged, base::Unretained(this))); | 697 &NTPSnippetsService::OnDisabledReasonChanged, base::Unretained(this))); |
| 728 | 698 |
| 729 // Always notify here even if we got nothing from the database, because we | 699 // Always notify here even if we got nothing from the database, because we |
| 730 // don't know how long the fetch will take or if it will even complete. | 700 // don't know how long the fetch will take or if it will even complete. |
| 731 NotifyNewSuggestions(); | 701 NotifyNewSuggestions(); |
| 732 } | 702 } |
| 733 | 703 |
| 734 void NTPSnippetsService::OnDisabledReasonChanged( | 704 void NTPSnippetsService::OnDisabledReasonChanged( |
| 735 DisabledReason disabled_reason) { | 705 DisabledReason disabled_reason) { |
| 736 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, | |
| 737 NTPSnippetsServiceDisabledReasonChanged(disabled_reason)); | |
| 738 | |
| 739 switch (disabled_reason) { | 706 switch (disabled_reason) { |
| 740 case DisabledReason::NONE: | 707 case DisabledReason::NONE: |
| 741 // Do not change the status. That will be done in EnterStateEnabled() | 708 // Do not change the status. That will be done in EnterStateEnabled() |
| 742 EnterState(State::READY, category_status_); | 709 EnterState(State::READY, category_status_); |
| 743 break; | 710 break; |
| 744 | 711 |
| 745 case DisabledReason::EXPLICITLY_DISABLED: | 712 case DisabledReason::EXPLICITLY_DISABLED: |
| 746 EnterState(State::DISABLED, CategoryStatus::CATEGORY_EXPLICITLY_DISABLED); | 713 EnterState(State::DISABLED, CategoryStatus::CATEGORY_EXPLICITLY_DISABLED); |
| 747 break; | 714 break; |
| 748 | 715 |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 776 } | 743 } |
| 777 | 744 |
| 778 case State::DISABLED: | 745 case State::DISABLED: |
| 779 DCHECK(state_ == State::NOT_INITED || state_ == State::READY); | 746 DCHECK(state_ == State::NOT_INITED || state_ == State::READY); |
| 780 | 747 |
| 781 DVLOG(1) << "Entering state: DISABLED"; | 748 DVLOG(1) << "Entering state: DISABLED"; |
| 782 state_ = State::DISABLED; | 749 state_ = State::DISABLED; |
| 783 EnterStateDisabled(); | 750 EnterStateDisabled(); |
| 784 return; | 751 return; |
| 785 | 752 |
| 786 case State::SHUT_DOWN: | 753 case State::ERROR: |
| 787 DVLOG(1) << "Entering state: SHUT_DOWN"; | 754 DVLOG(1) << "Entering state: ERROR"; |
| 788 state_ = State::SHUT_DOWN; | 755 state_ = State::ERROR; |
| 789 EnterStateShutdown(); | 756 EnterStateError(); |
| 790 return; | 757 return; |
| 791 } | 758 } |
| 792 } | 759 } |
| 793 | 760 |
| 794 void NTPSnippetsService::NotifyNewSuggestions() { | 761 void NTPSnippetsService::NotifyNewSuggestions() { |
| 795 // TODO(pke): Remove this as soon as this becomes a pure provider. | |
| 796 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, | |
| 797 NTPSnippetsServiceLoaded()); | |
| 798 | |
| 799 if (!observer_) | |
| 800 return; | |
| 801 | |
| 802 std::vector<ContentSuggestion> result; | 762 std::vector<ContentSuggestion> result; |
| 803 for (const std::unique_ptr<NTPSnippet>& snippet : snippets_) { | 763 for (const std::unique_ptr<NTPSnippet>& snippet : snippets_) { |
| 804 if (!snippet->is_complete()) | 764 if (!snippet->is_complete()) |
| 805 continue; | 765 continue; |
| 806 ContentSuggestion suggestion( | 766 ContentSuggestion suggestion( |
| 807 MakeUniqueID(provided_category_, snippet->id()), | 767 MakeUniqueID(provided_category_, snippet->id()), |
| 808 snippet->best_source().url); | 768 snippet->best_source().url); |
| 809 suggestion.set_amp_url(snippet->best_source().amp_url); | 769 suggestion.set_amp_url(snippet->best_source().amp_url); |
| 810 suggestion.set_title(base::UTF8ToUTF16(snippet->title())); | 770 suggestion.set_title(base::UTF8ToUTF16(snippet->title())); |
| 811 suggestion.set_snippet_text(base::UTF8ToUTF16(snippet->snippet())); | 771 suggestion.set_snippet_text(base::UTF8ToUTF16(snippet->snippet())); |
| 812 suggestion.set_publish_date(snippet->publish_date()); | 772 suggestion.set_publish_date(snippet->publish_date()); |
| 813 suggestion.set_publisher_name( | 773 suggestion.set_publisher_name( |
| 814 base::UTF8ToUTF16(snippet->best_source().publisher_name)); | 774 base::UTF8ToUTF16(snippet->best_source().publisher_name)); |
| 815 suggestion.set_score(snippet->score()); | 775 suggestion.set_score(snippet->score()); |
| 816 result.emplace_back(std::move(suggestion)); | 776 result.emplace_back(std::move(suggestion)); |
| 817 } | 777 } |
| 818 observer_->OnNewSuggestions(this, provided_category_, std::move(result)); | 778 observer()->OnNewSuggestions(this, provided_category_, std::move(result)); |
| 819 } | 779 } |
| 820 | 780 |
| 821 void NTPSnippetsService::UpdateCategoryStatus(CategoryStatus status) { | 781 void NTPSnippetsService::UpdateCategoryStatus(CategoryStatus status) { |
| 822 if (status == category_status_) | 782 if (status == category_status_) |
| 823 return; | 783 return; |
| 824 | 784 |
| 825 category_status_ = status; | 785 category_status_ = status; |
| 826 if (observer_) { | 786 observer()->OnCategoryStatusChanged(this, provided_category_, |
| 827 observer_->OnCategoryStatusChanged(this, provided_category_, | 787 category_status_); |
| 828 category_status_); | |
| 829 } | |
| 830 } | 788 } |
| 831 | 789 |
| 832 } // namespace ntp_snippets | 790 } // namespace ntp_snippets |
| OLD | NEW |