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 |