Bug 1080474 - Part 2 - expose device information via PresentationDeviceInfoManager API. r=khuey r=fabrice.

This commit is contained in:
Shih-Chiang Chien 2014-11-14 13:55:24 -08:00
Родитель de67b6547d
Коммит fbddc387d5
18 изменённых файлов: 577 добавлений и 0 удалений

Просмотреть файл

@ -405,6 +405,8 @@
@BINPATH@/components/nsAsyncShutdown.js
@BINPATH@/components/htmlMenuBuilder.js
@BINPATH@/components/htmlMenuBuilder.manifest
@BINPATH@/components/PresentationDeviceInfoManager.manifest
@BINPATH@/components/PresentationDeviceInfoManager.js
; WiFi, NetworkManager, NetworkStats
#ifdef MOZ_WIDGET_GONK

Просмотреть файл

@ -609,6 +609,9 @@
@RESPATH@/components/nsAsyncShutdown.manifest
@RESPATH@/components/nsAsyncShutdown.js
@RESPATH@/components/PresentationDeviceInfoManager.manifest
@RESPATH@/components/PresentationDeviceInfoManager.js
; InputMethod API
@RESPATH@/components/MozKeyboard.js
@RESPATH@/components/InputMethod.manifest

Просмотреть файл

@ -526,6 +526,12 @@ this.PermissionsTable = { geolocation: {
trusted: DENY_ACTION,
privileged: DENY_ACTION,
certified: ALLOW_ACTION
},
"presentation-device-manage": {
app: DENY_ACTION,
trusted: DENY_ACTION,
privileged: DENY_ACTION,
certified: ALLOW_ACTION
}
};

Просмотреть файл

@ -14,6 +14,7 @@ skip-if = (toolkit == 'gonk' && debug) #debug-only failure
skip-if = buildapp == 'b2g' || toolkit == 'android' # b2g(https not working, bug 907770) b2g-debug(https not working, bug 907770) b2g-desktop(Bug 907770)
[test_permissions.html]
[test_power.html]
[test_presentation-device-manage.html]
[test_systemXHR.html]
[test_tcp-socket.html]
[test_udp-socket.html]

Просмотреть файл

@ -0,0 +1,38 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1080474
-->
<head>
<meta charset="utf-8">
<title>Test for presentation-device-manage permission</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1080474">test presentation-device-manage</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
<script type="application/javascript;version=1.8" src="file_framework.js"></script>
<script type="application/javascript;version=1.8">
function verifier(success, failure) {
if (window.navigator.mozPresentationDeviceInfo) {
success("Got mozPresentationDeviceInfo object!");
} else {
failure("Failed to get mozPresentationDeviceInfo object!");
}
}
var gData = [
{
perm: ["presentation-device-manage"],
settings: [["dom.presentation.enabled", true]],
obj: "mozPresentationDeviceInfo",
webidl: "PresentationDeviceInfoManager"
}
]
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,120 @@
/* 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 {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
function log(aMsg) {
//dump("-*- PresentationDeviceInfoManager.js : " + aMsg + "\n");
}
const PRESENTATIONDEVICEINFOMANAGER_CID = Components.ID("{1bd66bef-f643-4be3-b690-0c656353eafd}");
const PRESENTATIONDEVICEINFOMANAGER_CONTRACTID = "@mozilla.org/presentation-device/deviceInfo;1";
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1",
"nsIMessageSender");
function PresentationDeviceInfoManager() {}
PresentationDeviceInfoManager.prototype = {
__proto__: DOMRequestIpcHelper.prototype,
classID: PRESENTATIONDEVICEINFOMANAGER_CID,
contractID: PRESENTATIONDEVICEINFOMANAGER_CONTRACTID,
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference,
Ci.nsIObserver,
Ci.nsIDOMGlobalPropertyInitializer]),
receiveMessage: function(aMsg) {
if (!aMsg || !aMsg.data) {
return;
}
let data = aMsg.data;
log("receive aMsg: " + aMsg.name);
switch (aMsg.name) {
case "PresentationDeviceInfoManager:OnDeviceChange": {
let detail = {
detail: {
type: data.type,
deviceInfo: data.deviceInfo,
}
};
let event = new this._window.CustomEvent("devicechange", Cu.cloneInto(detail, this._window));
this.__DOM_IMPL__.dispatchEvent(event);
break;
}
case "PresentationDeviceInfoManager:GetAll:Result:Ok": {
let resolver = this.takePromiseResolver(data.requestId);
if (!resolver) {
return;
}
resolver.resolve(Cu.cloneInto(data.devices, this._window));
break;
}
case "PresentationDeviceInfoManager:GetAll:Result:Error": {
let resolver = this.takePromiseResolver(data.requestId);
if (!resolver) {
return;
}
resolver.reject(data.error);
break;
}
}
},
init: function(aWin) {
log("init");
this.initDOMRequestHelper(aWin, [
{name: "PresentationDeviceInfoManager:OnDeviceChange", weakRef: true},
{name: "PresentationDeviceInfoManager:GetAll:Result:Ok", weakRef: true},
{name: "PresentationDeviceInfoManager:GetAll:Result:Error", weakRef: true},
]);
},
uninit: function() {
log("uninit");
let self = this;
this.forEachPromiseResolver(function(aKey) {
self.takePromiseResolver(aKey).reject("PresentationDeviceInfoManager got destroyed");
});
},
get ondevicechange() {
return this.__DOM_IMPL__.getEventHandler("ondevicechange");
},
set ondevicechange(aHandler) {
this.__DOM_IMPL__.setEventHandler("ondevicechange", aHandler);
},
getAll: function() {
log("getAll");
let self = this;
return this.createPromise(function(aResolve, aReject) {
let resolverId = self.getPromiseResolverId({ resolve: aResolve, reject: aReject });
cpmm.sendAsyncMessage("PresentationDeviceInfoManager:GetAll", {
requestId: resolverId,
});
});
},
forceDiscovery: function() {
cpmm.sendAsyncMessage("PresentationDeviceInfoManager:ForceDiscovery");
},
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PresentationDeviceInfoManager]);

Просмотреть файл

@ -0,0 +1,104 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- /
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* 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 {classes: Cc, interfaces: Ci, utils: Cu} = Components;
this.EXPORTED_SYMBOLS = ["PresentationDeviceInfoService"];
function log(aMsg) {
//dump("PresentationDeviceInfoManager.jsm: " + aMsg + "\n");
}
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "presentationDeviceManager",
"@mozilla.org/presentation-device/manager;1",
"nsIPresentationDeviceManager");
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
"@mozilla.org/parentprocessmessagemanager;1",
"nsIMessageBroadcaster");
this.PresentationDeviceInfoService = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIMessageListener,
Ci.nsIObserver]),
init: function() {
log("init");
ppmm.addMessageListener("PresentationDeviceInfoManager:GetAll", this);
ppmm.addMessageListener("PresentationDeviceInfoManager:ForceDiscovery", this);
Services.obs.addObserver(this, "presentation-device-change", false);
},
getAll: function(aData, aMm) {
log("getAll");
let deviceArray = presentationDeviceManager.getAvailableDevices().QueryInterface(Ci.nsIArray);
if (!deviceArray) {
aData.error = "DataError";
aMm.sendAsyncMessage("PresentationDeviceInfoManager:GetAll:Result:Error", aData);
return;
}
aData.devices = [];
for (let i = 0; i < deviceArray.length; i++) {
let device = deviceArray.queryElementAt(i, Ci.nsIPresentationDevice);
aData.devices.push({
id: device.id,
name: device.name,
type: device.type,
});
}
aMm.sendAsyncMessage("PresentationDeviceInfoManager:GetAll:Result:Ok", aData);
},
forceDiscovery: function() {
log("forceDiscovery");
presentationDeviceManager.forceDiscovery();
},
observe: function(aSubject, aTopic, aData) {
log("observe: " + aTopic);
let device = aSubject.QueryInterface(Ci.nsIPresentationDevice);
let data = {
type: aData,
deviceInfo: {
id: device.id,
name: device.name,
type: device.type,
},
};
ppmm.broadcastAsyncMessage("PresentationDeviceInfoManager:OnDeviceChange", data);
},
receiveMessage: function(aMessage) {
if (!aMessage.target.assertPermission("presentation-device-manage")) {
debug("receive message " + aMessage.name +
" from a content process with no 'presentation-device-manage' privileges.");
return null;
}
let msg = aMessage.data || {};
let mm = aMessage.target;
log("receiveMessage: " + aMessage.name);
switch (aMessage.name) {
case "PresentationDeviceInfoManager:GetAll": {
this.getAll(msg, mm);
break;
}
case "PresentationDeviceInfoManager:ForceDiscovery": {
this.forceDiscovery();
break;
}
}
},
};
this.PresentationDeviceInfoService.init();

Просмотреть файл

@ -0,0 +1,3 @@
# PresentationDeviceInfoManager.js
component {1bd66bef-f643-4be3-b690-0c656353eafd} PresentationDeviceInfoManager.js
contract @mozilla.org/presentation-device/deviceInfo;1 {1bd66bef-f643-4be3-b690-0c656353eafd}

Просмотреть файл

@ -7,6 +7,7 @@
DIRS += ['interfaces']
XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell/xpcshell.ini']
MOCHITEST_MANIFESTS += ['tests/mochitest/mochitest.ini']
EXPORTS.mozilla.dom.presentation += [
'PresentationDeviceManager.h',
@ -17,6 +18,15 @@ SOURCES += [
'PresentationSessionRequest.cpp',
]
EXTRA_COMPONENTS += [
'PresentationDeviceInfoManager.js',
'PresentationDeviceInfoManager.manifest',
]
EXTRA_JS_MODULES += [
'PresentationDeviceInfoManager.jsm',
]
FAIL_ON_WARNINGS = True
include('/ipc/chromium/chromium-config.mozbuild')

Просмотреть файл

@ -0,0 +1,60 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.import('resource://gre/modules/PresentationDeviceInfoManager.jsm');
const { XPCOMUtils } = Cu.import('resource://gre/modules/XPCOMUtils.jsm');
const manager = Cc['@mozilla.org/presentation-device/manager;1']
.getService(Ci.nsIPresentationDeviceManager);
var testProvider = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceProvider]),
forceDiscovery: function() {
sendAsyncMessage('force-discovery');
},
listener: null,
};
var testDevice = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
establishSessionTransport: function(url, presentationId) {
return null;
},
id: null,
name: null,
type: null,
listener: null,
};
addMessageListener('setup', function() {
manager.addDeviceProvider(testProvider);
sendAsyncMessage('setup-complete');
});
addMessageListener('trigger-device-add', function(device) {
testDevice.id = device.id;
testDevice.name = device.name;
testDevice.type = device.type;
manager.addDevice(testDevice);
});
addMessageListener('trigger-device-update', function(device) {
testDevice.id = device.id;
testDevice.name = device.name;
testDevice.type = device.type;
manager.updateDevice(testDevice);
});
addMessageListener('trigger-device-remove', function() {
manager.removeDevice(testDevice);
});
addMessageListener('teardown', function() {
manager.removeDeviceProvider(testProvider);
});

Просмотреть файл

@ -0,0 +1,6 @@
[DEFAULT]
support-files =
PresentationDeviceInfoChromeScript.js
[test_presentation_device_info.html]
[test_presentation_device_info_permission.html]

Просмотреть файл

@ -0,0 +1,148 @@
<!DOCTYPE HTML>
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for B2G Presentation Device Info API</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1080474">Test for B2G Presentation Device Info API</a>
<script type="application/javascript;version=1.8">
'use strict';
SimpleTest.waitForExplicitFinish();
var testDevice = {
id: 'id',
name: 'name',
type: 'type',
};
var gUrl = SimpleTest.getTestFileURL('PresentationDeviceInfoChromeScript.js');
var gScript = SpecialPowers.loadChromeScript(gUrl);
function testSetup() {
return new Promise(function(resolve, reject) {
gScript.addMessageListener('setup-complete', function() {
resolve();
});
gScript.sendAsyncMessage('setup');
});
}
function testForceDiscovery() {
info('test force discovery');
return new Promise(function(resolve, reject) {
gScript.addMessageListener('force-discovery', function() {
ok(true, 'nsIPresentationDeviceProvider.forceDiscovery is invoked');
resolve();
});
navigator.mozPresentationDeviceInfo.forceDiscovery();
});
}
function testDeviceAdd() {
info('test device add');
return new Promise(function(resolve, reject) {
navigator.mozPresentationDeviceInfo.addEventListener('devicechange', function deviceChangeHandler(e) {
navigator.mozPresentationDeviceInfo.removeEventListener('devicechange', deviceChangeHandler);
let detail = e.detail;
is(detail.type, 'add', 'expected update type');
is(detail.deviceInfo.id, testDevice.id, 'expected device id');
is(detail.deviceInfo.name, testDevice.name, 'expected device name');
is(detail.deviceInfo.type, testDevice.type, 'expected device type');
navigator.mozPresentationDeviceInfo.getAll()
.then(function(devices) {
is(devices.length, 1, 'expected 1 available device');
is(devices[0].id, testDevice.id, 'expected device id');
is(devices[0].name, testDevice.name, 'expected device name');
is(devices[0].type, testDevice.type, 'expected device type');
resolve();
});
});
gScript.sendAsyncMessage('trigger-device-add', testDevice);
});
}
function testDeviceUpdate() {
info('test device update');
return new Promise(function(resolve, reject) {
testDevice.name = 'name-update';
navigator.mozPresentationDeviceInfo.addEventListener('devicechange', function deviceChangeHandler(e) {
navigator.mozPresentationDeviceInfo.removeEventListener('devicechange', deviceChangeHandler);
let detail = e.detail;
is(detail.type, 'update', 'expected update type');
is(detail.deviceInfo.id, testDevice.id, 'expected device id');
is(detail.deviceInfo.name, testDevice.name, 'expected device name');
is(detail.deviceInfo.type, testDevice.type, 'expected device type');
navigator.mozPresentationDeviceInfo.getAll()
.then(function(devices) {
is(devices.length, 1, 'expected 1 available device');
is(devices[0].id, testDevice.id, 'expected device id');
is(devices[0].name, testDevice.name, 'expected device name');
is(devices[0].type, testDevice.type, 'expected device type');
resolve();
});
});
gScript.sendAsyncMessage('trigger-device-update', testDevice);
});
}
function testDeviceRemove() {
info('test device remove');
return new Promise(function(resolve, reject) {
navigator.mozPresentationDeviceInfo.addEventListener('devicechange', function deviceChangeHandler(e) {
navigator.mozPresentationDeviceInfo.removeEventListener('devicechange', deviceChangeHandler);
let detail = e.detail;
is(detail.type, 'remove', 'expected update type');
is(detail.deviceInfo.id, testDevice.id, 'expected device id');
is(detail.deviceInfo.name, testDevice.name, 'expected device name');
is(detail.deviceInfo.type, testDevice.type, 'expected device type');
navigator.mozPresentationDeviceInfo.getAll()
.then(function(devices) {
is(devices.length, 0, 'expected 0 available device');
resolve();
});
});
gScript.sendAsyncMessage('trigger-device-remove');
});
}
function runTests() {
testSetup()
.then(testForceDiscovery)
.then(testDeviceAdd)
.then(testDeviceUpdate)
.then(testDeviceRemove)
.then(function() {
info('test finished, teardown');
gScript.sendAsyncMessage('teardown', '');
gScript.destroy();
SimpleTest.finish();
});
}
window.addEventListener('load', function() {
SpecialPowers.pushPermissions([
{type: 'presentation-device-manage', allow: true, context: document},
], function() {
SpecialPowers.pushPrefEnv({
'set': [
['dom.presentation.enabled', true],
]
}, runTests);
});
});
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,39 @@
<!DOCTYPE HTML>
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for B2G Presentation Device Info API Permission</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1080474">Test for B2G Presentation Device Info API Permission</a>
<script type="application/javascript;version=1.8">
'use strict';
SimpleTest.waitForExplicitFinish();
function runTests() {
ise(navigator.mozPresentationDeviceInfo, undefined, 'navigator.mozPresentationDeviceInfo is undefined');
SimpleTest.finish();
}
window.addEventListener('load', function() {
SpecialPowers.pushPermissions([
{type: 'presentation-device-manage', allow: false, context: document},
], function() {
SpecialPowers.pushPrefEnv({
'set': [
['dom.presentation.enabled', true],
]
}, runTests);
});
});
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -883,6 +883,10 @@ var interfaceNamesInGlobalScope =
{name: "PopupBoxObject", xbl: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "PositionSensorVRDevice", pref: "dom.vr.enabled"},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "PresentationDeviceInfoManager",
pref: "dom.presentation.enabled",
permission: ["presentation-device-manage"]},
// IMPORTANT: Do not change this list without review from a DOM peer!
"ProcessingInstruction",
// IMPORTANT: Do not change this list without review from a DOM peer!

Просмотреть файл

@ -0,0 +1,26 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/.
*/
dictionary PresentationDeviceInfo {
DOMString id;
DOMString name;
DOMString type;
};
[NavigatorProperty="mozPresentationDeviceInfo",
JSImplementation="@mozilla.org/presentation-device/deviceInfo;1",
Pref="dom.presentation.enabled",
CheckPermissions="presentation-device-manage"]
interface PresentationDeviceInfoManager : EventTarget {
// notify if any device updated.
attribute EventHandler ondevicechange;
// retrieve all available device infos
Promise<sequence<PresentationDeviceInfo>> getAll();
// Force all registered device provider to update device information.
void forceDiscovery();
};

Просмотреть файл

@ -331,6 +331,7 @@ WEBIDL_FILES = [
'PopupBoxObject.webidl',
'Position.webidl',
'PositionError.webidl',
'PresentationDeviceInfoManager.webidl',
'ProcessingInstruction.webidl',
'ProfileTimelineMarker.webidl',
'Promise.webidl',

Просмотреть файл

@ -456,6 +456,9 @@
@BINPATH@/components/Downloads.manifest
@BINPATH@/components/DownloadLegacy.js
@BINPATH@/components/PresentationDeviceInfoManager.manifest
@BINPATH@/components/PresentationDeviceInfoManager.js
; Modules
@BINPATH@/modules/*

Просмотреть файл

@ -4422,6 +4422,9 @@ pref("dom.udpsocket.enabled", false);
// Disable before keyboard events and after keyboard events by default.
pref("dom.beforeAfterKeyboardEvent.enabled", false);
// Presentation API
pref("dom.presentation.enabled", false);
// Use raw ICU instead of CoreServices API in Unicode collation
#ifdef XP_MACOSX
pref("intl.collation.mac.use_icu", true);