Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(14)

Side by Side Diff: chrome/browser/extensions/extensions_ui.cc

Issue 7976023: Remove the old chrome://extensions page, since the URL now redirects to the new Settings page.BUG... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/extensions/extensions_ui.h ('k') | chrome/browser/prefs/browser_prefs.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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/extensions_ui.h"
6
7 #include <algorithm>
8
9 #include "base/base64.h"
10 #include "base/callback.h"
11 #include "base/file_util.h"
12 #include "base/memory/singleton.h"
13 #include "base/string_number_conversions.h"
14 #include "base/string_util.h"
15 #include "base/threading/thread.h"
16 #include "base/utf_string_conversions.h"
17 #include "base/version.h"
18 #include "chrome/browser/debugger/devtools_window.h"
19 #include "chrome/browser/extensions/crx_installer.h"
20 #include "chrome/browser/extensions/extension_disabled_infobar_delegate.h"
21 #include "chrome/browser/extensions/extension_error_reporter.h"
22 #include "chrome/browser/extensions/extension_host.h"
23 #include "chrome/browser/extensions/extension_message_service.h"
24 #include "chrome/browser/extensions/extension_service.h"
25 #include "chrome/browser/extensions/extension_updater.h"
26 #include "chrome/browser/google/google_util.h"
27 #include "chrome/browser/prefs/pref_service.h"
28 #include "chrome/browser/profiles/profile.h"
29 #include "chrome/browser/tab_contents/background_contents.h"
30 #include "chrome/browser/ui/browser_list.h"
31 #include "chrome/browser/ui/webui/chrome_web_ui_data_source.h"
32 #include "chrome/browser/ui/webui/extension_icon_source.h"
33 #include "chrome/common/chrome_notification_types.h"
34 #include "chrome/common/extensions/extension.h"
35 #include "chrome/common/extensions/extension_icon_set.h"
36 #include "chrome/common/extensions/url_pattern.h"
37 #include "chrome/common/extensions/user_script.h"
38 #include "chrome/common/jstemplate_builder.h"
39 #include "chrome/common/pref_names.h"
40 #include "chrome/common/url_constants.h"
41 #include "content/browser/renderer_host/render_process_host.h"
42 #include "content/browser/renderer_host/render_view_host.h"
43 #include "content/browser/renderer_host/render_widget_host.h"
44 #include "content/browser/tab_contents/tab_contents.h"
45 #include "content/browser/tab_contents/tab_contents_view.h"
46 #include "content/common/content_notification_types.h"
47 #include "content/common/notification_service.h"
48 #include "googleurl/src/gurl.h"
49 #include "grit/browser_resources.h"
50 #include "grit/chromium_strings.h"
51 #include "grit/generated_resources.h"
52 #include "grit/theme_resources.h"
53 #include "grit/theme_resources_standard.h"
54 #include "net/base/net_util.h"
55 #include "ui/base/l10n/l10n_util.h"
56 #include "ui/base/resource/resource_bundle.h"
57
58 namespace {
59
60 bool ShouldShowExtension(const Extension* extension) {
61 // Don't show themes since this page's UI isn't really useful for themes.
62 if (extension->is_theme())
63 return false;
64
65 // Don't show component extensions because they are only extensions as an
66 // implementation detail of Chrome.
67 if (extension->location() == Extension::COMPONENT)
68 return false;
69
70 // Always show unpacked extensions and apps.
71 if (extension->location() == Extension::LOAD)
72 return true;
73
74 // Unless they are unpacked, never show hosted apps.
75 if (extension->is_hosted_app())
76 return false;
77
78 return true;
79 }
80
81 } // namespace
82
83 ChromeWebUIDataSource* CreateExtensionsUIHTMLSource() {
84 ChromeWebUIDataSource* source =
85 new ChromeWebUIDataSource(chrome::kChromeUIExtensionsHost);
86
87 source->AddLocalizedString("title", IDS_EXTENSIONS_TITLE);
88 source->AddLocalizedString("devModeLink", IDS_EXTENSIONS_DEVELOPER_MODE_LINK);
89 source->AddLocalizedString("devModePrefix",
90 IDS_EXTENSIONS_DEVELOPER_MODE_PREFIX);
91 source->AddLocalizedString("loadUnpackedButton",
92 IDS_EXTENSIONS_LOAD_UNPACKED_BUTTON);
93 source->AddLocalizedString("packButton", IDS_EXTENSIONS_PACK_BUTTON);
94 source->AddLocalizedString("updateButton", IDS_EXTENSIONS_UPDATE_BUTTON);
95 source->AddLocalizedString("noExtensions", IDS_EXTENSIONS_NONE_INSTALLED);
96 source->AddLocalizedString("extensionCrashed",
97 IDS_EXTENSIONS_CRASHED_EXTENSION);
98 source->AddLocalizedString("extensionDisabled",
99 IDS_EXTENSIONS_DISABLED_EXTENSION);
100 source->AddLocalizedString("inDevelopment", IDS_EXTENSIONS_IN_DEVELOPMENT);
101 source->AddLocalizedString("viewIncognito", IDS_EXTENSIONS_VIEW_INCOGNITO);
102 source->AddLocalizedString("extensionId", IDS_EXTENSIONS_ID);
103 source->AddLocalizedString("extensionPath", IDS_EXTENSIONS_PATH);
104 source->AddLocalizedString("extensionVersion", IDS_EXTENSIONS_VERSION);
105 source->AddLocalizedString("inspectViews", IDS_EXTENSIONS_INSPECT_VIEWS);
106 source->AddLocalizedString("inspectPopupsInstructions",
107 IDS_EXTENSIONS_INSPECT_POPUPS_INSTRUCTIONS);
108 source->AddLocalizedString("disable", IDS_EXTENSIONS_DISABLE);
109 source->AddLocalizedString("enable", IDS_EXTENSIONS_ENABLE);
110 source->AddLocalizedString("enableIncognito",
111 IDS_EXTENSIONS_ENABLE_INCOGNITO);
112 source->AddLocalizedString("allowFileAccess",
113 IDS_EXTENSIONS_ALLOW_FILE_ACCESS);
114 source->AddLocalizedString("reload", IDS_EXTENSIONS_RELOAD);
115 source->AddLocalizedString("uninstall", IDS_EXTENSIONS_UNINSTALL);
116 source->AddLocalizedString("options", IDS_EXTENSIONS_OPTIONS);
117 source->AddLocalizedString("policyControlled",
118 IDS_EXTENSIONS_POLICY_CONTROLLED);
119 source->AddLocalizedString("packDialogTitle",
120 IDS_EXTENSION_PACK_DIALOG_TITLE);
121 source->AddLocalizedString("packDialogHeading",
122 IDS_EXTENSION_PACK_DIALOG_HEADING);
123 source->AddLocalizedString("rootDirectoryLabel",
124 IDS_EXTENSION_PACK_DIALOG_ROOT_DIRECTORY_LABEL);
125 source->AddLocalizedString("packDialogBrowse",
126 IDS_EXTENSION_PACK_DIALOG_BROWSE);
127 source->AddLocalizedString("privateKeyLabel",
128 IDS_EXTENSION_PACK_DIALOG_PRIVATE_KEY_LABEL);
129 source->AddLocalizedString("okButton", IDS_OK);
130 source->AddLocalizedString("cancelButton", IDS_CANCEL);
131 source->AddLocalizedString("showButton", IDS_EXTENSIONS_SHOW_BUTTON);
132
133 source->AddString("incognitoWarning",
134 l10n_util::GetStringFUTF16(IDS_EXTENSIONS_INCOGNITO_WARNING,
135 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
136
137 source->AddString("suggestGallery",
138 l10n_util::GetStringFUTF16(IDS_EXTENSIONS_NONE_INSTALLED_SUGGEST_GALLERY,
139 ASCIIToUTF16("<a href='") +
140 ASCIIToUTF16(google_util::AppendGoogleLocaleParam(
141 GURL(extension_urls::GetWebstoreLaunchURL())).spec()) +
142 ASCIIToUTF16("'>"),
143 ASCIIToUTF16("</a>")));
144
145 source->AddString("getMoreExtensions",
146 ASCIIToUTF16("<a href='") +
147 ASCIIToUTF16(google_util::AppendGoogleLocaleParam(
148 GURL(extension_urls::GetWebstoreLaunchURL())).spec()) +
149 ASCIIToUTF16("'>") +
150 l10n_util::GetStringUTF16(IDS_GET_MORE_EXTENSIONS) +
151 ASCIIToUTF16("</a>"));
152
153 source->set_json_path("strings.js");
154 source->add_resource_path("extensions_ui.js", IDR_EXTENSIONS_UI_JS);
155 source->set_default_resource(IDR_EXTENSIONS_UI_HTML);
156 return source;
157 }
158
159 ///////////////////////////////////////////////////////////////////////////////
160 //
161 // ExtensionsDOMHandler
162 //
163 ///////////////////////////////////////////////////////////////////////////////
164
165 ExtensionsDOMHandler::ExtensionsDOMHandler(ExtensionService* extension_service)
166 : extension_service_(extension_service),
167 ignore_notifications_(false),
168 deleting_rvh_(NULL) {
169 RegisterForNotifications();
170 }
171
172 void ExtensionsDOMHandler::RegisterMessages() {
173 web_ui_->RegisterMessageCallback("requestExtensionsData",
174 NewCallback(this, &ExtensionsDOMHandler::HandleRequestExtensionsData));
175 web_ui_->RegisterMessageCallback("toggleDeveloperMode",
176 NewCallback(this, &ExtensionsDOMHandler::HandleToggleDeveloperMode));
177 web_ui_->RegisterMessageCallback("inspect",
178 NewCallback(this, &ExtensionsDOMHandler::HandleInspectMessage));
179 web_ui_->RegisterMessageCallback("reload",
180 NewCallback(this, &ExtensionsDOMHandler::HandleReloadMessage));
181 web_ui_->RegisterMessageCallback("enable",
182 NewCallback(this, &ExtensionsDOMHandler::HandleEnableMessage));
183 web_ui_->RegisterMessageCallback("enableIncognito",
184 NewCallback(this, &ExtensionsDOMHandler::HandleEnableIncognitoMessage));
185 web_ui_->RegisterMessageCallback("allowFileAccess",
186 NewCallback(this, &ExtensionsDOMHandler::HandleAllowFileAccessMessage));
187 web_ui_->RegisterMessageCallback("uninstall",
188 NewCallback(this, &ExtensionsDOMHandler::HandleUninstallMessage));
189 web_ui_->RegisterMessageCallback("options",
190 NewCallback(this, &ExtensionsDOMHandler::HandleOptionsMessage));
191 web_ui_->RegisterMessageCallback("showButton",
192 NewCallback(this, &ExtensionsDOMHandler::HandleShowButtonMessage));
193 web_ui_->RegisterMessageCallback("load",
194 NewCallback(this, &ExtensionsDOMHandler::HandleLoadMessage));
195 web_ui_->RegisterMessageCallback("pack",
196 NewCallback(this, &ExtensionsDOMHandler::HandlePackMessage));
197 web_ui_->RegisterMessageCallback("autoupdate",
198 NewCallback(this, &ExtensionsDOMHandler::HandleAutoUpdateMessage));
199 web_ui_->RegisterMessageCallback("selectFilePath",
200 NewCallback(this, &ExtensionsDOMHandler::HandleSelectFilePathMessage));
201 }
202
203 void ExtensionsDOMHandler::HandleRequestExtensionsData(const ListValue* args) {
204 DictionaryValue results;
205
206 // Add the extensions to the results structure.
207 ListValue* extensions_list = new ListValue();
208
209 const ExtensionList* extensions = extension_service_->extensions();
210 for (ExtensionList::const_iterator extension = extensions->begin();
211 extension != extensions->end(); ++extension) {
212 if (ShouldShowExtension(*extension)) {
213 extensions_list->Append(CreateExtensionDetailValue(
214 extension_service_,
215 *extension,
216 GetActivePagesForExtension(*extension),
217 true, false)); // enabled, terminated
218 }
219 }
220 extensions = extension_service_->disabled_extensions();
221 for (ExtensionList::const_iterator extension = extensions->begin();
222 extension != extensions->end(); ++extension) {
223 if (ShouldShowExtension(*extension)) {
224 extensions_list->Append(CreateExtensionDetailValue(
225 extension_service_,
226 *extension,
227 GetActivePagesForExtension(*extension),
228 false, false)); // enabled, terminated
229 }
230 }
231 extensions = extension_service_->terminated_extensions();
232 std::vector<ExtensionPage> empty_pages;
233 for (ExtensionList::const_iterator extension = extensions->begin();
234 extension != extensions->end(); ++extension) {
235 if (ShouldShowExtension(*extension)) {
236 extensions_list->Append(CreateExtensionDetailValue(
237 extension_service_,
238 *extension,
239 empty_pages, // Terminated process has no active pages.
240 false, true)); // enabled, terminated
241 }
242 }
243 results.Set("extensions", extensions_list);
244
245 bool developer_mode = Profile::FromWebUI(web_ui_)->GetPrefs()->
246 GetBoolean(prefs::kExtensionsUIDeveloperMode);
247 results.SetBoolean("developerMode", developer_mode);
248
249 web_ui_->CallJavascriptFunction("returnExtensionsData", results);
250 }
251
252 void ExtensionsDOMHandler::RegisterForNotifications() {
253 // Register for notifications that we need to reload the page.
254 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
255 NotificationService::AllSources());
256 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_PROCESS_CREATED,
257 NotificationService::AllSources());
258 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
259 NotificationService::AllSources());
260 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED,
261 NotificationService::AllSources());
262 registrar_.Add(this,
263 content::NOTIFICATION_NAV_ENTRY_COMMITTED,
264 NotificationService::AllSources());
265 registrar_.Add(this,
266 content::NOTIFICATION_RENDER_VIEW_HOST_CREATED,
267 NotificationService::AllSources());
268 registrar_.Add(this,
269 content::NOTIFICATION_RENDER_VIEW_HOST_DELETED,
270 NotificationService::AllSources());
271 registrar_.Add(this,
272 chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED,
273 NotificationService::AllSources());
274 registrar_.Add(this,
275 chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED,
276 NotificationService::AllSources());
277 registrar_.Add(this,
278 chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED,
279 NotificationService::AllSources());
280 }
281
282 ExtensionUninstallDialog* ExtensionsDOMHandler::GetExtensionUninstallDialog() {
283 if (!extension_uninstall_dialog_.get()) {
284 extension_uninstall_dialog_.reset(
285 new ExtensionUninstallDialog(Profile::FromWebUI(web_ui_)));
286 }
287 return extension_uninstall_dialog_.get();
288 }
289
290 void ExtensionsDOMHandler::HandleToggleDeveloperMode(const ListValue* args) {
291 Profile* profile = Profile::FromWebUI(web_ui_);
292 bool developer_mode =
293 profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode);
294 profile->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode,
295 !developer_mode);
296 }
297
298 void ExtensionsDOMHandler::HandleInspectMessage(const ListValue* args) {
299 std::string render_process_id_str;
300 std::string render_view_id_str;
301 int render_process_id;
302 int render_view_id;
303 CHECK(args->GetSize() == 2);
304 CHECK(args->GetString(0, &render_process_id_str));
305 CHECK(args->GetString(1, &render_view_id_str));
306 CHECK(base::StringToInt(render_process_id_str, &render_process_id));
307 CHECK(base::StringToInt(render_view_id_str, &render_view_id));
308 RenderViewHost* host = RenderViewHost::FromID(render_process_id,
309 render_view_id);
310 if (!host) {
311 // This can happen if the host has gone away since the page was displayed.
312 return;
313 }
314
315 DevToolsWindow::OpenDevToolsWindow(host);
316 }
317
318 void ExtensionsDOMHandler::HandleReloadMessage(const ListValue* args) {
319 std::string extension_id = UTF16ToASCII(ExtractStringValue(args));
320 CHECK(!extension_id.empty());
321 extension_service_->ReloadExtension(extension_id);
322 }
323
324 void ExtensionsDOMHandler::HandleEnableMessage(const ListValue* args) {
325 CHECK(args->GetSize() == 2);
326 std::string extension_id, enable_str;
327 CHECK(args->GetString(0, &extension_id));
328 CHECK(args->GetString(1, &enable_str));
329 const Extension* extension =
330 extension_service_->GetExtensionById(extension_id, true);
331 DCHECK(extension);
332 if (!Extension::UserMayDisable(extension->location())) {
333 LOG(ERROR) << "Attempt to enable an extension that is non-usermanagable was"
334 << "made. Extension id: " << extension->id();
335 return;
336 }
337
338 if (enable_str == "true") {
339 ExtensionPrefs* prefs = extension_service_->extension_prefs();
340 if (prefs->DidExtensionEscalatePermissions(extension_id)) {
341 ShowExtensionDisabledDialog(extension_service_,
342 Profile::FromWebUI(web_ui_), extension);
343 } else {
344 extension_service_->EnableExtension(extension_id);
345 }
346 } else {
347 extension_service_->DisableExtension(extension_id);
348 }
349 }
350
351 void ExtensionsDOMHandler::HandleEnableIncognitoMessage(const ListValue* args) {
352 CHECK(args->GetSize() == 2);
353 std::string extension_id, enable_str;
354 CHECK(args->GetString(0, &extension_id));
355 CHECK(args->GetString(1, &enable_str));
356 const Extension* extension =
357 extension_service_->GetExtensionById(extension_id, true);
358 DCHECK(extension);
359
360 // Flipping the incognito bit will generate unload/load notifications for the
361 // extension, but we don't want to reload the page, because a) we've already
362 // updated the UI to reflect the change, and b) we want the yellow warning
363 // text to stay until the user has left the page.
364 //
365 // TODO(aa): This creates crapiness in some cases. For example, in a main
366 // window, when toggling this, the browser action will flicker because it gets
367 // unloaded, then reloaded. It would be better to have a dedicated
368 // notification for this case.
369 //
370 // Bug: http://crbug.com/41384
371 ignore_notifications_ = true;
372 extension_service_->SetIsIncognitoEnabled(extension_id,
373 enable_str == "true");
374 ignore_notifications_ = false;
375 }
376
377 void ExtensionsDOMHandler::HandleAllowFileAccessMessage(const ListValue* args) {
378 CHECK(args->GetSize() == 2);
379 std::string extension_id, allow_str;
380 CHECK(args->GetString(0, &extension_id));
381 CHECK(args->GetString(1, &allow_str));
382 const Extension* extension =
383 extension_service_->GetExtensionById(extension_id, true);
384 DCHECK(extension);
385 if (!Extension::UserMayDisable(extension->location())) {
386 LOG(ERROR) << "Attempt to change allow file access of an extension that is "
387 << "non-usermanagable was made. Extension id : "
388 << extension->id();
389 return;
390 }
391
392 extension_service_->SetAllowFileAccess(extension, allow_str == "true");
393 }
394
395 void ExtensionsDOMHandler::HandleUninstallMessage(const ListValue* args) {
396 std::string extension_id = UTF16ToASCII(ExtractStringValue(args));
397 CHECK(!extension_id.empty());
398 const Extension* extension =
399 extension_service_->GetExtensionById(extension_id, true);
400 if (!extension)
401 extension = extension_service_->GetTerminatedExtension(extension_id);
402 if (!extension)
403 return;
404
405 if (!Extension::UserMayDisable(extension->location())) {
406 LOG(ERROR) << "Attempt to uninstall an extension that is non-usermanagable "
407 << "was made. Extension id : " << extension->id();
408 return;
409 }
410
411 if (!extension_id_prompting_.empty())
412 return; // Only one prompt at a time.
413
414 extension_id_prompting_ = extension_id;
415
416 GetExtensionUninstallDialog()->ConfirmUninstall(this, extension);
417 }
418
419 void ExtensionsDOMHandler::ExtensionDialogAccepted() {
420 DCHECK(!extension_id_prompting_.empty());
421
422 bool was_terminated = false;
423
424 // The extension can be uninstalled in another window while the UI was
425 // showing. Do nothing in that case.
426 const Extension* extension =
427 extension_service_->GetExtensionById(extension_id_prompting_, true);
428 if (!extension) {
429 extension = extension_service_->GetTerminatedExtension(
430 extension_id_prompting_);
431 was_terminated = true;
432 }
433 if (!extension)
434 return;
435
436 extension_service_->UninstallExtension(extension_id_prompting_,
437 false /* external_uninstall */, NULL);
438 extension_id_prompting_ = "";
439
440 // There will be no EXTENSION_UNLOADED notification for terminated
441 // extensions as they were already unloaded.
442 if (was_terminated)
443 HandleRequestExtensionsData(NULL);
444 }
445
446 void ExtensionsDOMHandler::ExtensionDialogCanceled() {
447 extension_id_prompting_ = "";
448 }
449
450 void ExtensionsDOMHandler::HandleOptionsMessage(const ListValue* args) {
451 const Extension* extension = GetExtension(args);
452 if (!extension || extension->options_url().is_empty())
453 return;
454 Profile::FromWebUI(web_ui_)->GetExtensionProcessManager()->OpenOptionsPage(
455 extension, NULL);
456 }
457
458 void ExtensionsDOMHandler::HandleShowButtonMessage(const ListValue* args) {
459 const Extension* extension = GetExtension(args);
460 extension_service_->SetBrowserActionVisibility(extension, true);
461 }
462
463 void ExtensionsDOMHandler::HandleLoadMessage(const ListValue* args) {
464 FilePath::StringType string_path;
465 CHECK(args->GetSize() == 1) << args->GetSize();
466 CHECK(args->GetString(0, &string_path));
467 extension_service_->LoadExtension(FilePath(string_path));
468 }
469
470 void ExtensionsDOMHandler::ShowAlert(const std::string& message) {
471 ListValue arguments;
472 arguments.Append(Value::CreateStringValue(message));
473 web_ui_->CallJavascriptFunction("alert", arguments);
474 }
475
476 void ExtensionsDOMHandler::HandlePackMessage(const ListValue* args) {
477 std::string extension_path;
478 std::string private_key_path;
479 CHECK(args->GetSize() == 2);
480 CHECK(args->GetString(0, &extension_path));
481 CHECK(args->GetString(1, &private_key_path));
482
483 FilePath root_directory =
484 FilePath::FromWStringHack(UTF8ToWide(extension_path));
485 FilePath key_file = FilePath::FromWStringHack(UTF8ToWide(private_key_path));
486
487 if (root_directory.empty()) {
488 if (extension_path.empty()) {
489 ShowAlert(l10n_util::GetStringUTF8(
490 IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_REQUIRED));
491 } else {
492 ShowAlert(l10n_util::GetStringUTF8(
493 IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_INVALID));
494 }
495
496 return;
497 }
498
499 if (!private_key_path.empty() && key_file.empty()) {
500 ShowAlert(l10n_util::GetStringUTF8(
501 IDS_EXTENSION_PACK_DIALOG_ERROR_KEY_INVALID));
502 return;
503 }
504
505 pack_job_ = new PackExtensionJob(this, root_directory, key_file);
506 pack_job_->Start();
507 }
508
509 void ExtensionsDOMHandler::OnPackSuccess(const FilePath& crx_file,
510 const FilePath& pem_file) {
511 ShowAlert(UTF16ToUTF8(PackExtensionJob::StandardSuccessMessage(crx_file,
512 pem_file)));
513
514 ListValue results;
515 web_ui_->CallJavascriptFunction("hidePackDialog", results);
516 }
517
518 void ExtensionsDOMHandler::OnPackFailure(const std::string& error) {
519 ShowAlert(error);
520 }
521
522 void ExtensionsDOMHandler::HandleAutoUpdateMessage(const ListValue* args) {
523 ExtensionUpdater* updater = extension_service_->updater();
524 if (updater)
525 updater->CheckNow();
526 }
527
528 void ExtensionsDOMHandler::HandleSelectFilePathMessage(const ListValue* args) {
529 std::string select_type;
530 std::string operation;
531 CHECK(args->GetSize() == 2);
532 CHECK(args->GetString(0, &select_type));
533 CHECK(args->GetString(1, &operation));
534
535 SelectFileDialog::Type type = SelectFileDialog::SELECT_FOLDER;
536 SelectFileDialog::FileTypeInfo info;
537 int file_type_index = 0;
538 if (select_type == "file")
539 type = SelectFileDialog::SELECT_OPEN_FILE;
540
541 string16 select_title;
542 if (operation == "load") {
543 select_title = l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY);
544 } else if (operation == "packRoot") {
545 select_title = l10n_util::GetStringUTF16(
546 IDS_EXTENSION_PACK_DIALOG_SELECT_ROOT);
547 } else if (operation == "pem") {
548 select_title = l10n_util::GetStringUTF16(
549 IDS_EXTENSION_PACK_DIALOG_SELECT_KEY);
550 info.extensions.push_back(std::vector<FilePath::StringType>());
551 info.extensions.front().push_back(FILE_PATH_LITERAL("pem"));
552 info.extension_description_overrides.push_back(
553 l10n_util::GetStringUTF16(
554 IDS_EXTENSION_PACK_DIALOG_KEY_FILE_TYPE_DESCRIPTION));
555 info.include_all_files = true;
556 file_type_index = 1;
557 } else {
558 NOTREACHED();
559 return;
560 }
561
562 load_extension_dialog_ = SelectFileDialog::Create(this);
563 load_extension_dialog_->SelectFile(type, select_title, FilePath(), &info,
564 file_type_index, FILE_PATH_LITERAL(""), web_ui_->tab_contents(),
565 web_ui_->tab_contents()->view()->GetTopLevelNativeWindow(), NULL);
566 }
567
568
569 void ExtensionsDOMHandler::FileSelected(const FilePath& path, int index,
570 void* params) {
571 // Add the extensions to the results structure.
572 ListValue results;
573 results.Append(Value::CreateStringValue(path.value()));
574 web_ui_->CallJavascriptFunction("window.handleFilePathSelected", results);
575 }
576
577 void ExtensionsDOMHandler::MultiFilesSelected(
578 const std::vector<FilePath>& files, void* params) {
579 NOTREACHED();
580 }
581
582 void ExtensionsDOMHandler::Observe(int type,
583 const NotificationSource& source,
584 const NotificationDetails& details) {
585 switch (type) {
586 // We listen for notifications that will result in the page being
587 // repopulated with data twice for the same event in certain cases.
588 // For instance, EXTENSION_LOADED & EXTENSION_PROCESS_CREATED because
589 // we don't know about the views for an extension at EXTENSION_LOADED, but
590 // if we only listen to EXTENSION_PROCESS_CREATED, we'll miss extensions
591 // that don't have a process at startup. Similarly, NAV_ENTRY_COMMITTED &
592 // RENDER_VIEW_HOST_CREATED because we want to handle both
593 // the case of navigating from a non-extension page to an extension page in
594 // a TabContents (which will generate NAV_ENTRY_COMMITTED) as well as
595 // extension content being shown in popups and balloons (which will generate
596 // RENDER_VIEW_HOST_CREATED but no NAV_ENTRY_COMMITTED).
597 //
598 // Doing it this way gets everything but causes the page to be rendered
599 // more than we need. It doesn't seem to result in any noticeable flicker.
600 case content::NOTIFICATION_RENDER_VIEW_HOST_DELETED:
601 deleting_rvh_ = Source<RenderViewHost>(source).ptr();
602 MaybeUpdateAfterNotification();
603 break;
604 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED:
605 deleting_rvh_ = Details<BackgroundContents>(details)->render_view_host();
606 MaybeUpdateAfterNotification();
607 break;
608 case chrome::NOTIFICATION_EXTENSION_LOADED:
609 case chrome::NOTIFICATION_EXTENSION_PROCESS_CREATED:
610 case chrome::NOTIFICATION_EXTENSION_UNLOADED:
611 case chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED:
612 case content::NOTIFICATION_RENDER_VIEW_HOST_CREATED:
613 case content::NOTIFICATION_NAV_ENTRY_COMMITTED:
614 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED:
615 case chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED:
616 MaybeUpdateAfterNotification();
617 break;
618 default:
619 NOTREACHED();
620 }
621 }
622
623 const Extension* ExtensionsDOMHandler::GetExtension(const ListValue* args) {
624 std::string extension_id = UTF16ToASCII(ExtractStringValue(args));
625 CHECK(!extension_id.empty());
626 return extension_service_->GetExtensionById(extension_id, true);
627 }
628
629 void ExtensionsDOMHandler::MaybeUpdateAfterNotification() {
630 if (!ignore_notifications_ &&
631 web_ui_->tab_contents() &&
632 web_ui_->tab_contents()->render_view_host()) {
633 HandleRequestExtensionsData(NULL);
634 }
635 deleting_rvh_ = NULL;
636 }
637
638 // Static
639 DictionaryValue* ExtensionsDOMHandler::CreateExtensionDetailValue(
640 ExtensionService* service, const Extension* extension,
641 const std::vector<ExtensionPage>& pages, bool enabled, bool terminated) {
642 DictionaryValue* extension_data = new DictionaryValue();
643 GURL icon =
644 ExtensionIconSource::GetIconURL(extension,
645 Extension::EXTENSION_ICON_MEDIUM,
646 ExtensionIconSet::MATCH_BIGGER,
647 !enabled, NULL);
648 extension_data->SetString("id", extension->id());
649 extension_data->SetString("name", extension->name());
650 extension_data->SetString("description", extension->description());
651 if (extension->location() == Extension::LOAD)
652 extension_data->SetString("path", extension->path().value());
653 extension_data->SetString("version", extension->version()->GetString());
654 extension_data->SetString("icon", icon.spec());
655 extension_data->SetBoolean("isUnpacked",
656 extension->location() == Extension::LOAD);
657 extension_data->SetBoolean("mayDisable",
658 Extension::UserMayDisable(extension->location()));
659 extension_data->SetBoolean("enabled", enabled);
660 extension_data->SetBoolean("terminated", terminated);
661 extension_data->SetBoolean("enabledIncognito",
662 service ? service->IsIncognitoEnabled(extension->id()) : false);
663 extension_data->SetBoolean("wantsFileAccess", extension->wants_file_access());
664 extension_data->SetBoolean("allowFileAccess",
665 service ? service->AllowFileAccess(extension) : false);
666 extension_data->SetBoolean("allow_reload",
667 extension->location() == Extension::LOAD);
668 extension_data->SetBoolean("is_hosted_app", extension->is_hosted_app());
669
670 // Determine the sort order: Extensions loaded through --load-extensions show
671 // up at the top. Disabled extensions show up at the bottom.
672 if (extension->location() == Extension::LOAD)
673 extension_data->SetInteger("order", 1);
674 else
675 extension_data->SetInteger("order", 2);
676
677 if (!extension->options_url().is_empty())
678 extension_data->SetString("options_url", extension->options_url().spec());
679
680 if (service && !service->GetBrowserActionVisibility(extension))
681 extension_data->SetBoolean("enable_show_button", true);
682
683 // Add views
684 ListValue* views = new ListValue;
685 for (std::vector<ExtensionPage>::const_iterator iter = pages.begin();
686 iter != pages.end(); ++iter) {
687 DictionaryValue* view_value = new DictionaryValue;
688 if (iter->url.scheme() == chrome::kExtensionScheme) {
689 // No leading slash.
690 view_value->SetString("path", iter->url.path().substr(1));
691 } else {
692 // For live pages, use the full URL.
693 view_value->SetString("path", iter->url.spec());
694 }
695 view_value->SetInteger("renderViewId", iter->render_view_id);
696 view_value->SetInteger("renderProcessId", iter->render_process_id);
697 view_value->SetBoolean("incognito", iter->incognito);
698 views->Append(view_value);
699 }
700 extension_data->Set("views", views);
701 extension_data->SetBoolean("hasPopupAction",
702 extension->browser_action() || extension->page_action());
703 extension_data->SetString("homepageUrl", extension->GetHomepageURL().spec());
704
705 return extension_data;
706 }
707
708 std::vector<ExtensionPage> ExtensionsDOMHandler::GetActivePagesForExtension(
709 const Extension* extension) {
710 std::vector<ExtensionPage> result;
711
712 // Get the extension process's active views.
713 ExtensionProcessManager* process_manager =
714 extension_service_->profile()->GetExtensionProcessManager();
715 GetActivePagesForExtensionProcess(
716 process_manager->GetExtensionProcess(extension->url()),
717 extension, &result);
718
719 // Repeat for the incognito process, if applicable.
720 if (extension_service_->profile()->HasOffTheRecordProfile() &&
721 extension->incognito_split_mode()) {
722 ExtensionProcessManager* process_manager =
723 extension_service_->profile()->GetOffTheRecordProfile()->
724 GetExtensionProcessManager();
725 GetActivePagesForExtensionProcess(
726 process_manager->GetExtensionProcess(extension->url()),
727 extension, &result);
728 }
729
730 return result;
731 }
732
733 void ExtensionsDOMHandler::GetActivePagesForExtensionProcess(
734 RenderProcessHost* process,
735 const Extension* extension,
736 std::vector<ExtensionPage> *result) {
737 if (!process)
738 return;
739
740 RenderProcessHost::listeners_iterator iter = process->ListenersIterator();
741 for (; !iter.IsAtEnd(); iter.Advance()) {
742 const RenderWidgetHost* widget =
743 static_cast<const RenderWidgetHost*>(iter.GetCurrentValue());
744 DCHECK(widget);
745 if (!widget || !widget->IsRenderView())
746 continue;
747 const RenderViewHost* host = static_cast<const RenderViewHost*>(widget);
748 if (host == deleting_rvh_ ||
749 ViewType::EXTENSION_POPUP == host->delegate()->GetRenderViewType() ||
750 ViewType::EXTENSION_DIALOG == host->delegate()->GetRenderViewType())
751 continue;
752
753 GURL url = host->delegate()->GetURL();
754 if (url.SchemeIs(chrome::kExtensionScheme)) {
755 if (url.host() != extension->id())
756 continue;
757 } else if (!extension->web_extent().MatchesURL(url)) {
758 continue;
759 }
760
761 result->push_back(
762 ExtensionPage(url, process->id(), host->routing_id(),
763 process->browser_context()->IsOffTheRecord()));
764 }
765 }
766
767 ExtensionsDOMHandler::~ExtensionsDOMHandler() {
768 // There may be pending file dialogs, we need to tell them that we've gone
769 // away so they don't try and call back to us.
770 if (load_extension_dialog_.get())
771 load_extension_dialog_->ListenerDestroyed();
772
773 if (pack_job_.get())
774 pack_job_->ClearClient();
775
776 registrar_.RemoveAll();
777 }
778
779 // ExtensionsDOMHandler, public: -----------------------------------------------
780
781 ExtensionsUI::ExtensionsUI(TabContents* contents) : ChromeWebUI(contents) {
782 ExtensionService *extension_service =
783 GetProfile()->GetOriginalProfile()->GetExtensionService();
784
785 ExtensionsDOMHandler* handler = new ExtensionsDOMHandler(extension_service);
786 AddMessageHandler(handler);
787 handler->Attach(this);
788
789 // Set up the chrome://extensions/ source.
790 Profile* profile = Profile::FromBrowserContext(contents->browser_context());
791 profile->GetChromeURLDataManager()->AddDataSource(
792 CreateExtensionsUIHTMLSource());
793 }
794
795 // static
796 RefCountedMemory* ExtensionsUI::GetFaviconResourceBytes() {
797 return ResourceBundle::GetSharedInstance().
798 LoadDataResourceBytes(IDR_PLUGIN);
799 }
800
801 // static
802 void ExtensionsUI::RegisterUserPrefs(PrefService* prefs) {
803 prefs->RegisterBooleanPref(prefs::kExtensionsUIDeveloperMode,
804 false,
805 PrefService::SYNCABLE_PREF);
806 }
OLDNEW
« no previous file with comments | « chrome/browser/extensions/extensions_ui.h ('k') | chrome/browser/prefs/browser_prefs.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698