// Copyright 2014 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/extension_action_test_util.h" #include "base/memory/scoped_ptr.h" #include "base/run_loop.h" #include "chrome/browser/extensions/extension_action.h" #include "chrome/browser/extensions/extension_action_manager.h" #include "chrome/browser/extensions/location_bar_controller.h" #include "chrome/browser/extensions/tab_helper.h" #include "chrome/browser/extensions/test_extension_system.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sessions/session_tab_helper.h" #include "chrome/browser/ui/toolbar/toolbar_actions_model.h" #include "chrome/browser/ui/toolbar/toolbar_actions_model_factory.h" #include "components/crx_file/id_util.h" #include "content/public/browser/web_contents.h" #include "extensions/browser/extension_registry.h" #include "extensions/common/extension.h" #include "extensions/common/extension_builder.h" #include "extensions/common/feature_switch.h" #include "extensions/common/manifest_constants.h" #include "extensions/common/value_builder.h" namespace extensions { namespace extension_action_test_util { namespace { size_t GetPageActionCount(content::WebContents* web_contents, bool only_count_visible) { DCHECK(web_contents); size_t count = 0u; int tab_id = SessionTabHelper::IdForTab(web_contents); // Page actions are either stored in the location bar (and provided by the // LocationBarController), or in the main toolbar (and provided by the // ToolbarActionsModel), depending on whether or not the extension action // redesign is enabled. if (!FeatureSwitch::extension_action_redesign()->IsEnabled()) { std::vector page_actions = TabHelper::FromWebContents(web_contents)-> location_bar_controller()->GetCurrentActions(); count = page_actions.size(); // Trim any invisible page actions, if necessary. if (only_count_visible) { for (std::vector::iterator iter = page_actions.begin(); iter != page_actions.end(); ++iter) { if (!(*iter)->GetIsVisible(tab_id)) --count; } } } else { Profile* profile = Profile::FromBrowserContext(web_contents->GetBrowserContext()); ToolbarActionsModel* toolbar_model = ToolbarActionsModel::Get(profile); const std::vector& toolbar_items = toolbar_model->toolbar_items(); ExtensionActionManager* action_manager = ExtensionActionManager::Get(web_contents->GetBrowserContext()); for (const ToolbarActionsModel::ToolbarItem& item : toolbar_items) { if (item.type == ToolbarActionsModel::EXTENSION_ACTION) { const Extension* extension = ExtensionRegistry::Get(profile)->enabled_extensions().GetByID( item.id); ExtensionAction* extension_action = action_manager->GetPageAction(*extension); if (extension_action && (!only_count_visible || extension_action->GetIsVisible(tab_id))) ++count; } } } return count; } // Creates a new ToolbarActionsModel for the given |context|. scoped_ptr BuildToolbarModel(content::BrowserContext* context) { return make_scoped_ptr( new ToolbarActionsModel(Profile::FromBrowserContext(context), extensions::ExtensionPrefs::Get(context))); } // Creates a new ToolbarActionsModel for the given profile, optionally // triggering the extension system's ready signal. ToolbarActionsModel* CreateToolbarModelImpl(Profile* profile, bool wait_for_ready) { ToolbarActionsModel* model = ToolbarActionsModel::Get(profile); if (model) return model; // No existing model means it's a new profile (since we, by default, don't // create the ToolbarModel in testing). ToolbarActionsModelFactory::GetInstance()->SetTestingFactory( profile, &BuildToolbarModel); model = ToolbarActionsModel::Get(profile); if (wait_for_ready) { // Fake the extension system ready signal. // HACK ALERT! In production, the ready task on ExtensionSystem (and most // everything else on it, too) is shared between incognito and normal // profiles, but a TestExtensionSystem doesn't have the concept of "shared". // Because of this, we have to set any new profile's TestExtensionSystem's // ready task, too. static_cast(ExtensionSystem::Get(profile))-> SetReady(); // Run tasks posted to TestExtensionSystem. base::RunLoop().RunUntilIdle(); } return model; } } // namespace size_t GetVisiblePageActionCount(content::WebContents* web_contents) { return GetPageActionCount(web_contents, true); } size_t GetTotalPageActionCount(content::WebContents* web_contents) { return GetPageActionCount(web_contents, false); } scoped_refptr CreateActionExtension(const std::string& name, ActionType action_type) { return CreateActionExtension(name, action_type, Manifest::INTERNAL); } scoped_refptr CreateActionExtension( const std::string& name, ActionType action_type, Manifest::Location location) { DictionaryBuilder manifest; manifest.Set("name", name) .Set("description", "An extension") .Set("manifest_version", 2) .Set("version", "1.0.0"); const char* action_key = nullptr; switch (action_type) { case NO_ACTION: break; case PAGE_ACTION: action_key = manifest_keys::kPageAction; break; case BROWSER_ACTION: action_key = manifest_keys::kBrowserAction; break; } if (action_key) manifest.Set(action_key, DictionaryBuilder().Build()); return ExtensionBuilder() .SetManifest(manifest.Build()) .SetID(crx_file::id_util::GenerateId(name)) .SetLocation(location) .Build(); } ToolbarActionsModel* CreateToolbarModelForProfile(Profile* profile) { return CreateToolbarModelImpl(profile, true); } ToolbarActionsModel* CreateToolbarModelForProfileWithoutWaitingForReady( Profile* profile) { return CreateToolbarModelImpl(profile, false); } } // namespace extension_action_test_util } // namespace extensions