blob: 4f4ce9eb9cd61ff5469dbc8c6241587c948914e9 [file] [log] [blame]
// 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;
Profile* const profile_;
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_