| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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 #include "chrome/browser/extensions/apps_promo.h" | |
| 6 | |
| 7 #include "base/base64.h" | |
| 8 #include "base/command_line.h" | |
| 9 #include "base/metrics/histogram.h" | |
| 10 #include "chrome/browser/browser_process.h" | |
| 11 #include "chrome/browser/prefs/pref_service.h" | |
| 12 #include "chrome/browser/profiles/profile.h" | |
| 13 #include "chrome/common/chrome_notification_types.h" | |
| 14 #include "chrome/common/chrome_switches.h" | |
| 15 #include "chrome/common/extensions/extension.h" | |
| 16 #include "chrome/common/pref_names.h" | |
| 17 #include "content/public/browser/notification_service.h" | |
| 18 #include "content/public/common/url_constants.h" | |
| 19 | |
| 20 const int AppsPromo::kDefaultAppsCounterMax = 10; | |
| 21 | |
| 22 namespace { | |
| 23 | |
| 24 // The default logo for the promo. | |
| 25 const char kDefaultLogo[] = "chrome://theme/IDR_WEBSTORE_ICON"; | |
| 26 | |
| 27 // The default promo data (this is only used for testing with | |
| 28 // --force-apps-promo-visible). | |
| 29 const char kDefaultHeader[] = "Browse thousands of apps and games for Chrome"; | |
| 30 const char kDefaultButton[] = "Visit the Chrome Web Store"; | |
| 31 const char kDefaultExpire[] = "No thanks"; | |
| 32 const char kDefaultLink[] = "https://chrome.google.com/webstore"; | |
| 33 | |
| 34 // Returns the string pref at |path|, using |fallback| as the default (if there | |
| 35 // is no pref value present). |fallback| is used for debugging in concert with | |
| 36 // --force-apps-promo-visible. | |
| 37 std::string GetStringPref(const char* path, const std::string& fallback) { | |
| 38 PrefService* local_state = g_browser_process->local_state(); | |
| 39 std::string retval(local_state->GetString(path)); | |
| 40 if (retval.empty() && CommandLine::ForCurrentProcess()->HasSwitch( | |
| 41 switches::kForceAppsPromoVisible)) { | |
| 42 retval = fallback; | |
| 43 } | |
| 44 return retval; | |
| 45 } | |
| 46 | |
| 47 } // namespace | |
| 48 | |
| 49 AppsPromo::PromoData::PromoData() : user_group(AppsPromo::USERS_NONE) {} | |
| 50 AppsPromo::PromoData::PromoData(const std::string& id, | |
| 51 const std::string& header, | |
| 52 const std::string& button, | |
| 53 const GURL& link, | |
| 54 const std::string& expire, | |
| 55 const GURL& logo, | |
| 56 const int user_group) | |
| 57 : id(id), | |
| 58 header(header), | |
| 59 button(button), | |
| 60 link(link), | |
| 61 expire(expire), | |
| 62 logo(logo), | |
| 63 user_group(user_group) {} | |
| 64 | |
| 65 AppsPromo::PromoData::~PromoData() {} | |
| 66 | |
| 67 // static | |
| 68 void AppsPromo::RegisterPrefs(PrefService* local_state) { | |
| 69 std::string empty; | |
| 70 local_state->RegisterBooleanPref(prefs::kNtpWebStoreEnabled, false); | |
| 71 local_state->RegisterStringPref(prefs::kNtpWebStorePromoId, empty); | |
| 72 local_state->RegisterStringPref(prefs::kNtpWebStorePromoHeader, empty); | |
| 73 local_state->RegisterStringPref(prefs::kNtpWebStorePromoButton, empty); | |
| 74 local_state->RegisterStringPref(prefs::kNtpWebStorePromoLink, empty); | |
| 75 local_state->RegisterStringPref(prefs::kNtpWebStorePromoLogo, empty); | |
| 76 local_state->RegisterStringPref(prefs::kNtpWebStorePromoLogoSource, empty); | |
| 77 local_state->RegisterStringPref(prefs::kNtpWebStorePromoExpire, empty); | |
| 78 local_state->RegisterIntegerPref(prefs::kNtpWebStorePromoUserGroup, 0); | |
| 79 } | |
| 80 | |
| 81 // static | |
| 82 void AppsPromo::RegisterUserPrefs(PrefService* prefs) { | |
| 83 // Set the default value for the counter to max+1 since we don't install | |
| 84 // default apps for new users. | |
| 85 prefs->RegisterIntegerPref(prefs::kAppsPromoCounter, | |
| 86 kDefaultAppsCounterMax + 1, | |
| 87 PrefService::UNSYNCABLE_PREF); | |
| 88 prefs->RegisterBooleanPref(prefs::kDefaultAppsInstalled, | |
| 89 false, | |
| 90 PrefService::UNSYNCABLE_PREF); | |
| 91 prefs->RegisterStringPref(prefs::kNtpWebStorePromoLastId, | |
| 92 std::string(), | |
| 93 PrefService::UNSYNCABLE_PREF); | |
| 94 prefs->RegisterBooleanPref(prefs::kNtpHideWebStorePromo, | |
| 95 false, | |
| 96 PrefService::UNSYNCABLE_PREF); | |
| 97 } | |
| 98 | |
| 99 // static | |
| 100 bool AppsPromo::IsPromoSupportedForLocale() { | |
| 101 PrefService* local_state = g_browser_process->local_state(); | |
| 102 // PromoResourceService will clear the promo data if the current locale is | |
| 103 // not supported. | |
| 104 return local_state->HasPrefPath(prefs::kNtpWebStorePromoId) && | |
| 105 local_state->HasPrefPath(prefs::kNtpWebStorePromoHeader) && | |
| 106 local_state->HasPrefPath(prefs::kNtpWebStorePromoButton) && | |
| 107 local_state->HasPrefPath(prefs::kNtpWebStorePromoLink) && | |
| 108 local_state->HasPrefPath(prefs::kNtpWebStorePromoLogo) && | |
| 109 local_state->HasPrefPath(prefs::kNtpWebStorePromoExpire) && | |
| 110 local_state->HasPrefPath(prefs::kNtpWebStorePromoUserGroup); | |
| 111 } | |
| 112 | |
| 113 // static | |
| 114 bool AppsPromo::IsWebStoreSupportedForLocale() { | |
| 115 PrefService* local_state = g_browser_process->local_state(); | |
| 116 return local_state->GetBoolean(prefs::kNtpWebStoreEnabled); | |
| 117 } | |
| 118 | |
| 119 // static | |
| 120 void AppsPromo::SetWebStoreSupportedForLocale(bool supported) { | |
| 121 PrefService* local_state = g_browser_process->local_state(); | |
| 122 local_state->SetBoolean(prefs::kNtpWebStoreEnabled, supported); | |
| 123 } | |
| 124 | |
| 125 // static | |
| 126 void AppsPromo::ClearPromo() { | |
| 127 PrefService* local_state = g_browser_process->local_state(); | |
| 128 local_state->ClearPref(prefs::kNtpWebStoreEnabled); | |
| 129 local_state->ClearPref(prefs::kNtpWebStorePromoId); | |
| 130 local_state->ClearPref(prefs::kNtpWebStorePromoHeader); | |
| 131 local_state->ClearPref(prefs::kNtpWebStorePromoButton); | |
| 132 local_state->ClearPref(prefs::kNtpWebStorePromoLink); | |
| 133 local_state->ClearPref(prefs::kNtpWebStorePromoLogo); | |
| 134 local_state->ClearPref(prefs::kNtpWebStorePromoLogoSource); | |
| 135 local_state->ClearPref(prefs::kNtpWebStorePromoExpire); | |
| 136 local_state->ClearPref(prefs::kNtpWebStorePromoUserGroup); | |
| 137 } | |
| 138 | |
| 139 // static | |
| 140 AppsPromo::PromoData AppsPromo::GetPromo() { | |
| 141 PromoData data; | |
| 142 PrefService* local_state = g_browser_process->local_state(); | |
| 143 | |
| 144 data.id = GetStringPref(prefs::kNtpWebStorePromoId, ""); | |
| 145 data.link = GURL(GetStringPref(prefs::kNtpWebStorePromoLink, kDefaultLink)); | |
| 146 data.user_group = local_state->GetInteger(prefs::kNtpWebStorePromoUserGroup); | |
| 147 data.header = GetStringPref(prefs::kNtpWebStorePromoHeader, kDefaultHeader); | |
| 148 data.button = GetStringPref(prefs::kNtpWebStorePromoButton, kDefaultButton); | |
| 149 data.expire = GetStringPref(prefs::kNtpWebStorePromoExpire, kDefaultExpire); | |
| 150 | |
| 151 GURL logo_url(local_state->GetString(prefs::kNtpWebStorePromoLogo)); | |
| 152 if (logo_url.is_valid() && logo_url.SchemeIs(chrome::kDataScheme)) | |
| 153 data.logo = logo_url; | |
| 154 else | |
| 155 data.logo = GURL(kDefaultLogo); | |
| 156 | |
| 157 return data; | |
| 158 } | |
| 159 | |
| 160 // static | |
| 161 void AppsPromo::SetPromo(const AppsPromo::PromoData& data) { | |
| 162 PrefService* local_state = g_browser_process->local_state(); | |
| 163 local_state->SetString(prefs::kNtpWebStorePromoId, data.id); | |
| 164 local_state->SetString(prefs::kNtpWebStorePromoButton, data.button); | |
| 165 local_state->SetString(prefs::kNtpWebStorePromoHeader, data.header); | |
| 166 local_state->SetString(prefs::kNtpWebStorePromoLink, data.link.spec()); | |
| 167 local_state->SetString(prefs::kNtpWebStorePromoLogo, data.logo.spec()); | |
| 168 local_state->SetString(prefs::kNtpWebStorePromoExpire, data.expire); | |
| 169 local_state->SetInteger(prefs::kNtpWebStorePromoUserGroup, data.user_group); | |
| 170 } | |
| 171 | |
| 172 // static | |
| 173 GURL AppsPromo::GetSourcePromoLogoURL() { | |
| 174 return GURL(GetStringPref(prefs::kNtpWebStorePromoLogoSource, "")); | |
| 175 } | |
| 176 | |
| 177 // static | |
| 178 void AppsPromo::SetSourcePromoLogoURL(const GURL& logo_source) { | |
| 179 PrefService* local_state = g_browser_process->local_state(); | |
| 180 local_state->SetString(prefs::kNtpWebStorePromoLogoSource, | |
| 181 logo_source.spec()); | |
| 182 } | |
| 183 | |
| 184 AppsPromo::AppsPromo(PrefService* prefs) | |
| 185 : prefs_(prefs) { | |
| 186 // Poppit, Entanglement | |
| 187 old_default_app_ids_.insert("mcbkbpnkkkipelfledbfocopglifcfmi"); | |
| 188 old_default_app_ids_.insert("aciahcmjmecflokailenpkdchphgkefd"); | |
| 189 } | |
| 190 | |
| 191 AppsPromo::~AppsPromo() {} | |
| 192 | |
| 193 bool AppsPromo::ShouldShowPromo(const extensions::ExtensionIdSet& installed_ids, | |
| 194 bool* just_expired) { | |
| 195 *just_expired = false; | |
| 196 | |
| 197 if (CommandLine::ForCurrentProcess()->HasSwitch( | |
| 198 switches::kForceAppsPromoVisible)) { | |
| 199 return true; | |
| 200 } | |
| 201 | |
| 202 // Don't show the promo if the policy says not to. | |
| 203 if (prefs_->GetBoolean(prefs::kNtpHideWebStorePromo)) { | |
| 204 ExpireDefaultApps(); | |
| 205 return false; | |
| 206 } | |
| 207 | |
| 208 // Don't show the promo if one wasn't served to this locale. | |
| 209 if (!IsPromoSupportedForLocale()) | |
| 210 return false; | |
| 211 | |
| 212 int promo_counter = GetPromoCounter(); | |
| 213 if (GetDefaultAppsInstalled() && promo_counter <= kDefaultAppsCounterMax) { | |
| 214 // If the default apps were installed from a previous Chrome version, we | |
| 215 // should still show the promo. If we don't have the exact set of default | |
| 216 // apps, this means that the user manually installed or uninstalled one. | |
| 217 // We no longer keep track of the default apps once others have been | |
| 218 // installed, so expire them immediately. | |
| 219 if (old_default_app_ids_ != installed_ids) { | |
| 220 ExpireDefaultApps(); | |
| 221 return false; | |
| 222 } | |
| 223 | |
| 224 if (promo_counter == kDefaultAppsCounterMax) { | |
| 225 *just_expired = true; | |
| 226 | |
| 227 // The default apps have expired due to inaction, so ping PROMO_EXPIRE. | |
| 228 UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppsPromoHistogram, | |
| 229 extension_misc::PROMO_EXPIRE, | |
| 230 extension_misc::PROMO_BUCKET_BOUNDARY); | |
| 231 | |
| 232 ExpireDefaultApps(); | |
| 233 } else { | |
| 234 SetPromoCounter(++promo_counter); | |
| 235 } | |
| 236 return true; | |
| 237 } else if (installed_ids.empty()) { | |
| 238 return true; | |
| 239 } | |
| 240 | |
| 241 return false; | |
| 242 } | |
| 243 | |
| 244 bool AppsPromo::ShouldShowAppLauncher( | |
| 245 const extensions::ExtensionIdSet& installed_ids) { | |
| 246 // On Chrome OS the default apps are installed via a separate mechanism that | |
| 247 // is always enabled. Therefore we always show the launcher. | |
| 248 #if defined(OS_CHROMEOS) | |
| 249 return true; | |
| 250 #else | |
| 251 | |
| 252 // Always show the app launcher if an app is installed. | |
| 253 if (!installed_ids.empty()) | |
| 254 return true; | |
| 255 | |
| 256 // Otherwise, only show the app launcher if the web store is supported for the | |
| 257 // current locale. | |
| 258 return IsWebStoreSupportedForLocale(); | |
| 259 #endif | |
| 260 } | |
| 261 | |
| 262 void AppsPromo::ExpireDefaultApps() { | |
| 263 SetPromoCounter(kDefaultAppsCounterMax + 1); | |
| 264 } | |
| 265 | |
| 266 void AppsPromo::HidePromo() { | |
| 267 UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppsPromoHistogram, | |
| 268 extension_misc::PROMO_CLOSE, | |
| 269 extension_misc::PROMO_BUCKET_BOUNDARY); | |
| 270 | |
| 271 ExpireDefaultApps(); | |
| 272 } | |
| 273 | |
| 274 std::string AppsPromo::GetLastPromoId() { | |
| 275 return prefs_->GetString(prefs::kNtpWebStorePromoLastId); | |
| 276 } | |
| 277 | |
| 278 void AppsPromo::SetLastPromoId(const std::string& id) { | |
| 279 prefs_->SetString(prefs::kNtpWebStorePromoLastId, id); | |
| 280 } | |
| 281 | |
| 282 int AppsPromo::GetPromoCounter() const { | |
| 283 return prefs_->GetInteger(prefs::kAppsPromoCounter); | |
| 284 } | |
| 285 | |
| 286 void AppsPromo::SetPromoCounter(int val) { | |
| 287 prefs_->SetInteger(prefs::kAppsPromoCounter, val); | |
| 288 } | |
| 289 | |
| 290 bool AppsPromo::GetDefaultAppsInstalled() const { | |
| 291 return prefs_->GetBoolean(prefs::kDefaultAppsInstalled); | |
| 292 } | |
| 293 | |
| 294 AppsPromo::UserGroup AppsPromo::GetCurrentUserGroup() const { | |
| 295 const PrefService::Preference* last_promo_id | |
| 296 = prefs_->FindPreference(prefs::kNtpWebStorePromoLastId); | |
| 297 CHECK(last_promo_id); | |
| 298 return last_promo_id->IsDefaultValue() ? USERS_NEW : USERS_EXISTING; | |
| 299 } | |
| OLD | NEW |