Replace Webstore link with app info dialog link in chrome://apps
[chromium-blink-merge.git] / chrome / browser / ui / webui / extensions / extension_settings_handler.cc
blobe523d8981017739184c9e22703b1add7ae93c5ad
1 // Copyright (c) 2012 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.
5 #include "chrome/browser/ui/webui/extensions/extension_settings_handler.h"
7 #include "apps/app_load_service.h"
8 #include "apps/saved_files_service.h"
9 #include "base/auto_reset.h"
10 #include "base/base64.h"
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/location.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/metrics/histogram.h"
16 #include "base/prefs/pref_service.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "base/values.h"
21 #include "base/version.h"
22 #include "chrome/browser/background/background_contents.h"
23 #include "chrome/browser/browser_process.h"
24 #include "chrome/browser/chrome_notification_types.h"
25 #include "chrome/browser/devtools/devtools_window.h"
26 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
27 #include "chrome/browser/extensions/component_loader.h"
28 #include "chrome/browser/extensions/crx_installer.h"
29 #include "chrome/browser/extensions/devtools_util.h"
30 #include "chrome/browser/extensions/error_console/error_console.h"
31 #include "chrome/browser/extensions/extension_action_manager.h"
32 #include "chrome/browser/extensions/extension_error_reporter.h"
33 #include "chrome/browser/extensions/extension_management.h"
34 #include "chrome/browser/extensions/extension_service.h"
35 #include "chrome/browser/extensions/extension_tab_util.h"
36 #include "chrome/browser/extensions/extension_ui_util.h"
37 #include "chrome/browser/extensions/extension_util.h"
38 #include "chrome/browser/extensions/install_verifier.h"
39 #include "chrome/browser/extensions/path_util.h"
40 #include "chrome/browser/extensions/shared_module_service.h"
41 #include "chrome/browser/extensions/updater/extension_updater.h"
42 #include "chrome/browser/extensions/webstore_reinstaller.h"
43 #include "chrome/browser/platform_util.h"
44 #include "chrome/browser/prefs/incognito_mode_prefs.h"
45 #include "chrome/browser/profiles/profile.h"
46 #include "chrome/browser/ui/apps/app_info_dialog.h"
47 #include "chrome/browser/ui/browser.h"
48 #include "chrome/browser/ui/browser_finder.h"
49 #include "chrome/browser/ui/browser_window.h"
50 #include "chrome/browser/ui/extensions/app_launch_params.h"
51 #include "chrome/browser/ui/extensions/application_launch.h"
52 #include "chrome/browser/ui/webui/extensions/extension_basic_info.h"
53 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
54 #include "chrome/common/chrome_version_info.h"
55 #include "chrome/common/extensions/features/feature_channel.h"
56 #include "chrome/common/pref_names.h"
57 #include "chrome/common/url_constants.h"
58 #include "chrome/grit/chromium_strings.h"
59 #include "chrome/grit/generated_resources.h"
60 #include "components/google/core/browser/google_util.h"
61 #include "components/pref_registry/pref_registry_syncable.h"
62 #include "content/public/browser/notification_service.h"
63 #include "content/public/browser/notification_source.h"
64 #include "content/public/browser/notification_types.h"
65 #include "content/public/browser/render_process_host.h"
66 #include "content/public/browser/render_view_host.h"
67 #include "content/public/browser/site_instance.h"
68 #include "content/public/browser/web_contents.h"
69 #include "content/public/browser/web_ui.h"
70 #include "content/public/browser/web_ui_data_source.h"
71 #include "extensions/browser/api/device_permissions_manager.h"
72 #include "extensions/browser/app_window/app_window.h"
73 #include "extensions/browser/app_window/app_window_registry.h"
74 #include "extensions/browser/blacklist_state.h"
75 #include "extensions/browser/extension_error.h"
76 #include "extensions/browser/extension_host.h"
77 #include "extensions/browser/extension_registry.h"
78 #include "extensions/browser/extension_system.h"
79 #include "extensions/browser/lazy_background_task_queue.h"
80 #include "extensions/browser/management_policy.h"
81 #include "extensions/browser/pref_names.h"
82 #include "extensions/browser/uninstall_reason.h"
83 #include "extensions/browser/view_type_utils.h"
84 #include "extensions/browser/warning_set.h"
85 #include "extensions/common/constants.h"
86 #include "extensions/common/extension.h"
87 #include "extensions/common/extension_icon_set.h"
88 #include "extensions/common/extension_set.h"
89 #include "extensions/common/extension_urls.h"
90 #include "extensions/common/feature_switch.h"
91 #include "extensions/common/manifest.h"
92 #include "extensions/common/manifest_handlers/background_info.h"
93 #include "extensions/common/manifest_handlers/incognito_info.h"
94 #include "extensions/common/manifest_handlers/options_page_info.h"
95 #include "extensions/common/manifest_url_handlers.h"
96 #include "extensions/common/permissions/permissions_data.h"
97 #include "grit/browser_resources.h"
98 #include "grit/components_strings.h"
99 #include "grit/theme_resources.h"
100 #include "ui/base/l10n/l10n_util.h"
102 using base::DictionaryValue;
103 using base::ListValue;
104 using content::RenderViewHost;
105 using content::WebContents;
107 namespace {
109 const char kAppsDeveloperToolsExtensionId[] =
110 "ohmmkhmmmpcnpikjeljgnaoabkaalbgc";
112 } // namespace
114 namespace extensions {
116 ExtensionPage::ExtensionPage(const GURL& url,
117 int render_process_id,
118 int render_view_id,
119 bool incognito,
120 bool generated_background_page)
121 : url(url),
122 render_process_id(render_process_id),
123 render_view_id(render_view_id),
124 incognito(incognito),
125 generated_background_page(generated_background_page) {
128 // The install prompt is not necessarily modal (e.g. Mac, Linux Unity). This
129 // means that the user can navigate while the dialog is up, causing the dialog
130 // handler to outlive the ExtensionSettingsHandler. That's a problem because the
131 // dialog framework will try to contact us back once the dialog is closed, which
132 // causes a crash. This class is designed to broker the message between the two
133 // objects, while managing its own lifetime so that it can outlive the
134 // ExtensionSettingsHandler and (when doing so) gracefully ignore the message
135 // from the dialog.
136 class BrokerDelegate : public ExtensionInstallPrompt::Delegate {
137 public:
138 explicit BrokerDelegate(
139 const base::WeakPtr<ExtensionSettingsHandler>& delegate)
140 : delegate_(delegate) {}
142 // ExtensionInstallPrompt::Delegate implementation.
143 void InstallUIProceed() override {
144 if (delegate_)
145 delegate_->InstallUIProceed();
146 delete this;
149 void InstallUIAbort(bool user_initiated) override {
150 if (delegate_)
151 delegate_->InstallUIAbort(user_initiated);
152 delete this;
155 void AppInfoDialogClosed() {
156 if (delegate_)
157 delegate_->AppInfoDialogClosed();
158 delete this;
161 private:
162 base::WeakPtr<ExtensionSettingsHandler> delegate_;
164 DISALLOW_COPY_AND_ASSIGN(BrokerDelegate);
167 ///////////////////////////////////////////////////////////////////////////////
169 // ExtensionSettingsHandler
171 ///////////////////////////////////////////////////////////////////////////////
173 ExtensionSettingsHandler::ExtensionSettingsHandler()
174 : extension_service_(NULL),
175 management_policy_(NULL),
176 ignore_notifications_(false),
177 deleting_rvh_(NULL),
178 deleting_rwh_id_(-1),
179 deleting_rph_id_(-1),
180 registered_for_notifications_(false),
181 warning_service_observer_(this),
182 error_console_observer_(this),
183 extension_prefs_observer_(this),
184 extension_registry_observer_(this),
185 extension_management_observer_(this),
186 should_do_verification_check_(false) {
189 ExtensionSettingsHandler::~ExtensionSettingsHandler() {
192 ExtensionSettingsHandler::ExtensionSettingsHandler(ExtensionService* service,
193 ManagementPolicy* policy)
194 : extension_service_(service),
195 management_policy_(policy),
196 ignore_notifications_(false),
197 deleting_rvh_(NULL),
198 deleting_rwh_id_(-1),
199 deleting_rph_id_(-1),
200 registered_for_notifications_(false),
201 warning_service_observer_(this),
202 error_console_observer_(this),
203 extension_prefs_observer_(this),
204 extension_registry_observer_(this),
205 extension_management_observer_(this),
206 should_do_verification_check_(false) {
209 // static
210 void ExtensionSettingsHandler::RegisterProfilePrefs(
211 user_prefs::PrefRegistrySyncable* registry) {
212 registry->RegisterBooleanPref(
213 prefs::kExtensionsUIDeveloperMode,
214 false,
215 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
216 registry->RegisterBooleanPref(
217 prefs::kExtensionsUIDismissedADTPromo,
218 false,
219 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
222 base::DictionaryValue* ExtensionSettingsHandler::CreateExtensionDetailValue(
223 const Extension* extension,
224 const std::vector<ExtensionPage>& pages,
225 const WarningService* warning_service) {
226 // The items which are to be written into app_dict are also described in
227 // chrome/browser/resources/extensions/extension_list.js in @typedef for
228 // ExtensionData. Please update it whenever you add or remove any keys here.
229 base::DictionaryValue* extension_data = new base::DictionaryValue();
230 bool enabled = extension_service_->IsExtensionEnabled(extension->id());
231 GetExtensionBasicInfo(extension, enabled, extension_data);
233 ExtensionPrefs* prefs = ExtensionPrefs::Get(extension_service_->profile());
234 int disable_reasons = prefs->GetDisableReasons(extension->id());
236 bool suspicious_install =
237 (disable_reasons & Extension::DISABLE_NOT_VERIFIED) != 0;
238 extension_data->SetBoolean("suspiciousInstall", suspicious_install);
239 if (suspicious_install)
240 should_do_verification_check_ = true;
242 bool corrupt_install =
243 (disable_reasons & Extension::DISABLE_CORRUPTED) != 0;
244 extension_data->SetBoolean("corruptInstall", corrupt_install);
246 bool update_required_by_policy =
247 (disable_reasons & Extension::DISABLE_UPDATE_REQUIRED_BY_POLICY) != 0;
248 extension_data->SetBoolean("updateRequiredByPolicy",
249 update_required_by_policy);
251 bool managed_install =
252 !management_policy_->UserMayModifySettings(extension, NULL);
253 extension_data->SetBoolean("managedInstall", managed_install);
255 bool recommended_install =
256 !managed_install &&
257 management_policy_->MustRemainInstalled(extension, NULL);
258 extension_data->SetBoolean("recommendedInstall", recommended_install);
260 // Suspicious install should always be mutually exclusive to managed and/or
261 // recommended install.
262 DCHECK(!(managed_install || recommended_install) || !suspicious_install);
264 // |web_ui()| can be null in unit tests.
265 bool installed_by_custodian = web_ui() &&
266 util::IsExtensionSupervised(extension, Profile::FromWebUI(web_ui()));
267 extension_data->SetBoolean("installedByCustodian", installed_by_custodian);
269 GURL icon =
270 ExtensionIconSource::GetIconURL(extension,
271 extension_misc::EXTENSION_ICON_MEDIUM,
272 ExtensionIconSet::MATCH_BIGGER,
273 !enabled, NULL);
274 if (Manifest::IsUnpackedLocation(extension->location())) {
275 extension_data->SetString("path", extension->path().value());
276 extension_data->SetString(
277 "prettifiedPath",
278 extensions::path_util::PrettifyPath(extension->path()).value());
280 extension_data->SetString("icon", icon.spec());
281 extension_data->SetBoolean("isUnpacked",
282 Manifest::IsUnpackedLocation(extension->location()));
283 extension_data->SetBoolean("isFromStore",
284 extension->location() == Manifest::INTERNAL &&
285 ManifestURL::UpdatesFromGallery(extension));
286 ExtensionRegistry* registry =
287 ExtensionRegistry::Get(extension_service_->profile());
288 extension_data->SetBoolean(
289 "terminated",
290 registry->terminated_extensions().Contains(extension->id()));
291 extension_data->SetBoolean("enabledIncognito",
292 util::IsIncognitoEnabled(extension->id(), extension_service_->profile()));
293 extension_data->SetBoolean("incognitoCanBeEnabled",
294 extension->can_be_incognito_enabled());
295 extension_data->SetBoolean("wantsFileAccess", extension->wants_file_access());
296 extension_data->SetBoolean("allowFileAccess",
297 util::AllowFileAccess(extension->id(), extension_service_->profile()));
298 extension_data->SetBoolean("allow_reload",
299 Manifest::IsUnpackedLocation(extension->location()));
300 extension_data->SetBoolean("is_hosted_app", extension->is_hosted_app());
301 extension_data->SetBoolean("is_platform_app", extension->is_platform_app());
302 extension_data->SetBoolean("homepageProvided",
303 ManifestURL::SpecifiedHomepageURL(extension));
304 extension_data->SetBoolean("optionsOpenInTab",
305 OptionsPageInfo::ShouldOpenInTab(extension));
306 extension_data->SetString("optionsPageHref",
307 OptionsPageInfo::GetOptionsPage(extension).spec());
308 extension_data->SetBoolean("enableExtensionInfoDialog",
309 CanShowAppInfoDialog());
311 // Add dependent extensions.
312 base::ListValue* dependents_list = new base::ListValue;
313 if (extension->is_shared_module()) {
314 scoped_ptr<ExtensionSet> dependent_extensions =
315 extension_service_->shared_module_service()->GetDependentExtensions(
316 extension);
317 for (ExtensionSet::const_iterator i = dependent_extensions->begin();
318 i != dependent_extensions->end();
319 i++) {
320 base::DictionaryValue* dependent_entry = new base::DictionaryValue;
321 dependent_entry->SetString("id", (*i)->id());
322 dependent_entry->SetString("name", (*i)->name());
323 dependents_list->Append(dependent_entry);
326 extension_data->Set("dependentExtensions", dependents_list);
328 // We show the "all urls" checkbox if:
329 // - The feature is enabled for the given extension, or has been set in the
330 // past.
331 // - The extension has access to enough urls that we can't just let it run
332 // on those specified in the permissions.
333 content::BrowserContext* context = extension_service_->GetBrowserContext();
334 bool show_all_urls =
335 (FeatureSwitch::scripts_require_action()->IsEnabled() &&
336 PermissionsData::ScriptsMayRequireActionForExtension(
337 extension,
338 extension->permissions_data()->active_permissions().get())) ||
339 extension->permissions_data()->HasWithheldImpliedAllHosts() ||
340 util::HasSetAllowedScriptingOnAllUrls(extension->id(), context);
341 extension_data->SetBoolean("showAllUrls", show_all_urls);
342 extension_data->SetBoolean(
343 "allowAllUrls",
344 util::AllowedScriptingOnAllUrls(extension->id(), context));
346 base::string16 location_text;
347 if (extension->location() == Manifest::INTERNAL &&
348 !ManifestURL::UpdatesFromGallery(extension)) {
349 location_text = l10n_util::GetStringUTF16(
350 IDS_OPTIONS_INSTALL_LOCATION_UNKNOWN);
351 } else if (extension->location() == Manifest::EXTERNAL_REGISTRY) {
352 location_text = l10n_util::GetStringUTF16(
353 IDS_OPTIONS_INSTALL_LOCATION_3RD_PARTY);
354 } else if (extension->is_shared_module()) {
355 location_text = l10n_util::GetStringUTF16(
356 IDS_OPTIONS_INSTALL_LOCATION_SHARED_MODULE);
358 extension_data->SetString("locationText", location_text);
360 base::string16 policy_text;
361 if (Manifest::IsPolicyLocation(extension->location())) {
362 policy_text = l10n_util::GetStringUTF16(
363 IDS_OPTIONS_INSTALL_LOCATION_ENTERPRISE);
365 extension_data->SetString("policyText", policy_text);
367 base::string16 blacklist_text;
368 switch (prefs->GetExtensionBlacklistState(extension->id())) {
369 case BLACKLISTED_SECURITY_VULNERABILITY:
370 blacklist_text = l10n_util::GetStringUTF16(
371 IDS_OPTIONS_BLACKLISTED_SECURITY_VULNERABILITY);
372 break;
374 case BLACKLISTED_CWS_POLICY_VIOLATION:
375 blacklist_text = l10n_util::GetStringUTF16(
376 IDS_OPTIONS_BLACKLISTED_CWS_POLICY_VIOLATION);
377 break;
379 case BLACKLISTED_POTENTIALLY_UNWANTED:
380 blacklist_text = l10n_util::GetStringUTF16(
381 IDS_OPTIONS_BLACKLISTED_POTENTIALLY_UNWANTED);
382 break;
384 default:
385 break;
387 extension_data->SetString("blacklistText", blacklist_text);
389 // Force unpacked extensions to show at the top.
390 if (Manifest::IsUnpackedLocation(extension->location()))
391 extension_data->SetInteger("order", 1);
392 else
393 extension_data->SetInteger("order", 2);
395 // Don't show the "show button" for the browser action if the toolbar
396 // redesign is enabled, because "hidden" buttons are now just hidden in the
397 // wrench menu.
398 if (!ExtensionActionAPI::GetBrowserActionVisibility(prefs, extension->id()) &&
399 !FeatureSwitch::extension_action_redesign()->IsEnabled()) {
400 extension_data->SetBoolean("enable_show_button", true);
403 // Add views
404 base::ListValue* views = new base::ListValue;
405 for (std::vector<ExtensionPage>::const_iterator iter = pages.begin();
406 iter != pages.end(); ++iter) {
407 base::DictionaryValue* view_value = new base::DictionaryValue;
408 if (iter->url.scheme() == kExtensionScheme) {
409 // No leading slash.
410 view_value->SetString("path", iter->url.path().substr(1));
411 } else {
412 // For live pages, use the full URL.
413 view_value->SetString("path", iter->url.spec());
415 view_value->SetInteger("renderViewId", iter->render_view_id);
416 view_value->SetInteger("renderProcessId", iter->render_process_id);
417 view_value->SetBoolean("incognito", iter->incognito);
418 view_value->SetBoolean("generatedBackgroundPage",
419 iter->generated_background_page);
420 views->Append(view_value);
422 extension_data->Set("views", views);
423 ExtensionActionManager* extension_action_manager =
424 ExtensionActionManager::Get(extension_service_->profile());
425 extension_data->SetBoolean(
426 "hasPopupAction",
427 extension_action_manager->GetBrowserAction(*extension) ||
428 extension_action_manager->GetPageAction(*extension));
430 // Add warnings.
431 if (warning_service) {
432 std::vector<std::string> warnings =
433 warning_service->GetWarningMessagesForExtension(extension->id());
435 if (!warnings.empty()) {
436 base::ListValue* warnings_list = new base::ListValue;
437 for (std::vector<std::string>::const_iterator iter = warnings.begin();
438 iter != warnings.end(); ++iter) {
439 warnings_list->Append(new base::StringValue(*iter));
441 extension_data->Set("warnings", warnings_list);
445 // If the ErrorConsole is enabled and the extension is unpacked, use the more
446 // detailed errors from the ErrorConsole. Otherwise, use the install warnings
447 // (using both is redundant).
448 ErrorConsole* error_console =
449 ErrorConsole::Get(extension_service_->profile());
450 bool error_console_is_enabled =
451 error_console->IsEnabledForChromeExtensionsPage();
452 extension_data->SetBoolean("wantsErrorCollection", error_console_is_enabled);
453 if (error_console_is_enabled) {
454 extension_data->SetBoolean("errorCollectionEnabled",
455 error_console->IsReportingEnabledForExtension(
456 extension->id()));
457 const ErrorList& errors =
458 error_console->GetErrorsForExtension(extension->id());
459 if (!errors.empty()) {
460 scoped_ptr<base::ListValue> manifest_errors(new base::ListValue);
461 scoped_ptr<base::ListValue> runtime_errors(new base::ListValue);
462 for (ErrorList::const_iterator iter = errors.begin();
463 iter != errors.end(); ++iter) {
464 if ((*iter)->type() == ExtensionError::MANIFEST_ERROR) {
465 manifest_errors->Append((*iter)->ToValue().release());
466 } else { // Handle runtime error.
467 const RuntimeError* error = static_cast<const RuntimeError*>(*iter);
468 scoped_ptr<base::DictionaryValue> value = error->ToValue();
469 bool can_inspect =
470 !(deleting_rwh_id_ == error->render_view_id() &&
471 deleting_rph_id_ == error->render_process_id()) &&
472 RenderViewHost::FromID(error->render_process_id(),
473 error->render_view_id()) != NULL;
474 value->SetBoolean("canInspect", can_inspect);
475 runtime_errors->Append(value.release());
478 if (!manifest_errors->empty())
479 extension_data->Set("manifestErrors", manifest_errors.release());
480 if (!runtime_errors->empty())
481 extension_data->Set("runtimeErrors", runtime_errors.release());
483 } else if (Manifest::IsUnpackedLocation(extension->location())) {
484 const std::vector<InstallWarning>& install_warnings =
485 extension->install_warnings();
486 if (!install_warnings.empty()) {
487 scoped_ptr<base::ListValue> list(new base::ListValue());
488 for (std::vector<InstallWarning>::const_iterator it =
489 install_warnings.begin(); it != install_warnings.end(); ++it) {
490 base::DictionaryValue* item = new base::DictionaryValue();
491 item->SetString("message", it->message);
492 list->Append(item);
494 extension_data->Set("installWarnings", list.release());
498 return extension_data;
501 void ExtensionSettingsHandler::GetLocalizedValues(
502 content::WebUIDataSource* source) {
503 source->AddString("extensionSettings",
504 l10n_util::GetStringUTF16(IDS_MANAGE_EXTENSIONS_SETTING_WINDOWS_TITLE));
506 source->AddString("extensionSettingsDeveloperMode",
507 l10n_util::GetStringUTF16(IDS_EXTENSIONS_DEVELOPER_MODE_LINK));
508 source->AddString("extensionSettingsNoExtensions",
509 l10n_util::GetStringUTF16(IDS_EXTENSIONS_NONE_INSTALLED));
510 source->AddString(
511 "extensionSettingsSuggestGallery",
512 l10n_util::GetStringFUTF16(
513 IDS_EXTENSIONS_NONE_INSTALLED_SUGGEST_GALLERY,
514 base::ASCIIToUTF16(
515 google_util::AppendGoogleLocaleParam(
516 GURL(extension_urls::GetWebstoreExtensionsCategoryURL()),
517 g_browser_process->GetApplicationLocale()).spec())));
518 source->AddString("extensionSettingsGetMoreExtensions",
519 l10n_util::GetStringUTF16(IDS_GET_MORE_EXTENSIONS));
520 source->AddString(
521 "extensionSettingsGetMoreExtensionsUrl",
522 base::ASCIIToUTF16(
523 google_util::AppendGoogleLocaleParam(
524 GURL(extension_urls::GetWebstoreExtensionsCategoryURL()),
525 g_browser_process->GetApplicationLocale()).spec()));
526 source->AddString("extensionSettingsExtensionId",
527 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ID));
528 source->AddString("extensionSettingsExtensionPath",
529 l10n_util::GetStringUTF16(IDS_EXTENSIONS_PATH));
530 source->AddString("extensionSettingsInspectViews",
531 l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSPECT_VIEWS));
532 source->AddString("extensionSettingsInstallWarnings",
533 l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSTALL_WARNINGS));
534 source->AddString("viewIncognito",
535 l10n_util::GetStringUTF16(IDS_EXTENSIONS_VIEW_INCOGNITO));
536 source->AddString("viewInactive",
537 l10n_util::GetStringUTF16(IDS_EXTENSIONS_VIEW_INACTIVE));
538 source->AddString("backgroundPage",
539 l10n_util::GetStringUTF16(IDS_EXTENSIONS_BACKGROUND_PAGE));
540 source->AddString("extensionSettingsEnable",
541 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLE));
542 source->AddString("extensionSettingsEnabled",
543 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLED));
544 source->AddString("extensionSettingsRemove",
545 l10n_util::GetStringUTF16(IDS_EXTENSIONS_REMOVE));
546 source->AddString("extensionSettingsEnableIncognito",
547 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLE_INCOGNITO));
548 source->AddString("extensionSettingsEnableErrorCollection",
549 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLE_ERROR_COLLECTION));
550 source->AddString("extensionSettingsAllowFileAccess",
551 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ALLOW_FILE_ACCESS));
552 source->AddString("extensionSettingsAllowOnAllUrls",
553 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ALLOW_ON_ALL_URLS));
554 source->AddString("extensionSettingsIncognitoWarning",
555 l10n_util::GetStringUTF16(IDS_EXTENSIONS_INCOGNITO_WARNING));
556 source->AddString("extensionSettingsReloadTerminated",
557 l10n_util::GetStringUTF16(IDS_EXTENSIONS_RELOAD_TERMINATED));
558 source->AddString("extensionSettingsRepairCorrupted",
559 l10n_util::GetStringUTF16(IDS_EXTENSIONS_REPAIR_CORRUPTED));
560 source->AddString("extensionSettingsLaunch",
561 l10n_util::GetStringUTF16(IDS_EXTENSIONS_LAUNCH));
562 source->AddString("extensionSettingsReloadUnpacked",
563 l10n_util::GetStringUTF16(IDS_EXTENSIONS_RELOAD_UNPACKED));
564 source->AddString("extensionSettingsOptions",
565 l10n_util::GetStringUTF16(IDS_EXTENSIONS_OPTIONS_LINK));
566 if (CanShowAppInfoDialog()) {
567 source->AddString("extensionSettingsPermissions",
568 l10n_util::GetStringUTF16(IDS_EXTENSIONS_INFO_LINK));
569 } else {
570 source->AddString(
571 "extensionSettingsPermissions",
572 l10n_util::GetStringUTF16(IDS_EXTENSIONS_PERMISSIONS_LINK));
574 source->AddString("extensionSettingsVisitWebsite",
575 l10n_util::GetStringUTF16(IDS_EXTENSIONS_VISIT_WEBSITE));
576 source->AddString("extensionSettingsVisitWebStore",
577 l10n_util::GetStringUTF16(IDS_EXTENSIONS_VISIT_WEBSTORE));
578 source->AddString("extensionSettingsPolicyControlled",
579 l10n_util::GetStringUTF16(IDS_EXTENSIONS_POLICY_CONTROLLED));
580 source->AddString("extensionSettingsPolicyRecommeneded",
581 l10n_util::GetStringUTF16(IDS_EXTENSIONS_POLICY_RECOMMENDED));
582 source->AddString("extensionSettingsDependentExtensions",
583 l10n_util::GetStringUTF16(IDS_EXTENSIONS_DEPENDENT_EXTENSIONS));
584 source->AddString("extensionSettingsSupervisedUser",
585 l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOCKED_SUPERVISED_USER));
586 source->AddString("extensionSettingsCorruptInstall",
587 l10n_util::GetStringUTF16(
588 IDS_EXTENSIONS_CORRUPTED_EXTENSION));
589 source->AddString("extensionSettingsSuspiciousInstall",
590 l10n_util::GetStringFUTF16(
591 IDS_EXTENSIONS_ADDED_WITHOUT_KNOWLEDGE,
592 l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE)));
593 source->AddString("extensionSettingsLearnMore",
594 l10n_util::GetStringUTF16(IDS_LEARN_MORE));
595 source->AddString("extensionSettingsSuspiciousInstallHelpUrl",
596 base::ASCIIToUTF16(
597 google_util::AppendGoogleLocaleParam(
598 GURL(chrome::kRemoveNonCWSExtensionURL),
599 g_browser_process->GetApplicationLocale()).spec()));
600 source->AddString("extensionSettingsShowButton",
601 l10n_util::GetStringUTF16(IDS_EXTENSIONS_SHOW_BUTTON));
602 source->AddString("extensionSettingsLoadUnpackedButton",
603 l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_UNPACKED_BUTTON));
604 source->AddString("extensionSettingsPackButton",
605 l10n_util::GetStringUTF16(IDS_EXTENSIONS_PACK_BUTTON));
606 source->AddString("extensionSettingsCommandsLink",
607 l10n_util::GetStringUTF16(IDS_EXTENSIONS_COMMANDS_CONFIGURE));
608 source->AddString("extensionSettingsUpdateButton",
609 l10n_util::GetStringUTF16(IDS_EXTENSIONS_UPDATE_BUTTON));
610 source->AddString(
611 "extensionSettingsAppsDevToolsPromoHTML",
612 l10n_util::GetStringFUTF16(
613 IDS_EXTENSIONS_APPS_DEV_TOOLS_PROMO_HTML,
614 base::ASCIIToUTF16(
615 google_util::AppendGoogleLocaleParam(
616 GURL(extension_urls::GetWebstoreItemDetailURLPrefix() +
617 kAppsDeveloperToolsExtensionId),
618 g_browser_process->GetApplicationLocale()).spec())));
619 source->AddString(
620 "extensionSettingsAppDevToolsPromoClose",
621 l10n_util::GetStringUTF16(IDS_CLOSE));
622 source->AddString("extensionSettingsCrashMessage",
623 l10n_util::GetStringUTF16(IDS_EXTENSIONS_CRASHED_EXTENSION));
624 source->AddString("extensionSettingsInDevelopment",
625 l10n_util::GetStringUTF16(IDS_EXTENSIONS_IN_DEVELOPMENT));
626 source->AddString("extensionSettingsWarningsTitle",
627 l10n_util::GetStringUTF16(IDS_EXTENSION_WARNINGS_TITLE));
628 source->AddString("extensionSettingsShowDetails",
629 l10n_util::GetStringUTF16(IDS_EXTENSIONS_SHOW_DETAILS));
630 source->AddString("extensionSettingsHideDetails",
631 l10n_util::GetStringUTF16(IDS_EXTENSIONS_HIDE_DETAILS));
632 source->AddString("extensionSettingsUpdateRequiredBePolicy",
633 l10n_util::GetStringUTF16(
634 IDS_EXTENSIONS_DISABLED_UPDATE_REQUIRED_BY_POLICY));
636 // TODO(estade): comb through the above strings to find ones no longer used in
637 // uber extensions.
638 source->AddString("extensionUninstall",
639 l10n_util::GetStringUTF16(IDS_EXTENSIONS_UNINSTALL));
642 void ExtensionSettingsHandler::RenderViewDeleted(
643 RenderViewHost* render_view_host) {
644 deleting_rvh_ = render_view_host;
645 Profile* source_profile = Profile::FromBrowserContext(
646 render_view_host->GetSiteInstance()->GetBrowserContext());
647 if (!Profile::FromWebUI(web_ui())->IsSameProfile(source_profile))
648 return;
649 MaybeUpdateAfterNotification();
652 void ExtensionSettingsHandler::DidStartNavigationToPendingEntry(
653 const GURL& url,
654 content::NavigationController::ReloadType reload_type) {
655 if (reload_type != content::NavigationController::NO_RELOAD)
656 ReloadUnpackedExtensions();
659 void ExtensionSettingsHandler::RegisterMessages() {
660 // Don't override an |extension_service_| or |management_policy_| injected
661 // for testing.
662 if (!extension_service_) {
663 Profile* profile = Profile::FromWebUI(web_ui())->GetOriginalProfile();
664 extension_service_ =
665 extensions::ExtensionSystem::Get(profile)->extension_service();
667 if (!management_policy_) {
668 management_policy_ = ExtensionSystem::Get(
669 extension_service_->profile())->management_policy();
672 web_ui()->RegisterMessageCallback("extensionSettingsRequestExtensionsData",
673 base::Bind(&ExtensionSettingsHandler::HandleRequestExtensionsData,
674 AsWeakPtr()));
675 web_ui()->RegisterMessageCallback("extensionSettingsToggleDeveloperMode",
676 base::Bind(&ExtensionSettingsHandler::HandleToggleDeveloperMode,
677 AsWeakPtr()));
678 web_ui()->RegisterMessageCallback("extensionSettingsInspect",
679 base::Bind(&ExtensionSettingsHandler::HandleInspectMessage,
680 AsWeakPtr()));
681 web_ui()->RegisterMessageCallback("extensionSettingsLaunch",
682 base::Bind(&ExtensionSettingsHandler::HandleLaunchMessage,
683 AsWeakPtr()));
684 web_ui()->RegisterMessageCallback("extensionSettingsReload",
685 base::Bind(&ExtensionSettingsHandler::HandleReloadMessage,
686 AsWeakPtr()));
687 web_ui()->RegisterMessageCallback("extensionSettingsRepair",
688 base::Bind(&ExtensionSettingsHandler::HandleRepairMessage,
689 AsWeakPtr()));
690 web_ui()->RegisterMessageCallback("extensionSettingsEnableIncognito",
691 base::Bind(&ExtensionSettingsHandler::HandleEnableIncognitoMessage,
692 AsWeakPtr()));
693 web_ui()->RegisterMessageCallback("extensionSettingsEnableErrorCollection",
694 base::Bind(&ExtensionSettingsHandler::HandleEnableErrorCollectionMessage,
695 AsWeakPtr()));
696 web_ui()->RegisterMessageCallback("extensionSettingsAllowFileAccess",
697 base::Bind(&ExtensionSettingsHandler::HandleAllowFileAccessMessage,
698 AsWeakPtr()));
699 web_ui()->RegisterMessageCallback("extensionSettingsAllowOnAllUrls",
700 base::Bind(&ExtensionSettingsHandler::HandleAllowOnAllUrlsMessage,
701 AsWeakPtr()));
702 web_ui()->RegisterMessageCallback("extensionSettingsUninstall",
703 base::Bind(&ExtensionSettingsHandler::HandleUninstallMessage,
704 AsWeakPtr()));
705 web_ui()->RegisterMessageCallback("extensionSettingsOptions",
706 base::Bind(&ExtensionSettingsHandler::HandleOptionsMessage,
707 AsWeakPtr()));
708 web_ui()->RegisterMessageCallback("extensionSettingsPermissions",
709 base::Bind(&ExtensionSettingsHandler::HandlePermissionsMessage,
710 AsWeakPtr()));
711 web_ui()->RegisterMessageCallback("extensionSettingsShowButton",
712 base::Bind(&ExtensionSettingsHandler::HandleShowButtonMessage,
713 AsWeakPtr()));
714 web_ui()->RegisterMessageCallback("extensionSettingsAutoupdate",
715 base::Bind(&ExtensionSettingsHandler::HandleAutoUpdateMessage,
716 AsWeakPtr()));
717 web_ui()->RegisterMessageCallback("extensionSettingsDismissADTPromo",
718 base::Bind(&ExtensionSettingsHandler::HandleDismissADTPromoMessage,
719 AsWeakPtr()));
720 web_ui()->RegisterMessageCallback("extensionSettingsShowPath",
721 base::Bind(&ExtensionSettingsHandler::HandleShowPath,
722 AsWeakPtr()));
725 void ExtensionSettingsHandler::OnErrorAdded(const ExtensionError* error) {
726 MaybeUpdateAfterNotification();
729 void ExtensionSettingsHandler::Observe(
730 int type,
731 const content::NotificationSource& source,
732 const content::NotificationDetails& details) {
733 Profile* profile = Profile::FromWebUI(web_ui());
734 Profile* source_profile = NULL;
735 switch (type) {
736 // We listen for notifications that will result in the page being
737 // repopulated with data twice for the same event in certain cases.
738 // For instance, EXTENSION_LOADED & EXTENSION_HOST_CREATED because
739 // we don't know about the views for an extension at EXTENSION_LOADED, but
740 // if we only listen to EXTENSION_HOST_CREATED, we'll miss extensions
741 // that don't have a process at startup.
743 // Doing it this way gets everything but causes the page to be rendered
744 // more than we need. It doesn't seem to result in any noticeable flicker.
745 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED:
746 deleting_rvh_ = content::Details<BackgroundContents>(details)->
747 web_contents()->GetRenderViewHost();
748 // Fall through.
749 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED:
750 case extensions::NOTIFICATION_EXTENSION_HOST_CREATED:
751 source_profile = content::Source<Profile>(source).ptr();
752 if (!profile->IsSameProfile(source_profile))
753 return;
754 MaybeUpdateAfterNotification();
755 break;
756 case content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED: {
757 content::RenderWidgetHost* rwh =
758 content::Source<content::RenderWidgetHost>(source).ptr();
759 deleting_rwh_id_ = rwh->GetRoutingID();
760 deleting_rph_id_ = rwh->GetProcess()->GetID();
761 MaybeUpdateAfterNotification();
762 break;
764 case extensions::NOTIFICATION_EXTENSION_UPDATE_DISABLED:
765 case extensions::NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED:
766 MaybeUpdateAfterNotification();
767 break;
768 case extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED:
769 // This notification is sent when the extension host destruction begins,
770 // not when it finishes. We use PostTask to delay the update until after
771 // the destruction finishes.
772 base::MessageLoop::current()->PostTask(
773 FROM_HERE,
774 base::Bind(&ExtensionSettingsHandler::MaybeUpdateAfterNotification,
775 AsWeakPtr()));
776 break;
777 default:
778 NOTREACHED();
782 void ExtensionSettingsHandler::OnExtensionLoaded(
783 content::BrowserContext* browser_context,
784 const Extension* extension) {
785 MaybeUpdateAfterNotification();
788 void ExtensionSettingsHandler::OnExtensionUnloaded(
789 content::BrowserContext* browser_context,
790 const Extension* extension,
791 UnloadedExtensionInfo::Reason reason) {
792 MaybeUpdateAfterNotification();
795 void ExtensionSettingsHandler::OnExtensionUninstalled(
796 content::BrowserContext* browser_context,
797 const Extension* extension,
798 extensions::UninstallReason reason) {
799 MaybeUpdateAfterNotification();
802 void ExtensionSettingsHandler::OnExtensionDisableReasonsChanged(
803 const std::string& extension_id, int disable_reasons) {
804 MaybeUpdateAfterNotification();
807 void ExtensionSettingsHandler::OnExtensionManagementSettingsChanged() {
808 MaybeUpdateAfterNotification();
811 void ExtensionSettingsHandler::ExtensionUninstallAccepted() {
812 DCHECK(!extension_id_prompting_.empty());
814 bool was_terminated = false;
816 // The extension can be uninstalled in another window while the UI was
817 // showing. Do nothing in that case.
818 const Extension* extension =
819 extension_service_->GetExtensionById(extension_id_prompting_, true);
820 if (!extension) {
821 extension =
822 ExtensionRegistry::Get(Profile::FromWebUI(web_ui()))->GetExtensionById(
823 extension_id_prompting_, ExtensionRegistry::TERMINATED);
824 was_terminated = true;
826 if (!extension)
827 return;
829 extension_service_->UninstallExtension(
830 extension_id_prompting_,
831 extensions::UNINSTALL_REASON_USER_INITIATED,
832 base::Bind(&base::DoNothing),
833 NULL); // Error.
834 extension_id_prompting_ = "";
836 // There will be no EXTENSION_UNLOADED notification for terminated
837 // extensions as they were already unloaded.
838 if (was_terminated)
839 HandleRequestExtensionsData(NULL);
842 void ExtensionSettingsHandler::ExtensionUninstallCanceled() {
843 extension_id_prompting_ = "";
846 void ExtensionSettingsHandler::ExtensionWarningsChanged() {
847 MaybeUpdateAfterNotification();
850 // This is called when the user clicks "Revoke File/Device Access."
851 void ExtensionSettingsHandler::InstallUIProceed() {
852 Profile* profile = Profile::FromWebUI(web_ui());
853 extensions::DevicePermissionsManager::Get(profile)
854 ->Clear(extension_id_prompting_);
855 apps::SavedFilesService::Get(profile)->ClearQueue(
856 extension_service_->GetExtensionById(extension_id_prompting_, true));
857 apps::AppLoadService::Get(profile)
858 ->RestartApplicationIfRunning(extension_id_prompting_);
859 extension_id_prompting_.clear();
862 void ExtensionSettingsHandler::InstallUIAbort(bool user_initiated) {
863 extension_id_prompting_.clear();
866 void ExtensionSettingsHandler::AppInfoDialogClosed() {
867 extension_id_prompting_.clear();
870 void ExtensionSettingsHandler::ReloadUnpackedExtensions() {
871 ExtensionRegistry* registry =
872 ExtensionRegistry::Get(extension_service_->profile());
873 std::vector<const Extension*> unpacked_extensions;
874 for (const scoped_refptr<const extensions::Extension>& extension :
875 registry->enabled_extensions()) {
876 if (Manifest::IsUnpackedLocation(extension->location()))
877 unpacked_extensions.push_back(extension.get());
880 for (std::vector<const Extension*>::iterator iter =
881 unpacked_extensions.begin(); iter != unpacked_extensions.end(); ++iter) {
882 extension_service_->ReloadExtensionWithQuietFailure((*iter)->id());
886 void ExtensionSettingsHandler::HandleRequestExtensionsData(
887 const base::ListValue* args) {
888 // The items which are to be written into results are also described in
889 // chrome/browser/resources/extensions/extensions.js in @typedef for
890 // ExtensionDataResponse. Please update it whenever you add or remove any keys
891 // here.
892 base::DictionaryValue results;
894 Profile* profile = Profile::FromWebUI(web_ui());
896 // Add the extensions to the results structure.
897 base::ListValue* extensions_list = new base::ListValue();
899 WarningService* warnings = WarningService::Get(profile);
901 ExtensionRegistry* registry = ExtensionRegistry::Get(profile);
902 const ExtensionSet& enabled_set = registry->enabled_extensions();
903 for (ExtensionSet::const_iterator extension = enabled_set.begin();
904 extension != enabled_set.end(); ++extension) {
905 if (ui_util::ShouldDisplayInExtensionSettings(extension->get(), profile)) {
906 extensions_list->Append(CreateExtensionDetailValue(
907 extension->get(),
908 GetInspectablePagesForExtension(extension->get(), true),
909 warnings));
912 const ExtensionSet& disabled_set = registry->disabled_extensions();
913 for (ExtensionSet::const_iterator extension = disabled_set.begin();
914 extension != disabled_set.end(); ++extension) {
915 if (ui_util::ShouldDisplayInExtensionSettings(extension->get(), profile)) {
916 extensions_list->Append(CreateExtensionDetailValue(
917 extension->get(),
918 GetInspectablePagesForExtension(extension->get(), false),
919 warnings));
922 const ExtensionSet& terminated_set = registry->terminated_extensions();
923 std::vector<ExtensionPage> empty_pages;
924 for (ExtensionSet::const_iterator extension = terminated_set.begin();
925 extension != terminated_set.end(); ++extension) {
926 if (ui_util::ShouldDisplayInExtensionSettings(extension->get(), profile)) {
927 extensions_list->Append(CreateExtensionDetailValue(
928 extension->get(),
929 empty_pages, // Terminated process has no active pages.
930 warnings));
933 results.Set("extensions", extensions_list);
935 bool is_supervised = profile->IsSupervised();
936 bool incognito_available =
937 IncognitoModePrefs::GetAvailability(profile->GetPrefs()) !=
938 IncognitoModePrefs::DISABLED;
939 bool developer_mode =
940 !is_supervised &&
941 profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode);
942 results.SetBoolean("profileIsSupervised", is_supervised);
943 results.SetBoolean("incognitoAvailable", incognito_available);
944 results.SetBoolean("developerMode", developer_mode);
946 // Promote the Chrome Apps & Extensions Developer Tools if they are not
947 // installed and the user has not previously dismissed the warning.
948 bool promote_apps_dev_tools = false;
949 if (!ExtensionRegistry::Get(Profile::FromWebUI(web_ui()))->
950 GetExtensionById(kAppsDeveloperToolsExtensionId,
951 ExtensionRegistry::EVERYTHING) &&
952 !profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDismissedADTPromo)) {
953 promote_apps_dev_tools = true;
955 results.SetBoolean("promoteAppsDevTools", promote_apps_dev_tools);
957 const bool load_unpacked_disabled =
958 ExtensionManagementFactory::GetForBrowserContext(profile)
959 ->BlacklistedByDefault();
960 results.SetBoolean("loadUnpackedDisabled", load_unpacked_disabled);
962 web_ui()->CallJavascriptFunction(
963 "extensions.ExtensionSettings.returnExtensionsData", results);
965 MaybeRegisterForNotifications();
966 UMA_HISTOGRAM_BOOLEAN("ExtensionSettings.ShouldDoVerificationCheck",
967 should_do_verification_check_);
968 if (should_do_verification_check_) {
969 should_do_verification_check_ = false;
970 ExtensionSystem::Get(Profile::FromWebUI(web_ui()))
971 ->install_verifier()
972 ->VerifyAllExtensions();
976 void ExtensionSettingsHandler::HandleToggleDeveloperMode(
977 const base::ListValue* args) {
978 Profile* profile = Profile::FromWebUI(web_ui());
979 if (profile->IsSupervised())
980 return;
982 bool developer_mode_on;
983 CHECK(args->GetBoolean(0, &developer_mode_on));
984 profile->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode,
985 developer_mode_on);
988 void ExtensionSettingsHandler::HandleInspectMessage(
989 const base::ListValue* args) {
990 std::string extension_id;
991 std::string render_process_id_str;
992 std::string render_view_id_str;
993 int render_process_id;
994 int render_view_id;
995 bool incognito;
996 CHECK_EQ(4U, args->GetSize());
997 CHECK(args->GetString(0, &extension_id));
998 CHECK(args->GetString(1, &render_process_id_str));
999 CHECK(args->GetString(2, &render_view_id_str));
1000 CHECK(args->GetBoolean(3, &incognito));
1001 CHECK(base::StringToInt(render_process_id_str, &render_process_id));
1002 CHECK(base::StringToInt(render_view_id_str, &render_view_id));
1004 if (render_process_id == -1) {
1005 // This message is for a lazy background page. Start the page if necessary.
1006 Profile* profile = Profile::FromWebUI(web_ui());
1007 const Extension* extension =
1008 ExtensionRegistry::Get(profile)->enabled_extensions().GetByID(
1009 extension_id);
1010 DCHECK(extension);
1011 if (incognito)
1012 profile = profile->GetOffTheRecordProfile();
1013 devtools_util::InspectBackgroundPage(extension, profile);
1014 return;
1017 RenderViewHost* host = RenderViewHost::FromID(render_process_id,
1018 render_view_id);
1019 if (!host || !WebContents::FromRenderViewHost(host)) {
1020 // This can happen if the host has gone away since the page was displayed.
1021 return;
1024 DevToolsWindow::OpenDevToolsWindow(WebContents::FromRenderViewHost(host));
1027 void ExtensionSettingsHandler::HandleLaunchMessage(
1028 const base::ListValue* args) {
1029 CHECK_EQ(1U, args->GetSize());
1030 std::string extension_id;
1031 CHECK(args->GetString(0, &extension_id));
1032 const Extension* extension =
1033 extension_service_->GetExtensionById(extension_id, false);
1034 OpenApplication(AppLaunchParams(extension_service_->profile(), extension,
1035 extensions::LAUNCH_CONTAINER_WINDOW,
1036 NEW_WINDOW,
1037 extensions::SOURCE_EXTENSIONS_PAGE));
1040 void ExtensionSettingsHandler::HandleReloadMessage(
1041 const base::ListValue* args) {
1042 std::string extension_id = base::UTF16ToUTF8(ExtractStringValue(args));
1043 CHECK(!extension_id.empty());
1044 extension_service_->ReloadExtensionWithQuietFailure(extension_id);
1047 void ExtensionSettingsHandler::HandleRepairMessage(
1048 const base::ListValue* args) {
1049 std::string extension_id = base::UTF16ToUTF8(ExtractStringValue(args));
1050 CHECK(!extension_id.empty());
1051 scoped_refptr<WebstoreReinstaller> reinstaller(new WebstoreReinstaller(
1052 web_contents(),
1053 extension_id,
1054 base::Bind(&ExtensionSettingsHandler::OnReinstallComplete,
1055 AsWeakPtr())));
1056 reinstaller->BeginReinstall();
1059 void ExtensionSettingsHandler::HandleEnableIncognitoMessage(
1060 const base::ListValue* args) {
1061 CHECK_EQ(2U, args->GetSize());
1062 std::string extension_id, enable_str;
1063 CHECK(args->GetString(0, &extension_id));
1064 CHECK(args->GetString(1, &enable_str));
1065 const Extension* extension =
1066 extension_service_->GetInstalledExtension(extension_id);
1067 if (!extension)
1068 return;
1070 // Flipping the incognito bit will generate unload/load notifications for the
1071 // extension, but we don't want to reload the page, because a) we've already
1072 // updated the UI to reflect the change, and b) we want the yellow warning
1073 // text to stay until the user has left the page.
1075 // TODO(aa): This creates crappiness in some cases. For example, in a main
1076 // window, when toggling this, the browser action will flicker because it gets
1077 // unloaded, then reloaded. It would be better to have a dedicated
1078 // notification for this case.
1080 // Bug: http://crbug.com/41384
1081 base::AutoReset<bool> auto_reset_ignore_notifications(
1082 &ignore_notifications_, true);
1083 util::SetIsIncognitoEnabled(extension->id(),
1084 extension_service_->profile(),
1085 enable_str == "true");
1088 void ExtensionSettingsHandler::HandleEnableErrorCollectionMessage(
1089 const base::ListValue* args) {
1090 CHECK_EQ(2u, args->GetSize());
1091 std::string extension_id;
1092 std::string enable_str;
1093 CHECK(args->GetString(0, &extension_id));
1094 CHECK(args->GetString(1, &enable_str));
1095 bool enabled = enable_str == "true";
1096 ErrorConsole::Get(Profile::FromWebUI(web_ui()))
1097 ->SetReportingAllForExtension(extension_id, enabled);
1100 void ExtensionSettingsHandler::HandleAllowFileAccessMessage(
1101 const base::ListValue* args) {
1102 CHECK_EQ(2U, args->GetSize());
1103 std::string extension_id, allow_str;
1104 CHECK(args->GetString(0, &extension_id));
1105 CHECK(args->GetString(1, &allow_str));
1106 const Extension* extension =
1107 extension_service_->GetInstalledExtension(extension_id);
1108 if (!extension)
1109 return;
1111 if (util::IsExtensionSupervised(extension, Profile::FromWebUI(web_ui())))
1112 return;
1114 if (!management_policy_->UserMayModifySettings(extension, NULL)) {
1115 LOG(ERROR) << "An attempt was made to change allow file access of an"
1116 << " extension that is non-usermanagable. Extension id : "
1117 << extension->id();
1118 return;
1121 util::SetAllowFileAccess(
1122 extension_id, extension_service_->profile(), allow_str == "true");
1125 void ExtensionSettingsHandler::HandleAllowOnAllUrlsMessage(
1126 const base::ListValue* args) {
1127 DCHECK(FeatureSwitch::scripts_require_action()->IsEnabled());
1128 CHECK_EQ(2u, args->GetSize());
1129 std::string extension_id;
1130 std::string allow_str;
1131 CHECK(args->GetString(0, &extension_id));
1132 CHECK(args->GetString(1, &allow_str));
1133 util::SetAllowedScriptingOnAllUrls(extension_id,
1134 extension_service_->GetBrowserContext(),
1135 allow_str == "true");
1138 void ExtensionSettingsHandler::HandleUninstallMessage(
1139 const base::ListValue* args) {
1140 CHECK_EQ(1U, args->GetSize());
1141 std::string extension_id;
1142 CHECK(args->GetString(0, &extension_id));
1143 const Extension* extension =
1144 extension_service_->GetInstalledExtension(extension_id);
1145 if (!extension)
1146 return;
1148 if (!management_policy_->UserMayModifySettings(extension, NULL) ||
1149 management_policy_->MustRemainInstalled(extension, NULL)) {
1150 LOG(ERROR) << "An attempt was made to uninstall an extension that is "
1151 << "non-usermanagable. Extension id : " << extension->id();
1152 return;
1155 if (!extension_id_prompting_.empty())
1156 return; // Only one prompt at a time.
1158 extension_id_prompting_ = extension_id;
1160 GetExtensionUninstallDialog()->ConfirmUninstall(extension);
1163 void ExtensionSettingsHandler::HandleOptionsMessage(
1164 const base::ListValue* args) {
1165 const Extension* extension = GetActiveExtension(args);
1166 if (!extension || OptionsPageInfo::GetOptionsPage(extension).is_empty())
1167 return;
1168 ExtensionTabUtil::OpenOptionsPage(extension,
1169 chrome::FindBrowserWithWebContents(web_ui()->GetWebContents()));
1172 void ExtensionSettingsHandler::HandlePermissionsMessage(
1173 const base::ListValue* args) {
1174 std::string extension_id(base::UTF16ToUTF8(ExtractStringValue(args)));
1175 CHECK(!extension_id.empty());
1176 const Extension* extension =
1177 ExtensionRegistry::Get(Profile::FromWebUI(web_ui()))
1178 ->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
1179 if (!extension)
1180 return;
1182 if (!extension_id_prompting_.empty())
1183 return; // Only one prompt at a time.
1184 extension_id_prompting_ = extension->id();
1186 // The BrokerDelegate manages its own lifetime.
1187 BrokerDelegate* broker_delegate = new BrokerDelegate(AsWeakPtr());
1189 // Show the new-style extensions dialog when it is available. It is currently
1190 // unavailable by default on Mac.
1191 if (CanShowAppInfoDialog()) {
1192 UMA_HISTOGRAM_ENUMERATION("Apps.AppInfoDialog.Launches",
1193 AppInfoLaunchSource::FROM_EXTENSIONS_PAGE,
1194 AppInfoLaunchSource::NUM_LAUNCH_SOURCES);
1196 // Display the dialog at a size similar to the app list.
1197 ShowAppInfoInNativeDialog(
1198 web_contents()->GetTopLevelNativeWindow(),
1199 GetAppInfoNativeDialogSize(),
1200 Profile::FromWebUI(web_ui()), extension,
1201 base::Bind(&BrokerDelegate::AppInfoDialogClosed,
1202 base::Unretained(broker_delegate)));
1203 } else {
1204 prompt_.reset(new ExtensionInstallPrompt(web_contents()));
1205 std::vector<base::FilePath> retained_file_paths;
1206 if (extension->permissions_data()->HasAPIPermission(
1207 APIPermission::kFileSystem)) {
1208 std::vector<apps::SavedFileEntry> retained_file_entries =
1209 apps::SavedFilesService::Get(Profile::FromWebUI(web_ui()))
1210 ->GetAllFileEntries(extension_id_prompting_);
1211 for (size_t i = 0; i < retained_file_entries.size(); ++i) {
1212 retained_file_paths.push_back(retained_file_entries[i].path);
1215 std::vector<base::string16> retained_device_messages;
1216 if (extension->permissions_data()->HasAPIPermission(APIPermission::kUsb)) {
1217 retained_device_messages =
1218 extensions::DevicePermissionsManager::Get(
1219 Profile::FromWebUI(web_ui()))
1220 ->GetPermissionMessageStrings(extension_id_prompting_);
1223 prompt_->ReviewPermissions(broker_delegate, extension, retained_file_paths,
1224 retained_device_messages);
1228 void ExtensionSettingsHandler::HandleShowButtonMessage(
1229 const base::ListValue* args) {
1230 const Extension* extension = GetActiveExtension(args);
1231 if (!extension)
1232 return;
1233 ExtensionActionAPI::SetBrowserActionVisibility(
1234 ExtensionPrefs::Get(extension_service_->profile()),
1235 extension->id(),
1236 true);
1239 void ExtensionSettingsHandler::HandleAutoUpdateMessage(
1240 const base::ListValue* args) {
1241 ExtensionUpdater* updater = extension_service_->updater();
1242 if (updater) {
1243 ExtensionUpdater::CheckParams params;
1244 params.install_immediately = true;
1245 updater->CheckNow(params);
1249 void ExtensionSettingsHandler::HandleDismissADTPromoMessage(
1250 const base::ListValue* args) {
1251 DCHECK(args->empty());
1252 Profile::FromWebUI(web_ui())->GetPrefs()->SetBoolean(
1253 prefs::kExtensionsUIDismissedADTPromo, true);
1256 void ExtensionSettingsHandler::HandleShowPath(const base::ListValue* args) {
1257 DCHECK(!args->empty());
1258 std::string extension_id = base::UTF16ToUTF8(ExtractStringValue(args));
1260 Profile* profile = Profile::FromWebUI(web_ui());
1261 ExtensionRegistry* registry = ExtensionRegistry::Get(profile);
1262 const Extension* extension = registry->GetExtensionById(
1263 extension_id,
1264 ExtensionRegistry::EVERYTHING);
1265 CHECK(extension);
1266 // We explicitly show manifest.json in order to work around an issue in OSX
1267 // where opening the directory doesn't focus the Finder.
1268 platform_util::ShowItemInFolder(profile,
1269 extension->path().Append(kManifestFilename));
1272 void ExtensionSettingsHandler::ShowAlert(const std::string& message) {
1273 base::ListValue arguments;
1274 arguments.Append(new base::StringValue(message));
1275 web_ui()->CallJavascriptFunction("alert", arguments);
1278 const Extension* ExtensionSettingsHandler::GetActiveExtension(
1279 const base::ListValue* args) {
1280 std::string extension_id = base::UTF16ToUTF8(ExtractStringValue(args));
1281 CHECK(!extension_id.empty());
1282 return extension_service_->GetExtensionById(extension_id, false);
1285 void ExtensionSettingsHandler::MaybeUpdateAfterNotification() {
1286 WebContents* contents = web_ui()->GetWebContents();
1287 if (!ignore_notifications_ && contents && contents->GetRenderViewHost())
1288 HandleRequestExtensionsData(NULL);
1289 deleting_rvh_ = NULL;
1292 void ExtensionSettingsHandler::MaybeRegisterForNotifications() {
1293 if (registered_for_notifications_)
1294 return;
1296 registered_for_notifications_ = true;
1297 Profile* profile = Profile::FromWebUI(web_ui());
1299 // Register for notifications that we need to reload the page.
1300 registrar_.Add(this,
1301 extensions::NOTIFICATION_EXTENSION_UPDATE_DISABLED,
1302 content::Source<Profile>(profile));
1303 registrar_.Add(this,
1304 extensions::NOTIFICATION_EXTENSION_HOST_CREATED,
1305 content::NotificationService::AllBrowserContextsAndSources());
1306 registrar_.Add(this,
1307 chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED,
1308 content::NotificationService::AllBrowserContextsAndSources());
1309 registrar_.Add(this,
1310 chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED,
1311 content::NotificationService::AllBrowserContextsAndSources());
1312 registrar_.Add(
1313 this,
1314 extensions::NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED,
1315 content::Source<ExtensionPrefs>(ExtensionPrefs::Get(profile)));
1316 registrar_.Add(this,
1317 extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED,
1318 content::NotificationService::AllBrowserContextsAndSources());
1319 registrar_.Add(this,
1320 content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED,
1321 content::NotificationService::AllBrowserContextsAndSources());
1323 extension_registry_observer_.Add(ExtensionRegistry::Get(profile));
1325 content::WebContentsObserver::Observe(web_ui()->GetWebContents());
1327 warning_service_observer_.Add(WarningService::Get(profile));
1329 error_console_observer_.Add(ErrorConsole::Get(profile));
1331 extension_management_observer_.Add(
1332 ExtensionManagementFactory::GetForBrowserContext(profile));
1335 std::vector<ExtensionPage>
1336 ExtensionSettingsHandler::GetInspectablePagesForExtension(
1337 const Extension* extension, bool extension_is_enabled) {
1338 std::vector<ExtensionPage> result;
1340 // Get the extension process's active views.
1341 extensions::ProcessManager* process_manager =
1342 ProcessManager::Get(extension_service_->profile());
1343 GetInspectablePagesForExtensionProcess(
1344 extension,
1345 process_manager->GetRenderViewHostsForExtension(extension->id()),
1346 &result);
1348 // Get app window views
1349 GetAppWindowPagesForExtensionProfile(
1350 extension, extension_service_->profile(), &result);
1352 // Include a link to start the lazy background page, if applicable.
1353 if (BackgroundInfo::HasLazyBackgroundPage(extension) &&
1354 extension_is_enabled &&
1355 !process_manager->GetBackgroundHostForExtension(extension->id())) {
1356 result.push_back(ExtensionPage(
1357 BackgroundInfo::GetBackgroundURL(extension),
1360 false,
1361 BackgroundInfo::HasGeneratedBackgroundPage(extension)));
1364 // Repeat for the incognito process, if applicable. Don't try to get
1365 // app windows for incognito processes.
1366 if (extension_service_->profile()->HasOffTheRecordProfile() &&
1367 IncognitoInfo::IsSplitMode(extension) &&
1368 util::IsIncognitoEnabled(extension->id(),
1369 extension_service_->profile())) {
1370 extensions::ProcessManager* process_manager = ProcessManager::Get(
1371 extension_service_->profile()->GetOffTheRecordProfile());
1372 GetInspectablePagesForExtensionProcess(
1373 extension,
1374 process_manager->GetRenderViewHostsForExtension(extension->id()),
1375 &result);
1377 if (BackgroundInfo::HasLazyBackgroundPage(extension) &&
1378 extension_is_enabled &&
1379 !process_manager->GetBackgroundHostForExtension(extension->id())) {
1380 result.push_back(ExtensionPage(
1381 BackgroundInfo::GetBackgroundURL(extension),
1384 true,
1385 BackgroundInfo::HasGeneratedBackgroundPage(extension)));
1389 return result;
1392 void ExtensionSettingsHandler::GetInspectablePagesForExtensionProcess(
1393 const Extension* extension,
1394 const std::set<RenderViewHost*>& views,
1395 std::vector<ExtensionPage>* result) {
1396 bool has_generated_background_page =
1397 BackgroundInfo::HasGeneratedBackgroundPage(extension);
1398 for (std::set<RenderViewHost*>::const_iterator iter = views.begin();
1399 iter != views.end(); ++iter) {
1400 RenderViewHost* host = *iter;
1401 WebContents* web_contents = WebContents::FromRenderViewHost(host);
1402 ViewType host_type = GetViewType(web_contents);
1403 if (host == deleting_rvh_ ||
1404 VIEW_TYPE_EXTENSION_POPUP == host_type ||
1405 VIEW_TYPE_EXTENSION_DIALOG == host_type)
1406 continue;
1408 GURL url = web_contents->GetURL();
1409 content::RenderProcessHost* process = host->GetProcess();
1410 bool is_background_page =
1411 (url == BackgroundInfo::GetBackgroundURL(extension));
1412 result->push_back(
1413 ExtensionPage(url,
1414 process->GetID(),
1415 host->GetRoutingID(),
1416 process->GetBrowserContext()->IsOffTheRecord(),
1417 is_background_page && has_generated_background_page));
1421 void ExtensionSettingsHandler::GetAppWindowPagesForExtensionProfile(
1422 const Extension* extension,
1423 Profile* profile,
1424 std::vector<ExtensionPage>* result) {
1425 AppWindowRegistry* registry = AppWindowRegistry::Get(profile);
1426 if (!registry) return;
1428 const AppWindowRegistry::AppWindowList windows =
1429 registry->GetAppWindowsForApp(extension->id());
1431 bool has_generated_background_page =
1432 BackgroundInfo::HasGeneratedBackgroundPage(extension);
1433 for (AppWindowRegistry::const_iterator it = windows.begin();
1434 it != windows.end();
1435 ++it) {
1436 WebContents* web_contents = (*it)->web_contents();
1437 RenderViewHost* host = web_contents->GetRenderViewHost();
1438 content::RenderProcessHost* process = host->GetProcess();
1440 bool is_background_page =
1441 (web_contents->GetURL() == BackgroundInfo::GetBackgroundURL(extension));
1442 result->push_back(
1443 ExtensionPage(web_contents->GetURL(),
1444 process->GetID(),
1445 host->GetRoutingID(),
1446 process->GetBrowserContext()->IsOffTheRecord(),
1447 is_background_page && has_generated_background_page));
1451 ExtensionUninstallDialog*
1452 ExtensionSettingsHandler::GetExtensionUninstallDialog() {
1453 if (!extension_uninstall_dialog_.get()) {
1454 Browser* browser = chrome::FindBrowserWithWebContents(
1455 web_ui()->GetWebContents());
1456 extension_uninstall_dialog_.reset(
1457 ExtensionUninstallDialog::Create(extension_service_->profile(),
1458 browser->window()->GetNativeWindow(),
1459 this));
1461 return extension_uninstall_dialog_.get();
1464 void ExtensionSettingsHandler::OnReinstallComplete(
1465 bool success,
1466 const std::string& error,
1467 webstore_install::Result result) {
1468 MaybeUpdateAfterNotification();
1471 } // namespace extensions