blob: 2afc96f6038210c1428be6ee7062672ea3a82812 [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.
#include "chrome/browser/extensions/component_migration_helper.h"
#include "base/stl_util.h"
#include "base/values.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system_impl.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "content/public/browser/browser_context.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/common/feature_switch.h"
namespace extensions {
ComponentMigrationHelper::ComponentMigrationHelper(
Profile* profile,
ComponentActionDelegate* delegate)
: profile_(profile),
delegate_(delegate),
extension_registry_(ExtensionRegistry::Get(profile)),
pref_service_(profile->GetPrefs()),
extension_system_(ExtensionSystem::Get(profile)),
extension_registry_observer_(this) {
DCHECK(delegate_);
extension_registry_observer_.Add(extension_registry_);
}
ComponentMigrationHelper::~ComponentMigrationHelper() {}
// static
void ComponentMigrationHelper::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterDictionaryPref(
::prefs::kToolbarMigratedComponentActionStatus);
}
void ComponentMigrationHelper::Register(const std::string& component_action_id,
const ExtensionId& extension_id) {
DCHECK(GetActionIdForExtensionId(extension_id).empty());
migrated_actions_.push_back(
std::make_pair(component_action_id, extension_id));
}
void ComponentMigrationHelper::Unregister(
const std::string& component_action_id,
const ExtensionId& extension_id) {
for (auto it = migrated_actions_.begin(); it != migrated_actions_.end();
it++) {
if (it->first == component_action_id && it->second == extension_id) {
migrated_actions_.erase(it);
return;
}
}
}
void ComponentMigrationHelper::OnFeatureEnabled(
const std::string& component_action_id) {
DCHECK(FeatureSwitch::extension_action_redesign()->IsEnabled());
std::vector<ExtensionId> extension_ids =
GetExtensionIdsForActionId(component_action_id);
DCHECK(!extension_ids.empty());
enabled_actions_.insert(component_action_id);
// Unload any extensions that we are migrating from.
bool extension_was_installed = false;
for (const auto& id : extension_ids) {
if (IsExtensionInstalledAndEnabled(id)) {
extension_was_installed = true;
UnloadExtension(id);
}
}
// Read the pref to determine component action status. If not set, set to
// true if we unloaded an extension.
const base::DictionaryValue* migration_pref = pref_service_->GetDictionary(
::prefs::kToolbarMigratedComponentActionStatus);
bool has_component_action_pref = migration_pref->HasKey(component_action_id);
bool component_action_pref = false;
if (has_component_action_pref) {
bool success =
migration_pref->GetBoolean(component_action_id, &component_action_pref);
DCHECK(success); // Shouldn't fail, but can in case of pref corruption.
}
if (!has_component_action_pref && extension_was_installed) {
SetComponentActionPref(component_action_id, true);
component_action_pref = true;
}
if (component_action_pref &&
!delegate_->HasComponentAction(component_action_id)) {
delegate_->AddComponentAction(component_action_id);
}
}
void ComponentMigrationHelper::OnFeatureDisabled(
const std::string& component_action_id) {
std::vector<ExtensionId> extension_ids =
GetExtensionIdsForActionId(component_action_id);
DCHECK(!extension_ids.empty());
enabled_actions_.erase(component_action_id);
RemoveComponentActionPref(component_action_id);
if (FeatureSwitch::extension_action_redesign()->IsEnabled() &&
delegate_->HasComponentAction(component_action_id))
delegate_->RemoveComponentAction(component_action_id);
}
void ComponentMigrationHelper::OnActionRemoved(
const std::string& component_action_id) {
// Record preference for the future.
SetComponentActionPref(component_action_id, false);
// Remove the action.
if (delegate_->HasComponentAction(component_action_id))
delegate_->RemoveComponentAction(component_action_id);
}
void ComponentMigrationHelper::OnExtensionReady(
content::BrowserContext* browser_context,
const Extension* extension) {
const ExtensionId& extension_id = extension->id();
const std::string& component_action_id =
GetActionIdForExtensionId(extension_id);
if (component_action_id.empty())
return;
if (ContainsKey(enabled_actions_, component_action_id)) {
UnloadExtension(extension_id);
SetComponentActionPref(component_action_id, true);
if (!delegate_->HasComponentAction(component_action_id))
delegate_->AddComponentAction(component_action_id);
}
}
void ComponentMigrationHelper::SetComponentActionPref(
const std::string& component_action_id,
bool enabled) {
DictionaryPrefUpdate update(pref_service_,
::prefs::kToolbarMigratedComponentActionStatus);
update->SetBoolean(component_action_id, enabled);
}
bool ComponentMigrationHelper::IsExtensionInstalledAndEnabled(
const ExtensionId& extension_id) const {
return extension_registry_->enabled_extensions().Contains(extension_id) ||
extension_registry_->terminated_extensions().Contains(extension_id);
}
void ComponentMigrationHelper::UnloadExtension(
const ExtensionId& extension_id) {
extension_system_->extension_service()->UnloadExtension(
extension_id, UnloadedExtensionInfo::REASON_MIGRATED_TO_COMPONENT);
}
void ComponentMigrationHelper::RemoveComponentActionPref(
const std::string& component_action_id) {
DictionaryPrefUpdate update(pref_service_,
::prefs::kToolbarMigratedComponentActionStatus);
update->Remove(component_action_id, nullptr);
}
std::vector<std::string> ComponentMigrationHelper::GetExtensionIdsForActionId(
const std::string& component_action_id) const {
std::vector<ExtensionId> extension_ids;
for (const auto& i : migrated_actions_) {
if (i.first == component_action_id)
extension_ids.push_back(i.second);
}
return extension_ids;
}
std::string ComponentMigrationHelper::GetActionIdForExtensionId(
const ExtensionId& extension_id) const {
for (const auto& i : migrated_actions_) {
if (i.second == extension_id)
return i.first;
}
return "";
}
} // namespace extensions