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.
5 #include "chrome/browser/signin/signin_promo.h"
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/theme_source.h"
25 #include "chrome/common/chrome_switches.h"
26 #include "chrome/common/net/url_util.h"
27 #include "chrome/common/pref_names.h"
28 #include "chrome/common/url_constants.h"
29 #include "components/user_prefs/pref_registry_syncable.h"
30 #include "content/public/browser/url_data_source.h"
31 #include "content/public/browser/web_contents.h"
32 #include "content/public/browser/web_ui.h"
33 #include "content/public/browser/web_ui_data_source.h"
34 #include "google_apis/gaia/gaia_urls.h"
35 #include "grit/browser_resources.h"
36 #include "grit/generated_resources.h"
37 #include "grit/theme_resources.h"
38 #include "net/base/escape.h"
39 #include "net/base/network_change_notifier.h"
40 #include "net/base/url_util.h"
41 #include "ui/base/l10n/l10n_util.h"
43 using content::WebContents;
47 const char kSignInPromoQueryKeyAutoClose[] = "auto_close";
48 const char kSignInPromoQueryKeyContinue[] = "continue";
49 const char kSignInPromoQueryKeySource[] = "source";
51 // Gaia cannot support about:blank as a continue URL, so using a hosted blank
53 const char kSignInLandingUrlPrefix[] =
54 "https://www.google.com/intl/%s/chrome/blank.html";
56 // The maximum number of times we want to show the sign in promo at startup.
57 const int kSignInPromoShowAtStartupMaximum = 10;
59 // Forces the web based signin flow when set.
60 bool g_force_web_based_signin_flow = false;
62 // Checks we want to show the sign in promo for the given brand.
63 bool AllowPromoAtStartupForCurrentBrand() {
65 google_util::GetBrand(&brand);
70 if (google_util::IsInternetCafeBrandCode(brand))
73 // Enable for both organic and distribution.
77 // Returns true if a user has seen the sign in promo at startup previously.
78 bool HasShownPromoAtStartup(Profile* profile) {
79 return profile->GetPrefs()->HasPrefPath(prefs::kSignInPromoStartupCount);
82 // Returns true if the user has previously skipped the sign in promo.
83 bool HasUserSkippedPromo(Profile* profile) {
84 return profile->GetPrefs()->GetBoolean(prefs::kSignInPromoUserSkipped);
91 bool ShouldShowPromo(Profile* profile) {
92 #if defined(OS_CHROMEOS)
93 // There's no need to show the sign in promo on cros since cros users are
98 // Don't bother if we don't have any kind of network connection.
99 if (net::NetworkChangeNotifier::IsOffline())
102 // Don't show for managed profiles.
103 if (profile->IsManaged())
106 // Display the signin promo if the user is not signed in.
107 SigninManager* signin = SigninManagerFactory::GetForProfile(
108 profile->GetOriginalProfile());
109 return !signin->AuthInProgress() && signin->IsSigninAllowed() &&
110 signin->GetAuthenticatedUsername().empty();
114 bool ShouldShowPromoAtStartup(Profile* profile, bool is_new_profile) {
117 // Don't show if the profile is an incognito.
118 if (profile->IsOffTheRecord())
121 if (!ShouldShowPromo(profile))
124 if (!is_new_profile) {
125 if (!HasShownPromoAtStartup(profile))
129 if (HasUserSkippedPromo(profile))
132 // For Chinese users skip the sign in promo.
133 if (g_browser_process->GetApplicationLocale() == "zh-CN")
136 PrefService* prefs = profile->GetPrefs();
137 int show_count = prefs->GetInteger(prefs::kSignInPromoStartupCount);
138 if (show_count >= kSignInPromoShowAtStartupMaximum)
141 // This pref can be set in the master preferences file to allow or disallow
142 // showing the sign in promo at startup.
143 if (prefs->HasPrefPath(prefs::kSignInPromoShowOnFirstRunAllowed))
144 return prefs->GetBoolean(prefs::kSignInPromoShowOnFirstRunAllowed);
146 // For now don't show the promo for some brands.
147 if (!AllowPromoAtStartupForCurrentBrand())
150 // Default to show the promo for Google Chrome builds.
151 #if defined(GOOGLE_CHROME_BUILD)
158 void DidShowPromoAtStartup(Profile* profile) {
159 int show_count = profile->GetPrefs()->GetInteger(
160 prefs::kSignInPromoStartupCount);
162 profile->GetPrefs()->SetInteger(prefs::kSignInPromoStartupCount, show_count);
165 void SetUserSkippedPromo(Profile* profile) {
166 profile->GetPrefs()->SetBoolean(prefs::kSignInPromoUserSkipped, true);
169 GURL GetLandingURL(const char* option, int value) {
170 const std::string& locale = g_browser_process->GetApplicationLocale();
171 std::string url = base::StringPrintf(kSignInLandingUrlPrefix, locale.c_str());
172 base::StringAppendF(&url, "?%s=%d", option, value);
176 GURL GetPromoURL(Source source, bool auto_close) {
177 DCHECK_NE(SOURCE_UNKNOWN, source);
179 bool enable_inline = CommandLine::ForCurrentProcess()->HasSwitch(
180 switches::kEnableInlineSignin);
182 std::string url(chrome::kChromeUIInlineLoginURL);
183 base::StringAppendF(&url, "?%s=%d", kSignInPromoQueryKeySource, source);
186 &url, "&%s=1", kSignInPromoQueryKeyAutoClose);
190 // Build a Gaia-based URL that can be used to sign the user into chrome.
191 // There are required request parameters:
193 // - tell Gaia which service the user is signing into. In this case,
194 // a chrome sign in uses the service "chromiumsync"
195 // - provide a continue URL. This is the URL that Gaia will redirect to
196 // once the sign is complete.
198 // The continue URL includes a source parameter that can be extracted using
199 // the function GetSourceForSignInPromoURL() below. This is used to know
200 // which of the chrome sign in access points was used to sign the user in.
201 // It is also parsed for the |auto_close| flag, which indicates that the tab
202 // must be closed after sync setup is successful.
203 // See OneClickSigninHelper for details.
204 std::string query_string = "?service=chromiumsync&sarp=1";
206 std::string continue_url = GetLandingURL(kSignInPromoQueryKeySource,
207 static_cast<int>(source)).spec();
209 base::StringAppendF(&continue_url, "&%s=1", kSignInPromoQueryKeyAutoClose);
211 base::StringAppendF(&query_string, "&%s=%s", kSignInPromoQueryKeyContinue,
212 net::EscapeQueryParamValue(
213 continue_url, false).c_str());
215 return GaiaUrls::GetInstance()->service_login_url().Resolve(query_string);
218 GURL GetNextPageURLForPromoURL(const GURL& url) {
220 if (net::GetValueForKeyInQuery(url, kSignInPromoQueryKeyContinue, &value))
226 Source GetSourceForPromoURL(const GURL& url) {
228 if (net::GetValueForKeyInQuery(url, kSignInPromoQueryKeySource, &value)) {
230 if (base::StringToInt(value, &source) && source >= SOURCE_START_PAGE &&
231 source < SOURCE_UNKNOWN) {
232 return static_cast<Source>(source);
235 return SOURCE_UNKNOWN;
238 bool IsAutoCloseEnabledInURL(const GURL& url) {
240 if (net::GetValueForKeyInQuery(url, kSignInPromoQueryKeyAutoClose, &value)) {
242 if (base::StringToInt(value, &enabled) && enabled == 1)
248 bool IsContinueUrlForWebBasedSigninFlow(const GURL& url) {
249 GURL::Replacements replacements;
250 replacements.ClearQuery();
251 const std::string& locale = g_browser_process->GetApplicationLocale();
252 return url.ReplaceComponents(replacements) ==
253 GURL(base::StringPrintf(kSignInLandingUrlPrefix, locale.c_str()));
256 void ForceWebBasedSigninFlowForTesting(bool force) {
257 g_force_web_based_signin_flow = force;
260 void RegisterProfilePrefs(
261 user_prefs::PrefRegistrySyncable* registry) {
262 registry->RegisterIntegerPref(
263 prefs::kSignInPromoStartupCount,
265 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
266 registry->RegisterBooleanPref(
267 prefs::kSignInPromoUserSkipped,
269 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
270 registry->RegisterBooleanPref(
271 prefs::kSignInPromoShowOnFirstRunAllowed,
273 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
274 registry->RegisterBooleanPref(
275 prefs::kSignInPromoShowNTPBubble,
277 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
280 } // namespace signin