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 if (!manifest_handler_helpers::LoadIconsFromDictionary(
96 extension_misc::kExtensionActionIconSizes
,
97 extension_misc::kNumExtensionActionIconSizes
,
98 &result
->default_icon
,
100 return scoped_ptr
<ActionInfo
>();
102 } else if (dict
->GetString(keys::kPageActionDefaultIcon
, &default_icon
) &&
103 manifest_handler_helpers::NormalizeAndValidatePath(
105 result
->default_icon
.Add(extension_misc::EXTENSION_ICON_ACTION
,
108 *error
= base::ASCIIToUTF16(errors::kInvalidPageActionIconPath
);
109 return scoped_ptr
<ActionInfo
>();
113 // Read the page action title from |default_title| if present, |name| if not
115 if (dict
->HasKey(keys::kPageActionDefaultTitle
)) {
116 if (!dict
->GetString(keys::kPageActionDefaultTitle
,
117 &result
->default_title
)) {
118 *error
= base::ASCIIToUTF16(errors::kInvalidPageActionDefaultTitle
);
119 return scoped_ptr
<ActionInfo
>();
121 } else if (extension
->manifest_version() == 1 && dict
->HasKey(keys::kName
)) {
122 if (!dict
->GetString(keys::kName
, &result
->default_title
)) {
123 *error
= base::ASCIIToUTF16(errors::kInvalidPageActionName
);
124 return scoped_ptr
<ActionInfo
>();
128 // Read the action's |popup| (optional).
129 const char* popup_key
= NULL
;
130 if (dict
->HasKey(keys::kPageActionDefaultPopup
))
131 popup_key
= keys::kPageActionDefaultPopup
;
133 if (extension
->manifest_version() == 1 &&
134 dict
->HasKey(keys::kPageActionPopup
)) {
136 *error
= ErrorUtils::FormatErrorMessageUTF16(
137 errors::kInvalidPageActionOldAndNewKeys
,
138 keys::kPageActionDefaultPopup
,
139 keys::kPageActionPopup
);
140 return scoped_ptr
<ActionInfo
>();
142 popup_key
= keys::kPageActionPopup
;
146 const base::DictionaryValue
* popup
= NULL
;
149 if (dict
->GetString(popup_key
, &url_str
)) {
150 // On success, |url_str| is set. Nothing else to do.
151 } else if (extension
->manifest_version() == 1 &&
152 dict
->GetDictionary(popup_key
, &popup
)) {
153 if (!popup
->GetString(keys::kPageActionPopupPath
, &url_str
)) {
154 *error
= ErrorUtils::FormatErrorMessageUTF16(
155 errors::kInvalidPageActionPopupPath
, "<missing>");
156 return scoped_ptr
<ActionInfo
>();
159 *error
= base::ASCIIToUTF16(errors::kInvalidPageActionPopup
);
160 return scoped_ptr
<ActionInfo
>();
163 if (!url_str
.empty()) {
164 // An empty string is treated as having no popup.
165 result
->default_popup_url
= Extension::GetResourceURL(extension
->url(),
167 if (!result
->default_popup_url
.is_valid()) {
168 *error
= ErrorUtils::FormatErrorMessageUTF16(
169 errors::kInvalidPageActionPopupPath
, url_str
);
170 return scoped_ptr
<ActionInfo
>();
173 DCHECK(result
->default_popup_url
.is_empty())
174 << "Shouldn't be possible for the popup to be set.";
178 return result
.Pass();
182 const ActionInfo
* ActionInfo::GetBrowserActionInfo(const Extension
* extension
) {
183 return GetActionInfo(extension
, keys::kBrowserAction
);
186 const ActionInfo
* ActionInfo::GetPageActionInfo(const Extension
* extension
) {
187 return GetActionInfo(extension
, keys::kPageAction
);
191 const ActionInfo
* ActionInfo::GetSystemIndicatorInfo(
192 const Extension
* extension
) {
193 return GetActionInfo(extension
, keys::kSystemIndicator
);
197 void ActionInfo::SetBrowserActionInfo(Extension
* extension
, ActionInfo
* info
) {
198 extension
->SetManifestData(keys::kBrowserAction
,
199 new ActionInfoData(info
));
203 void ActionInfo::SetPageActionInfo(Extension
* extension
, ActionInfo
* info
) {
204 extension
->SetManifestData(keys::kPageAction
,
205 new ActionInfoData(info
));
209 void ActionInfo::SetSystemIndicatorInfo(Extension
* extension
,
211 extension
->SetManifestData(keys::kSystemIndicator
, new ActionInfoData(info
));
215 bool ActionInfo::IsVerboseInstallMessage(const Extension
* extension
) {
216 const ActionInfo
* page_action_info
= GetPageActionInfo(extension
);
217 return page_action_info
&&
218 (CommandsInfo::GetPageActionCommand(extension
) ||
219 !page_action_info
->default_icon
.empty());
222 } // namespace extensions