mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to inbound. a=merge
CLOSED TREE
This commit is contained in:
commit
d9725dbb72
@ -1 +0,0 @@
|
||||
b2g/branding/official/content/splash.png
|
@ -1 +0,0 @@
|
||||
b2g/branding/unofficial/content/splash.png
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="2eda36a4795012a5d1275b77ebb20ac377c8cd26">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="eb3f82f3b947f1ed52fa4e9246bed0f0b3e49785"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="426fe6450ab8da92bb473fef12ccb39c6c920dd0"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
|
||||
<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="eb3f82f3b947f1ed52fa4e9246bed0f0b3e49785"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="426fe6450ab8da92bb473fef12ccb39c6c920dd0"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="9a9797062c6001d6346504161c51187a2968466b"/>
|
||||
|
@ -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="eb3f82f3b947f1ed52fa4e9246bed0f0b3e49785"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="426fe6450ab8da92bb473fef12ccb39c6c920dd0"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0627790166dccd8dd370fa7d9f434ed9fc027fb4"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="2eda36a4795012a5d1275b77ebb20ac377c8cd26">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="eb3f82f3b947f1ed52fa4e9246bed0f0b3e49785"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="426fe6450ab8da92bb473fef12ccb39c6c920dd0"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -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="eb3f82f3b947f1ed52fa4e9246bed0f0b3e49785"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="426fe6450ab8da92bb473fef12ccb39c6c920dd0"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
|
||||
<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="eb3f82f3b947f1ed52fa4e9246bed0f0b3e49785"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="426fe6450ab8da92bb473fef12ccb39c6c920dd0"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="9a9797062c6001d6346504161c51187a2968466b"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="2eda36a4795012a5d1275b77ebb20ac377c8cd26">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="eb3f82f3b947f1ed52fa4e9246bed0f0b3e49785"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="426fe6450ab8da92bb473fef12ccb39c6c920dd0"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="eb3f82f3b947f1ed52fa4e9246bed0f0b3e49785"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="426fe6450ab8da92bb473fef12ccb39c6c920dd0"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0627790166dccd8dd370fa7d9f434ed9fc027fb4"/>
|
||||
|
@ -1,9 +1,9 @@
|
||||
{
|
||||
"git": {
|
||||
"git_revision": "eb3f82f3b947f1ed52fa4e9246bed0f0b3e49785",
|
||||
"git_revision": "426fe6450ab8da92bb473fef12ccb39c6c920dd0",
|
||||
"remote": "https://git.mozilla.org/releases/gaia.git",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "78e99873114b371f245690c3b0b80834a649f2f2",
|
||||
"revision": "b48088c5abd6ad5a64b9b870e52d6de14b3f2bc3",
|
||||
"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="eb3f82f3b947f1ed52fa4e9246bed0f0b3e49785"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="426fe6450ab8da92bb473fef12ccb39c6c920dd0"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0627790166dccd8dd370fa7d9f434ed9fc027fb4"/>
|
||||
|
@ -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="eb3f82f3b947f1ed52fa4e9246bed0f0b3e49785"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="426fe6450ab8da92bb473fef12ccb39c6c920dd0"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -1443,16 +1443,15 @@ pref("devtools.performance.ui.show-idle-blocks", true);
|
||||
pref("devtools.performance.ui.enable-memory", false);
|
||||
pref("devtools.performance.ui.enable-framerate", true);
|
||||
pref("devtools.performance.ui.show-jit-optimizations", false);
|
||||
// If in aurora (40.0, will revert for 40.1), set default
|
||||
// If in aurora/dev edition (40.0, will revert for 40.1), set default
|
||||
// to retro mode.
|
||||
// TODO bug 1160313
|
||||
#if MOZ_UPDATE_CHANNEL == aurora
|
||||
#ifdef MOZ_DEV_EDITION
|
||||
pref("devtools.performance.ui.retro-mode", true);
|
||||
#else
|
||||
pref("devtools.performance.ui.retro-mode", false);
|
||||
#endif
|
||||
|
||||
|
||||
// The default cache UI setting
|
||||
pref("devtools.cache.disabled", false);
|
||||
|
||||
|
@ -49,7 +49,6 @@
|
||||
"no-empty": 0, // TODO: Remove (use default)
|
||||
"no-extra-bind": 0, // Leave as 0
|
||||
"no-extra-boolean-cast": 0, // TODO: Remove (use default)
|
||||
"no-extra-semi": 0, // TODO: Remove (use default)
|
||||
"no-multi-spaces": 0, // TBD.
|
||||
"no-new": 0, // TODO: Remove (use default)
|
||||
"no-redeclare": 0, // TODO: Remove (use default)
|
||||
@ -64,8 +63,6 @@
|
||||
"no-use-before-define": 0, // TODO: Remove (use default)
|
||||
"no-wrap-func": 0, // TODO: Remove (use default)
|
||||
"quotes": 0, // [2, "double", "avoid-escape"],
|
||||
"semi": 0, // TODO: Remove (use default)
|
||||
"semi-spacing": 0, // TODO: Remove (use default)
|
||||
"space-infix-ops": 0, // TODO: Remove (use default)
|
||||
"space-return-throw-case": 0, // TODO: Remove (use default)
|
||||
"strict": 0, // [2, "function"],
|
||||
|
@ -18,7 +18,7 @@ var inChrome = typeof Components != "undefined" && "utils" in Components;
|
||||
throw new Error("mozL10n.get not availabled from chrome!");
|
||||
}};
|
||||
} else {
|
||||
mozL10n = document.mozL10n || navigator.mozL10n
|
||||
mozL10n = document.mozL10n || navigator.mozL10n;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -46,7 +46,7 @@ loop.CallConnectionWebSocket = (function() {
|
||||
loop.shared.utils.getBoolPreference("debug.websocket");
|
||||
|
||||
_.extend(this, Backbone.Events);
|
||||
};
|
||||
}
|
||||
|
||||
CallConnectionWebSocket.prototype = {
|
||||
/**
|
||||
|
@ -306,7 +306,7 @@ this.CardDavImporter.prototype = {
|
||||
// a supported field. We're saving it off here in case we
|
||||
// need to use it if the fullname is blank.
|
||||
nickname = value;
|
||||
};
|
||||
}
|
||||
|
||||
if (name === "ADR") {
|
||||
value = value.replace(/\\;/g, "\r");
|
||||
@ -455,7 +455,7 @@ this.CardDavImporter.prototype = {
|
||||
|
||||
req.onerror = function(error) {
|
||||
reject(error);
|
||||
}
|
||||
};
|
||||
|
||||
req.send(body);
|
||||
});
|
||||
|
@ -325,7 +325,7 @@ this.GoogleImporter.prototype = {
|
||||
|
||||
request.onerror = function(error) {
|
||||
reject(error);
|
||||
}
|
||||
};
|
||||
|
||||
request.send();
|
||||
});
|
||||
@ -514,7 +514,7 @@ this.GoogleImporter.prototype = {
|
||||
for (let [,orgNode] of Iterator(orgNodes)) {
|
||||
let orgElement = orgNode.getElementsByTagNameNS(kNS_GD, "orgName")[0];
|
||||
let titleElement = orgNode.getElementsByTagNameNS(kNS_GD, "orgTitle")[0];
|
||||
contact.org.push(orgElement ? orgElement.textContent : "")
|
||||
contact.org.push(orgElement ? orgElement.textContent : "");
|
||||
contact.jobTitle.push(titleElement ? titleElement.textContent : "");
|
||||
}
|
||||
}
|
||||
|
@ -53,8 +53,9 @@ CallProgressSocket.prototype = {
|
||||
*/
|
||||
connect: function(onSuccess, onError) {
|
||||
this._onSuccess = onSuccess;
|
||||
this._onError = onError ||
|
||||
(reason => {MozLoopService.log.warn("LoopCalls::callProgessSocket - ", reason);});
|
||||
this._onError = onError || (reason => {
|
||||
MozLoopService.log.warn("LoopCalls::callProgessSocket - ", reason);
|
||||
});
|
||||
|
||||
if (!onSuccess) {
|
||||
this._onError("missing onSuccess argument");
|
||||
@ -237,7 +238,7 @@ let LoopCallsInternal = {
|
||||
|
||||
_getCalls: function(sessionType, version) {
|
||||
return MozLoopService.hawkRequest(sessionType, "/calls?version=" + version, "GET").then(
|
||||
response => {this._processCalls(response, sessionType);}
|
||||
response => { this._processCalls(response, sessionType); }
|
||||
);
|
||||
},
|
||||
|
||||
@ -309,7 +310,7 @@ let LoopCallsInternal = {
|
||||
}
|
||||
|
||||
openChat();
|
||||
})
|
||||
});
|
||||
} else {
|
||||
openChat();
|
||||
}
|
||||
@ -397,7 +398,7 @@ let LoopCallsInternal = {
|
||||
}
|
||||
// This instance of CallProgressSocket should stay alive until the underlying
|
||||
// websocket is closed since it is passed to the websocket as the nsIWebSocketListener.
|
||||
callProgress.connect(() => {callProgress.sendBusy();});
|
||||
callProgress.connect(() => { callProgress.sendBusy(); });
|
||||
}
|
||||
};
|
||||
Object.freeze(LoopCallsInternal);
|
||||
|
@ -288,7 +288,7 @@ const batch = function(operation, data, callback) {
|
||||
}
|
||||
callback(null, processed);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Extend a `target` object with the properties defined in `source`.
|
||||
|
@ -7,11 +7,13 @@ const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
const {MozLoopService, LOOP_SESSION_TYPE} = Cu.import("resource:///modules/loop/MozLoopService.jsm", {});
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/Promise.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "CommonUtils",
|
||||
"resource://services-common/utils.js");
|
||||
XPCOMUtils.defineLazyGetter(this, "eventEmitter", function() {
|
||||
const {EventEmitter} = Cu.import("resource://gre/modules/devtools/event-emitter.js", {});
|
||||
return new EventEmitter();
|
||||
@ -19,8 +21,11 @@ XPCOMUtils.defineLazyGetter(this, "eventEmitter", function() {
|
||||
XPCOMUtils.defineLazyGetter(this, "gLoopBundle", function() {
|
||||
return Services.strings.createBundle('chrome://browser/locale/loop/loop.properties');
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "LoopRoomsCache",
|
||||
"resource:///modules/loop/LoopRoomsCache.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "loopUtils",
|
||||
"resource:///modules/loop/utils.js", "utils")
|
||||
"resource:///modules/loop/utils.js", "utils");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "loopCrypto",
|
||||
"resource:///modules/loop/crypto.js", "LoopCrypto");
|
||||
|
||||
@ -41,6 +46,8 @@ const roomsPushNotification = function(version, channelID) {
|
||||
let gDirty = true;
|
||||
// Global variable that keeps track of the currently used account.
|
||||
let gCurrentUser = null;
|
||||
// Global variable that keeps track of the room cache.
|
||||
let gRoomsCache = null;
|
||||
|
||||
/**
|
||||
* Extend a `target` object with the properties defined in `source`.
|
||||
@ -123,6 +130,13 @@ let LoopRoomsInternal = {
|
||||
*/
|
||||
rooms: new Map(),
|
||||
|
||||
get roomsCache() {
|
||||
if (!gRoomsCache) {
|
||||
gRoomsCache = new LoopRoomsCache();
|
||||
}
|
||||
return gRoomsCache;
|
||||
},
|
||||
|
||||
/**
|
||||
* @var {String} sessionType The type of user session. May be 'FXA' or 'GUEST'.
|
||||
*/
|
||||
@ -275,12 +289,40 @@ let LoopRoomsInternal = {
|
||||
throw new Error("Missing wrappedKey");
|
||||
}
|
||||
|
||||
// Bug 1152761 will cause us to additionally store keys locally. We'll
|
||||
// need to add some code for recovery in case decryption fails.
|
||||
let key = yield this.promiseDecryptRoomKey(roomData.context.wrappedKey);
|
||||
let savedRoomKey = yield this.roomsCache.getKey(this.sessionType, roomData.roomToken);
|
||||
let fallback = false;
|
||||
let key;
|
||||
|
||||
try {
|
||||
key = yield this.promiseDecryptRoomKey(roomData.context.wrappedKey);
|
||||
} catch (error) {
|
||||
// If we don't have a key saved, then we can't do anything.
|
||||
if (!savedRoomKey) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
// We failed to decrypt the room key, so has our FxA key changed?
|
||||
// If so, we fall-back to the saved room key.
|
||||
key = savedRoomKey;
|
||||
fallback = true;
|
||||
}
|
||||
|
||||
let decryptedData = yield loopCrypto.decryptBytes(key, roomData.context.value);
|
||||
|
||||
if (fallback) {
|
||||
// Fallback decryption succeeded, so we need to re-encrypt the room key and
|
||||
// save the data back again.
|
||||
// XXX Bug 1152764 will implement this or make it a separate bug.
|
||||
} else if (!savedRoomKey || key != savedRoomKey) {
|
||||
// Decryption succeeded, but we don't have the right key saved.
|
||||
try {
|
||||
yield this.roomsCache.setKey(this.sessionType, roomData.roomToken, key);
|
||||
}
|
||||
catch (error) {
|
||||
MozLoopService.log.error("Failed to save room key:", error);
|
||||
}
|
||||
}
|
||||
|
||||
roomData.roomKey = key;
|
||||
roomData.decryptedContext = JSON.parse(decryptedData);
|
||||
|
||||
@ -337,11 +379,11 @@ let LoopRoomsInternal = {
|
||||
|
||||
this.saveAndNotifyUpdate(roomData, isUpdate);
|
||||
} catch (error) {
|
||||
MozLoopService.log.error("Failed to decrypt room data: " + error);
|
||||
MozLoopService.log.error("Failed to decrypt room data: ", error);
|
||||
// Do what we can to save the room data.
|
||||
room.decryptedContext = {};
|
||||
this.saveAndNotifyUpdate(room, isUpdate);
|
||||
};
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
@ -490,6 +532,9 @@ let LoopRoomsInternal = {
|
||||
this.setGuestCreatedRoom(true);
|
||||
}
|
||||
|
||||
// Now we've got the room token, we can save the key to disk.
|
||||
yield this.roomsCache.setKey(this.sessionType, room.roomToken, room.roomKey);
|
||||
|
||||
eventEmitter.emit("add", room);
|
||||
callback(null, room);
|
||||
}.bind(this)).catch(callback);
|
||||
@ -700,6 +745,10 @@ let LoopRoomsInternal = {
|
||||
sendData = {
|
||||
roomName: newRoomName
|
||||
};
|
||||
} else {
|
||||
// This might be an upgrade to encrypted rename, so store the key
|
||||
// just in case.
|
||||
yield this.roomsCache.setKey(this.sessionType, all.roomToken, all.roomKey);
|
||||
}
|
||||
|
||||
let response = yield MozLoopService.hawkRequest(this.sessionType,
|
||||
@ -727,8 +776,12 @@ let LoopRoomsInternal = {
|
||||
return;
|
||||
}
|
||||
|
||||
let oldDirty = gDirty;
|
||||
gDirty = true;
|
||||
this.getAll(version, () => {});
|
||||
// If we were already dirty, then get the full set of rooms. For example,
|
||||
// we'd already be dirty if we had started up but not got the list of rooms
|
||||
// yet.
|
||||
this.getAll(oldDirty ? null : version, () => {});
|
||||
},
|
||||
|
||||
/**
|
||||
|
159
browser/components/loop/modules/LoopRoomsCache.jsm
Normal file
159
browser/components/loop/modules/LoopRoomsCache.jsm
Normal file
@ -0,0 +1,159 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
const {MozLoopService, LOOP_SESSION_TYPE} =
|
||||
Cu.import("resource:///modules/loop/MozLoopService.jsm", {});
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "CommonUtils",
|
||||
"resource://services-common/utils.js");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["LoopRoomsCache"];
|
||||
|
||||
const LOOP_ROOMS_CACHE_FILENAME = "loopRoomsCache.json";
|
||||
|
||||
/**
|
||||
* RoomsCache is a cache for saving simple rooms data to the disk in case we
|
||||
* need it for back-up purposes, e.g. recording room keys for FxA if the user
|
||||
* changes their password.
|
||||
*
|
||||
* The format of the data is:
|
||||
*
|
||||
* {
|
||||
* <sessionType>: {
|
||||
* <roomToken>: {
|
||||
* "key": <roomKey>
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* It is intended to try and keep the data forward and backwards compatible in
|
||||
* a reasonable manner, hence why the structure is more complex than it needs
|
||||
* to be to store tokens and keys.
|
||||
*
|
||||
* @param {Object} options The options for the RoomsCache, containing:
|
||||
* - {String} baseDir The base directory in which to save the file.
|
||||
* - {String} filename The filename for the cache file.
|
||||
*/
|
||||
function LoopRoomsCache(options) {
|
||||
options = options || {};
|
||||
|
||||
this.baseDir = options.baseDir || OS.Constants.Path.profileDir;
|
||||
this.path = OS.Path.join(
|
||||
this.baseDir,
|
||||
options.filename || LOOP_ROOMS_CACHE_FILENAME
|
||||
);
|
||||
this._cache = null;
|
||||
}
|
||||
|
||||
LoopRoomsCache.prototype = {
|
||||
/**
|
||||
* Updates the local copy of the cache and saves it to disk.
|
||||
*
|
||||
* @param {Object} contents An object to be saved in json format.
|
||||
* @return {Promise} A promise that is resolved once the save is complete.
|
||||
*/
|
||||
_setCache: function(contents) {
|
||||
this._cache = contents;
|
||||
|
||||
return OS.File.makeDir(this.baseDir, {ignoreExisting: true}).then(() => {
|
||||
return CommonUtils.writeJSON(contents, this.path);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the local copy of the cache if there is one, otherwise it reads
|
||||
* it from the disk.
|
||||
*
|
||||
* @return {Promise} A promise that is resolved once the read is complete.
|
||||
*/
|
||||
_getCache: Task.async(function* () {
|
||||
if (this._cache) {
|
||||
return this._cache;
|
||||
}
|
||||
|
||||
try {
|
||||
return (this._cache = yield CommonUtils.readJSON(this.path));
|
||||
} catch(error) {
|
||||
// This is really complex due to OSFile's error handling, see bug 1160109.
|
||||
if ((OS.Constants.libc && error.unixErrno != OS.Constants.libc.ENOENT) ||
|
||||
(OS.Constants.Win && error.winLastError != OS.Constants.Win.ERROR_FILE_NOT_FOUND)) {
|
||||
MozLoopService.log.debug("Error reading the cache:", error);
|
||||
}
|
||||
return (this._cache = {});
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Function for testability purposes. Clears the cache.
|
||||
*
|
||||
* @return {Promise} A promise that is resolved once the clear is complete.
|
||||
*/
|
||||
clear: function() {
|
||||
this._cache = null;
|
||||
return OS.File.remove(this.path);
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets a room key from the cache.
|
||||
*
|
||||
* @param {LOOP_SESSION_TYPE} sessionType The session type for the room.
|
||||
* @param {String} roomToken The token for the room.
|
||||
* @return {Promise} A promise that is resolved when the data has been read
|
||||
* with the value of the key, or null if it isn't present.
|
||||
*/
|
||||
getKey: Task.async(function* (sessionType, roomToken) {
|
||||
if (sessionType != LOOP_SESSION_TYPE.FXA) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let sessionData = (yield this._getCache())[sessionType];
|
||||
|
||||
if (!sessionData || !sessionData[roomToken]) {
|
||||
return null;
|
||||
}
|
||||
return sessionData[roomToken].key;
|
||||
}),
|
||||
|
||||
/**
|
||||
* Stores a room key into the cache. Note, if the key has not changed,
|
||||
* the store will not be re-written.
|
||||
*
|
||||
* @param {LOOP_SESSION_TYPE} sessionType The session type for the room.
|
||||
* @param {String} roomToken The token for the room.
|
||||
* @param {String} roomKey The encryption key for the room.
|
||||
* @return {Promise} A promise that is resolved when the data has been stored.
|
||||
*/
|
||||
setKey: Task.async(function* (sessionType, roomToken, roomKey) {
|
||||
if (sessionType != LOOP_SESSION_TYPE.FXA) {
|
||||
return;
|
||||
}
|
||||
|
||||
let cache = yield this._getCache();
|
||||
|
||||
// Create these objects if they don't exist.
|
||||
// We aim to do this creation and setting of the room key in a
|
||||
// forwards-compatible way so that if new fields are added to rooms later
|
||||
// then we don't mess them up (if there's no keys).
|
||||
if (!cache[sessionType]) {
|
||||
cache[sessionType] = {};
|
||||
}
|
||||
|
||||
if (!cache[sessionType][roomToken]) {
|
||||
cache[sessionType][roomToken] = {};
|
||||
}
|
||||
|
||||
// Only save it if there's no key, or it is different.
|
||||
if (!cache[sessionType][roomToken].key ||
|
||||
cache[sessionType][roomToken].key != roomKey) {
|
||||
cache[sessionType][roomToken].key = roomKey;
|
||||
return yield this._setCache(cache);
|
||||
}
|
||||
})
|
||||
};
|
@ -10,7 +10,7 @@ Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Timer.jsm");
|
||||
|
||||
const {MozLoopService} = Cu.import("resource:///modules/loop/MozLoopService.jsm", {});
|
||||
const { MozLoopService } = Cu.import("resource:///modules/loop/MozLoopService.jsm", {});
|
||||
const consoleLog = MozLoopService.log;
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["MozLoopPushHandler"];
|
||||
@ -296,7 +296,7 @@ PingMonitor.prototype = {
|
||||
restart: function () {
|
||||
consoleLog.info("PushHandler: ping timeout restart");
|
||||
this.stop();
|
||||
this._pingTimerID = setTimeout(() => {this._pingSend()}, this._pingInterval);
|
||||
this._pingTimerID = setTimeout(() => { this._pingSend(); }, this._pingInterval);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -503,7 +503,7 @@ let MozLoopPushHandler = {
|
||||
this._channelsToRegister.push(channelID);
|
||||
this._registerChannels();
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Un-register a notification channel.
|
||||
*
|
||||
@ -771,14 +771,14 @@ let MozLoopPushHandler = {
|
||||
(aMsg) => this._onMsg(aMsg),
|
||||
() => this._onStart(),
|
||||
(aCode, aReason) => this._onClose(aCode, aReason));
|
||||
}
|
||||
};
|
||||
|
||||
let pushServerURLFetchError = () => {
|
||||
consoleLog.warn("PushHandler: Could not retrieve push server URL from Loop server, will retry");
|
||||
this._pushSocket = undefined;
|
||||
this._retryManager.retry(() => this._openSocket());
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
this.pushServerUri = Services.prefs.getCharPref("loop.debug.pushserver");
|
||||
@ -871,4 +871,4 @@ let MozLoopPushHandler = {
|
||||
channelID: channelID});
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
@ -64,7 +64,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "injectLoopAPI",
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "convertToRTCStatsReport",
|
||||
"resource://gre/modules/media/RTCStatsReport.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "loopUtils",
|
||||
"resource:///modules/loop/utils.js", "utils")
|
||||
"resource:///modules/loop/utils.js", "utils");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "loopCrypto",
|
||||
"resource:///modules/loop/crypto.js", "LoopCrypto");
|
||||
|
||||
@ -170,12 +170,12 @@ let MozLoopServiceInternal = {
|
||||
deferredRegistrations: new Map(),
|
||||
|
||||
get pushHandler() {
|
||||
return this.mocks.pushHandler || MozLoopPushHandler
|
||||
return this.mocks.pushHandler || MozLoopPushHandler;
|
||||
},
|
||||
|
||||
// The uri of the Loop server.
|
||||
get loopServerUri() {
|
||||
return Services.prefs.getCharPref("loop.server")
|
||||
return Services.prefs.getCharPref("loop.server");
|
||||
},
|
||||
|
||||
/**
|
||||
@ -365,7 +365,7 @@ let MozLoopServiceInternal = {
|
||||
} else {
|
||||
resolve(this.registerWithLoopServer(sessionType, serviceType, pushURL));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.pushHandler.register(channelID, onRegistered, onNotification);
|
||||
});
|
||||
@ -443,7 +443,7 @@ let MozLoopServiceInternal = {
|
||||
|
||||
// Create a blank URL record set if none exists for this sessionType.
|
||||
if (!pushURLs) {
|
||||
pushURLs = {calls: undefined, rooms: undefined};
|
||||
pushURLs = { calls: undefined, rooms: undefined };
|
||||
this.pushURLs.set(sessionType, pushURLs);
|
||||
}
|
||||
|
||||
@ -456,7 +456,7 @@ let MozLoopServiceInternal = {
|
||||
newURLs[serviceType] = pushURL;
|
||||
|
||||
return this.hawkRequestInternal(sessionType, "/registration", "POST",
|
||||
{simplePushURLs: newURLs}).then(
|
||||
{ simplePushURLs: newURLs }).then(
|
||||
(response) => {
|
||||
// If this failed we got an invalid token.
|
||||
if (!this.storeSessionToken(sessionType, response.headers)) {
|
||||
@ -533,7 +533,7 @@ let MozLoopServiceInternal = {
|
||||
log.error("Failed to unregister with the loop server. Error: ", error);
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return Promise.all([unregister(sessionType, callsPushURL), unregister(sessionType, roomsPushURL)]);
|
||||
},
|
||||
@ -584,7 +584,7 @@ let MozLoopServiceInternal = {
|
||||
} else {
|
||||
newPayloadObj[property] = payloadObj[property];
|
||||
}
|
||||
};
|
||||
}
|
||||
payloadObj = newPayloadObj;
|
||||
}
|
||||
|
||||
@ -804,7 +804,7 @@ let MozLoopServiceInternal = {
|
||||
log.info(e.data.ok ?
|
||||
"Successfully staged loop report for telemetry upload." :
|
||||
("Failed to stage loop report. Error: " + e.data.fail));
|
||||
}
|
||||
};
|
||||
worker.postMessage(job);
|
||||
});
|
||||
}, pc.id);
|
||||
@ -942,7 +942,7 @@ let MozLoopServiceInternal = {
|
||||
|
||||
return JSON.parse(response.body);
|
||||
},
|
||||
error => {this._hawkRequestError(error);});
|
||||
error => { this._hawkRequestError(error); });
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1025,7 +1025,7 @@ let MozLoopServiceInternal = {
|
||||
return this.hawkRequestInternal(LOOP_SESSION_TYPE.FXA, "/fxa-oauth/token", "POST", payload).then(response => {
|
||||
return JSON.parse(response.body);
|
||||
},
|
||||
error => {this._hawkRequestError(error);});
|
||||
error => { this._hawkRequestError(error); });
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1689,7 +1689,7 @@ this.MozLoopService = {
|
||||
*/
|
||||
hawkRequest: function(sessionType, path, method, payloadObj) {
|
||||
return MozLoopServiceInternal.hawkRequest(sessionType, path, method, payloadObj).catch(
|
||||
error => {MozLoopServiceInternal._hawkRequestError(error);});
|
||||
error => { MozLoopServiceInternal._hawkRequestError(error); });
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -20,6 +20,7 @@ EXTRA_JS_MODULES.loop += [
|
||||
'modules/LoopCalls.jsm',
|
||||
'modules/LoopContacts.jsm',
|
||||
'modules/LoopRooms.jsm',
|
||||
'modules/LoopRoomsCache.jsm',
|
||||
'modules/LoopStorage.jsm',
|
||||
'modules/MozLoopAPI.jsm',
|
||||
'modules/MozLoopPushHandler.jsm',
|
||||
|
@ -58,7 +58,7 @@ loop.standaloneMedia = (function() {
|
||||
if (typeof cb == "function") {
|
||||
cb(param);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
function handleSuccess(localStream) {
|
||||
this.userMedia.pending = false;
|
||||
@ -134,7 +134,7 @@ loop.standaloneMedia = (function() {
|
||||
// This function is needed to pull in the instance
|
||||
// of the singleton for tests to overwrite the used instance.
|
||||
singletonMultiplexGum.getPermsAndCacheMedia.apply(singletonMultiplexGum, arguments);
|
||||
};
|
||||
}
|
||||
patchSymbolIfExtant("navigator", "mozGetUserMedia", myGetUserMedia);
|
||||
patchSymbolIfExtant("navigator", "webkitGetUserMedia", myGetUserMedia);
|
||||
patchSymbolIfExtant("navigator", "getUserMedia", myGetUserMedia);
|
||||
|
@ -36,7 +36,7 @@ loop.store.StandaloneMetricsStore = (function() {
|
||||
pageLoad: "page load messages",
|
||||
success: "success",
|
||||
support: "support link click"
|
||||
}
|
||||
};
|
||||
|
||||
var StandaloneMetricsStore = loop.store.createStore({
|
||||
actions: [
|
||||
@ -132,7 +132,7 @@ loop.store.StandaloneMetricsStore = (function() {
|
||||
*/
|
||||
mediaConnected: function() {
|
||||
this._storeEvent(METRICS_GA_CATEGORY.general, METRICS_GA_ACTIONS.success,
|
||||
"Media connected")
|
||||
"Media connected");
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -215,7 +215,7 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
if (event.target && event.target.href) {
|
||||
this.props.dispatcher.dispatch(new sharedActions.RecordClick({
|
||||
linkInfo: event.target.href
|
||||
}))
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
@ -288,7 +288,7 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
getInitialState: function() {
|
||||
return {
|
||||
failureLogged: false
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
_logFailure: function(message) {
|
||||
|
@ -215,7 +215,7 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
if (event.target && event.target.href) {
|
||||
this.props.dispatcher.dispatch(new sharedActions.RecordClick({
|
||||
linkInfo: event.target.href
|
||||
}))
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
@ -288,7 +288,7 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
getInitialState: function() {
|
||||
return {
|
||||
failureLogged: false
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
_logFailure: function(message) {
|
||||
|
@ -680,6 +680,6 @@ describe("loop.roomViews", function () {
|
||||
React.addons.TestUtils.Simulate.click(closeBtn);
|
||||
expect(view.getDOMNode()).to.eql(null);
|
||||
});
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -9,7 +9,7 @@ const kAuth = {
|
||||
"method": "basic",
|
||||
"user": "username",
|
||||
"password": "p455w0rd"
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// "pid" for "provider ID"
|
||||
@ -166,7 +166,7 @@ const monkeyPatchImporter = function(importer) {
|
||||
});
|
||||
}.bind(importer);
|
||||
return importer;
|
||||
}
|
||||
};
|
||||
|
||||
add_task(function* test_CardDavImport() {
|
||||
let importer = monkeyPatchImporter(new CardDavImporter());
|
||||
@ -323,4 +323,4 @@ add_task(function* test_CardDavImport() {
|
||||
}, (err, result) => { err ? resolve(err) : reject(new Error("Should have failed")); }, mockDb);
|
||||
});
|
||||
Assert.equal(error.message, "No authentication specified", "Missing parameters should generate error");
|
||||
})
|
||||
});
|
||||
|
@ -106,7 +106,7 @@ const normalizeContact = function(contact) {
|
||||
// Get a copy of contact without private properties.
|
||||
for (let prop of Object.getOwnPropertyNames(contact)) {
|
||||
if (!prop.startsWith("_")) {
|
||||
result[prop] = contact[prop]
|
||||
result[prop] = contact[prop];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@ -189,7 +189,7 @@ add_task(function* () {
|
||||
Assert.ok(!err, "There shouldn't be an error");
|
||||
Assert.equal(found.length, 0, "There shouldn't be any contacts left");
|
||||
resolve();
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -33,7 +33,7 @@ function promiseWindowIdReceivedOnAdd(handler) {
|
||||
handler.resolve = resolve;
|
||||
gMozLoopAPI.addBrowserSharingListener(handler.listener);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
let createdTabs = [];
|
||||
|
||||
@ -52,7 +52,7 @@ function promiseWindowIdReceivedNewTab(handlers = []) {
|
||||
promiseHandlers.push(promiseTabLoadEvent(createdTab, "about:mozilla"));
|
||||
|
||||
return Promise.all(promiseHandlers);
|
||||
};
|
||||
}
|
||||
|
||||
function promiseRemoveTab(tab) {
|
||||
return new Promise(resolve => {
|
||||
@ -170,7 +170,7 @@ add_task(function* test_infoBar() {
|
||||
"The popup should be opening anchored to the dropmarker");
|
||||
Assert.strictEqual(button.getElementsByTagNameNS(kNSXUL, "menupopup").length, 1,
|
||||
"There should be a popup attached to the button");
|
||||
}
|
||||
};
|
||||
|
||||
testBarProps();
|
||||
|
||||
|
@ -19,9 +19,9 @@ describe("loop.OTSdkDriver", function () {
|
||||
beforeEach(function() {
|
||||
sandbox = sinon.sandbox.create();
|
||||
|
||||
fakeLocalElement = {fake: 1};
|
||||
fakeRemoteElement = {fake: 2};
|
||||
fakeScreenElement = {fake: 3};
|
||||
fakeLocalElement = { fake: 1 };
|
||||
fakeRemoteElement = { fake: 2 };
|
||||
fakeScreenElement = { fake: 3 };
|
||||
fakeEvent = {
|
||||
preventDefault: sinon.stub()
|
||||
};
|
||||
@ -98,7 +98,7 @@ describe("loop.OTSdkDriver", function () {
|
||||
describe("Constructor", function() {
|
||||
it("should throw an error if the dispatcher is missing", function() {
|
||||
expect(function() {
|
||||
new loop.OTSdkDriver({sdk: sdk});
|
||||
new loop.OTSdkDriver({ sdk: sdk });
|
||||
}).to.Throw(/dispatcher/);
|
||||
});
|
||||
|
||||
@ -112,8 +112,8 @@ describe("loop.OTSdkDriver", function () {
|
||||
describe("#setupStreamElements", function() {
|
||||
it("should call initPublisher", function() {
|
||||
driver.setupStreamElements(new sharedActions.SetupStreamElements({
|
||||
getLocalElementFunc: function() {return fakeLocalElement;},
|
||||
getRemoteElementFunc: function() {return fakeRemoteElement;},
|
||||
getLocalElementFunc: function() { return fakeLocalElement; },
|
||||
getRemoteElementFunc: function() { return fakeRemoteElement; },
|
||||
publisherConfig: publisherConfig
|
||||
}));
|
||||
|
||||
@ -127,8 +127,8 @@ describe("loop.OTSdkDriver", function () {
|
||||
sdk.initPublisher.returns(publisher);
|
||||
|
||||
driver.setupStreamElements(new sharedActions.SetupStreamElements({
|
||||
getLocalElementFunc: function() {return fakeLocalElement;},
|
||||
getRemoteElementFunc: function() {return fakeRemoteElement;},
|
||||
getLocalElementFunc: function() { return fakeLocalElement; },
|
||||
getRemoteElementFunc: function() { return fakeRemoteElement; },
|
||||
publisherConfig: publisherConfig
|
||||
}));
|
||||
});
|
||||
@ -158,8 +158,8 @@ describe("loop.OTSdkDriver", function () {
|
||||
sdk.initPublisher.returns(publisher);
|
||||
|
||||
driver.setupStreamElements(new sharedActions.SetupStreamElements({
|
||||
getLocalElementFunc: function() {return fakeLocalElement;},
|
||||
getRemoteElementFunc: function() {return fakeRemoteElement;},
|
||||
getLocalElementFunc: function() { return fakeLocalElement; },
|
||||
getRemoteElementFunc: function() { return fakeRemoteElement; },
|
||||
publisherConfig: publisherConfig
|
||||
}));
|
||||
});
|
||||
@ -604,9 +604,9 @@ describe("loop.OTSdkDriver", function () {
|
||||
driver.connectSession(sessionData);
|
||||
|
||||
driver.setupStreamElements(new sharedActions.SetupStreamElements({
|
||||
getLocalElementFunc: function() {return fakeLocalElement;},
|
||||
getScreenShareElementFunc: function() {return fakeScreenElement;},
|
||||
getRemoteElementFunc: function() {return fakeRemoteElement;},
|
||||
getLocalElementFunc: function() {return fakeLocalElement; },
|
||||
getScreenShareElementFunc: function() {return fakeScreenElement; },
|
||||
getRemoteElementFunc: function() {return fakeRemoteElement; },
|
||||
publisherConfig: publisherConfig
|
||||
}));
|
||||
});
|
||||
@ -732,7 +732,7 @@ describe("loop.OTSdkDriver", function () {
|
||||
});
|
||||
|
||||
it("should dispatch a VideoDimensionsChanged action", function() {
|
||||
publisher.trigger("streamCreated", {stream: fakeStream});
|
||||
publisher.trigger("streamCreated", { stream: fakeStream });
|
||||
|
||||
sinon.assert.called(dispatcher.dispatch);
|
||||
sinon.assert.calledWithExactly(dispatcher.dispatch,
|
||||
@ -773,21 +773,21 @@ describe("loop.OTSdkDriver", function () {
|
||||
});
|
||||
|
||||
it("should dispatch a VideoDimensionsChanged action", function() {
|
||||
session.trigger("streamCreated", {stream: fakeStream});
|
||||
session.trigger("streamCreated", { stream: fakeStream });
|
||||
|
||||
sinon.assert.called(dispatcher.dispatch);
|
||||
sinon.assert.calledWithExactly(dispatcher.dispatch,
|
||||
new sharedActions.VideoDimensionsChanged({
|
||||
isLocal: false,
|
||||
videoType: "camera",
|
||||
dimensions: {width: 1, height: 2}
|
||||
dimensions: { width: 1, height: 2 }
|
||||
}));
|
||||
});
|
||||
|
||||
it("should dispatch a ConnectionStatus action", function() {
|
||||
driver._metrics.connections = 1;
|
||||
|
||||
session.trigger("streamCreated", {stream: fakeStream});
|
||||
session.trigger("streamCreated", { stream: fakeStream });
|
||||
|
||||
sinon.assert.called(dispatcher.dispatch);
|
||||
sinon.assert.calledWithExactly(dispatcher.dispatch,
|
||||
@ -801,7 +801,7 @@ describe("loop.OTSdkDriver", function () {
|
||||
});
|
||||
|
||||
it("should subscribe to a camera stream", function() {
|
||||
session.trigger("streamCreated", {stream: fakeStream});
|
||||
session.trigger("streamCreated", { stream: fakeStream });
|
||||
|
||||
sinon.assert.calledOnce(session.subscribe);
|
||||
sinon.assert.calledWithExactly(session.subscribe,
|
||||
@ -811,7 +811,7 @@ describe("loop.OTSdkDriver", function () {
|
||||
it("should subscribe to a screen sharing stream", function() {
|
||||
fakeStream.videoType = "screen";
|
||||
|
||||
session.trigger("streamCreated", {stream: fakeStream});
|
||||
session.trigger("streamCreated", { stream: fakeStream });
|
||||
|
||||
sinon.assert.calledOnce(session.subscribe);
|
||||
sinon.assert.calledWithExactly(session.subscribe,
|
||||
@ -821,7 +821,7 @@ describe("loop.OTSdkDriver", function () {
|
||||
it("should dispatch a mediaConnected action if both streams are up", function() {
|
||||
driver._publishedLocalStream = true;
|
||||
|
||||
session.trigger("streamCreated", {stream: fakeStream});
|
||||
session.trigger("streamCreated", { stream: fakeStream });
|
||||
|
||||
// Called twice due to the VideoDimensionsChanged above.
|
||||
sinon.assert.called(dispatcher.dispatch);
|
||||
@ -836,19 +836,19 @@ describe("loop.OTSdkDriver", function () {
|
||||
var startTime = 1;
|
||||
sandbox.stub(performance, "now").returns(startTime);
|
||||
|
||||
session.trigger("streamCreated", {stream: fakeStream});
|
||||
session.trigger("streamCreated", { stream: fakeStream });
|
||||
|
||||
expect(driver._getTwoWayMediaStartTime()).to.eql(startTime);
|
||||
});
|
||||
|
||||
it("should not store the start time when both streams are up and" +
|
||||
" driver._isDesktop is false", function() {
|
||||
driver._isDesktop = false ;
|
||||
driver._isDesktop = false;
|
||||
driver._publishedLocalStream = true;
|
||||
var startTime = 73;
|
||||
sandbox.stub(performance, "now").returns(startTime);
|
||||
|
||||
session.trigger("streamCreated", {stream: fakeStream});
|
||||
session.trigger("streamCreated", { stream: fakeStream });
|
||||
|
||||
expect(driver._getTwoWayMediaStartTime()).to.not.eql(startTime);
|
||||
});
|
||||
@ -859,7 +859,7 @@ describe("loop.OTSdkDriver", function () {
|
||||
driver._publishedLocalStream = true;
|
||||
fakeStream.videoType = "screen";
|
||||
|
||||
session.trigger("streamCreated", {stream: fakeStream});
|
||||
session.trigger("streamCreated", { stream: fakeStream });
|
||||
|
||||
sinon.assert.neverCalledWithMatch(dispatcher.dispatch,
|
||||
sinon.match.hasOwn("name", "mediaConnected"));
|
||||
@ -877,12 +877,12 @@ describe("loop.OTSdkDriver", function () {
|
||||
function() {
|
||||
fakeStream.videoType = "screen";
|
||||
|
||||
session.trigger("streamCreated", {stream: fakeStream});
|
||||
session.trigger("streamCreated", { stream: fakeStream });
|
||||
|
||||
// Called twice due to the VideoDimensionsChanged above.
|
||||
sinon.assert.called(dispatcher.dispatch);
|
||||
sinon.assert.calledWithExactly(dispatcher.dispatch,
|
||||
new sharedActions.ReceivingScreenShare({receiving: true}));
|
||||
new sharedActions.ReceivingScreenShare({ receiving: true }));
|
||||
});
|
||||
});
|
||||
|
||||
@ -916,7 +916,7 @@ describe("loop.OTSdkDriver", function () {
|
||||
});
|
||||
|
||||
it("should dispatch a ReceivingScreenShare action", function() {
|
||||
session.trigger("streamDestroyed", {stream: fakeStream});
|
||||
session.trigger("streamDestroyed", { stream: fakeStream });
|
||||
|
||||
sinon.assert.called(dispatcher.dispatch);
|
||||
sinon.assert.calledWithExactly(dispatcher.dispatch,
|
||||
@ -946,7 +946,7 @@ describe("loop.OTSdkDriver", function () {
|
||||
it("should not dispatch an action if the videoType is camera", function() {
|
||||
fakeStream.videoType = "camera";
|
||||
|
||||
session.trigger("streamDestroyed", {stream: fakeStream});
|
||||
session.trigger("streamDestroyed", { stream: fakeStream });
|
||||
|
||||
sinon.assert.neverCalledWithMatch(dispatcher.dispatch,
|
||||
sinon.match.hasOwn("name", "receivingScreenShare"));
|
||||
@ -1001,7 +1001,7 @@ describe("loop.OTSdkDriver", function () {
|
||||
it("should dispatch a RemotePeerConnected action if this is for a remote user",
|
||||
function() {
|
||||
session.trigger("connectionCreated", {
|
||||
connection: {id: "remoteUser"}
|
||||
connection: { id: "remoteUser" }
|
||||
});
|
||||
|
||||
sinon.assert.called(dispatcher.dispatch);
|
||||
@ -1011,7 +1011,7 @@ describe("loop.OTSdkDriver", function () {
|
||||
|
||||
it("should store the connection details for a remote user", function() {
|
||||
session.trigger("connectionCreated", {
|
||||
connection: {id: "remoteUser"}
|
||||
connection: { id: "remoteUser" }
|
||||
});
|
||||
|
||||
expect(driver.connections).to.include.keys("remoteUser");
|
||||
@ -1022,7 +1022,7 @@ describe("loop.OTSdkDriver", function () {
|
||||
driver._metrics.sendStreams = 1;
|
||||
|
||||
session.trigger("connectionCreated", {
|
||||
connection: {id: "remoteUser"}
|
||||
connection: { id: "remoteUser" }
|
||||
});
|
||||
|
||||
sinon.assert.called(dispatcher.dispatch);
|
||||
@ -1039,7 +1039,7 @@ describe("loop.OTSdkDriver", function () {
|
||||
it("should not dispatch an RemotePeerConnected action if this is for a local user",
|
||||
function() {
|
||||
session.trigger("connectionCreated", {
|
||||
connection: {id: "localUser"}
|
||||
connection: { id: "localUser" }
|
||||
});
|
||||
|
||||
sinon.assert.neverCalledWithMatch(dispatcher.dispatch,
|
||||
@ -1048,7 +1048,7 @@ describe("loop.OTSdkDriver", function () {
|
||||
|
||||
it("should not store the connection details for a local user", function() {
|
||||
session.trigger("connectionCreated", {
|
||||
connection: {id: "localUser"}
|
||||
connection: { id: "localUser" }
|
||||
});
|
||||
|
||||
expect(driver.connections).to.not.include.keys("localUser");
|
||||
@ -1059,7 +1059,7 @@ describe("loop.OTSdkDriver", function () {
|
||||
driver._metrics.sendStreams = 0;
|
||||
|
||||
session.trigger("connectionCreated", {
|
||||
connection: {id: "localUser"}
|
||||
connection: { id: "localUser" }
|
||||
});
|
||||
|
||||
sinon.assert.called(dispatcher.dispatch);
|
||||
|
@ -92,7 +92,7 @@ describe("loop.store.StandaloneMetricsStore", function() {
|
||||
sinon.assert.calledWithExactly(window.ga,
|
||||
"send", "event", METRICS_GA_CATEGORY.general, METRICS_GA_ACTIONS.linkClick,
|
||||
"fake");
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
describe("Store Change Handlers", function() {
|
||||
|
@ -249,7 +249,7 @@ describe("loop.standaloneRoomViews", function() {
|
||||
local: {},
|
||||
remote: {}
|
||||
});
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
describe("#publishStream", function() {
|
||||
|
@ -94,7 +94,7 @@ describe("loop.StandaloneClient", function() {
|
||||
sinon.assert.calledWithExactly(console.error, "Server error",
|
||||
"HTTP 404 Not Found", serverResponse);
|
||||
});
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
@ -5,6 +5,9 @@
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
// Initialize this before the imports, as some of them need it.
|
||||
do_get_profile();
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Http.jsm");
|
||||
@ -13,7 +16,9 @@ Cu.import("resource:///modules/loop/MozLoopService.jsm");
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource:///modules/loop/LoopCalls.jsm");
|
||||
Cu.import("resource:///modules/loop/LoopRooms.jsm");
|
||||
Cu.import("resource://gre/modules/osfile.jsm");
|
||||
const { MozLoopServiceInternal } = Cu.import("resource:///modules/loop/MozLoopService.jsm", {});
|
||||
const { LoopRoomsInternal } = Cu.import("resource:///modules/loop/LoopRooms.jsm", {});
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "MozLoopPushHandler",
|
||||
"resource:///modules/loop/MozLoopPushHandler.jsm");
|
||||
@ -135,7 +140,7 @@ let mockPushHandler = {
|
||||
* enables us to check parameters and return messages similar to the push
|
||||
* server.
|
||||
*/
|
||||
function MockWebSocketChannel() {};
|
||||
function MockWebSocketChannel() {}
|
||||
|
||||
MockWebSocketChannel.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI(Ci.nsIWebSocketChannel),
|
||||
@ -211,3 +216,10 @@ MockWebSocketChannel.prototype = {
|
||||
this.listener.onServerClose(this.context, err || -1);
|
||||
},
|
||||
};
|
||||
|
||||
const extend = function(target, source) {
|
||||
for (let key of Object.getOwnPropertyNames(source)) {
|
||||
target[key] = source[key];
|
||||
}
|
||||
return target;
|
||||
};
|
||||
|
@ -33,7 +33,7 @@ function generateSessionTypeVerificationStub(desiredSessionType) {
|
||||
|
||||
resolve();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
return hawkRequestStub;
|
||||
}
|
||||
|
@ -130,10 +130,10 @@ add_test(function test_ping_websocket() {
|
||||
mockWebSocket.defaultMsgHandler = (msg) => {
|
||||
pingReceived = true;
|
||||
// Do not send a ping response.
|
||||
}
|
||||
};
|
||||
mockWebSocket.close = () => {
|
||||
socketClosed = true;
|
||||
}
|
||||
};
|
||||
|
||||
MozLoopPushHandler.shutdown();
|
||||
MozLoopPushHandler.initialize({mockWebSocket: mockWebSocket});
|
||||
@ -220,4 +220,4 @@ function run_test() {
|
||||
});
|
||||
|
||||
run_next_test();
|
||||
};
|
||||
}
|
||||
|
@ -182,13 +182,6 @@ const kCreateRoomData = {
|
||||
const kChannelGuest = MozLoopService.channelIDs.roomsGuest;
|
||||
const kChannelFxA = MozLoopService.channelIDs.roomsFxA;
|
||||
|
||||
const extend = function(target, source) {
|
||||
for (let key of Object.getOwnPropertyNames(source)) {
|
||||
target[key] = source[key];
|
||||
}
|
||||
return target;
|
||||
};
|
||||
|
||||
const normalizeRoom = function(room) {
|
||||
let newRoom = extend({}, room);
|
||||
let name = newRoom.decryptedContext.roomName;
|
||||
@ -470,33 +463,38 @@ add_task(function* test_roomUpdates() {
|
||||
"781f012b-f1ea-4ce1-9105-7cfc36fb4ec7"
|
||||
];
|
||||
roomsPushNotification("1", kChannelGuest);
|
||||
yield waitForCondition(() => Object.getOwnPropertyNames(gExpectedLeaves).length === 0);
|
||||
yield waitForCondition(() => Object.getOwnPropertyNames(gExpectedLeaves).length === 0 &&
|
||||
gExpectedUpdates.length === 0);
|
||||
|
||||
gExpectedUpdates.push("_nxD4V4FflQ");
|
||||
gExpectedJoins["_nxD4V4FflQ"] = ["2a1787a6-4a73-43b5-ae3e-906ec1e763cb"];
|
||||
roomsPushNotification("2", kChannelGuest);
|
||||
yield waitForCondition(() => Object.getOwnPropertyNames(gExpectedJoins).length === 0);
|
||||
yield waitForCondition(() => Object.getOwnPropertyNames(gExpectedJoins).length === 0 &&
|
||||
gExpectedUpdates.length === 0);
|
||||
|
||||
gExpectedUpdates.push("_nxD4V4FflQ");
|
||||
gExpectedJoins["_nxD4V4FflQ"] = ["781f012b-f1ea-4ce1-9105-7cfc36fb4ec7"];
|
||||
gExpectedLeaves["_nxD4V4FflQ"] = ["2a1787a6-4a73-43b5-ae3e-906ec1e763cb"];
|
||||
roomsPushNotification("3", kChannelGuest);
|
||||
yield waitForCondition(() => Object.getOwnPropertyNames(gExpectedLeaves).length === 0);
|
||||
yield waitForCondition(() => Object.getOwnPropertyNames(gExpectedLeaves).length === 0 &&
|
||||
Object.getOwnPropertyNames(gExpectedJoins).length === 0 &&
|
||||
gExpectedUpdates.length === 0);
|
||||
|
||||
gExpectedUpdates.push("_nxD4V4FflQ");
|
||||
gExpectedJoins["_nxD4V4FflQ"] = [
|
||||
"2a1787a6-4a73-43b5-ae3e-906ec1e763cb",
|
||||
"5de6281c-6568-455f-af08-c0b0a973100e"];
|
||||
roomsPushNotification("4", kChannelGuest);
|
||||
yield waitForCondition(() => Object.getOwnPropertyNames(gExpectedJoins).length === 0);
|
||||
yield waitForCondition(() => Object.getOwnPropertyNames(gExpectedJoins).length === 0 &&
|
||||
gExpectedUpdates.length === 0);
|
||||
});
|
||||
|
||||
// Test if push updates' channelIDs are respected.
|
||||
add_task(function* () {
|
||||
add_task(function* test_channelIdsRespected() {
|
||||
function badRoomJoin() {
|
||||
Assert.ok(false, "Unexpected 'joined' event emitted!");
|
||||
}
|
||||
LoopRooms.on("join", onRoomLeft);
|
||||
LoopRooms.on("join", badRoomJoin);
|
||||
roomsPushNotification("4", kChannelFxA);
|
||||
LoopRooms.off("join", badRoomJoin);
|
||||
|
||||
@ -510,7 +508,8 @@ add_task(function* () {
|
||||
"5de6281c-6568-455f-af08-c0b0a973100e"
|
||||
];
|
||||
roomsPushNotification("3", kChannelFxA);
|
||||
yield waitForCondition(() => Object.getOwnPropertyNames(gExpectedLeaves).length === 0);
|
||||
yield waitForCondition(() => Object.getOwnPropertyNames(gExpectedLeaves).length === 0 &&
|
||||
gExpectedUpdates.length === 0);
|
||||
});
|
||||
|
||||
// Test if joining a room as Guest works as expected.
|
||||
|
@ -0,0 +1,269 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
const { LOOP_ROOMS_CACHE_FILENAME } = Cu.import("resource:///modules/loop/LoopRoomsCache.jsm", {});
|
||||
|
||||
const kContextEnabledPref = "loop.contextInConverations.enabled";
|
||||
|
||||
const kFxAKey = "uGIs-kGbYt1hBBwjyW7MLQ";
|
||||
|
||||
// Rooms details as responded by the server.
|
||||
const kRoomsResponses = new Map([
|
||||
["_nxD4V4FflQ", {
|
||||
// Encrypted with roomKey "FliIGLUolW-xkKZVWstqKw".
|
||||
// roomKey is wrapped with kFxAKey.
|
||||
context: {
|
||||
wrappedKey: "F3V27oPB+FgjFbVPML2PupONYqoIZ53XRU4BqG46Lr3eyIGumgCEqgjSe/MXAXiQ//8=",
|
||||
value: "df7B4SNxhOI44eJjQavCevADyCCxz6/DEZbkOkRUMVUxzS42FbzN6C2PqmCKDYUGyCJTwJ0jln8TLw==",
|
||||
alg: "AES-GCM"
|
||||
},
|
||||
roomToken: "_nxD4V4FflQ",
|
||||
roomUrl: "http://localhost:3000/rooms/_nxD4V4FflQ"
|
||||
}],
|
||||
["QzBbvGmIZWU", {
|
||||
context: {
|
||||
wrappedKey: "AFu7WwFNjhWR5J6L8ks7S6H/1ktYVEw3yt1eIIWVaMabZaB3vh5612/FNzua4oS2oCM=",
|
||||
value: "sqj+xRNEty8K3Q1gSMd5bIUYKu34JfiO2+LIMlJrOetFIbJdBoQ+U8JZNaTFl6Qp3RULZ41x0zeSBSk=",
|
||||
alg: "AES-GCM"
|
||||
},
|
||||
roomToken: "QzBbvGmIZWU",
|
||||
roomUrl: "http://localhost:3000/rooms/QzBbvGmIZWU"
|
||||
}]
|
||||
]);
|
||||
|
||||
const kExpectedRooms = new Map([
|
||||
["_nxD4V4FflQ", {
|
||||
context: {
|
||||
wrappedKey: "F3V27oPB+FgjFbVPML2PupONYqoIZ53XRU4BqG46Lr3eyIGumgCEqgjSe/MXAXiQ//8=",
|
||||
value: "df7B4SNxhOI44eJjQavCevADyCCxz6/DEZbkOkRUMVUxzS42FbzN6C2PqmCKDYUGyCJTwJ0jln8TLw==",
|
||||
alg: "AES-GCM"
|
||||
},
|
||||
decryptedContext: {
|
||||
roomName: "First Room Name"
|
||||
},
|
||||
roomKey: "FliIGLUolW-xkKZVWstqKw",
|
||||
roomToken: "_nxD4V4FflQ",
|
||||
roomUrl: "http://localhost:3000/rooms/_nxD4V4FflQ#FliIGLUolW-xkKZVWstqKw"
|
||||
}],
|
||||
["QzBbvGmIZWU", {
|
||||
context: {
|
||||
wrappedKey: "AFu7WwFNjhWR5J6L8ks7S6H/1ktYVEw3yt1eIIWVaMabZaB3vh5612/FNzua4oS2oCM=",
|
||||
value: "sqj+xRNEty8K3Q1gSMd5bIUYKu34JfiO2+LIMlJrOetFIbJdBoQ+U8JZNaTFl6Qp3RULZ41x0zeSBSk=",
|
||||
alg: "AES-GCM"
|
||||
},
|
||||
decryptedContext: {
|
||||
roomName: "Loopy Discussion",
|
||||
},
|
||||
roomKey: "h2H8Sa9QxLCTTiXNmJVtRA",
|
||||
roomToken: "QzBbvGmIZWU",
|
||||
roomUrl: "http://localhost:3000/rooms/QzBbvGmIZWU"
|
||||
}]
|
||||
]);
|
||||
|
||||
const kCreateRoomProps = {
|
||||
decryptedContext: {
|
||||
roomName: "Say Hello",
|
||||
},
|
||||
roomOwner: "Gavin",
|
||||
maxSize: 2
|
||||
};
|
||||
|
||||
const kCreateRoomData = {
|
||||
roomToken: "Vo2BFQqIaAM",
|
||||
roomUrl: "http://localhost:3000/rooms/_nxD4V4FflQ",
|
||||
expiresAt: 1405534180
|
||||
};
|
||||
|
||||
function getCachePath() {
|
||||
return OS.Path.join(OS.Constants.Path.profileDir, LOOP_ROOMS_CACHE_FILENAME);
|
||||
}
|
||||
|
||||
function readRoomsCache() {
|
||||
return CommonUtils.readJSON(getCachePath());
|
||||
}
|
||||
|
||||
function saveRoomsCache(contents) {
|
||||
delete LoopRoomsInternal.roomsCache._cache;
|
||||
return CommonUtils.writeJSON(contents, getCachePath());
|
||||
}
|
||||
|
||||
function clearRoomsCache() {
|
||||
return LoopRoomsInternal.roomsCache.clear();
|
||||
}
|
||||
|
||||
// This is a cut-down version of the one in test_looprooms.js.
|
||||
add_task(function* setup_server() {
|
||||
loopServer.registerPathHandler("/registration", (req, res) => {
|
||||
res.setStatusLine(null, 200, "OK");
|
||||
res.processAsync();
|
||||
res.finish();
|
||||
});
|
||||
|
||||
loopServer.registerPathHandler("/rooms", (req, res) => {
|
||||
res.setStatusLine(null, 200, "OK");
|
||||
|
||||
if (req.method == "POST") {
|
||||
Assert.ok(req.bodyInputStream, "POST request should have a payload");
|
||||
let body = CommonUtils.readBytesFromInputStream(req.bodyInputStream);
|
||||
let data = JSON.parse(body);
|
||||
|
||||
Assert.ok(!("decryptedContext" in data), "should not have any decrypted data");
|
||||
Assert.ok("context" in data, "should have context");
|
||||
|
||||
res.write(JSON.stringify(kCreateRoomData));
|
||||
} else {
|
||||
res.write(JSON.stringify([...kRoomsResponses.values()]));
|
||||
}
|
||||
|
||||
res.processAsync();
|
||||
res.finish();
|
||||
});
|
||||
|
||||
function returnRoomDetails(res, roomName) {
|
||||
roomDetail.roomName = roomName;
|
||||
res.setStatusLine(null, 200, "OK");
|
||||
res.write(JSON.stringify(roomDetail));
|
||||
res.processAsync();
|
||||
res.finish();
|
||||
}
|
||||
|
||||
function getJSONData(body) {
|
||||
return JSON.parse(CommonUtils.readBytesFromInputStream(body));
|
||||
}
|
||||
|
||||
// Add a request handler for each room in the list.
|
||||
[...kRoomsResponses.values()].forEach(function(room) {
|
||||
loopServer.registerPathHandler("/rooms/" + encodeURIComponent(room.roomToken), (req, res) => {
|
||||
if (req.method == "POST") {
|
||||
let data = getJSONData(req.bodyInputStream);
|
||||
res.setStatusLine(null, 200, "OK");
|
||||
res.write(JSON.stringify(data));
|
||||
res.processAsync();
|
||||
res.finish();
|
||||
} else if (req.method == "PATCH") {
|
||||
let data = getJSONData(req.bodyInputStream);
|
||||
Assert.ok("context" in data, "should have encrypted context");
|
||||
// We return a fake encrypted name here as the context is
|
||||
// encrypted.
|
||||
returnRoomDetails(res, "fakeEncrypted");
|
||||
} else {
|
||||
res.setStatusLine(null, 200, "OK");
|
||||
res.write(JSON.stringify(room));
|
||||
res.processAsync();
|
||||
res.finish();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
loopServer.registerPathHandler("/rooms/error401", (req, res) => {
|
||||
res.setStatusLine(null, 401, "Not Found");
|
||||
res.processAsync();
|
||||
res.finish();
|
||||
});
|
||||
|
||||
loopServer.registerPathHandler("/rooms/errorMalformed", (req, res) => {
|
||||
res.setStatusLine(null, 200, "OK");
|
||||
res.write("{\"some\": \"Syntax Error!\"}}}}}}");
|
||||
res.processAsync();
|
||||
res.finish();
|
||||
});
|
||||
|
||||
mockPushHandler.registrationPushURL = kEndPointUrl;
|
||||
|
||||
yield MozLoopService.promiseRegisteredWithServers();
|
||||
});
|
||||
|
||||
|
||||
// Test if getting rooms saves unknown keys correctly.
|
||||
add_task(function* test_get_rooms_saves_unknown_keys() {
|
||||
let rooms = yield LoopRooms.promise("getAll");
|
||||
|
||||
// Check that we've saved the encryption keys correctly.
|
||||
let roomsCache = yield readRoomsCache();
|
||||
for (let room of [...kExpectedRooms.values()]) {
|
||||
if (room.context.wrappedKey) {
|
||||
Assert.equal(roomsCache[LOOP_SESSION_TYPE.FXA][room.roomToken].key, room.roomKey);
|
||||
}
|
||||
}
|
||||
|
||||
yield clearRoomsCache();
|
||||
});
|
||||
|
||||
// Test that when we get a room it updates the saved key if it is different.
|
||||
add_task(function* test_get_rooms_saves_different_keys() {
|
||||
let roomsCache = {};
|
||||
roomsCache[LOOP_SESSION_TYPE.FXA] = {
|
||||
QzBbvGmIZWU: {key: "fakeKey"}
|
||||
};
|
||||
yield saveRoomsCache(roomsCache);
|
||||
|
||||
const kRoomToken = "QzBbvGmIZWU";
|
||||
|
||||
let room = yield LoopRooms.promise("get", kRoomToken);
|
||||
|
||||
// Check that we've saved the encryption keys correctly.
|
||||
roomsCache = yield readRoomsCache();
|
||||
|
||||
Assert.notEqual(roomsCache[LOOP_SESSION_TYPE.FXA][kRoomToken].key, "fakeKey");
|
||||
Assert.equal(roomsCache[LOOP_SESSION_TYPE.FXA][kRoomToken].key, room.roomKey);
|
||||
|
||||
yield clearRoomsCache();
|
||||
});
|
||||
|
||||
// Test that if roomKey decryption fails, the saved key is used for decryption.
|
||||
add_task(function* test_get_rooms_uses_saved_key() {
|
||||
const kRoomToken = "_nxD4V4FflQ";
|
||||
const kExpected = kExpectedRooms.get(kRoomToken);
|
||||
|
||||
let roomsCache = {};
|
||||
roomsCache[LOOP_SESSION_TYPE.FXA] = {
|
||||
"_nxD4V4FflQ": {key: kExpected.roomKey}
|
||||
};
|
||||
yield saveRoomsCache(roomsCache);
|
||||
|
||||
// Change the encryption key for FxA, so that decoding the room key will break.
|
||||
Services.prefs.setCharPref("loop.key.fxa", "invalidKey");
|
||||
|
||||
let room = yield LoopRooms.promise("get", kRoomToken);
|
||||
|
||||
Assert.deepEqual(room, kExpected);
|
||||
|
||||
Services.prefs.setCharPref("loop.key.fxa", kFxAKey);
|
||||
yield clearRoomsCache();
|
||||
});
|
||||
|
||||
// Test that when a room is created the new key is saved.
|
||||
add_task(function* test_create_room_saves_key() {
|
||||
let room = yield LoopRooms.promise("create", kCreateRoomProps);
|
||||
|
||||
let roomsCache = yield readRoomsCache();
|
||||
|
||||
Assert.equal(roomsCache[LOOP_SESSION_TYPE.FXA][room.roomToken].key, room.roomKey);
|
||||
|
||||
yield clearRoomsCache();
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
setupFakeLoopServer();
|
||||
|
||||
Services.prefs.setCharPref("loop.key.fxa", kFxAKey);
|
||||
Services.prefs.setBoolPref(kContextEnabledPref, true);
|
||||
|
||||
// Pretend we're signed into FxA.
|
||||
MozLoopServiceInternal.fxAOAuthTokenData = { token_type: "bearer" };
|
||||
MozLoopServiceInternal.fxAOAuthProfile = { email: "fake@invalid.com" };
|
||||
|
||||
do_register_cleanup(function () {
|
||||
Services.prefs.clearUserPref(kContextEnabledPref);
|
||||
Services.prefs.clearUserPref("loop.key.fxa");
|
||||
|
||||
MozLoopServiceInternal.fxAOAuthTokenData = null;
|
||||
MozLoopServiceInternal.fxAOAuthProfile = null;
|
||||
});
|
||||
|
||||
run_next_test();
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
Cu.import("resource:///modules/loop/LoopRooms.jsm");
|
||||
Cu.import("resource:///modules/Chat.jsm");
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
|
||||
const kGuestKey = "uGIs-kGbYt1hBBwjyW7MLQ";
|
||||
const kChannelGuest = MozLoopService.channelIDs.roomsGuest;
|
||||
|
||||
const kRoomsResponses = new Map([
|
||||
["_nxD4V4FflQ", {
|
||||
roomToken: "_nxD4V4FflQ",
|
||||
// Encrypted with roomKey "FliIGLUolW-xkKZVWstqKw".
|
||||
// roomKey is wrapped with kGuestKey.
|
||||
context: {
|
||||
wrappedKey: "F3V27oPB+FgjFbVPML2PupONYqoIZ53XRU4BqG46Lr3eyIGumgCEqgjSe/MXAXiQ//8=",
|
||||
value: "df7B4SNxhOI44eJjQavCevADyCCxz6/DEZbkOkRUMVUxzS42FbzN6C2PqmCKDYUGyCJTwJ0jln8TLw==",
|
||||
alg: "AES-GCM"
|
||||
},
|
||||
roomUrl: "http://localhost:3000/rooms/_nxD4V4FflQ",
|
||||
maxSize: 2,
|
||||
ctime: 1405517546,
|
||||
participants: [{
|
||||
displayName: "Alexis",
|
||||
account: "alexis@example.com",
|
||||
roomConnectionId: "2a1787a6-4a73-43b5-ae3e-906ec1e763cb"
|
||||
}, {
|
||||
displayName: "Adam",
|
||||
roomConnectionId: "781f012b-f1ea-4ce1-9105-7cfc36fb4ec7"
|
||||
}]
|
||||
}],
|
||||
["QzBbvGmIZWU", {
|
||||
roomToken: "QzBbvGmIZWU",
|
||||
roomName: "Second Room Name",
|
||||
roomUrl: "http://localhost:3000/rooms/QzBbvGmIZWU",
|
||||
maxSize: 2,
|
||||
ctime: 140551741
|
||||
}],
|
||||
]);
|
||||
|
||||
let gRoomsAdded = [];
|
||||
let gRoomsUpdated = [];
|
||||
|
||||
const onRoomAdded = function(e, room) {
|
||||
gRoomsAdded.push(room);
|
||||
};
|
||||
|
||||
const onRoomUpdated = function(e, room) {
|
||||
gRoomsUpdated.push(room);
|
||||
};
|
||||
|
||||
let gQueryString = null;
|
||||
|
||||
add_task(function* setup_server() {
|
||||
loopServer.registerPathHandler("/registration", (req, res) => {
|
||||
res.setStatusLine(null, 200, "OK");
|
||||
res.processAsync();
|
||||
res.finish();
|
||||
});
|
||||
|
||||
loopServer.registerPathHandler("/rooms", (req, res) => {
|
||||
gQueryString = req.queryString;
|
||||
|
||||
res.setStatusLine(null, 200, "OK");
|
||||
// For this simple test, always send all rooms, even though this wouldn't
|
||||
// happen normally.
|
||||
res.write(JSON.stringify([...kRoomsResponses.values()]));
|
||||
res.processAsync();
|
||||
res.finish();
|
||||
});
|
||||
|
||||
mockPushHandler.registrationPushURL = kEndPointUrl;
|
||||
|
||||
yield MozLoopService.promiseRegisteredWithServers();
|
||||
});
|
||||
|
||||
// Test if notifying from push correctly gets all rooms the first time.
|
||||
add_task(function* test_notification_firstTime() {
|
||||
roomsPushNotification("1", kChannelGuest);
|
||||
|
||||
// Wait for the notification to complete before we getAll, otherwise
|
||||
// the getAll may cover up what we're testing.
|
||||
yield waitForCondition(() => gRoomsAdded.length === 2);
|
||||
|
||||
let rooms = yield LoopRooms.promise("getAll");
|
||||
Assert.equal(rooms.length, 2);
|
||||
Assert.equal(gQueryString, "", "Query string should not be set.");
|
||||
});
|
||||
|
||||
// Test if notifying from push correctly only gets the specific room the second time.
|
||||
add_task(function* test_notification_firstTime() {
|
||||
roomsPushNotification("2", kChannelGuest);
|
||||
yield waitForCondition(() => gRoomsUpdated.length === 2);
|
||||
|
||||
let rooms = yield LoopRooms.promise("getAll");
|
||||
Assert.equal(rooms.length, 2);
|
||||
Assert.equal(gQueryString, "version=2", "Query string should be set.");
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
setupFakeLoopServer();
|
||||
|
||||
Services.prefs.setCharPref("loop.key", kGuestKey);
|
||||
LoopRooms.on("add", onRoomAdded);
|
||||
LoopRooms.on("update", onRoomUpdated);
|
||||
|
||||
do_register_cleanup(function () {
|
||||
Services.prefs.clearUserPref("loop.key");
|
||||
|
||||
LoopRooms.off("add", onRoomAdded);
|
||||
LoopRooms.off("update", onRoomUpdated);
|
||||
});
|
||||
|
||||
run_next_test();
|
||||
}
|
@ -120,4 +120,4 @@ function run_test() {
|
||||
});
|
||||
|
||||
run_next_test();
|
||||
};
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ skip-if = toolkit == 'gonk'
|
||||
[test_loopapi_hawk_request.js]
|
||||
[test_looppush_initialize.js]
|
||||
[test_looprooms.js]
|
||||
[test_looprooms_encryption_in_fxa.js]
|
||||
[test_looprooms_first_notification.js]
|
||||
[test_loopservice_directcall.js]
|
||||
[test_loopservice_dnd.js]
|
||||
[test_loopservice_encryptionkey.js]
|
||||
|
@ -632,7 +632,6 @@ BrowserGlue.prototype = {
|
||||
let buttons = [
|
||||
{
|
||||
label: win.gNavigatorBundle.getFormattedString("addonwatch.disable.label", [addon.name]),
|
||||
accessKey: win.gNavigatorBundle.getString("addonwatch.disable.accesskey"),
|
||||
callback: function() {
|
||||
addon.userDisabled = true;
|
||||
if (addon.pendingOperations != addon.PENDING_NONE) {
|
||||
|
@ -19,14 +19,17 @@ loader.lazyRequireGetter(this, "TimelineFront",
|
||||
"devtools/server/actors/timeline", true);
|
||||
loader.lazyRequireGetter(this, "MemoryFront",
|
||||
"devtools/server/actors/memory", true);
|
||||
loader.lazyRequireGetter(this, "timers",
|
||||
"resource://gre/modules/Timer.jsm");
|
||||
loader.lazyRequireGetter(this, "Poller",
|
||||
"devtools/shared/poller", true);
|
||||
|
||||
// how often do we pull allocation sites from the memory actor
|
||||
const ALLOCATION_SITE_POLL_TIMER = 200; // ms
|
||||
|
||||
// how often do we check the status of the profiler's circular buffer
|
||||
const BUFFER_CHECK_TIMER = 5000; // ms
|
||||
|
||||
const MEMORY_ACTOR_METHODS = [
|
||||
"destroy", "attach", "detach", "getState", "getAllocationsSettings",
|
||||
"attach", "detach", "getState", "getAllocationsSettings",
|
||||
"getAllocations", "startRecordingAllocations", "stopRecordingAllocations"
|
||||
];
|
||||
|
||||
@ -45,6 +48,9 @@ const PROFILER_ACTOR_METHODS = [
|
||||
function ProfilerFrontFacade (target) {
|
||||
this._target = target;
|
||||
this._onProfilerEvent = this._onProfilerEvent.bind(this);
|
||||
this._checkBufferStatus = this._checkBufferStatus.bind(this);
|
||||
this._BUFFER_CHECK_TIMER = this._target.TEST_MOCK_BUFFER_CHECK_TIMER || BUFFER_CHECK_TIMER;
|
||||
|
||||
EventEmitter.decorate(this);
|
||||
}
|
||||
|
||||
@ -72,6 +78,9 @@ ProfilerFrontFacade.prototype = {
|
||||
* Unregisters events for the underlying profiler actor.
|
||||
*/
|
||||
destroy: Task.async(function *() {
|
||||
if (this._poller) {
|
||||
yield this._poller.destroy();
|
||||
}
|
||||
yield this.unregisterEventNotifications({ events: this.EVENTS });
|
||||
// TODO bug 1159389, listen directly to actor if supporting new front
|
||||
this._target.client.removeListener("eventNotification", this._onProfilerEvent);
|
||||
@ -79,16 +88,29 @@ ProfilerFrontFacade.prototype = {
|
||||
|
||||
/**
|
||||
* Starts the profiler actor, if necessary.
|
||||
*
|
||||
* @option {number?} bufferSize
|
||||
* @option {number?} sampleFrequency
|
||||
*/
|
||||
start: Task.async(function *(options={}) {
|
||||
// Check for poller status even if the profiler is already active --
|
||||
// profiler can be activated via `console.profile` or another source, like
|
||||
// the Gecko Profiler.
|
||||
if (!this._poller) {
|
||||
this._poller = new Poller(this._checkBufferStatus, this._BUFFER_CHECK_TIMER, false);
|
||||
}
|
||||
if (!this._poller.isPolling()) {
|
||||
this._poller.on();
|
||||
}
|
||||
|
||||
// Start the profiler only if it wasn't already active. The built-in
|
||||
// nsIPerformance module will be kept recording, because it's the same instance
|
||||
// for all targets and interacts with the whole platform, so we don't want
|
||||
// to affect other clients by stopping (or restarting) it.
|
||||
let profilerStatus = yield this.isActive();
|
||||
if (profilerStatus.isActive) {
|
||||
let { isActive, currentTime, position, generation, totalSize } = yield this.isActive();
|
||||
if (isActive) {
|
||||
this.emit("profiler-already-active");
|
||||
return profilerStatus.currentTime;
|
||||
return { startTime: currentTime, position, generation, totalSize };
|
||||
}
|
||||
|
||||
// Translate options from the recording model into profiler-specific
|
||||
@ -101,7 +123,16 @@ ProfilerFrontFacade.prototype = {
|
||||
yield this.startProfiler(profilerOptions);
|
||||
|
||||
this.emit("profiler-activated");
|
||||
return 0;
|
||||
return { startTime: 0, position, generation, totalSize };
|
||||
}),
|
||||
|
||||
/**
|
||||
* Indicates the end of a recording -- does not actually stop the profiler
|
||||
* (stopProfiler does that), but notes that we no longer need to poll
|
||||
* for buffer status.
|
||||
*/
|
||||
stop: Task.async(function *() {
|
||||
yield this._poller.off();
|
||||
}),
|
||||
|
||||
/**
|
||||
@ -136,6 +167,10 @@ ProfilerFrontFacade.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_checkBufferStatus: Task.async(function *() {
|
||||
this.emit("buffer-status", (yield this.isActive()));
|
||||
}),
|
||||
|
||||
toString: () => "[object ProfilerFrontFacade]"
|
||||
};
|
||||
|
||||
@ -200,6 +235,7 @@ exports.TimelineFront = TimelineFrontFacade;
|
||||
function MemoryFrontFacade (target) {
|
||||
this._target = target;
|
||||
this._pullAllocationSites = this._pullAllocationSites.bind(this);
|
||||
|
||||
EventEmitter.decorate(this);
|
||||
}
|
||||
|
||||
@ -213,6 +249,16 @@ MemoryFrontFacade.prototype = {
|
||||
this.IS_MOCK = !supported;
|
||||
}),
|
||||
|
||||
/**
|
||||
* Disables polling and destroys actor.
|
||||
*/
|
||||
destroy: Task.async(function *() {
|
||||
if (this._poller) {
|
||||
yield this._poller.destroy();
|
||||
}
|
||||
yield this._actor.destroy();
|
||||
}),
|
||||
|
||||
/**
|
||||
* Starts polling for allocation information.
|
||||
*/
|
||||
@ -235,7 +281,12 @@ MemoryFrontFacade.prototype = {
|
||||
|
||||
let startTime = yield this.startRecordingAllocations(allocationOptions);
|
||||
|
||||
yield this._pullAllocationSites();
|
||||
if (!this._poller) {
|
||||
this._poller = new Poller(this._pullAllocationSites, ALLOCATION_SITE_POLL_TIMER, false);
|
||||
}
|
||||
if (!this._poller.isPolling()) {
|
||||
this._poller.on();
|
||||
}
|
||||
|
||||
return startTime;
|
||||
}),
|
||||
@ -253,8 +304,8 @@ MemoryFrontFacade.prototype = {
|
||||
// be stopped before that method finishes executing. Therefore, we need to
|
||||
// wait for the last request to `getAllocations` to finish before actually
|
||||
// stopping recording allocations.
|
||||
yield this._poller.off();
|
||||
yield this._lastPullAllocationSitesFinished;
|
||||
timers.clearTimeout(this._sitesPullTimeout);
|
||||
|
||||
let endTime = yield this.stopRecordingAllocations();
|
||||
yield this.detach();
|
||||
@ -287,8 +338,6 @@ MemoryFrontFacade.prototype = {
|
||||
counts: memoryData.counts
|
||||
});
|
||||
|
||||
this._sitesPullTimeout = timers.setTimeout(this._pullAllocationSites, ALLOCATION_SITE_POLL_TIMER);
|
||||
|
||||
resolve();
|
||||
}),
|
||||
|
||||
|
@ -153,6 +153,13 @@ function legacyRequest (target, actor, method, args) {
|
||||
*/
|
||||
function actorCompatibilityBridge (method) {
|
||||
return function () {
|
||||
// If there's no target or client on this actor facade,
|
||||
// abort silently -- this occurs in tests when polling occurs
|
||||
// after the test ends, when tests do not wait for toolbox destruction
|
||||
// (which will destroy the actor facade, turning off the polling).
|
||||
if (!this._target || !this._target.client) {
|
||||
return;
|
||||
}
|
||||
// Check to see if this is a modern ActorFront, which has its
|
||||
// own `request` method. Also, check if its a mock actor, as it mimicks
|
||||
// the ActorFront interface.
|
||||
|
@ -21,14 +21,11 @@ loader.lazyImporter(this, "gDevTools",
|
||||
loader.lazyImporter(this, "Promise",
|
||||
"resource://gre/modules/Promise.jsm");
|
||||
|
||||
|
||||
// How often do we pull allocation sites from the memory actor.
|
||||
const DEFAULT_ALLOCATION_SITES_PULL_TIMEOUT = 200; // ms
|
||||
|
||||
// Events to pipe from PerformanceActorsConnection to the PerformanceFront
|
||||
const CONNECTION_PIPE_EVENTS = [
|
||||
"timeline-data", "profiler-already-active", "profiler-activated",
|
||||
"recording-starting", "recording-started", "recording-stopping", "recording-stopped"
|
||||
"recording-starting", "recording-started", "recording-stopping", "recording-stopped",
|
||||
"buffer-status"
|
||||
];
|
||||
|
||||
/**
|
||||
@ -79,6 +76,7 @@ function PerformanceActorsConnection(target) {
|
||||
this._onTimelineData = this._onTimelineData.bind(this);
|
||||
this._onConsoleProfileStart = this._onConsoleProfileStart.bind(this);
|
||||
this._onConsoleProfileEnd = this._onConsoleProfileEnd.bind(this);
|
||||
this._onBufferStatus = this._onBufferStatus.bind(this);
|
||||
this._onProfilerUnexpectedlyStopped = this._onProfilerUnexpectedlyStopped.bind(this);
|
||||
|
||||
Services.obs.notifyObservers(null, "performance-actors-connection-created", null);
|
||||
@ -173,6 +171,7 @@ PerformanceActorsConnection.prototype = {
|
||||
this._profiler.on("profiler-stopped", this._onProfilerUnexpectedlyStopped);
|
||||
this._profiler.on("profiler-already-active", this._pipeToConnection);
|
||||
this._profiler.on("profiler-activated", this._pipeToConnection);
|
||||
this._profiler.on("buffer-status", this._onBufferStatus);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -186,6 +185,7 @@ PerformanceActorsConnection.prototype = {
|
||||
this._profiler.off("profiler-stopped", this._onProfilerUnexpectedlyStopped);
|
||||
this._profiler.off("profiler-already-active", this._pipeToConnection);
|
||||
this._profiler.off("profiler-activated", this._pipeToConnection);
|
||||
this._profiler.off("buffer-status", this._onBufferStatus);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -289,10 +289,25 @@ PerformanceActorsConnection.prototype = {
|
||||
* Populate our internal store of recordings for all currently recording sessions.
|
||||
*/
|
||||
_onTimelineData: function (_, ...data) {
|
||||
this._recordings.forEach(e => e.addTimelineData.apply(e, data));
|
||||
this._recordings.forEach(e => e._addTimelineData.apply(e, data));
|
||||
this.emit("timeline-data", ...data);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called whenever the underlying profiler polls its buffer status.
|
||||
*/
|
||||
_onBufferStatus: function (_, data) {
|
||||
// If no buffer data emitted (whether from an older actor being destroyed
|
||||
// from a previous test, or the server does not support it), just ignore.
|
||||
// Also check for a value of buffer status (`position`) to see if it's
|
||||
// because of an unsupported server.
|
||||
if (!data || data.position === void 0) {
|
||||
return;
|
||||
}
|
||||
this._recordings.forEach(e => e._addBufferStatusData.call(e, data));
|
||||
this.emit("buffer-status", data);
|
||||
},
|
||||
|
||||
/**
|
||||
* Begins a recording session
|
||||
*
|
||||
@ -310,15 +325,18 @@ PerformanceActorsConnection.prototype = {
|
||||
// Get the corresponding start times from each one of them.
|
||||
// The timeline and memory actors are target-dependent, so start those as well,
|
||||
// even though these are mocked in older Geckos (FF < 35)
|
||||
let profilerStartTime = yield this._profiler.start(options);
|
||||
let { startTime, position, generation, totalSize } = yield this._profiler.start(options);
|
||||
let timelineStartTime = yield this._timeline.start(options);
|
||||
let memoryStartTime = yield this._memory.start(options);
|
||||
|
||||
let data = { profilerStartTime, timelineStartTime, memoryStartTime };
|
||||
let data = {
|
||||
profilerStartTime: startTime, timelineStartTime, memoryStartTime,
|
||||
generation, position, totalSize
|
||||
};
|
||||
|
||||
// Signify to the model that the recording has started,
|
||||
// populate with data and store the recording model here.
|
||||
model.populate(data);
|
||||
model._populate(data);
|
||||
this._recordings.push(model);
|
||||
|
||||
this.emit("recording-started", model);
|
||||
@ -368,6 +386,9 @@ PerformanceActorsConnection.prototype = {
|
||||
// juse use Date.now() for the memory and timeline end times, as those
|
||||
// are only used in tests.
|
||||
if (!this.isRecording()) {
|
||||
// This doesn't stop the profiler, just turns off polling for
|
||||
// events, and also turns off events on memory/timeline actors.
|
||||
yield this._profiler.stop();
|
||||
memoryEndTime = yield this._memory.stop(config);
|
||||
timelineEndTime = yield this._timeline.stop(config);
|
||||
}
|
||||
|
@ -345,7 +345,11 @@ GraphsController.prototype = {
|
||||
},
|
||||
|
||||
getMappedSelection: function ({ mapStart, mapEnd }) {
|
||||
return this._getPrimaryLink().getMappedSelection({ mapStart, mapEnd });
|
||||
if (this._getPrimaryLink()) {
|
||||
return this._getPrimaryLink().getMappedSelection({ mapStart, mapEnd });
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -43,6 +43,8 @@ RecordingModel.prototype = {
|
||||
_timelineStartTime: 0,
|
||||
_memoryStartTime: 0,
|
||||
_configuration: {},
|
||||
_originalBufferStatus: null,
|
||||
_bufferPercent: null,
|
||||
|
||||
// Serializable fields, necessary and sufficient for import and export.
|
||||
_label: "",
|
||||
@ -90,7 +92,7 @@ RecordingModel.prototype = {
|
||||
* Sets up the instance with data from the SharedPerformanceConnection when
|
||||
* starting a recording. Should only be called by SharedPerformanceConnection.
|
||||
*/
|
||||
populate: function (info) {
|
||||
_populate: function (info) {
|
||||
// Times must come from the actor in order to be self-consistent.
|
||||
// However, we also want to update the view with the elapsed time
|
||||
// even when the actor is not generating data. To do this we get
|
||||
@ -100,6 +102,12 @@ RecordingModel.prototype = {
|
||||
this._profilerStartTime = info.profilerStartTime;
|
||||
this._timelineStartTime = info.timelineStartTime;
|
||||
this._memoryStartTime = info.memoryStartTime;
|
||||
this._originalBufferStatus = {
|
||||
position: info.position,
|
||||
totalSize: info.totalSize,
|
||||
generation: info.generation
|
||||
};
|
||||
|
||||
this._recording = true;
|
||||
|
||||
this._markers = [];
|
||||
@ -280,10 +288,36 @@ RecordingModel.prototype = {
|
||||
return this._recording;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the percent (value between 0 and 1) of buffer used in this
|
||||
* recording. Returns `null` for recordings that are no longer recording.
|
||||
*/
|
||||
getBufferUsage: function () {
|
||||
return this.isRecording() ? this._bufferPercent : null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Fired whenever the PerformanceFront has new buffer data.
|
||||
*/
|
||||
_addBufferStatusData: function (bufferStatus) {
|
||||
// If this model isn't currently recording, or if the server does not
|
||||
// support buffer status (or if this fires after actors are being destroyed),
|
||||
// ignore this information.
|
||||
if (!bufferStatus || !this.isRecording()) {
|
||||
return;
|
||||
}
|
||||
let { position: currentPosition, totalSize, generation: currentGeneration } = bufferStatus;
|
||||
let { position: origPosition, generation: origGeneration } = this._originalBufferStatus;
|
||||
|
||||
let normalizedCurrent = (totalSize * (currentGeneration - origGeneration)) + currentPosition;
|
||||
let percent = (normalizedCurrent - origPosition) / totalSize;
|
||||
this._bufferPercent = percent > 1 ? 1 : percent;
|
||||
},
|
||||
|
||||
/**
|
||||
* Fired whenever the PerformanceFront emits markers, memory or ticks.
|
||||
*/
|
||||
addTimelineData: function (eventName, ...data) {
|
||||
_addTimelineData: function (eventName, ...data) {
|
||||
// If this model isn't currently recording,
|
||||
// ignore the timeline data.
|
||||
if (!this.isRecording()) {
|
||||
@ -343,7 +377,9 @@ RecordingModel.prototype = {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toString: () => "[object RecordingModel]"
|
||||
};
|
||||
|
||||
exports.RecordingModel = RecordingModel;
|
||||
|
@ -19,6 +19,7 @@ support-files =
|
||||
[browser_perf-compatibility-03.js]
|
||||
[browser_perf-compatibility-04.js]
|
||||
[browser_perf-compatibility-05.js]
|
||||
[browser_perf-compatibility-06.js]
|
||||
[browser_perf-clear-01.js]
|
||||
[browser_perf-clear-02.js]
|
||||
[browser_perf-columns-js-calltree.js]
|
||||
@ -90,6 +91,7 @@ support-files =
|
||||
[browser_perf-refresh.js]
|
||||
[browser_perf-ui-recording.js]
|
||||
[browser_perf-recording-model-01.js]
|
||||
[browser_perf-recording-model-02.js]
|
||||
[browser_perf-recording-notices-01.js]
|
||||
[browser_perf-recording-notices-02.js]
|
||||
[browser_perf_recordings-io-01.js]
|
||||
|
@ -0,0 +1,46 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests that when using an older server (< Fx40) where the profiler actor does not
|
||||
* have the `getBufferInfo` method that nothing breaks and RecordingModels have null
|
||||
* `getBufferUsage()` values.
|
||||
*/
|
||||
|
||||
function spawnTest () {
|
||||
let { target, front } = yield initBackend(SIMPLE_URL, { TEST_MOCK_BUFFER_CHECK_TIMER: 10 });
|
||||
let frontBufferStatusCalled = false;
|
||||
|
||||
// Explicitly override the profiler's `isActive` method, where
|
||||
// all the buffer info is retrieved, and delete the buffer properties.
|
||||
let isActive = front._connection._profiler.isActive;
|
||||
front._connection._profiler.isActive = function () {
|
||||
return isActive.apply(front._connection._profiler, arguments).then(res => {
|
||||
return { isActive: res.isActive, currentTime: res.currentTime };
|
||||
});
|
||||
};
|
||||
|
||||
front.on("buffer-status", () => frontBufferStatusCalled = true);
|
||||
let model = yield front.startRecording();
|
||||
let [_, stats] = yield onceSpread(front._connection._profiler, "buffer-status");
|
||||
is(stats.generation, void 0, "buffer-status has void `generation`");
|
||||
is(stats.totalSize, void 0, "buffer-status has void `totalSize`");
|
||||
is(stats.position, void 0, "buffer-status has void `position`");
|
||||
|
||||
let count = 0;
|
||||
while (count < 5) {
|
||||
let [_, stats] = yield onceSpread(front._connection._profiler, "buffer-status");
|
||||
is(stats.generation, void 0, "buffer-status has void `generation`");
|
||||
is(stats.totalSize, void 0, "buffer-status has void `totalSize`");
|
||||
is(stats.position, void 0, "buffer-status has void `position`");
|
||||
count++;
|
||||
}
|
||||
|
||||
is(model.getBufferUsage(), null, "model should have `null` for its buffer usage");
|
||||
yield front.stopRecording(model);
|
||||
is(model.getBufferUsage(), null, "after recording, model should still have `null` for its buffer usage");
|
||||
ok(!frontBufferStatusCalled, "the front should never emit a buffer-status event when not supported.");
|
||||
|
||||
yield removeTab(target.tab);
|
||||
finish();
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Test that buffer status is correctly updated in recording models.
|
||||
*/
|
||||
|
||||
let BUFFER_SIZE = 20000;
|
||||
|
||||
function spawnTest () {
|
||||
let { target, front } = yield initBackend(SIMPLE_URL, { TEST_MOCK_BUFFER_CHECK_TIMER: 10 });
|
||||
let config = { bufferSize: BUFFER_SIZE };
|
||||
|
||||
let model = yield front.startRecording(config);
|
||||
let [_, stats] = yield onceSpread(front, "buffer-status");
|
||||
is(stats.totalSize, BUFFER_SIZE, `buffer-status event has correct totalSize: ${stats.totalSize}`);
|
||||
ok(stats.position < BUFFER_SIZE, `buffer-status event has correct position: ${stats.position}`);
|
||||
is(stats.generation, 0, `buffer-status event has correct generation: ${stats.generation}`);
|
||||
|
||||
// Halt once more for a buffer status to ensure we're beyond 0
|
||||
yield once(front, "buffer-status");
|
||||
|
||||
let lastBufferStatus = 0;
|
||||
let checkCount = 0;
|
||||
while (lastBufferStatus < 1) {
|
||||
let currentBufferStatus = model.getBufferUsage();
|
||||
ok(currentBufferStatus > lastBufferStatus, `buffer is more filled than before: ${currentBufferStatus}`);
|
||||
lastBufferStatus = currentBufferStatus;
|
||||
checkCount++;
|
||||
yield once(front, "buffer-status");
|
||||
}
|
||||
|
||||
ok(checkCount >= 1, "atleast 1 event were fired until the buffer was filled");
|
||||
is(lastBufferStatus, 1, "buffer usage cannot surpass 100%");
|
||||
yield front.stopRecording(model);
|
||||
|
||||
is(model.getBufferUsage(), null, "getBufferUsage() should be null when no longer recording.");
|
||||
|
||||
yield removeTab(target.tab);
|
||||
finish();
|
||||
}
|
@ -195,6 +195,7 @@ function initBackend(aUrl, targetOps={}) {
|
||||
// may not exist. Possible options that will actually work:
|
||||
// TEST_MOCK_MEMORY_ACTOR = true
|
||||
// TEST_MOCK_TIMELINE_ACTOR = true
|
||||
// TEST_MOCK_BUFFER_CHECK_TIMER = number
|
||||
merge(target, targetOps);
|
||||
|
||||
let connection = getPerformanceActorsConnection(target);
|
||||
|
@ -155,6 +155,11 @@ let OverviewView = {
|
||||
let mapStart = () => 0;
|
||||
let mapEnd = () => recording.getDuration();
|
||||
let selection = this.graphs.getMappedSelection({ mapStart, mapEnd });
|
||||
// If no selection returned, this means the overview graphs have not been rendered
|
||||
// yet, so act as if we have no selection (the full recording).
|
||||
if (!selection) {
|
||||
return { startTime: 0, endTime: recording.getDuration() };
|
||||
}
|
||||
return { startTime: selection.min, endTime: selection.max };
|
||||
},
|
||||
|
||||
|
@ -1062,7 +1062,7 @@ Messages.Extended.prototype = Heritage.extend(Messages.Simple.prototype,
|
||||
* DOM node or a function to invoke.
|
||||
* @return Element
|
||||
*/
|
||||
_renderBodyPiece: function(piece)
|
||||
_renderBodyPiece: function(piece, options = {})
|
||||
{
|
||||
if (piece instanceof Ci.nsIDOMNode) {
|
||||
return piece;
|
||||
@ -1071,7 +1071,7 @@ Messages.Extended.prototype = Heritage.extend(Messages.Simple.prototype,
|
||||
return piece(this);
|
||||
}
|
||||
|
||||
return this._renderValueGrip(piece);
|
||||
return this._renderValueGrip(piece, options);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1410,20 +1410,21 @@ Messages.ConsoleGeneric.prototype = Heritage.extend(Messages.Extended.prototype,
|
||||
_renderBodyPieces: function(container)
|
||||
{
|
||||
let lastStyle = null;
|
||||
let stylePieces = this._styles.length > 0 ? this._styles.length : 1;
|
||||
|
||||
for (let i = 0; i < this._messagePieces.length; i++) {
|
||||
let separator = i > 0 ? this._renderBodyPieceSeparator() : null;
|
||||
if (separator) {
|
||||
container.appendChild(separator);
|
||||
// Pieces with an associated style definition come from "%c" formatting.
|
||||
// For body pieces beyond that, add a separator before each one.
|
||||
if (i >= stylePieces) {
|
||||
container.appendChild(this._renderBodyPieceSeparator());
|
||||
}
|
||||
|
||||
let piece = this._messagePieces[i];
|
||||
let style = this._styles[i];
|
||||
|
||||
// No long string support.
|
||||
if (style && typeof style == "string" ) {
|
||||
lastStyle = this.cleanupStyle(style);
|
||||
}
|
||||
lastStyle = (style && typeof style == "string") ?
|
||||
this.cleanupStyle(style) : null;
|
||||
|
||||
container.appendChild(this._renderBodyPiece(piece, lastStyle));
|
||||
}
|
||||
@ -1434,7 +1435,9 @@ Messages.ConsoleGeneric.prototype = Heritage.extend(Messages.Extended.prototype,
|
||||
|
||||
_renderBodyPiece: function(piece, style)
|
||||
{
|
||||
let elem = Messages.Extended.prototype._renderBodyPiece.call(this, piece);
|
||||
// Skip quotes for top-level strings.
|
||||
let options = { noStringQuotes: true };
|
||||
let elem = Messages.Extended.prototype._renderBodyPiece.call(this, piece, options);
|
||||
let result = elem;
|
||||
|
||||
if (style) {
|
||||
@ -3298,11 +3301,16 @@ Widgets.ObjectRenderers.add({
|
||||
* The owning message.
|
||||
* @param object longStringActor
|
||||
* The LongStringActor to display.
|
||||
* @param object options
|
||||
* Options, such as noStringQuotes
|
||||
*/
|
||||
Widgets.LongString = function(message, longStringActor)
|
||||
Widgets.LongString = function(message, longStringActor, options)
|
||||
{
|
||||
Widgets.BaseWidget.call(this, message);
|
||||
this.longStringActor = longStringActor;
|
||||
this.noStringQuotes = (options && "noStringQuotes" in options) ?
|
||||
options.noStringQuotes : !this.message._quoteStrings;
|
||||
|
||||
this._onClick = this._onClick.bind(this);
|
||||
this._onSubstring = this._onSubstring.bind(this);
|
||||
};
|
||||
@ -3338,7 +3346,7 @@ Widgets.LongString.prototype = Heritage.extend(Widgets.BaseWidget.prototype,
|
||||
_renderString: function(str)
|
||||
{
|
||||
this.element.textContent = VariablesView.getString(str, {
|
||||
noStringQuotes: !this.message._quoteStrings,
|
||||
noStringQuotes: this.noStringQuotes,
|
||||
noEllipsis: true,
|
||||
});
|
||||
},
|
||||
|
@ -89,7 +89,7 @@ function* testMethod(aMethod, aHud, aOutputNode) {
|
||||
yield waitForMessages({
|
||||
webconsole: aHud,
|
||||
messages: [{
|
||||
text: '"foo" "bar"',
|
||||
text: 'foo bar',
|
||||
category: CATEGORY_WEBDEV,
|
||||
}],
|
||||
})
|
||||
|
@ -29,6 +29,7 @@ let inputTests = [
|
||||
{
|
||||
input: "'hello \\nfrom \\rthe \\\"string world!'",
|
||||
output: "\"hello \nfrom \rthe \"string world!\"",
|
||||
consoleOutput: "hello \nfrom \rthe \"string world!",
|
||||
},
|
||||
|
||||
// 1
|
||||
@ -36,12 +37,14 @@ let inputTests = [
|
||||
// unicode test
|
||||
input: "'\xFA\u1E47\u0129\xE7\xF6d\xEA \u021B\u0115\u0219\u0165'",
|
||||
output: "\"\xFA\u1E47\u0129\xE7\xF6d\xEA \u021B\u0115\u0219\u0165\"",
|
||||
consoleOutput: "\xFA\u1E47\u0129\xE7\xF6d\xEA \u021B\u0115\u0219\u0165",
|
||||
},
|
||||
|
||||
// 2
|
||||
{
|
||||
input: "'" + longString + "'",
|
||||
output: '"' + initialString + "\"[\u2026]",
|
||||
consoleOutput: initialString + "[\u2026]",
|
||||
printOutput: initialString,
|
||||
},
|
||||
|
||||
@ -49,6 +52,7 @@ let inputTests = [
|
||||
{
|
||||
input: "''",
|
||||
output: '""',
|
||||
consoleOutput: "",
|
||||
printOutput: '""',
|
||||
},
|
||||
|
||||
@ -62,6 +66,7 @@ let inputTests = [
|
||||
{
|
||||
input: "'0'",
|
||||
output: '"0"',
|
||||
consoleOutput: "0",
|
||||
},
|
||||
|
||||
// 6
|
||||
@ -74,6 +79,7 @@ let inputTests = [
|
||||
{
|
||||
input: "'42'",
|
||||
output: '"42"',
|
||||
consoleOutput: "42",
|
||||
},
|
||||
|
||||
// 8
|
||||
|
@ -35,7 +35,7 @@ let test = asyncTest(function* () {
|
||||
webconsole: hud,
|
||||
messages: [{
|
||||
name: "console.log() output for mousemove",
|
||||
text: /"eventLogger" mousemove { target: .+, buttons: 0, clientX: \d+, clientY: \d+, layerX: \d+, layerY: \d+ }/,
|
||||
text: /eventLogger mousemove { target: .+, buttons: 0, clientX: \d+, clientY: \d+, layerX: \d+, layerY: \d+ }/,
|
||||
category: CATEGORY_WEBDEV,
|
||||
severity: SEVERITY_LOG,
|
||||
}],
|
||||
@ -45,7 +45,7 @@ let test = asyncTest(function* () {
|
||||
webconsole: hud,
|
||||
messages: [{
|
||||
name: "console.log() output for keypress",
|
||||
text: /"eventLogger" keypress Shift { target: .+, key: .+, charCode: \d+, keyCode: \d+ }/,
|
||||
text: /eventLogger keypress Shift { target: .+, key: .+, charCode: \d+, keyCode: \d+ }/,
|
||||
category: CATEGORY_WEBDEV,
|
||||
severity: SEVERITY_LOG,
|
||||
}],
|
||||
|
@ -31,7 +31,7 @@ let test = asyncTest(function*() {
|
||||
category: CATEGORY_OUTPUT,
|
||||
},
|
||||
{
|
||||
text: '"foo" "bar"',
|
||||
text: 'foo bar',
|
||||
category: CATEGORY_WEBDEV,
|
||||
severity: SEVERITY_LOG,
|
||||
}],
|
||||
|
@ -1421,6 +1421,9 @@ function whenDelayedStartupFinished(aWindow, aCallback)
|
||||
* opening vview for them is very slow (they can cause timeouts in debug
|
||||
* builds).
|
||||
*
|
||||
* - consoleOutput: string|RegExp, optional, expected consoleOutput
|
||||
* If not provided consoleOuput = output;
|
||||
*
|
||||
* - printOutput: string|RegExp, optional, expected output for
|
||||
* |print(input)|. If this is not provided, printOutput = output.
|
||||
*
|
||||
@ -1462,11 +1465,14 @@ function checkOutputForInputs(hud, inputTests)
|
||||
hud.jsterm.clearOutput();
|
||||
hud.jsterm.execute("console.log(" + entry.input + ")");
|
||||
|
||||
let consoleOutput = "consoleOutput" in entry ?
|
||||
entry.consoleOutput : entry.output;
|
||||
|
||||
let [result] = yield waitForMessages({
|
||||
webconsole: hud,
|
||||
messages: [{
|
||||
name: "console.log() output: " + entry.output,
|
||||
text: entry.output,
|
||||
name: "console.log() output: " + consoleOutput,
|
||||
text: consoleOutput,
|
||||
category: CATEGORY_WEBDEV,
|
||||
severity: SEVERITY_LOG,
|
||||
}],
|
||||
|
@ -52,8 +52,6 @@ const HELP_URL = "https://developer.mozilla.org/docs/Tools/Web_Console/Helpers";
|
||||
|
||||
const VARIABLES_VIEW_URL = "chrome://browser/content/devtools/widgets/VariablesView.xul";
|
||||
|
||||
const CONSOLE_DIR_VIEW_HEIGHT = 0.6;
|
||||
|
||||
const IGNORED_SOURCE_URLS = ["debugger eval code"];
|
||||
|
||||
// The amount of time in milliseconds that we wait before performing a live
|
||||
@ -2664,9 +2662,6 @@ WebConsoleFrame.prototype = {
|
||||
|
||||
// Display the variables view after the message node.
|
||||
if (aLevel == "dir") {
|
||||
bodyNode.style.height = (this.window.innerHeight *
|
||||
CONSOLE_DIR_VIEW_HEIGHT) + "px";
|
||||
|
||||
let options = {
|
||||
objectActor: body.arguments[0],
|
||||
targetElement: bodyNode,
|
||||
|
@ -51,7 +51,6 @@ addonConfirmInstall.message=This site would like to install an add-on in #1:;Thi
|
||||
|
||||
addonwatch.slow=%1$S might be making %2$S run slowly
|
||||
addonwatch.disable.label=Disable %S
|
||||
addonwatch.disable.accesskey=D
|
||||
addonwatch.ignoreSession.label=Ignore for now
|
||||
addonwatch.ignoreSession.accesskey=I
|
||||
addonwatch.ignorePerm.label=Ignore permanently
|
||||
|
@ -8485,6 +8485,9 @@ AC_SUBST(MOZ_ANDROID_SHARE_OVERLAY)
|
||||
AC_SUBST(MOZ_ANDROID_TAB_QUEUE)
|
||||
AC_SUBST(MOZ_ANDROID_MLS_STUMBLER)
|
||||
AC_SUBST(MOZ_ANDROID_DOWNLOADS_INTEGRATION)
|
||||
AC_SUBST(MOZ_ANDROID_APPLICATION_CLASS)
|
||||
AC_SUBST(MOZ_ANDROID_BROWSER_INTENT_CLASS)
|
||||
AC_SUBST(MOZ_ANDROID_SEARCH_INTENT_CLASS)
|
||||
AC_SUBST(MOZ_INSTALL_TRACKING)
|
||||
AC_SUBST(ENABLE_STRIP)
|
||||
AC_SUBST(PKG_SKIP_STRIP)
|
||||
|
@ -1361,6 +1361,27 @@ Console::ProcessCallData(ConsoleCallData* aData)
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// Helper method for ProcessArguments. Flushes output, if non-empty, to aSequence.
|
||||
void
|
||||
FlushOutput(JSContext* aCx, Sequence<JS::Value>& aSequence, nsString &output)
|
||||
{
|
||||
if (!output.IsEmpty()) {
|
||||
JS::Rooted<JSString*> str(aCx, JS_NewUCStringCopyN(aCx,
|
||||
output.get(),
|
||||
output.Length()));
|
||||
if (!str) {
|
||||
return;
|
||||
}
|
||||
|
||||
aSequence.AppendElement(JS::StringValue(str));
|
||||
output.Truncate();
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void
|
||||
Console::ProcessArguments(JSContext* aCx,
|
||||
const nsTArray<JS::Heap<JS::Value>>& aData,
|
||||
@ -1472,17 +1493,7 @@ Console::ProcessArguments(JSContext* aCx,
|
||||
case 'o':
|
||||
case 'O':
|
||||
{
|
||||
if (!output.IsEmpty()) {
|
||||
JS::Rooted<JSString*> str(aCx, JS_NewUCStringCopyN(aCx,
|
||||
output.get(),
|
||||
output.Length()));
|
||||
if (!str) {
|
||||
return;
|
||||
}
|
||||
|
||||
aSequence.AppendElement(JS::StringValue(str));
|
||||
output.Truncate();
|
||||
}
|
||||
FlushOutput(aCx, aSequence, output);
|
||||
|
||||
JS::Rooted<JS::Value> v(aCx);
|
||||
if (index < aData.Length()) {
|
||||
@ -1495,17 +1506,7 @@ Console::ProcessArguments(JSContext* aCx,
|
||||
|
||||
case 'c':
|
||||
{
|
||||
if (!output.IsEmpty()) {
|
||||
JS::Rooted<JSString*> str(aCx, JS_NewUCStringCopyN(aCx,
|
||||
output.get(),
|
||||
output.Length()));
|
||||
if (!str) {
|
||||
return;
|
||||
}
|
||||
|
||||
aSequence.AppendElement(JS::StringValue(str));
|
||||
output.Truncate();
|
||||
}
|
||||
FlushOutput(aCx, aSequence, output);
|
||||
|
||||
if (index < aData.Length()) {
|
||||
JS::Rooted<JS::Value> v(aCx, aData[index++]);
|
||||
@ -1579,14 +1580,11 @@ Console::ProcessArguments(JSContext* aCx,
|
||||
}
|
||||
}
|
||||
|
||||
if (!output.IsEmpty()) {
|
||||
JS::Rooted<JSString*> str(aCx, JS_NewUCStringCopyN(aCx, output.get(),
|
||||
output.Length()));
|
||||
if (!str) {
|
||||
return;
|
||||
}
|
||||
FlushOutput(aCx, aSequence, output);
|
||||
|
||||
aSequence.AppendElement(JS::StringValue(str));
|
||||
// Discard trailing style element if there is no output to apply it to.
|
||||
if (aStyles.Length() > aSequence.Length()) {
|
||||
aStyles.TruncateLength(aSequence.Length());
|
||||
}
|
||||
|
||||
// The rest of the array, if unused by the format string.
|
||||
|
@ -298,11 +298,7 @@ BluetoothA2dpManager::ResetAvrcp()
|
||||
mMediaNumber = 0;
|
||||
mTotalMediaCount = 0;
|
||||
mPosition = 0;
|
||||
#ifdef MOZ_B2G_BT_API_V2
|
||||
mPlayStatus = ControlPlayStatus::PLAYSTATUS_UNKNOWN;
|
||||
#else
|
||||
mPlayStatus = ControlPlayStatus::PLAYSTATUS_STOPPED;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@ -933,9 +929,6 @@ BluetoothA2dpManager::UpdateRegisterNotification(BluetoothAvrcpEvent aEvent,
|
||||
}
|
||||
mPlaybackInterval = aParam;
|
||||
break;
|
||||
#ifdef MOZ_B2G_BT_API_V2
|
||||
// Missing in bluetooth2
|
||||
#else
|
||||
case AVRCP_EVENT_APP_SETTINGS_CHANGED:
|
||||
mAppSettingsChangedNotifyType = AVRCP_NTF_INTERIM;
|
||||
param.mNumAttr = 2;
|
||||
@ -944,7 +937,6 @@ BluetoothA2dpManager::UpdateRegisterNotification(BluetoothAvrcpEvent aEvent,
|
||||
param.mIds[1] = AVRCP_PLAYER_ATTRIBUTE_SHUFFLE;
|
||||
param.mValues[1] = AVRCP_PLAYER_VAL_OFF_SHUFFLE;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1512,6 +1512,12 @@ BluetoothDaemonProtocol::Send(BluetoothDaemonPDU* aPDU, void* aUserData)
|
||||
aPDU->SetConsumer(this);
|
||||
aPDU->SetUserData(aUserData);
|
||||
aPDU->UpdateHeader();
|
||||
|
||||
if (mConnection->GetConnectionStatus() == SOCKET_DISCONNECTED) {
|
||||
BT_LOGR("Connection to Bluetooth daemon is closed.");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mConnection->SendSocketData(aPDU); // Forward PDU to command channel
|
||||
|
||||
return NS_OK;
|
||||
|
@ -89,15 +89,11 @@ BluetoothOppManager::Observe(nsISupports* aSubject,
|
||||
{
|
||||
MOZ_ASSERT(sBluetoothOppManager);
|
||||
|
||||
#ifdef MOZ_B2G_BT_API_V2
|
||||
// Removed in bluetooth2
|
||||
#else
|
||||
// if state of any volume was changed
|
||||
if (!strcmp(aTopic, NS_VOLUME_STATE_CHANGED)) {
|
||||
HandleVolumeStateChanged(aSubject);
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
|
||||
HandleShutdown();
|
||||
@ -226,13 +222,9 @@ BluetoothOppManager::~BluetoothOppManager()
|
||||
BT_WARNING("Failed to remove shutdown observer!");
|
||||
}
|
||||
|
||||
#ifdef MOZ_B2G_BT_API_V2
|
||||
// Removed in bluetooth2
|
||||
#else
|
||||
if (NS_FAILED(obs->RemoveObserver(this, NS_VOLUME_STATE_CHANGED))) {
|
||||
BT_WARNING("Failed to remove volume observer!");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
@ -245,14 +237,10 @@ BluetoothOppManager::Init()
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef MOZ_B2G_BT_API_V2
|
||||
// Removed in bluetooth2
|
||||
#else
|
||||
if (NS_FAILED(obs->AddObserver(this, NS_VOLUME_STATE_CHANGED, false))) {
|
||||
BT_WARNING("Failed to add ns volume observer!");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* We don't start listening here as BluetoothServiceBluedroid calls Listen()
|
||||
@ -321,9 +309,6 @@ BluetoothOppManager::HandleShutdown()
|
||||
sBluetoothOppManager = nullptr;
|
||||
}
|
||||
|
||||
#ifdef MOZ_B2G_BT_API_V2
|
||||
// Removed in bluetooth2
|
||||
#else
|
||||
void
|
||||
BluetoothOppManager::HandleVolumeStateChanged(nsISupports* aSubject)
|
||||
{
|
||||
@ -357,7 +342,6 @@ BluetoothOppManager::HandleVolumeStateChanged(nsISupports* aSubject)
|
||||
Disconnect(nullptr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
BluetoothOppManager::Listen()
|
||||
|
@ -77,11 +77,7 @@ private:
|
||||
bool Init();
|
||||
void HandleShutdown();
|
||||
|
||||
#ifdef MOZ_B2G_BT_API_V2
|
||||
// Removed in bluetooth2
|
||||
#else
|
||||
void HandleVolumeStateChanged(nsISupports* aSubject);
|
||||
#endif
|
||||
|
||||
void StartFileTransfer();
|
||||
void StartSendingNextFile();
|
||||
|
@ -208,27 +208,6 @@ BluetoothHfpManager::ResetCallArray()
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MOZ_B2G_BT_API_V2
|
||||
void
|
||||
BluetoothHfpManager::Reset()
|
||||
{
|
||||
mReceiveVgsFlag = false;
|
||||
mDialingRequestProcessed = true;
|
||||
|
||||
mConnectionState = HFP_CONNECTION_STATE_DISCONNECTED;
|
||||
mPrevConnectionState = HFP_CONNECTION_STATE_DISCONNECTED;
|
||||
mAudioState = HFP_AUDIO_STATE_DISCONNECTED;
|
||||
|
||||
// Phone & Device CIND
|
||||
ResetCallArray();
|
||||
mBattChg = 5;
|
||||
mService = HFP_NETWORK_STATE_NOT_AVAILABLE;
|
||||
mRoam = HFP_SERVICE_TYPE_HOME;
|
||||
mSignal = 0;
|
||||
|
||||
mController = nullptr;
|
||||
}
|
||||
#else
|
||||
void
|
||||
BluetoothHfpManager::Cleanup()
|
||||
{
|
||||
@ -255,17 +234,12 @@ BluetoothHfpManager::Reset()
|
||||
mAudioState = HFP_AUDIO_STATE_DISCONNECTED;
|
||||
Cleanup();
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
BluetoothHfpManager::Init()
|
||||
{
|
||||
#ifdef MOZ_B2G_BT_API_V2
|
||||
// The function must run at b2g process since it would access SettingsService.
|
||||
MOZ_ASSERT(IsMainProcess());
|
||||
#else
|
||||
// Missing on bluetooth1
|
||||
#endif
|
||||
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
@ -624,11 +598,7 @@ BluetoothHfpManager::NotifyConnectionStateChanged(const nsAString& aType)
|
||||
} else {
|
||||
OnDisconnect(EmptyString());
|
||||
}
|
||||
#ifdef MOZ_B2G_BT_API_V2
|
||||
Reset();
|
||||
#else
|
||||
Cleanup();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -719,7 +689,6 @@ BluetoothHfpManager::HandleVoiceConnectionChanged(uint32_t aClientId)
|
||||
nsString regState;
|
||||
voiceInfo->GetState(regState);
|
||||
|
||||
#ifdef MOZ_B2G_BT_API_V2
|
||||
BluetoothHandsfreeNetworkState service =
|
||||
(regState.EqualsLiteral("registered")) ? HFP_NETWORK_STATE_AVAILABLE :
|
||||
HFP_NETWORK_STATE_NOT_AVAILABLE;
|
||||
@ -728,15 +697,6 @@ BluetoothHfpManager::HandleVoiceConnectionChanged(uint32_t aClientId)
|
||||
mListener->ServiceChanged(aClientId, service);
|
||||
}
|
||||
mService = service;
|
||||
#else
|
||||
int service = (regState.EqualsLiteral("registered")) ? 1 : 0;
|
||||
if (service != mService) {
|
||||
// Notify BluetoothRilListener of service change
|
||||
mListener->ServiceChanged(aClientId, service);
|
||||
}
|
||||
mService = service ? HFP_NETWORK_STATE_AVAILABLE :
|
||||
HFP_NETWORK_STATE_NOT_AVAILABLE;
|
||||
#endif
|
||||
|
||||
// Signal
|
||||
JS::Rooted<JS::Value> value(nsContentUtils::RootingCxForThread());
|
||||
|
@ -172,11 +172,7 @@ private:
|
||||
BluetoothHfpManager();
|
||||
bool Init();
|
||||
|
||||
#ifdef MOZ_B2G_BT_API_V2
|
||||
// Removed in bluetooth2
|
||||
#else
|
||||
void Cleanup();
|
||||
#endif
|
||||
|
||||
void HandleShutdown();
|
||||
void HandleVolumeChanged(nsISupports* aSubject);
|
||||
|
@ -300,8 +300,8 @@ BluetoothGattCharacteristic::WriteValue(const ArrayBuffer& aValue,
|
||||
NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
|
||||
|
||||
BT_ENSURE_TRUE_REJECT(mProperties &
|
||||
(GATT_CHAR_PROP_BIT_WRITE_NO_RESPONSE ||
|
||||
GATT_CHAR_PROP_BIT_WRITE ||
|
||||
(GATT_CHAR_PROP_BIT_WRITE_NO_RESPONSE |
|
||||
GATT_CHAR_PROP_BIT_WRITE |
|
||||
GATT_CHAR_PROP_BIT_SIGNED_WRITE),
|
||||
promise,
|
||||
NS_ERROR_NOT_AVAILABLE);
|
||||
|
@ -442,12 +442,8 @@ BluetoothHfpManager::Reset()
|
||||
bool
|
||||
BluetoothHfpManager::Init()
|
||||
{
|
||||
#ifdef MOZ_B2G_BT_API_V2
|
||||
// The function must run at b2g process since it would access SettingsService.
|
||||
MOZ_ASSERT(IsMainProcess());
|
||||
#else
|
||||
// Missing in bluetooth1
|
||||
#endif
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
@ -597,11 +593,8 @@ BluetoothHfpManager::HandleVolumeChanged(nsISupports* aSubject)
|
||||
// {"key":"volumeup", "value":10}
|
||||
// {"key":"volumedown", "value":2}
|
||||
|
||||
#ifdef MOZ_B2G_BT_API_V2
|
||||
RootedDictionary<dom::SettingChangeNotification> setting(nsContentUtils::RootingCx());
|
||||
#else
|
||||
RootedDictionary<SettingChangeNotification> setting(nsContentUtils::RootingCx());
|
||||
#endif
|
||||
|
||||
if (!WrappedJSToDictionary(aSubject, setting)) {
|
||||
return;
|
||||
}
|
||||
@ -1115,20 +1108,7 @@ BluetoothHfpManager::ReceiveSocketData(BluetoothSocket* aSocket,
|
||||
}
|
||||
#endif // MOZ_B2G_RIL
|
||||
} else {
|
||||
#ifdef MOZ_B2G_BT_API_V2
|
||||
nsCString warningMsg;
|
||||
warningMsg.Append(NS_LITERAL_CSTRING("Unsupported AT command: "));
|
||||
warningMsg.Append(msg);
|
||||
warningMsg.Append(NS_LITERAL_CSTRING(", reply with ERROR"));
|
||||
BT_WARNING(warningMsg.get());
|
||||
#else
|
||||
nsCString warningMsg;
|
||||
warningMsg.AppendLiteral("Unsupported AT command: ");
|
||||
warningMsg.Append(msg);
|
||||
warningMsg.AppendLiteral(", reply with ERROR");
|
||||
BT_WARNING(warningMsg.get());
|
||||
#endif
|
||||
|
||||
BT_WARNING("Unsupported AT command: %s, reply with ERROR", msg.get());
|
||||
SendLine("ERROR");
|
||||
return;
|
||||
}
|
||||
@ -1700,11 +1680,7 @@ BluetoothHfpManager::HandleCallStateChanged(uint32_t aCallIndex,
|
||||
GetNumberOfCalls(nsITelephonyService::CALL_STATE_DISCONNECTED)) {
|
||||
// In order to let user hear busy tone via connected Bluetooth headset,
|
||||
// we postpone the timing of dropping SCO.
|
||||
#ifdef MOZ_B2G_BT_API_V2
|
||||
if (!(aError.Equals(NS_LITERAL_STRING("BusyError")))) {
|
||||
#else
|
||||
if (!(aError.EqualsLiteral("BusyError"))) {
|
||||
#endif
|
||||
DisconnectSco();
|
||||
} else {
|
||||
// Close Sco later since Dialer is still playing busy tone via HF.
|
||||
|
@ -845,6 +845,16 @@ AutoMounter::UpdateState()
|
||||
break;
|
||||
|
||||
case STATE_UMS_CONFIGURING:
|
||||
if (mtpEnabled) {
|
||||
// MTP was enabled. Start reconfiguring.
|
||||
SetState(STATE_MTP_CONFIGURING);
|
||||
SetUsbFunction(USB_FUNC_MTP);
|
||||
break;
|
||||
}
|
||||
if (rndisConfigured) {
|
||||
SetState(STATE_RNDIS_CONFIGURED);
|
||||
break;
|
||||
}
|
||||
// While configuring, the USB configuration state will change from
|
||||
// CONFIGURED -> CONNECTED -> DISCONNECTED -> CONNECTED -> CONFIGURED
|
||||
// so we don't check for cable unplugged here. However, having said
|
||||
@ -853,18 +863,8 @@ AutoMounter::UpdateState()
|
||||
// in. This is why we need to check for mtpEnabled once we get the
|
||||
// configured event.
|
||||
if (umsConfigured) {
|
||||
if (mtpEnabled) {
|
||||
// MTP was enabled. Start reconfiguring.
|
||||
SetState(STATE_MTP_CONFIGURING);
|
||||
SetUsbFunction(USB_FUNC_MTP);
|
||||
break;
|
||||
}
|
||||
SetState(STATE_UMS_CONFIGURED);
|
||||
}
|
||||
if (rndisConfigured) {
|
||||
SetState(STATE_RNDIS_CONFIGURED);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_UMS_CONFIGURED:
|
||||
@ -1119,6 +1119,7 @@ void AutoMounter::GetStatus(bool& umsAvail, bool& umsConfigured, bool& umsEnable
|
||||
bool& mtpAvail, bool& mtpConfigured, bool& mtpEnabled,
|
||||
bool& rndisConfigured)
|
||||
{
|
||||
umsAvail = false;
|
||||
umsConfigured = false;
|
||||
umsEnabled = false;
|
||||
mtpAvail = false;
|
||||
|
@ -39,8 +39,6 @@ XPCOMUtils.defineLazyGetter(this, "gRil", function() {
|
||||
return null;
|
||||
});
|
||||
|
||||
const TOPIC_INTERFACE_REGISTERED = "network-interface-registered";
|
||||
const TOPIC_INTERFACE_UNREGISTERED = "network-interface-unregistered";
|
||||
const TOPIC_MOZSETTINGS_CHANGED = "mozsettings-changed";
|
||||
const TOPIC_CONNECTION_STATE_CHANGED = "network-connection-state-changed";
|
||||
const TOPIC_PREF_CHANGED = "nsPref:changed";
|
||||
@ -126,8 +124,6 @@ function TetheringService() {
|
||||
Services.obs.addObserver(this, TOPIC_XPCOM_SHUTDOWN, false);
|
||||
Services.obs.addObserver(this, TOPIC_MOZSETTINGS_CHANGED, false);
|
||||
Services.obs.addObserver(this, TOPIC_CONNECTION_STATE_CHANGED, false);
|
||||
Services.obs.addObserver(this, TOPIC_INTERFACE_REGISTERED, false);
|
||||
Services.obs.addObserver(this, TOPIC_INTERFACE_UNREGISTERED, false);
|
||||
Services.prefs.addObserver(PREF_NETWORK_DEBUG_ENABLED, this, false);
|
||||
|
||||
this._dataDefaultServiceId = 0;
|
||||
@ -257,28 +253,10 @@ TetheringService.prototype = {
|
||||
" changed state to " + network.state);
|
||||
this.onConnectionChanged(network);
|
||||
break;
|
||||
case TOPIC_INTERFACE_REGISTERED:
|
||||
network = aSubject.QueryInterface(Ci.nsINetworkInterface);
|
||||
if (network &&
|
||||
network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_DUN) {
|
||||
debug("Force setting " + SETTINGS_DUN_REQUIRED + " to true.");
|
||||
this.tetheringSettings[SETTINGS_DUN_REQUIRED] = true;
|
||||
}
|
||||
break;
|
||||
case TOPIC_INTERFACE_UNREGISTERED:
|
||||
network = aSubject.QueryInterface(Ci.nsINetworkInterface);
|
||||
if (network &&
|
||||
network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_DUN) {
|
||||
this.tetheringSettings[SETTINGS_DUN_REQUIRED] =
|
||||
libcutils.property_get("ro.tethering.dun_required") === "1";
|
||||
}
|
||||
break;
|
||||
case TOPIC_XPCOM_SHUTDOWN:
|
||||
Services.obs.removeObserver(this, TOPIC_XPCOM_SHUTDOWN);
|
||||
Services.obs.removeObserver(this, TOPIC_MOZSETTINGS_CHANGED);
|
||||
Services.obs.removeObserver(this, TOPIC_CONNECTION_STATE_CHANGED);
|
||||
Services.obs.removeObserver(this, TOPIC_INTERFACE_REGISTERED);
|
||||
Services.obs.removeObserver(this, TOPIC_INTERFACE_UNREGISTERED);
|
||||
Services.prefs.removeObserver(PREF_NETWORK_DEBUG_ENABLED, this);
|
||||
|
||||
this.dunConnectTimer.cancel();
|
||||
@ -643,6 +621,10 @@ TetheringService.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
// Re-check again, test cases set this property later.
|
||||
this.tetheringSettings[SETTINGS_DUN_REQUIRED] =
|
||||
libcutils.property_get("ro.tethering.dun_required") === "1";
|
||||
|
||||
if (!aEnable) {
|
||||
this.enableWifiTethering(false, aConfig, aCallback);
|
||||
return;
|
||||
|
@ -218,6 +218,14 @@ let gTestSuite = (function() {
|
||||
return setSettings1(SETTINGS_KEY_DATA_APN_SETTINGS, aApnSettings, aAllowError);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set 'ro.tethering.dun_required' system property to 1. Note that this is a
|
||||
* 'ro' property, it can only be set once.
|
||||
*/
|
||||
function setTetheringDunRequired() {
|
||||
return runEmulatorShellSafe(['setprop', 'ro.tethering.dun_required', '1']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap DOMRequest onsuccess/onerror events to Promise resolve/reject.
|
||||
*
|
||||
@ -704,6 +712,7 @@ let gTestSuite = (function() {
|
||||
suite.setWifiTetheringEnabled = setWifiTetheringEnabled;
|
||||
suite.getDataApnSettings = getDataApnSettings;
|
||||
suite.setDataApnSettings = setDataApnSettings;
|
||||
suite.setTetheringDunRequired = setTetheringDunRequired;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -4,4 +4,6 @@ browser = false
|
||||
qemu = true
|
||||
|
||||
[test_wifi_tethering_enabled.js]
|
||||
; The following test must be the last tethering test ran, as it sets the
|
||||
; 'ro.tethering.dun_required' property.
|
||||
[test_wifi_tethering_dun.js]
|
||||
|
@ -22,6 +22,7 @@ gTestSuite.startTest(function() {
|
||||
"types": ["dun"] } ]];
|
||||
return gTestSuite.setDataApnSettings(apnSettings);
|
||||
})
|
||||
.then(() => gTestSuite.setTetheringDunRequired())
|
||||
.then(() => gTestSuite.startTetheringTest(function() {
|
||||
return gTestSuite.ensureWifiEnabled(false)
|
||||
.then(() => gTestSuite.setWifiTetheringEnabled(true, true))
|
||||
|
@ -87,7 +87,7 @@
|
||||
<application android:label="@string/moz_app_displayname"
|
||||
android:icon="@drawable/icon"
|
||||
android:logo="@drawable/logo"
|
||||
android:name="org.mozilla.gecko.GeckoApplication"
|
||||
android:name="@MOZ_ANDROID_APPLICATION_CLASS@"
|
||||
android:hardwareAccelerated="true"
|
||||
# The preprocessor does not yet support arbitrary parentheses, so this cannot
|
||||
# be parenthesized thus to clarify that the logical AND operator has precedence:
|
||||
@ -107,7 +107,7 @@
|
||||
|
||||
<!-- If the windowSoftInputMode adjust* flag changes below, the
|
||||
setSoftInputMode call in BrowserSearch#onStop must also be updated. -->
|
||||
<activity android:name="org.mozilla.gecko.BrowserApp"
|
||||
<activity android:name="@MOZ_ANDROID_BROWSER_INTENT_CLASS@"
|
||||
android:label="@string/moz_app_displayname"
|
||||
android:taskAffinity="@ANDROID_PACKAGE_NAME@.BROWSER"
|
||||
android:alwaysRetainTaskState="true"
|
||||
@ -134,7 +134,7 @@
|
||||
for backwards compatibility. -->
|
||||
<activity-alias android:name=".App"
|
||||
android:label="@MOZ_APP_DISPLAYNAME@"
|
||||
android:targetActivity="org.mozilla.gecko.BrowserApp">
|
||||
android:targetActivity="@MOZ_ANDROID_BROWSER_INTENT_CLASS@">
|
||||
<!-- android:priority ranges between -1000 and 1000. We never want
|
||||
another activity to usurp the MAIN action, so we ratchet our
|
||||
priority up. -->
|
||||
@ -356,7 +356,7 @@
|
||||
<!-- Masquerade as the Resolver so that we can be opened from the Marketplace. -->
|
||||
<activity-alias
|
||||
android:name="com.android.internal.app.ResolverActivity"
|
||||
android:targetActivity="org.mozilla.gecko.BrowserApp"
|
||||
android:targetActivity="@MOZ_ANDROID_BROWSER_INTENT_CLASS@"
|
||||
android:exported="true" />
|
||||
|
||||
<receiver android:name="org.mozilla.gecko.GeckoUpdateReceiver">
|
||||
|
@ -81,10 +81,17 @@ public class AppConstants {
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the Java class that launches the browser.
|
||||
* The name of the Java class that represents the android application.
|
||||
*/
|
||||
public static final String BROWSER_INTENT_CLASS_NAME = "org.mozilla.gecko.BrowserApp";
|
||||
public static final String SEARCH_INTENT_CLASS_NAME = "org.mozilla.search.SearchActivity";
|
||||
public static final String MOZ_ANDROID_APPLICATION_CLASS = "@MOZ_ANDROID_APPLICATION_CLASS@";
|
||||
/**
|
||||
* The name of the Java class that launches the browser activity.
|
||||
*/
|
||||
public static final String MOZ_ANDROID_BROWSER_INTENT_CLASS = "@MOZ_ANDROID_BROWSER_INTENT_CLASS@";
|
||||
/**
|
||||
* The name of the Java class that launches the search activity.
|
||||
*/
|
||||
public static final String MOZ_ANDROID_SEARCH_INTENT_CLASS = "@MOZ_ANDROID_SEARCH_INTENT_CLASS@";
|
||||
|
||||
public static final String GRE_MILESTONE = "@GRE_MILESTONE@";
|
||||
|
||||
|
@ -1869,7 +1869,7 @@ public class BrowserApp extends GeckoApp
|
||||
} else if (event.equals("Prompt:ShowTop")) {
|
||||
// Bring this activity to front so the prompt is visible..
|
||||
Intent bringToFrontIntent = new Intent();
|
||||
bringToFrontIntent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, AppConstants.BROWSER_INTENT_CLASS_NAME);
|
||||
bringToFrontIntent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
|
||||
bringToFrontIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
|
||||
startActivity(bringToFrontIntent);
|
||||
} else if (event.equals("Accounts:Exist")) {
|
||||
|
@ -449,7 +449,7 @@ public class CrashReporter extends Activity
|
||||
String action = "android.intent.action.MAIN";
|
||||
Intent intent = new Intent(action);
|
||||
intent.setClassName(AppConstants.ANDROID_PACKAGE_NAME,
|
||||
AppConstants.BROWSER_INTENT_CLASS_NAME);
|
||||
AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
|
||||
intent.putExtra("didRestart", true);
|
||||
Log.i(LOGTAG, intent.toString());
|
||||
startActivity(intent);
|
||||
|
@ -76,7 +76,7 @@ public class DataReportingNotification {
|
||||
try {
|
||||
// Launch main App to launch Data choices when notification is clicked.
|
||||
Intent prefIntent = new Intent(GeckoApp.ACTION_LAUNCH_SETTINGS);
|
||||
prefIntent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, AppConstants.BROWSER_INTENT_CLASS_NAME);
|
||||
prefIntent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
|
||||
|
||||
GeckoPreferences.setResourceToOpen(prefIntent, "preferences_vendor");
|
||||
prefIntent.putExtra(ALERT_NAME_DATAREPORTING_NOTIFICATION, true);
|
||||
|
@ -847,7 +847,7 @@ public class GeckoAppShell
|
||||
shortcutIntent.setAction(GeckoApp.ACTION_HOMESCREEN_SHORTCUT);
|
||||
shortcutIntent.setData(Uri.parse(aURI));
|
||||
shortcutIntent.setClassName(AppConstants.ANDROID_PACKAGE_NAME,
|
||||
AppConstants.BROWSER_INTENT_CLASS_NAME);
|
||||
AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
|
||||
@ -1205,7 +1205,7 @@ public class GeckoAppShell
|
||||
// Return an intent with a URI that will open the YouTube page in the
|
||||
// current Fennec instance.
|
||||
final Class<?> c;
|
||||
final String browserClassName = AppConstants.BROWSER_INTENT_CLASS_NAME;
|
||||
final String browserClassName = AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS;
|
||||
try {
|
||||
c = Class.forName(browserClassName);
|
||||
} catch (ClassNotFoundException e) {
|
||||
|
@ -41,7 +41,7 @@ public class GuestSession {
|
||||
|
||||
private static PendingIntent getNotificationIntent(Context context) {
|
||||
Intent intent = new Intent(NOTIFICATION_INTENT);
|
||||
intent.setClassName(context, AppConstants.BROWSER_INTENT_CLASS_NAME);
|
||||
intent.setClassName(context, AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
|
||||
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ public class Restarter extends Service {
|
||||
restartIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
.putExtra("didRestart", true)
|
||||
.setClassName(getApplicationContext(),
|
||||
AppConstants.BROWSER_INTENT_CLASS_NAME);
|
||||
AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
|
||||
startActivity(restartIntent);
|
||||
Log.d(LOGTAG, "Launched " + restartIntent);
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import org.mozilla.gecko.AppConstants;
|
||||
*/
|
||||
public class GlobalConstants {
|
||||
public static final String BROWSER_INTENT_PACKAGE = AppConstants.ANDROID_PACKAGE_NAME;
|
||||
public static final String BROWSER_INTENT_CLASS = AppConstants.BROWSER_INTENT_CLASS_NAME;
|
||||
public static final String BROWSER_INTENT_CLASS = AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS;
|
||||
|
||||
/**
|
||||
* Bug 800244: this signing-level permission protects broadcast intents that
|
||||
|
@ -753,6 +753,7 @@ for var in ('ANDROID_PACKAGE_NAME', 'ANDROID_CPU_ARCH',
|
||||
'GRE_MILESTONE', 'MOZ_APP_BASENAME', 'MOZ_MOZILLA_API_KEY',
|
||||
'MOZ_APP_DISPLAYNAME', 'MOZ_APP_ID', 'MOZ_APP_NAME',
|
||||
'MOZ_APP_VENDOR', 'MOZ_APP_VERSION', 'MOZ_CHILD_PROCESS_NAME',
|
||||
'MOZ_ANDROID_APPLICATION_CLASS', 'MOZ_ANDROID_BROWSER_INTENT_CLASS', 'MOZ_ANDROID_SEARCH_INTENT_CLASS',
|
||||
'MOZ_CRASHREPORTER', 'MOZ_UPDATE_CHANNEL', 'OMNIJAR_NAME',
|
||||
'OS_TARGET', 'TARGET_XPCOM_ABI'):
|
||||
DEFINES[var] = CONFIG[var]
|
||||
|
@ -408,7 +408,7 @@ public class ShareDialog extends Locales.LocaleAwareActivity implements SendTabT
|
||||
try {
|
||||
// This can launch in the guest profile. Sorry.
|
||||
final Intent i = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
|
||||
i.setClassName(AppConstants.ANDROID_PACKAGE_NAME, AppConstants.BROWSER_INTENT_CLASS_NAME);
|
||||
i.setClassName(AppConstants.ANDROID_PACKAGE_NAME, AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
|
||||
startActivity(i);
|
||||
} catch (URISyntaxException e) {
|
||||
// Nothing much we can do.
|
||||
|
@ -68,7 +68,7 @@ public class TabQueueDispatcher extends Locales.LocaleAwareActivity {
|
||||
* Start fennec with the supplied intent.
|
||||
*/
|
||||
private void loadNormally(Intent intent) {
|
||||
intent.setClassName(getApplicationContext(), AppConstants.BROWSER_INTENT_CLASS_NAME);
|
||||
intent.setClassName(getApplicationContext(), AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ public class TabQueueHelper {
|
||||
ThreadUtils.assertNotOnUiThread();
|
||||
|
||||
Intent resultIntent = new Intent();
|
||||
resultIntent.setClassName(context, AppConstants.BROWSER_INTENT_CLASS_NAME);
|
||||
resultIntent.setClassName(context, AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
|
||||
resultIntent.setAction(TabQueueHelper.LOAD_URLS_ACTION);
|
||||
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, resultIntent, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
|
@ -190,7 +190,7 @@ public class TabQueueService extends Service {
|
||||
|
||||
private void openNow(Intent intent) {
|
||||
Intent forwardIntent = new Intent(intent);
|
||||
forwardIntent.setClassName(getApplicationContext(), AppConstants.BROWSER_INTENT_CLASS_NAME);
|
||||
forwardIntent.setClassName(getApplicationContext(), AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
|
||||
forwardIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(forwardIntent);
|
||||
|
||||
|
@ -16,6 +16,12 @@ MOZ_OFFICIAL_BRANDING_DIRECTORY=mobile/android/branding/official
|
||||
# See the --enable-android-min-sdk and --enable-android-max-sdk arguments in configure.in.
|
||||
MOZ_ANDROID_MIN_SDK_VERSION=9
|
||||
|
||||
# There are several entry points into the Firefox application. These are the names of some of the classes that are
|
||||
# listed in the Android manifest. They are specified in here to avoid hard-coding them in source code files.
|
||||
MOZ_ANDROID_APPLICATION_CLASS=org.mozilla.gecko.GeckoApplication
|
||||
MOZ_ANDROID_BROWSER_INTENT_CLASS=org.mozilla.gecko.BrowserApp
|
||||
MOZ_ANDROID_SEARCH_INTENT_CLASS=org.mozilla.search.SearchActivity
|
||||
|
||||
MOZ_SAFE_BROWSING=1
|
||||
|
||||
MOZ_NO_SMART_CARDS=1
|
||||
|
@ -130,7 +130,7 @@ public class PostSearchFragment extends Fragment {
|
||||
|
||||
// If the intent URI didn't specify a package, open this in Fennec.
|
||||
if (i.getPackage() == null) {
|
||||
i.setClassName(AppConstants.ANDROID_PACKAGE_NAME, AppConstants.BROWSER_INTENT_CLASS_NAME);
|
||||
i.setClassName(AppConstants.ANDROID_PACKAGE_NAME, AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL,
|
||||
TelemetryContract.Method.CONTENT, "search-result");
|
||||
} else {
|
||||
|
@ -68,7 +68,7 @@ public class SearchWidget extends AppWidgetProvider {
|
||||
case ACTION_LAUNCH_BROWSER:
|
||||
redirect = buildRedirectIntent(Intent.ACTION_MAIN,
|
||||
AppConstants.ANDROID_PACKAGE_NAME,
|
||||
AppConstants.BROWSER_INTENT_CLASS_NAME,
|
||||
AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS,
|
||||
intent);
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.LAUNCH,
|
||||
TelemetryContract.Method.WIDGET, "browser");
|
||||
@ -76,7 +76,7 @@ public class SearchWidget extends AppWidgetProvider {
|
||||
case ACTION_LAUNCH_NEW_TAB:
|
||||
redirect = buildRedirectIntent(Intent.ACTION_VIEW,
|
||||
AppConstants.ANDROID_PACKAGE_NAME,
|
||||
AppConstants.BROWSER_INTENT_CLASS_NAME,
|
||||
AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS,
|
||||
intent);
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.LAUNCH,
|
||||
TelemetryContract.Method.WIDGET, "new-tab");
|
||||
@ -84,7 +84,7 @@ public class SearchWidget extends AppWidgetProvider {
|
||||
case ACTION_LAUNCH_SEARCH:
|
||||
redirect = buildRedirectIntent(Intent.ACTION_VIEW,
|
||||
AppConstants.ANDROID_PACKAGE_NAME,
|
||||
AppConstants.SEARCH_INTENT_CLASS_NAME,
|
||||
AppConstants.MOZ_ANDROID_SEARCH_INTENT_CLASS,
|
||||
intent);
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.LAUNCH,
|
||||
TelemetryContract.Method.WIDGET, "search");
|
||||
|
@ -1,5 +1,5 @@
|
||||
<activity
|
||||
android:name="org.mozilla.search.SearchActivity"
|
||||
android:name="@MOZ_ANDROID_SEARCH_INTENT_CLASS@"
|
||||
android:launchMode="singleTop"
|
||||
android:icon="@drawable/search_launcher"
|
||||
android:label="@string/search_app_name"
|
||||
@ -40,9 +40,9 @@
|
||||
android:name="org.mozilla.search.SearchPreferenceActivity"
|
||||
android:logo="@drawable/search_launcher"
|
||||
android:label="@string/search_pref_title"
|
||||
android:parentActivityName="org.mozilla.search.SearchActivity"
|
||||
android:parentActivityName="@MOZ_ANDROID_SEARCH_INTENT_CLASS@"
|
||||
android:theme="@style/SettingsTheme" >
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="org.mozilla.search.SearchActivity"/>
|
||||
android:value="@MOZ_ANDROID_SEARCH_INTENT_CLASS@"/>
|
||||
</activity>
|
||||
|
@ -20,7 +20,7 @@ public class BrowserTestCase extends ActivityInstrumentationTestCase2<Activity>
|
||||
/**
|
||||
* The Java Class instance that launches the browser.
|
||||
* <p>
|
||||
* This should always agree with {@link AppConstants#BROWSER_INTENT_CLASS_NAME}.
|
||||
* This should always agree with {@link AppConstants#MOZ_ANDROID_BROWSER_INTENT_CLASS}.
|
||||
*/
|
||||
public static final Class<? extends Activity> BROWSER_INTENT_CLASS;
|
||||
|
||||
@ -30,7 +30,7 @@ public class BrowserTestCase extends ActivityInstrumentationTestCase2<Activity>
|
||||
static {
|
||||
Class<? extends Activity> cl;
|
||||
try {
|
||||
cl = (Class<? extends Activity>) Class.forName(AppConstants.BROWSER_INTENT_CLASS_NAME);
|
||||
cl = (Class<? extends Activity>) Class.forName(AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
|
||||
} catch (ClassNotFoundException e) {
|
||||
// Oh well.
|
||||
cl = Activity.class;
|
||||
|
@ -43,7 +43,7 @@ public abstract class BaseRobocopTest extends ActivityInstrumentationTestCase2<A
|
||||
/**
|
||||
* The Java Class instance that launches the browser.
|
||||
* <p>
|
||||
* This should always agree with {@link AppConstants#BROWSER_INTENT_CLASS_NAME}.
|
||||
* This should always agree with {@link AppConstants#MOZ_ANDROID_BROWSER_INTENT_CLASS}.
|
||||
*/
|
||||
public static final Class<? extends Activity> BROWSER_INTENT_CLASS;
|
||||
|
||||
@ -51,7 +51,7 @@ public abstract class BaseRobocopTest extends ActivityInstrumentationTestCase2<A
|
||||
static {
|
||||
Class<? extends Activity> cl;
|
||||
try {
|
||||
cl = (Class<? extends Activity>) Class.forName(AppConstants.BROWSER_INTENT_CLASS_NAME);
|
||||
cl = (Class<? extends Activity>) Class.forName(AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
|
||||
} catch (ClassNotFoundException e) {
|
||||
// Oh well.
|
||||
cl = Activity.class;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user