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 "extensions/common/constants.h"
11 #include "extensions/common/error_utils.h"
12 #include "extensions/common/extension.h"
13 #include "extensions/common/manifest_constants.h"
14 #include "extensions/common/manifest_handler_helpers.h"
16 namespace extensions
{
18 namespace errors
= manifest_errors
;
19 namespace keys
= manifest_keys
;
23 // The manifest data container for the ActionInfos for BrowserActions,
24 // PageActions and SystemIndicators.
25 struct ActionInfoData
: public Extension::ManifestData
{
26 explicit ActionInfoData(ActionInfo
* action_info
);
27 virtual ~ActionInfoData();
29 // The action associated with the BrowserAction.
30 scoped_ptr
<ActionInfo
> action_info
;
33 ActionInfoData::ActionInfoData(ActionInfo
* info
) : action_info(info
) {
36 ActionInfoData::~ActionInfoData() {
39 static const ActionInfo
* GetActionInfo(const Extension
* extension
,
40 const std::string
& key
) {
41 ActionInfoData
* data
= static_cast<ActionInfoData
*>(
42 extension
->GetManifestData(key
));
43 return data
? data
->action_info
.get() : NULL
;
48 ActionInfo::ActionInfo() {
51 ActionInfo::~ActionInfo() {
55 scoped_ptr
<ActionInfo
> ActionInfo::Load(const Extension
* extension
,
56 const base::DictionaryValue
* dict
,
57 base::string16
* error
) {
58 scoped_ptr
<ActionInfo
> result(new ActionInfo());
60 if (extension
->manifest_version() == 1) {
61 // kPageActionIcons is obsolete, and used by very few extensions. Continue
62 // loading it, but only take the first icon as the default_icon path.
63 const base::ListValue
* icons
= NULL
;
64 if (dict
->HasKey(keys::kPageActionIcons
) &&
65 dict
->GetList(keys::kPageActionIcons
, &icons
)) {
66 base::ListValue::const_iterator iter
= icons
->begin();
68 if (iter
== icons
->end() ||
69 !(*iter
)->GetAsString(&path
) ||
70 !manifest_handler_helpers::NormalizeAndValidatePath(&path
)) {
71 *error
= base::ASCIIToUTF16(errors::kInvalidPageActionIconPath
);
72 return scoped_ptr
<ActionInfo
>();
74 result
->default_icon
.Add(extension_misc::EXTENSION_ICON_ACTION
, path
);
78 if (dict
->HasKey(keys::kPageActionId
)) {
79 if (!dict
->GetString(keys::kPageActionId
, &id
)) {
80 *error
= base::ASCIIToUTF16(errors::kInvalidPageActionId
);
81 return scoped_ptr
<ActionInfo
>();
87 // Read the page action |default_icon| (optional).
88 // The |default_icon| value can be either dictionary {icon size -> icon path}
89 // or non empty string value.
90 if (dict
->HasKey(keys::kPageActionDefaultIcon
)) {
91 const base::DictionaryValue
* icons_value
= NULL
;
92 std::string default_icon
;
93 if (dict
->GetDictionary(keys::kPageActionDefaultIcon
, &icons_value
)) {
94 int icon_sizes
[extension_misc::kNumExtensionActionIconSizes
];
95 for (size_t i
= 0u; i
< extension_misc::kNumExtensionActionIconSizes
; ++i
)
96 icon_sizes
[i
] = extension_misc::kExtensionActionIconSizes
[i
].size
;
97 if (!manifest_handler_helpers::LoadIconsFromDictionary(
100 extension_misc::kNumExtensionActionIconSizes
,
101 &result
->default_icon
,
103 return scoped_ptr
<ActionInfo
>();
105 } else if (dict
->GetString(keys::kPageActionDefaultIcon
, &default_icon
) &&
106 manifest_handler_helpers::NormalizeAndValidatePath(
108 result
->default_icon
.Add(extension_misc::EXTENSION_ICON_ACTION
,
111 *error
= base::ASCIIToUTF16(errors::kInvalidPageActionIconPath
);
112 return scoped_ptr
<ActionInfo
>();
116 // Read the page action title from |default_title| if present, |name| if not
118 if (dict
->HasKey(keys::kPageActionDefaultTitle
)) {
119 if (!dict
->GetString(keys::kPageActionDefaultTitle
,
120 &result
->default_title
)) {
121 *error
= base::ASCIIToUTF16(errors::kInvalidPageActionDefaultTitle
);
122 return scoped_ptr
<ActionInfo
>();
124 } else if (extension
->manifest_version() == 1 && dict
->HasKey(keys::kName
)) {
125 if (!dict
->GetString(keys::kName
, &result
->default_title
)) {
126 *error
= base::ASCIIToUTF16(errors::kInvalidPageActionName
);
127 return scoped_ptr
<ActionInfo
>();
131 // Read the action's |popup| (optional).
132 const char* popup_key
= NULL
;
133 if (dict
->HasKey(keys::kPageActionDefaultPopup
))
134 popup_key
= keys::kPageActionDefaultPopup
;
136 if (extension
->manifest_version() == 1 &&
137 dict
->HasKey(keys::kPageActionPopup
)) {
139 *error
= ErrorUtils::FormatErrorMessageUTF16(
140 errors::kInvalidPageActionOldAndNewKeys
,
141 keys::kPageActionDefaultPopup
,
142 keys::kPageActionPopup
);
143 return scoped_ptr
<ActionInfo
>();
145 popup_key
= keys::kPageActionPopup
;
149 const base::DictionaryValue
* popup
= NULL
;
152 if (dict
->GetString(popup_key
, &url_str
)) {
153 // On success, |url_str| is set. Nothing else to do.
154 } else if (extension
->manifest_version() == 1 &&
155 dict
->GetDictionary(popup_key
, &popup
)) {
156 if (!popup
->GetString(keys::kPageActionPopupPath
, &url_str
)) {
157 *error
= ErrorUtils::FormatErrorMessageUTF16(
158 errors::kInvalidPageActionPopupPath
, "<missing>");
159 return scoped_ptr
<ActionInfo
>();
162 *error
= base::ASCIIToUTF16(errors::kInvalidPageActionPopup
);
163 return scoped_ptr
<ActionInfo
>();
166 if (!url_str
.empty()) {
167 // An empty string is treated as having no popup.
168 result
->default_popup_url
= Extension::GetResourceURL(extension
->url(),
170 if (!result
->default_popup_url
.is_valid()) {
171 *error
= ErrorUtils::FormatErrorMessageUTF16(
172 errors::kInvalidPageActionPopupPath
, url_str
);
173 return scoped_ptr
<ActionInfo
>();
176 DCHECK(result
->default_popup_url
.is_empty())
177 << "Shouldn't be possible for the popup to be set.";
181 return result
.Pass();
185 const ActionInfo
* ActionInfo::GetBrowserActionInfo(const Extension
* extension
) {
186 return GetActionInfo(extension
, keys::kBrowserAction
);
189 const ActionInfo
* ActionInfo::GetPageActionInfo(const Extension
* extension
) {
190 return GetActionInfo(extension
, keys::kPageAction
);
194 const ActionInfo
* ActionInfo::GetSystemIndicatorInfo(
195 const Extension
* extension
) {
196 return GetActionInfo(extension
, keys::kSystemIndicator
);
200 void ActionInfo::SetBrowserActionInfo(Extension
* extension
, ActionInfo
* info
) {
201 extension
->SetManifestData(keys::kBrowserAction
,
202 new ActionInfoData(info
));
206 void ActionInfo::SetPageActionInfo(Extension
* extension
, ActionInfo
* info
) {
207 extension
->SetManifestData(keys::kPageAction
,
208 new ActionInfoData(info
));
212 void ActionInfo::SetSystemIndicatorInfo(Extension
* extension
,
214 extension
->SetManifestData(keys::kSystemIndicator
, new ActionInfoData(info
));
218 bool ActionInfo::IsVerboseInstallMessage(const Extension
* extension
) {
219 const ActionInfo
* page_action_info
= GetPageActionInfo(extension
);
220 return page_action_info
&&
221 (CommandsInfo::GetPageActionCommand(extension
) ||
222 !page_action_info
->default_icon
.empty());
225 } // namespace extensions