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 3 // found in the LICENSE file. 4 5 #ifndef CHROME_BROWSER_BANNERS_APP_BANNER_SETTINGS_HELPER_H_ 6 #define CHROME_BROWSER_BANNERS_APP_BANNER_SETTINGS_HELPER_H_ 7 8 #include <set> 9 #include <string> 10 11 #include "base/macros.h" 12 #include "base/optional.h" 13 #include "base/time/time.h" 14 #include "chrome/browser/installable/installable_logging.h" 15 16 namespace content { 17 class WebContents; 18 } // namespace content 19 20 class GURL; 21 class Profile; 22 23 // Utility class to record banner events for the given package or start url. 24 // 25 // These events are used to decide when banners should be shown, using a 26 // heuristic based on how many different days in a recent period of time (for 27 // example the past two weeks) the banner could have been shown, when it was 28 // last shown, when it was last blocked, and when it was last installed (for 29 // ServiceWorker style apps - native apps can query whether the app was 30 // installed directly). 31 // 32 // The desired effect is to have banners appear once a user has demonstrated 33 // an ongoing relationship with the app, and not to pester the user too much. 34 // 35 // For most events only the last event is recorded. The exception are the 36 // could show events. For these a list of the events is maintained. At most 37 // one event is stored per day, and events outside the window the heuristic 38 // uses are discarded. Local times are used to enforce these rules, to ensure 39 // what we count as a day matches what the user perceives to be days. 40 class AppBannerSettingsHelper { 41 public: 42 // An enum containing possible app menu verbiage for installing a web app. 43 // A Java counterpart will be generated for this enum. 44 // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.banners 45 enum AppMenuVerbiage { 46 APP_MENU_OPTION_UNKNOWN = 0, 47 APP_MENU_OPTION_MIN = APP_MENU_OPTION_UNKNOWN, 48 APP_MENU_OPTION_ADD_TO_HOMESCREEN = 1, 49 APP_MENU_OPTION_INSTALL = 2, 50 APP_MENU_OPTION_MAX = APP_MENU_OPTION_INSTALL, 51 }; 52 53 // The various types of banner events recorded as timestamps in the app banner 54 // content setting per origin and package_name_or_start_url pair. This enum 55 // corresponds to the kBannerEventsKeys array. 56 // TODO(mariakhomenko): Rename events to reflect that they are used in more 57 // contexts now. 58 enum AppBannerEvent { 59 // Records the first time that a site met the conditions to show a banner. 60 // Used for computing the MinutesFromFirstVisitToBannerShown metric. 61 APP_BANNER_EVENT_COULD_SHOW, 62 // Records the latest time a banner was shown to the user. Used to suppress 63 // the banner from being shown too often. 64 APP_BANNER_EVENT_DID_SHOW, 65 // Records the latest time a banner was dismissed by the user. Used to 66 // suppress the banner for some time if the user explicitly didn't want it. 67 APP_BANNER_EVENT_DID_BLOCK, 68 // Records the latest time the user added a site to the homescreen from a 69 // banner, or launched that site from homescreen. Used to ensure banners are 70 // not shown for sites which were added, and to determine if sites were 71 // launched recently. 72 APP_BANNER_EVENT_DID_ADD_TO_HOMESCREEN, 73 APP_BANNER_EVENT_NUM_EVENTS, 74 }; 75 76 static const char kInstantAppsKey[]; 77 78 // The content setting basically records a simplified subset of history. 79 // For privacy reasons this needs to be cleared. The ClearHistoryForURLs 80 // function removes any information from the banner content settings for the 81 // given URls. 82 static void ClearHistoryForURLs(Profile* profile, 83 const std::set<GURL>& origin_urls); 84 85 // Record a banner installation event, for either a WEB or NATIVE app. 86 static void RecordBannerInstallEvent( 87 content::WebContents* web_contents, 88 const std::string& package_name_or_start_url); 89 90 // Record a banner dismissal event, for either a WEB or NATIVE app. 91 static void RecordBannerDismissEvent( 92 content::WebContents* web_contents, 93 const std::string& package_name_or_start_url); 94 95 // Record a banner event specified by |event|. 96 static void RecordBannerEvent(content::WebContents* web_contents, 97 const GURL& origin_url, 98 const std::string& package_name_or_start_url, 99 AppBannerEvent event, 100 base::Time time); 101 102 // Reports whether the app install banner was blocked by the user recently 103 // enough with respect to |now| that another banner should not yet be shown. 104 // |package_name_or_start_url| must be non-empty. 105 static bool WasBannerRecentlyBlocked( 106 content::WebContents* web_contents, 107 const GURL& origin_url, 108 const std::string& package_name_or_start_url, 109 base::Time now); 110 111 // Reports whether the app install banner was ignored by the user recently 112 // enough with respect to |now| that another banner should not yet be shown. 113 // |package_name_or_start_url| must be non-empty. 114 static bool WasBannerRecentlyIgnored( 115 content::WebContents* web_contents, 116 const GURL& origin_url, 117 const std::string& package_name_or_start_url, 118 base::Time now); 119 120 // Returns whether the supplied app has ever been installed from |origin_url|. 121 static bool HasBeenInstalled(content::WebContents* web_contents, 122 const GURL& origin_url, 123 const std::string& package_name_or_start_url); 124 125 // Get the time that |event| was recorded, or a nullopt if it no dict to 126 // record yet(such as exceed max num per site) . Exposed for testing. 127 static base::Optional<base::Time> GetSingleBannerEvent( 128 content::WebContents* web_contents, 129 const GURL& origin_url, 130 const std::string& package_name_or_start_url, 131 AppBannerEvent event); 132 133 // Returns true if |total_engagement| is sufficiently high to warrant 134 // triggering a banner, or if the command-line flag to bypass engagement 135 // checking is true. 136 static bool HasSufficientEngagement(double total_engagement); 137 138 // Record a UMA statistic measuring the minutes between the first visit to the 139 // site and the first showing of the banner. 140 static void RecordMinutesFromFirstVisitToShow( 141 content::WebContents* web_contents, 142 const GURL& origin_url, 143 const std::string& package_name_or_start_url, 144 base::Time time); 145 146 // Returns true if any site under |origin| was launched from homescreen in the 147 // last ten days. This allows services outside app banners to utilise the 148 // content setting that ensures app banners are not shown for sites which ave 149 // already been added to homescreen. 150 static bool WasLaunchedRecently(Profile* profile, 151 const GURL& origin_url, 152 base::Time now); 153 154 // Set the number of days which dismissing/ignoring the banner should prevent 155 // a banner from showing. 156 static void SetDaysAfterDismissAndIgnoreToTrigger(unsigned int dismiss_days, 157 unsigned int ignore_days); 158 159 // Set the total engagement weight required to trigger a banner. 160 static void SetTotalEngagementToTrigger(double total_engagement); 161 162 // Resets the engagement weights, minimum minutes, and total engagement to 163 // trigger to their default values. 164 static void SetDefaultParameters(); 165 166 // Updates all values from field trial. 167 static void UpdateFromFieldTrial(); 168 169 // Returns whether we are out of |scope|'s animation suppression period and 170 // can show an animation. 171 static bool CanShowInstallTextAnimation(content::WebContents* web_contents, 172 const GURL& scope); 173 174 // Records the fact that we've shown an animation for |scope| and updates its 175 // animation suppression period. 176 static void RecordInstallTextAnimationShown( 177 content::WebContents* web_contents, 178 const GURL& scope); 179 180 // Utility class for testing, which sets how long the banner should be 181 // suppressed after it is dismissed or ignored. The previous configuration 182 // is restored when this object is destructed. 183 class ScopedTriggerSettings { 184 public: 185 ScopedTriggerSettings(unsigned int dismiss_days, unsigned int ignore_days); 186 virtual ~ScopedTriggerSettings(); 187 188 private: 189 unsigned int old_dismiss_, old_ignore_; 190 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedTriggerSettings); 191 }; 192 193 private: 194 DISALLOW_IMPLICIT_CONSTRUCTORS(AppBannerSettingsHelper); 195 }; 196 197 #endif // CHROME_BROWSER_BANNERS_APP_BANNER_SETTINGS_HELPER_H_ 198