| 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 |
| 11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
| 12 #include "base/files/file_path.h" | 12 #include "base/files/file_path.h" |
| 13 #include "base/files/file_util.h" | 13 #include "base/files/file_util.h" |
| 14 #include "base/location.h" | 14 #include "base/location.h" |
| 15 #include "base/metrics/histogram_macros.h" | 15 #include "base/metrics/histogram_macros.h" |
| 16 #include "base/metrics/sparse_histogram.h" | 16 #include "base/metrics/sparse_histogram.h" |
| 17 #include "base/path_service.h" | 17 #include "base/path_service.h" |
| 18 #include "base/strings/string_number_conversions.h" | 18 #include "base/strings/string_number_conversions.h" |
| 19 #include "base/task_runner_util.h" | 19 #include "base/task_runner_util.h" |
| 20 #include "base/time/time.h" | 20 #include "base/time/time.h" |
| 21 #include "base/values.h" | 21 #include "base/values.h" |
| 22 #include "components/image_fetcher/image_fetcher.h" | 22 #include "components/image_fetcher/image_fetcher.h" |
| 23 #include "components/ntp_snippets/ntp_snippets_constants.h" | 23 #include "components/ntp_snippets/ntp_snippets_constants.h" |
| 24 #include "components/ntp_snippets/ntp_snippets_database.h" |
| 24 #include "components/ntp_snippets/pref_names.h" | 25 #include "components/ntp_snippets/pref_names.h" |
| 25 #include "components/ntp_snippets/switches.h" | 26 #include "components/ntp_snippets/switches.h" |
| 26 #include "components/prefs/pref_registry_simple.h" | 27 #include "components/prefs/pref_registry_simple.h" |
| 27 #include "components/prefs/pref_service.h" | 28 #include "components/prefs/pref_service.h" |
| 28 #include "components/suggestions/proto/suggestions.pb.h" | 29 #include "components/suggestions/proto/suggestions.pb.h" |
| 29 #include "components/sync_driver/sync_service.h" | 30 #include "components/sync_driver/sync_service.h" |
| 30 #include "components/variations/variations_associated_data.h" | 31 #include "components/variations/variations_associated_data.h" |
| 31 #include "ui/gfx/image/image.h" | 32 #include "ui/gfx/image/image.h" |
| 32 | 33 |
| 33 using image_fetcher::ImageFetcher; | 34 using image_fetcher::ImageFetcher; |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 150 std::set<std::string> hosts; | 151 std::set<std::string> hosts; |
| 151 for (int i = 0; i < suggestions.suggestions_size(); ++i) { | 152 for (int i = 0; i < suggestions.suggestions_size(); ++i) { |
| 152 const ChromeSuggestion& suggestion = suggestions.suggestions(i); | 153 const ChromeSuggestion& suggestion = suggestions.suggestions(i); |
| 153 GURL url(suggestion.url()); | 154 GURL url(suggestion.url()); |
| 154 if (url.is_valid()) | 155 if (url.is_valid()) |
| 155 hosts.insert(url.host()); | 156 hosts.insert(url.host()); |
| 156 } | 157 } |
| 157 return hosts; | 158 return hosts; |
| 158 } | 159 } |
| 159 | 160 |
| 160 std::unique_ptr<base::ListValue> SnippetsToListValue( | |
| 161 const NTPSnippet::PtrVector& snippets) { | |
| 162 std::unique_ptr<base::ListValue> list(new base::ListValue); | |
| 163 for (const auto& snippet : snippets) { | |
| 164 std::unique_ptr<base::DictionaryValue> dict = snippet->ToDictionary(); | |
| 165 list->Append(std::move(dict)); | |
| 166 } | |
| 167 return list; | |
| 168 } | |
| 169 | |
| 170 void InsertAllIDs(const NTPSnippet::PtrVector& snippets, | 161 void InsertAllIDs(const NTPSnippet::PtrVector& snippets, |
| 171 std::set<std::string>* ids) { | 162 std::set<std::string>* ids) { |
| 172 for (const std::unique_ptr<NTPSnippet>& snippet : snippets) { | 163 for (const std::unique_ptr<NTPSnippet>& snippet : snippets) { |
| 173 ids->insert(snippet->id()); | 164 ids->insert(snippet->id()); |
| 174 for (const SnippetSource& source : snippet->sources()) | 165 for (const SnippetSource& source : snippet->sources()) |
| 175 ids->insert(source.url.spec()); | 166 ids->insert(source.url.spec()); |
| 176 } | 167 } |
| 177 } | 168 } |
| 178 | 169 |
| 170 void Compact(NTPSnippet::PtrVector* snippets) { |
| 171 snippets->erase( |
| 172 std::remove_if( |
| 173 snippets->begin(), snippets->end(), |
| 174 [](const std::unique_ptr<NTPSnippet>& snippet) { return !snippet; }), |
| 175 snippets->end()); |
| 176 } |
| 177 |
| 179 } // namespace | 178 } // namespace |
| 180 | 179 |
| 181 NTPSnippetsService::NTPSnippetsService( | 180 NTPSnippetsService::NTPSnippetsService( |
| 182 bool enabled, | 181 bool enabled, |
| 183 PrefService* pref_service, | 182 PrefService* pref_service, |
| 184 sync_driver::SyncService* sync_service, | 183 sync_driver::SyncService* sync_service, |
| 185 SuggestionsService* suggestions_service, | 184 SuggestionsService* suggestions_service, |
| 186 scoped_refptr<base::SequencedTaskRunner> file_task_runner, | |
| 187 const std::string& application_language_code, | 185 const std::string& application_language_code, |
| 188 NTPSnippetsScheduler* scheduler, | 186 NTPSnippetsScheduler* scheduler, |
| 189 std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher, | 187 std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher, |
| 190 std::unique_ptr<ImageFetcher> image_fetcher) | 188 std::unique_ptr<ImageFetcher> image_fetcher, |
| 189 std::unique_ptr<NTPSnippetsDatabase> database) |
| 191 : state_(State::INITED), | 190 : state_(State::INITED), |
| 192 enabled_(enabled), | 191 enabled_(enabled), |
| 193 pref_service_(pref_service), | 192 pref_service_(pref_service), |
| 194 sync_service_(sync_service), | 193 sync_service_(sync_service), |
| 195 sync_service_observer_(this), | 194 sync_service_observer_(this), |
| 196 suggestions_service_(suggestions_service), | 195 suggestions_service_(suggestions_service), |
| 197 file_task_runner_(file_task_runner), | |
| 198 application_language_code_(application_language_code), | 196 application_language_code_(application_language_code), |
| 199 scheduler_(scheduler), | 197 scheduler_(scheduler), |
| 200 snippets_fetcher_(std::move(snippets_fetcher)), | 198 snippets_fetcher_(std::move(snippets_fetcher)), |
| 201 image_fetcher_(std::move(image_fetcher)) { | 199 image_fetcher_(std::move(image_fetcher)), |
| 200 database_(std::move(database)), |
| 201 fetch_after_load_(false) { |
| 202 snippets_fetcher_->SetCallback(base::Bind( | 202 snippets_fetcher_->SetCallback(base::Bind( |
| 203 &NTPSnippetsService::OnFetchFinished, base::Unretained(this))); | 203 &NTPSnippetsService::OnFetchFinished, base::Unretained(this))); |
| 204 | 204 |
| 205 // |sync_service_| can be null in tests or if sync is disabled. | 205 // |sync_service_| can be null in tests or if sync is disabled. |
| 206 if (sync_service_) | 206 if (sync_service_) |
| 207 sync_service_observer_.Add(sync_service_); | 207 sync_service_observer_.Add(sync_service_); |
| 208 | 208 |
| 209 if (enabled_) { | 209 if (enabled_) { |
| 210 // |suggestions_service_| can be null in tests. | 210 database_->Load(base::Bind(&NTPSnippetsService::OnDatabaseLoaded, |
| 211 if (snippets_fetcher_->UsesHostRestrictions() && suggestions_service_) { | 211 base::Unretained(this))); |
| 212 suggestions_service_subscription_ = suggestions_service_->AddCallback( | |
| 213 base::Bind(&NTPSnippetsService::OnSuggestionsChanged, | |
| 214 base::Unretained(this))); | |
| 215 } | |
| 216 | |
| 217 // Get any existing snippets immediately from prefs. | |
| 218 LoadDiscardedSnippetsFromPrefs(); | |
| 219 LoadSnippetsFromPrefs(); | |
| 220 | |
| 221 // If we don't have any snippets yet, start a fetch. | |
| 222 if (snippets_.empty()) | |
| 223 FetchSnippets(); | |
| 224 } | 212 } |
| 225 | 213 |
| 226 RescheduleFetching(); | 214 RescheduleFetching(); |
| 215 |
| 216 ClearDeprecatedPrefs(); |
| 227 } | 217 } |
| 228 | 218 |
| 229 NTPSnippetsService::~NTPSnippetsService() { | 219 NTPSnippetsService::~NTPSnippetsService() { |
| 230 DCHECK(state_ == State::SHUT_DOWN); | 220 DCHECK(state_ == State::SHUT_DOWN); |
| 231 } | 221 } |
| 232 | 222 |
| 233 // static | 223 // static |
| 234 void NTPSnippetsService::RegisterProfilePrefs(PrefRegistrySimple* registry) { | 224 void NTPSnippetsService::RegisterProfilePrefs(PrefRegistrySimple* registry) { |
| 235 registry->RegisterListPref(prefs::kSnippets); | 225 registry->RegisterListPref(prefs::kDeprecatedSnippets); |
| 236 registry->RegisterListPref(prefs::kDiscardedSnippets); | 226 registry->RegisterListPref(prefs::kDeprecatedDiscardedSnippets); |
| 237 registry->RegisterListPref(prefs::kSnippetHosts); | 227 registry->RegisterListPref(prefs::kSnippetHosts); |
| 238 } | 228 } |
| 239 | 229 |
| 240 void NTPSnippetsService::Shutdown() { | 230 void NTPSnippetsService::Shutdown() { |
| 241 DCHECK(state_ == State::INITED); | 231 DCHECK(state_ == State::INITED || state_ == State::LOADED); |
| 242 state_ = State::SHUT_DOWN; | 232 state_ = State::SHUT_DOWN; |
| 243 | 233 |
| 244 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, | 234 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, |
| 245 NTPSnippetsServiceShutdown()); | 235 NTPSnippetsServiceShutdown()); |
| 236 expiry_timer_.Stop(); |
| 246 suggestions_service_subscription_.reset(); | 237 suggestions_service_subscription_.reset(); |
| 247 enabled_ = false; | 238 enabled_ = false; |
| 248 } | 239 } |
| 249 | 240 |
| 250 void NTPSnippetsService::FetchSnippets() { | 241 void NTPSnippetsService::FetchSnippets() { |
| 251 FetchSnippetsFromHosts(GetSuggestionsHosts()); | 242 if (loaded()) |
| 243 FetchSnippetsFromHosts(GetSuggestionsHosts()); |
| 244 else |
| 245 fetch_after_load_ = true; |
| 252 } | 246 } |
| 253 | 247 |
| 254 void NTPSnippetsService::FetchSnippetsFromHosts( | 248 void NTPSnippetsService::FetchSnippetsFromHosts( |
| 255 const std::set<std::string>& hosts) { | 249 const std::set<std::string>& hosts) { |
| 250 if (!loaded()) |
| 251 return; |
| 256 snippets_fetcher_->FetchSnippetsFromHosts(hosts, application_language_code_, | 252 snippets_fetcher_->FetchSnippetsFromHosts(hosts, application_language_code_, |
| 257 kMaxSnippetCount); | 253 kMaxSnippetCount); |
| 258 } | 254 } |
| 259 | 255 |
| 260 void NTPSnippetsService::RescheduleFetching() { | 256 void NTPSnippetsService::RescheduleFetching() { |
| 261 // The scheduler only exists on Android so far, it's null on other platforms. | 257 // The scheduler only exists on Android so far, it's null on other platforms. |
| 262 if (!scheduler_) | 258 if (!scheduler_) |
| 263 return; | 259 return; |
| 264 | 260 |
| 265 if (enabled_) { | 261 if (enabled_) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 286 return; | 282 return; |
| 287 } | 283 } |
| 288 | 284 |
| 289 const NTPSnippet& snippet = *it->get(); | 285 const NTPSnippet& snippet = *it->get(); |
| 290 image_fetcher_->StartOrQueueNetworkRequest( | 286 image_fetcher_->StartOrQueueNetworkRequest( |
| 291 snippet.id(), snippet.salient_image_url(), callback); | 287 snippet.id(), snippet.salient_image_url(), callback); |
| 292 // TODO(treib): Cache/persist the snippet image. | 288 // TODO(treib): Cache/persist the snippet image. |
| 293 } | 289 } |
| 294 | 290 |
| 295 void NTPSnippetsService::ClearSnippets() { | 291 void NTPSnippetsService::ClearSnippets() { |
| 292 if (!loaded()) |
| 293 return; |
| 294 |
| 295 database_->Delete(snippets_); |
| 296 snippets_.clear(); | 296 snippets_.clear(); |
| 297 | 297 |
| 298 StoreSnippetsToPrefs(); | |
| 299 | |
| 300 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, | 298 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, |
| 301 NTPSnippetsServiceLoaded()); | 299 NTPSnippetsServiceLoaded()); |
| 302 } | 300 } |
| 303 | 301 |
| 304 std::set<std::string> NTPSnippetsService::GetSuggestionsHosts() const { | 302 std::set<std::string> NTPSnippetsService::GetSuggestionsHosts() const { |
| 305 // |suggestions_service_| can be null in tests. | 303 // |suggestions_service_| can be null in tests. |
| 306 if (!suggestions_service_) | 304 if (!suggestions_service_) |
| 307 return std::set<std::string>(); | 305 return std::set<std::string>(); |
| 308 | 306 |
| 309 // TODO(treib) this should just call GetSnippetHostsFromPrefs | 307 // TODO(treib): This should just call GetSnippetHostsFromPrefs. |
| 310 return GetSuggestionsHostsImpl( | 308 return GetSuggestionsHostsImpl( |
| 311 suggestions_service_->GetSuggestionsDataFromCache()); | 309 suggestions_service_->GetSuggestionsDataFromCache()); |
| 312 } | 310 } |
| 313 | 311 |
| 314 bool NTPSnippetsService::DiscardSnippet(const std::string& snippet_id) { | 312 bool NTPSnippetsService::DiscardSnippet(const std::string& snippet_id) { |
| 313 if (!loaded()) |
| 314 return false; |
| 315 |
| 315 auto it = | 316 auto it = |
| 316 std::find_if(snippets_.begin(), snippets_.end(), | 317 std::find_if(snippets_.begin(), snippets_.end(), |
| 317 [&snippet_id](const std::unique_ptr<NTPSnippet>& snippet) { | 318 [&snippet_id](const std::unique_ptr<NTPSnippet>& snippet) { |
| 318 return snippet->id() == snippet_id; | 319 return snippet->id() == snippet_id; |
| 319 }); | 320 }); |
| 320 if (it == snippets_.end()) | 321 if (it == snippets_.end()) |
| 321 return false; | 322 return false; |
| 323 |
| 324 (*it)->set_discarded(true); |
| 325 |
| 326 database_->Save(**it); |
| 327 |
| 322 discarded_snippets_.push_back(std::move(*it)); | 328 discarded_snippets_.push_back(std::move(*it)); |
| 323 snippets_.erase(it); | 329 snippets_.erase(it); |
| 324 StoreDiscardedSnippetsToPrefs(); | 330 |
| 325 StoreSnippetsToPrefs(); | |
| 326 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, | 331 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, |
| 327 NTPSnippetsServiceLoaded()); | 332 NTPSnippetsServiceLoaded()); |
| 328 return true; | 333 return true; |
| 329 } | 334 } |
| 330 | 335 |
| 331 void NTPSnippetsService::ClearDiscardedSnippets() { | 336 void NTPSnippetsService::ClearDiscardedSnippets() { |
| 337 if (!loaded()) |
| 338 return; |
| 339 |
| 340 database_->Delete(discarded_snippets_); |
| 332 discarded_snippets_.clear(); | 341 discarded_snippets_.clear(); |
| 333 StoreDiscardedSnippetsToPrefs(); | 342 |
| 334 FetchSnippets(); | 343 FetchSnippets(); |
| 335 } | 344 } |
| 336 | 345 |
| 337 void NTPSnippetsService::AddObserver(NTPSnippetsServiceObserver* observer) { | 346 void NTPSnippetsService::AddObserver(NTPSnippetsServiceObserver* observer) { |
| 338 observers_.AddObserver(observer); | 347 observers_.AddObserver(observer); |
| 339 } | 348 } |
| 340 | 349 |
| 341 void NTPSnippetsService::RemoveObserver(NTPSnippetsServiceObserver* observer) { | 350 void NTPSnippetsService::RemoveObserver(NTPSnippetsServiceObserver* observer) { |
| 342 observers_.RemoveObserver(observer); | 351 observers_.RemoveObserver(observer); |
| 343 } | 352 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 358 NTPSnippetsServiceDisabled()); | 367 NTPSnippetsServiceDisabled()); |
| 359 return; | 368 return; |
| 360 } | 369 } |
| 361 | 370 |
| 362 // TODO(dgn): When the data sources change, we may want to not fetch here, | 371 // TODO(dgn): When the data sources change, we may want to not fetch here, |
| 363 // as we will get notified of changes from the snippet sources as well, and | 372 // as we will get notified of changes from the snippet sources as well, and |
| 364 // start multiple fetches. | 373 // start multiple fetches. |
| 365 FetchSnippets(); | 374 FetchSnippets(); |
| 366 } | 375 } |
| 367 | 376 |
| 377 void NTPSnippetsService::OnDatabaseLoaded(NTPSnippet::PtrVector snippets) { |
| 378 DCHECK(state_ == State::INITED || state_ == State::SHUT_DOWN); |
| 379 if (state_ == State::SHUT_DOWN) |
| 380 return; |
| 381 state_ = State::LOADED; |
| 382 |
| 383 DCHECK(snippets_.empty()); |
| 384 DCHECK(discarded_snippets_.empty()); |
| 385 for (std::unique_ptr<NTPSnippet>& snippet : snippets) { |
| 386 if (snippet->is_discarded()) |
| 387 discarded_snippets_.emplace_back(std::move(snippet)); |
| 388 else |
| 389 snippets_.emplace_back(std::move(snippet)); |
| 390 } |
| 391 std::sort(snippets_.begin(), snippets_.end(), |
| 392 [](const std::unique_ptr<NTPSnippet>& lhs, |
| 393 const std::unique_ptr<NTPSnippet>& rhs) { |
| 394 return lhs->score() > rhs->score(); |
| 395 }); |
| 396 LoadingSnippetsFinished(); |
| 397 |
| 398 // If host restrictions are enabled, register for host list updates. |
| 399 // |suggestions_service_| can be null in tests. |
| 400 if (snippets_fetcher_->UsesHostRestrictions() && suggestions_service_) { |
| 401 suggestions_service_subscription_ = |
| 402 suggestions_service_->AddCallback(base::Bind( |
| 403 &NTPSnippetsService::OnSuggestionsChanged, base::Unretained(this))); |
| 404 } |
| 405 |
| 406 // Start a fetch if we don't have any snippets yet, or a fetch was requested |
| 407 // earlier. |
| 408 if (snippets_.empty() || fetch_after_load_) { |
| 409 fetch_after_load_ = false; |
| 410 FetchSnippets(); |
| 411 } |
| 412 } |
| 413 |
| 368 void NTPSnippetsService::OnSuggestionsChanged( | 414 void NTPSnippetsService::OnSuggestionsChanged( |
| 369 const SuggestionsProfile& suggestions) { | 415 const SuggestionsProfile& suggestions) { |
| 416 DCHECK(loaded()); |
| 417 |
| 370 std::set<std::string> hosts = GetSuggestionsHostsImpl(suggestions); | 418 std::set<std::string> hosts = GetSuggestionsHostsImpl(suggestions); |
| 371 if (hosts == GetSnippetHostsFromPrefs()) | 419 if (hosts == GetSnippetHostsFromPrefs()) |
| 372 return; | 420 return; |
| 373 | 421 |
| 374 // Remove existing snippets that aren't in the suggestions anymore. | 422 // Remove existing snippets that aren't in the suggestions anymore. |
| 375 // TODO(treib,maybelle): If there is another source with an allowed host, | 423 // TODO(treib,maybelle): If there is another source with an allowed host, |
| 376 // then we should fall back to that. | 424 // then we should fall back to that. |
| 377 snippets_.erase( | 425 // First, move them over into |to_delete|. |
| 378 std::remove_if(snippets_.begin(), snippets_.end(), | 426 NTPSnippet::PtrVector to_delete; |
| 379 [&hosts](const std::unique_ptr<NTPSnippet>& snippet) { | 427 for (std::unique_ptr<NTPSnippet>& snippet : snippets_) { |
| 380 return !hosts.count(snippet->best_source().url.host()); | 428 if (!hosts.count(snippet->best_source().url.host())) |
| 381 }), | 429 to_delete.emplace_back(std::move(snippet)); |
| 382 snippets_.end()); | 430 } |
| 431 Compact(&snippets_); |
| 432 // Then delete the removed snippets from the database. |
| 433 database_->Delete(to_delete); |
| 383 | 434 |
| 384 StoreSnippetsToPrefs(); | |
| 385 StoreSnippetHostsToPrefs(hosts); | 435 StoreSnippetHostsToPrefs(hosts); |
| 386 | 436 |
| 387 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, | 437 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, |
| 388 NTPSnippetsServiceLoaded()); | 438 NTPSnippetsServiceLoaded()); |
| 389 | 439 |
| 390 FetchSnippetsFromHosts(hosts); | 440 FetchSnippetsFromHosts(hosts); |
| 391 } | 441 } |
| 392 | 442 |
| 393 void NTPSnippetsService::OnFetchFinished( | 443 void NTPSnippetsService::OnFetchFinished( |
| 394 NTPSnippetsFetcher::OptionalSnippets snippets) { | 444 NTPSnippetsFetcher::OptionalSnippets snippets) { |
| 445 if (!loaded()) |
| 446 return; |
| 447 |
| 395 if (snippets) { | 448 if (snippets) { |
| 396 // Sparse histogram used because the number of snippets is small (bound by | 449 // Sparse histogram used because the number of snippets is small (bound by |
| 397 // kMaxSnippetCount). | 450 // kMaxSnippetCount). |
| 398 DCHECK_LE(snippets->size(), static_cast<size_t>(kMaxSnippetCount)); | 451 DCHECK_LE(snippets->size(), static_cast<size_t>(kMaxSnippetCount)); |
| 399 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticlesFetched", | 452 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticlesFetched", |
| 400 snippets->size()); | 453 snippets->size()); |
| 401 MergeSnippets(std::move(*snippets)); | 454 MergeSnippets(std::move(*snippets)); |
| 402 } | 455 } |
| 403 LoadingSnippetsFinished(); | 456 LoadingSnippetsFinished(); |
| 404 } | 457 } |
| 405 | 458 |
| 406 void NTPSnippetsService::MergeSnippets(NTPSnippet::PtrVector new_snippets) { | 459 void NTPSnippetsService::MergeSnippets(NTPSnippet::PtrVector new_snippets) { |
| 460 DCHECK(loaded()); |
| 461 |
| 407 // Remove new snippets that we already have, or that have been discarded. | 462 // Remove new snippets that we already have, or that have been discarded. |
| 408 std::set<std::string> old_snippet_ids; | 463 std::set<std::string> old_snippet_ids; |
| 409 InsertAllIDs(discarded_snippets_, &old_snippet_ids); | 464 InsertAllIDs(discarded_snippets_, &old_snippet_ids); |
| 410 InsertAllIDs(snippets_, &old_snippet_ids); | 465 InsertAllIDs(snippets_, &old_snippet_ids); |
| 411 new_snippets.erase( | 466 new_snippets.erase( |
| 412 std::remove_if( | 467 std::remove_if( |
| 413 new_snippets.begin(), new_snippets.end(), | 468 new_snippets.begin(), new_snippets.end(), |
| 414 [&old_snippet_ids](const std::unique_ptr<NTPSnippet>& snippet) { | 469 [&old_snippet_ids](const std::unique_ptr<NTPSnippet>& snippet) { |
| 415 if (old_snippet_ids.count(snippet->id())) | 470 if (old_snippet_ids.count(snippet->id())) |
| 416 return true; | 471 return true; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 447 }), | 502 }), |
| 448 new_snippets.end()); | 503 new_snippets.end()); |
| 449 int num_snippets_discarded = num_new_snippets - new_snippets.size(); | 504 int num_snippets_discarded = num_new_snippets - new_snippets.size(); |
| 450 UMA_HISTOGRAM_BOOLEAN("NewTabPage.Snippets.IncompleteSnippetsAfterFetch", | 505 UMA_HISTOGRAM_BOOLEAN("NewTabPage.Snippets.IncompleteSnippetsAfterFetch", |
| 451 num_snippets_discarded > 0); | 506 num_snippets_discarded > 0); |
| 452 if (num_snippets_discarded > 0) { | 507 if (num_snippets_discarded > 0) { |
| 453 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumIncompleteSnippets", | 508 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumIncompleteSnippets", |
| 454 num_snippets_discarded); | 509 num_snippets_discarded); |
| 455 } | 510 } |
| 456 } | 511 } |
| 512 |
| 513 // Save the new snippets to the DB. |
| 514 database_->Save(new_snippets); |
| 515 |
| 457 // Insert the new snippets at the front. | 516 // Insert the new snippets at the front. |
| 458 snippets_.insert(snippets_.begin(), | 517 snippets_.insert(snippets_.begin(), |
| 459 std::make_move_iterator(new_snippets.begin()), | 518 std::make_move_iterator(new_snippets.begin()), |
| 460 std::make_move_iterator(new_snippets.end())); | 519 std::make_move_iterator(new_snippets.end())); |
| 461 } | 520 } |
| 462 | 521 |
| 463 void NTPSnippetsService::LoadSnippetsFromPrefs() { | |
| 464 NTPSnippet::PtrVector prefs_snippets; | |
| 465 bool success = NTPSnippet::AddFromListValue( | |
| 466 *pref_service_->GetList(prefs::kSnippets), &prefs_snippets); | |
| 467 DCHECK(success) << "Failed to parse snippets from prefs"; | |
| 468 MergeSnippets(std::move(prefs_snippets)); | |
| 469 LoadingSnippetsFinished(); | |
| 470 } | |
| 471 | |
| 472 void NTPSnippetsService::StoreSnippetsToPrefs() { | |
| 473 pref_service_->Set(prefs::kSnippets, *SnippetsToListValue(snippets_)); | |
| 474 } | |
| 475 | |
| 476 void NTPSnippetsService::LoadDiscardedSnippetsFromPrefs() { | |
| 477 discarded_snippets_.clear(); | |
| 478 bool success = NTPSnippet::AddFromListValue( | |
| 479 *pref_service_->GetList(prefs::kDiscardedSnippets), &discarded_snippets_); | |
| 480 DCHECK(success) << "Failed to parse discarded snippets from prefs"; | |
| 481 } | |
| 482 | |
| 483 void NTPSnippetsService::StoreDiscardedSnippetsToPrefs() { | |
| 484 pref_service_->Set(prefs::kDiscardedSnippets, | |
| 485 *SnippetsToListValue(discarded_snippets_)); | |
| 486 } | |
| 487 | |
| 488 std::set<std::string> NTPSnippetsService::GetSnippetHostsFromPrefs() const { | 522 std::set<std::string> NTPSnippetsService::GetSnippetHostsFromPrefs() const { |
| 489 std::set<std::string> hosts; | 523 std::set<std::string> hosts; |
| 490 const base::ListValue* list = pref_service_->GetList(prefs::kSnippetHosts); | 524 const base::ListValue* list = pref_service_->GetList(prefs::kSnippetHosts); |
| 491 for (const auto& value : *list) { | 525 for (const auto& value : *list) { |
| 492 std::string str; | 526 std::string str; |
| 493 bool success = value->GetAsString(&str); | 527 bool success = value->GetAsString(&str); |
| 494 DCHECK(success) << "Failed to parse snippet host from prefs"; | 528 DCHECK(success) << "Failed to parse snippet host from prefs"; |
| 495 hosts.insert(std::move(str)); | 529 hosts.insert(std::move(str)); |
| 496 } | 530 } |
| 497 return hosts; | 531 return hosts; |
| 498 } | 532 } |
| 499 | 533 |
| 500 void NTPSnippetsService::StoreSnippetHostsToPrefs( | 534 void NTPSnippetsService::StoreSnippetHostsToPrefs( |
| 501 const std::set<std::string>& hosts) { | 535 const std::set<std::string>& hosts) { |
| 502 base::ListValue list; | 536 base::ListValue list; |
| 503 for (const std::string& host : hosts) | 537 for (const std::string& host : hosts) |
| 504 list.AppendString(host); | 538 list.AppendString(host); |
| 505 pref_service_->Set(prefs::kSnippetHosts, list); | 539 pref_service_->Set(prefs::kSnippetHosts, list); |
| 506 } | 540 } |
| 507 | 541 |
| 508 void NTPSnippetsService::LoadingSnippetsFinished() { | 542 void NTPSnippetsService::LoadingSnippetsFinished() { |
| 543 DCHECK(loaded()); |
| 544 |
| 509 // Remove expired snippets. | 545 // Remove expired snippets. |
| 510 base::Time expiry = base::Time::Now(); | 546 base::Time expiry = base::Time::Now(); |
| 511 | 547 |
| 512 snippets_.erase( | 548 // Move expired snippets over into |to_delete|. |
| 513 std::remove_if(snippets_.begin(), snippets_.end(), | 549 NTPSnippet::PtrVector to_delete; |
| 514 [&expiry](const std::unique_ptr<NTPSnippet>& snippet) { | 550 for (std::unique_ptr<NTPSnippet>& snippet : snippets_) { |
| 515 return snippet->expiry_date() <= expiry; | 551 if (snippet->expiry_date() <= expiry) |
| 516 }), | 552 to_delete.emplace_back(std::move(snippet)); |
| 517 snippets_.end()); | 553 } |
| 554 Compact(&snippets_); |
| 518 | 555 |
| 519 // If there are more snippets now than we want to show, drop the extra ones | 556 // If there are still more snippets than we want to show, move the extra ones |
| 520 // from the end of the list. | 557 // over into |to_delete| as well. |
| 521 if (snippets_.size() > kMaxSnippetCount) | 558 if (snippets_.size() > kMaxSnippetCount) { |
| 559 to_delete.insert( |
| 560 to_delete.end(), |
| 561 std::make_move_iterator(snippets_.begin() + kMaxSnippetCount), |
| 562 std::make_move_iterator(snippets_.end())); |
| 522 snippets_.resize(kMaxSnippetCount); | 563 snippets_.resize(kMaxSnippetCount); |
| 564 } |
| 523 | 565 |
| 524 StoreSnippetsToPrefs(); | 566 // Move expired discarded snippets over into |to_delete| as well. |
| 567 for (std::unique_ptr<NTPSnippet>& snippet : discarded_snippets_) { |
| 568 if (snippet->expiry_date() <= expiry) |
| 569 to_delete.emplace_back(std::move(snippet)); |
| 570 } |
| 571 Compact(&discarded_snippets_); |
| 525 | 572 |
| 526 discarded_snippets_.erase( | 573 // Finally, actually delete the removed snippets from the DB. |
| 527 std::remove_if(discarded_snippets_.begin(), discarded_snippets_.end(), | 574 database_->Delete(to_delete); |
| 528 [&expiry](const std::unique_ptr<NTPSnippet>& snippet) { | |
| 529 return snippet->expiry_date() <= expiry; | |
| 530 }), | |
| 531 discarded_snippets_.end()); | |
| 532 StoreDiscardedSnippetsToPrefs(); | |
| 533 | 575 |
| 534 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticles", | 576 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticles", |
| 535 snippets_.size()); | 577 snippets_.size()); |
| 536 if (snippets_.empty() && !discarded_snippets_.empty()) { | 578 if (snippets_.empty() && !discarded_snippets_.empty()) { |
| 537 UMA_HISTOGRAM_COUNTS("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded", | 579 UMA_HISTOGRAM_COUNTS("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded", |
| 538 discarded_snippets_.size()); | 580 discarded_snippets_.size()); |
| 539 } | 581 } |
| 540 | 582 |
| 541 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, | 583 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, |
| 542 NTPSnippetsServiceLoaded()); | 584 NTPSnippetsServiceLoaded()); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 562 | 604 |
| 563 bool NTPSnippetsService::IsSyncStateIncompatible() { | 605 bool NTPSnippetsService::IsSyncStateIncompatible() { |
| 564 if (!sync_service_ || !sync_service_->CanSyncStart()) | 606 if (!sync_service_ || !sync_service_->CanSyncStart()) |
| 565 return true; | 607 return true; |
| 566 if (!sync_service_->IsSyncActive() || !sync_service_->ConfigurationDone()) | 608 if (!sync_service_->IsSyncActive() || !sync_service_->ConfigurationDone()) |
| 567 return false; // Sync service is not initialized, yet not disabled. | 609 return false; // Sync service is not initialized, yet not disabled. |
| 568 return !sync_service_->GetActiveDataTypes().Has( | 610 return !sync_service_->GetActiveDataTypes().Has( |
| 569 syncer::HISTORY_DELETE_DIRECTIVES); | 611 syncer::HISTORY_DELETE_DIRECTIVES); |
| 570 } | 612 } |
| 571 | 613 |
| 614 void NTPSnippetsService::ClearDeprecatedPrefs() { |
| 615 pref_service_->ClearPref(prefs::kDeprecatedSnippets); |
| 616 pref_service_->ClearPref(prefs::kDeprecatedDiscardedSnippets); |
| 617 } |
| 618 |
| 572 } // namespace ntp_snippets | 619 } // namespace ntp_snippets |
| OLD | NEW |