OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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. | |
4 | |
5 #include "chrome/browser/extensions/extension_sidebar_api.h" | |
6 | |
7 #include "base/json/json_writer.h" | |
8 #include "base/string16.h" | |
9 #include "base/string_number_conversions.h" | |
10 #include "base/string_util.h" | |
11 #include "base/values.h" | |
12 #include "chrome/browser/extensions/extension_event_router.h" | |
13 #include "chrome/browser/extensions/extension_service.h" | |
14 #include "chrome/browser/extensions/extension_tab_util.h" | |
15 #include "chrome/browser/profiles/profile.h" | |
16 #include "chrome/browser/sidebar/sidebar_container.h" | |
17 #include "chrome/browser/sidebar/sidebar_manager.h" | |
18 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" | |
19 #include "chrome/common/extensions/extension.h" | |
20 #include "chrome/common/extensions/extension_constants.h" | |
21 #include "chrome/common/extensions/extension_error_utils.h" | |
22 #include "chrome/common/extensions/extension_sidebar_utils.h" | |
23 #include "chrome/common/render_messages.h" | |
24 #include "content/browser/tab_contents/tab_contents.h" | |
25 #include "ipc/ipc_message_utils.h" | |
26 #include "third_party/skia/include/core/SkBitmap.h" | |
27 | |
28 using content::WebContents; | |
29 | |
30 namespace { | |
31 // Errors. | |
32 const char kNoSidebarError[] = | |
33 "This extension has no sidebar specified."; | |
34 const char kNoTabError[] = "No tab with id: *."; | |
35 const char kNoCurrentWindowError[] = "No current browser window was found"; | |
36 const char kNoDefaultTabError[] = "No default tab was found"; | |
37 const char kInvalidExpandContextError[] = | |
38 "Sidebar can be expanded only in response to an explicit user gesture"; | |
39 // Keys. | |
40 const char kBadgeTextKey[] = "text"; | |
41 const char kImageDataKey[] = "imageData"; | |
42 const char kPathKey[] = "path"; | |
43 const char kStateKey[] = "state"; | |
44 const char kTabIdKey[] = "tabId"; | |
45 const char kTitleKey[] = "title"; | |
46 // Events. | |
47 const char kOnStateChanged[] = "experimental.sidebar.onStateChanged"; | |
48 } // namespace | |
49 | |
50 namespace extension_sidebar_constants { | |
51 // Sidebar states. | |
52 const char kActiveState[] = "active"; | |
53 const char kHiddenState[] = "hidden"; | |
54 const char kShownState[] = "shown"; | |
55 } // namespace extension_sidebar_constants | |
56 | |
57 // static | |
58 void ExtensionSidebarEventRouter::OnStateChanged( | |
59 Profile* profile, WebContents* tab, const std::string& content_id, | |
60 const std::string& state) { | |
61 int tab_id = ExtensionTabUtil::GetTabId(tab); | |
62 DictionaryValue* details = new DictionaryValue; | |
63 details->Set(kTabIdKey, Value::CreateIntegerValue(tab_id)); | |
64 details->Set(kStateKey, Value::CreateStringValue(state)); | |
65 | |
66 ListValue args; | |
67 args.Set(0, details); | |
68 std::string json_args; | |
69 base::JSONWriter::Write(&args, false, &json_args); | |
70 | |
71 profile->GetExtensionEventRouter()->DispatchEventToExtension( | |
72 extension_sidebar_utils::GetExtensionIdByContentId(content_id), | |
73 kOnStateChanged, json_args, profile, GURL()); | |
74 } | |
75 | |
76 | |
77 // List is considered empty if it is actually empty or contains just one value, | |
78 // either 'null' or 'undefined'. | |
79 static bool IsArgumentListEmpty(const ListValue* arguments) { | |
80 if (arguments->empty()) | |
81 return true; | |
82 if (arguments->GetSize() == 1) { | |
83 Value* first_value = 0; | |
84 if (!arguments->Get(0, &first_value)) | |
85 return true; | |
86 if (first_value->GetType() == Value::TYPE_NULL) | |
87 return true; | |
88 } | |
89 return false; | |
90 } | |
91 | |
92 bool SidebarFunction::RunImpl() { | |
93 if (!GetExtension()->sidebar_defaults()) { | |
94 error_ = kNoSidebarError; | |
95 return false; | |
96 } | |
97 | |
98 if (!args_.get()) | |
99 return false; | |
100 | |
101 DictionaryValue* details = NULL; | |
102 DictionaryValue default_details; | |
103 if (IsArgumentListEmpty(args_.get())) { | |
104 details = &default_details; | |
105 } else { | |
106 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &details)); | |
107 } | |
108 | |
109 int tab_id; | |
110 TabContentsWrapper* tab_contents = NULL; | |
111 if (details->HasKey(kTabIdKey)) { | |
112 EXTENSION_FUNCTION_VALIDATE(details->GetInteger(kTabIdKey, &tab_id)); | |
113 if (!ExtensionTabUtil::GetTabById(tab_id, profile(), include_incognito(), | |
114 NULL, NULL, &tab_contents, NULL)) { | |
115 error_ = ExtensionErrorUtils::FormatErrorMessage( | |
116 kNoTabError, base::IntToString(tab_id)); | |
117 return false; | |
118 } | |
119 } else { | |
120 Browser* browser = GetCurrentBrowser(); | |
121 if (!browser) { | |
122 error_ = kNoCurrentWindowError; | |
123 return false; | |
124 } | |
125 if (!ExtensionTabUtil::GetDefaultTab(browser, &tab_contents, &tab_id)) { | |
126 error_ = kNoDefaultTabError; | |
127 return false; | |
128 } | |
129 } | |
130 if (!tab_contents) | |
131 return false; | |
132 | |
133 std::string content_id(GetExtension()->id()); | |
134 return RunImpl(static_cast<TabContents*>(tab_contents->web_contents()), | |
135 content_id, *details); | |
136 } | |
137 | |
138 | |
139 bool CollapseSidebarFunction::RunImpl(TabContents* tab, | |
140 const std::string& content_id, | |
141 const DictionaryValue& details) { | |
142 SidebarManager::GetInstance()->CollapseSidebar(tab, content_id); | |
143 return true; | |
144 } | |
145 | |
146 bool ExpandSidebarFunction::RunImpl(TabContents* tab, | |
147 const std::string& content_id, | |
148 const DictionaryValue& details) { | |
149 // TODO(alekseys): enable this check back when WebKit's user gesture flag | |
150 // reporting for extension calls is fixed. | |
151 // if (!user_gesture()) { | |
152 // error_ = kInvalidExpandContextError; | |
153 // return false; | |
154 // } | |
155 SidebarManager::GetInstance()->ExpandSidebar(tab, content_id); | |
156 return true; | |
157 } | |
158 | |
159 bool GetStateSidebarFunction::RunImpl(TabContents* tab, | |
160 const std::string& content_id, | |
161 const DictionaryValue& details) { | |
162 SidebarManager* manager = SidebarManager::GetInstance(); | |
163 | |
164 const char* result = extension_sidebar_constants::kHiddenState; | |
165 if (manager->GetSidebarTabContents(tab, content_id)) { | |
166 bool is_active = false; | |
167 // Sidebar is considered active only if tab is selected, sidebar UI | |
168 // is expanded and this extension's content is displayed on it. | |
169 SidebarContainer* active_sidebar = | |
170 manager->GetActiveSidebarContainerFor(tab); | |
171 // Check if sidebar UI is expanded and this extension's content | |
172 // is displayed on it. | |
173 if (active_sidebar && active_sidebar->content_id() == content_id) { | |
174 if (!details.HasKey(kTabIdKey)) { | |
175 is_active = NULL != GetCurrentBrowser(); | |
176 } else { | |
177 int tab_id; | |
178 EXTENSION_FUNCTION_VALIDATE(details.GetInteger(kTabIdKey, &tab_id)); | |
179 | |
180 // Check if this tab is selected. | |
181 Browser* browser = GetCurrentBrowser(); | |
182 TabContentsWrapper* contents = NULL; | |
183 int default_tab_id = -1; | |
184 if (browser && | |
185 ExtensionTabUtil::GetDefaultTab(browser, &contents, | |
186 &default_tab_id)) { | |
187 is_active = default_tab_id == tab_id; | |
188 } | |
189 } | |
190 } | |
191 | |
192 result = is_active ? extension_sidebar_constants::kActiveState : | |
193 extension_sidebar_constants::kShownState; | |
194 } | |
195 | |
196 result_.reset(Value::CreateStringValue(result)); | |
197 return true; | |
198 } | |
199 | |
200 bool HideSidebarFunction::RunImpl(TabContents* tab, | |
201 const std::string& content_id, | |
202 const DictionaryValue& details) { | |
203 SidebarManager::GetInstance()->HideSidebar(tab, content_id); | |
204 return true; | |
205 } | |
206 | |
207 bool NavigateSidebarFunction::RunImpl(TabContents* tab, | |
208 const std::string& content_id, | |
209 const DictionaryValue& details) { | |
210 std::string path_string; | |
211 EXTENSION_FUNCTION_VALIDATE(details.GetString(kPathKey, &path_string)); | |
212 | |
213 GURL url = extension_sidebar_utils::ResolveRelativePath( | |
214 path_string, GetExtension(), &error_); | |
215 if (!url.is_valid()) | |
216 return false; | |
217 | |
218 SidebarManager::GetInstance()->NavigateSidebar(tab, content_id, url); | |
219 return true; | |
220 } | |
221 | |
222 bool SetBadgeTextSidebarFunction::RunImpl(TabContents* tab, | |
223 const std::string& content_id, | |
224 const DictionaryValue& details) { | |
225 string16 badge_text; | |
226 EXTENSION_FUNCTION_VALIDATE(details.GetString(kBadgeTextKey, &badge_text)); | |
227 SidebarManager::GetInstance()->SetSidebarBadgeText( | |
228 tab, content_id, badge_text); | |
229 return true; | |
230 } | |
231 | |
232 bool SetIconSidebarFunction::RunImpl(TabContents* tab, | |
233 const std::string& content_id, | |
234 const DictionaryValue& details) { | |
235 base::BinaryValue* binary; | |
236 EXTENSION_FUNCTION_VALIDATE(details.GetBinary(kImageDataKey, &binary)); | |
237 IPC::Message bitmap_pickle(binary->GetBuffer(), binary->GetSize()); | |
238 void* iter = NULL; | |
239 scoped_ptr<SkBitmap> bitmap(new SkBitmap); | |
240 EXTENSION_FUNCTION_VALIDATE( | |
241 IPC::ReadParam(&bitmap_pickle, &iter, bitmap.get())); | |
242 SidebarManager::GetInstance()->SetSidebarIcon(tab, content_id, *bitmap); | |
243 return true; | |
244 } | |
245 | |
246 bool SetTitleSidebarFunction::RunImpl(TabContents* tab, | |
247 const std::string& content_id, | |
248 const DictionaryValue& details) { | |
249 string16 title; | |
250 EXTENSION_FUNCTION_VALIDATE(details.GetString(kTitleKey, &title)); | |
251 SidebarManager::GetInstance()->SetSidebarTitle(tab, content_id, title); | |
252 return true; | |
253 } | |
254 | |
255 bool ShowSidebarFunction::RunImpl(TabContents* tab, | |
256 const std::string& content_id, | |
257 const DictionaryValue& details) { | |
258 SidebarManager::GetInstance()->ShowSidebar(tab, content_id); | |
259 return true; | |
260 } | |
OLD | NEW |