blob: e7a6fcc4a2f680b124abc4cb2c6911fed8dd3b2a [file] [log] [blame]
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001// 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/first_run/first_run.h"
6
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00007#include <algorithm>
8
Torne (Richard Coles)58218062012-11-14 11:43:16 +00009#include "base/command_line.h"
10#include "base/compiler_specific.h"
11#include "base/file_util.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010012#include "base/files/file_path.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000013#include "base/lazy_instance.h"
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010014#include "base/memory/ref_counted.h"
Ben Murdochca12bfa2013-07-23 11:17:05 +010015#include "base/message_loop/message_loop.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000016#include "base/metrics/histogram.h"
17#include "base/path_service.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000018#include "base/prefs/pref_service.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010019#include "base/strings/stringprintf.h"
20#include "base/strings/utf_string_conversions.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000021#include "build/build_config.h"
22#include "chrome/browser/browser_process.h"
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010023#include "chrome/browser/chrome_notification_types.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000024#include "chrome/browser/extensions/extension_service.h"
25#include "chrome/browser/extensions/updater/extension_updater.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000026#include "chrome/browser/first_run/first_run_internal.h"
27#include "chrome/browser/google/google_util.h"
28#include "chrome/browser/importer/external_process_importer_host.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000029#include "chrome/browser/importer/importer_list.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000030#include "chrome/browser/importer/importer_progress_observer.h"
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010031#include "chrome/browser/importer/importer_uma.h"
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010032#include "chrome/browser/importer/profile_writer.h"
Ben Murdoch9ab55632013-07-18 11:57:30 +010033#include "chrome/browser/profiles/profiles_state.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000034#include "chrome/browser/search_engines/template_url_service.h"
35#include "chrome/browser/search_engines/template_url_service_factory.h"
36#include "chrome/browser/shell_integration.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010037#include "chrome/browser/signin/signin_manager.h"
38#include "chrome/browser/signin/signin_manager_factory.h"
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010039#include "chrome/browser/signin/signin_promo.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010040#include "chrome/browser/signin/signin_tracker.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000041#include "chrome/browser/ui/browser.h"
42#include "chrome/browser/ui/browser_finder.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000043#include "chrome/browser/ui/global_error/global_error_service.h"
44#include "chrome/browser/ui/global_error/global_error_service_factory.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000045#include "chrome/browser/ui/tabs/tab_strip_model.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000046#include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
47#include "chrome/common/chrome_paths.h"
48#include "chrome/common/chrome_switches.h"
49#include "chrome/common/pref_names.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000050#include "chrome/common/url_constants.h"
51#include "chrome/installer/util/master_preferences.h"
52#include "chrome/installer/util/master_preferences_constants.h"
53#include "chrome/installer/util/util_constants.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000054#include "components/user_prefs/pref_registry_syncable.h"
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010055#include "content/public/browser/notification_observer.h"
56#include "content/public/browser/notification_registrar.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000057#include "content/public/browser/notification_service.h"
58#include "content/public/browser/notification_types.h"
59#include "content/public/browser/user_metrics.h"
60#include "content/public/browser/web_contents.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000061#include "google_apis/gaia/gaia_auth_util.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010062#include "url/gurl.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000063
64using content::UserMetricsAction;
65
66namespace {
67
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010068// A bitfield formed from values in AutoImportState to record the state of
69// AutoImport. This is used in testing to verify import startup actions that
70// occur before an observer can be registered in the test.
71uint16 g_auto_import_state = first_run::AUTO_IMPORT_NONE;
72
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000073// Flags for functions of similar name.
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010074bool g_should_show_welcome_page = false;
75bool g_should_do_autofill_personal_data_manager_first_run = false;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000076
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010077// This class acts as an observer for the ImporterProgressObserver::ImportEnded
78// callback. When the import process is started, certain errors may cause
79// ImportEnded() to be called synchronously, but the typical case is that
80// ImportEnded() is called asynchronously. Thus we have to handle both cases.
81class ImportEndedObserver : public importer::ImporterProgressObserver {
82 public:
83 ImportEndedObserver() : ended_(false),
84 should_quit_message_loop_(false) {}
85 virtual ~ImportEndedObserver() {}
86
87 // importer::ImporterProgressObserver:
88 virtual void ImportStarted() OVERRIDE {}
89 virtual void ImportItemStarted(importer::ImportItem item) OVERRIDE {}
90 virtual void ImportItemEnded(importer::ImportItem item) OVERRIDE {}
91 virtual void ImportEnded() OVERRIDE {
92 ended_ = true;
93 if (should_quit_message_loop_)
94 base::MessageLoop::current()->Quit();
95 }
96
97 void set_should_quit_message_loop() {
98 should_quit_message_loop_ = true;
99 }
100
101 bool ended() const {
102 return ended_;
103 }
104
105 private:
106 // Set if the import has ended.
107 bool ended_;
108
109 bool should_quit_message_loop_;
110};
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000111
112// Helper class that performs delayed first-run tasks that need more of the
113// chrome infrastructure to be up and running before they can be attempted.
114class FirstRunDelayedTasks : public content::NotificationObserver {
115 public:
116 enum Tasks {
117 NO_TASK,
118 INSTALL_EXTENSIONS
119 };
120
121 explicit FirstRunDelayedTasks(Tasks task) {
122 if (task == INSTALL_EXTENSIONS) {
123 registrar_.Add(this, chrome::NOTIFICATION_EXTENSIONS_READY,
124 content::NotificationService::AllSources());
125 }
126 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED,
127 content::NotificationService::AllSources());
128 }
129
130 virtual void Observe(int type,
131 const content::NotificationSource& source,
132 const content::NotificationDetails& details) OVERRIDE {
133 // After processing the notification we always delete ourselves.
134 if (type == chrome::NOTIFICATION_EXTENSIONS_READY) {
135 DoExtensionWork(
136 content::Source<Profile>(source).ptr()->GetExtensionService());
137 }
138 delete this;
139 }
140
141 private:
142 // Private ctor forces it to be created only in the heap.
143 virtual ~FirstRunDelayedTasks() {}
144
145 // The extension work is to basically trigger an extension update check.
146 // If the extension specified in the master pref is older than the live
147 // extension it will get updated which is the same as get it installed.
148 void DoExtensionWork(ExtensionService* service) {
149 if (service)
150 service->updater()->CheckNow(extensions::ExtensionUpdater::CheckParams());
151 }
152
153 content::NotificationRegistrar registrar_;
154};
155
156// Installs a task to do an extensions update check once the extensions system
157// is running.
158void DoDelayedInstallExtensions() {
159 new FirstRunDelayedTasks(FirstRunDelayedTasks::INSTALL_EXTENSIONS);
160}
161
162void DoDelayedInstallExtensionsIfNeeded(
163 installer::MasterPreferences* install_prefs) {
164 DictionaryValue* extensions = 0;
165 if (install_prefs->GetExtensionsBlock(&extensions)) {
166 VLOG(1) << "Extensions block found in master preferences";
167 DoDelayedInstallExtensions();
168 }
169}
170
171base::FilePath GetDefaultPrefFilePath(bool create_profile_dir,
172 const base::FilePath& user_data_dir) {
173 base::FilePath default_pref_dir =
Ben Murdoch9ab55632013-07-18 11:57:30 +0100174 profiles::GetDefaultProfileDir(user_data_dir);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000175 if (create_profile_dir) {
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100176 if (!base::PathExists(default_pref_dir)) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000177 if (!file_util::CreateDirectory(default_pref_dir))
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000178 return base::FilePath();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000179 }
180 }
Ben Murdoch9ab55632013-07-18 11:57:30 +0100181 return profiles::GetProfilePrefsPath(default_pref_dir);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000182}
183
184// Sets the |items| bitfield according to whether the import data specified by
185// |import_type| should be be auto imported or not.
186void SetImportItem(PrefService* user_prefs,
187 const char* pref_path,
188 int import_items,
189 int dont_import_items,
190 importer::ImportItem import_type,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100191 int* items) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000192 // Work out whether an item is to be imported according to what is specified
193 // in master preferences.
194 bool should_import = false;
195 bool master_pref_set =
196 ((import_items | dont_import_items) & import_type) != 0;
197 bool master_pref = ((import_items & ~dont_import_items) & import_type) != 0;
198
199 if (import_type == importer::HISTORY ||
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100200 (import_type != importer::FAVORITES &&
201 first_run::internal::IsOrganicFirstRun())) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000202 // History is always imported unless turned off in master_preferences.
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100203 // Search engines and home page are imported in organic builds only
204 // unless turned off in master_preferences.
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000205 should_import = !master_pref_set || master_pref;
206 } else {
207 // Bookmarks are never imported, unless turned on in master_preferences.
208 // Search engine and home page import behaviour is similar in non organic
209 // builds.
210 should_import = master_pref_set && master_pref;
211 }
212
213 // If an import policy is set, import items according to policy. If no master
214 // preference is set, but a corresponding recommended policy is set, import
215 // item according to recommended policy. If both a master preference and a
216 // recommended policy is set, the master preference wins. If neither
217 // recommended nor managed policies are set, import item according to what we
218 // worked out above.
219 if (master_pref_set)
220 user_prefs->SetBoolean(pref_path, should_import);
221
222 if (!user_prefs->FindPreference(pref_path)->IsDefaultValue()) {
223 if (user_prefs->GetBoolean(pref_path))
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100224 *items |= import_type;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000225 } else { // no policy (recommended or managed) is set
226 if (should_import)
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100227 *items |= import_type;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000228 }
229
230 user_prefs->ClearPref(pref_path);
231}
232
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100233// Launches the import, via |importer_host|, from |source_profile| into
234// |target_profile| for the items specified in the |items_to_import| bitfield.
235// This may be done in a separate process depending on the platform, but it will
236// always block until done.
Ben Murdocheb525c52013-07-10 11:40:50 +0100237void ImportFromSourceProfile(ExternalProcessImporterHost* importer_host,
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100238 const importer::SourceProfile& source_profile,
239 Profile* target_profile,
240 uint16 items_to_import) {
241 ImportEndedObserver observer;
Ben Murdocheb525c52013-07-10 11:40:50 +0100242 importer_host->set_observer(&observer);
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100243 importer_host->StartImportSettings(source_profile,
244 target_profile,
245 items_to_import,
246 new ProfileWriter(target_profile));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100247 // If the import process has not errored out, block on it.
248 if (!observer.ended()) {
249 observer.set_should_quit_message_loop();
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100250 base::MessageLoop::current()->Run();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100251 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000252}
253
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100254// Imports bookmarks from an html file whose path is provided by
255// |import_bookmarks_path|.
256void ImportFromFile(Profile* profile,
Ben Murdocheb525c52013-07-10 11:40:50 +0100257 ExternalProcessImporterHost* file_importer_host,
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100258 const std::string& import_bookmarks_path) {
259 importer::SourceProfile source_profile;
260 source_profile.importer_type = importer::TYPE_BOOKMARKS_FILE;
261
262 const base::FilePath::StringType& import_bookmarks_path_str =
263#if defined(OS_WIN)
264 UTF8ToUTF16(import_bookmarks_path);
265#else
266 import_bookmarks_path;
267#endif
268 source_profile.source_path = base::FilePath(import_bookmarks_path_str);
269
270 ImportFromSourceProfile(file_importer_host, source_profile, profile,
271 importer::FAVORITES);
272 g_auto_import_state |= first_run::AUTO_IMPORT_BOOKMARKS_FILE_IMPORTED;
273}
274
275// Imports settings from the first profile in |importer_list|.
276void ImportSettings(Profile* profile,
Ben Murdocheb525c52013-07-10 11:40:50 +0100277 ExternalProcessImporterHost* importer_host,
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100278 scoped_refptr<ImporterList> importer_list,
279 int items_to_import) {
280 const importer::SourceProfile& source_profile =
281 importer_list->GetSourceProfileAt(0);
282
283 // Ensure that importers aren't requested to import items that they do not
284 // support. If there is no overlap, skip.
285 items_to_import &= source_profile.services_supported;
286 if (items_to_import == 0)
287 return;
288
289 ImportFromSourceProfile(importer_host, source_profile, profile,
290 items_to_import);
291 g_auto_import_state |= first_run::AUTO_IMPORT_PROFILE_IMPORTED;
292}
293
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000294GURL UrlFromString(const std::string& in) {
295 return GURL(in);
296}
297
298void ConvertStringVectorToGURLVector(
299 const std::vector<std::string>& src,
300 std::vector<GURL>* ret) {
301 ret->resize(src.size());
302 std::transform(src.begin(), src.end(), ret->begin(), &UrlFromString);
303}
304
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100305// Show the first run search engine bubble at the first appropriate opportunity.
306// This bubble may be delayed by other UI, like global errors and sync promos.
307class FirstRunBubbleLauncher : public content::NotificationObserver {
308 public:
309 // Show the bubble at the first appropriate opportunity. This function
310 // instantiates a FirstRunBubbleLauncher, which manages its own lifetime.
311 static void ShowFirstRunBubbleSoon();
312
313 private:
314 FirstRunBubbleLauncher();
315 virtual ~FirstRunBubbleLauncher();
316
317 // content::NotificationObserver:
318 virtual void Observe(int type,
319 const content::NotificationSource& source,
320 const content::NotificationDetails& details) OVERRIDE;
321
322 content::NotificationRegistrar registrar_;
323
324 DISALLOW_COPY_AND_ASSIGN(FirstRunBubbleLauncher);
325};
326
327// static
328void FirstRunBubbleLauncher::ShowFirstRunBubbleSoon() {
329 SetShowFirstRunBubblePref(first_run::FIRST_RUN_BUBBLE_SHOW);
330 // This FirstRunBubbleLauncher instance will manage its own lifetime.
331 new FirstRunBubbleLauncher();
332}
333
334FirstRunBubbleLauncher::FirstRunBubbleLauncher() {
335 registrar_.Add(this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
336 content::NotificationService::AllSources());
337
338 // This notification is required to observe the switch between the sync setup
339 // page and the general settings page.
340 registrar_.Add(this, chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
341 content::NotificationService::AllSources());
342}
343
344FirstRunBubbleLauncher::~FirstRunBubbleLauncher() {}
345
346void FirstRunBubbleLauncher::Observe(
347 int type,
348 const content::NotificationSource& source,
349 const content::NotificationDetails& details) {
350 DCHECK(type == content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME ||
351 type == chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED);
352
353 Browser* browser = chrome::FindBrowserWithWebContents(
354 content::Source<content::WebContents>(source).ptr());
355 if (!browser || !browser->is_type_tabbed())
356 return;
357
358 // Check the preference to determine if the bubble should be shown.
359 PrefService* prefs = g_browser_process->local_state();
360 if (!prefs || prefs->GetInteger(prefs::kShowFirstRunBubbleOption) !=
361 first_run::FIRST_RUN_BUBBLE_SHOW) {
362 delete this;
363 return;
364 }
365
366 content::WebContents* contents =
367 browser->tab_strip_model()->GetActiveWebContents();
368
369 // Suppress the first run bubble if a Gaia sign in page, the continue
370 // URL for the sign in page or the sync setup page is showing.
371 if (contents &&
372 (gaia::IsGaiaSignonRealm(contents->GetURL().GetOrigin()) ||
373 signin::IsContinueUrlForWebBasedSigninFlow(contents->GetURL()) ||
374 contents->GetURL() == GURL(std::string(chrome::kChromeUISettingsURL) +
375 chrome::kSyncSetupSubPage))) {
376 return;
377 }
378
379 if (contents && contents->GetURL().SchemeIs(chrome::kChromeUIScheme)) {
380 // Suppress the first run bubble if 'make chrome metro' flow is showing.
381 if (contents->GetURL().host() == chrome::kChromeUIMetroFlowHost)
382 return;
383
384 // Suppress the first run bubble if the NTP sync promo bubble is showing
385 // or if sign in is in progress.
386 if (contents->GetURL().host() == chrome::kChromeUINewTabHost) {
387 Profile* profile =
388 Profile::FromBrowserContext(contents->GetBrowserContext());
389 SigninManagerBase* manager =
390 SigninManagerFactory::GetForProfile(profile);
391 bool signin_in_progress = manager &&
392 (!manager->GetAuthenticatedUsername().empty() &&
393 SigninTracker::GetSigninState(profile, NULL) !=
394 SigninTracker::SIGNIN_COMPLETE);
395 bool is_promo_bubble_visible =
Ben Murdochbb1529c2013-08-08 10:24:53 +0100396 profile->GetPrefs()->GetBoolean(prefs::kSignInPromoShowNTPBubble);
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100397
398 if (is_promo_bubble_visible || signin_in_progress)
399 return;
400 }
401 }
402
403 // Suppress the first run bubble if a global error bubble is pending.
404 GlobalErrorService* global_error_service =
405 GlobalErrorServiceFactory::GetForProfile(browser->profile());
406 if (global_error_service->GetFirstGlobalErrorWithBubbleView() != NULL)
407 return;
408
409 // Reset the preference and notifications to avoid showing the bubble again.
410 prefs->SetInteger(prefs::kShowFirstRunBubbleOption,
411 first_run::FIRST_RUN_BUBBLE_DONT_SHOW);
412
413 // Show the bubble now and destroy this bubble launcher.
414 browser->ShowFirstRunBubble();
415 delete this;
416}
417
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000418} // namespace
419
420namespace first_run {
421namespace internal {
422
423FirstRunState first_run_ = FIRST_RUN_UNKNOWN;
424
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000425static base::LazyInstance<base::FilePath> master_prefs_path_for_testing
426 = LAZY_INSTANCE_INITIALIZER;
427
428installer::MasterPreferences*
429 LoadMasterPrefs(base::FilePath* master_prefs_path) {
430 if (!master_prefs_path_for_testing.Get().empty())
431 *master_prefs_path = master_prefs_path_for_testing.Get();
432 else
433 *master_prefs_path = base::FilePath(MasterPrefsPath());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000434 if (master_prefs_path->empty())
435 return NULL;
436 installer::MasterPreferences* install_prefs =
437 new installer::MasterPreferences(*master_prefs_path);
438 if (!install_prefs->read_from_file()) {
439 delete install_prefs;
440 return NULL;
441 }
442
443 return install_prefs;
444}
445
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000446bool CopyPrefFile(const base::FilePath& user_data_dir,
447 const base::FilePath& master_prefs_path) {
448 base::FilePath user_prefs = GetDefaultPrefFilePath(true, user_data_dir);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000449 if (user_prefs.empty())
450 return false;
451
452 // The master prefs are regular prefs so we can just copy the file
453 // to the default place and they just work.
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100454 return base::CopyFile(master_prefs_path, user_prefs);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000455}
456
457void SetupMasterPrefsFromInstallPrefs(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000458 const installer::MasterPreferences& install_prefs,
459 MasterPrefs* out_prefs) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100460 ConvertStringVectorToGURLVector(
461 install_prefs.GetFirstRunTabs(), &out_prefs->new_tabs);
462
463 install_prefs.GetInt(installer::master_preferences::kDistroPingDelay,
464 &out_prefs->ping_delay);
465
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000466 bool value = false;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000467 if (install_prefs.GetBool(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000468 installer::master_preferences::kDistroImportSearchPref, &value)) {
469 if (value) {
470 out_prefs->do_import_items |= importer::SEARCH_ENGINES;
471 } else {
472 out_prefs->dont_import_items |= importer::SEARCH_ENGINES;
473 }
474 }
475
476 // If we're suppressing the first-run bubble, set that preference now.
477 // Otherwise, wait until the user has completed first run to set it, so the
478 // user is guaranteed to see the bubble iff he or she has completed the first
479 // run process.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000480 if (install_prefs.GetBool(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000481 installer::master_preferences::kDistroSuppressFirstRunBubble,
482 &value) && value)
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000483 SetShowFirstRunBubblePref(FIRST_RUN_BUBBLE_SUPPRESS);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000484
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000485 if (install_prefs.GetBool(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000486 installer::master_preferences::kDistroImportHistoryPref,
487 &value)) {
488 if (value) {
489 out_prefs->do_import_items |= importer::HISTORY;
490 } else {
491 out_prefs->dont_import_items |= importer::HISTORY;
492 }
493 }
494
495 std::string not_used;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000496 out_prefs->homepage_defined = install_prefs.GetString(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000497 prefs::kHomePage, &not_used);
498
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000499 if (install_prefs.GetBool(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000500 installer::master_preferences::kDistroImportHomePagePref,
501 &value)) {
502 if (value) {
503 out_prefs->do_import_items |= importer::HOME_PAGE;
504 } else {
505 out_prefs->dont_import_items |= importer::HOME_PAGE;
506 }
507 }
508
509 // Bookmarks are never imported unless specifically turned on.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000510 if (install_prefs.GetBool(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000511 installer::master_preferences::kDistroImportBookmarksPref,
512 &value)) {
513 if (value)
514 out_prefs->do_import_items |= importer::FAVORITES;
515 else
516 out_prefs->dont_import_items |= importer::FAVORITES;
517 }
518
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000519 if (install_prefs.GetBool(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000520 installer::master_preferences::kMakeChromeDefaultForUser,
521 &value) && value) {
522 out_prefs->make_chrome_default = true;
523 }
524
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000525 if (install_prefs.GetBool(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000526 installer::master_preferences::kSuppressFirstRunDefaultBrowserPrompt,
527 &value) && value) {
528 out_prefs->suppress_first_run_default_browser_prompt = true;
529 }
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000530
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100531 install_prefs.GetString(
532 installer::master_preferences::kDistroImportBookmarksFromFilePref,
533 &out_prefs->import_bookmarks_path);
534
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000535 out_prefs->variations_seed = install_prefs.GetVariationsSeed();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100536
537 install_prefs.GetString(
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100538 installer::master_preferences::kDistroSuppressDefaultBrowserPromptPref,
539 &out_prefs->suppress_default_browser_prompt_for_version);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000540}
541
542void SetDefaultBrowser(installer::MasterPreferences* install_prefs){
543 // Even on the first run we only allow for the user choice to take effect if
544 // no policy has been set by the admin.
545 if (!g_browser_process->local_state()->IsManagedPreference(
546 prefs::kDefaultBrowserSettingEnabled)) {
547 bool value = false;
548 if (install_prefs->GetBool(
549 installer::master_preferences::kMakeChromeDefaultForUser,
550 &value) && value) {
551 ShellIntegration::SetAsDefaultBrowser();
552 }
553 } else {
554 if (g_browser_process->local_state()->GetBoolean(
555 prefs::kDefaultBrowserSettingEnabled)) {
556 ShellIntegration::SetAsDefaultBrowser();
557 }
558 }
559}
560
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100561bool CreateSentinel() {
562 base::FilePath first_run_sentinel;
563 if (!internal::GetFirstRunSentinelFilePath(&first_run_sentinel))
564 return false;
565 return file_util::WriteFile(first_run_sentinel, "", 0) != -1;
566}
567
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000568// -- Platform-specific functions --
569
570#if !defined(OS_LINUX) && !defined(OS_BSD)
571bool IsOrganicFirstRun() {
572 std::string brand;
573 google_util::GetBrand(&brand);
574 return google_util::IsOrganicFirstRun(brand);
575}
576#endif
577
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000578} // namespace internal
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000579
580MasterPrefs::MasterPrefs()
581 : ping_delay(0),
582 homepage_defined(false),
583 do_import_items(0),
584 dont_import_items(0),
585 make_chrome_default(false),
586 suppress_first_run_default_browser_prompt(false) {
587}
588
589MasterPrefs::~MasterPrefs() {}
590
591bool IsChromeFirstRun() {
592 if (internal::first_run_ != internal::FIRST_RUN_UNKNOWN)
593 return internal::first_run_ == internal::FIRST_RUN_TRUE;
594
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100595 internal::first_run_ = internal::FIRST_RUN_FALSE;
596
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000597 base::FilePath first_run_sentinel;
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100598 const CommandLine* command_line = CommandLine::ForCurrentProcess();
599 if (command_line->HasSwitch(switches::kForceFirstRun)) {
600 internal::first_run_ = internal::FIRST_RUN_TRUE;
601 } else if (command_line->HasSwitch(switches::kNoFirstRun)) {
602 internal::first_run_ = internal::FIRST_RUN_CANCEL;
603 } else if (internal::GetFirstRunSentinelFilePath(&first_run_sentinel) &&
604 !base::PathExists(first_run_sentinel)) {
605 internal::first_run_ = internal::FIRST_RUN_TRUE;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000606 }
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100607
608 return internal::first_run_ == internal::FIRST_RUN_TRUE;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000609}
610
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100611void CreateSentinelIfNeeded() {
612 if (IsChromeFirstRun() ||
613 internal::first_run_ == internal::FIRST_RUN_CANCEL) {
614 internal::CreateSentinel();
615 }
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000616}
617
618std::string GetPingDelayPrefName() {
619 return base::StringPrintf("%s.%s",
620 installer::master_preferences::kDistroDict,
621 installer::master_preferences::kDistroPingDelay);
622}
623
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100624void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100625 registry->RegisterIntegerPref(
626 GetPingDelayPrefName().c_str(),
627 0,
628 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000629}
630
631bool RemoveSentinel() {
632 base::FilePath first_run_sentinel;
633 if (!internal::GetFirstRunSentinelFilePath(&first_run_sentinel))
634 return false;
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100635 return base::DeleteFile(first_run_sentinel, false);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000636}
637
638bool SetShowFirstRunBubblePref(FirstRunBubbleOptions show_bubble_option) {
639 PrefService* local_state = g_browser_process->local_state();
640 if (!local_state)
641 return false;
642 if (local_state->GetInteger(
643 prefs::kShowFirstRunBubbleOption) != FIRST_RUN_BUBBLE_SUPPRESS) {
644 // Set the new state as long as the bubble wasn't explicitly suppressed
645 // already.
646 local_state->SetInteger(prefs::kShowFirstRunBubbleOption,
647 show_bubble_option);
648 }
649 return true;
650}
651
652void SetShouldShowWelcomePage() {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100653 g_should_show_welcome_page = true;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000654}
655
656bool ShouldShowWelcomePage() {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100657 bool retval = g_should_show_welcome_page;
658 g_should_show_welcome_page = false;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000659 return retval;
660}
661
662void SetShouldDoPersonalDataManagerFirstRun() {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100663 g_should_do_autofill_personal_data_manager_first_run = true;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000664}
665
666bool ShouldDoPersonalDataManagerFirstRun() {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100667 bool retval = g_should_do_autofill_personal_data_manager_first_run;
668 g_should_do_autofill_personal_data_manager_first_run = false;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000669 return retval;
670}
671
672void LogFirstRunMetric(FirstRunBubbleMetric metric) {
673 UMA_HISTOGRAM_ENUMERATION("FirstRun.SearchEngineBubble", metric,
674 NUM_FIRST_RUN_BUBBLE_METRICS);
675}
676
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000677void SetMasterPrefsPathForTesting(const base::FilePath& master_prefs) {
678 internal::master_prefs_path_for_testing.Get() = master_prefs;
679}
680
681ProcessMasterPreferencesResult ProcessMasterPreferences(
682 const base::FilePath& user_data_dir,
683 MasterPrefs* out_prefs) {
684 DCHECK(!user_data_dir.empty());
685
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000686 base::FilePath master_prefs_path;
687 scoped_ptr<installer::MasterPreferences>
688 install_prefs(internal::LoadMasterPrefs(&master_prefs_path));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000689
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100690 // Default value in case master preferences is missing or corrupt, or
691 // ping_delay is missing.
692 out_prefs->ping_delay = 90;
693 if (install_prefs.get()) {
694 if (!internal::ShowPostInstallEULAIfNeeded(install_prefs.get()))
695 return EULA_EXIT_NOW;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000696
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100697 if (!internal::CopyPrefFile(user_data_dir, master_prefs_path))
698 DLOG(ERROR) << "Failed to copy master_preferences to user data dir.";
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000699
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100700 DoDelayedInstallExtensionsIfNeeded(install_prefs.get());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000701
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100702 internal::SetupMasterPrefsFromInstallPrefs(*install_prefs, out_prefs);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000703
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100704 internal::SetDefaultBrowser(install_prefs.get());
705 }
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000706
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100707 return FIRST_RUN_PROCEED;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000708}
709
710void AutoImport(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000711 Profile* profile,
712 bool homepage_defined,
713 int import_items,
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100714 int dont_import_items,
715 const std::string& import_bookmarks_path) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100716 // Deletes itself.
Ben Murdocheb525c52013-07-10 11:40:50 +0100717 ExternalProcessImporterHost* importer_host = new ExternalProcessImporterHost;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000718
719 base::FilePath local_state_path;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000720 PathService::Get(chrome::FILE_LOCAL_STATE, &local_state_path);
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100721 bool local_state_file_exists = base::PathExists(local_state_path);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000722
Ben Murdocheb525c52013-07-10 11:40:50 +0100723 scoped_refptr<ImporterList> importer_list(new ImporterList());
724 importer_list->DetectSourceProfilesHack(
725 g_browser_process->GetApplicationLocale());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000726
727 // Do import if there is an available profile for us to import.
728 if (importer_list->count() > 0) {
729 // Don't show the warning dialog if import fails.
730 importer_host->set_headless();
731 int items = 0;
732
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000733 if (internal::IsOrganicFirstRun()) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000734 // Home page is imported in organic builds only unless turned off or
735 // defined in master_preferences.
736 if (homepage_defined) {
737 dont_import_items |= importer::HOME_PAGE;
738 if (import_items & importer::HOME_PAGE)
739 import_items &= ~importer::HOME_PAGE;
740 }
741 // Search engines are not imported automatically in organic builds if the
742 // user already has a user preferences directory.
743 if (local_state_file_exists) {
744 dont_import_items |= importer::SEARCH_ENGINES;
745 if (import_items & importer::SEARCH_ENGINES)
746 import_items &= ~importer::SEARCH_ENGINES;
747 }
748 }
749
750 PrefService* user_prefs = profile->GetPrefs();
751
752 SetImportItem(user_prefs,
753 prefs::kImportHistory,
754 import_items,
755 dont_import_items,
756 importer::HISTORY,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100757 &items);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000758 SetImportItem(user_prefs,
759 prefs::kImportHomepage,
760 import_items,
761 dont_import_items,
762 importer::HOME_PAGE,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100763 &items);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000764 SetImportItem(user_prefs,
765 prefs::kImportSearchEngine,
766 import_items,
767 dont_import_items,
768 importer::SEARCH_ENGINES,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100769 &items);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000770 SetImportItem(user_prefs,
771 prefs::kImportBookmarks,
772 import_items,
773 dont_import_items,
774 importer::FAVORITES,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100775 &items);
776
777 importer::LogImporterUseToMetrics(
778 "AutoImport", importer_list->GetSourceProfileAt(0).importer_type);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000779
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100780 ImportSettings(profile, importer_host, importer_list, items);
781 }
782
783 if (!import_bookmarks_path.empty()) {
784 // Deletes itself.
Ben Murdocheb525c52013-07-10 11:40:50 +0100785 ExternalProcessImporterHost* file_importer_host =
786 new ExternalProcessImporterHost;
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100787 file_importer_host->set_headless();
788
789 ImportFromFile(profile, file_importer_host, import_bookmarks_path);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000790 }
791
792 content::RecordAction(UserMetricsAction("FirstRunDef_Accept"));
793
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100794 g_auto_import_state |= AUTO_IMPORT_CALLED;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000795}
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000796
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000797void DoPostImportTasks(Profile* profile, bool make_chrome_default) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000798 if (make_chrome_default &&
799 ShellIntegration::CanSetAsDefaultBrowser() ==
800 ShellIntegration::SET_DEFAULT_UNATTENDED) {
801 ShellIntegration::SetAsDefaultBrowser();
802 }
803
804 // Display the first run bubble if there is a default search provider.
805 TemplateURLService* template_url =
806 TemplateURLServiceFactory::GetForProfile(profile);
807 if (template_url && template_url->GetDefaultSearchProvider())
808 FirstRunBubbleLauncher::ShowFirstRunBubbleSoon();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000809 SetShouldShowWelcomePage();
810 SetShouldDoPersonalDataManagerFirstRun();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000811
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100812 internal::DoPostImportPlatformSpecificTasks(profile);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000813}
814
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100815uint16 auto_import_state() {
816 return g_auto_import_state;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000817}
818
819} // namespace first_run