| 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/physical_web_pages/physical_web_page_suggestio
ns_provider.h" | 5 #include "components/ntp_snippets/physical_web_pages/physical_web_page_suggestio
ns_provider.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <memory> | 8 #include <memory> |
| 9 #include <set> | 9 #include <set> |
| 10 #include <string> | 10 #include <string> |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 145 gfx::Image::CreateFrom1xPNGBytes( | 145 gfx::Image::CreateFrom1xPNGBytes( |
| 146 reinterpret_cast<const unsigned char*>(raw_data.data()), | 146 reinterpret_cast<const unsigned char*>(raw_data.data()), |
| 147 raw_data.size()))); | 147 raw_data.size()))); |
| 148 } | 148 } |
| 149 | 149 |
| 150 void PhysicalWebPageSuggestionsProvider::Fetch( | 150 void PhysicalWebPageSuggestionsProvider::Fetch( |
| 151 const Category& category, | 151 const Category& category, |
| 152 const std::set<std::string>& known_suggestion_ids, | 152 const std::set<std::string>& known_suggestion_ids, |
| 153 const FetchDoneCallback& callback) { | 153 const FetchDoneCallback& callback) { |
| 154 DCHECK_EQ(category, provided_category_); | 154 DCHECK_EQ(category, provided_category_); |
| 155 std::vector<ContentSuggestion> suggestions = |
| 156 GetMostRecentPhysicalWebPagesWithFilter(kMaxSuggestionsCount, |
| 157 known_suggestion_ids); |
| 158 AppendToShownScannedUrls(suggestions); |
| 155 base::ThreadTaskRunnerHandle::Get()->PostTask( | 159 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 156 FROM_HERE, | 160 FROM_HERE, base::Bind(callback, Status::Success(), |
| 157 base::Bind(callback, Status::Success(), | 161 base::Passed(std::move(suggestions)))); |
| 158 base::Passed(GetMostRecentPhysicalWebPagesWithFilter( | |
| 159 kMaxSuggestionsCount, known_suggestion_ids)))); | |
| 160 } | 162 } |
| 161 | 163 |
| 162 void PhysicalWebPageSuggestionsProvider::ClearHistory( | 164 void PhysicalWebPageSuggestionsProvider::ClearHistory( |
| 163 base::Time begin, | 165 base::Time begin, |
| 164 base::Time end, | 166 base::Time end, |
| 165 const base::Callback<bool(const GURL& url)>& filter) { | 167 const base::Callback<bool(const GURL& url)>& filter) { |
| 166 ClearDismissedSuggestionsForDebugging(provided_category_); | 168 ClearDismissedSuggestionsForDebugging(provided_category_); |
| 167 } | 169 } |
| 168 | 170 |
| 169 void PhysicalWebPageSuggestionsProvider::ClearCachedSuggestions( | 171 void PhysicalWebPageSuggestionsProvider::ClearCachedSuggestions( |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 208 CategoryStatus new_status) { | 210 CategoryStatus new_status) { |
| 209 if (category_status_ == new_status) { | 211 if (category_status_ == new_status) { |
| 210 return; | 212 return; |
| 211 } | 213 } |
| 212 category_status_ = new_status; | 214 category_status_ = new_status; |
| 213 observer()->OnCategoryStatusChanged(this, provided_category_, new_status); | 215 observer()->OnCategoryStatusChanged(this, provided_category_, new_status); |
| 214 } | 216 } |
| 215 | 217 |
| 216 void PhysicalWebPageSuggestionsProvider::FetchPhysicalWebPages() { | 218 void PhysicalWebPageSuggestionsProvider::FetchPhysicalWebPages() { |
| 217 DCHECK_EQ(CategoryStatus::AVAILABLE, category_status_); | 219 DCHECK_EQ(CategoryStatus::AVAILABLE, category_status_); |
| 220 std::vector<ContentSuggestion> suggestions = |
| 221 GetMostRecentPhysicalWebPagesWithFilter( |
| 222 kMaxSuggestionsCount, |
| 223 /*excluded_ids=*/std::set<std::string>()); |
| 224 shown_resolved_urls_by_scanned_url_.clear(); |
| 225 AppendToShownScannedUrls(suggestions); |
| 218 observer()->OnNewSuggestions(this, provided_category_, | 226 observer()->OnNewSuggestions(this, provided_category_, |
| 219 GetMostRecentPhysicalWebPagesWithFilter( | 227 std::move(suggestions)); |
| 220 kMaxSuggestionsCount, | |
| 221 /*excluded_ids=*/std::set<std::string>())); | |
| 222 } | 228 } |
| 223 | 229 |
| 224 std::vector<ContentSuggestion> | 230 std::vector<ContentSuggestion> |
| 225 PhysicalWebPageSuggestionsProvider::GetMostRecentPhysicalWebPagesWithFilter( | 231 PhysicalWebPageSuggestionsProvider::GetMostRecentPhysicalWebPagesWithFilter( |
| 226 int max_quantity, | 232 int max_count, |
| 227 const std::set<std::string>& excluded_ids) { | 233 const std::set<std::string>& excluded_ids) { |
| 228 std::unique_ptr<physical_web::MetadataList> page_metadata_list = | 234 std::unique_ptr<physical_web::MetadataList> page_metadata_list = |
| 229 physical_web_data_source_->GetMetadataList(); | 235 physical_web_data_source_->GetMetadataList(); |
| 230 | 236 |
| 231 // These is to filter out dismissed suggestions and at the same time prune the | 237 // These is to filter out dismissed suggestions and at the same time prune the |
| 232 // dismissed IDs list removing nonavailable pages (this is need since some | 238 // dismissed IDs list removing nonavailable pages (this is needed since some |
| 233 // OnLost() calls may have been missed). | 239 // OnLost() calls may have been missed). |
| 234 const std::set<std::string> old_dismissed_ids = ReadDismissedIDsFromPrefs(); | 240 const std::set<std::string> old_dismissed_ids = ReadDismissedIDsFromPrefs(); |
| 235 std::set<std::string> new_dismissed_ids; | 241 std::set<std::string> new_dismissed_ids; |
| 236 physical_web::MetadataList filtered_metadata_list; | 242 physical_web::MetadataList filtered_metadata_list; |
| 237 for (const auto& page_metadata : *page_metadata_list) { | 243 for (const auto& page_metadata : *page_metadata_list) { |
| 238 const std::string page_id = GetPageId(page_metadata); | 244 const std::string page_id = GetPageId(page_metadata); |
| 239 if (!excluded_ids.count(page_id) && !old_dismissed_ids.count(page_id)) { | 245 if (!excluded_ids.count(page_id) && !old_dismissed_ids.count(page_id)) { |
| 240 filtered_metadata_list.push_back(page_metadata); | 246 filtered_metadata_list.push_back(page_metadata); |
| 241 } | 247 } |
| 242 | 248 |
| 243 if (old_dismissed_ids.count(page_id)) { | 249 if (old_dismissed_ids.count(page_id)) { |
| 244 new_dismissed_ids.insert(page_id); | 250 new_dismissed_ids.insert(page_id); |
| 245 } | 251 } |
| 246 } | 252 } |
| 247 | 253 |
| 248 if (old_dismissed_ids.size() != new_dismissed_ids.size()) { | 254 if (old_dismissed_ids.size() != new_dismissed_ids.size()) { |
| 249 StoreDismissedIDsToPrefs(new_dismissed_ids); | 255 StoreDismissedIDsToPrefs(new_dismissed_ids); |
| 250 } | 256 } |
| 251 | 257 |
| 252 FilterOutByGroupId(filtered_metadata_list); | 258 FilterOutByGroupId(filtered_metadata_list); |
| 253 | 259 |
| 254 std::sort(filtered_metadata_list.begin(), filtered_metadata_list.end(), | 260 std::sort(filtered_metadata_list.begin(), filtered_metadata_list.end(), |
| 255 CompareByDistance); | 261 CompareByDistance); |
| 256 | 262 |
| 257 std::vector<ContentSuggestion> suggestions; | 263 std::vector<ContentSuggestion> suggestions; |
| 258 for (const auto& page_metadata : filtered_metadata_list) { | 264 for (const auto& page_metadata : filtered_metadata_list) { |
| 259 if (static_cast<int>(suggestions.size()) == max_quantity) { | 265 if (static_cast<int>(suggestions.size()) == max_count) { |
| 260 break; | 266 break; |
| 261 } | 267 } |
| 262 suggestions.push_back(ConvertPhysicalWebPage(page_metadata)); | 268 suggestions.push_back(ConvertPhysicalWebPage(page_metadata)); |
| 263 } | 269 } |
| 264 | 270 |
| 265 return suggestions; | 271 return suggestions; |
| 266 } | 272 } |
| 267 | 273 |
| 268 ContentSuggestion PhysicalWebPageSuggestionsProvider::ConvertPhysicalWebPage( | 274 ContentSuggestion PhysicalWebPageSuggestionsProvider::ConvertPhysicalWebPage( |
| 269 const physical_web::Metadata& page) const { | 275 const physical_web::Metadata& page) const { |
| 270 ContentSuggestion suggestion(provided_category_, GetPageId(page), | 276 ContentSuggestion suggestion(provided_category_, GetPageId(page), |
| 271 page.resolved_url); | 277 page.resolved_url); |
| 272 DCHECK(base::IsStringUTF8(page.title)); | 278 DCHECK(base::IsStringUTF8(page.title)); |
| 273 suggestion.set_title(base::UTF8ToUTF16(page.title)); | 279 suggestion.set_title(base::UTF8ToUTF16(page.title)); |
| 274 suggestion.set_publisher_name(base::UTF8ToUTF16(page.resolved_url.host())); | 280 suggestion.set_publisher_name(base::UTF8ToUTF16(page.resolved_url.host())); |
| 275 DCHECK(base::IsStringUTF8(page.description)); | 281 DCHECK(base::IsStringUTF8(page.description)); |
| 276 suggestion.set_snippet_text(base::UTF8ToUTF16(page.description)); | 282 suggestion.set_snippet_text(base::UTF8ToUTF16(page.description)); |
| 277 return suggestion; | 283 return suggestion; |
| 278 } | 284 } |
| 279 | 285 |
| 280 // PhysicalWebListener implementation. | 286 // PhysicalWebListener implementation. |
| 281 void PhysicalWebPageSuggestionsProvider::OnFound(const GURL& url) { | 287 void PhysicalWebPageSuggestionsProvider::OnFound(const GURL& url) { |
| 282 FetchPhysicalWebPages(); | 288 FetchPhysicalWebPages(); |
| 283 } | 289 } |
| 284 | 290 |
| 285 void PhysicalWebPageSuggestionsProvider::OnLost(const GURL& url) { | 291 void PhysicalWebPageSuggestionsProvider::OnLost(const GURL& url) { |
| 286 InvalidateSuggestion(url.spec()); | 292 auto it = shown_resolved_urls_by_scanned_url_.find(url); |
| 293 if (it == shown_resolved_urls_by_scanned_url_.end()) { |
| 294 // The notification is propagated further in case the suggestion is shown on |
| 295 // old NTPs (created before last |shown_resolved_urls_by_scanned_url_| |
| 296 // update). |
| 297 |
| 298 // TODO(vitaliii): Use |resolved_url| here when it is available. Currently |
| 299 // there is no way to find out |resolved_url|, which corresponds to this |
| 300 // |scanned_url| (the metadata has been already removed from the Physical |
| 301 // Web list). We use |scanned_url| (it may be the same as |resolved_url|, |
| 302 // otherwise nothing happens), however, we should use the latter once it is |
| 303 // provided (e.g. as an argument). |
| 304 InvalidateSuggestion(url.spec()); |
| 305 return; |
| 306 } |
| 307 |
| 308 // This is not a reference, because the multimap pair will be removed below. |
| 309 const GURL lost_resolved_url = it->second; |
| 310 shown_resolved_urls_by_scanned_url_.erase(it); |
| 311 if (std::find_if(shown_resolved_urls_by_scanned_url_.begin(), |
| 312 shown_resolved_urls_by_scanned_url_.end(), |
| 313 [lost_resolved_url](const std::pair<GURL, GURL>& pair) { |
| 314 return lost_resolved_url == pair.second; |
| 315 }) == shown_resolved_urls_by_scanned_url_.end()) { |
| 316 // There are no more beacons for this URL. |
| 317 InvalidateSuggestion(lost_resolved_url.spec()); |
| 318 } |
| 287 } | 319 } |
| 288 | 320 |
| 289 void PhysicalWebPageSuggestionsProvider::OnDistanceChanged( | 321 void PhysicalWebPageSuggestionsProvider::OnDistanceChanged( |
| 290 const GURL& url, | 322 const GURL& url, |
| 291 double distance_estimate) { | 323 double distance_estimate) { |
| 292 FetchPhysicalWebPages(); | 324 FetchPhysicalWebPages(); |
| 293 } | 325 } |
| 294 | 326 |
| 295 void PhysicalWebPageSuggestionsProvider::InvalidateSuggestion( | 327 void PhysicalWebPageSuggestionsProvider::InvalidateSuggestion( |
| 296 const std::string& page_id) { | 328 const std::string& page_id) { |
| 297 observer()->OnSuggestionInvalidated( | 329 observer()->OnSuggestionInvalidated( |
| 298 this, ContentSuggestion::ID(provided_category_, page_id)); | 330 this, ContentSuggestion::ID(provided_category_, page_id)); |
| 299 | 331 |
| 300 // Remove |page_id| from dismissed suggestions, if present. | 332 // Remove |page_id| from dismissed suggestions, if present. |
| 301 std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs(); | 333 std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs(); |
| 302 auto it = dismissed_ids.find(page_id); | 334 auto it = dismissed_ids.find(page_id); |
| 303 if (it != dismissed_ids.end()) { | 335 if (it != dismissed_ids.end()) { |
| 304 dismissed_ids.erase(it); | 336 dismissed_ids.erase(it); |
| 305 StoreDismissedIDsToPrefs(dismissed_ids); | 337 StoreDismissedIDsToPrefs(dismissed_ids); |
| 306 } | 338 } |
| 307 } | 339 } |
| 308 | 340 |
| 341 void PhysicalWebPageSuggestionsProvider::AppendToShownScannedUrls( |
| 342 const std::vector<ContentSuggestion>& suggestions) { |
| 343 std::unique_ptr<physical_web::MetadataList> page_metadata_list = |
| 344 physical_web_data_source_->GetMetadataList(); |
| 345 for (const auto& page_metadata : *page_metadata_list) { |
| 346 if (std::find_if(suggestions.begin(), suggestions.end(), |
| 347 [page_metadata](const ContentSuggestion& suggestion) { |
| 348 return suggestion.url() == page_metadata.resolved_url; |
| 349 }) != suggestions.end()) { |
| 350 shown_resolved_urls_by_scanned_url_.insert(std::make_pair( |
| 351 page_metadata.scanned_url, page_metadata.resolved_url)); |
| 352 } |
| 353 } |
| 354 } |
| 355 |
| 309 std::set<std::string> | 356 std::set<std::string> |
| 310 PhysicalWebPageSuggestionsProvider::ReadDismissedIDsFromPrefs() const { | 357 PhysicalWebPageSuggestionsProvider::ReadDismissedIDsFromPrefs() const { |
| 311 return prefs::ReadDismissedIDsFromPrefs( | 358 return prefs::ReadDismissedIDsFromPrefs( |
| 312 *pref_service_, prefs::kDismissedPhysicalWebPageSuggestions); | 359 *pref_service_, prefs::kDismissedPhysicalWebPageSuggestions); |
| 313 } | 360 } |
| 314 | 361 |
| 315 void PhysicalWebPageSuggestionsProvider::StoreDismissedIDsToPrefs( | 362 void PhysicalWebPageSuggestionsProvider::StoreDismissedIDsToPrefs( |
| 316 const std::set<std::string>& dismissed_ids) { | 363 const std::set<std::string>& dismissed_ids) { |
| 317 prefs::StoreDismissedIDsToPrefs(pref_service_, | 364 prefs::StoreDismissedIDsToPrefs(pref_service_, |
| 318 prefs::kDismissedPhysicalWebPageSuggestions, | 365 prefs::kDismissedPhysicalWebPageSuggestions, |
| 319 dismissed_ids); | 366 dismissed_ids); |
| 320 } | 367 } |
| 321 | 368 |
| 322 } // namespace ntp_snippets | 369 } // namespace ntp_snippets |
| OLD | NEW |