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 |