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/common/extensions/api/extension_action/action_info.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/common/extensions/api/commands/commands_handler.h"
10 #include "chrome/common/extensions/extension.h"
11 #include "chrome/common/extensions/extension_constants.h"
12 #include "chrome/common/extensions/manifest_handler_helpers.h"
13 #include "extensions/common/error_utils.h"
14 #include "extensions/common/manifest_constants.h"
16 namespace extensions {
18 namespace errors = manifest_errors;
19 namespace keys = manifest_keys;
23 // The manifest data container for the ActionInfos for BrowserActions and
25 struct ActionInfoData : public Extension::ManifestData {
26 explicit ActionInfoData(ActionInfo* action_info);
27 virtual ~ActionInfoData();
29 // The action associated with the BrowserAction or ScriptBadge.
30 // This is never NULL for ScriptBadge.
31 scoped_ptr<ActionInfo> action_info;
34 ActionInfoData::ActionInfoData(ActionInfo* info) : action_info(info) {
37 ActionInfoData::~ActionInfoData() {
40 static const ActionInfo* GetActionInfo(const Extension* extension,
41 const std::string& key) {
42 ActionInfoData* data = static_cast<ActionInfoData*>(
43 extension->GetManifestData(key));
44 return data ? data->action_info.get() : NULL;
49 ActionInfo::ActionInfo() {
52 ActionInfo::~ActionInfo() {
56 scoped_ptr<ActionInfo> ActionInfo::Load(const Extension* extension,
57 const base::DictionaryValue* dict,
59 scoped_ptr<ActionInfo> result(new ActionInfo());
61 if (extension->manifest_version() == 1) {
62 // kPageActionIcons is obsolete, and used by very few extensions. Continue
63 // loading it, but only take the first icon as the default_icon path.
64 const base::ListValue* icons = NULL;
65 if (dict->HasKey(keys::kPageActionIcons) &&
66 dict->GetList(keys::kPageActionIcons, &icons)) {
67 base::ListValue::const_iterator iter = icons->begin();
69 if (iter == icons->end() ||
70 !(*iter)->GetAsString(&path) ||
71 !manifest_handler_helpers::NormalizeAndValidatePath(&path)) {
72 *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath);
73 return scoped_ptr<ActionInfo>();
75 result->default_icon.Add(extension_misc::EXTENSION_ICON_ACTION, path);
79 if (dict->HasKey(keys::kPageActionId)) {
80 if (!dict->GetString(keys::kPageActionId, &id)) {
81 *error = ASCIIToUTF16(errors::kInvalidPageActionId);
82 return scoped_ptr<ActionInfo>();
88 // Read the page action |default_icon| (optional).
89 // The |default_icon| value can be either dictionary {icon size -> icon path}
90 // or non empty string value.
91 if (dict->HasKey(keys::kPageActionDefaultIcon)) {
92 const DictionaryValue* icons_value = NULL;
93 std::string default_icon;
94 if (dict->GetDictionary(keys::kPageActionDefaultIcon, &icons_value)) {
95 if (!manifest_handler_helpers::LoadIconsFromDictionary(
97 extension_misc::kExtensionActionIconSizes,
98 extension_misc::kNumExtensionActionIconSizes,
99 &result->default_icon,
101 return scoped_ptr<ActionInfo>();
103 } else if (dict->GetString(keys::kPageActionDefaultIcon, &default_icon) &&
104 manifest_handler_helpers::NormalizeAndValidatePath(
106 result->default_icon.Add(extension_misc::EXTENSION_ICON_ACTION,
109 *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath);
110 return scoped_ptr<ActionInfo>();
114 // Read the page action title from |default_title| if present, |name| if not
116 if (dict->HasKey(keys::kPageActionDefaultTitle)) {
117 if (!dict->GetString(keys::kPageActionDefaultTitle,
118 &result->default_title)) {
119 *error = ASCIIToUTF16(errors::kInvalidPageActionDefaultTitle);
120 return scoped_ptr<ActionInfo>();
122 } else if (extension->manifest_version() == 1 && dict->HasKey(keys::kName)) {
123 if (!dict->GetString(keys::kName, &result->default_title)) {
124 *error = ASCIIToUTF16(errors::kInvalidPageActionName);
125 return scoped_ptr<ActionInfo>();
129 // Read the action's |popup| (optional).
130 const char* popup_key = NULL;
131 if (dict->HasKey(keys::kPageActionDefaultPopup))
132 popup_key = keys::kPageActionDefaultPopup;
134 if (extension->manifest_version() == 1 &&
135 dict->HasKey(keys::kPageActionPopup)) {
137 *error = ErrorUtils::FormatErrorMessageUTF16(
138 errors::kInvalidPageActionOldAndNewKeys,
139 keys::kPageActionDefaultPopup,
140 keys::kPageActionPopup);
141 return scoped_ptr<ActionInfo>();
143 popup_key = keys::kPageActionPopup;
147 const DictionaryValue* popup = NULL;
150 if (dict->GetString(popup_key, &url_str)) {
151 // On success, |url_str| is set. Nothing else to do.
152 } else if (extension->manifest_version() == 1 &&
153 dict->GetDictionary(popup_key, &popup)) {
154 if (!popup->GetString(keys::kPageActionPopupPath, &url_str)) {
155 *error = ErrorUtils::FormatErrorMessageUTF16(
156 errors::kInvalidPageActionPopupPath, "<missing>");
157 return scoped_ptr<ActionInfo>();
160 *error = ASCIIToUTF16(errors::kInvalidPageActionPopup);
161 return scoped_ptr<ActionInfo>();
164 if (!url_str.empty()) {
165 // An empty string is treated as having no popup.
166 result->default_popup_url = Extension::GetResourceURL(extension->url(),
168 if (!result->default_popup_url.is_valid()) {
169 *error = ErrorUtils::FormatErrorMessageUTF16(
170 errors::kInvalidPageActionPopupPath, url_str);
171 return scoped_ptr<ActionInfo>();
174 DCHECK(result->default_popup_url.is_empty())
175 << "Shouldn't be possible for the popup to be set.";
179 return result.Pass();
183 const ActionInfo* ActionInfo::GetBrowserActionInfo(const Extension* extension) {
184 return GetActionInfo(extension, keys::kBrowserAction);
187 const ActionInfo* ActionInfo::GetPageActionInfo(const Extension* extension) {
188 return GetActionInfo(extension, keys::kPageAction);
192 const ActionInfo* ActionInfo::GetScriptBadgeInfo(const Extension* extension) {
193 return GetActionInfo(extension, keys::kScriptBadge);
197 const ActionInfo* ActionInfo::GetSystemIndicatorInfo(
198 const Extension* extension) {
199 return GetActionInfo(extension, keys::kSystemIndicator);
203 void ActionInfo::SetBrowserActionInfo(Extension* extension, ActionInfo* info) {
204 extension->SetManifestData(keys::kBrowserAction,
205 new ActionInfoData(info));
209 void ActionInfo::SetPageActionInfo(Extension* extension, ActionInfo* info) {
210 extension->SetManifestData(keys::kPageAction,
211 new ActionInfoData(info));
215 void ActionInfo::SetScriptBadgeInfo(Extension* extension, ActionInfo* info) {
216 extension->SetManifestData(keys::kScriptBadge,
217 new ActionInfoData(info));
221 void ActionInfo::SetSystemIndicatorInfo(Extension* extension,
223 extension->SetManifestData(keys::kSystemIndicator, new ActionInfoData(info));
227 bool ActionInfo::IsVerboseInstallMessage(const Extension* extension) {
228 const ActionInfo* page_action_info = GetPageActionInfo(extension);
229 return page_action_info &&
230 (CommandsInfo::GetPageActionCommand(extension) ||
231 !page_action_info->default_icon.empty());
234 } // namespace extensions