| 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> |
| (...skipping 21 matching lines...) Expand all Loading... |
| 32 | 32 |
| 33 namespace { | 33 namespace { |
| 34 | 34 |
| 35 // Max number of apps (including ServiceWorker based web apps) that a particular | 35 // Max number of apps (including ServiceWorker based web apps) that a particular |
| 36 // site may show a banner for. | 36 // site may show a banner for. |
| 37 const size_t kMaxAppsPerSite = 3; | 37 const size_t kMaxAppsPerSite = 3; |
| 38 | 38 |
| 39 // Oldest could show banner event we care about, in days. | 39 // Oldest could show banner event we care about, in days. |
| 40 const unsigned int kOldestCouldShowBannerEventInDays = 14; | 40 const unsigned int kOldestCouldShowBannerEventInDays = 14; |
| 41 | 41 |
| 42 // Number of days that showing the banner will prevent it being seen again for. | 42 // Default number of days that dismissing or ignoring the banner will prevent it |
| 43 // being seen again for. |
| 44 const unsigned int kMinimumBannerBlockedToBannerShown = 90; |
| 43 const unsigned int kMinimumDaysBetweenBannerShows = 14; | 45 const unsigned int kMinimumDaysBetweenBannerShows = 14; |
| 44 | 46 |
| 45 const unsigned int kNumberOfMinutesInADay = 1440; | 47 const unsigned int kNumberOfMinutesInADay = 1440; |
| 46 | 48 |
| 47 // Number of days that the banner being blocked will prevent it being seen again | |
| 48 // for. | |
| 49 const unsigned int kMinimumBannerBlockedToBannerShown = 90; | |
| 50 | |
| 51 // Default scores assigned to direct and indirect navigations respectively. | 49 // Default scores assigned to direct and indirect navigations respectively. |
| 52 const unsigned int kDefaultDirectNavigationEngagement = 1; | 50 const unsigned int kDefaultDirectNavigationEngagement = 1; |
| 53 const unsigned int kDefaultIndirectNavigationEngagement = 1; | 51 const unsigned int kDefaultIndirectNavigationEngagement = 1; |
| 54 | 52 |
| 55 // Default number of navigations required to trigger the banner. | 53 // Default number of navigations required to trigger the banner. |
| 56 const unsigned int kDefaultTotalEngagementToTrigger = 2; | 54 const unsigned int kDefaultTotalEngagementToTrigger = 2; |
| 57 | 55 |
| 58 // The number of days in the past that a site should be launched from homescreen | 56 // The number of days in the past that a site should be launched from homescreen |
| 59 // to be considered recent. | 57 // to be considered recent. |
| 60 // TODO(dominickn): work out how to unify this with | 58 // TODO(dominickn): work out how to unify this with |
| (...skipping 12 matching lines...) Expand all Loading... |
| 73 const char kBannerTimeKey[] = "time"; | 71 const char kBannerTimeKey[] = "time"; |
| 74 const char kBannerEngagementKey[] = "engagement"; | 72 const char kBannerEngagementKey[] = "engagement"; |
| 75 | 73 |
| 76 // Keys to use when querying the variations params. | 74 // Keys to use when querying the variations params. |
| 77 const char kBannerParamsKey[] = "AppBannerTriggering"; | 75 const char kBannerParamsKey[] = "AppBannerTriggering"; |
| 78 const char kBannerParamsDirectKey[] = "direct"; | 76 const char kBannerParamsDirectKey[] = "direct"; |
| 79 const char kBannerParamsIndirectKey[] = "indirect"; | 77 const char kBannerParamsIndirectKey[] = "indirect"; |
| 80 const char kBannerParamsTotalKey[] = "total"; | 78 const char kBannerParamsTotalKey[] = "total"; |
| 81 const char kBannerParamsMinutesKey[] = "minutes"; | 79 const char kBannerParamsMinutesKey[] = "minutes"; |
| 82 const char kBannerParamsEngagementTotalKey[] = "site_engagement_total"; | 80 const char kBannerParamsEngagementTotalKey[] = "site_engagement_total"; |
| 81 const char kBannerParamsDaysAfterBannerDismissedKey[] = "days_after_dismiss"; |
| 82 const char kBannerParamsDaysAfterBannerIgnoredKey[] = "days_after_ignore"; |
| 83 const char kBannerSiteEngagementParamsKey[] = "use_site_engagement"; | 83 const char kBannerSiteEngagementParamsKey[] = "use_site_engagement"; |
| 84 | 84 |
| 85 // Engagement weight assigned to direct and indirect navigations. | 85 // Engagement weight assigned to direct and indirect navigations. |
| 86 // By default, a direct navigation is a page visit via ui::PAGE_TRANSITION_TYPED | 86 // By default, a direct navigation is a page visit via ui::PAGE_TRANSITION_TYPED |
| 87 // or ui::PAGE_TRANSITION_GENERATED. | 87 // or ui::PAGE_TRANSITION_GENERATED. |
| 88 double gDirectNavigationEngagement = kDefaultDirectNavigationEngagement; | 88 double gDirectNavigationEngagement = kDefaultDirectNavigationEngagement; |
| 89 double gIndirectNavigationEnagagement = kDefaultIndirectNavigationEngagement; | 89 double gIndirectNavigationEnagagement = kDefaultIndirectNavigationEngagement; |
| 90 | 90 |
| 91 // Number of minutes between visits that will trigger a could show banner event. | 91 // Number of minutes between visits that will trigger a could show banner event. |
| 92 // Defaults to the number of minutes in a day. | 92 // Defaults to the number of minutes in a day. |
| 93 unsigned int gMinimumMinutesBetweenVisits = kNumberOfMinutesInADay; | 93 unsigned int gMinimumMinutesBetweenVisits = kNumberOfMinutesInADay; |
| 94 | 94 |
| 95 // Total engagement score required before a banner will actually be triggered. | 95 // Total engagement score required before a banner will actually be triggered. |
| 96 double gTotalEngagementToTrigger = kDefaultTotalEngagementToTrigger; | 96 double gTotalEngagementToTrigger = kDefaultTotalEngagementToTrigger; |
| 97 | 97 |
| 98 unsigned int gDaysAfterDismissedToShow = kMinimumBannerBlockedToBannerShown; |
| 99 unsigned int gDaysAfterIgnoredToShow = kMinimumDaysBetweenBannerShows; |
| 100 |
| 98 std::unique_ptr<base::DictionaryValue> GetOriginDict( | 101 std::unique_ptr<base::DictionaryValue> GetOriginDict( |
| 99 HostContentSettingsMap* settings, | 102 HostContentSettingsMap* settings, |
| 100 const GURL& origin_url) { | 103 const GURL& origin_url) { |
| 101 if (!settings) | 104 if (!settings) |
| 102 return base::MakeUnique<base::DictionaryValue>(); | 105 return base::MakeUnique<base::DictionaryValue>(); |
| 103 | 106 |
| 104 std::unique_ptr<base::DictionaryValue> dict = | 107 std::unique_ptr<base::DictionaryValue> dict = |
| 105 base::DictionaryValue::From(settings->GetWebsiteSetting( | 108 base::DictionaryValue::From(settings->GetWebsiteSetting( |
| 106 origin_url, origin_url, CONTENT_SETTINGS_TYPE_APP_BANNER, | 109 origin_url, origin_url, CONTENT_SETTINGS_TYPE_APP_BANNER, |
| 107 std::string(), NULL)); | 110 std::string(), NULL)); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 130 if (ui::PageTransitionCoreTypeIs(transition_type, | 133 if (ui::PageTransitionCoreTypeIs(transition_type, |
| 131 ui::PAGE_TRANSITION_TYPED) || | 134 ui::PAGE_TRANSITION_TYPED) || |
| 132 ui::PageTransitionCoreTypeIs(transition_type, | 135 ui::PageTransitionCoreTypeIs(transition_type, |
| 133 ui::PAGE_TRANSITION_GENERATED)) { | 136 ui::PAGE_TRANSITION_GENERATED)) { |
| 134 return gDirectNavigationEngagement; | 137 return gDirectNavigationEngagement; |
| 135 } else { | 138 } else { |
| 136 return gIndirectNavigationEnagagement; | 139 return gIndirectNavigationEnagagement; |
| 137 } | 140 } |
| 138 } | 141 } |
| 139 | 142 |
| 143 // Queries variations for the number of days which dismissing and ignoring the |
| 144 // banner should prevent a banner from showing. |
| 145 void UpdateDaysBetweenShowing() { |
| 146 std::string dismiss_param = variations::GetVariationParamValue( |
| 147 kBannerParamsKey, kBannerParamsDaysAfterBannerDismissedKey); |
| 148 std::string ignore_param = variations::GetVariationParamValue( |
| 149 kBannerParamsKey, kBannerParamsDaysAfterBannerIgnoredKey); |
| 150 |
| 151 if (!dismiss_param.empty() && !ignore_param.empty()) { |
| 152 unsigned int dismiss_days = 0; |
| 153 unsigned int ignore_days = 0; |
| 154 |
| 155 if (base::StringToUint(dismiss_param, &dismiss_days) && |
| 156 base::StringToUint(ignore_param, &ignore_days)) { |
| 157 AppBannerSettingsHelper::SetDaysAfterDismissAndIgnoreToTrigger( |
| 158 dismiss_days, ignore_days); |
| 159 } |
| 160 } |
| 161 } |
| 162 |
| 140 // Queries variations for the maximum site engagement score required to trigger | 163 // Queries variations for the maximum site engagement score required to trigger |
| 141 // the banner showing. | 164 // the banner showing. |
| 142 void UpdateSiteEngagementToTrigger() { | 165 void UpdateSiteEngagementToTrigger() { |
| 143 std::string total_param = variations::GetVariationParamValue( | 166 std::string total_param = variations::GetVariationParamValue( |
| 144 kBannerParamsKey, kBannerParamsEngagementTotalKey); | 167 kBannerParamsKey, kBannerParamsEngagementTotalKey); |
| 145 | 168 |
| 146 if (!total_param.empty()) { | 169 if (!total_param.empty()) { |
| 147 double total_engagement = -1; | 170 double total_engagement = -1; |
| 148 | 171 |
| 149 if (base::StringToDouble(total_param, &total_engagement) && | 172 if (base::StringToDouble(total_param, &total_engagement) && |
| (...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 400 if (!added_time.is_null()) | 423 if (!added_time.is_null()) |
| 401 return ALREADY_INSTALLED; | 424 return ALREADY_INSTALLED; |
| 402 | 425 |
| 403 base::Time blocked_time = | 426 base::Time blocked_time = |
| 404 GetSingleBannerEvent(web_contents, origin_url, package_name_or_start_url, | 427 GetSingleBannerEvent(web_contents, origin_url, package_name_or_start_url, |
| 405 APP_BANNER_EVENT_DID_BLOCK); | 428 APP_BANNER_EVENT_DID_BLOCK); |
| 406 | 429 |
| 407 // Null times are in the distant past, so the delta between real times and | 430 // Null times are in the distant past, so the delta between real times and |
| 408 // null events will always be greater than the limits. | 431 // null events will always be greater than the limits. |
| 409 if (time - blocked_time < | 432 if (time - blocked_time < |
| 410 base::TimeDelta::FromDays(kMinimumBannerBlockedToBannerShown)) { | 433 base::TimeDelta::FromDays(gDaysAfterDismissedToShow)) { |
| 411 return PREVIOUSLY_BLOCKED; | 434 return PREVIOUSLY_BLOCKED; |
| 412 } | 435 } |
| 413 | 436 |
| 414 base::Time shown_time = | 437 base::Time shown_time = |
| 415 GetSingleBannerEvent(web_contents, origin_url, package_name_or_start_url, | 438 GetSingleBannerEvent(web_contents, origin_url, package_name_or_start_url, |
| 416 APP_BANNER_EVENT_DID_SHOW); | 439 APP_BANNER_EVENT_DID_SHOW); |
| 417 if (time - shown_time < | 440 if (time - shown_time < base::TimeDelta::FromDays(gDaysAfterIgnoredToShow)) { |
| 418 base::TimeDelta::FromDays(kMinimumDaysBetweenBannerShows)) { | |
| 419 return PREVIOUSLY_IGNORED; | 441 return PREVIOUSLY_IGNORED; |
| 420 } | 442 } |
| 421 | 443 |
| 422 // If we have gotten this far and want to use site engagement, the banner flow | 444 // If we have gotten this far and want to use site engagement, the banner flow |
| 423 // was triggered by the site engagement service informing the banner manager | 445 // was triggered by the site engagement service informing the banner manager |
| 424 // that sufficient engagement has been accumulated. Hence there is no need to | 446 // that sufficient engagement has been accumulated. Hence there is no need to |
| 425 // check the total amount of engagement. | 447 // check the total amount of engagement. |
| 426 // TODO(dominickn): just return true here and remove all of the following code | 448 // TODO(dominickn): just return true here and remove all of the following code |
| 427 // in this method when app banners have fully migrated to using site | 449 // in this method when app banners have fully migrated to using site |
| 428 // engagement as a trigger condition. See crbug.com/616322. | 450 // engagement as a trigger condition. See crbug.com/616322. |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 575 if ((now - added_time) <= | 597 if ((now - added_time) <= |
| 576 base::TimeDelta::FromDays(kRecentLastLaunchInDays)) { | 598 base::TimeDelta::FromDays(kRecentLastLaunchInDays)) { |
| 577 return true; | 599 return true; |
| 578 } | 600 } |
| 579 } | 601 } |
| 580 } | 602 } |
| 581 | 603 |
| 582 return false; | 604 return false; |
| 583 } | 605 } |
| 584 | 606 |
| 607 void AppBannerSettingsHelper::SetDaysAfterDismissAndIgnoreToTrigger( |
| 608 unsigned int dismiss_days, |
| 609 unsigned int ignore_days) { |
| 610 gDaysAfterDismissedToShow = dismiss_days; |
| 611 gDaysAfterIgnoredToShow = ignore_days; |
| 612 } |
| 613 |
| 585 void AppBannerSettingsHelper::SetEngagementWeights(double direct_engagement, | 614 void AppBannerSettingsHelper::SetEngagementWeights(double direct_engagement, |
| 586 double indirect_engagement) { | 615 double indirect_engagement) { |
| 587 gDirectNavigationEngagement = direct_engagement; | 616 gDirectNavigationEngagement = direct_engagement; |
| 588 gIndirectNavigationEnagagement = indirect_engagement; | 617 gIndirectNavigationEnagagement = indirect_engagement; |
| 589 } | 618 } |
| 590 | 619 |
| 591 void AppBannerSettingsHelper::SetMinimumMinutesBetweenVisits( | 620 void AppBannerSettingsHelper::SetMinimumMinutesBetweenVisits( |
| 592 unsigned int minutes) { | 621 unsigned int minutes) { |
| 593 gMinimumMinutesBetweenVisits = minutes; | 622 gMinimumMinutesBetweenVisits = minutes; |
| 594 } | 623 } |
| 595 | 624 |
| 596 void AppBannerSettingsHelper::SetTotalEngagementToTrigger( | 625 void AppBannerSettingsHelper::SetTotalEngagementToTrigger( |
| 597 double total_engagement) { | 626 double total_engagement) { |
| 598 gTotalEngagementToTrigger = total_engagement; | 627 gTotalEngagementToTrigger = total_engagement; |
| 599 } | 628 } |
| 600 | 629 |
| 601 void AppBannerSettingsHelper::SetDefaultParameters() { | 630 void AppBannerSettingsHelper::SetDefaultParameters() { |
| 631 SetDaysAfterDismissAndIgnoreToTrigger(kMinimumBannerBlockedToBannerShown, |
| 632 kMinimumDaysBetweenBannerShows); |
| 602 SetEngagementWeights(kDefaultDirectNavigationEngagement, | 633 SetEngagementWeights(kDefaultDirectNavigationEngagement, |
| 603 kDefaultIndirectNavigationEngagement); | 634 kDefaultIndirectNavigationEngagement); |
| 604 SetMinimumMinutesBetweenVisits(kNumberOfMinutesInADay); | 635 SetMinimumMinutesBetweenVisits(kNumberOfMinutesInADay); |
| 605 SetTotalEngagementToTrigger(kDefaultTotalEngagementToTrigger); | 636 SetTotalEngagementToTrigger(kDefaultTotalEngagementToTrigger); |
| 606 } | 637 } |
| 607 | 638 |
| 608 // Given a time, returns that time scoped to the nearest minute resolution | 639 // Given a time, returns that time scoped to the nearest minute resolution |
| 609 // locally. For example, if the resolution is one hour, this function will | 640 // locally. For example, if the resolution is one hour, this function will |
| 610 // return the time to the closest (previous) hour in the local time zone. | 641 // return the time to the closest (previous) hour in the local time zone. |
| 611 base::Time AppBannerSettingsHelper::BucketTimeToResolution( | 642 base::Time AppBannerSettingsHelper::BucketTimeToResolution( |
| (...skipping 15 matching lines...) Expand all Loading... |
| 627 int total_minutes = exploded.hour * 60 + exploded.minute; | 658 int total_minutes = exploded.hour * 60 + exploded.minute; |
| 628 | 659 |
| 629 // Use truncating integer division here. | 660 // Use truncating integer division here. |
| 630 return time.LocalMidnight() + | 661 return time.LocalMidnight() + |
| 631 base::TimeDelta::FromMinutes((total_minutes / minutes) * minutes); | 662 base::TimeDelta::FromMinutes((total_minutes / minutes) * minutes); |
| 632 } | 663 } |
| 633 | 664 |
| 634 void AppBannerSettingsHelper::UpdateFromFieldTrial() { | 665 void AppBannerSettingsHelper::UpdateFromFieldTrial() { |
| 635 // If we are using the site engagement score, only extract the total | 666 // If we are using the site engagement score, only extract the total |
| 636 // engagement to trigger from the params variations. | 667 // engagement to trigger from the params variations. |
| 668 UpdateDaysBetweenShowing(); |
| 637 if (ShouldUseSiteEngagementScore()) { | 669 if (ShouldUseSiteEngagementScore()) { |
| 638 UpdateSiteEngagementToTrigger(); | 670 UpdateSiteEngagementToTrigger(); |
| 639 } else { | 671 } else { |
| 640 UpdateEngagementWeights(); | 672 UpdateEngagementWeights(); |
| 641 UpdateMinutesBetweenVisits(); | 673 UpdateMinutesBetweenVisits(); |
| 642 } | 674 } |
| 643 } | 675 } |
| 644 | 676 |
| 645 bool AppBannerSettingsHelper::ShouldUseSiteEngagementScore() { | 677 bool AppBannerSettingsHelper::ShouldUseSiteEngagementScore() { |
| 646 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | 678 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 647 switches::kEnableSiteEngagementAppBanner)) { | 679 switches::kEnableSiteEngagementAppBanner)) { |
| 648 return true; | 680 return true; |
| 649 } | 681 } |
| 650 | 682 |
| 651 // Assume any value which is not "0" or "false" indicates that we should use | 683 // Assume any value which is not "0" or "false" indicates that we should use |
| 652 // site engagement. | 684 // site engagement. |
| 653 std::string param = variations::GetVariationParamValue( | 685 std::string param = variations::GetVariationParamValue( |
| 654 kBannerParamsKey, kBannerSiteEngagementParamsKey); | 686 kBannerParamsKey, kBannerSiteEngagementParamsKey); |
| 655 | 687 |
| 656 return (!param.empty() && param != "0" && param != "false"); | 688 return (!param.empty() && param != "0" && param != "false"); |
| 657 } | 689 } |
| OLD | NEW |