зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to inbound, a=merge CLOSED TREE
This commit is contained in:
Коммит
fd401f9e9b
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="0d67eb545b2f4342525d14e1a10e80c91c87ada0"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8ca93673869a64e09ed6153c5402896822dfb253"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="0d67eb545b2f4342525d14e1a10e80c91c87ada0"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8ca93673869a64e09ed6153c5402896822dfb253"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="0d67eb545b2f4342525d14e1a10e80c91c87ada0"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="8ca93673869a64e09ed6153c5402896822dfb253"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="22664edc4c73e5fe8f5095ff1d5549db78a2bc10"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="0d67eb545b2f4342525d14e1a10e80c91c87ada0"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8ca93673869a64e09ed6153c5402896822dfb253"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="53517af1f57810bef745f03602f407161a475d76"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="0d67eb545b2f4342525d14e1a10e80c91c87ada0"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8ca93673869a64e09ed6153c5402896822dfb253"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -129,7 +129,7 @@
|
|||
<!-- Emulator specific things -->
|
||||
<project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="72ffdf71c68a96309212eb13d63560d66db14c9e"/>
|
||||
<project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="f390788a00706c06e5248edfd8d27b365387e84a"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="fbd2becab3825c49e756db5149552f85049c66e2"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="82800d4ed59429da2ba628d4558ea0653a902a4e"/>
|
||||
<project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="f37bd545063039e30a92f2550ae78c0e6e4e2d08"/>
|
||||
<project name="platform_external_wpa_supplicant_8" path="external/wpa_supplicant_8" remote="b2g" revision="0c6a6547cd1fd302fa2b0f6e375654df36bf0ec4"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="42f61f665e7a9857da8cd14b455e15bae98e6b44"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="0d67eb545b2f4342525d14e1a10e80c91c87ada0"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8ca93673869a64e09ed6153c5402896822dfb253"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="0d67eb545b2f4342525d14e1a10e80c91c87ada0"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="8ca93673869a64e09ed6153c5402896822dfb253"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="22664edc4c73e5fe8f5095ff1d5549db78a2bc10"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="0d67eb545b2f4342525d14e1a10e80c91c87ada0"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8ca93673869a64e09ed6153c5402896822dfb253"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"git": {
|
||||
"git_revision": "0d67eb545b2f4342525d14e1a10e80c91c87ada0",
|
||||
"git_revision": "8ca93673869a64e09ed6153c5402896822dfb253",
|
||||
"remote": "https://git.mozilla.org/releases/gaia.git",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "da5a1b63adc3322a73c57d22690472857fed353a",
|
||||
"revision": "ce5b9f84c7e253e3615694be152d257995ce2238",
|
||||
"repo_path": "integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="0d67eb545b2f4342525d14e1a10e80c91c87ada0"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8ca93673869a64e09ed6153c5402896822dfb253"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="53517af1f57810bef745f03602f407161a475d76"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="0d67eb545b2f4342525d14e1a10e80c91c87ada0"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8ca93673869a64e09ed6153c5402896822dfb253"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
|
|
@ -330,6 +330,7 @@ loop.conversationViews = (function(mozL10n) {
|
|||
|
||||
var errorString;
|
||||
switch (this.props.failureReason) {
|
||||
case FAILURE_DETAILS.NO_MEDIA:
|
||||
case FAILURE_DETAILS.UNABLE_TO_PUBLISH_MEDIA:
|
||||
errorString = mozL10n.get("no_media_failure_message");
|
||||
break;
|
||||
|
|
|
@ -330,6 +330,7 @@ loop.conversationViews = (function(mozL10n) {
|
|||
|
||||
var errorString;
|
||||
switch (this.props.failureReason) {
|
||||
case FAILURE_DETAILS.NO_MEDIA:
|
||||
case FAILURE_DETAILS.UNABLE_TO_PUBLISH_MEDIA:
|
||||
errorString = mozL10n.get("no_media_failure_message");
|
||||
break;
|
||||
|
|
|
@ -978,7 +978,7 @@ loop.OTSdkDriver = (function() {
|
|||
|
||||
var bucket = this.mozLoop.SHARING_STATE_CHANGE[type.toUpperCase() + "_" +
|
||||
(enabled ? "ENABLED" : "DISABLED")];
|
||||
if (!bucket) {
|
||||
if (typeof bucket === "undefined") {
|
||||
console.error("No sharing state bucket found for '" + type + "'");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -241,7 +241,7 @@ let LoopRoomsInternal = {
|
|||
* @param {String} roomToken The token for the room that needs encrypting.
|
||||
*/
|
||||
queueForEncryption: function(roomToken) {
|
||||
if (!this.encryptionQueue.queue.includes(roomToken)) {
|
||||
if (this.encryptionQueue.queue.indexOf(roomToken) == -1) {
|
||||
this.encryptionQueue.queue.push(roomToken);
|
||||
}
|
||||
|
||||
|
|
|
@ -939,6 +939,15 @@ describe("loop.conversationViews", function () {
|
|||
expect(view.getDOMNode().querySelector("h2").textContent).eql("no_media_failure_message");
|
||||
});
|
||||
|
||||
it("should show 'no media' for FAILURE_DETAILS.NO_MEDIA reason", function() {
|
||||
view = mountTestComponent({
|
||||
cancelCall: function() {},
|
||||
failureReason: FAILURE_DETAILS.NO_MEDIA
|
||||
});
|
||||
|
||||
expect(view.getDOMNode().querySelector("h2").textContent).eql("no_media_failure_message");
|
||||
});
|
||||
|
||||
it("should show 'generic_failure_title' when no reason is specified", function() {
|
||||
view = mountTestComponent({cancelCall: function() {}});
|
||||
|
||||
|
|
|
@ -78,16 +78,16 @@ describe("loop.OTSdkDriver", function () {
|
|||
mozLoop = {
|
||||
telemetryAddValue: sinon.stub(),
|
||||
TWO_WAY_MEDIA_CONN_LENGTH: {
|
||||
SHORTER_THAN_10S: "SHORTER_THAN_10S",
|
||||
BETWEEN_10S_AND_30S: "BETWEEN_10S_AND_30S",
|
||||
BETWEEN_30S_AND_5M: "BETWEEN_30S_AND_5M",
|
||||
MORE_THAN_5M: "MORE_THAN_5M"
|
||||
SHORTER_THAN_10S: 0,
|
||||
BETWEEN_10S_AND_30S: 1,
|
||||
BETWEEN_30S_AND_5M: 2,
|
||||
MORE_THAN_5M: 3
|
||||
},
|
||||
SHARING_STATE_CHANGE: {
|
||||
WINDOW_ENABLED: "WINDOW_ENABLED",
|
||||
WINDOW_DISABLED: "WINDOW_DISABLED",
|
||||
BROWSER_ENABLED: "BROWSER_ENABLED",
|
||||
BROWSER_DISABLED: "BROWSER_DISABLED"
|
||||
WINDOW_ENABLED: 0,
|
||||
WINDOW_DISABLED: 1,
|
||||
BROWSER_ENABLED: 2,
|
||||
BROWSER_DISABLED: 3
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -190,8 +190,8 @@ EventEmitter.decorate(this);
|
|||
/**
|
||||
* DOM query helpers.
|
||||
*/
|
||||
function $(selector, target = document) target.querySelector(selector);
|
||||
function $all(selector, target = document) target.querySelectorAll(selector);
|
||||
let $ = (selector, target = document) => target.querySelector(selector);
|
||||
let $all = (selector, target = document) => target.querySelectorAll(selector);
|
||||
|
||||
/**
|
||||
* Helper for getting an nsIURL instance out of a string.
|
||||
|
|
|
@ -57,7 +57,9 @@ CanvasDebuggerPanel.prototype = {
|
|||
|
||||
// DevToolPanel API
|
||||
|
||||
get target() this._toolbox.target,
|
||||
get target() {
|
||||
return this._toolbox.target;
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
// Make sure this panel is not already destroyed.
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* You can also use this initialization format as a template for other tests.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, front } = yield initCallWatcherBackend(SIMPLE_CANVAS_URL);
|
||||
|
||||
ok(target, "Should have a target available.");
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* and that their stack is successfully retrieved.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, front } = yield initCallWatcherBackend(SIMPLE_CANVAS_URL);
|
||||
|
||||
let navigated = once(target, "navigate");
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* for a canvas context.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, front } = yield initCanvasDebuggerBackend(SIMPLE_CANVAS_URL);
|
||||
|
||||
let navigated = once(target, "navigate");
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* the correct thumbnails.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, front } = yield initCanvasDebuggerBackend(SIMPLE_CANVAS_URL);
|
||||
|
||||
let navigated = once(target, "navigate");
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* the correct "end result" screenshot.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, front } = yield initCanvasDebuggerBackend(SIMPLE_CANVAS_URL);
|
||||
|
||||
let navigated = once(target, "navigate");
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Tests if screenshots for arbitrary draw calls are generated properly.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, front } = yield initCanvasDebuggerBackend(SIMPLE_CANVAS_TRANSPARENT_URL);
|
||||
|
||||
let navigated = once(target, "navigate");
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* by deferring the the most recent previous draw-call.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, front } = yield initCanvasDebuggerBackend(SIMPLE_CANVAS_URL);
|
||||
|
||||
let navigated = once(target, "navigate");
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* forms if the method's signature does not expect an enum. Bug 999687.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, front } = yield initCanvasDebuggerBackend(SIMPLE_BITMASKS_URL);
|
||||
|
||||
let navigated = once(target, "navigate");
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* forms if the method's signature does not expect an enum. Bug 999687.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, front } = yield initCanvasDebuggerBackend(WEBGL_ENUM_URL);
|
||||
|
||||
let navigated = once(target, "navigate");
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* after generating screenshots using the actor.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, front } = yield initCanvasDebuggerBackend(WEBGL_BINDINGS_URL);
|
||||
loadFrameScripts();
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* for a canvas context, and that the generated screenshots are correct.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, front } = yield initCanvasDebuggerBackend(SET_TIMEOUT_URL);
|
||||
|
||||
let navigated = once(target, "navigate");
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* in the event no rAF loop is found.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, front } = yield initCanvasDebuggerBackend(NO_CANVAS_URL);
|
||||
loadFrameScripts();
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Tests if certain function calls are properly highlighted in the UI.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, $, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* are properly displayed in the UI.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, $, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Tests if filtering the items in the call list works properly.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, $, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||
let searchbox = $("#calls-searchbox");
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Tests if the a function call's stack is properly displayed in the UI.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_DEEP_STACK_URL);
|
||||
let { window, $, $all, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* and jumping to source in the debugger for the topmost call item works.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_DEEP_STACK_URL);
|
||||
let { window, $, $all, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* on a function call item.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_DEEP_STACK_URL);
|
||||
let { window, $, $all, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Tests if clearing the snapshots list works as expected.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, EVENTS, SnapshotsListView } = panel.panelWin;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Tests if screenshots are properly displayed in the UI.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, $, EVENTS, SnapshotsListView } = panel.panelWin;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Tests if thumbnails are properly displayed in the UI.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, $, $all, EVENTS, SnapshotsListView } = panel.panelWin;
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* function call items and their respective screenshots.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, $, $all, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Tests that the frontend UI is properly configured when opening the tool.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { $ } = panel.panelWin;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Tests whether the frontend behaves correctly while reording a snapshot.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, EVENTS, $, SnapshotsListView } = panel.panelWin;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Tests whether the frontend displays a placeholder snapshot while recording.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, EVENTS, L10N, $, SnapshotsListView } = panel.panelWin;
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* after finishing recording.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, EVENTS, $, SnapshotsListView } = panel.panelWin;
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* of its loop, when the recording starts before the rAFs start.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(RAF_BEGIN_URL);
|
||||
let { window, EVENTS, gFront, SnapshotsListView } = panel.panelWin;
|
||||
loadFrameScripts();
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Tests that the frontend UI is properly reconfigured after reloading.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, $, EVENTS } = panel.panelWin;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Tests that the frontend UI is properly reconfigured after reloading.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, $, $all, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Tests if the slider in the calls list view works as advertised.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, $, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Tests if the slider in the calls list view works as advertised.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, $, EVENTS, gFront, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* respective to their recorded animation frame.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, $, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* respective to their recorded animation frame.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, $, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Tests if the stepping buttons in the call list toolbar work as advertised.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, $, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Tests that you can stop a recording that does not have a rAF cycle.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(NO_CANVAS_URL);
|
||||
let { window, EVENTS, $, SnapshotsListView } = panel.panelWin;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Tests that a recording that does not have a rAF cycle fails after timeout.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(NO_CANVAS_URL);
|
||||
let { window, EVENTS, $, SnapshotsListView } = panel.panelWin;
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* after timeout.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(RAF_NO_CANVAS_URL);
|
||||
let { window, EVENTS, $, SnapshotsListView } = panel.panelWin;
|
||||
|
||||
|
|
|
@ -66,6 +66,7 @@ support-files =
|
|||
[browser_graphs-09f.js]
|
||||
[browser_graphs-10a.js]
|
||||
[browser_graphs-10b.js]
|
||||
[browser_graphs-10c.js]
|
||||
[browser_graphs-11a.js]
|
||||
[browser_graphs-11b.js]
|
||||
[browser_graphs-12.js]
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
|
||||
// Tests that graphs properly handle resizing.
|
||||
|
||||
const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
|
||||
let {LineGraphWidget} = Cu.import("resource:///modules/devtools/Graphs.jsm", {});
|
||||
let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
|
||||
|
||||
add_task(function*() {
|
||||
yield promiseTab("about:blank");
|
||||
yield performTest();
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
function* performTest() {
|
||||
let [host, win, doc] = yield createHost("window");
|
||||
doc.body.setAttribute("style", "position: fixed; width: 100%; height: 100%; margin: 0;");
|
||||
|
||||
let graph = new LineGraphWidget(doc.body, "fps");
|
||||
yield graph.once("ready");
|
||||
|
||||
let refreshCount = 0;
|
||||
graph.on("refresh", () => refreshCount++);
|
||||
|
||||
yield testGraph(host, graph);
|
||||
|
||||
is(refreshCount, 2, "The graph should've been refreshed 2 times.");
|
||||
|
||||
yield graph.destroy();
|
||||
host.destroy();
|
||||
}
|
||||
|
||||
function* testGraph(host, graph) {
|
||||
graph.setData(TEST_DATA);
|
||||
|
||||
host._window.resizeTo(500, 500);
|
||||
yield graph.once("refresh");
|
||||
let oldBounds = host.frame.getBoundingClientRect();
|
||||
|
||||
is (graph._width, oldBounds.width * window.devicePixelRatio,
|
||||
"The window was properly resized (1).");
|
||||
is (graph._height, oldBounds.height * window.devicePixelRatio,
|
||||
"The window was properly resized (1).");
|
||||
|
||||
dragStart(graph, 100);
|
||||
dragStop(graph, 400);
|
||||
|
||||
is(graph.getSelection().start, 100,
|
||||
"The current selection start value is correct (1).");
|
||||
is(graph.getSelection().end, 400,
|
||||
"The current selection end value is correct (1).");
|
||||
|
||||
info("Making sure the selection updates when the window is resized");
|
||||
|
||||
host._window.resizeTo(250, 250);
|
||||
yield graph.once("refresh");
|
||||
let newBounds = host.frame.getBoundingClientRect();
|
||||
|
||||
is (graph._width, newBounds.width * window.devicePixelRatio,
|
||||
"The window was properly resized (2).");
|
||||
is (graph._height, newBounds.height * window.devicePixelRatio,
|
||||
"The window was properly resized (2).");
|
||||
|
||||
let ratio = oldBounds.width / newBounds.width;
|
||||
info("The window resize ratio is: " + ratio);
|
||||
|
||||
is(graph.getSelection().start, Math.round(100 / ratio),
|
||||
"The current selection start value is correct (2).");
|
||||
is(graph.getSelection().end, Math.round(400 / ratio),
|
||||
"The current selection end value is correct (2).");
|
||||
}
|
||||
|
||||
// EventUtils just doesn't work!
|
||||
|
||||
function dragStart(graph, x, y = 1) {
|
||||
x /= window.devicePixelRatio;
|
||||
y /= window.devicePixelRatio;
|
||||
graph._onMouseMove({ testX: x, testY: y });
|
||||
graph._onMouseDown({ testX: x, testY: y });
|
||||
}
|
||||
|
||||
function dragStop(graph, x, y = 1) {
|
||||
x /= window.devicePixelRatio;
|
||||
y /= window.devicePixelRatio;
|
||||
graph._onMouseMove({ testX: x, testY: y });
|
||||
graph._onMouseUp({ testX: x, testY: y });
|
||||
}
|
|
@ -684,6 +684,13 @@ AbstractCanvasGraph.prototype = {
|
|||
return;
|
||||
}
|
||||
|
||||
// Handle a changed size by mapping the old selection to the new width
|
||||
if (this._width && newWidth && this.hasSelection()) {
|
||||
let ratio = this._width / (newWidth * this._pixelRatio);
|
||||
this._selection.start = Math.round(this._selection.start / ratio);
|
||||
this._selection.end = Math.round(this._selection.end / ratio);
|
||||
}
|
||||
|
||||
bounds.width = newWidth;
|
||||
bounds.height = newHeight;
|
||||
this._iframe.setAttribute("width", bounds.width);
|
||||
|
|
|
@ -151,6 +151,7 @@ function CssHtmlTree(aStyleInspector, aPageStyle)
|
|||
this._onClick = this._onClick.bind(this);
|
||||
this._onCopy = this._onCopy.bind(this);
|
||||
this._onCopyColor = this._onCopyColor.bind(this);
|
||||
this._onCopyImageDataUrl = this._onCopyImageDataUrl.bind(this);
|
||||
this._onFilterStyles = this._onFilterStyles.bind(this);
|
||||
this._onFilterKeyPress = this._onFilterKeyPress.bind(this);
|
||||
this._onClearSearch = this._onClearSearch.bind(this);
|
||||
|
@ -328,7 +329,7 @@ CssHtmlTree.prototype = {
|
|||
* - type {String} One of the VIEW_NODE_XXX_TYPE const in
|
||||
* style-inspector-overlays
|
||||
* - value {Object} Depends on the type of the node
|
||||
* returns null of the node isn't anything we care about
|
||||
* returns null if the node isn't anything we care about
|
||||
*/
|
||||
getNodeInfo: function(node) {
|
||||
if (!node) {
|
||||
|
@ -351,7 +352,7 @@ CssHtmlTree.prototype = {
|
|||
return {
|
||||
type: overlays.VIEW_NODE_SELECTOR_TYPE,
|
||||
value: selectorText.trim()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Walk up the nodes to find out where node is
|
||||
|
@ -715,6 +716,13 @@ CssHtmlTree.prototype = {
|
|||
command: this._onCopyColor
|
||||
});
|
||||
|
||||
// Copy data URI
|
||||
this.menuitemCopyImageDataUrl = createMenuItem(this._contextmenu, {
|
||||
label: "styleinspector.contextmenu.copyImageDataUrl",
|
||||
accesskey: "styleinspector.contextmenu.copyImageDataUrl.accessKey",
|
||||
command: this._onCopyImageDataUrl
|
||||
});
|
||||
|
||||
// Show Original Sources
|
||||
this.menuitemSources= createMenuItem(this._contextmenu, {
|
||||
label: "ruleView.contextmenu.showOrigSources",
|
||||
|
@ -745,6 +753,7 @@ CssHtmlTree.prototype = {
|
|||
this.menuitemSources.setAttribute("checked", showOrig);
|
||||
|
||||
this.menuitemCopyColor.hidden = !this._isColorPopup();
|
||||
this.menuitemCopyImageDataUrl.hidden = !this._isImageUrlPopup();
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -757,14 +766,12 @@ CssHtmlTree.prototype = {
|
|||
_isColorPopup: function () {
|
||||
this._colorToCopy = "";
|
||||
|
||||
let trigger = this.popupNode;
|
||||
if (!trigger) {
|
||||
|
||||
let container = this._getPopupNodeContainer();
|
||||
if (!container) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let container = (trigger.nodeType == trigger.TEXT_NODE) ?
|
||||
trigger.parentElement : trigger;
|
||||
|
||||
let isColorNode = el => el.dataset && "color" in el.dataset;
|
||||
|
||||
while (!isColorNode(container)) {
|
||||
|
@ -778,6 +785,52 @@ CssHtmlTree.prototype = {
|
|||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if the context menu popup was opened with a click on an image link
|
||||
* If true, save the image url to this._imageUrlToCopy
|
||||
*/
|
||||
_isImageUrlPopup: function () {
|
||||
this._imageUrlToCopy = "";
|
||||
|
||||
let container = this._getPopupNodeContainer();
|
||||
let isImageUrlNode = this._isImageUrlNode(container);
|
||||
if (isImageUrlNode) {
|
||||
this._imageUrlToCopy = container.href;
|
||||
}
|
||||
|
||||
return isImageUrlNode;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if a node is an image url
|
||||
* @param {DOMNode} node The node which we want information about
|
||||
* @return {Boolean} true if the node is an image url
|
||||
*/
|
||||
_isImageUrlNode: function (node) {
|
||||
let nodeInfo = this.getNodeInfo(node);
|
||||
if (!nodeInfo) {
|
||||
return false
|
||||
}
|
||||
return nodeInfo.type == overlays.VIEW_NODE_IMAGE_URL_TYPE;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the DOM Node container for the current popupNode.
|
||||
* If popupNode is a textNode, return the parent node, otherwise return popupNode itself.
|
||||
* @return {DOMNode}
|
||||
*/
|
||||
_getPopupNodeContainer: function () {
|
||||
let container = null;
|
||||
let node = this.popupNode;
|
||||
|
||||
if (node) {
|
||||
let isTextNode = node.nodeType == node.TEXT_NODE;
|
||||
container = isTextNode ? node.parentElement : node;
|
||||
}
|
||||
|
||||
return container;
|
||||
},
|
||||
|
||||
/**
|
||||
* Context menu handler.
|
||||
*/
|
||||
|
@ -821,6 +874,22 @@ CssHtmlTree.prototype = {
|
|||
clipboardHelper.copyString(this._colorToCopy);
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve the image data for the selected image url and copy it to the clipboard
|
||||
*/
|
||||
_onCopyImageDataUrl: Task.async(function*() {
|
||||
let message;
|
||||
try {
|
||||
let inspectorFront = this.inspector.inspector;
|
||||
let data = yield inspectorFront.getImageDataFromURL(this._imageUrlToCopy);
|
||||
message = yield data.data.string();
|
||||
} catch (e) {
|
||||
message = CssHtmlTree.l10n("styleinspector.copyImageDataUrlError");
|
||||
}
|
||||
|
||||
clipboardHelper.copyString(message);
|
||||
}),
|
||||
|
||||
/**
|
||||
* Copy selected text.
|
||||
*
|
||||
|
@ -910,6 +979,10 @@ CssHtmlTree.prototype = {
|
|||
this.menuitemCopyColor.removeEventListener("command", this._onCopyColor);
|
||||
this.menuitemCopyColor = null;
|
||||
|
||||
// Destroy Copy Data URI menuitem.
|
||||
this.menuitemCopyImageDataUrl.removeEventListener("command", this._onCopyImageDataUrl);
|
||||
this.menuitemCopyImageDataUrl = null;
|
||||
|
||||
// Destroy the context menu.
|
||||
this._contextmenu.removeEventListener("popupshowing", this._contextMenuUpdate);
|
||||
this._contextmenu.parentNode.removeChild(this._contextmenu);
|
||||
|
|
|
@ -1123,6 +1123,7 @@ function CssRuleView(aInspector, aDoc, aStore, aPageStyle) {
|
|||
this._onSelectAll = this._onSelectAll.bind(this);
|
||||
this._onCopy = this._onCopy.bind(this);
|
||||
this._onCopyColor = this._onCopyColor.bind(this);
|
||||
this._onCopyImageDataUrl = this._onCopyImageDataUrl.bind(this);
|
||||
this._onToggleOrigSources = this._onToggleOrigSources.bind(this);
|
||||
this._onShowMdnDocs = this._onShowMdnDocs.bind(this);
|
||||
this._onFilterStyles = this._onFilterStyles.bind(this);
|
||||
|
@ -1214,6 +1215,11 @@ CssRuleView.prototype = {
|
|||
accesskey: "ruleView.contextmenu.copyColor.accessKey",
|
||||
command: this._onCopyColor
|
||||
});
|
||||
this.menuitemCopyImageDataUrl = createMenuItem(this._contextmenu, {
|
||||
label: "styleinspector.contextmenu.copyImageDataUrl",
|
||||
accesskey: "styleinspector.contextmenu.copyImageDataUrl.accessKey",
|
||||
command: this._onCopyImageDataUrl
|
||||
});
|
||||
this.menuitemSources = createMenuItem(this._contextmenu, {
|
||||
label: "ruleView.contextmenu.showOrigSources",
|
||||
accesskey: "ruleView.contextmenu.showOrigSources.accessKey",
|
||||
|
@ -1348,6 +1354,7 @@ CssRuleView.prototype = {
|
|||
}
|
||||
|
||||
this.menuitemCopyColor.hidden = !this._isColorPopup();
|
||||
this.menuitemCopyImageDataUrl.hidden = !this._isImageUrlPopup();
|
||||
this.menuitemCopy.disabled = !copy;
|
||||
|
||||
var showOrig = Services.prefs.getBoolPref(PREF_ORIG_SOURCES);
|
||||
|
@ -1398,7 +1405,7 @@ CssRuleView.prototype = {
|
|||
pseudoElement: prop.rule.pseudoElement,
|
||||
sheetHref: prop.rule.domRule.href
|
||||
};
|
||||
} else if (classes.contains("theme-link") && prop) {
|
||||
} else if (classes.contains("theme-link") && !classes.contains("ruleview-rule-source") && prop) {
|
||||
type = overlays.VIEW_NODE_IMAGE_URL_TYPE;
|
||||
value = {
|
||||
property: getPropertyNameAndValue(node).name,
|
||||
|
@ -1430,14 +1437,11 @@ CssRuleView.prototype = {
|
|||
_isColorPopup: function () {
|
||||
this._colorToCopy = "";
|
||||
|
||||
let trigger = this.doc.popupNode;
|
||||
if (!trigger) {
|
||||
let container = this._getPopupNodeContainer();
|
||||
if (!container) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let container = (trigger.nodeType == trigger.TEXT_NODE) ?
|
||||
trigger.parentElement : trigger;
|
||||
|
||||
let isColorNode = el => el.dataset && "color" in el.dataset;
|
||||
|
||||
while (!isColorNode(container)) {
|
||||
|
@ -1451,6 +1455,52 @@ CssRuleView.prototype = {
|
|||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if the context menu popup was opened with a click on an image link
|
||||
* If true, save the image url to this._imageUrlToCopy
|
||||
*/
|
||||
_isImageUrlPopup: function () {
|
||||
this._imageUrlToCopy = "";
|
||||
|
||||
let container = this._getPopupNodeContainer();
|
||||
let isImageUrlNode = this._isImageUrlNode(container);
|
||||
if (isImageUrlNode) {
|
||||
this._imageUrlToCopy = container.href;
|
||||
}
|
||||
|
||||
return isImageUrlNode;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if a node is an image url
|
||||
* @param {DOMNode} node The node which we want information about
|
||||
* @return {Boolean} true if the node is an image url
|
||||
*/
|
||||
_isImageUrlNode: function (node) {
|
||||
let nodeInfo = this.getNodeInfo(node);
|
||||
if (!nodeInfo) {
|
||||
return false
|
||||
}
|
||||
return nodeInfo.type == overlays.VIEW_NODE_IMAGE_URL_TYPE;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the DOM Node container for the current popupNode.
|
||||
* If popupNode is a textNode, return the parent node, otherwise return popupNode itself.
|
||||
* @return {DOMNode}
|
||||
*/
|
||||
_getPopupNodeContainer: function () {
|
||||
let container = null;
|
||||
let node = this.doc.popupNode;
|
||||
|
||||
if (node) {
|
||||
let isTextNode = node.nodeType == node.TEXT_NODE;
|
||||
container = isTextNode ? node.parentElement : node;
|
||||
}
|
||||
|
||||
return container;
|
||||
},
|
||||
|
||||
/**
|
||||
* Context menu handler.
|
||||
*/
|
||||
|
@ -1525,6 +1575,22 @@ CssRuleView.prototype = {
|
|||
clipboardHelper.copyString(this._colorToCopy);
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve the image data for the selected image url and copy it to the clipboard
|
||||
*/
|
||||
_onCopyImageDataUrl: Task.async(function*() {
|
||||
let message;
|
||||
try {
|
||||
let inspectorFront = this.inspector.inspector;
|
||||
let data = yield inspectorFront.getImageDataFromURL(this._imageUrlToCopy);
|
||||
message = yield data.data.string();
|
||||
} catch (e) {
|
||||
message = _strings.GetStringFromName("styleinspector.copyImageDataUrlError");
|
||||
}
|
||||
|
||||
clipboardHelper.copyString(message);
|
||||
}),
|
||||
|
||||
/**
|
||||
* Toggle the original sources pref.
|
||||
*/
|
||||
|
@ -1729,6 +1795,10 @@ CssRuleView.prototype = {
|
|||
this.menuitemCopyColor.removeEventListener("command", this._onCopyColor);
|
||||
this.menuitemCopyColor = null;
|
||||
|
||||
// Destroy Copy Data URI menuitem.
|
||||
this.menuitemCopyImageDataUrl.removeEventListener("command", this._onCopyImageDataUrl);
|
||||
this.menuitemCopyImageDataUrl = null;
|
||||
|
||||
this.menuitemSources.removeEventListener("command", this._onToggleOrigSources);
|
||||
this.menuitemSources = null;
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ const {
|
|||
SwatchFilterTooltip
|
||||
} = require("devtools/shared/widgets/Tooltip");
|
||||
const {CssLogic} = require("devtools/styleinspector/css-logic");
|
||||
const EventEmitter = require("devtools/toolkit/event-emitter");
|
||||
const {Promise:promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
@ -59,6 +60,8 @@ function HighlightersOverlay(view) {
|
|||
// Only initialize the overlay if at least one of the highlighter types is
|
||||
// supported
|
||||
this.supportsHighlighters = this.highlighterUtils.supportsCustomHighlighters();
|
||||
|
||||
EventEmitter.decorate(this);
|
||||
}
|
||||
|
||||
exports.HighlightersOverlay = HighlightersOverlay;
|
||||
|
@ -124,9 +127,13 @@ HighlightersOverlay.prototype = {
|
|||
if (type) {
|
||||
this.highlighterShown = type;
|
||||
let node = this.view.inspector.selection.nodeFront;
|
||||
this._getHighlighter(type).then(highlighter => {
|
||||
highlighter.show(node);
|
||||
});
|
||||
this._getHighlighter(type)
|
||||
.then(highlighter => highlighter.show(node))
|
||||
.then(shown => {
|
||||
if (shown) {
|
||||
this.emit("highlighter-shown");
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -176,6 +183,7 @@ HighlightersOverlay.prototype = {
|
|||
promise.then(null, Cu.reportError);
|
||||
}
|
||||
this.highlighterShown = null;
|
||||
this.emit("highlighter-hidden");
|
||||
});
|
||||
}
|
||||
},
|
||||
|
|
|
@ -151,6 +151,7 @@ skip-if = e10s # bug 1040670 Cannot open inline styles in viewSourceUtils
|
|||
[browser_ruleview_user-property-reset.js]
|
||||
[browser_styleinspector_context-menu-copy-color_01.js]
|
||||
[browser_styleinspector_context-menu-copy-color_02.js]
|
||||
[browser_styleinspector_context-menu-copy-data-uri.js]
|
||||
[browser_styleinspector_csslogic-content-stylesheets.js]
|
||||
[browser_styleinspector_output-parser.js]
|
||||
[browser_styleinspector_refresh_when_active.js]
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const PROPERTIES_URL = "chrome://global/locale/devtools/styleinspector.properties";
|
||||
const TEST_DATA_URI = "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=";
|
||||
|
||||
// invalid URL still needs to be reachable otherwise getImageDataUrl will timeout.
|
||||
// Reusing the properties bundle URL as a workaround
|
||||
const INVALID_IMAGE_URI = PROPERTIES_URL;
|
||||
|
||||
const ERROR_MESSAGE = Services.strings
|
||||
.createBundle(PROPERTIES_URL)
|
||||
.GetStringFromName("styleinspector.copyImageDataUrlError");
|
||||
|
||||
add_task(function*() {
|
||||
const PAGE_CONTENT = [
|
||||
"<style type=\"text/css\">",
|
||||
" .valid-background {",
|
||||
" background-image: url(" + TEST_DATA_URI + ");",
|
||||
" }",
|
||||
" .invalid-background {",
|
||||
" background-image: url(" + INVALID_IMAGE_URI + ");",
|
||||
" }",
|
||||
"</style>",
|
||||
"<div class=\"valid-background\">Valid background image</div>",
|
||||
"<div class=\"invalid-background\">Invalid background image</div>"
|
||||
].join("\n");
|
||||
|
||||
yield addTab("data:text/html;charset=utf8," + encodeURIComponent(PAGE_CONTENT));
|
||||
|
||||
yield startTest();
|
||||
});
|
||||
|
||||
function* startTest() {
|
||||
info("Opening rule view");
|
||||
let ruleViewData = yield openRuleView();
|
||||
|
||||
info("Test valid background image URL in rule view");
|
||||
yield testCopyImageDataUrlToClipboard(ruleViewData, ".valid-background", TEST_DATA_URI);
|
||||
info("Test invalid background image URL in rue view");
|
||||
yield testCopyImageDataUrlToClipboard(ruleViewData, ".invalid-background", ERROR_MESSAGE);
|
||||
|
||||
info("Opening computed view");
|
||||
let computedViewData = yield openComputedView();
|
||||
|
||||
info("Test valid background image URL in computed view");
|
||||
yield testCopyImageDataUrlToClipboard(computedViewData, ".valid-background", TEST_DATA_URI);
|
||||
info("Test invalid background image URL in computed view");
|
||||
yield testCopyImageDataUrlToClipboard(computedViewData, ".invalid-background", ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
function* testCopyImageDataUrlToClipboard({view, inspector}, selector, expected) {
|
||||
info("Select node in inspector panel");
|
||||
yield selectNode(selector, inspector);
|
||||
|
||||
info("Retrieve background-image link for selected node in current styleinspector view");
|
||||
let property = getBackgroundImageProperty(view, selector);
|
||||
let imageLink = property.valueSpan.querySelector(".theme-link");
|
||||
ok(imageLink, "Background-image link element found");
|
||||
|
||||
info("Simulate right click on the background-image URL");
|
||||
let popup = once(view._contextmenu, "popupshown");
|
||||
|
||||
// Cannot rely on synthesizeMouseAtCenter here. The image URL can be displayed on several lines.
|
||||
// A click simulated at the exact center may click between the lines and miss the target
|
||||
// Instead, using the top-left corner of first client rect, with an offset of 2 pixels.
|
||||
let rect = imageLink.getClientRects()[0];
|
||||
let x = rect.left + 2;
|
||||
let y = rect.top + 2;
|
||||
|
||||
EventUtils.synthesizeMouseAtPoint(x, y, {button: 2, type: "contextmenu"}, getViewWindow(view));
|
||||
yield popup;
|
||||
|
||||
info("Context menu is displayed");
|
||||
ok(!view.menuitemCopyImageDataUrl.hidden, "\"Copy Image Data-URL\" menu entry is displayed");
|
||||
|
||||
info("Click Copy Data URI and wait for clipboard");
|
||||
yield waitForClipboard(() => view.menuitemCopyImageDataUrl.click(), expected);
|
||||
|
||||
info("Hide context menu");
|
||||
view._contextmenu.hidePopup();
|
||||
}
|
||||
|
||||
function getBackgroundImageProperty(view, selector) {
|
||||
let isRuleView = view instanceof CssRuleView;
|
||||
if (isRuleView) {
|
||||
return getRuleViewProperty(view, selector, "background-image");
|
||||
} else {
|
||||
return getComputedViewProperty(view, "background-image");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that returns the window for a given view.
|
||||
*/
|
||||
function getViewWindow(view) {
|
||||
let viewDocument = view.styleDocument ? view.styleDocument : view.doc;
|
||||
return viewDocument.defaultView;
|
||||
}
|
|
@ -36,7 +36,9 @@ add_task(function*() {
|
|||
|
||||
info("Faking a mousemove on a transform property");
|
||||
({valueSpan} = getRuleViewProperty(rView, "body", "transform"));
|
||||
let onHighlighterShown = hs.once("highlighter-shown");
|
||||
hs._onMouseMove({target: valueSpan});
|
||||
yield onHighlighterShown;
|
||||
ok(hs.promises[TYPE], "The highlighter is being initialized");
|
||||
let h = yield hs.promises[TYPE];
|
||||
is(h, hs.highlighters[TYPE], "The initialized highlighter is the right one");
|
||||
|
@ -57,7 +59,9 @@ add_task(function*() {
|
|||
|
||||
info("Faking a mousemove on a transform property");
|
||||
({valueSpan} = getComputedViewProperty(cView, "transform"));
|
||||
onHighlighterShown = hs.once("highlighter-shown");
|
||||
hs._onMouseMove({target: valueSpan});
|
||||
yield onHighlighterShown;
|
||||
ok(hs.promises[TYPE], "The highlighter is being initialized");
|
||||
h = yield hs.promises[TYPE];
|
||||
is(h, hs.highlighters[TYPE], "The initialized highlighter is the right one");
|
||||
|
|
|
@ -39,53 +39,64 @@ add_task(function*() {
|
|||
this.nodeFront = nodeFront;
|
||||
this.isShown = true;
|
||||
this.nbOfTimesShown ++;
|
||||
return promise.resolve(true);
|
||||
},
|
||||
hide: function() {
|
||||
this.nodeFront = null;
|
||||
this.isShown = false;
|
||||
return promise.resolve();
|
||||
}
|
||||
};
|
||||
|
||||
// Inject the mock highlighter in the rule-view
|
||||
rView.highlighters.promises[TYPE] = {
|
||||
then: function(cb) {
|
||||
cb(HighlighterFront);
|
||||
}
|
||||
};
|
||||
let hs = rView.highlighters;
|
||||
hs.promises[TYPE] = promise.resolve(HighlighterFront);
|
||||
|
||||
let {valueSpan} = getRuleViewProperty(rView, "body", "transform");
|
||||
|
||||
info("Checking that the HighlighterFront's show/hide methods are called");
|
||||
rView.highlighters._onMouseMove({target: valueSpan});
|
||||
let onHighlighterShown = hs.once("highlighter-shown");
|
||||
hs._onMouseMove({target: valueSpan});
|
||||
yield onHighlighterShown;
|
||||
ok(HighlighterFront.isShown, "The highlighter is shown");
|
||||
rView.highlighters._onMouseLeave();
|
||||
let onHighlighterHidden = hs.once("highlighter-hidden");
|
||||
hs._onMouseLeave();
|
||||
yield onHighlighterHidden;
|
||||
ok(!HighlighterFront.isShown, "The highlighter is hidden");
|
||||
|
||||
info("Checking that hovering several times over the same property doesn't" +
|
||||
" show the highlighter several times");
|
||||
let nb = HighlighterFront.nbOfTimesShown;
|
||||
rView.highlighters._onMouseMove({target: valueSpan});
|
||||
onHighlighterShown = hs.once("highlighter-shown");
|
||||
hs._onMouseMove({target: valueSpan});
|
||||
yield onHighlighterShown;
|
||||
is(HighlighterFront.nbOfTimesShown, nb + 1, "The highlighter was shown once");
|
||||
rView.highlighters._onMouseMove({target: valueSpan});
|
||||
rView.highlighters._onMouseMove({target: valueSpan});
|
||||
hs._onMouseMove({target: valueSpan});
|
||||
hs._onMouseMove({target: valueSpan});
|
||||
is(HighlighterFront.nbOfTimesShown, nb + 1,
|
||||
"The highlighter was shown once, after several mousemove");
|
||||
|
||||
info("Checking that the right NodeFront reference is passed");
|
||||
yield selectNode("html", inspector);
|
||||
({valueSpan} = getRuleViewProperty(rView, "html", "transform"));
|
||||
rView.highlighters._onMouseMove({target: valueSpan});
|
||||
onHighlighterShown = hs.once("highlighter-shown");
|
||||
hs._onMouseMove({target: valueSpan});
|
||||
yield onHighlighterShown;
|
||||
is(HighlighterFront.nodeFront.tagName, "HTML",
|
||||
"The right NodeFront is passed to the highlighter (1)");
|
||||
|
||||
yield selectNode("body", inspector);
|
||||
({valueSpan} = getRuleViewProperty(rView, "body", "transform"));
|
||||
rView.highlighters._onMouseMove({target: valueSpan});
|
||||
onHighlighterShown = hs.once("highlighter-shown");
|
||||
hs._onMouseMove({target: valueSpan});
|
||||
yield onHighlighterShown;
|
||||
is(HighlighterFront.nodeFront.tagName, "BODY",
|
||||
"The right NodeFront is passed to the highlighter (2)");
|
||||
|
||||
info("Checking that the highlighter gets hidden when hovering a non-transform property");
|
||||
({valueSpan} = getRuleViewProperty(rView, "body", "color"));
|
||||
rView.highlighters._onMouseMove({target: valueSpan});
|
||||
onHighlighterHidden = hs.once("highlighter-hidden");
|
||||
hs._onMouseMove({target: valueSpan});
|
||||
yield onHighlighterHidden;
|
||||
ok(!HighlighterFront.isShown, "The highlighter is hidden");
|
||||
});
|
||||
|
|
|
@ -55,7 +55,9 @@ add_task(function*() {
|
|||
|
||||
info("Faking a mousemove on the now unoverriden property");
|
||||
({valueSpan} = getRuleViewProperty(rView, "div", "transform"));
|
||||
let onHighlighterShown = hs.once("highlighter-shown");
|
||||
hs._onMouseMove({target: valueSpan});
|
||||
yield onHighlighterShown;
|
||||
ok(hs.promises[TYPE], "The highlighter is being initialized now");
|
||||
let h = yield hs.promises[TYPE];
|
||||
is(h, hs.highlighters[TYPE], "The initialized highlighter is the right one");
|
||||
|
|
|
@ -431,7 +431,7 @@ if test -z "$RUSTC" -a -n "$MOZ_RUST"; then
|
|||
To compile rust language sources, you must have 'rustc' in your path.
|
||||
See http://www.rust-lang.org/ for more information.])
|
||||
fi
|
||||
if test -n "$MOZ_RUST" -a -z "$_RUSTC_MAJOR_VERSION" -o \
|
||||
if test -n "$MOZ_RUST" && test -z "$_RUSTC_MAJOR_VERSION" -o \
|
||||
"$_RUSTC_MAJOR_VERSION" -lt 1; then
|
||||
AC_MSG_ERROR([Rust compiler ${RUSTC_VERSION} is too old.
|
||||
To compile rust language sources please install at least
|
||||
|
|
|
@ -1369,9 +1369,10 @@ private:
|
|||
|
||||
(this->*(HandleNtf[index]))(aHeader, aPDU);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const int BluetoothDaemonCoreModule::MAX_NUM_CLIENTS = 1;
|
||||
|
||||
//
|
||||
// Protocol handling
|
||||
//
|
||||
|
@ -1421,8 +1422,6 @@ private:
|
|||
//
|
||||
// - |HandleSvc|,
|
||||
//
|
||||
const int BluetoothDaemonCoreModule::MAX_NUM_CLIENTS = 1;
|
||||
|
||||
// which is called by |BluetoothDaemonProtcol| to hand over received
|
||||
// PDUs into a module.
|
||||
//
|
||||
|
@ -1624,117 +1623,6 @@ BluetoothDaemonProtocol::FetchUserData(const BluetoothDaemonPDUHeader& aHeader)
|
|||
return userData;
|
||||
}
|
||||
|
||||
//
|
||||
// Listen socket
|
||||
//
|
||||
|
||||
class BluetoothDaemonListenSocket final : public ipc::ListenSocket
|
||||
{
|
||||
public:
|
||||
BluetoothDaemonListenSocket(BluetoothDaemonInterface* aInterface);
|
||||
|
||||
// Connection state
|
||||
//
|
||||
|
||||
void OnConnectSuccess() override;
|
||||
void OnConnectError() override;
|
||||
void OnDisconnect() override;
|
||||
|
||||
private:
|
||||
BluetoothDaemonInterface* mInterface;
|
||||
};
|
||||
|
||||
BluetoothDaemonListenSocket::BluetoothDaemonListenSocket(
|
||||
BluetoothDaemonInterface* aInterface)
|
||||
: mInterface(aInterface)
|
||||
{ }
|
||||
|
||||
void
|
||||
BluetoothDaemonListenSocket::OnConnectSuccess()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mInterface);
|
||||
|
||||
mInterface->OnConnectSuccess(BluetoothDaemonInterface::LISTEN_SOCKET);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothDaemonListenSocket::OnConnectError()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mInterface);
|
||||
|
||||
mInterface->OnConnectError(BluetoothDaemonInterface::LISTEN_SOCKET);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothDaemonListenSocket::OnDisconnect()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mInterface);
|
||||
|
||||
mInterface->OnDisconnect(BluetoothDaemonInterface::LISTEN_SOCKET);
|
||||
}
|
||||
|
||||
//
|
||||
// Channels
|
||||
//
|
||||
|
||||
class BluetoothDaemonChannel final : public BluetoothDaemonConnection
|
||||
{
|
||||
public:
|
||||
BluetoothDaemonChannel(BluetoothDaemonInterface* aInterface,
|
||||
BluetoothDaemonInterface::Channel aChannel,
|
||||
BluetoothDaemonPDUConsumer* aConsumer);
|
||||
|
||||
// SocketBase
|
||||
//
|
||||
|
||||
void OnConnectSuccess() override;
|
||||
void OnConnectError() override;
|
||||
void OnDisconnect() override;
|
||||
|
||||
private:
|
||||
BluetoothDaemonInterface* mInterface;
|
||||
BluetoothDaemonInterface::Channel mChannel;
|
||||
};
|
||||
|
||||
BluetoothDaemonChannel::BluetoothDaemonChannel(
|
||||
BluetoothDaemonInterface* aInterface,
|
||||
BluetoothDaemonInterface::Channel aChannel,
|
||||
BluetoothDaemonPDUConsumer* aConsumer)
|
||||
: BluetoothDaemonConnection(aConsumer)
|
||||
, mInterface(aInterface)
|
||||
, mChannel(aChannel)
|
||||
{ }
|
||||
|
||||
void
|
||||
BluetoothDaemonChannel::OnConnectSuccess()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mInterface);
|
||||
|
||||
mInterface->OnConnectSuccess(mChannel);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothDaemonChannel::OnConnectError()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mInterface);
|
||||
|
||||
mInterface->OnConnectError(mChannel);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothDaemonChannel::OnDisconnect()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mInterface);
|
||||
|
||||
mInterface->OnDisconnect(mChannel);
|
||||
}
|
||||
|
||||
//
|
||||
// Interface
|
||||
//
|
||||
|
@ -1863,149 +1751,6 @@ private:
|
|||
bool mRegisteredSocketModule;
|
||||
};
|
||||
|
||||
void
|
||||
BluetoothDaemonInterface::OnConnectSuccess(enum Channel aChannel)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mResultHandlerQ.IsEmpty());
|
||||
|
||||
switch (aChannel) {
|
||||
case LISTEN_SOCKET: {
|
||||
// Init, step 2: Start Bluetooth daemon */
|
||||
nsCString value("bluetoothd:-a ");
|
||||
value.Append(mListenSocketName);
|
||||
if (NS_WARN_IF(property_set("ctl.start", value.get()) < 0)) {
|
||||
OnConnectError(CMD_CHANNEL);
|
||||
}
|
||||
|
||||
/*
|
||||
* If Bluetooth daemon is not running, retry to start it later.
|
||||
*
|
||||
* This condition happens when when we restart Bluetooth daemon
|
||||
* immediately after it crashed, as the daemon state remains 'stopping'
|
||||
* instead of 'stopped'. Due to the limitation of property service,
|
||||
* hereby add delay. See Bug 1143925 Comment 41.
|
||||
*/
|
||||
if (!IsDaemonRunning()) {
|
||||
MessageLoop::current()->PostDelayedTask(FROM_HERE,
|
||||
new StartDaemonTask(this, value), sRetryInterval);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CMD_CHANNEL:
|
||||
// Init, step 3: Listen for notification channel...
|
||||
if (!mNtfChannel) {
|
||||
mNtfChannel = new BluetoothDaemonChannel(this, NTF_CHANNEL, mProtocol);
|
||||
} else if (
|
||||
NS_WARN_IF(mNtfChannel->GetConnectionStatus() == SOCKET_CONNECTED)) {
|
||||
/* Notification channel should not be open; let's close it. */
|
||||
mNtfChannel->Close();
|
||||
}
|
||||
if (NS_FAILED(mListenSocket->Listen(mNtfChannel))) {
|
||||
OnConnectError(NTF_CHANNEL);
|
||||
}
|
||||
break;
|
||||
case NTF_CHANNEL: {
|
||||
nsRefPtr<BluetoothResultHandler> res = mResultHandlerQ.ElementAt(0);
|
||||
mResultHandlerQ.RemoveElementAt(0);
|
||||
|
||||
// Init, step 4: Register Core module
|
||||
nsresult rv = mProtocol->RegisterModuleCmd(
|
||||
0x01, 0x00, BluetoothDaemonCoreModule::MAX_NUM_CLIENTS,
|
||||
new InitResultHandler(this, res));
|
||||
if (NS_FAILED(rv) && res) {
|
||||
DispatchError(res, STATUS_FAIL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothDaemonInterface::OnConnectError(enum Channel aChannel)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mResultHandlerQ.IsEmpty());
|
||||
|
||||
switch (aChannel) {
|
||||
case NTF_CHANNEL:
|
||||
// Close command channel
|
||||
mCmdChannel->Close();
|
||||
case CMD_CHANNEL:
|
||||
// Stop daemon and close listen socket
|
||||
unused << NS_WARN_IF(property_set("ctl.stop", "bluetoothd"));
|
||||
mListenSocket->Close();
|
||||
case LISTEN_SOCKET:
|
||||
if (!mResultHandlerQ.IsEmpty()) {
|
||||
// Signal error to caller
|
||||
nsRefPtr<BluetoothResultHandler> res = mResultHandlerQ.ElementAt(0);
|
||||
mResultHandlerQ.RemoveElementAt(0);
|
||||
|
||||
if (res) {
|
||||
DispatchError(res, STATUS_FAIL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Three cases for restarting:
|
||||
* a) during startup
|
||||
* b) during regular service
|
||||
* c) during shutdown
|
||||
* For (a)/(c) cases, mResultHandlerQ contains an element, but case (b)
|
||||
* mResultHandlerQ shall be empty. The following procedure to recover from crashed
|
||||
* consists of several steps for case (b).
|
||||
* 1) Close listen socket.
|
||||
* 2) Wait for all sockets disconnected and inform BluetoothServiceBluedroid to
|
||||
* perform the regular stop bluetooth procedure.
|
||||
* 3) When stop bluetooth procedures complete, fire
|
||||
* AdapterStateChangedNotification to cleanup all necessary data members and
|
||||
* deinit ProfileManagers.
|
||||
* 4) After all resources cleanup, call |StartBluetooth|
|
||||
*/
|
||||
void
|
||||
BluetoothDaemonInterface::OnDisconnect(enum Channel aChannel)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
switch (aChannel) {
|
||||
case CMD_CHANNEL:
|
||||
// We don't have to do anything here. Step 4 is triggered
|
||||
// by the daemon.
|
||||
break;
|
||||
case NTF_CHANNEL:
|
||||
// Cleanup, step 4 (Recovery, step 1): Close listen socket
|
||||
mListenSocket->Close();
|
||||
break;
|
||||
case LISTEN_SOCKET:
|
||||
if (!mResultHandlerQ.IsEmpty()) {
|
||||
nsRefPtr<BluetoothResultHandler> res = mResultHandlerQ.ElementAt(0);
|
||||
mResultHandlerQ.RemoveElementAt(0);
|
||||
// Cleanup, step 5: Signal success to caller
|
||||
if (res) {
|
||||
res->Cleanup();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* For recovery make sure all sockets disconnected, in order to avoid
|
||||
* the remaining disconnects interfere with the restart procedure.
|
||||
*/
|
||||
if (sNotificationHandler && mResultHandlerQ.IsEmpty()) {
|
||||
if (mListenSocket->GetConnectionStatus() == SOCKET_DISCONNECTED &&
|
||||
mCmdChannel->GetConnectionStatus() == SOCKET_DISCONNECTED &&
|
||||
mNtfChannel->GetConnectionStatus() == SOCKET_DISCONNECTED) {
|
||||
// Assume daemon crashed during regular service; notify
|
||||
// BluetoothServiceBluedroid to prepare restart-daemon procedure
|
||||
sNotificationHandler->BackendErrorNotification(true);
|
||||
sNotificationHandler = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
BluetoothDaemonInterface::CreateRandomAddressString(
|
||||
const nsACString& aPrefix, unsigned long aPostfixLength,
|
||||
|
@ -2098,13 +1843,13 @@ BluetoothDaemonInterface::Init(
|
|||
}
|
||||
|
||||
if (!mListenSocket) {
|
||||
mListenSocket = new BluetoothDaemonListenSocket(this);
|
||||
mListenSocket = new ListenSocket(this, LISTEN_SOCKET);
|
||||
}
|
||||
|
||||
// Init, step 1: Listen for command channel... */
|
||||
|
||||
if (!mCmdChannel) {
|
||||
mCmdChannel = new BluetoothDaemonChannel(this, CMD_CHANNEL, mProtocol);
|
||||
mCmdChannel = new BluetoothDaemonConnection(mProtocol, this, CMD_CHANNEL);
|
||||
} else if (
|
||||
NS_WARN_IF(mCmdChannel->GetConnectionStatus() == SOCKET_CONNECTED)) {
|
||||
// Command channel should not be open; let's close it.
|
||||
|
@ -2556,4 +2301,149 @@ BluetoothDaemonInterface::GetBluetoothGattInterface()
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// |BluetoothDaemonConnectionConsumer|, |ListenSocketConsumer|
|
||||
|
||||
void
|
||||
BluetoothDaemonInterface::OnConnectSuccess(int aIndex)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mResultHandlerQ.IsEmpty());
|
||||
|
||||
switch (aIndex) {
|
||||
case LISTEN_SOCKET: {
|
||||
// Init, step 2: Start Bluetooth daemon */
|
||||
nsCString value("bluetoothd:-a ");
|
||||
value.Append(mListenSocketName);
|
||||
if (NS_WARN_IF(property_set("ctl.start", value.get()) < 0)) {
|
||||
OnConnectError(CMD_CHANNEL);
|
||||
}
|
||||
|
||||
/*
|
||||
* If Bluetooth daemon is not running, retry to start it later.
|
||||
*
|
||||
* This condition happens when when we restart Bluetooth daemon
|
||||
* immediately after it crashed, as the daemon state remains 'stopping'
|
||||
* instead of 'stopped'. Due to the limitation of property service,
|
||||
* hereby add delay. See Bug 1143925 Comment 41.
|
||||
*/
|
||||
if (!IsDaemonRunning()) {
|
||||
MessageLoop::current()->PostDelayedTask(FROM_HERE,
|
||||
new StartDaemonTask(this, value), sRetryInterval);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CMD_CHANNEL:
|
||||
// Init, step 3: Listen for notification channel...
|
||||
if (!mNtfChannel) {
|
||||
mNtfChannel = new BluetoothDaemonConnection(mProtocol, this, NTF_CHANNEL);
|
||||
} else if (
|
||||
NS_WARN_IF(mNtfChannel->GetConnectionStatus() == SOCKET_CONNECTED)) {
|
||||
/* Notification channel should not be open; let's close it. */
|
||||
mNtfChannel->Close();
|
||||
}
|
||||
if (NS_FAILED(mListenSocket->Listen(mNtfChannel))) {
|
||||
OnConnectError(NTF_CHANNEL);
|
||||
}
|
||||
break;
|
||||
case NTF_CHANNEL: {
|
||||
nsRefPtr<BluetoothResultHandler> res = mResultHandlerQ.ElementAt(0);
|
||||
mResultHandlerQ.RemoveElementAt(0);
|
||||
|
||||
// Init, step 4: Register Core module
|
||||
nsresult rv = mProtocol->RegisterModuleCmd(
|
||||
0x01, 0x00, BluetoothDaemonCoreModule::MAX_NUM_CLIENTS,
|
||||
new InitResultHandler(this, res));
|
||||
if (NS_FAILED(rv) && res) {
|
||||
DispatchError(res, STATUS_FAIL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothDaemonInterface::OnConnectError(int aIndex)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mResultHandlerQ.IsEmpty());
|
||||
|
||||
switch (aIndex) {
|
||||
case NTF_CHANNEL:
|
||||
// Close command channel
|
||||
mCmdChannel->Close();
|
||||
case CMD_CHANNEL:
|
||||
// Stop daemon and close listen socket
|
||||
unused << NS_WARN_IF(property_set("ctl.stop", "bluetoothd"));
|
||||
mListenSocket->Close();
|
||||
case LISTEN_SOCKET:
|
||||
if (!mResultHandlerQ.IsEmpty()) {
|
||||
// Signal error to caller
|
||||
nsRefPtr<BluetoothResultHandler> res = mResultHandlerQ.ElementAt(0);
|
||||
mResultHandlerQ.RemoveElementAt(0);
|
||||
|
||||
if (res) {
|
||||
DispatchError(res, STATUS_FAIL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Three cases for restarting:
|
||||
* a) during startup
|
||||
* b) during regular service
|
||||
* c) during shutdown
|
||||
* For (a)/(c) cases, mResultHandlerQ contains an element, but case (b)
|
||||
* mResultHandlerQ shall be empty. The following procedure to recover from crashed
|
||||
* consists of several steps for case (b).
|
||||
* 1) Close listen socket.
|
||||
* 2) Wait for all sockets disconnected and inform BluetoothServiceBluedroid to
|
||||
* perform the regular stop bluetooth procedure.
|
||||
* 3) When stop bluetooth procedures complete, fire
|
||||
* AdapterStateChangedNotification to cleanup all necessary data members and
|
||||
* deinit ProfileManagers.
|
||||
* 4) After all resources cleanup, call |StartBluetooth|
|
||||
*/
|
||||
void
|
||||
BluetoothDaemonInterface::OnDisconnect(int aIndex)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
switch (aIndex) {
|
||||
case CMD_CHANNEL:
|
||||
// We don't have to do anything here. Step 4 is triggered
|
||||
// by the daemon.
|
||||
break;
|
||||
case NTF_CHANNEL:
|
||||
// Cleanup, step 4 (Recovery, step 1): Close listen socket
|
||||
mListenSocket->Close();
|
||||
break;
|
||||
case LISTEN_SOCKET:
|
||||
if (!mResultHandlerQ.IsEmpty()) {
|
||||
nsRefPtr<BluetoothResultHandler> res = mResultHandlerQ.ElementAt(0);
|
||||
mResultHandlerQ.RemoveElementAt(0);
|
||||
// Cleanup, step 5: Signal success to caller
|
||||
if (res) {
|
||||
res->Cleanup();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* For recovery make sure all sockets disconnected, in order to avoid
|
||||
* the remaining disconnects interfere with the restart procedure.
|
||||
*/
|
||||
if (sNotificationHandler && mResultHandlerQ.IsEmpty()) {
|
||||
if (mListenSocket->GetConnectionStatus() == SOCKET_DISCONNECTED &&
|
||||
mCmdChannel->GetConnectionStatus() == SOCKET_DISCONNECTED &&
|
||||
mNtfChannel->GetConnectionStatus() == SOCKET_DISCONNECTED) {
|
||||
// Assume daemon crashed during regular service; notify
|
||||
// BluetoothServiceBluedroid to prepare restart-daemon procedure
|
||||
sNotificationHandler->BackendErrorNotification(true);
|
||||
sNotificationHandler = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
END_BLUETOOTH_NAMESPACE
|
||||
|
|
|
@ -8,26 +8,36 @@
|
|||
#define mozilla_dom_bluetooth_bluedroid_bluetoothdaemoninterface_h__
|
||||
|
||||
#include "BluetoothInterface.h"
|
||||
#include "mozilla/ipc/BluetoothDaemonConnectionConsumer.h"
|
||||
#include "mozilla/ipc/ListenSocketConsumer.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
class BluetoothDaemonConnection;
|
||||
class ListenSocket;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
BEGIN_BLUETOOTH_NAMESPACE
|
||||
|
||||
class BluetoothDaemonListenSocket;
|
||||
class BluetoothDaemonChannel;
|
||||
class BluetoothDaemonA2dpInterface;
|
||||
class BluetoothDaemonAvrcpInterface;
|
||||
class BluetoothDaemonHandsfreeInterface;
|
||||
class BluetoothDaemonProtocol;
|
||||
class BluetoothDaemonSocketInterface;
|
||||
|
||||
class BluetoothDaemonInterface final : public BluetoothInterface
|
||||
class BluetoothDaemonInterface final
|
||||
: public BluetoothInterface
|
||||
, public mozilla::ipc::BluetoothDaemonConnectionConsumer
|
||||
, public mozilla::ipc::ListenSocketConsumer
|
||||
{
|
||||
public:
|
||||
class CleanupResultHandler;
|
||||
class InitResultHandler;
|
||||
class StartDaemonTask;
|
||||
|
||||
friend class BluetoothDaemonListenSocket;
|
||||
friend class BluetoothDaemonChannel;
|
||||
friend class CleanupResultHandler;
|
||||
friend class InitResultHandler;
|
||||
friend class StartDaemonTask;
|
||||
|
@ -128,22 +138,25 @@ protected:
|
|||
BluetoothDaemonInterface();
|
||||
~BluetoothDaemonInterface();
|
||||
|
||||
void OnConnectSuccess(enum Channel aChannel);
|
||||
void OnConnectError(enum Channel aChannel);
|
||||
void OnDisconnect(enum Channel aChannel);
|
||||
|
||||
nsresult CreateRandomAddressString(const nsACString& aPrefix,
|
||||
unsigned long aPostfixLength,
|
||||
nsACString& aAddress);
|
||||
|
||||
// Methods for |BluetoothDaemonConnectionConsumer| and |ListenSocketConsumer|
|
||||
//
|
||||
|
||||
void OnConnectSuccess(int aIndex) override;
|
||||
void OnConnectError(int aIndex) override;
|
||||
void OnDisconnect(int aIndex) override;
|
||||
|
||||
private:
|
||||
void DispatchError(BluetoothResultHandler* aRes, BluetoothStatus aStatus);
|
||||
void DispatchError(BluetoothResultHandler* aRes, nsresult aRv);
|
||||
|
||||
nsCString mListenSocketName;
|
||||
nsRefPtr<BluetoothDaemonListenSocket> mListenSocket;
|
||||
nsRefPtr<BluetoothDaemonChannel> mCmdChannel;
|
||||
nsRefPtr<BluetoothDaemonChannel> mNtfChannel;
|
||||
nsRefPtr<mozilla::ipc::ListenSocket> mListenSocket;
|
||||
nsRefPtr<mozilla::ipc::BluetoothDaemonConnection> mCmdChannel;
|
||||
nsRefPtr<mozilla::ipc::BluetoothDaemonConnection> mNtfChannel;
|
||||
nsAutoPtr<BluetoothDaemonProtocol> mProtocol;
|
||||
|
||||
nsTArray<nsRefPtr<BluetoothResultHandler> > mResultHandlerQ;
|
||||
|
|
|
@ -95,6 +95,10 @@ MobileMessageCallback::~MobileMessageCallback()
|
|||
nsresult
|
||||
MobileMessageCallback::NotifySuccess(JS::Handle<JS::Value> aResult, bool aAsync)
|
||||
{
|
||||
if (NS_WARN_IF(!mDOMRequest->GetOwner())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (aAsync) {
|
||||
nsCOMPtr<nsIDOMRequestService> rs =
|
||||
do_GetService(DOMREQUEST_SERVICE_CONTRACTID);
|
||||
|
@ -126,6 +130,10 @@ MobileMessageCallback::NotifySuccess(nsISupports *aMessage, bool aAsync)
|
|||
nsresult
|
||||
MobileMessageCallback::NotifyError(int32_t aError, DOMError *aDetailedError, bool aAsync)
|
||||
{
|
||||
if (NS_WARN_IF(!mDOMRequest->GetOwner())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (aAsync) {
|
||||
NS_ASSERTION(!aDetailedError,
|
||||
"No Support to FireDetailedErrorAsync() in nsIDOMRequestService!");
|
||||
|
@ -156,18 +164,23 @@ MobileMessageCallback::NotifyMessageSent(nsISupports *aMessage)
|
|||
NS_IMETHODIMP
|
||||
MobileMessageCallback::NotifySendMessageFailed(int32_t aError, nsISupports *aMessage)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> window = mDOMRequest->GetOwner();
|
||||
if (NS_WARN_IF(!window)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsRefPtr<DOMMobileMessageError> domMobileMessageError;
|
||||
if (aMessage) {
|
||||
nsAutoString errorStr = ConvertErrorCodeToErrorString(aError);
|
||||
nsCOMPtr<nsIDOMMozSmsMessage> smsMsg = do_QueryInterface(aMessage);
|
||||
if (smsMsg) {
|
||||
domMobileMessageError =
|
||||
new DOMMobileMessageError(mDOMRequest->GetOwner(), errorStr, smsMsg);
|
||||
new DOMMobileMessageError(window, errorStr, smsMsg);
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIDOMMozMmsMessage> mmsMsg = do_QueryInterface(aMessage);
|
||||
domMobileMessageError =
|
||||
new DOMMobileMessageError(mDOMRequest->GetOwner(), errorStr, mmsMsg);
|
||||
new DOMMobileMessageError(window, errorStr, mmsMsg);
|
||||
}
|
||||
NS_ASSERTION(domMobileMessageError, "Invalid DOMMobileMessageError!");
|
||||
}
|
||||
|
|
|
@ -128,7 +128,13 @@ MobileMessageManager::GetSegmentInfoForText(const nsAString& aText,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
|
||||
nsCOMPtr<nsPIDOMWindow> window = GetOwner();
|
||||
if (!window) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<DOMRequest> request = new DOMRequest(window);
|
||||
nsCOMPtr<nsIMobileMessageCallback> msgCallback =
|
||||
new MobileMessageCallback(request);
|
||||
nsresult rv = smsService->GetSegmentInfoForText(aText, msgCallback);
|
||||
|
@ -147,7 +153,13 @@ MobileMessageManager::Send(nsISmsService* aSmsService,
|
|||
const nsAString& aText,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
|
||||
nsCOMPtr<nsPIDOMWindow> window = GetOwner();
|
||||
if (!window) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<DOMRequest> request = new DOMRequest(window);
|
||||
nsCOMPtr<nsIMobileMessageCallback> msgCallback =
|
||||
new MobileMessageCallback(request);
|
||||
|
||||
|
@ -248,8 +260,14 @@ MobileMessageManager::SendMMS(const MmsParameters& aParams,
|
|||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> window = GetOwner();
|
||||
if (!window) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(GetOwner()))) {
|
||||
if (NS_WARN_IF(!jsapi.Init(window))) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -261,7 +279,7 @@ MobileMessageManager::SendMMS(const MmsParameters& aParams,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
|
||||
nsRefPtr<DOMRequest> request = new DOMRequest(window);
|
||||
nsCOMPtr<nsIMobileMessageCallback> msgCallback = new MobileMessageCallback(request);
|
||||
rv = mmsService->Send(serviceId, val, msgCallback);
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -283,7 +301,13 @@ MobileMessageManager::GetMessage(int32_t aId,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
|
||||
nsCOMPtr<nsPIDOMWindow> window = GetOwner();
|
||||
if (!window) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<DOMRequest> request = new DOMRequest(window);
|
||||
nsCOMPtr<nsIMobileMessageCallback> msgCallback = new MobileMessageCallback(request);
|
||||
nsresult rv = dbService->GetMessageMoz(aId, msgCallback);
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -306,7 +330,13 @@ MobileMessageManager::Delete(int32_t* aIdArray,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
|
||||
nsCOMPtr<nsPIDOMWindow> window = GetOwner();
|
||||
if (!window) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<DOMRequest> request = new DOMRequest(window);
|
||||
nsCOMPtr<nsIMobileMessageCallback> msgCallback =
|
||||
new MobileMessageCallback(request);
|
||||
|
||||
|
@ -454,8 +484,14 @@ MobileMessageManager::GetMessages(const MobileMessageFilter& aFilter,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> window = GetOwner();
|
||||
if (!window) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
cursorCallback->mDOMCursor =
|
||||
new MobileMessageCursor(GetOwner(), continueCallback);
|
||||
new MobileMessageCursor(window, continueCallback);
|
||||
|
||||
nsRefPtr<DOMCursor> cursor(cursorCallback->mDOMCursor);
|
||||
return cursor.forget();
|
||||
|
@ -474,7 +510,13 @@ MobileMessageManager::MarkMessageRead(int32_t aId,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
|
||||
nsCOMPtr<nsPIDOMWindow> window = GetOwner();
|
||||
if (!window) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<DOMRequest> request = new DOMRequest(window);
|
||||
nsCOMPtr<nsIMobileMessageCallback> msgCallback = new MobileMessageCallback(request);
|
||||
nsresult rv = dbService->MarkMessageRead(aId, aValue, aSendReadReport,
|
||||
msgCallback);
|
||||
|
@ -507,8 +549,14 @@ MobileMessageManager::GetThreads(ErrorResult& aRv)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> window = GetOwner();
|
||||
if (!window) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
cursorCallback->mDOMCursor =
|
||||
new MobileMessageCursor(GetOwner(), continueCallback);
|
||||
new MobileMessageCursor(window, continueCallback);
|
||||
|
||||
nsRefPtr<DOMCursor> cursor(cursorCallback->mDOMCursor);
|
||||
return cursor.forget();
|
||||
|
@ -524,7 +572,13 @@ MobileMessageManager::RetrieveMMS(int32_t aId,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
|
||||
nsCOMPtr<nsPIDOMWindow> window = GetOwner();
|
||||
if (!window) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<DOMRequest> request = new DOMRequest(window);
|
||||
nsCOMPtr<nsIMobileMessageCallback> msgCallback = new MobileMessageCallback(request);
|
||||
|
||||
nsresult rv = mmsService->Retrieve(aId, msgCallback);
|
||||
|
@ -692,7 +746,13 @@ MobileMessageManager::GetSmscAddress(const Optional<uint32_t>& aServiceId,
|
|||
}
|
||||
}
|
||||
|
||||
nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
|
||||
nsCOMPtr<nsPIDOMWindow> window = GetOwner();
|
||||
if (!window) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<DOMRequest> request = new DOMRequest(window);
|
||||
nsCOMPtr<nsIMobileMessageCallback> msgCallback = new MobileMessageCallback(request);
|
||||
rv = smsService->GetSmscAddress(serviceId, msgCallback);
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -727,7 +787,13 @@ MobileMessageManager::SetSmscAddress(const SmscAddress& aSmscAddress,
|
|||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
|
||||
nsCOMPtr<nsPIDOMWindow> window = GetOwner();
|
||||
if (!window) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(window);
|
||||
if (!global) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
|
|
|
@ -32,6 +32,7 @@ const kSmsSentObserverTopic = "sms-sent";
|
|||
const kSmsFailedObserverTopic = "sms-failed";
|
||||
const kSmsDeliverySuccessObserverTopic = "sms-delivery-success";
|
||||
const kSmsDeliveryErrorObserverTopic = "sms-delivery-error";
|
||||
const kSmsDeletedObserverTopic = "sms-deleted";
|
||||
|
||||
const DOM_MOBILE_MESSAGE_DELIVERY_RECEIVED = "received";
|
||||
const DOM_MOBILE_MESSAGE_DELIVERY_SENDING = "sending";
|
||||
|
@ -75,6 +76,21 @@ XPCOMUtils.defineLazyGetter(this, "gWAP", function() {
|
|||
return ns;
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gSmsSendingSchedulars", function() {
|
||||
return {
|
||||
_schedulars: [],
|
||||
getSchedularByServiceId: function(aServiceId) {
|
||||
let schedular = this._schedulars[aServiceId];
|
||||
if (!schedular) {
|
||||
schedular = this._schedulars[aServiceId] =
|
||||
new SmsSendingSchedular(aServiceId);
|
||||
}
|
||||
|
||||
return schedular;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gCellBroadcastService",
|
||||
"@mozilla.org/cellbroadcast/cellbroadcastservice;1",
|
||||
"nsIGonkCellBroadcastService");
|
||||
|
@ -273,11 +289,82 @@ SmsService.prototype = {
|
|||
return index;
|
||||
},
|
||||
|
||||
_notifySendingError: function(aErrorCode, aSendingMessage, aSilent, aRequest) {
|
||||
if (aSilent || aErrorCode === Ci.nsIMobileMessageCallback.NOT_FOUND_ERROR) {
|
||||
// There is no way to modify nsIDOMMozSmsMessage attributes as they
|
||||
// are read only so we just create a new sms instance to send along
|
||||
// with the notification.
|
||||
aRequest.notifySendMessageFailed(aErrorCode,
|
||||
gMobileMessageService.createSmsMessage(aSendingMessage.id,
|
||||
aSendingMessage.threadId,
|
||||
aSendingMessage.iccId,
|
||||
DOM_MOBILE_MESSAGE_DELIVERY_ERROR,
|
||||
RIL.GECKO_SMS_DELIVERY_STATUS_ERROR,
|
||||
aSendingMessage.sender,
|
||||
aSendingMessage.receiver,
|
||||
aSendingMessage.body,
|
||||
aSendingMessage.messageClass,
|
||||
aSendingMessage.timestamp,
|
||||
0,
|
||||
0,
|
||||
aSendingMessage.read));
|
||||
|
||||
if (!aSilent) {
|
||||
Services.obs.notifyObservers(aSendingMessage, kSmsFailedObserverTopic, null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
gMobileMessageDatabaseService
|
||||
.setMessageDeliveryByMessageId(aSendingMessage.id,
|
||||
null,
|
||||
DOM_MOBILE_MESSAGE_DELIVERY_ERROR,
|
||||
RIL.GECKO_SMS_DELIVERY_STATUS_ERROR,
|
||||
null,
|
||||
(aRv, aDomMessage) => {
|
||||
// TODO bug 832140 handle !Components.isSuccessCode(aRv)
|
||||
this._broadcastSmsSystemMessage(
|
||||
Ci.nsISmsMessenger.NOTIFICATION_TYPE_SENT_FAILED, aDomMessage);
|
||||
aRequest.notifySendMessageFailed(aErrorCode, aDomMessage);
|
||||
Services.obs.notifyObservers(aDomMessage, kSmsFailedObserverTopic, null);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Schedule the sending request.
|
||||
*/
|
||||
_scheduleSending: function(aServiceId, aDomMessage, aSilent, aOptions, aRequest) {
|
||||
gSmsSendingSchedulars.getSchedularByServiceId(aServiceId)
|
||||
.schedule({
|
||||
messageId: aDomMessage.id,
|
||||
onSend: () => {
|
||||
if (DEBUG) debug("onSend: " + aDomMessage.id);
|
||||
this._sendToTheAir(aServiceId,
|
||||
aDomMessage,
|
||||
aSilent,
|
||||
aOptions,
|
||||
aRequest);
|
||||
},
|
||||
onCancel: (aErrorCode) => {
|
||||
if (DEBUG) debug("onCancel: " + aErrorCode);
|
||||
this._notifySendingError(aErrorCode, aDomMessage, aSilent, aRequest);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Send a SMS message to the modem.
|
||||
*/
|
||||
_sendToTheAir: function(aServiceId, aDomMessage, aSilent, aOptions, aRequest) {
|
||||
// Keep current SMS message info for sent/delivered notifications
|
||||
let sentMessage = aDomMessage;
|
||||
let requestStatusReport = aOptions.requestStatusReport;
|
||||
|
||||
// Retry count for GECKO_ERROR_SMS_SEND_FAIL_RETRY
|
||||
if (!aOptions.retryCount) {
|
||||
aOptions.retryCount = 0;
|
||||
}
|
||||
|
||||
gRadioInterfaces[aServiceId].sendWorkerMessage("sendSMS",
|
||||
aOptions,
|
||||
(aResponse) => {
|
||||
|
@ -288,43 +375,18 @@ SmsService.prototype = {
|
|||
error = Ci.nsIMobileMessageCallback.NO_SIGNAL_ERROR;
|
||||
} else if (aResponse.errorMsg === RIL.GECKO_ERROR_FDN_CHECK_FAILURE) {
|
||||
error = Ci.nsIMobileMessageCallback.FDN_CHECK_ERROR;
|
||||
} else if (aResponse.errorMsg === RIL.GECKO_ERROR_SMS_SEND_FAIL_RETRY &&
|
||||
aOptions.retryCount < RIL.SMS_RETRY_MAX) {
|
||||
aOptions.retryCount++;
|
||||
this._scheduleSending(aServiceId,
|
||||
aDomMessage,
|
||||
aSilent,
|
||||
aOptions,
|
||||
aRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
if (aSilent) {
|
||||
// There is no way to modify nsIDOMMozSmsMessage attributes as they
|
||||
// are read only so we just create a new sms instance to send along
|
||||
// with the notification.
|
||||
aRequest.notifySendMessageFailed(
|
||||
error,
|
||||
gMobileMessageService.createSmsMessage(sentMessage.id,
|
||||
sentMessage.threadId,
|
||||
sentMessage.iccId,
|
||||
DOM_MOBILE_MESSAGE_DELIVERY_ERROR,
|
||||
RIL.GECKO_SMS_DELIVERY_STATUS_ERROR,
|
||||
sentMessage.sender,
|
||||
sentMessage.receiver,
|
||||
sentMessage.body,
|
||||
sentMessage.messageClass,
|
||||
sentMessage.timestamp,
|
||||
0,
|
||||
0,
|
||||
sentMessage.read));
|
||||
return false;
|
||||
}
|
||||
|
||||
gMobileMessageDatabaseService
|
||||
.setMessageDeliveryByMessageId(aDomMessage.id,
|
||||
null,
|
||||
DOM_MOBILE_MESSAGE_DELIVERY_ERROR,
|
||||
RIL.GECKO_SMS_DELIVERY_STATUS_ERROR,
|
||||
null,
|
||||
(aRv, aDomMessage) => {
|
||||
// TODO bug 832140 handle !Components.isSuccessCode(aRv)
|
||||
this._broadcastSmsSystemMessage(
|
||||
Ci.nsISmsMessenger.NOTIFICATION_TYPE_SENT_FAILED, aDomMessage);
|
||||
aRequest.notifySendMessageFailed(error, aDomMessage);
|
||||
Services.obs.notifyObservers(aDomMessage, kSmsFailedObserverTopic, null);
|
||||
});
|
||||
this._notifySendingError(error, sentMessage, aSilent, aRequest);
|
||||
return false;
|
||||
} // End of send failure.
|
||||
|
||||
|
@ -906,28 +968,12 @@ SmsService.prototype = {
|
|||
errorCode = Ci.nsIMobileMessageCallback.NO_SIM_CARD_ERROR;
|
||||
}
|
||||
if (errorCode) {
|
||||
if (aSilent) {
|
||||
aRequest.notifySendMessageFailed(errorCode, aSendingMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
gMobileMessageDatabaseService
|
||||
.setMessageDeliveryByMessageId(aSendingMessage.id,
|
||||
null,
|
||||
DOM_MOBILE_MESSAGE_DELIVERY_ERROR,
|
||||
RIL.GECKO_SMS_DELIVERY_STATUS_ERROR,
|
||||
null,
|
||||
(aRv, aDomMessage) => {
|
||||
// TODO bug 832140 handle !Components.isSuccessCode(aRv)
|
||||
this._broadcastSmsSystemMessage(
|
||||
Ci.nsISmsMessenger.NOTIFICATION_TYPE_SENT_FAILED, aDomMessage);
|
||||
aRequest.notifySendMessageFailed(errorCode, aDomMessage);
|
||||
Services.obs.notifyObservers(aDomMessage, kSmsFailedObserverTopic, null);
|
||||
});
|
||||
this._notifySendingError(errorCode, aSendingMessage, aSilent, aRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
this._sendToTheAir(aServiceId, aSendingMessage, aSilent, options, aRequest);
|
||||
this._scheduleSending(aServiceId, aSendingMessage, aSilent, options,
|
||||
aRequest);
|
||||
}; // End of |saveSendingMessageCallback|.
|
||||
|
||||
// Don't save message into DB for silent SMS.
|
||||
|
@ -1147,4 +1193,171 @@ function getEnabledGsmTableTuplesFromMcc() {
|
|||
return tuples;
|
||||
};
|
||||
|
||||
function SmsSendingSchedular(aServiceId) {
|
||||
this._serviceId = aServiceId;
|
||||
this._queue = [];
|
||||
|
||||
Services.obs.addObserver(this, kSmsDeletedObserverTopic, false);
|
||||
Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
|
||||
}
|
||||
SmsSendingSchedular.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileConnectionListener]),
|
||||
|
||||
_serviceId: 0,
|
||||
_isObservingMoboConn: false,
|
||||
_queue: null,
|
||||
|
||||
/**
|
||||
* Ensure the handler is listening on MobileConnection events.
|
||||
*/
|
||||
_ensureMoboConnObserverRegistration: function() {
|
||||
if (!this._isObservingMoboConn) {
|
||||
let connection =
|
||||
gMobileConnectionService.getItemByServiceId(this._serviceId);
|
||||
if (connection) {
|
||||
connection.registerListener(this);
|
||||
this._isObservingMoboConn = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Ensure the handler is not listening on MobileConnection events.
|
||||
*/
|
||||
_ensureMoboConnObserverUnregistration: function() {
|
||||
if (this._isObservingMoboConn) {
|
||||
let connection =
|
||||
gMobileConnectionService.getItemByServiceId(this._serviceId);
|
||||
if (connection) {
|
||||
connection.unregisterListener(this);
|
||||
this._isObservingMoboConn = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Schedule a sending request.
|
||||
*
|
||||
* @param aSendingRequest
|
||||
* An object with the following properties:
|
||||
* - messageId
|
||||
* The messageId in MobileMessageDB.
|
||||
* - onSend
|
||||
* The callback to invoke to trigger a sending or retry.
|
||||
* - onCancel
|
||||
* The callback to invoke when the request is canceled and won't
|
||||
* retry.
|
||||
*/
|
||||
schedule: function(aSendingRequest) {
|
||||
if (aSendingRequest) {
|
||||
this._ensureMoboConnObserverRegistration();
|
||||
this._queue.push(aSendingRequest)
|
||||
|
||||
// Keep the queue in order to guarantee the sending order matches user
|
||||
// expectation.
|
||||
this._queue.sort(function(a, b) {
|
||||
return a.messageId - b.messageId;
|
||||
});
|
||||
}
|
||||
|
||||
this.send();
|
||||
},
|
||||
|
||||
/**
|
||||
* Send all requests in the queue if voice connection is available.
|
||||
*/
|
||||
send: function() {
|
||||
let connection =
|
||||
gMobileConnectionService.getItemByServiceId(this._servicdeId);
|
||||
|
||||
// If the voice connection is temporarily unavailable, pend the request.
|
||||
let voiceInfo = connection && connection.voice;
|
||||
let voiceConnected = voiceInfo && voiceInfo.connected;
|
||||
if (!voiceConnected) {
|
||||
if (DEBUG) {
|
||||
debug("Voice connection is temporarily unavailable. Skip sending.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let snapshot = this._queue;
|
||||
this._queue = [];
|
||||
let req;
|
||||
while ((req = snapshot.shift())) {
|
||||
req.onSend();
|
||||
}
|
||||
|
||||
// The sending / retry could fail and being re-scheduled immediately.
|
||||
// Only unregister listener when the queue is empty after retries.
|
||||
if (this._queue.length === 0) {
|
||||
this._ensureMoboConnObserverUnregistration();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* nsIObserver interface.
|
||||
*/
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
switch (aTopic) {
|
||||
case kSmsDeletedObserverTopic:
|
||||
if (DEBUG) {
|
||||
debug("Observe " + kSmsDeletedObserverTopic + ": " +
|
||||
JSON.stringify(aSubject));
|
||||
}
|
||||
|
||||
if (aSubject && aSubject.deletedMessageIds) {
|
||||
for (let id of aSubject.deletedMessageIds) {
|
||||
for (let i = 0; i < this._queue.length; i++) {
|
||||
if (this._queue[i].messageId === id) {
|
||||
if (DEBUG) debug("Deleting message with id=" + id);
|
||||
this._queue.splice(i, 1)[0].onCancel(
|
||||
Ci.nsIMobileMessageCallback.NOT_FOUND_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NS_XPCOM_SHUTDOWN_OBSERVER_ID:
|
||||
this._ensureMoboConnObserverUnregistration();
|
||||
Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
|
||||
Services.obs.removeObserver(this, kSmsDeletedObserverTopic);
|
||||
|
||||
// Cancel all pending requests and clear the queue.
|
||||
for (let req of this._queue) {
|
||||
req.onCancel(Ci.nsIMobileMessageCallback.NO_SIGNAL_ERROR);
|
||||
}
|
||||
this._queue = [];
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* nsIMobileConnectionListener implementation.
|
||||
*/
|
||||
notifyVoiceChanged: function() {
|
||||
let connection = gMobileConnectionService.getItemByServiceId(this._serviceId);
|
||||
let voiceInfo = connection && connection.voice;
|
||||
let voiceConnected = voiceInfo && voiceInfo.connected;
|
||||
if (voiceConnected) {
|
||||
if (DEBUG) {
|
||||
debug("Voice connected. Resend pending requests.");
|
||||
}
|
||||
|
||||
this.send();
|
||||
}
|
||||
},
|
||||
|
||||
// Unused nsIMobileConnectionListener methods.
|
||||
notifyDataChanged: function() {},
|
||||
notifyDataError: function(message) {},
|
||||
notifyCFStateChanged: function(action, reason, number, timeSeconds, serviceClass) {},
|
||||
notifyEmergencyCbModeChanged: function(active, timeoutMs) {},
|
||||
notifyOtaStatusChanged: function(status) {},
|
||||
notifyRadioStateChanged: function() {},
|
||||
notifyClirModeChanged: function(mode) {},
|
||||
notifyLastKnownNetworkChanged: function() {},
|
||||
notifyLastKnownHomeNetworkChanged: function() {},
|
||||
notifyNetworkSelectionModeChanged: function() {}
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SmsService]);
|
||||
|
|
|
@ -77,6 +77,49 @@ function ensureMobileMessage() {
|
|||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push required permissions and test if |navigator.mozMobileConnections| exists.
|
||||
* Resolve if it does, reject otherwise.
|
||||
*
|
||||
* Fulfill params:
|
||||
* manager -- an reference to navigator.mozMobileConnections.
|
||||
*
|
||||
* Reject params: (none)
|
||||
*
|
||||
* @param aServiceId [optional]
|
||||
* A numeric DSDS service id. Default: 0.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
let mobileConnection;
|
||||
function ensureMobileConnection(aServiceId) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
let permissions = [{
|
||||
"type": "mobileconnection",
|
||||
"allow": 1,
|
||||
"context": document,
|
||||
}];
|
||||
SpecialPowers.pushPermissions(permissions, function() {
|
||||
ok(true, "permissions pushed: " + JSON.stringify(permissions));
|
||||
|
||||
let serviceId = aServiceId || 0;
|
||||
mobileConnection = window.navigator.mozMobileConnections[serviceId];
|
||||
if (mobileConnection) {
|
||||
log("navigator.mozMobileConnections[" + serviceId + "] is instance of " +
|
||||
mobileConnection.constructor);
|
||||
} else {
|
||||
log("navigator.mozMobileConnections[" + serviceId + "] is undefined");
|
||||
}
|
||||
|
||||
if (mobileConnection instanceof MozMobileConnection) {
|
||||
resolve(mobileConnection);
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for one named MobileMessageManager event.
|
||||
*
|
||||
|
@ -501,6 +544,28 @@ function sendMultipleRawSmsToEmulatorAndWait(aPdus) {
|
|||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set voice state and wait for state change.
|
||||
*
|
||||
* @param aState
|
||||
* "unregistered", "searching", "denied", "roaming", or "home".
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function setEmulatorVoiceStateAndWait(aState) {
|
||||
let promises = [];
|
||||
promises.push(new Promise(function(resolve, reject) {
|
||||
mobileConnection.addEventListener("voicechange", function onevent(aEvent) {
|
||||
log("voicechange: connected=" + mobileConnection.voice.connected);
|
||||
mobileConnection.removeEventListener("voicechange", onevent);
|
||||
resolve(aEvent);
|
||||
})
|
||||
}));
|
||||
|
||||
promises.push(runEmulatorCmdSafe("gsm voice " + aState));
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new array of id attribute of input messages.
|
||||
*
|
||||
|
|
|
@ -53,3 +53,4 @@ qemu = true
|
|||
[test_decode_spanish_fallback.js]
|
||||
[test_update_gsm_nl_on_mcc_chanages.js]
|
||||
[test_set_smsc_address.js]
|
||||
[test_outgoing_unstable_voice_connection.js]
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
MARIONETTE_TIMEOUT = 60000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
const RECEIVER = "15555215555";
|
||||
|
||||
// The Book of Mozilla, 15:1
|
||||
const MESSAGES = [
|
||||
"The twins of Mammon quarrelled.",
|
||||
"Their warring plunged the world into a new darkness, and the beast abhorred the darkness.",
|
||||
"So it began to move swiftly, and grew more powerful, and went forth and multiplied.",
|
||||
"And the beasts brought fire and light to the darkness."
|
||||
];
|
||||
|
||||
/**
|
||||
* Send messages and verify that corresponding "sending" events are received.
|
||||
*
|
||||
* @return an array of message IDs.
|
||||
*/
|
||||
function sendMessagesAndVerifySending() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
try {
|
||||
let eventCount = 0;
|
||||
let now = Date.now();
|
||||
let messageIds = [];
|
||||
manager.addEventListener("sending", function onevent(aEvent) {
|
||||
log("onsending event received.");
|
||||
|
||||
let message = aEvent.message;
|
||||
let expectedBody = MESSAGES[eventCount++];
|
||||
messageIds.push(message.id);
|
||||
is(message.delivery, "sending", "message.delivery");
|
||||
is(message.deliveryStatus, "pending", "message.deliveryStatus");
|
||||
is(message.body, expectedBody, "message.body: expected '" + expectedBody
|
||||
+ "'' but got '" + message.body + "'");
|
||||
|
||||
// timestamp is in seconds.
|
||||
ok(Math.floor(message.timestamp / 1000) >= Math.floor(now / 1000),
|
||||
"expected " + message.timestamp + " >= " + now);
|
||||
|
||||
// resolve when all messages are appeared "sending"
|
||||
if (eventCount == MESSAGES.length) {
|
||||
manager.removeEventListener("sending", onevent);
|
||||
resolve(messageIds);
|
||||
}
|
||||
});
|
||||
|
||||
// send messages
|
||||
for (let body of MESSAGES) {
|
||||
manager.send(RECEIVER, body);
|
||||
}
|
||||
} catch (err) {
|
||||
log("Error: " + err);
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn on voice connection, delete specified messages, and verify all the
|
||||
* corresponding "sent" / "failed" events are received.
|
||||
*
|
||||
* @param aMessageIdsToDelete
|
||||
* An array of message ids to delete.
|
||||
* @param aExpectedSentMessages
|
||||
* Expected successfully sent messages, ordered.
|
||||
* @param aExpectedFailures
|
||||
* Expected number of failures.
|
||||
*/
|
||||
function turnOnVoiceDeleteMessagesAndVerify(aMessageIdsToDelete,
|
||||
aExpectedSentMessages, aExpectedFailures) {
|
||||
let promises = [];
|
||||
|
||||
// Wait for "sent" and "failed" events.
|
||||
promises.push(new Promise(function(resolve, reject) {
|
||||
try {
|
||||
let sentEventCount = 0;
|
||||
let failedEventCount = 0;
|
||||
|
||||
let onSentHandler = function(aEvent) {
|
||||
log("onsent event received.");
|
||||
|
||||
let message = aEvent.message;
|
||||
let expectedBody = aExpectedSentMessages[sentEventCount++];
|
||||
is(message.delivery, "sent", "message.delivery");
|
||||
is(message.receiver, RECEIVER, "message.receiver");
|
||||
is(message.body, expectedBody, "message.body: expected '" + expectedBody
|
||||
+ "'' but got '" + message.body + "'");
|
||||
|
||||
tryResolve();
|
||||
}
|
||||
|
||||
let onFailedHandler = function(aEvent) {
|
||||
log("onfailed event received.");
|
||||
failedEventCount++;
|
||||
tryResolve();
|
||||
}
|
||||
|
||||
let tryResolve = function() {
|
||||
log("sentEventCount=" + sentEventCount + "; failedEventCount=" + failedEventCount);
|
||||
if (sentEventCount === aExpectedSentMessages.length &&
|
||||
failedEventCount === aExpectedFailures) {
|
||||
manager.removeEventListener("sent", onSentHandler);
|
||||
manager.removeEventListener("failed", onFailedHandler);
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
|
||||
manager.addEventListener("sent", onSentHandler);
|
||||
manager.addEventListener("failed", onFailedHandler);
|
||||
} catch (err) {
|
||||
log("Error: " + err);
|
||||
reject(err);
|
||||
}
|
||||
}));
|
||||
|
||||
// Delete messages with given ids.
|
||||
promises.push(deleteMessagesById(aMessageIdsToDelete));
|
||||
|
||||
// wait for 3 seconds and turn on voice connection.
|
||||
promises.push(new Promise(function(resolve, reject) {
|
||||
setTimeout(() => resolve(), 3000);
|
||||
}).then(() => setEmulatorVoiceStateAndWait("on")));
|
||||
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
startTestCommon(function testCaseMain() {
|
||||
return pushPrefEnv({ set: [['dom.sms.requestStatusReport', true]] })
|
||||
.then(() => ensureMobileConnection())
|
||||
.then(() => setEmulatorVoiceStateAndWait("unregistered"))
|
||||
.then(() => sendMessagesAndVerifySending())
|
||||
// Delete the first message and wait for result.
|
||||
.then((aMessageIds) => turnOnVoiceDeleteMessagesAndVerify([aMessageIds[0]],
|
||||
MESSAGES.slice().splice(1, MESSAGES.length - 1), 1));
|
||||
});
|
|
@ -27,6 +27,36 @@ using namespace android;
|
|||
using namespace mozilla::dom;
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
namespace {
|
||||
|
||||
class SendNfcSocketDataTask final : public nsRunnable
|
||||
{
|
||||
public:
|
||||
SendNfcSocketDataTask(StreamSocket* aSocket, UnixSocketRawData* aRawData)
|
||||
: mSocket(aSocket)
|
||||
, mRawData(aRawData)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!mSocket || mSocket->GetConnectionStatus() != SOCKET_CONNECTED) {
|
||||
// Probably shutting down.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mSocket->SendSocketData(mRawData.forget());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<StreamSocket> mSocket;
|
||||
nsAutoPtr<UnixSocketRawData> mRawData;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
static NfcService* gNfcService;
|
||||
|
@ -41,11 +71,15 @@ assertIsNfcServiceThread()
|
|||
}
|
||||
|
||||
// Runnable used to call Marshall on the NFC thread.
|
||||
class NfcCommandRunnable : public nsRunnable
|
||||
class NfcCommandRunnable final : public nsRunnable
|
||||
{
|
||||
public:
|
||||
NfcCommandRunnable(NfcMessageHandler* aHandler, NfcConsumer* aConsumer, CommandOptions aOptions)
|
||||
: mHandler(aHandler), mConsumer(aConsumer), mOptions(aOptions)
|
||||
NfcCommandRunnable(NfcMessageHandler* aHandler,
|
||||
NfcService* aService,
|
||||
CommandOptions aOptions)
|
||||
: mHandler(aHandler)
|
||||
, mService(aService)
|
||||
, mOptions(aOptions)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
@ -60,13 +94,13 @@ public:
|
|||
parcel.setDataPosition(0);
|
||||
uint32_t sizeBE = htonl(parcel.dataSize() - sizeof(int));
|
||||
parcel.writeInt32(sizeBE);
|
||||
mConsumer->PostToNfcDaemon(parcel.data(), parcel.dataSize());
|
||||
mService->PostToNfcDaemon(parcel.data(), parcel.dataSize());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
NfcMessageHandler* mHandler;
|
||||
NfcConsumer* mConsumer;
|
||||
NfcService* mService;
|
||||
CommandOptions mOptions;
|
||||
};
|
||||
|
||||
|
@ -307,15 +341,15 @@ NfcService::Start(nsINfcGonkEventListener* aListener)
|
|||
|
||||
mListener = aListener;
|
||||
mHandler = new NfcMessageHandler();
|
||||
mConsumer = new NfcConsumer(this);
|
||||
mStreamSocket = new StreamSocket(this, STREAM_SOCKET);
|
||||
|
||||
mListenSocketName = BASE_SOCKET_NAME;
|
||||
|
||||
mListenSocket = new NfcListenSocket(this);
|
||||
mListenSocket = new ListenSocket(this, LISTEN_SOCKET);
|
||||
nsresult rv = mListenSocket->Listen(new NfcConnector(mListenSocketName),
|
||||
mConsumer);
|
||||
mStreamSocket);
|
||||
if (NS_FAILED(rv)) {
|
||||
mConsumer = nullptr;
|
||||
mStreamSocket = nullptr;
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -324,8 +358,8 @@ NfcService::Start(nsINfcGonkEventListener* aListener)
|
|||
NS_WARNING("Can't create Nfc worker thread.");
|
||||
mListenSocket->Close();
|
||||
mListenSocket = nullptr;
|
||||
mConsumer->Shutdown();
|
||||
mConsumer = nullptr;
|
||||
mStreamSocket->Close();
|
||||
mStreamSocket = nullptr;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -344,13 +378,24 @@ NfcService::Shutdown()
|
|||
|
||||
mListenSocket->Close();
|
||||
mListenSocket = nullptr;
|
||||
|
||||
mConsumer->Shutdown();
|
||||
mConsumer = nullptr;
|
||||
mStreamSocket->Close();
|
||||
mStreamSocket = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
NfcService::PostToNfcDaemon(const uint8_t* aData, size_t aSize)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
UnixSocketRawData* raw = new UnixSocketRawData(aData, aSize);
|
||||
nsRefPtr<SendNfcSocketDataTask> task =
|
||||
new SendNfcSocketDataTask(mStreamSocket, raw);
|
||||
NS_DispatchToMainThread(task);
|
||||
return true;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
NfcService::SendCommand(JS::HandleValue aOptions, JSContext* aCx)
|
||||
{
|
||||
|
@ -365,7 +410,8 @@ NfcService::SendCommand(JS::HandleValue aOptions, JSContext* aCx)
|
|||
|
||||
// Dispatch the command to the NFC thread.
|
||||
CommandOptions commandOptions(options);
|
||||
nsCOMPtr<nsIRunnable> runnable = new NfcCommandRunnable(mHandler, mConsumer, commandOptions);
|
||||
nsCOMPtr<nsIRunnable> runnable = new NfcCommandRunnable(mHandler, this,
|
||||
commandOptions);
|
||||
mThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -385,8 +431,11 @@ NfcService::DispatchNfcEvent(const mozilla::dom::NfcEventOptions& aOptions)
|
|||
mListener->OnEvent(val);
|
||||
}
|
||||
|
||||
// |StreamSocketConsumer|, |ListenSocketConsumer|
|
||||
|
||||
void
|
||||
NfcService::ReceiveSocketData(nsAutoPtr<UnixSocketBuffer>& aBuffer)
|
||||
NfcService::ReceiveSocketData(
|
||||
int aIndex, nsAutoPtr<mozilla::ipc::UnixSocketBuffer>& aBuffer)
|
||||
{
|
||||
MOZ_ASSERT(mHandler);
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
|
@ -395,11 +444,11 @@ NfcService::ReceiveSocketData(nsAutoPtr<UnixSocketBuffer>& aBuffer)
|
|||
}
|
||||
|
||||
void
|
||||
NfcService::OnConnectSuccess(enum SocketType aSocketType)
|
||||
NfcService::OnConnectSuccess(int aIndex)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
switch (aSocketType) {
|
||||
switch (aIndex) {
|
||||
case LISTEN_SOCKET: {
|
||||
nsCString value("nfcd:-a ");
|
||||
value.Append(mListenSocketName);
|
||||
|
@ -415,7 +464,7 @@ NfcService::OnConnectSuccess(enum SocketType aSocketType)
|
|||
}
|
||||
|
||||
void
|
||||
NfcService::OnConnectError(enum SocketType aSocketType)
|
||||
NfcService::OnConnectError(int aIndex)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
|
@ -423,7 +472,7 @@ NfcService::OnConnectError(enum SocketType aSocketType)
|
|||
}
|
||||
|
||||
void
|
||||
NfcService::OnDisconnect(enum SocketType aSocketType)
|
||||
NfcService::OnDisconnect(int aIndex)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
|
|
@ -7,8 +7,10 @@
|
|||
#ifndef NfcService_h
|
||||
#define NfcService_h
|
||||
|
||||
#include "mozilla/ipc/Nfc.h"
|
||||
#include "mozilla/ipc/SocketBase.h"
|
||||
#include <mozilla/ipc/ListenSocket.h>
|
||||
#include "mozilla/ipc/ListenSocketConsumer.h"
|
||||
#include <mozilla/ipc/StreamSocket.h>
|
||||
#include "mozilla/ipc/StreamSocketConsumer.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsINfcService.h"
|
||||
#include "NfcMessageHandler.h"
|
||||
|
@ -20,8 +22,10 @@ namespace dom {
|
|||
class NfcEventOptions;
|
||||
} // namespace dom
|
||||
|
||||
class NfcService final : public nsINfcService,
|
||||
public mozilla::ipc::NfcSocketListener
|
||||
class NfcService final
|
||||
: public nsINfcService
|
||||
, public mozilla::ipc::StreamSocketConsumer
|
||||
, public mozilla::ipc::ListenSocketConsumer
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
@ -31,25 +35,34 @@ public:
|
|||
|
||||
void DispatchNfcEvent(const mozilla::dom::NfcEventOptions& aOptions);
|
||||
|
||||
virtual void ReceiveSocketData(
|
||||
nsAutoPtr<mozilla::ipc::UnixSocketBuffer>& aBuffer) override;
|
||||
|
||||
virtual void OnConnectSuccess(enum SocketType aSocketType) override;
|
||||
virtual void OnConnectError(enum SocketType aSocketType) override;
|
||||
virtual void OnDisconnect(enum SocketType aSocketType) override;
|
||||
bool PostToNfcDaemon(const uint8_t* aData, size_t aSize);
|
||||
|
||||
nsCOMPtr<nsIThread> GetThread() {
|
||||
return mThread;
|
||||
}
|
||||
|
||||
// Methods for |StreamSocketConsumer| and |ListenSocketConsumer|
|
||||
//
|
||||
|
||||
void ReceiveSocketData(
|
||||
int aIndex, nsAutoPtr<mozilla::ipc::UnixSocketBuffer>& aBuffer) override;
|
||||
void OnConnectSuccess(int aIndex) override;
|
||||
void OnConnectError(int aIndex) override;
|
||||
void OnDisconnect(int aIndex) override;
|
||||
|
||||
private:
|
||||
enum SocketType {
|
||||
LISTEN_SOCKET,
|
||||
STREAM_SOCKET
|
||||
};
|
||||
|
||||
NfcService();
|
||||
~NfcService();
|
||||
|
||||
nsCOMPtr<nsIThread> mThread;
|
||||
nsCOMPtr<nsINfcGonkEventListener> mListener;
|
||||
nsRefPtr<mozilla::ipc::NfcListenSocket> mListenSocket;
|
||||
nsRefPtr<mozilla::ipc::NfcConsumer> mConsumer;
|
||||
nsRefPtr<mozilla::ipc::ListenSocket> mListenSocket;
|
||||
nsRefPtr<mozilla::ipc::StreamSocket> mStreamSocket;
|
||||
nsAutoPtr<NfcMessageHandler> mHandler;
|
||||
nsCString mListenSocketName;
|
||||
};
|
||||
|
|
|
@ -1457,10 +1457,6 @@ RilObject.prototype = {
|
|||
options.langIndex = options.langIndex || PDU_NL_IDENTIFIER_DEFAULT;
|
||||
options.langShiftIndex = options.langShiftIndex || PDU_NL_IDENTIFIER_DEFAULT;
|
||||
|
||||
if (!options.retryCount) {
|
||||
options.retryCount = 0;
|
||||
}
|
||||
|
||||
if (!options.segmentSeq) {
|
||||
// Fist segment to send
|
||||
options.segmentSeq = 1;
|
||||
|
@ -4024,15 +4020,6 @@ RilObject.prototype = {
|
|||
options.errorMsg);
|
||||
}
|
||||
|
||||
if (options.errorMsg === GECKO_ERROR_SMS_SEND_FAIL_RETRY &&
|
||||
options.retryCount < SMS_RETRY_MAX) {
|
||||
options.retryCount++;
|
||||
// TODO: bug 736702 TP-MR, retry interval, retry timeout
|
||||
this.sendSMS(options);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback to default error handling if it meets max retry count.
|
||||
this.sendChromeMessage({
|
||||
rilMessageType: options.rilMessageType,
|
||||
rilMessageToken: options.rilMessageToken,
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
#include "mozilla/ipc/BluetoothDaemonConnectionConsumer.h"
|
||||
#include "mozilla/ipc/DataSocket.h"
|
||||
#include "mozilla/ipc/UnixSocketConnector.h"
|
||||
#include "mozilla/ipc/UnixSocketWatcher.h"
|
||||
|
@ -433,8 +434,12 @@ BluetoothDaemonConnectionIO::ShutdownOnIOThread()
|
|||
//
|
||||
|
||||
BluetoothDaemonConnection::BluetoothDaemonConnection(
|
||||
BluetoothDaemonPDUConsumer* aConsumer)
|
||||
: mConsumer(aConsumer)
|
||||
BluetoothDaemonPDUConsumer* aPDUConsumer,
|
||||
BluetoothDaemonConnectionConsumer* aConsumer,
|
||||
int aIndex)
|
||||
: mPDUConsumer(aPDUConsumer)
|
||||
, mConsumer(aConsumer)
|
||||
, mIndex(aIndex)
|
||||
, mIO(nullptr)
|
||||
{
|
||||
MOZ_ASSERT(mConsumer);
|
||||
|
@ -461,7 +466,7 @@ BluetoothDaemonConnection::PrepareAccept(UnixSocketConnector* aConnector,
|
|||
|
||||
mIO = new BluetoothDaemonConnectionIO(
|
||||
XRE_GetIOMessageLoop(), -1, UnixSocketWatcher::SOCKET_IS_CONNECTING,
|
||||
this, mConsumer);
|
||||
this, mPDUConsumer);
|
||||
aIO = mIO;
|
||||
|
||||
return NS_OK;
|
||||
|
@ -500,5 +505,29 @@ BluetoothDaemonConnection::Close()
|
|||
NotifyDisconnect();
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothDaemonConnection::OnConnectSuccess()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mConsumer->OnConnectSuccess(mIndex);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothDaemonConnection::OnConnectError()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mConsumer->OnConnectError(mIndex);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothDaemonConnection::OnDisconnect()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mConsumer->OnDisconnect(mIndex);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
class BluetoothDaemonConnectionConsumer;
|
||||
class BluetoothDaemonConnectionIO;
|
||||
class BluetoothDaemonPDUConsumer;
|
||||
|
||||
|
@ -113,7 +114,9 @@ protected:
|
|||
class BluetoothDaemonConnection : public ConnectionOrientedSocket
|
||||
{
|
||||
public:
|
||||
BluetoothDaemonConnection(BluetoothDaemonPDUConsumer* aConsumer);
|
||||
BluetoothDaemonConnection(BluetoothDaemonPDUConsumer* aPDUConsumer,
|
||||
BluetoothDaemonConnectionConsumer* aConsumer,
|
||||
int aIndex);
|
||||
virtual ~BluetoothDaemonConnection();
|
||||
|
||||
// Methods for |ConnectionOrientedSocket|
|
||||
|
@ -131,9 +134,14 @@ public:
|
|||
//
|
||||
|
||||
void Close() override;
|
||||
void OnConnectSuccess() override;
|
||||
void OnConnectError() override;
|
||||
void OnDisconnect() override;
|
||||
|
||||
private:
|
||||
BluetoothDaemonPDUConsumer* mConsumer;
|
||||
BluetoothDaemonPDUConsumer* mPDUConsumer;
|
||||
BluetoothDaemonConnectionConsumer* mConsumer;
|
||||
int mIndex;
|
||||
BluetoothDaemonConnectionIO* mIO;
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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 "BluetoothDaemonConnectionConsumer.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
//
|
||||
// BluetoothDaemonConnectionConsumer
|
||||
//
|
||||
|
||||
BluetoothDaemonConnectionConsumer::BluetoothDaemonConnectionConsumer()
|
||||
{ }
|
||||
|
||||
BluetoothDaemonConnectionConsumer::~BluetoothDaemonConnectionConsumer()
|
||||
{ }
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_ipc_BluetoothDaemonConnectionConsumer_h
|
||||
#define mozilla_ipc_BluetoothDaemonConnectionConsumer_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/FileUtils.h"
|
||||
#include "mozilla/ipc/ConnectionOrientedSocket.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
/*
|
||||
* |BluetoothDaemonConnectionConsumer| handles socket events.
|
||||
*/
|
||||
class BluetoothDaemonConnectionConsumer
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Callback for socket success. Main-thread only.
|
||||
*
|
||||
* @param aIndex The index that has been given to the stream socket.
|
||||
*/
|
||||
virtual void OnConnectSuccess(int aIndex) = 0;
|
||||
|
||||
/**
|
||||
* Callback for socket errors. Main-thread only.
|
||||
*
|
||||
* @param aIndex The index that has been given to the stream socket.
|
||||
*/
|
||||
virtual void OnConnectError(int aIndex) = 0;
|
||||
|
||||
/**
|
||||
* Callback for socket disconnect. Main-thread only.
|
||||
*
|
||||
* @param aIndex The index that has been given to the stream socket.
|
||||
*/
|
||||
virtual void OnDisconnect(int aIndex) = 0;
|
||||
|
||||
protected:
|
||||
BluetoothDaemonConnectionConsumer();
|
||||
virtual ~BluetoothDaemonConnectionConsumer();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -5,11 +5,13 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXPORTS.mozilla.ipc += [
|
||||
'BluetoothDaemonConnection.h'
|
||||
'BluetoothDaemonConnection.h',
|
||||
'BluetoothDaemonConnectionConsumer.h'
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'BluetoothDaemonConnection.cpp'
|
||||
'BluetoothDaemonConnection.cpp',
|
||||
'BluetoothDaemonConnectionConsumer.cpp'
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
|
|
@ -672,79 +672,6 @@ checkPermission(uid_t uid)
|
|||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// KeyStore::ListenSocket
|
||||
//
|
||||
|
||||
KeyStore::ListenSocket::ListenSocket(KeyStore* aKeyStore)
|
||||
: mKeyStore(aKeyStore)
|
||||
{
|
||||
MOZ_ASSERT(mKeyStore);
|
||||
|
||||
MOZ_COUNT_CTOR(KeyStore::ListenSocket);
|
||||
}
|
||||
|
||||
void
|
||||
KeyStore::ListenSocket::OnConnectSuccess()
|
||||
{
|
||||
mKeyStore->OnConnectSuccess(LISTEN_SOCKET);
|
||||
|
||||
MOZ_COUNT_DTOR(KeyStore::ListenSocket);
|
||||
}
|
||||
|
||||
void
|
||||
KeyStore::ListenSocket::OnConnectError()
|
||||
{
|
||||
mKeyStore->OnConnectError(LISTEN_SOCKET);
|
||||
}
|
||||
|
||||
void
|
||||
KeyStore::ListenSocket::OnDisconnect()
|
||||
{
|
||||
mKeyStore->OnDisconnect(LISTEN_SOCKET);
|
||||
}
|
||||
|
||||
//
|
||||
// KeyStore::StreamSocket
|
||||
//
|
||||
|
||||
KeyStore::StreamSocket::StreamSocket(KeyStore* aKeyStore)
|
||||
: mKeyStore(aKeyStore)
|
||||
{
|
||||
MOZ_ASSERT(mKeyStore);
|
||||
|
||||
MOZ_COUNT_CTOR(KeyStore::StreamSocket);
|
||||
}
|
||||
|
||||
KeyStore::StreamSocket::~StreamSocket()
|
||||
{
|
||||
MOZ_COUNT_DTOR(KeyStore::StreamSocket);
|
||||
}
|
||||
|
||||
void
|
||||
KeyStore::StreamSocket::OnConnectSuccess()
|
||||
{
|
||||
mKeyStore->OnConnectSuccess(STREAM_SOCKET);
|
||||
}
|
||||
|
||||
void
|
||||
KeyStore::StreamSocket::OnConnectError()
|
||||
{
|
||||
mKeyStore->OnConnectError(STREAM_SOCKET);
|
||||
}
|
||||
|
||||
void
|
||||
KeyStore::StreamSocket::OnDisconnect()
|
||||
{
|
||||
mKeyStore->OnDisconnect(STREAM_SOCKET);
|
||||
}
|
||||
|
||||
void
|
||||
KeyStore::StreamSocket::ReceiveSocketData(nsAutoPtr<UnixSocketBuffer>& aBuffer)
|
||||
{
|
||||
mKeyStore->ReceiveSocketData(aBuffer);
|
||||
}
|
||||
|
||||
//
|
||||
// KeyStore
|
||||
//
|
||||
|
@ -795,12 +722,12 @@ KeyStore::Listen()
|
|||
if (mStreamSocket) {
|
||||
mStreamSocket->Close();
|
||||
} else {
|
||||
mStreamSocket = new StreamSocket(this);
|
||||
mStreamSocket = new StreamSocket(this, STREAM_SOCKET);
|
||||
}
|
||||
|
||||
if (!mListenSocket) {
|
||||
// We only ever allocate one |ListenSocket|...
|
||||
mListenSocket = new ListenSocket(this);
|
||||
mListenSocket = new ListenSocket(this, LISTEN_SOCKET);
|
||||
mListenSocket->Listen(new KeyStoreConnector(KEYSTORE_ALLOWED_USERS),
|
||||
mStreamSocket);
|
||||
} else {
|
||||
|
@ -952,8 +879,10 @@ KeyStore::SendData(const uint8_t *aData, int aLength)
|
|||
mStreamSocket->SendSocketData(data);
|
||||
}
|
||||
|
||||
// |StreamSocketConsumer|, |ListenSocketConsumer|
|
||||
|
||||
void
|
||||
KeyStore::ReceiveSocketData(nsAutoPtr<UnixSocketBuffer>& aMessage)
|
||||
KeyStore::ReceiveSocketData(int aIndex, nsAutoPtr<UnixSocketBuffer>& aMessage)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
|
@ -1013,34 +942,34 @@ KeyStore::ReceiveSocketData(nsAutoPtr<UnixSocketBuffer>& aMessage)
|
|||
}
|
||||
|
||||
void
|
||||
KeyStore::OnConnectSuccess(SocketType aSocketType)
|
||||
KeyStore::OnConnectSuccess(int aIndex)
|
||||
{
|
||||
if (aSocketType == STREAM_SOCKET) {
|
||||
if (aIndex == STREAM_SOCKET) {
|
||||
mShutdown = false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
KeyStore::OnConnectError(SocketType aSocketType)
|
||||
KeyStore::OnConnectError(int aIndex)
|
||||
{
|
||||
if (mShutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aSocketType == STREAM_SOCKET) {
|
||||
if (aIndex == STREAM_SOCKET) {
|
||||
// Stream socket error; start listening again
|
||||
Listen();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
KeyStore::OnDisconnect(SocketType aSocketType)
|
||||
KeyStore::OnDisconnect(int aIndex)
|
||||
{
|
||||
if (mShutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (aSocketType) {
|
||||
switch (aIndex) {
|
||||
case LISTEN_SOCKET:
|
||||
// Listen socket disconnected; start anew.
|
||||
mListenSocket = nullptr;
|
||||
|
|
|
@ -11,7 +11,9 @@
|
|||
#include <sys/un.h>
|
||||
#include "cert.h"
|
||||
#include "mozilla/ipc/ListenSocket.h"
|
||||
#include "mozilla/ipc/ListenSocketConsumer.h"
|
||||
#include "mozilla/ipc/StreamSocket.h"
|
||||
#include "mozilla/ipc/StreamSocketConsumer.h"
|
||||
#include "nsNSSShutDown.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -78,7 +80,10 @@ typedef enum {
|
|||
STATE_PROCESSING
|
||||
} ProtocolHandlerState;
|
||||
|
||||
class KeyStore final : public nsNSSShutDownObject
|
||||
class KeyStore final
|
||||
: public StreamSocketConsumer
|
||||
, public ListenSocketConsumer
|
||||
, public nsNSSShutDownObject
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(KeyStore)
|
||||
|
@ -96,50 +101,8 @@ private:
|
|||
STREAM_SOCKET
|
||||
};
|
||||
|
||||
class ListenSocket final : public mozilla::ipc::ListenSocket
|
||||
{
|
||||
public:
|
||||
ListenSocket(KeyStore* aKeyStore);
|
||||
ListenSocket();
|
||||
|
||||
// SocketBase
|
||||
//
|
||||
|
||||
void OnConnectSuccess() override;
|
||||
void OnConnectError() override;
|
||||
void OnDisconnect() override;
|
||||
|
||||
private:
|
||||
KeyStore* mKeyStore;
|
||||
};
|
||||
|
||||
class StreamSocket final : public mozilla::ipc::StreamSocket
|
||||
{
|
||||
public:
|
||||
StreamSocket(KeyStore* aKeyStore);
|
||||
~StreamSocket();
|
||||
|
||||
// SocketConsumerBase
|
||||
//
|
||||
|
||||
void OnConnectSuccess() override;
|
||||
void OnConnectError() override;
|
||||
void OnDisconnect() override;
|
||||
|
||||
void ReceiveSocketData(nsAutoPtr<UnixSocketBuffer>& aBuffer) override;
|
||||
|
||||
private:
|
||||
KeyStore* mKeyStore;
|
||||
};
|
||||
|
||||
~KeyStore();
|
||||
|
||||
void ReceiveSocketData(nsAutoPtr<UnixSocketBuffer>& aMessage);
|
||||
|
||||
void OnConnectSuccess(enum SocketType aSocketType);
|
||||
void OnConnectError(enum SocketType aSocketType);
|
||||
void OnDisconnect(enum SocketType aSocketType);
|
||||
|
||||
struct {
|
||||
ProtocolHandlerState state;
|
||||
uint8_t command;
|
||||
|
@ -157,6 +120,15 @@ private:
|
|||
void SendResponse(ResponseCode response);
|
||||
void SendData(const uint8_t *data, int length);
|
||||
|
||||
// Methods for |StreamSocketConsumer|
|
||||
//
|
||||
|
||||
void ReceiveSocketData(int aIndex,
|
||||
nsAutoPtr<UnixSocketBuffer>& aMessage) override;
|
||||
void OnConnectSuccess(int aIndex) override;
|
||||
void OnConnectError(int aIndex) override;
|
||||
void OnDisconnect(int aIndex) override;
|
||||
|
||||
bool mShutdown;
|
||||
|
||||
nsRefPtr<ListenSocket> mListenSocket;
|
||||
|
|
165
ipc/nfc/Nfc.cpp
165
ipc/nfc/Nfc.cpp
|
@ -1,165 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set sw=2 ts=8 et ft=cpp: */
|
||||
/* 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/. */
|
||||
|
||||
/* Copyright © 2013, Deutsche Telekom, Inc. */
|
||||
|
||||
#include "mozilla/ipc/Nfc.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#undef CHROMIUM_LOG
|
||||
#if (defined(MOZ_WIDGET_GONK) && defined(DEBUG))
|
||||
#include <android/log.h>
|
||||
#define CHROMIUM_LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk", args)
|
||||
#else
|
||||
#define CHROMIUM_LOG(args...)
|
||||
#endif
|
||||
|
||||
#include "jsfriendapi.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/ipc/NfcConnector.h"
|
||||
#include "nsThreadUtils.h" // For NS_IsMainThread.
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
namespace {
|
||||
|
||||
class SendNfcSocketDataTask final : public nsRunnable
|
||||
{
|
||||
public:
|
||||
SendNfcSocketDataTask(NfcConsumer* aConsumer, UnixSocketRawData* aRawData)
|
||||
: mConsumer(aConsumer)
|
||||
, mRawData(aRawData)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!mConsumer ||
|
||||
mConsumer->GetConnectionStatus() != SOCKET_CONNECTED) {
|
||||
// Probably shuting down.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mConsumer->SendSocketData(mRawData.forget());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
NfcConsumer* mConsumer;
|
||||
nsAutoPtr<UnixSocketRawData> mRawData;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
//
|
||||
// NfcListenSocket
|
||||
//
|
||||
|
||||
NfcListenSocket::NfcListenSocket(NfcSocketListener* aListener)
|
||||
: mListener(aListener)
|
||||
{ }
|
||||
|
||||
void
|
||||
NfcListenSocket::OnConnectSuccess()
|
||||
{
|
||||
if (mListener) {
|
||||
mListener->OnConnectSuccess(NfcSocketListener::LISTEN_SOCKET);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
NfcListenSocket::OnConnectError()
|
||||
{
|
||||
if (mListener) {
|
||||
mListener->OnConnectError(NfcSocketListener::LISTEN_SOCKET);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
NfcListenSocket::OnDisconnect()
|
||||
{
|
||||
if (mListener) {
|
||||
mListener->OnDisconnect(NfcSocketListener::LISTEN_SOCKET);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// NfcConsumer
|
||||
//
|
||||
|
||||
NfcConsumer::NfcConsumer(NfcSocketListener* aListener)
|
||||
: mListener(aListener)
|
||||
{ }
|
||||
|
||||
void
|
||||
NfcConsumer::Shutdown()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
bool
|
||||
NfcConsumer::PostToNfcDaemon(const uint8_t* aData, size_t aSize)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
UnixSocketRawData* raw = new UnixSocketRawData(aData, aSize);
|
||||
nsRefPtr<SendNfcSocketDataTask> task = new SendNfcSocketDataTask(this, raw);
|
||||
NS_DispatchToMainThread(task);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
NfcConsumer::ReceiveSocketData(nsAutoPtr<UnixSocketBuffer>& aBuffer)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mListener) {
|
||||
mListener->ReceiveSocketData(aBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
NfcConsumer::OnConnectSuccess()
|
||||
{
|
||||
CHROMIUM_LOG("NFC: %s\n", __FUNCTION__);
|
||||
|
||||
if (mListener) {
|
||||
mListener->OnConnectSuccess(NfcSocketListener::STREAM_SOCKET);
|
||||
}
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
void
|
||||
NfcConsumer::OnConnectError()
|
||||
{
|
||||
CHROMIUM_LOG("NFC: %s\n", __FUNCTION__);
|
||||
|
||||
if (mListener) {
|
||||
mListener->OnConnectError(NfcSocketListener::STREAM_SOCKET);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
NfcConsumer::OnDisconnect()
|
||||
{
|
||||
CHROMIUM_LOG("NFC: %s\n", __FUNCTION__);
|
||||
|
||||
if (mListener) {
|
||||
mListener->OnDisconnect(NfcSocketListener::STREAM_SOCKET);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
|
@ -1,68 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et ft=cpp: */
|
||||
/* 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/. */
|
||||
|
||||
/* Copyright © 2013, Deutsche Telekom, Inc. */
|
||||
|
||||
#ifndef mozilla_ipc_Nfc_h
|
||||
#define mozilla_ipc_Nfc_h 1
|
||||
|
||||
#include <mozilla/ipc/ListenSocket.h>
|
||||
#include <mozilla/ipc/StreamSocket.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
class NfcSocketListener
|
||||
{
|
||||
public:
|
||||
enum SocketType {
|
||||
LISTEN_SOCKET,
|
||||
STREAM_SOCKET
|
||||
};
|
||||
|
||||
virtual void ReceiveSocketData(nsAutoPtr<UnixSocketBuffer>& aData) = 0;
|
||||
|
||||
virtual void OnConnectSuccess(enum SocketType aSocketType) = 0;
|
||||
virtual void OnConnectError(enum SocketType aSocketType) = 0;
|
||||
virtual void OnDisconnect(enum SocketType aSocketType) = 0;
|
||||
};
|
||||
|
||||
class NfcListenSocket final : public mozilla::ipc::ListenSocket
|
||||
{
|
||||
public:
|
||||
NfcListenSocket(NfcSocketListener* aListener);
|
||||
|
||||
void OnConnectSuccess() override;
|
||||
void OnConnectError() override;
|
||||
void OnDisconnect() override;
|
||||
|
||||
private:
|
||||
NfcSocketListener* mListener;
|
||||
};
|
||||
|
||||
class NfcConsumer final : public mozilla::ipc::StreamSocket
|
||||
{
|
||||
public:
|
||||
NfcConsumer(NfcSocketListener* aListener);
|
||||
|
||||
void Shutdown();
|
||||
bool PostToNfcDaemon(const uint8_t* aData, size_t aSize);
|
||||
|
||||
private:
|
||||
void ReceiveSocketData(nsAutoPtr<UnixSocketBuffer>& aBuffer) override;
|
||||
|
||||
void OnConnectSuccess() override;
|
||||
void OnConnectError() override;
|
||||
void OnDisconnect() override;
|
||||
|
||||
private:
|
||||
NfcSocketListener* mListener;
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
} // namepsace mozilla
|
||||
|
||||
#endif // mozilla_ipc_Nfc_h
|
|
@ -5,11 +5,9 @@
|
|||
|
||||
if CONFIG['MOZ_NFC']:
|
||||
EXPORTS.mozilla.ipc += [
|
||||
'Nfc.h',
|
||||
'NfcConnector.h',
|
||||
]
|
||||
SOURCES += [
|
||||
'Nfc.cpp',
|
||||
'NfcConnector.cpp',
|
||||
]
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace {
|
|||
|
||||
static const char RIL_SOCKET_NAME[] = "/dev/socket/rilproxy";
|
||||
|
||||
static nsTArray<nsRefPtr<mozilla::ipc::RilConsumer> > sRilConsumers;
|
||||
static nsTArray<nsAutoPtr<mozilla::ipc::RilConsumer>> sRilConsumers;
|
||||
|
||||
class ConnectWorkerToRIL final : public WorkerTask
|
||||
{
|
||||
|
@ -53,15 +53,13 @@ public:
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (sRilConsumers.Length() <= mClientId ||
|
||||
!sRilConsumers[mClientId] ||
|
||||
sRilConsumers[mClientId]->GetConnectionStatus() != SOCKET_CONNECTED) {
|
||||
// Probably shuting down.
|
||||
if (sRilConsumers.Length() <= mClientId || !sRilConsumers[mClientId]) {
|
||||
// Probably shutting down.
|
||||
delete mRawData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
sRilConsumers[mClientId]->SendSocketData(mRawData);
|
||||
sRilConsumers[mClientId]->Send(mRawData);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -203,7 +201,6 @@ namespace ipc {
|
|||
RilConsumer::RilConsumer(unsigned long aClientId,
|
||||
WorkerCrossThreadDispatcher* aDispatcher)
|
||||
: mDispatcher(aDispatcher)
|
||||
, mClientId(aClientId)
|
||||
, mShutdown(false)
|
||||
{
|
||||
// Only append client id after RIL_SOCKET_NAME when it's not connected to
|
||||
|
@ -217,7 +214,8 @@ RilConsumer::RilConsumer(unsigned long aClientId,
|
|||
mAddress = addr_un.sun_path;
|
||||
}
|
||||
|
||||
Connect(new RilConnector(mAddress, mClientId));
|
||||
mSocket = new StreamSocket(this, aClientId);
|
||||
mSocket->Connect(new RilConnector(mAddress, aClientId));
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -250,7 +248,7 @@ RilConsumer::Shutdown()
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
for (unsigned long i = 0; i < sRilConsumers.Length(); i++) {
|
||||
nsRefPtr<RilConsumer>& instance = sRilConsumers[i];
|
||||
nsAutoPtr<RilConsumer> instance(sRilConsumers[i]);
|
||||
if (!instance) {
|
||||
continue;
|
||||
}
|
||||
|
@ -262,36 +260,58 @@ RilConsumer::Shutdown()
|
|||
}
|
||||
|
||||
void
|
||||
RilConsumer::ReceiveSocketData(nsAutoPtr<UnixSocketBuffer>& aBuffer)
|
||||
RilConsumer::Send(UnixSocketRawData* aRawData)
|
||||
{
|
||||
if (!mSocket || mSocket->GetConnectionStatus() != SOCKET_CONNECTED) {
|
||||
// Probably shutting down.
|
||||
delete aRawData;
|
||||
return;
|
||||
}
|
||||
mSocket->SendSocketData(aRawData);
|
||||
}
|
||||
|
||||
void
|
||||
RilConsumer::Close()
|
||||
{
|
||||
mSocket->Close();
|
||||
mSocket = nullptr;
|
||||
}
|
||||
|
||||
// |StreamSocketConnector|
|
||||
|
||||
void
|
||||
RilConsumer::ReceiveSocketData(int aIndex,
|
||||
nsAutoPtr<UnixSocketBuffer>& aBuffer)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsRefPtr<DispatchRILEvent> dre(new DispatchRILEvent(mClientId, aBuffer.forget()));
|
||||
nsRefPtr<DispatchRILEvent> dre(new DispatchRILEvent(aIndex, aBuffer.forget()));
|
||||
mDispatcher->PostTask(dre);
|
||||
}
|
||||
|
||||
void
|
||||
RilConsumer::OnConnectSuccess()
|
||||
RilConsumer::OnConnectSuccess(int aIndex)
|
||||
{
|
||||
// Nothing to do here.
|
||||
CHROMIUM_LOG("RIL[%lu]: %s\n", mClientId, __FUNCTION__);
|
||||
CHROMIUM_LOG("RIL[%d]: %s\n", aIndex, __FUNCTION__);
|
||||
}
|
||||
|
||||
void
|
||||
RilConsumer::OnConnectError()
|
||||
RilConsumer::OnConnectError(int aIndex)
|
||||
{
|
||||
CHROMIUM_LOG("RIL[%lu]: %s\n", mClientId, __FUNCTION__);
|
||||
CHROMIUM_LOG("RIL[%d]: %s\n", aIndex, __FUNCTION__);
|
||||
Close();
|
||||
}
|
||||
|
||||
void
|
||||
RilConsumer::OnDisconnect()
|
||||
RilConsumer::OnDisconnect(int aIndex)
|
||||
{
|
||||
CHROMIUM_LOG("RIL[%lu]: %s\n", mClientId, __FUNCTION__);
|
||||
CHROMIUM_LOG("RIL[%d]: %s\n", aIndex, __FUNCTION__);
|
||||
if (mShutdown) {
|
||||
return;
|
||||
}
|
||||
Connect(new RilConnector(mAddress, mClientId), GetSuggestedConnectDelayMs());
|
||||
mSocket->Connect(new RilConnector(mAddress, aIndex),
|
||||
mSocket->GetSuggestedConnectDelayMs());
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
|
|
|
@ -9,11 +9,12 @@
|
|||
|
||||
#include <mozilla/dom/workers/Workers.h>
|
||||
#include <mozilla/ipc/StreamSocket.h>
|
||||
#include <mozilla/ipc/StreamSocketConsumer.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
class RilConsumer final : public mozilla::ipc::StreamSocket
|
||||
class RilConsumer final : public StreamSocketConsumer
|
||||
{
|
||||
public:
|
||||
static nsresult Register(
|
||||
|
@ -21,18 +22,25 @@ public:
|
|||
mozilla::dom::workers::WorkerCrossThreadDispatcher* aDispatcher);
|
||||
static void Shutdown();
|
||||
|
||||
void Send(UnixSocketRawData* aRawData);
|
||||
|
||||
private:
|
||||
RilConsumer(unsigned long aClientId,
|
||||
mozilla::dom::workers::WorkerCrossThreadDispatcher* aDispatcher);
|
||||
|
||||
void ReceiveSocketData(nsAutoPtr<UnixSocketBuffer>& aBuffer) override;
|
||||
void Close();
|
||||
|
||||
void OnConnectSuccess() override;
|
||||
void OnConnectError() override;
|
||||
void OnDisconnect() override;
|
||||
// Methods for |StreamSocketConsumer|
|
||||
//
|
||||
|
||||
void ReceiveSocketData(int aIndex,
|
||||
nsAutoPtr<UnixSocketBuffer>& aBuffer) override;
|
||||
void OnConnectSuccess(int aIndex) override;
|
||||
void OnConnectError(int aIndex) override;
|
||||
void OnDisconnect(int aIndex) override;
|
||||
|
||||
nsRefPtr<StreamSocket> mSocket;
|
||||
nsRefPtr<mozilla::dom::workers::WorkerCrossThreadDispatcher> mDispatcher;
|
||||
unsigned long mClientId;
|
||||
nsCString mAddress;
|
||||
bool mShutdown;
|
||||
};
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <fcntl.h>
|
||||
#include "ConnectionOrientedSocket.h"
|
||||
#include "DataSocket.h"
|
||||
#include "ListenSocketConsumer.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "UnixSocketConnector.h"
|
||||
|
@ -291,9 +292,13 @@ private:
|
|||
// UnixSocketConsumer
|
||||
//
|
||||
|
||||
ListenSocket::ListenSocket()
|
||||
: mIO(nullptr)
|
||||
{ }
|
||||
ListenSocket::ListenSocket(ListenSocketConsumer* aConsumer, int aIndex)
|
||||
: mConsumer(aConsumer)
|
||||
, mIndex(aIndex)
|
||||
, mIO(nullptr)
|
||||
{
|
||||
MOZ_ASSERT(mConsumer);
|
||||
}
|
||||
|
||||
ListenSocket::~ListenSocket()
|
||||
{
|
||||
|
@ -376,5 +381,29 @@ ListenSocket::Close()
|
|||
NotifyDisconnect();
|
||||
}
|
||||
|
||||
void
|
||||
ListenSocket::OnConnectSuccess()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mConsumer->OnConnectSuccess(mIndex);
|
||||
}
|
||||
|
||||
void
|
||||
ListenSocket::OnConnectError()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mConsumer->OnConnectError(mIndex);
|
||||
}
|
||||
|
||||
void
|
||||
ListenSocket::OnDisconnect()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mConsumer->OnDisconnect(mIndex);
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -14,16 +14,17 @@ namespace mozilla {
|
|||
namespace ipc {
|
||||
|
||||
class ConnectionOrientedSocket;
|
||||
class ListenSocketConsumer;
|
||||
class ListenSocketIO;
|
||||
class UnixSocketConnector;
|
||||
|
||||
class ListenSocket : public SocketBase
|
||||
class ListenSocket final : public SocketBase
|
||||
{
|
||||
protected:
|
||||
virtual ~ListenSocket();
|
||||
|
||||
public:
|
||||
ListenSocket();
|
||||
ListenSocket(ListenSocketConsumer* aConsumer, int aIndex);
|
||||
|
||||
/**
|
||||
* Starts a task on the socket that will try to accept a new connection
|
||||
|
@ -52,8 +53,13 @@ public:
|
|||
//
|
||||
|
||||
void Close() override;
|
||||
void OnConnectSuccess() override;
|
||||
void OnConnectError() override;
|
||||
void OnDisconnect() override;
|
||||
|
||||
private:
|
||||
ListenSocketConsumer* mConsumer;
|
||||
int mIndex;
|
||||
ListenSocketIO* mIO;
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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 "ListenSocketConsumer.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
//
|
||||
// ListenSocketConsumer
|
||||
//
|
||||
|
||||
ListenSocketConsumer::~ListenSocketConsumer()
|
||||
{ }
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_ipc_listensocketconsumer_h
|
||||
#define mozilla_ipc_listensocketconsumer_h
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
/**
|
||||
* |ListenSocketConsumer| handles socket events.
|
||||
*/
|
||||
class ListenSocketConsumer
|
||||
{
|
||||
public:
|
||||
virtual ~ListenSocketConsumer();
|
||||
|
||||
/**
|
||||
* Callback for socket success. Main-thread only.
|
||||
*
|
||||
* @param aIndex The index that has been given to the listening socket.
|
||||
*/
|
||||
virtual void OnConnectSuccess(int aIndex) = 0;
|
||||
|
||||
/**
|
||||
* Callback for socket errors. Main-thread only.
|
||||
*
|
||||
* @param aIndex The index that has been given to the listening socket.
|
||||
*/
|
||||
virtual void OnConnectError(int aIndex) = 0;
|
||||
|
||||
/**
|
||||
* Callback for socket disconnect. Main-thread only.
|
||||
*
|
||||
* @param aIndex The index that has been given to the listeing socket.
|
||||
*/
|
||||
virtual void OnDisconnect(int aIndex) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -8,6 +8,7 @@
|
|||
#include <fcntl.h>
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "StreamSocketConsumer.h"
|
||||
#include "UnixSocketConnector.h"
|
||||
|
||||
static const size_t MAX_READ_SIZE = 1 << 16;
|
||||
|
@ -499,15 +500,27 @@ public:
|
|||
// StreamSocket
|
||||
//
|
||||
|
||||
StreamSocket::StreamSocket()
|
||||
: mIO(nullptr)
|
||||
{ }
|
||||
StreamSocket::StreamSocket(StreamSocketConsumer* aConsumer, int aIndex)
|
||||
: mConsumer(aConsumer)
|
||||
, mIndex(aIndex)
|
||||
, mIO(nullptr)
|
||||
{
|
||||
MOZ_ASSERT(mConsumer);
|
||||
}
|
||||
|
||||
StreamSocket::~StreamSocket()
|
||||
{
|
||||
MOZ_ASSERT(!mIO);
|
||||
}
|
||||
|
||||
void
|
||||
StreamSocket::ReceiveSocketData(nsAutoPtr<UnixSocketBuffer>& aBuffer)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mConsumer->ReceiveSocketData(mIndex, aBuffer);
|
||||
}
|
||||
|
||||
nsresult
|
||||
StreamSocket::Connect(UnixSocketConnector* aConnector,
|
||||
int aDelayMs)
|
||||
|
@ -586,5 +599,29 @@ StreamSocket::Close()
|
|||
NotifyDisconnect();
|
||||
}
|
||||
|
||||
void
|
||||
StreamSocket::OnConnectSuccess()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mConsumer->OnConnectSuccess(mIndex);
|
||||
}
|
||||
|
||||
void
|
||||
StreamSocket::OnConnectError()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mConsumer->OnConnectError(mIndex);
|
||||
}
|
||||
|
||||
void
|
||||
StreamSocket::OnDisconnect()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mConsumer->OnDisconnect(mIndex);
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -12,21 +12,21 @@
|
|||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
class StreamSocketConsumer;
|
||||
class StreamSocketIO;
|
||||
class UnixSocketConnector;
|
||||
|
||||
class StreamSocket : public ConnectionOrientedSocket
|
||||
class StreamSocket final : public ConnectionOrientedSocket
|
||||
{
|
||||
public:
|
||||
StreamSocket();
|
||||
StreamSocket(StreamSocketConsumer* aConsumer, int aIndex);
|
||||
|
||||
/**
|
||||
* Method to be called whenever data is received. This is only called on the
|
||||
* main thread.
|
||||
* Method to be called whenever data is received. Main-thread only.
|
||||
*
|
||||
* @param aBuffer Data received from the socket.
|
||||
*/
|
||||
virtual void ReceiveSocketData(nsAutoPtr<UnixSocketBuffer>& aBuffer) = 0;
|
||||
void ReceiveSocketData(nsAutoPtr<UnixSocketBuffer>& aBuffer);
|
||||
|
||||
/**
|
||||
* Starts a task on the socket that will try to connect to a socket in a
|
||||
|
@ -53,11 +53,16 @@ public:
|
|||
//
|
||||
|
||||
void Close() override;
|
||||
void OnConnectSuccess() override;
|
||||
void OnConnectError() override;
|
||||
void OnDisconnect() override;
|
||||
|
||||
protected:
|
||||
virtual ~StreamSocket();
|
||||
|
||||
private:
|
||||
StreamSocketConsumer* mConsumer;
|
||||
int mIndex;
|
||||
StreamSocketIO* mIO;
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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 "StreamSocketConsumer.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
//
|
||||
// StreamSocketConsumer
|
||||
//
|
||||
|
||||
StreamSocketConsumer::~StreamSocketConsumer()
|
||||
{ }
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_ipc_streamsocketconsumer_h
|
||||
#define mozilla_ipc_streamsocketconsumer_h
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
class UnixSocketBuffer;
|
||||
|
||||
/**
|
||||
* |StreamSocketConsumer| handles socket events and received data.
|
||||
*/
|
||||
class StreamSocketConsumer
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Method to be called whenever data is received. Main-thread only.
|
||||
*
|
||||
* @param aIndex The index that has been given to the stream socket.
|
||||
* @param aBuffer Data received from the socket.
|
||||
*/
|
||||
virtual void ReceiveSocketData(int aIndex,
|
||||
nsAutoPtr<UnixSocketBuffer>& aBuffer) = 0;
|
||||
|
||||
/**
|
||||
* Callback for socket success. Main-thread only.
|
||||
*
|
||||
* @param aIndex The index that has been given to the stream socket.
|
||||
*/
|
||||
virtual void OnConnectSuccess(int aIndex) = 0;
|
||||
|
||||
/**
|
||||
* Callback for socket errors. Main-thread only.
|
||||
*
|
||||
* @param aIndex The index that has been given to the stream socket.
|
||||
*/
|
||||
virtual void OnConnectError(int aIndex) = 0;
|
||||
|
||||
/**
|
||||
* Callback for socket disconnect. Main-thread only.
|
||||
*
|
||||
* @param aIndex The index that has been given to the stream socket.
|
||||
*/
|
||||
virtual void OnDisconnect(int aIndex) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~StreamSocketConsumer();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -8,8 +8,10 @@ EXPORTS.mozilla.ipc += [
|
|||
'ConnectionOrientedSocket.h',
|
||||
'DataSocket.h',
|
||||
'ListenSocket.h',
|
||||
'ListenSocketConsumer.h',
|
||||
'SocketBase.h',
|
||||
'StreamSocket.h',
|
||||
'StreamSocketConsumer.h',
|
||||
'UnixSocketConnector.h'
|
||||
]
|
||||
|
||||
|
@ -17,8 +19,10 @@ SOURCES += [
|
|||
'ConnectionOrientedSocket.cpp',
|
||||
'DataSocket.cpp',
|
||||
'ListenSocket.cpp',
|
||||
'ListenSocketConsumer.cpp',
|
||||
'SocketBase.cpp',
|
||||
'StreamSocket.cpp',
|
||||
'StreamSocketConsumer.cpp',
|
||||
'UnixSocketConnector.cpp'
|
||||
]
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче