Backed out changeset 5566e83980ed (bug 1313155) for mass build bustage a=backout CLOSED TREE

MozReview-Commit-ID: Co3f2Vkbf4y
This commit is contained in:
Wes Kocher 2017-01-12 14:16:52 -08:00
Родитель 4b54268de9
Коммит ca99354e00
64 изменённых файлов: 5590 добавлений и 10 удалений

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

@ -37,6 +37,16 @@ this.AccessFu = { // jshint ignore:line
Services.obs.addObserver(this, 'Accessibility:Settings', false);
} catch (x) {
// Not on Android
if (aWindow.navigator.mozSettings) {
let lock = aWindow.navigator.mozSettings.createLock();
let req = lock.get(SCREENREADER_SETTING);
req.addEventListener('success', () => {
this._systemPref = req.result[SCREENREADER_SETTING];
this._enableOrDisable();
});
aWindow.navigator.mozSettings.addObserver(
SCREENREADER_SETTING, this.handleEvent);
}
}
this._activatePref = new PrefCache(
@ -55,6 +65,9 @@ this.AccessFu = { // jshint ignore:line
}
if (Utils.MozBuildApp === 'mobile/android') {
Services.obs.removeObserver(this, 'Accessibility:Settings');
} else if (Utils.win.navigator.mozSettings) {
Utils.win.navigator.mozSettings.removeObserver(
SCREENREADER_SETTING, this.handleEvent);
}
delete this._activatePref;
Utils.uninit();

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

@ -4,7 +4,7 @@
/* global Components, XPCOMUtils, Services, PluralForm, Logger, Rect, Utils,
States, Relations, Roles, dump, Events, PivotContext, PrefCache */
/* exported Utils, Logger, PivotContext, PrefCache */
/* exported Utils, Logger, PivotContext, PrefCache, SettingCache */
'use strict';
@ -26,7 +26,8 @@ XPCOMUtils.defineLazyModuleGetter(this, 'States', // jshint ignore:line
XPCOMUtils.defineLazyModuleGetter(this, 'PluralForm', // jshint ignore:line
'resource://gre/modules/PluralForm.jsm');
this.EXPORTED_SYMBOLS = ['Utils', 'Logger', 'PivotContext', 'PrefCache']; // jshint ignore:line
this.EXPORTED_SYMBOLS = ['Utils', 'Logger', 'PivotContext', 'PrefCache', // jshint ignore:line
'SettingCache'];
this.Utils = { // jshint ignore:line
_buildAppMap: {
@ -1073,3 +1074,41 @@ PrefCache.prototype = {
QueryInterface : XPCOMUtils.generateQI([Ci.nsIObserver,
Ci.nsISupportsWeakReference])
};
this.SettingCache = function SettingCache(aName, aCallback, aOptions = {}) { // jshint ignore:line
this.value = aOptions.defaultValue;
let runCallback = () => {
if (aCallback) {
aCallback(aName, this.value);
if (aOptions.callbackOnce) {
runCallback = () => {};
}
}
};
let settings = Utils.win.navigator.mozSettings;
if (!settings) {
if (aOptions.callbackNow) {
runCallback();
}
return;
}
let lock = settings.createLock();
let req = lock.get(aName);
req.addEventListener('success', () => {
this.value = req.result[aName] === undefined ?
aOptions.defaultValue : req.result[aName];
if (aOptions.callbackNow) {
runCallback();
}
});
settings.addObserver(aName,
(evt) => {
this.value = evt.settingValue;
runCallback();
});
};

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

@ -149,7 +149,8 @@ var AccessFuTest = {
Logger.logLevel = Logger.DEBUG;
};
var prefs = [['accessibility.accessfu.notify_output', 1]];
var prefs = [['accessibility.accessfu.notify_output', 1],
['dom.mozSettings.enabled', true]];
prefs.push.apply(prefs, aAdditionalPrefs);
this.originalDwellThreshold = GestureSettings.dwellThreshold;

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

@ -216,6 +216,7 @@ DEFAULT_TEST_PREFS = {
'layout.css.report_errors': True,
'layout.css.grid.enabled': True,
'layout.spammy_warnings.enabled': False,
'dom.mozSettings.enabled': True,
# Make sure the disk cache doesn't get auto disabled
'network.http.bypass-cachelock-threshold': 200000,
# Always use network provider for geolocation tests

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

@ -31,6 +31,7 @@
"layout.css.report_errors": true,
"layout.css.grid.enabled": true,
"layout.spammy_warnings.enabled": false,
"dom.mozSettings.enabled": true,
"network.http.bypass-cachelock-threshold": 200000,
"geo.provider.testing": true,
"browser.pagethumbnails.capturing_disabled": true,

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

@ -278,6 +278,7 @@ pref("ui.threedlightshadow", "#ece7e2");
pref("ui.threedshadow", "#aea194");
pref("ui.windowframe", "#efebe7");
// Themable via mozSettings
pref("ui.menu", "#f97c17");
pref("ui.menutext", "#ffffff");
pref("ui.infobackground", "#343e40");
@ -408,6 +409,9 @@ pref("dom.webapps.firstRunWithSIM", true);
pref("dom.mozApps.single_variant_sourcedir", "/persist/svoperapps");
#endif
// WebSettings
pref("dom.mozSettings.enabled", true);
// controls if we want camera support
pref("device.camera.enabled", true);
pref("media.realtime_decoder.enabled", true);
@ -912,6 +916,27 @@ pref("dom.mapped_arraybuffer.enabled", true);
// UDPSocket API
pref("dom.udpsocket.enabled", true);
// Enable TV Manager API
pref("dom.tv.enabled", true);
// Enable Inputport Manager API
pref("dom.inputport.enabled", true);
pref("dom.mozSettings.SettingsDB.debug.enabled", true);
pref("dom.mozSettings.SettingsManager.debug.enabled", true);
pref("dom.mozSettings.SettingsRequestManager.debug.enabled", true);
pref("dom.mozSettings.SettingsService.debug.enabled", true);
pref("dom.mozSettings.SettingsDB.verbose.enabled", false);
pref("dom.mozSettings.SettingsManager.verbose.enabled", false);
pref("dom.mozSettings.SettingsRequestManager.verbose.enabled", false);
pref("dom.mozSettings.SettingsService.verbose.enabled", false);
// Controlling whether we want to allow forcing some Settings
// IndexedDB transactions to be opened as readonly or keep everything as
// readwrite.
pref("dom.mozSettings.allowForceReadOnly", false);
// Comma separated list of activity names that can only be provided by
// the system app in dev mode.
pref("dom.activities.developer_mode_only", "import-app");

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

@ -111,6 +111,8 @@ function checkDebuggerPort() {
if (dbgport) {
dump('Opening debugger server on ' + dbgport + '\n');
Services.prefs.setCharPref('devtools.debugger.unix-domain-socket', dbgport);
navigator.mozSettings.createLock().set(
{'debugger.remote-mode': 'adb-devtools'});
}
}

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

@ -207,6 +207,7 @@
@RESPATH@/components/dom_quota.xpt
@RESPATH@/components/dom_range.xpt
@RESPATH@/components/dom_security.xpt
@RESPATH@/components/dom_settings.xpt
@RESPATH@/components/dom_sidebar.xpt
@RESPATH@/components/dom_storage.xpt
@RESPATH@/components/dom_stylesheets.xpt
@ -501,6 +502,8 @@
@RESPATH@/components/XULStore.manifest
@RESPATH@/components/messageWakeupService.js
@RESPATH@/components/messageWakeupService.manifest
@RESPATH@/components/SettingsManager.js
@RESPATH@/components/SettingsManager.manifest
@RESPATH@/components/recording-cmdline.js
@RESPATH@/components/recording-cmdline.manifest
@RESPATH@/components/htmlMenuBuilder.js

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

@ -0,0 +1,81 @@
/* 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/. */
var Cu = Components.utils;
const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
const {AppManager} = require("devtools/client/webide/modules/app-manager");
const {Connection} = require("devtools/shared/client/connection-manager");
const ConfigView = require("devtools/client/webide/modules/config-view");
var configView = new ConfigView(window);
window.addEventListener("load", function onLoad() {
window.removeEventListener("load", onLoad);
AppManager.on("app-manager-update", OnAppManagerUpdate);
document.getElementById("close").onclick = CloseUI;
document.getElementById("device-fields").onchange = UpdateField;
document.getElementById("device-fields").onclick = CheckReset;
document.getElementById("search-bar").onkeyup = document.getElementById("search-bar").onclick = SearchField;
document.getElementById("custom-value").onclick = UpdateNewField;
document.getElementById("custom-value-type").onchange = ClearNewFields;
document.getElementById("add-custom-field").onkeyup = CheckNewFieldSubmit;
BuildUI();
}, true);
window.addEventListener("unload", function onUnload() {
window.removeEventListener("unload", onUnload);
AppManager.off("app-manager-update", OnAppManagerUpdate);
});
function CloseUI() {
window.parent.UI.openProject();
}
function OnAppManagerUpdate(event, what) {
if (what == "connection" || what == "runtime-global-actors") {
BuildUI();
}
}
function CheckNewFieldSubmit(event) {
configView.checkNewFieldSubmit(event);
}
function UpdateNewField() {
configView.updateNewField();
}
function ClearNewFields() {
configView.clearNewFields();
}
function CheckReset(event) {
configView.checkReset(event);
}
function UpdateField(event) {
configView.updateField(event);
}
function SearchField(event) {
configView.search(event);
}
var getAllSettings; // Used by tests
function BuildUI() {
configView.resetTable();
if (AppManager.connection &&
AppManager.connection.status == Connection.Status.CONNECTED &&
AppManager.settingsFront) {
configView.front = AppManager.settingsFront;
configView.kind = "Setting";
configView.includeTypeName = false;
getAllSettings = AppManager.settingsFront.getAllSettings()
.then(json => configView.generateDisplay(json));
} else {
CloseUI();
}
}

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

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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/. -->
<!DOCTYPE html [
<!ENTITY % webideDTD SYSTEM "chrome://devtools/locale/webide.dtd" >
%webideDTD;
]>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf8"/>
<link rel="stylesheet" href="chrome://webide/skin/deck.css" type="text/css"/>
<link rel="stylesheet" href="chrome://webide/skin/config-view.css" type="text/css"/>
<script type="application/javascript;version=1.8" src="chrome://webide/content/devicesettings.js"></script>
</head>
<body>
<header>
<div id="controls">
<a id="close">&deck_close;</a>
</div>
<h1>&devicesetting_title;</h1>
<div id="search">
<input type="text" id="search-bar" placeholder="&devicesetting_search;"/>
</div>
</header>
<table id="device-fields">
<tr id="add-custom-field">
<td>
<select id="custom-value-type">
<option value="" selected="selected">&device_typenone;</option>
<option value="boolean">&device_typeboolean;</option>
<option value="number">&device_typenumber;</option>
<option value="string">&device_typestring;</option>
<option value="object">&device_typeobject;</option>
</select>
<input type="text" id="custom-value-name" placeholder="&devicesetting_newname;"/>
</td>
<td class="custom-input">
<input type="text" id="custom-value-text" placeholder="&devicesetting_newtext;"/>
</td>
<td>
<button id="custom-value" class="new-editable">&devicesetting_addnew;</button>
</td>
</tr>
</table>
</body>
</html>

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

@ -20,6 +20,8 @@ webide.jar:
content/monitor.js (monitor.js)
content/devicepreferences.js (devicepreferences.js)
content/devicepreferences.xhtml (devicepreferences.xhtml)
content/devicesettings.js (devicesettings.js)
content/devicesettings.xhtml (devicesettings.xhtml)
content/wifi-auth.js (wifi-auth.js)
content/wifi-auth.xhtml (wifi-auth.xhtml)
content/logs.xhtml (logs.xhtml)

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

@ -1052,6 +1052,10 @@ var Cmds = {
UI.selectDeckPanel("devicepreferences");
},
showSettings: function () {
UI.selectDeckPanel("devicesettings");
},
showMonitor: function () {
UI.selectDeckPanel("monitor");
},

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

@ -157,6 +157,7 @@
<iframe id="deck-panel-runtimedetails" flex="1" lazysrc="runtimedetails.xhtml"/>
<iframe id="deck-panel-monitor" flex="1" lazysrc="monitor.xhtml"/>
<iframe id="deck-panel-devicepreferences" flex="1" lazysrc="devicepreferences.xhtml"/>
<iframe id="deck-panel-devicesettings" flex="1" lazysrc="devicesettings.xhtml"/>
<iframe id="deck-panel-logs" flex="1" src="logs.xhtml"/>
<iframe id="deck-panel-simulator" flex="1" lazysrc="simulator.xhtml"/>
</deck>

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

@ -60,6 +60,7 @@ skip-if = true # Bug 1201392 - Update add-ons after migration
[test_telemetry.html]
skip-if = true # Bug 1201392 - Update add-ons after migration
[test_device_preferences.html]
[test_device_settings.html]
[test_fullscreenToolbox.html]
[test_zoom.html]
[test_build.html]

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

@ -0,0 +1,87 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf8">
<title></title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
<script type="application/javascript;version=1.8" src="head.js"></script>
<script type="application/javascript;version=1.8" src="device_front_shared.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
</head>
<body>
<script type="application/javascript;version=1.8">
window.onload = function() {
SimpleTest.waitForExplicitFinish();
Task.spawn(function*() {
if (SpecialPowers.isMainProcess()) {
Cu.import("resource://gre/modules/SettingsRequestManager.jsm");
}
if (!DebuggerServer.initialized) {
DebuggerServer.init();
DebuggerServer.addBrowserActors();
}
let win = yield openWebIDE();
let settingIframe = win.document.querySelector("#deck-panel-devicesettings");
let docRuntime = getRuntimeDocument(win);
win.AppManager.update("runtime-list");
yield connectToLocalRuntime(win);
let settings = docRuntime.querySelector("#runtime-settings");
ok(!settings.hasAttribute("disabled"), "device settings cmd enabled");
let deck = win.document.querySelector("#deck");
win.Cmds.showSettings();
is(deck.selectedPanel, settingIframe, "device settings iframe selected");
yield nextTick();
yield lazyIframeIsLoaded(settingIframe);
yield settingIframe.contentWindow.getAllSettings;
setDocument(settingIframe);
let fields = doc.querySelectorAll(".editable");
addNewField();
addNewFieldWithEnter();
editExistingField();
addNewFieldInteger();
yield editFieldInteger();
yield resetNewField("new-string-field");
addNewFieldBoolean();
searchFields(deck, "new-boolean-field2");
DebuggerServer.destroy();
yield closeWebIDE(win);
SimpleTest.finish();
}).then(null, e => {
ok(false, "Exception: " + e);
SimpleTest.finish();
});
}
</script>
</body>
</html>

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

@ -0,0 +1,146 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {Cc, Ci} = require("chrome");
const protocol = require("devtools/shared/protocol");
const {DebuggerServer} = require("devtools/server/main");
const promise = require("promise");
const Services = require("Services");
const { settingsSpec } = require("devtools/shared/specs/settings");
const { FileUtils} = require("resource://gre/modules/FileUtils.jsm");
const { NetUtil} = require("resource://gre/modules/NetUtil.jsm");
var defaultSettings = {};
var settingsFile;
exports.register = function (handle) {
handle.addGlobalActor(SettingsActor, "settingsActor");
};
exports.unregister = function (handle) {
};
function getDefaultSettings() {
let chan = NetUtil.newChannel({
uri: NetUtil.newURI(settingsFile),
loadUsingSystemPrincipal: true});
let stream = chan.open2();
// Obtain a converter to read from a UTF-8 encoded input stream.
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Ci.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
let rawstr = converter.ConvertToUnicode(NetUtil.readInputStreamToString(
stream,
stream.available()) || "");
try {
defaultSettings = JSON.parse(rawstr);
} catch (e) { }
stream.close();
}
function loadSettingsFile() {
// Loading resource://app/defaults/settings.json doesn't work because
// settings.json is not in the omnijar.
// So we look for the app dir instead and go from here...
if (settingsFile) {
return;
}
settingsFile = FileUtils.getFile("DefRt", ["settings.json"], false);
if (!settingsFile || (settingsFile && !settingsFile.exists())) {
// On b2g desktop builds the settings.json file is moved in the
// profile directory by the build system.
settingsFile = FileUtils.getFile("ProfD", ["settings.json"], false);
if (!settingsFile || (settingsFile && !settingsFile.exists())) {
console.log("settings.json file does not exist");
}
}
if (settingsFile.exists()) {
getDefaultSettings();
}
}
var SettingsActor = exports.SettingsActor = protocol.ActorClassWithSpec(settingsSpec, {
_getSettingsService: function () {
let win = Services.wm.getMostRecentWindow(DebuggerServer.chromeWindowType);
return win.navigator.mozSettings;
},
getSetting: function (name) {
let deferred = promise.defer();
let lock = this._getSettingsService().createLock();
let req = lock.get(name);
req.onsuccess = function () {
deferred.resolve(req.result[name]);
};
req.onerror = function () {
deferred.reject(req.error);
};
return deferred.promise;
},
setSetting: function (name, value) {
let deferred = promise.defer();
let data = {};
data[name] = value;
let lock = this._getSettingsService().createLock();
let req = lock.set(data);
req.onsuccess = function () {
deferred.resolve(true);
};
req.onerror = function () {
deferred.reject(req.error);
};
return deferred.promise;
},
_hasUserSetting: function (name, value) {
if (typeof value === "object") {
return JSON.stringify(defaultSettings[name]) !== JSON.stringify(value);
}
return (defaultSettings[name] !== value);
},
getAllSettings: function () {
loadSettingsFile();
let settings = {};
let self = this;
let deferred = promise.defer();
let lock = this._getSettingsService().createLock();
let req = lock.get("*");
req.onsuccess = function () {
for (var name in req.result) {
settings[name] = {
value: req.result[name],
hasUserValue: self._hasUserSetting(name, req.result[name])
};
}
deferred.resolve(settings);
};
req.onfailure = function () {
deferred.reject(req.error);
};
return deferred.promise;
},
clearUserSetting: function (name) {
loadSettingsFile();
try {
this.setSetting(name, defaultSettings[name]);
} catch (e) {
console.log(e);
}
}
});
// For tests
exports._setDefaultSettings = function (settings) {
defaultSettings = settings || {};
};

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

@ -433,6 +433,13 @@ var DebuggerServer = {
type: { global: true }
});
}
if (Services.prefs.getBoolPref("dom.mozSettings.enabled")) {
this.registerModule("devtools/server/actors/settings", {
prefix: "settings",
constructor: "SettingsActor",
type: { global: true }
});
}
this.registerModule("devtools/server/actors/addons", {
prefix: "addons",
constructor: "AddonsActor",

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

@ -89,6 +89,7 @@ support-files =
[test_memory_gc_01.html]
[test_memory_gc_events.html]
[test_preference.html]
[test_settings.html]
[test_setupInParentChild.html]
[test_styles-applied.html]
[test_styles-computed.html]

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

@ -0,0 +1,130 @@
<!DOCTYPE HTML>
<html>
<!--
Bug 1022797 - Settings support from WebIDE
-->
<head>
<meta charset="utf-8">
<title>Test Settings Actor</title>
<script type="text/javascript" src="chrome://mochikit/content/MochiKit/MochiKit.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
</head>
<body>
<pre id="test">
<script>
function runTests() {
var Cu = Components.utils;
var Cc = Components.classes;
var Ci = Components.interfaces;
var {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
var {DebuggerClient} = require("devtools/shared/client/main");
var {DebuggerServer} = require("devtools/server/main");
if (SpecialPowers.isMainProcess()) {
Cu.import("resource://gre/modules/SettingsRequestManager.jsm");
}
SimpleTest.waitForExplicitFinish();
var {getSettingsFront} = require("devtools/shared/fronts/settings");
var {_setDefaultSettings} = require("devtools/server/actors/settings");
DebuggerServer.init(function () { return true; });
DebuggerServer.addBrowserActors();
var client = new DebuggerClient(DebuggerServer.connectPipe());
client.connect().then(function onConnect() {
client.listTabs(function onListTabs(aResponse) {
var s = getSettingsFront(client, aResponse);
var settings = {};
var resetSettings = {};
var fakeSettings = {
"wifi.enabled": true,
"audio.volume.alarm": 15,
"app.reportCrashes": "ask",
"app.someObject": { active: true }
};
var localSetting = {
"wifi.enabled": false,
"audio.volume.alarm": 0,
"app.reportCrashes": "none",
"app.someObject": {}
};
function checkValues() {
is(settings.allSettings["wifi.enabled"].hasUserValue, false, "original unchanged bool setting");
is(settings.allSettings["audio.volume.alarm"].hasUserValue, false, "original unchanged int setting");
is(settings.allSettings["app.reportCrashes"].hasUserValue, false, "original unchanged string setting");
is(settings.allSettings["app.someObject"].hasUserValue, false, "original unchanged object setting");
is(settings.allSettings["wifi.enabled"].value, fakeSettings["wifi.enabled"], "original read/write bool setting");
is(settings.allSettings["audio.volume.alarm"].value, fakeSettings["audio.volume.alarm"], "original read/write int setting");
is(settings.allSettings["app.reportCrashes"].value, fakeSettings["app.reportCrashes"], "original read/write string setting");
is(JSON.stringify(settings.allSettings["app.someObject"].value), JSON.stringify(fakeSettings["app.someObject"]), "original read/write object setting");
is(settings.allUpdatedSettings["wifi.enabled"].hasUserValue, true, "updated user-changed bool setting");
is(settings.allUpdatedSettings["audio.volume.alarm"].hasUserValue, true, "updated user-changed int setting");
is(settings.allUpdatedSettings["app.reportCrashes"].hasUserValue, true, "updated user-changed string setting");
is(settings.allUpdatedSettings["app.someObject"].hasUserValue, true, "updated user-changed object setting");
is(settings["wifi.enabled"], localSetting["wifi.enabled"], "updated bool setting");
is(settings["audio.volume.alarm"], localSetting["audio.volume.alarm"], "updated int setting");
is(settings["app.reportCrashes"], localSetting["app.reportCrashes"], "updated string setting");
is(JSON.stringify(settings["app.someObject"]), JSON.stringify(localSetting["app.someObject"]), "updated object as string setting");
is(resetSettings["wifi.enabled"], fakeSettings["wifi.enabled"], "reset to original bool setting");
is(resetSettings["audio.volume.alarm"], fakeSettings["audio.volume.alarm"], "reset to original int setting");
is(resetSettings["app.reportCrashes"], fakeSettings["app.reportCrashes"], "reset to original string setting");
is(JSON.stringify(resetSettings["app.someObject"]), JSON.stringify(fakeSettings["app.someObject"]), "reset to original object setting");
client.close().then(() => {
DebuggerServer.destroy();
SimpleTest.finish();
});
}
// settings.json doesn't exist outside of b2g so we will fake it.
_setDefaultSettings(fakeSettings);
s.setSetting("wifi.enabled", fakeSettings["wifi.enabled"])
.then(() => s.setSetting("audio.volume.alarm", fakeSettings["audio.volume.alarm"]))
.then(() => s.setSetting("app.reportCrashes", fakeSettings["app.reportCrashes"]))
.then(() => s.setSetting("app.someObject", fakeSettings["app.someObject"]))
.then(() => s.getAllSettings().then(json => settings.allSettings = json))
.then(() => s.setSetting("wifi.enabled", localSetting["wifi.enabled"]))
.then(() => s.setSetting("audio.volume.alarm", localSetting["audio.volume.alarm"]))
.then(() => s.setSetting("app.reportCrashes", localSetting["app.reportCrashes"]))
.then(() => s.setSetting("app.someObject", localSetting["app.someObject"]))
.then(() => s.getAllSettings().then(json => settings.allUpdatedSettings = json))
.then(() => s.getSetting("wifi.enabled")).then(value => settings["wifi.enabled"] = value)
.then(() => s.getSetting("audio.volume.alarm")).then(value => settings["audio.volume.alarm"] = value)
.then(() => s.getSetting("app.reportCrashes")).then(value => settings["app.reportCrashes"] = value)
.then(() => s.getSetting("app.someObject")).then(value => settings["app.someObject"] = value)
.then(() => s.clearUserSetting("wifi.enabled")).then(() => {
s.getSetting("wifi.enabled").then(value => resetSettings["wifi.enabled"] = value);
})
.then(() => s.clearUserSetting("audio.volume.alarm")).then(() => {
s.getSetting("audio.volume.alarm").then(value => resetSettings["audio.volume.alarm"] = value);
})
.then(() => s.clearUserSetting("app.reportCrashes")).then(() => {
s.getSetting("app.reportCrashes").then(value => resetSettings["app.reportCrashes"] = value);
})
.then(() => s.clearUserSetting("app.someObject")).then(() => {
s.getSetting("app.someObject").then(value => {
resetSettings["app.someObject"] = value
}).then(checkValues);
});
});
});
}
window.onload = function () {
runTests();
}
</script>
</pre>
</body>
</html>

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

@ -137,22 +137,45 @@ Transport.prototype = {
/**
* Manages the local device's name. The name can be generated in serveral
* platform-specific ways (see |_generate|). The aim is for each device on the
* same local network to have a unique name.
* same local network to have a unique name. If the Settings API is available,
* the name is saved there to persist across reboots.
*/
function LocalDevice() {
this._name = LocalDevice.UNKNOWN;
if ("@mozilla.org/settingsService;1" in Cc) {
this._settings =
Cc["@mozilla.org/settingsService;1"].getService(Ci.nsISettingsService);
Services.obs.addObserver(this, "mozsettings-changed", false);
}
// Trigger |_get| to load name eagerly
this._get();
}
LocalDevice.SETTING = "devtools.discovery.device";
LocalDevice.UNKNOWN = "unknown";
LocalDevice.prototype = {
_get: function () {
// Without Settings API, just generate a name and stop, since the value
// can't be persisted.
this._generate();
if (!this._settings) {
// Without Settings API, just generate a name and stop, since the value
// can't be persisted.
this._generate();
return;
}
// Initial read of setting value
this._settings.createLock().get(LocalDevice.SETTING, {
handle: (_, name) => {
if (name && name !== LocalDevice.UNKNOWN) {
this._name = name;
log("Device: " + this._name);
return;
}
// No existing name saved, so generate one.
this._generate();
},
handleError: () => log("Failed to get device name setting")
});
},
/**
@ -180,13 +203,39 @@ LocalDevice.prototype = {
}
},
/**
* Observe any changes that might be made via the Settings app
*/
observe: function (subject, topic, data) {
if (topic !== "mozsettings-changed") {
return;
}
if ("wrappedJSObject" in subject) {
subject = subject.wrappedJSObject;
}
if (subject.key !== LocalDevice.SETTING) {
return;
}
this._name = subject.value;
log("Device: " + this._name);
},
get name() {
return this._name;
},
set name(name) {
this._name = name;
log("Device: " + this._name);
if (!this._settings) {
this._name = name;
log("Device: " + this._name);
return;
}
// Persist to Settings API
// The new value will be seen and stored by the observer above
this._settings.createLock().set(LocalDevice.SETTING, name, {
handle: () => {},
handleError: () => log("Failed to set device name setting")
});
}
};

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

@ -0,0 +1,29 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {settingsSpec} = require("devtools/shared/specs/settings");
const protocol = require("devtools/shared/protocol");
const SettingsFront = protocol.FrontClassWithSpec(settingsSpec, {
initialize: function (client, form) {
protocol.Front.prototype.initialize.call(this, client);
this.actorID = form.settingsActor;
this.manage(this);
},
});
const _knownSettingsFronts = new WeakMap();
exports.getSettingsFront = function (client, form) {
if (!form.settingsActor) {
return null;
}
if (_knownSettingsFronts.has(client)) {
return _knownSettingsFronts.get(client);
}
let front = new SettingsFront(client, form);
_knownSettingsFronts.set(client, front);
return front;
};

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

@ -0,0 +1,31 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {Arg, RetVal, generateActorSpec} = require("devtools/shared/protocol");
const settingsSpec = generateActorSpec({
typeName: "settings",
methods: {
getSetting: {
request: { value: Arg(0) },
response: { value: RetVal("json") }
},
setSetting: {
request: { name: Arg(0), value: Arg(1) },
response: {}
},
getAllSettings: {
request: {},
response: { value: RetVal("json") }
},
clearUserSetting: {
request: { name: Arg(0) },
response: {}
}
},
});
exports.settingsSpec = settingsSpec;

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

@ -25,6 +25,7 @@
#include "nsGlobalWindow.h"
#include "nsPIDOMWindow.h"
#include "nsServiceManagerUtils.h"
#include "mozilla/dom/SettingChangeNotificationBinding.h"
#ifdef MOZ_WIDGET_GONK
#include "nsJSUtils.h"
@ -234,6 +235,11 @@ AudioChannelService::Shutdown()
if (IsParentProcess()) {
obs->RemoveObserver(gAudioChannelService, "ipc:content-shutdown");
#ifdef MOZ_WIDGET_GONK
// To monitor the volume settings based on audio channel.
obs->RemoveObserver(gAudioChannelService, "mozsettings-changed");
#endif
}
}
@ -273,6 +279,11 @@ AudioChannelService::AudioChannelService()
obs->AddObserver(this, "outer-window-destroyed", false);
if (IsParentProcess()) {
obs->AddObserver(this, "ipc:content-shutdown", false);
#ifdef MOZ_WIDGET_GONK
// To monitor the volume settings based on audio channel.
obs->AddObserver(this, "mozsettings-changed", false);
#endif
}
}

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

@ -139,6 +139,7 @@ LOCAL_INCLUDES += [
'/docshell/base',
'/dom/base',
'/dom/html',
'/dom/settings',
'/dom/storage',
'/dom/svg',
'/dom/workers',

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

@ -259,6 +259,14 @@ const kEventConstructors = {
return new MozOtaStatusEvent(aName, aProps);
},
},
MozSettingsEvent: { create: function (aName, aProps) {
return new MozSettingsEvent(aName, aProps);
},
},
MozSettingsTransactionEvent: { create: function (aName, aProps) {
return new MozSettingsTransactionEvent(aName, aProps);
},
},
MozSmsEvent: { create: function (aName, aProps) {
return new MozSmsEvent(aName, aProps);
},

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

@ -8,6 +8,21 @@ var browser = Services.wm.getMostRecentWindow('navigator:browser');
var connection = browser.navigator.mozMobileConnections[0];
// provide a fake APN and enable data connection.
function enableDataConnection() {
let setLock = browser.navigator.mozSettings.createLock();
setLock.set({
'ril.data.enabled': true,
'ril.data.apnSettings': [
[
{'carrier':'T-Mobile US',
'apn':'epc.tmobile.com',
'mmsc':'http://mms.msg.eng.t-mobile.com/mms/wapenc',
'types':['default','supl','mms']}
]
]
});
}
// enable 3G radio
function enableRadio() {
if (connection.radioState !== 'enabled') {
@ -32,6 +47,7 @@ addMessageListener('prepare-network', function(message) {
});
enableRadio();
enableDataConnection();
});
addMessageListener('network-cleanup', function(message) {

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

@ -12,6 +12,7 @@ interfaces = [
'core',
'html',
'events',
'settings',
'stylesheets',
'sidebar',
'css',
@ -66,6 +67,7 @@ DIRS += [
'push',
'quota',
'security',
'settings',
'storage',
'svg',
'time',

249
dom/settings/SettingsDB.jsm Normal file
Просмотреть файл

@ -0,0 +1,249 @@
/* 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";
var Cc = Components.classes;
var Ci = Components.interfaces;
var Cu = Components.utils;
Cu.importGlobalProperties(['Blob', 'File']);
Cu.import("resource://gre/modules/Services.jsm");
this.EXPORTED_SYMBOLS = ["SettingsDB", "SETTINGSDB_NAME", "SETTINGSSTORE_NAME"];
var DEBUG = false;
var VERBOSE = false;
try {
DEBUG =
Services.prefs.getBoolPref("dom.mozSettings.SettingsDB.debug.enabled");
VERBOSE =
Services.prefs.getBoolPref("dom.mozSettings.SettingsDB.verbose.enabled");
} catch (ex) { }
function debug(s) {
dump("-*- SettingsDB: " + s + "\n");
}
const TYPED_ARRAY_THINGS = new Set([
"Int8Array",
"Uint8Array",
"Uint8ClampedArray",
"Int16Array",
"Uint16Array",
"Int32Array",
"Uint32Array",
"Float32Array",
"Float64Array",
]);
this.SETTINGSDB_NAME = "settings";
this.SETTINGSDB_VERSION = 8;
this.SETTINGSSTORE_NAME = "settings";
Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
Cu.import("resource://gre/modules/FileUtils.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
this.SettingsDB = function SettingsDB() {}
SettingsDB.prototype = {
__proto__: IndexedDBHelper.prototype,
upgradeSchema: function upgradeSchema(aTransaction, aDb, aOldVersion, aNewVersion) {
let objectStore;
if (aOldVersion == 0) {
objectStore = aDb.createObjectStore(SETTINGSSTORE_NAME, { keyPath: "settingName" });
if (VERBOSE) debug("Created object stores");
} else if (aOldVersion == 1) {
if (VERBOSE) debug("Get object store for upgrade and remove old index");
objectStore = aTransaction.objectStore(SETTINGSSTORE_NAME);
objectStore.deleteIndex("settingValue");
} else {
if (VERBOSE) debug("Get object store for upgrade");
objectStore = aTransaction.objectStore(SETTINGSSTORE_NAME);
}
// Loading resource://app/defaults/settings.json doesn't work because
// settings.json is not in the omnijar.
// So we look for the app dir instead and go from here...
let settingsFile = FileUtils.getFile("DefRt", ["settings.json"], false);
if (!settingsFile || (settingsFile && !settingsFile.exists())) {
// On b2g desktop builds the settings.json file is moved in the
// profile directory by the build system.
settingsFile = FileUtils.getFile("ProfD", ["settings.json"], false);
if (!settingsFile || (settingsFile && !settingsFile.exists())) {
return;
}
}
let chan = NetUtil.newChannel({
uri: NetUtil.newURI(settingsFile),
loadUsingSystemPrincipal: true});
let stream = chan.open2();
// Obtain a converter to read from a UTF-8 encoded input stream.
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Ci.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
let rawstr = converter.ConvertToUnicode(NetUtil.readInputStreamToString(
stream,
stream.available()) || "");
let settings;
try {
settings = JSON.parse(rawstr);
} catch(e) {
if (DEBUG) debug("Error parsing " + settingsFile.path + " : " + e);
return;
}
stream.close();
objectStore.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
let value = cursor.value;
if (value.settingName in settings) {
if (VERBOSE) debug("Upgrade " +settings[value.settingName]);
value.defaultValue = this.prepareValue(settings[value.settingName]);
delete settings[value.settingName];
if ("settingValue" in value) {
value.userValue = this.prepareValue(value.settingValue);
delete value.settingValue;
}
cursor.update(value);
} else if ("userValue" in value || "settingValue" in value) {
value.defaultValue = undefined;
if (aOldVersion == 1 && value.settingValue) {
value.userValue = this.prepareValue(value.settingValue);
delete value.settingValue;
}
cursor.update(value);
} else {
cursor.delete();
}
cursor.continue();
} else {
for (let name in settings) {
let value = this.prepareValue(settings[name]);
if (VERBOSE) debug("Set new:" + name +", " + value);
objectStore.add({ settingName: name, defaultValue: value, userValue: undefined });
}
}
}.bind(this);
},
// If the value is a data: uri, convert it to a Blob.
convertDataURIToBlob: function(aValue) {
/* base64 to ArrayBuffer decoding, from
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding
*/
function b64ToUint6 (nChr) {
return nChr > 64 && nChr < 91 ?
nChr - 65
: nChr > 96 && nChr < 123 ?
nChr - 71
: nChr > 47 && nChr < 58 ?
nChr + 4
: nChr === 43 ?
62
: nChr === 47 ?
63
:
0;
}
function base64DecToArr(sBase64, nBlocksSize) {
let sB64Enc = sBase64.replace(/[^A-Za-z0-9\+\/]/g, ""),
nInLen = sB64Enc.length,
nOutLen = nBlocksSize ? Math.ceil((nInLen * 3 + 1 >> 2) / nBlocksSize) * nBlocksSize
: nInLen * 3 + 1 >> 2,
taBytes = new Uint8Array(nOutLen);
for (let nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) {
nMod4 = nInIdx & 3;
nUint24 |= b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << 18 - 6 * nMod4;
if (nMod4 === 3 || nInLen - nInIdx === 1) {
for (nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) {
taBytes[nOutIdx] = nUint24 >>> (16 >>> nMod3 & 24) & 255;
}
nUint24 = 0;
}
}
return taBytes;
}
// Check if we have a data: uri, and if it's base64 encoded.
// data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEA...
if (typeof aValue == "string" && aValue.startsWith("data:")) {
try {
let uri = Services.io.newURI(aValue);
// XXX: that would be nice to reuse the c++ bits of the data:
// protocol handler instead.
let mimeType = "application/octet-stream";
let mimeDelim = aValue.indexOf(";");
if (mimeDelim !== -1) {
mimeType = aValue.substring(5, mimeDelim);
}
let start = aValue.indexOf(",") + 1;
let isBase64 = ((aValue.indexOf("base64") + 7) == start);
let payload = aValue.substring(start);
return new Blob([isBase64 ? base64DecToArr(payload) : payload],
{ type: mimeType });
} catch(e) {
dump(e);
}
}
return aValue
},
getObjectKind: function(aObject) {
if (aObject === null || aObject === undefined) {
return "primitive";
} else if (Array.isArray(aObject)) {
return "array";
} else if (aObject instanceof File) {
return "file";
} else if (aObject instanceof Ci.nsIDOMBlob) {
return "blob";
} else if (aObject.constructor.name == "Date") {
return "date";
} else if (TYPED_ARRAY_THINGS.has(aObject.constructor.name)) {
return aObject.constructor.name;
} else if (typeof aObject == "object") {
return "object";
} else {
return "primitive";
}
},
// Makes sure any property that is a data: uri gets converted to a Blob.
prepareValue: function(aObject) {
let kind = this.getObjectKind(aObject);
if (kind == "array") {
let res = [];
aObject.forEach(function(aObj) {
res.push(this.prepareValue(aObj));
}, this);
return res;
} else if (kind == "file" || kind == "blob" || kind == "date") {
return aObject;
} else if (kind == "primitive") {
return this.convertDataURIToBlob(aObject);
}
// Fall-through, we now have a dictionary object.
let res = {};
for (let prop in aObject) {
res[prop] = this.prepareValue(aObject[prop]);
}
return res;
},
init: function init() {
this.initDBHelper(SETTINGSDB_NAME, SETTINGSDB_VERSION,
[SETTINGSSTORE_NAME]);
}
}

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

@ -0,0 +1,506 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
var DEBUG = false;
var VERBOSE = false;
try {
DEBUG =
Services.prefs.getBoolPref("dom.mozSettings.SettingsManager.debug.enabled");
VERBOSE =
Services.prefs.getBoolPref("dom.mozSettings.SettingsManager.verbose.enabled");
} catch (ex) { }
function debug(s) {
dump("-*- SettingsManager: " + s + "\n");
}
XPCOMUtils.defineLazyServiceGetter(Services, "DOMRequest",
"@mozilla.org/dom/dom-request-service;1",
"nsIDOMRequestService");
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1",
"nsIMessageSender");
XPCOMUtils.defineLazyServiceGetter(this, "mrm",
"@mozilla.org/memory-reporter-manager;1",
"nsIMemoryReporterManager");
XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
"@mozilla.org/uuid-generator;1",
"nsIUUIDGenerator");
const kObserverSoftLimit = 10;
/**
* In order to make SettingsManager work with Privileged Apps, we need the lock
* to be OOP. However, the lock state needs to be managed on the child process,
* while the IDB functions now happen on the parent process so we don't have to
* expose IDB permissions at the child process level. We use the
* DOMRequestHelper mechanism to deal with DOMRequests/promises across the
* processes.
*
* However, due to the nature of the IDBTransaction lifetime, we need to relay
* to the parent when to finalize the transaction once the child is done with the
* lock. We keep a list of all open requests for a lock, and once the lock
* reaches the end of its receiveMessage function with no more queued requests,
* we consider it dead. At that point, we send a message to the parent to notify
* it to finalize the transaction.
*/
function SettingsLock(aSettingsManager) {
if (VERBOSE) debug("settings lock init");
this._open = true;
this._settingsManager = aSettingsManager;
this._id = uuidgen.generateUUID().toString();
// DOMRequestIpcHelper.initHelper sets this._window
this.initDOMRequestHelper(this._settingsManager._window, ["Settings:Get:OK", "Settings:Get:KO",
"Settings:Clear:OK", "Settings:Clear:KO",
"Settings:Set:OK", "Settings:Set:KO",
"Settings:Finalize:OK", "Settings:Finalize:KO"]);
let createLockPayload = {
lockID: this._id,
isServiceLock: false,
windowID: this._settingsManager.innerWindowID,
lockStack: (new Error).stack
};
this.sendMessage("Settings:CreateLock", createLockPayload);
Services.tm.currentThread.dispatch(this._closeHelper.bind(this), Ci.nsIThread.DISPATCH_NORMAL);
// We only want to file closeHelper once per set of receiveMessage calls.
this._closeCalled = true;
}
SettingsLock.prototype = {
__proto__: DOMRequestIpcHelper.prototype,
set onsettingstransactionsuccess(aHandler) {
this.__DOM_IMPL__.setEventHandler("onsettingstransactionsuccess", aHandler);
},
get onsettingstransactionsuccess() {
return this.__DOM_IMPL__.getEventHandler("onsettingstransactionsuccess");
},
set onsettingstransactionfailure(aHandler) {
this.__DOM_IMPL__.setEventHandler("onsettingstransactionfailure", aHandler);
},
get onsettingstransactionfailure() {
return this.__DOM_IMPL__.getEventHandler("onsettingstransactionfailure");
},
get closed() {
return !this._open;
},
_closeHelper: function() {
if (VERBOSE) debug("closing lock " + this._id);
this._open = false;
this._closeCalled = false;
if (!this._requests || Object.keys(this._requests).length == 0) {
if (VERBOSE) debug("Requests exhausted, finalizing " + this._id);
this._settingsManager.unregisterLock(this._id);
this.sendMessage("Settings:Finalize", {lockID: this._id});
} else {
if (VERBOSE) debug("Requests left: " + Object.keys(this._requests).length);
this.sendMessage("Settings:Run", {lockID: this._id});
}
},
_wrap: function _wrap(obj) {
return Cu.cloneInto(obj, this._settingsManager._window);
},
sendMessage: function(aMessageName, aData) {
// sendMessage can be called after our window has died, or get
// queued to run later in a thread via _closeHelper, but the
// SettingsManager may have died in between the time it was
// scheduled and the time it runs. Make sure our window is valid
// before sending, otherwise just ignore.
if (!this._settingsManager._window) {
Cu.reportError(
"SettingsManager window died, cannot run settings transaction." +
" SettingsMessage: " + aMessageName +
" SettingsData: " + JSON.stringify(aData));
return;
}
cpmm.sendAsyncMessage(aMessageName,
aData,
undefined,
this._settingsManager._window.document.nodePrincipal);
},
receiveMessage: function(aMessage) {
let msg = aMessage.data;
// SettingsRequestManager broadcasts changes to all locks in the child. If
// our lock isn't being addressed, just return.
if (msg.lockID != this._id) {
return;
}
if (VERBOSE) debug("receiveMessage (" + this._id + "): " + aMessage.name);
// Finalizing a transaction does not return a request ID since we are
// supposed to fire callbacks.
//
// We also destroy the DOMRequestHelper after we've received the
// finalize message. At this point, we will be guarenteed no more
// request returns are coming from the SettingsRequestManager.
if (!msg.requestID) {
let event;
switch (aMessage.name) {
case "Settings:Finalize:OK":
if (VERBOSE) debug("Lock finalize ok: " + this._id);
event = new this._window.MozSettingsTransactionEvent("settingstransactionsuccess", {});
this.__DOM_IMPL__.dispatchEvent(event);
this.destroyDOMRequestHelper();
break;
case "Settings:Finalize:KO":
if (DEBUG) debug("Lock finalize failed: " + this._id);
event = new this._window.MozSettingsTransactionEvent("settingstransactionfailure", {
error: msg.errorMsg
});
this.__DOM_IMPL__.dispatchEvent(event);
this.destroyDOMRequestHelper();
break;
default:
if (DEBUG) debug("Message type " + aMessage.name + " is missing a requestID");
}
return;
}
let req = this.getRequest(msg.requestID);
if (!req) {
if (DEBUG) debug("Matching request not found.");
return;
}
this.removeRequest(msg.requestID);
// DOMRequest callbacks called from here can die due to having
// things like marionetteScriptFinished in them. Make sure we file
// our call to run/finalize BEFORE opening the lock and fulfilling
// DOMRequests.
if (!this._closeCalled) {
// We only want to file closeHelper once per set of receiveMessage calls.
Services.tm.currentThread.dispatch(this._closeHelper.bind(this), Ci.nsIThread.DISPATCH_NORMAL);
this._closeCalled = true;
}
if (VERBOSE) debug("receiveMessage: " + aMessage.name);
switch (aMessage.name) {
case "Settings:Get:OK":
for (let i in msg.settings) {
msg.settings[i] = this._wrap(msg.settings[i]);
}
this._open = true;
Services.DOMRequest.fireSuccess(req.request, this._wrap(msg.settings));
this._open = false;
break;
case "Settings:Set:OK":
case "Settings:Clear:OK":
this._open = true;
Services.DOMRequest.fireSuccess(req.request, 0);
this._open = false;
break;
case "Settings:Get:KO":
case "Settings:Set:KO":
case "Settings:Clear:KO":
if (DEBUG) debug("error:" + msg.errorMsg);
Services.DOMRequest.fireError(req.request, msg.errorMsg);
break;
default:
if (DEBUG) debug("Wrong message: " + aMessage.name);
}
},
get: function get(aName) {
if (VERBOSE) debug("get (" + this._id + "): " + aName);
if (!this._open) {
dump("Settings lock not open!\n");
throw Components.results.NS_ERROR_ABORT;
}
let req = this.createRequest();
let reqID = this.getRequestId({request: req});
this.sendMessage("Settings:Get", {requestID: reqID,
lockID: this._id,
name: aName});
return req;
},
set: function set(aSettings) {
if (VERBOSE) debug("send: " + JSON.stringify(aSettings));
if (!this._open) {
throw "Settings lock not open";
}
let req = this.createRequest();
let reqID = this.getRequestId({request: req});
this.sendMessage("Settings:Set", {requestID: reqID,
lockID: this._id,
settings: aSettings});
return req;
},
clear: function clear() {
if (VERBOSE) debug("clear");
if (!this._open) {
throw "Settings lock not open";
}
let req = this.createRequest();
let reqID = this.getRequestId({request: req});
this.sendMessage("Settings:Clear", {requestID: reqID,
lockID: this._id});
return req;
},
classID: Components.ID("{60c9357c-3ae0-4222-8f55-da01428470d5}"),
contractID: "@mozilla.org/settingsLock;1",
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
Ci.nsIObserver,
Ci.nsISupportsWeakReference])
};
function SettingsManager() {
this._callbacks = null;
this._isRegistered = false;
this._locks = [];
this._createdLocks = 0;
this._unregisteredLocks = 0;
}
SettingsManager.prototype = {
_wrap: function _wrap(obj) {
return Cu.cloneInto(obj, this._window);
},
set onsettingchange(aHandler) {
this.__DOM_IMPL__.setEventHandler("onsettingchange", aHandler);
this.checkMessageRegistration();
},
get onsettingchange() {
return this.__DOM_IMPL__.getEventHandler("onsettingchange");
},
createLock: function() {
let lock = new SettingsLock(this);
if (VERBOSE) debug("creating lock " + lock._id);
this._locks.push(lock._id);
this._createdLocks++;
return lock;
},
unregisterLock: function(aLockID) {
let lock_index = this._locks.indexOf(aLockID);
if (lock_index != -1) {
if (VERBOSE) debug("Unregistering lock " + aLockID);
this._locks.splice(lock_index, 1);
this._unregisteredLocks++;
}
},
receiveMessage: function(aMessage) {
if (VERBOSE) debug("Settings::receiveMessage: " + aMessage.name);
let msg = aMessage.json;
switch (aMessage.name) {
case "Settings:Change:Return:OK":
if (VERBOSE) debug('data:' + msg.key + ':' + msg.value + '\n');
let event = new this._window.MozSettingsEvent("settingchange", this._wrap({
settingName: msg.key,
settingValue: msg.value
}));
this.__DOM_IMPL__.dispatchEvent(event);
if (this._callbacks && this._callbacks[msg.key]) {
if (VERBOSE) debug("observe callback called! " + msg.key + " " + this._callbacks[msg.key].length);
this._callbacks[msg.key].forEach(function(cb) {
cb(this._wrap({settingName: msg.key, settingValue: msg.value}));
}.bind(this));
} else {
if (VERBOSE) debug("no observers stored!");
}
break;
default:
if (DEBUG) debug("Wrong message: " + aMessage.name);
}
},
// If we have either observer callbacks or an event handler,
// register for messages from the main thread. Otherwise, if no one
// is listening, unregister to reduce parent load.
checkMessageRegistration: function checkRegistration() {
let handler = this.__DOM_IMPL__.getEventHandler("onsettingchange");
if (!this._isRegistered) {
if (VERBOSE) debug("Registering for messages");
cpmm.sendAsyncMessage("Settings:RegisterForMessages",
undefined,
undefined,
this._window.document.nodePrincipal);
this._isRegistered = true;
} else {
if ((!this._callbacks || Object.keys(this._callbacks).length == 0) &&
!handler) {
if (VERBOSE) debug("Unregistering for messages");
cpmm.sendAsyncMessage("Settings:UnregisterForMessages",
undefined,
undefined,
this._window.document.nodePrincipal);
this._isRegistered = false;
this._callbacks = null;
}
}
},
addObserver: function addObserver(aName, aCallback) {
if (VERBOSE) debug("addObserver " + aName);
if (!this._callbacks) {
this._callbacks = {};
}
if (!this._callbacks[aName]) {
this._callbacks[aName] = [aCallback];
} else {
this._callbacks[aName].push(aCallback);
}
let length = this._callbacks[aName].length;
if (length >= kObserverSoftLimit) {
debug("WARNING: MORE THAN " + kObserverSoftLimit + " OBSERVERS FOR " +
aName + ": " + length + " FROM" + (new Error).stack);
#ifdef DEBUG
debug("JS STOPS EXECUTING AT THIS POINT IN DEBUG BUILDS!");
throw Components.results.NS_ERROR_ABORT;
#endif
}
this.checkMessageRegistration();
},
removeObserver: function removeObserver(aName, aCallback) {
if (VERBOSE) debug("deleteObserver " + aName);
if (this._callbacks && this._callbacks[aName]) {
let index = this._callbacks[aName].indexOf(aCallback);
if (index != -1) {
this._callbacks[aName].splice(index, 1);
if (this._callbacks[aName].length == 0) {
delete this._callbacks[aName];
}
} else {
if (VERBOSE) debug("Callback not found for: " + aName);
}
} else {
if (VERBOSE) debug("No observers stored for " + aName);
}
this.checkMessageRegistration();
},
init: function(aWindow) {
if (VERBOSE) debug("SettingsManager init");
mrm.registerStrongReporter(this);
cpmm.addMessageListener("Settings:Change:Return:OK", this);
Services.obs.addObserver(this, "inner-window-destroyed", false);
let util = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
this.innerWindowID = util.currentInnerWindowID;
this._window = aWindow;
},
observe: function(aSubject, aTopic, aData) {
if (VERBOSE) debug("Topic: " + aTopic);
if (aTopic === "inner-window-destroyed") {
let wId = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data;
if (wId === this.innerWindowID) {
if (DEBUG) debug("Received: inner-window-destroyed for valid innerWindowID=" + wId + ", cleanup.");
this.cleanup();
}
}
},
collectReports: function(aCallback, aData, aAnonymize) {
for (let topic in this._callbacks) {
let length = this._callbacks[topic].length;
if (length == 0) {
continue;
}
let path;
if (length < kObserverSoftLimit) {
path = "settings-observers";
} else {
path = "settings-observers-suspect/referent(topic=" +
(aAnonymize ? "<anonymized>" : topic) + ")";
}
aCallback.callback("", path,
Ci.nsIMemoryReporter.KIND_OTHER,
Ci.nsIMemoryReporter.UNITS_COUNT,
length,
"The number of settings observers for this topic.",
aData);
}
aCallback.callback("",
"settings-locks/alive",
Ci.nsIMemoryReporter.KIND_OTHER,
Ci.nsIMemoryReporter.UNITS_COUNT,
this._locks.length,
"The number of locks that are currently alives.",
aData);
aCallback.callback("",
"settings-locks/created",
Ci.nsIMemoryReporter.KIND_OTHER,
Ci.nsIMemoryReporter.UNITS_COUNT,
this._createdLocks,
"The number of locks that were created.",
aData);
aCallback.callback("",
"settings-locks/deleted",
Ci.nsIMemoryReporter.KIND_OTHER,
Ci.nsIMemoryReporter.UNITS_COUNT,
this._unregisteredLocks,
"The number of locks that were deleted.",
aData);
},
cleanup: function() {
Services.obs.removeObserver(this, "inner-window-destroyed");
// At this point, the window is dying, so there's nothing left
// that we could do with our lock. Go ahead and run finalize on
// it to make sure changes are commited.
for (let i = 0; i < this._locks.length; ++i) {
if (DEBUG) debug("Lock alive at destroy, finalizing: " + this._locks[i]);
// Due to bug 1105511 we should be able to send this without
// cached principals. However, this is scary because any iframe
// in the process could run this?
cpmm.sendAsyncMessage("Settings:Finalize",
{lockID: this._locks[i]});
}
cpmm.removeMessageListener("Settings:Change:Return:OK", this);
mrm.unregisterStrongReporter(this);
this.innerWindowID = null;
this._window = null;
},
classID: Components.ID("{c40b1c70-00fb-11e2-a21f-0800200c9a66}"),
contractID: "@mozilla.org/settingsManager;1",
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
Ci.nsIDOMGlobalPropertyInitializer,
Ci.nsIObserver,
Ci.nsIMemoryReporter]),
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SettingsManager, SettingsLock]);

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

@ -0,0 +1,5 @@
component {c40b1c70-00fb-11e2-a21f-0800200c9a66} SettingsManager.js
contract @mozilla.org/settingsManager;1 {c40b1c70-00fb-11e2-a21f-0800200c9a66}
component {60c9357c-3ae0-4222-8f55-da01428470d5} SettingsManager.js
contract @mozilla.org/settingsLock;1 {60c9357c-3ae0-4222-8f55-da01428470d5}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -0,0 +1,358 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import('resource://gre/modules/SettingsRequestManager.jsm');
/* static functions */
var DEBUG = false;
var VERBOSE = false;
try {
DEBUG =
Services.prefs.getBoolPref("dom.mozSettings.SettingsService.debug.enabled");
VERBOSE =
Services.prefs.getBoolPref("dom.mozSettings.SettingsService.verbose.enabled");
} catch (ex) { }
function debug(s) {
dump("-*- SettingsService: " + s + "\n");
}
XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
"@mozilla.org/uuid-generator;1",
"nsIUUIDGenerator");
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1",
"nsIMessageSender");
XPCOMUtils.defineLazyServiceGetter(this, "mrm",
"@mozilla.org/memory-reporter-manager;1",
"nsIMemoryReporterManager");
const nsIClassInfo = Ci.nsIClassInfo;
const kXpcomShutdownObserverTopic = "xpcom-shutdown";
const SETTINGSSERVICELOCK_CONTRACTID = "@mozilla.org/settingsServiceLock;1";
const SETTINGSSERVICELOCK_CID = Components.ID("{d7a395a0-e292-11e1-834e-1761d57f5f99}");
const nsISettingsServiceLock = Ci.nsISettingsServiceLock;
function makeSettingsServiceRequest(aCallback, aName, aValue) {
return {
callback: aCallback,
name: aName,
value: aValue
};
};
const kLockListeners = ["Settings:Get:OK", "Settings:Get:KO",
"Settings:Clear:OK", "Settings:Clear:KO",
"Settings:Set:OK", "Settings:Set:KO",
"Settings:Finalize:OK", "Settings:Finalize:KO"];
function SettingsServiceLock(aSettingsService, aTransactionCallback) {
if (VERBOSE) debug("settingsServiceLock constr!");
this._open = true;
this._settingsService = aSettingsService;
this._id = uuidgen.generateUUID().toString();
this._transactionCallback = aTransactionCallback;
this._requests = {};
let closeHelper = function() {
if (VERBOSE) debug("closing lock " + this._id);
this._open = false;
this.runOrFinalizeQueries();
}.bind(this);
this.addListeners();
let createLockPayload = {
lockID: this._id,
isServiceLock: true,
windowID: undefined,
lockStack: (new Error).stack
};
this.returnMessage("Settings:CreateLock", createLockPayload);
Services.tm.currentThread.dispatch(closeHelper, Ci.nsIThread.DISPATCH_NORMAL);
}
SettingsServiceLock.prototype = {
get closed() {
return !this._open;
},
addListeners: function() {
for (let msg of kLockListeners) {
cpmm.addMessageListener(msg, this);
}
},
removeListeners: function() {
for (let msg of kLockListeners) {
cpmm.removeMessageListener(msg, this);
}
},
returnMessage: function(aMessage, aData) {
SettingsRequestManager.receiveMessage({
name: aMessage,
data: aData,
target: undefined,
principal: Services.scriptSecurityManager.getSystemPrincipal()
});
},
runOrFinalizeQueries: function() {
if (!this._requests || Object.keys(this._requests).length == 0) {
this.returnMessage("Settings:Finalize", {lockID: this._id});
} else {
this.returnMessage("Settings:Run", {lockID: this._id});
}
},
receiveMessage: function(aMessage) {
let msg = aMessage.data;
// SettingsRequestManager broadcasts changes to all locks in the child. If
// our lock isn't being addressed, just return.
if(msg.lockID != this._id) {
return;
}
if (VERBOSE) debug("receiveMessage (" + this._id + "): " + aMessage.name);
// Finalizing a transaction does not return a request ID since we are
// supposed to fire callbacks.
if (!msg.requestID) {
switch (aMessage.name) {
case "Settings:Finalize:OK":
if (VERBOSE) debug("Lock finalize ok!");
this.callTransactionHandle();
break;
case "Settings:Finalize:KO":
if (DEBUG) debug("Lock finalize failed!");
this.callAbort();
break;
default:
if (DEBUG) debug("Message type " + aMessage.name + " is missing a requestID");
}
this._settingsService.unregisterLock(this._id);
return;
}
let req = this._requests[msg.requestID];
if (!req) {
if (DEBUG) debug("Matching request not found.");
return;
}
delete this._requests[msg.requestID];
switch (aMessage.name) {
case "Settings:Get:OK":
this._open = true;
let settings_names = Object.keys(msg.settings);
if (settings_names.length > 0) {
let name = settings_names[0];
if (DEBUG && settings_names.length > 1) {
debug("Warning: overloaded setting:" + name);
}
let result = msg.settings[name];
this.callHandle(req.callback, name, result);
} else {
this.callHandle(req.callback, req.name, null);
}
this._open = false;
break;
case "Settings:Set:OK":
this._open = true;
// We don't pass values back from sets in SettingsManager...
this.callHandle(req.callback, req.name, req.value);
this._open = false;
break;
case "Settings:Get:KO":
case "Settings:Set:KO":
if (DEBUG) debug("error:" + msg.errorMsg);
this.callError(req.callback, msg.error);
break;
default:
if (DEBUG) debug("Wrong message: " + aMessage.name);
}
this.runOrFinalizeQueries();
},
get: function get(aName, aCallback) {
if (VERBOSE) debug("get (" + this._id + "): " + aName);
if (!this._open) {
if (DEBUG) debug("Settings lock not open!\n");
throw Components.results.NS_ERROR_ABORT;
}
let reqID = uuidgen.generateUUID().toString();
this._requests[reqID] = makeSettingsServiceRequest(aCallback, aName);
this.returnMessage("Settings:Get", {requestID: reqID,
lockID: this._id,
name: aName});
},
set: function set(aName, aValue, aCallback) {
if (VERBOSE) debug("set: " + aName + " " + aValue);
if (!this._open) {
throw "Settings lock not open";
}
let reqID = uuidgen.generateUUID().toString();
this._requests[reqID] = makeSettingsServiceRequest(aCallback, aName, aValue);
let settings = {};
settings[aName] = aValue;
this.returnMessage("Settings:Set", {requestID: reqID,
lockID: this._id,
settings: settings});
},
callHandle: function callHandle(aCallback, aName, aValue) {
try {
aCallback && aCallback.handle ? aCallback.handle(aName, aValue) : null;
} catch (e) {
if (DEBUG) debug("settings 'handle' for " + aName + " callback threw an exception, dropping: " + e + "\n");
}
},
callAbort: function callAbort(aCallback, aMessage) {
try {
aCallback && aCallback.handleAbort ? aCallback.handleAbort(aMessage) : null;
} catch (e) {
if (DEBUG) debug("settings 'abort' callback threw an exception, dropping: " + e + "\n");
}
},
callError: function callError(aCallback, aMessage) {
try {
aCallback && aCallback.handleError ? aCallback.handleError(aMessage) : null;
} catch (e) {
if (DEBUG) debug("settings 'error' callback threw an exception, dropping: " + e + "\n");
}
},
callTransactionHandle: function callTransactionHandle() {
try {
this._transactionCallback && this._transactionCallback.handle ? this._transactionCallback.handle() : null;
} catch (e) {
if (DEBUG) debug("settings 'Transaction handle' callback threw an exception, dropping: " + e + "\n");
}
},
classID : SETTINGSSERVICELOCK_CID,
QueryInterface : XPCOMUtils.generateQI([nsISettingsServiceLock])
};
const SETTINGSSERVICE_CID = Components.ID("{f656f0c0-f776-11e1-a21f-0800200c9a66}");
function SettingsService()
{
if (VERBOSE) debug("settingsService Constructor");
this._locks = [];
this._serviceLocks = {};
this._createdLocks = 0;
this._unregisteredLocks = 0;
this.init();
}
SettingsService.prototype = {
init: function() {
Services.obs.addObserver(this, kXpcomShutdownObserverTopic, false);
mrm.registerStrongReporter(this);
},
uninit: function() {
Services.obs.removeObserver(this, kXpcomShutdownObserverTopic);
mrm.unregisterStrongReporter(this);
},
observe: function(aSubject, aTopic, aData) {
if (VERBOSE) debug("observe: " + aTopic);
if (aTopic === kXpcomShutdownObserverTopic) {
this.uninit();
}
},
receiveMessage: function(aMessage) {
if (VERBOSE) debug("Entering receiveMessage");
let lockID = aMessage.data.lockID;
if (!lockID) {
if (DEBUG) debug("No lock ID");
return;
}
if (!(lockID in this._serviceLocks)) {
if (DEBUG) debug("Received message for lock " + lockID + " but no lock");
return;
}
if (VERBOSE) debug("Delivering message");
this._serviceLocks[lockID].receiveMessage(aMessage);
},
createLock: function createLock(aCallback) {
if (VERBOSE) debug("Calling createLock");
var lock = new SettingsServiceLock(this, aCallback);
if (VERBOSE) debug("Created lock " + lock._id);
this.registerLock(lock);
return lock;
},
registerLock: function(aLock) {
if (VERBOSE) debug("Registering lock " + aLock._id);
this._locks.push(aLock._id);
this._serviceLocks[aLock._id] = aLock;
this._createdLocks++;
},
unregisterLock: function(aLockID) {
let lock_index = this._locks.indexOf(aLockID);
if (lock_index != -1) {
if (VERBOSE) debug("Unregistering lock " + aLockID);
this._locks.splice(lock_index, 1);
this._serviceLocks[aLockID].removeListeners();
this._serviceLocks[aLockID] = null;
delete this._serviceLocks[aLockID];
this._unregisteredLocks++;
}
},
collectReports: function(aCallback, aData, aAnonymize) {
aCallback.callback("",
"settings-service-locks/alive",
Ci.nsIMemoryReporter.KIND_OTHER,
Ci.nsIMemoryReporter.UNITS_COUNT,
this._locks.length,
"The number of service locks that are currently alives.",
aData);
aCallback.callback("",
"settings-service-locks/created",
Ci.nsIMemoryReporter.KIND_OTHER,
Ci.nsIMemoryReporter.UNITS_COUNT,
this._createdLocks,
"The number of service locks that were created.",
aData);
aCallback.callback("",
"settings-service-locks/deleted",
Ci.nsIMemoryReporter.KIND_OTHER,
Ci.nsIMemoryReporter.UNITS_COUNT,
this._unregisteredLocks,
"The number of service locks that were deleted.",
aData);
},
classID : SETTINGSSERVICE_CID,
QueryInterface : XPCOMUtils.generateQI([Ci.nsISettingsService,
Ci.nsIObserver,
Ci.nsIMemoryReporter])
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SettingsService, SettingsServiceLock]);

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

@ -0,0 +1,5 @@
component {d7a395a0-e292-11e1-834e-1761d57f5f99} SettingsService.js
contract @mozilla.org/settingsServiceLock;1 {d7a395a0-e292-11e1-834e-1761d57f5f99}
component {f656f0c0-f776-11e1-a21f-0800200c9a66} SettingsService.js
contract @mozilla.org/settingsService;1 {f656f0c0-f776-11e1-a21f-0800200c9a66}

28
dom/settings/moz.build Normal file
Просмотреть файл

@ -0,0 +1,28 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
EXTRA_COMPONENTS += [
'SettingsManager.manifest'
]
EXTRA_PP_COMPONENTS += [
'SettingsManager.js'
]
if CONFIG['MOZ_B2G']:
EXTRA_COMPONENTS += [
'SettingsService.js',
'SettingsService.manifest',
]
EXTRA_JS_MODULES += [
'SettingsDB.jsm',
'SettingsRequestManager.jsm'
]
MOCHITEST_CHROME_MANIFESTS += ['tests/chrome.ini']
XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']

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

@ -0,0 +1,24 @@
[DEFAULT]
skip-if = toolkit == 'android' # Bug 1287455: takes too long to complete on Android
support-files =
file_loadserver.js
file_bug1110872.js
file_bug1110872.html
test_settings_service.js
test_settings_service_callback.js
[test_settings_service.xul]
run-if = buildapp == 'b2g' || buildapp == 'mulet'
[test_settings_service_callback.xul]
run-if = buildapp == 'b2g' || buildapp == 'mulet'
[test_settings_basics.html]
[test_settings_permissions.html]
[test_settings_blobs.html]
[test_settings_data_uris.html]
[test_settings_events.html]
[test_settings_navigator_object.html]
[test_settings_onsettingchange.html]
[test_settings_bug1110872.html]
skip-if = !e10s
[test_settings_observer_killer.html]
skip-if = !debug

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

@ -0,0 +1,47 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for Bug {1110872} Settings API Reloads</title>
</head>
<body>
<script type="application/javascript;version=1.7">
var createLock = function (msg) {
var lock = navigator.mozSettings.createLock();
var req = lock.get("wallpaper.image");
// We don't actually care about success or failure here, we just
// want to know the queue gets processed at all.
req.onsuccess = function () {
parent.postMessage({name:"done" + msg.data.step}, "*");
}
req.onerror = function () {
parent.postMessage({name:"done" + msg.data.step}, "*");
};
return req;
}
window.onload = function() {
window.addEventListener("message", function (msg) {
var i;
var reqs = [];
if (msg.data.step == 1) {
for (i = 0; i < 100; ++i) {
reqs.push(createLock(msg));
}
} else {
reqs.push(createLock(msg));
}
// If this is our first time through, reload
// before the SettingsManager has a chance to get a response
// to our query.
if (msg.data.step == 1) {
location.reload();
}
});
}
</script>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id={1110872}">Mozilla Bug {1110872} Inner Window for Reload Test</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
</body>
</html>

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

@ -0,0 +1,47 @@
"use strict";
SimpleTest.waitForExplicitFinish();
var iframe;
var loadedEvents = 0;
function loadServer() {
var url = SimpleTest.getTestFileURL("file_loadserver.js");
var script = SpecialPowers.loadChromeScript(url);
}
function runTest() {
iframe = document.createElement('iframe');
document.body.appendChild(iframe);
iframe.addEventListener('load', mozbrowserLoaded);
iframe.src = 'file_bug1110872.html';
}
function iframeBodyRecv(msg) {
switch (loadedEvents) {
case 1:
// If we get a message back before we've seen 2 loads, that means
// something went wrong with the test. Fail immediately.
ok(true, 'got response from first test!');
break;
case 2:
// If we get a message back after 2 loads (initial load, reload),
// it means the callback for the last lock fired, which means the
// SettingsRequestManager queue has to have been cleared
// correctly.
ok(true, 'further queries returned ok after SettingsManager death');
SimpleTest.finish();
break;
}
}
function mozbrowserLoaded() {
loadedEvents++;
iframe.contentWindow.postMessage({name: "start", step: loadedEvents}, '*');
window.addEventListener('message', iframeBodyRecv);
}
window.addEventListener("load", function() {
loadServer();
runTest();
});

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

@ -0,0 +1,17 @@
var Ci = Components.interfaces;
var Cc = Components.classes;
var Cu = Components.utils;
// Stolen from SpecialPowers, since at this point we don't know we're in a test.
var isMainProcess = function() {
try {
return Cc["@mozilla.org/xre/app-info;1"].
getService(Ci.nsIXULRuntime).
processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
} catch (e) { }
return true;
};
if (isMainProcess()) {
Components.utils.import("resource://gre/modules/SettingsRequestManager.jsm");
}

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

@ -0,0 +1,816 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id={678695}
-->
<head>
<title>Test for Bug {678695} Settings API</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id={678695}">Mozilla Bug {678695}</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
"use strict";
var url = SimpleTest.getTestFileURL("file_loadserver.js");
var script = SpecialPowers.loadChromeScript(url);
function onUnwantedSuccess() {
ok(false, "onUnwantedSuccess: shouldn't get here");
}
function onFailure() {
ok(false, "in on Failure!");
}
const wifi = {"net3g.apn": "internet.mnc012.mcc345.gprs"};
const wifi2 = {"net3g.apn": "internet.mnc012.mcc345.test"};
var wifi3 = {"net3g.apn2": "internet.mnc012.mcc345.test3"};
var wifiEnabled = {"wifi.enabled": true};
var wifiDisabled = {"wifi.enabled": false};
var screenBright = {"screen.brightness": 0.7};
var screenBright2 = {"screen.brightness": 0.1};
var wifiNetworks0 = { "wifi.networks[0]": { ssid: "myfreenetwork", mac: "01:23:45:67:89:ab", passwd: "secret"}};
var wifiNetworks1 = { "wifi.networks[1]": { ssid: "myfreenetwork2", mac: "01:23:45:67:89:ab", passwd: "secret2"}};
var combination = {
"wifi.enabled": false,
"screen.brightness": 0.7,
"wifi.networks[0]": { ssid: "myfreenetwork", mac: "01:23:45:67:89:ab", passwd: "secret" },
"test.test": true,
"net3g.apn2": "internet.mnc012.mcc345.gprs"
}
function equals(o1, o2) {
var k1 = Object.keys(o1).sort();
var k2 = Object.keys(o2).sort();
if (k1.length != k2.length) return false;
return k1.zip(k2, function(keyPair) {
if(typeof o1[keyPair[0]] == typeof o2[keyPair[1]] == "object"){
return equals(o1[keyPair[0]], o2[keyPair[1]])
} else {
return o1[keyPair[0]] == o2[keyPair[1]];
}
}).all();
};
function observer1(setting) {
is(setting.settingName, "screen.brightness", "Same settingName");
is(setting.settingValue, 0.7, "Same settingvalue");
};
function observer2(setting) {
is(setting.settingName, "screen.brightness", "Same settingName");
is(setting.settingValue, 0.7, "Same settingvalue");
};
function observerWithNext(setting) {
is(setting.settingName, "screen.brightness", "Same settingName");
is(setting.settingValue, 0.7, "Same settingvalue");
next();
};
function onsettingschangeWithNext(event) {
is(event.settingName, "screen.brightness", "Same settingName");
is(event.settingValue, 0.7, "Same settingvalue");
next();
};
function check(o1, o2) {
is(JSON.stringify(o1), JSON.stringify(o2), "same");
}
var req, req2, req3, req4, req5, req6;
var index = 0;
var steps = [
function () {
ok(true, "Deleting database");
var lock = navigator.mozSettings.createLock();
req = lock.clear();
req.onsuccess = function () {
ok(true, "Deleted the database");
next();
};
},
function () {
ok(true, "Setting wifi");
var lock = navigator.mozSettings.createLock();
req = lock.set(wifi);
req.onsuccess = function () {
ok(true, "set done");
}
req.onerror = onFailure;
var lock2 = navigator.mozSettings.createLock();
req2 = lock2.get("net3g.apn");
req2.onsuccess = function () {
is(Object.keys(req2.result).length, 1, "length 1");
check(wifi, req2.result);
ok(true, "Get net3g.apn Done");
next();
};
req2.onerror = onFailure;
},
function () {
ok(true, "Change wifi1");
var lock = navigator.mozSettings.createLock();
req = lock.set(wifi2);
req.onsuccess = function () {
ok(true, "Set Done");
};
req.onerror = onFailure;
ok(true, "Get changed net3g.apn");
req2 = lock.get("net3g.apn");
req2.onsuccess = function () {
is(Object.keys(req2.result).length, 1, "length 1");
check(wifi2, req2.result);
ok(true, "Get net3g.apn Done");
next();
};
req2.onerror = onFailure;
},
function () {
ok(true, "Set Combination");
var lock = navigator.mozSettings.createLock();
req3 = lock.set(combination);
req3.onsuccess = function () {
ok(true, "set done");
req4 = lock.get("net3g.apn2");
req4.onsuccess = function() {
ok(true, "Done");
check(combination["net3g.apn2"], req4.result["net3g.apn2"]);
next();
}
}
req3.onerror = onFailure;
},
function() {
var lock = navigator.mozSettings.createLock();
req4 = lock.get("net3g.apn2");
req4.onsuccess = function() {
ok(true, "Done");
check(combination["net3g.apn2"], req4.result["net3g.apn2"]);
next();
}
req4.onerror = onFailure;
},
function() {
ok(true, "Get unknown key");
var lock = navigator.mozSettings.createLock();
req = lock.get("abc.def");
req.onsuccess = function() {
is(req.result["abc.def"], undefined, "no result");
next();
};
req.onerror = onFailure;
},
function() {
ok(true, "adding onsettingchange");
navigator.mozSettings.onsettingchange = onsettingschangeWithNext;
var lock = navigator.mozSettings.createLock();
req2 = lock.get("screen.brightness");
req2.onsuccess = function() {
ok(true, "end adding onsettingchange");
next();
};
req2.onerror = onFailure;
},
function() {
ok(true, "Test onsettingchange");
var lock = navigator.mozSettings.createLock();
req = lock.set(screenBright);
req.onsuccess = function () {
ok(true, "set done, observer has to call next");
}
req.onerror = onFailure;
},
function() {
ok(true, "delete onsettingschange");
var lock = navigator.mozSettings.createLock();
navigator.mozSettings.onsettingchange = null;
req = lock.set(screenBright);
req.onsuccess = function () {
ok(true, "set done");
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "Waiting for all set callbacks");
var lock = navigator.mozSettings.createLock();
req = lock.get("screen.brightness");
req.onsuccess = function() {
ok(true, "Done");
next();
}
req.onerror = onFailure;
},
function() {
ok(true, "adding Observers 1");
navigator.mozSettings.addObserver("screen.brightness", observer1);
navigator.mozSettings.addObserver("screen.brightness", observer1);
navigator.mozSettings.addObserver("screen.brightness", observer2);
navigator.mozSettings.addObserver("screen.brightness", observerWithNext);
var lock = navigator.mozSettings.createLock();
req2 = lock.get("screen.brightness");
req2.onsuccess = function() {
ok(true, "set observeSetting done!");
next();
};
req2.onerror = onFailure;
},
function() {
ok(true, "test observers");
var lock = navigator.mozSettings.createLock();
req = lock.set(screenBright);
req.onsuccess = function () {
ok(true, "set done");
}
req.onerror = onFailure;
},
function() {
ok(true, "removing Event Listener");
var lock = navigator.mozSettings.createLock();
req = lock.set(screenBright);
req.onsuccess = function () {
ok(true, "set done");
navigator.mozSettings.removeObserver("screen.brightness", observer2);
navigator.mozSettings.removeObserver("screen.brightness", observer1);
}
req.onerror = onFailure;
},
function() {
ok(true, "test Event Listener");
var lock = navigator.mozSettings.createLock();
req = lock.set(screenBright);
req.onsuccess = function () {
ok(true, "set done");
}
req.onerror = onFailure;
},
function() {
ok(true, "removing Event Listener");
var lock = navigator.mozSettings.createLock();
navigator.mozSettings.removeObserver("screen.brightness", observerWithNext);
req = lock.set(screenBright);
req.onsuccess = function () {
ok(true, "set done");
navigator.mozSettings.removeObserver("screen.brightness", observer2);
navigator.mozSettings.removeObserver("screen.brightness", observer1);
next();
}
req.onerror = onFailure;
},
function() {
ok(true, "removing Event Listener");
var lock = navigator.mozSettings.createLock();
req = lock.get("screen.brightness");
req.onsuccess = function () {
ok(true, "get done");
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "Nested test");
var lock = navigator.mozSettings.createLock();
req = lock.get("screen.brightness");
req.onsuccess = function () {
req3 = lock.set({"screen.brightness": req.result["screen.brightness"] + 1})
req3.onsuccess = function () {
req4 = lock.get("screen.brightness");
req4.onsuccess = function() {
is(req4.result["screen.brightness"], 1.7, "same Value");
}
req4.onerror = onFailure;
}
req3.onerror = onFailure;
};
req.onerror = onFailure;
req2 = lock.get("screen.brightness");
req2.onsuccess = function () {
is(req2.result["screen.brightness"], 0.7, "same Value");
}
req2.onerror = onFailure;
var lock2 = navigator.mozSettings.createLock();
req5 = lock2.get("screen.brightness");
req5.onsuccess = function () {
is(req5.result["screen.brightness"], 1.7, "same Value");
next();
}
req5.onerror = onFailure;
},
function () {
ok(true, "Deleting database");
var lock = navigator.mozSettings.createLock();
req = lock.clear();
req.onsuccess = function () {
ok(true, "Deleted the database");
next();
};
},
function () {
var lock = navigator.mozSettings.createLock();
req2 = lock.set(wifi);
req2.onsuccess = function () {
ok(true, "set done");
}
req2.onerror = onFailure;
ok(true, "Get all settings");
var lock2 = navigator.mozSettings.createLock();
req3 = lock2.get("*");
req3.onsuccess = function () {
is(Object.keys(req3.result).length, 1, "length 1");
check(req3.result, wifi);
ok(true, JSON.stringify(req3.result));
ok(true, "Get all settings Done");
};
req3.onerror = onFailure;
req4 = lock2.get("net3g.apn");
req4.onsuccess = function () {
is(Object.keys(req4.result).length, 1, "length 1");
check(wifi, req4.result);
ok(true, "Get net3g.apn Done");
next();
};
req4.onerror = onFailure;
},
function () {
ok(true, "Change wifi1");
var lock = navigator.mozSettings.createLock();
req = lock.set(wifi2);
req.onsuccess = function () {
ok(true, "Set Done");
};
req.onerror = onFailure;
ok(true, "Get changed net3g.apn");
req2 = lock.get("net3g.apn");
req2.onsuccess = function () {
is(Object.keys(req2.result).length, 1, "length 1");
check(wifi2, req2.result);
ok(true, "Get net3g.apn Done");
next();
};
req2.onerror = onFailure;
},
function () {
ok(true, "Test locking");
var lock = navigator.mozSettings.createLock();
var lock2 = navigator.mozSettings.createLock();
req = lock.set(wifiEnabled);
req.onsuccess = function () {
ok(true, "Test Locking Done");
};
req.onerror = onFailure;
req2 = lock2.set(wifiDisabled);
req2.onsuccess = function () {
ok(true, "Set Done");
next();
};
req2.onerror = onFailure;
},
function () {
ok(true, "Test locking result");
var lock = navigator.mozSettings.createLock();
req = lock.get("wifi.enabled");
req.onsuccess = function() {
check(req.result, wifiDisabled);
ok(true, "Test1 locking result done");
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "Test locking heavy");
for (var i=0; i<30; i++) {
// only new locks!
var lock = navigator.mozSettings.createLock();
var obj = {};
obj["wifi.enabled" + i] = true;
req = lock.set( obj );
req.onsuccess = function () {
ok(true, "Set1 Done");
};
req.onerror = onFailure;
};
{
var lock2 = navigator.mozSettings.createLock();
req2 = lock2.get("*");
req2.onsuccess = function () {
is(Object.keys(req2.result).length, 32, "length 12");
ok(true, JSON.stringify(req2.result));
ok(true, "Get all settings Done");
};
req2.onerror = onFailure;
}
var lock2 = navigator.mozSettings.createLock();
var obj = {};
obj["wifi.enabled" + 30] = true;
req3 = lock2.set( obj );
req3.onsuccess = function () {
ok(true, "Set12 Done");
};
req3.onerror = onFailure;
var lock3 = navigator.mozSettings.createLock();
// with one lock
for (var i = 0; i < 30; i++) {
req4 = lock3.get("wifi.enabled" + i);
var testObj = {};
testObj["wifi.enabled" + i] = true;
req4.onsuccess = function () {
check(this.request.result, this.testObj);
ok(true, "Get1 Done");
}.bind({testObj: testObj, request: req4});
req4.onerror = onFailure;
}
ok(true, "start next2!");
var lock4 = navigator.mozSettings.createLock();
for (var i=0; i<30; i++) {
var obj = {};
obj["wifi.enabled" + i] = false;
req4 = lock4.set( obj );
req4.onsuccess = function () {
ok(true, "Set2 Done");
};
req4.onerror = onFailure;
}
var lock5 = navigator.mozSettings.createLock();
for (var i=0; i<30; i++) {
req5 = lock5.get("wifi.enabled" + i);
var testObj = {};
testObj["wifi.enabled" + i] = false;
req5.onsuccess = function () {
check(this.request.result, this.testObj);
ok(true, "Get2 Done");
}.bind({testObj: testObj, request: req5});
req5.onerror = onFailure;
}
var lock6 = navigator.mozSettings.createLock();
req6 = lock6.clear();
req6.onsuccess = function () {
ok(true, "Deleted the database");
next();
};
req6.onerror = onFailure;
},
function () {
ok(true, "reverse Test locking");
var lock2 = navigator.mozSettings.createLock();
var lock = navigator.mozSettings.createLock();
req = lock.set(wifiEnabled);
req.onsuccess = function () {
ok(true, "Test Locking Done");
next();
};
req.onerror = onFailure;
req2 = lock2.set(wifiDisabled);
req2.onsuccess = function () {
ok(true, "Set Done");
};
req2.onerror = onFailure;
},
function () {
ok(true, "Test locking result");
var lock = navigator.mozSettings.createLock();
req = lock.get("wifi.enabled");
req.onsuccess = function() {
check(req.result, wifiEnabled);
ok(true, "Test2 locking result done");
}
req.onerror = onFailure;
var lock2 = navigator.mozSettings.createLock();
req2 = lock2.clear();
req2.onsuccess = function () {
ok(true, "Deleted the database");
};
req2.onerror = onFailure;
var lock3 = navigator.mozSettings.createLock();
req3 = lock3.set(wifi);
req3.onsuccess = function () {
ok(true, "set done");
next();
}
req3.onerror = onFailure;
},
function () {
ok(true, "Get all settings");
var lock = navigator.mozSettings.createLock();
req = lock.get("*");
req.onsuccess = function () {
is(Object.keys(req.result).length, 1, "length 1");
check(wifi, req.result);
ok(true, "Get all settings Done");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Get net3g.apn");
var lock = navigator.mozSettings.createLock();
req = lock.get("net3g.apn");
req.onsuccess = function () {
is(Object.keys(req.result).length, 1, "length 1");
check(wifi, req.result);
ok(true, "Get net3g.apn Done");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Change wifi2");
var lock = navigator.mozSettings.createLock();
req = lock.set(wifi2);
req.onsuccess = function () {
ok(true, "Set Done");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Get net3g.apn");
var lock = navigator.mozSettings.createLock();
req = lock.get("net3g.apn");
req.onsuccess = function () {
is(Object.keys(req.result).length, 1, "length 1");
check(wifi2, req.result);
ok(true, "Get net3g.apn Done");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Add wifi.enabled");
var lock = navigator.mozSettings.createLock();
req = lock.set(wifiEnabled);
req.onsuccess = function () {
ok(true, "Set Done");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Get Wifi Enabled");
var lock = navigator.mozSettings.createLock();
req = lock.get("wifi.enabled");
req.onsuccess = function () {
is(Object.keys(req.result).length, 1, "length 1");
check(wifiEnabled, req.result);
ok(true, "Get wifi.enabledDone");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Get all");
var lock = navigator.mozSettings.createLock();
req = lock.get("*");
req.onsuccess = function () {
is(Object.keys(req.result).length, 2, "length 2");
check(wifiEnabled["wifi.enabled"], req.result["wifi.enabled"]);
check(wifi2["net3g.apn"], req.result["net3g.apn"]);
ok(true, "Get all Done");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Add wifiNetworks");
var lock = navigator.mozSettings.createLock();
req = lock.set(wifiNetworks0);
req.onsuccess = function () {
ok(true, "Set Done");
};
req.onerror = onFailure;
req2 = lock.set(wifiNetworks1);
req2.onsuccess = function () {
ok(true, "Set Done");
next();
};
req2.onerror = onFailure;
},
function () {
ok(true, "Get Wifi Networks");
var lock = navigator.mozSettings.createLock();
req = lock.get("wifi.networks[0]");
req.onsuccess = function () {
is(Object.keys(req.result).length, 1, "length 1");
check(wifiNetworks0, req.result);
ok(true, "Get wifi.networks[0]");
next();
};
req.onerror = onFailure;
},
function() {
ok(true, "Clear DB, multiple locks");
var lock4 = navigator.mozSettings.createLock();
var lock3 = navigator.mozSettings.createLock();
var lock2 = navigator.mozSettings.createLock();
var lock = navigator.mozSettings.createLock();
var lock6 = navigator.mozSettings.createLock();
var lock7 = navigator.mozSettings.createLock();
req = lock.clear();
req.onsuccess = function () {
ok(true, "Deleted the database");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Add wifiNetworks");
var lock = navigator.mozSettings.createLock();
req = lock.set(wifiNetworks0);
req.onsuccess = function () {
ok(true, "Set Done");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Test set after lock closed");
var lockx = navigator.mozSettings.createLock();
var cb = function() {
var reqx = null;
try {
reqx = lockx.set(wifiNetworks0);
ok(false, "should have thrown");
} catch (ex) {
ok(reqx == null, "request is still null");
ok(true, "Caught Exception");
next();
}
}
SimpleTest.executeSoon(cb);
},
function() {
ok(true, "Clear DB");
var lock = navigator.mozSettings.createLock();
req = lock.clear();
req.onsuccess = function () {
ok(true, "Deleted the database");
next();
};
req.onerror = onFailure;
},
function() {
ok(true, "Set with multiple arguments");
var lock = navigator.mozSettings.createLock();
req = lock.set(combination);
req.onsuccess = function () {
ok(true, "Set Done");
next();
};
req.onerror = onFailure;
},
function() {
ok(true, "request argument from multiple set");
var lock = navigator.mozSettings.createLock();
req = lock.get("screen.brightness");
req.onsuccess = function () {
check(req.result["screen.brightness"], 0.7, "get done");
next();
}
req.onerror = onFailure;
},
function() {
ok(true, "Test closed attribute on a valid lock");
var lock = navigator.mozSettings.createLock();
is(lock.closed, false, "closed attribute is false on creation");
req = lock.get("screen.brightness");
req.onsuccess = function () {
is(lock.closed, false, "closed attribute is false on success callback");
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "Test closed attribute on invalid lock");
var lockx = navigator.mozSettings.createLock();
var cb = function() {
var reqx = null;
try {
reqx = lockx.set(wifiNetworks0);
ok(false, "should have thrown");
} catch (ex) {
is(lockx.closed, true, "closed attribute is true");
ok(true, "Caught Exception");
next();
}
}
SimpleTest.executeSoon(cb);
},
function() {
ok(true, "Clear DB");
var lock = navigator.mozSettings.createLock();
req = lock.clear();
req.onsuccess = function () {
ok(true, "Deleted the database");
next();
};
req.onerror = onFailure;
},
function() {
ok(true, "Set object value");
var lock = navigator.mozSettings.createLock();
req = lock.set({"setting-obj": {foo: {bar: 23}}});
req.onsuccess = function() {
req2 = lock.get("setting-obj");
req2.onsuccess = function(event) {
var result = event.target.result["setting-obj"];
ok(result, "Got valid result");
ok(typeof result == "object", "Result is object");
ok("foo" in result && "bar" in result.foo, "Result has properties");
ok(result.foo.bar == 23, "Result properties are set");
next();
};
};
},
function() {
ok(true, "Clear DB");
var lock = navigator.mozSettings.createLock();
req = lock.clear();
req.onsuccess = function () {
ok(true, "Deleted the database");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Call success callback when transaction commits");
var lock = navigator.mozSettings.createLock();
lock.onsettingstransactionsuccess = function () {
next();
};
req = lock.set({"setting-obj": {foo: {bar: 23}}});
req.onsuccess = function() {
req2 = lock.get("setting-obj");
req2.onsuccess = function(event) {
var result = event.target.result["setting-obj"];
ok(result, "Got valid result");
ok(typeof result == "object", "Result is object");
ok("foo" in result && "bar" in result.foo, "Result has properties");
ok(result.foo.bar == 23, "Result properties are set");
};
};
},
function() {
ok(true, "Clear DB");
var lock = navigator.mozSettings.createLock();
req = lock.clear();
req.onsuccess = function () {
ok(true, "Deleted the database");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "all done!\n");
SimpleTest.finish();
}
];
function next() {
ok(true, "Begin!");
if (index >= steps.length) {
ok(false, "Shouldn't get here!");
return;
}
try {
steps[index]();
} catch(ex) {
ok(false, "Caught exception", ex);
}
index += 1;
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(next);
</script>
</pre>
</body>
</html>

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

@ -0,0 +1,148 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=821630
-->
<head>
<title>Test for Bug 821630 Settings API</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=821630">Mozilla Bug 821630</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript;version=1.7">
"use strict";
var url = SimpleTest.getTestFileURL("file_loadserver.js");
var script = SpecialPowers.loadChromeScript(url);
function onUnwantedSuccess() {
ok(false, "onUnwantedSuccess: shouldn't get here");
}
function onFailure() {
return function(s) {
if (s) {
ok(false, "in on Failure! - " + s);
} else {
ok(false, "in on Failure!");
}
}
}
let req;
let storedBlob = new Blob(['12345'], {"type": "text/plain"});
function checkBlob(blob) {
try {
let url = URL.createObjectURL(blob);
ok(true, "Valid blob");
} catch (e) {
ok(false, "Valid blob");
}
}
let steps = [
function() {
let lock = navigator.mozSettings.createLock();
req = lock.clear();
req.onsuccess = next;
req.onerror = onFailure("Deleting database");
},
function() {
function obs(e) {
checkBlob(e.settingValue);
navigator.mozSettings.removeObserver("test1", obs);
next();
}
navigator.mozSettings.addObserver("test1", obs);
next();
},
function() {
// next is called by the observer above
let req = navigator.mozSettings.createLock().set({"test1": storedBlob});
req.onerror = onFailure("Saving blob");
},
function() {
let req = navigator.mozSettings.createLock().get("test1");
req.onsuccess = function(event) {
checkBlob(event.target.result["test1"]);
next();
};
req.onerror = onFailure("Getting blob");
},
function() {
let req = navigator.mozSettings.createLock().set({"test2": [1, 2, storedBlob, 4]});
req.onsuccess = next;
req.onerror = onFailure("Saving array");
},
function() {
let req = navigator.mozSettings.createLock().get("test2");
req.onsuccess = function(event) {
let val = event.target.result["test2"];
ok(Array.isArray(val), "Result is an array");
ok(val[0] == 1 && val[1] == 2 && val[3] == 4, "Primitives are preserved");
checkBlob(val[2]);
next();
};
req.onerror = onFailure("Getting array");
},
function() {
let req = navigator.mozSettings.createLock().set({"test3": {foo: "bar", baz: {number: 1, arr: [storedBlob]}}});
req.onsuccess = next();
req.onerror = onFailure("Saving object");
},
function() {
let req = navigator.mozSettings.createLock().get("test3");
req.onsuccess = function(event) {
let val = event.target.result["test3"];
ok(typeof(val) == "object", "Result is an object");
ok("foo" in val && typeof(val.foo) == "string", "String property preserved");
ok("baz" in val && typeof(val.baz) == "object", "Object property preserved");
let baz = val.baz;
ok("number" in baz && baz.number == 1, "Primite inside object preserved");
ok("arr" in baz && Array.isArray(baz.arr), "Array inside object is preserved");
checkBlob(baz.arr[0]);
next();
};
req.onerror = onFailure("Getting object");
},
function() {
let req = navigator.mozSettings.createLock().clear();
req.onsuccess = function() {
next();
};
req.onerror = onFailure("Deleting database");
},
function () {
ok(true, "all done!\n");
SimpleTest.finish();
}
];
function next() {
try {
let step = steps.shift();
if (step) {
step();
}
} catch(ex) {
ok(false, "Caught exception", ex);
}
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(next);
</script>
</pre>
</body>
</html>

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

@ -0,0 +1,17 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for Bug {1110872} Settings API</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="application/javascript;version=1.7" src="file_bug1110872.js">
</script>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id={1110872}">Mozilla Bug {1110872}</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
</body>
</html>

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

@ -0,0 +1,149 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=806374
-->
<head>
<title>Test for Bug 806374 Settings API</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=821630">Mozilla Bug 821630</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript;version=1.7">
"use strict";
var url = SimpleTest.getTestFileURL("file_loadserver.js");
var script = SpecialPowers.loadChromeScript(url);
function onUnwantedSuccess() {
ok(false, "onUnwantedSuccess: shouldn't get here");
}
function onFailure() {
return function(s) {
if (s) {
ok(false, "in on Failure! - " + s);
} else {
ok(false, "in on Failure!");
}
}
}
let req;
// A simple data URI that will be converted to a blob.
let dataURI = "data:text/html;charset=utf-8,%3C!DOCTYPE html>%3Cbody style='background:black;";
function checkBlob(blob) {
try {
let url = URL.createObjectURL(blob);
ok(true, "Valid blob");
} catch (e) {
ok(false, "Valid blob");
}
}
let steps = [
function() {
let lock = navigator.mozSettings.createLock();
req = lock.clear();
req.onsuccess = next;
req.onerror = onFailure("Deleting database");
},
function() {
function obs(e) {
checkBlob(e.settingValue);
navigator.mozSettings.removeObserver("test1", obs);
next();
}
navigator.mozSettings.addObserver("test1", obs);
next();
},
function() {
// next is called by the observer above
let req = navigator.mozSettings.createLock().set({"test1": dataURI});
req.onerror = onFailure("Saving blob");
},
function() {
let req = navigator.mozSettings.createLock().get("test1");
req.onsuccess = function(event) {
checkBlob(event.target.result["test1"]);
next();
};
req.onerror = onFailure("Getting blob");
},
function() {
let req = navigator.mozSettings.createLock().set({"test2": [1, 2, dataURI, 4]});
req.onsuccess = next;
req.onerror = onFailure("Saving array");
},
function() {
let req = navigator.mozSettings.createLock().get("test2");
req.onsuccess = function(event) {
let val = event.target.result["test2"];
ok(Array.isArray(val), "Result is an array");
ok(val[0] == 1 && val[1] == 2 && val[3] == 4, "Primitives are preserved");
checkBlob(val[2]);
next();
};
req.onerror = onFailure("Getting array");
},
function() {
let req = navigator.mozSettings.createLock().set({"test3": {foo: "bar", baz: {number: 1, arr: [dataURI]}}});
req.onsuccess = next();
req.onerror = onFailure("Saving object");
},
function() {
let req = navigator.mozSettings.createLock().get("test3");
req.onsuccess = function(event) {
let val = event.target.result["test3"];
ok(typeof(val) == "object", "Result is an object");
ok("foo" in val && typeof(val.foo) == "string", "String property preserved");
ok("baz" in val && typeof(val.baz) == "object", "Object property preserved");
let baz = val.baz;
ok("number" in baz && baz.number == 1, "Primite inside object preserved");
ok("arr" in baz && Array.isArray(baz.arr), "Array inside object is preserved");
checkBlob(baz.arr[0]);
next();
};
req.onerror = onFailure("Getting object");
},
function() {
let req = navigator.mozSettings.createLock().clear();
req.onsuccess = function() {
next();
};
req.onerror = onFailure("Deleting database");
},
function () {
ok(true, "all done!\n");
SimpleTest.finish();
}
];
function next() {
try {
let step = steps.shift();
if (step) {
step();
}
} catch(ex) {
ok(false, "Caught exception", ex);
}
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(next);
</script>
</pre>
</body>
</html>

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

@ -0,0 +1,47 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=678695
-->
<head>
<title>Test for Bug 678695</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=678695">Mozilla Bug 678695</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 678695 **/
var e = new MozSettingsEvent("settingchanged", {settingName: "a", settingValue: 1});
ok(e, "Should have settings event!");
is(e.settingName, "a", "Name should be a.");
is(e.settingValue, 1, "Value should be 1.");
e = new MozSettingsEvent("settingchanged", {settingName: "test", settingValue: {test: "test"}});
is(e.settingName, "test", "Name should be 'test'.");
is(e.settingValue.test, "test", "Name should be 'test'.");
e = new MozSettingsEvent("settingchanged", {settingName: "a", settingValue: true});
is(e.settingName, "a", "Name should be a.");
is(e.settingValue, true, "Value should be true.");
var e = new MozSettingsTransactionEvent("settingtransactionsuccess", {});
ok(e, "Should have settings event!");
is(e.error, "", "error should be null");
var e = new MozSettingsTransactionEvent("settingtransactionfailure", {error: "Test error."});
ok(e, "Should have settings event!");
is(e.error, "Test error.", "error should be 'Test error.'");
</script>
</pre>
</body>
</html>

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

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=898512
-->
<head>
<title>Test for Bug 898512 Settings API</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=898512">Mozilla Bug 898512</a>
<p id="display"></p>
<div id="content" style="display: none">
<iframe></iframe>
</div>
<pre id="test">
<script class="testbody" type="text/javascript;version=1.7">
SimpleTest.waitForExplicitFinish();
function testPref() {
SpecialPowers.pushPrefEnv({
set: [["dom.mozSettings.enabled", false]]
}, function() {
is(navigator.mozSettings, undefined, "navigator.mozSettings is undefined");
SimpleTest.finish();
});
}
testPref();
</script>
</pre>
</body>
</html>

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

@ -0,0 +1,60 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1193469
-->
<head>
<title>Test for Bug 1193469 Settings API</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1193469">Mozilla Bug 1193469</a>
<p id="display"></p>
<div id="content" style="display: none">
<iframe></iframe>
</div>
<pre id="test">
<script class="testbody" type="text/javascript;version=1.7">
var url = SimpleTest.getTestFileURL("file_loadserver.js");
var script = SpecialPowers.loadChromeScript(url);
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({
set: [["dom.mozSettings.enabled", true]]
},
function () {
ok(true, "abusing observers");
var obs;
for (obs = 0; obs < 9; obs++) {
navigator.mozSettings.addObserver("fake.setting.key", function(v) {
// nothing to do for real ...
ok(false, "should not be called");
});
ok(true, "first: added observer #" + obs);
}
ok(true, "adding first observers, should not have thrown");
try {
ok(true, "second: adding new observer");
navigator.mozSettings.addObserver("fake.setting.key", function(v) {
// nothing to do for real ...
ok(false, "should not be called");
});
ok(false, "adding too many observers should have thrown");
} catch (ex) {
ok(true, "got exception when trying to add too many observers");
}
SimpleTest.finish();
});
</script>
</pre>
</body>
</html>

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

@ -0,0 +1,306 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=678695
-->
<head>
<title>Test for Bug 678695 Settings API</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=678695">Mozilla Bug 678695</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
"use strict";
var url = SimpleTest.getTestFileURL("file_loadserver.js");
var script = SpecialPowers.loadChromeScript(url);
var screenBright = {"screen.brightness": 0.7};
function onFailure() {
ok(false, "in on Failure!");
}
function observer1(setting) {
dump("observer 1 called!\n");
is(setting.settingName, "screen.brightness", "Same settingName");
is(setting.settingValue, 0.7, "Same settingvalue");
};
function observer2(setting) {
dump("observer 2 called!\n");
is(setting.settingName, "screen.brightness", "Same settingName");
is(setting.settingValue, 0.7, "Same settingvalue");
};
var calls = 0;
function observerOnlyCalledOnce(setting) {
is(++calls, 1, "Observer only called once!");
};
function observerWithNext(setting) {
dump("observer with next called!\n");
is(setting.settingName, "screen.brightness", "Same settingName");
is(setting.settingValue, 0.7, "Same settingvalue");
next();
};
function onsettingschangeWithNext(event) {
dump("onsettingschangewithnext called!\n");
is(event.settingName, "screen.brightness", "Same settingName");
is(event.settingValue, 0.7, "Same settingvalue");
next();
};
var cset = {'a':'b','c':[{'d':'e'}]};
function onComplexSettingschangeWithNext(event) {
is(event.settingName, "test.key", "Same settingName");
is(event.settingValue['a'], "b", "Same settingvalue");
var c = event.settingValue['c'];
ok(Array.isArray(c), "c is array!");
is(c[0]['d'], 'e', "Right settingValue!");
next();
};
var req, req2;
var index = 0;
var steps = [
function () {
ok(true, "Deleting database");
var lock = navigator.mozSettings.createLock();
req = lock.clear();
req.onsuccess = function () {
ok(true, "Deleted the database");
next();
};
req.onerror = onFailure;
},
function () {
var lock = navigator.mozSettings.createLock();
req2 = lock.set(screenBright);
req2.onsuccess = function () {
ok(true, "set done");
navigator.mozSettings.onsettingchange = onsettingschangeWithNext;
next();
}
req2.onerror = onFailure;
},
function() {
ok(true, "testing");
var lock = navigator.mozSettings.createLock();
req2 = lock.set(screenBright);
req2.onsuccess = function() {
ok(true, "end adding onsettingchange");
};
req2.onerror = onFailure;
},
function() {
ok(true, "test observers");
var lock = navigator.mozSettings.createLock();
req = lock.get("screen.brightness");
req.onsuccess = function () {
ok(true, "get done");
next();
}
req.onerror = onFailure;
},
function() {
ok(true, "adding Observers 1");
navigator.mozSettings.addObserver("screen.brightness", observer1);
navigator.mozSettings.addObserver("screen.brightness", observer1);
navigator.mozSettings.addObserver("screen.brightness", observer2);
navigator.mozSettings.addObserver("screen.brightness", observerOnlyCalledOnce);
var lock = navigator.mozSettings.createLock();
req2 = lock.get("screen.brightness");
req2.onsuccess = function() {
ok(true, "set observeSetting done!");
next();
};
req2.onerror = onFailure;
},
function() {
ok(true, "test observers");
var lock = navigator.mozSettings.createLock();
req = lock.set(screenBright);
req.onsuccess = function () {
ok(true, "set1 done");
}
req.onerror = onFailure;
},
function() {
ok(true, "test observers");
var lock = navigator.mozSettings.createLock();
req = lock.get("screen.brightness");
navigator.mozSettings.removeObserver("screen.brightness", observerOnlyCalledOnce);
req.onsuccess = function () {
ok(true, "set1 done");
}
req.onerror = onFailure;
},
function() {
ok(true, "removing Event Listener");
var lock = navigator.mozSettings.createLock();
req = lock.set(screenBright);
req.onsuccess = function () {
ok(true, "set2 done");
navigator.mozSettings.removeObserver("screen.brightness", observer2);
navigator.mozSettings.removeObserver("screen.brightness", observer1);
navigator.mozSettings.removeObserver("screen.brightness", observer1);
}
req.onerror = onFailure;
},
function() {
ok(true, "delete onsettingschange");
var lock = navigator.mozSettings.createLock();
navigator.mozSettings.onsettingchange = null;
req = lock.set(screenBright);
req.onsuccess = function () {
ok(true, "set0 done");
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "Waiting for all set callbacks");
var lock = navigator.mozSettings.createLock();
req = lock.get("screen.brightness");
req.onsuccess = function() {
ok(true, "Done");
next();
}
req.onerror = onFailure;
},
function() {
ok(true, "adding Observers 1");
navigator.mozSettings.addObserver("screen.brightness", observer1);
navigator.mozSettings.addObserver("screen.brightness", observer1);
navigator.mozSettings.addObserver("screen.brightness", observer2);
navigator.mozSettings.addObserver("screen.brightness", observerWithNext);
var lock = navigator.mozSettings.createLock();
req2 = lock.get("screen.brightness");
req2.onsuccess = function() {
ok(true, "set observeSetting done!");
next();
};
req2.onerror = onFailure;
},
function() {
ok(true, "test observers");
var lock = navigator.mozSettings.createLock();
req = lock.set(screenBright);
req.onsuccess = function () {
ok(true, "set1 done");
}
req.onerror = onFailure;
},
function() {
ok(true, "removing Event Listener");
var lock = navigator.mozSettings.createLock();
req = lock.set(screenBright);
req.onsuccess = function () {
ok(true, "set2 done");
navigator.mozSettings.removeObserver("screen.brightness", observer2);
navigator.mozSettings.removeObserver("screen.brightness", observer1);
}
req.onerror = onFailure;
},
function() {
ok(true, "test Event Listener");
var lock = navigator.mozSettings.createLock();
req = lock.set(screenBright);
req.onsuccess = function () {
ok(true, "set3 done");
}
req.onerror = onFailure;
},
function() {
ok(true, "removing Event Listener");
var lock = navigator.mozSettings.createLock();
navigator.mozSettings.removeObserver("screen.brightness", observerWithNext);
req = lock.set(screenBright);
req.onsuccess = function () {
ok(true, "set4 done");
navigator.mozSettings.removeObserver("screen.brightness", observer2);
navigator.mozSettings.removeObserver("screen.brightness", observer1);
next();
}
req.onerror = onFailure;
},
function() {
ok(true, "removing Event Listener");
var lock = navigator.mozSettings.createLock();
req = lock.get("screen.brightness");
req.onsuccess = function () {
ok(true, "get5 done");
next();
}
req.onerror = onFailure;
},
function() {
ok(true, "Clear DB");
var lock = navigator.mozSettings.createLock();
req = lock.clear();
req.onsuccess = function () {
ok(true, "Deleted the database");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Deleting database");
var lock = navigator.mozSettings.createLock();
req = lock.clear();
req.onsuccess = function () {
ok(true, "Deleted the database");
next();
};
req.onerror = onFailure;
},
function () {
var lock = navigator.mozSettings.createLock();
navigator.mozSettings.onsettingchange = onComplexSettingschangeWithNext;
req2 = navigator.mozSettings.createLock().set({'test.key': cset});
req2.onsuccess = function () {
ok(true, "set done");
}
req2.onerror = onFailure;
},
function () {
ok(true, "all done!\n");
SimpleTest.finish();
}
];
function next() {
ok(true, "Begin!");
if (index >= steps.length) {
ok(false, "Shouldn't get here!");
return;
}
try {
steps[index]();
} catch(ex) {
ok(false, "Caught exception", ex);
}
index += 1;
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(next);
</script>
</pre>
</body>
</html>

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

@ -0,0 +1,184 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id={678695}
-->
<head>
<title>Test for Bug {678695} Settings API</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id={900551}">Mozilla Bug {900551}</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
"use strict";
var url = SimpleTest.getTestFileURL("file_loadserver.js");
var script = SpecialPowers.loadChromeScript(url);
function onUnwantedSuccess() {
ok(false, "onUnwantedSuccess: shouldn't get here");
}
// No more permissions, so failure cannot happen
function onFailure() {
ok(true, "in on Failure!");
next();
}
const wifi = {"wifi.enabled": false}
const wallpaper = {"wallpaper.image": "test-image"};
var combination = {
"wifi.enabled": false,
"wallpaper.image": "test-image"
}
function equals(o1, o2) {
var k1 = Object.keys(o1).sort();
var k2 = Object.keys(o2).sort();
if (k1.length != k2.length) return false;
return k1.zip(k2, function(keyPair) {
if(typeof o1[keyPair[0]] == typeof o2[keyPair[1]] == "object"){
return equals(o1[keyPair[0]], o2[keyPair[1]])
} else {
return o1[keyPair[0]] == o2[keyPair[1]];
}
}).all();
};
function observer1(setting) {
is(setting.settingName, "screen.brightness", "Same settingName");
is(setting.settingValue, "0.7", "Same settingvalue");
};
function onsettingschangeWithNext(event) {
is(event.settingName, "screen.brightness", "Same settingName");
is(event.settingValue, "0.7", "Same settingvalue");
next();
};
function check(o1, o2) {
is(JSON.stringify(o1), JSON.stringify(o2), "same");
}
var req, req2, req3, req4, req5, req6;
var index = 0;
var steps = [
// Can't delete database here since that requires permissions we don't want
// to give the page.
function () {
ok(true, "Setting wallpaper");
var lock = navigator.mozSettings.createLock();
req = lock.set(wallpaper);
req.onsuccess = function () {
ok(true, "set done");
}
req.onerror = onFailure;
var lock2 = navigator.mozSettings.createLock();
req2 = lock2.get("wallpaper.image");
req2.onsuccess = function () {
is(Object.keys(req2.result).length, 1, "length 1");
check(wallpaper, req2.result);
ok(true, "Get wallpaper Done");
next();
};
req2.onerror = onFailure;
},
function () {
ok(true, "Get Wifi");
var lock = navigator.mozSettings.createLock();
req = lock.get("wifi.enabled");
req.onerror = function () {
ok(true, "get failed (expected)");
next();
}
req.onsuccess = onFailure;
},
function () {
ok(true, "Set Wifi");
var lock = navigator.mozSettings.createLock();
req = lock.set(wifi);
req.onerror = function () {
ok(true, "set failed (expected)");
next();
}
req.onsuccess = onFailure;
},
function () {
ok(true, "Set combination (1 valid 1 not valid)");
var lock = navigator.mozSettings.createLock();
req = lock.set(combination);
req.onerror = function () {
ok(true, "set failed (expected)");
next();
}
req.onsuccess = onFailure;
},
function () {
ok(true, "All requests on a failed lock should fail");
var lock = navigator.mozSettings.createLock();
lock.onsettingstransactionfailure = function (evt) {
ok(evt.error == "Lock failed a permissions check, all requests now failing.", "transaction failure on permissions error message correct.");
ok(true, "transaction failed (expected) ");
next();
};
lock.onsettingstransactionsuccess = onFailure;
req = lock.set(wifi);
req.onerror = function () {
ok(true, "set failed (expected)");
}
req.onsuccess = onFailure;
req2 = lock.get("wallpaper.image");
req2.onerror = function () {
ok(true, "get failed (expected)");
}
req2.onsuccess = onFailure;
},
function () {
ok(true, "Set combination (1 valid 1 not valid)");
var lock = navigator.mozSettings.createLock();
req = lock.set(combination);
req.onerror = function () {
ok(true, "set failed (expected)");
next();
}
req.onsuccess = onFailure;
},
function () {
ok(true, "all done!\n");
SimpleTest.finish();
}
];
function next() {
ok(true, "Begin!");
if (index >= steps.length) {
ok(false, "Shouldn't get here!");
return;
}
try {
steps[index]();
} catch(ex) {
ok(false, "Caught exception", ex);
}
index += 1;
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(next);
</script>
</pre>
</body>
</html>

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

@ -0,0 +1,138 @@
"use strict";
var Cu = Components.utils;
var Cc = Components.classes;
var Ci = Components.interfaces;
if (SpecialPowers.isMainProcess()) {
SpecialPowers.Cu.import("resource://gre/modules/SettingsRequestManager.jsm");
}
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
SimpleTest.waitForExplicitFinish();
XPCOMUtils.defineLazyServiceGetter(this, "SettingsService",
"@mozilla.org/settingsService;1",
"nsISettingsService");
var tests = [
/* Callback tests */
function() {
let callbackCount = 10;
let callback = {
handle: function(name, result) {
switch (callbackCount) {
case 10:
case 9:
is(result, true, "result is true");
break;
case 8:
case 7:
is(result, false, "result is false");
break;
case 6:
case 5:
is(result, 9, "result is 9");
break;
case 4:
case 3:
is(result, 9.4, "result is 9.4");
break;
case 2:
is(result, false, "result is false");
break;
case 1:
is(result, null, "result is null");
break;
default:
ok(false, "Unexpected call: " + callbackCount);
}
--callbackCount;
if (callbackCount === 0) {
next();
}
},
handleError: function(name) {
ok(false, "error: " + name);
}
};
let lock = SettingsService.createLock();
let lock1 = SettingsService.createLock();
lock.set("asdf", true, callback, null);
lock1.get("asdf", callback);
lock.get("asdf", callback);
lock.set("asdf", false, callback, null);
lock.get("asdf", callback);
lock.set("int", 9, callback, null);
lock.get("int", callback);
lock.set("doub", 9.4, callback, null);
lock.get("doub", callback);
lock1.get("asdfxxx", callback);
},
/* Observer tests */
function() {
const MOZSETTINGS_CHANGED = "mozsettings-changed";
const TEST_OBSERVER_KEY = "test.observer.key";
const TEST_OBSERVER_VALUE = true;
const TEST_OBSERVER_MESSAGE = "test.observer.message";
var obs = {
observe: function (subject, topic, data) {
if (topic !== MOZSETTINGS_CHANGED) {
ok(false, "Event is not mozsettings-changed.");
return;
}
// Data is now stored in subject
if ("wrappedJSObject" in subject) {
ok(true, "JS object wrapped into subject");
subject = subject.wrappedJSObject;
}
if (subject["key"] != TEST_OBSERVER_KEY) {
return;
}
function checkProp(name, type, value) {
ok(name in subject, "subject." + name + " is present");
is(typeof subject[name], type, "subject." + name + " is " + type);
is(subject[name], value, "subject." + name + " is " + value);
}
checkProp("key", "string", TEST_OBSERVER_KEY);
checkProp("value", "boolean", TEST_OBSERVER_VALUE);
checkProp("isInternalChange", "boolean", true);
Services.obs.removeObserver(this, MOZSETTINGS_CHANGED);
next();
}
};
Services.obs.addObserver(obs, MOZSETTINGS_CHANGED, false);
let lock = SettingsService.createLock();
lock.set(TEST_OBSERVER_KEY, TEST_OBSERVER_VALUE, null);
}
];
function next() {
let step = tests.shift();
if (step) {
try {
step();
} catch(e) {
ok(false, "Test threw: " + e);
}
} else {
SimpleTest.finish();
}
}
next();

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

@ -0,0 +1,19 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=678695
-->
<window title="Mozilla Bug 678695"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=678695"
target="_blank">Mozilla Bug 678695</a>
</body>
<script type="application/javascript;version=1.7" src="test_settings_service.js" />
</window>

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

@ -0,0 +1,47 @@
"use strict";
var Cu = Components.utils;
var Cc = Components.classes;
var Ci = Components.interfaces;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
SimpleTest.waitForExplicitFinish();
XPCOMUtils.defineLazyServiceGetter(this, "SettingsService",
"@mozilla.org/settingsService;1",
"nsISettingsService");
var tests = [
function () {
let callback = {
handle: function() {
ok(true, "handle called!");
next();
},
handleAbort: function(name) {
ok(false, "error: " + name);
next();
}
}
let lock = SettingsService.createLock(callback);
lock.set("xasdf", true, null, null);
}
];
function next() {
let step = tests.shift();
if (step) {
try {
step();
} catch(e) {
ok(false, "Test threw: " + e);
}
} else {
SimpleTest.finish();
}
}
next();

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

@ -0,0 +1,19 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1012214
-->
<window title="Mozilla Bug 1012214"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1012214"
target="_blank">Mozilla Bug 1012214</a>
</body>
<script type="application/javascript;version=1.7" src="test_settings_service_callback.js" />
</window>

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

@ -0,0 +1,174 @@
"use strict";
var Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1",
"nsIMessageSender");
var principal = Services.scriptSecurityManager.getSystemPrincipal();
var lockID = "{435d2192-4f21-48d4-90b7-285f147a56be}";
// Helper to start the Settings Request Manager
function startSettingsRequestManager() {
Cu.import("resource://gre/modules/SettingsRequestManager.jsm");
}
function handlerHelper(reply, callback, runNext = true) {
let handler = {
receiveMessage: function(message) {
if (message.name === reply) {
cpmm.removeMessageListener(reply, handler);
callback(message);
if (runNext) {
run_next_test();
}
}
}
};
cpmm.addMessageListener(reply, handler);
}
// Helper function to add a listener, send message and treat the reply
function addAndSend(msg, reply, callback, payload, runNext = true) {
handlerHelper(reply, callback, runNext);
cpmm.sendAsyncMessage(msg, payload, undefined, principal);
}
function errorHandler(reply, str) {
let errHandler = function(message) {
ok(true, str);
};
handlerHelper(reply, errHandler);
}
// We need to trigger a Settings:Run message to make the queue progress
function send_settingsRun() {
let msg = {lockID: lockID, isServiceLock: true};
cpmm.sendAsyncMessage("Settings:Run", msg, undefined, principal);
}
function kill_child() {
let msg = {lockID: lockID, isServiceLock: true};
cpmm.sendAsyncMessage("child-process-shutdown", msg, undefined, principal);
}
function run_test() {
do_get_profile();
startSettingsRequestManager();
run_next_test();
}
add_test(function test_createLock() {
let msg = {lockID: lockID, isServiceLock: true};
cpmm.sendAsyncMessage("Settings:CreateLock", msg, undefined, principal);
cpmm.sendAsyncMessage(
"Settings:RegisterForMessages", undefined, undefined, principal);
ok(true);
run_next_test();
});
add_test(function test_get_empty() {
let requestID = 10;
let msgReply = "Settings:Get:OK";
let msgHandler = function(message) {
equal(requestID, message.data.requestID);
equal(lockID, message.data.lockID);
ok(Object.keys(message.data.settings).length >= 0);
};
errorHandler("Settings:Get:KO", "Settings GET failed");
addAndSend("Settings:Get", msgReply, msgHandler, {
requestID: requestID,
lockID: lockID,
name: "language.current"
});
send_settingsRun();
});
add_test(function test_set_get_nonempty() {
let settings = { "language.current": "fr-FR:XPC" };
let requestIDSet = 20;
let msgReplySet = "Settings:Set:OK";
let msgHandlerSet = function(message) {
equal(requestIDSet, message.data.requestID);
equal(lockID, message.data.lockID);
};
errorHandler("Settings:Set:KO", "Settings SET failed");
addAndSend("Settings:Set", msgReplySet, msgHandlerSet, {
requestID: requestIDSet,
lockID: lockID,
settings: settings
}, false);
let requestIDGet = 25;
let msgReplyGet = "Settings:Get:OK";
let msgHandlerGet = function(message) {
equal(requestIDGet, message.data.requestID);
equal(lockID, message.data.lockID);
for(let p in settings) {
equal(settings[p], message.data.settings[p]);
}
};
addAndSend("Settings:Get", msgReplyGet, msgHandlerGet, {
requestID: requestIDGet,
lockID: lockID,
name: Object.keys(settings)[0]
});
// Set and Get have been push into the queue, let's run
send_settingsRun();
});
// This test exposes bug 1076597 behavior
add_test(function test_wait_for_finalize() {
let settings = { "language.current": "en-US:XPC" };
let requestIDSet = 30;
let msgReplySet = "Settings:Set:OK";
let msgHandlerSet = function(message) {
equal(requestIDSet, message.data.requestID);
equal(lockID, message.data.lockID);
};
errorHandler("Settings:Set:KO", "Settings SET failed");
addAndSend("Settings:Set", msgReplySet, msgHandlerSet, {
requestID: requestIDSet,
lockID: lockID,
settings: settings
}, false);
let requestIDGet = 35;
let msgReplyGet = "Settings:Get:OK";
let msgHandlerGet = function(message) {
equal(requestIDGet, message.data.requestID);
equal(lockID, message.data.lockID);
for(let p in settings) {
equal(settings[p], message.data.settings[p]);
}
};
errorHandler("Settings:Get:KO", "Settings GET failed");
addAndSend("Settings:Get", msgReplyGet, msgHandlerGet, {
requestID: requestIDGet,
lockID: lockID,
name: Object.keys(settings)[0]
});
// We simulate a child death, which will force previous requests to be set
// into finalize state
kill_child();
// Then when we issue Settings:Run, those finalized should be triggered
send_settingsRun();
});

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

@ -0,0 +1,6 @@
[DEFAULT]
head =
tail =
[test_settingsrequestmanager_messages.js]
skip-if = (buildapp != 'b2g')

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

@ -12,6 +12,9 @@ const Cc = Components.classes;
const Cu = Components.utils;
const POSITION_UNAVAILABLE = Ci.nsIDOMGeoPositionError.POSITION_UNAVAILABLE;
const SETTINGS_DEBUG_ENABLED = "geolocation.debugging.enabled";
const SETTINGS_CHANGED_TOPIC = "mozsettings-changed";
const SETTINGS_WIFI_ENABLED = "wifi.enabled";
var gLoggingEnabled = false;
@ -252,6 +255,24 @@ WifiGeoPositionProvider.prototype = {
Ci.nsIObserver]),
listener: null,
observe: function(aSubject, aTopic, aData) {
if (aTopic != SETTINGS_CHANGED_TOPIC) {
return;
}
try {
if ("wrappedJSObject" in aSubject) {
aSubject = aSubject.wrappedJSObject;
}
if (aSubject.key == SETTINGS_DEBUG_ENABLED) {
gLoggingEnabled = aSubject.value;
} else if (aSubject.key == SETTINGS_WIFI_ENABLED) {
gWifiScanningEnabled = aSubject.value;
}
} catch (e) {
}
},
resetTimer: function() {
if (this.timer) {
this.timer.cancel();
@ -270,6 +291,37 @@ WifiGeoPositionProvider.prototype = {
this.started = true;
let self = this;
let settingsCallback = {
handle: function(name, result) {
// Stop the B2G UI setting from overriding the js prefs setting, and turning off logging
// If gLoggingEnabled is already on during startup, that means it was set in js prefs.
if (name == SETTINGS_DEBUG_ENABLED && !gLoggingEnabled) {
gLoggingEnabled = result;
} else if (name == SETTINGS_WIFI_ENABLED) {
gWifiScanningEnabled = result;
if (self.wifiService) {
self.wifiService.stopWatching(self);
}
if (gWifiScanningEnabled) {
self.wifiService = Cc["@mozilla.org/wifi/monitor;1"].getService(Ci.nsIWifiMonitor);
self.wifiService.startWatching(self);
}
}
},
handleError: function(message) {
gLoggingEnabled = false;
LOG("settings callback threw an exception, dropping");
}
};
Services.obs.addObserver(this, SETTINGS_CHANGED_TOPIC, false);
let settingsService = Cc["@mozilla.org/settingsService;1"];
if (settingsService) {
let settings = settingsService.getService(Ci.nsISettingsService);
settings.createLock().get(SETTINGS_WIFI_ENABLED, settingsCallback);
settings.createLock().get(SETTINGS_DEBUG_ENABLED, settingsCallback);
}
if (gWifiScanningEnabled && Cc["@mozilla.org/wifi/monitor;1"]) {
if (this.wifiService) {
@ -307,6 +359,8 @@ WifiGeoPositionProvider.prototype = {
this.wifiService = null;
}
Services.obs.removeObserver(this, SETTINGS_CHANGED_TOPIC);
this.listener = null;
this.started = false;
},

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

@ -867,6 +867,8 @@ var interfaceNamesInGlobalScope =
"ServiceWorkerMessageEvent",
// IMPORTANT: Do not change this list without review from a DOM peer!
"ServiceWorkerRegistration",
// IMPORTANT: Do not change this list without review from a DOM peer!
"SettingsLock",
// IMPORTANT: Do not change this list without review from a DOM peer!
"ShadowRoot", // Bogus, but the test harness forces it on. See bug 1159768.
// IMPORTANT: Do not change this list without review from a DOM peer!

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

@ -0,0 +1,19 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
[Constructor(DOMString type, optional MozSettingsEventInit eventInitDict),
ChromeOnly]
interface MozSettingsEvent : Event
{
readonly attribute DOMString? settingName;
readonly attribute any settingValue;
};
dictionary MozSettingsEventInit : EventInit
{
DOMString settingName = "";
any settingValue = null;
};

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

@ -0,0 +1,17 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
[Constructor(DOMString type, optional MozSettingsTransactionEventInit eventInitDict),
ChromeOnly]
interface MozSettingsTransactionEvent : Event
{
readonly attribute DOMString? error;
};
dictionary MozSettingsTransactionEventInit : EventInit
{
DOMString error = "";
};

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

@ -0,0 +1,42 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
[JSImplementation="@mozilla.org/settingsLock;1",
Pref="dom.mozSettings.enabled"]
interface SettingsLock : EventTarget {
// Whether this lock is invalid
readonly attribute boolean closed;
// Contains a JSON object with name/value pairs to be set.
DOMRequest set(object settings);
// Result contains the value of the setting.
DOMRequest get(DOMString name);
DOMRequest clear();
attribute EventHandler onsettingstransactionsuccess;
attribute EventHandler onsettingstransactionfailure;
};
dictionary SettingChange {
DOMString settingName;
DOMString settingValue;
};
callback SettingChangeCallback = void (SettingChange setting);
[JSImplementation="@mozilla.org/settingsManager;1",
NavigatorProperty="mozSettings",
Pref="dom.mozSettings.enabled",
ChromeOnly]
interface SettingsManager : EventTarget {
SettingsLock createLock();
void addObserver(DOMString name, SettingChangeCallback callback);
void removeObserver(DOMString name, SettingChangeCallback callback);
attribute EventHandler onsettingchange;
};

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

@ -398,6 +398,7 @@ WEBIDL_FILES = [
'ServiceWorkerGlobalScope.webidl',
'ServiceWorkerRegistration.webidl',
'SettingChangeNotification.webidl',
'SettingsManager.webidl',
'ShadowRoot.webidl',
'SharedWorker.webidl',
'SharedWorkerGlobalScope.webidl',
@ -645,6 +646,7 @@ WEBIDL_FILES += [
'DeviceOrientationEvent.webidl',
'DeviceStorageChangeEvent.webidl',
'HashChangeEvent.webidl',
'MozSettingsEvent.webidl',
'PageTransitionEvent.webidl',
'PopStateEvent.webidl',
'PopupBlockedEvent.webidl',
@ -697,6 +699,8 @@ GENERATED_EVENTS_WEBIDL_FILES = [
'ImageCaptureErrorEvent.webidl',
'MediaStreamEvent.webidl',
'MediaStreamTrackEvent.webidl',
'MozSettingsEvent.webidl',
'MozSettingsTransactionEvent.webidl',
'OfflineAudioCompletionEvent.webidl',
'PageTransitionEvent.webidl',
'PerformanceEntryEvent.webidl',

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

@ -41,6 +41,10 @@ Cu.import("chrome://reftest/content/reftest.jsm", reftest);
// Prevent display off during testing.
navigator.mozPower.screenEnabled = true;
var settingLock = navigator.mozSettings.createLock();
var settingResult = settingLock.set({
'screen.timeout': 0
});
settingResult.onsuccess = function () {
dump("Set screen.time to 0\n");
// Start the reftests

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

@ -132,6 +132,7 @@
@BINPATH@/components/dom_quota.xpt
@BINPATH@/components/dom_range.xpt
@BINPATH@/components/dom_security.xpt
@BINPATH@/components/dom_settings.xpt
@BINPATH@/components/dom_sidebar.xpt
@BINPATH@/components/dom_mobilemessage.xpt
@BINPATH@/components/dom_storage.xpt
@ -270,6 +271,8 @@
@BINPATH@/components/Push.manifest
@BINPATH@/components/PushComponents.js
#endif
@BINPATH@/components/SettingsManager.js
@BINPATH@/components/SettingsManager.manifest
@BINPATH@/components/BrowserElementParent.manifest
@BINPATH@/components/BrowserElementParent.js
@BINPATH@/components/FeedProcessor.manifest

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

@ -4846,6 +4846,9 @@ pref("dom.push.http2.reset_retry_count_after_ms", 60000);
pref("dom.push.http2.maxRetries", 2);
pref("dom.push.http2.retryInterval", 5000);
// WebSettings
pref("dom.mozSettings.enabled", false);
// W3C touch events
// 0 - disabled, 1 - enabled, 2 - autodetect
// Autodetection is currently only supported on Windows and GTK3
@ -5284,6 +5287,23 @@ pref("intl.allow-insecure-text-input", false);
// Enable meta-viewport support in remote APZ-enabled frames.
pref("dom.meta-viewport.enabled", false);
// MozSettings debugging prefs for each component
pref("dom.mozSettings.SettingsDB.debug.enabled", false);
pref("dom.mozSettings.SettingsManager.debug.enabled", false);
pref("dom.mozSettings.SettingsRequestManager.debug.enabled", false);
pref("dom.mozSettings.SettingsService.debug.enabled", false);
// MozSettings verbose mode to track everything
pref("dom.mozSettings.SettingsDB.verbose.enabled", false);
pref("dom.mozSettings.SettingsManager.verbose.enabled", false);
pref("dom.mozSettings.SettingsRequestManager.verbose.enabled", false);
pref("dom.mozSettings.SettingsService.verbose.enabled", false);
// Controlling whether we want to allow forcing some Settings
// IndexedDB transactions to be opened as readonly or keep everything as
// readwrite.
pref("dom.mozSettings.allowForceReadOnly", false);
// The interval at which to check for slow running addons
#ifdef NIGHTLY_BUILD
pref("browser.addon-watch.interval", 15000);

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

@ -193,6 +193,12 @@ user_pref("layout.spammy_warnings.enabled", false);
user_pref("media.mediasource.mp4.enabled", true);
user_pref("media.mediasource.webm.enabled", true);
// Enable mozContacts
user_pref("dom.mozContacts.enabled", true);
// Enable mozSettings
user_pref("dom.mozSettings.enabled", true);
// Make sure the disk cache doesn't get auto disabled
user_pref("network.http.bypass-cachelock-threshold", 200000);

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

@ -195,6 +195,7 @@
"scratchpad-manager.jsm": ["ScratchpadManager"],
"server.js": ["MarionetteServer"],
"service.js": ["Service"],
"SettingsDB.jsm": ["SettingsDB", "SETTINGSDB_NAME", "SETTINGSSTORE_NAME"],
"SharedPromptUtils.jsm": ["PromptUtils", "EnableDelayHelper"],
"ShutdownLeaksCollector.jsm": ["ContentCollector"],
"SignInToWebsite.jsm": ["SignInToWebsiteController"],
@ -229,7 +230,7 @@
"userapi.js": ["UserAPI10Client"],
"util.js": ["getChromeWindow", "XPCOMUtils", "Services", "Utils", "Async", "Svc", "Str"],
"utils.js": ["applicationName", "assert", "Copy", "getBrowserObject", "getChromeWindow", "getWindows", "getWindowByTitle", "getWindowByType", "getWindowId", "getMethodInWindows", "getPreference", "saveDataURL", "setPreference", "sleep", "startTimer", "stopTimer", "takeScreenshot", "unwrapNode", "waitFor", "btoa", "encryptPayload", "isConfiguredWithLegacyIdentity", "ensureLegacyIdentityManager", "setBasicCredentials", "makeIdentityConfig", "makeFxAccountsInternalMock", "configureFxAccountIdentity", "configureIdentity", "SyncTestingInfrastructure", "waitForZeroTimer", "Promise", "add_identity_test", "MockFxaStorageManager", "AccountState", "sumHistogram", "CommonUtils", "CryptoUtils", "TestingUtils"],
"Utils.jsm": ["Utils", "Logger", "PivotContext", "PrefCache"],
"Utils.jsm": ["Utils", "Logger", "PivotContext", "PrefCache", "SettingCache"],
"VariablesView.jsm": ["VariablesView", "escapeHTML"],
"VariablesViewController.jsm": ["VariablesViewController", "StackFrameUtils"],
"version.jsm": ["VERSION"],