OLD | NEW |
---|---|
(Empty) | |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "components/ntp_snippets/content_suggestions_service.h" | |
6 | |
7 #include <algorithm> | |
8 #include <iterator> | |
9 | |
10 #include "base/bind.h" | |
11 #include "base/strings/string_number_conversions.h" | |
12 #include "ui/gfx/image/image.h" | |
13 | |
14 namespace ntp_snippets { | |
15 | |
16 ContentSuggestionsService::ContentSuggestionsService(State enabled) | |
17 : enabled_(enabled) {} | |
18 | |
19 ContentSuggestionsService::~ContentSuggestionsService() {} | |
20 | |
21 void ContentSuggestionsService::Shutdown() { | |
22 DCHECK(providers_.empty()); | |
23 DCHECK(categories_.empty()); | |
24 DCHECK(suggestions_by_category_.empty()); | |
25 DCHECK(id_category_map_.empty()); | |
26 enabled_ = State::DISABLED; | |
27 FOR_EACH_OBSERVER(Observer, observers_, ContentSuggestionsServiceShutdown()); | |
28 observers_.Clear(); | |
29 } | |
30 | |
31 ContentSuggestionsCategoryStatus ContentSuggestionsService::GetCategoryStatus( | |
32 ContentSuggestionsCategory category) const { | |
33 if (enabled_ == State::DISABLED) | |
34 return ContentSuggestionsCategoryStatus:: | |
35 ALL_SUGGESTIONS_EXPLICITLY_DISABLED; | |
36 | |
37 auto iterator = providers_.find(category); | |
38 if (iterator == providers_.end()) | |
39 return ContentSuggestionsCategoryStatus::NOT_PROVIDED; | |
40 | |
41 return iterator->second->GetCategoryStatus(category); | |
42 } | |
43 | |
44 const std::vector<ContentSuggestion>& | |
45 ContentSuggestionsService::GetSuggestionsForCategory( | |
46 ContentSuggestionsCategory category) const { | |
47 auto iterator = suggestions_by_category_.find(category); | |
48 if (iterator == suggestions_by_category_.end()) { | |
49 return no_suggestions_; | |
tschumann
2016/07/06 06:36:12
I wonder if handing out references to the underlyi
Marc Treib
2016/07/06 08:20:44
Generally, the convention is that a reference is s
Philipp Keck
2016/07/06 15:53:20
Acknowledged.
| |
50 } | |
51 return iterator->second; | |
52 } | |
53 | |
54 void ContentSuggestionsService::FetchSuggestionImage( | |
55 const std::string& suggestion_id, | |
56 const ImageFetchedCallback& callback) { | |
57 if (!id_category_map_.count(suggestion_id)) { | |
58 LOG(WARNING) << "Requested image for unknown suggestion " << suggestion_id; | |
59 callback.Run(suggestion_id, gfx::Image()); | |
60 return; | |
61 } | |
62 ContentSuggestionsCategory category = id_category_map_[suggestion_id]; | |
63 if (!providers_.count(category)) { | |
64 LOG(WARNING) << "Requested image for suggestion " << suggestion_id | |
65 << " for unavailable category " << int(category); | |
66 callback.Run(suggestion_id, gfx::Image()); | |
67 return; | |
68 } | |
69 providers_[category]->FetchSuggestionImage(suggestion_id, callback); | |
70 } | |
71 | |
72 void ContentSuggestionsService::ClearCachedSuggestionsForDebugging() { | |
73 suggestions_by_category_.clear(); | |
74 id_category_map_.clear(); | |
75 for (auto& provider : providers_) { | |
76 provider.second->ClearCachedSuggestionsForDebugging(); | |
77 } | |
78 FOR_EACH_OBSERVER(Observer, observers_, OnNewSuggestions()); | |
79 } | |
80 | |
81 void ContentSuggestionsService::ClearDiscardedSuggestionsForDebugging() { | |
82 for (auto& provider : providers_) { | |
83 provider.second->ClearDiscardedSuggestionsForDebugging(); | |
84 } | |
85 } | |
86 | |
87 void ContentSuggestionsService::DiscardSuggestion( | |
88 const std::string& suggestion_id) { | |
89 if (!id_category_map_.count(suggestion_id)) { | |
90 LOG(WARNING) << "Discarded unknown suggestion " << suggestion_id; | |
91 return; | |
92 } | |
93 ContentSuggestionsCategory category = id_category_map_[suggestion_id]; | |
94 if (!providers_.count(category)) { | |
95 LOG(WARNING) << "Discarded suggestion " << suggestion_id | |
96 << " for unavailable category " << int(category); | |
97 return; | |
98 } | |
99 providers_[category]->DiscardSuggestion(suggestion_id); | |
100 | |
101 // Remove the suggestion locally. | |
102 id_category_map_.erase(suggestion_id); | |
103 std::vector<ContentSuggestion>* suggestions = | |
104 &suggestions_by_category_[category]; | |
105 auto position = | |
106 std::find_if(suggestions->begin(), suggestions->end(), | |
107 [&suggestion_id](const ContentSuggestion& suggestion) { | |
108 return suggestion_id == suggestion.id(); | |
109 }); | |
110 DCHECK(position != suggestions->end()); | |
111 suggestions->erase(position); | |
112 } | |
113 | |
114 void ContentSuggestionsService::AddObserver(Observer* observer) { | |
115 observers_.AddObserver(observer); | |
116 } | |
117 | |
118 void ContentSuggestionsService::RemoveObserver(Observer* observer) { | |
119 observers_.RemoveObserver(observer); | |
120 } | |
121 | |
122 void ContentSuggestionsService::RegisterProvider( | |
123 ContentSuggestionsProvider* provider) { | |
124 if (enabled_ == State::DISABLED) | |
125 return; | |
126 | |
127 for (ContentSuggestionsCategory category : provider->provided_categories()) { | |
128 DCHECK_EQ(0ul, providers_.count(category)); | |
129 providers_[category] = provider; | |
130 // TODO(pke) In the future, make sure that the categories have some useful | |
131 // (maybe constant, at least consistent) ordering for the UI. | |
132 categories_.push_back(category); | |
133 if (IsContentSuggestionsCategoryStatusAvailable( | |
134 provider->GetCategoryStatus(category))) { | |
135 suggestions_by_category_[category] = std::vector<ContentSuggestion>(); | |
136 } | |
137 provider->SetObserver(this); | |
138 FOR_EACH_OBSERVER(Observer, observers_, | |
139 OnCategoryStatusChanged( | |
140 category, provider->GetCategoryStatus(category))); | |
141 } | |
142 } | |
143 | |
144 //////////////////////////////////////////////////////////////////////////////// | |
145 // Private methods | |
146 | |
147 void ContentSuggestionsService::OnNewSuggestions( | |
148 ContentSuggestionsCategory changed_category, | |
149 std::vector<ContentSuggestion> new_suggestions) { | |
150 DCHECK(IsCategoryRegistered(changed_category)); | |
151 | |
152 for (const ContentSuggestion& suggestion : | |
153 suggestions_by_category_[changed_category]) { | |
154 id_category_map_.erase(suggestion.id()); | |
155 } | |
156 | |
157 for (const ContentSuggestion& suggestion : new_suggestions) { | |
158 id_category_map_[suggestion.id()] = changed_category; | |
159 } | |
160 | |
161 suggestions_by_category_[changed_category] = std::move(new_suggestions); | |
162 | |
163 FOR_EACH_OBSERVER(Observer, observers_, OnNewSuggestions()); | |
164 } | |
165 | |
166 void ContentSuggestionsService::OnCategoryStatusChanged( | |
167 ContentSuggestionsCategory changed_category, | |
168 ContentSuggestionsCategoryStatus new_status) { | |
169 if (!IsContentSuggestionsCategoryStatusAvailable(new_status)) { | |
170 for (const ContentSuggestion& suggestion : | |
171 suggestions_by_category_[changed_category]) { | |
172 id_category_map_.erase(suggestion.id()); | |
173 } | |
174 suggestions_by_category_.erase(changed_category); | |
175 } | |
176 FOR_EACH_OBSERVER(Observer, observers_, | |
177 OnCategoryStatusChanged(changed_category, new_status)); | |
178 } | |
179 | |
180 void ContentSuggestionsService::OnProviderShutdown( | |
181 ContentSuggestionsProvider* provider) { | |
182 for (ContentSuggestionsCategory category : provider->provided_categories()) { | |
183 auto iterator = std::find(categories_.begin(), categories_.end(), category); | |
184 DCHECK(iterator != categories_.end()); | |
185 categories_.erase(iterator); | |
186 for (const ContentSuggestion& suggestion : | |
187 suggestions_by_category_[category]) { | |
188 id_category_map_.erase(suggestion.id()); | |
189 } | |
190 suggestions_by_category_.erase(category); | |
191 providers_.erase(category); | |
192 FOR_EACH_OBSERVER( | |
193 Observer, observers_, | |
194 OnCategoryStatusChanged(category, GetCategoryStatus(category))); | |
195 } | |
196 provider->SetObserver(nullptr); | |
197 } | |
198 | |
199 bool ContentSuggestionsService::IsCategoryRegistered( | |
200 ContentSuggestionsCategory category) const { | |
201 return std::find(categories_.begin(), categories_.end(), category) != | |
202 categories_.end(); | |
203 } | |
204 | |
205 } // namespace ntp_snippets | |
OLD | NEW |