1 // Copyright (c) 2011 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
7 #include "base/command_line.h"
8 #include "base/compiler_specific.h"
9 #include "base/file_util.h"
10 #include "base/path_service.h"
11 #include "base/utf_string_conversions.h"
12 #include "build/build_config.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/first_run/first_run_dialog.h"
15 #include "chrome/browser/first_run/first_run_import_observer.h"
16 #include "chrome/browser/importer/external_process_importer_host.h"
17 #include "chrome/browser/importer/importer_host.h"
18 #include "chrome/browser/importer/importer_list.h"
19 #include "chrome/browser/importer/importer_progress_dialog.h"
20 #include "chrome/browser/importer/importer_progress_observer.h"
21 #include "chrome/browser/metrics/user_metrics.h"
22 #include "chrome/browser/prefs/pref_service.h"
23 #include "chrome/browser/process_singleton.h"
24 #include "chrome/browser/profiles/profile_manager.h"
25 #include "chrome/browser/search_engines/template_url_model.h"
26 #include "chrome/browser/shell_integration.h"
27 #include "chrome/common/chrome_paths.h"
28 #include "chrome/common/chrome_switches.h"
29 #include "chrome/common/pref_names.h"
30 #include "chrome/installer/util/master_preferences.h"
31 #include "chrome/installer/util/master_preferences_constants.h"
32 #include "chrome/installer/util/util_constants.h"
33 #include "googleurl/src/gurl.h"
34
35 #if defined(OS_WIN)
36 // TODO(port): move more code in back from the first_run_win.cc module.
37 #include "chrome/installer/util/google_update_settings.h"
38 #include "chrome/installer/util/install_util.h"
39 #endif
40
41 namespace {
42
43 // The kSentinelFile file absence will tell us it is a first run.
44 const char kSentinelFile[] = "First Run";
45
GetDefaultPrefFilePath(bool create_profile_dir,const FilePath & user_data_dir)46 FilePath GetDefaultPrefFilePath(bool create_profile_dir,
47 const FilePath& user_data_dir) {
48 FilePath default_pref_dir =
49 ProfileManager::GetDefaultProfileDir(user_data_dir);
50 if (create_profile_dir) {
51 if (!file_util::PathExists(default_pref_dir)) {
52 if (!file_util::CreateDirectory(default_pref_dir))
53 return FilePath();
54 }
55 }
56 return ProfileManager::GetProfilePrefsPath(default_pref_dir);
57 }
58
59 } // namespace
60
61 // FirstRun -------------------------------------------------------------------
62
63 FirstRun::FirstRunState FirstRun::first_run_ = FIRST_RUN_UNKNOWN;
64
MasterPrefs()65 FirstRun::MasterPrefs::MasterPrefs()
66 : ping_delay(0),
67 homepage_defined(false),
68 do_import_items(0),
69 dont_import_items(0),
70 run_search_engine_experiment(false),
71 randomize_search_engine_experiment(false),
72 make_chrome_default(false) {
73 }
74
~MasterPrefs()75 FirstRun::MasterPrefs::~MasterPrefs() {}
76
77 // TODO(port): Import switches need to be ported to both Mac and Linux. Not all
78 // import switches here are implemented for Linux. None are implemented for Mac
79 // (as this function will not be called on Mac).
ImportNow(Profile * profile,const CommandLine & cmdline)80 int FirstRun::ImportNow(Profile* profile, const CommandLine& cmdline) {
81 int return_code = true;
82 if (cmdline.HasSwitch(switches::kImportFromFile)) {
83 // Silently import preset bookmarks from file.
84 // This is an OEM scenario.
85 return_code = ImportFromFile(profile, cmdline);
86 }
87 if (cmdline.HasSwitch(switches::kImport)) {
88 #if defined(OS_WIN)
89 return_code = ImportFromBrowser(profile, cmdline);
90 #else
91 NOTIMPLEMENTED();
92 #endif
93 }
94 return return_code;
95 }
96
97 // static
ProcessMasterPreferences(const FilePath & user_data_dir,MasterPrefs * out_prefs)98 bool FirstRun::ProcessMasterPreferences(const FilePath& user_data_dir,
99 MasterPrefs* out_prefs) {
100 DCHECK(!user_data_dir.empty());
101
102 // The standard location of the master prefs is next to the chrome binary.
103 FilePath master_prefs;
104 if (!PathService::Get(base::DIR_EXE, &master_prefs))
105 return true;
106 master_prefs = master_prefs.AppendASCII(installer::kDefaultMasterPrefs);
107
108 installer::MasterPreferences prefs(master_prefs);
109 if (!prefs.read_from_file())
110 return true;
111
112 out_prefs->new_tabs = prefs.GetFirstRunTabs();
113
114 bool value = false;
115
116 #if defined(OS_WIN)
117 // RLZ is currently a Windows-only phenomenon. When it comes to the Mac/
118 // Linux, enable it here.
119 if (!prefs.GetInt(installer::master_preferences::kDistroPingDelay,
120 &out_prefs->ping_delay)) {
121 // 90 seconds is the default that we want to use in case master
122 // preferences is missing, corrupt or ping_delay is missing.
123 out_prefs->ping_delay = 90;
124 }
125
126 if (prefs.GetBool(installer::master_preferences::kRequireEula, &value) &&
127 value) {
128 // Show the post-installation EULA. This is done by setup.exe and the
129 // result determines if we continue or not. We wait here until the user
130 // dismisses the dialog.
131
132 // The actual eula text is in a resource in chrome. We extract it to
133 // a text file so setup.exe can use it as an inner frame.
134 FilePath inner_html;
135 if (WriteEULAtoTempFile(&inner_html)) {
136 int retcode = 0;
137 if (!LaunchSetupWithParam(installer::switches::kShowEula,
138 inner_html.value(), &retcode) ||
139 (retcode == installer::EULA_REJECTED)) {
140 LOG(WARNING) << "EULA rejected. Fast exit.";
141 ::ExitProcess(1);
142 }
143 if (retcode == installer::EULA_ACCEPTED) {
144 VLOG(1) << "EULA : no collection";
145 GoogleUpdateSettings::SetCollectStatsConsent(false);
146 } else if (retcode == installer::EULA_ACCEPTED_OPT_IN) {
147 VLOG(1) << "EULA : collection consent";
148 GoogleUpdateSettings::SetCollectStatsConsent(true);
149 }
150 }
151 }
152 #endif
153
154 if (prefs.GetBool(installer::master_preferences::kAltFirstRunBubble,
155 &value) && value) {
156 FirstRun::SetOEMFirstRunBubblePref();
157 }
158
159 FilePath user_prefs = GetDefaultPrefFilePath(true, user_data_dir);
160 if (user_prefs.empty())
161 return true;
162
163 // The master prefs are regular prefs so we can just copy the file
164 // to the default place and they just work.
165 if (!file_util::CopyFile(master_prefs, user_prefs))
166 return true;
167
168 #if defined(OS_WIN)
169 DictionaryValue* extensions = 0;
170 if (prefs.GetExtensionsBlock(&extensions)) {
171 VLOG(1) << "Extensions block found in master preferences";
172 DoDelayedInstallExtensions();
173 }
174 #endif
175
176 if (prefs.GetBool(installer::master_preferences::kDistroImportSearchPref,
177 &value)) {
178 if (value) {
179 out_prefs->do_import_items |= importer::SEARCH_ENGINES;
180 } else {
181 out_prefs->dont_import_items |= importer::SEARCH_ENGINES;
182 }
183 }
184
185 // Check to see if search engine logos should be randomized.
186 if (prefs.GetBool(
187 installer::master_preferences::
188 kSearchEngineExperimentRandomizePref,
189 &value) && value) {
190 out_prefs->randomize_search_engine_experiment = true;
191 }
192
193 // If we're suppressing the first-run bubble, set that preference now.
194 // Otherwise, wait until the user has completed first run to set it, so the
195 // user is guaranteed to see the bubble iff he or she has completed the first
196 // run process.
197 if (prefs.GetBool(
198 installer::master_preferences::kDistroSuppressFirstRunBubble,
199 &value) && value)
200 FirstRun::SetShowFirstRunBubblePref(false);
201
202 if (prefs.GetBool(
203 installer::master_preferences::kDistroImportHistoryPref,
204 &value)) {
205 if (value) {
206 out_prefs->do_import_items |= importer::HISTORY;
207 } else {
208 out_prefs->dont_import_items |= importer::HISTORY;
209 }
210 }
211
212 std::string not_used;
213 out_prefs->homepage_defined = prefs.GetString(prefs::kHomePage, ¬_used);
214
215 if (prefs.GetBool(
216 installer::master_preferences::kDistroImportHomePagePref,
217 &value)) {
218 if (value) {
219 out_prefs->do_import_items |= importer::HOME_PAGE;
220 } else {
221 out_prefs->dont_import_items |= importer::HOME_PAGE;
222 }
223 }
224
225 // Bookmarks are never imported unless specifically turned on.
226 if (prefs.GetBool(
227 installer::master_preferences::kDistroImportBookmarksPref,
228 &value) && value) {
229 out_prefs->do_import_items |= importer::FAVORITES;
230 }
231
232 if (prefs.GetBool(
233 installer::master_preferences::kMakeChromeDefaultForUser,
234 &value) && value) {
235 out_prefs->make_chrome_default = true;
236 }
237
238 // TODO(mirandac): Refactor skip-first-run-ui process into regular first run
239 // import process. http://crbug.com/49647
240 // Note we are skipping all other master preferences if skip-first-run-ui
241 // is *not* specified. (That is, we continue only if skipping first run ui.)
242 if (!prefs.GetBool(
243 installer::master_preferences::kDistroSkipFirstRunPref,
244 &value) || !value) {
245 return true;
246 }
247
248 #if !defined(OS_WIN)
249 // From here on we won't show first run so we need to do the work to show the
250 // bubble anyway, unless it's already been explicitly suppressed.
251 FirstRun::SetShowFirstRunBubblePref(true);
252 #endif
253
254 // We need to be able to create the first run sentinel or else we cannot
255 // proceed because ImportSettings will launch the importer process which
256 // would end up here if the sentinel is not present.
257 if (!FirstRun::CreateSentinel())
258 return false;
259
260 if (prefs.GetBool(installer::master_preferences::kDistroShowWelcomePage,
261 &value) && value) {
262 FirstRun::SetShowWelcomePagePref();
263 }
264
265 std::string import_bookmarks_path;
266 prefs.GetString(
267 installer::master_preferences::kDistroImportBookmarksFromFilePref,
268 &import_bookmarks_path);
269
270 #if defined(OS_WIN)
271 if (!IsOrganicFirstRun()) {
272 // If search engines aren't explicitly imported, don't import.
273 if (!(out_prefs->do_import_items & importer::SEARCH_ENGINES)) {
274 out_prefs->dont_import_items |= importer::SEARCH_ENGINES;
275 }
276 // If home page isn't explicitly imported, don't import.
277 if (!(out_prefs->do_import_items & importer::HOME_PAGE)) {
278 out_prefs->dont_import_items |= importer::HOME_PAGE;
279 }
280 // If history isn't explicitly forbidden, do import.
281 if (!(out_prefs->dont_import_items & importer::HISTORY)) {
282 out_prefs->do_import_items |= importer::HISTORY;
283 }
284 }
285
286 if (out_prefs->do_import_items || !import_bookmarks_path.empty()) {
287 // There is something to import from the default browser. This launches
288 // the importer process and blocks until done or until it fails.
289 scoped_refptr<ImporterList> importer_list(new ImporterList);
290 importer_list->DetectSourceProfilesHack();
291 if (!FirstRun::ImportSettings(NULL,
292 importer_list->GetSourceProfileAt(0).importer_type,
293 out_prefs->do_import_items,
294 FilePath::FromWStringHack(UTF8ToWide(import_bookmarks_path)),
295 true, NULL)) {
296 LOG(WARNING) << "silent import failed";
297 }
298 }
299 #else
300 if (!import_bookmarks_path.empty()) {
301 // There are bookmarks to import from a file.
302 FilePath path = FilePath::FromWStringHack(UTF8ToWide(
303 import_bookmarks_path));
304 if (!FirstRun::ImportBookmarks(path)) {
305 LOG(WARNING) << "silent bookmark import failed";
306 }
307 }
308 #endif
309
310 // Even on the first run we only allow for the user choice to take effect if
311 // no policy has been set by the admin.
312 if (!g_browser_process->local_state()->IsManagedPreference(
313 prefs::kDefaultBrowserSettingEnabled)) {
314 if (prefs.GetBool(
315 installer::master_preferences::kMakeChromeDefaultForUser,
316 &value) && value) {
317 ShellIntegration::SetAsDefaultBrowser();
318 }
319 } else {
320 if (g_browser_process->local_state()->GetBoolean(
321 prefs::kDefaultBrowserSettingEnabled)) {
322 ShellIntegration::SetAsDefaultBrowser();
323 }
324 }
325
326 return false;
327 }
328
329 // static
IsChromeFirstRun()330 bool FirstRun::IsChromeFirstRun() {
331 if (first_run_ != FIRST_RUN_UNKNOWN)
332 return first_run_ == FIRST_RUN_TRUE;
333
334 FilePath first_run_sentinel;
335 if (!GetFirstRunSentinelFilePath(&first_run_sentinel) ||
336 file_util::PathExists(first_run_sentinel)) {
337 first_run_ = FIRST_RUN_FALSE;
338 return false;
339 }
340 first_run_ = FIRST_RUN_TRUE;
341 return true;
342 }
343
344 // static
RemoveSentinel()345 bool FirstRun::RemoveSentinel() {
346 FilePath first_run_sentinel;
347 if (!GetFirstRunSentinelFilePath(&first_run_sentinel))
348 return false;
349 return file_util::Delete(first_run_sentinel, false);
350 }
351
352 // static
CreateSentinel()353 bool FirstRun::CreateSentinel() {
354 FilePath first_run_sentinel;
355 if (!GetFirstRunSentinelFilePath(&first_run_sentinel))
356 return false;
357 return file_util::WriteFile(first_run_sentinel, "", 0) != -1;
358 }
359
360 // static
SetShowFirstRunBubblePref(bool show_bubble)361 bool FirstRun::SetShowFirstRunBubblePref(bool show_bubble) {
362 PrefService* local_state = g_browser_process->local_state();
363 if (!local_state)
364 return false;
365 if (!local_state->FindPreference(prefs::kShouldShowFirstRunBubble)) {
366 local_state->RegisterBooleanPref(prefs::kShouldShowFirstRunBubble, false);
367 local_state->SetBoolean(prefs::kShouldShowFirstRunBubble, show_bubble);
368 }
369 return true;
370 }
371
372 // static
SetShowWelcomePagePref()373 bool FirstRun::SetShowWelcomePagePref() {
374 PrefService* local_state = g_browser_process->local_state();
375 if (!local_state)
376 return false;
377 if (!local_state->FindPreference(prefs::kShouldShowWelcomePage)) {
378 local_state->RegisterBooleanPref(prefs::kShouldShowWelcomePage, false);
379 local_state->SetBoolean(prefs::kShouldShowWelcomePage, true);
380 }
381 return true;
382 }
383
384 // static
SetPersonalDataManagerFirstRunPref()385 bool FirstRun::SetPersonalDataManagerFirstRunPref() {
386 PrefService* local_state = g_browser_process->local_state();
387 if (!local_state)
388 return false;
389 if (!local_state->FindPreference(
390 prefs::kAutofillPersonalDataManagerFirstRun)) {
391 local_state->RegisterBooleanPref(
392 prefs::kAutofillPersonalDataManagerFirstRun, false);
393 local_state->SetBoolean(prefs::kAutofillPersonalDataManagerFirstRun, true);
394 }
395 return true;
396 }
397
398 // static
SearchEngineSelectorDisallowed()399 bool FirstRun::SearchEngineSelectorDisallowed() {
400 // For now, the only case in which the search engine dialog should never be
401 // shown is if the locale is Russia.
402 std::string locale = g_browser_process->GetApplicationLocale();
403 return (locale == "ru");
404 }
405
406 // static
SetOEMFirstRunBubblePref()407 bool FirstRun::SetOEMFirstRunBubblePref() {
408 PrefService* local_state = g_browser_process->local_state();
409 if (!local_state)
410 return false;
411 if (!local_state->FindPreference(prefs::kShouldUseOEMFirstRunBubble)) {
412 local_state->RegisterBooleanPref(prefs::kShouldUseOEMFirstRunBubble,
413 false);
414 local_state->SetBoolean(prefs::kShouldUseOEMFirstRunBubble, true);
415 }
416 return true;
417 }
418
419 // static
SetMinimalFirstRunBubblePref()420 bool FirstRun::SetMinimalFirstRunBubblePref() {
421 PrefService* local_state = g_browser_process->local_state();
422 if (!local_state)
423 return false;
424 if (!local_state->FindPreference(prefs::kShouldUseMinimalFirstRunBubble)) {
425 local_state->RegisterBooleanPref(prefs::kShouldUseMinimalFirstRunBubble,
426 false);
427 local_state->SetBoolean(prefs::kShouldUseMinimalFirstRunBubble, true);
428 }
429 return true;
430 }
431
432 // static
ImportFromFile(Profile * profile,const CommandLine & cmdline)433 int FirstRun::ImportFromFile(Profile* profile, const CommandLine& cmdline) {
434 FilePath file_path = cmdline.GetSwitchValuePath(switches::kImportFromFile);
435 if (file_path.empty()) {
436 NOTREACHED();
437 return false;
438 }
439 scoped_refptr<ImporterHost> importer_host(new ImporterHost);
440 importer_host->set_headless();
441
442 importer::SourceProfile source_profile;
443 source_profile.importer_type = importer::BOOKMARKS_HTML;
444 source_profile.source_path = file_path;
445
446 FirstRunImportObserver importer_observer;
447 importer::ShowImportProgressDialog(NULL,
448 importer::FAVORITES,
449 importer_host,
450 &importer_observer,
451 source_profile,
452 profile,
453 true);
454
455 importer_observer.RunLoop();
456 return importer_observer.import_result();
457 }
458
459 // static
GetFirstRunSentinelFilePath(FilePath * path)460 bool FirstRun::GetFirstRunSentinelFilePath(FilePath* path) {
461 FilePath first_run_sentinel;
462
463 #if defined(OS_WIN)
464 FilePath exe_path;
465 if (!PathService::Get(base::DIR_EXE, &exe_path))
466 return false;
467 if (InstallUtil::IsPerUserInstall(exe_path.value().c_str())) {
468 first_run_sentinel = exe_path;
469 } else {
470 if (!PathService::Get(chrome::DIR_USER_DATA, &first_run_sentinel))
471 return false;
472 }
473 #else
474 if (!PathService::Get(chrome::DIR_USER_DATA, &first_run_sentinel))
475 return false;
476 #endif
477
478 *path = first_run_sentinel.AppendASCII(kSentinelFile);
479 return true;
480 }
481
482 // static
AutoImport(Profile * profile,bool homepage_defined,int import_items,int dont_import_items,bool search_engine_experiment,bool randomize_search_engine_experiment,bool make_chrome_default,ProcessSingleton * process_singleton)483 void FirstRun::AutoImport(
484 Profile* profile,
485 bool homepage_defined,
486 int import_items,
487 int dont_import_items,
488 bool search_engine_experiment,
489 bool randomize_search_engine_experiment,
490 bool make_chrome_default,
491 ProcessSingleton* process_singleton) {
492 // We need to avoid dispatching new tabs when we are importing because
493 // that will lead to data corruption or a crash. Because there is no UI for
494 // the import process, we pass NULL as the window to bring to the foreground
495 // when a CopyData message comes in; this causes the message to be silently
496 // discarded, which is the correct behavior during the import process.
497 process_singleton->Lock(NULL);
498
499 PlatformSetup();
500
501 FilePath local_state_path;
502 PathService::Get(chrome::FILE_LOCAL_STATE, &local_state_path);
503 bool local_state_file_exists = file_util::PathExists(local_state_path);
504
505 scoped_refptr<ImporterHost> importer_host;
506 // TODO(csilv,mirandac): Out-of-process import has only been qualified on
507 // MacOS X, so we will only use it on that platform since it is required.
508 // Remove this conditional logic once oop import is qualified for
509 // Linux/Windows. http://crbug.com/22142
510 #if defined(OS_MACOSX)
511 importer_host = new ExternalProcessImporterHost;
512 #else
513 importer_host = new ImporterHost;
514 #endif
515
516 scoped_refptr<ImporterList> importer_list(new ImporterList);
517 importer_list->DetectSourceProfilesHack();
518
519 // Do import if there is an available profile for us to import.
520 if (importer_list->count() > 0) {
521 // Don't show the warning dialog if import fails.
522 importer_host->set_headless();
523 int items = 0;
524
525 // History is always imported unless turned off in master_preferences.
526 if (!(dont_import_items & importer::HISTORY))
527 items = items | importer::HISTORY;
528 // Home page is imported in organic builds only unless turned off or
529 // defined in master_preferences.
530 if (IsOrganicFirstRun()) {
531 if (!(dont_import_items & importer::HOME_PAGE) && !homepage_defined)
532 items = items | importer::HOME_PAGE;
533 } else {
534 if (import_items & importer::HOME_PAGE)
535 items = items | importer::HOME_PAGE;
536 }
537 // Search engines are only imported in certain builds unless overridden
538 // in master_preferences. Search engines are not imported automatically
539 // if the user already has a user preferences directory.
540 if (IsOrganicFirstRun()) {
541 if (!(dont_import_items & importer::SEARCH_ENGINES) &&
542 !local_state_file_exists) {
543 items = items | importer::SEARCH_ENGINES;
544 }
545 } else if (import_items & importer::SEARCH_ENGINES) {
546 items = items | importer::SEARCH_ENGINES;
547 }
548
549 // Bookmarks are never imported, unless turned on in master_preferences.
550 if (import_items & importer::FAVORITES)
551 items = items | importer::FAVORITES;
552
553 ImportSettings(profile, importer_host, importer_list, items);
554 }
555
556 UserMetrics::RecordAction(UserMetricsAction("FirstRunDef_Accept"));
557
558 // Launch the search engine dialog only for certain builds, and only if the
559 // user has not already set preferences.
560 if (IsOrganicFirstRun() && !local_state_file_exists) {
561 // The home page string may be set in the preferences, but the user should
562 // initially use Chrome with the NTP as home page in organic builds.
563 profile->GetPrefs()->SetBoolean(prefs::kHomePageIsNewTabPage, true);
564 first_run::ShowFirstRunDialog(profile, randomize_search_engine_experiment);
565 }
566
567 if (make_chrome_default)
568 ShellIntegration::SetAsDefaultBrowser();
569
570 // Don't display the minimal bubble if there is no default search provider.
571 TemplateURLModel* search_engines_model = profile->GetTemplateURLModel();
572 if (search_engines_model &&
573 search_engines_model->GetDefaultSearchProvider()) {
574 FirstRun::SetShowFirstRunBubblePref(true);
575 // Set the first run bubble to minimal.
576 FirstRun::SetMinimalFirstRunBubblePref();
577 }
578 FirstRun::SetShowWelcomePagePref();
579 FirstRun::SetPersonalDataManagerFirstRunPref();
580
581 process_singleton->Unlock();
582 FirstRun::CreateSentinel();
583 }
584
585 #if defined(OS_POSIX)
586 namespace {
587
588 // This class acts as an observer for the ImporterProgressObserver::ImportEnded
589 // callback. When the import process is started, certain errors may cause
590 // ImportEnded() to be called synchronously, but the typical case is that
591 // ImportEnded() is called asynchronously. Thus we have to handle both cases.
592 class ImportEndedObserver : public importer::ImporterProgressObserver {
593 public:
ImportEndedObserver()594 ImportEndedObserver() : ended_(false),
595 should_quit_message_loop_(false) {}
~ImportEndedObserver()596 virtual ~ImportEndedObserver() {}
597
598 // importer::ImporterProgressObserver:
ImportStarted()599 virtual void ImportStarted() OVERRIDE {}
ImportItemStarted(importer::ImportItem item)600 virtual void ImportItemStarted(importer::ImportItem item) OVERRIDE {}
ImportItemEnded(importer::ImportItem item)601 virtual void ImportItemEnded(importer::ImportItem item) OVERRIDE {}
ImportEnded()602 virtual void ImportEnded() OVERRIDE {
603 ended_ = true;
604 if (should_quit_message_loop_)
605 MessageLoop::current()->Quit();
606 }
607
set_should_quit_message_loop()608 void set_should_quit_message_loop() {
609 should_quit_message_loop_ = true;
610 }
611
ended()612 bool ended() {
613 return ended_;
614 }
615
616 private:
617 // Set if the import has ended.
618 bool ended_;
619
620 // Set by the client (via set_should_quit_message_loop) if, when the import
621 // ends, this class should quit the message loop.
622 bool should_quit_message_loop_;
623 };
624
625 } // namespace
626
627 // static
ImportSettings(Profile * profile,scoped_refptr<ImporterHost> importer_host,scoped_refptr<ImporterList> importer_list,int items_to_import)628 bool FirstRun::ImportSettings(Profile* profile,
629 scoped_refptr<ImporterHost> importer_host,
630 scoped_refptr<ImporterList> importer_list,
631 int items_to_import) {
632 const importer::SourceProfile& source_profile =
633 importer_list->GetSourceProfileAt(0);
634
635 // Ensure that importers aren't requested to import items that they do not
636 // support.
637 items_to_import &= source_profile.services_supported;
638
639 scoped_ptr<ImportEndedObserver> observer(new ImportEndedObserver);
640 importer_host->SetObserver(observer.get());
641 importer_host->StartImportSettings(source_profile,
642 profile,
643 items_to_import,
644 new ProfileWriter(profile),
645 true);
646 // If the import process has not errored out, block on it.
647 if (!observer->ended()) {
648 observer->set_should_quit_message_loop();
649 MessageLoop::current()->Run();
650 }
651
652 // Unfortunately there's no success/fail signal in ImporterHost.
653 return true;
654 }
655
656 #endif // OS_POSIX
657