background_mode_manager.cc revision f2477e01787aa58f445919b809d89e252beef54f
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/base_paths.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_registry_simple.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h"
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/app/chrome_command_ids.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/background/background_application_list_model.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/background/background_mode_manager.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/browser_process.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/browser_shutdown.h"
217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/extension_system.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/lifetime/application_lifetime.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile_info_cache.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile_manager.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/status_icons/status_icon.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/status_icons/status_tray.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser_commands.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser_finder.h"
331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "chrome/browser/ui/browser_list.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/chrome_pages.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/extensions/application_launch.h"
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/host_desktop.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_constants.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_switches.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/extension_constants.h"
400f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "chrome/common/extensions/manifest_url_handler.h"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h"
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_service.h"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/user_metrics.h"
44f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h"
451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "extensions/common/permissions/permission_set.h"
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "grit/chrome_unscaled_resources.h"
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/chromium_strings.h"
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/generated_resources.h"
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::UserMetricsAction;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using extensions::Extension;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using extensions::UpdatedExtensionPermissionsInfo;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
56f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)namespace {
57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const int kInvalidExtensionIndex = -1;
58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
59f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BackgroundModeManager::BackgroundModeData::BackgroundModeData(
61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    Profile* profile,
62f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    CommandIdExtensionVector* command_id_extension_vector)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : applications_(new BackgroundApplicationListModel(profile)),
64f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      profile_(profile),
65f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      command_id_extension_vector_(command_id_extension_vector) {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BackgroundModeManager::BackgroundModeData::~BackgroundModeData() {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
72424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)//  BackgroundModeManager::BackgroundModeData, StatusIconMenuModel overrides
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BackgroundModeManager::BackgroundModeData::ExecuteCommand(
74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    int command_id,
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int event_flags) {
76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  switch (command_id) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case IDC_MinimumLabelValue:
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Do nothing. This is just a label.
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
81f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // Launch the app associated with this Command ID.
82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      int extension_index = command_id_extension_vector_->at(command_id);
83f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      if (extension_index != kInvalidExtensionIndex) {
84f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        const Extension* extension =
85f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            applications_->GetExtension(extension_index);
86f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        BackgroundModeManager::LaunchBackgroundApplication(profile_, extension);
87f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      }
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Browser* BackgroundModeManager::BackgroundModeData::GetBrowserWindow() {
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  chrome::HostDesktopType host_desktop_type = chrome::GetActiveDesktop();
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Browser* browser = chrome::FindLastActiveWithProfile(profile_,
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                       host_desktop_type);
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return browser ? browser : chrome::OpenEmptyWindow(profile_,
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                     host_desktop_type);
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BackgroundModeManager::BackgroundModeData::GetBackgroundAppCount() const {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return applications_->size();
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::BackgroundModeData::BuildProfileMenu(
105424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    StatusIconMenuModel* menu,
106424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    StatusIconMenuModel* containing_menu) {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int position = 0;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // When there are no background applications, we want to display
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // just a label stating that none are running.
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (applications_->size() < 1) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    menu->AddItemWithStringId(IDC_MinimumLabelValue,
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              IDS_BACKGROUND_APP_NOT_INSTALLED);
113424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    menu->SetCommandIdEnabled(IDC_MinimumLabelValue, false);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (extensions::ExtensionList::const_iterator cursor =
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             applications_->begin();
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         cursor != applications_->end();
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         ++cursor, ++position) {
119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      const gfx::ImageSkia* icon = applications_->GetIcon(cursor->get());
120868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      DCHECK(position == applications_->GetPosition(cursor->get()));
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const std::string& name = (*cursor)->name();
122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      int command_id = command_id_extension_vector_->size();
123f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // Check that the command ID is within the dynamic range.
124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      DCHECK(command_id < IDC_MinimumLabelValue);
125f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      command_id_extension_vector_->push_back(position);
126f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      menu->AddItem(command_id, UTF8ToUTF16(name));
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (icon)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        menu->SetIcon(menu->GetItemCount() - 1, gfx::Image(*icon));
1290f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1300f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      // Component extensions with background that do not have an options page
1310f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      // will cause this menu item to go to the extensions page with an
1320f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      // absent component extension.
1330f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      //
1340f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      // Ideally, we would remove this item, but this conflicts with the user
1350f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      // model where this menu shows the extensions with background.
1360f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      //
1370f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      // The compromise is to disable the item, avoiding the non-actionable
1380f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      // navigate to the extensions page and preserving the user model.
1390f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      if ((*cursor)->location() == extensions::Manifest::COMPONENT) {
1400f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        GURL options_page = extensions::ManifestURL::GetOptionsPage(*cursor);
1410f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        if (!options_page.is_valid())
142f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          menu->SetCommandIdEnabled(command_id, false);
1430f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      }
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
146f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (containing_menu) {
147f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    int menu_command_id = command_id_extension_vector_->size();
148f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Check that the command ID is within the dynamic range.
149f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    DCHECK(menu_command_id < IDC_MinimumLabelValue);
150f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    command_id_extension_vector_->push_back(kInvalidExtensionIndex);
151f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    containing_menu->AddSubMenu(menu_command_id, name_, menu);
152f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::BackgroundModeData::SetName(
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const string16& new_profile_name) {
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  name_ = new_profile_name;
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)string16 BackgroundModeManager::BackgroundModeData::name() {
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return name_;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BackgroundModeManager::BackgroundModeData::BackgroundModeDataCompare(
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BackgroundModeData* bmd1,
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BackgroundModeData* bmd2) {
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return bmd1->name_ < bmd2->name_;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//  BackgroundModeManager, public
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BackgroundModeManager::BackgroundModeManager(
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CommandLine* command_line,
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProfileInfoCache* profile_cache)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : profile_cache_(profile_cache),
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      status_tray_(NULL),
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      status_icon_(NULL),
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      context_menu_(NULL),
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      in_background_mode_(false),
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      keep_alive_for_startup_(false),
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      keep_alive_for_test_(false),
1841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      background_mode_suspended_(false),
185f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      keeping_alive_(false) {
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We should never start up if there is no browser process or if we are
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // currently quitting.
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(g_browser_process != NULL);
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(!browser_shutdown::IsTryingToQuit());
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add self as an observer for the profile info cache so we know when profiles
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // are deleted and their names change.
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  profile_cache_->AddObserver(this);
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Listen for the background mode preference changing.
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (g_browser_process->local_state()) {  // Skip for unit tests
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pref_registrar_.Init(g_browser_process->local_state());
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    pref_registrar_.Add(
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        prefs::kBackgroundModeEnabled,
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&BackgroundModeManager::OnBackgroundModeEnabledPrefChanged,
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Unretained(this)));
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Keep the browser alive until extensions are done loading - this is needed
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // by the --no-startup-window flag. We want to stay alive until we load
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // extensions, at which point we should either run in background mode (if
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // there are background apps) or exit if there are none.
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (command_line->HasSwitch(switches::kNoStartupWindow)) {
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    keep_alive_for_startup_ = true;
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    chrome::StartKeepAlive();
2111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  } else {
2121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // Otherwise, start with background mode suspended in case we're launching
2131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // in a mode that doesn't open a browser window. It will be resumed when the
2141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // first browser window is opened.
2151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    SuspendBackgroundMode();
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the -keep-alive-for-test flag is passed, then always keep chrome running
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // in the background until the user explicitly terminates it.
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (command_line->HasSwitch(switches::kKeepAliveForTest))
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    keep_alive_for_test_ = true;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ShouldBeInBackgroundMode())
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    StartBackgroundMode();
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Listen for the application shutting down so we can decrement our KeepAlive
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // count.
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 content::NotificationService::AllSources());
2301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  BrowserList::AddObserver(this);
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BackgroundModeManager::~BackgroundModeManager() {
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove ourselves from the application observer list (only needed by unit
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // tests since APP_TERMINATING is what does this in a real running system).
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (BackgroundModeInfoMap::iterator it =
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       background_mode_data_.begin();
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != background_mode_data_.end();
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++it) {
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    it->second->applications_->RemoveObserver(this);
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  BrowserList::RemoveObserver(this);
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We're going away, so exit background mode (does nothing if we aren't in
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // background mode currently). This is primarily needed for unit tests,
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // because in an actual running system we'd get an APP_TERMINATING
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // notification before being destroyed.
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EndBackgroundMode();
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BackgroundModeManager::RegisterPrefs(PrefRegistrySimple* registry) {
253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#if defined(OS_MACOSX)
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  registry->RegisterBooleanPref(prefs::kUserRemovedLoginItem, false);
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  registry->RegisterBooleanPref(prefs::kChromeCreatedLoginItem, false);
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  registry->RegisterBooleanPref(prefs::kMigratedLoginItemPref, false);
257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  registry->RegisterBooleanPref(prefs::kBackgroundModeEnabled, true);
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::RegisterProfile(Profile* profile) {
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We don't want to register multiple times for one profile.
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(background_mode_data_.find(profile) == background_mode_data_.end());
265f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  BackgroundModeInfo bmd(new BackgroundModeData(profile,
266f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                                &command_id_extension_vector_));
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  background_mode_data_[profile] = bmd;
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Initially set the name for this background mode data.
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t index = profile_cache_->GetIndexOfProfileWithPath(profile->GetPath());
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  string16 name = l10n_util::GetStringUTF16(IDS_PROFILES_DEFAULT_NAME);
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (index != std::string::npos)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    name = profile_cache_->GetNameOfProfileAtIndex(index);
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bmd->SetName(name);
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Listen for when extensions are loaded or add the background permission so
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we can display a "background app installed" notification and enter
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // "launch on login" mode on the Mac.
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 content::Source<Profile>(profile));
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED,
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 content::Source<Profile>(profile));
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check for the presence of background apps after all extensions have been
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // loaded, to handle the case where an extension has been manually removed
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // while Chrome was not running.
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  registrar_.Add(this, chrome::NOTIFICATION_EXTENSIONS_READY,
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 content::Source<Profile>(profile));
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bmd->applications_->AddObserver(this);
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we're adding a new profile and running in multi-profile mode, this new
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // profile should be added to the status icon if one currently exists.
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (in_background_mode_ && status_icon_)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateStatusTrayIconContextMenu();
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::LaunchBackgroundApplication(
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Profile* profile,
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension) {
3034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  OpenApplication(AppLaunchParams(profile, extension, NEW_FOREGROUND_TAB));
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3068bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool BackgroundModeManager::IsBackgroundModeActive() {
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return in_background_mode_;
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BackgroundModeManager::NumberOfBackgroundModeData() {
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return background_mode_data_.size();
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//  BackgroundModeManager, content::NotificationObserver overrides
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::Observe(
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int type,
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const content::NotificationSource& source,
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const content::NotificationDetails& details) {
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (type) {
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case chrome::NOTIFICATION_EXTENSIONS_READY:
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Extensions are loaded, so we don't need to manually keep the browser
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // process alive any more when running in no-startup-window mode.
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      EndKeepAliveForStartup();
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case chrome::NOTIFICATION_EXTENSION_LOADED: {
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Extension* extension = content::Details<Extension>(details).ptr();
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Profile* profile = content::Source<Profile>(source).ptr();
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (BackgroundApplicationListModel::IsBackgroundApp(
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                *extension, profile)) {
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Extensions loaded after the ExtensionsService is ready should be
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // treated as new installs.
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          if (extensions::ExtensionSystem::Get(profile)->extension_service()->
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                  is_ready()) {
336eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            bool is_being_reloaded = false;
337eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            CheckReloadStatus(extension, &is_being_reloaded);
338eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            // No need to show the notification if we showed to the user
339eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            // previously for this app.
340eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            if (!is_being_reloaded)
341eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch              OnBackgroundAppInstalled(extension);
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          }
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case chrome::NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED: {
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        UpdatedExtensionPermissionsInfo* info =
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            content::Details<UpdatedExtensionPermissionsInfo>(details).ptr();
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (info->permissions->HasAPIPermission(
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                extensions::APIPermission::kBackground) &&
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            info->reason == UpdatedExtensionPermissionsInfo::ADDED) {
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Turned on background permission, so treat this as a new install.
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          OnBackgroundAppInstalled(info->extension);
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case chrome::NOTIFICATION_APP_TERMINATING:
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Make sure we aren't still keeping the app alive (only happens if we
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // don't receive an EXTENSIONS_READY notification for some reason).
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      EndKeepAliveForStartup();
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Performing an explicit shutdown, so exit background mode (does nothing
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // if we aren't in background mode currently).
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      EndBackgroundMode();
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Shutting down, so don't listen for any more notifications so we don't
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // try to re-enter/exit background mode again.
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      registrar_.RemoveAll();
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (BackgroundModeInfoMap::iterator it =
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               background_mode_data_.begin();
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           it != background_mode_data_.end();
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           ++it) {
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        it->second->applications_->RemoveObserver(this);
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::OnBackgroundModeEnabledPrefChanged() {
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsBackgroundModePrefEnabled())
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EnableBackgroundMode();
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DisableBackgroundMode();
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//  BackgroundModeManager, BackgroundApplicationListModel::Observer overrides
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::OnApplicationDataChanged(
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension, Profile* profile) {
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateStatusTrayIconContextMenu();
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::OnApplicationListChanged(Profile* profile) {
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!IsBackgroundModePrefEnabled())
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Update the profile cache with the fact whether background apps are running
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // for this profile.
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t profile_index = profile_cache_->GetIndexOfProfileWithPath(
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      profile->GetPath());
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (profile_index != std::string::npos) {
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    profile_cache_->SetBackgroundStatusOfProfileAtIndex(
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        profile_index, GetBackgroundAppCountForProfile(profile) != 0);
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ShouldBeInBackgroundMode()) {
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We've uninstalled our last background app, make sure we exit background
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // mode and no longer launch on startup.
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EnableLaunchOnStartup(false);
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EndBackgroundMode();
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We have at least one background app running - make sure we're in
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // background mode.
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!in_background_mode_) {
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We're entering background mode - make sure we have launch-on-startup
417c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // enabled. On Mac, the platform-specific code tracks whether the user
418c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // has deleted a login item in the past, and if so, no login item will
419c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // be created (to avoid overriding the specific user action).
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      EnableLaunchOnStartup(true);
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      StartBackgroundMode();
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // List of applications changed so update the UI.
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateStatusTrayIconContextMenu();
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//  BackgroundModeManager, ProfileInfoCacheObserver overrides
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BackgroundModeManager::OnProfileAdded(const base::FilePath& profile_path) {
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProfileInfoCache& cache =
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      g_browser_process->profile_manager()->GetProfileInfoCache();
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  string16 profile_name = cache.GetNameOfProfileAtIndex(
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cache.GetIndexOfProfileWithPath(profile_path));
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // At this point, the profile should be registered with the background mode
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // manager, but when it's actually added to the cache is when its name is
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // set so we need up to update that with the background_mode_data.
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (BackgroundModeInfoMap::const_iterator it =
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       background_mode_data_.begin();
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != background_mode_data_.end();
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++it) {
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (it->first->GetPath() == profile_path) {
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      it->second->SetName(profile_name);
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UpdateStatusTrayIconContextMenu();
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::OnProfileWillBeRemoved(
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& profile_path) {
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProfileInfoCache& cache =
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      g_browser_process->profile_manager()->GetProfileInfoCache();
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  string16 profile_name = cache.GetNameOfProfileAtIndex(
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cache.GetIndexOfProfileWithPath(profile_path));
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove the profile from our map of profiles.
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BackgroundModeInfoMap::iterator it =
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetBackgroundModeIterator(profile_name);
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If a profile isn't running a background app, it may not be in the map.
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it != background_mode_data_.end()) {
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    background_mode_data_.erase(it);
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateStatusTrayIconContextMenu();
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::OnProfileNameChanged(
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& profile_path,
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const string16& old_profile_name) {
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProfileInfoCache& cache =
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      g_browser_process->profile_manager()->GetProfileInfoCache();
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  string16 new_profile_name = cache.GetNameOfProfileAtIndex(
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cache.GetIndexOfProfileWithPath(profile_path));
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BackgroundModeInfoMap::const_iterator it =
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetBackgroundModeIterator(old_profile_name);
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We check that the returned iterator is valid due to unittests, but really
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // this should only be called on profiles already known by the background
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // mode manager.
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it != background_mode_data_.end()) {
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    it->second->SetName(new_profile_name);
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateStatusTrayIconContextMenu();
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
486424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)//  BackgroundModeManager::BackgroundModeData, StatusIconMenuModel overrides
4872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BackgroundModeManager::ExecuteCommand(int command_id, int event_flags) {
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // When a browser window is necessary, we use the first profile. The windows
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // opened for these commands are not profile-specific, so any profile would
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // work and the first is convenient.
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BackgroundModeData* bmd = background_mode_data_.begin()->second.get();
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (command_id) {
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case IDC_ABOUT:
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      chrome::ShowAboutChrome(bmd->GetBrowserWindow());
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case IDC_TASK_MANAGER:
497eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      chrome::OpenTaskManager(bmd->GetBrowserWindow());
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case IDC_EXIT:
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::RecordAction(UserMetricsAction("Exit"));
5011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      chrome::CloseAllBrowsers();
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case IDC_STATUS_TRAY_KEEP_CHROME_RUNNING_IN_BACKGROUND: {
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Background mode must already be enabled (as otherwise this menu would
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // not be visible).
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(IsBackgroundModePrefEnabled());
5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      DCHECK(chrome::WillKeepAlive());
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Set the background mode pref to "disabled" - the resulting notification
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // will result in a call to DisableBackgroundMode().
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PrefService* service = g_browser_process->local_state();
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(service);
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      service->SetBoolean(prefs::kBackgroundModeEnabled, false);
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      bmd->ExecuteCommand(command_id, event_flags);
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//  BackgroundModeManager, private
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::EndKeepAliveForStartup() {
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (keep_alive_for_startup_) {
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    keep_alive_for_startup_ = false;
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We call this via the message queue to make sure we don't try to end
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // keep-alive (which can shutdown Chrome) before the message loop has
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // started.
53190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(FROM_HERE,
53290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                           base::Bind(&chrome::EndKeepAlive));
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::StartBackgroundMode() {
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ShouldBeInBackgroundMode());
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Don't bother putting ourselves in background mode if we're already there
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // or if background mode is disabled.
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (in_background_mode_)
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Mark ourselves as running in background mode.
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  in_background_mode_ = true;
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  UpdateKeepAliveAndTrayIcon();
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::NotificationService::current()->Notify(
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      chrome::NOTIFICATION_BACKGROUND_MODE_CHANGED,
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::Source<BackgroundModeManager>(this),
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::Details<bool>(&in_background_mode_));
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::EndBackgroundMode() {
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!in_background_mode_)
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  in_background_mode_ = false;
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  UpdateKeepAliveAndTrayIcon();
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::NotificationService::current()->Notify(
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      chrome::NOTIFICATION_BACKGROUND_MODE_CHANGED,
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::Source<BackgroundModeManager>(this),
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::Details<bool>(&in_background_mode_));
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::EnableBackgroundMode() {
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(IsBackgroundModePrefEnabled());
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If background mode should be enabled, but isn't, turn it on.
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!in_background_mode_ && ShouldBeInBackgroundMode()) {
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    StartBackgroundMode();
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EnableLaunchOnStartup(true);
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::DisableBackgroundMode() {
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!IsBackgroundModePrefEnabled());
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If background mode is currently enabled, turn it off.
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (in_background_mode_) {
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EndBackgroundMode();
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EnableLaunchOnStartup(false);
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void BackgroundModeManager::SuspendBackgroundMode() {
5861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  background_mode_suspended_ = true;
5871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  UpdateKeepAliveAndTrayIcon();
5881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
5891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
5901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void BackgroundModeManager::ResumeBackgroundMode() {
5911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  background_mode_suspended_ = false;
5921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  UpdateKeepAliveAndTrayIcon();
5931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
5941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
5951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void BackgroundModeManager::UpdateKeepAliveAndTrayIcon() {
5961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (in_background_mode_ && !background_mode_suspended_) {
5971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if (!keeping_alive_) {
5981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      keeping_alive_ = true;
5991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      chrome::StartKeepAlive();
6001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    }
6011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    CreateStatusTrayIcon();
6021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return;
6031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
6041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
6051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  RemoveStatusTrayIcon();
6061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (keeping_alive_) {
6071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    keeping_alive_ = false;
6081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    chrome::EndKeepAlive();
6091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
6101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
6111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
6121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void BackgroundModeManager::OnBrowserAdded(Browser* browser) {
6131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  ResumeBackgroundMode();
6141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
6151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BackgroundModeManager::GetBackgroundAppCount() const {
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int count = 0;
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Walk the BackgroundModeData for all profiles and count the number of apps.
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (BackgroundModeInfoMap::const_iterator it =
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       background_mode_data_.begin();
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != background_mode_data_.end();
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++it) {
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    count += it->second->GetBackgroundAppCount();
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(count >= 0);
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return count;
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BackgroundModeManager::GetBackgroundAppCountForProfile(
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Profile* const profile) const {
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BackgroundModeData* bmd = GetBackgroundModeData(profile);
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return bmd->GetBackgroundAppCount();
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BackgroundModeManager::ShouldBeInBackgroundMode() const {
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return IsBackgroundModePrefEnabled() &&
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (GetBackgroundAppCount() > 0 || keep_alive_for_test_);
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::OnBackgroundAppInstalled(
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension) {
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Background mode is disabled - don't do anything.
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!IsBackgroundModePrefEnabled())
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Ensure we have a tray icon (needed so we can display the app-installed
6471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // notification below).
6481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EnableBackgroundMode();
6491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  ResumeBackgroundMode();
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Notify the user that a background app has been installed.
652eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (extension) {  // NULL when called by unit tests.
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DisplayAppInstalledNotification(extension);
654eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
655eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
656eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
657eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid BackgroundModeManager::CheckReloadStatus(
658eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const Extension* extension,
659eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    bool* is_being_reloaded) {
660eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Walk the BackgroundModeData for all profiles to see if one of their
661eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // extensions is being reloaded.
662eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    for (BackgroundModeInfoMap::const_iterator it =
663eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch             background_mode_data_.begin();
664eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch         it != background_mode_data_.end();
665eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch         ++it) {
666eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      Profile* profile = it->first;
667eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // If the extension is being reloaded, no need to show a notification.
668eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      if (profile->GetExtensionService()->IsBeingReloaded(extension->id()))
669eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        *is_being_reloaded = true;
670eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::CreateStatusTrayIcon() {
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Only need status icons on windows/linux. ChromeOS doesn't allow exiting
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Chrome and Mac can use the dock icon instead.
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Since there are multiple profiles which share the status tray, we now
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // use the browser process to keep track of it.
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_MACOSX) && !defined(OS_CHROMEOS)
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!status_tray_)
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    status_tray_ = g_browser_process->status_tray();
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the platform doesn't support status icons, or we've already created
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // our status icon, just return.
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!status_tray_ || status_icon_)
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(rlp): Status tray icon should have submenus for each profile.
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::ImageSkia* image_skia = ui::ResourceBundle::GetSharedInstance().
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetImageSkiaNamed(IDR_STATUS_TRAY_ICON);
692a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
693a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  status_icon_ = status_tray_->CreateStatusIcon(
694a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      StatusTray::BACKGROUND_MODE_ICON,
695a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      *image_skia,
696a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
697a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (!status_icon_)
698a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return;
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateStatusTrayIconContextMenu();
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::UpdateStatusTrayIconContextMenu() {
7031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Ensure we have a tray icon if appropriate.
7041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  UpdateKeepAliveAndTrayIcon();
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we don't have a status icon or one could not be created succesfully,
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // then no need to continue the update.
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!status_icon_)
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We should only get here if we have a profile loaded, or if we're running
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // in test mode.
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (background_mode_data_.empty()) {
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(keep_alive_for_test_);
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
718f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // We are building a new menu. Reset the Command IDs.
719f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  command_id_extension_vector_.clear();
720f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
721f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Clear the submenus too since we will be creating new ones.
722f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  submenus.clear();
723f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(rlp): Add current profile color or indicator.
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create a context menu item for Chrome.
726424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  scoped_ptr<StatusIconMenuModel> menu(new StatusIconMenuModel(this));
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add About item
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu->AddItem(IDC_ABOUT, l10n_util::GetStringUTF16(IDS_ABOUT));
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu->AddItemWithStringId(IDC_TASK_MANAGER, IDS_TASK_MANAGER);
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu->AddSeparator(ui::NORMAL_SEPARATOR);
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (profile_cache_->GetNumberOfProfiles() > 1) {
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<BackgroundModeData*> bmd_vector;
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (BackgroundModeInfoMap::iterator it =
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         background_mode_data_.begin();
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         it != background_mode_data_.end();
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         ++it) {
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       bmd_vector.push_back(it->second.get());
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::sort(bmd_vector.begin(), bmd_vector.end(),
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              &BackgroundModeData::BackgroundModeDataCompare);
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int profiles_with_apps = 0;
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (std::vector<BackgroundModeData*>::const_iterator bmd_it =
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         bmd_vector.begin();
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         bmd_it != bmd_vector.end();
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         ++bmd_it) {
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BackgroundModeData* bmd = *bmd_it;
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We should only display the profile in the status icon if it has at
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // least one background app.
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (bmd->GetBackgroundAppCount() > 0) {
751424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        StatusIconMenuModel* submenu = new StatusIconMenuModel(bmd);
752f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        // The submenu constructor caller owns the lifetime of the submenu.
753f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        // The containing menu does not handle the lifetime.
754f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        submenus.push_back(submenu);
755424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        bmd->BuildProfileMenu(submenu, menu.get());
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        profiles_with_apps++;
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We should only be displaying the status tray icon if there is at least
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // one profile with a background app.
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_GT(profiles_with_apps, 0);
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We should only have one profile in the cache if we are not
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // using multi-profiles. If keep_alive_for_test_ is set, then we may not
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // have any profiles in the cache.
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(profile_cache_->GetNumberOfProfiles() == size_t(1) ||
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           keep_alive_for_test_);
768424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    background_mode_data_.begin()->second->BuildProfileMenu(menu.get(), NULL);
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  menu->AddSeparator(ui::NORMAL_SEPARATOR);
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu->AddCheckItemWithStringId(
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      IDC_STATUS_TRAY_KEEP_CHROME_RUNNING_IN_BACKGROUND,
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      IDS_STATUS_TRAY_KEEP_CHROME_RUNNING_IN_BACKGROUND);
775424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  menu->SetCommandIdChecked(IDC_STATUS_TRAY_KEEP_CHROME_RUNNING_IN_BACKGROUND,
776424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                            true);
777424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
778424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  PrefService* service = g_browser_process->local_state();
779424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(service);
780424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  bool enabled =
781424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      service->IsUserModifiablePreference(prefs::kBackgroundModeEnabled);
782424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  menu->SetCommandIdEnabled(IDC_STATUS_TRAY_KEEP_CHROME_RUNNING_IN_BACKGROUND,
783424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                            enabled);
784424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu->AddItemWithStringId(IDC_EXIT, IDS_EXIT);
7862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
787424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  context_menu_ = menu.get();
788424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  status_icon_->SetContextMenu(menu.Pass());
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::RemoveStatusTrayIcon() {
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status_icon_)
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    status_tray_->RemoveStatusIcon(status_icon_);
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  status_icon_ = NULL;
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  context_menu_ = NULL;
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BackgroundModeManager::BackgroundModeData*
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BackgroundModeManager::GetBackgroundModeData(Profile* const profile) const {
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(background_mode_data_.find(profile) != background_mode_data_.end());
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return background_mode_data_.find(profile)->second.get();
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BackgroundModeManager::BackgroundModeInfoMap::iterator
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BackgroundModeManager::GetBackgroundModeIterator(
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const string16& profile_name) {
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BackgroundModeInfoMap::iterator profile_it =
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      background_mode_data_.end();
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (BackgroundModeInfoMap::iterator it =
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       background_mode_data_.begin();
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != background_mode_data_.end();
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++it) {
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (it->second->name() == profile_name) {
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      profile_it = it;
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return profile_it;
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BackgroundModeManager::IsBackgroundModePrefEnabled() const {
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PrefService* service = g_browser_process->local_state();
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(service);
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return service->GetBoolean(prefs::kBackgroundModeEnabled);
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
825