first_run.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
1// 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 7#include "base/command_line.h" 8#include "base/compiler_specific.h" 9#include "base/file_util.h" 10#include "base/metrics/histogram.h" 11#include "base/path_service.h" 12#include "base/stringprintf.h" 13#include "base/utf_string_conversions.h" 14#include "build/build_config.h" 15#include "chrome/browser/browser_process.h" 16#include "chrome/browser/first_run/first_run_dialog.h" 17#include "chrome/browser/first_run/first_run_import_observer.h" 18#include "chrome/browser/first_run/first_run_internal.h" 19#include "chrome/browser/google/google_util.h" 20#include "chrome/browser/importer/external_process_importer_host.h" 21#include "chrome/browser/importer/importer_host.h" 22#include "chrome/browser/importer/importer_list.h" 23#include "chrome/browser/importer/importer_progress_dialog.h" 24#include "chrome/browser/importer/importer_progress_observer.h" 25#include "chrome/browser/prefs/pref_service.h" 26#include "chrome/browser/process_singleton.h" 27#include "chrome/browser/profiles/profile_manager.h" 28#include "chrome/browser/search_engines/template_url_service.h" 29#include "chrome/browser/search_engines/template_url_service_factory.h" 30#include "chrome/browser/shell_integration.h" 31#include "chrome/browser/ui/browser.h" 32#include "chrome/browser/ui/browser_finder.h" 33#include "chrome/browser/ui/browser_tabstrip.h" 34#include "chrome/browser/ui/global_error/global_error_service.h" 35#include "chrome/browser/ui/global_error/global_error_service_factory.h" 36#include "chrome/browser/ui/webui/ntp/new_tab_ui.h" 37#include "chrome/common/chrome_paths.h" 38#include "chrome/common/chrome_switches.h" 39#include "chrome/common/pref_names.h" 40#include "chrome/common/startup_metric_utils.h" 41#include "chrome/common/url_constants.h" 42#include "chrome/installer/util/master_preferences.h" 43#include "chrome/installer/util/master_preferences_constants.h" 44#include "chrome/installer/util/util_constants.h" 45#include "content/public/browser/notification_service.h" 46#include "content/public/browser/notification_types.h" 47#include "content/public/browser/user_metrics.h" 48#include "content/public/browser/web_contents.h" 49#include "googleurl/src/gurl.h" 50 51using content::UserMetricsAction; 52 53namespace { 54 55FilePath GetDefaultPrefFilePath(bool create_profile_dir, 56 const FilePath& user_data_dir) { 57 FilePath default_pref_dir = 58 ProfileManager::GetDefaultProfileDir(user_data_dir); 59 if (create_profile_dir) { 60 if (!file_util::PathExists(default_pref_dir)) { 61 if (!file_util::CreateDirectory(default_pref_dir)) 62 return FilePath(); 63 } 64 } 65 return ProfileManager::GetProfilePrefsPath(default_pref_dir); 66} 67 68// Sets the |items| bitfield according to whether the import data specified by 69// |import_type| should be be auto imported or not. 70void SetImportItem(PrefService* user_prefs, 71 const char* pref_path, 72 int import_items, 73 int dont_import_items, 74 importer::ImportItem import_type, 75 int& items) { 76 // Work out whether an item is to be imported according to what is specified 77 // in master preferences. 78 bool should_import = false; 79 bool master_pref_set = 80 ((import_items | dont_import_items) & import_type) != 0; 81 bool master_pref = ((import_items & ~dont_import_items) & import_type) != 0; 82 83 if (import_type == importer::HISTORY || 84 ((import_type != importer::FAVORITES) && 85 first_run::internal::IsOrganicFirstRun())) { 86 // History is always imported unless turned off in master_preferences. 87 // Search engines are only imported in certain builds unless overridden 88 // in master_preferences.Home page is imported in organic builds only unless 89 // turned off in master_preferences. 90 should_import = !master_pref_set || master_pref; 91 } else { 92 // Bookmarks are never imported, unless turned on in master_preferences. 93 // Search engine and home page import behaviour is similar in non organic 94 // builds. 95 should_import = master_pref_set && master_pref; 96 } 97 98 // If an import policy is set, import items according to policy. If no master 99 // preference is set, but a corresponding recommended policy is set, import 100 // item according to recommended policy. If both a master preference and a 101 // recommended policy is set, the master preference wins. If neither 102 // recommended nor managed policies are set, import item according to what we 103 // worked out above. 104 if (master_pref_set) 105 user_prefs->SetBoolean(pref_path, should_import); 106 107 if (!user_prefs->FindPreference(pref_path)->IsDefaultValue()) { 108 if (user_prefs->GetBoolean(pref_path)) 109 items |= import_type; 110 } else { // no policy (recommended or managed) is set 111 if (should_import) 112 items |= import_type; 113 } 114 115 user_prefs->ClearPref(pref_path); 116} 117 118// Imports bookmarks from an html file. The path to the file is provided in 119// the command line. 120int ImportFromFile(Profile* profile, const CommandLine& cmdline) { 121 FilePath file_path = cmdline.GetSwitchValuePath(switches::kImportFromFile); 122 if (file_path.empty()) { 123 NOTREACHED(); 124 return false; 125 } 126 scoped_refptr<ImporterHost> importer_host(new ImporterHost); 127 importer_host->set_headless(); 128 129 importer::SourceProfile source_profile; 130 source_profile.importer_type = importer::TYPE_BOOKMARKS_FILE; 131 source_profile.source_path = file_path; 132 133 FirstRunImportObserver importer_observer; 134 importer::ShowImportProgressDialog(importer::FAVORITES, 135 importer_host, 136 &importer_observer, 137 source_profile, 138 profile, 139 true); 140 141 importer_observer.RunLoop(); 142 return importer_observer.import_result(); 143} 144 145} // namespace 146 147namespace first_run { 148namespace internal { 149 150FirstRunState first_run_ = FIRST_RUN_UNKNOWN; 151 152installer::MasterPreferences* LoadMasterPrefs(FilePath* master_prefs_path) 153{ 154 *master_prefs_path = FilePath(MasterPrefsPath()); 155 if (master_prefs_path->empty()) 156 return NULL; 157 installer::MasterPreferences* install_prefs = 158 new installer::MasterPreferences(*master_prefs_path); 159 if (!install_prefs->read_from_file()) { 160 delete install_prefs; 161 return NULL; 162 } 163 164 return install_prefs; 165} 166 167bool CopyPrefFile(const FilePath& user_data_dir, 168 const FilePath& master_prefs_path) { 169 FilePath user_prefs = GetDefaultPrefFilePath(true, user_data_dir); 170 if (user_prefs.empty()) 171 return false; 172 173 // The master prefs are regular prefs so we can just copy the file 174 // to the default place and they just work. 175 return file_util::CopyFile(master_prefs_path, user_prefs); 176} 177 178void SetupMasterPrefsFromInstallPrefs( 179 MasterPrefs* out_prefs, 180 installer::MasterPreferences* install_prefs) { 181 bool value = false; 182 if (install_prefs->GetBool( 183 installer::master_preferences::kDistroImportSearchPref, &value)) { 184 if (value) { 185 out_prefs->do_import_items |= importer::SEARCH_ENGINES; 186 } else { 187 out_prefs->dont_import_items |= importer::SEARCH_ENGINES; 188 } 189 } 190 191 // If we're suppressing the first-run bubble, set that preference now. 192 // Otherwise, wait until the user has completed first run to set it, so the 193 // user is guaranteed to see the bubble iff he or she has completed the first 194 // run process. 195 if (install_prefs->GetBool( 196 installer::master_preferences::kDistroSuppressFirstRunBubble, 197 &value) && value) 198 SetShowFirstRunBubblePref(false); 199 200 if (install_prefs->GetBool( 201 installer::master_preferences::kDistroImportHistoryPref, 202 &value)) { 203 if (value) { 204 out_prefs->do_import_items |= importer::HISTORY; 205 } else { 206 out_prefs->dont_import_items |= importer::HISTORY; 207 } 208 } 209 210 std::string not_used; 211 out_prefs->homepage_defined = install_prefs->GetString( 212 prefs::kHomePage, ¬_used); 213 214 if (install_prefs->GetBool( 215 installer::master_preferences::kDistroImportHomePagePref, 216 &value)) { 217 if (value) { 218 out_prefs->do_import_items |= importer::HOME_PAGE; 219 } else { 220 out_prefs->dont_import_items |= importer::HOME_PAGE; 221 } 222 } 223 224 // Bookmarks are never imported unless specifically turned on. 225 if (install_prefs->GetBool( 226 installer::master_preferences::kDistroImportBookmarksPref, 227 &value)) { 228 if (value) 229 out_prefs->do_import_items |= importer::FAVORITES; 230 else 231 out_prefs->dont_import_items |= importer::FAVORITES; 232 } 233 234 if (install_prefs->GetBool( 235 installer::master_preferences::kMakeChromeDefaultForUser, 236 &value) && value) { 237 out_prefs->make_chrome_default = true; 238 } 239 240 if (install_prefs->GetBool( 241 installer::master_preferences::kSuppressFirstRunDefaultBrowserPrompt, 242 &value) && value) { 243 out_prefs->suppress_first_run_default_browser_prompt = true; 244 } 245} 246 247void SetDefaultBrowser(installer::MasterPreferences* install_prefs){ 248 // Even on the first run we only allow for the user choice to take effect if 249 // no policy has been set by the admin. 250 if (!g_browser_process->local_state()->IsManagedPreference( 251 prefs::kDefaultBrowserSettingEnabled)) { 252 bool value = false; 253 if (install_prefs->GetBool( 254 installer::master_preferences::kMakeChromeDefaultForUser, 255 &value) && value) { 256 ShellIntegration::SetAsDefaultBrowser(); 257 } 258 } else { 259 if (g_browser_process->local_state()->GetBoolean( 260 prefs::kDefaultBrowserSettingEnabled)) { 261 ShellIntegration::SetAsDefaultBrowser(); 262 } 263 } 264} 265 266void SetShowWelcomePagePrefIfNeeded( 267 installer::MasterPreferences* install_prefs) { 268 bool value = false; 269 if (install_prefs->GetBool( 270 installer::master_preferences::kDistroShowWelcomePage, &value) 271 && value) { 272 SetShowWelcomePagePref(); 273 } 274} 275 276bool SkipFirstRunUI(installer::MasterPreferences* install_prefs) { 277 bool value = false; 278 install_prefs->GetBool(installer::master_preferences::kDistroSkipFirstRunPref, 279 &value); 280 return value; 281} 282 283void SetRLZPref(first_run::MasterPrefs* out_prefs, 284 installer::MasterPreferences* install_prefs) { 285 if (!install_prefs->GetInt(installer::master_preferences::kDistroPingDelay, 286 &out_prefs->ping_delay)) { 287 // Default value in case master preferences is missing or corrupt, 288 // or ping_delay is missing. 289 out_prefs->ping_delay = 90; 290 } 291} 292 293// -- Platform-specific functions -- 294 295#if !defined(OS_LINUX) && !defined(OS_BSD) 296bool IsOrganicFirstRun() { 297 std::string brand; 298 google_util::GetBrand(&brand); 299 return google_util::IsOrganicFirstRun(brand); 300} 301#endif 302 303#if !defined(USE_AURA) 304void AutoImportPlatformCommon( 305 scoped_refptr<ImporterHost> importer_host, 306 Profile* profile, 307 bool homepage_defined, 308 int import_items, 309 int dont_import_items, 310 bool make_chrome_default) { 311 FilePath local_state_path; 312 PathService::Get(chrome::FILE_LOCAL_STATE, &local_state_path); 313 bool local_state_file_exists = file_util::PathExists(local_state_path); 314 315 scoped_refptr<ImporterList> importer_list(new ImporterList(NULL)); 316 importer_list->DetectSourceProfilesHack(); 317 318 // Do import if there is an available profile for us to import. 319 if (importer_list->count() > 0) { 320 // Don't show the warning dialog if import fails. 321 importer_host->set_headless(); 322 int items = 0; 323 324 if (IsOrganicFirstRun()) { 325 // Home page is imported in organic builds only unless turned off or 326 // defined in master_preferences. 327 if (homepage_defined) { 328 dont_import_items |= importer::HOME_PAGE; 329 if (import_items & importer::HOME_PAGE) 330 import_items &= ~importer::HOME_PAGE; 331 } 332 // Search engines are not imported automatically in organic builds if the 333 // user already has a user preferences directory. 334 if (local_state_file_exists) { 335 dont_import_items |= importer::SEARCH_ENGINES; 336 if (import_items & importer::SEARCH_ENGINES) 337 import_items &= ~importer::SEARCH_ENGINES; 338 } 339 } 340 341 PrefService* user_prefs = profile->GetPrefs(); 342 343 SetImportItem(user_prefs, 344 prefs::kImportHistory, 345 import_items, 346 dont_import_items, 347 importer::HISTORY, 348 items); 349 SetImportItem(user_prefs, 350 prefs::kImportHomepage, 351 import_items, 352 dont_import_items, 353 importer::HOME_PAGE, 354 items); 355 SetImportItem(user_prefs, 356 prefs::kImportSearchEngine, 357 import_items, 358 dont_import_items, 359 importer::SEARCH_ENGINES, 360 items); 361 SetImportItem(user_prefs, 362 prefs::kImportBookmarks, 363 import_items, 364 dont_import_items, 365 importer::FAVORITES, 366 items); 367 368 ImportSettings(profile, importer_host, importer_list, items); 369 } 370 371 content::RecordAction(UserMetricsAction("FirstRunDef_Accept")); 372 373 // Launch the first run dialog only for certain builds, and only if the user 374 // has not already set preferences. 375 if (IsOrganicFirstRun() && !local_state_file_exists) { 376 startup_metric_utils::SetNonBrowserUIDisplayed(); 377 ShowFirstRunDialog(profile); 378 } 379 380 if (make_chrome_default && 381 ShellIntegration::CanSetAsDefaultBrowser() == 382 ShellIntegration::SET_DEFAULT_UNATTENDED) { 383 ShellIntegration::SetAsDefaultBrowser(); 384 } 385 386 // Display the first run bubble if there is a default search provider. 387 TemplateURLService* template_url = 388 TemplateURLServiceFactory::GetForProfile(profile); 389 if (template_url && template_url->GetDefaultSearchProvider()) 390 FirstRunBubbleLauncher::ShowFirstRunBubbleSoon(); 391 SetShowWelcomePagePref(); 392 SetPersonalDataManagerFirstRunPref(); 393} 394#endif // !defined(USE_AURA) 395 396int ImportBookmarkFromFileIfNeeded(Profile* profile, 397 const CommandLine& cmdline) { 398 int return_code = true; 399 if (cmdline.HasSwitch(switches::kImportFromFile)) { 400 // Silently import preset bookmarks from file. 401 // This is an OEM scenario. 402 return_code = ImportFromFile(profile, cmdline); 403 } 404 return return_code; 405} 406 407} // namespace internal 408} // namespace first_run 409 410namespace first_run { 411 412MasterPrefs::MasterPrefs() 413 : ping_delay(0), 414 homepage_defined(false), 415 do_import_items(0), 416 dont_import_items(0), 417 make_chrome_default(false), 418 suppress_first_run_default_browser_prompt(false) { 419} 420 421MasterPrefs::~MasterPrefs() {} 422 423bool IsChromeFirstRun() { 424 if (internal::first_run_ != internal::FIRST_RUN_UNKNOWN) 425 return internal::first_run_ == internal::FIRST_RUN_TRUE; 426 427 FilePath first_run_sentinel; 428 if (!internal::GetFirstRunSentinelFilePath(&first_run_sentinel) || 429 file_util::PathExists(first_run_sentinel)) { 430 internal::first_run_ = internal::FIRST_RUN_FALSE; 431 return false; 432 } 433 internal::first_run_ = internal::FIRST_RUN_TRUE; 434 return true; 435} 436 437bool CreateSentinel() { 438 FilePath first_run_sentinel; 439 if (!internal::GetFirstRunSentinelFilePath(&first_run_sentinel)) 440 return false; 441 return file_util::WriteFile(first_run_sentinel, "", 0) != -1; 442} 443 444std::string GetPingDelayPrefName() { 445 return base::StringPrintf("%s.%s", 446 installer::master_preferences::kDistroDict, 447 installer::master_preferences::kDistroPingDelay); 448} 449 450void RegisterUserPrefs(PrefService* prefs) { 451 prefs->RegisterIntegerPref(GetPingDelayPrefName().c_str(), 452 0, 453 PrefService::UNSYNCABLE_PREF); 454} 455 456bool RemoveSentinel() { 457 FilePath first_run_sentinel; 458 if (!internal::GetFirstRunSentinelFilePath(&first_run_sentinel)) 459 return false; 460 return file_util::Delete(first_run_sentinel, false); 461} 462 463bool SetShowFirstRunBubblePref(bool show_bubble) { 464 PrefService* local_state = g_browser_process->local_state(); 465 if (!local_state) 466 return false; 467 local_state->SetBoolean(prefs::kShouldShowFirstRunBubble, show_bubble); 468 return true; 469} 470 471bool SetShowWelcomePagePref() { 472 PrefService* local_state = g_browser_process->local_state(); 473 if (!local_state) 474 return false; 475 if (!local_state->FindPreference(prefs::kShouldShowWelcomePage)) { 476 local_state->RegisterBooleanPref(prefs::kShouldShowWelcomePage, false); 477 local_state->SetBoolean(prefs::kShouldShowWelcomePage, true); 478 } 479 return true; 480} 481 482bool SetPersonalDataManagerFirstRunPref() { 483 PrefService* local_state = g_browser_process->local_state(); 484 if (!local_state) 485 return false; 486 if (!local_state->FindPreference( 487 prefs::kAutofillPersonalDataManagerFirstRun)) { 488 local_state->RegisterBooleanPref( 489 prefs::kAutofillPersonalDataManagerFirstRun, false); 490 local_state->SetBoolean(prefs::kAutofillPersonalDataManagerFirstRun, true); 491 } 492 return true; 493} 494 495void LogFirstRunMetric(FirstRunBubbleMetric metric) { 496 UMA_HISTOGRAM_ENUMERATION("FirstRun.SearchEngineBubble", metric, 497 NUM_FIRST_RUN_BUBBLE_METRICS); 498} 499 500// static 501void FirstRunBubbleLauncher::ShowFirstRunBubbleSoon() { 502 SetShowFirstRunBubblePref(true); 503 // This FirstRunBubbleLauncher instance will manage its own lifetime. 504 new FirstRunBubbleLauncher(); 505} 506 507FirstRunBubbleLauncher::FirstRunBubbleLauncher() { 508 registrar_.Add(this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME, 509 content::NotificationService::AllSources()); 510} 511 512FirstRunBubbleLauncher::~FirstRunBubbleLauncher() {} 513 514void FirstRunBubbleLauncher::Observe( 515 int type, 516 const content::NotificationSource& source, 517 const content::NotificationDetails& details) { 518 DCHECK_EQ(type, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME); 519 Browser* browser = browser::FindBrowserWithWebContents( 520 content::Source<content::WebContents>(source).ptr()); 521 if (!browser || !browser->is_type_tabbed()) 522 return; 523 524 // Check the preference to determine if the bubble should be shown. 525 PrefService* prefs = g_browser_process->local_state(); 526 if (!prefs || !prefs->GetBoolean(prefs::kShouldShowFirstRunBubble)) { 527 delete this; 528 return; 529 } 530 531 content::WebContents* contents = chrome::GetActiveWebContents(browser); 532 if (contents && contents->GetURL().SchemeIs(chrome::kChromeUIScheme)) { 533 // Suppress the first run bubble if the sync promo is showing. 534 if (contents->GetURL().host() == chrome::kChromeUISyncPromoHost) 535 return; 536 537 // Suppress the first run bubble if 'make chrome metro' flow is showing. 538 if (contents->GetURL().host() == chrome::kChromeUIMetroFlowHost) 539 return; 540 541 // Suppress the first run bubble if the NTP sync promo bubble is showing. 542 if (contents->GetURL().host() == chrome::kChromeUINewTabHost) { 543 NewTabUI* new_tab_ui = 544 NewTabUI::FromWebUIController(contents->GetWebUI()->GetController()); 545 if (new_tab_ui && new_tab_ui->showing_sync_bubble()) 546 return; 547 } 548 } 549 550 // Suppress the first run bubble if a global error bubble is pending. 551 GlobalErrorService* global_error_service = 552 GlobalErrorServiceFactory::GetForProfile(browser->profile()); 553 if (global_error_service->GetFirstGlobalErrorWithBubbleView() != NULL) 554 return; 555 556 // Reset the preference and notifications to avoid showing the bubble again. 557 prefs->SetBoolean(prefs::kShouldShowFirstRunBubble, false); 558 559 // Show the bubble now and destroy this bubble launcher. 560 browser->ShowFirstRunBubble(); 561 delete this; 562} 563 564} // namespace first_run 565