1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/api/declarative_content/content_action.h"
9 #include "base/lazy_instance.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/values.h"
12 #include "chrome/browser/extensions/api/declarative_content/content_constants.h"
13 #include "chrome/browser/extensions/extension_action.h"
14 #include "chrome/browser/extensions/extension_action_manager.h"
15 #include "chrome/browser/extensions/extension_service.h"
16 #include "chrome/browser/extensions/extension_system.h"
17 #include "chrome/browser/extensions/extension_tab_util.h"
18 #include "chrome/common/extensions/extension.h"
19 #include "content/public/browser/invalidate_type.h"
20 #include "content/public/browser/web_contents.h"
22 namespace extensions {
24 namespace keys = declarative_content_constants;
28 const char kInvalidInstanceTypeError[] =
29 "An action has an invalid instanceType: %s";
30 const char kNoPageAction[] =
31 "Can't use declarativeContent.ShowPageAction without a page action";
33 #define INPUT_FORMAT_VALIDATE(test) do { \
35 *bad_message = true; \
36 return scoped_refptr<ContentAction>(NULL); \
41 // The following are concrete actions.
44 // Action that instructs to show an extension's page action.
45 class ShowPageAction : public ContentAction {
49 static scoped_refptr<ContentAction> Create(const Extension* extension,
50 const base::DictionaryValue* dict,
53 // We can't show a page action if the extension doesn't have one.
54 if (ActionInfo::GetPageActionInfo(extension) == NULL) {
55 *error = kNoPageAction;
56 return scoped_refptr<ContentAction>();
58 return scoped_refptr<ContentAction>(new ShowPageAction);
61 // Implementation of ContentAction:
62 virtual Type GetType() const OVERRIDE { return ACTION_SHOW_PAGE_ACTION; }
63 virtual void Apply(const std::string& extension_id,
64 const base::Time& extension_install_time,
65 ApplyInfo* apply_info) const OVERRIDE {
66 GetPageAction(apply_info->profile, extension_id)->DeclarativeShow(
67 ExtensionTabUtil::GetTabId(apply_info->tab));
68 apply_info->tab->NotifyNavigationStateChanged(
69 content::INVALIDATE_TYPE_PAGE_ACTIONS);
71 virtual void Revert(const std::string& extension_id,
72 const base::Time& extension_install_time,
73 ApplyInfo* apply_info) const OVERRIDE {
74 if (ExtensionAction* action =
75 GetPageAction(apply_info->profile, extension_id)) {
76 action->UndoDeclarativeShow(ExtensionTabUtil::GetTabId(apply_info->tab));
77 apply_info->tab->NotifyNavigationStateChanged(
78 content::INVALIDATE_TYPE_PAGE_ACTIONS);
83 static ExtensionAction* GetPageAction(Profile* profile,
84 const std::string& extension_id) {
85 ExtensionService* service =
86 ExtensionSystem::Get(profile)->extension_service();
87 const Extension* extension = service->GetInstalledExtension(extension_id);
90 return ExtensionActionManager::Get(profile)->GetPageAction(*extension);
92 virtual ~ShowPageAction() {}
94 DISALLOW_COPY_AND_ASSIGN(ShowPageAction);
97 struct ContentActionFactory {
98 // Factory methods for ContentAction instances. |extension| is the extension
99 // for which the action is being created. |dict| contains the json dictionary
100 // that describes the action. |error| is used to return error messages in case
101 // the extension passed an action that was syntactically correct but
102 // semantically incorrect. |bad_message| is set to true in case |dict| does
103 // not confirm to the validated JSON specification.
104 typedef scoped_refptr<ContentAction>(*FactoryMethod)(
105 const Extension* /* extension */,
106 const base::DictionaryValue* /* dict */,
107 std::string* /* error */,
108 bool* /* bad_message */);
109 // Maps the name of a declarativeContent action type to the factory
110 // function creating it.
111 std::map<std::string, FactoryMethod> factory_methods;
113 ContentActionFactory() {
114 factory_methods[keys::kShowPageAction] =
115 &ShowPageAction::Create;
119 base::LazyInstance<ContentActionFactory>::Leaky
120 g_content_action_factory = LAZY_INSTANCE_INITIALIZER;
128 ContentAction::ContentAction() {}
130 ContentAction::~ContentAction() {}
133 scoped_refptr<ContentAction> ContentAction::Create(
134 const Extension* extension,
135 const base::Value& json_action,
139 *bad_message = false;
141 const base::DictionaryValue* action_dict = NULL;
142 INPUT_FORMAT_VALIDATE(json_action.GetAsDictionary(&action_dict));
144 std::string instance_type;
145 INPUT_FORMAT_VALIDATE(
146 action_dict->GetString(keys::kInstanceType, &instance_type));
148 ContentActionFactory& factory = g_content_action_factory.Get();
149 std::map<std::string, ContentActionFactory::FactoryMethod>::iterator
150 factory_method_iter = factory.factory_methods.find(instance_type);
151 if (factory_method_iter != factory.factory_methods.end())
152 return (*factory_method_iter->second)(
153 extension, action_dict, error, bad_message);
155 *error = base::StringPrintf(kInvalidInstanceTypeError, instance_type.c_str());
156 return scoped_refptr<ContentAction>();
159 } // namespace extensions