extension_settings_handler.cc revision b2df76ea8fec9e32f6f3718986dba0d95315b29c
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.
4
5#include "chrome/browser/ui/webui/extensions/extension_settings_handler.h"
6
7#include "base/auto_reset.h"
8#include "base/base64.h"
9#include "base/bind.h"
10#include "base/bind_helpers.h"
11#include "base/command_line.h"
12#include "base/file_util.h"
13#include "base/prefs/pref_service.h"
14#include "base/string_util.h"
15#include "base/strings/string_number_conversions.h"
16#include "base/utf_string_conversions.h"
17#include "base/values.h"
18#include "base/version.h"
19#include "chrome/browser/browser_process.h"
20#include "chrome/browser/devtools/devtools_window.h"
21#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
22#include "chrome/browser/extensions/crx_installer.h"
23#include "chrome/browser/extensions/extension_action_manager.h"
24#include "chrome/browser/extensions/extension_disabled_ui.h"
25#include "chrome/browser/extensions/extension_error_reporter.h"
26#include "chrome/browser/extensions/extension_host.h"
27#include "chrome/browser/extensions/extension_service.h"
28#include "chrome/browser/extensions/extension_system.h"
29#include "chrome/browser/extensions/extension_tab_util.h"
30#include "chrome/browser/extensions/extension_warning_set.h"
31#include "chrome/browser/extensions/lazy_background_task_queue.h"
32#include "chrome/browser/extensions/management_policy.h"
33#include "chrome/browser/extensions/shell_window_registry.h"
34#include "chrome/browser/extensions/unpacked_installer.h"
35#include "chrome/browser/extensions/updater/extension_updater.h"
36#include "chrome/browser/google/google_util.h"
37#include "chrome/browser/managed_mode/managed_mode_navigation_observer.h"
38#include "chrome/browser/managed_mode/managed_user_service.h"
39#include "chrome/browser/managed_mode/managed_user_service_factory.h"
40#include "chrome/browser/profiles/profile.h"
41#include "chrome/browser/tab_contents/background_contents.h"
42#include "chrome/browser/ui/browser_finder.h"
43#include "chrome/browser/ui/chrome_select_file_policy.h"
44#include "chrome/browser/ui/extensions/application_launch.h"
45#include "chrome/browser/ui/extensions/shell_window.h"
46#include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
47#include "chrome/common/chrome_notification_types.h"
48#include "chrome/common/chrome_switches.h"
49#include "chrome/common/extensions/background_info.h"
50#include "chrome/common/extensions/extension.h"
51#include "chrome/common/extensions/extension_constants.h"
52#include "chrome/common/extensions/extension_icon_set.h"
53#include "chrome/common/extensions/extension_set.h"
54#include "chrome/common/extensions/feature_switch.h"
55#include "chrome/common/extensions/incognito_handler.h"
56#include "chrome/common/extensions/manifest_url_handler.h"
57#include "chrome/common/pref_names.h"
58#include "chrome/common/url_constants.h"
59#include "components/user_prefs/pref_registry_syncable.h"
60#include "content/public/browser/notification_service.h"
61#include "content/public/browser/notification_source.h"
62#include "content/public/browser/notification_types.h"
63#include "content/public/browser/render_process_host.h"
64#include "content/public/browser/render_view_host.h"
65#include "content/public/browser/site_instance.h"
66#include "content/public/browser/web_contents.h"
67#include "content/public/browser/web_contents_view.h"
68#include "content/public/browser/web_ui.h"
69#include "content/public/browser/web_ui_data_source.h"
70#include "extensions/browser/view_type_utils.h"
71#include "extensions/common/constants.h"
72#include "grit/browser_resources.h"
73#include "grit/chromium_strings.h"
74#include "grit/generated_resources.h"
75#include "grit/theme_resources.h"
76#include "ui/base/l10n/l10n_util.h"
77#include "ui/base/resource/resource_bundle.h"
78
79
80using content::RenderViewHost;
81using content::WebContents;
82using extensions::Extension;
83using extensions::ExtensionUpdater;
84using extensions::ExtensionWarning;
85using extensions::ManagementPolicy;
86using extensions::Manifest;
87
88///////////////////////////////////////////////////////////////////////////////
89//
90// ExtensionSettingsHandler
91//
92///////////////////////////////////////////////////////////////////////////////
93
94ExtensionSettingsHandler::ExtensionSettingsHandler()
95    : extension_service_(NULL),
96      management_policy_(NULL),
97      ignore_notifications_(false),
98      deleting_rvh_(NULL),
99      registered_for_notifications_(false),
100      rvh_created_callback_(
101          base::Bind(&ExtensionSettingsHandler::RenderViewHostCreated,
102                     base::Unretained(this))),
103      warning_service_observer_(this) {
104}
105
106ExtensionSettingsHandler::~ExtensionSettingsHandler() {
107  content::RenderViewHost::RemoveCreatedCallback(rvh_created_callback_);
108
109  // There may be pending file dialogs, we need to tell them that we've gone
110  // away so they don't try and call back to us.
111  if (load_extension_dialog_)
112    load_extension_dialog_->ListenerDestroyed();
113}
114
115ExtensionSettingsHandler::ExtensionSettingsHandler(ExtensionService* service,
116                                                   ManagementPolicy* policy)
117    : extension_service_(service),
118      management_policy_(policy),
119      ignore_notifications_(false),
120      deleting_rvh_(NULL),
121      registered_for_notifications_(false),
122      warning_service_observer_(this) {
123}
124
125// static
126void ExtensionSettingsHandler::RegisterUserPrefs(
127    user_prefs::PrefRegistrySyncable* registry) {
128  registry->RegisterBooleanPref(
129      prefs::kExtensionsUIDeveloperMode,
130      false,
131      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
132}
133
134DictionaryValue* ExtensionSettingsHandler::CreateExtensionDetailValue(
135    const Extension* extension,
136    const std::vector<ExtensionPage>& pages,
137    const extensions::ExtensionWarningService* warning_service) {
138  DictionaryValue* extension_data = new DictionaryValue();
139  bool enabled = extension_service_->IsExtensionEnabled(extension->id());
140  extension->GetBasicInfo(enabled, extension_data);
141
142  extension_data->SetBoolean("userModifiable",
143      CheckUserMayModifySettings(extension));
144
145  GURL icon =
146      ExtensionIconSource::GetIconURL(extension,
147                                      extension_misc::EXTENSION_ICON_MEDIUM,
148                                      ExtensionIconSet::MATCH_BIGGER,
149                                      !enabled, NULL);
150  if (Manifest::IsUnpackedLocation(extension->location()))
151    extension_data->SetString("path", extension->path().value());
152  extension_data->SetString("icon", icon.spec());
153  extension_data->SetBoolean("isUnpacked",
154      Manifest::IsUnpackedLocation(extension->location()));
155  extension_data->SetBoolean("terminated",
156      extension_service_->terminated_extensions()->Contains(extension->id()));
157  extension_data->SetBoolean("enabledIncognito",
158      extension_service_->IsIncognitoEnabled(extension->id()));
159  extension_data->SetBoolean("incognitoCanBeEnabled",
160                             extension->can_be_incognito_enabled());
161  extension_data->SetBoolean("wantsFileAccess", extension->wants_file_access());
162  extension_data->SetBoolean("allowFileAccess",
163                             extension_service_->AllowFileAccess(extension));
164  extension_data->SetBoolean("allow_activity",
165      enabled && CommandLine::ForCurrentProcess()->HasSwitch(
166          switches::kEnableExtensionActivityUI));
167  extension_data->SetBoolean("allow_reload",
168      Manifest::IsUnpackedLocation(extension->location()));
169  extension_data->SetBoolean("is_hosted_app", extension->is_hosted_app());
170  extension_data->SetBoolean("is_platform_app", extension->is_platform_app());
171  extension_data->SetBoolean("homepageProvided",
172      extensions::ManifestURL::GetHomepageURL(extension).is_valid());
173
174  // Determine the sort order: Extensions loaded through --load-extensions show
175  // up at the top. Disabled extensions show up at the bottom.
176  if (Manifest::IsUnpackedLocation(extension->location()))
177    extension_data->SetInteger("order", 1);
178  else
179    extension_data->SetInteger("order", 2);
180
181  if (!extensions::ExtensionActionAPI::GetBrowserActionVisibility(
182          extension_service_->extension_prefs(), extension->id())) {
183    extension_data->SetBoolean("enable_show_button", true);
184  }
185
186  // Add views
187  ListValue* views = new ListValue;
188  for (std::vector<ExtensionPage>::const_iterator iter = pages.begin();
189       iter != pages.end(); ++iter) {
190    DictionaryValue* view_value = new DictionaryValue;
191    if (iter->url.scheme() == extensions::kExtensionScheme) {
192      // No leading slash.
193      view_value->SetString("path", iter->url.path().substr(1));
194    } else {
195      // For live pages, use the full URL.
196      view_value->SetString("path", iter->url.spec());
197    }
198    view_value->SetInteger("renderViewId", iter->render_view_id);
199    view_value->SetInteger("renderProcessId", iter->render_process_id);
200    view_value->SetBoolean("incognito", iter->incognito);
201    views->Append(view_value);
202  }
203  extension_data->Set("views", views);
204  extensions::ExtensionActionManager* extension_action_manager =
205      extensions::ExtensionActionManager::Get(extension_service_->profile());
206  extension_data->SetBoolean(
207      "hasPopupAction",
208      extension_action_manager->GetBrowserAction(*extension) ||
209      extension_action_manager->GetPageAction(*extension));
210
211  // Add warnings.
212  if (warning_service) {
213    std::vector<std::string> warnings =
214        warning_service->GetWarningMessagesForExtension(extension->id());
215
216    if (!warnings.empty()) {
217      ListValue* warnings_list = new ListValue;
218      for (std::vector<std::string>::const_iterator iter = warnings.begin();
219           iter != warnings.end(); ++iter) {
220        warnings_list->Append(Value::CreateStringValue(*iter));
221      }
222      extension_data->Set("warnings", warnings_list);
223    }
224  }
225
226  // Add install warnings (these are not the same as warnings!).
227  if (Manifest::IsUnpackedLocation(extension->location())) {
228    const std::vector<extensions::InstallWarning>& install_warnings =
229        extension->install_warnings();
230    if (!install_warnings.empty()) {
231      scoped_ptr<ListValue> list(new ListValue());
232      for (std::vector<extensions::InstallWarning>::const_iterator it =
233               install_warnings.begin(); it != install_warnings.end(); ++it) {
234        DictionaryValue* item = new DictionaryValue();
235        item->SetBoolean("isHTML",
236                         it->format == extensions::InstallWarning::FORMAT_HTML);
237        item->SetString("message", it->message);
238        list->Append(item);
239      }
240      extension_data->Set("installWarnings", list.release());
241    }
242  }
243
244  return extension_data;
245}
246
247void ExtensionSettingsHandler::GetLocalizedValues(
248    content::WebUIDataSource* source) {
249  source->AddString("extensionSettings",
250      l10n_util::GetStringUTF16(IDS_MANAGE_EXTENSIONS_SETTING_WINDOWS_TITLE));
251
252  source->AddString("extensionSettingsDeveloperMode",
253      l10n_util::GetStringUTF16(IDS_EXTENSIONS_DEVELOPER_MODE_LINK));
254  source->AddString("extensionSettingsNoExtensions",
255      l10n_util::GetStringUTF16(IDS_EXTENSIONS_NONE_INSTALLED));
256  source->AddString("extensionSettingsSuggestGallery",
257      l10n_util::GetStringFUTF16(IDS_EXTENSIONS_NONE_INSTALLED_SUGGEST_GALLERY,
258          ASCIIToUTF16(google_util::AppendGoogleLocaleParam(
259              GURL(extension_urls::GetExtensionGalleryURL())).spec())));
260  source->AddString("extensionSettingsGetMoreExtensions",
261      l10n_util::GetStringUTF16(IDS_GET_MORE_EXTENSIONS));
262  source->AddString("extensionSettingsGetMoreExtensionsUrl",
263      ASCIIToUTF16(google_util::AppendGoogleLocaleParam(
264          GURL(extension_urls::GetExtensionGalleryURL())).spec()));
265  source->AddString("extensionSettingsExtensionId",
266      l10n_util::GetStringUTF16(IDS_EXTENSIONS_ID));
267  source->AddString("extensionSettingsExtensionPath",
268      l10n_util::GetStringUTF16(IDS_EXTENSIONS_PATH));
269  source->AddString("extensionSettingsInspectViews",
270      l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSPECT_VIEWS));
271  source->AddString("extensionSettingsInstallWarnings",
272      l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSTALL_WARNINGS));
273  source->AddString("viewIncognito",
274      l10n_util::GetStringUTF16(IDS_EXTENSIONS_VIEW_INCOGNITO));
275  source->AddString("viewInactive",
276      l10n_util::GetStringUTF16(IDS_EXTENSIONS_VIEW_INACTIVE));
277  source->AddString("extensionSettingsEnable",
278      l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLE));
279  source->AddString("extensionSettingsEnabled",
280      l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLED));
281  source->AddString("extensionSettingsRemove",
282      l10n_util::GetStringUTF16(IDS_EXTENSIONS_REMOVE));
283  source->AddString("extensionSettingsEnableIncognito",
284      l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLE_INCOGNITO));
285  source->AddString("extensionSettingsAllowFileAccess",
286      l10n_util::GetStringUTF16(IDS_EXTENSIONS_ALLOW_FILE_ACCESS));
287  source->AddString("extensionSettingsIncognitoWarning",
288      l10n_util::GetStringUTF16(IDS_EXTENSIONS_INCOGNITO_WARNING));
289  source->AddString("extensionSettingsReloadTerminated",
290      l10n_util::GetStringUTF16(IDS_EXTENSIONS_RELOAD_TERMINATED));
291  source->AddString("extensionSettingsLaunch",
292      l10n_util::GetStringUTF16(IDS_EXTENSIONS_LAUNCH));
293  source->AddString("extensionSettingsRestart",
294      l10n_util::GetStringUTF16(IDS_EXTENSIONS_RESTART));
295  source->AddString("extensionSettingsReloadUnpacked",
296      l10n_util::GetStringUTF16(IDS_EXTENSIONS_RELOAD_UNPACKED));
297  source->AddString("extensionSettingsOptions",
298      l10n_util::GetStringUTF16(IDS_EXTENSIONS_OPTIONS_LINK));
299  source->AddString("extensionSettingsPermissions",
300      l10n_util::GetStringUTF16(IDS_EXTENSIONS_PERMISSIONS_LINK));
301  source->AddString("extensionSettingsActivity",
302      l10n_util::GetStringUTF16(IDS_EXTENSIONS_ACTIVITY_LINK));
303  source->AddString("extensionSettingsVisitWebsite",
304      l10n_util::GetStringUTF16(IDS_EXTENSIONS_VISIT_WEBSITE));
305  source->AddString("extensionSettingsVisitWebStore",
306      l10n_util::GetStringUTF16(IDS_EXTENSIONS_VISIT_WEBSTORE));
307  source->AddString("extensionSettingsPolicyControlled",
308     l10n_util::GetStringUTF16(IDS_EXTENSIONS_POLICY_CONTROLLED));
309  source->AddString("extensionSettingsManagedMode",
310     l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOCKED_MANAGED_MODE));
311  source->AddString("sideloadWipeoutUrl",
312      chrome::kSideloadWipeoutHelpURL);
313  source->AddString("sideloadWipoutLearnMore",
314      l10n_util::GetStringUTF16(IDS_LEARN_MORE));
315  source->AddString("extensionSettingsShowButton",
316      l10n_util::GetStringUTF16(IDS_EXTENSIONS_SHOW_BUTTON));
317  source->AddString("extensionSettingsLoadUnpackedButton",
318      l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_UNPACKED_BUTTON));
319  source->AddString("extensionSettingsPackButton",
320      l10n_util::GetStringUTF16(IDS_EXTENSIONS_PACK_BUTTON));
321  source->AddString("extensionSettingsCommandsLink",
322      l10n_util::GetStringUTF16(IDS_EXTENSIONS_COMMANDS_CONFIGURE));
323  source->AddString("extensionSettingsUpdateButton",
324      l10n_util::GetStringUTF16(IDS_EXTENSIONS_UPDATE_BUTTON));
325  source->AddString("extensionSettingsCrashMessage",
326      l10n_util::GetStringUTF16(IDS_EXTENSIONS_CRASHED_EXTENSION));
327  source->AddString("extensionSettingsInDevelopment",
328      l10n_util::GetStringUTF16(IDS_EXTENSIONS_IN_DEVELOPMENT));
329  source->AddString("extensionSettingsWarningsTitle",
330      l10n_util::GetStringUTF16(IDS_EXTENSION_WARNINGS_TITLE));
331  source->AddString("extensionSettingsShowDetails",
332      l10n_util::GetStringUTF16(IDS_EXTENSIONS_SHOW_DETAILS));
333  source->AddString("extensionSettingsHideDetails",
334      l10n_util::GetStringUTF16(IDS_EXTENSIONS_HIDE_DETAILS));
335  source->AddString("unlockButton",
336      l10n_util::GetStringUTF16(IDS_EXTENSIONS_UNLOCK_BUTTON));
337  source->AddString("lockButton",
338      l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOCK_BUTTON));
339
340  // TODO(estade): comb through the above strings to find ones no longer used in
341  // uber extensions.
342  source->AddString("extensionUninstall",
343      l10n_util::GetStringUTF16(IDS_EXTENSIONS_UNINSTALL));
344}
345
346void ExtensionSettingsHandler::RenderViewHostCreated(
347    content::RenderViewHost* render_view_host) {
348  Profile* source_profile = Profile::FromBrowserContext(
349      render_view_host->GetSiteInstance()->GetBrowserContext());
350  if (!Profile::FromWebUI(web_ui())->IsSameProfile(source_profile))
351    return;
352  MaybeUpdateAfterNotification();
353}
354
355void ExtensionSettingsHandler::RenderViewDeleted(
356    content::RenderViewHost* render_view_host) {
357  deleting_rvh_ = render_view_host;
358  Profile* source_profile = Profile::FromBrowserContext(
359      render_view_host->GetSiteInstance()->GetBrowserContext());
360  if (!Profile::FromWebUI(web_ui())->IsSameProfile(source_profile))
361    return;
362  MaybeUpdateAfterNotification();
363}
364
365void ExtensionSettingsHandler::NavigateToPendingEntry(const GURL& url,
366    content::NavigationController::ReloadType reload_type) {
367  if (reload_type != content::NavigationController::NO_RELOAD)
368    ReloadUnpackedExtensions();
369}
370
371void ExtensionSettingsHandler::RegisterMessages() {
372  // Don't override an |extension_service_| or |management_policy_| injected
373  // for testing.
374  if (!extension_service_) {
375    extension_service_ = Profile::FromWebUI(web_ui())->GetOriginalProfile()->
376        GetExtensionService();
377  }
378  if (!management_policy_) {
379    management_policy_ = extensions::ExtensionSystem::Get(
380        extension_service_->profile())->management_policy();
381  }
382
383  web_ui()->RegisterMessageCallback("setElevated",
384      base::Bind(&ExtensionSettingsHandler::ManagedUserSetElevated,
385                 base::Unretained(this)));
386  web_ui()->RegisterMessageCallback("extensionSettingsRequestExtensionsData",
387      base::Bind(&ExtensionSettingsHandler::HandleRequestExtensionsData,
388                 base::Unretained(this)));
389  web_ui()->RegisterMessageCallback("extensionSettingsToggleDeveloperMode",
390      base::Bind(&ExtensionSettingsHandler::HandleToggleDeveloperMode,
391                 base::Unretained(this)));
392  web_ui()->RegisterMessageCallback("extensionSettingsInspect",
393      base::Bind(&ExtensionSettingsHandler::HandleInspectMessage,
394                 base::Unretained(this)));
395  web_ui()->RegisterMessageCallback("extensionSettingsLaunch",
396      base::Bind(&ExtensionSettingsHandler::HandleLaunchMessage,
397                 base::Unretained(this)));
398  web_ui()->RegisterMessageCallback("extensionSettingsRestart",
399      base::Bind(&ExtensionSettingsHandler::HandleRestartMessage,
400                 base::Unretained(this)));
401  web_ui()->RegisterMessageCallback("extensionSettingsReload",
402      base::Bind(&ExtensionSettingsHandler::HandleReloadMessage,
403                 base::Unretained(this)));
404  web_ui()->RegisterMessageCallback("extensionSettingsEnable",
405      base::Bind(&ExtensionSettingsHandler::HandleEnableMessage,
406                 base::Unretained(this)));
407  web_ui()->RegisterMessageCallback("extensionSettingsEnableIncognito",
408      base::Bind(&ExtensionSettingsHandler::HandleEnableIncognitoMessage,
409                 base::Unretained(this)));
410  web_ui()->RegisterMessageCallback("extensionSettingsAllowFileAccess",
411      base::Bind(&ExtensionSettingsHandler::HandleAllowFileAccessMessage,
412                 base::Unretained(this)));
413  web_ui()->RegisterMessageCallback("extensionSettingsUninstall",
414      base::Bind(&ExtensionSettingsHandler::HandleUninstallMessage,
415                 base::Unretained(this)));
416  web_ui()->RegisterMessageCallback("extensionSettingsOptions",
417      base::Bind(&ExtensionSettingsHandler::HandleOptionsMessage,
418                 base::Unretained(this)));
419  web_ui()->RegisterMessageCallback("extensionSettingsPermissions",
420      base::Bind(&ExtensionSettingsHandler::HandlePermissionsMessage,
421                 base::Unretained(this)));
422  web_ui()->RegisterMessageCallback("extensionSettingsShowButton",
423      base::Bind(&ExtensionSettingsHandler::HandleShowButtonMessage,
424                 base::Unretained(this)));
425  web_ui()->RegisterMessageCallback("extensionSettingsAutoupdate",
426      base::Bind(&ExtensionSettingsHandler::HandleAutoUpdateMessage,
427                 base::Unretained(this)));
428  web_ui()->RegisterMessageCallback("extensionSettingsLoadUnpackedExtension",
429      base::Bind(&ExtensionSettingsHandler::HandleLoadUnpackedExtensionMessage,
430                 base::Unretained(this)));
431}
432
433void ExtensionSettingsHandler::FileSelected(const base::FilePath& path,
434                                            int index,
435                                            void* params) {
436  last_unpacked_directory_ = base::FilePath(path);
437  extensions::UnpackedInstaller::Create(extension_service_)->Load(path);
438}
439
440void ExtensionSettingsHandler::MultiFilesSelected(
441    const std::vector<base::FilePath>& files, void* params) {
442  NOTREACHED();
443}
444
445void ExtensionSettingsHandler::Observe(
446    int type,
447    const content::NotificationSource& source,
448    const content::NotificationDetails& details) {
449  Profile* profile = Profile::FromWebUI(web_ui());
450  Profile* source_profile = NULL;
451  switch (type) {
452    // We listen for notifications that will result in the page being
453    // repopulated with data twice for the same event in certain cases.
454    // For instance, EXTENSION_LOADED & EXTENSION_HOST_CREATED because
455    // we don't know about the views for an extension at EXTENSION_LOADED, but
456    // if we only listen to EXTENSION_HOST_CREATED, we'll miss extensions
457    // that don't have a process at startup.
458    //
459    // Doing it this way gets everything but causes the page to be rendered
460    // more than we need. It doesn't seem to result in any noticeable flicker.
461    case chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED:
462      deleting_rvh_ = content::Details<BackgroundContents>(details)->
463          web_contents()->GetRenderViewHost();
464      // Fall through.
465    case chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED:
466    case chrome::NOTIFICATION_EXTENSION_HOST_CREATED:
467      source_profile = content::Source<Profile>(source).ptr();
468      if (!profile->IsSameProfile(source_profile))
469          return;
470      MaybeUpdateAfterNotification();
471      break;
472    case chrome::NOTIFICATION_EXTENSION_LOADED:
473    case chrome::NOTIFICATION_EXTENSION_UNLOADED:
474    case chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED:
475    case chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED:
476      MaybeUpdateAfterNotification();
477      break;
478    default:
479      NOTREACHED();
480  }
481}
482
483void ExtensionSettingsHandler::ExtensionUninstallAccepted() {
484  DCHECK(!extension_id_prompting_.empty());
485
486  bool was_terminated = false;
487
488  // The extension can be uninstalled in another window while the UI was
489  // showing. Do nothing in that case.
490  const Extension* extension =
491      extension_service_->GetExtensionById(extension_id_prompting_, true);
492  if (!extension) {
493    extension = extension_service_->GetTerminatedExtension(
494        extension_id_prompting_);
495    was_terminated = true;
496  }
497  if (!extension)
498    return;
499
500  extension_service_->UninstallExtension(extension_id_prompting_,
501                                         false,  // External uninstall.
502                                         NULL);  // Error.
503  extension_id_prompting_ = "";
504
505  // There will be no EXTENSION_UNLOADED notification for terminated
506  // extensions as they were already unloaded.
507  if (was_terminated)
508    HandleRequestExtensionsData(NULL);
509}
510
511void ExtensionSettingsHandler::ExtensionUninstallCanceled() {
512  extension_id_prompting_ = "";
513}
514
515void ExtensionSettingsHandler::ExtensionWarningsChanged() {
516  MaybeUpdateAfterNotification();
517}
518
519void ExtensionSettingsHandler::InstallUIProceed() {
520  // This should never happen. The dialog only has a cancel button.
521  NOTREACHED();
522}
523
524void ExtensionSettingsHandler::InstallUIAbort(bool user_initiated) {
525}
526
527void ExtensionSettingsHandler::ReloadUnpackedExtensions() {
528  const ExtensionSet* extensions = extension_service_->extensions();
529  std::vector<const Extension*> unpacked_extensions;
530  for (ExtensionSet::const_iterator extension = extensions->begin();
531       extension != extensions->end(); ++extension) {
532    if (Manifest::IsUnpackedLocation((*extension)->location()))
533      unpacked_extensions.push_back(*extension);
534  }
535
536  for (std::vector<const Extension*>::iterator iter =
537       unpacked_extensions.begin(); iter != unpacked_extensions.end(); ++iter) {
538    extension_service_->ReloadExtension((*iter)->id());
539  }
540}
541
542void ExtensionSettingsHandler::PassphraseDialogCallback(bool success) {
543  if (!success)
544    return;
545  ManagedModeNavigationObserver* observer =
546      ManagedModeNavigationObserver::FromWebContents(
547          web_ui()->GetWebContents());
548  observer->set_elevated(true);
549  HandleRequestExtensionsData(NULL);
550}
551
552void ExtensionSettingsHandler::ManagedUserSetElevated(const ListValue* args) {
553  ManagedUserService* service = ManagedUserServiceFactory::GetForProfile(
554      Profile::FromWebUI(web_ui()));
555  bool elevated;
556  CHECK(args->GetBoolean(0, &elevated));
557  if (elevated) {
558    service->RequestAuthorization(
559        web_ui()->GetWebContents(),
560        base::Bind(&ExtensionSettingsHandler::PassphraseDialogCallback,
561                   base::Unretained(this)));
562  } else {
563    ManagedModeNavigationObserver* observer =
564        ManagedModeNavigationObserver::FromWebContents(
565            web_ui()->GetWebContents());
566    observer->set_elevated(false);
567    HandleRequestExtensionsData(NULL);
568  }
569}
570
571scoped_ptr<ScopedExtensionElevation>
572    ExtensionSettingsHandler::GetScopedElevation(
573        const std::string& extension_id) {
574  // web_ui() can be NULL in a unit_test.
575  if (web_ui() == NULL)
576    return scoped_ptr<ScopedExtensionElevation>(NULL);
577  ManagedUserService* service = ManagedUserServiceFactory::GetForProfile(
578      Profile::FromWebUI(web_ui()));
579  scoped_ptr<ScopedExtensionElevation> elevation(
580      new ScopedExtensionElevation(service));
581  if (service->ProfileIsManaged() &&
582      service->IsElevatedForWebContents(web_ui()->GetWebContents())) {
583    elevation->AddExtension(extension_id);
584  }
585  return elevation.Pass();
586}
587
588bool ExtensionSettingsHandler::CheckUserMayModifySettings(
589    const Extension* extension) {
590  // Get managed user elevation for a specific extension id. The elevation will
591  // be removed automatically when |elevation| goes out of scope.
592  scoped_ptr<ScopedExtensionElevation> elevation =
593      GetScopedElevation(extension->id());
594  return management_policy_->UserMayModifySettings(extension, NULL);
595}
596
597void ExtensionSettingsHandler::HandleRequestExtensionsData(
598    const ListValue* args) {
599  DictionaryValue results;
600
601  Profile* profile = Profile::FromWebUI(web_ui());
602
603  // Add the extensions to the results structure.
604  ListValue *extensions_list = new ListValue();
605
606  extensions::ExtensionWarningService* warnings =
607      extensions::ExtensionSystem::Get(profile)->warning_service();
608
609  const ExtensionSet* extensions = extension_service_->extensions();
610  for (ExtensionSet::const_iterator extension = extensions->begin();
611       extension != extensions->end(); ++extension) {
612    if ((*extension)->ShouldDisplayInExtensionSettings()) {
613      extensions_list->Append(CreateExtensionDetailValue(
614          *extension,
615          GetInspectablePagesForExtension(*extension, true),
616          warnings));
617    }
618  }
619  extensions = extension_service_->disabled_extensions();
620  for (ExtensionSet::const_iterator extension = extensions->begin();
621       extension != extensions->end(); ++extension) {
622    if ((*extension)->ShouldDisplayInExtensionSettings()) {
623      extensions_list->Append(CreateExtensionDetailValue(
624          *extension,
625          GetInspectablePagesForExtension(*extension, false),
626          warnings));
627    }
628  }
629  extensions = extension_service_->terminated_extensions();
630  std::vector<ExtensionPage> empty_pages;
631  for (ExtensionSet::const_iterator extension = extensions->begin();
632       extension != extensions->end(); ++extension) {
633    if ((*extension)->ShouldDisplayInExtensionSettings()) {
634      extensions_list->Append(CreateExtensionDetailValue(
635          *extension,
636          empty_pages,  // Terminated process has no active pages.
637          warnings));
638    }
639  }
640  results.Set("extensions", extensions_list);
641
642  ManagedUserService* service =
643      ManagedUserServiceFactory::GetForProfile(profile);
644
645  bool is_managed = service->ProfileIsManaged();
646  bool is_elevated =
647      service->IsElevatedForWebContents(web_ui()->GetWebContents());
648  bool developer_mode =
649      (!is_managed || is_elevated) &&
650      profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode);
651  results.SetBoolean("profileIsManaged", is_managed);
652  results.SetBoolean("profileIsElevated", is_elevated);
653  results.SetBoolean("developerMode", developer_mode);
654
655  bool load_unpacked_disabled =
656      extension_service_->extension_prefs()->ExtensionsBlacklistedByDefault();
657  results.SetBoolean("loadUnpackedDisabled", load_unpacked_disabled);
658
659  web_ui()->CallJavascriptFunction("ExtensionSettings.returnExtensionsData",
660                                   results);
661
662  MaybeRegisterForNotifications();
663}
664
665void ExtensionSettingsHandler::HandleToggleDeveloperMode(
666    const ListValue* args) {
667  Profile* profile = Profile::FromWebUI(web_ui());
668  if (ManagedUserServiceFactory::GetForProfile(profile)->ProfileIsManaged())
669    return;
670
671  bool developer_mode =
672      profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode);
673  profile->GetPrefs()->SetBoolean(
674      prefs::kExtensionsUIDeveloperMode, !developer_mode);
675}
676
677void ExtensionSettingsHandler::HandleInspectMessage(const ListValue* args) {
678  std::string extension_id;
679  std::string render_process_id_str;
680  std::string render_view_id_str;
681  int render_process_id;
682  int render_view_id;
683  bool incognito;
684  CHECK_EQ(4U, args->GetSize());
685  CHECK(args->GetString(0, &extension_id));
686  CHECK(args->GetString(1, &render_process_id_str));
687  CHECK(args->GetString(2, &render_view_id_str));
688  CHECK(args->GetBoolean(3, &incognito));
689  CHECK(base::StringToInt(render_process_id_str, &render_process_id));
690  CHECK(base::StringToInt(render_view_id_str, &render_view_id));
691
692  if (render_process_id == -1) {
693    // This message is for a lazy background page. Start the page if necessary.
694    const Extension* extension =
695        extension_service_->extensions()->GetByID(extension_id);
696    DCHECK(extension);
697
698    ExtensionService* service = extension_service_;
699    if (incognito)
700      service = extensions::ExtensionSystem::Get(extension_service_->
701          profile()->GetOffTheRecordProfile())->extension_service();
702
703    service->InspectBackgroundPage(extension);
704    return;
705  }
706
707  RenderViewHost* host = RenderViewHost::FromID(render_process_id,
708                                                render_view_id);
709  if (!host) {
710    // This can happen if the host has gone away since the page was displayed.
711    return;
712  }
713
714  DevToolsWindow::OpenDevToolsWindow(host);
715}
716
717void ExtensionSettingsHandler::HandleLaunchMessage(const ListValue* args) {
718  CHECK_EQ(1U, args->GetSize());
719  std::string extension_id;
720  CHECK(args->GetString(0, &extension_id));
721  const extensions::Extension* extension =
722      extension_service_->GetExtensionById(extension_id, false);
723  chrome::OpenApplication(chrome::AppLaunchParams(extension_service_->profile(),
724                                                  extension,
725                                                  extension_misc::LAUNCH_WINDOW,
726                                                  NEW_WINDOW));
727}
728
729void ExtensionSettingsHandler::HandleRestartMessage(const ListValue* args) {
730  CHECK_EQ(1U, args->GetSize());
731  std::string extension_id;
732  CHECK(args->GetString(0, &extension_id));
733  extension_service_->RestartExtension(extension_id);
734}
735
736void ExtensionSettingsHandler::HandleReloadMessage(const ListValue* args) {
737  std::string extension_id = UTF16ToUTF8(ExtractStringValue(args));
738  CHECK(!extension_id.empty());
739  extension_service_->ReloadExtension(extension_id);
740}
741
742void ExtensionSettingsHandler::HandleEnableMessage(const ListValue* args) {
743  CHECK_EQ(2U, args->GetSize());
744  std::string extension_id, enable_str;
745  CHECK(args->GetString(0, &extension_id));
746  CHECK(args->GetString(1, &enable_str));
747
748  const Extension* extension =
749      extension_service_->GetInstalledExtension(extension_id);
750  if (!extension || !CheckUserMayModifySettings(extension)) {
751    LOG(ERROR) << "Attempt to enable an extension that is non-usermanagable was"
752               << "made. Extension id: " << extension->id();
753    return;
754  }
755
756  if (enable_str == "true") {
757    extensions::ExtensionPrefs* prefs = extension_service_->extension_prefs();
758    if (prefs->DidExtensionEscalatePermissions(extension_id)) {
759      extensions::ShowExtensionDisabledDialog(
760          extension_service_, web_ui()->GetWebContents(), extension);
761    } else if ((prefs->GetDisableReasons(extension_id) &
762                   Extension::DISABLE_UNSUPPORTED_REQUIREMENT) &&
763               !requirements_checker_.get()) {
764      // Recheck the requirements.
765      scoped_refptr<const Extension> extension =
766          extension_service_->GetExtensionById(extension_id,
767                                               true /* include disabled */);
768      requirements_checker_.reset(new extensions::RequirementsChecker());
769      requirements_checker_->Check(
770          extension,
771          base::Bind(&ExtensionSettingsHandler::OnRequirementsChecked,
772                     AsWeakPtr(), extension_id));
773    } else {
774      extension_service_->EnableExtension(extension_id);
775
776      // Make sure any browser action contained within it is not hidden.
777      extensions::ExtensionActionAPI::SetBrowserActionVisibility(
778          prefs, extension->id(), true);
779    }
780  } else {
781    // Get managed user elevation for a specific extension id. The elevation
782    // will be removed automatically when |elevation| goes out of scope.
783    scoped_ptr<ScopedExtensionElevation> elevation =
784        GetScopedElevation(extension_id);
785    extension_service_->DisableExtension(
786        extension_id, Extension::DISABLE_USER_ACTION);
787  }
788}
789
790void ExtensionSettingsHandler::HandleEnableIncognitoMessage(
791    const ListValue* args) {
792  CHECK_EQ(2U, args->GetSize());
793  std::string extension_id, enable_str;
794  CHECK(args->GetString(0, &extension_id));
795  CHECK(args->GetString(1, &enable_str));
796  const Extension* extension =
797      extension_service_->GetInstalledExtension(extension_id);
798  if (!extension)
799    return;
800
801  // Flipping the incognito bit will generate unload/load notifications for the
802  // extension, but we don't want to reload the page, because a) we've already
803  // updated the UI to reflect the change, and b) we want the yellow warning
804  // text to stay until the user has left the page.
805  //
806  // TODO(aa): This creates crappiness in some cases. For example, in a main
807  // window, when toggling this, the browser action will flicker because it gets
808  // unloaded, then reloaded. It would be better to have a dedicated
809  // notification for this case.
810  //
811  // Bug: http://crbug.com/41384
812  base::AutoReset<bool> auto_reset_ignore_notifications(
813      &ignore_notifications_, true);
814  extension_service_->SetIsIncognitoEnabled(extension->id(),
815                                            enable_str == "true");
816}
817
818void ExtensionSettingsHandler::HandleAllowFileAccessMessage(
819    const ListValue* args) {
820  CHECK_EQ(2U, args->GetSize());
821  std::string extension_id, allow_str;
822  CHECK(args->GetString(0, &extension_id));
823  CHECK(args->GetString(1, &allow_str));
824  const Extension* extension =
825      extension_service_->GetInstalledExtension(extension_id);
826  if (!extension)
827    return;
828
829  if (!CheckUserMayModifySettings(extension)) {
830    LOG(ERROR) << "Attempt to change allow file access of an extension that is "
831               << "non-usermanagable was made. Extension id : "
832               << extension->id();
833    return;
834  }
835
836  extension_service_->SetAllowFileAccess(extension, allow_str == "true");
837}
838
839void ExtensionSettingsHandler::HandleUninstallMessage(const ListValue* args) {
840  CHECK_EQ(1U, args->GetSize());
841  std::string extension_id;
842  CHECK(args->GetString(0, &extension_id));
843  const Extension* extension =
844      extension_service_->GetInstalledExtension(extension_id);
845  if (!extension)
846    return;
847
848  if (!CheckUserMayModifySettings(extension)) {
849    LOG(ERROR) << "Attempt to uninstall an extension that is non-usermanagable "
850               << "was made. Extension id : " << extension->id();
851    return;
852  }
853
854  if (!extension_id_prompting_.empty())
855    return;  // Only one prompt at a time.
856
857  extension_id_prompting_ = extension_id;
858
859  GetExtensionUninstallDialog()->ConfirmUninstall(extension);
860}
861
862void ExtensionSettingsHandler::HandleOptionsMessage(const ListValue* args) {
863  const Extension* extension = GetActiveExtension(args);
864  if (!extension ||
865      extensions::ManifestURL::GetOptionsPage(extension).is_empty())
866    return;
867  ExtensionTabUtil::OpenOptionsPage(extension,
868      chrome::FindBrowserWithWebContents(web_ui()->GetWebContents()));
869}
870
871void ExtensionSettingsHandler::HandlePermissionsMessage(const ListValue* args) {
872  std::string extension_id(UTF16ToUTF8(ExtractStringValue(args)));
873  CHECK(!extension_id.empty());
874  const Extension* extension =
875      extension_service_->GetExtensionById(extension_id, true);
876  if (!extension)
877    return;
878
879  prompt_.reset(new ExtensionInstallPrompt(web_contents()));
880  prompt_->ReviewPermissions(this, extension);
881}
882
883void ExtensionSettingsHandler::HandleShowButtonMessage(const ListValue* args) {
884  const Extension* extension = GetActiveExtension(args);
885  if (!extension)
886    return;
887  extensions::ExtensionActionAPI::SetBrowserActionVisibility(
888      extension_service_->extension_prefs(), extension->id(), true);
889}
890
891void ExtensionSettingsHandler::HandleAutoUpdateMessage(const ListValue* args) {
892  ExtensionUpdater* updater = extension_service_->updater();
893  if (updater) {
894    ExtensionUpdater::CheckParams params;
895    params.install_immediately = true;
896    updater->CheckNow(params);
897  }
898}
899
900void ExtensionSettingsHandler::HandleLoadUnpackedExtensionMessage(
901    const ListValue* args) {
902  DCHECK(args->empty());
903
904  string16 select_title =
905      l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY);
906
907  const int kFileTypeIndex = 0;  // No file type information to index.
908  const ui::SelectFileDialog::Type kSelectType =
909      ui::SelectFileDialog::SELECT_FOLDER;
910  load_extension_dialog_ = ui::SelectFileDialog::Create(
911      this, new ChromeSelectFilePolicy(web_ui()->GetWebContents()));
912  load_extension_dialog_->SelectFile(
913      kSelectType,
914      select_title,
915      last_unpacked_directory_,
916      NULL,
917      kFileTypeIndex,
918      base::FilePath::StringType(),
919      web_ui()->GetWebContents()->GetView()->GetTopLevelNativeWindow(),
920      NULL);
921}
922
923void ExtensionSettingsHandler::ShowAlert(const std::string& message) {
924  ListValue arguments;
925  arguments.Append(Value::CreateStringValue(message));
926  web_ui()->CallJavascriptFunction("alert", arguments);
927}
928
929const Extension* ExtensionSettingsHandler::GetActiveExtension(
930    const ListValue* args) {
931  std::string extension_id = UTF16ToUTF8(ExtractStringValue(args));
932  CHECK(!extension_id.empty());
933  return extension_service_->GetExtensionById(extension_id, false);
934}
935
936void ExtensionSettingsHandler::MaybeUpdateAfterNotification() {
937  WebContents* contents = web_ui()->GetWebContents();
938  if (!ignore_notifications_ && contents && contents->GetRenderViewHost())
939    HandleRequestExtensionsData(NULL);
940  deleting_rvh_ = NULL;
941}
942
943void ExtensionSettingsHandler::MaybeRegisterForNotifications() {
944  if (registered_for_notifications_)
945    return;
946
947  registered_for_notifications_  = true;
948  Profile* profile = Profile::FromWebUI(web_ui());
949
950  // Register for notifications that we need to reload the page.
951  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
952                 content::Source<Profile>(profile));
953  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
954                 content::Source<Profile>(profile));
955  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED,
956                 content::Source<Profile>(profile));
957  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_CREATED,
958                 content::NotificationService::AllBrowserContextsAndSources());
959  registrar_.Add(this,
960                 chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED,
961                 content::NotificationService::AllBrowserContextsAndSources());
962  registrar_.Add(this,
963                 chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED,
964                 content::NotificationService::AllBrowserContextsAndSources());
965  registrar_.Add(
966      this,
967      chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED,
968      content::Source<extensions::ExtensionPrefs>(
969          profile->GetExtensionService()->extension_prefs()));
970
971  content::RenderViewHost::AddCreatedCallback(rvh_created_callback_);
972
973  content::WebContentsObserver::Observe(web_ui()->GetWebContents());
974
975  warning_service_observer_.Add(
976      extensions::ExtensionSystem::Get(profile)->warning_service());
977
978  base::Closure callback = base::Bind(
979      &ExtensionSettingsHandler::MaybeUpdateAfterNotification,
980      base::Unretained(this));
981
982  pref_registrar_.Init(profile->GetPrefs());
983  pref_registrar_.Add(prefs::kExtensionInstallDenyList, callback);
984}
985
986std::vector<ExtensionPage>
987ExtensionSettingsHandler::GetInspectablePagesForExtension(
988    const Extension* extension, bool extension_is_enabled) {
989  std::vector<ExtensionPage> result;
990
991  // Get the extension process's active views.
992  ExtensionProcessManager* process_manager =
993      extensions::ExtensionSystem::Get(extension_service_->profile())->
994          process_manager();
995  GetInspectablePagesForExtensionProcess(
996      process_manager->GetRenderViewHostsForExtension(extension->id()),
997      &result);
998
999  // Get shell window views
1000  GetShellWindowPagesForExtensionProfile(extension,
1001      extension_service_->profile(), &result);
1002
1003  // Include a link to start the lazy background page, if applicable.
1004  if (extensions::BackgroundInfo::HasLazyBackgroundPage(extension) &&
1005      extension_is_enabled &&
1006      !process_manager->GetBackgroundHostForExtension(extension->id())) {
1007    result.push_back(
1008        ExtensionPage(extensions::BackgroundInfo::GetBackgroundURL(extension),
1009                      -1, -1, false));
1010  }
1011
1012  // Repeat for the incognito process, if applicable. Don't try to get
1013  // shell windows for incognito processes.
1014  if (extension_service_->profile()->HasOffTheRecordProfile() &&
1015      extensions::IncognitoInfo::IsSplitMode(extension)) {
1016    ExtensionProcessManager* process_manager =
1017        extensions::ExtensionSystem::Get(extension_service_->profile()->
1018            GetOffTheRecordProfile())->process_manager();
1019    GetInspectablePagesForExtensionProcess(
1020        process_manager->GetRenderViewHostsForExtension(extension->id()),
1021        &result);
1022
1023    if (extensions::BackgroundInfo::HasLazyBackgroundPage(extension)
1024        && extension_is_enabled &&
1025        !process_manager->GetBackgroundHostForExtension(extension->id())) {
1026      result.push_back(
1027          ExtensionPage(extensions::BackgroundInfo::GetBackgroundURL(extension),
1028                        -1, -1, true));
1029    }
1030  }
1031
1032  return result;
1033}
1034
1035void ExtensionSettingsHandler::GetInspectablePagesForExtensionProcess(
1036    const std::set<RenderViewHost*>& views,
1037    std::vector<ExtensionPage>* result) {
1038  for (std::set<RenderViewHost*>::const_iterator iter = views.begin();
1039       iter != views.end(); ++iter) {
1040    RenderViewHost* host = *iter;
1041    WebContents* web_contents = WebContents::FromRenderViewHost(host);
1042    extensions::ViewType host_type = extensions::GetViewType(web_contents);
1043    if (host == deleting_rvh_ ||
1044        extensions::VIEW_TYPE_EXTENSION_POPUP == host_type ||
1045        extensions::VIEW_TYPE_EXTENSION_DIALOG == host_type)
1046      continue;
1047
1048    GURL url = web_contents->GetURL();
1049    content::RenderProcessHost* process = host->GetProcess();
1050    result->push_back(
1051        ExtensionPage(url, process->GetID(), host->GetRoutingID(),
1052                      process->GetBrowserContext()->IsOffTheRecord()));
1053  }
1054}
1055
1056void ExtensionSettingsHandler::GetShellWindowPagesForExtensionProfile(
1057    const Extension* extension,
1058    Profile* profile,
1059    std::vector<ExtensionPage>* result) {
1060  extensions::ShellWindowRegistry* registry =
1061      extensions::ShellWindowRegistry::Get(profile);
1062  if (!registry) return;
1063
1064  const extensions::ShellWindowRegistry::ShellWindowSet windows =
1065      registry->GetShellWindowsForApp(extension->id());
1066
1067  for (extensions::ShellWindowRegistry::const_iterator it = windows.begin();
1068       it != windows.end(); ++it) {
1069    WebContents* web_contents = (*it)->web_contents();
1070    RenderViewHost* host = web_contents->GetRenderViewHost();
1071    content::RenderProcessHost* process = host->GetProcess();
1072
1073    result->push_back(
1074        ExtensionPage(web_contents->GetURL(), process->GetID(),
1075                      host->GetRoutingID(),
1076                      process->GetBrowserContext()->IsOffTheRecord()));
1077  }
1078}
1079
1080ExtensionUninstallDialog*
1081ExtensionSettingsHandler::GetExtensionUninstallDialog() {
1082#if !defined(OS_ANDROID)
1083  if (!extension_uninstall_dialog_.get()) {
1084    Browser* browser = chrome::FindBrowserWithWebContents(
1085        web_ui()->GetWebContents());
1086    extension_uninstall_dialog_.reset(
1087        ExtensionUninstallDialog::Create(extension_service_->profile(),
1088                                         browser, this));
1089  }
1090  return extension_uninstall_dialog_.get();
1091#else
1092  return NULL;
1093#endif  // !defined(OS_ANDROID)
1094}
1095
1096void ExtensionSettingsHandler::OnRequirementsChecked(
1097    std::string extension_id,
1098    std::vector<std::string> requirement_errors) {
1099  if (requirement_errors.empty()) {
1100    extension_service_->EnableExtension(extension_id);
1101  } else {
1102    ExtensionErrorReporter::GetInstance()->ReportError(
1103        UTF8ToUTF16(JoinString(requirement_errors, ' ')),
1104        true /* be noisy */);
1105  }
1106  requirements_checker_.reset();
1107}
1108