| Index: chrome/browser/android/preferences/important_sites_util.cc
|
| diff --git a/chrome/browser/android/preferences/important_sites_util.cc b/chrome/browser/android/preferences/important_sites_util.cc
|
| deleted file mode 100644
|
| index 85103067b8dfdb2f1828cbd70a071ff36b7cafbc..0000000000000000000000000000000000000000
|
| --- a/chrome/browser/android/preferences/important_sites_util.cc
|
| +++ /dev/null
|
| @@ -1,440 +0,0 @@
|
| -// Copyright 2016 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "chrome/browser/android/preferences/important_sites_util.h"
|
| -
|
| -#include <algorithm>
|
| -#include <map>
|
| -#include <memory>
|
| -#include <set>
|
| -#include <utility>
|
| -
|
| -#include "base/containers/hash_tables.h"
|
| -#include "base/memory/ptr_util.h"
|
| -#include "base/metrics/histogram_macros.h"
|
| -#include "base/stl_util.h"
|
| -#include "base/time/time.h"
|
| -#include "base/values.h"
|
| -#include "chrome/browser/banners/app_banner_settings_helper.h"
|
| -#include "chrome/browser/bookmarks/bookmark_model_factory.h"
|
| -#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
|
| -#include "chrome/browser/engagement/site_engagement_score.h"
|
| -#include "chrome/browser/engagement/site_engagement_service.h"
|
| -#include "chrome/browser/profiles/profile.h"
|
| -#include "components/bookmarks/browser/bookmark_model.h"
|
| -#include "components/content_settings/core/browser/host_content_settings_map.h"
|
| -#include "components/content_settings/core/common/content_settings.h"
|
| -#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
|
| -#include "url/gurl.h"
|
| -
|
| -namespace {
|
| -using bookmarks::BookmarkModel;
|
| -using ImportantDomainInfo = ImportantSitesUtil::ImportantDomainInfo;
|
| -
|
| -static const char kNumTimesIgnoredName[] = "NumTimesIgnored";
|
| -static const int kTimesIgnoredForBlacklist = 3;
|
| -
|
| -// These are the maximum # of bookmarks we can use as signals. If the user has
|
| -// <= kMaxBookmarks, then we just use those bookmarks. Otherwise we filter all
|
| -// bookmarks on site engagement > 0, sort, and trim to kMaxBookmarks.
|
| -static const int kMaxBookmarks = 5;
|
| -
|
| -// Do not change the values here, as they are used for UMA histograms.
|
| -enum ImportantReason {
|
| - ENGAGEMENT = 0,
|
| - DURABLE = 1,
|
| - BOOKMARKS = 2,
|
| - HOME_SCREEN = 3,
|
| - NOTIFICATIONS = 4,
|
| - REASON_BOUNDARY
|
| -};
|
| -
|
| -// We need this to be a macro, as the histogram macros cache their pointers
|
| -// after the first call, so when we change the uma name we check fail if we're
|
| -// just a method.
|
| -#define RECORD_UMA_FOR_IMPORTANT_REASON(uma_name, uma_count_name, \
|
| - reason_bitfield) \
|
| - do { \
|
| - int count = 0; \
|
| - int32_t bitfield = (reason_bitfield); \
|
| - for (int i = 0; i < ImportantReason::REASON_BOUNDARY; i++) { \
|
| - if ((bitfield >> i) & 1) { \
|
| - count++; \
|
| - UMA_HISTOGRAM_ENUMERATION((uma_name), i, \
|
| - ImportantReason::REASON_BOUNDARY); \
|
| - } \
|
| - } \
|
| - UMA_HISTOGRAM_ENUMERATION((uma_count_name), count, \
|
| - ImportantReason::REASON_BOUNDARY); \
|
| - } while (0)
|
| -
|
| -// Do not change the values here, as they are used for UMA histograms and
|
| -// testing in important_sites_util_unittest.
|
| -enum CrossedReason {
|
| - CROSSED_DURABLE = 0,
|
| - CROSSED_NOTIFICATIONS = 1,
|
| - CROSSED_ENGAGEMENT = 2,
|
| - CROSSED_NOTIFICATIONS_AND_ENGAGEMENT = 3,
|
| - CROSSED_DURABLE_AND_ENGAGEMENT = 4,
|
| - CROSSED_NOTIFICATIONS_AND_DURABLE = 5,
|
| - CROSSED_NOTIFICATIONS_AND_DURABLE_AND_ENGAGEMENT = 6,
|
| - CROSSED_REASON_UNKNOWN = 7,
|
| - CROSSED_REASON_BOUNDARY
|
| -};
|
| -
|
| -CrossedReason GetCrossedReasonFromBitfield(int32_t reason_bitfield) {
|
| - bool durable = reason_bitfield & (1 << ImportantReason::DURABLE);
|
| - bool notifications = reason_bitfield & (1 << ImportantReason::NOTIFICATIONS);
|
| - bool engagement = reason_bitfield & (1 << ImportantReason::ENGAGEMENT);
|
| - if (durable && notifications && engagement)
|
| - return CROSSED_NOTIFICATIONS_AND_DURABLE_AND_ENGAGEMENT;
|
| - else if (notifications && durable)
|
| - return CROSSED_NOTIFICATIONS_AND_DURABLE;
|
| - else if (notifications && engagement)
|
| - return CROSSED_NOTIFICATIONS_AND_ENGAGEMENT;
|
| - else if (durable && engagement)
|
| - return CROSSED_DURABLE_AND_ENGAGEMENT;
|
| - else if (notifications)
|
| - return CROSSED_NOTIFICATIONS;
|
| - else if (durable)
|
| - return CROSSED_DURABLE;
|
| - else if (engagement)
|
| - return CROSSED_ENGAGEMENT;
|
| - return CROSSED_REASON_UNKNOWN;
|
| -}
|
| -
|
| -std::string GetRegisterableDomainOrIP(const GURL& url) {
|
| - std::string registerable_domain =
|
| - net::registry_controlled_domains::GetDomainAndRegistry(
|
| - url, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
|
| - if (registerable_domain.empty() && url.HostIsIPAddress())
|
| - registerable_domain = url.host();
|
| - return registerable_domain;
|
| -}
|
| -
|
| -void MaybePopulateImportantInfoForReason(
|
| - const GURL& origin,
|
| - std::set<GURL>* visited_origins,
|
| - ImportantReason reason,
|
| - base::hash_map<std::string, ImportantDomainInfo>* output) {
|
| - if (!origin.is_valid() || !visited_origins->insert(origin).second)
|
| - return;
|
| - std::string registerable_domain = GetRegisterableDomainOrIP(origin);
|
| - ImportantDomainInfo& info = (*output)[registerable_domain];
|
| - info.reason_bitfield |= 1 << reason;
|
| - if (info.example_origin.is_empty()) {
|
| - info.registerable_domain = registerable_domain;
|
| - info.example_origin = origin;
|
| - }
|
| -}
|
| -
|
| -// Returns the score associated with the given reason. The order of
|
| -// ImportantReason does not need to correspond to the score order. The higher
|
| -// the score, the more important the reason is.
|
| -int GetScoreForReason(ImportantReason reason) {
|
| - switch (reason) {
|
| - case ImportantReason::ENGAGEMENT:
|
| - return 1 << 0;
|
| - case ImportantReason::DURABLE:
|
| - return 1 << 1;
|
| - case ImportantReason::BOOKMARKS:
|
| - return 1 << 2;
|
| - case ImportantReason::HOME_SCREEN:
|
| - return 1 << 3;
|
| - case ImportantReason::NOTIFICATIONS:
|
| - return 1 << 4;
|
| - case ImportantReason::REASON_BOUNDARY:
|
| - return 0;
|
| - }
|
| - return 0;
|
| -}
|
| -
|
| -int GetScoreForReasonsBitfield(int32_t reason_bitfield) {
|
| - int score = 0;
|
| - for (int i = 0; i < ImportantReason::REASON_BOUNDARY; i++) {
|
| - if ((reason_bitfield >> i) & 1) {
|
| - score += GetScoreForReason(static_cast<ImportantReason>(i));
|
| - }
|
| - }
|
| - return score;
|
| -}
|
| -
|
| -// Returns if |a| has a higher score than |b|, so that when we sort the higher
|
| -// score is first.
|
| -bool CompareDescendingImportantInfo(
|
| - const std::pair<std::string, ImportantDomainInfo>& a,
|
| - const std::pair<std::string, ImportantDomainInfo>& b) {
|
| - int score_a = GetScoreForReasonsBitfield(a.second.reason_bitfield);
|
| - int score_b = GetScoreForReasonsBitfield(b.second.reason_bitfield);
|
| - int bitfield_diff = score_a - score_b;
|
| - if (bitfield_diff != 0)
|
| - return bitfield_diff > 0;
|
| - return a.second.engagement_score > b.second.engagement_score;
|
| -}
|
| -
|
| -base::hash_set<std::string> GetBlacklistedImportantDomains(Profile* profile) {
|
| - ContentSettingsForOneType content_settings_list;
|
| - HostContentSettingsMap* map =
|
| - HostContentSettingsMapFactory::GetForProfile(profile);
|
| - map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO,
|
| - content_settings::ResourceIdentifier(),
|
| - &content_settings_list);
|
| - base::hash_set<std::string> ignoring_domains;
|
| - for (const ContentSettingPatternSource& site : content_settings_list) {
|
| - GURL origin(site.primary_pattern.ToString());
|
| - if (!origin.is_valid() ||
|
| - base::ContainsKey(ignoring_domains, origin.host())) {
|
| - continue;
|
| - }
|
| -
|
| - std::unique_ptr<base::DictionaryValue> dict =
|
| - base::DictionaryValue::From(map->GetWebsiteSetting(
|
| - origin, origin, CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO, "",
|
| - nullptr));
|
| -
|
| - if (!dict)
|
| - continue;
|
| -
|
| - int times_ignored = 0;
|
| - if (!dict->GetInteger(kNumTimesIgnoredName, ×_ignored) ||
|
| - times_ignored < kTimesIgnoredForBlacklist) {
|
| - continue;
|
| - }
|
| -
|
| - ignoring_domains.insert(origin.host());
|
| - }
|
| - return ignoring_domains;
|
| -}
|
| -
|
| -void PopulateInfoMapWithSiteEngagement(
|
| - Profile* profile,
|
| - SiteEngagementService::EngagementLevel minimum_engagement,
|
| - std::map<GURL, double>* engagement_map,
|
| - base::hash_map<std::string, ImportantDomainInfo>* output) {
|
| - SiteEngagementService* service = SiteEngagementService::Get(profile);
|
| - *engagement_map = service->GetScoreMap();
|
| - // We can have multiple origins for a single domain, so we record the one
|
| - // with the highest engagement score.
|
| - for (const auto& url_engagement_pair : *engagement_map) {
|
| - if (!service->IsEngagementAtLeast(url_engagement_pair.first,
|
| - minimum_engagement)) {
|
| - continue;
|
| - }
|
| - std::string registerable_domain =
|
| - GetRegisterableDomainOrIP(url_engagement_pair.first);
|
| - ImportantDomainInfo& info = (*output)[registerable_domain];
|
| - if (url_engagement_pair.second > info.engagement_score) {
|
| - info.registerable_domain = registerable_domain;
|
| - info.engagement_score = url_engagement_pair.second;
|
| - info.example_origin = url_engagement_pair.first;
|
| - info.reason_bitfield |= 1 << ImportantReason::ENGAGEMENT;
|
| - }
|
| - }
|
| -}
|
| -
|
| -void PopulateInfoMapWithContentTypeAllowed(
|
| - Profile* profile,
|
| - ContentSettingsType content_type,
|
| - ImportantReason reason,
|
| - base::hash_map<std::string, ImportantDomainInfo>* output) {
|
| - // Grab our content settings list.
|
| - ContentSettingsForOneType content_settings_list;
|
| - HostContentSettingsMapFactory::GetForProfile(profile)->GetSettingsForOneType(
|
| - content_type, content_settings::ResourceIdentifier(),
|
| - &content_settings_list);
|
| - // Extract a set of urls, using the primary pattern. We don't handle
|
| - // wildcard patterns.
|
| - std::set<GURL> content_origins;
|
| - for (const ContentSettingPatternSource& site : content_settings_list) {
|
| - if (site.setting != CONTENT_SETTING_ALLOW)
|
| - continue;
|
| - MaybePopulateImportantInfoForReason(GURL(site.primary_pattern.ToString()),
|
| - &content_origins, reason, output);
|
| - }
|
| -}
|
| -
|
| -void PopulateInfoMapWithBookmarks(
|
| - Profile* profile,
|
| - const std::map<GURL, double>& engagement_map,
|
| - base::hash_map<std::string, ImportantDomainInfo>* output) {
|
| - SiteEngagementService* service = SiteEngagementService::Get(profile);
|
| - BookmarkModel* model =
|
| - BookmarkModelFactory::GetForBrowserContextIfExists(profile);
|
| - if (!model)
|
| - return;
|
| - std::vector<BookmarkModel::URLAndTitle> untrimmed_bookmarks;
|
| - model->GetBookmarks(&untrimmed_bookmarks);
|
| -
|
| - // Process the bookmarks and optionally trim them if we have too many.
|
| - std::vector<BookmarkModel::URLAndTitle> result_bookmarks;
|
| - if (untrimmed_bookmarks.size() > kMaxBookmarks) {
|
| - std::copy_if(untrimmed_bookmarks.begin(), untrimmed_bookmarks.end(),
|
| - std::back_inserter(result_bookmarks),
|
| - [service](const BookmarkModel::URLAndTitle& entry) {
|
| - return service->IsEngagementAtLeast(
|
| - entry.url.GetOrigin(),
|
| - SiteEngagementService::ENGAGEMENT_LEVEL_LOW);
|
| - });
|
| - std::sort(result_bookmarks.begin(), result_bookmarks.end(),
|
| - [&engagement_map](const BookmarkModel::URLAndTitle& a,
|
| - const BookmarkModel::URLAndTitle& b) {
|
| - double a_score = engagement_map.at(a.url.GetOrigin());
|
| - double b_score = engagement_map.at(b.url.GetOrigin());
|
| - return a_score > b_score;
|
| - });
|
| - if (result_bookmarks.size() > kMaxBookmarks)
|
| - result_bookmarks.resize(kMaxBookmarks);
|
| - } else {
|
| - result_bookmarks = std::move(untrimmed_bookmarks);
|
| - }
|
| -
|
| - std::set<GURL> content_origins;
|
| - for (const BookmarkModel::URLAndTitle& bookmark : result_bookmarks) {
|
| - MaybePopulateImportantInfoForReason(bookmark.url, &content_origins,
|
| - ImportantReason::BOOKMARKS, output);
|
| - }
|
| -}
|
| -
|
| -void PopulateInfoMapWithHomeScreen(
|
| - Profile* profile,
|
| - base::hash_map<std::string, ImportantDomainInfo>* output) {
|
| - ContentSettingsForOneType content_settings_list;
|
| - HostContentSettingsMapFactory::GetForProfile(profile)->GetSettingsForOneType(
|
| - CONTENT_SETTINGS_TYPE_APP_BANNER, content_settings::ResourceIdentifier(),
|
| - &content_settings_list);
|
| - // Extract a set of urls, using the primary pattern. We don't handle
|
| - // wildcard patterns.
|
| - std::set<GURL> content_origins;
|
| - base::Time now = base::Time::Now();
|
| - for (const ContentSettingPatternSource& site : content_settings_list) {
|
| - GURL origin(site.primary_pattern.ToString());
|
| - if (!AppBannerSettingsHelper::WasLaunchedRecently(profile, origin, now))
|
| - continue;
|
| - MaybePopulateImportantInfoForReason(origin, &content_origins,
|
| - ImportantReason::HOME_SCREEN, output);
|
| - }
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -std::vector<ImportantDomainInfo>
|
| -ImportantSitesUtil::GetImportantRegisterableDomains(Profile* profile,
|
| - size_t max_results) {
|
| - base::hash_map<std::string, ImportantDomainInfo> important_info;
|
| - std::map<GURL, double> engagement_map;
|
| -
|
| - PopulateInfoMapWithSiteEngagement(
|
| - profile, SiteEngagementService::ENGAGEMENT_LEVEL_MEDIUM, &engagement_map,
|
| - &important_info);
|
| -
|
| - PopulateInfoMapWithContentTypeAllowed(
|
| - profile, CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
|
| - ImportantReason::NOTIFICATIONS, &important_info);
|
| -
|
| - PopulateInfoMapWithContentTypeAllowed(
|
| - profile, CONTENT_SETTINGS_TYPE_DURABLE_STORAGE, ImportantReason::DURABLE,
|
| - &important_info);
|
| -
|
| - PopulateInfoMapWithBookmarks(profile, engagement_map, &important_info);
|
| -
|
| - PopulateInfoMapWithHomeScreen(profile, &important_info);
|
| -
|
| - base::hash_set<std::string> blacklisted_domains =
|
| - GetBlacklistedImportantDomains(profile);
|
| -
|
| - std::vector<std::pair<std::string, ImportantDomainInfo>> items(
|
| - important_info.begin(), important_info.end());
|
| - std::sort(items.begin(), items.end(), &CompareDescendingImportantInfo);
|
| -
|
| - std::vector<ImportantDomainInfo> final_list;
|
| - for (std::pair<std::string, ImportantDomainInfo>& domain_info : items) {
|
| - if (final_list.size() >= max_results)
|
| - return final_list;
|
| - if (blacklisted_domains.find(domain_info.first) !=
|
| - blacklisted_domains.end()) {
|
| - continue;
|
| - }
|
| - final_list.push_back(domain_info.second);
|
| - RECORD_UMA_FOR_IMPORTANT_REASON(
|
| - "Storage.ImportantSites.GeneratedReason",
|
| - "Storage.ImportantSites.GeneratedReasonCount",
|
| - domain_info.second.reason_bitfield);
|
| - }
|
| -
|
| - return final_list;
|
| -}
|
| -
|
| -void ImportantSitesUtil::RecordBlacklistedAndIgnoredImportantSites(
|
| - Profile* profile,
|
| - const std::vector<std::string>& blacklisted_sites,
|
| - const std::vector<int32_t>& blacklisted_sites_reason_bitfield,
|
| - const std::vector<std::string>& ignored_sites,
|
| - const std::vector<int32_t>& ignored_sites_reason_bitfield) {
|
| - // First, record the metrics for blacklisted and ignored sites.
|
| - for (int32_t reason_bitfield : blacklisted_sites_reason_bitfield) {
|
| - RECORD_UMA_FOR_IMPORTANT_REASON(
|
| - "Storage.ImportantSites.CBDChosenReason",
|
| - "Storage.ImportantSites.CBDChosenReasonCount", reason_bitfield);
|
| - }
|
| - for (int32_t reason_bitfield : ignored_sites_reason_bitfield) {
|
| - RECORD_UMA_FOR_IMPORTANT_REASON(
|
| - "Storage.ImportantSites.CBDIgnoredReason",
|
| - "Storage.ImportantSites.CBDIgnoredReasonCount", reason_bitfield);
|
| - }
|
| -
|
| - // We use the ignored sites to update our important sites blacklist.
|
| - HostContentSettingsMap* map =
|
| - HostContentSettingsMapFactory::GetForProfile(profile);
|
| - for (const std::string& ignored_site : ignored_sites) {
|
| - GURL origin("http://" + ignored_site);
|
| - std::unique_ptr<base::Value> value = map->GetWebsiteSetting(
|
| - origin, origin, CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO, "", nullptr);
|
| -
|
| - std::unique_ptr<base::DictionaryValue> dict =
|
| - base::DictionaryValue::From(map->GetWebsiteSetting(
|
| - origin, origin, CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO, "",
|
| - nullptr));
|
| -
|
| - int times_ignored = 0;
|
| - if (dict)
|
| - dict->GetInteger(kNumTimesIgnoredName, ×_ignored);
|
| - else
|
| - dict = base::MakeUnique<base::DictionaryValue>();
|
| - dict->SetInteger(kNumTimesIgnoredName, ++times_ignored);
|
| -
|
| - map->SetWebsiteSettingDefaultScope(
|
| - origin, origin, CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO, "",
|
| - std::move(dict));
|
| - }
|
| -
|
| - // We clear our blacklist for sites that the user chose.
|
| - for (const std::string& ignored_site : blacklisted_sites) {
|
| - GURL origin("http://" + ignored_site);
|
| - std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
|
| - dict->SetInteger(kNumTimesIgnoredName, 0);
|
| - map->SetWebsiteSettingDefaultScope(
|
| - origin, origin, CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO, "",
|
| - std::move(dict));
|
| - }
|
| -
|
| - // Finally, record our old crossed-stats.
|
| - // Note: we don't plan on adding new metrics here, this is just for the finch
|
| - // experiment to give us initial data on what signals actually mattered.
|
| - for (int32_t reason_bitfield : blacklisted_sites_reason_bitfield) {
|
| - UMA_HISTOGRAM_ENUMERATION("Storage.BlacklistedImportantSites.Reason",
|
| - GetCrossedReasonFromBitfield(reason_bitfield),
|
| - CROSSED_REASON_BOUNDARY);
|
| - }
|
| -}
|
| -
|
| -void ImportantSitesUtil::MarkOriginAsImportantForTesting(Profile* profile,
|
| - const GURL& origin) {
|
| - // First get data from site engagement.
|
| - SiteEngagementService* site_engagement_service =
|
| - SiteEngagementService::Get(profile);
|
| - site_engagement_service->ResetScoreForURL(
|
| - origin, SiteEngagementScore::GetMediumEngagementBoundary());
|
| - DCHECK(site_engagement_service->IsEngagementAtLeast(
|
| - origin, SiteEngagementService::ENGAGEMENT_LEVEL_MEDIUM));
|
| -}
|
|
|