background_mode_manager.cc revision a36e5920737c6adbddd3e43b760e5de8431db6e0
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" 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/chrome_pages.h" 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/extensions/application_launch.h" 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/host_desktop.h" 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_constants.h" 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_switches.h" 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/extension.h" 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/extension_constants.h" 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/permissions/permission_set.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" 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "grit/chrome_unscaled_resources.h" 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/chromium_strings.h" 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/generated_resources.h" 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h" 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h" 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::UserMetricsAction; 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using extensions::Extension; 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using extensions::UpdatedExtensionPermissionsInfo; 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BackgroundModeManager::BackgroundModeData::BackgroundModeData( 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int command_id, 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Profile* profile) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : applications_(new BackgroundApplicationListModel(profile)), 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command_id_(command_id), 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile_(profile) { 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BackgroundModeManager::BackgroundModeData::~BackgroundModeData() { 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/////////////////////////////////////////////////////////////////////////////// 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// BackgroundModeManager::BackgroundModeData, ui::SimpleMenuModel overrides 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BackgroundModeManager::BackgroundModeData::IsCommandIdChecked( 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int command_id) const { 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED() << "There are no checked items in the profile submenu."; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BackgroundModeManager::BackgroundModeData::IsCommandIdEnabled( 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int command_id) const { 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return command_id != IDC_MinimumLabelValue; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BackgroundModeManager::BackgroundModeData::GetAcceleratorForCommandId( 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int command_id, ui::Accelerator* accelerator) { 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No accelerators for status icon context menus. 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BackgroundModeManager::BackgroundModeData::ExecuteCommand( 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int item, 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int event_flags) { 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (item) { 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case IDC_MinimumLabelValue: 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Do nothing. This is just a label. 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Launch the app associated with this item. 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const Extension* extension = applications_-> 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetExtension(item); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BackgroundModeManager::LaunchBackgroundApplication(profile_, extension); 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Browser* BackgroundModeManager::BackgroundModeData::GetBrowserWindow() { 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) chrome::HostDesktopType host_desktop_type = chrome::GetActiveDesktop(); 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Browser* browser = chrome::FindLastActiveWithProfile(profile_, 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) host_desktop_type); 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return browser ? browser : chrome::OpenEmptyWindow(profile_, 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) host_desktop_type); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BackgroundModeManager::BackgroundModeData::GetBackgroundAppCount() const { 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return applications_->size(); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::BackgroundModeData::BuildProfileMenu( 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::SimpleMenuModel* menu, 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::SimpleMenuModel* containing_menu) { 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int position = 0; 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // When there are no background applications, we want to display 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // just a label stating that none are running. 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (applications_->size() < 1) { 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) menu->AddItemWithStringId(IDC_MinimumLabelValue, 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDS_BACKGROUND_APP_NOT_INSTALLED); 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (extensions::ExtensionList::const_iterator cursor = 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) applications_->begin(); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cursor != applications_->end(); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++cursor, ++position) { 126868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const gfx::ImageSkia* icon = applications_->GetIcon(cursor->get()); 127868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(position == applications_->GetPosition(cursor->get())); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& name = (*cursor)->name(); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) menu->AddItem(position, UTF8ToUTF16(name)); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (icon) 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) menu->SetIcon(menu->GetItemCount() - 1, gfx::Image(*icon)); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (containing_menu) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) containing_menu->AddSubMenu(command_id_, name_, menu); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::BackgroundModeData::SetName( 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const string16& new_profile_name) { 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name_ = new_profile_name; 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)string16 BackgroundModeManager::BackgroundModeData::name() { 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return name_; 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BackgroundModeManager::BackgroundModeData::BackgroundModeDataCompare( 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BackgroundModeData* bmd1, 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BackgroundModeData* bmd2) { 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return bmd1->name_ < bmd2->name_; 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/////////////////////////////////////////////////////////////////////////////// 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// BackgroundModeManager, public 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BackgroundModeManager::BackgroundModeManager( 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CommandLine* command_line, 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProfileInfoCache* profile_cache) 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : profile_cache_(profile_cache), 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_tray_(NULL), 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_icon_(NULL), 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_menu_(NULL), 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in_background_mode_(false), 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keep_alive_for_startup_(false), 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keep_alive_for_test_(false), 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_command_id_(0) { 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We should never start up if there is no browser process or if we are 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // currently quitting. 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(g_browser_process != NULL); 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(!browser_shutdown::IsTryingToQuit()); 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Add self as an observer for the profile info cache so we know when profiles 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // are deleted and their names change. 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile_cache_->AddObserver(this); 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Listen for the background mode preference changing. 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (g_browser_process->local_state()) { // Skip for unit tests 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pref_registrar_.Init(g_browser_process->local_state()); 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pref_registrar_.Add( 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) prefs::kBackgroundModeEnabled, 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&BackgroundModeManager::OnBackgroundModeEnabledPrefChanged, 1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Unretained(this))); 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Keep the browser alive until extensions are done loading - this is needed 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // by the --no-startup-window flag. We want to stay alive until we load 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // extensions, at which point we should either run in background mode (if 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // there are background apps) or exit if there are none. 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (command_line->HasSwitch(switches::kNoStartupWindow)) { 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keep_alive_for_startup_ = true; 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) chrome::StartKeepAlive(); 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the -keep-alive-for-test flag is passed, then always keep chrome running 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // in the background until the user explicitly terminates it. 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (command_line->HasSwitch(switches::kKeepAliveForTest)) 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keep_alive_for_test_ = true; 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ShouldBeInBackgroundMode()) 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartBackgroundMode(); 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Listen for the application shutting down so we can decrement our KeepAlive 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // count. 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING, 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::NotificationService::AllSources()); 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BackgroundModeManager::~BackgroundModeManager() { 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Remove ourselves from the application observer list (only needed by unit 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // tests since APP_TERMINATING is what does this in a real running system). 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (BackgroundModeInfoMap::iterator it = 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) background_mode_data_.begin(); 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != background_mode_data_.end(); 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++it) { 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it->second->applications_->RemoveObserver(this); 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We're going away, so exit background mode (does nothing if we aren't in 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // background mode currently). This is primarily needed for unit tests, 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // because in an actual running system we'd get an APP_TERMINATING 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // notification before being destroyed. 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EndBackgroundMode(); 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BackgroundModeManager::RegisterPrefs(PrefRegistrySimple* registry) { 228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#if defined(OS_MACOSX) 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) registry->RegisterBooleanPref(prefs::kUserRemovedLoginItem, false); 230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) registry->RegisterBooleanPref(prefs::kChromeCreatedLoginItem, false); 231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) registry->RegisterBooleanPref(prefs::kMigratedLoginItemPref, false); 232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) registry->RegisterBooleanPref(prefs::kBackgroundModeEnabled, true); 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::RegisterProfile(Profile* profile) { 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We don't want to register multiple times for one profile. 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(background_mode_data_.find(profile) == background_mode_data_.end()); 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BackgroundModeInfo bmd(new BackgroundModeData(current_command_id_++, 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile)); 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) background_mode_data_[profile] = bmd; 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initially set the name for this background mode data. 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t index = profile_cache_->GetIndexOfProfileWithPath(profile->GetPath()); 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 name = l10n_util::GetStringUTF16(IDS_PROFILES_DEFAULT_NAME); 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (index != std::string::npos) 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name = profile_cache_->GetNameOfProfileAtIndex(index); 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bmd->SetName(name); 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Listen for when extensions are loaded or add the background permission so 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we can display a "background app installed" notification and enter 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "launch on login" mode on the Mac. 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::Source<Profile>(profile)); 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED, 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::Source<Profile>(profile)); 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check for the presence of background apps after all extensions have been 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // loaded, to handle the case where an extension has been manually removed 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // while Chrome was not running. 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) registrar_.Add(this, chrome::NOTIFICATION_EXTENSIONS_READY, 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::Source<Profile>(profile)); 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bmd->applications_->AddObserver(this); 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we're adding a new profile and running in multi-profile mode, this new 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // profile should be added to the status icon if one currently exists. 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (in_background_mode_ && status_icon_) 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateStatusTrayIconContextMenu(); 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::LaunchBackgroundApplication( 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Profile* profile, 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const Extension* extension) { 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) chrome::OpenApplication(chrome::AppLaunchParams(profile, extension, 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NEW_FOREGROUND_TAB)); 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BackgroundModeManager::IsBackgroundModeActiveForTest() { 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return in_background_mode_; 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BackgroundModeManager::NumberOfBackgroundModeData() { 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return background_mode_data_.size(); 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/////////////////////////////////////////////////////////////////////////////// 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// BackgroundModeManager, content::NotificationObserver overrides 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::Observe( 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int type, 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const content::NotificationSource& source, 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const content::NotificationDetails& details) { 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (type) { 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case chrome::NOTIFICATION_EXTENSIONS_READY: 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Extensions are loaded, so we don't need to manually keep the browser 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // process alive any more when running in no-startup-window mode. 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EndKeepAliveForStartup(); 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case chrome::NOTIFICATION_EXTENSION_LOADED: { 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Extension* extension = content::Details<Extension>(details).ptr(); 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Profile* profile = content::Source<Profile>(source).ptr(); 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (BackgroundApplicationListModel::IsBackgroundApp( 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *extension, profile)) { 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Extensions loaded after the ExtensionsService is ready should be 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // treated as new installs. 3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (extensions::ExtensionSystem::Get(profile)->extension_service()-> 3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) is_ready()) { 312eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool is_being_reloaded = false; 313eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CheckReloadStatus(extension, &is_being_reloaded); 314eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // No need to show the notification if we showed to the user 315eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // previously for this app. 316eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!is_being_reloaded) 317eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch OnBackgroundAppInstalled(extension); 3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case chrome::NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED: { 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdatedExtensionPermissionsInfo* info = 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::Details<UpdatedExtensionPermissionsInfo>(details).ptr(); 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (info->permissions->HasAPIPermission( 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extensions::APIPermission::kBackground) && 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info->reason == UpdatedExtensionPermissionsInfo::ADDED) { 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Turned on background permission, so treat this as a new install. 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OnBackgroundAppInstalled(info->extension); 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case chrome::NOTIFICATION_APP_TERMINATING: 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make sure we aren't still keeping the app alive (only happens if we 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // don't receive an EXTENSIONS_READY notification for some reason). 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EndKeepAliveForStartup(); 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Performing an explicit shutdown, so exit background mode (does nothing 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // if we aren't in background mode currently). 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EndBackgroundMode(); 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Shutting down, so don't listen for any more notifications so we don't 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // try to re-enter/exit background mode again. 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) registrar_.RemoveAll(); 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (BackgroundModeInfoMap::iterator it = 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) background_mode_data_.begin(); 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != background_mode_data_.end(); 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++it) { 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it->second->applications_->RemoveObserver(this); 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::OnBackgroundModeEnabledPrefChanged() { 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsBackgroundModePrefEnabled()) 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnableBackgroundMode(); 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DisableBackgroundMode(); 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/////////////////////////////////////////////////////////////////////////////// 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// BackgroundModeManager, BackgroundApplicationListModel::Observer overrides 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::OnApplicationDataChanged( 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const Extension* extension, Profile* profile) { 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateStatusTrayIconContextMenu(); 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::OnApplicationListChanged(Profile* profile) { 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsBackgroundModePrefEnabled()) 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Update the profile cache with the fact whether background apps are running 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for this profile. 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t profile_index = profile_cache_->GetIndexOfProfileWithPath( 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->GetPath()); 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (profile_index != std::string::npos) { 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile_cache_->SetBackgroundStatusOfProfileAtIndex( 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile_index, GetBackgroundAppCountForProfile(profile) != 0); 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ShouldBeInBackgroundMode()) { 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We've uninstalled our last background app, make sure we exit background 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // mode and no longer launch on startup. 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnableLaunchOnStartup(false); 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EndBackgroundMode(); 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We have at least one background app running - make sure we're in 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // background mode. 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!in_background_mode_) { 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We're entering background mode - make sure we have launch-on-startup 393c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // enabled. On Mac, the platform-specific code tracks whether the user 394c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // has deleted a login item in the past, and if so, no login item will 395c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // be created (to avoid overriding the specific user action). 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnableLaunchOnStartup(true); 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartBackgroundMode(); 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // List of applications changed so update the UI. 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateStatusTrayIconContextMenu(); 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/////////////////////////////////////////////////////////////////////////////// 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// BackgroundModeManager, ProfileInfoCacheObserver overrides 4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BackgroundModeManager::OnProfileAdded(const base::FilePath& profile_path) { 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProfileInfoCache& cache = 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_browser_process->profile_manager()->GetProfileInfoCache(); 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 profile_name = cache.GetNameOfProfileAtIndex( 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cache.GetIndexOfProfileWithPath(profile_path)); 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // At this point, the profile should be registered with the background mode 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // manager, but when it's actually added to the cache is when its name is 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // set so we need up to update that with the background_mode_data. 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (BackgroundModeInfoMap::const_iterator it = 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) background_mode_data_.begin(); 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != background_mode_data_.end(); 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++it) { 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it->first->GetPath() == profile_path) { 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it->second->SetName(profile_name); 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateStatusTrayIconContextMenu(); 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::OnProfileWillBeRemoved( 4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& profile_path) { 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProfileInfoCache& cache = 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_browser_process->profile_manager()->GetProfileInfoCache(); 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 profile_name = cache.GetNameOfProfileAtIndex( 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cache.GetIndexOfProfileWithPath(profile_path)); 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Remove the profile from our map of profiles. 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BackgroundModeInfoMap::iterator it = 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetBackgroundModeIterator(profile_name); 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If a profile isn't running a background app, it may not be in the map. 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it != background_mode_data_.end()) { 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) background_mode_data_.erase(it); 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateStatusTrayIconContextMenu(); 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::OnProfileNameChanged( 4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& profile_path, 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const string16& old_profile_name) { 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProfileInfoCache& cache = 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_browser_process->profile_manager()->GetProfileInfoCache(); 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 new_profile_name = cache.GetNameOfProfileAtIndex( 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cache.GetIndexOfProfileWithPath(profile_path)); 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BackgroundModeInfoMap::const_iterator it = 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetBackgroundModeIterator(old_profile_name); 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We check that the returned iterator is valid due to unittests, but really 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // this should only be called on profiles already known by the background 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // mode manager. 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it != background_mode_data_.end()) { 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it->second->SetName(new_profile_name); 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateStatusTrayIconContextMenu(); 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/////////////////////////////////////////////////////////////////////////////// 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// BackgroundModeManager::BackgroundModeData, ui::SimpleMenuModel overrides 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BackgroundModeManager::IsCommandIdChecked( 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int command_id) const { 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(command_id == IDC_STATUS_TRAY_KEEP_CHROME_RUNNING_IN_BACKGROUND); 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BackgroundModeManager::IsCommandIdEnabled( 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int command_id) const { 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (command_id == IDC_STATUS_TRAY_KEEP_CHROME_RUNNING_IN_BACKGROUND) { 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrefService* service = g_browser_process->local_state(); 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(service); 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return service->IsUserModifiablePreference(prefs::kBackgroundModeEnabled); 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return command_id != IDC_MinimumLabelValue; 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BackgroundModeManager::GetAcceleratorForCommandId( 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int command_id, ui::Accelerator* accelerator) { 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No accelerators for status icon context menus. 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BackgroundModeManager::ExecuteCommand(int command_id, int event_flags) { 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // When a browser window is necessary, we use the first profile. The windows 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // opened for these commands are not profile-specific, so any profile would 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // work and the first is convenient. 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BackgroundModeData* bmd = background_mode_data_.begin()->second.get(); 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (command_id) { 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case IDC_ABOUT: 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::ShowAboutChrome(bmd->GetBrowserWindow()); 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case IDC_TASK_MANAGER: 495eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch chrome::OpenTaskManager(bmd->GetBrowserWindow()); 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case IDC_EXIT: 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::RecordAction(UserMetricsAction("Exit")); 4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) chrome::AttemptExit(); 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case IDC_STATUS_TRAY_KEEP_CHROME_RUNNING_IN_BACKGROUND: { 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Background mode must already be enabled (as otherwise this menu would 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // not be visible). 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(IsBackgroundModePrefEnabled()); 5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(chrome::WillKeepAlive()); 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set the background mode pref to "disabled" - the resulting notification 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // will result in a call to DisableBackgroundMode(). 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrefService* service = g_browser_process->local_state(); 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(service); 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) service->SetBoolean(prefs::kBackgroundModeEnabled, false); 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bmd->ExecuteCommand(command_id, event_flags); 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/////////////////////////////////////////////////////////////////////////////// 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// BackgroundModeManager, private 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::EndKeepAliveForStartup() { 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (keep_alive_for_startup_) { 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keep_alive_for_startup_ = false; 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We call this via the message queue to make sure we don't try to end 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // keep-alive (which can shutdown Chrome) before the message loop has 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // started. 52990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::MessageLoop::current()->PostTask(FROM_HERE, 53090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::Bind(&chrome::EndKeepAlive)); 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::StartBackgroundMode() { 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(ShouldBeInBackgroundMode()); 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Don't bother putting ourselves in background mode if we're already there 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // or if background mode is disabled. 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (in_background_mode_) 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mark ourselves as running in background mode. 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in_background_mode_ = true; 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Put ourselves in KeepAlive mode and create a status tray icon. 5452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) chrome::StartKeepAlive(); 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Display a status icon to exit Chrome. 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InitStatusTrayIcon(); 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::NotificationService::current()->Notify( 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::NOTIFICATION_BACKGROUND_MODE_CHANGED, 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::Source<BackgroundModeManager>(this), 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::Details<bool>(&in_background_mode_)); 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::InitStatusTrayIcon() { 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only initialize status tray icons for those profiles which actually 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // have a background app running. 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ShouldBeInBackgroundMode()) 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CreateStatusTrayIcon(); 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::EndBackgroundMode() { 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!in_background_mode_) 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in_background_mode_ = false; 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // End KeepAlive mode and blow away our status tray icon. 5692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) chrome::EndKeepAlive(); 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RemoveStatusTrayIcon(); 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::NotificationService::current()->Notify( 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::NOTIFICATION_BACKGROUND_MODE_CHANGED, 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::Source<BackgroundModeManager>(this), 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::Details<bool>(&in_background_mode_)); 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::EnableBackgroundMode() { 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(IsBackgroundModePrefEnabled()); 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If background mode should be enabled, but isn't, turn it on. 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!in_background_mode_ && ShouldBeInBackgroundMode()) { 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartBackgroundMode(); 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnableLaunchOnStartup(true); 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::DisableBackgroundMode() { 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!IsBackgroundModePrefEnabled()); 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If background mode is currently enabled, turn it off. 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (in_background_mode_) { 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EndBackgroundMode(); 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnableLaunchOnStartup(false); 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BackgroundModeManager::GetBackgroundAppCount() const { 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int count = 0; 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Walk the BackgroundModeData for all profiles and count the number of apps. 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (BackgroundModeInfoMap::const_iterator it = 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) background_mode_data_.begin(); 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != background_mode_data_.end(); 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++it) { 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) count += it->second->GetBackgroundAppCount(); 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(count >= 0); 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return count; 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BackgroundModeManager::GetBackgroundAppCountForProfile( 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Profile* const profile) const { 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BackgroundModeData* bmd = GetBackgroundModeData(profile); 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return bmd->GetBackgroundAppCount(); 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BackgroundModeManager::ShouldBeInBackgroundMode() const { 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return IsBackgroundModePrefEnabled() && 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (GetBackgroundAppCount() > 0 || keep_alive_for_test_); 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::OnBackgroundAppInstalled( 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const Extension* extension) { 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Background mode is disabled - don't do anything. 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsBackgroundModePrefEnabled()) 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check if we need a status tray icon and make one if we do (needed so we 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // can display the app-installed notification below). 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CreateStatusTrayIcon(); 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Notify the user that a background app has been installed. 631eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (extension) { // NULL when called by unit tests. 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DisplayAppInstalledNotification(extension); 633eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 634eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 635eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 636eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid BackgroundModeManager::CheckReloadStatus( 637eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const Extension* extension, 638eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool* is_being_reloaded) { 639eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Walk the BackgroundModeData for all profiles to see if one of their 640eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // extensions is being reloaded. 641eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (BackgroundModeInfoMap::const_iterator it = 642eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch background_mode_data_.begin(); 643eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch it != background_mode_data_.end(); 644eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ++it) { 645eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Profile* profile = it->first; 646eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // If the extension is being reloaded, no need to show a notification. 647eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (profile->GetExtensionService()->IsBeingReloaded(extension->id())) 648eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch *is_being_reloaded = true; 649eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::CreateStatusTrayIcon() { 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only need status icons on windows/linux. ChromeOS doesn't allow exiting 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Chrome and Mac can use the dock icon instead. 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Since there are multiple profiles which share the status tray, we now 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // use the browser process to keep track of it. 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_MACOSX) && !defined(OS_CHROMEOS) 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!status_tray_) 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_tray_ = g_browser_process->status_tray(); 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the platform doesn't support status icons, or we've already created 6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // our status icon, just return. 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!status_tray_ || status_icon_) 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(rlp): Status tray icon should have submenus for each profile. 6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::ImageSkia* image_skia = ui::ResourceBundle::GetSharedInstance(). 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetImageSkiaNamed(IDR_STATUS_TRAY_ICON); 671a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 672a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) status_icon_ = status_tray_->CreateStatusIcon( 673a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) StatusTray::BACKGROUND_MODE_ICON, 674a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) *image_skia, 675a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)); 676a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (!status_icon_) 677a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return; 6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateStatusTrayIconContextMenu(); 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::UpdateStatusTrayIconContextMenu() { 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If no status icon exists, it's either because one wasn't created when 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // it should have been which can happen when extensions load after the 6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // profile has already been registered with the background mode manager. 6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (in_background_mode_ && !status_icon_) 6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CreateStatusTrayIcon(); 6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we don't have a status icon or one could not be created succesfully, 6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // then no need to continue the update. 6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!status_icon_) 6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We should only get here if we have a profile loaded, or if we're running 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // in test mode. 6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (background_mode_data_.empty()) { 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(keep_alive_for_test_); 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(rlp): Add current profile color or indicator. 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create a context menu item for Chrome. 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::SimpleMenuModel* menu = new ui::SimpleMenuModel(this); 7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Add About item 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) menu->AddItem(IDC_ABOUT, l10n_util::GetStringUTF16(IDS_ABOUT)); 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) menu->AddItemWithStringId(IDC_TASK_MANAGER, IDS_TASK_MANAGER); 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) menu->AddSeparator(ui::NORMAL_SEPARATOR); 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (profile_cache_->GetNumberOfProfiles() > 1) { 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<BackgroundModeData*> bmd_vector; 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (BackgroundModeInfoMap::iterator it = 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) background_mode_data_.begin(); 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != background_mode_data_.end(); 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++it) { 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bmd_vector.push_back(it->second.get()); 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::sort(bmd_vector.begin(), bmd_vector.end(), 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &BackgroundModeData::BackgroundModeDataCompare); 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int profiles_with_apps = 0; 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (std::vector<BackgroundModeData*>::const_iterator bmd_it = 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bmd_vector.begin(); 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bmd_it != bmd_vector.end(); 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++bmd_it) { 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BackgroundModeData* bmd = *bmd_it; 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We should only display the profile in the status icon if it has at 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // least one background app. 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (bmd->GetBackgroundAppCount() > 0) { 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(bmd); 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bmd->BuildProfileMenu(submenu, menu); 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profiles_with_apps++; 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We should only be displaying the status tray icon if there is at least 7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // one profile with a background app. 7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_GT(profiles_with_apps, 0); 7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We should only have one profile in the cache if we are not 7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // using multi-profiles. If keep_alive_for_test_ is set, then we may not 7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // have any profiles in the cache. 7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(profile_cache_->GetNumberOfProfiles() == size_t(1) || 7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keep_alive_for_test_); 7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) background_mode_data_.begin()->second->BuildProfileMenu(menu, NULL); 7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 7442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) menu->AddSeparator(ui::NORMAL_SEPARATOR); 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) menu->AddCheckItemWithStringId( 7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDC_STATUS_TRAY_KEEP_CHROME_RUNNING_IN_BACKGROUND, 7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDS_STATUS_TRAY_KEEP_CHROME_RUNNING_IN_BACKGROUND); 7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) menu->AddItemWithStringId(IDC_EXIT, IDS_EXIT); 7492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_menu_ = menu; 7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_icon_->SetContextMenu(menu); 7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BackgroundModeManager::RemoveStatusTrayIcon() { 7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (status_icon_) 7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_tray_->RemoveStatusIcon(status_icon_); 7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_icon_ = NULL; 7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_menu_ = NULL; 7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BackgroundModeManager::BackgroundModeData* 7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BackgroundModeManager::GetBackgroundModeData(Profile* const profile) const { 7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(background_mode_data_.find(profile) != background_mode_data_.end()); 7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return background_mode_data_.find(profile)->second.get(); 7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BackgroundModeManager::BackgroundModeInfoMap::iterator 7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BackgroundModeManager::GetBackgroundModeIterator( 7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const string16& profile_name) { 7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BackgroundModeInfoMap::iterator profile_it = 7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) background_mode_data_.end(); 7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (BackgroundModeInfoMap::iterator it = 7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) background_mode_data_.begin(); 7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != background_mode_data_.end(); 7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++it) { 7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it->second->name() == profile_name) { 7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile_it = it; 7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return profile_it; 7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BackgroundModeManager::IsBackgroundModePrefEnabled() const { 7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrefService* service = g_browser_process->local_state(); 7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(service); 7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return service->GetBoolean(prefs::kBackgroundModeEnabled); 7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 788