| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/banners/app_banner_settings_helper.h" | 5 #include "chrome/browser/banners/app_banner_settings_helper.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <string> | 10 #include <string> |
| 11 #include <utility> | 11 #include <utility> |
| 12 | 12 |
| 13 #include "base/command_line.h" | 13 #include "base/command_line.h" |
| 14 #include "base/memory/ptr_util.h" | 14 #include "base/memory/ptr_util.h" |
| 15 #include "base/metrics/field_trial.h" | 15 #include "base/metrics/field_trial.h" |
| 16 #include "base/strings/string_number_conversions.h" | 16 #include "base/strings/string_number_conversions.h" |
| 17 #include "base/strings/string_util.h" | 17 #include "base/strings/string_util.h" |
| 18 #include "chrome/browser/banners/app_banner_data_fetcher.h" | 18 #include "chrome/browser/banners/app_banner_data_fetcher.h" |
| 19 #include "chrome/browser/banners/app_banner_metrics.h" | 19 #include "chrome/browser/banners/app_banner_metrics.h" |
| 20 #include "chrome/browser/browser_process.h" | 20 #include "chrome/browser/browser_process.h" |
| 21 #include "chrome/browser/content_settings/host_content_settings_map_factory.h" | 21 #include "chrome/browser/content_settings/host_content_settings_map_factory.h" |
| 22 #include "chrome/browser/engagement/site_engagement_service.h" | |
| 23 #include "chrome/browser/profiles/profile.h" | 22 #include "chrome/browser/profiles/profile.h" |
| 24 #include "chrome/common/chrome_switches.h" | 23 #include "chrome/common/chrome_switches.h" |
| 25 #include "components/content_settings/core/browser/host_content_settings_map.h" | 24 #include "components/content_settings/core/browser/host_content_settings_map.h" |
| 26 #include "components/content_settings/core/common/content_settings_pattern.h" | 25 #include "components/content_settings/core/common/content_settings_pattern.h" |
| 27 #include "components/rappor/rappor_utils.h" | 26 #include "components/rappor/rappor_utils.h" |
| 28 #include "components/variations/variations_associated_data.h" | 27 #include "components/variations/variations_associated_data.h" |
| 29 #include "content/public/browser/web_contents.h" | 28 #include "content/public/browser/web_contents.h" |
| 30 #include "net/base/escape.h" | 29 #include "net/base/escape.h" |
| 31 #include "url/gurl.h" | 30 #include "url/gurl.h" |
| 32 | 31 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 66 // Keys to use when storing BannerEvent structs. | 65 // Keys to use when storing BannerEvent structs. |
| 67 const char kBannerTimeKey[] = "time"; | 66 const char kBannerTimeKey[] = "time"; |
| 68 const char kBannerEngagementKey[] = "engagement"; | 67 const char kBannerEngagementKey[] = "engagement"; |
| 69 | 68 |
| 70 // Keys to use when querying the variations params. | 69 // Keys to use when querying the variations params. |
| 71 const char kBannerParamsKey[] = "AppBannerTriggering"; | 70 const char kBannerParamsKey[] = "AppBannerTriggering"; |
| 72 const char kBannerParamsDirectKey[] = "direct"; | 71 const char kBannerParamsDirectKey[] = "direct"; |
| 73 const char kBannerParamsIndirectKey[] = "indirect"; | 72 const char kBannerParamsIndirectKey[] = "indirect"; |
| 74 const char kBannerParamsTotalKey[] = "total"; | 73 const char kBannerParamsTotalKey[] = "total"; |
| 75 const char kBannerParamsMinutesKey[] = "minutes"; | 74 const char kBannerParamsMinutesKey[] = "minutes"; |
| 76 const char kBannerSiteEngagementParamsKey[] = "app_banner_triggering"; | 75 const char kBannerSiteEngagementParamsKey[] = "use_site_engagement"; |
| 77 const char kBannerSiteEngagementParamsTotalKey[] = | |
| 78 "app_banner_triggering_total"; | |
| 79 | 76 |
| 80 // Engagement weight assigned to direct and indirect navigations. | 77 // Engagement weight assigned to direct and indirect navigations. |
| 81 // By default, a direct navigation is a page visit via ui::PAGE_TRANSITION_TYPED | 78 // By default, a direct navigation is a page visit via ui::PAGE_TRANSITION_TYPED |
| 82 // or ui::PAGE_TRANSITION_GENERATED. | 79 // or ui::PAGE_TRANSITION_GENERATED. |
| 83 double gDirectNavigationEngagement = kDefaultDirectNavigationEngagement; | 80 double gDirectNavigationEngagement = kDefaultDirectNavigationEngagement; |
| 84 double gIndirectNavigationEnagagement = kDefaultIndirectNavigationEngagement; | 81 double gIndirectNavigationEnagagement = kDefaultIndirectNavigationEngagement; |
| 85 | 82 |
| 86 // Number of minutes between visits that will trigger a could show banner event. | 83 // Number of minutes between visits that will trigger a could show banner event. |
| 87 // Defaults to the number of minutes in a day. | 84 // Defaults to the number of minutes in a day. |
| 88 unsigned int gMinimumMinutesBetweenVisits = kNumberOfMinutesInADay; | 85 unsigned int gMinimumMinutesBetweenVisits = kNumberOfMinutesInADay; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 129 return gDirectNavigationEngagement; | 126 return gDirectNavigationEngagement; |
| 130 } else { | 127 } else { |
| 131 return gIndirectNavigationEnagagement; | 128 return gIndirectNavigationEnagagement; |
| 132 } | 129 } |
| 133 } | 130 } |
| 134 | 131 |
| 135 // Queries variations for the maximum site engagement score required to trigger | 132 // Queries variations for the maximum site engagement score required to trigger |
| 136 // the banner showing. | 133 // the banner showing. |
| 137 void UpdateSiteEngagementToTrigger() { | 134 void UpdateSiteEngagementToTrigger() { |
| 138 std::string total_param = variations::GetVariationParamValue( | 135 std::string total_param = variations::GetVariationParamValue( |
| 139 SiteEngagementService::kEngagementParams, | 136 kBannerParamsKey, kBannerParamsTotalKey); |
| 140 kBannerSiteEngagementParamsTotalKey); | |
| 141 | 137 |
| 142 if (!total_param.empty()) { | 138 if (!total_param.empty()) { |
| 143 double total_engagement = -1; | 139 double total_engagement = -1; |
| 144 | 140 |
| 145 if (base::StringToDouble(total_param, &total_engagement) && | 141 if (base::StringToDouble(total_param, &total_engagement) && |
| 146 total_engagement > 0) { | 142 total_engagement > 0) { |
| 147 AppBannerSettingsHelper::SetTotalEngagementToTrigger(total_engagement); | 143 AppBannerSettingsHelper::SetTotalEngagementToTrigger(total_engagement); |
| 148 } | 144 } |
| 149 } | 145 } |
| 150 } | 146 } |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 186 void UpdateMinutesBetweenVisits() { | 182 void UpdateMinutesBetweenVisits() { |
| 187 std::string param = variations::GetVariationParamValue( | 183 std::string param = variations::GetVariationParamValue( |
| 188 kBannerParamsKey, kBannerParamsMinutesKey); | 184 kBannerParamsKey, kBannerParamsMinutesKey); |
| 189 if (!param.empty()) { | 185 if (!param.empty()) { |
| 190 int minimum_minutes = 0; | 186 int minimum_minutes = 0; |
| 191 if (base::StringToInt(param, &minimum_minutes)) | 187 if (base::StringToInt(param, &minimum_minutes)) |
| 192 AppBannerSettingsHelper::SetMinimumMinutesBetweenVisits(minimum_minutes); | 188 AppBannerSettingsHelper::SetMinimumMinutesBetweenVisits(minimum_minutes); |
| 193 } | 189 } |
| 194 } | 190 } |
| 195 | 191 |
| 196 // Returns the site engagement karma score for the given origin URL under the | |
| 197 // current profile. | |
| 198 double GetSiteEngagementScoreForOrigin( | |
| 199 content::WebContents* web_contents, | |
| 200 const GURL& origin_url) { | |
| 201 SiteEngagementService* service = SiteEngagementService::Get( | |
| 202 Profile::FromBrowserContext(web_contents->GetBrowserContext())); | |
| 203 return service ? service->GetScore(origin_url) : 0; | |
| 204 } | |
| 205 | |
| 206 } // namespace | 192 } // namespace |
| 207 | 193 |
| 208 void AppBannerSettingsHelper::ClearHistoryForURLs( | 194 void AppBannerSettingsHelper::ClearHistoryForURLs( |
| 209 Profile* profile, | 195 Profile* profile, |
| 210 const std::set<GURL>& origin_urls) { | 196 const std::set<GURL>& origin_urls) { |
| 211 HostContentSettingsMap* settings = | 197 HostContentSettingsMap* settings = |
| 212 HostContentSettingsMapFactory::GetForProfile(profile); | 198 HostContentSettingsMapFactory::GetForProfile(profile); |
| 213 for (const GURL& origin_url : origin_urls) { | 199 for (const GURL& origin_url : origin_urls) { |
| 214 settings->SetWebsiteSettingDefaultScope(origin_url, GURL(), | 200 settings->SetWebsiteSettingDefaultScope(origin_url, GURL(), |
| 215 CONTENT_SETTINGS_TYPE_APP_BANNER, | 201 CONTENT_SETTINGS_TYPE_APP_BANNER, |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 421 | 407 |
| 422 base::Time shown_time = | 408 base::Time shown_time = |
| 423 GetSingleBannerEvent(web_contents, origin_url, package_name_or_start_url, | 409 GetSingleBannerEvent(web_contents, origin_url, package_name_or_start_url, |
| 424 APP_BANNER_EVENT_DID_SHOW); | 410 APP_BANNER_EVENT_DID_SHOW); |
| 425 if (time - shown_time < | 411 if (time - shown_time < |
| 426 base::TimeDelta::FromDays(kMinimumDaysBetweenBannerShows)) { | 412 base::TimeDelta::FromDays(kMinimumDaysBetweenBannerShows)) { |
| 427 banners::TrackDisplayEvent(banners::DISPLAY_EVENT_IGNORED_PREVIOUSLY); | 413 banners::TrackDisplayEvent(banners::DISPLAY_EVENT_IGNORED_PREVIOUSLY); |
| 428 return false; | 414 return false; |
| 429 } | 415 } |
| 430 | 416 |
| 417 // If we have gotten this far and want to use site engagement, the banner flow |
| 418 // was triggered by the site engagement service informing the banner manager |
| 419 // that sufficient engagement has been accumulated. Hence there is no need to |
| 420 // check the total amount of engagement. |
| 421 // TODO(dominickn): just return true here and remove all of the following code |
| 422 // in this method when app banners have fully migrated to using site |
| 423 // engagement as a trigger condition. See crbug.com/616322. |
| 424 if (ShouldUseSiteEngagementScore()) |
| 425 return true; |
| 426 |
| 431 double total_engagement = 0; | 427 double total_engagement = 0; |
| 432 if (ShouldUseSiteEngagementScore()) { | 428 std::vector<BannerEvent> could_show_events = GetCouldShowBannerEvents( |
| 433 total_engagement = | 429 web_contents, origin_url, package_name_or_start_url); |
| 434 GetSiteEngagementScoreForOrigin(web_contents, origin_url); | |
| 435 } else { | |
| 436 std::vector<BannerEvent> could_show_events = GetCouldShowBannerEvents( | |
| 437 web_contents, origin_url, package_name_or_start_url); | |
| 438 | 430 |
| 439 for (const auto& event : could_show_events) | 431 for (const auto& event : could_show_events) |
| 440 total_engagement += event.engagement; | 432 total_engagement += event.engagement; |
| 441 } | |
| 442 | 433 |
| 443 if (total_engagement < gTotalEngagementToTrigger) { | 434 if (!HasSufficientEngagement(total_engagement)) { |
| 444 banners::TrackDisplayEvent(banners::DISPLAY_EVENT_NOT_VISITED_ENOUGH); | 435 banners::TrackDisplayEvent(banners::DISPLAY_EVENT_NOT_VISITED_ENOUGH); |
| 445 return false; | 436 return false; |
| 446 } | 437 } |
| 447 | 438 |
| 448 return true; | 439 return true; |
| 449 } | 440 } |
| 450 | 441 |
| 451 std::vector<AppBannerSettingsHelper::BannerEvent> | 442 std::vector<AppBannerSettingsHelper::BannerEvent> |
| 452 AppBannerSettingsHelper::GetCouldShowBannerEvents( | 443 AppBannerSettingsHelper::GetCouldShowBannerEvents( |
| 453 content::WebContents* web_contents, | 444 content::WebContents* web_contents, |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 517 return base::Time(); | 508 return base::Time(); |
| 518 | 509 |
| 519 std::string event_key(kBannerEventKeys[event]); | 510 std::string event_key(kBannerEventKeys[event]); |
| 520 double internal_time; | 511 double internal_time; |
| 521 if (!app_dict->GetDouble(event_key, &internal_time)) | 512 if (!app_dict->GetDouble(event_key, &internal_time)) |
| 522 return base::Time(); | 513 return base::Time(); |
| 523 | 514 |
| 524 return base::Time::FromInternalValue(internal_time); | 515 return base::Time::FromInternalValue(internal_time); |
| 525 } | 516 } |
| 526 | 517 |
| 518 bool AppBannerSettingsHelper::HasSufficientEngagement(double total_engagement) { |
| 519 return (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 520 switches::kBypassAppBannerEngagementChecks)) || |
| 521 (total_engagement >= gTotalEngagementToTrigger); |
| 522 } |
| 523 |
| 527 void AppBannerSettingsHelper::RecordMinutesFromFirstVisitToShow( | 524 void AppBannerSettingsHelper::RecordMinutesFromFirstVisitToShow( |
| 528 content::WebContents* web_contents, | 525 content::WebContents* web_contents, |
| 529 const GURL& origin_url, | 526 const GURL& origin_url, |
| 530 const std::string& package_name_or_start_url, | 527 const std::string& package_name_or_start_url, |
| 531 base::Time time) { | 528 base::Time time) { |
| 532 std::vector<BannerEvent> could_show_events = GetCouldShowBannerEvents( | 529 std::vector<BannerEvent> could_show_events = GetCouldShowBannerEvents( |
| 533 web_contents, origin_url, package_name_or_start_url); | 530 web_contents, origin_url, package_name_or_start_url); |
| 534 | 531 |
| 535 int minutes = 0; | 532 int minutes = 0; |
| 536 if (could_show_events.size()) | 533 if (could_show_events.size()) |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 598 UpdateMinutesBetweenVisits(); | 595 UpdateMinutesBetweenVisits(); |
| 599 } | 596 } |
| 600 } | 597 } |
| 601 | 598 |
| 602 bool AppBannerSettingsHelper::ShouldUseSiteEngagementScore() { | 599 bool AppBannerSettingsHelper::ShouldUseSiteEngagementScore() { |
| 603 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | 600 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 604 switches::kEnableSiteEngagementAppBanner)) { | 601 switches::kEnableSiteEngagementAppBanner)) { |
| 605 return true; | 602 return true; |
| 606 } | 603 } |
| 607 | 604 |
| 608 // This experiment is controlled under the same key as the broader site | 605 // Assume any value which is not "0" or "false" indicates that we should use |
| 609 // engagement experiment rather than the banner experiment. This avoids cross | 606 // site engagement. |
| 610 // pollution with other site engagement experiments. However, this experiment | |
| 611 // must only be active when there is one singular group under the banner | |
| 612 // experiment, otherwise the banner and site engagement banner experiments | |
| 613 // will conflict. | |
| 614 // | |
| 615 // Making the experiment active when a variations key is present allows us | |
| 616 // to have experiments which enable multiple features under site engagement. | |
| 617 std::string param = variations::GetVariationParamValue( | 607 std::string param = variations::GetVariationParamValue( |
| 618 SiteEngagementService::kEngagementParams, kBannerSiteEngagementParamsKey); | 608 kBannerParamsKey, kBannerSiteEngagementParamsKey); |
| 619 return !param.empty(); | 609 |
| 610 return (!param.empty() && param != "0" && param != "false"); |
| 620 } | 611 } |
| OLD | NEW |