text: // Copyright 2016 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef CHROME_BROWSER_EXTENSIONS_COMPONENT_MIGRATION_HELPER_H_
  #define CHROME_BROWSER_EXTENSIONS_COMPONENT_MIGRATION_HELPER_H_
  
  #include <set>
  #include <string>
  #include <utility>
  #include <vector>
  
  #include "base/macros.h"
  #include "base/scoped_observer.h"
  #include "extensions/browser/extension_registry_observer.h"
  
  class Profile;
  class PrefRegistrySimple;
  class PrefService;
  
  namespace content {
  class BrowserContext;
  }
  
  namespace extensions {
  
  class ExtensionRegistry;
  class ExtensionSystem;
  
  // For migrating existing extensions to component actions, and vice versa.  A
  // previous enabled extension is used as a signal to add the corresponding
  // component action to the visible area of the toolbar. This allows users who
  // have already installed the extension to have their preference for a component
  // action in the visible area of the toolbar respected, without enabling this
  // for the entire user base.
  //
  // MIGRATION LOGIC
  //
  // When the feature is enabled (i.e. by experiment or flag), the client should
  // call OnFeatureEnabled(action_id).  The extension action redesign MUST also be
  // enabled.
  //
  //   - If the extension is enabled, it is unloaded with a reason of
  //     MIGRATED_TO_COMPONENT, the component action shown, and a pref set
  //     recording the migration.
  //   - If pref is set the component action is shown.
  //   - Otherwise, the component action is not shown.
  //
  // When the feature is disabled (for example, by starting with a flag off), the
  // client should call OnFeatureDisabled(action_id).
  //
  //   - The pref is removed.
  //   - If the extension action redesign is enabled, the associated component
  //     action is removed.
  //
  // USAGE
  // helper->Register("some-action-id", "some-extension-id");
  // helper->Register("some-action-id", "other-extension-id");
  // ...
  // // When feature is enabled
  // helper->OnFeatureEnabled("some-action-id");
  // ...
  // // When feature is disabled
  // helper->OnFeatureDisabled("some-action-id");
  //
  // It is legal to register more than one extension per action but not vice
  // versa.
  class ComponentMigrationHelper : public ExtensionRegistryObserver {
   public:
    // Object that knows how to manage component actions in the toolbar model.
    class ComponentActionDelegate {
     public:
      // Adds or removes the component action labeled by |action_id| from the
      // toolbar model.  The caller will not add the same action twice.
      virtual void AddComponentAction(const std::string& action_id) = 0;
      virtual void RemoveComponentAction(const std::string& action_id) = 0;
  
      // Returns |true| if the toolbar model has an action for |action_id|.
      virtual bool HasComponentAction(const std::string& action_id) const = 0;
    };
  
    ComponentMigrationHelper(Profile* profile, ComponentActionDelegate* delegate);
    ~ComponentMigrationHelper() override;
  
    static void RegisterPrefs(PrefRegistrySimple* registry);
  
    // Registers and unregisters a component action/extension pair.  A component
    // action may have more than one associated extension id, but not vice versa.
    void Register(const std::string& component_action_id,
                  const ExtensionId& extension_id);
    void Unregister(const std::string& component_action_id,
                    const ExtensionId& extension_id);
  
    // Call when we should potentially add the component action and unload
    // the extension.  PREREQUISITE: The extension action redesign MUST be
    // enabled.
    void OnFeatureEnabled(const std::string& component_action_id);
  
    // Call when we should potentially remove the component action and re-enable
    // extension loading.
    void OnFeatureDisabled(const std::string& component_action_id);
  
    // Call when the user manually removes the component action from the toolbar.
    void OnActionRemoved(const std::string& component_action_id);
  
    // extensions::ExtensionRegistryObserver:
    void OnExtensionReady(content::BrowserContext* browser_context,
                          const Extension* extension) override;
  
   protected:
    // Protected for unit testing.
    void SetComponentActionPref(const std::string& component_action_id,
                                bool enabled);
  
    // A set of component action ids whose features are currently enabled.
    // Protected for unit testing.
    std::set<std::string> enabled_actions_;
  
   private:
    bool IsExtensionInstalledAndEnabled(const ExtensionId& extension_id) const;
    void UnloadExtension(const ExtensionId& extension_id);
    void RemoveComponentActionPref(const std::string& component_action_id);
    std::vector<std::string> GetExtensionIdsForActionId(
        const std::string& component_action_id) const;
    std::string GetActionIdForExtensionId(const ExtensionId& extension_id) const;
  
    ComponentActionDelegate* const delegate_;
    // The ExtensionRegistry, PrefService, and ExtensionSystem, cached for
    // convenience.
    ExtensionRegistry* const extension_registry_;
    PrefService* const pref_service_;
    ExtensionSystem* const extension_system_;
  
    ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver>
        extension_registry_observer_;
  
    // A list of pairs of component action ids and extension ids.
    std::vector<std::pair<std::string, ExtensionId>> migrated_actions_;
  
    DISALLOW_COPY_AND_ASSIGN(ComponentMigrationHelper);
  };
  
  }  // namespace extensions
  
  #endif  // CHROME_BROWSER_EXTENSIONS_COMPONENT_MIGRATION_HELPER_H_
  