summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/extensions/api/developer_private/developer_private_api.cc50
-rw-r--r--chrome/browser/extensions/api/developer_private/developer_private_api.h31
-rw-r--r--chrome/browser/extensions/api/developer_private/extension_info_generator.cc65
-rw-r--r--chrome/browser/extensions/api/developer_private/extension_info_generator.h2
-rw-r--r--chrome/browser/resources/extensions/extension_command_list.js89
-rw-r--r--chrome/browser/resources/extensions/extension_commands_overlay.js37
-rw-r--r--chrome/browser/resources/extensions/extension_list.js15
-rw-r--r--chrome/browser/ui/webui/extensions/command_handler.cc200
-rw-r--r--chrome/browser/ui/webui/extensions/command_handler.h85
-rw-r--r--chrome/browser/ui/webui/extensions/extension_settings_handler.cc17
-rw-r--r--chrome/browser/ui/webui/extensions/extensions_ui.cc5
-rw-r--r--chrome/chrome_browser_ui.gypi2
-rw-r--r--chrome/common/extensions/api/developer_private.idl32
-rw-r--r--chrome/common/extensions/command.cc24
-rw-r--r--chrome/common/extensions/command.h5
-rw-r--r--extensions/browser/extension_function_histogram_value.h2
-rw-r--r--third_party/closure_compiler/externs/developer_private.js54
-rw-r--r--tools/metrics/histograms/histograms.xml2
18 files changed, 346 insertions, 371 deletions
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api.cc b/chrome/browser/extensions/api/developer_private/developer_private_api.cc
index 67c2add..8807294 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api.cc
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api.cc
@@ -12,6 +12,7 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/devtools/devtools_window.h"
+#include "chrome/browser/extensions/api/commands/command_service.h"
#include "chrome/browser/extensions/api/developer_private/developer_private_mangle.h"
#include "chrome/browser/extensions/api/developer_private/entry_picker.h"
#include "chrome/browser/extensions/api/developer_private/extension_info_generator.h"
@@ -19,6 +20,7 @@
#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
#include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
#include "chrome/browser/extensions/devtools_util.h"
+#include "chrome/browser/extensions/extension_commands_global_registry.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/extensions/extension_ui_util.h"
@@ -235,6 +237,12 @@ void DeveloperPrivateEventRouter::RemoveExtensionId(
extension_ids_.erase(extension_id);
}
+void DeveloperPrivateEventRouter::NotifyExtensionCommandUpdated(
+ const std::string& extension_id) {
+ BroadcastItemStateChanged(developer::EVENT_TYPE_PREFS_CHANGED,
+ extension_id);
+}
+
void DeveloperPrivateEventRouter::OnExtensionLoaded(
content::BrowserContext* browser_context,
const Extension* extension) {
@@ -1379,6 +1387,48 @@ ExtensionFunction::ResponseAction DeveloperPrivateShowPathFunction::Run() {
return RespondNow(NoArguments());
}
+DeveloperPrivateSetShortcutHandlingSuspendedFunction::
+~DeveloperPrivateSetShortcutHandlingSuspendedFunction() {}
+
+ExtensionFunction::ResponseAction
+DeveloperPrivateSetShortcutHandlingSuspendedFunction::Run() {
+ scoped_ptr<developer::SetShortcutHandlingSuspended::Params> params(
+ developer::SetShortcutHandlingSuspended::Params::Create(*args_));
+ EXTENSION_FUNCTION_VALIDATE(params);
+ ExtensionCommandsGlobalRegistry::Get(GetProfile())->
+ SetShortcutHandlingSuspended(params->is_suspended);
+ return RespondNow(NoArguments());
+}
+
+DeveloperPrivateUpdateExtensionCommandFunction::
+~DeveloperPrivateUpdateExtensionCommandFunction() {}
+
+ExtensionFunction::ResponseAction
+DeveloperPrivateUpdateExtensionCommandFunction::Run() {
+ scoped_ptr<developer::UpdateExtensionCommand::Params> params(
+ developer::UpdateExtensionCommand::Params::Create(*args_));
+ EXTENSION_FUNCTION_VALIDATE(params);
+ const developer::ExtensionCommandUpdate& update = params->update;
+
+ CommandService* command_service = CommandService::Get(GetProfile());
+
+ if (update.scope != developer::COMMAND_SCOPE_NONE) {
+ command_service->SetScope(update.extension_id, update.command_name,
+ update.scope == developer::COMMAND_SCOPE_GLOBAL);
+ }
+
+ if (update.keybinding) {
+ command_service->UpdateKeybindingPrefs(
+ update.extension_id, update.command_name, *update.keybinding);
+ }
+
+ DeveloperPrivateAPI::Get(browser_context())->
+ developer_private_event_router()->
+ NotifyExtensionCommandUpdated(update.extension_id);
+ return RespondNow(NoArguments());
+}
+
+
} // namespace api
} // namespace extensions
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api.h b/chrome/browser/extensions/api/developer_private/developer_private_api.h
index ad2227f..3127f0f 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api.h
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api.h
@@ -67,6 +67,11 @@ class DeveloperPrivateEventRouter : public ExtensionRegistryObserver,
void AddExtensionId(const std::string& extension_id);
void RemoveExtensionId(const std::string& extension_id);
+ // Notifies the event router that an extension's command has been updated.
+ // Since this presently only happens through this API, this doesn't need to
+ // be an observer method. If that changes, we should revisit it.
+ void NotifyExtensionCommandUpdated(const std::string& extension_id);
+
private:
// ExtensionRegistryObserver:
void OnExtensionLoaded(content::BrowserContext* browser_context,
@@ -181,6 +186,10 @@ class DeveloperPrivateAPI : public BrowserContextKeyedAPI,
void OnListenerAdded(const EventListenerInfo& details) override;
void OnListenerRemoved(const EventListenerInfo& details) override;
+ DeveloperPrivateEventRouter* developer_private_event_router() {
+ return developer_private_event_router_.get();
+ }
+
private:
friend class BrowserContextKeyedAPIFactory<DeveloperPrivateAPI>;
@@ -571,6 +580,28 @@ class DeveloperPrivateShowPathFunction : public DeveloperPrivateAPIFunction {
ResponseAction Run() override;
};
+class DeveloperPrivateSetShortcutHandlingSuspendedFunction
+ : public DeveloperPrivateAPIFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("developerPrivate.setShortcutHandlingSuspended",
+ DEVELOPERPRIVATE_SETSHORTCUTHANDLINGSUSPENDED);
+
+ protected:
+ ~DeveloperPrivateSetShortcutHandlingSuspendedFunction() override;
+ ResponseAction Run() override;
+};
+
+class DeveloperPrivateUpdateExtensionCommandFunction
+ : public DeveloperPrivateAPIFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("developerPrivate.updateExtensionCommand",
+ DEVELOPERPRIVATE_UPDATEEXTENSIONCOMMAND);
+
+ protected:
+ ~DeveloperPrivateUpdateExtensionCommandFunction() override;
+ ResponseAction Run() override;
+};
+
} // namespace api
} // namespace extensions
diff --git a/chrome/browser/extensions/api/developer_private/extension_info_generator.cc b/chrome/browser/extensions/api/developer_private/extension_info_generator.cc
index 17048f5..97738c0 100644
--- a/chrome/browser/extensions/api/developer_private/extension_info_generator.cc
+++ b/chrome/browser/extensions/api/developer_private/extension_info_generator.cc
@@ -6,6 +6,7 @@
#include "base/base64.h"
#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/extensions/api/commands/command_service.h"
#include "chrome/browser/extensions/api/developer_private/inspectable_views_finder.h"
#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
#include "chrome/browser/extensions/error_console/error_console.h"
@@ -16,6 +17,7 @@
#include "chrome/browser/extensions/shared_module_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
+#include "chrome/common/extensions/command.h"
#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
#include "chrome/grit/generated_resources.h"
#include "content/public/browser/render_view_host.h"
@@ -143,11 +145,66 @@ linked_ptr<developer::RuntimeError> ConstructRuntimeError(
return result;
}
+// Constructs any commands for the extension with the given |id|, and adds them
+// to the list of |commands|.
+void ConstructCommands(CommandService* command_service,
+ const std::string& extension_id,
+ std::vector<linked_ptr<developer::Command>>* commands) {
+ auto construct_command = [](const Command& command,
+ bool active,
+ bool is_extension_action) {
+ developer::Command* command_value = new developer::Command();
+ command_value->description = is_extension_action ?
+ l10n_util::GetStringUTF8(IDS_EXTENSION_COMMANDS_GENERIC_ACTIVATE) :
+ base::UTF16ToUTF8(command.description());
+ command_value->keybinding =
+ base::UTF16ToUTF8(command.accelerator().GetShortcutText());
+ command_value->name = command.command_name();
+ command_value->is_active = active;
+ command_value->scope = command.global() ? developer::COMMAND_SCOPE_GLOBAL :
+ developer::COMMAND_SCOPE_CHROME;
+ command_value->is_extension_action = is_extension_action;
+ return command_value;
+ };
+ bool active = false;
+ Command browser_action;
+ if (command_service->GetBrowserActionCommand(extension_id,
+ CommandService::ALL,
+ &browser_action,
+ &active)) {
+ commands->push_back(
+ make_linked_ptr(construct_command(browser_action, active, true)));
+ }
+
+ Command page_action;
+ if (command_service->GetPageActionCommand(extension_id,
+ CommandService::ALL,
+ &page_action,
+ &active)) {
+ commands->push_back(
+ make_linked_ptr(construct_command(page_action, active, true)));
+ }
+
+ CommandMap named_commands;
+ if (command_service->GetNamedCommands(extension_id,
+ CommandService::ALL,
+ CommandService::ANY_SCOPE,
+ &named_commands)) {
+ for (const auto& pair : named_commands) {
+ const Command& command = pair.second;
+ bool active = command.accelerator().key_code() != ui::VKEY_UNKNOWN;
+ commands->push_back(
+ make_linked_ptr(construct_command(command, active, false)));
+ }
+ }
+}
+
} // namespace
ExtensionInfoGenerator::ExtensionInfoGenerator(
content::BrowserContext* browser_context)
: browser_context_(browser_context),
+ command_service_(CommandService::Get(browser_context)),
extension_system_(ExtensionSystem::Get(browser_context)),
extension_prefs_(ExtensionPrefs::Get(browser_context)),
extension_action_api_(ExtensionActionAPI::Get(browser_context)),
@@ -259,6 +316,7 @@ void ExtensionInfoGenerator::CreateExtensionInfoHelper(
Profile* profile = Profile::FromBrowserContext(browser_context_);
+ // ControlledInfo.
bool is_policy_location = Manifest::IsPolicyLocation(extension.location());
if (is_policy_location || util::IsExtensionSupervised(&extension, profile)) {
info->controlled_info.reset(new developer::ControlledInfo());
@@ -278,6 +336,12 @@ void ExtensionInfoGenerator::CreateExtensionInfoHelper(
}
}
+ bool is_enabled = state == developer::EXTENSION_STATE_ENABLED;
+
+ // Commands.
+ if (is_enabled)
+ ConstructCommands(command_service_, extension.id(), &info->commands);
+
// Dependent extensions.
if (extension.is_shared_module()) {
scoped_ptr<ExtensionSet> dependent_extensions =
@@ -436,7 +500,6 @@ void ExtensionInfoGenerator::CreateExtensionInfoHelper(
info->version = extension.GetVersionForDisplay();
- bool is_enabled = state == developer::EXTENSION_STATE_ENABLED;
if (state != developer::EXTENSION_STATE_TERMINATED) {
info->views = InspectableViewsFinder(profile).
GetViewsForExtension(extension, is_enabled);
diff --git a/chrome/browser/extensions/api/developer_private/extension_info_generator.h b/chrome/browser/extensions/api/developer_private/extension_info_generator.h
index 626e56a..51d8c91 100644
--- a/chrome/browser/extensions/api/developer_private/extension_info_generator.h
+++ b/chrome/browser/extensions/api/developer_private/extension_info_generator.h
@@ -19,6 +19,7 @@ class Image;
}
namespace extensions {
+class CommandService;
class ErrorConsole;
class Extension;
class ExtensionActionAPI;
@@ -70,6 +71,7 @@ class ExtensionInfoGenerator {
// Various systems, cached for convenience.
content::BrowserContext* browser_context_;
+ CommandService* command_service_;
ExtensionSystem* extension_system_;
ExtensionPrefs* extension_prefs_;
ExtensionActionAPI* extension_action_api_;
diff --git a/chrome/browser/resources/extensions/extension_command_list.js b/chrome/browser/resources/extensions/extension_command_list.js
index 0a184dc..aa0a3cc 100644
--- a/chrome/browser/resources/extensions/extension_command_list.js
+++ b/chrome/browser/resources/extensions/extension_command_list.js
@@ -15,14 +15,6 @@ var ExtensionCommand;
cr.define('options', function() {
'use strict';
- /**
- * Creates a new list of extension commands.
- * @param {Object=} opt_propertyBag Optional properties.
- * @constructor
- * @extends {HTMLDivElement}
- */
- var ExtensionCommandList = cr.ui.define('div');
-
/** @const */ var keyComma = 188;
/** @const */ var keyDel = 46;
/** @const */ var keyDown = 40;
@@ -184,6 +176,17 @@ cr.define('options', function() {
(countShiftAsModifier && event.shiftKey);
}
+ /**
+ * Creates a new list of extension commands.
+ * @param {HTMLDivElement} div
+ * @constructor
+ * @extends {HTMLDivElement}
+ */
+ function ExtensionCommandList(div) {
+ div.__proto__ = ExtensionCommandList.prototype;
+ return div;
+ }
+
ExtensionCommandList.prototype = {
__proto__: HTMLDivElement.prototype,
@@ -212,20 +215,30 @@ cr.define('options', function() {
*/
capturingElement_: null,
- decorate: function() {
+ /**
+ * Updates the extensions data for the overlay.
+ * @param {!Array<ExtensionInfo>} data The extension data.
+ */
+ setData: function(data) {
+ /** @private {!Array<ExtensionInfo>} */
+ this.data_ = data;
+
this.textContent = '';
// Iterate over the extension data and add each item to the list.
- this.data_.commands.forEach(this.createNodeForExtension_.bind(this));
+ this.data_.forEach(this.createNodeForExtension_.bind(this));
},
/**
* Synthesizes and initializes an HTML element for the extension command
* metadata given in |extension|.
- * @param {Object} extension A dictionary of extension metadata.
+ * @param {ExtensionInfo} extension A dictionary of extension metadata.
* @private
*/
createNodeForExtension_: function(extension) {
+ if (extension.commands.length == 0)
+ return;
+
var template = $('template-collection-extension-commands').querySelector(
'.extension-command-list-extension-item-wrapper');
var node = template.cloneNode(true);
@@ -237,22 +250,22 @@ cr.define('options', function() {
// Iterate over the commands data within the extension and add each item
// to the list.
- extension.commands.forEach(this.createNodeForCommand_.bind(this));
+ extension.commands.forEach(
+ this.createNodeForCommand_.bind(this, extension.id));
},
/**
* Synthesizes and initializes an HTML element for the extension command
* metadata given in |command|.
- * @param {ExtensionCommand} command A dictionary of extension command
- * metadata.
+ * @param {string} extensionId The associated extension's id.
+ * @param {Command} command A dictionary of extension command metadata.
* @private
*/
- createNodeForCommand_: function(command) {
+ createNodeForCommand_: function(extensionId, command) {
var template = $('template-collection-extension-commands').querySelector(
'.extension-command-list-command-item-wrapper');
var node = template.cloneNode(true);
- node.id = this.createElementId_(
- 'command', command.extension_id, command.command_name);
+ node.id = this.createElementId_('command', extensionId, command.name);
var description = node.querySelector('.command-description');
description.textContent = command.description;
@@ -264,7 +277,7 @@ cr.define('options', function() {
shortcutNode.addEventListener('blur', this.handleBlur_.bind(this));
shortcutNode.addEventListener('keydown', this.handleKeyDown_.bind(this));
shortcutNode.addEventListener('keyup', this.handleKeyUp_.bind(this));
- if (!command.active) {
+ if (!command.isActive) {
shortcutNode.textContent =
loadTimeData.getString('extensionCommandsInactive');
@@ -276,19 +289,19 @@ cr.define('options', function() {
var commandClear = node.querySelector('.command-clear');
commandClear.id = this.createElementId_(
- 'clear', command.extension_id, command.command_name);
+ 'clear', extensionId, command.name);
commandClear.title = loadTimeData.getString('extensionCommandsDelete');
commandClear.addEventListener('click', this.handleClear_.bind(this));
var select = node.querySelector('.command-scope');
select.id = this.createElementId_(
- 'setCommandScope', command.extension_id, command.command_name);
+ 'setCommandScope', extensionId, command.name);
select.hidden = false;
// Add the 'In Chrome' option.
var option = document.createElement('option');
option.textContent = loadTimeData.getString('extensionCommandsRegular');
select.appendChild(option);
- if (command.extension_action) {
+ if (command.isExtensionAction) {
// Extension actions cannot be global, so we might as well disable the
// combo box, to signify that.
select.disabled = true;
@@ -297,7 +310,7 @@ cr.define('options', function() {
option = document.createElement('option');
option.textContent = loadTimeData.getString('extensionCommandsGlobal');
select.appendChild(option);
- select.selectedIndex = command.global ? 1 : 0;
+ select.selectedIndex = command.isGlobal ? 1 : 0;
select.addEventListener(
'change', this.handleSetCommandScope_.bind(this));
@@ -316,7 +329,7 @@ cr.define('options', function() {
if (this.capturingElement_)
return; // Already capturing.
- chrome.send('setShortcutHandlingSuspended', [true]);
+ chrome.developerPrivate.setShortcutHandlingSuspended(true);
var shortcutNode = event.target;
this.oldValue_ = shortcutNode.textContent;
@@ -341,7 +354,7 @@ cr.define('options', function() {
if (!this.capturingElement_)
return; // Not capturing.
- chrome.send('setShortcutHandlingSuspended', [false]);
+ chrome.developerPrivate.setShortcutHandlingSuspended(false);
var shortcutNode = this.capturingElement_;
var commandShortcut = shortcutNode.parentElement;
@@ -406,8 +419,11 @@ cr.define('options', function() {
this.endCapture_(event);
var parsed = this.parseElementId_('clear',
event.target.parentElement.querySelector('.command-clear').id);
- chrome.send('setExtensionCommandShortcut',
- [parsed.extensionId, parsed.commandName, '']);
+ chrome.developerPrivate.updateExtensionCommand({
+ extensionId: parsed.extensionId,
+ commandName: parsed.commandName,
+ keybinding: ''
+ });
event.preventDefault();
event.stopPropagation();
return;
@@ -496,8 +512,10 @@ cr.define('options', function() {
// Ending the capture must occur before calling
// setExtensionCommandShortcut to ensure the shortcut is set.
this.endCapture_(event);
- chrome.send('setExtensionCommandShortcut',
- [parsed.extensionId, parsed.commandName, keystroke]);
+ chrome.developerPrivate.updateExtensionCommand(
+ {extensionId: parsed.extensionId,
+ commandName: parsed.commandName,
+ keybinding: keystroke});
}
},
@@ -508,8 +526,10 @@ cr.define('options', function() {
*/
handleClear_: function(event) {
var parsed = this.parseElementId_('clear', event.target.id);
- chrome.send('setExtensionCommandShortcut',
- [parsed.extensionId, parsed.commandName, '']);
+ chrome.developerPrivate.updateExtensionCommand(
+ {extensionId: parsed.extensionId,
+ commandName: parsed.commandName,
+ keybinding: ''});
},
/**
@@ -521,8 +541,13 @@ cr.define('options', function() {
var parsed = this.parseElementId_('setCommandScope', event.target.id);
var element = document.getElementById(
'setCommandScope-' + parsed.extensionId + '-' + parsed.commandName);
- chrome.send('setCommandScope',
- [parsed.extensionId, parsed.commandName, element.selectedIndex == 1]);
+ var scope = element.selectedIndex == 1 ?
+ chrome.developerPrivate.CommandScope.GLOBAL :
+ chrome.developerPrivate.CommandScope.CHROME;
+ chrome.developerPrivate.updateExtensionCommand(
+ {extensionId: parsed.extensionId,
+ commandName: parsed.commandName,
+ scope: scope});
},
/**
diff --git a/chrome/browser/resources/extensions/extension_commands_overlay.js b/chrome/browser/resources/extensions/extension_commands_overlay.js
index a96ef44..ab56eb4 100644
--- a/chrome/browser/resources/extensions/extension_commands_overlay.js
+++ b/chrome/browser/resources/extensions/extension_commands_overlay.js
@@ -31,12 +31,14 @@ cr.define('extensions', function() {
cr.ui.overlay.globalInitialization();
overlay.addEventListener('cancelOverlay', this.handleDismiss_.bind(this));
+ this.extensionCommandList_ = new ExtensionCommandList(
+ /**@type {HTMLDivElement} */($('extension-command-list')));
+
$('extension-commands-dismiss').addEventListener('click',
this.handleDismiss_.bind(this));
- // This will request the data to show on the page and will get a response
- // back in returnExtensionsData.
- chrome.send('extensionCommandsRequestExtensionsData');
+ // The ExtensionList will update us with its data, so we don't need to
+ // handle that here.
},
/**
@@ -51,25 +53,28 @@ cr.define('extensions', function() {
/**
* Called by the dom_ui_ to re-populate the page with data representing
* the current state of extension commands.
- * @param {!{commands: Array<{name: string, id: string, commands: ?Array}>}}
- * extensionsData
+ * @param {!Array<ExtensionInfo>} extensionsData
*/
- ExtensionCommandsOverlay.returnExtensionsData = function(extensionsData) {
- ExtensionCommandList.prototype.data_ = extensionsData;
- var extensionCommandList = $('extension-command-list');
- ExtensionCommandList.decorate(extensionCommandList);
+ ExtensionCommandsOverlay.updateExtensionsData = function(extensionsData) {
+ var overlay = ExtensionCommandsOverlay.getInstance();
+ overlay.extensionCommandList_.setData(extensionsData);
+
+ var hasAnyCommands = false;
+ for (var i = 0; i < extensionsData.length; ++i) {
+ if (extensionsData[i].commands.length > 0) {
+ hasAnyCommands = true;
+ break;
+ }
+ }
// Make sure the config link is visible, since there are commands to show
// and potentially configure.
document.querySelector('.extension-commands-config').hidden =
- extensionsData.commands.length == 0;
+ !hasAnyCommands;
- $('no-commands').hidden = extensionsData.commands.length > 0;
- var list = $('extension-command-list');
- if (extensionsData.commands.length == 0)
- list.classList.add('empty-extension-commands-list');
- else
- list.classList.remove('empty-extension-commands-list');
+ $('no-commands').hidden = hasAnyCommands;
+ overlay.extensionCommandList_.classList.toggle(
+ 'empty-extension-commands-list', !hasAnyCommands);
};
// Export
diff --git a/chrome/browser/resources/extensions/extension_list.js b/chrome/browser/resources/extensions/extension_list.js
index 7fa99909..c9f866b 100644
--- a/chrome/browser/resources/extensions/extension_list.js
+++ b/chrome/browser/resources/extensions/extension_list.js
@@ -147,6 +147,8 @@ ExtensionFocusRow.prototype = {
cr.define('extensions', function() {
'use strict';
+ var ExtensionCommandsOverlay = extensions.ExtensionCommandsOverlay;
+
/**
* Compares two extensions for the order they should appear in the list.
* @param {ExtensionInfo} a The first extension.
@@ -294,6 +296,14 @@ cr.define('extensions', function() {
eventData.event_type == EventType.UNINSTALLED) {
this.delegate_.onExtensionCountChanged();
}
+
+ if (eventData.event_type == EventType.INSTALLED ||
+ eventData.event_type == EventType.UNINSTALLED ||
+ eventData.event_type == EventType.PREFS_CHANGED) {
+ // We update the commands overlay whenever an extension is added or
+ // removed (other updates wouldn't affect command-ly things).
+ ExtensionCommandsOverlay.updateExtensionsData(this.extensions_);
+ }
}.bind(this));
},
@@ -320,6 +330,11 @@ cr.define('extensions', function() {
extensions.sort(compareExtensions);
this.extensions_ = extensions;
this.showExtensionNodes_();
+
+ // We keep the commands overlay's extension info in sync, so that we
+ // don't duplicate the same querying logic there.
+ ExtensionCommandsOverlay.updateExtensionsData(this.extensions_);
+
resolve();
// |resolve| is async so it's necessary to use |then| here in order to
diff --git a/chrome/browser/ui/webui/extensions/command_handler.cc b/chrome/browser/ui/webui/extensions/command_handler.cc
deleted file mode 100644
index 79f942a..0000000
--- a/chrome/browser/ui/webui/extensions/command_handler.cc
+++ /dev/null
@@ -1,200 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/webui/extensions/command_handler.h"
-
-#include "base/bind.h"
-#include "base/values.h"
-#include "chrome/browser/extensions/api/commands/command_service.h"
-#include "chrome/browser/extensions/extension_commands_global_registry.h"
-#include "chrome/browser/extensions/extension_keybinding_registry.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/grit/generated_resources.h"
-#include "content/public/browser/web_ui.h"
-#include "content/public/browser/web_ui_data_source.h"
-#include "extensions/browser/extension_registry.h"
-#include "extensions/browser/extension_system.h"
-#include "extensions/common/extension_set.h"
-#include "ui/base/l10n/l10n_util.h"
-
-namespace extensions {
-
-CommandHandler::CommandHandler(Profile* profile)
- : profile_(profile),
- extension_registry_observer_(this) {
-}
-
-CommandHandler::~CommandHandler() {
-}
-
-void CommandHandler::GetLocalizedValues(content::WebUIDataSource* source) {
- source->AddString("extensionCommandsOverlay",
- l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_DIALOG_TITLE));
- source->AddString("extensionCommandsEmpty",
- l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_EMPTY));
- source->AddString("extensionCommandsInactive",
- l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_INACTIVE));
- source->AddString("extensionCommandsStartTyping",
- l10n_util::GetStringUTF16(IDS_EXTENSION_TYPE_SHORTCUT));
- source->AddString("extensionCommandsDelete",
- l10n_util::GetStringUTF16(IDS_EXTENSION_DELETE_SHORTCUT));
- source->AddString("extensionCommandsGlobal",
- l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_GLOBAL));
- source->AddString("extensionCommandsRegular",
- l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_NOT_GLOBAL));
- source->AddString("ok", l10n_util::GetStringUTF16(IDS_OK));
-}
-
-void CommandHandler::RegisterMessages() {
- extension_registry_observer_.Add(ExtensionRegistry::Get(profile_));
-
- web_ui()->RegisterMessageCallback("extensionCommandsRequestExtensionsData",
- base::Bind(&CommandHandler::HandleRequestExtensionsData,
- base::Unretained(this)));
- web_ui()->RegisterMessageCallback("setShortcutHandlingSuspended",
- base::Bind(&CommandHandler::HandleSetShortcutHandlingSuspended,
- base::Unretained(this)));
- web_ui()->RegisterMessageCallback("setExtensionCommandShortcut",
- base::Bind(&CommandHandler::HandleSetExtensionCommandShortcut,
- base::Unretained(this)));
- web_ui()->RegisterMessageCallback("setCommandScope",
- base::Bind(&CommandHandler::HandleSetCommandScope,
- base::Unretained(this)));
-}
-
-void CommandHandler::OnExtensionLoaded(content::BrowserContext* browser_context,
- const Extension* extension) {
- UpdateCommandDataOnPage();
-}
-
-void CommandHandler::OnExtensionUnloaded(
- content::BrowserContext* browser_context,
- const Extension* extension,
- UnloadedExtensionInfo::Reason reason) {
- UpdateCommandDataOnPage();
-}
-
-void CommandHandler::UpdateCommandDataOnPage() {
- base::DictionaryValue results;
- GetAllCommands(&results);
- web_ui()->CallJavascriptFunction(
- "extensions.ExtensionCommandsOverlay.returnExtensionsData", results);
-}
-
-void CommandHandler::HandleRequestExtensionsData(const base::ListValue* args) {
- UpdateCommandDataOnPage();
-}
-
-void CommandHandler::HandleSetExtensionCommandShortcut(
- const base::ListValue* args) {
- std::string extension_id;
- std::string command_name;
- std::string keystroke;
- if (!args->GetString(0, &extension_id) ||
- !args->GetString(1, &command_name) ||
- !args->GetString(2, &keystroke)) {
- NOTREACHED();
- return;
- }
-
- Profile* profile = Profile::FromWebUI(web_ui());
- CommandService* command_service = CommandService::Get(profile);
- command_service->UpdateKeybindingPrefs(extension_id, command_name, keystroke);
-
- UpdateCommandDataOnPage();
-}
-
-void CommandHandler::HandleSetCommandScope(
- const base::ListValue* args) {
- std::string extension_id;
- std::string command_name;
- bool global;
- if (!args->GetString(0, &extension_id) ||
- !args->GetString(1, &command_name) ||
- !args->GetBoolean(2, &global)) {
- NOTREACHED();
- return;
- }
-
- Profile* profile = Profile::FromWebUI(web_ui());
- CommandService* command_service = CommandService::Get(profile);
- if (command_service->SetScope(extension_id, command_name, global))
- UpdateCommandDataOnPage();
-}
-
-void CommandHandler::HandleSetShortcutHandlingSuspended(
- const base::ListValue* args) {
- bool suspended;
- if (args->GetBoolean(0, &suspended)) {
- ExtensionCommandsGlobalRegistry::Get(Profile::FromWebUI(web_ui()))->
- SetShortcutHandlingSuspended(suspended);
- }
-}
-
-void CommandHandler::GetAllCommands(base::DictionaryValue* commands) {
- base::ListValue* results = new base::ListValue;
-
- Profile* profile = Profile::FromWebUI(web_ui());
- CommandService* command_service = CommandService::Get(profile);
-
- const ExtensionSet& extensions =
- ExtensionRegistry::Get(profile)->enabled_extensions();
- for (ExtensionSet::const_iterator extension = extensions.begin();
- extension != extensions.end();
- ++extension) {
- scoped_ptr<base::DictionaryValue> extension_dict(new base::DictionaryValue);
- extension_dict->SetString("name", (*extension)->name());
- extension_dict->SetString("id", (*extension)->id());
-
- // Add the keybindings to a list structure.
- scoped_ptr<base::ListValue> extensions_list(new base::ListValue());
-
- bool active = false;
-
- Command browser_action;
- if (command_service->GetBrowserActionCommand((*extension)->id(),
- CommandService::ALL,
- &browser_action,
- &active)) {
- extensions_list->Append(
- browser_action.ToValue((extension->get()), active));
- }
-
- Command page_action;
- if (command_service->GetPageActionCommand((*extension)->id(),
- CommandService::ALL,
- &page_action,
- &active)) {
- extensions_list->Append(page_action.ToValue((extension->get()), active));
- }
-
- CommandMap named_commands;
- if (command_service->GetNamedCommands((*extension)->id(),
- CommandService::ALL,
- CommandService::ANY_SCOPE,
- &named_commands)) {
- for (CommandMap::const_iterator iter = named_commands.begin();
- iter != named_commands.end();
- ++iter) {
- Command command = command_service->FindCommandByName(
- (*extension)->id(), iter->second.command_name());
- ui::Accelerator shortcut_assigned = command.accelerator();
-
- active = (shortcut_assigned.key_code() != ui::VKEY_UNKNOWN);
-
- extensions_list->Append(
- iter->second.ToValue((extension->get()), active));
- }
- }
-
- if (!extensions_list->empty()) {
- extension_dict->Set("commands", extensions_list.release());
- results->Append(extension_dict.release());
- }
- }
-
- commands->Set("commands", results);
-}
-
-} // namespace extensions
diff --git a/chrome/browser/ui/webui/extensions/command_handler.h b/chrome/browser/ui/webui/extensions/command_handler.h
deleted file mode 100644
index 7bc62d7..0000000
--- a/chrome/browser/ui/webui/extensions/command_handler.h
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_WEBUI_EXTENSIONS_COMMAND_HANDLER_H_
-#define CHROME_BROWSER_UI_WEBUI_EXTENSIONS_COMMAND_HANDLER_H_
-
-#include "base/compiler_specific.h"
-#include "base/scoped_observer.h"
-#include "content/public/browser/web_ui_message_handler.h"
-#include "extensions/browser/extension_registry_observer.h"
-
-class Profile;
-
-namespace base {
-class DictionaryValue;
-class ListValue;
-}
-
-namespace content {
-class WebUIDataSource;
-}
-
-namespace extensions {
-class Command;
-class CommandService;
-class Extension;
-class ExtensionRegistry;
-
-// The handler page for the Extension Commands UI overlay.
-class CommandHandler : public content::WebUIMessageHandler,
- public ExtensionRegistryObserver {
- public:
- explicit CommandHandler(Profile* profile);
- ~CommandHandler() override;
-
- // Fetches the localized values for the page and deposits them into |source|.
- void GetLocalizedValues(content::WebUIDataSource* source);
-
- // WebUIMessageHandler implementation.
- void RegisterMessages() override;
-
- private:
- // ExtensionRegistryObserver implementation.
- void OnExtensionLoaded(content::BrowserContext* browser_context,
- const Extension* extension) override;
- void OnExtensionUnloaded(content::BrowserContext* browser_context,
- const Extension* extension,
- UnloadedExtensionInfo::Reason reason) override;
-
- // Update the list of extension commands in the config UI.
- void UpdateCommandDataOnPage();
-
- // Handles requests from javascript to fetch the extensions data, including
- // the commands it contains.
- // Replies back through: ExtensionCommandsOverlay.returnExtensionsData.
- void HandleRequestExtensionsData(const base::ListValue* args);
-
- // Handles requests from javascript to set a particular keyboard shortcut
- // for a given extension command.
- void HandleSetExtensionCommandShortcut(const base::ListValue* args);
-
- // Handles requests from javascript to change the scope of a particular
- // keyboard shortcut for a given extension command.
- void HandleSetCommandScope(const base::ListValue* args);
-
- // Handles requests from javascript to temporarily disable general Chrome
- // shortcut handling while the web page is capturing which shortcut to use.
- void HandleSetShortcutHandlingSuspended(const base::ListValue* args);
-
- // Fetches all known commands, active and inactive and returns them through
- // |commands|.
- void GetAllCommands(base::DictionaryValue* commands);
-
- Profile* profile_;
-
- ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver>
- extension_registry_observer_;
-
- DISALLOW_COPY_AND_ASSIGN(CommandHandler);
-};
-
-} // namespace extensions
-
-#endif // CHROME_BROWSER_UI_WEBUI_EXTENSIONS_COMMAND_HANDLER_H_
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_handler.cc b/chrome/browser/ui/webui/extensions/extension_settings_handler.cc
index be76abb..f6bfc5d 100644
--- a/chrome/browser/ui/webui/extensions/extension_settings_handler.cc
+++ b/chrome/browser/ui/webui/extensions/extension_settings_handler.cc
@@ -238,6 +238,23 @@ void ExtensionSettingsHandler::GetLocalizedValues(
source->AddString(
"extensionErrorOverlayNoCodeToDisplay",
l10n_util::GetStringUTF16(IDS_EXTENSIONS_ERROR_NO_CODE_TO_DISPLAY));
+
+ // Extension Commands Overlay:
+ source->AddString("extensionCommandsOverlay",
+ l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_DIALOG_TITLE));
+ source->AddString("extensionCommandsEmpty",
+ l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_EMPTY));
+ source->AddString("extensionCommandsInactive",
+ l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_INACTIVE));
+ source->AddString("extensionCommandsStartTyping",
+ l10n_util::GetStringUTF16(IDS_EXTENSION_TYPE_SHORTCUT));
+ source->AddString("extensionCommandsDelete",
+ l10n_util::GetStringUTF16(IDS_EXTENSION_DELETE_SHORTCUT));
+ source->AddString("extensionCommandsGlobal",
+ l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_GLOBAL));
+ source->AddString("extensionCommandsRegular",
+ l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_NOT_GLOBAL));
+ source->AddString("ok", l10n_util::GetStringUTF16(IDS_OK));
}
void ExtensionSettingsHandler::DidStartNavigationToPendingEntry(
diff --git a/chrome/browser/ui/webui/extensions/extensions_ui.cc b/chrome/browser/ui/webui/extensions/extensions_ui.cc
index 681fd3f..1c6acb2 100644
--- a/chrome/browser/ui/webui/extensions/extensions_ui.cc
+++ b/chrome/browser/ui/webui/extensions/extensions_ui.cc
@@ -5,7 +5,6 @@
#include "chrome/browser/ui/webui/extensions/extensions_ui.h"
#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/webui/extensions/command_handler.h"
#include "chrome/browser/ui/webui/extensions/extension_loader_handler.h"
#include "chrome/browser/ui/webui/extensions/extension_settings_handler.h"
#include "chrome/browser/ui/webui/extensions/install_extension_handler.h"
@@ -50,10 +49,6 @@ ExtensionsUI::ExtensionsUI(content::WebUI* web_ui) : WebUIController(web_ui) {
handler->GetLocalizedValues(source);
web_ui->AddMessageHandler(handler);
- CommandHandler* commands_handler = new CommandHandler(profile);
- commands_handler->GetLocalizedValues(source);
- web_ui->AddMessageHandler(commands_handler);
-
ExtensionLoaderHandler* extension_loader_handler =
new ExtensionLoaderHandler(profile);
extension_loader_handler->GetLocalizedValues(source);
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi
index f8dd2e7..a9c41bd 100644
--- a/chrome/chrome_browser_ui.gypi
+++ b/chrome/chrome_browser_ui.gypi
@@ -1751,8 +1751,6 @@
'browser/ui/webui/downloads_dom_handler.h',
'browser/ui/webui/downloads_ui.cc',
'browser/ui/webui/downloads_ui.h',
- 'browser/ui/webui/extensions/command_handler.cc',
- 'browser/ui/webui/extensions/command_handler.h',
'browser/ui/webui/extensions/extension_loader_handler.cc',
'browser/ui/webui/extensions/extension_loader_handler.h',
'browser/ui/webui/extensions/extension_settings_handler.cc',
diff --git a/chrome/common/extensions/api/developer_private.idl b/chrome/common/extensions/api/developer_private.idl
index 539bd6a..0990f26 100644
--- a/chrome/common/extensions/api/developer_private.idl
+++ b/chrome/common/extensions/api/developer_private.idl
@@ -87,6 +87,11 @@ namespace developerPrivate {
TERMINATED
};
+ enum CommandScope {
+ GLOBAL,
+ CHROME
+ };
+
dictionary AccessModifier {
boolean isEnabled;
boolean isActive;
@@ -161,9 +166,19 @@ namespace developerPrivate {
DOMString text;
};
+ dictionary Command {
+ DOMString description;
+ DOMString keybinding;
+ DOMString name;
+ boolean isActive;
+ CommandScope scope;
+ boolean isExtensionAction;
+ };
+
dictionary ExtensionInfo {
boolean actionButtonHidden;
DOMString? blacklistText;
+ Command[] commands;
ControlledInfo? controlledInfo;
DOMString[] dependentExtensions;
DOMString description;
@@ -259,6 +274,13 @@ namespace developerPrivate {
boolean? inDeveloperMode;
};
+ dictionary ExtensionCommandUpdate {
+ DOMString extensionId;
+ DOMString commandName;
+ CommandScope? scope;
+ DOMString? keybinding;
+ };
+
dictionary ReloadOptions {
// If false, an alert dialog will show in the event of a reload error.
// Defaults to false.
@@ -527,6 +549,16 @@ namespace developerPrivate {
// |extensionId| : The id of the extension to show the path for.
static void showPath(DOMString extensionId, optional VoidCallback callback);
+ // (Un)suspends global shortcut handling.
+ // |isSuspended| : Whether or not shortcut handling should be suspended.
+ static void setShortcutHandlingSuspended(boolean isSuspended,
+ optional VoidCallback callback);
+
+ // Updates an extension command.
+ // |update| : The parameters for updating the extension command.
+ static void updateExtensionCommand(ExtensionCommandUpdate update,
+ optional VoidCallback callback);
+
[nocompile, deprecated="Use management.setEnabled"]
static void enable(DOMString id,
boolean enabled,
diff --git a/chrome/common/extensions/command.cc b/chrome/common/extensions/command.cc
index 10ee539..ba42e1c 100644
--- a/chrome/common/extensions/command.cc
+++ b/chrome/common/extensions/command.cc
@@ -552,28 +552,4 @@ bool Command::Parse(const base::DictionaryValue* command,
return true;
}
-base::DictionaryValue* Command::ToValue(const Extension* extension,
- bool active) const {
- base::DictionaryValue* extension_data = new base::DictionaryValue();
-
- base::string16 command_description;
- bool extension_action = false;
- if (command_name() == values::kBrowserActionCommandEvent ||
- command_name() == values::kPageActionCommandEvent) {
- command_description =
- l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_GENERIC_ACTIVATE);
- extension_action = true;
- } else {
- command_description = description();
- }
- extension_data->SetString("description", command_description);
- extension_data->SetBoolean("active", active);
- extension_data->SetString("keybinding", accelerator().GetShortcutText());
- extension_data->SetString("command_name", command_name());
- extension_data->SetString("extension_id", extension->id());
- extension_data->SetBoolean("global", global());
- extension_data->SetBoolean("extension_action", extension_action);
- return extension_data;
-}
-
} // namespace extensions
diff --git a/chrome/common/extensions/command.h b/chrome/common/extensions/command.h
index 41ec35a..7541cde 100644
--- a/chrome/common/extensions/command.h
+++ b/chrome/common/extensions/command.h
@@ -53,11 +53,6 @@ class Command {
int index,
base::string16* error);
- // Convert a Command object from |extension| to a DictionaryValue.
- // |active| specifies whether the command is active or not.
- base::DictionaryValue* ToValue(
- const Extension* extension, bool active) const;
-
// Accessors:
const std::string& command_name() const { return command_name_; }
const ui::Accelerator& accelerator() const { return accelerator_; }
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index e183baf..be63214 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -1100,6 +1100,8 @@ enum HistogramValue {
PASSWORDSPRIVATE_GETPLAINTEXTPASSWORD,
LAUNCHERPAGE_HIDE,
PLATFORMKEYS_VERIFYTLSSERVERCERTIFICATE,
+ DEVELOPERPRIVATE_SETSHORTCUTHANDLINGSUSPENDED,
+ DEVELOPERPRIVATE_UPDATEEXTENSIONCOMMAND,
// Last entry: Add new entries above and ensure to update
// tools/metrics/histograms/histograms.xml.
ENUM_BOUNDARY
diff --git a/third_party/closure_compiler/externs/developer_private.js b/third_party/closure_compiler/externs/developer_private.js
index 338120f..c4a94f3 100644
--- a/third_party/closure_compiler/externs/developer_private.js
+++ b/third_party/closure_compiler/externs/developer_private.js
@@ -122,6 +122,15 @@ chrome.developerPrivate.ExtensionState = {
};
/**
+ * @enum {string}
+ * @see https://developer.chrome.com/extensions/developerPrivate#type-CommandScope
+ */
+chrome.developerPrivate.CommandScope = {
+ GLOBAL: 'GLOBAL',
+ CHROME: 'CHROME',
+};
+
+/**
* @typedef {{
* isEnabled: boolean,
* isActive: boolean
@@ -235,8 +244,22 @@ var ControlledInfo;
/**
* @typedef {{
+ * description: string,
+ * keybinding: string,
+ * name: string,
+ * isActive: boolean,
+ * scope: !chrome.developerPrivate.CommandScope,
+ * isExtensionAction: boolean
+ * }}
+ * @see https://developer.chrome.com/extensions/developerPrivate#type-Command
+ */
+var Command;
+
+/**
+ * @typedef {{
* actionButtonHidden: boolean,
* blacklistText: (string|undefined),
+ * commands: !Array<Command>,
* controlledInfo: (ControlledInfo|undefined),
* dependentExtensions: !Array<string>,
* description: string,
@@ -350,6 +373,17 @@ var ProfileConfigurationUpdate;
/**
* @typedef {{
+ * extensionId: string,
+ * commandName: string,
+ * scope: (!chrome.developerPrivate.CommandScope|undefined),
+ * keybinding: (string|undefined)
+ * }}
+ * @see https://developer.chrome.com/extensions/developerPrivate#type-ExtensionCommandUpdate
+ */
+var ExtensionCommandUpdate;
+
+/**
+ * @typedef {{
* failQuietly: (boolean|undefined)
* }}
* @see https://developer.chrome.com/extensions/developerPrivate#type-ReloadOptions
@@ -666,6 +700,24 @@ chrome.developerPrivate.showOptions = function(extensionId, callback) {};
chrome.developerPrivate.showPath = function(extensionId, callback) {};
/**
+ * (Un)suspends global shortcut handling.
+ * @param {boolean} isSuspended Whether or not shortcut handling should be
+ * suspended.
+ * @param {function():void=} callback
+ * @see https://developer.chrome.com/extensions/developerPrivate#method-setShortcutHandlingSuspended
+ */
+chrome.developerPrivate.setShortcutHandlingSuspended = function(isSuspended, callback) {};
+
+/**
+ * Updates an extension command.
+ * @param {ExtensionCommandUpdate} update The parameters for updating the
+ * extension command.
+ * @param {function():void=} callback
+ * @see https://developer.chrome.com/extensions/developerPrivate#method-updateExtensionCommand
+ */
+chrome.developerPrivate.updateExtensionCommand = function(update, callback) {};
+
+/**
* @param {string} id
* @param {boolean} enabled
* @param {function():void=} callback
@@ -712,4 +764,4 @@ chrome.developerPrivate.onItemStateChanged;
* @type {!ChromeEvent}
* @see https://developer.chrome.com/extensions/developerPrivate#event-onProfileStateChanged
*/
-chrome.developerPrivate.onProfileStateChanged; \ No newline at end of file
+chrome.developerPrivate.onProfileStateChanged;
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index b1c92da..7f036b4 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -52892,6 +52892,8 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="1039" label="PASSWORDSPRIVATE_GETPLAINTEXTPASSWORD"/>
<int value="1040" label="LAUNCHERPAGE_HIDE"/>
<int value="1041" label="PLATFORMKEYS_VERIFYTLSSERVERCERTIFICATE"/>
+ <int value="1042" label="DEVELOPERPRIVATE_SETSHORTCUTHANDLINGSUSPENDED"/>
+ <int value="1043" label="DEVELOPERPRIVATE_UPDATEEXTENSIONCOMMAND"/>
</enum>
<enum name="ExtensionInstallCause" type="int">