Chromium Code Reviews| 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 "chrome/browser/engagement/important_sites_util.h" | 5 #include "chrome/browser/engagement/important_sites_util.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <map> | 8 #include <map> |
| 9 #include <memory> | 9 #include <memory> |
| 10 #include <set> | 10 #include <set> |
| 11 #include <utility> | 11 #include <utility> |
| 12 | 12 |
| 13 #include "base/containers/hash_tables.h" | 13 #include "base/containers/hash_tables.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/stl_util.h" | 16 #include "base/stl_util.h" |
| 17 #include "base/strings/string_number_conversions.h" | |
| 17 #include "base/time/time.h" | 18 #include "base/time/time.h" |
| 18 #include "base/values.h" | 19 #include "base/values.h" |
| 19 #include "chrome/browser/banners/app_banner_settings_helper.h" | 20 #include "chrome/browser/banners/app_banner_settings_helper.h" |
| 20 #include "chrome/browser/bookmarks/bookmark_model_factory.h" | 21 #include "chrome/browser/bookmarks/bookmark_model_factory.h" |
| 21 #include "chrome/browser/content_settings/host_content_settings_map_factory.h" | 22 #include "chrome/browser/content_settings/host_content_settings_map_factory.h" |
| 22 #include "chrome/browser/engagement/site_engagement_score.h" | 23 #include "chrome/browser/engagement/site_engagement_score.h" |
| 23 #include "chrome/browser/engagement/site_engagement_service.h" | 24 #include "chrome/browser/engagement/site_engagement_service.h" |
| 24 #include "chrome/browser/profiles/profile.h" | 25 #include "chrome/browser/profiles/profile.h" |
| 26 #include "chrome/common/pref_names.h" | |
| 25 #include "components/bookmarks/browser/bookmark_model.h" | 27 #include "components/bookmarks/browser/bookmark_model.h" |
| 26 #include "components/content_settings/core/browser/host_content_settings_map.h" | 28 #include "components/content_settings/core/browser/host_content_settings_map.h" |
| 27 #include "components/content_settings/core/common/content_settings.h" | 29 #include "components/content_settings/core/common/content_settings.h" |
| 30 #include "components/pref_registry/pref_registry_syncable.h" | |
| 31 #include "components/prefs/pref_service.h" | |
| 32 #include "components/prefs/scoped_user_pref_update.h" | |
| 28 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" | 33 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
| 29 #include "third_party/WebKit/public/platform/site_engagement.mojom.h" | 34 #include "third_party/WebKit/public/platform/site_engagement.mojom.h" |
| 30 #include "url/gurl.h" | 35 #include "url/gurl.h" |
| 31 | 36 |
| 32 namespace { | 37 namespace { |
| 33 using bookmarks::BookmarkModel; | 38 using bookmarks::BookmarkModel; |
| 34 using ImportantDomainInfo = ImportantSitesUtil::ImportantDomainInfo; | 39 using ImportantDomainInfo = ImportantSitesUtil::ImportantDomainInfo; |
| 35 | 40 |
| 41 static const char kTimeLastIgnored[] = "TimeBlacklisted"; | |
| 42 static const int kBlacklistExpirationTimeDays = 30 * 5; | |
| 43 | |
| 36 static const char kNumTimesIgnoredName[] = "NumTimesIgnored"; | 44 static const char kNumTimesIgnoredName[] = "NumTimesIgnored"; |
| 37 static const int kTimesIgnoredForBlacklist = 3; | 45 static const int kTimesIgnoredForBlacklist = 3; |
| 38 | 46 |
| 39 // These are the maximum # of bookmarks we can use as signals. If the user has | 47 // These are the maximum # of bookmarks we can use as signals. If the user has |
| 40 // <= kMaxBookmarks, then we just use those bookmarks. Otherwise we filter all | 48 // <= kMaxBookmarks, then we just use those bookmarks. Otherwise we filter all |
| 41 // bookmarks on site engagement > 0, sort, and trim to kMaxBookmarks. | 49 // bookmarks on site engagement > 0, sort, and trim to kMaxBookmarks. |
| 42 static const int kMaxBookmarks = 5; | 50 static const int kMaxBookmarks = 5; |
| 43 | 51 |
| 44 // Do not change the values here, as they are used for UMA histograms. | 52 // Do not change the values here, as they are used for UMA histograms. |
| 45 enum ImportantReason { | 53 enum ImportantReason { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 77 CROSSED_NOTIFICATIONS = 1, | 85 CROSSED_NOTIFICATIONS = 1, |
| 78 CROSSED_ENGAGEMENT = 2, | 86 CROSSED_ENGAGEMENT = 2, |
| 79 CROSSED_NOTIFICATIONS_AND_ENGAGEMENT = 3, | 87 CROSSED_NOTIFICATIONS_AND_ENGAGEMENT = 3, |
| 80 CROSSED_DURABLE_AND_ENGAGEMENT = 4, | 88 CROSSED_DURABLE_AND_ENGAGEMENT = 4, |
| 81 CROSSED_NOTIFICATIONS_AND_DURABLE = 5, | 89 CROSSED_NOTIFICATIONS_AND_DURABLE = 5, |
| 82 CROSSED_NOTIFICATIONS_AND_DURABLE_AND_ENGAGEMENT = 6, | 90 CROSSED_NOTIFICATIONS_AND_DURABLE_AND_ENGAGEMENT = 6, |
| 83 CROSSED_REASON_UNKNOWN = 7, | 91 CROSSED_REASON_UNKNOWN = 7, |
| 84 CROSSED_REASON_BOUNDARY | 92 CROSSED_REASON_BOUNDARY |
| 85 }; | 93 }; |
| 86 | 94 |
| 95 void IncrementTimesIgnoredAndSetDate(base::DictionaryValue* dict) { | |
| 96 int times_ignored = 0; | |
| 97 dict->GetInteger(kNumTimesIgnoredName, ×_ignored); | |
| 98 dict->SetInteger(kNumTimesIgnoredName, ++times_ignored); | |
| 99 dict->SetString(kTimeLastIgnored, | |
| 100 base::Int64ToString(base::Time::Now().ToInternalValue())); | |
|
dominickn
2017/02/01 22:22:04
Instead of a string, can you use a double? It seem
dmurph
2017/02/02 23:53:29
Done.
| |
| 101 } | |
| 102 | |
| 103 // Returns if we cleared the blacklist. | |
| 104 bool ClearBlacklistIfOld(base::DictionaryValue* dict) { | |
| 105 std::string date_blacklisted; | |
| 106 dict->GetString(kTimeLastIgnored, &date_blacklisted); | |
| 107 int64_t time_internal_value; | |
| 108 if (!date_blacklisted.empty() && | |
| 109 base::StringToInt64(date_blacklisted, &time_internal_value)) { | |
| 110 base::TimeDelta diff = | |
| 111 base::Time::Now() - base::Time::FromInternalValue(time_internal_value); | |
| 112 if (diff >= base::TimeDelta::FromDays(kBlacklistExpirationTimeDays)) { | |
| 113 dict->SetInteger(kNumTimesIgnoredName, 0); | |
| 114 return true; | |
| 115 } | |
| 116 } | |
| 117 return false; | |
| 118 } | |
| 119 | |
| 87 CrossedReason GetCrossedReasonFromBitfield(int32_t reason_bitfield) { | 120 CrossedReason GetCrossedReasonFromBitfield(int32_t reason_bitfield) { |
| 88 bool durable = (reason_bitfield & (1 << ImportantReason::DURABLE)) != 0; | 121 bool durable = (reason_bitfield & (1 << ImportantReason::DURABLE)) != 0; |
| 89 bool notifications = | 122 bool notifications = |
| 90 (reason_bitfield & (1 << ImportantReason::NOTIFICATIONS)) != 0; | 123 (reason_bitfield & (1 << ImportantReason::NOTIFICATIONS)) != 0; |
| 91 bool engagement = (reason_bitfield & (1 << ImportantReason::ENGAGEMENT)) != 0; | 124 bool engagement = (reason_bitfield & (1 << ImportantReason::ENGAGEMENT)) != 0; |
| 92 if (durable && notifications && engagement) | 125 if (durable && notifications && engagement) |
| 93 return CROSSED_NOTIFICATIONS_AND_DURABLE_AND_ENGAGEMENT; | 126 return CROSSED_NOTIFICATIONS_AND_DURABLE_AND_ENGAGEMENT; |
| 94 else if (notifications && durable) | 127 else if (notifications && durable) |
| 95 return CROSSED_NOTIFICATIONS_AND_DURABLE; | 128 return CROSSED_NOTIFICATIONS_AND_DURABLE; |
| 96 else if (notifications && engagement) | 129 else if (notifications && engagement) |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 191 } | 224 } |
| 192 | 225 |
| 193 std::unique_ptr<base::DictionaryValue> dict = | 226 std::unique_ptr<base::DictionaryValue> dict = |
| 194 base::DictionaryValue::From(map->GetWebsiteSetting( | 227 base::DictionaryValue::From(map->GetWebsiteSetting( |
| 195 origin, origin, CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO, "", | 228 origin, origin, CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO, "", |
| 196 nullptr)); | 229 nullptr)); |
| 197 | 230 |
| 198 if (!dict) | 231 if (!dict) |
| 199 continue; | 232 continue; |
| 200 | 233 |
| 234 bool cleared_blacklist = ClearBlacklistIfOld(dict.get()); | |
| 235 | |
| 201 int times_ignored = 0; | 236 int times_ignored = 0; |
| 202 if (!dict->GetInteger(kNumTimesIgnoredName, ×_ignored) || | 237 if (cleared_blacklist || |
| 238 !dict->GetInteger(kNumTimesIgnoredName, ×_ignored) || | |
| 203 times_ignored < kTimesIgnoredForBlacklist) { | 239 times_ignored < kTimesIgnoredForBlacklist) { |
| 204 continue; | 240 continue; |
| 205 } | 241 } |
| 206 | 242 |
| 207 ignoring_domains.insert(origin.host()); | 243 ignoring_domains.insert(origin.host()); |
| 208 } | 244 } |
| 209 return ignoring_domains; | 245 return ignoring_domains; |
| 210 } | 246 } |
| 211 | 247 |
| 212 void PopulateInfoMapWithSiteEngagement( | 248 void PopulateInfoMapWithSiteEngagement( |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 313 GURL origin(site.primary_pattern.ToString()); | 349 GURL origin(site.primary_pattern.ToString()); |
| 314 if (!AppBannerSettingsHelper::WasLaunchedRecently(profile, origin, now)) | 350 if (!AppBannerSettingsHelper::WasLaunchedRecently(profile, origin, now)) |
| 315 continue; | 351 continue; |
| 316 MaybePopulateImportantInfoForReason(origin, &content_origins, | 352 MaybePopulateImportantInfoForReason(origin, &content_origins, |
| 317 ImportantReason::HOME_SCREEN, output); | 353 ImportantReason::HOME_SCREEN, output); |
| 318 } | 354 } |
| 319 } | 355 } |
| 320 | 356 |
| 321 } // namespace | 357 } // namespace |
| 322 | 358 |
| 359 bool ImportantSitesUtil::IsDialogDisabled(Profile* profile) { | |
|
dominickn
2017/02/01 22:22:04
This method doesn't seem to be called from anywher
dmurph
2017/02/02 23:53:29
Changed, we now call it from Java.
| |
| 360 PrefService* service = profile->GetPrefs(); | |
| 361 DictionaryPrefUpdate update(service, prefs::kImportantSitesDialogHistory); | |
| 362 | |
| 363 if (ClearBlacklistIfOld(update.Get())) { | |
|
dominickn
2017/02/01 22:22:04
Nit: remove {} for consistency.
dmurph
2017/02/02 23:53:29
Done.
| |
| 364 return false; | |
| 365 } | |
| 366 | |
| 367 int times_ignored = 0; | |
| 368 update->GetInteger(kNumTimesIgnoredName, ×_ignored); | |
| 369 return times_ignored >= kTimesIgnoredForBlacklist; | |
| 370 } | |
| 371 | |
| 372 void ImportantSitesUtil::RegisterProfilePrefs( | |
| 373 user_prefs::PrefRegistrySyncable* registry) { | |
| 374 auto dict = base::MakeUnique<base::DictionaryValue>(); | |
| 375 dict->SetInteger(kNumTimesIgnoredName, 0); | |
| 376 registry->RegisterDictionaryPref(prefs::kImportantSitesDialogHistory, | |
| 377 dict.release()); | |
| 378 } | |
| 379 | |
| 323 std::vector<ImportantDomainInfo> | 380 std::vector<ImportantDomainInfo> |
| 324 ImportantSitesUtil::GetImportantRegisterableDomains(Profile* profile, | 381 ImportantSitesUtil::GetImportantRegisterableDomains(Profile* profile, |
| 325 size_t max_results) { | 382 size_t max_results) { |
| 326 base::hash_map<std::string, ImportantDomainInfo> important_info; | 383 base::hash_map<std::string, ImportantDomainInfo> important_info; |
| 327 std::map<GURL, double> engagement_map; | 384 std::map<GURL, double> engagement_map; |
| 328 | 385 |
| 329 PopulateInfoMapWithSiteEngagement( | 386 PopulateInfoMapWithSiteEngagement( |
| 330 profile, blink::mojom::EngagementLevel::MEDIUM, &engagement_map, | 387 profile, blink::mojom::EngagementLevel::MEDIUM, &engagement_map, |
| 331 &important_info); | 388 &important_info); |
| 332 | 389 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 378 RECORD_UMA_FOR_IMPORTANT_REASON( | 435 RECORD_UMA_FOR_IMPORTANT_REASON( |
| 379 "Storage.ImportantSites.CBDChosenReason", | 436 "Storage.ImportantSites.CBDChosenReason", |
| 380 "Storage.ImportantSites.CBDChosenReasonCount", reason_bitfield); | 437 "Storage.ImportantSites.CBDChosenReasonCount", reason_bitfield); |
| 381 } | 438 } |
| 382 for (int32_t reason_bitfield : ignored_sites_reason_bitfield) { | 439 for (int32_t reason_bitfield : ignored_sites_reason_bitfield) { |
| 383 RECORD_UMA_FOR_IMPORTANT_REASON( | 440 RECORD_UMA_FOR_IMPORTANT_REASON( |
| 384 "Storage.ImportantSites.CBDIgnoredReason", | 441 "Storage.ImportantSites.CBDIgnoredReason", |
| 385 "Storage.ImportantSites.CBDIgnoredReasonCount", reason_bitfield); | 442 "Storage.ImportantSites.CBDIgnoredReasonCount", reason_bitfield); |
| 386 } | 443 } |
| 387 | 444 |
| 388 // We use the ignored sites to update our important sites blacklist. | |
| 389 HostContentSettingsMap* map = | 445 HostContentSettingsMap* map = |
| 390 HostContentSettingsMapFactory::GetForProfile(profile); | 446 HostContentSettingsMapFactory::GetForProfile(profile); |
| 391 for (const std::string& ignored_site : ignored_sites) { | |
| 392 GURL origin("http://" + ignored_site); | |
| 393 std::unique_ptr<base::Value> value = map->GetWebsiteSetting( | |
| 394 origin, origin, CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO, "", nullptr); | |
| 395 | 447 |
| 396 std::unique_ptr<base::DictionaryValue> dict = | 448 // We use the ignored sites to update our important sites blacklist only if |
| 397 base::DictionaryValue::From(map->GetWebsiteSetting( | 449 // the user chose to blacklist a site. |
| 398 origin, origin, CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO, "", | 450 if (ignored_sites.size() != blacklisted_sites.size()) { |
| 399 nullptr)); | 451 for (const std::string& ignored_site : ignored_sites) { |
| 452 GURL origin("http://" + ignored_site); | |
| 453 std::unique_ptr<base::Value> value = map->GetWebsiteSetting( | |
|
dominickn
2017/02/01 22:22:04
What is this line doing? It doesn't appear to be u
dmurph
2017/02/02 23:53:29
You're right. Removed.
| |
| 454 origin, origin, CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO, "", | |
| 455 nullptr); | |
| 456 std::unique_ptr<base::DictionaryValue> dict = | |
| 457 base::DictionaryValue::From(map->GetWebsiteSetting( | |
| 458 origin, origin, CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO, "", | |
| 459 nullptr)); | |
| 400 | 460 |
| 401 int times_ignored = 0; | 461 if (!dict) |
| 402 if (dict) | 462 dict = base::MakeUnique<base::DictionaryValue>(); |
| 403 dict->GetInteger(kNumTimesIgnoredName, ×_ignored); | |
| 404 else | |
| 405 dict = base::MakeUnique<base::DictionaryValue>(); | |
| 406 dict->SetInteger(kNumTimesIgnoredName, ++times_ignored); | |
| 407 | 463 |
| 408 map->SetWebsiteSettingDefaultScope( | 464 IncrementTimesIgnoredAndSetDate(dict.get()); |
| 409 origin, origin, CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO, "", | 465 |
| 410 std::move(dict)); | 466 map->SetWebsiteSettingDefaultScope( |
| 467 origin, origin, CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO, "", | |
| 468 std::move(dict)); | |
| 469 } | |
| 470 } else { | |
| 471 // Record that the user did not interact with the dialog. | |
| 472 PrefService* service = profile->GetPrefs(); | |
| 473 DictionaryPrefUpdate update(service, prefs::kImportantSitesDialogHistory); | |
| 474 IncrementTimesIgnoredAndSetDate(update.Get()); | |
| 411 } | 475 } |
| 412 | 476 |
| 413 // We clear our blacklist for sites that the user chose. | 477 // We clear our blacklist for sites that the user chose. |
| 414 for (const std::string& ignored_site : blacklisted_sites) { | 478 for (const std::string& ignored_site : blacklisted_sites) { |
| 415 GURL origin("http://" + ignored_site); | 479 GURL origin("http://" + ignored_site); |
| 416 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); | 480 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); |
| 417 dict->SetInteger(kNumTimesIgnoredName, 0); | 481 dict->SetInteger(kNumTimesIgnoredName, 0); |
| 418 map->SetWebsiteSettingDefaultScope( | 482 map->SetWebsiteSettingDefaultScope( |
| 419 origin, origin, CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO, "", | 483 origin, origin, CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO, "", |
| 420 std::move(dict)); | 484 std::move(dict)); |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 434 const GURL& origin) { | 498 const GURL& origin) { |
| 435 SiteEngagementScore::SetParamValuesForTesting(); | 499 SiteEngagementScore::SetParamValuesForTesting(); |
| 436 // First get data from site engagement. | 500 // First get data from site engagement. |
| 437 SiteEngagementService* site_engagement_service = | 501 SiteEngagementService* site_engagement_service = |
| 438 SiteEngagementService::Get(profile); | 502 SiteEngagementService::Get(profile); |
| 439 site_engagement_service->ResetScoreForURL( | 503 site_engagement_service->ResetScoreForURL( |
| 440 origin, SiteEngagementScore::GetMediumEngagementBoundary()); | 504 origin, SiteEngagementScore::GetMediumEngagementBoundary()); |
| 441 DCHECK(site_engagement_service->IsEngagementAtLeast( | 505 DCHECK(site_engagement_service->IsEngagementAtLeast( |
| 442 origin, blink::mojom::EngagementLevel::MEDIUM)); | 506 origin, blink::mojom::EngagementLevel::MEDIUM)); |
| 443 } | 507 } |
| OLD | NEW |