OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/remote/remote_suggestions_provider_impl.h" | 5 #include "components/ntp_snippets/remote/remote_suggestions_provider_impl.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <iterator> | 8 #include <iterator> |
9 #include <utility> | 9 #include <utility> |
10 | 10 |
11 #include "base/bind.h" | 11 #include "base/bind.h" |
12 #include "base/command_line.h" | 12 #include "base/command_line.h" |
13 #include "base/location.h" | 13 #include "base/location.h" |
14 #include "base/memory/ptr_util.h" | 14 #include "base/memory/ptr_util.h" |
15 #include "base/metrics/histogram_macros.h" | 15 #include "base/metrics/histogram_macros.h" |
16 #include "base/metrics/sparse_histogram.h" | 16 #include "base/metrics/sparse_histogram.h" |
17 #include "base/stl_util.h" | 17 #include "base/stl_util.h" |
18 #include "base/strings/string_number_conversions.h" | 18 #include "base/strings/string_number_conversions.h" |
19 #include "base/threading/thread_task_runner_handle.h" | 19 #include "base/threading/thread_task_runner_handle.h" |
20 #include "base/time/default_clock.h" | 20 #include "base/time/default_clock.h" |
21 #include "base/time/time.h" | 21 #include "base/time/time.h" |
22 #include "base/values.h" | 22 #include "base/values.h" |
23 #include "components/data_use_measurement/core/data_use_user_data.h" | 23 #include "components/data_use_measurement/core/data_use_user_data.h" |
24 #include "components/image_fetcher/image_decoder.h" | 24 #include "components/image_fetcher/image_decoder.h" |
25 #include "components/image_fetcher/image_fetcher.h" | 25 #include "components/image_fetcher/image_fetcher.h" |
26 #include "components/ntp_snippets/category_rankers/category_ranker.h" | 26 #include "components/ntp_snippets/category_rankers/category_ranker.h" |
27 #include "components/ntp_snippets/pref_names.h" | 27 #include "components/ntp_snippets/pref_names.h" |
28 #include "components/ntp_snippets/remote/remote_suggestions_database.h" | 28 #include "components/ntp_snippets/remote/remote_suggestions_database.h" |
29 #include "components/ntp_snippets/remote/remote_suggestions_scheduler.h" | |
29 #include "components/ntp_snippets/switches.h" | 30 #include "components/ntp_snippets/switches.h" |
30 #include "components/prefs/pref_registry_simple.h" | 31 #include "components/prefs/pref_registry_simple.h" |
31 #include "components/prefs/pref_service.h" | 32 #include "components/prefs/pref_service.h" |
32 #include "grit/components_strings.h" | 33 #include "grit/components_strings.h" |
33 #include "ui/gfx/image/image.h" | 34 #include "ui/gfx/image/image.h" |
34 | 35 |
35 namespace ntp_snippets { | 36 namespace ntp_snippets { |
36 | 37 |
37 namespace { | 38 namespace { |
38 | 39 |
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
277 suggestions_fetcher_(std::move(suggestions_fetcher)), | 278 suggestions_fetcher_(std::move(suggestions_fetcher)), |
278 database_(std::move(database)), | 279 database_(std::move(database)), |
279 image_fetcher_(std::move(image_fetcher), | 280 image_fetcher_(std::move(image_fetcher), |
280 std::move(image_decoder), | 281 std::move(image_decoder), |
281 pref_service, | 282 pref_service, |
282 database_.get()), | 283 database_.get()), |
283 status_service_(std::move(status_service)), | 284 status_service_(std::move(status_service)), |
284 fetch_when_ready_(false), | 285 fetch_when_ready_(false), |
285 fetch_when_ready_interactive_(false), | 286 fetch_when_ready_interactive_(false), |
286 fetch_when_ready_callback_(nullptr), | 287 fetch_when_ready_callback_(nullptr), |
287 provider_status_callback_(nullptr), | 288 remote_suggestions_scheduler_(nullptr), |
288 nuke_when_initialized_(false), | 289 clear_any_history_when_initialized_(false), |
289 clock_(base::MakeUnique<base::DefaultClock>()) { | 290 clock_(base::MakeUnique<base::DefaultClock>()) { |
290 RestoreCategoriesFromPrefs(); | 291 RestoreCategoriesFromPrefs(); |
291 // The articles category always exists. Add it if we didn't get it from prefs. | 292 // The articles category always exists. Add it if we didn't get it from prefs. |
292 // TODO(treib): Rethink this. | 293 // TODO(treib): Rethink this. |
293 category_contents_.insert( | 294 category_contents_.insert( |
294 std::make_pair(articles_category_, | 295 std::make_pair(articles_category_, |
295 CategoryContent(BuildArticleCategoryInfo(base::nullopt)))); | 296 CategoryContent(BuildArticleCategoryInfo(base::nullopt)))); |
296 // Tell the observer about all the categories. | 297 // Tell the observer about all the categories. |
297 for (const auto& entry : category_contents_) { | 298 for (const auto& entry : category_contents_) { |
298 observer->OnCategoryStatusChanged(this, entry.first, entry.second.status); | 299 observer->OnCategoryStatusChanged(this, entry.first, entry.second.status); |
(...skipping 20 matching lines...) Expand all Loading... | |
319 | 320 |
320 // static | 321 // static |
321 void RemoteSuggestionsProviderImpl::RegisterProfilePrefs( | 322 void RemoteSuggestionsProviderImpl::RegisterProfilePrefs( |
322 PrefRegistrySimple* registry) { | 323 PrefRegistrySimple* registry) { |
323 registry->RegisterListPref(prefs::kRemoteSuggestionCategories); | 324 registry->RegisterListPref(prefs::kRemoteSuggestionCategories); |
324 registry->RegisterInt64Pref(prefs::kLastSuccessfulBackgroundFetchTime, 0); | 325 registry->RegisterInt64Pref(prefs::kLastSuccessfulBackgroundFetchTime, 0); |
325 | 326 |
326 RemoteSuggestionsStatusService::RegisterProfilePrefs(registry); | 327 RemoteSuggestionsStatusService::RegisterProfilePrefs(registry); |
327 } | 328 } |
328 | 329 |
329 void RemoteSuggestionsProviderImpl::SetProviderStatusCallback( | 330 void RemoteSuggestionsProviderImpl::SetRemoteSuggestionsScheduler( |
330 std::unique_ptr<ProviderStatusCallback> callback) { | 331 RemoteSuggestionsScheduler* scheduler) { |
331 provider_status_callback_ = std::move(callback); | 332 remote_suggestions_scheduler_ = scheduler; |
332 // Call the observer right away if we've reached any final state. | 333 // Call the observer right away if we've reached any final state. |
333 NotifyStateChanged(); | 334 NotifyStateChanged(); |
334 } | 335 } |
335 | 336 |
336 void RemoteSuggestionsProviderImpl::ReloadSuggestions() { | 337 void RemoteSuggestionsProviderImpl::ReloadSuggestions() { |
337 FetchSuggestions(/*interactive_request=*/true, | 338 FetchSuggestions(/*interactive_request=*/true, |
338 /*callback=*/nullptr); | 339 /*callback=*/nullptr); |
339 } | 340 } |
340 | 341 |
341 void RemoteSuggestionsProviderImpl::RefetchInTheBackground( | 342 void RemoteSuggestionsProviderImpl::RefetchInTheBackground( |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
440 suggestion_id.id_within_category()); | 441 suggestion_id.id_within_category()); |
441 } | 442 } |
442 | 443 |
443 void RemoteSuggestionsProviderImpl::ClearHistory( | 444 void RemoteSuggestionsProviderImpl::ClearHistory( |
444 base::Time begin, | 445 base::Time begin, |
445 base::Time end, | 446 base::Time end, |
446 const base::Callback<bool(const GURL& url)>& filter) { | 447 const base::Callback<bool(const GURL& url)>& filter) { |
447 // Both time range and the filter are ignored and all suggestions are removed, | 448 // Both time range and the filter are ignored and all suggestions are removed, |
448 // because it is not known which history entries were used for the suggestions | 449 // because it is not known which history entries were used for the suggestions |
449 // personalization. | 450 // personalization. |
450 if (!ready()) { | 451 ClearAnyHistory(); |
451 // No need to refresh the UI afterwards as we didn't provide any data to the | |
452 // UI so far. | |
453 nuke_when_initialized_ = true; | |
454 } else { | |
455 NukeAllSuggestions(); | |
456 } | |
457 } | 452 } |
458 | 453 |
459 void RemoteSuggestionsProviderImpl::ClearCachedSuggestions(Category category) { | 454 void RemoteSuggestionsProviderImpl::ClearCachedSuggestions(Category category) { |
460 if (!initialized()) { | 455 if (!initialized()) { |
461 return; | 456 return; |
462 } | 457 } |
463 | 458 |
464 auto content_it = category_contents_.find(category); | 459 auto content_it = category_contents_.find(category); |
465 if (content_it == category_contents_.end()) { | 460 if (content_it == category_contents_.end()) { |
466 return; | 461 return; |
(...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
874 for (const auto& suggestion_ptr : content.suggestions) { | 869 for (const auto& suggestion_ptr : content.suggestions) { |
875 alive_suggestions->insert(suggestion_ptr->id()); | 870 alive_suggestions->insert(suggestion_ptr->id()); |
876 } | 871 } |
877 for (const auto& suggestion_ptr : content.dismissed) { | 872 for (const auto& suggestion_ptr : content.dismissed) { |
878 alive_suggestions->insert(suggestion_ptr->id()); | 873 alive_suggestions->insert(suggestion_ptr->id()); |
879 } | 874 } |
880 } | 875 } |
881 database_->GarbageCollectImages(std::move(alive_suggestions)); | 876 database_->GarbageCollectImages(std::move(alive_suggestions)); |
882 } | 877 } |
883 | 878 |
879 void RemoteSuggestionsProviderImpl::ClearAnyHistory() { | |
880 if (!ready()) { | |
881 clear_any_history_when_initialized_ = true; | |
882 return; | |
883 } | |
884 | |
885 if (remote_suggestions_scheduler_) { | |
886 remote_suggestions_scheduler_->OnHistoryCleared(); | |
887 } | |
888 NukeAllSuggestions(); | |
889 } | |
890 | |
891 void RemoteSuggestionsProviderImpl::ClearSuggestions() { | |
892 NukeAllSuggestions(); | |
Marc Treib
2017/02/23 13:52:24
Should this also check ready()? Or if this can't b
jkrcal
2017/02/24 09:21:43
Done.
| |
893 if (remote_suggestions_scheduler_) { | |
894 remote_suggestions_scheduler_->OnSuggestionsCleared(); | |
Marc Treib
2017/02/23 13:52:24
Here we first nuke, then notify; in the method abo
jkrcal
2017/02/24 09:21:43
Done.
| |
895 } | |
896 } | |
897 | |
884 void RemoteSuggestionsProviderImpl::NukeAllSuggestions() { | 898 void RemoteSuggestionsProviderImpl::NukeAllSuggestions() { |
885 for (const auto& item : category_contents_) { | 899 for (const auto& item : category_contents_) { |
886 Category category = item.first; | 900 Category category = item.first; |
887 const CategoryContent& content = item.second; | 901 const CategoryContent& content = item.second; |
888 | 902 |
889 ClearCachedSuggestions(category); | 903 ClearCachedSuggestions(category); |
890 // Update listeners about the new (empty) state. | 904 // Update listeners about the new (empty) state. |
891 if (IsCategoryStatusAvailable(content.status)) { | 905 if (IsCategoryStatusAvailable(content.status)) { |
892 NotifyNewSuggestions(category, content); | 906 NotifyNewSuggestions(category, content); |
893 } | 907 } |
(...skipping 18 matching lines...) Expand all Loading... | |
912 // find it in the database (and also can't fetch it remotely). Cut the | 926 // find it in the database (and also can't fetch it remotely). Cut the |
913 // lookup short and return directly. | 927 // lookup short and return directly. |
914 base::ThreadTaskRunnerHandle::Get()->PostTask( | 928 base::ThreadTaskRunnerHandle::Get()->PostTask( |
915 FROM_HERE, base::Bind(callback, gfx::Image())); | 929 FROM_HERE, base::Bind(callback, gfx::Image())); |
916 return; | 930 return; |
917 } | 931 } |
918 image_fetcher_.FetchSuggestionImage(suggestion_id, image_url, callback); | 932 image_fetcher_.FetchSuggestionImage(suggestion_id, image_url, callback); |
919 } | 933 } |
920 | 934 |
921 void RemoteSuggestionsProviderImpl::EnterStateReady() { | 935 void RemoteSuggestionsProviderImpl::EnterStateReady() { |
922 if (nuke_when_initialized_) { | 936 if (clear_any_history_when_initialized_) { |
923 NukeAllSuggestions(); | 937 clear_any_history_when_initialized_ = false; |
924 nuke_when_initialized_ = false; | 938 ClearAnyHistory(); |
925 } | 939 } |
926 | 940 |
927 auto article_category_it = category_contents_.find(articles_category_); | 941 auto article_category_it = category_contents_.find(articles_category_); |
928 DCHECK(article_category_it != category_contents_.end()); | 942 DCHECK(article_category_it != category_contents_.end()); |
929 if (article_category_it->second.suggestions.empty() || fetch_when_ready_) { | 943 if (fetch_when_ready_) { |
930 // TODO(jkrcal): Fetching suggestions automatically upon creation of this | |
931 // lazily created service can cause troubles, e.g. in unit tests where | |
932 // network I/O is not allowed. | |
933 // Either add a DCHECK here that we actually are allowed to do network I/O | |
934 // or change the logic so that some explicit call is always needed for the | |
935 // network request. | |
936 FetchSuggestions(fetch_when_ready_interactive_, | 944 FetchSuggestions(fetch_when_ready_interactive_, |
937 std::move(fetch_when_ready_callback_)); | 945 std::move(fetch_when_ready_callback_)); |
938 fetch_when_ready_ = false; | 946 fetch_when_ready_ = false; |
939 } | 947 } |
940 | 948 |
941 for (const auto& item : category_contents_) { | 949 for (const auto& item : category_contents_) { |
942 Category category = item.first; | 950 Category category = item.first; |
943 const CategoryContent& content = item.second; | 951 const CategoryContent& content = item.second; |
944 // FetchSuggestions has set the status to |AVAILABLE_LOADING| if relevant, | 952 // FetchSuggestions has set the status to |AVAILABLE_LOADING| if relevant, |
945 // otherwise we transition to |AVAILABLE| here. | 953 // otherwise we transition to |AVAILABLE| here. |
946 if (content.status != CategoryStatus::AVAILABLE_LOADING) { | 954 if (content.status != CategoryStatus::AVAILABLE_LOADING) { |
947 UpdateCategoryStatus(category, CategoryStatus::AVAILABLE); | 955 UpdateCategoryStatus(category, CategoryStatus::AVAILABLE); |
948 } | 956 } |
949 } | 957 } |
950 } | 958 } |
951 | 959 |
952 void RemoteSuggestionsProviderImpl::EnterStateDisabled() { | 960 void RemoteSuggestionsProviderImpl::EnterStateDisabled() { |
953 NukeAllSuggestions(); | 961 ClearSuggestions(); |
954 } | 962 } |
955 | 963 |
956 void RemoteSuggestionsProviderImpl::EnterStateError() { | 964 void RemoteSuggestionsProviderImpl::EnterStateError() { |
957 status_service_.reset(); | 965 status_service_.reset(); |
958 } | 966 } |
959 | 967 |
960 void RemoteSuggestionsProviderImpl::FinishInitialization() { | 968 void RemoteSuggestionsProviderImpl::FinishInitialization() { |
961 if (nuke_when_initialized_) { | 969 if (clear_any_history_when_initialized_) { |
962 // We nuke here in addition to EnterStateReady, so that it happens even if | 970 // We clear here in addition to EnterStateReady, so that it happens even if |
963 // we enter the DISABLED state below. | 971 // we enter the DISABLED state below. |
964 NukeAllSuggestions(); | 972 clear_any_history_when_initialized_ = false; |
965 nuke_when_initialized_ = false; | 973 ClearAnyHistory(); |
966 } | 974 } |
967 | 975 |
968 // Note: Initializing the status service will run the callback right away with | 976 // Note: Initializing the status service will run the callback right away with |
969 // the current state. | 977 // the current state. |
970 status_service_->Init(base::Bind( | 978 status_service_->Init(base::Bind( |
971 &RemoteSuggestionsProviderImpl::OnStatusChanged, base::Unretained(this))); | 979 &RemoteSuggestionsProviderImpl::OnStatusChanged, base::Unretained(this))); |
972 | 980 |
973 // Always notify here even if we got nothing from the database, because we | 981 // Always notify here even if we got nothing from the database, because we |
974 // don't know how long the fetch will take or if it will even complete. | 982 // don't know how long the fetch will take or if it will even complete. |
975 for (const auto& item : category_contents_) { | 983 for (const auto& item : category_contents_) { |
976 Category category = item.first; | 984 Category category = item.first; |
977 const CategoryContent& content = item.second; | 985 const CategoryContent& content = item.second; |
978 // Note: We might be in a non-available status here, e.g. DISABLED due to | 986 // Note: We might be in a non-available status here, e.g. DISABLED due to |
979 // enterprise policy. | 987 // enterprise policy. |
980 if (IsCategoryStatusAvailable(content.status)) { | 988 if (IsCategoryStatusAvailable(content.status)) { |
981 NotifyNewSuggestions(category, content); | 989 NotifyNewSuggestions(category, content); |
982 } | 990 } |
983 } | 991 } |
984 } | 992 } |
985 | 993 |
986 void RemoteSuggestionsProviderImpl::OnStatusChanged( | 994 void RemoteSuggestionsProviderImpl::OnStatusChanged( |
987 RemoteSuggestionsStatus old_status, | 995 RemoteSuggestionsStatus old_status, |
988 RemoteSuggestionsStatus new_status) { | 996 RemoteSuggestionsStatus new_status) { |
989 switch (new_status) { | 997 switch (new_status) { |
990 case RemoteSuggestionsStatus::ENABLED_AND_SIGNED_IN: | 998 case RemoteSuggestionsStatus::ENABLED_AND_SIGNED_IN: |
991 if (old_status == RemoteSuggestionsStatus::ENABLED_AND_SIGNED_OUT) { | 999 if (old_status == RemoteSuggestionsStatus::ENABLED_AND_SIGNED_OUT) { |
992 DCHECK(state_ == State::READY); | 1000 DCHECK(state_ == State::READY); |
993 // Clear nonpersonalized suggestions. | 1001 // Clear nonpersonalized suggestions (and notify the scheduler there are |
994 NukeAllSuggestions(); | 1002 // no suggestions). |
995 // Fetch personalized ones. | 1003 ClearSuggestions(); |
996 // TODO(jkrcal): Loop in SchedulingRemoteSuggestionsProvider somehow. | |
997 FetchSuggestions(/*interactive_request=*/true, | |
998 /*callback=*/nullptr); | |
999 } else { | 1004 } else { |
1000 // Do not change the status. That will be done in EnterStateReady(). | 1005 // Do not change the status. That will be done in EnterStateReady(). |
1001 EnterState(State::READY); | 1006 EnterState(State::READY); |
1002 } | 1007 } |
1003 break; | 1008 break; |
1004 | 1009 |
1005 case RemoteSuggestionsStatus::ENABLED_AND_SIGNED_OUT: | 1010 case RemoteSuggestionsStatus::ENABLED_AND_SIGNED_OUT: |
1006 if (old_status == RemoteSuggestionsStatus::ENABLED_AND_SIGNED_IN) { | 1011 if (old_status == RemoteSuggestionsStatus::ENABLED_AND_SIGNED_IN) { |
1007 DCHECK(state_ == State::READY); | 1012 DCHECK(state_ == State::READY); |
1008 // Clear personalized suggestions. | 1013 // Clear personalized suggestions (and notify the scheduler there are |
1009 NukeAllSuggestions(); | 1014 // no suggestions). |
1010 // Fetch nonpersonalized ones. | 1015 ClearSuggestions(); |
1011 // TODO(jkrcal): Loop in SchedulingRemoteSuggestionsProvider somehow. | |
1012 FetchSuggestions(/*interactive_request=*/true, | |
1013 /*callback=*/nullptr); | |
1014 } else { | 1016 } else { |
1015 // Do not change the status. That will be done in EnterStateReady(). | 1017 // Do not change the status. That will be done in EnterStateReady(). |
1016 EnterState(State::READY); | 1018 EnterState(State::READY); |
1017 } | 1019 } |
1018 break; | 1020 break; |
1019 | 1021 |
1020 case RemoteSuggestionsStatus::EXPLICITLY_DISABLED: | 1022 case RemoteSuggestionsStatus::EXPLICITLY_DISABLED: |
1021 EnterState(State::DISABLED); | 1023 EnterState(State::DISABLED); |
1022 UpdateAllCategoryStatus(CategoryStatus::CATEGORY_EXPLICITLY_DISABLED); | 1024 UpdateAllCategoryStatus(CategoryStatus::CATEGORY_EXPLICITLY_DISABLED); |
1023 break; | 1025 break; |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1063 | 1065 |
1064 case State::COUNT: | 1066 case State::COUNT: |
1065 NOTREACHED(); | 1067 NOTREACHED(); |
1066 break; | 1068 break; |
1067 } | 1069 } |
1068 | 1070 |
1069 NotifyStateChanged(); | 1071 NotifyStateChanged(); |
1070 } | 1072 } |
1071 | 1073 |
1072 void RemoteSuggestionsProviderImpl::NotifyStateChanged() { | 1074 void RemoteSuggestionsProviderImpl::NotifyStateChanged() { |
1073 if (!provider_status_callback_) { | 1075 if (!remote_suggestions_scheduler_) { |
1074 return; | 1076 return; |
1075 } | 1077 } |
1076 | 1078 |
1077 switch (state_) { | 1079 switch (state_) { |
1078 case State::NOT_INITED: | 1080 case State::NOT_INITED: |
1079 // Initial state, not sure yet whether active or not. | 1081 // Initial state, not sure yet whether active or not. |
1080 break; | 1082 break; |
1081 case State::READY: | 1083 case State::READY: |
1082 provider_status_callback_->Run(ProviderStatus::ACTIVE); | 1084 remote_suggestions_scheduler_->OnProviderActivated(); |
1083 break; | 1085 break; |
1084 case State::DISABLED: | 1086 case State::DISABLED: |
1085 provider_status_callback_->Run(ProviderStatus::INACTIVE); | 1087 remote_suggestions_scheduler_->OnProviderInactivated(); |
Marc Treib
2017/02/23 13:52:24
nit: s/Inactivated/Deactivated/ (I don't think ina
jkrcal
2017/02/24 09:21:43
Done.
| |
1086 break; | 1088 break; |
1087 case State::ERROR_OCCURRED: | 1089 case State::ERROR_OCCURRED: |
1088 provider_status_callback_->Run(ProviderStatus::INACTIVE); | 1090 remote_suggestions_scheduler_->OnProviderInactivated(); |
1089 break; | 1091 break; |
1090 case State::COUNT: | 1092 case State::COUNT: |
1091 NOTREACHED(); | 1093 NOTREACHED(); |
1092 break; | 1094 break; |
1093 } | 1095 } |
1094 } | 1096 } |
1095 | 1097 |
1096 void RemoteSuggestionsProviderImpl::NotifyNewSuggestions( | 1098 void RemoteSuggestionsProviderImpl::NotifyNewSuggestions( |
1097 Category category, | 1099 Category category, |
1098 const CategoryContent& content) { | 1100 const CategoryContent& content) { |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1270 RemoteSuggestionsProviderImpl::CategoryContent::CategoryContent( | 1272 RemoteSuggestionsProviderImpl::CategoryContent::CategoryContent( |
1271 CategoryContent&&) = default; | 1273 CategoryContent&&) = default; |
1272 | 1274 |
1273 RemoteSuggestionsProviderImpl::CategoryContent::~CategoryContent() = default; | 1275 RemoteSuggestionsProviderImpl::CategoryContent::~CategoryContent() = default; |
1274 | 1276 |
1275 RemoteSuggestionsProviderImpl::CategoryContent& | 1277 RemoteSuggestionsProviderImpl::CategoryContent& |
1276 RemoteSuggestionsProviderImpl::CategoryContent::operator=(CategoryContent&&) = | 1278 RemoteSuggestionsProviderImpl::CategoryContent::operator=(CategoryContent&&) = |
1277 default; | 1279 default; |
1278 | 1280 |
1279 } // namespace ntp_snippets | 1281 } // namespace ntp_snippets |
OLD | NEW |