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_constants.h"
11 #include "chrome/common/extensions/manifest_handler_helpers.h"
12 #include "extensions/common/error_utils.h"
13 #include "extensions/common/extension.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
,
58 base::string16
* error
) {
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
= base::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
= base::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 base::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
= base::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
= base::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
= base::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 base::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
= base::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