| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ui/browser_init.h" |
| |
| #include <algorithm> // For max(). |
| |
| #include "base/compiler_specific.h" |
| #include "base/environment.h" |
| #include "base/event_recorder.h" |
| #include "base/file_path.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/metrics/histogram.h" |
| #include "base/path_service.h" |
| #include "base/string_number_conversions.h" |
| #include "base/string_split.h" |
| #include "base/threading/thread_restrictions.h" |
| #include "base/utf_string_conversions.h" |
| #include "chrome/browser/automation/automation_provider.h" |
| #include "chrome/browser/automation/automation_provider_list.h" |
| #include "chrome/browser/automation/chrome_frame_automation_provider.h" |
| #include "chrome/browser/automation/testing_automation_provider.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/defaults.h" |
| #include "chrome/browser/extensions/extension_creator.h" |
| #include "chrome/browser/extensions/extension_service.h" |
| #include "chrome/browser/extensions/pack_extension_job.h" |
| #include "chrome/browser/first_run/first_run.h" |
| #include "chrome/browser/net/predictor_api.h" |
| #include "chrome/browser/net/url_fixer_upper.h" |
| #include "chrome/browser/notifications/desktop_notification_service.h" |
| #include "chrome/browser/platform_util.h" |
| #include "chrome/browser/prefs/pref_service.h" |
| #include "chrome/browser/prefs/session_startup_pref.h" |
| #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h" |
| #include "chrome/browser/printing/print_dialog_cloud.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/search_engines/template_url.h" |
| #include "chrome/browser/search_engines/template_url_model.h" |
| #include "chrome/browser/sessions/session_restore.h" |
| #include "chrome/browser/sessions/session_service.h" |
| #include "chrome/browser/shell_integration.h" |
| #include "chrome/browser/tab_contents/link_infobar_delegate.h" |
| #include "chrome/browser/tab_contents/simple_alert_infobar_delegate.h" |
| #include "chrome/browser/tabs/pinned_tab_codec.h" |
| #include "chrome/browser/tabs/tab_strip_model.h" |
| #include "chrome/browser/ui/browser_list.h" |
| #include "chrome/browser/ui/browser_navigator.h" |
| #include "chrome/browser/ui/browser_window.h" |
| #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
| #include "chrome/common/chrome_constants.h" |
| #include "chrome/common/chrome_paths.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "chrome/common/extensions/extension_constants.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/common/url_constants.h" |
| #include "chrome/installer/util/browser_distribution.h" |
| #include "content/browser/browser_thread.h" |
| #include "content/browser/child_process_security_policy.h" |
| #include "content/browser/renderer_host/render_process_host.h" |
| #include "content/browser/tab_contents/navigation_controller.h" |
| #include "content/browser/tab_contents/tab_contents.h" |
| #include "content/browser/tab_contents/tab_contents_view.h" |
| #include "content/common/result_codes.h" |
| #include "grit/chromium_strings.h" |
| #include "grit/generated_resources.h" |
| #include "grit/locale_settings.h" |
| #include "grit/theme_resources.h" |
| #include "net/base/net_util.h" |
| #include "net/url_request/url_request.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/base/resource/resource_bundle.h" |
| #include "webkit/glue/webkit_glue.h" |
| |
| #if defined(OS_MACOSX) |
| #include "chrome/browser/ui/cocoa/keystone_infobar.h" |
| #endif |
| |
| #if defined(TOOLKIT_USES_GTK) |
| #include "chrome/browser/ui/gtk/gtk_util.h" |
| #endif |
| |
| #if defined(OS_CHROMEOS) |
| #include "chrome/browser/chromeos/cros/cros_library.h" |
| #include "chrome/browser/chromeos/cros/mount_library.h" |
| #include "chrome/browser/chromeos/cros/network_library.h" |
| #include "chrome/browser/chromeos/customization_document.h" |
| #include "chrome/browser/chromeos/enterprise_extension_observer.h" |
| #include "chrome/browser/chromeos/gview_request_interceptor.h" |
| #include "chrome/browser/chromeos/low_battery_observer.h" |
| #include "chrome/browser/chromeos/network_message_observer.h" |
| #include "chrome/browser/chromeos/network_state_notifier.h" |
| #include "chrome/browser/chromeos/sms_observer.h" |
| #include "chrome/browser/chromeos/update_observer.h" |
| #include "chrome/browser/chromeos/wm_message_listener.h" |
| #include "chrome/browser/chromeos/wm_overview_controller.h" |
| #include "chrome/browser/ui/webui/mediaplayer_ui.h" |
| #endif |
| |
| #if defined(HAVE_XINPUT2) |
| #include "views/focus/accelerator_handler.h" |
| #endif |
| |
| namespace { |
| |
| // SetAsDefaultBrowserTask ---------------------------------------------------- |
| |
| class SetAsDefaultBrowserTask : public Task { |
| public: |
| SetAsDefaultBrowserTask(); |
| virtual ~SetAsDefaultBrowserTask(); |
| |
| private: |
| virtual void Run(); |
| |
| DISALLOW_COPY_AND_ASSIGN(SetAsDefaultBrowserTask); |
| }; |
| |
| SetAsDefaultBrowserTask::SetAsDefaultBrowserTask() { |
| } |
| |
| SetAsDefaultBrowserTask::~SetAsDefaultBrowserTask() { |
| } |
| |
| void SetAsDefaultBrowserTask::Run() { |
| ShellIntegration::SetAsDefaultBrowser(); |
| } |
| |
| |
| // DefaultBrowserInfoBarDelegate ---------------------------------------------- |
| |
| // The delegate for the infobar shown when Chrome is not the default browser. |
| class DefaultBrowserInfoBarDelegate : public ConfirmInfoBarDelegate { |
| public: |
| explicit DefaultBrowserInfoBarDelegate(TabContents* contents); |
| |
| private: |
| virtual ~DefaultBrowserInfoBarDelegate(); |
| |
| void AllowExpiry() { should_expire_ = true; } |
| |
| // ConfirmInfoBarDelegate: |
| virtual bool ShouldExpire( |
| const NavigationController::LoadCommittedDetails& details) const OVERRIDE; |
| virtual void InfoBarClosed() OVERRIDE; |
| virtual SkBitmap* GetIcon() const OVERRIDE; |
| virtual string16 GetMessageText() const OVERRIDE; |
| virtual string16 GetButtonLabel(InfoBarButton button) const OVERRIDE; |
| virtual bool NeedElevation(InfoBarButton button) const OVERRIDE; |
| virtual bool Accept() OVERRIDE; |
| virtual bool Cancel() OVERRIDE; |
| |
| // The Profile that we restore sessions from. |
| Profile* profile_; |
| |
| // Whether the user clicked one of the buttons. |
| bool action_taken_; |
| |
| // Whether the info-bar should be dismissed on the next navigation. |
| bool should_expire_; |
| |
| // Used to delay the expiration of the info-bar. |
| ScopedRunnableMethodFactory<DefaultBrowserInfoBarDelegate> method_factory_; |
| |
| DISALLOW_COPY_AND_ASSIGN(DefaultBrowserInfoBarDelegate); |
| }; |
| |
| DefaultBrowserInfoBarDelegate::DefaultBrowserInfoBarDelegate( |
| TabContents* contents) |
| : ConfirmInfoBarDelegate(contents), |
| profile_(contents->profile()), |
| action_taken_(false), |
| should_expire_(false), |
| ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { |
| // We want the info-bar to stick-around for few seconds and then be hidden |
| // on the next navigation after that. |
| MessageLoop::current()->PostDelayedTask(FROM_HERE, |
| method_factory_.NewRunnableMethod( |
| &DefaultBrowserInfoBarDelegate::AllowExpiry), 8000); // 8 seconds. |
| } |
| |
| DefaultBrowserInfoBarDelegate::~DefaultBrowserInfoBarDelegate() { |
| } |
| |
| bool DefaultBrowserInfoBarDelegate::ShouldExpire( |
| const NavigationController::LoadCommittedDetails& details) const { |
| return should_expire_; |
| } |
| |
| void DefaultBrowserInfoBarDelegate::InfoBarClosed() { |
| if (!action_taken_) |
| UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.Ignored", 1); |
| delete this; |
| } |
| |
| SkBitmap* DefaultBrowserInfoBarDelegate::GetIcon() const { |
| return ResourceBundle::GetSharedInstance().GetBitmapNamed( |
| IDR_PRODUCT_ICON_32); |
| } |
| |
| string16 DefaultBrowserInfoBarDelegate::GetMessageText() const { |
| return l10n_util::GetStringUTF16(IDS_DEFAULT_BROWSER_INFOBAR_SHORT_TEXT); |
| } |
| |
| string16 DefaultBrowserInfoBarDelegate::GetButtonLabel( |
| InfoBarButton button) const { |
| return l10n_util::GetStringUTF16((button == BUTTON_OK) ? |
| IDS_SET_AS_DEFAULT_INFOBAR_BUTTON_LABEL : |
| IDS_DONT_ASK_AGAIN_INFOBAR_BUTTON_LABEL); |
| } |
| |
| bool DefaultBrowserInfoBarDelegate::NeedElevation(InfoBarButton button) const { |
| return button == BUTTON_OK; |
| } |
| |
| bool DefaultBrowserInfoBarDelegate::Accept() { |
| action_taken_ = true; |
| UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.SetAsDefault", 1); |
| g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE, |
| new SetAsDefaultBrowserTask()); |
| return true; |
| } |
| |
| bool DefaultBrowserInfoBarDelegate::Cancel() { |
| action_taken_ = true; |
| UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.DontSetAsDefault", 1); |
| // User clicked "Don't ask me again", remember that. |
| profile_->GetPrefs()->SetBoolean(prefs::kCheckDefaultBrowser, false); |
| return true; |
| } |
| |
| |
| // NotifyNotDefaultBrowserTask ------------------------------------------------ |
| |
| class NotifyNotDefaultBrowserTask : public Task { |
| public: |
| NotifyNotDefaultBrowserTask(); |
| virtual ~NotifyNotDefaultBrowserTask(); |
| |
| private: |
| virtual void Run(); |
| |
| DISALLOW_COPY_AND_ASSIGN(NotifyNotDefaultBrowserTask); |
| }; |
| |
| NotifyNotDefaultBrowserTask::NotifyNotDefaultBrowserTask() { |
| } |
| |
| NotifyNotDefaultBrowserTask::~NotifyNotDefaultBrowserTask() { |
| } |
| |
| void NotifyNotDefaultBrowserTask::Run() { |
| Browser* browser = BrowserList::GetLastActive(); |
| if (!browser) |
| return; // Reached during ui tests. |
| // Don't show the info-bar if there are already info-bars showing. |
| // In ChromeBot tests, there might be a race. This line appears to get |
| // called during shutdown and |tab| can be NULL. |
| TabContents* tab = browser->GetSelectedTabContents(); |
| if (!tab || tab->infobar_count() > 0) |
| return; |
| tab->AddInfoBar(new DefaultBrowserInfoBarDelegate(tab)); |
| } |
| |
| |
| // CheckDefaultBrowserTask ---------------------------------------------------- |
| |
| class CheckDefaultBrowserTask : public Task { |
| public: |
| CheckDefaultBrowserTask(); |
| virtual ~CheckDefaultBrowserTask(); |
| |
| private: |
| virtual void Run(); |
| |
| DISALLOW_COPY_AND_ASSIGN(CheckDefaultBrowserTask); |
| }; |
| |
| CheckDefaultBrowserTask::CheckDefaultBrowserTask() { |
| } |
| |
| CheckDefaultBrowserTask::~CheckDefaultBrowserTask() { |
| } |
| |
| void CheckDefaultBrowserTask::Run() { |
| if (ShellIntegration::IsDefaultBrowser() || |
| !platform_util::CanSetAsDefaultBrowser()) { |
| return; |
| } |
| BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| new NotifyNotDefaultBrowserTask()); |
| } |
| |
| |
| // SessionCrashedInfoBarDelegate ---------------------------------------------- |
| |
| // A delegate for the InfoBar shown when the previous session has crashed. |
| class SessionCrashedInfoBarDelegate : public ConfirmInfoBarDelegate { |
| public: |
| explicit SessionCrashedInfoBarDelegate(TabContents* contents); |
| |
| private: |
| virtual ~SessionCrashedInfoBarDelegate(); |
| |
| // ConfirmInfoBarDelegate: |
| virtual void InfoBarClosed() OVERRIDE; |
| virtual SkBitmap* GetIcon() const OVERRIDE; |
| virtual string16 GetMessageText() const OVERRIDE; |
| virtual int GetButtons() const OVERRIDE; |
| virtual string16 GetButtonLabel(InfoBarButton button) const OVERRIDE; |
| virtual bool Accept() OVERRIDE; |
| |
| // The Profile that we restore sessions from. |
| Profile* profile_; |
| |
| DISALLOW_COPY_AND_ASSIGN(SessionCrashedInfoBarDelegate); |
| }; |
| |
| SessionCrashedInfoBarDelegate::SessionCrashedInfoBarDelegate( |
| TabContents* contents) |
| : ConfirmInfoBarDelegate(contents), |
| profile_(contents->profile()) { |
| } |
| |
| SessionCrashedInfoBarDelegate::~SessionCrashedInfoBarDelegate() { |
| } |
| |
| void SessionCrashedInfoBarDelegate::InfoBarClosed() { |
| delete this; |
| } |
| |
| SkBitmap* SessionCrashedInfoBarDelegate::GetIcon() const { |
| return ResourceBundle::GetSharedInstance().GetBitmapNamed( |
| IDR_INFOBAR_RESTORE_SESSION); |
| } |
| |
| string16 SessionCrashedInfoBarDelegate::GetMessageText() const { |
| return l10n_util::GetStringUTF16(IDS_SESSION_CRASHED_VIEW_MESSAGE); |
| } |
| |
| int SessionCrashedInfoBarDelegate::GetButtons() const { |
| return BUTTON_OK; |
| } |
| |
| string16 SessionCrashedInfoBarDelegate::GetButtonLabel( |
| InfoBarButton button) const { |
| DCHECK_EQ(BUTTON_OK, button); |
| return l10n_util::GetStringUTF16(IDS_SESSION_CRASHED_VIEW_RESTORE_BUTTON); |
| } |
| |
| bool SessionCrashedInfoBarDelegate::Accept() { |
| SessionRestore::RestoreSession(profile_, NULL, true, false, |
| std::vector<GURL>()); |
| return true; |
| } |
| |
| |
| // Utility functions ---------------------------------------------------------- |
| |
| SessionStartupPref GetSessionStartupPref(const CommandLine& command_line, |
| Profile* profile) { |
| SessionStartupPref pref = SessionStartupPref::GetStartupPref(profile); |
| if (command_line.HasSwitch(switches::kRestoreLastSession)) |
| pref.type = SessionStartupPref::LAST; |
| if (command_line.HasSwitch(switches::kIncognito) && |
| pref.type == SessionStartupPref::LAST && |
| profile->GetPrefs()->GetBoolean(prefs::kIncognitoEnabled)) { |
| // We don't store session information when incognito. If the user has |
| // chosen to restore last session and launched incognito, fallback to |
| // default launch behavior. |
| pref.type = SessionStartupPref::DEFAULT; |
| } |
| return pref; |
| } |
| |
| enum LaunchMode { |
| LM_TO_BE_DECIDED = 0, // Possibly direct launch or via a shortcut. |
| LM_AS_WEBAPP, // Launched as a installed web application. |
| LM_WITH_URLS, // Launched with urls in the cmd line. |
| LM_SHORTCUT_NONE, // Not launched from a shortcut. |
| LM_SHORTCUT_NONAME, // Launched from shortcut but no name available. |
| LM_SHORTCUT_UNKNOWN, // Launched from user-defined shortcut. |
| LM_SHORTCUT_QUICKLAUNCH, // Launched from the quick launch bar. |
| LM_SHORTCUT_DESKTOP, // Launched from a desktop shortcut. |
| LM_SHORTCUT_STARTMENU, // Launched from start menu. |
| LM_LINUX_MAC_BEOS // Other OS buckets start here. |
| }; |
| |
| #if defined(OS_WIN) |
| // Undocumented flag in the startup info structure tells us what shortcut was |
| // used to launch the browser. See http://www.catch22.net/tuts/undoc01 for |
| // more information. Confirmed to work on XP, Vista and Win7. |
| LaunchMode GetLaunchShortcutKind() { |
| STARTUPINFOW si = { sizeof(si) }; |
| GetStartupInfoW(&si); |
| if (si.dwFlags & 0x800) { |
| if (!si.lpTitle) |
| return LM_SHORTCUT_NONAME; |
| std::wstring shortcut(si.lpTitle); |
| // The windows quick launch path is not localized. |
| if (shortcut.find(L"\\Quick Launch\\") != std::wstring::npos) |
| return LM_SHORTCUT_QUICKLAUNCH; |
| scoped_ptr<base::Environment> env(base::Environment::Create()); |
| std::string appdata_path; |
| env->GetVar("USERPROFILE", &appdata_path); |
| if (!appdata_path.empty() && |
| shortcut.find(ASCIIToWide(appdata_path)) != std::wstring::npos) |
| return LM_SHORTCUT_DESKTOP; |
| return LM_SHORTCUT_UNKNOWN; |
| } |
| return LM_SHORTCUT_NONE; |
| } |
| #else |
| // TODO(cpu): Port to other platforms. |
| LaunchMode GetLaunchShortcutKind() { |
| return LM_LINUX_MAC_BEOS; |
| } |
| #endif |
| |
| // Log in a histogram the frequency of launching by the different methods. See |
| // LaunchMode enum for the actual values of the buckets. |
| void RecordLaunchModeHistogram(LaunchMode mode) { |
| int bucket = (mode == LM_TO_BE_DECIDED) ? GetLaunchShortcutKind() : mode; |
| UMA_HISTOGRAM_COUNTS_100("Launch.Modes", bucket); |
| } |
| |
| static bool in_startup = false; |
| |
| GURL GetWelcomePageURL() { |
| std::string welcome_url = l10n_util::GetStringUTF8(IDS_WELCOME_PAGE_URL); |
| return GURL(welcome_url); |
| } |
| |
| void UrlsToTabs(const std::vector<GURL>& urls, |
| std::vector<BrowserInit::LaunchWithProfile::Tab>* tabs) { |
| for (size_t i = 0; i < urls.size(); ++i) { |
| BrowserInit::LaunchWithProfile::Tab tab; |
| tab.is_pinned = false; |
| tab.url = urls[i]; |
| tabs->push_back(tab); |
| } |
| } |
| |
| // Return true if the command line option --app-id is used. Set |
| // |out_extension| to the app to open, and |out_launch_container| |
| // to the type of window into which the app should be open. |
| bool GetAppLaunchContainer( |
| Profile* profile, |
| const std::string& app_id, |
| const Extension** out_extension, |
| extension_misc::LaunchContainer* out_launch_container) { |
| |
| ExtensionService* extensions_service = profile->GetExtensionService(); |
| const Extension* extension = |
| extensions_service->GetExtensionById(app_id, false); |
| |
| // The extension with id |app_id| may have been uninstalled. |
| if (!extension) |
| return false; |
| |
| // Look at preferences to find the right launch container. If no |
| // preference is set, launch as a window. |
| extension_misc::LaunchContainer launch_container = |
| extensions_service->extension_prefs()->GetLaunchContainer( |
| extension, ExtensionPrefs::LAUNCH_WINDOW); |
| |
| *out_extension = extension; |
| *out_launch_container = launch_container; |
| return true; |
| } |
| |
| void RecordCmdLineAppHistogram() { |
| UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppLaunchHistogram, |
| extension_misc::APP_LAUNCH_CMD_LINE_APP, |
| extension_misc::APP_LAUNCH_BUCKET_BOUNDARY); |
| } |
| |
| void RecordAppLaunches( |
| Profile* profile, |
| const std::vector<GURL>& cmd_line_urls, |
| const std::vector<BrowserInit::LaunchWithProfile::Tab>& autolaunch_tabs) { |
| ExtensionService* extension_service = profile->GetExtensionService(); |
| DCHECK(extension_service); |
| for (size_t i = 0; i < cmd_line_urls.size(); ++i) { |
| if (extension_service->IsInstalledApp(cmd_line_urls.at(i))) { |
| UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppLaunchHistogram, |
| extension_misc::APP_LAUNCH_CMD_LINE_URL, |
| extension_misc::APP_LAUNCH_BUCKET_BOUNDARY); |
| } |
| } |
| for (size_t i = 0; i < autolaunch_tabs.size(); ++i) { |
| if (extension_service->IsInstalledApp(autolaunch_tabs.at(i).url)) { |
| UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppLaunchHistogram, |
| extension_misc::APP_LAUNCH_AUTOLAUNCH, |
| extension_misc::APP_LAUNCH_BUCKET_BOUNDARY); |
| } |
| } |
| } |
| |
| } // namespace |
| |
| |
| // BrowserInit ---------------------------------------------------------------- |
| |
| BrowserInit::BrowserInit() {} |
| |
| BrowserInit::~BrowserInit() {} |
| |
| void BrowserInit::AddFirstRunTab(const GURL& url) { |
| first_run_tabs_.push_back(url); |
| } |
| |
| // static |
| bool BrowserInit::InProcessStartup() { |
| return in_startup; |
| } |
| |
| bool BrowserInit::LaunchBrowser(const CommandLine& command_line, |
| Profile* profile, |
| const FilePath& cur_dir, |
| bool process_startup, |
| int* return_code) { |
| in_startup = process_startup; |
| DCHECK(profile); |
| #if defined(OS_CHROMEOS) |
| if (process_startup) { |
| // NetworkStateNotifier has to be initialized before Launching browser |
| // because the page load can happen in parallel to this UI thread |
| // and IO thread may access the NetworkStateNotifier. |
| chromeos::CrosLibrary::Get()->GetNetworkLibrary() |
| ->AddNetworkManagerObserver( |
| chromeos::NetworkStateNotifier::GetInstance()); |
| } |
| #endif |
| |
| // Continue with the incognito profile from here on if --incognito |
| if (command_line.HasSwitch(switches::kIncognito) && |
| profile->GetPrefs()->GetBoolean(prefs::kIncognitoEnabled)) { |
| profile = profile->GetOffTheRecordProfile(); |
| } |
| |
| BrowserInit::LaunchWithProfile lwp(cur_dir, command_line, this); |
| std::vector<GURL> urls_to_launch = BrowserInit::GetURLsFromCommandLine( |
| command_line, cur_dir, profile); |
| bool launched = lwp.Launch(profile, urls_to_launch, process_startup); |
| in_startup = false; |
| |
| if (!launched) { |
| LOG(ERROR) << "launch error"; |
| if (return_code) |
| *return_code = ResultCodes::INVALID_CMDLINE_URL; |
| return false; |
| } |
| |
| #if defined(OS_CHROMEOS) |
| // Initialize Chrome OS preferences like touch pad sensitivity. For the |
| // preferences to work in the guest mode, the initialization has to be |
| // done after |profile| is switched to the incognito profile (which |
| // is actually GuestSessionProfile in the guest mode). See the |
| // GetOffTheRecordProfile() call above. |
| profile->InitChromeOSPreferences(); |
| |
| // Create the WmMessageListener so that it can listen for messages regardless |
| // of what window has focus. |
| chromeos::WmMessageListener::GetInstance(); |
| |
| // Create the WmOverviewController so it can register with the listener. |
| chromeos::WmOverviewController::GetInstance(); |
| |
| // Install the GView request interceptor that will redirect requests |
| // of compatible documents (PDF, etc) to the GView document viewer. |
| const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); |
| if (parsed_command_line.HasSwitch(switches::kEnableGView)) { |
| chromeos::GViewRequestInterceptor::GetInstance(); |
| } |
| if (process_startup) { |
| // This observer is a singleton. It is never deleted but the pointer is kept |
| // in a static so that it isn't reported as a leak. |
| static chromeos::LowBatteryObserver* low_battery_observer = |
| new chromeos::LowBatteryObserver(profile); |
| chromeos::CrosLibrary::Get()->GetPowerLibrary()->AddObserver( |
| low_battery_observer); |
| |
| static chromeos::UpdateObserver* update_observer = |
| new chromeos::UpdateObserver(profile); |
| chromeos::CrosLibrary::Get()->GetUpdateLibrary()->AddObserver( |
| update_observer); |
| |
| static chromeos::NetworkMessageObserver* network_message_observer = |
| new chromeos::NetworkMessageObserver(profile); |
| chromeos::CrosLibrary::Get()->GetNetworkLibrary() |
| ->AddNetworkManagerObserver(network_message_observer); |
| chromeos::CrosLibrary::Get()->GetNetworkLibrary() |
| ->AddCellularDataPlanObserver(network_message_observer); |
| chromeos::CrosLibrary::Get()->GetNetworkLibrary() |
| ->AddUserActionObserver(network_message_observer); |
| |
| static chromeos::SmsObserver* sms_observer = |
| new chromeos::SmsObserver(profile); |
| chromeos::CrosLibrary::Get()->GetNetworkLibrary() |
| ->AddNetworkManagerObserver(sms_observer); |
| |
| profile->SetupChromeOSEnterpriseExtensionObserver(); |
| } |
| #endif |
| return true; |
| } |
| |
| |
| // BrowserInit::LaunchWithProfile::Tab ---------------------------------------- |
| |
| BrowserInit::LaunchWithProfile::Tab::Tab() : is_app(false), is_pinned(true) {} |
| |
| BrowserInit::LaunchWithProfile::Tab::~Tab() {} |
| |
| |
| // BrowserInit::LaunchWithProfile --------------------------------------------- |
| |
| BrowserInit::LaunchWithProfile::LaunchWithProfile( |
| const FilePath& cur_dir, |
| const CommandLine& command_line) |
| : cur_dir_(cur_dir), |
| command_line_(command_line), |
| profile_(NULL), |
| browser_init_(NULL) { |
| } |
| |
| BrowserInit::LaunchWithProfile::LaunchWithProfile( |
| const FilePath& cur_dir, |
| const CommandLine& command_line, |
| BrowserInit* browser_init) |
| : cur_dir_(cur_dir), |
| command_line_(command_line), |
| profile_(NULL), |
| browser_init_(browser_init) { |
| } |
| |
| BrowserInit::LaunchWithProfile::~LaunchWithProfile() { |
| } |
| |
| bool BrowserInit::LaunchWithProfile::Launch( |
| Profile* profile, |
| const std::vector<GURL>& urls_to_open, |
| bool process_startup) { |
| DCHECK(profile); |
| profile_ = profile; |
| |
| if (command_line_.HasSwitch(switches::kDnsLogDetails)) |
| chrome_browser_net::EnablePredictorDetailedLog(true); |
| if (command_line_.HasSwitch(switches::kDnsPrefetchDisable)) |
| chrome_browser_net::EnablePredictor(false); |
| |
| if (command_line_.HasSwitch(switches::kDumpHistogramsOnExit)) |
| base::StatisticsRecorder::set_dump_on_exit(true); |
| |
| if (command_line_.HasSwitch(switches::kRemoteShellPort)) { |
| std::string port_str = |
| command_line_.GetSwitchValueASCII(switches::kRemoteShellPort); |
| int64 port; |
| if (base::StringToInt64(port_str, &port) && port > 0 && port < 65535) { |
| g_browser_process->InitDevToolsLegacyProtocolHandler( |
| static_cast<int>(port)); |
| } else { |
| DLOG(WARNING) << "Invalid remote shell port number " << port; |
| } |
| } else if (command_line_.HasSwitch(switches::kRemoteDebuggingPort)) { |
| std::string port_str = |
| command_line_.GetSwitchValueASCII(switches::kRemoteDebuggingPort); |
| int64 port; |
| if (base::StringToInt64(port_str, &port) && port > 0 && port < 65535) { |
| g_browser_process->InitDevToolsHttpProtocolHandler( |
| "127.0.0.1", |
| static_cast<int>(port), |
| ""); |
| } else { |
| DLOG(WARNING) << "Invalid http debugger port number " << port; |
| } |
| } |
| |
| if (command_line_.HasSwitch(switches::kUserAgent)) { |
| webkit_glue::SetUserAgent(command_line_.GetSwitchValueASCII( |
| switches::kUserAgent)); |
| } |
| |
| // Open the required browser windows and tabs. First, see if |
| // we're being run as an application window. If so, the user |
| // opened an app shortcut. Don't restore tabs or open initial |
| // URLs in that case. The user should see the window as an app, |
| // not as chrome. |
| if (OpenApplicationWindow(profile)) { |
| RecordLaunchModeHistogram(LM_AS_WEBAPP); |
| } else { |
| RecordLaunchModeHistogram(urls_to_open.empty()? |
| LM_TO_BE_DECIDED : LM_WITH_URLS); |
| ProcessLaunchURLs(process_startup, urls_to_open); |
| |
| // If this is an app launch, but we didn't open an app window, it may |
| // be an app tab. |
| OpenApplicationTab(profile); |
| |
| if (process_startup) { |
| if (browser_defaults::kOSSupportsOtherBrowsers && |
| !command_line_.HasSwitch(switches::kNoDefaultBrowserCheck)) { |
| // Check whether we are the default browser. |
| CheckDefaultBrowser(profile); |
| } |
| #if defined(OS_MACOSX) |
| // Check whether the auto-update system needs to be promoted from user |
| // to system. |
| KeystoneInfoBar::PromotionInfoBar(profile); |
| #endif |
| } |
| } |
| |
| #if defined(OS_WIN) |
| // Print the selected page if the command line switch exists. Note that the |
| // current selected tab would be the page which will be printed. |
| if (command_line_.HasSwitch(switches::kPrint)) { |
| Browser* browser = BrowserList::GetLastActive(); |
| browser->Print(); |
| } |
| #endif |
| |
| // If we're recording or playing back, startup the EventRecorder now |
| // unless otherwise specified. |
| if (!command_line_.HasSwitch(switches::kNoEvents)) { |
| FilePath script_path; |
| PathService::Get(chrome::FILE_RECORDED_SCRIPT, &script_path); |
| |
| bool record_mode = command_line_.HasSwitch(switches::kRecordMode); |
| bool playback_mode = command_line_.HasSwitch(switches::kPlaybackMode); |
| |
| if (record_mode && chrome::kRecordModeEnabled) |
| base::EventRecorder::current()->StartRecording(script_path); |
| if (playback_mode) |
| base::EventRecorder::current()->StartPlayback(script_path); |
| } |
| |
| #if defined(OS_WIN) |
| if (process_startup) |
| ShellIntegration::MigrateChromiumShortcuts(); |
| #endif // defined(OS_WIN) |
| |
| return true; |
| } |
| |
| bool BrowserInit::LaunchWithProfile::IsAppLaunch(std::string* app_url, |
| std::string* app_id) { |
| if (command_line_.HasSwitch(switches::kApp)) { |
| if (app_url) |
| *app_url = command_line_.GetSwitchValueASCII(switches::kApp); |
| return true; |
| } |
| if (command_line_.HasSwitch(switches::kAppId)) { |
| if (app_id) |
| *app_id = command_line_.GetSwitchValueASCII(switches::kAppId); |
| return true; |
| } |
| return false; |
| } |
| |
| bool BrowserInit::LaunchWithProfile::OpenApplicationTab(Profile* profile) { |
| std::string app_id; |
| // App shortcuts to URLs always open in an app window. Because this |
| // function will open an app that should be in a tab, there is no need |
| // to look at the app URL. OpenApplicationWindow() will open app url |
| // shortcuts. |
| if (!IsAppLaunch(NULL, &app_id) || app_id.empty()) |
| return false; |
| |
| extension_misc::LaunchContainer launch_container; |
| const Extension* extension; |
| if (!GetAppLaunchContainer(profile, app_id, &extension, &launch_container)) |
| return false; |
| |
| // If the user doesn't want to open a tab, fail. |
| if (launch_container != extension_misc::LAUNCH_TAB) |
| return false; |
| |
| RecordCmdLineAppHistogram(); |
| |
| TabContents* app_tab = Browser::OpenApplicationTab(profile, extension, NULL); |
| return (app_tab != NULL); |
| } |
| |
| bool BrowserInit::LaunchWithProfile::OpenApplicationWindow(Profile* profile) { |
| std::string url_string, app_id; |
| if (!IsAppLaunch(&url_string, &app_id)) |
| return false; |
| |
| // This can fail if the app_id is invalid. It can also fail if the |
| // extension is external, and has not yet been installed. |
| // TODO(skerner): Do something reasonable here. Pop up a warning panel? |
| // Open an URL to the gallery page of the extension id? |
| if (!app_id.empty()) { |
| extension_misc::LaunchContainer launch_container; |
| const Extension* extension; |
| if (!GetAppLaunchContainer(profile, app_id, &extension, &launch_container)) |
| return false; |
| |
| // TODO(skerner): Could pass in |extension| and |launch_container|, |
| // and avoid calling GetAppLaunchContainer() both here and in |
| // OpenApplicationTab(). |
| |
| if (launch_container == extension_misc::LAUNCH_TAB) |
| return false; |
| |
| RecordCmdLineAppHistogram(); |
| TabContents* tab_in_app_window = Browser::OpenApplication( |
| profile, extension, launch_container, NULL); |
| return (tab_in_app_window != NULL); |
| } |
| |
| if (url_string.empty()) |
| return false; |
| |
| #if defined(OS_WIN) // Fix up Windows shortcuts. |
| ReplaceSubstringsAfterOffset(&url_string, 0, "\\x", "%"); |
| #endif |
| GURL url(url_string); |
| |
| // Restrict allowed URLs for --app switch. |
| if (!url.is_empty() && url.is_valid()) { |
| ChildProcessSecurityPolicy *policy = |
| ChildProcessSecurityPolicy::GetInstance(); |
| if (policy->IsWebSafeScheme(url.scheme()) || |
| url.SchemeIs(chrome::kFileScheme)) { |
| |
| if (profile->GetExtensionService()->IsInstalledApp(url)) { |
| RecordCmdLineAppHistogram(); |
| } else { |
| UMA_HISTOGRAM_ENUMERATION( |
| extension_misc::kAppLaunchHistogram, |
| extension_misc::APP_LAUNCH_CMD_LINE_APP_LEGACY, |
| extension_misc::APP_LAUNCH_BUCKET_BOUNDARY); |
| } |
| TabContents* app_tab = Browser::OpenAppShortcutWindow( |
| profile, |
| url, |
| true); // Update app info. |
| return (app_tab != NULL); |
| } |
| } |
| return false; |
| } |
| |
| void BrowserInit::LaunchWithProfile::ProcessLaunchURLs( |
| bool process_startup, |
| const std::vector<GURL>& urls_to_open) { |
| // If we're starting up in "background mode" (no open browser window) then |
| // don't open any browser windows. |
| if (process_startup && command_line_.HasSwitch(switches::kNoStartupWindow)) |
| return; |
| |
| if (process_startup && ProcessStartupURLs(urls_to_open)) { |
| // ProcessStartupURLs processed the urls, nothing else to do. |
| return; |
| } |
| |
| if (!process_startup && |
| (profile_->GetSessionService() && |
| profile_->GetSessionService()->RestoreIfNecessary(urls_to_open))) { |
| // We're already running and session restore wanted to run. This can happen |
| // at various points, such as if there is only an app window running and the |
| // user double clicked the chrome icon. Return so we don't open the urls. |
| return; |
| } |
| |
| // Session restore didn't occur, open the urls. |
| |
| Browser* browser = NULL; |
| std::vector<GURL> adjust_urls = urls_to_open; |
| if (adjust_urls.empty()) |
| AddStartupURLs(&adjust_urls); |
| else if (!command_line_.HasSwitch(switches::kOpenInNewWindow)) |
| browser = BrowserList::GetLastActiveWithProfile(profile_); |
| |
| browser = OpenURLsInBrowser(browser, process_startup, adjust_urls); |
| if (process_startup) |
| AddInfoBarsIfNecessary(browser); |
| } |
| |
| bool BrowserInit::LaunchWithProfile::ProcessStartupURLs( |
| const std::vector<GURL>& urls_to_open) { |
| SessionStartupPref pref = GetSessionStartupPref(command_line_, profile_); |
| if (command_line_.HasSwitch(switches::kTestingChannelID) && |
| !command_line_.HasSwitch(switches::kRestoreLastSession) && |
| browser_defaults::kDefaultSessionStartupType != |
| SessionStartupPref::DEFAULT) { |
| // When we have non DEFAULT session start type, then we won't open up a |
| // fresh session. But none of the tests are written with this in mind, so |
| // we explicitly ignore it during testing. |
| return false; |
| } |
| |
| if (pref.type == SessionStartupPref::LAST) { |
| if (!profile_->DidLastSessionExitCleanly() && |
| !command_line_.HasSwitch(switches::kRestoreLastSession)) { |
| // The last session crashed. It's possible automatically loading the |
| // page will trigger another crash, locking the user out of chrome. |
| // To avoid this, don't restore on startup but instead show the crashed |
| // infobar. |
| return false; |
| } |
| Browser* browser = |
| SessionRestore::RestoreSessionSynchronously(profile_, urls_to_open); |
| AddInfoBarsIfNecessary(browser); |
| return true; |
| } |
| |
| std::vector<Tab> tabs = PinnedTabCodec::ReadPinnedTabs(profile_); |
| |
| RecordAppLaunches(profile_, urls_to_open, tabs); |
| |
| if (!urls_to_open.empty()) { |
| // If urls were specified on the command line, use them. |
| UrlsToTabs(urls_to_open, &tabs); |
| } else if (pref.type == SessionStartupPref::URLS && !pref.urls.empty()) { |
| // Only use the set of urls specified in preferences if nothing was |
| // specified on the command line. Filter out any urls that are to be |
| // restored by virtue of having been previously pinned. |
| AddUniqueURLs(pref.urls, &tabs); |
| } else if (pref.type == SessionStartupPref::DEFAULT && !tabs.empty()) { |
| // Make sure the home page is opened even if there are pinned tabs. |
| std::vector<GURL> urls; |
| AddStartupURLs(&urls); |
| UrlsToTabs(urls, &tabs); |
| } |
| |
| if (tabs.empty()) |
| return false; |
| |
| Browser* browser = OpenTabsInBrowser(NULL, true, tabs); |
| AddInfoBarsIfNecessary(browser); |
| return true; |
| } |
| |
| void BrowserInit::LaunchWithProfile::AddUniqueURLs( |
| const std::vector<GURL>& urls, |
| std::vector<Tab>* tabs) { |
| size_t num_existing_tabs = tabs->size(); |
| for (size_t i = 0; i < urls.size(); ++i) { |
| bool in_tabs = false; |
| for (size_t j = 0; j < num_existing_tabs; ++j) { |
| if (urls[i] == (*tabs)[j].url) { |
| in_tabs = true; |
| break; |
| } |
| } |
| if (!in_tabs) { |
| BrowserInit::LaunchWithProfile::Tab tab; |
| tab.is_pinned = false; |
| tab.url = urls[i]; |
| tabs->push_back(tab); |
| } |
| } |
| } |
| |
| Browser* BrowserInit::LaunchWithProfile::OpenURLsInBrowser( |
| Browser* browser, |
| bool process_startup, |
| const std::vector<GURL>& urls) { |
| std::vector<Tab> tabs; |
| UrlsToTabs(urls, &tabs); |
| return OpenTabsInBrowser(browser, process_startup, tabs); |
| } |
| |
| Browser* BrowserInit::LaunchWithProfile::OpenTabsInBrowser( |
| Browser* browser, |
| bool process_startup, |
| const std::vector<Tab>& tabs) { |
| DCHECK(!tabs.empty()); |
| // If we don't yet have a profile, try to use the one we're given from |
| // |browser|. While we may not end up actually using |browser| (since it |
| // could be a popup window), we can at least use the profile. |
| if (!profile_ && browser) |
| profile_ = browser->profile(); |
| |
| if (!browser || browser->type() != Browser::TYPE_NORMAL) { |
| browser = Browser::Create(profile_); |
| } else { |
| #if defined(TOOLKIT_GTK) |
| // Setting the time of the last action on the window here allows us to steal |
| // focus, which is what the user wants when opening a new tab in an existing |
| // browser window. |
| gtk_util::SetWMLastUserActionTime(browser->window()->GetNativeHandle()); |
| #endif |
| } |
| |
| #if !defined(OS_MACOSX) |
| // In kiosk mode, we want to always be fullscreen, so switch to that now. |
| if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode)) |
| browser->ToggleFullscreenMode(); |
| #endif |
| |
| bool first_tab = true; |
| for (size_t i = 0; i < tabs.size(); ++i) { |
| // We skip URLs that we'd have to launch an external protocol handler for. |
| // This avoids us getting into an infinite loop asking ourselves to open |
| // a URL, should the handler be (incorrectly) configured to be us. Anyone |
| // asking us to open such a URL should really ask the handler directly. |
| if (!process_startup && !net::URLRequest::IsHandledURL(tabs[i].url)) |
| continue; |
| |
| int add_types = first_tab ? TabStripModel::ADD_ACTIVE : |
| TabStripModel::ADD_NONE; |
| add_types |= TabStripModel::ADD_FORCE_INDEX; |
| if (tabs[i].is_pinned) |
| add_types |= TabStripModel::ADD_PINNED; |
| int index = browser->GetIndexForInsertionDuringRestore(i); |
| |
| browser::NavigateParams params(browser, tabs[i].url, |
| PageTransition::START_PAGE); |
| params.disposition = first_tab ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB; |
| params.tabstrip_index = index; |
| params.tabstrip_add_types = add_types; |
| params.extension_app_id = tabs[i].app_id; |
| browser::Navigate(¶ms); |
| |
| first_tab = false; |
| } |
| browser->window()->Show(); |
| // TODO(jcampan): http://crbug.com/8123 we should not need to set the initial |
| // focus explicitly. |
| browser->GetSelectedTabContents()->view()->SetInitialFocus(); |
| |
| return browser; |
| } |
| |
| void BrowserInit::LaunchWithProfile::AddInfoBarsIfNecessary(Browser* browser) { |
| if (!browser || !profile_ || browser->tab_count() == 0) |
| return; |
| |
| TabContents* tab_contents = browser->GetSelectedTabContents(); |
| AddCrashedInfoBarIfNecessary(tab_contents); |
| AddBadFlagsInfoBarIfNecessary(tab_contents); |
| AddDNSCertProvenanceCheckingWarningInfoBarIfNecessary(tab_contents); |
| AddObsoleteSystemInfoBarIfNecessary(tab_contents); |
| } |
| |
| void BrowserInit::LaunchWithProfile::AddCrashedInfoBarIfNecessary( |
| TabContents* tab) { |
| // Assume that if the user is launching incognito they were previously |
| // running incognito so that we have nothing to restore from. |
| if (!profile_->DidLastSessionExitCleanly() && |
| !profile_->IsOffTheRecord()) { |
| // The last session didn't exit cleanly. Show an infobar to the user |
| // so that they can restore if they want. The delegate deletes itself when |
| // it is closed. |
| tab->AddInfoBar(new SessionCrashedInfoBarDelegate(tab)); |
| } |
| } |
| |
| void BrowserInit::LaunchWithProfile::AddBadFlagsInfoBarIfNecessary( |
| TabContents* tab) { |
| // Unsupported flags for which to display a warning that "stability and |
| // security will suffer". |
| static const char* kBadFlags[] = { |
| // These imply disabling the sandbox. |
| switches::kSingleProcess, |
| switches::kNoSandbox, |
| switches::kInProcessWebGL, |
| // These are scary features for developers that shouldn't be turned on |
| // persistently. |
| switches::kEnableNaCl, |
| NULL |
| }; |
| |
| const char* bad_flag = NULL; |
| for (const char** flag = kBadFlags; *flag; ++flag) { |
| if (command_line_.HasSwitch(*flag)) { |
| bad_flag = *flag; |
| break; |
| } |
| } |
| |
| if (bad_flag) { |
| tab->AddInfoBar(new SimpleAlertInfoBarDelegate(tab, NULL, |
| l10n_util::GetStringFUTF16(IDS_BAD_FLAGS_WARNING_MESSAGE, |
| UTF8ToUTF16(std::string("--") + bad_flag)), |
| false)); |
| } |
| } |
| |
| class LearnMoreInfoBar : public LinkInfoBarDelegate { |
| public: |
| explicit LearnMoreInfoBar(TabContents* tab_contents, |
| const string16& message, |
| const GURL& url); |
| virtual ~LearnMoreInfoBar(); |
| |
| virtual string16 GetMessageTextWithOffset(size_t* link_offset) const OVERRIDE; |
| virtual string16 GetLinkText() const OVERRIDE; |
| virtual bool LinkClicked(WindowOpenDisposition disposition) OVERRIDE; |
| |
| private: |
| TabContents* const tab_contents_; |
| string16 message_; |
| GURL learn_more_url_; |
| |
| DISALLOW_COPY_AND_ASSIGN(LearnMoreInfoBar); |
| }; |
| |
| LearnMoreInfoBar::LearnMoreInfoBar(TabContents* tab_contents, |
| const string16& message, |
| const GURL& url) |
| : LinkInfoBarDelegate(tab_contents), |
| tab_contents_(tab_contents), |
| message_(message), |
| learn_more_url_(url) { |
| } |
| |
| LearnMoreInfoBar::~LearnMoreInfoBar() { |
| } |
| |
| string16 LearnMoreInfoBar::GetMessageTextWithOffset(size_t* link_offset) const { |
| string16 text = message_; |
| text.push_back(' '); // Add a space before the following link. |
| *link_offset = text.size(); |
| return text; |
| } |
| |
| string16 LearnMoreInfoBar::GetLinkText() const { |
| return l10n_util::GetStringUTF16(IDS_LEARN_MORE); |
| } |
| |
| bool LearnMoreInfoBar::LinkClicked(WindowOpenDisposition disposition) { |
| tab_contents_->OpenURL(learn_more_url_, GURL(), disposition, |
| PageTransition::LINK); |
| return false; |
| } |
| |
| // This is the page which provides information on DNS certificate provenance |
| // checking. |
| void BrowserInit::LaunchWithProfile:: |
| AddDNSCertProvenanceCheckingWarningInfoBarIfNecessary(TabContents* tab) { |
| if (!command_line_.HasSwitch(switches::kEnableDNSCertProvenanceChecking)) |
| return; |
| |
| const char* kLearnMoreURL = |
| "http://dev.chromium.org/dnscertprovenancechecking"; |
| string16 message = l10n_util::GetStringUTF16( |
| IDS_DNS_CERT_PROVENANCE_CHECKING_WARNING_MESSAGE); |
| tab->AddInfoBar(new LearnMoreInfoBar(tab, |
| message, |
| GURL(kLearnMoreURL))); |
| } |
| |
| void BrowserInit::LaunchWithProfile::AddObsoleteSystemInfoBarIfNecessary( |
| TabContents* tab) { |
| #if defined(TOOLKIT_USES_GTK) |
| // We've deprecated support for Ubuntu Hardy. Rather than attempting to |
| // determine whether you're using that, we instead key off the GTK version; |
| // this will also deprecate other distributions (including variants of Ubuntu) |
| // that are of a similar age. |
| // Version key: |
| // Ubuntu Hardy: GTK 2.12 |
| // RHEL 6: GTK 2.18 |
| // Ubuntu Lucid: GTK 2.20 |
| if (gtk_check_version(2, 18, 0)) { |
| string16 message = |
| l10n_util::GetStringFUTF16(IDS_SYSTEM_OBSOLETE_MESSAGE, |
| l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)); |
| // Link to an article in the help center on minimum system requirements. |
| const char* kLearnMoreURL = |
| "http://www.google.com/support/chrome/bin/answer.py?answer=95411"; |
| tab->AddInfoBar(new LearnMoreInfoBar(tab, |
| message, |
| GURL(kLearnMoreURL))); |
| } |
| #endif |
| } |
| |
| void BrowserInit::LaunchWithProfile::AddStartupURLs( |
| std::vector<GURL>* startup_urls) const { |
| // If we have urls specified beforehand (i.e. from command line) use them |
| // and nothing else. |
| if (!startup_urls->empty()) |
| return; |
| // If we have urls specified by the first run master preferences use them |
| // and nothing else. |
| if (browser_init_) { |
| if (!browser_init_->first_run_tabs_.empty()) { |
| std::vector<GURL>::iterator it = browser_init_->first_run_tabs_.begin(); |
| while (it != browser_init_->first_run_tabs_.end()) { |
| // Replace magic names for the actual urls. |
| if (it->host() == "new_tab_page") { |
| startup_urls->push_back(GURL(chrome::kChromeUINewTabURL)); |
| } else if (it->host() == "welcome_page") { |
| startup_urls->push_back(GetWelcomePageURL()); |
| } else { |
| startup_urls->push_back(*it); |
| } |
| ++it; |
| } |
| browser_init_->first_run_tabs_.clear(); |
| return; |
| } |
| } |
| |
| // Otherwise open at least the new tab page (and the welcome page, if this |
| // is the first time the browser is being started), or the set of URLs |
| // specified on the command line. |
| startup_urls->push_back(GURL()); // New tab page. |
| PrefService* prefs = g_browser_process->local_state(); |
| if (prefs->FindPreference(prefs::kShouldShowWelcomePage) && |
| prefs->GetBoolean(prefs::kShouldShowWelcomePage)) { |
| // Reset the preference so we don't show the welcome page next time. |
| prefs->ClearPref(prefs::kShouldShowWelcomePage); |
| startup_urls->push_back(GetWelcomePageURL()); |
| } |
| } |
| |
| void BrowserInit::LaunchWithProfile::CheckDefaultBrowser(Profile* profile) { |
| // We do not check if we are the default browser if: |
| // - the user said "don't ask me again" on the infobar earlier. |
| // - this is the first launch after the first run flow. |
| // - There is a policy in control of this setting. |
| if (!profile->GetPrefs()->GetBoolean(prefs::kCheckDefaultBrowser) || |
| FirstRun::IsChromeFirstRun()) { |
| return; |
| } |
| if (g_browser_process->local_state()->IsManagedPreference( |
| prefs::kDefaultBrowserSettingEnabled)) { |
| if (g_browser_process->local_state()->GetBoolean( |
| prefs::kDefaultBrowserSettingEnabled)) { |
| BrowserThread::PostTask( |
| BrowserThread::FILE, FROM_HERE, NewRunnableFunction( |
| &ShellIntegration::SetAsDefaultBrowser)); |
| } else { |
| // TODO(pastarmovj): We can't really do anything meaningful here yet but |
| // just prevent showing the infobar. |
| } |
| return; |
| } |
| BrowserThread::PostTask( |
| BrowserThread::FILE, FROM_HERE, new CheckDefaultBrowserTask()); |
| } |
| |
| std::vector<GURL> BrowserInit::GetURLsFromCommandLine( |
| const CommandLine& command_line, |
| const FilePath& cur_dir, |
| Profile* profile) { |
| std::vector<GURL> urls; |
| const std::vector<CommandLine::StringType>& params = command_line.args(); |
| |
| for (size_t i = 0; i < params.size(); ++i) { |
| FilePath param = FilePath(params[i]); |
| // Handle Vista way of searching - "? <search-term>" |
| if (param.value().size() > 2 && |
| param.value()[0] == '?' && param.value()[1] == ' ') { |
| const TemplateURL* default_provider = |
| profile->GetTemplateURLModel()->GetDefaultSearchProvider(); |
| if (default_provider && default_provider->url()) { |
| const TemplateURLRef* search_url = default_provider->url(); |
| DCHECK(search_url->SupportsReplacement()); |
| string16 search_term = param.LossyDisplayName().substr(2); |
| urls.push_back(GURL(search_url->ReplaceSearchTerms( |
| *default_provider, search_term, |
| TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, |
| string16()))); |
| continue; |
| } |
| } |
| |
| // Otherwise, fall through to treating it as a URL. |
| |
| // This will create a file URL or a regular URL. |
| // This call can (in rare circumstances) block the UI thread. |
| // Allow it until this bug is fixed. |
| // http://code.google.com/p/chromium/issues/detail?id=60641 |
| GURL url; |
| { |
| base::ThreadRestrictions::ScopedAllowIO allow_io; |
| url = URLFixerUpper::FixupRelativeFile(cur_dir, param); |
| } |
| // Exclude dangerous schemes. |
| if (url.is_valid()) { |
| ChildProcessSecurityPolicy *policy = |
| ChildProcessSecurityPolicy::GetInstance(); |
| if (policy->IsWebSafeScheme(url.scheme()) || |
| url.SchemeIs(chrome::kFileScheme) || |
| #if defined(OS_CHROMEOS) |
| // In ChromeOS, allow a settings page to be specified on the |
| // command line. See ExistingUserController::OnLoginSuccess. |
| (url.spec().find(chrome::kChromeUISettingsURL) == 0) || |
| #endif |
| (url.spec().compare(chrome::kAboutBlankURL) == 0)) { |
| urls.push_back(url); |
| } |
| } |
| } |
| return urls; |
| } |
| |
| bool BrowserInit::ProcessCmdLineImpl(const CommandLine& command_line, |
| const FilePath& cur_dir, |
| bool process_startup, |
| Profile* profile, |
| int* return_code, |
| BrowserInit* browser_init) { |
| DCHECK(profile); |
| if (process_startup) { |
| if (command_line.HasSwitch(switches::kDisablePromptOnRepost)) |
| NavigationController::DisablePromptOnRepost(); |
| |
| // Look for the testing channel ID ONLY during process startup |
| if (command_line.HasSwitch(switches::kTestingChannelID)) { |
| std::string testing_channel_id = command_line.GetSwitchValueASCII( |
| switches::kTestingChannelID); |
| // TODO(sanjeevr) Check if we need to make this a singleton for |
| // compatibility with the old testing code |
| // If there are any extra parameters, we expect each one to generate a |
| // new tab; if there are none then we get one homepage tab. |
| int expected_tab_count = 1; |
| if (command_line.HasSwitch(switches::kNoStartupWindow)) { |
| expected_tab_count = 0; |
| #if defined(OS_CHROMEOS) |
| // kLoginManager will cause Chrome to start up with the ChromeOS login |
| // screen instead of a browser window, so it won't load any tabs. |
| } else if (command_line.HasSwitch(switches::kLoginManager)) { |
| expected_tab_count = 0; |
| #endif |
| } else if (command_line.HasSwitch(switches::kRestoreLastSession)) { |
| std::string restore_session_value( |
| command_line.GetSwitchValueASCII(switches::kRestoreLastSession)); |
| base::StringToInt(restore_session_value, &expected_tab_count); |
| } else { |
| std::vector<GURL> urls_to_open = GetURLsFromCommandLine( |
| command_line, cur_dir, profile); |
| expected_tab_count = |
| std::max(1, static_cast<int>(urls_to_open.size())); |
| } |
| if (!CreateAutomationProvider<TestingAutomationProvider>( |
| testing_channel_id, |
| profile, |
| static_cast<size_t>(expected_tab_count))) |
| return false; |
| } |
| } |
| |
| bool silent_launch = false; |
| |
| if (command_line.HasSwitch(switches::kAutomationClientChannelID)) { |
| std::string automation_channel_id = command_line.GetSwitchValueASCII( |
| switches::kAutomationClientChannelID); |
| // If there are any extra parameters, we expect each one to generate a |
| // new tab; if there are none then we have no tabs |
| std::vector<GURL> urls_to_open = GetURLsFromCommandLine( |
| command_line, cur_dir, profile); |
| size_t expected_tabs = |
| std::max(static_cast<int>(urls_to_open.size()), 0); |
| if (expected_tabs == 0) |
| silent_launch = true; |
| |
| if (command_line.HasSwitch(switches::kChromeFrame)) { |
| if (!CreateAutomationProvider<ChromeFrameAutomationProvider>( |
| automation_channel_id, profile, expected_tabs)) |
| return false; |
| } else { |
| if (!CreateAutomationProvider<AutomationProvider>( |
| automation_channel_id, profile, expected_tabs)) |
| return false; |
| } |
| } |
| |
| // If we have been invoked to display a desktop notification on behalf of |
| // the service process, we do not want to open any browser windows. |
| if (command_line.HasSwitch(switches::kNotifyCloudPrintTokenExpired)) { |
| silent_launch = true; |
| profile->GetCloudPrintProxyService()->ShowTokenExpiredNotification(); |
| } |
| |
| // If we are just displaying a print dialog we shouldn't open browser |
| // windows. |
| if (print_dialog_cloud::CreatePrintDialogFromCommandLine(command_line)) { |
| silent_launch = true; |
| } |
| |
| if (command_line.HasSwitch(switches::kExplicitlyAllowedPorts)) { |
| std::string allowed_ports = |
| command_line.GetSwitchValueASCII(switches::kExplicitlyAllowedPorts); |
| net::SetExplicitlyAllowedPorts(allowed_ports); |
| } |
| |
| #if defined(OS_CHROMEOS) |
| // The browser will be launched after the user logs in. |
| if (command_line.HasSwitch(switches::kLoginManager) || |
| command_line.HasSwitch(switches::kLoginPassword)) { |
| silent_launch = true; |
| } |
| #endif |
| |
| #if defined(HAVE_XINPUT2) && defined(TOUCH_UI) |
| // Get a list of pointer-devices that should be treated as touch-devices. |
| // TODO(sad): Instead of/in addition to getting the list from the |
| // command-line, query X for a list of touch devices. |
| std::string touch_devices = |
| command_line.GetSwitchValueASCII(switches::kTouchDevices); |
| |
| if (!touch_devices.empty()) { |
| std::vector<std::string> devs; |
| std::vector<unsigned int> device_ids; |
| unsigned int devid; |
| base::SplitString(touch_devices, ',', &devs); |
| for (std::vector<std::string>::iterator iter = devs.begin(); |
| iter != devs.end(); ++iter) { |
| if (base::StringToInt(*iter, reinterpret_cast<int*>(&devid))) { |
| device_ids.push_back(devid); |
| } else { |
| DLOG(WARNING) << "Invalid touch-device id: " << *iter; |
| } |
| } |
| views::SetTouchDeviceList(device_ids); |
| } |
| #endif |
| |
| // If we don't want to launch a new browser window or tab (in the case |
| // of an automation request), we are done here. |
| if (!silent_launch) { |
| return browser_init->LaunchBrowser( |
| command_line, profile, cur_dir, process_startup, return_code); |
| } |
| return true; |
| } |
| |
| template <class AutomationProviderClass> |
| bool BrowserInit::CreateAutomationProvider(const std::string& channel_id, |
| Profile* profile, |
| size_t expected_tabs) { |
| scoped_refptr<AutomationProviderClass> automation = |
| new AutomationProviderClass(profile); |
| |
| if (!automation->InitializeChannel(channel_id)) |
| return false; |
| automation->SetExpectedTabCount(expected_tabs); |
| |
| AutomationProviderList* list = |
| g_browser_process->InitAutomationProviderList(); |
| DCHECK(list); |
| list->AddProvider(automation); |
| |
| return true; |
| } |