// 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 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 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 ComponentMigrationHelper::GetExtensionIdsForActionId( const std::string& component_action_id) const { std::vector 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