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