background_mode_manager.cc revision 4a5e2dc747d50c653511c68ccb2cfbfb740bd5a7
13345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Copyright (c) 2010 The Chromium Authors. All rights reserved.
23345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Use of this source code is governed by a BSD-style license that can be
33345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// found in the LICENSE file.
43345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
53345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "app/l10n_util.h"
63345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "app/resource_bundle.h"
73345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/base_paths.h"
83345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/command_line.h"
93345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/file_path.h"
103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/logging.h"
113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/path_service.h"
12513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "base/utf_string_conversions.h"
13513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "chrome/app/chrome_command_ids.h"
14513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "chrome/browser/background_application_list_model.h"
153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/background_mode_manager.h"
163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/browser_list.h"
17513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "chrome/browser/extensions/extensions_service.h"
183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/metrics/user_metrics.h"
193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/prefs/pref_service.h"
203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/profile.h"
213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/shell_integration.h"
223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/status_icons/status_icon.h"
233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/status_icons/status_tray.h"
243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/common/chrome_switches.h"
253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/common/extensions/extension.h"
263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/common/notification_service.h"
273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/common/notification_type.h"
283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/common/pref_names.h"
293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "grit/browser_resources.h"
303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "grit/chromium_strings.h"
313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "grit/generated_resources.h"
323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "grit/theme_resources.h"
333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#if defined(OS_LINUX)
353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include <unistd.h>
363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/environment.h"
373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/file_util.h"
38513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "base/nix/xdg_util.h"
393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/task.h"
403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/utf_string_conversions.h"
413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/common/chrome_version_info.h"
423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#endif
433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#if defined(OS_MACOSX)
453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/mac_util.h"
463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#endif
473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#if defined(TOOLKIT_GTK)
493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/gtk/gtk_util.h"
503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#endif
513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#if defined(OS_LINUX)
533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstatic const FilePath::CharType kAutostart[] = "autostart";
543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstatic const FilePath::CharType kConfig[] = ".config";
553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstatic const char kXdgConfigHome[] = "XDG_CONFIG_HOME";
563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#endif
573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#if defined(OS_WIN)
59731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/win/registry.h"
603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst HKEY kBackgroundModeRegistryRootKey = HKEY_CURRENT_USER;
613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst wchar_t* kBackgroundModeRegistrySubkey =
623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    L"Software\\Microsoft\\Windows\\CurrentVersion\\Run";
633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst wchar_t* kBackgroundModeRegistryKeyName = L"chromium";
643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#endif
653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#if defined(OS_LINUX)
673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merricknamespace {
683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
693345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickFilePath GetAutostartDirectory(base::Environment* environment) {
70731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  FilePath result =
72731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      base::nix::GetXDGDirectory(environment, kXdgConfigHome, kConfig);
733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  result = result.Append(kAutostart);
743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return result;
753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
773345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickFilePath GetAutostartFilename(base::Environment* environment) {
783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  FilePath directory = GetAutostartDirectory(environment);
793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return directory.Append(ShellIntegration::GetDesktopName(environment));
803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}  // namespace
833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickclass DisableLaunchOnStartupTask : public Task {
853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick public:
863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  virtual void Run() {
873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    scoped_ptr<base::Environment> environment(base::Environment::Create());
883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!file_util::Delete(GetAutostartFilename(environment.get()), false)) {
893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      LOG(WARNING) << "Failed to deregister launch on login.";
903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick};
933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// TODO(rickcam): Bug 56280: Share implementation with ShellIntegration
953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickclass EnableLaunchOnStartupTask : public Task {
963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick public:
973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  virtual void Run() {
983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    scoped_ptr<base::Environment> environment(base::Environment::Create());
993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    scoped_ptr<chrome::VersionInfo> version_info(new chrome::VersionInfo());
1003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    FilePath autostart_directory = GetAutostartDirectory(environment.get());
1013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    FilePath autostart_file = GetAutostartFilename(environment.get());
1023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!file_util::DirectoryExists(autostart_directory) &&
1033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        !file_util::CreateDirectory(autostart_directory)) {
104731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      LOG(WARNING)
105731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        << "Failed to register launch on login.  No autostart directory.";
1063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      return;
1073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
1083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    std::string wrapper_script;
1093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!environment->GetVar("CHROME_WRAPPER", &wrapper_script)) {
110731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      LOG(WARNING)
111731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        << "Failed to register launch on login.  CHROME_WRAPPER not set.";
1123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      return;
1133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
1143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    std::string autostart_file_contents =
1153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        "[Desktop Entry]\n"
1163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        "Type=Application\n"
1173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        "Terminal=false\n"
118731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        "Exec=" + wrapper_script +
119731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        " --enable-background-mode --no-startup-window\n"
1203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        "Name=" + version_info->Name() + "\n";
121731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    std::string::size_type content_length = autostart_file_contents.length();
1223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (file_util::WriteFile(autostart_file, autostart_file_contents.c_str(),
123731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                             content_length) !=
124731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        static_cast<int>(content_length)) {
125731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      LOG(WARNING) << "Failed to register launch on login.  Failed to write "
126731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                   << autostart_file.value();
127731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      file_util::Delete(GetAutostartFilename(environment.get()), false);
128731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    }
1293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick};
1313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#endif  // defined(OS_LINUX)
1323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
133513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid BackgroundModeManager::OnApplicationDataChanged(
134513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const Extension* extension) {
135513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  UpdateContextMenuEntryIcon(extension);
136513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
137513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
138513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid BackgroundModeManager::OnApplicationListChanged() {
139513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  UpdateStatusTrayIconContextMenu();
140513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
141513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
1423345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickBackgroundModeManager::BackgroundModeManager(Profile* profile,
1433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                             CommandLine* command_line)
1443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    : profile_(profile),
145513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      applications_(profile),
1463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      background_app_count_(0),
147513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      context_menu_(NULL),
148513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      context_menu_application_offset_(0),
1493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      in_background_mode_(false),
150731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      keep_alive_for_startup_(false),
1513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      status_tray_(NULL),
1523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      status_icon_(NULL) {
153731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // If background mode or apps are disabled, just exit - don't listen for
1543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // any notifications.
155731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!command_line->HasSwitch(switches::kEnableBackgroundMode) ||
156731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      command_line->HasSwitch(switches::kDisableExtensions))
1573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
1583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
159731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // Keep the browser alive until extensions are done loading - this is needed
160731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // by the --no-startup-window flag. We want to stay alive until we load
161731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // extensions, at which point we should either run in background mode (if
162731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // there are background apps) or exit if there are none.
163731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (command_line->HasSwitch(switches::kNoStartupWindow)) {
164731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    keep_alive_for_startup_ = true;
165731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    BrowserList::StartKeepAlive();
166731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
167731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
1683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // If the -keep-alive-for-test flag is passed, then always keep chrome running
1693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // in the background until the user explicitly terminates it, by acting as if
1703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // we loaded a background app.
1713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKeepAliveForTest))
1723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    OnBackgroundAppLoaded();
1733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // When an extension is installed, make sure launch on startup is properly
1753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // set if appropriate. Likewise, turn off launch on startup when the last
1763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // background app is uninstalled.
1773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  registrar_.Add(this, NotificationType::EXTENSION_INSTALLED,
1783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                 Source<Profile>(profile));
1793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  registrar_.Add(this, NotificationType::EXTENSION_UNINSTALLED,
1803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                 Source<Profile>(profile));
1813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Listen for when extensions are loaded/unloaded so we can track the
1823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // number of background apps.
1833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  registrar_.Add(this, NotificationType::EXTENSION_LOADED,
1843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                 Source<Profile>(profile));
1853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
1863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                 Source<Profile>(profile));
1873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Check for the presence of background apps after all extensions have been
1893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // loaded, to handle the case where an extension has been manually removed
1903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // while Chrome was not running.
1913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  registrar_.Add(this, NotificationType::EXTENSIONS_READY,
1923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                 Source<Profile>(profile));
1933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Listen for the application shutting down so we can decrement our KeepAlive
1953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // count.
1963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  registrar_.Add(this, NotificationType::APP_TERMINATING,
1973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                 NotificationService::AllSources());
1983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Listen for changes to the background mode preference.
2003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  pref_registrar_.Init(profile_->GetPrefs());
2013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  pref_registrar_.Add(prefs::kBackgroundModeEnabled, this);
202513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
203513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  applications_.AddObserver(this);
2043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2063345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickBackgroundModeManager::~BackgroundModeManager() {
207513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  applications_.RemoveObserver(this);
208513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
2093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // We're going away, so exit background mode (does nothing if we aren't in
2103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // background mode currently). This is primarily needed for unit tests,
2113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // because in an actual running system we'd get an APP_TERMINATING
2123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // notification before being destroyed.
2133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  EndBackgroundMode();
2143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool BackgroundModeManager::IsBackgroundModeEnabled() {
2173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return profile_->GetPrefs()->GetBoolean(prefs::kBackgroundModeEnabled);
2183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool BackgroundModeManager::IsLaunchOnStartupResetAllowed() {
2213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return profile_->GetPrefs()->GetBoolean(prefs::kLaunchOnStartupResetAllowed);
2223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BackgroundModeManager::SetLaunchOnStartupResetAllowed(bool allowed) {
2253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  profile_->GetPrefs()->SetBoolean(prefs::kLaunchOnStartupResetAllowed,
2263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                   allowed);
2273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BackgroundModeManager::Observe(NotificationType type,
2303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                    const NotificationSource& source,
2313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                    const NotificationDetails& details) {
2323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  switch (type.value) {
2333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    case NotificationType::EXTENSIONS_READY:
234731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // Extensions are loaded, so we don't need to manually keep the browser
235731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // process alive any more when running in no-startup-window mode.
236731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      EndKeepAliveForStartup();
237731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
238731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // On a Mac, we use 'login items' mechanism which has user-facing UI so we
239731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // don't want to stomp on user choice every time we start and load
240731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // registered extensions.
2413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#if !defined(OS_MACOSX)
2423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      EnableLaunchOnStartup(IsBackgroundModeEnabled() &&
2433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                            background_app_count_ > 0);
2443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#endif
2453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      break;
2463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    case NotificationType::EXTENSION_LOADED:
247513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      if (BackgroundApplicationListModel::IsBackgroundApp(
248513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch              *Details<Extension>(details).ptr())) {
2493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        OnBackgroundAppLoaded();
250513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      }
2513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      break;
2523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    case NotificationType::EXTENSION_UNLOADED:
253513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      if (BackgroundApplicationListModel::IsBackgroundApp(
254513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch              *Details<Extension>(details).ptr())) {
2553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        OnBackgroundAppUnloaded();
256513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      }
2573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      break;
2583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    case NotificationType::EXTENSION_INSTALLED:
259513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      if (BackgroundApplicationListModel::IsBackgroundApp(
260513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch              *Details<Extension>(details).ptr())) {
2613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        OnBackgroundAppInstalled();
262513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      }
2633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      break;
2643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    case NotificationType::EXTENSION_UNINSTALLED:
265513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      if (Extension::HasApiPermission(
266513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch            Details<UninstalledExtensionInfo>(details).ptr()->
267513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                extension_api_permissions,
268513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch            Extension::kBackgroundPermission)) {
2693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        OnBackgroundAppUninstalled();
270513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      }
2713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      break;
2723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    case NotificationType::APP_TERMINATING:
273731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // Make sure we aren't still keeping the app alive (only happens if we
274731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // don't receive an EXTENSIONS_READY notification for some reason).
275731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      EndKeepAliveForStartup();
2763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // Performing an explicit shutdown, so exit background mode (does nothing
2773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // if we aren't in background mode currently).
2783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      EndBackgroundMode();
2793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // Shutting down, so don't listen for any more notifications so we don't
2803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // try to re-enter/exit background mode again.
2813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      registrar_.RemoveAll();
2823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      break;
2833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    case NotificationType::PREF_CHANGED:
2843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      DCHECK(0 == Details<std::string>(details).ptr()->compare(
2853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          prefs::kBackgroundModeEnabled));
2863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      OnBackgroundModePrefChanged();
2873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      break;
2883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    default:
2893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      NOTREACHED();
2903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      break;
2913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
2923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
294731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid BackgroundModeManager::EndKeepAliveForStartup() {
295731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (keep_alive_for_startup_) {
296731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    keep_alive_for_startup_ = false;
297731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // We call this via the message queue to make sure we don't try to end
298731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // keep-alive (which can shutdown Chrome) before the message loop has
299731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // started.
300731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    MessageLoop::current()->PostTask(
301731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        FROM_HERE, NewRunnableFunction(BrowserList::EndKeepAlive));
302731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
3033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
3043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BackgroundModeManager::OnBackgroundModePrefChanged() {
3063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Background mode has been enabled/disabled in preferences, so update our
3073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // state accordingly.
3083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (IsBackgroundModeEnabled() && !in_background_mode_ &&
3093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      background_app_count_ > 0) {
3103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // We should be in background mode, but we're not, so switch to background
3113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // mode.
3123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    EnableLaunchOnStartup(true);
3133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    StartBackgroundMode();
3143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
3153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!IsBackgroundModeEnabled() && in_background_mode_) {
3163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // We're in background mode, but we shouldn't be any longer.
3173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    EnableLaunchOnStartup(false);
3183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    EndBackgroundMode();
3193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
3203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
3213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BackgroundModeManager::OnBackgroundAppLoaded() {
3233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // When a background app loads, increment our count and also enable
3243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // KeepAlive mode if the preference is set.
3253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  background_app_count_++;
3263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (background_app_count_ == 1 && IsBackgroundModeEnabled())
3273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    StartBackgroundMode();
3283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
3293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BackgroundModeManager::StartBackgroundMode() {
3313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Don't bother putting ourselves in background mode if we're already there.
3323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (in_background_mode_)
3333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
3343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Mark ourselves as running in background mode.
3363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  in_background_mode_ = true;
3373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Put ourselves in KeepAlive mode and create a status tray icon.
3393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  BrowserList::StartKeepAlive();
3403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Display a status icon to exit Chrome.
3423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  CreateStatusTrayIcon();
3433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
3443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BackgroundModeManager::OnBackgroundAppUnloaded() {
3463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // When a background app unloads, decrement our count and also end
3473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // KeepAlive mode if appropriate.
3483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  background_app_count_--;
3493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK(background_app_count_ >= 0);
3503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (background_app_count_ == 0 && IsBackgroundModeEnabled())
3513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    EndBackgroundMode();
3523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
3533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BackgroundModeManager::EndBackgroundMode() {
3553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!in_background_mode_)
3563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
3573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  in_background_mode_ = false;
3583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // End KeepAlive mode and blow away our status tray icon.
3603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  BrowserList::EndKeepAlive();
3613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  RemoveStatusTrayIcon();
3623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
3633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BackgroundModeManager::OnBackgroundAppInstalled() {
3653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // We're installing a background app. If this is the first background app
3663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // being installed, make sure we are set to launch on startup.
3673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (IsBackgroundModeEnabled() && background_app_count_ == 0)
3683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    EnableLaunchOnStartup(true);
3693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
3703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BackgroundModeManager::OnBackgroundAppUninstalled() {
372731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // When uninstalling a background app, disable launch on startup if
373731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // we have no more background apps.
374731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (IsBackgroundModeEnabled() && background_app_count_ == 0)
3753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    EnableLaunchOnStartup(false);
3763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
3773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BackgroundModeManager::EnableLaunchOnStartup(bool should_launch) {
3793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // This functionality is only defined for default profile, currently.
3803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUserDataDir))
3813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
3823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#if defined(OS_LINUX)
3833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (should_launch)
384731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
385731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                            new EnableLaunchOnStartupTask());
3863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  else
387731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
388731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                            new DisableLaunchOnStartupTask());
3893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#elif defined(OS_MACOSX)
3903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (should_launch) {
3913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // Return if Chrome is already a Login Item (avoid overriding user choice).
3923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (mac_util::CheckLoginItemStatus(NULL))
3933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      return;
3943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    mac_util::AddToLoginItems(true);  // Hide on startup.
3963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // Remember we set Login Item, not the user - so we can reset it later.
3983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    SetLaunchOnStartupResetAllowed(true);
3993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  } else {
4003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // If we didn't set Login Item, don't mess with it.
4013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!IsLaunchOnStartupResetAllowed())
4023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      return;
4033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    SetLaunchOnStartupResetAllowed(false);
4043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
4053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // Check if Chrome is not a login Item, or is a Login Item but w/o 'hidden'
4063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // flag - most likely user has modified the setting, don't override it.
4073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    bool is_hidden = false;
4083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!mac_util::CheckLoginItemStatus(&is_hidden) || !is_hidden)
4093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      return;
4103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
4113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    mac_util::RemoveFromLoginItems();
4123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
4133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#elif defined(OS_WIN)
4143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // TODO(rickcam): Bug 53597: Make RegKey mockable.
4153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // TODO(rickcam): Bug 53600: Use distinct registry keys per flavor+profile.
4163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  const wchar_t* key_name = kBackgroundModeRegistryKeyName;
417731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  base::win::RegKey read_key(kBackgroundModeRegistryRootKey,
418731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                             kBackgroundModeRegistrySubkey, KEY_READ);
419731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  base::win::RegKey write_key(kBackgroundModeRegistryRootKey,
420731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                              kBackgroundModeRegistrySubkey, KEY_WRITE);
4213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (should_launch) {
4223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    FilePath executable;
4233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!PathService::Get(base::FILE_EXE, &executable))
4243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      return;
425731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    std::wstring new_value = executable.value() +
426731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        L" --enable-background-mode --no-startup-window";
4273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (read_key.ValueExists(key_name)) {
4283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      std::wstring current_value;
4293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      if (read_key.ReadValue(key_name, &current_value) &&
430731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          (current_value == new_value))
4313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        return;
4323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
433731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!write_key.WriteValue(key_name, new_value.c_str()))
4343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      LOG(WARNING) << "Failed to register launch on login.";
4353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  } else {
4363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (read_key.ValueExists(key_name) && !write_key.DeleteValue(key_name))
4373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      LOG(WARNING) << "Failed to deregister launch on login.";
4383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
4393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#endif
4403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
4413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
4423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BackgroundModeManager::CreateStatusTrayIcon() {
4433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Only need status icons on windows/linux. ChromeOS doesn't allow exiting
4443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Chrome and Mac can use the dock icon instead.
4453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#if !defined(OS_MACOSX) && !defined(OS_CHROMEOS)
4463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!status_tray_)
4473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    status_tray_ = profile_->GetStatusTray();
4483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#endif
4493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
4503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // If the platform doesn't support status icons, or we've already created
4513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // our status icon, just return.
4523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!status_tray_ || status_icon_)
4533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
4543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  status_icon_ = status_tray_->CreateStatusIcon();
4553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!status_icon_)
4563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
4573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
4583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Set the image and add ourselves as a click observer on it
4593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  SkBitmap* bitmap = ResourceBundle::GetSharedInstance().GetBitmapNamed(
4603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      IDR_STATUS_TRAY_ICON);
4613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  status_icon_->SetImage(*bitmap);
4623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  status_icon_->SetToolTip(l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
463513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  UpdateStatusTrayIconContextMenu();
464513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
465513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
466513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid BackgroundModeManager::UpdateContextMenuEntryIcon(
467513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const Extension* extension) {
468513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!context_menu_)
469513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return;
470513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  context_menu_->SetIcon(
471513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      context_menu_application_offset_ + applications_.GetPosition(extension),
472513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      *(applications_.GetIcon(extension)));
473513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  status_icon_->SetContextMenu(context_menu_);  // for Update effect
474513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
475513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
476513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid BackgroundModeManager::UpdateStatusTrayIconContextMenu() {
477513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!status_icon_)
478513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return;
4793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
4803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Create a context menu item for Chrome.
4813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  menus::SimpleMenuModel* menu = new menus::SimpleMenuModel(this);
482513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Add About item
483513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  menu->AddItem(IDC_ABOUT, l10n_util::GetStringFUTF16(IDS_ABOUT,
484513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
485513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
486513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Add Preferences item
487731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (CommandLine::ForCurrentProcess()->HasSwitch(
488731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          switches::kEnableTabbedOptions)) {
489731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    menu->AddItemWithStringId(IDC_OPTIONS, IDS_SETTINGS);
490731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  } else {
4913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#if defined(TOOLKIT_GTK)
492731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    string16 preferences = gtk_util::GetStockPreferencesMenuLabel();
493731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (preferences.empty())
494731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      menu->AddItemWithStringId(IDC_OPTIONS, IDS_OPTIONS);
495731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    else
496731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      menu->AddItem(IDC_OPTIONS, preferences);
4973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#else
498731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    menu->AddItemWithStringId(IDC_OPTIONS, IDS_OPTIONS);
4993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#endif
500731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
501513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  menu->AddSeparator();
502513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  int application_position = 0;
503513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  context_menu_application_offset_ = menu->GetItemCount();
504513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  for (ExtensionList::const_iterator cursor = applications_.begin();
505513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch       cursor != applications_.end();
506513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch       ++cursor, ++application_position) {
507513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const SkBitmap* icon = applications_.GetIcon(*cursor);
508513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    int sort_position = applications_.GetPosition(*cursor);
509513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    DCHECK(sort_position == application_position);
510513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const std::string& name = (*cursor)->name();
511513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    menu->AddItem(sort_position, ASCIIToUTF16(name));
512513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (icon)
513513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      menu->SetIcon(menu->GetItemCount() - 1, *icon);
514513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
5153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  menu->AddSeparator();
5163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  menu->AddItemWithStringId(IDC_EXIT, IDS_EXIT);
517513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  context_menu_ = menu;
5183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  status_icon_->SetContextMenu(menu);
5193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
5203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
5213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool BackgroundModeManager::IsCommandIdChecked(int command_id) const {
5223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return false;
5233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
5243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
5253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool BackgroundModeManager::IsCommandIdEnabled(int command_id) const {
5263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // For now, we do not support disabled items.
5273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return true;
5283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
5293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
5303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool BackgroundModeManager::GetAcceleratorForCommandId(
5313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    int command_id,
5323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    menus::Accelerator* accelerator) {
5333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // No accelerators for status icon context menus.
5343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return false;
5353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
5363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
5373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BackgroundModeManager::RemoveStatusTrayIcon() {
5383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (status_icon_)
5393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    status_tray_->RemoveStatusIcon(status_icon_);
5403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  status_icon_ = NULL;
5413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
5423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
543513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid BackgroundModeManager::ExecuteApplication(int item) {
5444a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  DCHECK(item >= 0 && item < static_cast<int>(applications_.size()));
545513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  Browser* browser = BrowserList::GetLastActive();
546513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!browser) {
547513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    Browser::OpenEmptyWindow(profile_);
548513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    browser = BrowserList::GetLastActive();
549513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
550513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  const Extension* extension = applications_.GetExtension(item);
551513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  browser->OpenApplicationTab(profile_, extension, NULL);
552513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
5533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
5543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BackgroundModeManager::ExecuteCommand(int item) {
5553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  switch (item) {
5563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    case IDC_EXIT:
5573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      UserMetrics::RecordAction(UserMetricsAction("Exit"), profile_);
5583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      BrowserList::CloseAllBrowsersAndExit();
5593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      break;
5603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    case IDC_ABOUT:
5613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      GetBrowserWindow()->OpenAboutChromeDialog();
5623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      break;
5633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    case IDC_OPTIONS:
5643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      GetBrowserWindow()->OpenOptionsDialog();
5653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      break;
5663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    default:
567513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      ExecuteApplication(item);
5683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      break;
5693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
5703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
5713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
5723345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickBrowser* BackgroundModeManager::GetBrowserWindow() {
5733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  Browser* browser = BrowserList::GetLastActive();
5743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!browser) {
5753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    Browser::OpenEmptyWindow(profile_);
5763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    browser = BrowserList::GetLastActive();
5773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
5783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return browser;
5793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
5803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
5813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// static
5823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BackgroundModeManager::RegisterUserPrefs(PrefService* prefs) {
5833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  prefs->RegisterBooleanPref(prefs::kBackgroundModeEnabled, true);
5843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  prefs->RegisterBooleanPref(prefs::kLaunchOnStartupResetAllowed, false);
5853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
586