| 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 |