Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1268)

Side by Side Diff: components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.cc

Issue 2684973014: Only show Last N Pages in the UI when the corresponding tab is visible. (Closed)
Patch Set: Move impl out Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/offline_pages/recent_tab_suggestions_provider. h" 5 #include "components/ntp_snippets/offline_pages/recent_tab_suggestions_provider. h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/memory/ptr_util.h" 11 #include "base/memory/ptr_util.h"
12 #include "base/strings/string_number_conversions.h" 12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/utf_string_conversions.h" 13 #include "base/strings/utf_string_conversions.h"
14 #include "base/threading/thread_task_runner_handle.h" 14 #include "base/threading/thread_task_runner_handle.h"
15 #include "components/ntp_snippets/features.h" 15 #include "components/ntp_snippets/features.h"
16 #include "components/ntp_snippets/pref_names.h" 16 #include "components/ntp_snippets/pref_names.h"
17 #include "components/ntp_snippets/pref_util.h" 17 #include "components/ntp_snippets/pref_util.h"
18 #include "components/offline_pages/core/client_policy_controller.h" 18 #include "components/offline_pages/core/client_policy_controller.h"
19 #include "components/offline_pages/core/offline_page_item.h" 19 #include "components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_deleg ate.h"
20 #include "components/offline_pages/core/offline_page_model_query.h"
21 #include "components/prefs/pref_registry_simple.h" 20 #include "components/prefs/pref_registry_simple.h"
22 #include "components/prefs/pref_service.h" 21 #include "components/prefs/pref_service.h"
23 #include "components/variations/variations_associated_data.h" 22 #include "components/variations/variations_associated_data.h"
24 #include "grit/components_strings.h" 23 #include "grit/components_strings.h"
25 #include "ui/base/l10n/l10n_util.h" 24 #include "ui/base/l10n/l10n_util.h"
26 #include "ui/gfx/image/image.h" 25 #include "ui/gfx/image/image.h"
27 26
28 using offline_pages::ClientId; 27 using offline_pages::ClientId;
29 using offline_pages::OfflinePageItem; 28 using offline_pages::DownloadUIAdapter;
30 using offline_pages::OfflinePageModelQuery; 29 using offline_pages::DownloadUIItem;
31 using offline_pages::OfflinePageModelQueryBuilder;
32 30
33 namespace ntp_snippets { 31 namespace ntp_snippets {
34 32
35 namespace { 33 namespace {
36 34
37 const int kDefaultMaxSuggestionsCount = 5; 35 const int kDefaultMaxSuggestionsCount = 5;
38 36
39 const char* kMaxSuggestionsCountParamName = "recent_tabs_max_count"; 37 const char* kMaxSuggestionsCountParamName = "recent_tabs_max_count";
40 38
41 int GetMaxSuggestionsCount() { 39 int GetMaxSuggestionsCount() {
42 return variations::GetVariationParamByFeatureAsInt( 40 return variations::GetVariationParamByFeatureAsInt(
43 kRecentOfflineTabSuggestionsFeature, kMaxSuggestionsCountParamName, 41 kRecentOfflineTabSuggestionsFeature, kMaxSuggestionsCountParamName,
44 kDefaultMaxSuggestionsCount); 42 kDefaultMaxSuggestionsCount);
45 } 43 }
46 44
47 struct OrderOfflinePagesByMostRecentlyCreatedFirst { 45 struct OrderUIItemsByMostRecentlyCreatedFirst {
48 bool operator()(const OfflinePageItem* left, 46 bool operator()(const DownloadUIItem* left,
49 const OfflinePageItem* right) const { 47 const DownloadUIItem* right) const {
50 return left->creation_time > right->creation_time; 48 return left->start_time > right->start_time;
51 } 49 }
52 }; 50 };
53 51
54 struct OrderOfflinePagesByUrlAndThenMostRecentlyCreatedFirst { 52 struct OrderUIItemsByUrlAndThenMostRecentlyCreatedFirst {
55 bool operator()(const OfflinePageItem* left, 53 bool operator()(const DownloadUIItem* left,
56 const OfflinePageItem* right) const { 54 const DownloadUIItem* right) const {
57 if (left->url != right->url) { 55 if (left->url != right->url) {
58 return left->url < right->url; 56 return left->url < right->url;
59 } 57 }
60 return left->creation_time > right->creation_time; 58 return left->start_time > right->start_time;
61 } 59 }
62 }; 60 };
63 61
64 std::unique_ptr<OfflinePageModelQuery> BuildRecentTabsQuery(
65 offline_pages::OfflinePageModel* model) {
66 OfflinePageModelQueryBuilder builder;
67 builder.RequireShownAsRecentlyVisitedSite(
68 OfflinePageModelQuery::Requirement::INCLUDE_MATCHING);
69 return builder.Build(model->GetPolicyController());
70 }
71
72 bool IsRecentTab(offline_pages::ClientPolicyController* policy_controller,
73 const OfflinePageItem& offline_page) {
74 return policy_controller->IsShownAsRecentlyVisitedSite(
75 offline_page.client_id.name_space);
76 }
77
78 } // namespace 62 } // namespace
79 63
80 RecentTabSuggestionsProvider::RecentTabSuggestionsProvider( 64 RecentTabSuggestionsProvider::RecentTabSuggestionsProvider(
81 ContentSuggestionsProvider::Observer* observer, 65 ContentSuggestionsProvider::Observer* observer,
82 offline_pages::OfflinePageModel* offline_page_model, 66 offline_pages::DownloadUIAdapter* ui_adapter,
83 PrefService* pref_service) 67 PrefService* pref_service)
84 : ContentSuggestionsProvider(observer), 68 : ContentSuggestionsProvider(observer),
85 category_status_(CategoryStatus::AVAILABLE_LOADING), 69 category_status_(CategoryStatus::AVAILABLE_LOADING),
86 provided_category_( 70 provided_category_(
87 Category::FromKnownCategory(KnownCategories::RECENT_TABS)), 71 Category::FromKnownCategory(KnownCategories::RECENT_TABS)),
88 offline_page_model_(offline_page_model), 72 recent_tabs_ui_adapter_(ui_adapter),
89 pref_service_(pref_service), 73 pref_service_(pref_service),
90 weak_ptr_factory_(this) { 74 weak_ptr_factory_(this) {
91 observer->OnCategoryStatusChanged(this, provided_category_, category_status_); 75 observer->OnCategoryStatusChanged(this, provided_category_, category_status_);
92 offline_page_model_->AddObserver(this); 76 recent_tabs_ui_adapter_->AddObserver(this);
93 FetchRecentTabs();
94 } 77 }
95 78
96 RecentTabSuggestionsProvider::~RecentTabSuggestionsProvider() { 79 RecentTabSuggestionsProvider::~RecentTabSuggestionsProvider() {
97 offline_page_model_->RemoveObserver(this); 80 recent_tabs_ui_adapter_->RemoveObserver(this);
98 } 81 }
99 82
100 CategoryStatus RecentTabSuggestionsProvider::GetCategoryStatus( 83 CategoryStatus RecentTabSuggestionsProvider::GetCategoryStatus(
101 Category category) { 84 Category category) {
102 if (category == provided_category_) { 85 if (category == provided_category_) {
103 return category_status_; 86 return category_status_;
104 } 87 }
105 NOTREACHED() << "Unknown category " << category.id(); 88 NOTREACHED() << "Unknown category " << category.id();
106 return CategoryStatus::NOT_PROVIDED; 89 return CategoryStatus::NOT_PROVIDED;
107 } 90 }
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
158 141
159 void RecentTabSuggestionsProvider::ClearCachedSuggestions(Category category) { 142 void RecentTabSuggestionsProvider::ClearCachedSuggestions(Category category) {
160 // Ignored. 143 // Ignored.
161 } 144 }
162 145
163 void RecentTabSuggestionsProvider::GetDismissedSuggestionsForDebugging( 146 void RecentTabSuggestionsProvider::GetDismissedSuggestionsForDebugging(
164 Category category, 147 Category category,
165 const DismissedSuggestionsCallback& callback) { 148 const DismissedSuggestionsCallback& callback) {
166 DCHECK_EQ(provided_category_, category); 149 DCHECK_EQ(provided_category_, category);
167 150
168 // Offline pages which are not related to recent tabs are also queried here, 151 std::vector<const DownloadUIItem*> items =
169 // so that they can be returned if they happen to be dismissed (e.g. due to a 152 recent_tabs_ui_adapter_->GetAllItems();
170 // bug). 153
171 OfflinePageModelQueryBuilder query_builder; 154 std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs();
172 offline_page_model_->GetPagesMatchingQuery( 155 std::vector<ContentSuggestion> suggestions;
173 query_builder.Build(offline_page_model_->GetPolicyController()), 156 for (const DownloadUIItem* item : items) {
174 base::Bind(&RecentTabSuggestionsProvider:: 157 int64_t offline_page_id =
175 GetPagesMatchingQueryCallbackForGetDismissedSuggestions, 158 recent_tabs_ui_adapter_->GetOfflineIdByGuid(item->guid);
176 weak_ptr_factory_.GetWeakPtr(), callback)); 159 if (!dismissed_ids.count(base::IntToString(offline_page_id))) {
160 continue;
161 }
162
163 suggestions.push_back(ConvertUIItem(*item));
164 }
165 callback.Run(std::move(suggestions));
177 } 166 }
178 167
179 void RecentTabSuggestionsProvider::ClearDismissedSuggestionsForDebugging( 168 void RecentTabSuggestionsProvider::ClearDismissedSuggestionsForDebugging(
180 Category category) { 169 Category category) {
181 DCHECK_EQ(provided_category_, category); 170 DCHECK_EQ(provided_category_, category);
182 StoreDismissedIDsToPrefs(std::set<std::string>()); 171 StoreDismissedIDsToPrefs(std::set<std::string>());
183 FetchRecentTabs(); 172 FetchRecentTabs();
184 } 173 }
185 174
186 // static 175 // static
187 void RecentTabSuggestionsProvider::RegisterProfilePrefs( 176 void RecentTabSuggestionsProvider::RegisterProfilePrefs(
188 PrefRegistrySimple* registry) { 177 PrefRegistrySimple* registry) {
189 registry->RegisterListPref(prefs::kDismissedRecentOfflineTabSuggestions); 178 registry->RegisterListPref(prefs::kDismissedRecentOfflineTabSuggestions);
190 } 179 }
191 180
192 //////////////////////////////////////////////////////////////////////////////// 181 ////////////////////////////////////////////////////////////////////////////////
193 // Private methods 182 // Private methods
194 183
195 void RecentTabSuggestionsProvider:: 184 void RecentTabSuggestionsProvider::ItemsLoaded() {
196 GetPagesMatchingQueryCallbackForGetDismissedSuggestions( 185 FetchRecentTabs();
197 const DismissedSuggestionsCallback& callback,
198 const std::vector<OfflinePageItem>& offline_pages) const {
199 std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs();
200 std::vector<ContentSuggestion> suggestions;
201 for (const OfflinePageItem& item : offline_pages) {
202 if (!dismissed_ids.count(base::IntToString(item.offline_id))) {
203 continue;
204 }
205
206 suggestions.push_back(ConvertOfflinePage(item));
207 }
208 callback.Run(std::move(suggestions));
209 } 186 }
210 187
211 void RecentTabSuggestionsProvider::OfflinePageModelLoaded( 188 void RecentTabSuggestionsProvider::ItemAdded(const DownloadUIItem& ui_item) {
212 offline_pages::OfflinePageModel* model) {} 189 FetchRecentTabs();
190 }
213 191
214 void RecentTabSuggestionsProvider::OfflinePageAdded( 192 void RecentTabSuggestionsProvider::ItemUpdated(const DownloadUIItem& ui_item) {
215 offline_pages::OfflinePageModel* model, 193 FetchRecentTabs();
216 const offline_pages::OfflinePageItem& added_page) { 194 }
217 DCHECK_EQ(offline_page_model_, model); 195
218 if (IsRecentTab(model->GetPolicyController(), added_page)) { 196 void RecentTabSuggestionsProvider::ItemDeleted(
219 FetchRecentTabs(); 197 const std::string& ui_item_guid) {
198 // Because we never switch to NOT_PROVIDED dynamically, there can be no open
199 // UI containing an invalidated suggestion unless the status is something
200 // other than NOT_PROVIDED, so only notify invalidation in that case.
201 if (category_status_ != CategoryStatus::NOT_PROVIDED) {
202 InvalidateSuggestion(ui_item_guid);
220 } 203 }
221 } 204 }
222 205
223 void RecentTabSuggestionsProvider:: 206 void RecentTabSuggestionsProvider::FetchRecentTabs() {
224 GetPagesMatchingQueryCallbackForFetchRecentTabs( 207 std::vector<const DownloadUIItem*> ui_items =
225 const std::vector<OfflinePageItem>& offline_pages) { 208 recent_tabs_ui_adapter_->GetAllItems();
226 NotifyStatusChanged(CategoryStatus::AVAILABLE); 209 NotifyStatusChanged(CategoryStatus::AVAILABLE);
227 std::set<std::string> old_dismissed_ids = ReadDismissedIDsFromPrefs(); 210 std::set<std::string> old_dismissed_ids = ReadDismissedIDsFromPrefs();
228 std::set<std::string> new_dismissed_ids; 211 std::set<std::string> new_dismissed_ids;
229 std::vector<const OfflinePageItem*> recent_tab_items; 212 std::vector<const DownloadUIItem*> non_dismissed_items;
230 for (const OfflinePageItem& item : offline_pages) { 213
231 std::string offline_page_id = base::IntToString(item.offline_id); 214 for (const DownloadUIItem* item : ui_items) {
215 std::string offline_page_id = base::IntToString(
216 recent_tabs_ui_adapter_->GetOfflineIdByGuid(item->guid));
232 if (old_dismissed_ids.count(offline_page_id)) { 217 if (old_dismissed_ids.count(offline_page_id)) {
233 new_dismissed_ids.insert(offline_page_id); 218 new_dismissed_ids.insert(offline_page_id);
234 } else { 219 } else {
235 recent_tab_items.push_back(&item); 220 non_dismissed_items.push_back(item);
236 } 221 }
237 } 222 }
238 223
239 observer()->OnNewSuggestions( 224 observer()->OnNewSuggestions(
240 this, provided_category_, 225 this, provided_category_,
241 GetMostRecentlyCreatedWithoutDuplicates(std::move(recent_tab_items))); 226 GetMostRecentlyCreatedWithoutDuplicates(std::move(non_dismissed_items)));
242 if (new_dismissed_ids.size() != old_dismissed_ids.size()) { 227 if (new_dismissed_ids.size() != old_dismissed_ids.size()) {
243 StoreDismissedIDsToPrefs(new_dismissed_ids); 228 StoreDismissedIDsToPrefs(new_dismissed_ids);
244 } 229 }
245 } 230 }
246 231
247 void RecentTabSuggestionsProvider::OfflinePageDeleted(
248 int64_t offline_id,
249 const ClientId& client_id) {
250 // Because we never switch to NOT_PROVIDED dynamically, there can be no open
251 // UI containing an invalidated suggestion unless the status is something
252 // other than NOT_PROVIDED, so only notify invalidation in that case.
253 if (category_status_ != CategoryStatus::NOT_PROVIDED) {
254 InvalidateSuggestion(offline_id);
255 }
256 }
257
258 void RecentTabSuggestionsProvider::FetchRecentTabs() {
259 offline_page_model_->GetPagesMatchingQuery(
260 BuildRecentTabsQuery(offline_page_model_),
261 base::Bind(&RecentTabSuggestionsProvider::
262 GetPagesMatchingQueryCallbackForFetchRecentTabs,
263 weak_ptr_factory_.GetWeakPtr()));
264 }
265
266 void RecentTabSuggestionsProvider::NotifyStatusChanged( 232 void RecentTabSuggestionsProvider::NotifyStatusChanged(
267 CategoryStatus new_status) { 233 CategoryStatus new_status) {
268 DCHECK_NE(CategoryStatus::NOT_PROVIDED, category_status_); 234 DCHECK_NE(CategoryStatus::NOT_PROVIDED, category_status_);
269 if (category_status_ == new_status) { 235 if (category_status_ == new_status) {
270 return; 236 return;
271 } 237 }
272 category_status_ = new_status; 238 category_status_ = new_status;
273 observer()->OnCategoryStatusChanged(this, provided_category_, new_status); 239 observer()->OnCategoryStatusChanged(this, provided_category_, new_status);
274 } 240 }
275 241
276 ContentSuggestion RecentTabSuggestionsProvider::ConvertOfflinePage( 242 ContentSuggestion RecentTabSuggestionsProvider::ConvertUIItem(
277 const OfflinePageItem& offline_page) const { 243 const DownloadUIItem& ui_item) const {
244 // UI items have the Tab ID embedded in the GUID and the offline ID is
245 // available by querying.
246 //
278 // TODO(vitaliii): Make sure the URL is opened in the existing tab. 247 // TODO(vitaliii): Make sure the URL is opened in the existing tab.
248 int64_t offline_page_id =
249 recent_tabs_ui_adapter_->GetOfflineIdByGuid(ui_item.guid);
279 ContentSuggestion suggestion(provided_category_, 250 ContentSuggestion suggestion(provided_category_,
280 base::IntToString(offline_page.offline_id), 251 base::IntToString(offline_page_id), ui_item.url);
281 offline_page.url); 252 suggestion.set_title(ui_item.title);
282 253 suggestion.set_publish_date(ui_item.start_time);
283 if (offline_page.title.empty()) { 254 suggestion.set_publisher_name(base::UTF8ToUTF16(ui_item.url.host()));
284 // TODO(vitaliii): Remove this fallback once the OfflinePageModel provides
285 // titles for all (relevant) OfflinePageItems.
286 suggestion.set_title(base::UTF8ToUTF16(offline_page.url.spec()));
287 } else {
288 suggestion.set_title(offline_page.title);
289 }
290 suggestion.set_publish_date(offline_page.creation_time);
291 suggestion.set_publisher_name(base::UTF8ToUTF16(offline_page.url.host()));
292 auto extra = base::MakeUnique<RecentTabSuggestionExtra>(); 255 auto extra = base::MakeUnique<RecentTabSuggestionExtra>();
293 int tab_id; 256 int tab_id;
294 bool success = base::StringToInt(offline_page.client_id.id, &tab_id); 257 bool success = base::StringToInt(ui_item.guid, &tab_id);
295 DCHECK(success); 258 DCHECK(success);
296 extra->tab_id = tab_id; 259 extra->tab_id = tab_id;
297 extra->offline_page_id = offline_page.offline_id; 260 extra->offline_page_id = offline_page_id;
298 suggestion.set_recent_tab_suggestion_extra(std::move(extra)); 261 suggestion.set_recent_tab_suggestion_extra(std::move(extra));
262
299 return suggestion; 263 return suggestion;
300 } 264 }
301 265
302 std::vector<ContentSuggestion> 266 std::vector<ContentSuggestion>
303 RecentTabSuggestionsProvider::GetMostRecentlyCreatedWithoutDuplicates( 267 RecentTabSuggestionsProvider::GetMostRecentlyCreatedWithoutDuplicates(
304 std::vector<const OfflinePageItem*> offline_page_items) const { 268 std::vector<const DownloadUIItem*> ui_items) const {
305 // |std::unique| only removes duplicates that immediately follow each other. 269 // |std::unique| only removes duplicates that immediately follow each other.
306 // Thus, first, we have to sort by URL and creation time and only then remove 270 // Thus, first, we have to sort by URL and creation time and only then remove
307 // duplicates and sort the remaining items by creation time. 271 // duplicates and sort the remaining items by creation time.
308 std::sort(offline_page_items.begin(), offline_page_items.end(), 272 std::sort(ui_items.begin(), ui_items.end(),
309 OrderOfflinePagesByUrlAndThenMostRecentlyCreatedFirst()); 273 OrderUIItemsByUrlAndThenMostRecentlyCreatedFirst());
310 std::vector<const OfflinePageItem*>::iterator new_end = std::unique( 274 std::vector<const DownloadUIItem*>::iterator new_end =
311 offline_page_items.begin(), offline_page_items.end(), 275 std::unique(ui_items.begin(), ui_items.end(),
312 [](const OfflinePageItem* left, const OfflinePageItem* right) { 276 [](const DownloadUIItem* left, const DownloadUIItem* right) {
313 return left->url == right->url; 277 return left->url == right->url;
314 }); 278 });
315 offline_page_items.erase(new_end, offline_page_items.end()); 279 ui_items.erase(new_end, ui_items.end());
316 std::sort(offline_page_items.begin(), offline_page_items.end(), 280 std::sort(ui_items.begin(), ui_items.end(),
317 OrderOfflinePagesByMostRecentlyCreatedFirst()); 281 OrderUIItemsByMostRecentlyCreatedFirst());
318 std::vector<ContentSuggestion> suggestions; 282 std::vector<ContentSuggestion> suggestions;
319 for (const OfflinePageItem* offline_page_item : offline_page_items) { 283 for (const DownloadUIItem* ui_item : ui_items) {
320 suggestions.push_back(ConvertOfflinePage(*offline_page_item)); 284 suggestions.push_back(ConvertUIItem(*ui_item));
321 if (static_cast<int>(suggestions.size()) == GetMaxSuggestionsCount()) { 285 if (static_cast<int>(suggestions.size()) == GetMaxSuggestionsCount()) {
322 break; 286 break;
323 } 287 }
324 } 288 }
325 return suggestions; 289 return suggestions;
326 } 290 }
327 291
328 void RecentTabSuggestionsProvider::InvalidateSuggestion(int64_t offline_id) { 292 void RecentTabSuggestionsProvider::InvalidateSuggestion(
329 std::string offline_page_id = base::IntToString(offline_id); 293 const std::string& ui_item_guid) {
294 std::string offline_page_id = base::IntToString(
295 recent_tabs_ui_adapter_->GetOfflineIdByGuid(ui_item_guid));
330 observer()->OnSuggestionInvalidated( 296 observer()->OnSuggestionInvalidated(
331 this, ContentSuggestion::ID(provided_category_, offline_page_id)); 297 this, ContentSuggestion::ID(provided_category_, offline_page_id));
332 298
333 std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs(); 299 std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs();
334 auto it = dismissed_ids.find(offline_page_id); 300 auto it = dismissed_ids.find(offline_page_id);
335 if (it != dismissed_ids.end()) { 301 if (it != dismissed_ids.end()) {
336 dismissed_ids.erase(it); 302 dismissed_ids.erase(it);
337 StoreDismissedIDsToPrefs(dismissed_ids); 303 StoreDismissedIDsToPrefs(dismissed_ids);
338 } 304 }
339 } 305 }
340 306
341 std::set<std::string> RecentTabSuggestionsProvider::ReadDismissedIDsFromPrefs() 307 std::set<std::string> RecentTabSuggestionsProvider::ReadDismissedIDsFromPrefs()
342 const { 308 const {
343 return prefs::ReadDismissedIDsFromPrefs( 309 return prefs::ReadDismissedIDsFromPrefs(
344 *pref_service_, prefs::kDismissedRecentOfflineTabSuggestions); 310 *pref_service_, prefs::kDismissedRecentOfflineTabSuggestions);
345 } 311 }
346 312
347 void RecentTabSuggestionsProvider::StoreDismissedIDsToPrefs( 313 void RecentTabSuggestionsProvider::StoreDismissedIDsToPrefs(
348 const std::set<std::string>& dismissed_ids) { 314 const std::set<std::string>& dismissed_ids) {
349 prefs::StoreDismissedIDsToPrefs(pref_service_, 315 prefs::StoreDismissedIDsToPrefs(pref_service_,
350 prefs::kDismissedRecentOfflineTabSuggestions, 316 prefs::kDismissedRecentOfflineTabSuggestions,
351 dismissed_ids); 317 dismissed_ids);
352 } 318 }
353 319
354 } // namespace ntp_snippets 320 } // namespace ntp_snippets
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698