Bug 997564 - Implement Engineering Mode Web API. sr=sicking r=fabrice

This commit is contained in:
Evelyn Hung 2014-09-21 09:06:00 +02:00
parent 942c9765a8
commit e4072eab90
10 changed files with 379 additions and 1 deletions

View File

@ -207,6 +207,7 @@
@BINPATH@/components/dom_xpath.xpt
@BINPATH@/components/dom_xul.xpt
@BINPATH@/components/dom_time.xpt
@BINPATH@/components/dom_engineeringmode.xpt
@BINPATH@/components/downloads.xpt
@BINPATH@/components/editor.xpt
@BINPATH@/components/embed_base.xpt
@ -595,6 +596,10 @@
@BINPATH@/components/MozKeyboard.js
@BINPATH@/components/InputMethod.manifest
@BINPATH@/components/EngineeringMode.manifest
@BINPATH@/components/EngineeringModeAPI.js
@BINPATH@/components/EngineeringModeService.js
#ifdef MOZ_DEBUG
@BINPATH@/components/TestInterfaceJS.js
@BINPATH@/components/TestInterfaceJS.manifest

View File

@ -487,6 +487,12 @@ this.PermissionsTable = { geolocation: {
certified: ALLOW_ACTION,
access: ["read", "write"],
additional: ["settings-api"]
},
"engineering-mode": {
app: DENY_ACTION,
trusted: DENY_ACTION,
privileged: DENY_ACTION,
certified: ALLOW_ACTION
}
};

View File

@ -0,0 +1,6 @@
component {27e55b94-fc43-42b3-b0f0-28bebdd804f1} EngineeringModeAPI.js
contract @mozilla.org/dom/engineering-mode-api;1 {27e55b94-fc43-42b3-b0f0-28bebdd804f1}
component {1345a96a-7b8d-4017-a776-07d918f14d84} EngineeringModeService.js
contract @mozilla.org/engineering-mode-service;1 {1345a96a-7b8d-4017-a776-07d918f14d84}
category profile-after-change EngineeringModeService @mozilla.org/engineering-mode-service;1

View File

@ -0,0 +1,135 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const DEBUG = false;
function debug(s) {
if (DEBUG) dump("-*- EngineeringModeAPI: " + s + "\n");
}
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1",
"nsIMessageSender");
function EngineeringModeAPI() {
}
EngineeringModeAPI.prototype = {
__proto__: DOMRequestIpcHelper.prototype,
classDescription: "Engineering Mode API",
classID: Components.ID("{27e55b94-fc43-42b3-b0f0-28bebdd804f1}"),
contractID: "@mozilla.org/dom/engineering-mode-api;1",
// For DOMRequestHelper: must have nsISupportsWeakReference and nsIObserver.
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer,
Ci.nsISupportsWeakReference,
Ci.nsIObserver]),
init: function(aWindow) {
this.initDOMRequestHelper(aWindow, ["EngineeringMode:OnMessage",
"EngineeringMode:SetValue:Result:OK",
"EngineeringMode:SetValue:Result:KO",
"EngineeringMode:GetValue:Result:OK",
"EngineeringMode:GetValue:Result:KO"]);
cpmm.sendAsyncMessage("EngineeringMode:Register", null);
},
uninit: function() {
cpmm.sendAsyncMessage("EngineeringMode:Unregister", null);
},
// This returns a Promise<DOMString>
getValue: function getValue(aName) {
debug("getValue " + aName);
let promiseInit = function(resolve, reject) {
debug("promise init called for getValue " + aName);
let resolverId = this.getPromiseResolverId({resolve: resolve,
reject: reject });
debug("promise init " + resolverId);
cpmm.sendAsyncMessage("EngineeringMode:GetValue", {
requestId: resolverId,
name: aName
});
}.bind(this);
return this.createPromise(promiseInit);
},
// This returns a Promise<void>
setValue: function setValue(aName, aValue) {
debug("setValue " + aName + ' as ' + aValue );
let promiseInit = function(resolve, reject) {
debug("promise init called for setValue " + aName);
let resolverId = this.getPromiseResolverId({resolve: resolve,
reject: reject });
debug("promise init " + resolverId);
cpmm.sendAsyncMessage("EngineeringMode:SetValue", {
requestId: resolverId,
name: aName,
value: aValue
});
}.bind(this);
return this.createPromise(promiseInit);
},
set onmessage(aHandler) {
this.__DOM_IMPL__.setEventHandler("onmessage", aHandler);
},
get onmessage() {
return this.__DOM_IMPL__.getEventHandler("onmessage");
},
receiveMessage: function(aMessage) {
debug("receiveMessage: name: " + aMessage.name);
let resolver = null;
let data = aMessage.data;
switch (aMessage.name) {
case "EngineeringMode:OnMessage":
let detail = Cu.cloneInto(data, this._window);
let event = new this._window.CustomEvent("message", {"detail": detail});
this.__DOM_IMPL__.dispatchEvent(event);
break;
case "EngineeringMode:GetValue:Result:OK":
case "EngineeringMode:GetValue:Result:KO":
resolver = this.takePromiseResolver(data.requestId);
if (!resolver) {
return;
}
if (aMessage.name === "EngineeringMode:GetValue:Result:OK") {
resolver.resolve(data.value);
} else {
resolver.reject(data.reason);
}
break;
case "EngineeringMode:SetValue:Result:OK":
case "EngineeringMode:SetValue:Result:KO":
resolver = this.takePromiseResolver(data.requestId);
if (!resolver) {
return;
}
if (aMessage.name === "EngineeringMode:SetValue:Result:OK") {
resolver.resolve();
} else {
resolver.reject(data.reason);
}
break;
}
}
}
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([EngineeringModeAPI]);

View File

@ -0,0 +1,163 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const DEBUG = false;
function debug(s) {
if (DEBUG) dump("-*- EngineeringModeService: " + s + "\n");
}
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
"@mozilla.org/parentprocessmessagemanager;1",
"nsIMessageBroadcaster");
XPCOMUtils.defineLazyServiceGetter(this, "EngineeringMode",
"@mozilla.org/b2g/engineering-mode-impl;1",
"nsIEngineeringMode");
function EngineeringModeService() {
}
EngineeringModeService.prototype = {
classID: Components.ID("{1345a96a-7b8d-4017-a776-07d918f14d84}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
Ci.nsIEngineeringModeMessageHandler]),
observe: function(aSubject, aTopic, aData) {
debug("-- init");
switch(aTopic) {
case "profile-after-change":
Services.obs.addObserver(this, "xpcom-shutdown", false);
ppmm.addMessageListener("EngineeringMode:Register", this);
ppmm.addMessageListener("EngineeringMode:Unregister", this);
ppmm.addMessageListener("EngineeringMode:SetValue", this);
ppmm.addMessageListener("EngineeringMode:GetValue", this);
this._clients = [];
break;
case "xpcom-shutdown":
Services.obs.removeObserver(this, "xpcom-shutdown");
ppmm.removeMessageListener("EngineeringMode:Register", this);
ppmm.removeMessageListener("EngineeringMode:Unregister", this);
ppmm.removeMessageListener("EngineeringMode:SetValue", this);
ppmm.removeMessageListener("EngineeringMode:GetValue", this);
if (this._hasEngineeringModeImpl()) {
EngineeringMode.setMessageHandler(function(){});
}
this._clients = null;
break;
}
},
receiveMessage: function(aMessage) {
debug("receiveMessage: name: " + aMessage.name);
if (!aMessage.target.assertPermission("engineering-mode")) {
debug(aMessage.name + " from a content process with no 'engineering-mode' privileges.");
return;
}
switch (aMessage.name) {
case "EngineeringMode:Register":
// Lazy bind message handler until we have first client.
if (this._hasEngineeringModeImpl() && this._clients.length === 0) {
EngineeringMode.setMessageHandler(this.onMessage.bind(this));
}
this._clients.push(aMessage.target);
break;
case "EngineeringMode:Unregister":
let index = this._clients.indexOf(aMessage.target);
if (index > -1) {
this._clients.splice(index, 1);
}
break;
case "EngineeringMode:SetValue":
this.setValue(aMessage.target, aMessage.data);
break;
case "EngineeringMode:GetValue":
this.getValue(aMessage.target, aMessage.data);
break;
}
},
setValue: function(aTarget, aData) {
if (!this._hasEngineeringModeImpl()) {
aTarget.sendAsyncMessage("EngineeringMode:SetValue:Result:KO", {
requestId: aData.requestId,
reason: "No engineering mode implementation"
});
return;
}
EngineeringMode.setValue(aData.name, aData.value, {
onsuccess: function() {
aTarget.sendAsyncMessage("EngineeringMode:SetValue:Result:OK", {
requestId: aData.requestId
});
},
onerror: function(aError) {
aTarget.sendAsyncMessage("EngineeringMode:SetValue:Result:KO", {
requestId: aData.requestId,
reason: "Error: code " + aError
});
}
});
},
getValue: function(aTarget, aData) {
if (!this._hasEngineeringModeImpl()) {
aTarget.sendAsyncMessage("EngineeringMode:GetValue:Result:KO", {
requestId: aData.requestId,
reason: "No engineering mode implementation"
});
return;
}
EngineeringMode.getValue(aData.name, {
onsuccess: function(aValue) {
aTarget.sendAsyncMessage("EngineeringMode:GetValue:Result:OK", {
requestId: aData.requestId,
value: aValue
});
},
onerror: function(aError) {
aTarget.sendAsyncMessage("EngineeringMode:GetValue:Result:KO", {
requestId: aData.requestId,
reason: "Error: code " + aError
});
}
});
},
onMessage: function(aMessage) {
this._clients.forEach(function(aClient) {
aClient.sendAsyncMessage("EngineeringMode:OnMessage", {
data: aMessage
});
});
},
_hasEngineeringModeImpl: function() {
if (typeof Cc["@mozilla.org/b2g/engineering-mode-impl;1"] === "undefined") {
debug("Can not get engineering mode implementation.");
return false;
}
return true;
}
}
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([EngineeringModeService]);

View File

@ -0,0 +1,19 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
if CONFIG['MOZ_B2G']:
EXTRA_COMPONENTS += [
'EngineeringMode.manifest',
'EngineeringModeAPI.js',
'EngineeringModeService.js',
]
XPIDL_SOURCES += [
'nsIEngineeringMode.idl',
]
XPIDL_MODULE = 'dom_engineeringmode'

View File

@ -0,0 +1,29 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
[scriptable, function, uuid(82e7c515-d174-4e84-9091-e7e89617a6d9)]
interface nsIEngineeringModeMessageHandler : nsISupports
{
void handleMessage(in DOMString message);
};
[scriptable, uuid(fdae21b9-bd8c-4d01-bc6a-6c3a7b5efb27)]
interface nsIEngineeringModeCallback : nsISupports
{
void onsuccess([optional] in DOMString value);
void onerror(in int32_t error);
};
// Implemented by contract id @mozilla.org/b2g/engineering-mode-impl;1
[scriptable, uuid(7251c99b-225f-4e39-8336-a7e2a087aa21)]
interface nsIEngineeringMode : nsISupports
{
void getValue(in DOMString name, in nsIEngineeringModeCallback callback);
void setValue(in DOMString name, in DOMString value,
in nsIEngineeringModeCallback callback);
void setMessageHandler(in nsIEngineeringModeMessageHandler handler);
};

View File

@ -128,7 +128,8 @@ if CONFIG['MOZ_NFC']:
if CONFIG['MOZ_B2G']:
DIRS += [
'downloads',
'mobileid'
'mobileid',
'engineeringmode'
]
if CONFIG['MOZ_B2G_BT_API_V2']:

View File

@ -0,0 +1,13 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
[JSImplementation="@mozilla.org/dom/engineering-mode-api;1",
NavigatorProperty="engineeringMode",
AvailableIn=CertifiedApps,
CheckPermissions="engineering-mode"]
interface EngineeringMode : EventTarget {
Promise<DOMString> getValue(DOMString name);
Promise<void> setValue(DOMString name, DOMString value);
attribute EventHandler onmessage;
};

View File

@ -119,6 +119,7 @@ WEBIDL_FILES = [
'DummyBinding.webidl',
'DynamicsCompressorNode.webidl',
'Element.webidl',
'EngineeringMode.webidl',
'Event.webidl',
'EventHandler.webidl',
'EventListener.webidl',