Home | History | Annotate | Download | only in background
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef CHROME_BROWSER_BACKGROUND_BACKGROUND_MODE_MANAGER_H_
      6 #define CHROME_BROWSER_BACKGROUND_BACKGROUND_MODE_MANAGER_H_
      7 
      8 #include <map>
      9 
     10 #include "base/gtest_prod_util.h"
     11 #include "base/prefs/pref_change_registrar.h"
     12 #include "chrome/browser/background/background_application_list_model.h"
     13 #include "chrome/browser/profiles/profile_info_cache_observer.h"
     14 #include "chrome/browser/status_icons/status_icon.h"
     15 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
     16 #include "content/public/browser/notification_observer.h"
     17 #include "content/public/browser/notification_registrar.h"
     18 #include "ui/base/models/simple_menu_model.h"
     19 
     20 class Browser;
     21 class CommandLine;
     22 class PrefRegistrySimple;
     23 class Profile;
     24 class ProfileInfoCache;
     25 class StatusIcon;
     26 class StatusTray;
     27 
     28 namespace extensions {
     29 class Extension;
     30 }
     31 
     32 // BackgroundModeManager is responsible for switching Chrome into and out of
     33 // "background mode" and for providing UI for the user to exit Chrome when there
     34 // are no open browser windows.
     35 //
     36 // Chrome enters background mode whenever there is an application with the
     37 // "background" permission installed. This class monitors the set of
     38 // installed/loaded extensions to ensure that Chrome enters/exits background
     39 // mode at the appropriate time.
     40 //
     41 // When Chrome is in background mode, it will continue running even after the
     42 // last browser window is closed, until the user explicitly exits the app.
     43 // Additionally, when in background mode, Chrome will launch on OS login with
     44 // no open windows to allow apps with the "background" permission to run in the
     45 // background.
     46 class BackgroundModeManager
     47     : public content::NotificationObserver,
     48       public BackgroundApplicationListModel::Observer,
     49       public ProfileInfoCacheObserver,
     50       public ui::SimpleMenuModel::Delegate {
     51  public:
     52   BackgroundModeManager(CommandLine* command_line,
     53                         ProfileInfoCache* profile_cache);
     54   virtual ~BackgroundModeManager();
     55 
     56   static void RegisterPrefs(PrefRegistrySimple* registry);
     57 
     58   virtual void RegisterProfile(Profile* profile);
     59 
     60   static void LaunchBackgroundApplication(Profile* profile,
     61       const extensions::Extension* extension);
     62 
     63   // For testing purposes.
     64   int NumberOfBackgroundModeData();
     65 
     66  private:
     67   friend class AppBackgroundPageApiTest;
     68   friend class BackgroundModeManagerTest;
     69   friend class TestBackgroundModeManager;
     70   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
     71                            BackgroundAppLoadUnload);
     72   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
     73                            BackgroundLaunchOnStartup);
     74   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
     75                            BackgroundAppInstallUninstallWhileDisabled);
     76   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
     77                            BackgroundModeDisabledPreventsKeepAliveOnStartup);
     78   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
     79                            DisableBackgroundModeUnderTestFlag);
     80   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
     81                            EnableAfterBackgroundAppInstall);
     82   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
     83                            MultiProfile);
     84   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
     85                            ProfileInfoCacheStorage);
     86   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
     87                            ProfileInfoCacheObserver);
     88   FRIEND_TEST_ALL_PREFIXES(BackgroundAppBrowserTest,
     89                            ReloadBackgroundApp);
     90 
     91   class BackgroundModeData : public ui::SimpleMenuModel::Delegate {
     92    public:
     93     explicit BackgroundModeData(
     94         int command_id,
     95         Profile* profile);
     96     virtual ~BackgroundModeData();
     97 
     98     // The cached list of BackgroundApplications.
     99     scoped_ptr<BackgroundApplicationListModel> applications_;
    100 
    101     // Overrides from SimpleMenuModel::Delegate implementation.
    102     virtual bool IsCommandIdChecked(int command_id) const OVERRIDE;
    103     virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE;
    104     virtual bool GetAcceleratorForCommandId(int command_id,
    105                                             ui::Accelerator* accelerator)
    106                                             OVERRIDE;
    107     virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
    108 
    109     // Returns a browser window, or creates one if none are open. Used by
    110     // operations (like displaying the preferences dialog) that require a
    111     // Browser window.
    112     Browser* GetBrowserWindow();
    113 
    114     // Returns the number of background apps for this profile.
    115     int GetBackgroundAppCount() const;
    116 
    117     // Builds the profile specific parts of the menu. The menu passed in may
    118     // be a submenu in the case of multi-profiles or the main menu in the case
    119     // of the single profile case. If containing_menu is valid, we will add
    120     // menu as a submenu to it.
    121     void BuildProfileMenu(ui::SimpleMenuModel* menu,
    122                           ui::SimpleMenuModel* containing_menu);
    123 
    124     // Set the name associated with this background mode data for displaying in
    125     // the status tray.
    126     void SetName(const string16& new_profile_name);
    127 
    128     // The name associated with this background mode data. This should match
    129     // the name in the ProfileInfoCache for this profile.
    130     string16 name();
    131 
    132     // Used for sorting BackgroundModeData*s.
    133     static bool BackgroundModeDataCompare(const BackgroundModeData* bmd1,
    134                                           const BackgroundModeData* bmd2);
    135 
    136    private:
    137     // Command id for the sub menu for this BackgroundModeData.
    138     int command_id_;
    139 
    140     // Name associated with this profile which is used to label its submenu.
    141     string16 name_;
    142 
    143     // The profile associated with this background app data.
    144     Profile* profile_;
    145   };
    146 
    147   // Ideally we would want our BackgroundModeData to be scoped_ptrs,
    148   // but since maps copy their entries, we can't used scoped_ptrs.
    149   // Similarly, we can't just have a map of BackgroundModeData objects,
    150   // since BackgroundModeData contains a scoped_ptr which once again
    151   // can't be copied. So rather than using BackgroundModeData* which
    152   // we'd have to remember to delete, we use the ref-counted linked_ptr
    153   // which is similar to a shared_ptr.
    154   typedef linked_ptr<BackgroundModeData> BackgroundModeInfo;
    155 
    156   typedef std::map<Profile*, BackgroundModeInfo> BackgroundModeInfoMap;
    157 
    158   // content::NotificationObserver implementation.
    159   virtual void Observe(int type,
    160                        const content::NotificationSource& source,
    161                        const content::NotificationDetails& details) OVERRIDE;
    162 
    163   // Called when the kBackgroundModeEnabled preference changes.
    164   void OnBackgroundModeEnabledPrefChanged();
    165 
    166   // BackgroundApplicationListModel::Observer implementation.
    167   virtual void OnApplicationDataChanged(const extensions::Extension* extension,
    168                                         Profile* profile) OVERRIDE;
    169   virtual void OnApplicationListChanged(Profile* profile) OVERRIDE;
    170 
    171   // Overrides from ProfileInfoCacheObserver
    172   virtual void OnProfileAdded(const base::FilePath& profile_path) OVERRIDE;
    173   virtual void OnProfileWillBeRemoved(
    174       const base::FilePath& profile_path) OVERRIDE;
    175   virtual void OnProfileNameChanged(const base::FilePath& profile_path,
    176                                     const string16& old_profile_name) OVERRIDE;
    177 
    178   // Overrides from SimpleMenuModel::Delegate implementation.
    179   virtual bool IsCommandIdChecked(int command_id) const OVERRIDE;
    180   virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE;
    181   virtual bool GetAcceleratorForCommandId(int command_id,
    182                                           ui::Accelerator* accelerator)
    183                                           OVERRIDE;
    184   virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
    185 
    186   // Invoked when an extension is installed so we can ensure that
    187   // launch-on-startup is enabled if appropriate. |extension| can be NULL when
    188   // called from unit tests.
    189   void OnBackgroundAppInstalled(
    190       const extensions::Extension* extension);
    191 
    192   // Walk the list of profiles and see if an extension or app is being
    193   // currently upgraded or reloaded by any profile.  If so, update the
    194   // output variables appropriately.
    195   void CheckReloadStatus(
    196       const extensions::Extension* extension,
    197       bool* is_being_reloaded);
    198 
    199   // Called to make sure that our launch-on-startup mode is properly set.
    200   // (virtual so we can override for tests).
    201   virtual void EnableLaunchOnStartup(bool should_launch);
    202 
    203   // Invoked when a background app is installed so we can display a
    204   // platform-specific notification to the user.
    205   virtual void DisplayAppInstalledNotification(
    206       const extensions::Extension* extension);
    207 
    208   // Invoked to put Chrome in KeepAlive mode - chrome runs in the background
    209   // and has a status bar icon.
    210   void StartBackgroundMode();
    211 
    212   // Invoked to create the status icon if any profiles currently running
    213   // background apps so that there is a way to exit Chrome.
    214   void InitStatusTrayIcon();
    215 
    216   // Invoked to take Chrome out of KeepAlive mode - chrome stops running in
    217   // the background and removes its status bar icon.
    218   void EndBackgroundMode();
    219 
    220   // If --no-startup-window is passed, BackgroundModeManager will manually keep
    221   // chrome running while waiting for apps to load. This is called when we no
    222   // longer need to do this (either because the user has chosen to exit chrome
    223   // manually, or all apps have been loaded).
    224   void EndKeepAliveForStartup();
    225 
    226   // Return an appropriate name for a Preferences menu entry.  Preferences is
    227   // sometimes called Options or Settings.
    228   string16 GetPreferencesMenuLabel();
    229 
    230   // Create a status tray icon to allow the user to shutdown Chrome when running
    231   // in background mode. Virtual to enable testing.
    232   virtual void CreateStatusTrayIcon();
    233 
    234   // Removes the status tray icon because we are exiting background mode.
    235   // Virtual to enable testing.
    236   virtual void RemoveStatusTrayIcon();
    237 
    238   // Create a context menu, or replace/update an existing context menu, for the
    239   // status tray icon which, among other things, allows the user to shutdown
    240   // Chrome when running in background mode. All profiles are listed under
    241   // the one context menu.
    242   virtual void UpdateStatusTrayIconContextMenu();
    243 
    244   // Returns the BackgroundModeData associated with this profile. If it does
    245   // not exist, returns NULL.
    246   BackgroundModeManager::BackgroundModeData* GetBackgroundModeData(
    247       Profile* const profile) const;
    248 
    249   // Returns the iterator associated with a particular profile name.
    250   // This should not be used to iterate over the background mode data. It is
    251   // used to efficiently delete an item from the background mode data map.
    252   BackgroundModeInfoMap::iterator GetBackgroundModeIterator(
    253       const string16& profile_name);
    254 
    255   // Returns true if the "Let chrome run in the background" pref is checked.
    256   // (virtual to allow overriding in tests).
    257   virtual bool IsBackgroundModePrefEnabled() const;
    258 
    259   // Returns true if background mode is active. Used only by tests.
    260   bool IsBackgroundModeActiveForTest();
    261 
    262   // Turns off background mode if it's currently enabled.
    263   void DisableBackgroundMode();
    264 
    265   // Turns on background mode if it's currently disabled.
    266   void EnableBackgroundMode();
    267 
    268   // Returns the number of background apps in the system (virtual to allow
    269   // overriding in unit tests).
    270   virtual int GetBackgroundAppCount() const;
    271 
    272   // Returns the number of background apps for a profile.
    273   virtual int GetBackgroundAppCountForProfile(Profile* const profile) const;
    274 
    275   // Returns true if we should be in background mode.
    276   bool ShouldBeInBackgroundMode() const;
    277 
    278   // Reference to the profile info cache. It is used to update the background
    279   // app status of profiles when they open/close background apps.
    280   ProfileInfoCache* profile_cache_;
    281 
    282   // Registrars for managing our change observers.
    283   content::NotificationRegistrar registrar_;
    284   PrefChangeRegistrar pref_registrar_;
    285 
    286   // The profile-keyed data for this background mode manager. Keyed on profile.
    287   BackgroundModeInfoMap background_mode_data_;
    288 
    289   // Reference to our status tray. If null, the platform doesn't support status
    290   // icons.
    291   StatusTray* status_tray_;
    292 
    293   // Reference to our status icon (if any) - owned by the StatusTray.
    294   StatusIcon* status_icon_;
    295 
    296   // Reference to our status icon's context menu (if any) - owned by the
    297   // status_icon_.
    298   ui::SimpleMenuModel* context_menu_;
    299 
    300   // Set to true when we are running in background mode. Allows us to track our
    301   // current background state so we can take the appropriate action when the
    302   // user disables/enables background mode via preferences.
    303   bool in_background_mode_;
    304 
    305   // Set when we are keeping chrome running during the startup process - this
    306   // is required when running with the --no-startup-window flag, as otherwise
    307   // chrome would immediately exit due to having no open windows.
    308   bool keep_alive_for_startup_;
    309 
    310   // Set to true when Chrome is running with the --keep-alive-for-test flag
    311   // (used for testing background mode without having to install a background
    312   // app).
    313   bool keep_alive_for_test_;
    314 
    315   // Provides a command id for each profile as they are created.
    316   int current_command_id_;
    317 
    318   DISALLOW_COPY_AND_ASSIGN(BackgroundModeManager);
    319 };
    320 
    321 #endif  // CHROME_BROWSER_BACKGROUND_BACKGROUND_MODE_MANAGER_H_
    322