sync_promo_ui.cc revision ca12bfac764ba476d6cd062bf1dde12cc64c3f40
1// Copyright 2013 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/ui/sync/sync_promo_ui.h" 6 7#include "base/command_line.h" 8#include "base/prefs/pref_service.h" 9#include "base/strings/string_number_conversions.h" 10#include "base/strings/string_util.h" 11#include "base/strings/stringprintf.h" 12#include "base/strings/utf_string_conversions.h" 13#include "chrome/browser/browser_process.h" 14#include "chrome/browser/first_run/first_run.h" 15#include "chrome/browser/google/google_util.h" 16#include "chrome/browser/profiles/profile.h" 17#include "chrome/browser/profiles/profile_info_cache.h" 18#include "chrome/browser/profiles/profile_manager.h" 19#include "chrome/browser/signin/signin_manager.h" 20#include "chrome/browser/signin/signin_manager_factory.h" 21#include "chrome/browser/sync/profile_sync_service.h" 22#include "chrome/browser/sync/profile_sync_service_factory.h" 23#include "chrome/browser/ui/webui/options/core_options_handler.h" 24#include "chrome/browser/ui/webui/sync_promo/sync_promo_trial.h" 25#include "chrome/browser/ui/webui/theme_source.h" 26#include "chrome/common/chrome_switches.h" 27#include "chrome/common/net/url_util.h" 28#include "chrome/common/pref_names.h" 29#include "chrome/common/url_constants.h" 30#include "components/user_prefs/pref_registry_syncable.h" 31#include "content/public/browser/url_data_source.h" 32#include "content/public/browser/web_contents.h" 33#include "content/public/browser/web_ui.h" 34#include "content/public/browser/web_ui_data_source.h" 35#include "google_apis/gaia/gaia_urls.h" 36#include "grit/browser_resources.h" 37#include "grit/generated_resources.h" 38#include "grit/theme_resources.h" 39#include "net/base/escape.h" 40#include "net/base/network_change_notifier.h" 41#include "net/base/url_util.h" 42#include "ui/base/l10n/l10n_util.h" 43 44using content::WebContents; 45 46namespace { 47 48const char kStringsJsFile[] = "strings.js"; 49const char kSyncPromoJsFile[] = "sync_promo.js"; 50 51const char kSyncPromoQueryKeyAutoClose[] = "auto_close"; 52const char kSyncPromoQueryKeyContinue[] = "continue"; 53const char kSyncPromoQueryKeySource[] = "source"; 54 55// Gaia cannot support about:blank as a continue URL, so using a hosted blank 56// page instead. 57const char kSyncLandingUrlPrefix[] = 58 "https://www.google.com/intl/%s/chrome/blank.html"; 59 60// The maximum number of times we want to show the sync promo at startup. 61const int kSyncPromoShowAtStartupMaximum = 10; 62 63// Forces the web based signin flow when set. 64bool g_force_web_based_signin_flow = false; 65 66// Checks we want to show the sync promo for the given brand. 67bool AllowPromoAtStartupForCurrentBrand() { 68 std::string brand; 69 google_util::GetBrand(&brand); 70 71 if (brand.empty()) 72 return true; 73 74 if (google_util::IsInternetCafeBrandCode(brand)) 75 return false; 76 77 // Enable for both organic and distribution. 78 return true; 79} 80 81} // namespace 82 83// static 84bool SyncPromoUI::HasShownPromoAtStartup(Profile* profile) { 85 return profile->GetPrefs()->HasPrefPath(prefs::kSyncPromoStartupCount); 86} 87 88// static 89bool SyncPromoUI::ShouldShowSyncPromo(Profile* profile) { 90#if defined(OS_CHROMEOS) 91 // There's no need to show the sync promo on cros since cros users are logged 92 // into sync already. 93 return false; 94#else 95 96 // Don't bother if we don't have any kind of network connection. 97 if (net::NetworkChangeNotifier::IsOffline()) 98 return false; 99 100 // Don't show for managed profiles. 101 if (profile->GetPrefs()->GetBoolean(prefs::kProfileIsManaged)) 102 return false; 103 104 // Display the signin promo if the user is not signed in. 105 SigninManager* signin = SigninManagerFactory::GetForProfile( 106 profile->GetOriginalProfile()); 107 return !signin->AuthInProgress() && signin->IsSigninAllowed() && 108 signin->GetAuthenticatedUsername().empty(); 109#endif 110} 111 112// static 113void SyncPromoUI::RegisterProfilePrefs( 114 user_prefs::PrefRegistrySyncable* registry) { 115 registry->RegisterIntegerPref( 116 prefs::kSyncPromoStartupCount, 117 0, 118 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 119 registry->RegisterBooleanPref( 120 prefs::kSyncPromoUserSkipped, 121 false, 122 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 123 registry->RegisterBooleanPref( 124 prefs::kSyncPromoShowOnFirstRunAllowed, 125 true, 126 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 127 registry->RegisterBooleanPref( 128 prefs::kSyncPromoShowNTPBubble, 129 false, 130 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 131 registry->RegisterStringPref( 132 prefs::kSyncPromoErrorMessage, 133 std::string(), 134 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 135} 136 137// static 138bool SyncPromoUI::ShouldShowSyncPromoAtStartup(Profile* profile, 139 bool is_new_profile) { 140 DCHECK(profile); 141 142 // Don't show if the profile is an incognito. 143 if (profile->IsOffTheRecord()) 144 return false; 145 146 if (!ShouldShowSyncPromo(profile)) 147 return false; 148 149 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 150 if (command_line.HasSwitch(switches::kNoFirstRun)) 151 is_new_profile = false; 152 153 if (!is_new_profile) { 154 if (!HasShownPromoAtStartup(profile)) 155 return false; 156 } 157 158 if (HasUserSkippedSyncPromo(profile)) 159 return false; 160 161 // For Chinese users skip the sync promo. 162 if (g_browser_process->GetApplicationLocale() == "zh-CN") 163 return false; 164 165 PrefService* prefs = profile->GetPrefs(); 166 int show_count = prefs->GetInteger(prefs::kSyncPromoStartupCount); 167 if (show_count >= kSyncPromoShowAtStartupMaximum) 168 return false; 169 170 // This pref can be set in the master preferences file to allow or disallow 171 // showing the sync promo at startup. 172 if (prefs->HasPrefPath(prefs::kSyncPromoShowOnFirstRunAllowed)) 173 return prefs->GetBoolean(prefs::kSyncPromoShowOnFirstRunAllowed); 174 175 // For now don't show the promo for some brands. 176 if (!AllowPromoAtStartupForCurrentBrand()) 177 return false; 178 179 // Default to show the promo for Google Chrome builds. 180#if defined(GOOGLE_CHROME_BUILD) 181 return true; 182#else 183 return false; 184#endif 185} 186 187void SyncPromoUI::DidShowSyncPromoAtStartup(Profile* profile) { 188 int show_count = profile->GetPrefs()->GetInteger( 189 prefs::kSyncPromoStartupCount); 190 show_count++; 191 profile->GetPrefs()->SetInteger(prefs::kSyncPromoStartupCount, show_count); 192} 193 194bool SyncPromoUI::HasUserSkippedSyncPromo(Profile* profile) { 195 return profile->GetPrefs()->GetBoolean(prefs::kSyncPromoUserSkipped); 196} 197 198void SyncPromoUI::SetUserSkippedSyncPromo(Profile* profile) { 199 profile->GetPrefs()->SetBoolean(prefs::kSyncPromoUserSkipped, true); 200} 201 202// static 203std::string SyncPromoUI::GetSyncLandingURL(const char* option, int value) { 204 const std::string& locale = g_browser_process->GetApplicationLocale(); 205 std::string url = base::StringPrintf(kSyncLandingUrlPrefix, locale.c_str()); 206 base::StringAppendF(&url, "?%s=%d", option, value); 207 return url; 208} 209 210// static 211GURL SyncPromoUI::GetSyncPromoURL(Source source, bool auto_close) { 212 DCHECK_NE(SOURCE_UNKNOWN, source); 213 214 std::string url_string; 215 216 // Build a Gaia-based URL that can be used to sign the user into chrome. 217 // There are required request parameters: 218 // 219 // - tell Gaia which service the user is signing into. In this case, 220 // a chrome sign in uses the service "chromiumsync" 221 // - provide a continue URL. This is the URL that Gaia will redirect to 222 // once the sign is complete. 223 // 224 // The continue URL includes a source parameter that can be extracted using 225 // the function GetSourceForSyncPromoURL() below. This is used to know 226 // which of the chrome sign in access points was used to sign the user in. 227 // It is also parsed for the |auto_close| flag, which indicates that the tab 228 // must be closed after sync setup is successful. 229 // See OneClickSigninHelper for details. 230 url_string = GaiaUrls::GetInstance()->service_login_url(); 231 url_string.append("?service=chromiumsync&sarp=1"); 232 233 std::string continue_url = GetSyncLandingURL( 234 kSyncPromoQueryKeySource, static_cast<int>(source)); 235 if (auto_close) 236 base::StringAppendF(&continue_url, "&%s=1", kSyncPromoQueryKeyAutoClose); 237 238 base::StringAppendF(&url_string, "&%s=%s", kSyncPromoQueryKeyContinue, 239 net::EscapeQueryParamValue( 240 continue_url, false).c_str()); 241 242 return GURL(url_string); 243} 244 245// static 246GURL SyncPromoUI::GetNextPageURLForSyncPromoURL(const GURL& url) { 247 std::string value; 248 if (net::GetValueForKeyInQuery(url, kSyncPromoQueryKeyContinue, &value)) 249 return GURL(value); 250 251 return GURL(); 252} 253 254// static 255SyncPromoUI::Source SyncPromoUI::GetSourceForSyncPromoURL(const GURL& url) { 256 std::string value; 257 if (net::GetValueForKeyInQuery(url, kSyncPromoQueryKeySource, &value)) { 258 int source = 0; 259 if (base::StringToInt(value, &source) && source >= SOURCE_START_PAGE && 260 source < SOURCE_UNKNOWN) { 261 return static_cast<Source>(source); 262 } 263 } 264 return SOURCE_UNKNOWN; 265} 266 267// static 268bool SyncPromoUI::IsAutoCloseEnabledInURL(const GURL& url) { 269 std::string value; 270 if (net::GetValueForKeyInQuery(url, kSyncPromoQueryKeyAutoClose, &value)) { 271 int enabled = 0; 272 if (base::StringToInt(value, &enabled) && enabled == 1) 273 return true; 274 } 275 return false; 276} 277 278// static 279bool SyncPromoUI::IsContinueUrlForWebBasedSigninFlow(const GURL& url) { 280 GURL::Replacements replacements; 281 replacements.ClearQuery(); 282 const std::string& locale = g_browser_process->GetApplicationLocale(); 283 return url.ReplaceComponents(replacements) == 284 GURL(base::StringPrintf(kSyncLandingUrlPrefix, locale.c_str())); 285} 286 287// static 288void SyncPromoUI::ForceWebBasedSigninFlowForTesting(bool force) { 289 g_force_web_based_signin_flow = force; 290} 291