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