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