| 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/ui/webui/options2/extension_settings_handler.h" | |
| 6 | |
| 7 #include "base/auto_reset.h" | |
| 8 #include "base/base64.h" | |
| 9 #include "base/bind.h" | |
| 10 #include "base/bind_helpers.h" | |
| 11 #include "base/command_line.h" | |
| 12 #include "base/file_util.h" | |
| 13 #include "base/string_number_conversions.h" | |
| 14 #include "base/utf_string_conversions.h" | |
| 15 #include "base/values.h" | |
| 16 #include "base/version.h" | |
| 17 #include "chrome/browser/debugger/devtools_window.h" | |
| 18 #include "chrome/browser/extensions/crx_installer.h" | |
| 19 #include "chrome/browser/extensions/extension_disabled_infobar_delegate.h" | |
| 20 #include "chrome/browser/extensions/extension_service.h" | |
| 21 #include "chrome/browser/extensions/extension_updater.h" | |
| 22 #include "chrome/browser/extensions/extension_warning_set.h" | |
| 23 #include "chrome/browser/extensions/unpacked_installer.h" | |
| 24 #include "chrome/browser/google/google_util.h" | |
| 25 #include "chrome/browser/profiles/profile.h" | |
| 26 #include "chrome/browser/tab_contents/background_contents.h" | |
| 27 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h" | |
| 28 #include "chrome/common/chrome_switches.h" | |
| 29 #include "chrome/common/chrome_view_type.h" | |
| 30 #include "chrome/common/extensions/extension.h" | |
| 31 #include "chrome/common/pref_names.h" | |
| 32 #include "chrome/common/url_constants.h" | |
| 33 #include "content/browser/browsing_instance.h" | |
| 34 #include "content/browser/renderer_host/render_view_host.h" | |
| 35 #include "content/browser/tab_contents/tab_contents.h" | |
| 36 #include "content/browser/tab_contents/tab_contents_view.h" | |
| 37 #include "content/public/browser/notification_service.h" | |
| 38 #include "content/public/browser/notification_types.h" | |
| 39 #include "grit/browser_resources.h" | |
| 40 #include "grit/chromium_strings.h" | |
| 41 #include "grit/generated_resources.h" | |
| 42 #include "grit/theme_resources.h" | |
| 43 #include "ui/base/l10n/l10n_util.h" | |
| 44 #include "ui/base/resource/resource_bundle.h" | |
| 45 | |
| 46 namespace { | |
| 47 | |
| 48 bool ShouldShowExtension(const Extension* extension) { | |
| 49 // Don't show themes since this page's UI isn't really useful for themes. | |
| 50 if (extension->is_theme()) | |
| 51 return false; | |
| 52 | |
| 53 // Don't show component extensions because they are only extensions as an | |
| 54 // implementation detail of Chrome. | |
| 55 if (extension->location() == Extension::COMPONENT && | |
| 56 !CommandLine::ForCurrentProcess()->HasSwitch( | |
| 57 switches::kShowComponentExtensionOptions)) | |
| 58 return false; | |
| 59 | |
| 60 // Always show unpacked extensions and apps. | |
| 61 if (extension->location() == Extension::LOAD) | |
| 62 return true; | |
| 63 | |
| 64 // Unless they are unpacked, never show hosted apps. | |
| 65 if (extension->is_hosted_app()) | |
| 66 return false; | |
| 67 | |
| 68 return true; | |
| 69 } | |
| 70 | |
| 71 } // namespace | |
| 72 | |
| 73 /////////////////////////////////////////////////////////////////////////////// | |
| 74 // | |
| 75 // ExtensionSettingsHandler | |
| 76 // | |
| 77 /////////////////////////////////////////////////////////////////////////////// | |
| 78 | |
| 79 ExtensionSettingsHandler::ExtensionSettingsHandler() | |
| 80 : extension_service_(NULL), | |
| 81 ignore_notifications_(false), | |
| 82 deleting_rvh_(NULL), | |
| 83 registered_for_notifications_(false) { | |
| 84 } | |
| 85 | |
| 86 ExtensionSettingsHandler::~ExtensionSettingsHandler() { | |
| 87 // There may be pending file dialogs, we need to tell them that we've gone | |
| 88 // away so they don't try and call back to us. | |
| 89 if (load_extension_dialog_.get()) | |
| 90 load_extension_dialog_->ListenerDestroyed(); | |
| 91 | |
| 92 registrar_.RemoveAll(); | |
| 93 } | |
| 94 | |
| 95 // static | |
| 96 void ExtensionSettingsHandler::RegisterUserPrefs(PrefService* prefs) { | |
| 97 prefs->RegisterBooleanPref(prefs::kExtensionsUIDeveloperMode, | |
| 98 false, | |
| 99 PrefService::SYNCABLE_PREF); | |
| 100 } | |
| 101 | |
| 102 void ExtensionSettingsHandler::RegisterMessages() { | |
| 103 web_ui_->RegisterMessageCallback("extensionSettingsRequestExtensionsData", | |
| 104 base::Bind(&ExtensionSettingsHandler::HandleRequestExtensionsData, | |
| 105 base::Unretained(this))); | |
| 106 web_ui_->RegisterMessageCallback("extensionSettingsToggleDeveloperMode", | |
| 107 base::Bind(&ExtensionSettingsHandler::HandleToggleDeveloperMode, | |
| 108 base::Unretained(this))); | |
| 109 web_ui_->RegisterMessageCallback("extensionSettingsInspect", | |
| 110 base::Bind(&ExtensionSettingsHandler::HandleInspectMessage, | |
| 111 base::Unretained(this))); | |
| 112 web_ui_->RegisterMessageCallback("extensionSettingsReload", | |
| 113 base::Bind(&ExtensionSettingsHandler::HandleReloadMessage, | |
| 114 base::Unretained(this))); | |
| 115 web_ui_->RegisterMessageCallback("extensionSettingsEnable", | |
| 116 base::Bind(&ExtensionSettingsHandler::HandleEnableMessage, | |
| 117 base::Unretained(this))); | |
| 118 web_ui_->RegisterMessageCallback("extensionSettingsEnableIncognito", | |
| 119 base::Bind(&ExtensionSettingsHandler::HandleEnableIncognitoMessage, | |
| 120 base::Unretained(this))); | |
| 121 web_ui_->RegisterMessageCallback("extensionSettingsAllowFileAccess", | |
| 122 base::Bind(&ExtensionSettingsHandler::HandleAllowFileAccessMessage, | |
| 123 base::Unretained(this))); | |
| 124 web_ui_->RegisterMessageCallback("extensionSettingsUninstall", | |
| 125 base::Bind(&ExtensionSettingsHandler::HandleUninstallMessage, | |
| 126 base::Unretained(this))); | |
| 127 web_ui_->RegisterMessageCallback("extensionSettingsOptions", | |
| 128 base::Bind(&ExtensionSettingsHandler::HandleOptionsMessage, | |
| 129 base::Unretained(this))); | |
| 130 web_ui_->RegisterMessageCallback("extensionSettingsShowButton", | |
| 131 base::Bind(&ExtensionSettingsHandler::HandleShowButtonMessage, | |
| 132 base::Unretained(this))); | |
| 133 web_ui_->RegisterMessageCallback("extensionSettingsLoad", | |
| 134 base::Bind(&ExtensionSettingsHandler::HandleLoadMessage, | |
| 135 base::Unretained(this))); | |
| 136 web_ui_->RegisterMessageCallback("extensionSettingsAutoupdate", | |
| 137 base::Bind(&ExtensionSettingsHandler::HandleAutoUpdateMessage, | |
| 138 base::Unretained(this))); | |
| 139 web_ui_->RegisterMessageCallback("extensionSettingsSelectFilePath", | |
| 140 base::Bind(&ExtensionSettingsHandler::HandleSelectFilePathMessage, | |
| 141 base::Unretained(this))); | |
| 142 } | |
| 143 | |
| 144 void ExtensionSettingsHandler::HandleRequestExtensionsData( | |
| 145 const ListValue* args) { | |
| 146 DictionaryValue results; | |
| 147 | |
| 148 // Add the extensions to the results structure. | |
| 149 ListValue *extensions_list = new ListValue(); | |
| 150 | |
| 151 ExtensionWarningSet* warnings = extension_service_->extension_warnings(); | |
| 152 | |
| 153 const ExtensionSet* extensions = extension_service_->extensions(); | |
| 154 for (ExtensionSet::const_iterator extension = extensions->begin(); | |
| 155 extension != extensions->end(); ++extension) { | |
| 156 if (ShouldShowExtension(*extension)) { | |
| 157 extensions_list->Append(CreateExtensionDetailValue( | |
| 158 extension_service_, | |
| 159 *extension, | |
| 160 GetActivePagesForExtension(*extension), | |
| 161 warnings, | |
| 162 true, false)); // enabled, terminated | |
| 163 } | |
| 164 } | |
| 165 extensions = extension_service_->disabled_extensions(); | |
| 166 for (ExtensionSet::const_iterator extension = extensions->begin(); | |
| 167 extension != extensions->end(); ++extension) { | |
| 168 if (ShouldShowExtension(*extension)) { | |
| 169 extensions_list->Append(CreateExtensionDetailValue( | |
| 170 extension_service_, | |
| 171 *extension, | |
| 172 GetActivePagesForExtension(*extension), | |
| 173 warnings, | |
| 174 false, false)); // enabled, terminated | |
| 175 } | |
| 176 } | |
| 177 extensions = extension_service_->terminated_extensions(); | |
| 178 std::vector<ExtensionPage> empty_pages; | |
| 179 for (ExtensionSet::const_iterator extension = extensions->begin(); | |
| 180 extension != extensions->end(); ++extension) { | |
| 181 if (ShouldShowExtension(*extension)) { | |
| 182 extensions_list->Append(CreateExtensionDetailValue( | |
| 183 extension_service_, | |
| 184 *extension, | |
| 185 empty_pages, // Terminated process has no active pages. | |
| 186 warnings, | |
| 187 false, true)); // enabled, terminated | |
| 188 } | |
| 189 } | |
| 190 results.Set("extensions", extensions_list); | |
| 191 | |
| 192 Profile* profile = Profile::FromWebUI(web_ui_); | |
| 193 bool developer_mode = | |
| 194 profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode); | |
| 195 results.SetBoolean("developerMode", developer_mode); | |
| 196 | |
| 197 web_ui_->CallJavascriptFunction("ExtensionSettings.returnExtensionsData", | |
| 198 results); | |
| 199 | |
| 200 MaybeRegisterForNotifications(); | |
| 201 } | |
| 202 | |
| 203 void ExtensionSettingsHandler::MaybeRegisterForNotifications() { | |
| 204 if (registered_for_notifications_) | |
| 205 return; | |
| 206 | |
| 207 registered_for_notifications_ = true; | |
| 208 Profile* profile = Profile::FromWebUI(web_ui_); | |
| 209 | |
| 210 // Register for notifications that we need to reload the page. | |
| 211 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, | |
| 212 content::Source<Profile>(profile)); | |
| 213 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, | |
| 214 content::Source<Profile>(profile)); | |
| 215 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED, | |
| 216 content::Source<Profile>(profile)); | |
| 217 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_WARNING_CHANGED, | |
| 218 content::Source<Profile>(profile)); | |
| 219 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_CREATED, | |
| 220 content::NotificationService::AllBrowserContextsAndSources()); | |
| 221 registrar_.Add(this, | |
| 222 content::NOTIFICATION_RENDER_VIEW_HOST_CREATED, | |
| 223 content::NotificationService::AllBrowserContextsAndSources()); | |
| 224 registrar_.Add(this, | |
| 225 content::NOTIFICATION_RENDER_VIEW_HOST_DELETED, | |
| 226 content::NotificationService::AllBrowserContextsAndSources()); | |
| 227 registrar_.Add(this, | |
| 228 chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED, | |
| 229 content::NotificationService::AllBrowserContextsAndSources()); | |
| 230 registrar_.Add(this, | |
| 231 chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED, | |
| 232 content::NotificationService::AllBrowserContextsAndSources()); | |
| 233 registrar_.Add( | |
| 234 this, | |
| 235 chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED, | |
| 236 content::Source<ExtensionPrefs>(profile->GetExtensionService()-> | |
| 237 extension_prefs())); | |
| 238 } | |
| 239 | |
| 240 ExtensionUninstallDialog* | |
| 241 ExtensionSettingsHandler::GetExtensionUninstallDialog() { | |
| 242 if (!extension_uninstall_dialog_.get()) { | |
| 243 extension_uninstall_dialog_.reset( | |
| 244 ExtensionUninstallDialog::Create(Profile::FromWebUI(web_ui_), this)); | |
| 245 } | |
| 246 return extension_uninstall_dialog_.get(); | |
| 247 } | |
| 248 | |
| 249 void ExtensionSettingsHandler::HandleToggleDeveloperMode( | |
| 250 const ListValue* args) { | |
| 251 Profile* profile = Profile::FromWebUI(web_ui_); | |
| 252 bool developer_mode = | |
| 253 profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode); | |
| 254 profile->GetPrefs()->SetBoolean( | |
| 255 prefs::kExtensionsUIDeveloperMode, !developer_mode); | |
| 256 HandleRequestExtensionsData(NULL); | |
| 257 } | |
| 258 | |
| 259 void ExtensionSettingsHandler::HandleInspectMessage(const ListValue* args) { | |
| 260 std::string render_process_id_str; | |
| 261 std::string render_view_id_str; | |
| 262 int render_process_id; | |
| 263 int render_view_id; | |
| 264 CHECK_EQ(2U, args->GetSize()); | |
| 265 CHECK(args->GetString(0, &render_process_id_str)); | |
| 266 CHECK(args->GetString(1, &render_view_id_str)); | |
| 267 CHECK(base::StringToInt(render_process_id_str, &render_process_id)); | |
| 268 CHECK(base::StringToInt(render_view_id_str, &render_view_id)); | |
| 269 RenderViewHost* host = RenderViewHost::FromID(render_process_id, | |
| 270 render_view_id); | |
| 271 if (!host) { | |
| 272 // This can happen if the host has gone away since the page was displayed. | |
| 273 return; | |
| 274 } | |
| 275 | |
| 276 DevToolsWindow::OpenDevToolsWindow(host); | |
| 277 } | |
| 278 | |
| 279 void ExtensionSettingsHandler::HandleReloadMessage(const ListValue* args) { | |
| 280 std::string extension_id = UTF16ToUTF8(ExtractStringValue(args)); | |
| 281 CHECK(!extension_id.empty()); | |
| 282 extension_service_->ReloadExtension(extension_id); | |
| 283 } | |
| 284 | |
| 285 void ExtensionSettingsHandler::HandleEnableMessage(const ListValue* args) { | |
| 286 CHECK_EQ(2U, args->GetSize()); | |
| 287 std::string extension_id, enable_str; | |
| 288 CHECK(args->GetString(0, &extension_id)); | |
| 289 CHECK(args->GetString(1, &enable_str)); | |
| 290 | |
| 291 const Extension* extension = | |
| 292 extension_service_->GetExtensionById(extension_id, true); | |
| 293 if (!Extension::UserMayDisable(extension->location())) { | |
| 294 LOG(ERROR) << "Attempt to enable an extension that is non-usermanagable was" | |
| 295 << "made. Extension id: " << extension->id(); | |
| 296 return; | |
| 297 } | |
| 298 | |
| 299 if (enable_str == "true") { | |
| 300 ExtensionPrefs* prefs = extension_service_->extension_prefs(); | |
| 301 if (prefs->DidExtensionEscalatePermissions(extension_id)) { | |
| 302 ShowExtensionDisabledDialog(extension_service_, | |
| 303 Profile::FromWebUI(web_ui_), extension); | |
| 304 } else { | |
| 305 extension_service_->EnableExtension(extension_id); | |
| 306 } | |
| 307 } else { | |
| 308 extension_service_->DisableExtension(extension_id); | |
| 309 } | |
| 310 } | |
| 311 | |
| 312 void ExtensionSettingsHandler::HandleEnableIncognitoMessage( | |
| 313 const ListValue* args) { | |
| 314 CHECK_EQ(2U, args->GetSize()); | |
| 315 std::string extension_id, enable_str; | |
| 316 CHECK(args->GetString(0, &extension_id)); | |
| 317 CHECK(args->GetString(1, &enable_str)); | |
| 318 const Extension* extension = | |
| 319 extension_service_->GetExtensionById(extension_id, true); | |
| 320 DCHECK(extension); | |
| 321 | |
| 322 // Flipping the incognito bit will generate unload/load notifications for the | |
| 323 // extension, but we don't want to reload the page, because a) we've already | |
| 324 // updated the UI to reflect the change, and b) we want the yellow warning | |
| 325 // text to stay until the user has left the page. | |
| 326 // | |
| 327 // TODO(aa): This creates crapiness in some cases. For example, in a main | |
| 328 // window, when toggling this, the browser action will flicker because it gets | |
| 329 // unloaded, then reloaded. It would be better to have a dedicated | |
| 330 // notification for this case. | |
| 331 // | |
| 332 // Bug: http://crbug.com/41384 | |
| 333 AutoReset<bool> auto_reset_ignore_notifications(&ignore_notifications_, true); | |
| 334 extension_service_->SetIsIncognitoEnabled(extension->id(), | |
| 335 enable_str == "true"); | |
| 336 } | |
| 337 | |
| 338 void ExtensionSettingsHandler::HandleAllowFileAccessMessage( | |
| 339 const ListValue* args) { | |
| 340 CHECK_EQ(2U, args->GetSize()); | |
| 341 std::string extension_id, allow_str; | |
| 342 CHECK(args->GetString(0, &extension_id)); | |
| 343 CHECK(args->GetString(1, &allow_str)); | |
| 344 const Extension* extension = | |
| 345 extension_service_->GetExtensionById(extension_id, true); | |
| 346 DCHECK(extension); | |
| 347 | |
| 348 if (!Extension::UserMayDisable(extension->location())) { | |
| 349 LOG(ERROR) << "Attempt to change allow file access of an extension that is " | |
| 350 << "non-usermanagable was made. Extension id : " | |
| 351 << extension->id(); | |
| 352 return; | |
| 353 } | |
| 354 | |
| 355 extension_service_->SetAllowFileAccess(extension, allow_str == "true"); | |
| 356 } | |
| 357 | |
| 358 void ExtensionSettingsHandler::HandleUninstallMessage(const ListValue* args) { | |
| 359 std::string extension_id = UTF16ToUTF8(ExtractStringValue(args)); | |
| 360 CHECK(!extension_id.empty()); | |
| 361 const Extension* extension = | |
| 362 extension_service_->GetExtensionById(extension_id, true); | |
| 363 if (!extension) | |
| 364 extension = extension_service_->GetTerminatedExtension(extension_id); | |
| 365 if (!extension) | |
| 366 return; | |
| 367 | |
| 368 if (!Extension::UserMayDisable(extension->location())) { | |
| 369 LOG(ERROR) << "Attempt to uninstall an extension that is non-usermanagable " | |
| 370 << "was made. Extension id : " << extension->id(); | |
| 371 return; | |
| 372 } | |
| 373 | |
| 374 if (!extension_id_prompting_.empty()) | |
| 375 return; // Only one prompt at a time. | |
| 376 | |
| 377 extension_id_prompting_ = extension_id; | |
| 378 | |
| 379 GetExtensionUninstallDialog()->ConfirmUninstall(extension); | |
| 380 } | |
| 381 | |
| 382 void ExtensionSettingsHandler::ExtensionUninstallAccepted() { | |
| 383 DCHECK(!extension_id_prompting_.empty()); | |
| 384 | |
| 385 bool was_terminated = false; | |
| 386 | |
| 387 // The extension can be uninstalled in another window while the UI was | |
| 388 // showing. Do nothing in that case. | |
| 389 const Extension* extension = | |
| 390 extension_service_->GetExtensionById(extension_id_prompting_, true); | |
| 391 if (!extension) { | |
| 392 extension = extension_service_->GetTerminatedExtension( | |
| 393 extension_id_prompting_); | |
| 394 was_terminated = true; | |
| 395 } | |
| 396 if (!extension) | |
| 397 return; | |
| 398 | |
| 399 extension_service_->UninstallExtension(extension_id_prompting_, | |
| 400 false, // External uninstall. | |
| 401 NULL); // Error. | |
| 402 extension_id_prompting_ = ""; | |
| 403 | |
| 404 // There will be no EXTENSION_UNLOADED notification for terminated | |
| 405 // extensions as they were already unloaded. | |
| 406 if (was_terminated) | |
| 407 HandleRequestExtensionsData(NULL); | |
| 408 } | |
| 409 | |
| 410 void ExtensionSettingsHandler::ExtensionUninstallCanceled() { | |
| 411 extension_id_prompting_ = ""; | |
| 412 } | |
| 413 | |
| 414 void ExtensionSettingsHandler::HandleOptionsMessage(const ListValue* args) { | |
| 415 const Extension* extension = GetExtension(args); | |
| 416 if (!extension || extension->options_url().is_empty()) | |
| 417 return; | |
| 418 Profile::FromWebUI(web_ui_)->GetExtensionProcessManager()->OpenOptionsPage( | |
| 419 extension, NULL); | |
| 420 } | |
| 421 | |
| 422 void ExtensionSettingsHandler::HandleShowButtonMessage(const ListValue* args) { | |
| 423 const Extension* extension = GetExtension(args); | |
| 424 extension_service_->SetBrowserActionVisibility(extension, true); | |
| 425 } | |
| 426 | |
| 427 void ExtensionSettingsHandler::HandleLoadMessage(const ListValue* args) { | |
| 428 FilePath::StringType string_path; | |
| 429 CHECK_EQ(1U, args->GetSize()) << args->GetSize(); | |
| 430 CHECK(args->GetString(0, &string_path)); | |
| 431 extensions::UnpackedInstaller::Create(extension_service_)-> | |
| 432 Load(FilePath(string_path)); | |
| 433 } | |
| 434 | |
| 435 void ExtensionSettingsHandler::ShowAlert(const std::string& message) { | |
| 436 ListValue arguments; | |
| 437 arguments.Append(Value::CreateStringValue(message)); | |
| 438 web_ui_->CallJavascriptFunction("alert", arguments); | |
| 439 } | |
| 440 | |
| 441 void ExtensionSettingsHandler::HandleAutoUpdateMessage(const ListValue* args) { | |
| 442 ExtensionUpdater* updater = extension_service_->updater(); | |
| 443 if (updater) | |
| 444 updater->CheckNow(); | |
| 445 } | |
| 446 | |
| 447 void ExtensionSettingsHandler::HandleSelectFilePathMessage( | |
| 448 const ListValue* args) { | |
| 449 std::string select_type; | |
| 450 std::string operation; | |
| 451 CHECK_EQ(2U, args->GetSize()); | |
| 452 CHECK(args->GetString(0, &select_type)); | |
| 453 CHECK(args->GetString(1, &operation)); | |
| 454 | |
| 455 SelectFileDialog::Type type = SelectFileDialog::SELECT_FOLDER; | |
| 456 SelectFileDialog::FileTypeInfo info; | |
| 457 int file_type_index = 0; | |
| 458 if (select_type == "file") | |
| 459 type = SelectFileDialog::SELECT_OPEN_FILE; | |
| 460 | |
| 461 string16 select_title; | |
| 462 if (operation == "load") { | |
| 463 select_title = l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY); | |
| 464 } else if (operation == "packRoot") { | |
| 465 select_title = l10n_util::GetStringUTF16( | |
| 466 IDS_EXTENSION_PACK_DIALOG_SELECT_ROOT); | |
| 467 } else if (operation == "pem") { | |
| 468 select_title = l10n_util::GetStringUTF16( | |
| 469 IDS_EXTENSION_PACK_DIALOG_SELECT_KEY); | |
| 470 info.extensions.push_back(std::vector<FilePath::StringType>()); | |
| 471 info.extensions.front().push_back(FILE_PATH_LITERAL("pem")); | |
| 472 info.extension_description_overrides.push_back( | |
| 473 l10n_util::GetStringUTF16( | |
| 474 IDS_EXTENSION_PACK_DIALOG_KEY_FILE_TYPE_DESCRIPTION)); | |
| 475 info.include_all_files = true; | |
| 476 file_type_index = 1; | |
| 477 } else { | |
| 478 NOTREACHED(); | |
| 479 return; | |
| 480 } | |
| 481 | |
| 482 load_extension_dialog_ = SelectFileDialog::Create(this); | |
| 483 load_extension_dialog_->SelectFile(type, select_title, FilePath(), &info, | |
| 484 file_type_index, FILE_PATH_LITERAL(""), web_ui_->tab_contents(), | |
| 485 web_ui_->tab_contents()->view()->GetTopLevelNativeWindow(), NULL); | |
| 486 } | |
| 487 | |
| 488 | |
| 489 void ExtensionSettingsHandler::FileSelected(const FilePath& path, int index, | |
| 490 void* params) { | |
| 491 // Add the extensions to the results structure. | |
| 492 ListValue results; | |
| 493 results.Append(Value::CreateStringValue(path.value())); | |
| 494 web_ui_->CallJavascriptFunction("window.handleFilePathSelected", results); | |
| 495 } | |
| 496 | |
| 497 void ExtensionSettingsHandler::MultiFilesSelected( | |
| 498 const std::vector<FilePath>& files, void* params) { | |
| 499 NOTREACHED(); | |
| 500 } | |
| 501 | |
| 502 void ExtensionSettingsHandler::GetLocalizedValues( | |
| 503 DictionaryValue* localized_strings) { | |
| 504 DCHECK(localized_strings); | |
| 505 | |
| 506 RegisterTitle(localized_strings, "extensionSettings", | |
| 507 IDS_MANAGE_EXTENSIONS_SETTING_WINDOWS_TITLE); | |
| 508 | |
| 509 localized_strings->SetString("extensionSettingsVisitWebsite", | |
| 510 l10n_util::GetStringUTF16(IDS_EXTENSIONS_VISIT_WEBSITE)); | |
| 511 | |
| 512 localized_strings->SetString("extensionSettingsDeveloperMode", | |
| 513 l10n_util::GetStringUTF16(IDS_EXTENSIONS_DEVELOPER_MODE_LINK)); | |
| 514 localized_strings->SetString("extensionSettingsNoExtensions", | |
| 515 l10n_util::GetStringUTF16(IDS_EXTENSIONS_NONE_INSTALLED)); | |
| 516 localized_strings->SetString("extensionSettingsSuggestGallery", | |
| 517 l10n_util::GetStringFUTF16(IDS_EXTENSIONS_NONE_INSTALLED_SUGGEST_GALLERY, | |
| 518 ASCIIToUTF16("<a href='") + | |
| 519 ASCIIToUTF16(google_util::AppendGoogleLocaleParam( | |
| 520 GURL(extension_urls::GetWebstoreLaunchURL())).spec()) + | |
| 521 ASCIIToUTF16("'>"), | |
| 522 ASCIIToUTF16("</a>"))); | |
| 523 localized_strings->SetString("extensionSettingsGetMoreExtensions", | |
| 524 ASCIIToUTF16("<a href='") + | |
| 525 ASCIIToUTF16(google_util::AppendGoogleLocaleParam( | |
| 526 GURL(extension_urls::GetWebstoreLaunchURL())).spec()) + | |
| 527 ASCIIToUTF16("'>") + | |
| 528 l10n_util::GetStringUTF16(IDS_GET_MORE_EXTENSIONS) + | |
| 529 ASCIIToUTF16("</a>")); | |
| 530 localized_strings->SetString("extensionSettingsExtensionId", | |
| 531 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ID)); | |
| 532 localized_strings->SetString("extensionSettingsExtensionPath", | |
| 533 l10n_util::GetStringUTF16(IDS_EXTENSIONS_PATH)); | |
| 534 localized_strings->SetString("extensionSettingsInspectViews", | |
| 535 l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSPECT_VIEWS)); | |
| 536 localized_strings->SetString("viewIncognito", | |
| 537 l10n_util::GetStringUTF16(IDS_EXTENSIONS_VIEW_INCOGNITO)); | |
| 538 localized_strings->SetString("extensionSettingsEnable", | |
| 539 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLE)); | |
| 540 localized_strings->SetString("extensionSettingsEnabled", | |
| 541 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLED)); | |
| 542 localized_strings->SetString("extensionSettingsRemove", | |
| 543 l10n_util::GetStringUTF16(IDS_EXTENSIONS_REMOVE)); | |
| 544 localized_strings->SetString("extensionSettingsEnableIncognito", | |
| 545 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLE_INCOGNITO)); | |
| 546 localized_strings->SetString("extensionSettingsAllowFileAccess", | |
| 547 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ALLOW_FILE_ACCESS)); | |
| 548 localized_strings->SetString("extensionSettingsIncognitoWarning", | |
| 549 l10n_util::GetStringFUTF16(IDS_EXTENSIONS_INCOGNITO_WARNING, | |
| 550 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME))); | |
| 551 localized_strings->SetString("extensionSettingsReload", | |
| 552 l10n_util::GetStringUTF16(IDS_EXTENSIONS_RELOAD)); | |
| 553 localized_strings->SetString("extensionSettingsOptions", | |
| 554 l10n_util::GetStringUTF16(IDS_EXTENSIONS_OPTIONS)); | |
| 555 localized_strings->SetString("extensionSettingsPolicyControlled", | |
| 556 l10n_util::GetStringUTF16(IDS_EXTENSIONS_POLICY_CONTROLLED)); | |
| 557 localized_strings->SetString("extensionSettingsShowButton", | |
| 558 l10n_util::GetStringUTF16(IDS_EXTENSIONS_SHOW_BUTTON)); | |
| 559 localized_strings->SetString("extensionSettingsLoadUnpackedButton", | |
| 560 l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_UNPACKED_BUTTON)); | |
| 561 localized_strings->SetString("extensionSettingsPackButton", | |
| 562 l10n_util::GetStringUTF16(IDS_EXTENSIONS_PACK_BUTTON)); | |
| 563 localized_strings->SetString("extensionSettingsUpdateButton", | |
| 564 l10n_util::GetStringUTF16(IDS_EXTENSIONS_UPDATE_BUTTON)); | |
| 565 localized_strings->SetString("extensionSettingsCrashMessage", | |
| 566 l10n_util::GetStringUTF16(IDS_EXTENSIONS_CRASHED_EXTENSION)); | |
| 567 localized_strings->SetString("extensionSettingsInDevelopment", | |
| 568 l10n_util::GetStringUTF16(IDS_EXTENSIONS_IN_DEVELOPMENT)); | |
| 569 localized_strings->SetString("extensionSettingsWarningsTitle", | |
| 570 l10n_util::GetStringUTF16(IDS_EXTENSION_WARNINGS_TITLE)); | |
| 571 localized_strings->SetString("extensionSettingsShowDetails", | |
| 572 l10n_util::GetStringUTF16(IDS_EXTENSIONS_SHOW_DETAILS)); | |
| 573 localized_strings->SetString("extensionSettingsHideDetails", | |
| 574 l10n_util::GetStringUTF16(IDS_EXTENSIONS_HIDE_DETAILS)); | |
| 575 } | |
| 576 | |
| 577 void ExtensionSettingsHandler::Initialize() { | |
| 578 } | |
| 579 | |
| 580 WebUIMessageHandler* ExtensionSettingsHandler::Attach(WebUI* web_ui) { | |
| 581 // Call through to superclass. | |
| 582 WebUIMessageHandler* handler = OptionsPage2UIHandler::Attach(web_ui); | |
| 583 | |
| 584 extension_service_ = Profile::FromWebUI(web_ui_) | |
| 585 ->GetOriginalProfile()->GetExtensionService(); | |
| 586 | |
| 587 // Return result from the superclass. | |
| 588 return handler; | |
| 589 } | |
| 590 | |
| 591 void ExtensionSettingsHandler::Observe( | |
| 592 int type, | |
| 593 const content::NotificationSource& source, | |
| 594 const content::NotificationDetails& details) { | |
| 595 Profile* profile = Profile::FromWebUI(web_ui_); | |
| 596 Profile* source_profile = NULL; | |
| 597 switch (type) { | |
| 598 // We listen for notifications that will result in the page being | |
| 599 // repopulated with data twice for the same event in certain cases. | |
| 600 // For instance, EXTENSION_LOADED & EXTENSION_HOST_CREATED because | |
| 601 // we don't know about the views for an extension at EXTENSION_LOADED, but | |
| 602 // if we only listen to EXTENSION_HOST_CREATED, we'll miss extensions | |
| 603 // that don't have a process at startup. | |
| 604 // | |
| 605 // Doing it this way gets everything but causes the page to be rendered | |
| 606 // more than we need. It doesn't seem to result in any noticeable flicker. | |
| 607 case content::NOTIFICATION_RENDER_VIEW_HOST_DELETED: | |
| 608 deleting_rvh_ = content::Source<RenderViewHost>(source).ptr(); | |
| 609 // Fall through. | |
| 610 case content::NOTIFICATION_RENDER_VIEW_HOST_CREATED: | |
| 611 source_profile = Profile::FromBrowserContext( | |
| 612 content::Source<RenderViewHost>(source)->site_instance()-> | |
| 613 browsing_instance()->browser_context()); | |
| 614 if (!profile->IsSameProfile(source_profile)) | |
| 615 return; | |
| 616 MaybeUpdateAfterNotification(); | |
| 617 break; | |
| 618 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED: | |
| 619 deleting_rvh_ = content::Details<BackgroundContents>(details)-> | |
| 620 tab_contents()->render_view_host(); | |
| 621 // Fall through. | |
| 622 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED: | |
| 623 case chrome::NOTIFICATION_EXTENSION_HOST_CREATED: | |
| 624 source_profile = content::Source<Profile>(source).ptr(); | |
| 625 if (!profile->IsSameProfile(source_profile)) | |
| 626 return; | |
| 627 MaybeUpdateAfterNotification(); | |
| 628 break; | |
| 629 case chrome::NOTIFICATION_EXTENSION_LOADED: | |
| 630 case chrome::NOTIFICATION_EXTENSION_UNLOADED: | |
| 631 case chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED: | |
| 632 case chrome::NOTIFICATION_EXTENSION_WARNING_CHANGED: | |
| 633 case chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED: | |
| 634 MaybeUpdateAfterNotification(); | |
| 635 break; | |
| 636 default: | |
| 637 NOTREACHED(); | |
| 638 } | |
| 639 } | |
| 640 | |
| 641 const Extension* ExtensionSettingsHandler::GetExtension(const ListValue* args) { | |
| 642 std::string extension_id = UTF16ToUTF8(ExtractStringValue(args)); | |
| 643 CHECK(!extension_id.empty()); | |
| 644 return extension_service_->GetExtensionById(extension_id, true); | |
| 645 } | |
| 646 | |
| 647 void ExtensionSettingsHandler::MaybeUpdateAfterNotification() { | |
| 648 TabContents* contents = web_ui_->tab_contents(); | |
| 649 if (!ignore_notifications_ && contents && contents->render_view_host()) | |
| 650 HandleRequestExtensionsData(NULL); | |
| 651 deleting_rvh_ = NULL; | |
| 652 } | |
| 653 | |
| 654 // Static | |
| 655 DictionaryValue* ExtensionSettingsHandler::CreateExtensionDetailValue( | |
| 656 ExtensionService* service, const Extension* extension, | |
| 657 const std::vector<ExtensionPage>& pages, | |
| 658 const ExtensionWarningSet* warnings_set, | |
| 659 bool enabled, bool terminated) { | |
| 660 DictionaryValue* extension_data = new DictionaryValue(); | |
| 661 GURL icon = | |
| 662 ExtensionIconSource::GetIconURL(extension, | |
| 663 Extension::EXTENSION_ICON_MEDIUM, | |
| 664 ExtensionIconSet::MATCH_BIGGER, | |
| 665 !enabled, NULL); | |
| 666 extension_data->SetString("id", extension->id()); | |
| 667 extension_data->SetString("name", extension->name()); | |
| 668 extension_data->SetString("description", extension->description()); | |
| 669 if (extension->location() == Extension::LOAD) | |
| 670 extension_data->SetString("path", extension->path().value()); | |
| 671 extension_data->SetString("version", extension->version()->GetString()); | |
| 672 extension_data->SetString("icon", icon.spec()); | |
| 673 extension_data->SetBoolean("isUnpacked", | |
| 674 extension->location() == Extension::LOAD); | |
| 675 extension_data->SetBoolean("mayDisable", | |
| 676 Extension::UserMayDisable(extension->location())); | |
| 677 extension_data->SetBoolean("enabled", enabled); | |
| 678 extension_data->SetBoolean("terminated", terminated); | |
| 679 extension_data->SetBoolean("enabledIncognito", | |
| 680 service ? service->IsIncognitoEnabled(extension->id()) : false); | |
| 681 extension_data->SetBoolean("wantsFileAccess", extension->wants_file_access()); | |
| 682 extension_data->SetBoolean("allowFileAccess", | |
| 683 service ? service->AllowFileAccess(extension) : false); | |
| 684 extension_data->SetBoolean("allow_reload", | |
| 685 extension->location() == Extension::LOAD); | |
| 686 extension_data->SetBoolean("is_hosted_app", extension->is_hosted_app()); | |
| 687 | |
| 688 // Determine the sort order: Extensions loaded through --load-extensions show | |
| 689 // up at the top. Disabled extensions show up at the bottom. | |
| 690 if (extension->location() == Extension::LOAD) | |
| 691 extension_data->SetInteger("order", 1); | |
| 692 else | |
| 693 extension_data->SetInteger("order", 2); | |
| 694 | |
| 695 if (!extension->options_url().is_empty() && enabled) | |
| 696 extension_data->SetString("options_url", extension->options_url().spec()); | |
| 697 | |
| 698 if (service && !service->GetBrowserActionVisibility(extension)) | |
| 699 extension_data->SetBoolean("enable_show_button", true); | |
| 700 | |
| 701 // Add views | |
| 702 ListValue* views = new ListValue; | |
| 703 for (std::vector<ExtensionPage>::const_iterator iter = pages.begin(); | |
| 704 iter != pages.end(); ++iter) { | |
| 705 DictionaryValue* view_value = new DictionaryValue; | |
| 706 if (iter->url.scheme() == chrome::kExtensionScheme) { | |
| 707 // No leading slash. | |
| 708 view_value->SetString("path", iter->url.path().substr(1)); | |
| 709 } else { | |
| 710 // For live pages, use the full URL. | |
| 711 view_value->SetString("path", iter->url.spec()); | |
| 712 } | |
| 713 view_value->SetInteger("renderViewId", iter->render_view_id); | |
| 714 view_value->SetInteger("renderProcessId", iter->render_process_id); | |
| 715 view_value->SetBoolean("incognito", iter->incognito); | |
| 716 views->Append(view_value); | |
| 717 } | |
| 718 extension_data->Set("views", views); | |
| 719 extension_data->SetBoolean("hasPopupAction", | |
| 720 extension->browser_action() || extension->page_action()); | |
| 721 extension_data->SetString("homepageUrl", extension->GetHomepageURL().spec()); | |
| 722 | |
| 723 // Add warnings. | |
| 724 ListValue* warnings_list = new ListValue; | |
| 725 if (warnings_set) { | |
| 726 std::set<ExtensionWarningSet::WarningType> warnings; | |
| 727 warnings_set->GetWarningsAffectingExtension(extension->id(), &warnings); | |
| 728 | |
| 729 for (std::set<ExtensionWarningSet::WarningType>::const_iterator iter = | |
| 730 warnings.begin(); | |
| 731 iter != warnings.end(); | |
| 732 ++iter) { | |
| 733 string16 warning_string(ExtensionWarningSet::GetLocalizedWarning(*iter)); | |
| 734 warnings_list->Append(Value::CreateStringValue(warning_string)); | |
| 735 } | |
| 736 } | |
| 737 extension_data->Set("warnings", warnings_list); | |
| 738 | |
| 739 return extension_data; | |
| 740 } | |
| 741 | |
| 742 std::vector<ExtensionPage> ExtensionSettingsHandler::GetActivePagesForExtension( | |
| 743 const Extension* extension) { | |
| 744 std::vector<ExtensionPage> result; | |
| 745 | |
| 746 // Get the extension process's active views. | |
| 747 ExtensionProcessManager* process_manager = | |
| 748 extension_service_->profile()->GetExtensionProcessManager(); | |
| 749 GetActivePagesForExtensionProcess( | |
| 750 process_manager->GetRenderViewHostsForExtension( | |
| 751 extension->id()), &result); | |
| 752 | |
| 753 // Repeat for the incognito process, if applicable. | |
| 754 if (extension_service_->profile()->HasOffTheRecordProfile() && | |
| 755 extension->incognito_split_mode()) { | |
| 756 ExtensionProcessManager* process_manager = | |
| 757 extension_service_->profile()->GetOffTheRecordProfile()-> | |
| 758 GetExtensionProcessManager(); | |
| 759 GetActivePagesForExtensionProcess( | |
| 760 process_manager->GetRenderViewHostsForExtension( | |
| 761 extension->id()), &result); | |
| 762 } | |
| 763 | |
| 764 return result; | |
| 765 } | |
| 766 | |
| 767 void ExtensionSettingsHandler::GetActivePagesForExtensionProcess( | |
| 768 const std::set<RenderViewHost*>& views, | |
| 769 std::vector<ExtensionPage> *result) { | |
| 770 for (std::set<RenderViewHost*>::const_iterator iter = views.begin(); | |
| 771 iter != views.end(); ++iter) { | |
| 772 RenderViewHost* host = *iter; | |
| 773 int host_type = host->delegate()->GetRenderViewType(); | |
| 774 if (host == deleting_rvh_ || | |
| 775 chrome::VIEW_TYPE_EXTENSION_POPUP == host_type || | |
| 776 chrome::VIEW_TYPE_EXTENSION_DIALOG == host_type) | |
| 777 continue; | |
| 778 | |
| 779 GURL url = host->delegate()->GetURL(); | |
| 780 content::RenderProcessHost* process = host->process(); | |
| 781 result->push_back( | |
| 782 ExtensionPage(url, process->GetID(), host->routing_id(), | |
| 783 process->GetBrowserContext()->IsOffTheRecord())); | |
| 784 } | |
| 785 } | |
| OLD | NEW |