blob: 729d6aab5fcb1fa94b08a1130c7d95e4541e9442 [file] [log] [blame]
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +01001// 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/signin/signin_promo.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"
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010024#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"
42
43using content::WebContents;
44
45namespace {
46
47const char kStringsJsFile[] = "strings.js";
48const char kSignInPromoJsFile[] = "sync_promo.js";
49
50const char kSignInPromoQueryKeyAutoClose[] = "auto_close";
51const char kSignInPromoQueryKeyContinue[] = "continue";
52const char kSignInPromoQueryKeySource[] = "source";
53
54// Gaia cannot support about:blank as a continue URL, so using a hosted blank
55// page instead.
56const char kSignInLandingUrlPrefix[] =
57 "https://www.google.com/intl/%s/chrome/blank.html";
58
59// The maximum number of times we want to show the sign in promo at startup.
60const int kSignInPromoShowAtStartupMaximum = 10;
61
62// Forces the web based signin flow when set.
63bool g_force_web_based_signin_flow = false;
64
65// Checks we want to show the sign in promo for the given brand.
66bool AllowPromoAtStartupForCurrentBrand() {
67 std::string brand;
68 google_util::GetBrand(&brand);
69
70 if (brand.empty())
71 return true;
72
73 if (google_util::IsInternetCafeBrandCode(brand))
74 return false;
75
76 // Enable for both organic and distribution.
77 return true;
78}
79
80// Returns true if a user has seen the sign in promo at startup previously.
81bool HasShownPromoAtStartup(Profile* profile) {
Ben Murdochbb1529c2013-08-08 10:24:53 +010082 return profile->GetPrefs()->HasPrefPath(prefs::kSignInPromoStartupCount);
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010083}
84
85// Returns true if the user has previously skipped the sign in promo.
86bool HasUserSkippedPromo(Profile* profile) {
Ben Murdochbb1529c2013-08-08 10:24:53 +010087 return profile->GetPrefs()->GetBoolean(prefs::kSignInPromoUserSkipped);
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010088}
89
90} // namespace
91
92namespace signin {
93
94bool ShouldShowPromo(Profile* profile) {
95#if defined(OS_CHROMEOS)
96 // There's no need to show the sign in promo on cros since cros users are
97 // already logged in.
98 return false;
99#else
100
101 // Don't bother if we don't have any kind of network connection.
102 if (net::NetworkChangeNotifier::IsOffline())
103 return false;
104
105 // Don't show for managed profiles.
Ben Murdoch2385ea32013-08-06 11:01:04 +0100106 if (profile->IsManaged())
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100107 return false;
108
109 // Display the signin promo if the user is not signed in.
110 SigninManager* signin = SigninManagerFactory::GetForProfile(
111 profile->GetOriginalProfile());
112 return !signin->AuthInProgress() && signin->IsSigninAllowed() &&
113 signin->GetAuthenticatedUsername().empty();
114#endif
115}
116
117bool ShouldShowPromoAtStartup(Profile* profile, bool is_new_profile) {
118 DCHECK(profile);
119
120 // Don't show if the profile is an incognito.
121 if (profile->IsOffTheRecord())
122 return false;
123
124 if (!ShouldShowPromo(profile))
125 return false;
126
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100127 if (!is_new_profile) {
128 if (!HasShownPromoAtStartup(profile))
129 return false;
130 }
131
132 if (HasUserSkippedPromo(profile))
133 return false;
134
135 // For Chinese users skip the sign in promo.
136 if (g_browser_process->GetApplicationLocale() == "zh-CN")
137 return false;
138
139 PrefService* prefs = profile->GetPrefs();
Ben Murdochbb1529c2013-08-08 10:24:53 +0100140 int show_count = prefs->GetInteger(prefs::kSignInPromoStartupCount);
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100141 if (show_count >= kSignInPromoShowAtStartupMaximum)
142 return false;
143
144 // This pref can be set in the master preferences file to allow or disallow
145 // showing the sign in promo at startup.
Ben Murdochbb1529c2013-08-08 10:24:53 +0100146 if (prefs->HasPrefPath(prefs::kSignInPromoShowOnFirstRunAllowed))
147 return prefs->GetBoolean(prefs::kSignInPromoShowOnFirstRunAllowed);
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100148
149 // For now don't show the promo for some brands.
150 if (!AllowPromoAtStartupForCurrentBrand())
151 return false;
152
153 // Default to show the promo for Google Chrome builds.
154#if defined(GOOGLE_CHROME_BUILD)
155 return true;
156#else
157 return false;
158#endif
159}
160
161void DidShowPromoAtStartup(Profile* profile) {
162 int show_count = profile->GetPrefs()->GetInteger(
Ben Murdochbb1529c2013-08-08 10:24:53 +0100163 prefs::kSignInPromoStartupCount);
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100164 show_count++;
Ben Murdochbb1529c2013-08-08 10:24:53 +0100165 profile->GetPrefs()->SetInteger(prefs::kSignInPromoStartupCount, show_count);
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100166}
167
168void SetUserSkippedPromo(Profile* profile) {
Ben Murdochbb1529c2013-08-08 10:24:53 +0100169 profile->GetPrefs()->SetBoolean(prefs::kSignInPromoUserSkipped, true);
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100170}
171
172GURL GetLandingURL(const char* option, int value) {
173 const std::string& locale = g_browser_process->GetApplicationLocale();
174 std::string url = base::StringPrintf(kSignInLandingUrlPrefix, locale.c_str());
175 base::StringAppendF(&url, "?%s=%d", option, value);
176 return GURL(url);
177}
178
179GURL GetPromoURL(Source source, bool auto_close) {
180 DCHECK_NE(SOURCE_UNKNOWN, source);
181
182 std::string url_string;
183
184 // Build a Gaia-based URL that can be used to sign the user into chrome.
185 // There are required request parameters:
186 //
187 // - tell Gaia which service the user is signing into. In this case,
188 // a chrome sign in uses the service "chromiumsync"
189 // - provide a continue URL. This is the URL that Gaia will redirect to
190 // once the sign is complete.
191 //
192 // The continue URL includes a source parameter that can be extracted using
193 // the function GetSourceForSignInPromoURL() below. This is used to know
194 // which of the chrome sign in access points was used to sign the user in.
195 // It is also parsed for the |auto_close| flag, which indicates that the tab
196 // must be closed after sync setup is successful.
197 // See OneClickSigninHelper for details.
198 url_string = GaiaUrls::GetInstance()->service_login_url();
199 url_string.append("?service=chromiumsync&sarp=1");
200
201 std::string continue_url = GetLandingURL(kSignInPromoQueryKeySource,
202 static_cast<int>(source)).spec();
203 if (auto_close)
204 base::StringAppendF(&continue_url, "&%s=1", kSignInPromoQueryKeyAutoClose);
205
206 base::StringAppendF(&url_string, "&%s=%s", kSignInPromoQueryKeyContinue,
207 net::EscapeQueryParamValue(
208 continue_url, false).c_str());
209
210 return GURL(url_string);
211}
212
213GURL GetNextPageURLForPromoURL(const GURL& url) {
214 std::string value;
215 if (net::GetValueForKeyInQuery(url, kSignInPromoQueryKeyContinue, &value))
216 return GURL(value);
217
218 return GURL();
219}
220
221Source GetSourceForPromoURL(const GURL& url) {
222 std::string value;
223 if (net::GetValueForKeyInQuery(url, kSignInPromoQueryKeySource, &value)) {
224 int source = 0;
225 if (base::StringToInt(value, &source) && source >= SOURCE_START_PAGE &&
226 source < SOURCE_UNKNOWN) {
227 return static_cast<Source>(source);
228 }
229 }
230 return SOURCE_UNKNOWN;
231}
232
233bool IsAutoCloseEnabledInURL(const GURL& url) {
234 std::string value;
235 if (net::GetValueForKeyInQuery(url, kSignInPromoQueryKeyAutoClose, &value)) {
236 int enabled = 0;
237 if (base::StringToInt(value, &enabled) && enabled == 1)
238 return true;
239 }
240 return false;
241}
242
243bool IsContinueUrlForWebBasedSigninFlow(const GURL& url) {
244 GURL::Replacements replacements;
245 replacements.ClearQuery();
246 const std::string& locale = g_browser_process->GetApplicationLocale();
247 return url.ReplaceComponents(replacements) ==
248 GURL(base::StringPrintf(kSignInLandingUrlPrefix, locale.c_str()));
249}
250
251void ForceWebBasedSigninFlowForTesting(bool force) {
252 g_force_web_based_signin_flow = force;
253}
254
255void RegisterProfilePrefs(
256 user_prefs::PrefRegistrySyncable* registry) {
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100257 registry->RegisterIntegerPref(
Ben Murdochbb1529c2013-08-08 10:24:53 +0100258 prefs::kSignInPromoStartupCount,
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100259 0,
260 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
261 registry->RegisterBooleanPref(
Ben Murdochbb1529c2013-08-08 10:24:53 +0100262 prefs::kSignInPromoUserSkipped,
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100263 false,
264 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
265 registry->RegisterBooleanPref(
Ben Murdochbb1529c2013-08-08 10:24:53 +0100266 prefs::kSignInPromoShowOnFirstRunAllowed,
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100267 true,
268 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
269 registry->RegisterBooleanPref(
Ben Murdochbb1529c2013-08-08 10:24:53 +0100270 prefs::kSignInPromoShowNTPBubble,
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100271 false,
272 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100273}
274
275} // namespace signin