mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to inbound.
This commit is contained in:
commit
cff17d804d
@ -12,7 +12,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="3fc26ae786e3869a7ef1e23afc9807ac1b4741f2"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="260effa7f342db418b8d5a95dc61c6e8dd8d09f4"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="49c722fa1a5e1873fa0010829fd97d0b74009ca5"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/>
|
||||
|
@ -11,7 +11,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="3fc26ae786e3869a7ef1e23afc9807ac1b4741f2"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="260effa7f342db418b8d5a95dc61c6e8dd8d09f4"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="49c722fa1a5e1873fa0010829fd97d0b74009ca5"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="788d9ce293a9b44f64536130cf4ad577e8101dbe"/>
|
||||
|
@ -12,7 +12,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="3fc26ae786e3869a7ef1e23afc9807ac1b4741f2"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="260effa7f342db418b8d5a95dc61c6e8dd8d09f4"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="49c722fa1a5e1873fa0010829fd97d0b74009ca5"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/>
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"revision": "34a411a6261587124fc6746fb18a19c05571437a",
|
||||
"revision": "e11cf4c78874de3469c4f338cf275aeae31854ee",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -11,7 +11,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="3fc26ae786e3869a7ef1e23afc9807ac1b4741f2"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="260effa7f342db418b8d5a95dc61c6e8dd8d09f4"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="49c722fa1a5e1873fa0010829fd97d0b74009ca5"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
||||
|
@ -10,7 +10,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="3fc26ae786e3869a7ef1e23afc9807ac1b4741f2"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="260effa7f342db418b8d5a95dc61c6e8dd8d09f4"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="49c722fa1a5e1873fa0010829fd97d0b74009ca5"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
||||
|
@ -12,7 +12,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="3fc26ae786e3869a7ef1e23afc9807ac1b4741f2"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="260effa7f342db418b8d5a95dc61c6e8dd8d09f4"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="49c722fa1a5e1873fa0010829fd97d0b74009ca5"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
||||
|
@ -11,7 +11,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="3fc26ae786e3869a7ef1e23afc9807ac1b4741f2"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="260effa7f342db418b8d5a95dc61c6e8dd8d09f4"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="49c722fa1a5e1873fa0010829fd97d0b74009ca5"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
||||
|
@ -11,7 +11,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="3fc26ae786e3869a7ef1e23afc9807ac1b4741f2"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="260effa7f342db418b8d5a95dc61c6e8dd8d09f4"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="49c722fa1a5e1873fa0010829fd97d0b74009ca5"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="788d9ce293a9b44f64536130cf4ad577e8101dbe"/>
|
||||
|
@ -11,7 +11,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="3fc26ae786e3869a7ef1e23afc9807ac1b4741f2"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="260effa7f342db418b8d5a95dc61c6e8dd8d09f4"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="49c722fa1a5e1873fa0010829fd97d0b74009ca5"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
||||
|
@ -328,22 +328,6 @@ const PanelUI = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This function can be used as a command event listener for subviews
|
||||
* so that the panel knows if and when to close itself.
|
||||
*/
|
||||
onCommandHandler: function(aEvent) {
|
||||
let closemenu = aEvent.originalTarget.getAttribute("closemenu");
|
||||
if (closemenu == "none") {
|
||||
return;
|
||||
}
|
||||
if (closemenu == "single") {
|
||||
this.showMainView();
|
||||
return;
|
||||
}
|
||||
this.hide();
|
||||
},
|
||||
|
||||
/**
|
||||
* Open a dialog window that allow the user to customize listed character sets.
|
||||
*/
|
||||
|
@ -120,7 +120,6 @@ support-files =
|
||||
[browser_console_click_focus.js]
|
||||
[browser_console_consolejsm_output.js]
|
||||
[browser_console_dead_objects.js]
|
||||
skip-if = true # bug 963869
|
||||
[browser_console_error_source_click.js]
|
||||
[browser_console_filters.js]
|
||||
[browser_console_iframe_messages.js]
|
||||
|
@ -8,96 +8,89 @@
|
||||
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-eval-in-stackframe.html";
|
||||
|
||||
let gWebConsole, gJSTerm, gVariablesView;
|
||||
|
||||
function test()
|
||||
{
|
||||
registerCleanupFunction(() => {
|
||||
gWebConsole = gJSTerm = gVariablesView = null;
|
||||
});
|
||||
let hud;
|
||||
|
||||
addTab(TEST_URI);
|
||||
browser.addEventListener("load", function onLoad() {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
openConsole(null, consoleOpened);
|
||||
}, true);
|
||||
Task.spawn(runner).then(finishTest);
|
||||
|
||||
function* runner() {
|
||||
let {tab} = yield loadTab(TEST_URI);
|
||||
hud = yield openConsole(tab);
|
||||
let jsterm = hud.jsterm;
|
||||
|
||||
let msg = yield execute("fooObj");
|
||||
ok(msg, "output message found");
|
||||
|
||||
let anchor = msg.querySelector("a");
|
||||
ok(anchor, "object anchor");
|
||||
isnot(anchor.textContent.indexOf('testProp: "testValue"'), -1,
|
||||
"message text check");
|
||||
|
||||
msg.scrollIntoView();
|
||||
executeSoon(() => {
|
||||
EventUtils.synthesizeMouse(anchor, 2, 2, {}, hud.iframeWindow);
|
||||
});
|
||||
|
||||
let vviewVar = yield jsterm.once("variablesview-fetched");
|
||||
let vview = vviewVar._variablesView;
|
||||
ok(vview, "variables view object");
|
||||
|
||||
let [result] = yield findVariableViewProperties(vviewVar, [
|
||||
{ name: "testProp", value: "testValue" },
|
||||
], { webconsole: hud });
|
||||
|
||||
let prop = result.matchedProp;
|
||||
ok(prop, "matched the |testProp| property in the variables view");
|
||||
|
||||
is(content.wrappedJSObject.fooObj.testProp, result.value,
|
||||
"|fooObj.testProp| value is correct");
|
||||
|
||||
vview.window.focus();
|
||||
|
||||
executeSoon(() => {
|
||||
EventUtils.synthesizeKey("VK_ESCAPE", {});
|
||||
});
|
||||
yield jsterm.once("sidebar-closed");
|
||||
|
||||
jsterm.clearOutput();
|
||||
|
||||
msg = yield execute("window");
|
||||
ok(msg, "output message found");
|
||||
|
||||
let anchor = msg.querySelector("a");
|
||||
ok(anchor, "object anchor");
|
||||
isnot(anchor.textContent.indexOf("Window \u2192 http://example.com/browser/"), -1,
|
||||
"message text check");
|
||||
|
||||
msg.scrollIntoView();
|
||||
executeSoon(() => {
|
||||
EventUtils.synthesizeMouse(anchor, 2, 2, {}, hud.iframeWindow)
|
||||
});
|
||||
vviewVar = yield jsterm.once("variablesview-fetched");
|
||||
|
||||
vview = vviewVar._variablesView;
|
||||
ok(vview, "variables view object");
|
||||
|
||||
yield findVariableViewProperties(vviewVar, [
|
||||
{ name: "foo", value: "globalFooBug783499" },
|
||||
], { webconsole: hud });
|
||||
|
||||
vview.window.focus();
|
||||
|
||||
msg.scrollIntoView();
|
||||
executeSoon(() => {
|
||||
EventUtils.synthesizeKey("VK_ESCAPE", {});
|
||||
});
|
||||
|
||||
yield jsterm.once("sidebar-closed");
|
||||
}
|
||||
|
||||
function execute(str) {
|
||||
let deferred = promise.defer();
|
||||
hud.jsterm.execute(str, (msg) => {
|
||||
deferred.resolve(msg);
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
}
|
||||
|
||||
function consoleOpened(hud)
|
||||
{
|
||||
gWebConsole = hud;
|
||||
gJSTerm = hud.jsterm;
|
||||
gJSTerm.execute("fooObj", onExecuteFooObj);
|
||||
}
|
||||
|
||||
function onExecuteFooObj(msg)
|
||||
{
|
||||
ok(msg, "output message found");
|
||||
|
||||
let anchor = msg.querySelector("a");
|
||||
ok(anchor, "object anchor");
|
||||
isnot(anchor.textContent.indexOf('testProp: "testValue"'), -1,
|
||||
"message text check");
|
||||
|
||||
gJSTerm.once("variablesview-fetched", onFooObjFetch);
|
||||
EventUtils.synthesizeMouse(anchor, 2, 2, {}, gWebConsole.iframeWindow)
|
||||
}
|
||||
|
||||
function onFooObjFetch(aEvent, aVar)
|
||||
{
|
||||
gVariablesView = aVar._variablesView;
|
||||
ok(gVariablesView, "variables view object");
|
||||
|
||||
findVariableViewProperties(aVar, [
|
||||
{ name: "testProp", value: "testValue" },
|
||||
], { webconsole: gWebConsole }).then(onTestPropFound);
|
||||
}
|
||||
|
||||
function onTestPropFound(aResults)
|
||||
{
|
||||
let prop = aResults[0].matchedProp;
|
||||
ok(prop, "matched the |testProp| property in the variables view");
|
||||
|
||||
is(content.wrappedJSObject.fooObj.testProp, aResults[0].value,
|
||||
"|fooObj.testProp| value is correct");
|
||||
|
||||
gVariablesView.window.focus();
|
||||
gJSTerm.once("sidebar-closed", onSidebarClosed);
|
||||
EventUtils.synthesizeKey("VK_ESCAPE", {}, gVariablesView.window);
|
||||
}
|
||||
|
||||
function onSidebarClosed()
|
||||
{
|
||||
gJSTerm.clearOutput();
|
||||
gJSTerm.execute("window", onExecuteWindow);
|
||||
}
|
||||
|
||||
function onExecuteWindow(msg)
|
||||
{
|
||||
ok(msg, "output message found");
|
||||
let anchor = msg.querySelector("a");
|
||||
ok(anchor, "object anchor");
|
||||
isnot(anchor.textContent.indexOf("Window \u2192 http://example.com/browser/"), -1,
|
||||
"message text check");
|
||||
|
||||
gJSTerm.once("variablesview-fetched", onWindowFetch);
|
||||
EventUtils.synthesizeMouse(anchor, 2, 2, {}, gWebConsole.iframeWindow)
|
||||
}
|
||||
|
||||
function onWindowFetch(aEvent, aVar)
|
||||
{
|
||||
gVariablesView = aVar._variablesView;
|
||||
ok(gVariablesView, "variables view object");
|
||||
|
||||
findVariableViewProperties(aVar, [
|
||||
{ name: "foo", value: "globalFooBug783499" },
|
||||
], { webconsole: gWebConsole }).then(onFooFound);
|
||||
}
|
||||
|
||||
function onFooFound(aResults)
|
||||
{
|
||||
gVariablesView.window.focus();
|
||||
gJSTerm.once("sidebar-closed", finishTest);
|
||||
EventUtils.synthesizeKey("VK_ESCAPE", {}, gVariablesView.window);
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,13 @@
|
||||
*/
|
||||
|
||||
// Check that Dead Objects do not break the Web/Browser Consoles. See bug 883649.
|
||||
// This test does:
|
||||
// - opens a new tab,
|
||||
// - opens the Browser Console,
|
||||
// - stores a reference to the content document of the tab on the chrome window object,
|
||||
// - closes the tab,
|
||||
// - tries to use the object that was pointing to the now-defunct content
|
||||
// document. This is the dead object.
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf8,<p>dead objects!";
|
||||
|
||||
@ -11,35 +18,30 @@ function test()
|
||||
{
|
||||
let hud = null;
|
||||
|
||||
addTab(TEST_URI);
|
||||
browser.addEventListener("load", function onLoad() {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
info("open the browser console");
|
||||
HUDService.toggleBrowserConsole().then(onBrowserConsoleOpen);
|
||||
}, true);
|
||||
Task.spawn(runner).then(finishTest);
|
||||
|
||||
function onBrowserConsoleOpen(aHud)
|
||||
{
|
||||
hud = aHud;
|
||||
function* runner() {
|
||||
let {tab} = yield loadTab(TEST_URI);
|
||||
|
||||
info("open the browser console");
|
||||
|
||||
hud = yield HUDService.toggleBrowserConsole();
|
||||
ok(hud, "browser console opened");
|
||||
|
||||
hud.jsterm.clearOutput();
|
||||
hud.jsterm.execute("Cu = Components.utils;" +
|
||||
"Cu.import('resource://gre/modules/Services.jsm');" +
|
||||
"chromeWindow = Services.wm.getMostRecentWindow('navigator:browser');" +
|
||||
"foobarzTezt = chromeWindow.content.document;" +
|
||||
"delete chromeWindow", onAddVariable);
|
||||
}
|
||||
|
||||
function onAddVariable()
|
||||
{
|
||||
// Add the reference to the content document.
|
||||
|
||||
yield execute("Cu = Components.utils;" +
|
||||
"Cu.import('resource://gre/modules/Services.jsm');" +
|
||||
"chromeWindow = Services.wm.getMostRecentWindow('navigator:browser');" +
|
||||
"foobarzTezt = chromeWindow.content.document;" +
|
||||
"delete chromeWindow");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
|
||||
hud.jsterm.execute("foobarzTezt", onReadVariable);
|
||||
}
|
||||
let msg = yield execute("foobarzTezt");
|
||||
|
||||
function onReadVariable(msg)
|
||||
{
|
||||
isnot(hud.outputNode.textContent.indexOf("[object DeadObject]"), -1,
|
||||
"dead object found");
|
||||
|
||||
@ -49,38 +51,36 @@ function test()
|
||||
EventUtils.synthesizeKey(c, {}, hud.iframeWindow);
|
||||
}
|
||||
|
||||
hud.jsterm.execute(null, () => {
|
||||
// executeSoon() is needed to get out of the execute() event loop.
|
||||
executeSoon(onReadProperty.bind(null, msg));
|
||||
});
|
||||
}
|
||||
yield execute();
|
||||
|
||||
function onReadProperty(deadObjectMessage)
|
||||
{
|
||||
isnot(hud.outputNode.textContent.indexOf("can't access dead object"), -1,
|
||||
"'cannot access dead object' message found");
|
||||
|
||||
// Click the second execute output.
|
||||
let clickable = deadObjectMessage.querySelector("a");
|
||||
let clickable = msg.querySelector("a");
|
||||
ok(clickable, "clickable object found");
|
||||
isnot(clickable.textContent.indexOf("[object DeadObject]"), -1,
|
||||
"message text check");
|
||||
|
||||
hud.jsterm.once("variablesview-fetched", onFetched);
|
||||
EventUtils.synthesizeMouse(clickable, 2, 2, {}, hud.iframeWindow);
|
||||
}
|
||||
msg.scrollIntoView();
|
||||
|
||||
function onFetched()
|
||||
{
|
||||
executeSoon(() => {
|
||||
EventUtils.synthesizeMouseAtCenter(clickable, {}, hud.iframeWindow);
|
||||
});
|
||||
|
||||
yield hud.jsterm.once("variablesview-fetched");
|
||||
ok(true, "variables view fetched");
|
||||
hud.jsterm.execute("delete window.foobarzTezt; 2013-26", onCalcResult);
|
||||
|
||||
msg = yield execute("delete window.foobarzTezt; 2013-26");
|
||||
|
||||
isnot(msg.textContent.indexOf("1987"), -1, "result message found");
|
||||
}
|
||||
|
||||
function onCalcResult()
|
||||
{
|
||||
isnot(hud.outputNode.textContent.indexOf("1987"), -1, "result message found");
|
||||
|
||||
// executeSoon() is needed to get out of the execute() event loop.
|
||||
executeSoon(finishTest);
|
||||
function execute(str) {
|
||||
let deferred = promise.defer();
|
||||
hud.jsterm.execute(str, (msg) => {
|
||||
deferred.resolve(msg);
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
}
|
||||
|
@ -407,7 +407,8 @@ this.UITour = {
|
||||
|
||||
teardownTour: function(aWindow, aWindowClosing = false) {
|
||||
aWindow.gBrowser.tabContainer.removeEventListener("TabSelect", this);
|
||||
aWindow.PanelUI.panel.removeEventListener("popuphiding", this.onAppMenuHiding);
|
||||
aWindow.PanelUI.panel.removeEventListener("popuphiding", this.hidePanelAnnotations);
|
||||
aWindow.PanelUI.panel.removeEventListener("ViewShowing", this.hidePanelAnnotations);
|
||||
aWindow.removeEventListener("SSWindowClosing", this);
|
||||
|
||||
let originTabs = this.originTabs.get(aWindow);
|
||||
@ -821,7 +822,8 @@ this.UITour = {
|
||||
|
||||
if (aMenuName == "appMenu") {
|
||||
aWindow.PanelUI.panel.setAttribute("noautohide", "true");
|
||||
aWindow.PanelUI.panel.addEventListener("popuphiding", this.onAppMenuHiding);
|
||||
aWindow.PanelUI.panel.addEventListener("popuphiding", this.hidePanelAnnotations);
|
||||
aWindow.PanelUI.panel.addEventListener("ViewShowing", this.hidePanelAnnotations);
|
||||
if (aOpenCallback) {
|
||||
aWindow.PanelUI.panel.addEventListener("popupshown", onPopupShown);
|
||||
}
|
||||
@ -846,7 +848,7 @@ this.UITour = {
|
||||
}
|
||||
},
|
||||
|
||||
onAppMenuHiding: function(aEvent) {
|
||||
hidePanelAnnotations: function(aEvent) {
|
||||
let win = aEvent.target.ownerDocument.defaultView;
|
||||
let annotationElements = new Map([
|
||||
// [annotationElement (panel), method to hide the annotation]
|
||||
|
@ -96,6 +96,44 @@ let tests = [
|
||||
}, "Highlight should be shown after showHighlight() for fixed panel items");
|
||||
},
|
||||
|
||||
function test_highlight_panel_open_subview(done) {
|
||||
gContentAPI.showHighlight("customize");
|
||||
gContentAPI.showInfo("backForward", "test title", "test text");
|
||||
waitForElementToBeVisible(highlight, function checkPanelIsOpen() {
|
||||
isnot(PanelUI.panel.state, "closed", "Panel should have opened");
|
||||
|
||||
// Click the help button which should open the subview in the panel menu.
|
||||
let helpButton = document.getElementById("PanelUI-help");
|
||||
EventUtils.synthesizeMouseAtCenter(helpButton, {});
|
||||
waitForElementToBeHidden(highlight, function highlightHidden() {
|
||||
is(PanelUI.panel.state, "open",
|
||||
"Panel should have stayed open when the subview opened");
|
||||
is(tooltip.state, "open", "The info panel should have remained open");
|
||||
PanelUI.hide();
|
||||
done();
|
||||
}, "Highlight should have disappeared when the subview opened");
|
||||
}, "Highlight should be shown after showHighlight() for fixed panel items");
|
||||
},
|
||||
|
||||
function test_info_panel_open_subview(done) {
|
||||
gContentAPI.showHighlight("urlbar");
|
||||
gContentAPI.showInfo("customize", "customize me!", "Open a subview");
|
||||
waitForElementToBeVisible(tooltip, function checkPanelIsOpen() {
|
||||
isnot(PanelUI.panel.state, "closed", "Panel should have opened");
|
||||
|
||||
// Click the help button which should open the subview in the panel menu.
|
||||
let helpButton = document.getElementById("PanelUI-help");
|
||||
EventUtils.synthesizeMouseAtCenter(helpButton, {});
|
||||
waitForElementToBeHidden(tooltip, function tooltipHidden() {
|
||||
is(PanelUI.panel.state, "open",
|
||||
"Panel should have stayed open when the subview opened");
|
||||
is(highlight.parentElement.state, "open", "The highlight should have remained open");
|
||||
PanelUI.hide();
|
||||
done();
|
||||
}, "Tooltip should have disappeared when the subview opened");
|
||||
}, "Highlight should be shown after showHighlight() for fixed panel items");
|
||||
},
|
||||
|
||||
function test_info_move_outside_panel(done) {
|
||||
gContentAPI.showInfo("addons", "test title", "test text");
|
||||
gContentAPI.showHighlight("urlbar");
|
||||
|
@ -132,11 +132,14 @@
|
||||
#TabsToolbar:not(:-moz-lwtheme) {
|
||||
background-color: transparent !important;
|
||||
color: black;
|
||||
text-shadow: 0 0 .5em white, 0 0 .5em white, 0 1px 0 rgba(255,255,255,.4);
|
||||
border-left-style: none !important;
|
||||
border-right-style: none !important;
|
||||
}
|
||||
|
||||
#toolbar-menubar:not(:-moz-lwtheme) {
|
||||
text-shadow: 0 0 .5em white, 0 0 .5em white, 0 1px 0 rgba(255,255,255,.4);
|
||||
}
|
||||
|
||||
/* Vertical toolbar border */
|
||||
#main-window[sizemode=normal] #navigator-toolbox::after,
|
||||
#main-window[sizemode=normal] #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar) {
|
||||
@ -197,10 +200,6 @@
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.tabbrowser-tab:not(:-moz-lwtheme) {
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
#ctrlTab-panel {
|
||||
background: transparent;
|
||||
-moz-appearance: -moz-win-glass;
|
||||
|
@ -244,16 +244,43 @@ OpusTrackEncoder::GetMetadata()
|
||||
nsresult
|
||||
OpusTrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData)
|
||||
{
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
// Wait until initialized or cancelled.
|
||||
while (!mCanceled && !mInitialized) {
|
||||
mReentrantMonitor.Wait();
|
||||
}
|
||||
if (mCanceled || mEncodingComplete) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// calculation below depends on the truth that mInitialized is true.
|
||||
MOZ_ASSERT(mInitialized);
|
||||
|
||||
// re-sampled frames left last time which didn't fit into an Opus packet duration.
|
||||
const int framesLeft = mResampledLeftover.Length() / mChannels;
|
||||
// When framesLeft is 0, (GetPacketDuration() - framesLeft) is a multiple
|
||||
// of kOpusSamplingRate. There is not precision loss in the integer division
|
||||
// in computing framesToFetch. If frameLeft > 0, we need to add 1 to
|
||||
// framesToFetch to ensure there will be at least n frames after re-sampling.
|
||||
const int frameRoundUp = framesLeft ? 1 : 0;
|
||||
|
||||
MOZ_ASSERT(GetPacketDuration() >= framesLeft);
|
||||
// Try to fetch m frames such that there will be n frames
|
||||
// where (n + frameLeft) >= GetPacketDuration() after re-sampling.
|
||||
const int framesToFetch = !mResampler ? GetPacketDuration()
|
||||
: (GetPacketDuration() - framesLeft) * mSamplingRate / kOpusSamplingRate
|
||||
+ frameRoundUp;
|
||||
{
|
||||
// Move all the samples from mRawSegment to mSourceSegment. We only hold
|
||||
// the monitor in this block.
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
// Wait if mEncoder is not initialized, or when not enough raw data, but is
|
||||
// not the end of stream nor is being canceled.
|
||||
while (!mCanceled && (!mInitialized || (mRawSegment.GetDuration() +
|
||||
mSourceSegment.GetDuration() < GetPacketDuration() &&
|
||||
!mEndOfStream))) {
|
||||
// Wait until enough raw data, end of stream or cancelled.
|
||||
while (!mCanceled && mRawSegment.GetDuration() +
|
||||
mSourceSegment.GetDuration() < framesToFetch &&
|
||||
!mEndOfStream) {
|
||||
mReentrantMonitor.Wait();
|
||||
}
|
||||
|
||||
@ -276,13 +303,14 @@ OpusTrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData)
|
||||
pcm.SetLength(GetPacketDuration() * mChannels);
|
||||
AudioSegment::ChunkIterator iter(mSourceSegment);
|
||||
int frameCopied = 0;
|
||||
while (!iter.IsEnded() && frameCopied < GetPacketDuration()) {
|
||||
|
||||
while (!iter.IsEnded() && frameCopied < framesToFetch) {
|
||||
AudioChunk chunk = *iter;
|
||||
|
||||
// Chunk to the required frame size.
|
||||
int frameToCopy = chunk.GetDuration();
|
||||
if (frameCopied + frameToCopy > GetPacketDuration()) {
|
||||
frameToCopy = GetPacketDuration() - frameCopied;
|
||||
if (frameCopied + frameToCopy > framesToFetch) {
|
||||
frameToCopy = framesToFetch - frameCopied;
|
||||
}
|
||||
|
||||
if (!chunk.IsNull()) {
|
||||
@ -300,6 +328,7 @@ OpusTrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData)
|
||||
|
||||
nsRefPtr<EncodedFrame> audiodata = new EncodedFrame();
|
||||
audiodata->SetFrameType(EncodedFrame::AUDIO_FRAME);
|
||||
int framesInPCM = frameCopied;
|
||||
if (mResampler) {
|
||||
nsAutoTArray<AudioDataValue, 9600> resamplingDest;
|
||||
// We want to consume all the input data, so we slightly oversize the
|
||||
@ -322,9 +351,25 @@ OpusTrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData)
|
||||
out, &outframes);
|
||||
#endif
|
||||
|
||||
pcm = resamplingDest;
|
||||
MOZ_ASSERT(pcm.Length() >= mResampledLeftover.Length());
|
||||
PodCopy(pcm.Elements(), mResampledLeftover.Elements(),
|
||||
mResampledLeftover.Length());
|
||||
|
||||
uint32_t outframesToCopy = std::min(outframes,
|
||||
static_cast<uint32_t>(GetPacketDuration() - framesLeft));
|
||||
|
||||
MOZ_ASSERT(pcm.Length() - mResampledLeftover.Length() >=
|
||||
outframesToCopy * mChannels);
|
||||
PodCopy(pcm.Elements() + mResampledLeftover.Length(),
|
||||
resamplingDest.Elements(), outframesToCopy * mChannels);
|
||||
int frameLeftover = outframes - outframesToCopy;
|
||||
mResampledLeftover.SetLength(frameLeftover * mChannels);
|
||||
PodCopy(mResampledLeftover.Elements(),
|
||||
resamplingDest.Elements() + outframesToCopy * mChannels,
|
||||
mResampledLeftover.Length());
|
||||
// This is always at 48000Hz.
|
||||
audiodata->SetDuration(outframes);
|
||||
framesInPCM = framesLeft + outframesToCopy;
|
||||
audiodata->SetDuration(framesInPCM);
|
||||
} else {
|
||||
// The ogg time stamping and pre-skip is always timed at 48000.
|
||||
audiodata->SetDuration(frameCopied * (kOpusSamplingRate / mSamplingRate));
|
||||
@ -342,11 +387,13 @@ OpusTrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData)
|
||||
LOG("[Opus] Done encoding.");
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mEndOfStream || framesInPCM == GetPacketDuration());
|
||||
|
||||
// Append null data to pcm buffer if the leftover data is not enough for
|
||||
// opus encoder.
|
||||
if (frameCopied < GetPacketDuration() && mEndOfStream) {
|
||||
memset(pcm.Elements() + frameCopied * mChannels, 0,
|
||||
(GetPacketDuration()-frameCopied)*mChannels*sizeof(AudioDataValue));
|
||||
if (framesInPCM < GetPacketDuration() && mEndOfStream) {
|
||||
PodZero(pcm.Elements() + framesInPCM * mChannels,
|
||||
(GetPacketDuration() - framesInPCM) * mChannels);
|
||||
}
|
||||
nsTArray<uint8_t> frameData;
|
||||
// Encode the data with Opus Encoder.
|
||||
@ -372,6 +419,7 @@ OpusTrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData)
|
||||
speex_resampler_destroy(mResampler);
|
||||
mResampler = nullptr;
|
||||
}
|
||||
mResampledLeftover.SetLength(0);
|
||||
}
|
||||
|
||||
audiodata->SwapInFrameData(frameData);
|
||||
|
@ -74,6 +74,12 @@ private:
|
||||
* resampled.
|
||||
*/
|
||||
SpeexResamplerState* mResampler;
|
||||
|
||||
/**
|
||||
* Store the resampled frames that don't fit into an Opus packet duration.
|
||||
* They will be prepended to the resampled frames next encoding cycle.
|
||||
*/
|
||||
nsTArray<AudioDataValue> mResampledLeftover;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -1799,6 +1799,7 @@ Navigator::HasIccManagerSupport(JSContext* /* unused */,
|
||||
nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
|
||||
return win && CheckPermission(win, "mobileconnection");
|
||||
}
|
||||
#endif // MOZ_B2G_RIL
|
||||
|
||||
/* static */
|
||||
bool
|
||||
@ -1819,7 +1820,6 @@ Navigator::HasWifiManagerSupport(JSContext* /* unused */,
|
||||
permMgr->TestPermissionFromPrincipal(principal, "wifi-manage", &permission);
|
||||
return nsIPermissionManager::ALLOW_ACTION == permission;
|
||||
}
|
||||
#endif // MOZ_B2G_RIL
|
||||
|
||||
#ifdef MOZ_B2G_BT
|
||||
/* static */
|
||||
|
@ -264,9 +264,9 @@ public:
|
||||
JSObject* aGlobal);
|
||||
static bool HasIccManagerSupport(JSContext* /* unused */,
|
||||
JSObject* aGlobal);
|
||||
static bool HasWifiManagerSupport(JSContext* /* unused */,
|
||||
JSObject* aGlobal);
|
||||
#endif // MOZ_B2G_RIL
|
||||
static bool HasWifiManagerSupport(JSContext* /* unused */,
|
||||
JSObject* aGlobal);
|
||||
#ifdef MOZ_B2G_BT
|
||||
static bool HasBluetoothSupport(JSContext* /* unused */, JSObject* aGlobal);
|
||||
#endif // MOZ_B2G_BT
|
||||
|
@ -971,6 +971,13 @@ ParticularProcessPriorityManager::SetPriorityNow(ProcessPriority aPriority,
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
// Do not attempt to change the priority of the Nuwa process
|
||||
if (mContentParent->IsNuwaProcess()) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (aBackgroundLRU > 0 &&
|
||||
aPriority == PROCESS_PRIORITY_BACKGROUND &&
|
||||
mPriority == PROCESS_PRIORITY_BACKGROUND) {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -3811,37 +3811,39 @@ let RIL = {
|
||||
debug("handle supp svc notification: " + JSON.stringify(info));
|
||||
}
|
||||
|
||||
if (info.notificationType !== 1) {
|
||||
// We haven't supported MO intermediate result code, i.e.
|
||||
// info.notificationType === 0, which refers to code1 defined in 3GPP
|
||||
// 27.007 7.17. We only support partial MT unsolicited result code,
|
||||
// referring to code2, for now.
|
||||
return;
|
||||
}
|
||||
|
||||
let notification = null;
|
||||
let callIndex = -1;
|
||||
|
||||
if (info.notificationType === 0) {
|
||||
// MO intermediate result code. Refer to code1 defined in 3GPP 27.007
|
||||
// 7.17.
|
||||
} else if (info.notificationType === 1) {
|
||||
// MT unsolicited result code. Refer to code2 defined in 3GPP 27.007 7.17.
|
||||
switch (info.code) {
|
||||
case SUPP_SVC_NOTIFICATION_CODE2_PUT_ON_HOLD:
|
||||
case SUPP_SVC_NOTIFICATION_CODE2_RETRIEVED:
|
||||
notification = GECKO_SUPP_SVC_NOTIFICATION_FROM_CODE2[info.code];
|
||||
break;
|
||||
default:
|
||||
// Notification type not supported.
|
||||
return;
|
||||
}
|
||||
switch (info.code) {
|
||||
case SUPP_SVC_NOTIFICATION_CODE2_PUT_ON_HOLD:
|
||||
case SUPP_SVC_NOTIFICATION_CODE2_RETRIEVED:
|
||||
notification = GECKO_SUPP_SVC_NOTIFICATION_FROM_CODE2[info.code];
|
||||
break;
|
||||
default:
|
||||
// Notification type not supported.
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the target call object for this notification.
|
||||
let currentCallIndexes = Object.keys(this.currentCalls);
|
||||
if (currentCallIndexes.length === 1) {
|
||||
// Only one call exists. This should be the target.
|
||||
callIndex = currentCallIndexes[0];
|
||||
} else {
|
||||
// Find the call in |currentCalls| by the given number.
|
||||
if (info.number) {
|
||||
for each (let currentCall in this.currentCalls) {
|
||||
if (currentCall.number == info.number) {
|
||||
callIndex = currentCall.callIndex;
|
||||
break;
|
||||
}
|
||||
// Get the target call object for this notification.
|
||||
let currentCallIndexes = Object.keys(this.currentCalls);
|
||||
if (currentCallIndexes.length === 1) {
|
||||
// Only one call exists. This should be the target.
|
||||
callIndex = currentCallIndexes[0];
|
||||
} else {
|
||||
// Find the call in |currentCalls| by the given number.
|
||||
if (info.number) {
|
||||
for each (let currentCall in this.currentCalls) {
|
||||
if (currentCall.number == info.number) {
|
||||
callIndex = currentCall.callIndex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -315,7 +315,10 @@ TelephonyProvider.prototype = {
|
||||
case RIL.GECKO_SUPP_SVC_NOTIFICATION_REMOTE_RESUMED:
|
||||
return nsITelephonyProvider.NOTIFICATION_REMOTE_RESUMED;
|
||||
default:
|
||||
throw new Error("Unknown rilSuppSvcNotification: " + aNotification);
|
||||
if (DEBUG) {
|
||||
debug("Unknown rilSuppSvcNotification: " + aNotification);
|
||||
}
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -23,204 +23,13 @@
|
||||
|
||||
#include "DBusThread.h"
|
||||
#include "RawDBusConnection.h"
|
||||
#include "DBusUtils.h"
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "base/eintr_wrapper.h"
|
||||
#include "base/message_loop.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "mozilla/SyncRunnable.h"
|
||||
#include "mozilla/NullPtr.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "mozilla/FileUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#undef CHROMIUM_LOG
|
||||
#if defined(MOZ_WIDGET_GONK)
|
||||
#include <android/log.h>
|
||||
#define CHROMIUM_LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GonkDBus", args);
|
||||
#else
|
||||
#define BTDEBUG true
|
||||
#define CHROMIUM_LOG(args...) if (BTDEBUG) printf(args);
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
class DBusWatcher : public MessageLoopForIO::Watcher
|
||||
{
|
||||
public:
|
||||
DBusWatcher(RawDBusConnection* aConnection, DBusWatch* aWatch)
|
||||
: mConnection(aConnection),
|
||||
mWatch(aWatch)
|
||||
{
|
||||
MOZ_ASSERT(mConnection);
|
||||
MOZ_ASSERT(mWatch);
|
||||
}
|
||||
|
||||
~DBusWatcher()
|
||||
{ }
|
||||
|
||||
void StartWatching();
|
||||
void StopWatching();
|
||||
|
||||
static void FreeFunction(void* aData);
|
||||
static dbus_bool_t AddWatchFunction(DBusWatch* aWatch, void* aData);
|
||||
static void RemoveWatchFunction(DBusWatch* aWatch, void* aData);
|
||||
static void ToggleWatchFunction(DBusWatch* aWatch, void* aData);
|
||||
|
||||
RawDBusConnection* GetConnection();
|
||||
|
||||
private:
|
||||
void OnFileCanReadWithoutBlocking(int aFd);
|
||||
void OnFileCanWriteWithoutBlocking(int aFd);
|
||||
|
||||
// Read watcher for libevent. Only to be accessed on IO Thread.
|
||||
MessageLoopForIO::FileDescriptorWatcher mReadWatcher;
|
||||
|
||||
// Write watcher for libevent. Only to be accessed on IO Thread.
|
||||
MessageLoopForIO::FileDescriptorWatcher mWriteWatcher;
|
||||
|
||||
// DBus structures
|
||||
RawDBusConnection* mConnection;
|
||||
DBusWatch* mWatch;
|
||||
};
|
||||
|
||||
RawDBusConnection*
|
||||
DBusWatcher::GetConnection()
|
||||
{
|
||||
return mConnection;
|
||||
}
|
||||
|
||||
void DBusWatcher::StartWatching()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(mWatch);
|
||||
|
||||
int fd = dbus_watch_get_unix_fd(mWatch);
|
||||
|
||||
MessageLoopForIO* ioLoop = MessageLoopForIO::current();
|
||||
|
||||
unsigned int flags = dbus_watch_get_flags(mWatch);
|
||||
|
||||
if (flags & DBUS_WATCH_READABLE) {
|
||||
ioLoop->WatchFileDescriptor(fd, true, MessageLoopForIO::WATCH_READ,
|
||||
&mReadWatcher, this);
|
||||
}
|
||||
if (flags & DBUS_WATCH_WRITABLE) {
|
||||
ioLoop->WatchFileDescriptor(fd, true, MessageLoopForIO::WATCH_WRITE,
|
||||
&mWriteWatcher, this);
|
||||
}
|
||||
}
|
||||
|
||||
void DBusWatcher::StopWatching()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
unsigned int flags = dbus_watch_get_flags(mWatch);
|
||||
|
||||
if (flags & DBUS_WATCH_READABLE) {
|
||||
mReadWatcher.StopWatchingFileDescriptor();
|
||||
}
|
||||
if (flags & DBUS_WATCH_WRITABLE) {
|
||||
mWriteWatcher.StopWatchingFileDescriptor();
|
||||
}
|
||||
}
|
||||
|
||||
// DBus utility functions, used as function pointers in DBus setup
|
||||
|
||||
void
|
||||
DBusWatcher::FreeFunction(void* aData)
|
||||
{
|
||||
delete static_cast<DBusWatcher*>(aData);
|
||||
}
|
||||
|
||||
dbus_bool_t
|
||||
DBusWatcher::AddWatchFunction(DBusWatch* aWatch, void* aData)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
RawDBusConnection* connection = static_cast<RawDBusConnection*>(aData);
|
||||
|
||||
DBusWatcher* dbusWatcher = new DBusWatcher(connection, aWatch);
|
||||
dbus_watch_set_data(aWatch, dbusWatcher, DBusWatcher::FreeFunction);
|
||||
|
||||
if (dbus_watch_get_enabled(aWatch)) {
|
||||
dbusWatcher->StartWatching();
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
DBusWatcher::RemoveWatchFunction(DBusWatch* aWatch, void* aData)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
DBusWatcher* dbusWatcher =
|
||||
static_cast<DBusWatcher*>(dbus_watch_get_data(aWatch));
|
||||
dbusWatcher->StopWatching();
|
||||
}
|
||||
|
||||
void
|
||||
DBusWatcher::ToggleWatchFunction(DBusWatch* aWatch, void* aData)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
DBusWatcher* dbusWatcher =
|
||||
static_cast<DBusWatcher*>(dbus_watch_get_data(aWatch));
|
||||
|
||||
if (dbus_watch_get_enabled(aWatch)) {
|
||||
dbusWatcher->StartWatching();
|
||||
} else {
|
||||
dbusWatcher->StopWatching();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DBusWatcher::OnFileCanReadWithoutBlocking(int aFd)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
dbus_watch_handle(mWatch, DBUS_WATCH_READABLE);
|
||||
|
||||
DBusDispatchStatus dbusDispatchStatus;
|
||||
do {
|
||||
dbusDispatchStatus =
|
||||
dbus_connection_dispatch(mConnection->GetConnection());
|
||||
} while (dbusDispatchStatus == DBUS_DISPATCH_DATA_REMAINS);
|
||||
}
|
||||
|
||||
void
|
||||
DBusWatcher::OnFileCanWriteWithoutBlocking(int aFd)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
dbus_watch_handle(mWatch, DBUS_WATCH_WRITABLE);
|
||||
}
|
||||
|
||||
class WatchDBusConnectionTask : public Task
|
||||
{
|
||||
public:
|
||||
@ -232,15 +41,7 @@ public:
|
||||
|
||||
void Run()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
dbus_bool_t success =
|
||||
dbus_connection_set_watch_functions(mConnection->GetConnection(),
|
||||
DBusWatcher::AddWatchFunction,
|
||||
DBusWatcher::RemoveWatchFunction,
|
||||
DBusWatcher::ToggleWatchFunction,
|
||||
mConnection, nullptr);
|
||||
NS_ENSURE_TRUE_VOID(success == TRUE);
|
||||
mConnection->Watch();
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -23,13 +23,171 @@
|
||||
/* TODO: Remove BlueZ constant */
|
||||
#define BLUEZ_DBUS_BASE_IFC "org.bluez"
|
||||
|
||||
//
|
||||
// Runnables
|
||||
//
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
//
|
||||
// DBusWatcher
|
||||
//
|
||||
|
||||
class DBusWatcher : public MessageLoopForIO::Watcher
|
||||
{
|
||||
public:
|
||||
DBusWatcher(RawDBusConnection* aConnection, DBusWatch* aWatch)
|
||||
: mConnection(aConnection),
|
||||
mWatch(aWatch)
|
||||
{
|
||||
MOZ_ASSERT(mConnection);
|
||||
MOZ_ASSERT(mWatch);
|
||||
}
|
||||
|
||||
~DBusWatcher()
|
||||
{ }
|
||||
|
||||
void StartWatching();
|
||||
void StopWatching();
|
||||
|
||||
static void FreeFunction(void* aData);
|
||||
static dbus_bool_t AddWatchFunction(DBusWatch* aWatch, void* aData);
|
||||
static void RemoveWatchFunction(DBusWatch* aWatch, void* aData);
|
||||
static void ToggleWatchFunction(DBusWatch* aWatch, void* aData);
|
||||
|
||||
RawDBusConnection* GetConnection();
|
||||
|
||||
private:
|
||||
void OnFileCanReadWithoutBlocking(int aFd);
|
||||
void OnFileCanWriteWithoutBlocking(int aFd);
|
||||
|
||||
// Read watcher for libevent. Only to be accessed on IO Thread.
|
||||
MessageLoopForIO::FileDescriptorWatcher mReadWatcher;
|
||||
|
||||
// Write watcher for libevent. Only to be accessed on IO Thread.
|
||||
MessageLoopForIO::FileDescriptorWatcher mWriteWatcher;
|
||||
|
||||
// DBus structures
|
||||
RawDBusConnection* mConnection;
|
||||
DBusWatch* mWatch;
|
||||
};
|
||||
|
||||
RawDBusConnection*
|
||||
DBusWatcher::GetConnection()
|
||||
{
|
||||
return mConnection;
|
||||
}
|
||||
|
||||
void DBusWatcher::StartWatching()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(mWatch);
|
||||
|
||||
int fd = dbus_watch_get_unix_fd(mWatch);
|
||||
|
||||
MessageLoopForIO* ioLoop = MessageLoopForIO::current();
|
||||
|
||||
unsigned int flags = dbus_watch_get_flags(mWatch);
|
||||
|
||||
if (flags & DBUS_WATCH_READABLE) {
|
||||
ioLoop->WatchFileDescriptor(fd, true, MessageLoopForIO::WATCH_READ,
|
||||
&mReadWatcher, this);
|
||||
}
|
||||
if (flags & DBUS_WATCH_WRITABLE) {
|
||||
ioLoop->WatchFileDescriptor(fd, true, MessageLoopForIO::WATCH_WRITE,
|
||||
&mWriteWatcher, this);
|
||||
}
|
||||
}
|
||||
|
||||
void DBusWatcher::StopWatching()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
unsigned int flags = dbus_watch_get_flags(mWatch);
|
||||
|
||||
if (flags & DBUS_WATCH_READABLE) {
|
||||
mReadWatcher.StopWatchingFileDescriptor();
|
||||
}
|
||||
if (flags & DBUS_WATCH_WRITABLE) {
|
||||
mWriteWatcher.StopWatchingFileDescriptor();
|
||||
}
|
||||
}
|
||||
|
||||
// DBus utility functions, used as function pointers in DBus setup
|
||||
|
||||
void
|
||||
DBusWatcher::FreeFunction(void* aData)
|
||||
{
|
||||
delete static_cast<DBusWatcher*>(aData);
|
||||
}
|
||||
|
||||
dbus_bool_t
|
||||
DBusWatcher::AddWatchFunction(DBusWatch* aWatch, void* aData)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
RawDBusConnection* connection = static_cast<RawDBusConnection*>(aData);
|
||||
|
||||
DBusWatcher* dbusWatcher = new DBusWatcher(connection, aWatch);
|
||||
dbus_watch_set_data(aWatch, dbusWatcher, DBusWatcher::FreeFunction);
|
||||
|
||||
if (dbus_watch_get_enabled(aWatch)) {
|
||||
dbusWatcher->StartWatching();
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
DBusWatcher::RemoveWatchFunction(DBusWatch* aWatch, void* aData)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
DBusWatcher* dbusWatcher =
|
||||
static_cast<DBusWatcher*>(dbus_watch_get_data(aWatch));
|
||||
dbusWatcher->StopWatching();
|
||||
}
|
||||
|
||||
void
|
||||
DBusWatcher::ToggleWatchFunction(DBusWatch* aWatch, void* aData)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
DBusWatcher* dbusWatcher =
|
||||
static_cast<DBusWatcher*>(dbus_watch_get_data(aWatch));
|
||||
|
||||
if (dbus_watch_get_enabled(aWatch)) {
|
||||
dbusWatcher->StartWatching();
|
||||
} else {
|
||||
dbusWatcher->StopWatching();
|
||||
}
|
||||
}
|
||||
|
||||
// I/O-loop callbacks
|
||||
|
||||
void
|
||||
DBusWatcher::OnFileCanReadWithoutBlocking(int aFd)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
dbus_watch_handle(mWatch, DBUS_WATCH_READABLE);
|
||||
|
||||
DBusDispatchStatus dbusDispatchStatus;
|
||||
do {
|
||||
dbusDispatchStatus =
|
||||
dbus_connection_dispatch(mConnection->GetConnection());
|
||||
} while (dbusDispatchStatus == DBUS_DISPATCH_DATA_REMAINS);
|
||||
}
|
||||
|
||||
void
|
||||
DBusWatcher::OnFileCanWriteWithoutBlocking(int aFd)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
dbus_watch_handle(mWatch, DBUS_WATCH_WRITABLE);
|
||||
}
|
||||
|
||||
//
|
||||
// Notification
|
||||
//
|
||||
|
||||
class Notification
|
||||
{
|
||||
public:
|
||||
@ -103,6 +261,22 @@ nsresult RawDBusConnection::EstablishDBusConnection()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool RawDBusConnection::Watch()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(MessageLoop::current());
|
||||
|
||||
dbus_bool_t success =
|
||||
dbus_connection_set_watch_functions(mConnection,
|
||||
DBusWatcher::AddWatchFunction,
|
||||
DBusWatcher::RemoveWatchFunction,
|
||||
DBusWatcher::ToggleWatchFunction,
|
||||
this, nullptr);
|
||||
NS_ENSURE_TRUE(success == TRUE, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RawDBusConnection::ScopedDBusConnectionPtrTraits::release(DBusConnection* ptr)
|
||||
{
|
||||
if (ptr) {
|
||||
|
@ -31,6 +31,8 @@ public:
|
||||
|
||||
nsresult EstablishDBusConnection();
|
||||
|
||||
bool Watch();
|
||||
|
||||
DBusConnection* GetConnection()
|
||||
{
|
||||
return mConnection;
|
||||
|
@ -34,7 +34,6 @@ public class PanelGridView extends GridView
|
||||
super(context, null, R.attr.panelGridViewStyle);
|
||||
mAdapter = new PanelGridViewAdapter(context);
|
||||
setAdapter(mAdapter);
|
||||
setNumColumns(AUTO_FIT);
|
||||
setOnItemClickListener(new PanelGridItemClickListener());
|
||||
}
|
||||
|
||||
|
@ -41,11 +41,11 @@ public class PanelListRow extends TwoLineRow {
|
||||
|
||||
int titleIndex = cursor.getColumnIndexOrThrow(HomeItems.TITLE);
|
||||
final String title = cursor.getString(titleIndex);
|
||||
setPrimaryText(title);
|
||||
setTitle(title);
|
||||
|
||||
int urlIndex = cursor.getColumnIndexOrThrow(HomeItems.URL);
|
||||
final String url = cursor.getString(urlIndex);
|
||||
setSecondaryText(url);
|
||||
setDescription(url);
|
||||
|
||||
int imageIndex = cursor.getColumnIndexOrThrow(HomeItems.IMAGE_URL);
|
||||
final String imageUrl = cursor.getString(imageIndex);
|
||||
|
@ -21,12 +21,19 @@ import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
public class TwoLinePageRow extends TwoLineRow
|
||||
implements Tabs.OnTabsChangedListener {
|
||||
|
||||
private static final int NO_ICON = 0;
|
||||
|
||||
private final TextView mDescription;
|
||||
private int mSwitchToTabIconId;
|
||||
private int mPageTypeIconId;
|
||||
|
||||
private final FaviconView mFavicon;
|
||||
|
||||
private boolean mShowIcons;
|
||||
@ -72,6 +79,10 @@ public class TwoLinePageRow extends TwoLineRow
|
||||
|
||||
mShowIcons = true;
|
||||
|
||||
mDescription = (TextView) findViewById(R.id.description);
|
||||
mSwitchToTabIconId = NO_ICON;
|
||||
mPageTypeIconId = NO_ICON;
|
||||
|
||||
mFavicon = (FaviconView) findViewById(R.id.icon);
|
||||
mFaviconListener = new UpdateViewFaviconLoadedListener(mFavicon);
|
||||
}
|
||||
@ -104,6 +115,24 @@ public class TwoLinePageRow extends TwoLineRow
|
||||
}
|
||||
}
|
||||
|
||||
private void setSwitchToTabIcon(int iconId) {
|
||||
if (mSwitchToTabIconId == iconId) {
|
||||
return;
|
||||
}
|
||||
|
||||
mSwitchToTabIconId = iconId;
|
||||
mDescription.setCompoundDrawablesWithIntrinsicBounds(mSwitchToTabIconId, 0, mPageTypeIconId, 0);
|
||||
}
|
||||
|
||||
private void setPageTypeIcon(int iconId) {
|
||||
if (mPageTypeIconId == iconId) {
|
||||
return;
|
||||
}
|
||||
|
||||
mPageTypeIconId = iconId;
|
||||
mDescription.setCompoundDrawablesWithIntrinsicBounds(mSwitchToTabIconId, 0, mPageTypeIconId, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the page URL, so that we can use it to replace "Switch to tab" if the open
|
||||
* tab changes or is closed.
|
||||
@ -122,11 +151,11 @@ public class TwoLinePageRow extends TwoLineRow
|
||||
boolean isPrivate = Tabs.getInstance().getSelectedTab().isPrivate();
|
||||
Tab tab = Tabs.getInstance().getFirstTabForUrl(mPageUrl, isPrivate);
|
||||
if (!mShowIcons || tab == null) {
|
||||
setSecondaryText(mPageUrl);
|
||||
setSecondaryIcon(NO_ICON);
|
||||
setDescription(mPageUrl);
|
||||
setSwitchToTabIcon(NO_ICON);
|
||||
} else {
|
||||
setSecondaryText(R.string.switch_to_tab);
|
||||
setSecondaryIcon(R.drawable.ic_url_bar_tab);
|
||||
setDescription(R.string.switch_to_tab);
|
||||
setSwitchToTabIcon(R.drawable.ic_url_bar_tab);
|
||||
}
|
||||
}
|
||||
|
||||
@ -162,20 +191,20 @@ public class TwoLinePageRow extends TwoLineRow
|
||||
// The bookmark id will be 0 (null in database) when the url
|
||||
// is not a bookmark.
|
||||
if (bookmarkId == 0) {
|
||||
setPrimaryIcon(NO_ICON);
|
||||
setPageTypeIcon(NO_ICON);
|
||||
} else if (display == Combined.DISPLAY_READER) {
|
||||
setPrimaryIcon(R.drawable.ic_url_bar_reader);
|
||||
setPageTypeIcon(R.drawable.ic_url_bar_reader);
|
||||
} else {
|
||||
setPrimaryIcon(R.drawable.ic_url_bar_star);
|
||||
setPageTypeIcon(R.drawable.ic_url_bar_star);
|
||||
}
|
||||
} else {
|
||||
setPrimaryIcon(NO_ICON);
|
||||
setPageTypeIcon(NO_ICON);
|
||||
}
|
||||
}
|
||||
|
||||
// Use the URL instead of an empty title for consistency with the normal URL
|
||||
// bar view - this is the equivalent of getDisplayTitle() in Tab.java
|
||||
setPrimaryText(TextUtils.isEmpty(title) ? url : title);
|
||||
setTitle(TextUtils.isEmpty(title) ? url : title);
|
||||
|
||||
// No point updating the below things if URL has not changed. Prevents evil Favicon flicker.
|
||||
if (url.equals(mPageUrl)) {
|
||||
|
@ -18,13 +18,8 @@ import android.widget.TextView;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
public abstract class TwoLineRow extends LinearLayout {
|
||||
protected static final int NO_ICON = 0;
|
||||
|
||||
private final TextView mPrimaryText;
|
||||
private int mPrimaryIconId;
|
||||
|
||||
private final TextView mSecondaryText;
|
||||
private int mSecondaryIconId;
|
||||
private final TextView mTitle;
|
||||
private final TextView mDescription;
|
||||
|
||||
public TwoLineRow(Context context) {
|
||||
this(context, null);
|
||||
@ -35,42 +30,21 @@ public abstract class TwoLineRow extends LinearLayout {
|
||||
|
||||
setGravity(Gravity.CENTER_VERTICAL);
|
||||
|
||||
mSecondaryIconId = NO_ICON;
|
||||
mPrimaryIconId = NO_ICON;
|
||||
|
||||
LayoutInflater.from(context).inflate(R.layout.two_line_row, this);
|
||||
mPrimaryText = (TextView) findViewById(R.id.primary_text);
|
||||
mSecondaryText = (TextView) findViewById(R.id.secondary_text);
|
||||
mTitle = (TextView) findViewById(R.id.title);
|
||||
mDescription = (TextView) findViewById(R.id.description);
|
||||
}
|
||||
|
||||
protected void setPrimaryText(String text) {
|
||||
mPrimaryText.setText(text);
|
||||
protected void setTitle(String text) {
|
||||
mTitle.setText(text);
|
||||
}
|
||||
|
||||
protected void setSecondaryText(String text) {
|
||||
mSecondaryText.setText(text);
|
||||
protected void setDescription(String text) {
|
||||
mDescription.setText(text);
|
||||
}
|
||||
|
||||
protected void setSecondaryText(int stringId) {
|
||||
mSecondaryText.setText(stringId);
|
||||
}
|
||||
|
||||
protected void setPrimaryIcon(int iconId) {
|
||||
if (mPrimaryIconId == iconId) {
|
||||
return;
|
||||
}
|
||||
|
||||
mPrimaryIconId = iconId;
|
||||
mSecondaryText.setCompoundDrawablesWithIntrinsicBounds(mSecondaryIconId, 0, mPrimaryIconId, 0);
|
||||
}
|
||||
|
||||
protected void setSecondaryIcon(int iconId) {
|
||||
if (mSecondaryIconId == iconId) {
|
||||
return;
|
||||
}
|
||||
|
||||
mSecondaryIconId = iconId;
|
||||
mSecondaryText.setCompoundDrawablesWithIntrinsicBounds(mSecondaryIconId, 0, mPrimaryIconId, 0);
|
||||
protected void setDescription(int stringId) {
|
||||
mDescription.setText(stringId);
|
||||
}
|
||||
|
||||
public abstract void updateFromCursor(Cursor cursor);
|
||||
|
@ -68,13 +68,13 @@ public class PanelsPreferenceCategory extends CustomListCategory {
|
||||
@Override
|
||||
public void onPostExecute(List<PanelConfig> panelConfigs) {
|
||||
mPanelConfigs = panelConfigs;
|
||||
displayPanelConfig();
|
||||
displayHomeConfig();
|
||||
}
|
||||
};
|
||||
mLoadTask.execute();
|
||||
}
|
||||
|
||||
private void displayPanelConfig() {
|
||||
private void displayHomeConfig() {
|
||||
for (PanelConfig panelConfig : mPanelConfigs) {
|
||||
// Create and add the pref.
|
||||
final PanelsPreference pref = new PanelsPreference(getContext(), PanelsPreferenceCategory.this);
|
||||
@ -145,13 +145,13 @@ public class PanelsPreferenceCategory extends CustomListCategory {
|
||||
* Update the local HomeConfig default state from mDefaultReference.
|
||||
*/
|
||||
private void updateConfigDefault() {
|
||||
String mId = null;
|
||||
String id = null;
|
||||
if (mDefaultReference != null) {
|
||||
mId = mDefaultReference.getKey();
|
||||
id = mDefaultReference.getKey();
|
||||
}
|
||||
|
||||
for (PanelConfig panelConfig : mPanelConfigs) {
|
||||
if (TextUtils.equals(panelConfig.getId(), mId)) {
|
||||
if (TextUtils.equals(panelConfig.getId(), id)) {
|
||||
panelConfig.setIsDefault(true);
|
||||
panelConfig.setIsDisabled(false);
|
||||
} else {
|
||||
@ -166,10 +166,10 @@ public class PanelsPreferenceCategory extends CustomListCategory {
|
||||
// This could change the default, so update the local version of the config.
|
||||
updateConfigDefault();
|
||||
|
||||
final String mId = pref.getKey();
|
||||
final String id = pref.getKey();
|
||||
PanelConfig toRemove = null;
|
||||
for (PanelConfig panelConfig : mPanelConfigs) {
|
||||
if (TextUtils.equals(panelConfig.getId(), mId)) {
|
||||
if (TextUtils.equals(panelConfig.getId(), id)) {
|
||||
toRemove = panelConfig;
|
||||
break;
|
||||
}
|
||||
@ -190,9 +190,9 @@ public class PanelsPreferenceCategory extends CustomListCategory {
|
||||
pref.setHidden(toHide);
|
||||
ensureDefaultForHide(pref, toHide);
|
||||
|
||||
final String mId = pref.getKey();
|
||||
final String id = pref.getKey();
|
||||
for (PanelConfig panelConfig : mPanelConfigs) {
|
||||
if (TextUtils.equals(panelConfig.getId(), mId)) {
|
||||
if (TextUtils.equals(panelConfig.getId(), id)) {
|
||||
panelConfig.setIsDisabled(toHide);
|
||||
break;
|
||||
}
|
||||
|
@ -18,14 +18,14 @@
|
||||
android:orientation="vertical">
|
||||
|
||||
<org.mozilla.gecko.home.FadedTextView
|
||||
android:id="@+id/primary_text"
|
||||
style="@style/Widget.TwoLineRow.PrimaryText"
|
||||
android:id="@+id/title"
|
||||
style="@style/Widget.TwoLineRow.Title"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
gecko:fadeWidth="30dp"/>
|
||||
|
||||
<TextView android:id="@+id/secondary_text"
|
||||
style="@style/Widget.TwoLineRow.SecondaryText"
|
||||
<TextView android:id="@+id/description"
|
||||
style="@style/Widget.TwoLineRow.Description"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawablePadding="5dp"
|
||||
|
@ -9,7 +9,7 @@
|
||||
<item name="android:orientation">vertical</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.BookmarkFolderView" parent="Widget.TwoLineRow.PrimaryText">
|
||||
<style name="Widget.BookmarkFolderView" parent="Widget.TwoLineRow.Title">
|
||||
<item name="android:paddingLeft">60dip</item>
|
||||
<item name="android:drawablePadding">10dip</item>
|
||||
<item name="android:drawableLeft">@drawable/bookmark_folder</item>
|
||||
|
@ -9,5 +9,6 @@
|
||||
<dimen name="browser_toolbar_button_padding">16dp</dimen>
|
||||
<dimen name="menu_popup_arrow_margin">8dip</dimen>
|
||||
<dimen name="tabs_counter_size">26sp</dimen>
|
||||
<dimen name="panel_grid_view_column_width">200dp</dimen>
|
||||
|
||||
</resources>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<item name="android:fontFamily">sans-serif-light</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.Widget.TwoLineRow.PrimaryText" parent="TextAppearance.Medium">
|
||||
<style name="TextAppearance.Widget.TwoLineRow.Title" parent="TextAppearance.Medium">
|
||||
<item name="android:fontFamily">sans-serif-light</item>
|
||||
</style>
|
||||
|
||||
|
@ -103,5 +103,5 @@
|
||||
<dimen name="icongrid_padding">16dp</dimen>
|
||||
|
||||
<!-- PanelGridView dimensions -->
|
||||
<dimen name="panel_grid_view_column_width">180dp</dimen>
|
||||
<dimen name="panel_grid_view_column_width">150dp</dimen>
|
||||
</resources>
|
||||
|
@ -111,20 +111,20 @@
|
||||
|
||||
<style name="Widget.TwoLineRow" />
|
||||
|
||||
<style name="Widget.TwoLineRow.PrimaryText">
|
||||
<item name="android:textAppearance">@style/TextAppearance.Widget.TwoLineRow.PrimaryText</item>
|
||||
<style name="Widget.TwoLineRow.Title">
|
||||
<item name="android:textAppearance">@style/TextAppearance.Widget.TwoLineRow.Title</item>
|
||||
<item name="android:singleLine">true</item>
|
||||
<item name="android:ellipsize">none</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.TwoLineRow.SecondaryText">
|
||||
<item name="android:textAppearance">@style/TextAppearance.Widget.TwoLineRow.SecondaryText</item>
|
||||
<style name="Widget.TwoLineRow.Description">
|
||||
<item name="android:textAppearance">@style/TextAppearance.Widget.TwoLineRow.Description</item>
|
||||
<item name="android:includeFontPadding">false</item>
|
||||
<item name="android:singleLine">true</item>
|
||||
<item name="android:ellipsize">middle</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.BookmarkFolderView" parent="Widget.TwoLineRow.PrimaryText">
|
||||
<style name="Widget.BookmarkFolderView" parent="Widget.TwoLineRow.Title">
|
||||
<item name="android:paddingLeft">10dip</item>
|
||||
<item name="android:drawablePadding">10dip</item>
|
||||
<item name="android:drawableLeft">@drawable/bookmark_folder</item>
|
||||
@ -150,19 +150,20 @@
|
||||
<item name="android:layout_height">fill_parent</item>
|
||||
<item name="android:paddingTop">0dp</item>
|
||||
<item name="android:stretchMode">columnWidth</item>
|
||||
<item name="android:numColumns">auto_fit</item>
|
||||
<item name="android:columnWidth">@dimen/panel_grid_view_column_width</item>
|
||||
<item name="android:horizontalSpacing">2dp</item>
|
||||
<item name="android:verticalSpacing">2dp</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.PanelGridItemView">
|
||||
<item name="android:layout_width">fill_parent</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.PanelGridItemImageView">
|
||||
<item name="android:layout_height">@dimen/panel_grid_view_column_width</item>
|
||||
<item name="android:layout_width">fill_parent</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:scaleType">centerCrop</item>
|
||||
<item name="android:adjustViewBounds">true</item>
|
||||
<item name="android:background">@color/panel_grid_item_image_background</item>
|
||||
@ -344,9 +345,9 @@
|
||||
|
||||
<style name="TextAppearance.Widget.TwoLineRow" />
|
||||
|
||||
<style name="TextAppearance.Widget.TwoLineRow.PrimaryText" parent="TextAppearance.Medium"/>
|
||||
<style name="TextAppearance.Widget.TwoLineRow.Title" parent="TextAppearance.Medium"/>
|
||||
|
||||
<style name="TextAppearance.Widget.TwoLineRow.SecondaryText" parent="TextAppearance.Micro">
|
||||
<style name="TextAppearance.Widget.TwoLineRow.Description" parent="TextAppearance.Micro">
|
||||
<item name="android:textColor">?android:attr/textColorSecondary</item>
|
||||
</style>
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
Cu.import("resource://gre/modules/osfile.jsm")
|
||||
Cu.import("resource://gre/modules/osfile.jsm");
|
||||
|
||||
function run_test() {
|
||||
initTestLogging();
|
||||
|
@ -17,11 +17,57 @@ Cu.import("resource://gre/modules/Timer.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/FxAccountsClient.jsm");
|
||||
Cu.import("resource://gre/modules/FxAccountsCommon.js");
|
||||
Cu.import("resource://gre/modules/FxAccountsUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "jwcrypto",
|
||||
"resource://gre/modules/identity/jwcrypto.jsm");
|
||||
"resource://gre/modules/identity/jwcrypto.jsm");
|
||||
|
||||
InternalMethods = function(mock) {
|
||||
// All properties exposed by the public FxAccounts API.
|
||||
let publicProperties = [
|
||||
"getAccountsURI",
|
||||
"getAssertion",
|
||||
"getKeys",
|
||||
"getSignedInUser",
|
||||
"loadAndPoll",
|
||||
"localtimeOffsetMsec",
|
||||
"now",
|
||||
"promiseAccountsForceSigninURI",
|
||||
"resendVerificationEmail",
|
||||
"setSignedInUser",
|
||||
"signOut",
|
||||
"version",
|
||||
"whenVerified"
|
||||
];
|
||||
|
||||
/**
|
||||
* The public API's constructor.
|
||||
*/
|
||||
this.FxAccounts = function (mockInternal) {
|
||||
let internal = new FxAccountsInternal();
|
||||
let external = {};
|
||||
|
||||
// Copy all public properties to the 'external' object.
|
||||
let prototype = FxAccountsInternal.prototype;
|
||||
let options = {keys: publicProperties, bind: internal};
|
||||
FxAccountsUtils.copyObjectProperties(prototype, external, options);
|
||||
|
||||
// Copy all of the mock's properties to the internal object.
|
||||
if (mockInternal && !mockInternal.onlySetInternal) {
|
||||
FxAccountsUtils.copyObjectProperties(mockInternal, internal);
|
||||
}
|
||||
|
||||
if (mockInternal) {
|
||||
// Exposes the internal object for testing only.
|
||||
external.internal = internal;
|
||||
}
|
||||
|
||||
return Object.freeze(external);
|
||||
}
|
||||
|
||||
/**
|
||||
* The internal API's constructor.
|
||||
*/
|
||||
function FxAccountsInternal() {
|
||||
this.cert = null;
|
||||
this.keyPair = null;
|
||||
this.signedInUser = null;
|
||||
@ -49,23 +95,23 @@ InternalMethods = function(mock) {
|
||||
|
||||
this.fxAccountsClient = new FxAccountsClient();
|
||||
|
||||
if (mock) { // Testing.
|
||||
Object.keys(mock).forEach((prop) => {
|
||||
log.debug("InternalMethods: mocking: " + prop);
|
||||
this[prop] = mock[prop];
|
||||
});
|
||||
}
|
||||
if (!this.signedInUserStorage) {
|
||||
// Normal (i.e., non-testing) initialization.
|
||||
// We don't reference |profileDir| in the top-level module scope
|
||||
// as we may be imported before we know where it is.
|
||||
this.signedInUserStorage = new JSONStorage({
|
||||
filename: DEFAULT_STORAGE_FILENAME,
|
||||
baseDir: OS.Constants.Path.profileDir,
|
||||
});
|
||||
}
|
||||
// We don't reference |profileDir| in the top-level module scope
|
||||
// as we may be imported before we know where it is.
|
||||
this.signedInUserStorage = new JSONStorage({
|
||||
filename: DEFAULT_STORAGE_FILENAME,
|
||||
baseDir: OS.Constants.Path.profileDir,
|
||||
});
|
||||
}
|
||||
InternalMethods.prototype = {
|
||||
|
||||
/**
|
||||
* The internal API's prototype.
|
||||
*/
|
||||
FxAccountsInternal.prototype = {
|
||||
|
||||
/**
|
||||
* The current data format's version number.
|
||||
*/
|
||||
version: DATA_FORMAT_VERSION,
|
||||
|
||||
/**
|
||||
* Return the current time in milliseconds as an integer. Allows tests to
|
||||
@ -102,6 +148,125 @@ InternalMethods.prototype = {
|
||||
return this.fxAccountsClient.accountKeys(keyFetchToken);
|
||||
},
|
||||
|
||||
// set() makes sure that polling is happening, if necessary.
|
||||
// get() does not wait for verification, and returns an object even if
|
||||
// unverified. The caller of get() must check .verified .
|
||||
// The "fxaccounts:onverified" event will fire only when the verified
|
||||
// state goes from false to true, so callers must register their observer
|
||||
// and then call get(). In particular, it will not fire when the account
|
||||
// was found to be verified in a previous boot: if our stored state says
|
||||
// the account is verified, the event will never fire. So callers must do:
|
||||
// register notification observer (go)
|
||||
// userdata = get()
|
||||
// if (userdata.verified()) {go()}
|
||||
|
||||
/**
|
||||
* Get the user currently signed in to Firefox Accounts.
|
||||
*
|
||||
* @return Promise
|
||||
* The promise resolves to the credentials object of the signed-in user:
|
||||
* {
|
||||
* email: The user's email address
|
||||
* uid: The user's unique id
|
||||
* sessionToken: Session for the FxA server
|
||||
* kA: An encryption key from the FxA server
|
||||
* kB: An encryption key derived from the user's FxA password
|
||||
* verified: email verification status
|
||||
* }
|
||||
* or null if no user is signed in.
|
||||
*/
|
||||
getSignedInUser: function getSignedInUser() {
|
||||
return this.getUserAccountData().then(data => {
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
if (!this.isUserEmailVerified(data)) {
|
||||
// If the email is not verified, start polling for verification,
|
||||
// but return null right away. We don't want to return a promise
|
||||
// that might not be fulfilled for a long time.
|
||||
this.startVerifiedCheck(data);
|
||||
}
|
||||
return data;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the current user signed in to Firefox Accounts.
|
||||
*
|
||||
* @param credentials
|
||||
* The credentials object obtained by logging in or creating
|
||||
* an account on the FxA server:
|
||||
* {
|
||||
* email: The users email address
|
||||
* uid: The user's unique id
|
||||
* sessionToken: Session for the FxA server
|
||||
* keyFetchToken: an unused keyFetchToken
|
||||
* verified: true/false
|
||||
* }
|
||||
* @return Promise
|
||||
* The promise resolves to null when the data is saved
|
||||
* successfully and is rejected on error.
|
||||
*/
|
||||
setSignedInUser: function setSignedInUser(credentials) {
|
||||
log.debug("setSignedInUser - aborting any existing flows");
|
||||
this.abortExistingFlow();
|
||||
|
||||
let record = {version: this.version, accountData: credentials};
|
||||
// Cache a clone of the credentials object.
|
||||
this.signedInUser = JSON.parse(JSON.stringify(record));
|
||||
|
||||
// This promise waits for storage, but not for verification.
|
||||
// We're telling the caller that this is durable now.
|
||||
return this.signedInUserStorage.set(record).then(() => {
|
||||
this.notifyObservers(ONLOGIN_NOTIFICATION);
|
||||
if (!this.isUserEmailVerified(credentials)) {
|
||||
this.startVerifiedCheck(credentials);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* returns a promise that fires with the assertion. If there is no verified
|
||||
* signed-in user, fires with null.
|
||||
*/
|
||||
getAssertion: function getAssertion(audience) {
|
||||
log.debug("enter getAssertion()");
|
||||
let mustBeValidUntil = this.now() + ASSERTION_LIFETIME;
|
||||
return this.getUserAccountData().then(data => {
|
||||
if (!data) {
|
||||
// No signed-in user
|
||||
return null;
|
||||
}
|
||||
if (!this.isUserEmailVerified(data)) {
|
||||
// Signed-in user has not verified email
|
||||
return null;
|
||||
}
|
||||
return this.getKeyPair(mustBeValidUntil).then(keyPair => {
|
||||
return this.getCertificate(data, keyPair, mustBeValidUntil)
|
||||
.then(cert => {
|
||||
return this.getAssertionFromCert(data, keyPair, cert, audience);
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Resend the verification email fot the currently signed-in user.
|
||||
*
|
||||
*/
|
||||
resendVerificationEmail: function resendVerificationEmail() {
|
||||
return this.getSignedInUser().then(data => {
|
||||
// If the caller is asking for verification to be re-sent, and there is
|
||||
// no signed-in user to begin with, this is probably best regarded as an
|
||||
// error.
|
||||
if (data) {
|
||||
this.pollEmailStatus(data.sessionToken, "start");
|
||||
return this.fxAccountsClient.resendVerificationEmail(data.sessionToken);
|
||||
}
|
||||
throw new Error("Cannot resend verification email; no signed-in user");
|
||||
});
|
||||
},
|
||||
|
||||
/*
|
||||
* Reset state such that any previous flow is canceled.
|
||||
*/
|
||||
@ -179,14 +344,14 @@ InternalMethods.prototype = {
|
||||
return Task.spawn(function* task() {
|
||||
// Sign out if we don't have a key fetch token.
|
||||
if (!keyFetchToken) {
|
||||
yield internal.signOut();
|
||||
yield this.signOut();
|
||||
return null;
|
||||
}
|
||||
let myGenerationCount = internal.generationCount;
|
||||
let myGenerationCount = this.generationCount;
|
||||
|
||||
let {kA, wrapKB} = yield internal.fetchKeys(keyFetchToken);
|
||||
let {kA, wrapKB} = yield this.fetchKeys(keyFetchToken);
|
||||
|
||||
let data = yield internal.getUserAccountData();
|
||||
let data = yield this.getUserAccountData();
|
||||
|
||||
// Sanity check that the user hasn't changed out from under us
|
||||
if (data.keyFetchToken !== keyFetchToken) {
|
||||
@ -208,16 +373,16 @@ InternalMethods.prototype = {
|
||||
|
||||
// Before writing any data, ensure that a new flow hasn't been
|
||||
// started behind our backs.
|
||||
if (internal.generationCount !== myGenerationCount) {
|
||||
if (this.generationCount !== myGenerationCount) {
|
||||
return null;
|
||||
}
|
||||
|
||||
yield internal.setUserAccountData(data);
|
||||
yield this.setUserAccountData(data);
|
||||
|
||||
// We are now ready for business. This should only be invoked once
|
||||
// per setSignedInUser(), regardless of whether we've rebooted since
|
||||
// setSignedInUser() was called.
|
||||
internal.notifyObservers(ONVERIFIED_NOTIFICATION);
|
||||
this.notifyObservers(ONVERIFIED_NOTIFICATION);
|
||||
return data;
|
||||
}.bind(this));
|
||||
},
|
||||
@ -227,8 +392,8 @@ InternalMethods.prototype = {
|
||||
let payload = {};
|
||||
let d = Promise.defer();
|
||||
let options = {
|
||||
localtimeOffsetMsec: internal.localtimeOffsetMsec,
|
||||
now: internal.now()
|
||||
localtimeOffsetMsec: this.localtimeOffsetMsec,
|
||||
now: this.now()
|
||||
};
|
||||
// "audience" should look like "http://123done.org".
|
||||
// The generated assertion will expire in two minutes.
|
||||
@ -252,7 +417,7 @@ InternalMethods.prototype = {
|
||||
return Promise.resolve(this.cert.cert);
|
||||
}
|
||||
// else get our cert signed
|
||||
let willBeValidUntil = internal.now() + CERT_LIFETIME;
|
||||
let willBeValidUntil = this.now() + CERT_LIFETIME;
|
||||
return this.getCertificateSigned(data.sessionToken,
|
||||
keyPair.serializedPublicKey,
|
||||
CERT_LIFETIME)
|
||||
@ -279,7 +444,7 @@ InternalMethods.prototype = {
|
||||
return Promise.resolve(this.keyPair.keyPair);
|
||||
}
|
||||
// Otherwse, create a keypair and set validity limit.
|
||||
let willBeValidUntil = internal.now() + KEY_LIFETIME;
|
||||
let willBeValidUntil = this.now() + KEY_LIFETIME;
|
||||
let d = Promise.defer();
|
||||
jwcrypto.generateKeyPair("DS160", (err, kp) => {
|
||||
if (err) {
|
||||
@ -368,18 +533,6 @@ InternalMethods.prototype = {
|
||||
return this.whenVerifiedPromise.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
* Resend the verification email to the logged-in user.
|
||||
*
|
||||
* @return Promise
|
||||
* fulfilled: json data returned from xhr call
|
||||
* rejected: error
|
||||
*/
|
||||
resendVerificationEmail: function(data) {
|
||||
this.pollEmailStatus(data.sessionToken, "start");
|
||||
return this.fxAccountsClient.resendVerificationEmail(data.sessionToken);
|
||||
},
|
||||
|
||||
notifyObservers: function(topic) {
|
||||
log.debug("Notifying observers of " + topic);
|
||||
Services.obs.notifyObservers(null, topic, null);
|
||||
@ -445,194 +598,12 @@ InternalMethods.prototype = {
|
||||
},
|
||||
|
||||
setUserAccountData: function(accountData) {
|
||||
return this.signedInUserStorage.get().then((record) => {
|
||||
return this.signedInUserStorage.get().then(record => {
|
||||
record.accountData = accountData;
|
||||
this.signedInUser = record;
|
||||
return this.signedInUserStorage.set(record)
|
||||
.then(() => accountData);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
let internal = null;
|
||||
|
||||
/**
|
||||
* FxAccounts delegates private methods to an instance of InternalMethods,
|
||||
* which is not exported. The xpcshell tests need two overrides:
|
||||
* 1) Access to the real internal.signedInUserStorage.
|
||||
* 2) The ability to mock InternalMethods.
|
||||
* If mockInternal is undefined, we are live.
|
||||
* If mockInternal.onlySetInternal is present, we are executing the first
|
||||
* case by binding internal to the FxAccounts instance.
|
||||
* Otherwise if we have a mock instance, we are executing the second case.
|
||||
*/
|
||||
this.FxAccounts = function(mockInternal) {
|
||||
let mocks = mockInternal;
|
||||
if (mocks && mocks.onlySetInternal) {
|
||||
mocks = null;
|
||||
}
|
||||
internal = new InternalMethods(mocks);
|
||||
if (mockInternal) {
|
||||
// Exposes the internal object for testing only.
|
||||
this.internal = internal;
|
||||
}
|
||||
}
|
||||
this.FxAccounts.prototype = Object.freeze({
|
||||
version: DATA_FORMAT_VERSION,
|
||||
|
||||
now: function() {
|
||||
if (this.internal) {
|
||||
return this.internal.now();
|
||||
}
|
||||
return internal.now();
|
||||
},
|
||||
|
||||
get localtimeOffsetMsec() {
|
||||
if (this.internal) {
|
||||
return this.internal.localtimeOffsetMsec;
|
||||
}
|
||||
return internal.localtimeOffsetMsec;
|
||||
},
|
||||
|
||||
// set() makes sure that polling is happening, if necessary.
|
||||
// get() does not wait for verification, and returns an object even if
|
||||
// unverified. The caller of get() must check .verified .
|
||||
// The "fxaccounts:onverified" event will fire only when the verified
|
||||
// state goes from false to true, so callers must register their observer
|
||||
// and then call get(). In particular, it will not fire when the account
|
||||
// was found to be verified in a previous boot: if our stored state says
|
||||
// the account is verified, the event will never fire. So callers must do:
|
||||
// register notification observer (go)
|
||||
// userdata = get()
|
||||
// if (userdata.verified()) {go()}
|
||||
|
||||
/**
|
||||
* Set the current user signed in to Firefox Accounts.
|
||||
*
|
||||
* @param credentials
|
||||
* The credentials object obtained by logging in or creating
|
||||
* an account on the FxA server:
|
||||
* {
|
||||
* email: The users email address
|
||||
* uid: The user's unique id
|
||||
* sessionToken: Session for the FxA server
|
||||
* keyFetchToken: an unused keyFetchToken
|
||||
* verified: true/false
|
||||
* }
|
||||
* @return Promise
|
||||
* The promise resolves to null when the data is saved
|
||||
* successfully and is rejected on error.
|
||||
*/
|
||||
setSignedInUser: function setSignedInUser(credentials) {
|
||||
log.debug("setSignedInUser - aborting any existing flows");
|
||||
internal.abortExistingFlow();
|
||||
|
||||
let record = {version: this.version, accountData: credentials};
|
||||
// Cache a clone of the credentials object.
|
||||
internal.signedInUser = JSON.parse(JSON.stringify(record));
|
||||
|
||||
// This promise waits for storage, but not for verification.
|
||||
// We're telling the caller that this is durable now.
|
||||
return internal.signedInUserStorage.set(record)
|
||||
.then(() => {
|
||||
internal.notifyObservers(ONLOGIN_NOTIFICATION);
|
||||
if (!internal.isUserEmailVerified(credentials)) {
|
||||
internal.startVerifiedCheck(credentials);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the user currently signed in to Firefox Accounts.
|
||||
*
|
||||
* @return Promise
|
||||
* The promise resolves to the credentials object of the signed-in user:
|
||||
* {
|
||||
* email: The user's email address
|
||||
* uid: The user's unique id
|
||||
* sessionToken: Session for the FxA server
|
||||
* kA: An encryption key from the FxA server
|
||||
* kB: An encryption key derived from the user's FxA password
|
||||
* verified: email verification status
|
||||
* }
|
||||
* or null if no user is signed in.
|
||||
*/
|
||||
getSignedInUser: function getSignedInUser() {
|
||||
return internal.getUserAccountData()
|
||||
.then((data) => {
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
if (!internal.isUserEmailVerified(data)) {
|
||||
// If the email is not verified, start polling for verification,
|
||||
// but return null right away. We don't want to return a promise
|
||||
// that might not be fulfilled for a long time.
|
||||
internal.startVerifiedCheck(data);
|
||||
}
|
||||
return data;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Resend the verification email fot the currently signed-in user.
|
||||
*
|
||||
*/
|
||||
resendVerificationEmail: function resendVerificationEmail() {
|
||||
return this.getSignedInUser().then((data) => {
|
||||
// If the caller is asking for verification to be re-sent, and there is
|
||||
// no signed-in user to begin with, this is probably best regarded as an
|
||||
// error.
|
||||
if (data) {
|
||||
return internal.resendVerificationEmail(data);
|
||||
}
|
||||
throw new Error("Cannot resend verification email; no signed-in user");
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* returns a promise that fires with the assertion. If there is no verified
|
||||
* signed-in user, fires with null.
|
||||
*/
|
||||
getAssertion: function getAssertion(audience) {
|
||||
log.debug("enter getAssertion()");
|
||||
let mustBeValidUntil = internal.now() + ASSERTION_LIFETIME;
|
||||
return internal.getUserAccountData()
|
||||
.then((data) => {
|
||||
if (!data) {
|
||||
// No signed-in user
|
||||
return null;
|
||||
}
|
||||
if (!internal.isUserEmailVerified(data)) {
|
||||
// Signed-in user has not verified email
|
||||
return null;
|
||||
}
|
||||
return internal.getKeyPair(mustBeValidUntil)
|
||||
.then((keyPair) => {
|
||||
return internal.getCertificate(data, keyPair, mustBeValidUntil)
|
||||
.then((cert) => {
|
||||
return internal.getAssertionFromCert(data, keyPair,
|
||||
cert, audience)
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
getKeys: function() {
|
||||
return internal.getKeys();
|
||||
},
|
||||
|
||||
whenVerified: function(userData) {
|
||||
return internal.whenVerified(userData);
|
||||
},
|
||||
|
||||
/**
|
||||
* Sign the current user out.
|
||||
*
|
||||
* @return Promise
|
||||
* The promise is rejected if a storage error occurs.
|
||||
*/
|
||||
signOut: function signOut() {
|
||||
return internal.signOut();
|
||||
},
|
||||
|
||||
// Return the URI of the remote UI flows.
|
||||
@ -661,8 +632,7 @@ this.FxAccounts.prototype = Object.freeze({
|
||||
return url + newQueryPortion;
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* JSONStorage constructor that creates instances that may set/get
|
||||
@ -697,8 +667,7 @@ XPCOMUtils.defineLazyGetter(this, "fxAccounts", function() {
|
||||
|
||||
// XXX Bug 947061 - We need a strategy for resuming email verification after
|
||||
// browser restart
|
||||
internal.loadAndPoll();
|
||||
a.loadAndPoll();
|
||||
|
||||
return a;
|
||||
});
|
||||
|
||||
|
49
services/fxaccounts/FxAccountsUtils.jsm
Normal file
49
services/fxaccounts/FxAccountsUtils.jsm
Normal file
@ -0,0 +1,49 @@
|
||||
/* 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";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["FxAccountsUtils"];
|
||||
|
||||
this.FxAccountsUtils = Object.freeze({
|
||||
/**
|
||||
* Copies properties from a given object to another object.
|
||||
*
|
||||
* @param from (object)
|
||||
* The object we read property descriptors from.
|
||||
* @param to (object)
|
||||
* The object that we set property descriptors on.
|
||||
* @param options (object) (optional)
|
||||
* {keys: [...]}
|
||||
* Lets the caller pass the names of all properties they want to be
|
||||
* copied. Will copy all properties of the given source object by
|
||||
* default.
|
||||
* {bind: object}
|
||||
* Lets the caller specify the object that will be used to .bind()
|
||||
* all function properties we find to. Will bind to the given target
|
||||
* object by default.
|
||||
*/
|
||||
copyObjectProperties: function (from, to, opts = {}) {
|
||||
let keys = (opts && opts.keys) || Object.keys(from);
|
||||
let thisArg = (opts && opts.bind) || to;
|
||||
|
||||
for (let prop of keys) {
|
||||
let desc = Object.getOwnPropertyDescriptor(from, prop);
|
||||
|
||||
if (typeof(desc.value) == "function") {
|
||||
desc.value = desc.value.bind(thisArg);
|
||||
}
|
||||
|
||||
if (desc.get) {
|
||||
desc.get = desc.get.bind(thisArg);
|
||||
}
|
||||
|
||||
if (desc.set) {
|
||||
desc.set = desc.set.bind(thisArg);
|
||||
}
|
||||
|
||||
Object.defineProperty(to, prop, desc);
|
||||
}
|
||||
}
|
||||
});
|
@ -11,7 +11,8 @@ TEST_DIRS += ['tests']
|
||||
EXTRA_JS_MODULES += [
|
||||
'FxAccounts.jsm',
|
||||
'FxAccountsClient.jsm',
|
||||
'FxAccountsCommon.js'
|
||||
'FxAccountsCommon.js',
|
||||
'FxAccountsUtils.jsm'
|
||||
]
|
||||
|
||||
# For now, we will only be using the FxA manager in B2G.
|
||||
|
@ -102,28 +102,23 @@ MockStorage.prototype = Object.freeze({
|
||||
* mock the now() method, so that we can simulate the passing of
|
||||
* time and verify that signatures expire correctly.
|
||||
*/
|
||||
let MockFxAccounts = function() {
|
||||
this._getCertificateSigned_calls = [];
|
||||
this._d_signCertificate = Promise.defer();
|
||||
this._now_is = new Date();
|
||||
|
||||
let mockInternal = {
|
||||
function MockFxAccounts() {
|
||||
return new FxAccounts({
|
||||
_getCertificateSigned_calls: [],
|
||||
_d_signCertificate: Promise.defer(),
|
||||
_now_is: new Date(),
|
||||
signedInUserStorage: new MockStorage(),
|
||||
now: () => {
|
||||
now: function () {
|
||||
return this._now_is;
|
||||
},
|
||||
getCertificateSigned: (sessionToken, serializedPublicKey) => {
|
||||
_("mock getCerificateSigned\n");
|
||||
getCertificateSigned: function (sessionToken, serializedPublicKey) {
|
||||
_("mock getCertificateSigned\n");
|
||||
this._getCertificateSigned_calls.push([sessionToken, serializedPublicKey]);
|
||||
return this._d_signCertificate.promise;
|
||||
},
|
||||
fxAccountsClient: new MockFxAccountsClient()
|
||||
};
|
||||
FxAccounts.apply(this, [mockInternal]);
|
||||
};
|
||||
MockFxAccounts.prototype = {
|
||||
__proto__: FxAccounts.prototype,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
add_test(function test_non_https_remote_server_uri() {
|
||||
Services.prefs.setCharPref(
|
||||
@ -394,15 +389,15 @@ add_task(function test_getAssertion() {
|
||||
// the test, we will update 'now', but leave 'start' where it is.
|
||||
let now = Date.parse("Mon, 13 Jan 2014 21:45:06 GMT");
|
||||
let start = now;
|
||||
fxa._now_is = now;
|
||||
fxa.internal._now_is = now;
|
||||
|
||||
let d = fxa.getAssertion("audience.example.com");
|
||||
// At this point, a thread has been spawned to generate the keys.
|
||||
_("-- back from fxa.getAssertion\n");
|
||||
fxa._d_signCertificate.resolve("cert1");
|
||||
fxa.internal._d_signCertificate.resolve("cert1");
|
||||
let assertion = yield d;
|
||||
do_check_eq(fxa._getCertificateSigned_calls.length, 1);
|
||||
do_check_eq(fxa._getCertificateSigned_calls[0][0], "sessionToken");
|
||||
do_check_eq(fxa.internal._getCertificateSigned_calls.length, 1);
|
||||
do_check_eq(fxa.internal._getCertificateSigned_calls[0][0], "sessionToken");
|
||||
do_check_neq(assertion, null);
|
||||
_("ASSERTION: " + assertion + "\n");
|
||||
let pieces = assertion.split("~");
|
||||
@ -424,18 +419,18 @@ add_task(function test_getAssertion() {
|
||||
do_check_eq(exp, now + TWO_MINUTES_MS);
|
||||
|
||||
// Reset for next call.
|
||||
fxa._d_signCertificate = Promise.defer();
|
||||
fxa.internal._d_signCertificate = Promise.defer();
|
||||
|
||||
// Getting a new assertion "soon" (i.e., w/o incrementing "now"), even for
|
||||
// a new audience, should not provoke key generation or a signing request.
|
||||
assertion = yield fxa.getAssertion("other.example.com");
|
||||
|
||||
// There were no additional calls - same number of getcert calls as before
|
||||
do_check_eq(fxa._getCertificateSigned_calls.length, 1);
|
||||
do_check_eq(fxa.internal._getCertificateSigned_calls.length, 1);
|
||||
|
||||
// Wait an hour; assertion expires, but not the certificate
|
||||
now += ONE_HOUR_MS;
|
||||
fxa._now_is = now;
|
||||
fxa.internal._now_is = now;
|
||||
|
||||
// This won't block on anything - will make an assertion, but not get a
|
||||
// new certificate.
|
||||
@ -462,12 +457,12 @@ add_task(function test_getAssertion() {
|
||||
// Now we wait even longer, and expect both assertion and cert to expire. So
|
||||
// we will have to get a new keypair and cert.
|
||||
now += ONE_DAY_MS;
|
||||
fxa._now_is = now;
|
||||
fxa.internal._now_is = now;
|
||||
d = fxa.getAssertion("fourth.example.com");
|
||||
fxa._d_signCertificate.resolve("cert2");
|
||||
fxa.internal._d_signCertificate.resolve("cert2");
|
||||
assertion = yield d;
|
||||
do_check_eq(fxa._getCertificateSigned_calls.length, 2);
|
||||
do_check_eq(fxa._getCertificateSigned_calls[1][0], "sessionToken");
|
||||
do_check_eq(fxa.internal._getCertificateSigned_calls.length, 2);
|
||||
do_check_eq(fxa.internal._getCertificateSigned_calls[1][0], "sessionToken");
|
||||
pieces = assertion.split("~");
|
||||
do_check_eq(pieces[0], "cert2");
|
||||
p2 = pieces[1].split(".");
|
||||
|
@ -63,6 +63,8 @@ function AuthenticationError(message) {
|
||||
}
|
||||
|
||||
this.BrowserIDManager = function BrowserIDManager() {
|
||||
// NOTE: _fxaService and _tokenServerClient are replaced with mocks by
|
||||
// the test suite.
|
||||
this._fxaService = fxAccounts;
|
||||
this._tokenServerClient = new TokenServerClient();
|
||||
// will be a promise that resolves when we are ready to authenticate
|
||||
@ -112,7 +114,7 @@ this.BrowserIDManager.prototype = {
|
||||
this.whenReadyToAuthenticate = Promise.defer();
|
||||
this._shouldHaveSyncKeyBundle = false;
|
||||
|
||||
return fxAccounts.getSignedInUser().then(accountData => {
|
||||
return this._fxaService.getSignedInUser().then(accountData => {
|
||||
if (!accountData) {
|
||||
this._log.info("initializeWithCurrentIdentity has no user logged in");
|
||||
this._account = null;
|
||||
@ -124,7 +126,7 @@ this.BrowserIDManager.prototype = {
|
||||
// this and the rest of initialization off in the background (ie, we
|
||||
// don't return the promise)
|
||||
this._log.info("Waiting for user to be verified.");
|
||||
fxAccounts.whenVerified(accountData).then(accountData => {
|
||||
this._fxaService.whenVerified(accountData).then(accountData => {
|
||||
// We do the background keybundle fetch...
|
||||
this._log.info("Starting fetch for key bundle.");
|
||||
if (this.needsCustomization) {
|
||||
@ -141,7 +143,7 @@ this.BrowserIDManager.prototype = {
|
||||
Services.prefs.clearUserPref(PREF_SYNC_SHOW_CUSTOMIZATION);
|
||||
} else {
|
||||
// Log out if the user canceled the dialog.
|
||||
return fxAccounts.signOut();
|
||||
return this._fxaService.signOut();
|
||||
}
|
||||
}
|
||||
}).then(() => {
|
||||
@ -411,6 +413,7 @@ this.BrowserIDManager.prototype = {
|
||||
let tokenServerURI = Svc.Prefs.get("tokenServerURI");
|
||||
let log = this._log;
|
||||
let client = this._tokenServerClient;
|
||||
let fxa = this._fxaService;
|
||||
|
||||
// Both Jelly and FxAccounts give us kB as hex
|
||||
let kBbytes = CommonUtils.hexToBytes(userData.kB);
|
||||
@ -437,7 +440,7 @@ this.BrowserIDManager.prototype = {
|
||||
function getAssertion() {
|
||||
log.debug("Getting an assertion");
|
||||
let audience = Services.io.newURI(tokenServerURI, null, null).prePath;
|
||||
return fxAccounts.getAssertion(audience).then(null, err => {
|
||||
return fxa.getAssertion(audience).then(null, err => {
|
||||
if (err.code === 401) {
|
||||
throw new AuthenticationError("Unable to get assertion for user");
|
||||
} else {
|
||||
@ -448,7 +451,7 @@ this.BrowserIDManager.prototype = {
|
||||
|
||||
// wait until the account email is verified and we know that
|
||||
// getAssertion() will return a real assertion (not null).
|
||||
return this._fxaService.whenVerified(userData)
|
||||
return fxa.whenVerified(userData)
|
||||
.then(() => getAssertion())
|
||||
.then(assertion => getToken(tokenServerURI, assertion))
|
||||
.then(token => {
|
||||
@ -561,8 +564,9 @@ BrowserIDClusterManager.prototype = {
|
||||
__proto__: ClusterManager.prototype,
|
||||
|
||||
_findCluster: function() {
|
||||
let fxa = this.identity._fxaService; // will be mocked for tests.
|
||||
let promiseClusterURL = function() {
|
||||
return fxAccounts.getSignedInUser().then(userData => {
|
||||
return fxa.getSignedInUser().then(userData => {
|
||||
return this.identity._fetchTokenForUser(userData).then(token => {
|
||||
let endpoint = token.endpoint;
|
||||
// For Sync 1.5 storage endpoints, we use the base endpoint verbatim.
|
||||
|
@ -100,28 +100,12 @@ TabStore.prototype = {
|
||||
return id == this.engine.service.clientsEngine.localID;
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the recorded last used time of the provided tab, or
|
||||
* 0 if none is present.
|
||||
* The result will always be an integer value.
|
||||
*/
|
||||
tabLastUsed: function tabLastUsed(tab) {
|
||||
// weaveLastUsed will only be set if the tab was ever selected (or
|
||||
// opened after Sync was running).
|
||||
let weaveLastUsed = tab.extData && tab.extData.weaveLastUsed;
|
||||
if (!weaveLastUsed) {
|
||||
return 0;
|
||||
}
|
||||
return parseInt(weaveLastUsed, 10) || 0;
|
||||
},
|
||||
|
||||
getAllTabs: function getAllTabs(filter) {
|
||||
let filteredUrls = new RegExp(Svc.Prefs.get("engine.tabs.filteredUrls"), "i");
|
||||
|
||||
let allTabs = [];
|
||||
|
||||
let currentState = JSON.parse(Svc.Session.getBrowserState());
|
||||
let tabLastUsed = this.tabLastUsed;
|
||||
currentState.windows.forEach(function (window) {
|
||||
if (window.isPrivate) {
|
||||
return;
|
||||
@ -145,7 +129,7 @@ TabStore.prototype = {
|
||||
title: entry.title || "",
|
||||
urlHistory: [entry.url],
|
||||
icon: tab.attributes && tab.attributes.image || "",
|
||||
lastUsed: tabLastUsed(tab)
|
||||
lastUsed: Math.floor((tab.lastAccessed || 0) / 1000)
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -329,20 +313,10 @@ TabTracker.prototype = {
|
||||
this._log.trace("onTab event: " + event.type);
|
||||
this.modified = true;
|
||||
|
||||
// For pageshow events, only give a partial score bump (~.1)
|
||||
let chance = .1;
|
||||
|
||||
// For regular Tab events, do a full score bump and remember when it changed
|
||||
if (event.type != "pageshow") {
|
||||
chance = 1;
|
||||
|
||||
// Store a timestamp in the tab to track when it was last used
|
||||
Svc.Session.setTabValue(event.originalTarget, "weaveLastUsed",
|
||||
Math.floor(Date.now() / 1000));
|
||||
}
|
||||
|
||||
// Only increase the score by whole numbers, so use random for partial score
|
||||
if (Math.random() < chance)
|
||||
// For page shows, bump the score 10% of the time, emulating a partial
|
||||
// score. We don't want to sync too frequently. For all other page
|
||||
// events, always bump the score.
|
||||
if (event.type != "pageshow" || Math.random() < .1)
|
||||
this.score += SCORE_INCREMENT_SMALL;
|
||||
},
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ Cu.import("resource://testing-common/services/sync/utils.js");
|
||||
Cu.import("resource://services-common/hawk.js");
|
||||
Cu.import("resource://gre/modules/FxAccounts.jsm");
|
||||
Cu.import("resource://gre/modules/FxAccountsClient.jsm");
|
||||
Cu.import("resource://gre/modules/FxAccountsCommon.js");
|
||||
|
||||
const SECOND_MS = 1000;
|
||||
const MINUTE_MS = SECOND_MS * 60;
|
||||
@ -33,22 +34,25 @@ MockFxAccountsClient.prototype = {
|
||||
__proto__: FxAccountsClient.prototype
|
||||
};
|
||||
|
||||
let MockFxAccounts = function() {
|
||||
this._now_is = Date.now();
|
||||
function MockFxAccounts() {
|
||||
return new FxAccounts({
|
||||
_now_is: Date.now(),
|
||||
|
||||
let mockInternal = {
|
||||
now: () => {
|
||||
now: function () {
|
||||
return this._now_is;
|
||||
},
|
||||
|
||||
fxAccountsClient: new MockFxAccountsClient()
|
||||
};
|
||||
getCertificate: function(data, keyPair, mustBeValidUntil) {
|
||||
this.cert = {
|
||||
validUntil: Date.now() + CERT_LIFETIME,
|
||||
cert: "certificate",
|
||||
};
|
||||
return Promise.resolve(this.cert.cert);
|
||||
},
|
||||
|
||||
FxAccounts.apply(this, [mockInternal]);
|
||||
};
|
||||
MockFxAccounts.prototype = {
|
||||
__proto__: FxAccounts.prototype,
|
||||
};
|
||||
fxAccountsClient: new MockFxAccountsClient()
|
||||
});
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
initTestLogging("Trace");
|
||||
@ -129,7 +133,7 @@ add_test(function test_resourceAuthenticatorSkew() {
|
||||
do_check_eq(fxaClient.localtimeOffsetMsec, localtimeOffsetMsec);
|
||||
|
||||
let fxa = new MockFxAccounts();
|
||||
fxa._now_is = now;
|
||||
fxa.internal._now_is = now;
|
||||
fxa.internal.fxAccountsClient = fxaClient;
|
||||
|
||||
// Picked up by the signed-in user module
|
||||
@ -141,6 +145,10 @@ add_test(function test_resourceAuthenticatorSkew() {
|
||||
|
||||
// Mocks within mocks...
|
||||
configureFxAccountIdentity(browseridManager, identityConfig);
|
||||
|
||||
// Ensure the new FxAccounts mock has a signed-in user.
|
||||
fxa.internal.signedInUser = browseridManager._fxaService.internal.signedInUser;
|
||||
|
||||
browseridManager._fxaService = fxa;
|
||||
|
||||
do_check_eq(browseridManager._fxaService.internal.now(), now);
|
||||
@ -186,10 +194,14 @@ add_test(function test_RESTResourceAuthenticatorSkew() {
|
||||
let fxaClient = new MockFxAccountsClient();
|
||||
fxaClient.hawk = hawkClient;
|
||||
let fxa = new MockFxAccounts();
|
||||
fxa._now_is = now;
|
||||
fxa.internal._now_is = now;
|
||||
fxa.internal.fxAccountsClient = fxaClient;
|
||||
|
||||
configureFxAccountIdentity(browseridManager, identityConfig);
|
||||
|
||||
// Ensure the new FxAccounts mock has a signed-in user.
|
||||
fxa.internal.signedInUser = browseridManager._fxaService.internal.signedInUser;
|
||||
|
||||
browseridManager._fxaService = fxa;
|
||||
|
||||
do_check_eq(browseridManager._fxaService.internal.now(), now);
|
||||
|
@ -46,10 +46,8 @@ add_task(function test_locally_changed_keys() {
|
||||
}],
|
||||
attributes: {
|
||||
image: "image"
|
||||
},
|
||||
extData: {
|
||||
weaveLastUsed: 1
|
||||
}}]}]};
|
||||
}
|
||||
}]}]};
|
||||
delete Svc.Session;
|
||||
Svc.Session = {
|
||||
getBrowserState: function () JSON.stringify(myTabs)
|
||||
|
@ -54,10 +54,8 @@ add_test(function v4_upgrade() {
|
||||
}],
|
||||
attributes: {
|
||||
image: "image"
|
||||
},
|
||||
extData: {
|
||||
weaveLastUsed: 1
|
||||
}}]}]};
|
||||
}
|
||||
}]}]};
|
||||
delete Svc.Session;
|
||||
Svc.Session = {
|
||||
getBrowserState: function () JSON.stringify(myTabs)
|
||||
@ -225,10 +223,8 @@ add_test(function v5_upgrade() {
|
||||
}],
|
||||
attributes: {
|
||||
image: "image"
|
||||
},
|
||||
extData: {
|
||||
weaveLastUsed: 1
|
||||
}}]}]};
|
||||
}
|
||||
}]}]};
|
||||
delete Svc.Session;
|
||||
Svc.Session = {
|
||||
getBrowserState: function () JSON.stringify(myTabs)
|
||||
|
@ -16,9 +16,6 @@ function fakeSessionSvc() {
|
||||
}],
|
||||
attributes: {
|
||||
image: "image"
|
||||
},
|
||||
extData: {
|
||||
weaveLastUsed: 1
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -6,25 +6,6 @@ Cu.import("resource://services-sync/service.js");
|
||||
Cu.import("resource://services-sync/util.js");
|
||||
Cu.import("resource://testing-common/services-common/utils.js");
|
||||
|
||||
function test_lastUsed() {
|
||||
let store = new TabEngine(Service)._store;
|
||||
|
||||
_("Check extraction of last used times from tab objects.");
|
||||
let expected = [
|
||||
[0, {}],
|
||||
[0, {extData: null}],
|
||||
[0, {extData: {}}],
|
||||
[0, {extData: {weaveLastUsed: null}}],
|
||||
[123456789, {extData: {weaveLastUsed: "123456789"}}],
|
||||
[123456789, {extData: {weaveLastUsed: 123456789}}],
|
||||
[123456789, {extData: {weaveLastUsed: 123456789.12}}]
|
||||
];
|
||||
|
||||
for each (let [ex, input] in expected) {
|
||||
do_check_eq(ex, store.tabLastUsed(input));
|
||||
}
|
||||
}
|
||||
|
||||
function test_create() {
|
||||
let store = new TabEngine(Service)._store;
|
||||
|
||||
@ -76,9 +57,7 @@ function fakeSessionSvc(url, numtabs) {
|
||||
attributes: {
|
||||
image: "image"
|
||||
},
|
||||
extData: {
|
||||
weaveLastUsed: 1
|
||||
}
|
||||
lastAccessed: 1499
|
||||
}]
|
||||
}]
|
||||
};
|
||||
@ -136,7 +115,6 @@ function test_createRecord() {
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
test_lastUsed();
|
||||
test_create();
|
||||
test_getAllTabs();
|
||||
test_createRecord();
|
||||
|
@ -34,18 +34,6 @@ function fakeSvcWinMediator() {
|
||||
return logs;
|
||||
}
|
||||
|
||||
function fakeSvcSession() {
|
||||
// actions on Session are captured in logs
|
||||
let logs = [];
|
||||
delete Svc.Session;
|
||||
Svc.Session = {
|
||||
setTabValue: function(target, prop, value) {
|
||||
logs.push({target: target, prop: prop, value: value});
|
||||
}
|
||||
};
|
||||
return logs;
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
let engine = Service.engineManager.get("tabs");
|
||||
|
||||
@ -88,8 +76,6 @@ function run_test() {
|
||||
}
|
||||
|
||||
_("Test tab listener");
|
||||
logs = fakeSvcSession();
|
||||
let idx = 0;
|
||||
for each (let evttype in ["TabOpen", "TabClose", "TabSelect"]) {
|
||||
// Pretend we just synced.
|
||||
tracker.clearChangedIDs();
|
||||
@ -100,11 +86,6 @@ function run_test() {
|
||||
do_check_true(tracker.modified);
|
||||
do_check_true(Utils.deepEquals(Object.keys(engine.getChangedIDs()),
|
||||
[clientsEngine.localID]));
|
||||
do_check_eq(logs.length, idx+1);
|
||||
do_check_eq(logs[idx].target, evttype);
|
||||
do_check_eq(logs[idx].prop, "weaveLastUsed");
|
||||
do_check_true(typeof logs[idx].value == "number");
|
||||
idx++;
|
||||
}
|
||||
|
||||
// Pretend we just synced.
|
||||
@ -114,5 +95,4 @@ function run_test() {
|
||||
tracker.onTab({type: "pageshow", originalTarget: "pageshow"});
|
||||
do_check_true(Utils.deepEquals(Object.keys(engine.getChangedIDs()),
|
||||
[clientsEngine.localID]));
|
||||
do_check_eq(logs.length, idx); // test that setTabValue isn't called
|
||||
}
|
||||
|
@ -336,6 +336,24 @@ Type.prototype = {
|
||||
return type;
|
||||
},
|
||||
|
||||
/**
|
||||
* Lazy variant of releaseWith.
|
||||
* Attach a finalizer lazily to a type.
|
||||
*
|
||||
* @param {function} getFinalizer The function that
|
||||
* returns finalizer lazily.
|
||||
*/
|
||||
releaseWithLazy: function releaseWithLazy(getFinalizer) {
|
||||
let parent = this;
|
||||
let type = this.withName("[auto " + this.name + ", (lazy)] ");
|
||||
type.importFromC = function importFromC(value, operation) {
|
||||
return ctypes.CDataFinalizer(
|
||||
parent.importFromC(value, operation),
|
||||
getFinalizer());
|
||||
};
|
||||
return type;
|
||||
},
|
||||
|
||||
/**
|
||||
* Return an alias to a type with a different name.
|
||||
*/
|
||||
@ -912,6 +930,7 @@ Library.prototype = Object.freeze({
|
||||
for (let candidate of this._candidates) {
|
||||
try {
|
||||
library = ctypes.open(candidate);
|
||||
break;
|
||||
} catch (ex) {
|
||||
LOG("Could not open library", candidate, ex);
|
||||
}
|
||||
@ -961,6 +980,33 @@ Library.prototype = Object.freeze({
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Define a js-ctypes function lazily using ctypes method declare.
|
||||
*
|
||||
* @param {object} The object containing the function as a field.
|
||||
* @param {string} The name of the field containing the function.
|
||||
* @param {string} symbol The name of the function, as defined in the
|
||||
* library.
|
||||
* @param {ctypes.abi} abi The abi to use, or |null| for default.
|
||||
* @param {ctypes.CType} returnType The type of values returned by the function.
|
||||
* @param {...ctypes.CType} argTypes The type of arguments to the function.
|
||||
*/
|
||||
declareLazy: function(object, field, ...args) {
|
||||
let lib = this;
|
||||
Object.defineProperty(object, field, {
|
||||
get: function() {
|
||||
delete this[field];
|
||||
let ffi = lib.library.declare(...args);
|
||||
if (ffi) {
|
||||
return this[field] = ffi;
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
configurable: true,
|
||||
enumerable: true
|
||||
});
|
||||
},
|
||||
|
||||
toString: function() {
|
||||
return "[Library " + this.name + "]";
|
||||
}
|
||||
|
@ -39,34 +39,20 @@ let LOG = SharedAll.LOG.bind(SharedAll, "Unix", "allthreads");
|
||||
let Const = SharedAll.Constants.libc;
|
||||
|
||||
// Open libc
|
||||
let libc;
|
||||
let libc_candidates = [ "libc.so",
|
||||
"libSystem.B.dylib",
|
||||
"a.out" ];
|
||||
for (let i = 0; i < libc_candidates.length; ++i) {
|
||||
try {
|
||||
libc = ctypes.open(libc_candidates[i]);
|
||||
break;
|
||||
} catch (x) {
|
||||
LOG("Could not open libc ", libc_candidates[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!libc) {
|
||||
// Note: If you change the string here, please adapt tests accordingly
|
||||
throw new Error("Could not open system library: no libc");
|
||||
}
|
||||
let libc = new SharedAll.Library("libc",
|
||||
"libc.so", "libSystem.B.dylib", "a.out");
|
||||
exports.libc = libc;
|
||||
|
||||
// Define declareFFI
|
||||
let declareFFI = SharedAll.declareFFI.bind(null, libc);
|
||||
exports.declareFFI = declareFFI;
|
||||
|
||||
// Define Error
|
||||
let strerror = libc.declare("strerror",
|
||||
ctypes.default_abi,
|
||||
/*return*/ ctypes.char.ptr,
|
||||
/*errnum*/ ctypes.int);
|
||||
// Define lazy binding
|
||||
let LazyBindings = {};
|
||||
libc.declareLazy(LazyBindings, "strerror",
|
||||
"strerror", ctypes.default_abi,
|
||||
/*return*/ ctypes.char.ptr,
|
||||
/*errnum*/ ctypes.int);
|
||||
|
||||
/**
|
||||
* A File-related error.
|
||||
@ -100,7 +86,7 @@ OSError.prototype = Object.create(SharedAll.OSError.prototype);
|
||||
OSError.prototype.toString = function toString() {
|
||||
return "Unix error " + this.unixErrno +
|
||||
" during operation " + this.operation +
|
||||
" (" + strerror(this.unixErrno).readString() + ")";
|
||||
" (" + LazyBindings.strerror(this.unixErrno).readString() + ")";
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -221,8 +221,8 @@
|
||||
// Declare libc functions as functions of |OS.Unix.File|
|
||||
|
||||
// Finalizer-related functions
|
||||
SharedAll.declareLazy(SysFile, "_close", libc,
|
||||
"close", ctypes.default_abi,
|
||||
libc.declareLazy(SysFile, "_close",
|
||||
"close", ctypes.default_abi,
|
||||
/*return */ctypes.int,
|
||||
/*fd*/ ctypes.int);
|
||||
|
||||
@ -231,8 +231,8 @@
|
||||
return fd.dispose();
|
||||
};
|
||||
|
||||
SharedAll.declareLazy(SysFile, "_close_dir", libc,
|
||||
"closedir", ctypes.default_abi,
|
||||
libc.declareLazy(SysFile, "_close_dir",
|
||||
"closedir", ctypes.default_abi,
|
||||
/*return */ctypes.int,
|
||||
/*dirp*/ Type.DIR.in_ptr.implementation);
|
||||
|
||||
@ -244,14 +244,14 @@
|
||||
{
|
||||
// Symbol free() is special.
|
||||
// We override the definition of free() on several platforms.
|
||||
let default_lib = libc;
|
||||
let default_lib = new SharedAll.Library("default_lib",
|
||||
"a.out");
|
||||
try {
|
||||
// On platforms for which we override free(), nspr defines
|
||||
// a special library name "a.out" that will resolve to the
|
||||
// correct implementation free().
|
||||
default_lib = ctypes.open("a.out");
|
||||
|
||||
SharedAll.declareLazy(SysFile, "free", default_lib,
|
||||
default_lib.declareLazy(SysFile, "free",
|
||||
"free", ctypes.default_abi,
|
||||
/*return*/ ctypes.void_t,
|
||||
/*ptr*/ ctypes.voidptr_t);
|
||||
@ -260,7 +260,7 @@
|
||||
// We don't have an a.out library or a.out doesn't contain free.
|
||||
// Either way, use the ordinary libc free.
|
||||
|
||||
SharedAll.declareLazy(SysFile, "free", libc,
|
||||
libc.declareLazy(SysFile, "free",
|
||||
"free", ctypes.default_abi,
|
||||
/*return*/ ctypes.void_t,
|
||||
/*ptr*/ ctypes.voidptr_t);
|
||||
@ -269,36 +269,42 @@
|
||||
|
||||
|
||||
// Other functions
|
||||
declareLazyFFI(SysFile, "access", libc, "access", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path,
|
||||
/*mode*/ Type.int);
|
||||
libc.declareLazyFFI(SysFile, "access",
|
||||
"access", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path,
|
||||
/*mode*/ Type.int);
|
||||
|
||||
declareLazyFFI(SysFile, "chdir", libc, "chdir", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path);
|
||||
libc.declareLazyFFI(SysFile, "chdir",
|
||||
"chdir", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path);
|
||||
|
||||
declareLazyFFI(SysFile, "chmod", libc, "chmod", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path,
|
||||
/*mode*/ Type.mode_t);
|
||||
libc.declareLazyFFI(SysFile, "chmod",
|
||||
"chmod", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path,
|
||||
/*mode*/ Type.mode_t);
|
||||
|
||||
declareLazyFFI(SysFile, "chown", libc, "chown", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path,
|
||||
/*uid*/ Type.uid_t,
|
||||
/*gid*/ Type.gid_t);
|
||||
libc.declareLazyFFI(SysFile, "chown",
|
||||
"chown", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path,
|
||||
/*uid*/ Type.uid_t,
|
||||
/*gid*/ Type.gid_t);
|
||||
|
||||
declareLazyFFI(SysFile, "copyfile", libc, "copyfile", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*source*/ Type.path,
|
||||
/*dest*/ Type.path,
|
||||
/*state*/ Type.void_t.in_ptr, // Ignored atm
|
||||
/*flags*/ Type.uint32_t);
|
||||
libc.declareLazyFFI(SysFile, "copyfile",
|
||||
"copyfile", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*source*/ Type.path,
|
||||
/*dest*/ Type.path,
|
||||
/*state*/ Type.void_t.in_ptr, // Ignored atm
|
||||
/*flags*/ Type.uint32_t);
|
||||
|
||||
declareLazyFFI(SysFile, "dup", libc, "dup", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_fd,
|
||||
/*fd*/ Type.fd);
|
||||
libc.declareLazyFFI(SysFile, "dup",
|
||||
"dup", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_fd,
|
||||
/*fd*/ Type.fd);
|
||||
|
||||
if ("OSFILE_SIZEOF_DIR" in Const) {
|
||||
// On platforms for which |dirfd| is a macro
|
||||
@ -308,127 +314,150 @@
|
||||
};
|
||||
} else {
|
||||
// On platforms for which |dirfd| is a function
|
||||
declareLazyFFI(SysFile, "dirfd", libc, "dirfd", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_fd,
|
||||
/*dir*/ Type.DIR.in_ptr);
|
||||
libc.declareLazyFFI(SysFile, "dirfd",
|
||||
"dirfd", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_fd,
|
||||
/*dir*/ Type.DIR.in_ptr);
|
||||
}
|
||||
|
||||
declareLazyFFI(SysFile, "chdir", libc, "chdir", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path);
|
||||
libc.declareLazyFFI(SysFile, "chdir",
|
||||
"chdir", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path);
|
||||
|
||||
declareLazyFFI(SysFile, "fchdir", libc, "fchdir", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*fd*/ Type.fd);
|
||||
libc.declareLazyFFI(SysFile, "fchdir",
|
||||
"fchdir", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*fd*/ Type.fd);
|
||||
|
||||
declareLazyFFI(SysFile, "fchown", libc, "fchown", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*fd*/ Type.fd,
|
||||
/*uid_t*/ Type.uid_t,
|
||||
/*gid_t*/ Type.gid_t);
|
||||
libc.declareLazyFFI(SysFile, "fchown",
|
||||
"fchown", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*fd*/ Type.fd,
|
||||
/*uid_t*/ Type.uid_t,
|
||||
/*gid_t*/ Type.gid_t);
|
||||
|
||||
declareLazyFFI(SysFile, "fsync", libc, "fsync", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*fd*/ Type.fd);
|
||||
libc.declareLazyFFI(SysFile, "fsync",
|
||||
"fsync", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*fd*/ Type.fd);
|
||||
|
||||
declareLazyFFI(SysFile, "getcwd", libc, "getcwd", ctypes.default_abi,
|
||||
/*return*/ Type.out_path,
|
||||
/*buf*/ Type.out_path,
|
||||
/*size*/ Type.size_t);
|
||||
libc.declareLazyFFI(SysFile, "getcwd",
|
||||
"getcwd", ctypes.default_abi,
|
||||
/*return*/ Type.out_path,
|
||||
/*buf*/ Type.out_path,
|
||||
/*size*/ Type.size_t);
|
||||
|
||||
declareLazyFFI(SysFile, "getwd", libc, "getwd", ctypes.default_abi,
|
||||
/*return*/ Type.out_path,
|
||||
/*buf*/ Type.out_path);
|
||||
libc.declareLazyFFI(SysFile, "getwd",
|
||||
"getwd", ctypes.default_abi,
|
||||
/*return*/ Type.out_path,
|
||||
/*buf*/ Type.out_path);
|
||||
|
||||
// Two variants of |getwd| which allocate the memory
|
||||
// dynamically.
|
||||
|
||||
// Linux/Android version
|
||||
declareLazyFFI(SysFile, "get_current_dir_name", libc,
|
||||
"get_current_dir_name", ctypes.default_abi,
|
||||
/*return*/ Type.out_path.releaseWith(SysFile.free));
|
||||
libc.declareLazyFFI(SysFile, "get_current_dir_name",
|
||||
"get_current_dir_name", ctypes.default_abi,
|
||||
/*return*/ Type.out_path.releaseWithLazy(() =>
|
||||
SysFile.free
|
||||
));
|
||||
|
||||
// MacOS/BSD version (will return NULL on Linux/Android)
|
||||
declareLazyFFI(SysFile, "getwd_auto", libc,
|
||||
"getwd", ctypes.default_abi,
|
||||
/*return*/ Type.out_path.releaseWith(SysFile.free),
|
||||
/*buf*/ Type.void_t.out_ptr);
|
||||
libc.declareLazyFFI(SysFile, "getwd_auto",
|
||||
"getwd", ctypes.default_abi,
|
||||
/*return*/ Type.out_path.releaseWithLazy(() =>
|
||||
SysFile.free
|
||||
),
|
||||
/*buf*/ Type.void_t.out_ptr);
|
||||
|
||||
declareLazyFFI(SysFile, "fdatasync", libc,
|
||||
"fdatasync", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*fd*/ Type.fd); // Note: MacOS/BSD-specific
|
||||
libc.declareLazyFFI(SysFile, "fdatasync",
|
||||
"fdatasync", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*fd*/ Type.fd); // Note: MacOS/BSD-specific
|
||||
|
||||
declareLazyFFI(SysFile, "ftruncate", libc,
|
||||
"ftruncate", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*fd*/ Type.fd,
|
||||
/*length*/ Type.off_t);
|
||||
libc.declareLazyFFI(SysFile, "ftruncate",
|
||||
"ftruncate", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*fd*/ Type.fd,
|
||||
/*length*/ Type.off_t);
|
||||
|
||||
|
||||
declareLazyFFI(SysFile, "lchown", libc, "lchown", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path,
|
||||
/*uid_t*/ Type.uid_t,
|
||||
/*gid_t*/ Type.gid_t);
|
||||
libc.declareLazyFFI(SysFile, "lchown",
|
||||
"lchown", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path,
|
||||
/*uid_t*/ Type.uid_t,
|
||||
/*gid_t*/ Type.gid_t);
|
||||
|
||||
declareLazyFFI(SysFile, "link", libc, "link", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*source*/ Type.path,
|
||||
/*dest*/ Type.path);
|
||||
libc.declareLazyFFI(SysFile, "link",
|
||||
"link", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*source*/ Type.path,
|
||||
/*dest*/ Type.path);
|
||||
|
||||
declareLazyFFI(SysFile, "lseek", libc, "lseek", ctypes.default_abi,
|
||||
/*return*/ Type.off_t,
|
||||
/*fd*/ Type.fd,
|
||||
/*offset*/ Type.off_t,
|
||||
/*whence*/ Type.int);
|
||||
libc.declareLazyFFI(SysFile, "lseek",
|
||||
"lseek", ctypes.default_abi,
|
||||
/*return*/ Type.off_t,
|
||||
/*fd*/ Type.fd,
|
||||
/*offset*/ Type.off_t,
|
||||
/*whence*/ Type.int);
|
||||
|
||||
declareLazyFFI(SysFile, "mkdir", libc, "mkdir", ctypes.default_abi,
|
||||
/*return*/ Type.int,
|
||||
/*path*/ Type.path,
|
||||
/*mode*/ Type.int);
|
||||
libc.declareLazyFFI(SysFile, "mkdir",
|
||||
"mkdir", ctypes.default_abi,
|
||||
/*return*/ Type.int,
|
||||
/*path*/ Type.path,
|
||||
/*mode*/ Type.int);
|
||||
|
||||
declareLazyFFI(SysFile, "mkstemp", libc, "mkstemp", ctypes.default_abi,
|
||||
/*return*/ Type.fd,
|
||||
/*template*/Type.out_path);
|
||||
libc.declareLazyFFI(SysFile, "mkstemp",
|
||||
"mkstemp", ctypes.default_abi,
|
||||
/*return*/ Type.fd,
|
||||
/*template*/ Type.out_path);
|
||||
|
||||
declareLazyFFI(SysFile, "open", libc, "open", ctypes.default_abi,
|
||||
/*return*/Type.negativeone_or_fd,
|
||||
/*path*/ Type.path,
|
||||
/*oflags*/Type.int,
|
||||
/*mode*/ Type.int);
|
||||
libc.declareLazyFFI(SysFile, "open",
|
||||
"open", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_fd,
|
||||
/*path*/ Type.path,
|
||||
/*oflags*/ Type.int,
|
||||
/*mode*/ Type.int);
|
||||
|
||||
if (OS.Constants.Sys.Name == "NetBSD") {
|
||||
declareLazyFFI(SysFile, "opendir", libc, "__opendir30", ctypes.default_abi,
|
||||
libc.declareLazyFFI(SysFile, "opendir",
|
||||
"__opendir30", ctypes.default_abi,
|
||||
/*return*/ Type.null_or_DIR_ptr,
|
||||
/*path*/ Type.path);
|
||||
} else {
|
||||
declareLazyFFI(SysFile, "opendir", libc, "opendir", ctypes.default_abi,
|
||||
libc.declareLazyFFI(SysFile, "opendir",
|
||||
"opendir", ctypes.default_abi,
|
||||
/*return*/ Type.null_or_DIR_ptr,
|
||||
/*path*/ Type.path);
|
||||
}
|
||||
|
||||
declareLazyFFI(SysFile, "pread", libc, "pread", ctypes.default_abi,
|
||||
libc.declareLazyFFI(SysFile, "pread",
|
||||
"pread", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_ssize_t,
|
||||
/*fd*/ Type.fd,
|
||||
/*buf*/ Type.void_t.out_ptr,
|
||||
/*nbytes*/ Type.size_t,
|
||||
/*offset*/ Type.off_t);
|
||||
|
||||
declareLazyFFI(SysFile, "pwrite", libc, "pwrite", ctypes.default_abi,
|
||||
libc.declareLazyFFI(SysFile, "pwrite",
|
||||
"pwrite", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_ssize_t,
|
||||
/*fd*/ Type.fd,
|
||||
/*buf*/ Type.void_t.in_ptr,
|
||||
/*nbytes*/ Type.size_t,
|
||||
/*offset*/ Type.off_t);
|
||||
|
||||
declareLazyFFI(SysFile, "read", libc, "read", ctypes.default_abi,
|
||||
libc.declareLazyFFI(SysFile, "read",
|
||||
"read", ctypes.default_abi,
|
||||
/*return*/Type.negativeone_or_ssize_t,
|
||||
/*fd*/ Type.fd,
|
||||
/*buf*/ Type.void_t.out_ptr,
|
||||
/*nbytes*/Type.size_t);
|
||||
|
||||
declareLazyFFI(SysFile, "posix_fadvise", libc, "posix_fadvise", ctypes.default_abi,
|
||||
libc.declareLazyFFI(SysFile, "posix_fadvise",
|
||||
"posix_fadvise", ctypes.default_abi,
|
||||
/*return*/ Type.int,
|
||||
/*fd*/ Type.fd,
|
||||
/*offset*/ Type.off_t,
|
||||
@ -440,29 +469,35 @@
|
||||
// Symbol name "readdir" still exists but is used for a
|
||||
// deprecated function that does not match the
|
||||
// constants of |Const|.
|
||||
declareLazyFFI(SysFile, "readdir", libc, "readdir$INODE64", ctypes.default_abi,
|
||||
/*return*/Type.null_or_dirent_ptr,
|
||||
libc.declareLazyFFI(SysFile, "readdir",
|
||||
"readdir$INODE64", ctypes.default_abi,
|
||||
/*return*/ Type.null_or_dirent_ptr,
|
||||
/*dir*/ Type.DIR.in_ptr); // For MacOS X
|
||||
} else if (OS.Constants.Sys.Name == "NetBSD") {
|
||||
declareLazyFFI(SysFile, "readdir", libc, "__readdir30", ctypes.default_abi,
|
||||
libc.declareLazyFFI(SysFile, "readdir",
|
||||
"__readdir30", ctypes.default_abi,
|
||||
/*return*/Type.null_or_dirent_ptr,
|
||||
/*dir*/ Type.DIR.in_ptr); // Other Unices
|
||||
} else {
|
||||
declareLazyFFI(SysFile, "readdir", libc, "readdir", ctypes.default_abi,
|
||||
libc.declareLazyFFI(SysFile, "readdir",
|
||||
"readdir", ctypes.default_abi,
|
||||
/*return*/Type.null_or_dirent_ptr,
|
||||
/*dir*/ Type.DIR.in_ptr); // Other Unices
|
||||
}
|
||||
|
||||
declareLazyFFI(SysFile, "rename", libc, "rename", ctypes.default_abi,
|
||||
libc.declareLazyFFI(SysFile, "rename",
|
||||
"rename", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*old*/ Type.path,
|
||||
/*new*/ Type.path);
|
||||
|
||||
declareLazyFFI(SysFile, "rmdir", libc, "rmdir", ctypes.default_abi,
|
||||
libc.declareLazyFFI(SysFile, "rmdir",
|
||||
"rmdir", ctypes.default_abi,
|
||||
/*return*/ Type.int,
|
||||
/*path*/ Type.path);
|
||||
|
||||
declareLazyFFI(SysFile, "splice", libc, "splice", ctypes.default_abi,
|
||||
libc.declareLazyFFI(SysFile, "splice",
|
||||
"splice", ctypes.default_abi,
|
||||
/*return*/ Type.long,
|
||||
/*fd_in*/ Type.fd,
|
||||
/*off_in*/ Type.off_t.in_ptr,
|
||||
@ -471,21 +506,25 @@
|
||||
/*len*/ Type.size_t,
|
||||
/*flags*/ Type.unsigned_int); // Linux/Android-specific
|
||||
|
||||
declareLazyFFI(SysFile, "symlink", libc, "symlink", ctypes.default_abi,
|
||||
libc.declareLazyFFI(SysFile, "symlink",
|
||||
"symlink", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*source*/ Type.path,
|
||||
/*dest*/ Type.path);
|
||||
|
||||
declareLazyFFI(SysFile, "truncate", libc, "truncate", ctypes.default_abi,
|
||||
libc.declareLazyFFI(SysFile, "truncate",
|
||||
"truncate", ctypes.default_abi,
|
||||
/*return*/Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path,
|
||||
/*length*/ Type.off_t);
|
||||
|
||||
declareLazyFFI(SysFile, "unlink", libc, "unlink", ctypes.default_abi,
|
||||
libc.declareLazyFFI(SysFile, "unlink",
|
||||
"unlink", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path);
|
||||
|
||||
declareLazyFFI(SysFile, "write", libc, "write", ctypes.default_abi,
|
||||
libc.declareLazyFFI(SysFile, "write",
|
||||
"write", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_ssize_t,
|
||||
/*fd*/ Type.fd,
|
||||
/*buf*/ Type.void_t.in_ptr,
|
||||
@ -497,17 +536,20 @@
|
||||
// 32-bits and 64-bits versions of |stat|, |lstat|, |fstat|.
|
||||
if (Const._DARWIN_FEATURE_64_BIT_INODE) {
|
||||
// MacOS X 64-bits
|
||||
declareLazyFFI(SysFile, "stat", libc, "stat$INODE64", ctypes.default_abi,
|
||||
libc.declareLazyFFI(SysFile, "stat",
|
||||
"stat$INODE64", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path,
|
||||
/*buf*/ Type.stat.out_ptr
|
||||
);
|
||||
declareLazyFFI(SysFile, "lstat", libc, "lstat$INODE64", ctypes.default_abi,
|
||||
libc.declareLazyFFI(SysFile, "lstat",
|
||||
"lstat$INODE64", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path,
|
||||
/*buf*/ Type.stat.out_ptr
|
||||
);
|
||||
declareLazyFFI(SysFile, "fstat", libc, "fstat$INODE64", ctypes.default_abi,
|
||||
libc.declareLazyFFI(SysFile, "fstat",
|
||||
"fstat$INODE64", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.fd,
|
||||
/*buf*/ Type.stat.out_ptr
|
||||
@ -528,18 +570,20 @@
|
||||
}
|
||||
|
||||
let Stat = {};
|
||||
declareLazyFFI(Stat, "xstat", libc, xstat_name, ctypes.default_abi,
|
||||
libc.declareLazyFFI(Stat, "xstat",
|
||||
xstat_name, ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*_stat_ver*/ Type.int,
|
||||
/*path*/ Type.path,
|
||||
/*buf*/ Type.stat.out_ptr);
|
||||
declareLazyFFI(Stat, "lxstat", libc, lxstat_name, ctypes.default_abi,
|
||||
libc.declareLazyFFI(Stat, "lxstat",
|
||||
lxstat_name, ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*_stat_ver*/ Type.int,
|
||||
/*path*/ Type.path,
|
||||
/*buf*/ Type.stat.out_ptr);
|
||||
declareLazyFFI(Stat, "fxstat", libc,
|
||||
fxstat_name, ctypes.default_abi,
|
||||
libc.declareLazyFFI(Stat, "fxstat",
|
||||
fxstat_name, ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*_stat_ver*/ Type.int,
|
||||
/*fd*/ Type.fd,
|
||||
@ -559,34 +603,40 @@
|
||||
};
|
||||
} else if (OS.Constants.Sys.Name == "NetBSD") {
|
||||
// NetBSD 5.0 and newer
|
||||
declareLazyFFI(SysFile, "stat", libc, "__stat50", ctypes.default_abi,
|
||||
libc.declareLazyFFI(SysFile, "stat",
|
||||
"__stat50", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path,
|
||||
/*buf*/ Type.stat.out_ptr
|
||||
);
|
||||
declareLazyFFI(SysFile, "lstat", libc, "__lstat50", ctypes.default_abi,
|
||||
libc.declareLazyFFI(SysFile, "lstat",
|
||||
"__lstat50", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path,
|
||||
/*buf*/ Type.stat.out_ptr
|
||||
);
|
||||
declareLazyFFI(SysFile, "fstat", libc, "__fstat50", ctypes.default_abi,
|
||||
libc.declareLazyFFI(SysFile, "fstat",
|
||||
"__fstat50", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*fd*/ Type.fd,
|
||||
/*buf*/ Type.stat.out_ptr
|
||||
);
|
||||
} else {
|
||||
// Mac OS X 32-bits, other Unix
|
||||
declareLazyFFI(SysFile, "stat", libc, "stat", ctypes.default_abi,
|
||||
libc.declareLazyFFI(SysFile, "stat",
|
||||
"stat", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path,
|
||||
/*buf*/ Type.stat.out_ptr
|
||||
);
|
||||
declareLazyFFI(SysFile, "lstat", libc, "lstat", ctypes.default_abi,
|
||||
libc.declareLazyFFI(SysFile, "lstat",
|
||||
"lstat", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path,
|
||||
/*buf*/ Type.stat.out_ptr
|
||||
);
|
||||
declareLazyFFI(SysFile, "fstat", libc, "fstat", ctypes.default_abi,
|
||||
libc.declareLazyFFI(SysFile, "fstat",
|
||||
"fstat", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*fd*/ Type.fd,
|
||||
/*buf*/ Type.stat.out_ptr
|
||||
@ -597,7 +647,7 @@
|
||||
// pipe cannot be directly defined as a C function.
|
||||
|
||||
let Pipe = {};
|
||||
declareLazyFFI(Pipe, "_pipe", libc,
|
||||
libc.declareLazyFFI(Pipe, "_pipe",
|
||||
"pipe", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*fds*/ new SharedAll.Type("two file descriptors",
|
||||
@ -617,26 +667,30 @@
|
||||
};
|
||||
|
||||
if (OS.Constants.Sys.Name == "NetBSD") {
|
||||
declareLazyFFI(SysFile, "utimes", libc, "__utimes50", ctypes.default_abi,
|
||||
libc.declareLazyFFI(SysFile, "utimes",
|
||||
"__utimes50", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path,
|
||||
/*timeval[2]*/ Type.timevals.out_ptr
|
||||
);
|
||||
} else {
|
||||
declareLazyFFI(SysFile, "utimes", libc, "utimes", ctypes.default_abi,
|
||||
libc.declareLazyFFI(SysFile, "utimes",
|
||||
"utimes", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path,
|
||||
/*timeval[2]*/ Type.timevals.out_ptr
|
||||
);
|
||||
}
|
||||
if (OS.Constants.Sys.Name == "NetBSD") {
|
||||
declareLazyFFI(SysFile, "futimes", libc, "__futimes50", ctypes.default_abi,
|
||||
libc.declareLazyFFI(SysFile, "futimes",
|
||||
"__futimes50", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*fd*/ Type.fd,
|
||||
/*timeval[2]*/ Type.timevals.out_ptr
|
||||
);
|
||||
} else {
|
||||
declareLazyFFI(SysFile, "futimes", libc, "futimes", ctypes.default_abi,
|
||||
libc.declareLazyFFI(SysFile, "futimes",
|
||||
"futimes", ctypes.default_abi,
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*fd*/ Type.fd,
|
||||
/*timeval[2]*/ Type.timevals.out_ptr
|
||||
|
@ -39,14 +39,7 @@ let LOG = SharedAll.LOG.bind(SharedAll, "Win", "allthreads");
|
||||
let Const = SharedAll.Constants.Win;
|
||||
|
||||
// Open libc
|
||||
let libc;
|
||||
try {
|
||||
libc = ctypes.open("kernel32.dll");
|
||||
} catch (ex) {
|
||||
// Note: If you change the string here, please adapt consumers and
|
||||
// tests accordingly
|
||||
throw new Error("Could not open system library: " + ex.message);
|
||||
}
|
||||
let libc = new SharedAll.Library("libc", "kernel32.dll");
|
||||
exports.libc = libc;
|
||||
|
||||
// Define declareFFI
|
||||
@ -56,17 +49,16 @@ exports.declareFFI = declareFFI;
|
||||
let Scope = {};
|
||||
|
||||
// Define Error
|
||||
SharedAll.declareLazy(Scope, "FormatMessage", libc,
|
||||
"FormatMessageW", ctypes.winapi_abi,
|
||||
/*return*/ ctypes.uint32_t,
|
||||
/*flags*/ ctypes.uint32_t,
|
||||
/*source*/ ctypes.voidptr_t,
|
||||
/*msgid*/ ctypes.uint32_t,
|
||||
/*langid*/ ctypes.uint32_t,
|
||||
/*buf*/ ctypes.jschar.ptr,
|
||||
/*size*/ ctypes.uint32_t,
|
||||
/*Arguments*/ctypes.voidptr_t
|
||||
);
|
||||
libc.declareLazy(Scope, "FormatMessage",
|
||||
"FormatMessageW", ctypes.winapi_abi,
|
||||
/*return*/ ctypes.uint32_t,
|
||||
/*flags*/ ctypes.uint32_t,
|
||||
/*source*/ ctypes.voidptr_t,
|
||||
/*msgid*/ ctypes.uint32_t,
|
||||
/*langid*/ ctypes.uint32_t,
|
||||
/*buf*/ ctypes.jschar.ptr,
|
||||
/*size*/ ctypes.uint32_t,
|
||||
/*Arguments*/ctypes.voidptr_t);
|
||||
|
||||
/**
|
||||
* A File-related error.
|
||||
|
@ -196,8 +196,8 @@
|
||||
|
||||
// Special case: these functions are used by the
|
||||
// finalizer
|
||||
SharedAll.declareLazy(SysFile, "_CloseHandle", libc,
|
||||
"CloseHandle", ctypes.winapi_abi,
|
||||
libc.declareLazy(SysFile, "_CloseHandle",
|
||||
"CloseHandle", ctypes.winapi_abi,
|
||||
/*return */ctypes.bool,
|
||||
/*handle*/ ctypes.voidptr_t);
|
||||
|
||||
@ -209,8 +209,8 @@
|
||||
}
|
||||
};
|
||||
|
||||
SharedAll.declareLazy(SysFile, "_FindClose", libc,
|
||||
"FindClose", ctypes.winapi_abi,
|
||||
libc.declareLazy(SysFile, "_FindClose",
|
||||
"FindClose", ctypes.winapi_abi,
|
||||
/*return */ctypes.bool,
|
||||
/*handle*/ ctypes.voidptr_t);
|
||||
|
||||
@ -224,20 +224,20 @@
|
||||
|
||||
// Declare libc functions as functions of |OS.Win.File|
|
||||
|
||||
declareLazyFFI(SysFile, "CopyFile", libc,
|
||||
libc.declareLazyFFI(SysFile, "CopyFile",
|
||||
"CopyFileW", ctypes.winapi_abi,
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*sourcePath*/ Type.path,
|
||||
/*destPath*/ Type.path,
|
||||
/*bailIfExist*/Type.bool);
|
||||
|
||||
declareLazyFFI(SysFile, "CreateDirectory", libc,
|
||||
libc.declareLazyFFI(SysFile, "CreateDirectory",
|
||||
"CreateDirectoryW", ctypes.winapi_abi,
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*name*/ Type.jschar.in_ptr,
|
||||
/*security*/Type.SECURITY_ATTRIBUTES.in_ptr);
|
||||
|
||||
declareLazyFFI(SysFile, "CreateFile", libc,
|
||||
libc.declareLazyFFI(SysFile, "CreateFile",
|
||||
"CreateFileW", ctypes.winapi_abi,
|
||||
/*return*/ Type.file_HANDLE,
|
||||
/*name*/ Type.path,
|
||||
@ -248,36 +248,36 @@
|
||||
/*flags*/ Type.DWORD,
|
||||
/*template*/Type.HANDLE);
|
||||
|
||||
declareLazyFFI(SysFile, "DeleteFile", libc,
|
||||
libc.declareLazyFFI(SysFile, "DeleteFile",
|
||||
"DeleteFileW", ctypes.winapi_abi,
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*path*/ Type.path);
|
||||
|
||||
declareLazyFFI(SysFile, "FileTimeToSystemTime", libc,
|
||||
libc.declareLazyFFI(SysFile, "FileTimeToSystemTime",
|
||||
"FileTimeToSystemTime", ctypes.winapi_abi,
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*filetime*/Type.FILETIME.in_ptr,
|
||||
/*systime*/ Type.SystemTime.out_ptr);
|
||||
|
||||
declareLazyFFI(SysFile, "SystemTimeToFileTime", libc,
|
||||
libc.declareLazyFFI(SysFile, "SystemTimeToFileTime",
|
||||
"SystemTimeToFileTime", ctypes.winapi_abi,
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*systime*/ Type.SystemTime.in_ptr,
|
||||
/*filetime*/ Type.FILETIME.out_ptr);
|
||||
|
||||
declareLazyFFI(SysFile, "FindFirstFile", libc,
|
||||
libc.declareLazyFFI(SysFile, "FindFirstFile",
|
||||
"FindFirstFileW", ctypes.winapi_abi,
|
||||
/*return*/ Type.find_HANDLE,
|
||||
/*pattern*/Type.path,
|
||||
/*data*/ Type.FindData.out_ptr);
|
||||
|
||||
declareLazyFFI(SysFile, "FindNextFile", libc,
|
||||
libc.declareLazyFFI(SysFile, "FindNextFile",
|
||||
"FindNextFileW", ctypes.winapi_abi,
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*prev*/ Type.find_HANDLE,
|
||||
/*data*/ Type.FindData.out_ptr);
|
||||
|
||||
declareLazyFFI(SysFile, "FormatMessage", libc,
|
||||
libc.declareLazyFFI(SysFile, "FormatMessage",
|
||||
"FormatMessageW", ctypes.winapi_abi,
|
||||
/*return*/ Type.DWORD,
|
||||
/*flags*/ Type.DWORD,
|
||||
@ -289,20 +289,20 @@
|
||||
/*Arguments*/Type.void_t.in_ptr
|
||||
);
|
||||
|
||||
declareLazyFFI(SysFile, "GetCurrentDirectory", libc,
|
||||
libc.declareLazyFFI(SysFile, "GetCurrentDirectory",
|
||||
"GetCurrentDirectoryW", ctypes.winapi_abi,
|
||||
/*return*/ Type.zero_or_DWORD,
|
||||
/*length*/ Type.DWORD,
|
||||
/*buf*/ Type.out_path
|
||||
);
|
||||
|
||||
declareLazyFFI(SysFile, "GetFileInformationByHandle", libc,
|
||||
libc.declareLazyFFI(SysFile, "GetFileInformationByHandle",
|
||||
"GetFileInformationByHandle", ctypes.winapi_abi,
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*handle*/ Type.HANDLE,
|
||||
/*info*/ Type.FILE_INFORMATION.out_ptr);
|
||||
|
||||
declareLazyFFI(SysFile, "MoveFileEx", libc,
|
||||
libc.declareLazyFFI(SysFile, "MoveFileEx",
|
||||
"MoveFileExW", ctypes.winapi_abi,
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*sourcePath*/ Type.path,
|
||||
@ -310,7 +310,7 @@
|
||||
/*flags*/ Type.DWORD
|
||||
);
|
||||
|
||||
declareLazyFFI(SysFile, "ReadFile", libc,
|
||||
libc.declareLazyFFI(SysFile, "ReadFile",
|
||||
"ReadFile", ctypes.winapi_abi,
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*file*/ Type.HANDLE,
|
||||
@ -320,23 +320,23 @@
|
||||
/*overlapped*/Type.void_t.inout_ptr // FIXME: Implement?
|
||||
);
|
||||
|
||||
declareLazyFFI(SysFile, "RemoveDirectory", libc,
|
||||
libc.declareLazyFFI(SysFile, "RemoveDirectory",
|
||||
"RemoveDirectoryW", ctypes.winapi_abi,
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*path*/ Type.path);
|
||||
|
||||
declareLazyFFI(SysFile, "SetCurrentDirectory", libc,
|
||||
libc.declareLazyFFI(SysFile, "SetCurrentDirectory",
|
||||
"SetCurrentDirectoryW", ctypes.winapi_abi,
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*path*/ Type.path
|
||||
);
|
||||
|
||||
declareLazyFFI(SysFile, "SetEndOfFile", libc,
|
||||
libc.declareLazyFFI(SysFile, "SetEndOfFile",
|
||||
"SetEndOfFile", ctypes.winapi_abi,
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*file*/ Type.HANDLE);
|
||||
|
||||
declareLazyFFI(SysFile, "SetFilePointer", libc,
|
||||
libc.declareLazyFFI(SysFile, "SetFilePointer",
|
||||
"SetFilePointer", ctypes.winapi_abi,
|
||||
/*return*/ Type.negative_or_DWORD,
|
||||
/*file*/ Type.HANDLE,
|
||||
@ -344,7 +344,7 @@
|
||||
/*disthi*/ Type.long.in_ptr,
|
||||
/*method*/ Type.DWORD);
|
||||
|
||||
declareLazyFFI(SysFile, "SetFileTime", libc,
|
||||
libc.declareLazyFFI(SysFile, "SetFileTime",
|
||||
"SetFileTime", ctypes.winapi_abi,
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*file*/ Type.HANDLE,
|
||||
@ -353,7 +353,7 @@
|
||||
/*write*/ Type.FILETIME.in_ptr);
|
||||
|
||||
|
||||
declareLazyFFI(SysFile, "WriteFile", libc,
|
||||
libc.declareLazyFFI(SysFile, "WriteFile",
|
||||
"WriteFile", ctypes.winapi_abi,
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*file*/ Type.HANDLE,
|
||||
@ -363,17 +363,17 @@
|
||||
/*overlapped*/Type.void_t.inout_ptr // FIXME: Implement?
|
||||
);
|
||||
|
||||
declareLazyFFI(SysFile, "FlushFileBuffers", libc,
|
||||
libc.declareLazyFFI(SysFile, "FlushFileBuffers",
|
||||
"FlushFileBuffers", ctypes.winapi_abi,
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*file*/ Type.HANDLE);
|
||||
|
||||
declareLazyFFI(SysFile, "GetFileAttributes", libc,
|
||||
libc.declareLazyFFI(SysFile, "GetFileAttributes",
|
||||
"GetFileAttributesW", ctypes.winapi_abi,
|
||||
/*return*/ Type.DWORD,
|
||||
/*fileName*/ Type.path);
|
||||
|
||||
declareLazyFFI(SysFile, "SetFileAttributes", libc,
|
||||
libc.declareLazyFFI(SysFile, "SetFileAttributes",
|
||||
"SetFileAttributesW", ctypes.winapi_abi,
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*fileName*/ Type.path,
|
||||
@ -402,7 +402,7 @@
|
||||
/*dacl*/ Type.PACL,
|
||||
/*sacl*/ Type.PACL);
|
||||
|
||||
declareLazyFFI(SysFile, "LocalFree", libc,
|
||||
libc.declareLazyFFI(SysFile, "LocalFree",
|
||||
"LocalFree", ctypes.winapi_abi,
|
||||
/*return*/ Type.HLOCAL,
|
||||
/*mem*/ Type.HLOCAL);
|
||||
|
@ -8,7 +8,7 @@ let Ci = Components.interfaces;
|
||||
Cu.import("resource://gre/modules/Services.jsm", this);
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
|
||||
Cu.import("resource://gre/modules/ThirdPartyCookieProbe.jsm", this);
|
||||
Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", this);
|
||||
Cu.import("resource://gre/modules/Promise.jsm", this);
|
||||
Cu.import("resource://gre/modules/TelemetryPing.jsm", this);
|
||||
|
||||
let TOPIC_ACCEPTED = "third-party-cookie-accepted";
|
||||
|
Loading…
Reference in New Issue
Block a user