| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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/content_suggestions_service.h" | 5 #include "components/ntp_snippets/content_suggestions_service.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <iterator> | 8 #include <iterator> |
| 9 #include <set> | 9 #include <set> |
| 10 #include <utility> | 10 #include <utility> |
| (...skipping 16 matching lines...) Expand all Loading... |
| 27 user_classifier_(pref_service) { | 27 user_classifier_(pref_service) { |
| 28 // Can be null in tests. | 28 // Can be null in tests. |
| 29 if (history_service) | 29 if (history_service) |
| 30 history_service_observer_.Add(history_service); | 30 history_service_observer_.Add(history_service); |
| 31 } | 31 } |
| 32 | 32 |
| 33 ContentSuggestionsService::~ContentSuggestionsService() {} | 33 ContentSuggestionsService::~ContentSuggestionsService() {} |
| 34 | 34 |
| 35 void ContentSuggestionsService::Shutdown() { | 35 void ContentSuggestionsService::Shutdown() { |
| 36 ntp_snippets_service_ = nullptr; | 36 ntp_snippets_service_ = nullptr; |
| 37 id_category_map_.clear(); | |
| 38 suggestions_by_category_.clear(); | 37 suggestions_by_category_.clear(); |
| 39 providers_by_category_.clear(); | 38 providers_by_category_.clear(); |
| 40 categories_.clear(); | 39 categories_.clear(); |
| 41 providers_.clear(); | 40 providers_.clear(); |
| 42 state_ = State::DISABLED; | 41 state_ = State::DISABLED; |
| 43 FOR_EACH_OBSERVER(Observer, observers_, ContentSuggestionsServiceShutdown()); | 42 FOR_EACH_OBSERVER(Observer, observers_, ContentSuggestionsServiceShutdown()); |
| 44 } | 43 } |
| 45 | 44 |
| 46 CategoryStatus ContentSuggestionsService::GetCategoryStatus( | 45 CategoryStatus ContentSuggestionsService::GetCategoryStatus( |
| 47 Category category) const { | 46 Category category) const { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 68 ContentSuggestionsService::GetSuggestionsForCategory(Category category) const { | 67 ContentSuggestionsService::GetSuggestionsForCategory(Category category) const { |
| 69 auto iterator = suggestions_by_category_.find(category); | 68 auto iterator = suggestions_by_category_.find(category); |
| 70 if (iterator == suggestions_by_category_.end()) | 69 if (iterator == suggestions_by_category_.end()) |
| 71 return no_suggestions_; | 70 return no_suggestions_; |
| 72 return iterator->second; | 71 return iterator->second; |
| 73 } | 72 } |
| 74 | 73 |
| 75 void ContentSuggestionsService::FetchSuggestionImage( | 74 void ContentSuggestionsService::FetchSuggestionImage( |
| 76 const std::string& suggestion_id, | 75 const std::string& suggestion_id, |
| 77 const ImageFetchedCallback& callback) { | 76 const ImageFetchedCallback& callback) { |
| 78 if (!id_category_map_.count(suggestion_id)) { | 77 Category category = category_factory_.GetCategoryFromUniqueID(suggestion_id); |
| 79 LOG(WARNING) << "Requested image for unknown suggestion " << suggestion_id; | |
| 80 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 81 FROM_HERE, base::Bind(callback, gfx::Image())); | |
| 82 return; | |
| 83 } | |
| 84 Category category = id_category_map_.at(suggestion_id); | |
| 85 if (!providers_by_category_.count(category)) { | 78 if (!providers_by_category_.count(category)) { |
| 86 LOG(WARNING) << "Requested image for suggestion " << suggestion_id | 79 LOG(WARNING) << "Requested image for suggestion " << suggestion_id |
| 87 << " for unavailable category " << category; | 80 << " for unavailable category " << category; |
| 88 base::ThreadTaskRunnerHandle::Get()->PostTask( | 81 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 89 FROM_HERE, base::Bind(callback, gfx::Image())); | 82 FROM_HERE, base::Bind(callback, gfx::Image())); |
| 90 return; | 83 return; |
| 91 } | 84 } |
| 92 providers_by_category_[category]->FetchSuggestionImage(suggestion_id, | 85 providers_by_category_[category]->FetchSuggestionImage(suggestion_id, |
| 93 callback); | 86 callback); |
| 94 } | 87 } |
| 95 | 88 |
| 96 void ContentSuggestionsService::ClearHistory( | 89 void ContentSuggestionsService::ClearHistory( |
| 97 base::Time begin, | 90 base::Time begin, |
| 98 base::Time end, | 91 base::Time end, |
| 99 const base::Callback<bool(const GURL& url)>& filter) { | 92 const base::Callback<bool(const GURL& url)>& filter) { |
| 100 for (const auto& provider : providers_) { | 93 for (const auto& provider : providers_) { |
| 101 provider->ClearHistory(begin, end, filter); | 94 provider->ClearHistory(begin, end, filter); |
| 102 } | 95 } |
| 103 } | 96 } |
| 104 | 97 |
| 105 void ContentSuggestionsService::ClearAllCachedSuggestions() { | 98 void ContentSuggestionsService::ClearAllCachedSuggestions() { |
| 106 suggestions_by_category_.clear(); | 99 suggestions_by_category_.clear(); |
| 107 id_category_map_.clear(); | |
| 108 for (const auto& category_provider_pair : providers_by_category_) { | 100 for (const auto& category_provider_pair : providers_by_category_) { |
| 109 category_provider_pair.second->ClearCachedSuggestions( | 101 category_provider_pair.second->ClearCachedSuggestions( |
| 110 category_provider_pair.first); | 102 category_provider_pair.first); |
| 111 FOR_EACH_OBSERVER(Observer, observers_, | 103 FOR_EACH_OBSERVER(Observer, observers_, |
| 112 OnNewSuggestions(category_provider_pair.first)); | 104 OnNewSuggestions(category_provider_pair.first)); |
| 113 } | 105 } |
| 114 } | 106 } |
| 115 | 107 |
| 116 void ContentSuggestionsService::ClearCachedSuggestions( | 108 void ContentSuggestionsService::ClearCachedSuggestions(Category category) { |
| 117 Category category) { | |
| 118 for (const ContentSuggestion& suggestion : | |
| 119 suggestions_by_category_[category]) { | |
| 120 id_category_map_.erase(suggestion.id()); | |
| 121 } | |
| 122 suggestions_by_category_[category].clear(); | 109 suggestions_by_category_[category].clear(); |
| 123 auto iterator = providers_by_category_.find(category); | 110 auto iterator = providers_by_category_.find(category); |
| 124 if (iterator != providers_by_category_.end()) | 111 if (iterator != providers_by_category_.end()) |
| 125 iterator->second->ClearCachedSuggestions(category); | 112 iterator->second->ClearCachedSuggestions(category); |
| 126 } | 113 } |
| 127 | 114 |
| 128 void ContentSuggestionsService::GetDismissedSuggestionsForDebugging( | 115 void ContentSuggestionsService::GetDismissedSuggestionsForDebugging( |
| 129 Category category, | 116 Category category, |
| 130 const DismissedSuggestionsCallback& callback) { | 117 const DismissedSuggestionsCallback& callback) { |
| 131 auto iterator = providers_by_category_.find(category); | 118 auto iterator = providers_by_category_.find(category); |
| 132 if (iterator != providers_by_category_.end()) | 119 if (iterator != providers_by_category_.end()) |
| 133 iterator->second->GetDismissedSuggestionsForDebugging(category, callback); | 120 iterator->second->GetDismissedSuggestionsForDebugging(category, callback); |
| 134 else | 121 else |
| 135 callback.Run(std::vector<ContentSuggestion>()); | 122 callback.Run(std::vector<ContentSuggestion>()); |
| 136 } | 123 } |
| 137 | 124 |
| 138 void ContentSuggestionsService::ClearDismissedSuggestionsForDebugging( | 125 void ContentSuggestionsService::ClearDismissedSuggestionsForDebugging( |
| 139 Category category) { | 126 Category category) { |
| 140 auto iterator = providers_by_category_.find(category); | 127 auto iterator = providers_by_category_.find(category); |
| 141 if (iterator != providers_by_category_.end()) | 128 if (iterator != providers_by_category_.end()) |
| 142 iterator->second->ClearDismissedSuggestionsForDebugging(category); | 129 iterator->second->ClearDismissedSuggestionsForDebugging(category); |
| 143 } | 130 } |
| 144 | 131 |
| 145 void ContentSuggestionsService::DismissSuggestion( | 132 void ContentSuggestionsService::DismissSuggestion( |
| 146 const std::string& suggestion_id) { | 133 const std::string& suggestion_id) { |
| 147 if (!id_category_map_.count(suggestion_id)) { | 134 Category category = category_factory_.GetCategoryFromUniqueID(suggestion_id); |
| 148 LOG(WARNING) << "Dismissed unknown suggestion " << suggestion_id; | |
| 149 return; | |
| 150 } | |
| 151 Category category = id_category_map_.at(suggestion_id); | |
| 152 if (!providers_by_category_.count(category)) { | 135 if (!providers_by_category_.count(category)) { |
| 153 LOG(WARNING) << "Dismissed suggestion " << suggestion_id | 136 LOG(WARNING) << "Dismissed suggestion " << suggestion_id |
| 154 << " for unavailable category " << category; | 137 << " for unavailable category " << category; |
| 155 return; | 138 return; |
| 156 } | 139 } |
| 157 providers_by_category_[category]->DismissSuggestion(suggestion_id); | 140 providers_by_category_[category]->DismissSuggestion(suggestion_id); |
| 158 | 141 |
| 159 // Remove the suggestion locally. | 142 // Remove the suggestion locally. |
| 160 bool removed = RemoveSuggestionByID(category, suggestion_id); | 143 bool removed = RemoveSuggestionByID(category, suggestion_id); |
| 161 DCHECK(removed) << "The dismissed suggestion " << suggestion_id | 144 DCHECK(removed) << "The dismissed suggestion " << suggestion_id |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 193 void ContentSuggestionsService::OnNewSuggestions( | 176 void ContentSuggestionsService::OnNewSuggestions( |
| 194 ContentSuggestionsProvider* provider, | 177 ContentSuggestionsProvider* provider, |
| 195 Category category, | 178 Category category, |
| 196 std::vector<ContentSuggestion> new_suggestions) { | 179 std::vector<ContentSuggestion> new_suggestions) { |
| 197 if (RegisterCategoryIfRequired(provider, category)) | 180 if (RegisterCategoryIfRequired(provider, category)) |
| 198 NotifyCategoryStatusChanged(category); | 181 NotifyCategoryStatusChanged(category); |
| 199 | 182 |
| 200 if (!IsCategoryStatusAvailable(provider->GetCategoryStatus(category))) | 183 if (!IsCategoryStatusAvailable(provider->GetCategoryStatus(category))) |
| 201 return; | 184 return; |
| 202 | 185 |
| 203 for (const ContentSuggestion& suggestion : | |
| 204 suggestions_by_category_[category]) { | |
| 205 id_category_map_.erase(suggestion.id()); | |
| 206 } | |
| 207 | |
| 208 for (const ContentSuggestion& suggestion : new_suggestions) | |
| 209 id_category_map_.insert(std::make_pair(suggestion.id(), category)); | |
| 210 | |
| 211 suggestions_by_category_[category] = std::move(new_suggestions); | 186 suggestions_by_category_[category] = std::move(new_suggestions); |
| 212 | 187 |
| 213 // The positioning of the bookmarks category depends on whether it's empty. | 188 // The positioning of the bookmarks category depends on whether it's empty. |
| 214 // TODO(treib): Remove this temporary hack, crbug.com/640568. | 189 // TODO(treib): Remove this temporary hack, crbug.com/640568. |
| 215 if (category.IsKnownCategory(KnownCategories::BOOKMARKS)) | 190 if (category.IsKnownCategory(KnownCategories::BOOKMARKS)) |
| 216 SortCategories(); | 191 SortCategories(); |
| 217 | 192 |
| 218 FOR_EACH_OBSERVER(Observer, observers_, OnNewSuggestions(category)); | 193 FOR_EACH_OBSERVER(Observer, observers_, OnNewSuggestions(category)); |
| 219 } | 194 } |
| 220 | 195 |
| 221 void ContentSuggestionsService::OnCategoryStatusChanged( | 196 void ContentSuggestionsService::OnCategoryStatusChanged( |
| 222 ContentSuggestionsProvider* provider, | 197 ContentSuggestionsProvider* provider, |
| 223 Category category, | 198 Category category, |
| 224 CategoryStatus new_status) { | 199 CategoryStatus new_status) { |
| 225 if (!IsCategoryStatusAvailable(new_status)) { | 200 if (!IsCategoryStatusAvailable(new_status)) { |
| 226 for (const ContentSuggestion& suggestion : | |
| 227 suggestions_by_category_[category]) { | |
| 228 id_category_map_.erase(suggestion.id()); | |
| 229 } | |
| 230 suggestions_by_category_.erase(category); | 201 suggestions_by_category_.erase(category); |
| 231 } | 202 } |
| 232 if (new_status == CategoryStatus::NOT_PROVIDED) { | 203 if (new_status == CategoryStatus::NOT_PROVIDED) { |
| 233 DCHECK(providers_by_category_.find(category) != | 204 DCHECK(providers_by_category_.find(category) != |
| 234 providers_by_category_.end()); | 205 providers_by_category_.end()); |
| 235 DCHECK_EQ(provider, providers_by_category_.find(category)->second); | 206 DCHECK_EQ(provider, providers_by_category_.find(category)->second); |
| 236 DismissCategory(category); | 207 DismissCategory(category); |
| 237 } else { | 208 } else { |
| 238 RegisterCategoryIfRequired(provider, category); | 209 RegisterCategoryIfRequired(provider, category); |
| 239 DCHECK_EQ(new_status, provider->GetCategoryStatus(category)); | 210 DCHECK_EQ(new_status, provider->GetCategoryStatus(category)); |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 311 if (IsCategoryStatusAvailable(provider->GetCategoryStatus(category))) { | 282 if (IsCategoryStatusAvailable(provider->GetCategoryStatus(category))) { |
| 312 suggestions_by_category_.insert( | 283 suggestions_by_category_.insert( |
| 313 std::make_pair(category, std::vector<ContentSuggestion>())); | 284 std::make_pair(category, std::vector<ContentSuggestion>())); |
| 314 } | 285 } |
| 315 return true; | 286 return true; |
| 316 } | 287 } |
| 317 | 288 |
| 318 bool ContentSuggestionsService::RemoveSuggestionByID( | 289 bool ContentSuggestionsService::RemoveSuggestionByID( |
| 319 Category category, | 290 Category category, |
| 320 const std::string& suggestion_id) { | 291 const std::string& suggestion_id) { |
| 321 id_category_map_.erase(suggestion_id); | |
| 322 std::vector<ContentSuggestion>* suggestions = | 292 std::vector<ContentSuggestion>* suggestions = |
| 323 &suggestions_by_category_[category]; | 293 &suggestions_by_category_[category]; |
| 324 auto position = | 294 auto position = |
| 325 std::find_if(suggestions->begin(), suggestions->end(), | 295 std::find_if(suggestions->begin(), suggestions->end(), |
| 326 [&suggestion_id](const ContentSuggestion& suggestion) { | 296 [&suggestion_id](const ContentSuggestion& suggestion) { |
| 327 return suggestion_id == suggestion.id(); | 297 return suggestion_id == suggestion.id(); |
| 328 }); | 298 }); |
| 329 if (position == suggestions->end()) | 299 if (position == suggestions->end()) |
| 330 return false; | 300 return false; |
| 331 suggestions->erase(position); | 301 suggestions->erase(position); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 358 if (left.IsKnownCategory(KnownCategories::BOOKMARKS)) | 328 if (left.IsKnownCategory(KnownCategories::BOOKMARKS)) |
| 359 return false; | 329 return false; |
| 360 if (right.IsKnownCategory(KnownCategories::BOOKMARKS)) | 330 if (right.IsKnownCategory(KnownCategories::BOOKMARKS)) |
| 361 return true; | 331 return true; |
| 362 } | 332 } |
| 363 return category_factory_.CompareCategories(left, right); | 333 return category_factory_.CompareCategories(left, right); |
| 364 }); | 334 }); |
| 365 } | 335 } |
| 366 | 336 |
| 367 } // namespace ntp_snippets | 337 } // namespace ntp_snippets |
| OLD | NEW |