mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 07:42:04 +00:00
Merge m-c to fx-team. a=merge
This commit is contained in:
commit
ff3f93c106
@ -707,6 +707,8 @@ var CustomEventManager = {
|
||||
switch(detail.type) {
|
||||
case 'webapps-install-granted':
|
||||
case 'webapps-install-denied':
|
||||
case 'webapps-uninstall-granted':
|
||||
case 'webapps-uninstall-denied':
|
||||
WebappsHelper.handleEvent(detail);
|
||||
break;
|
||||
case 'select-choicechange':
|
||||
@ -749,6 +751,7 @@ var WebappsHelper = {
|
||||
init: function webapps_init() {
|
||||
Services.obs.addObserver(this, "webapps-launch", false);
|
||||
Services.obs.addObserver(this, "webapps-ask-install", false);
|
||||
Services.obs.addObserver(this, "webapps-ask-uninstall", false);
|
||||
Services.obs.addObserver(this, "webapps-close", false);
|
||||
},
|
||||
|
||||
@ -771,6 +774,12 @@ var WebappsHelper = {
|
||||
case "webapps-install-denied":
|
||||
DOMApplicationRegistry.denyInstall(installer);
|
||||
break;
|
||||
case "webapps-uninstall-granted":
|
||||
DOMApplicationRegistry.confirmUninstall(installer);
|
||||
break;
|
||||
case "webapps-uninstall-denied":
|
||||
DOMApplicationRegistry.denyUninstall(installer);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
@ -778,6 +787,8 @@ var WebappsHelper = {
|
||||
let json = JSON.parse(data);
|
||||
json.mm = subject;
|
||||
|
||||
let id;
|
||||
|
||||
switch(topic) {
|
||||
case "webapps-launch":
|
||||
DOMApplicationRegistry.getManifestFor(json.manifestURL).then((aManifest) => {
|
||||
@ -795,13 +806,21 @@ var WebappsHelper = {
|
||||
});
|
||||
break;
|
||||
case "webapps-ask-install":
|
||||
let id = this.registerInstaller(json);
|
||||
id = this.registerInstaller(json);
|
||||
shell.sendChromeEvent({
|
||||
type: "webapps-ask-install",
|
||||
id: id,
|
||||
app: json.app
|
||||
});
|
||||
break;
|
||||
case "webapps-ask-uninstall":
|
||||
id = this.registerInstaller(json);
|
||||
shell.sendChromeEvent({
|
||||
type: "webapps-ask-uninstall",
|
||||
id: id,
|
||||
app: json.app
|
||||
});
|
||||
break;
|
||||
case "webapps-close":
|
||||
shell.sendCustomEvent("webapps-close", {
|
||||
"manifestURL": json.manifestURL
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="53a59364ce4f14068034c8d6fe01f4f6b9f78f23">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="a25ae14dbd2fe3e25144a7064efc0cc4e31042b8"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="1934a2297ffc0d90424cd9cd3294c4a8c74a7333"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
@ -133,9 +133,9 @@
|
||||
<project name="platform/hardware/akm" path="hardware/akm" revision="6d3be412647b0eab0adff8a2768736cf4eb68039"/>
|
||||
<project groups="invensense" name="platform/hardware/invensense" path="hardware/invensense" revision="e6d9ab28b4f4e7684f6c07874ee819c9ea0002a2"/>
|
||||
<project name="platform/hardware/ril" path="hardware/ril" revision="865ce3b4a2ba0b3a31421ca671f4d6c5595f8690"/>
|
||||
<project name="kernel/common" path="kernel" revision="388015e5f2f34a8156500226bf37be76a68154ce"/>
|
||||
<project name="kernel/common" path="kernel" revision="f3a717dd8dbb08e558c807c5ede071d83d454207"/>
|
||||
<project name="platform/system/core" path="system/core" revision="b5de04ae22343b6bdaa3455aee291bdf9a872738"/>
|
||||
<project name="u-boot" path="u-boot" revision="3ab28edd4be2673ac979a2338be8d9f0f25b8314"/>
|
||||
<project name="u-boot" path="u-boot" revision="d18f67c122a69f5ff7596a604cf484de5e824f9b"/>
|
||||
<project name="vendor/sprd/gps" path="vendor/sprd/gps" revision="7feb3df0e150053e0143ef525f6e082bda320aea"/>
|
||||
<project name="vendor/sprd/open-source" path="vendor/sprd/open-source" revision="8010ea42ca4963d610c88279dbe35dbaa2f6daf6"/>
|
||||
<project name="vendor/sprd/partner" path="vendor/sprd/partner" revision="8649c7145972251af11b0639997edfecabfc7c2e"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="a25ae14dbd2fe3e25144a7064efc0cc4e31042b8"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="1934a2297ffc0d90424cd9cd3294c4a8c74a7333"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="a25ae14dbd2fe3e25144a7064efc0cc4e31042b8"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="1934a2297ffc0d90424cd9cd3294c4a8c74a7333"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="d59843c1d66bd8d93c6012efda47fa447b99813c"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="53a59364ce4f14068034c8d6fe01f4f6b9f78f23">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="a25ae14dbd2fe3e25144a7064efc0cc4e31042b8"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="1934a2297ffc0d90424cd9cd3294c4a8c74a7333"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="a25ae14dbd2fe3e25144a7064efc0cc4e31042b8"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="1934a2297ffc0d90424cd9cd3294c4a8c74a7333"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="a25ae14dbd2fe3e25144a7064efc0cc4e31042b8"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="1934a2297ffc0d90424cd9cd3294c4a8c74a7333"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="d59843c1d66bd8d93c6012efda47fa447b99813c"/>
|
||||
|
@ -4,6 +4,6 @@
|
||||
"remote": "",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "75d8e419442b5810145a888944ab0ab4f75bbcc9",
|
||||
"revision": "5efa211f0198ab15798b456445f163d57e735cdb",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="a25ae14dbd2fe3e25144a7064efc0cc4e31042b8"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="1934a2297ffc0d90424cd9cd3294c4a8c74a7333"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="a25ae14dbd2fe3e25144a7064efc0cc4e31042b8"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="1934a2297ffc0d90424cd9cd3294c4a8c74a7333"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="a25ae14dbd2fe3e25144a7064efc0cc4e31042b8"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="1934a2297ffc0d90424cd9cd3294c4a8c74a7333"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="d59843c1d66bd8d93c6012efda47fa447b99813c"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="a25ae14dbd2fe3e25144a7064efc0cc4e31042b8"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="1934a2297ffc0d90424cd9cd3294c4a8c74a7333"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -63,7 +63,7 @@ class BaseTestFrontendUnits(MarionetteTestCase):
|
||||
# This extends the timeout for find_element to 10 seconds.
|
||||
# We need this as the tests take an amount of time to run after loading,
|
||||
# which we have to wait for.
|
||||
self.marionette.set_search_timeout(10000)
|
||||
self.marionette.set_search_timeout(60000)
|
||||
|
||||
# srcdir_path should be the directory relative to this file.
|
||||
def set_server_prefix(self, srcdir_path):
|
||||
|
@ -449,6 +449,12 @@ webapps.install.accesskey = I
|
||||
webapps.requestInstall = Do you want to install "%1$S" from this site (%2$S)?
|
||||
webapps.install.success = Application Installed
|
||||
webapps.install.inprogress = Installation in progress
|
||||
webapps.uninstall = Uninstall
|
||||
webapps.uninstall.accesskey = U
|
||||
webapps.doNotUninstall = Don't Uninstall
|
||||
webapps.doNotUninstall.accesskey = D
|
||||
#LOCALIZATION NOTE (webapps.requestUninstall) %1$S is the web app name
|
||||
webapps.requestUninstall = Do you want to uninstall "%1$S"?
|
||||
|
||||
# LOCALIZATION NOTE (fullscreen.entered): displayed when we enter HTML5 fullscreen mode, %S is the domain name of the focused website (e.g. mozilla.com).
|
||||
fullscreen.entered=%S is now fullscreen.
|
||||
|
@ -31,6 +31,7 @@ this.WebappManager = {
|
||||
|
||||
init: function() {
|
||||
Services.obs.addObserver(this, "webapps-ask-install", false);
|
||||
Services.obs.addObserver(this, "webapps-ask-uninstall", false);
|
||||
Services.obs.addObserver(this, "webapps-launch", false);
|
||||
Services.obs.addObserver(this, "webapps-uninstall", false);
|
||||
cpmm.addMessageListener("Webapps:Install:Return:OK", this);
|
||||
@ -40,6 +41,7 @@ this.WebappManager = {
|
||||
|
||||
uninit: function() {
|
||||
Services.obs.removeObserver(this, "webapps-ask-install");
|
||||
Services.obs.removeObserver(this, "webapps-ask-uninstall");
|
||||
Services.obs.removeObserver(this, "webapps-launch");
|
||||
Services.obs.removeObserver(this, "webapps-uninstall");
|
||||
cpmm.removeMessageListener("Webapps:Install:Return:OK", this);
|
||||
@ -81,13 +83,20 @@ this.WebappManager = {
|
||||
let data = JSON.parse(aData);
|
||||
data.mm = aSubject;
|
||||
|
||||
let win;
|
||||
switch(aTopic) {
|
||||
case "webapps-ask-install":
|
||||
let win = this._getWindowForId(data.oid);
|
||||
win = this._getWindowForId(data.oid);
|
||||
if (win && win.location.href == data.from) {
|
||||
this.doInstall(data, win);
|
||||
}
|
||||
break;
|
||||
case "webapps-ask-uninstall":
|
||||
win = this._getWindowForId(data.windowId);
|
||||
if (win && win.location.href == data.from) {
|
||||
this.doUninstall(data, win);
|
||||
}
|
||||
break;
|
||||
case "webapps-launch":
|
||||
WebappOSUtils.launch(data);
|
||||
break;
|
||||
@ -193,6 +202,49 @@ this.WebappManager = {
|
||||
"webapps-notification-icon",
|
||||
mainAction);
|
||||
|
||||
},
|
||||
|
||||
doUninstall: function(aData, aWindow) {
|
||||
let browser = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShell)
|
||||
.chromeEventHandler;
|
||||
let chromeDoc = browser.ownerDocument;
|
||||
let chromeWin = chromeDoc.defaultView;
|
||||
|
||||
let bundle = chromeWin.gNavigatorBundle;
|
||||
let jsonManifest = aData.app.manifest;
|
||||
|
||||
let notification;
|
||||
|
||||
let mainAction = {
|
||||
label: bundle.getString("webapps.uninstall"),
|
||||
accessKey: bundle.getString("webapps.uninstall.accesskey"),
|
||||
callback: () => {
|
||||
notification.remove();
|
||||
DOMApplicationRegistry.confirmUninstall(aData);
|
||||
}
|
||||
};
|
||||
|
||||
let secondaryAction = {
|
||||
label: bundle.getString("webapps.doNotUninstall"),
|
||||
accessKey: bundle.getString("webapps.doNotUninstall.accesskey"),
|
||||
callback: () => {
|
||||
notification.remove();
|
||||
DOMApplicationRegistry.denyUninstall(aData, "USER_DECLINED");
|
||||
}
|
||||
};
|
||||
|
||||
let manifest = new ManifestHelper(jsonManifest, aData.app.origin,
|
||||
aData.app.manifestURL);
|
||||
|
||||
let message = bundle.getFormattedString("webapps.requestUninstall",
|
||||
[manifest.name]);
|
||||
|
||||
notification = chromeWin.PopupNotifications.show(
|
||||
browser, "webapps-uninstall", message,
|
||||
"webapps-notification-icon",
|
||||
mainAction, [secondaryAction]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ GCONF_VERSION=1.2.1
|
||||
GIO_VERSION=2.20
|
||||
STARTUP_NOTIFICATION_VERSION=0.8
|
||||
DBUS_VERSION=0.60
|
||||
SQLITE_VERSION=3.8.5
|
||||
SQLITE_VERSION=3.8.6
|
||||
|
||||
MSMANIFEST_TOOL=
|
||||
|
||||
|
@ -405,9 +405,10 @@ interface nsIFrameScriptLoader : nsISupports
|
||||
jsval getDelayedFrameScripts();
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(ad57800b-ff21-4e2f-91d3-e68615ae8afe)]
|
||||
[scriptable, builtinclass, uuid(637e8538-4f8f-4a3d-8510-e74386233e19)]
|
||||
interface nsIProcessChecker : nsISupports
|
||||
{
|
||||
bool killChild();
|
||||
|
||||
/**
|
||||
* Return true if the "remote" process has |aPermission|. This is
|
||||
|
@ -803,6 +803,18 @@ nsFrameMessageManager::Atob(const nsAString& aAsciiString,
|
||||
|
||||
// nsIProcessChecker
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrameMessageManager::KillChild(bool *aValid)
|
||||
{
|
||||
if (!mCallback) {
|
||||
*aValid = false;
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
*aValid = mCallback->KillChild();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFrameMessageManager::AssertProcessInternal(ProcessCheckerType aType,
|
||||
const nsAString& aCapability,
|
||||
|
@ -98,6 +98,12 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool KillChild()
|
||||
{
|
||||
// By default, does nothing.
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool BuildClonedMessageDataForParent(nsIContentParent* aParent,
|
||||
const StructuredCloneData& aData,
|
||||
|
@ -54,10 +54,12 @@
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
let req = navigator.mozApps.mgmt.uninstall(app);
|
||||
req.onsuccess = function () {
|
||||
SimpleTest.finish();
|
||||
};
|
||||
SpecialPowers.autoConfirmAppUninstall(function () {
|
||||
let req = navigator.mozApps.mgmt.uninstall(app);
|
||||
req.onsuccess = function () {
|
||||
SimpleTest.finish();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
setupTest();
|
||||
|
@ -1201,7 +1201,8 @@ nsresult HTMLMediaElement::LoadResource()
|
||||
loadGroup,
|
||||
nullptr,
|
||||
nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY |
|
||||
nsIChannel::LOAD_TREAT_APPLICATION_OCTET_STREAM_AS_UNKNOWN,
|
||||
nsIChannel::LOAD_MEDIA_SNIFFER_OVERRIDES_CONTENT_TYPE |
|
||||
nsIChannel::LOAD_CALL_CONTENT_SNIFFERS,
|
||||
channelPolicy);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
|
@ -915,6 +915,11 @@ void
|
||||
AudioStream::Pause()
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
|
||||
if (mState == ERRORED) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mCubebStream || (mState != STARTED && mState != RUNNING)) {
|
||||
mNeedsStart = false;
|
||||
mState = STOPPED; // which also tells async OpenCubeb not to start, just init
|
||||
|
@ -11,6 +11,9 @@
|
||||
#include "nsAutoPtr.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
||||
#define WARN(...) NS_WARNING(nsPrintfCString(__VA_ARGS__).get())
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -193,11 +196,15 @@ CreateAndAddFilter(IGraphBuilder* aGraph,
|
||||
getter_AddRefs(filter));
|
||||
if (FAILED(hr)) {
|
||||
// Object probably not available on this system.
|
||||
WARN("CoCreateInstance failed, hr=%x", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = aGraph->AddFilter(filter, aFilterName);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
if (FAILED(hr)) {
|
||||
WARN("AddFilter failed, hr=%x", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
filter.forget(aOutFilter);
|
||||
|
||||
@ -219,25 +226,35 @@ AddMP3DMOWrapperFilter(IGraphBuilder* aGraph,
|
||||
CLSCTX_INPROC_SERVER,
|
||||
IID_IBaseFilter,
|
||||
getter_AddRefs(filter));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
if (FAILED(hr)) {
|
||||
WARN("CoCreateInstance failed, hr=%x", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
// Query for IDMOWrapperFilter.
|
||||
nsRefPtr<IDMOWrapperFilter> dmoWrapper;
|
||||
hr = filter->QueryInterface(IID_IDMOWrapperFilter,
|
||||
getter_AddRefs(dmoWrapper));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
if (FAILED(hr)) {
|
||||
WARN("QueryInterface failed, hr=%x", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = dmoWrapper->Init(CLSID_CMP3DecMediaObject, DMOCATEGORY_AUDIO_DECODER);
|
||||
if (FAILED(hr)) {
|
||||
// Can't instantiate MP3 DMO. It doesn't exist on Windows XP, we're
|
||||
// probably hitting that. Don't log warning to console, this is an
|
||||
// expected error.
|
||||
WARN("dmoWrapper Init failed, hr=%x", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
// Add the wrapper filter to graph.
|
||||
hr = aGraph->AddFilter(filter, L"MP3 Decoder DMO");
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
if (FAILED(hr)) {
|
||||
WARN("AddFilter failed, hr=%x", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
filter.forget(aOutFilter);
|
||||
|
||||
@ -307,3 +324,6 @@ ConnectFilters(IGraphBuilder* aGraph,
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
// avoid redefined macro in unified build
|
||||
#undef WARN
|
||||
|
@ -419,14 +419,14 @@ static bool isInEmulator()
|
||||
|
||||
bool OmxDecoder::AllocateMediaResources()
|
||||
{
|
||||
// OMXClient::connect() always returns OK and abort's fatally if
|
||||
// it can't connect.
|
||||
OMXClient client;
|
||||
DebugOnly<status_t> err = client.connect();
|
||||
NS_ASSERTION(err == OK, "Failed to connect to OMX in mediaserver.");
|
||||
sp<IOMX> omx = client.interface();
|
||||
|
||||
if ((mVideoTrack != nullptr) && (mVideoSource == nullptr)) {
|
||||
// OMXClient::connect() always returns OK and abort's fatally if
|
||||
// it can't connect.
|
||||
OMXClient client;
|
||||
DebugOnly<status_t> err = client.connect();
|
||||
NS_ASSERTION(err == OK, "Failed to connect to OMX in mediaserver.");
|
||||
sp<IOMX> omx = client.interface();
|
||||
|
||||
mNativeWindow = new GonkNativeWindow();
|
||||
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
|
||||
mNativeWindowClient = new GonkNativeWindowClient(mNativeWindow->getBufferQueue());
|
||||
@ -468,6 +468,13 @@ bool OmxDecoder::AllocateMediaResources()
|
||||
}
|
||||
|
||||
if ((mAudioTrack != nullptr) && (mAudioSource == nullptr)) {
|
||||
// OMXClient::connect() always returns OK and abort's fatally if
|
||||
// it can't connect.
|
||||
OMXClient client;
|
||||
DebugOnly<status_t> err = client.connect();
|
||||
NS_ASSERTION(err == OK, "Failed to connect to OMX in mediaserver.");
|
||||
sp<IOMX> omx = client.interface();
|
||||
|
||||
const char *audioMime = nullptr;
|
||||
sp<MetaData> meta = mAudioTrack->getFormat();
|
||||
if (!meta->findCString(kKeyMIMEType, &audioMime)) {
|
||||
|
@ -3,10 +3,6 @@
|
||||
<head>
|
||||
<title>Media test: chained ogg files.</title>
|
||||
<meta charset='utf-8'>
|
||||
<script type="text/javascript" src="/MochiKit/Base.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/DOM.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/Style.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/Signal.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<script type="text/javascript" src="manifest.js"></script>
|
||||
|
@ -2,11 +2,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Media test: seek test 1</title>
|
||||
<script type="text/javascript" src="/MochiKit/Base.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/DOM.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/Style.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/Signal.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="manifest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body onunload="mediaTestCleanup();">
|
||||
|
@ -2,11 +2,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Media test: seek test 1</title>
|
||||
<script type="text/javascript" src="/MochiKit/Base.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/DOM.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/Style.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/Signal.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="manifest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body onunload="mediaTestCleanup();">
|
||||
|
@ -2,11 +2,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Media test: seek test 1</title>
|
||||
<script type="text/javascript" src="/MochiKit/Base.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/DOM.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/Style.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/Signal.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="manifest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body onunload="mediaTestCleanup();">
|
||||
|
@ -2,11 +2,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Media test: seek test 1</title>
|
||||
<script type="text/javascript" src="/MochiKit/Base.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/DOM.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/Style.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/Signal.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="manifest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body onunload="mediaTestCleanup();">
|
||||
|
@ -2,11 +2,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Media test: seek test 1</title>
|
||||
<script type="text/javascript" src="/MochiKit/Base.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/DOM.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/Style.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/Signal.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="manifest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body onunload="mediaTestCleanup();">
|
||||
|
@ -2,11 +2,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Media test: seek test 1</title>
|
||||
<script type="text/javascript" src="/MochiKit/Base.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/DOM.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/Style.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/Signal.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="manifest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body onunload="mediaTestCleanup();">
|
||||
|
@ -2,13 +2,9 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Media test: X-Content-Duration</title>
|
||||
<script type="text/javascript" src="/MochiKit/Base.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/DOM.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/Style.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/Signal.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<script type="text/javascript" src="manifest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body onunload="mediaTestCleanup();">
|
||||
<pre id="test">
|
||||
|
@ -1,12 +1,8 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Media test: mozStopDownload</title>
|
||||
<title>Media test: sniffing</title>
|
||||
<meta charset='utf-8'>
|
||||
<script type="text/javascript" src="/MochiKit/Base.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/DOM.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/Style.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/Signal.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<script type="text/javascript" src="manifest.js"></script>
|
||||
@ -22,23 +18,15 @@ function finish_test(element) {
|
||||
manager.finished(element.token);
|
||||
}
|
||||
|
||||
function onApplicationOctetStreamLoaded(e) {
|
||||
var t = e.target;
|
||||
t.removeEventListener('loadedmetadata', onApplicationOctetStreamLoaded);
|
||||
ok(true, "The media loads when served with application/octet-stream.");
|
||||
finish_test(t);
|
||||
}
|
||||
|
||||
function checkApplicationOctetStream(t) {
|
||||
t.src = t.src.replace("&nomime", "&type=application/octet-stream");
|
||||
t.addEventListener("loadedmetadata", onApplicationOctetStreamLoaded);
|
||||
}
|
||||
|
||||
function onmetadataloaded(e) {
|
||||
var t = e.target;
|
||||
t.removeEventListener('loadedmetadata', onmetadataloaded)
|
||||
ok(true, "The media loads when served without a Content-Type.");
|
||||
checkApplicationOctetStream(t);
|
||||
++t.srcIndex;
|
||||
ok(true, "The media loads when loaded via " + t.src);
|
||||
if (t.srcIndex < t.srcList.length) {
|
||||
t.src = t.srcList[t.srcIndex];
|
||||
} else {
|
||||
finish_test(t);
|
||||
}
|
||||
}
|
||||
|
||||
function onerror(e) {
|
||||
@ -53,7 +41,16 @@ function startTest(test, token) {
|
||||
var element = document.createElement(elemType);
|
||||
// This .sjs file serve the media file without Content-Type header, or with a
|
||||
// specific Content-Type header.
|
||||
element.src = 'contentType.sjs?file=' + test.name + "&nomime";
|
||||
var baseSrc = 'contentType.sjs?file=' + test.name;
|
||||
element.srcList = [
|
||||
baseSrc + "&nomime",
|
||||
baseSrc + "&type=application/octet-stream",
|
||||
baseSrc + "&type=audio/wav",
|
||||
baseSrc + "&type=text/html",
|
||||
baseSrc + "&type=absolute_nonsense"
|
||||
];
|
||||
element.srcIndex = 0;
|
||||
element.src = element.srcList[element.srcIndex];
|
||||
element.token = token;
|
||||
element.controls = true;
|
||||
element.preload = "metadata";
|
||||
|
@ -2,10 +2,6 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Media test: networkState</title>
|
||||
<script type="text/javascript" src="/MochiKit/Base.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/DOM.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/Style.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/Signal.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<script type="text/javascript" src="manifest.js"></script>
|
||||
|
@ -2,11 +2,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Media test: server lies about range requests</title>
|
||||
<script type="text/javascript" src="/MochiKit/Base.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/DOM.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/Style.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/Signal.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="manifest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body onunload="mediaTestCleanup();">
|
||||
|
@ -1,6 +1,6 @@
|
||||
This is sqlite 3.8.5
|
||||
This is sqlite 3.8.6
|
||||
|
||||
-- Ryan VanderMeulen <ryanvm@gmail.com>, 06/2014
|
||||
-- Ryan VanderMeulen <ryanvm@gmail.com>, 08/2014
|
||||
|
||||
See http://www.sqlite.org/ for more info.
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -107,9 +107,9 @@ extern "C" {
|
||||
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
||||
** [sqlite_version()] and [sqlite_source_id()].
|
||||
*/
|
||||
#define SQLITE_VERSION "3.8.5"
|
||||
#define SQLITE_VERSION_NUMBER 3008005
|
||||
#define SQLITE_SOURCE_ID "2014-06-04 14:06:34 b1ed4f2a34ba66c29b130f8d13e9092758019212"
|
||||
#define SQLITE_VERSION "3.8.6"
|
||||
#define SQLITE_VERSION_NUMBER 3008006
|
||||
#define SQLITE_SOURCE_ID "2014-08-15 11:46:33 9491ba7d738528f168657adb43a198238abde19e"
|
||||
|
||||
/*
|
||||
** CAPI3REF: Run-Time Library Version Numbers
|
||||
@ -269,7 +269,7 @@ typedef sqlite_uint64 sqlite3_uint64;
|
||||
**
|
||||
** ^The sqlite3_close() and sqlite3_close_v2() routines are destructors
|
||||
** for the [sqlite3] object.
|
||||
** ^Calls to sqlite3_close() and sqlite3_close_v2() return SQLITE_OK if
|
||||
** ^Calls to sqlite3_close() and sqlite3_close_v2() return [SQLITE_OK] if
|
||||
** the [sqlite3] object is successfully destroyed and all associated
|
||||
** resources are deallocated.
|
||||
**
|
||||
@ -277,7 +277,7 @@ typedef sqlite_uint64 sqlite3_uint64;
|
||||
** statements or unfinished sqlite3_backup objects then sqlite3_close()
|
||||
** will leave the database connection open and return [SQLITE_BUSY].
|
||||
** ^If sqlite3_close_v2() is called with unfinalized prepared statements
|
||||
** and unfinished sqlite3_backups, then the database connection becomes
|
||||
** and/or unfinished sqlite3_backups, then the database connection becomes
|
||||
** an unusable "zombie" which will automatically be deallocated when the
|
||||
** last prepared statement is finalized or the last sqlite3_backup is
|
||||
** finished. The sqlite3_close_v2() interface is intended for use with
|
||||
@ -290,7 +290,7 @@ typedef sqlite_uint64 sqlite3_uint64;
|
||||
** with the [sqlite3] object prior to attempting to close the object. ^If
|
||||
** sqlite3_close_v2() is called on a [database connection] that still has
|
||||
** outstanding [prepared statements], [BLOB handles], and/or
|
||||
** [sqlite3_backup] objects then it returns SQLITE_OK but the deallocation
|
||||
** [sqlite3_backup] objects then it returns [SQLITE_OK] and the deallocation
|
||||
** of resources is deferred until all [prepared statements], [BLOB handles],
|
||||
** and [sqlite3_backup] objects are also destroyed.
|
||||
**
|
||||
@ -386,16 +386,14 @@ SQLITE_API int sqlite3_exec(
|
||||
|
||||
/*
|
||||
** CAPI3REF: Result Codes
|
||||
** KEYWORDS: SQLITE_OK {error code} {error codes}
|
||||
** KEYWORDS: {result code} {result codes}
|
||||
** KEYWORDS: {result code definitions}
|
||||
**
|
||||
** Many SQLite functions return an integer result code from the set shown
|
||||
** here in order to indicate success or failure.
|
||||
**
|
||||
** New error codes may be added in future versions of SQLite.
|
||||
**
|
||||
** See also: [SQLITE_IOERR_READ | extended result codes],
|
||||
** [sqlite3_vtab_on_conflict()] [SQLITE_ROLLBACK | result codes].
|
||||
** See also: [extended result code definitions]
|
||||
*/
|
||||
#define SQLITE_OK 0 /* Successful result */
|
||||
/* beginning-of-error-codes */
|
||||
@ -433,26 +431,19 @@ SQLITE_API int sqlite3_exec(
|
||||
|
||||
/*
|
||||
** CAPI3REF: Extended Result Codes
|
||||
** KEYWORDS: {extended error code} {extended error codes}
|
||||
** KEYWORDS: {extended result code} {extended result codes}
|
||||
** KEYWORDS: {extended result code definitions}
|
||||
**
|
||||
** In its default configuration, SQLite API routines return one of 26 integer
|
||||
** [SQLITE_OK | result codes]. However, experience has shown that many of
|
||||
** In its default configuration, SQLite API routines return one of 30 integer
|
||||
** [result codes]. However, experience has shown that many of
|
||||
** these result codes are too coarse-grained. They do not provide as
|
||||
** much information about problems as programmers might like. In an effort to
|
||||
** address this, newer versions of SQLite (version 3.3.8 and later) include
|
||||
** support for additional result codes that provide more detailed information
|
||||
** about errors. The extended result codes are enabled or disabled
|
||||
** about errors. These [extended result codes] are enabled or disabled
|
||||
** on a per database connection basis using the
|
||||
** [sqlite3_extended_result_codes()] API.
|
||||
**
|
||||
** Some of the available extended result codes are listed here.
|
||||
** One may expect the number of extended result codes will increase
|
||||
** over time. Software that uses extended result codes should expect
|
||||
** to see new result codes in future releases of SQLite.
|
||||
**
|
||||
** The SQLITE_OK result code will never be extended. It will always
|
||||
** be exactly zero.
|
||||
** [sqlite3_extended_result_codes()] API. Or, the extended code for
|
||||
** the most recent error can be obtained using
|
||||
** [sqlite3_extended_errcode()].
|
||||
*/
|
||||
#define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8))
|
||||
#define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8))
|
||||
@ -685,7 +676,7 @@ struct sqlite3_file {
|
||||
** locking strategy (for example to use dot-file locks), to inquire
|
||||
** about the status of a lock, or to break stale locks. The SQLite
|
||||
** core reserves all opcodes less than 100 for its own use.
|
||||
** A [SQLITE_FCNTL_LOCKSTATE | list of opcodes] less than 100 is available.
|
||||
** A [file control opcodes | list of opcodes] less than 100 is available.
|
||||
** Applications that define a custom xFileControl method should use opcodes
|
||||
** greater than 100 to avoid conflicts. VFS implementations should
|
||||
** return [SQLITE_NOTFOUND] for file control opcodes that they do not
|
||||
@ -758,6 +749,7 @@ struct sqlite3_io_methods {
|
||||
|
||||
/*
|
||||
** CAPI3REF: Standard File Control Opcodes
|
||||
** KEYWORDS: {file control opcodes} {file control opcode}
|
||||
**
|
||||
** These integer constants are opcodes for the xFileControl method
|
||||
** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()]
|
||||
@ -2037,27 +2029,33 @@ SQLITE_API int sqlite3_complete16(const void *sql);
|
||||
/*
|
||||
** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors
|
||||
**
|
||||
** ^This routine sets a callback function that might be invoked whenever
|
||||
** an attempt is made to open a database table that another thread
|
||||
** or process has locked.
|
||||
** ^The sqlite3_busy_handler(D,X,P) routine sets a callback function X
|
||||
** that might be invoked with argument P whenever
|
||||
** an attempt is made to access a database table associated with
|
||||
** [database connection] D when another thread
|
||||
** or process has the table locked.
|
||||
** The sqlite3_busy_handler() interface is used to implement
|
||||
** [sqlite3_busy_timeout()] and [PRAGMA busy_timeout].
|
||||
**
|
||||
** ^If the busy callback is NULL, then [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED]
|
||||
** ^If the busy callback is NULL, then [SQLITE_BUSY]
|
||||
** is returned immediately upon encountering the lock. ^If the busy callback
|
||||
** is not NULL, then the callback might be invoked with two arguments.
|
||||
**
|
||||
** ^The first argument to the busy handler is a copy of the void* pointer which
|
||||
** is the third argument to sqlite3_busy_handler(). ^The second argument to
|
||||
** the busy handler callback is the number of times that the busy handler has
|
||||
** been invoked for this locking event. ^If the
|
||||
** been invoked for the same locking event. ^If the
|
||||
** busy callback returns 0, then no additional attempts are made to
|
||||
** access the database and [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED] is returned.
|
||||
** access the database and [SQLITE_BUSY] is returned
|
||||
** to the application.
|
||||
** ^If the callback returns non-zero, then another attempt
|
||||
** is made to open the database for reading and the cycle repeats.
|
||||
** is made to access the database and the cycle repeats.
|
||||
**
|
||||
** The presence of a busy handler does not guarantee that it will be invoked
|
||||
** when there is lock contention. ^If SQLite determines that invoking the busy
|
||||
** handler could result in a deadlock, it will go ahead and return [SQLITE_BUSY]
|
||||
** or [SQLITE_IOERR_BLOCKED] instead of invoking the busy handler.
|
||||
** to the application instead of invoking the
|
||||
** busy handler.
|
||||
** Consider a scenario where one process is holding a read lock that
|
||||
** it is trying to promote to a reserved lock and
|
||||
** a second process is holding a reserved lock that it is trying
|
||||
@ -2071,28 +2069,15 @@ SQLITE_API int sqlite3_complete16(const void *sql);
|
||||
**
|
||||
** ^The default busy callback is NULL.
|
||||
**
|
||||
** ^The [SQLITE_BUSY] error is converted to [SQLITE_IOERR_BLOCKED]
|
||||
** when SQLite is in the middle of a large transaction where all the
|
||||
** changes will not fit into the in-memory cache. SQLite will
|
||||
** already hold a RESERVED lock on the database file, but it needs
|
||||
** to promote this lock to EXCLUSIVE so that it can spill cache
|
||||
** pages into the database file without harm to concurrent
|
||||
** readers. ^If it is unable to promote the lock, then the in-memory
|
||||
** cache will be left in an inconsistent state and so the error
|
||||
** code is promoted from the relatively benign [SQLITE_BUSY] to
|
||||
** the more severe [SQLITE_IOERR_BLOCKED]. ^This error code promotion
|
||||
** forces an automatic rollback of the changes. See the
|
||||
** <a href="/cvstrac/wiki?p=CorruptionFollowingBusyError">
|
||||
** CorruptionFollowingBusyError</a> wiki page for a discussion of why
|
||||
** this is important.
|
||||
**
|
||||
** ^(There can only be a single busy handler defined for each
|
||||
** [database connection]. Setting a new busy handler clears any
|
||||
** previously set handler.)^ ^Note that calling [sqlite3_busy_timeout()]
|
||||
** will also set or clear the busy handler.
|
||||
** or evaluating [PRAGMA busy_timeout=N] will change the
|
||||
** busy handler and thus clear any previously set busy handler.
|
||||
**
|
||||
** The busy callback should not take any actions which modify the
|
||||
** database connection that invoked the busy handler. Any such actions
|
||||
** database connection that invoked the busy handler. In other words,
|
||||
** the busy handler is not reentrant. Any such actions
|
||||
** result in undefined behavior.
|
||||
**
|
||||
** A busy handler must not close the database connection
|
||||
@ -2108,7 +2093,7 @@ SQLITE_API int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
|
||||
** will sleep multiple times until at least "ms" milliseconds of sleeping
|
||||
** have accumulated. ^After at least "ms" milliseconds of sleeping,
|
||||
** the handler returns 0 which causes [sqlite3_step()] to return
|
||||
** [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED].
|
||||
** [SQLITE_BUSY].
|
||||
**
|
||||
** ^Calling this routine with an argument less than or equal to zero
|
||||
** turns off all busy handlers.
|
||||
@ -2117,6 +2102,8 @@ SQLITE_API int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
|
||||
** [database connection] any any given moment. If another busy handler
|
||||
** was defined (using [sqlite3_busy_handler()]) prior to calling
|
||||
** this routine, that other busy handler is cleared.)^
|
||||
**
|
||||
** See also: [PRAGMA busy_timeout]
|
||||
*/
|
||||
SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
|
||||
|
||||
@ -2518,8 +2505,8 @@ SQLITE_API int sqlite3_set_authorizer(
|
||||
** [sqlite3_set_authorizer | authorizer documentation] for additional
|
||||
** information.
|
||||
**
|
||||
** Note that SQLITE_IGNORE is also used as a [SQLITE_ROLLBACK | return code]
|
||||
** from the [sqlite3_vtab_on_conflict()] interface.
|
||||
** Note that SQLITE_IGNORE is also used as a [conflict resolution mode]
|
||||
** returned from the [sqlite3_vtab_on_conflict()] interface.
|
||||
*/
|
||||
#define SQLITE_DENY 1 /* Abort the SQL statement with an error */
|
||||
#define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */
|
||||
@ -4706,6 +4693,13 @@ SQLITE_API int sqlite3_sleep(int);
|
||||
** is a NULL pointer, then SQLite performs a search for an appropriate
|
||||
** temporary file directory.
|
||||
**
|
||||
** Applications are strongly discouraged from using this global variable.
|
||||
** It is required to set a temporary folder on Windows Runtime (WinRT).
|
||||
** But for all other platforms, it is highly recommended that applications
|
||||
** neither read nor write this variable. This global variable is a relic
|
||||
** that exists for backwards compatibility of legacy applications and should
|
||||
** be avoided in new projects.
|
||||
**
|
||||
** It is not safe to read or modify this variable in more than one
|
||||
** thread at a time. It is not safe to read or modify this variable
|
||||
** if a [database connection] is being used at the same time in a separate
|
||||
@ -4724,6 +4718,11 @@ SQLITE_API int sqlite3_sleep(int);
|
||||
** Hence, if this variable is modified directly, either it should be
|
||||
** made NULL or made to point to memory obtained from [sqlite3_malloc]
|
||||
** or else the use of the [temp_store_directory pragma] should be avoided.
|
||||
** Except when requested by the [temp_store_directory pragma], SQLite
|
||||
** does not free the memory that sqlite3_temp_directory points to. If
|
||||
** the application wants that memory to be freed, it must do
|
||||
** so itself, taking care to only do so after all [database connection]
|
||||
** objects have been destroyed.
|
||||
**
|
||||
** <b>Note to Windows Runtime users:</b> The temporary directory must be set
|
||||
** prior to calling [sqlite3_open] or [sqlite3_open_v2]. Otherwise, various
|
||||
@ -5858,10 +5857,12 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
|
||||
** <li> SQLITE_MUTEX_RECURSIVE
|
||||
** <li> SQLITE_MUTEX_STATIC_MASTER
|
||||
** <li> SQLITE_MUTEX_STATIC_MEM
|
||||
** <li> SQLITE_MUTEX_STATIC_MEM2
|
||||
** <li> SQLITE_MUTEX_STATIC_OPEN
|
||||
** <li> SQLITE_MUTEX_STATIC_PRNG
|
||||
** <li> SQLITE_MUTEX_STATIC_LRU
|
||||
** <li> SQLITE_MUTEX_STATIC_LRU2
|
||||
** <li> SQLITE_MUTEX_STATIC_PMEM
|
||||
** <li> SQLITE_MUTEX_STATIC_APP1
|
||||
** <li> SQLITE_MUTEX_STATIC_APP2
|
||||
** </ul>)^
|
||||
**
|
||||
** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE)
|
||||
@ -6065,6 +6066,9 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
|
||||
#define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */
|
||||
#define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */
|
||||
#define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */
|
||||
#define SQLITE_MUTEX_STATIC_APP1 8 /* For use by application */
|
||||
#define SQLITE_MUTEX_STATIC_APP2 9 /* For use by application */
|
||||
#define SQLITE_MUTEX_STATIC_APP3 10 /* For use by application */
|
||||
|
||||
/*
|
||||
** CAPI3REF: Retrieve the mutex for a database connection
|
||||
@ -6160,7 +6164,8 @@ SQLITE_API int sqlite3_test_control(int op, ...);
|
||||
#define SQLITE_TESTCTRL_NEVER_CORRUPT 20
|
||||
#define SQLITE_TESTCTRL_VDBE_COVERAGE 21
|
||||
#define SQLITE_TESTCTRL_BYTEORDER 22
|
||||
#define SQLITE_TESTCTRL_LAST 22
|
||||
#define SQLITE_TESTCTRL_ISINIT 23
|
||||
#define SQLITE_TESTCTRL_LAST 23
|
||||
|
||||
/*
|
||||
** CAPI3REF: SQLite Runtime Status
|
||||
@ -7144,6 +7149,9 @@ SQLITE_API void *sqlite3_wal_hook(
|
||||
** ^The [wal_autocheckpoint pragma] can be used to invoke this interface
|
||||
** from SQL.
|
||||
**
|
||||
** ^Checkpoints initiated by this mechanism are
|
||||
** [sqlite3_wal_checkpoint_v2|PASSIVE].
|
||||
**
|
||||
** ^Every new [database connection] defaults to having the auto-checkpoint
|
||||
** enabled with a threshold of 1000 or [SQLITE_DEFAULT_WAL_AUTOCHECKPOINT]
|
||||
** pages. The use of this interface
|
||||
@ -7160,6 +7168,10 @@ SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
|
||||
** empty string, then a checkpoint is run on all databases of
|
||||
** connection D. ^If the database connection D is not in
|
||||
** [WAL | write-ahead log mode] then this interface is a harmless no-op.
|
||||
** ^The [sqlite3_wal_checkpoint(D,X)] interface initiates a
|
||||
** [sqlite3_wal_checkpoint_v2|PASSIVE] checkpoint.
|
||||
** Use the [sqlite3_wal_checkpoint_v2()] interface to get a FULL
|
||||
** or RESET checkpoint.
|
||||
**
|
||||
** ^The [wal_checkpoint pragma] can be used to invoke this interface
|
||||
** from SQL. ^The [sqlite3_wal_autocheckpoint()] interface and the
|
||||
@ -7182,10 +7194,12 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
|
||||
** Checkpoint as many frames as possible without waiting for any database
|
||||
** readers or writers to finish. Sync the db file if all frames in the log
|
||||
** are checkpointed. This mode is the same as calling
|
||||
** sqlite3_wal_checkpoint(). The busy-handler callback is never invoked.
|
||||
** sqlite3_wal_checkpoint(). The [sqlite3_busy_handler|busy-handler callback]
|
||||
** is never invoked.
|
||||
**
|
||||
** <dt>SQLITE_CHECKPOINT_FULL<dd>
|
||||
** This mode blocks (calls the busy-handler callback) until there is no
|
||||
** This mode blocks (it invokes the
|
||||
** [sqlite3_busy_handler|busy-handler callback]) until there is no
|
||||
** database writer and all readers are reading from the most recent database
|
||||
** snapshot. It then checkpoints all frames in the log file and syncs the
|
||||
** database file. This call blocks database writers while it is running,
|
||||
@ -7193,7 +7207,8 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
|
||||
**
|
||||
** <dt>SQLITE_CHECKPOINT_RESTART<dd>
|
||||
** This mode works the same way as SQLITE_CHECKPOINT_FULL, except after
|
||||
** checkpointing the log file it blocks (calls the busy-handler callback)
|
||||
** checkpointing the log file it blocks (calls the
|
||||
** [sqlite3_busy_handler|busy-handler callback])
|
||||
** until all readers are reading from the database file only. This ensures
|
||||
** that the next client to write to the database file restarts the log file
|
||||
** from the beginning. This call blocks database writers while it is running,
|
||||
@ -7331,6 +7346,7 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Conflict resolution modes
|
||||
** KEYWORDS: {conflict resolution mode}
|
||||
**
|
||||
** These constants are returned by [sqlite3_vtab_on_conflict()] to
|
||||
** inform a [virtual table] implementation what the [ON CONFLICT] mode
|
||||
|
@ -14,6 +14,7 @@ var faultyURL = "http://some-nonexistent-domain-27489274c892748217cn2384.com/";
|
||||
|
||||
var w = null;
|
||||
var phase = 0;
|
||||
var isWindowLoaded = false;
|
||||
|
||||
function pollForPage(expectErrorPage, f, w)
|
||||
{
|
||||
@ -42,6 +43,12 @@ function pollForPage(expectErrorPage, f, w)
|
||||
|
||||
function windowLoaded()
|
||||
{
|
||||
// The code under here should only be run once
|
||||
// The test popup window workingURL was already opened
|
||||
if (isWindowLoaded)
|
||||
return;
|
||||
isWindowLoaded = true;
|
||||
|
||||
/* 2. We have successfully loaded a page, now go to a faulty URL */
|
||||
// XXX The test fails when we change the location synchronously
|
||||
window.setTimeout(function() {
|
||||
|
@ -215,6 +215,7 @@ WebappsRegistry.prototype = {
|
||||
let mgmt = Cc["@mozilla.org/webapps/manager;1"]
|
||||
.createInstance(Ci.nsISupports);
|
||||
mgmt.wrappedJSObject.init(this._window);
|
||||
mgmt.wrappedJSObject._windowId = this._id;
|
||||
this._mgmt = mgmt.__DOM_IMPL__
|
||||
? mgmt.__DOM_IMPL__
|
||||
: this._window.DOMApplicationsManager._create(this._window, mgmt.wrappedJSObject);
|
||||
@ -721,10 +722,15 @@ WebappsApplicationMgmt.prototype = {
|
||||
|
||||
uninstall: function(aApp) {
|
||||
let request = this.createRequest();
|
||||
cpmm.sendAsyncMessage("Webapps:Uninstall", { origin: aApp.origin,
|
||||
manifestURL: aApp.manifestURL,
|
||||
oid: this._id,
|
||||
requestID: this.getRequestId(request) });
|
||||
|
||||
cpmm.sendAsyncMessage("Webapps:Uninstall", {
|
||||
origin: aApp.origin,
|
||||
manifestURL: aApp.manifestURL,
|
||||
oid: this._id,
|
||||
from: this._window.location.href,
|
||||
windowId: this._windowId,
|
||||
requestID: this.getRequestId(request)
|
||||
});
|
||||
return request;
|
||||
},
|
||||
|
||||
|
@ -162,6 +162,7 @@ this.DOMApplicationRegistry = {
|
||||
children: [ ],
|
||||
allAppsLaunchable: false,
|
||||
_updateHandlers: [ ],
|
||||
_pendingUninstalls: {},
|
||||
|
||||
init: function() {
|
||||
this.messages = ["Webapps:Install", "Webapps:Uninstall",
|
||||
@ -547,7 +548,7 @@ this.DOMApplicationRegistry = {
|
||||
if (this.webapps[id].manifestURL === httpsManifestURL) {
|
||||
debug("Found a http/https match: " + app.manifestURL + " / " +
|
||||
this.webapps[id].manifestURL);
|
||||
this.uninstall(app.manifestURL, function() {}, function() {});
|
||||
this.uninstall(app.manifestURL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -2638,7 +2639,7 @@ this.DOMApplicationRegistry = {
|
||||
manifest: jsonManifest
|
||||
},
|
||||
isReinstall,
|
||||
this.uninstall.bind(this, aData, aData.mm)
|
||||
this.doUninstall.bind(this, aData, aData.mm)
|
||||
);
|
||||
}
|
||||
|
||||
@ -3675,39 +3676,50 @@ this.DOMApplicationRegistry = {
|
||||
AppDownloadManager.remove(aNewApp.manifestURL);
|
||||
},
|
||||
|
||||
doUninstall: function(aData, aMm) {
|
||||
this.uninstall(aData.manifestURL,
|
||||
function onsuccess() {
|
||||
aMm.sendAsyncMessage("Webapps:Uninstall:Return:OK", aData);
|
||||
},
|
||||
function onfailure() {
|
||||
// Fall-through, fails to uninstall the desired app because:
|
||||
// - we cannot find the app to be uninstalled.
|
||||
// - the app to be uninstalled is not removable.
|
||||
aMm.sendAsyncMessage("Webapps:Uninstall:Return:KO", aData);
|
||||
doUninstall: Task.async(function*(aData, aMm) {
|
||||
// The yields here could get stuck forever, so we only hold
|
||||
// a weak reference to the message manager while yielding, to avoid
|
||||
// leaking the whole page associationed with the message manager.
|
||||
aMm = Cu.getWeakReference(aMm);
|
||||
|
||||
let response = "Webapps:Uninstall:Return:OK";
|
||||
|
||||
try {
|
||||
aData.app = yield this._getAppWithManifest(aData.manifestURL);
|
||||
|
||||
let prefName = "dom.mozApps.auto_confirm_uninstall";
|
||||
if (Services.prefs.prefHasUserValue(prefName) &&
|
||||
Services.prefs.getBoolPref(prefName)) {
|
||||
yield this._uninstallApp(aData.app);
|
||||
} else {
|
||||
yield this._promptForUninstall(aData);
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
aData.error = error;
|
||||
response = "Webapps:Uninstall:Return:KO";
|
||||
}
|
||||
|
||||
if (aMm = aMm.get()) {
|
||||
aMm.sendAsyncMessage(response, aData);
|
||||
}
|
||||
}),
|
||||
|
||||
uninstall: function(aManifestURL) {
|
||||
return this._getAppWithManifest(aManifestURL)
|
||||
.then(this._uninstallApp.bind(this));
|
||||
},
|
||||
|
||||
uninstall: function(aManifestURL, aOnSuccess, aOnFailure) {
|
||||
debug("uninstall " + aManifestURL);
|
||||
|
||||
let app = this.getAppByManifestURL(aManifestURL);
|
||||
if (!app) {
|
||||
aOnFailure("NO_SUCH_APP");
|
||||
return;
|
||||
}
|
||||
let id = app.id;
|
||||
|
||||
if (!app.removable) {
|
||||
_uninstallApp: Task.async(function*(aApp) {
|
||||
if (!aApp.removable) {
|
||||
debug("Error: cannot uninstall a non-removable app.");
|
||||
aOnFailure("NON_REMOVABLE_APP");
|
||||
return;
|
||||
throw new Error("NON_REMOVABLE_APP");
|
||||
}
|
||||
|
||||
let id = aApp.id;
|
||||
|
||||
// Check if we are downloading something for this app, and cancel the
|
||||
// download if needed.
|
||||
this.cancelDownload(app.manifestURL);
|
||||
this.cancelDownload(aApp.manifestURL);
|
||||
|
||||
// Clean up the deprecated manifest cache if needed.
|
||||
if (id in this._manifestCache) {
|
||||
@ -3715,18 +3727,13 @@ this.DOMApplicationRegistry = {
|
||||
}
|
||||
|
||||
// Clear private data first.
|
||||
this._clearPrivateData(app.localId, false);
|
||||
this._clearPrivateData(aApp.localId, false);
|
||||
|
||||
// Then notify observers.
|
||||
// We have to clone the app object as nsIDOMApplication objects are
|
||||
// stringified as an empty object. (see bug 830376)
|
||||
let appClone = AppsUtils.cloneAppObject(app);
|
||||
Services.obs.notifyObservers(null, "webapps-uninstall", JSON.stringify(appClone));
|
||||
Services.obs.notifyObservers(null, "webapps-uninstall", JSON.stringify(aApp));
|
||||
|
||||
if (supportSystemMessages()) {
|
||||
this._readManifests([{ id: id }]).then((aResult) => {
|
||||
this._unregisterActivities(aResult[0].manifest, app);
|
||||
});
|
||||
this._unregisterActivities(aApp.manifest, aApp);
|
||||
}
|
||||
|
||||
let dir = this._getAppDir(id);
|
||||
@ -3736,18 +3743,47 @@ this.DOMApplicationRegistry = {
|
||||
|
||||
delete this.webapps[id];
|
||||
|
||||
this._saveApps().then(() => {
|
||||
this.broadcastMessage("Webapps:Uninstall:Broadcast:Return:OK", appClone);
|
||||
this.broadcastMessage("Webapps:RemoveApp", { id: id });
|
||||
try {
|
||||
if (aOnSuccess) {
|
||||
aOnSuccess();
|
||||
}
|
||||
} catch(ex) {
|
||||
Cu.reportError("DOMApplicationRegistry: Exception on app uninstall: " +
|
||||
ex + "\n" + ex.stack);
|
||||
}
|
||||
});
|
||||
yield this._saveApps();
|
||||
|
||||
this.broadcastMessage("Webapps:Uninstall:Broadcast:Return:OK", aApp);
|
||||
this.broadcastMessage("Webapps:RemoveApp", { id: id });
|
||||
|
||||
return aApp;
|
||||
}),
|
||||
|
||||
_promptForUninstall: function(aData) {
|
||||
let deferred = Promise.defer();
|
||||
this._pendingUninstalls[aData.requestID] = deferred;
|
||||
Services.obs.notifyObservers(null, "webapps-ask-uninstall",
|
||||
JSON.stringify(aData));
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
confirmUninstall: function(aData) {
|
||||
let pending = this._pendingUninstalls[aData.requestID];
|
||||
if (pending) {
|
||||
delete this._pendingUninstalls[aData.requestID];
|
||||
return this._uninstallApp(aData.app).then(() => {
|
||||
pending.resolve();
|
||||
return aData.app;
|
||||
});
|
||||
}
|
||||
return Promise.reject(new Error("PENDING_UNINSTALL_NOT_FOUND"));
|
||||
},
|
||||
|
||||
denyUninstall: function(aData, aReason = "ERROR_UNKNOWN_FAILURE") {
|
||||
// Fails to uninstall the desired app because:
|
||||
// - we cannot find the app to be uninstalled.
|
||||
// - the app to be uninstalled is not removable.
|
||||
// - the user declined the confirmation
|
||||
debug("Failed to uninstall app: " + aReason);
|
||||
let pending = this._pendingUninstalls[aData.requestID];
|
||||
if (pending) {
|
||||
delete this._pendingUninstalls[aData.requestID];
|
||||
pending.reject(new Error(aReason));
|
||||
return Promise.resolve();
|
||||
}
|
||||
return Promise.reject(new Error("PENDING_UNINSTALL_NOT_FOUND"));
|
||||
},
|
||||
|
||||
getSelf: function(aData, aMm) {
|
||||
@ -4067,6 +4103,17 @@ this.DOMApplicationRegistry = {
|
||||
return AppsUtils.getAppByManifestURL(this.webapps, aManifestURL);
|
||||
},
|
||||
|
||||
_getAppWithManifest: Task.async(function*(aManifestURL) {
|
||||
let app = this.getAppByManifestURL(aManifestURL);
|
||||
if (!app) {
|
||||
throw new Error("NO_SUCH_APP");
|
||||
}
|
||||
|
||||
app.manifest = ( yield this._readManifests([{ id: app.id }]) )[0].manifest;
|
||||
|
||||
return app;
|
||||
}),
|
||||
|
||||
getCSPByLocalId: function(aLocalId) {
|
||||
debug("getCSPByLocalId:" + aLocalId);
|
||||
return AppsUtils.getCSPByLocalId(this.webapps, aLocalId);
|
||||
|
@ -72,6 +72,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=826058
|
||||
yield undefined;
|
||||
SpecialPowers.autoConfirmAppInstall(continueTest);
|
||||
yield undefined;
|
||||
SpecialPowers.autoConfirmAppUninstall(continueTest);
|
||||
yield undefined;
|
||||
|
||||
// Load the app, uninstalled.
|
||||
checkAppState(null, false, 1, continueTest);
|
||||
|
@ -44,6 +44,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=795164
|
||||
SpecialPowers.autoConfirmAppInstall(continueTest);
|
||||
yield undefined;
|
||||
|
||||
SpecialPowers.autoConfirmAppUninstall(continueTest);
|
||||
yield undefined;
|
||||
|
||||
// Keeping track of the number of times `mozApps.mgmt.onuninstall` gets triggered
|
||||
let uninstallCount = 0;
|
||||
|
||||
|
@ -71,6 +71,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=945152
|
||||
SpecialPowers.autoConfirmAppInstall(continueTest);
|
||||
yield undefined;
|
||||
|
||||
SpecialPowers.autoConfirmAppUninstall(continueTest);
|
||||
yield undefined;
|
||||
|
||||
// Create app on server side.
|
||||
createApp(continueTest);
|
||||
yield undefined;
|
||||
|
@ -60,6 +60,9 @@ function runTest() {
|
||||
SpecialPowers.autoConfirmAppInstall(continueTest);
|
||||
yield undefined;
|
||||
|
||||
SpecialPowers.autoConfirmAppUninstall(continueTest);
|
||||
yield undefined;
|
||||
|
||||
request = navigator.mozApps.mgmt.getAll();
|
||||
request.onerror = cbError;
|
||||
request.onsuccess = continueTest;
|
||||
|
@ -57,6 +57,9 @@ function runTest() {
|
||||
SpecialPowers.autoConfirmAppInstall(continueTest);
|
||||
yield undefined;
|
||||
|
||||
SpecialPowers.autoConfirmAppUninstall(continueTest);
|
||||
yield undefined;
|
||||
|
||||
// Test install with three valid receipts
|
||||
let valid_receipt1 = 'eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJwcm9kdWN0IjogeyJ1cmwiOiAiaHR0cHM6Ly93d3cubW96aWxsYS5vcmciLCAic3RvcmVkYXRhIjogIjUxNjkzMTQzNTYifSwgInJlaXNzdWUiOiAiaHR0cDovL21vY2hpLnRlc3Q6ODg4OC9yZWlzc3VlLzUxNjkzMTQzNTYiLCAidXNlciI6IHsidHlwZSI6ICJkaXJlY3RlZC1pZGVudGlmaWVyIiwgInZhbHVlIjogIjRmYjM1MTUxLTJiOWItNGJhMi04MjgzLWM0OWQzODE2NDBiZCJ9LCAidmVyaWZ5IjogImh0dHA6Ly9tb2NoaS50ZXN0Ojg4ODgvdmVyaWZ5LzUxNjkzMTQzNTYiLCAiaXNzIjogImh0dHA6Ly9tb2NoaS50ZXN0Ojg4ODgiLCAiaWF0IjogMTMxMzYwMTg4LCAidHlwIjogInB1cmNoYXNlLXJlY2VpcHQiLCAibmJmIjogMTMxMzYwMTg1LCAiZGV0YWlsIjogImh0dHA6Ly9tb2NoaS50ZXN0Ojg4ODgvcmVjZWlwdC81MTY5MzE0MzU2In0.eZpTEnCLUR3iP3rm9WyJOqx1k66mQaAxqcrvX11r5E0';
|
||||
|
||||
|
@ -131,8 +131,10 @@ PackagedTestHelper.setSteps([
|
||||
SpecialPowers.addPermission("webapps-manage", true, document);
|
||||
SpecialPowers.addPermission("browser", true, document);
|
||||
SpecialPowers.autoConfirmAppInstall(() =>
|
||||
SpecialPowers.pushPrefEnv({set: [["dom.mozBrowserFramesEnabled", true]]},
|
||||
PackagedTestHelper.next));
|
||||
SpecialPowers.autoConfirmAppUninstall(() =>
|
||||
SpecialPowers.pushPrefEnv({set: [["dom.mozBrowserFramesEnabled",
|
||||
true]]},
|
||||
PackagedTestHelper.next)));
|
||||
},
|
||||
function() {
|
||||
info("== TEST == Marketplace packaged app from https://marketplace.firefox.com/");
|
||||
|
@ -140,6 +140,9 @@ function runTest() {
|
||||
SpecialPowers.autoConfirmAppInstall(continueTest);
|
||||
yield undefined;
|
||||
|
||||
SpecialPowers.autoConfirmAppUninstall(continueTest);
|
||||
yield undefined;
|
||||
|
||||
setState("setVersion", 1, continueTest);
|
||||
yield undefined;
|
||||
|
||||
|
@ -90,6 +90,10 @@ var steps = [
|
||||
info("autoConfirmAppInstall");
|
||||
SpecialPowers.autoConfirmAppInstall(PackagedTestHelper.next);
|
||||
},
|
||||
function() {
|
||||
ok(true, "autoConfirmAppUninstall");
|
||||
SpecialPowers.autoConfirmAppUninstall(PackagedTestHelper.next);
|
||||
},
|
||||
function() {
|
||||
PackagedTestHelper.setAppVersion(0, PackagedTestHelper.next);
|
||||
},
|
||||
|
@ -57,6 +57,9 @@ function runTest() {
|
||||
SpecialPowers.autoConfirmAppInstall(continueTest);
|
||||
yield undefined;
|
||||
|
||||
SpecialPowers.autoConfirmAppUninstall(continueTest);
|
||||
yield undefined;
|
||||
|
||||
var request = navigator.mozApps.install(gManifestURL);
|
||||
request.onerror = cbError;
|
||||
request.onsuccess = continueTest;
|
||||
|
@ -106,6 +106,10 @@ var steps = [
|
||||
info("autoConfirmAppInstall");
|
||||
SpecialPowers.autoConfirmAppInstall(PackagedTestHelper.next);
|
||||
},
|
||||
function() {
|
||||
info("autoConfirmAppUninstall");
|
||||
SpecialPowers.autoConfirmAppUninstall(PackagedTestHelper.next);
|
||||
},
|
||||
function() {
|
||||
info("== TEST == Install packaged app");
|
||||
var miniManifestURL = gSJS + "?" + "app=valid&" + "version=1";
|
||||
|
@ -44,6 +44,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=830258
|
||||
SpecialPowers.autoConfirmAppInstall(continueTest);
|
||||
yield undefined;
|
||||
|
||||
SpecialPowers.autoConfirmAppUninstall(continueTest);
|
||||
yield undefined;
|
||||
|
||||
let request = navigator.mozApps.install(url1);
|
||||
request.onerror = mozAppsError;
|
||||
request.onsuccess = continueTest;
|
||||
|
@ -190,7 +190,9 @@
|
||||
|
||||
// No confirmation needed when an app is installed
|
||||
function() {
|
||||
SpecialPowers.autoConfirmAppInstall(runTest);
|
||||
SpecialPowers.autoConfirmAppInstall(() => {
|
||||
SpecialPowers.autoConfirmAppUninstall(runTest);
|
||||
});
|
||||
},
|
||||
|
||||
// Installing the app
|
||||
|
@ -2328,23 +2328,23 @@ BluetoothHandsfreeInterface::Init(
|
||||
BluetoothHandsfreeResultHandler* aRes)
|
||||
{
|
||||
static bthf_callbacks_t sCallbacks = {
|
||||
.size = sizeof(sCallbacks),
|
||||
.connection_state_cb = BluetoothHandsfreeCallback::ConnectionState,
|
||||
.audio_state_cb = BluetoothHandsfreeCallback::AudioState,
|
||||
.vr_cmd_cb = BluetoothHandsfreeCallback::VoiceRecognition,
|
||||
.answer_call_cmd_cb = BluetoothHandsfreeCallback::AnswerCall,
|
||||
.hangup_call_cmd_cb = BluetoothHandsfreeCallback::HangupCall,
|
||||
.volume_cmd_cb = BluetoothHandsfreeCallback::Volume,
|
||||
.dial_call_cmd_cb = BluetoothHandsfreeCallback::DialCall,
|
||||
.dtmf_cmd_cb = BluetoothHandsfreeCallback::Dtmf,
|
||||
.nrec_cmd_cb = BluetoothHandsfreeCallback::NoiseReductionEchoCancellation,
|
||||
.chld_cmd_cb = BluetoothHandsfreeCallback::CallHold,
|
||||
.cnum_cmd_cb = BluetoothHandsfreeCallback::Cnum,
|
||||
.cind_cmd_cb = BluetoothHandsfreeCallback::Cind,
|
||||
.cops_cmd_cb = BluetoothHandsfreeCallback::Cops,
|
||||
.clcc_cmd_cb = BluetoothHandsfreeCallback::Clcc,
|
||||
.unknown_at_cmd_cb = BluetoothHandsfreeCallback::UnknownAt,
|
||||
.key_pressed_cmd_cb = BluetoothHandsfreeCallback::KeyPressed
|
||||
sizeof(sCallbacks),
|
||||
BluetoothHandsfreeCallback::ConnectionState,
|
||||
BluetoothHandsfreeCallback::AudioState,
|
||||
BluetoothHandsfreeCallback::VoiceRecognition,
|
||||
BluetoothHandsfreeCallback::AnswerCall,
|
||||
BluetoothHandsfreeCallback::HangupCall,
|
||||
BluetoothHandsfreeCallback::Volume,
|
||||
BluetoothHandsfreeCallback::DialCall,
|
||||
BluetoothHandsfreeCallback::Dtmf,
|
||||
BluetoothHandsfreeCallback::NoiseReductionEchoCancellation,
|
||||
BluetoothHandsfreeCallback::CallHold,
|
||||
BluetoothHandsfreeCallback::Cnum,
|
||||
BluetoothHandsfreeCallback::Cind,
|
||||
BluetoothHandsfreeCallback::Cops,
|
||||
BluetoothHandsfreeCallback::Clcc,
|
||||
BluetoothHandsfreeCallback::UnknownAt,
|
||||
BluetoothHandsfreeCallback::KeyPressed
|
||||
};
|
||||
|
||||
sHandsfreeNotificationHandler = aNotificationHandler;
|
||||
|
@ -26,10 +26,10 @@ using namespace mozilla::dom;
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMCameraManager, mWindow)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMCameraManager)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIObserver)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMCameraManager)
|
||||
@ -116,7 +116,16 @@ nsDOMCameraManager::CreateInstance(nsPIDOMWindow* aWindow)
|
||||
new nsDOMCameraManager(aWindow);
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
obs->AddObserver(cameraManager, "xpcom-shutdown", true);
|
||||
if (!obs) {
|
||||
DOM_CAMERA_LOGE("Camera manager failed to get observer service\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsresult rv = obs->AddObserver(cameraManager, "xpcom-shutdown", true);
|
||||
if (NS_FAILED(rv)) {
|
||||
DOM_CAMERA_LOGE("Camera manager failed to add 'xpcom-shutdown' observer (0x%x)\n", rv);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return cameraManager.forget();
|
||||
}
|
||||
|
@ -4,6 +4,8 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "WebGLContext.h"
|
||||
|
||||
#include "WebGLContextLossHandler.h"
|
||||
#include "WebGL1Context.h"
|
||||
#include "WebGLObjectModel.h"
|
||||
#include "WebGLExtensions.h"
|
||||
@ -286,9 +288,7 @@ WebGLContext::WebGLContext()
|
||||
|
||||
mAllowContextRestore = true;
|
||||
mLastLossWasSimulated = false;
|
||||
mContextLossTimerRunning = false;
|
||||
mRunContextLossTimerAgain = false;
|
||||
mContextRestorer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
mContextLossHandler = new WebGLContextLossHandler(this);
|
||||
mContextStatus = ContextNotLost;
|
||||
mLoseContextOnMemoryPressure = false;
|
||||
mCanLoseContextInForeground = true;
|
||||
@ -324,8 +324,9 @@ WebGLContext::~WebGLContext()
|
||||
|
||||
DestroyResourcesAndContext();
|
||||
WebGLMemoryTracker::RemoveWebGLContext(this);
|
||||
TerminateContextLossTimer();
|
||||
mContextRestorer = nullptr;
|
||||
|
||||
mContextLossHandler->DisableTimer();
|
||||
mContextLossHandler = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
@ -1297,6 +1298,12 @@ WebGLContext::TryToRestoreContext()
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::RunContextLossTimer()
|
||||
{
|
||||
mContextLossHandler->RunTimer();
|
||||
}
|
||||
|
||||
class UpdateContextLossStatusTask : public nsRunnable
|
||||
{
|
||||
nsRefPtr<WebGLContext> mContext;
|
||||
@ -1417,7 +1424,7 @@ WebGLContext::UpdateContextLossStatus()
|
||||
|
||||
if (!TryToRestoreContext()) {
|
||||
// Failed to restore. Try again later.
|
||||
RunContextLossTimer();
|
||||
mContextLossHandler->RunTimer();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "mozilla/EnumeratedArray.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/WeakPtr.h"
|
||||
|
||||
#include "GLDefs.h"
|
||||
#include "WebGLActiveInfo.h"
|
||||
@ -62,6 +63,7 @@ class nsIDocShell;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class WebGLContextLossHandler;
|
||||
class WebGLObserver;
|
||||
class WebGLContextBoundObject;
|
||||
class WebGLActiveInfo;
|
||||
@ -138,7 +140,8 @@ class WebGLContext :
|
||||
public nsICanvasRenderingContextInternal,
|
||||
public nsSupportsWeakReference,
|
||||
public WebGLRectangleObject,
|
||||
public nsWrapperCache
|
||||
public nsWrapperCache,
|
||||
public SupportsWeakPtr<WebGLContext>
|
||||
{
|
||||
friend class WebGLContextUserData;
|
||||
friend class WebGLExtensionCompressedTextureATC;
|
||||
@ -165,6 +168,8 @@ class WebGLContext :
|
||||
public:
|
||||
WebGLContext();
|
||||
|
||||
MOZ_DECLARE_REFCOUNTED_TYPENAME(WebGLContext)
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(WebGLContext,
|
||||
@ -268,11 +273,9 @@ public:
|
||||
|
||||
bool MinCapabilityMode() const { return mMinCapability; }
|
||||
|
||||
void RunContextLossTimer();
|
||||
void UpdateContextLossStatus();
|
||||
void EnqueueUpdateContextLossStatus();
|
||||
static void ContextLossCallbackStatic(nsITimer* timer, void* thisPointer);
|
||||
void RunContextLossTimer();
|
||||
void TerminateContextLossTimer();
|
||||
|
||||
bool TryToRestoreContext();
|
||||
|
||||
@ -1264,11 +1267,9 @@ protected:
|
||||
GLsizei mViewportHeight;
|
||||
bool mAlreadyWarnedAboutViewportLargerThanDest;
|
||||
|
||||
nsCOMPtr<nsITimer> mContextRestorer;
|
||||
RefPtr<WebGLContextLossHandler> mContextLossHandler;
|
||||
bool mAllowContextRestore;
|
||||
bool mLastLossWasSimulated;
|
||||
bool mContextLossTimerRunning;
|
||||
bool mRunContextLossTimerAgain;
|
||||
ContextStatus mContextStatus;
|
||||
bool mContextLostErrorSet;
|
||||
|
||||
|
121
dom/canvas/WebGLContextLossHandler.cpp
Normal file
121
dom/canvas/WebGLContextLossHandler.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "WebGLContextLossHandler.h"
|
||||
|
||||
#include "nsITimer.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "WebGLContext.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
WebGLContextLossHandler::WebGLContextLossHandler(WebGLContext* webgl)
|
||||
: mWeakWebGL(webgl)
|
||||
, mTimer(do_CreateInstance(NS_TIMER_CONTRACTID))
|
||||
, mIsTimerRunning(false)
|
||||
, mShouldRunTimerAgain(false)
|
||||
, mIsDisabled(false)
|
||||
#ifdef DEBUG
|
||||
, mThread(NS_GetCurrentThread())
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
WebGLContextLossHandler::~WebGLContextLossHandler()
|
||||
{
|
||||
MOZ_ASSERT(!mIsTimerRunning);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContextLossHandler::StartTimer(unsigned long delayMS)
|
||||
{
|
||||
// We can't pass a TemporaryRef through InitWithFuncCallback, so we
|
||||
// should do the AddRef/Release manually.
|
||||
this->AddRef();
|
||||
|
||||
mTimer->InitWithFuncCallback(StaticTimerCallback,
|
||||
static_cast<void*>(this),
|
||||
delayMS,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
WebGLContextLossHandler::StaticTimerCallback(nsITimer*,
|
||||
void* voidHandler)
|
||||
{
|
||||
typedef WebGLContextLossHandler T;
|
||||
T* handler = static_cast<T*>(voidHandler);
|
||||
|
||||
handler->TimerCallback();
|
||||
|
||||
// Release the AddRef from StartTimer.
|
||||
handler->Release();
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContextLossHandler::TimerCallback()
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mThread);
|
||||
|
||||
if (mIsDisabled)
|
||||
return;
|
||||
|
||||
MOZ_ASSERT(mIsTimerRunning);
|
||||
mIsTimerRunning = false;
|
||||
|
||||
// If we need to run the timer again, restart it immediately.
|
||||
// Otherwise, the code we call into below might *also* try to
|
||||
// restart it.
|
||||
if (mShouldRunTimerAgain) {
|
||||
RunTimer();
|
||||
MOZ_ASSERT(mIsTimerRunning);
|
||||
}
|
||||
|
||||
if (mWeakWebGL) {
|
||||
mWeakWebGL->UpdateContextLossStatus();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContextLossHandler::RunTimer()
|
||||
{
|
||||
MOZ_ASSERT(!mIsDisabled);
|
||||
|
||||
// If the timer was already running, don't restart it here. Instead,
|
||||
// wait until the previous call is done, then fire it one more time.
|
||||
// This is an optimization to prevent unnecessary
|
||||
// cross-communication between threads.
|
||||
if (mIsTimerRunning) {
|
||||
mShouldRunTimerAgain = true;
|
||||
return;
|
||||
}
|
||||
|
||||
StartTimer(1000);
|
||||
|
||||
mIsTimerRunning = true;
|
||||
mShouldRunTimerAgain = false;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContextLossHandler::DisableTimer()
|
||||
{
|
||||
if (!mIsDisabled)
|
||||
return;
|
||||
|
||||
mIsDisabled = true;
|
||||
|
||||
// We can't just Cancel() the timer, as sometimes we end up
|
||||
// receiving a callback after calling Cancel(). This could cause us
|
||||
// to receive the callback after object destruction.
|
||||
|
||||
// Instead, we let the timer finish, but ignore it.
|
||||
|
||||
if (!mIsTimerRunning)
|
||||
return;
|
||||
|
||||
mTimer->SetDelay(0);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
47
dom/canvas/WebGLContextLossHandler.h
Normal file
47
dom/canvas/WebGLContextLossHandler.h
Normal file
@ -0,0 +1,47 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef WEBGL_CONTEXT_LOSS_HANDLER_H_
|
||||
#define WEBGL_CONTEXT_LOSS_HANDLER_H_
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/WeakPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsIThread;
|
||||
class nsITimer;
|
||||
|
||||
namespace mozilla {
|
||||
class WebGLContext;
|
||||
|
||||
class WebGLContextLossHandler
|
||||
: public RefCounted<WebGLContextLossHandler>
|
||||
{
|
||||
WeakPtr<WebGLContext> mWeakWebGL;
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
bool mIsTimerRunning;
|
||||
bool mShouldRunTimerAgain;
|
||||
bool mIsDisabled;
|
||||
DebugOnly<nsIThread*> mThread;
|
||||
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_TYPENAME(WebGLContextLossHandler)
|
||||
|
||||
WebGLContextLossHandler(WebGLContext* webgl);
|
||||
~WebGLContextLossHandler();
|
||||
|
||||
void RunTimer();
|
||||
void DisableTimer();
|
||||
|
||||
protected:
|
||||
void StartTimer(unsigned long delayMS);
|
||||
static void StaticTimerCallback(nsITimer*, void* tempRefForTimer);
|
||||
void TimerCallback();
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
@ -1,52 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "WebGLContext.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
/* static */ void
|
||||
WebGLContext::ContextLossCallbackStatic(nsITimer* timer, void* thisPointer)
|
||||
{
|
||||
(void)timer;
|
||||
WebGLContext* context = static_cast<WebGLContext*>(thisPointer);
|
||||
|
||||
context->TerminateContextLossTimer();
|
||||
|
||||
context->UpdateContextLossStatus();
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::RunContextLossTimer()
|
||||
{
|
||||
// If the timer was already running, don't restart it here. Instead,
|
||||
// wait until the previous call is done, then fire it one more time.
|
||||
// This is an optimization to prevent unnecessary
|
||||
// cross-communication between threads.
|
||||
if (mContextLossTimerRunning) {
|
||||
mRunContextLossTimerAgain = true;
|
||||
return;
|
||||
}
|
||||
mContextRestorer->InitWithFuncCallback(ContextLossCallbackStatic,
|
||||
static_cast<void*>(this),
|
||||
1000,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
mContextLossTimerRunning = true;
|
||||
mRunContextLossTimerAgain = false;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::TerminateContextLossTimer()
|
||||
{
|
||||
if (!mContextLossTimerRunning)
|
||||
return;
|
||||
|
||||
mContextRestorer->Cancel();
|
||||
mContextLossTimerRunning = false;
|
||||
|
||||
if (mRunContextLossTimerAgain) {
|
||||
RunContextLossTimer();
|
||||
}
|
||||
}
|
@ -51,7 +51,7 @@ UNIFIED_SOURCES += [
|
||||
'WebGLContextExtensions.cpp',
|
||||
'WebGLContextFramebufferOperations.cpp',
|
||||
'WebGLContextGL.cpp',
|
||||
'WebGLContextLossTimer.cpp',
|
||||
'WebGLContextLossHandler.cpp',
|
||||
'WebGLContextReporter.cpp',
|
||||
'WebGLContextState.cpp',
|
||||
'WebGLContextUtils.cpp',
|
||||
|
@ -54,6 +54,9 @@
|
||||
SpecialPowers.autoConfirmAppInstall(continueTest);
|
||||
yield undefined;
|
||||
|
||||
SpecialPowers.autoConfirmAppUninstall(continueTest);
|
||||
yield undefined;
|
||||
|
||||
var request = navigator.mozApps.install(gHostedManifestURL);
|
||||
request.onerror = cbError;
|
||||
request.onsuccess = continueTest;
|
||||
|
@ -95,7 +95,8 @@
|
||||
|
||||
// No confirmation needed when an app is installed
|
||||
function() {
|
||||
SpecialPowers.autoConfirmAppInstall(runTest);
|
||||
SpecialPowers.autoConfirmAppInstall(() =>
|
||||
SpecialPowers.autoConfirmAppUninstall(runTest));
|
||||
},
|
||||
|
||||
// Installing the app
|
||||
|
@ -95,7 +95,8 @@
|
||||
|
||||
// No confirmation needed when an app is installed
|
||||
function() {
|
||||
SpecialPowers.autoConfirmAppInstall(runTest);
|
||||
SpecialPowers.autoConfirmAppInstall(() =>
|
||||
SpecialPowers.autoConfirmAppUninstall(runTest));
|
||||
},
|
||||
|
||||
// Installing the app
|
||||
|
@ -95,7 +95,8 @@
|
||||
|
||||
// No confirmation needed when an app is installed
|
||||
function() {
|
||||
SpecialPowers.autoConfirmAppInstall(runTest);
|
||||
SpecialPowers.autoConfirmAppInstall(() =>
|
||||
SpecialPowers.autoConfirmAppUninstall(runTest));
|
||||
},
|
||||
|
||||
// Installing the app
|
||||
|
@ -96,7 +96,8 @@
|
||||
|
||||
// No confirmation needed when an app is installed
|
||||
function() {
|
||||
SpecialPowers.autoConfirmAppInstall(runTest);
|
||||
SpecialPowers.autoConfirmAppInstall(() =>
|
||||
SpecialPowers.autoConfirmAppUninstall(runTest));
|
||||
},
|
||||
|
||||
// Installing the app
|
||||
|
@ -95,7 +95,8 @@
|
||||
|
||||
// No confirmation needed when an app is installed
|
||||
function() {
|
||||
SpecialPowers.autoConfirmAppInstall(runTest);
|
||||
SpecialPowers.autoConfirmAppInstall(() =>
|
||||
SpecialPowers.autoConfirmAppUninstall(runTest));
|
||||
},
|
||||
|
||||
// Installing the app
|
||||
|
@ -112,6 +112,11 @@
|
||||
// Run tests in app
|
||||
testApp,
|
||||
|
||||
// No confirmation needed when an app is installed
|
||||
function() {
|
||||
SpecialPowers.autoConfirmAppUninstall(runTest);
|
||||
},
|
||||
|
||||
// Uninstall the app
|
||||
uninstallApp
|
||||
];
|
||||
|
@ -100,7 +100,8 @@
|
||||
|
||||
// No confirmation needed when an app is installed
|
||||
function() {
|
||||
SpecialPowers.autoConfirmAppInstall(runTest);
|
||||
SpecialPowers.autoConfirmAppInstall(() =>
|
||||
SpecialPowers.autoConfirmAppUninstall(runTest));
|
||||
},
|
||||
|
||||
// Installing the app1
|
||||
|
@ -92,7 +92,8 @@
|
||||
|
||||
// No confirmation needed when an app is installed
|
||||
function() {
|
||||
SpecialPowers.autoConfirmAppInstall(runTest);
|
||||
SpecialPowers.autoConfirmAppInstall(() =>
|
||||
SpecialPowers.autoConfirmAppUninstall(runTest));
|
||||
},
|
||||
|
||||
// Installing the app1
|
||||
|
@ -102,7 +102,8 @@
|
||||
|
||||
// No confirmation needed when an app is installed
|
||||
function() {
|
||||
SpecialPowers.autoConfirmAppInstall(runTest);
|
||||
SpecialPowers.autoConfirmAppInstall(() =>
|
||||
SpecialPowers.autoConfirmAppUninstall(runTest));
|
||||
},
|
||||
|
||||
// Installing the app
|
||||
|
@ -138,7 +138,8 @@
|
||||
|
||||
// No confirmation needed when an app is installed
|
||||
function() {
|
||||
SpecialPowers.autoConfirmAppInstall(runTest);
|
||||
SpecialPowers.autoConfirmAppInstall(() =>
|
||||
SpecialPowers.autoConfirmAppUninstall(runTest));
|
||||
},
|
||||
|
||||
// Installing the app1
|
||||
|
@ -95,7 +95,8 @@
|
||||
|
||||
// No confirmation needed when an app is installed
|
||||
function() {
|
||||
SpecialPowers.autoConfirmAppInstall(runTest);
|
||||
SpecialPowers.autoConfirmAppInstall(() =>
|
||||
SpecialPowers.autoConfirmAppUninstall(runTest));
|
||||
},
|
||||
|
||||
// Installing the app
|
||||
|
@ -95,7 +95,8 @@
|
||||
|
||||
// No confirmation needed when an app is installed
|
||||
function() {
|
||||
SpecialPowers.autoConfirmAppInstall(runTest);
|
||||
SpecialPowers.autoConfirmAppInstall(() =>
|
||||
SpecialPowers.autoConfirmAppUninstall(runTest));
|
||||
},
|
||||
|
||||
// Installing the app
|
||||
|
@ -89,7 +89,9 @@
|
||||
function() {
|
||||
SpecialPowers.setAllAppsLaunchable(true);
|
||||
// No confirmation needed when an app is installed.
|
||||
SpecialPowers.autoConfirmAppInstall(runTest);
|
||||
SpecialPowers.autoConfirmAppInstall(() => {
|
||||
SpecialPowers.autoConfirmAppUninstall(runTest);
|
||||
});
|
||||
},
|
||||
|
||||
function() {
|
||||
|
@ -96,7 +96,8 @@
|
||||
|
||||
// No confirmation needed when an app is installed
|
||||
function() {
|
||||
SpecialPowers.autoConfirmAppInstall(runTest);
|
||||
SpecialPowers.autoConfirmAppInstall(() =>
|
||||
SpecialPowers.autoConfirmAppUninstall(runTest));
|
||||
},
|
||||
|
||||
// Installing the app
|
||||
|
@ -124,7 +124,8 @@
|
||||
|
||||
// No confirmation needed when an app is installed
|
||||
function() {
|
||||
SpecialPowers.autoConfirmAppInstall(runTest);
|
||||
SpecialPowers.autoConfirmAppInstall(() =>
|
||||
SpecialPowers.autoConfirmAppUninstall(runTest));
|
||||
},
|
||||
|
||||
// Installing the apps
|
||||
|
@ -40,6 +40,9 @@
|
||||
SpecialPowers.autoConfirmAppInstall(continueTest);
|
||||
yield undefined;
|
||||
|
||||
SpecialPowers.autoConfirmAppUninstall(continueTest);
|
||||
yield undefined;
|
||||
|
||||
var request = navigator.mozApps.install(gHostedManifestURL);
|
||||
request.onerror = cbError;
|
||||
request.onsuccess = continueTest;
|
||||
|
@ -94,7 +94,8 @@
|
||||
|
||||
// No confirmation needed when an app is installed
|
||||
function() {
|
||||
SpecialPowers.autoConfirmAppInstall(runTest);
|
||||
SpecialPowers.autoConfirmAppInstall(() =>
|
||||
SpecialPowers.autoConfirmAppUninstall(runTest));
|
||||
},
|
||||
|
||||
// Installing the app
|
||||
|
@ -94,7 +94,8 @@
|
||||
|
||||
// No confirmation needed when an app is installed
|
||||
function() {
|
||||
SpecialPowers.autoConfirmAppInstall(runTest);
|
||||
SpecialPowers.autoConfirmAppInstall(() =>
|
||||
SpecialPowers.autoConfirmAppUninstall(runTest));
|
||||
},
|
||||
|
||||
// Installing the app
|
||||
|
@ -95,7 +95,8 @@
|
||||
|
||||
// No confirmation needed when an app is installed
|
||||
function() {
|
||||
SpecialPowers.autoConfirmAppInstall(runTest);
|
||||
SpecialPowers.autoConfirmAppInstall(() =>
|
||||
SpecialPowers.autoConfirmAppUninstall(runTest));
|
||||
},
|
||||
|
||||
// Installing the app
|
||||
|
@ -132,6 +132,25 @@ function runTests() {
|
||||
is(mouseleavecount, 7, "Unexpected mouseleave event count!");
|
||||
|
||||
checkRelatedTarget = false;
|
||||
|
||||
iframe.contentDocument.body.firstChild.onmouseenter = null;
|
||||
iframe.contentDocument.body.firstChild.onmouseleave = null;
|
||||
iframe.contentDocument.body.lastChild.onmouseenter = null;
|
||||
iframe.contentDocument.body.lastChild.onmouseleave = null;
|
||||
|
||||
container.onmouseenter = null;
|
||||
container.onmouseleave = null;
|
||||
container.onmouseout = null;
|
||||
container.onmouseover = null;
|
||||
|
||||
var children = container.getElementsByTagName('*');
|
||||
for (var i=0;i<children.length;i++) {
|
||||
children[i].onmouseenter = null;
|
||||
children[i].onmouseleave = null;
|
||||
children[i].onmouseout = null;
|
||||
children[i].onmouseover = null;
|
||||
}
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
@ -3746,6 +3746,13 @@ ContentParent::CheckAppHasStatus(unsigned short aStatus)
|
||||
return AssertAppHasStatus(this, aStatus);
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::KillChild()
|
||||
{
|
||||
KillHard();
|
||||
return true;
|
||||
}
|
||||
|
||||
PBlobParent*
|
||||
ContentParent::SendPBlobConstructor(PBlobParent* aActor,
|
||||
const BlobConstructorParams& aParams)
|
||||
|
@ -161,6 +161,7 @@ public:
|
||||
virtual bool CheckManifestURL(const nsAString& aManifestURL) MOZ_OVERRIDE;
|
||||
virtual bool CheckAppHasPermission(const nsAString& aPermission) MOZ_OVERRIDE;
|
||||
virtual bool CheckAppHasStatus(unsigned short aStatus) MOZ_OVERRIDE;
|
||||
virtual bool KillChild() MOZ_OVERRIDE;
|
||||
|
||||
/** Notify that a tab is beginning its destruction sequence. */
|
||||
void NotifyTabDestroying(PBrowserParent* aTab);
|
||||
|
@ -4292,7 +4292,7 @@ RadioInterface.prototype = {
|
||||
if (!response.errorMsg) {
|
||||
request.notifyGetSmscAddress(response.smscAddress);
|
||||
} else {
|
||||
request.notifyGetSmscAddressFailed(response.errorMsg);
|
||||
request.notifyGetSmscAddressFailed(Ci.nsIMobileMessageCallback.NOT_FOUND_ERROR);
|
||||
}
|
||||
}).bind(this));
|
||||
},
|
||||
|
@ -243,7 +243,7 @@ var interfaceNamesInGlobalScope =
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"CSSFontFaceRule",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "CSSFontFeatureValuesRule", release: false},
|
||||
"CSSFontFeatureValuesRule",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"CSSGroupingRule",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
@ -183,7 +183,9 @@ function browserLoadEvent() {
|
||||
|
||||
addLoadEvent(() =>
|
||||
SpecialPowers.pushPrefEnv({set: [['dom.mozBrowserFramesEnabled', true]]}, () =>
|
||||
SpecialPowers.autoConfirmAppInstall(runTest)
|
||||
SpecialPowers.autoConfirmAppInstall(() =>
|
||||
SpecialPowers.autoConfirmAppUninstall(runTest)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -197,7 +197,9 @@ function checks() {
|
||||
|
||||
addLoadEvent(() =>
|
||||
SpecialPowers.pushPrefEnv({set: [['dom.mozBrowserFramesEnabled', true]]}, () =>
|
||||
SpecialPowers.autoConfirmAppInstall(runTest)
|
||||
SpecialPowers.autoConfirmAppInstall(() =>
|
||||
SpecialPowers.autoConfirmAppUninstall(runTest)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
var parent = SpecialPowers.wrap(window).parent;
|
||||
|
||||
confirmNextInstall();
|
||||
confirmNextPopup();
|
||||
navigator.mozApps.install(parent.url2, null).onsuccess = function onInstall() {
|
||||
// Give the test page a reference to the installed app, so it can uninstall it
|
||||
// after it finishes the tests.
|
||||
|
@ -34,19 +34,22 @@ function runAll(steps) {
|
||||
next();
|
||||
}
|
||||
|
||||
function confirmNextInstall() {
|
||||
function confirmNextPopup() {
|
||||
var Ci = SpecialPowers.Ci;
|
||||
|
||||
var popupPanel = SpecialPowers.wrap(window).top.
|
||||
QueryInterface(Ci.nsIInterfaceRequestor).
|
||||
getInterface(Ci.nsIWebNavigation).
|
||||
QueryInterface(Ci.nsIDocShell).
|
||||
chromeEventHandler.ownerDocument.defaultView.
|
||||
PopupNotifications.panel;
|
||||
var popupNotifications = SpecialPowers.wrap(window).top.
|
||||
QueryInterface(Ci.nsIInterfaceRequestor).
|
||||
getInterface(Ci.nsIWebNavigation).
|
||||
QueryInterface(Ci.nsIDocShell).
|
||||
chromeEventHandler.ownerDocument.defaultView.
|
||||
PopupNotifications;
|
||||
|
||||
var popupPanel = popupNotifications.panel;
|
||||
|
||||
function onPopupShown() {
|
||||
popupPanel.removeEventListener("popupshown", onPopupShown, false);
|
||||
SpecialPowers.wrap(this).childNodes[0].button.doCommand();
|
||||
popupNotifications._dismiss();
|
||||
}
|
||||
popupPanel.addEventListener("popupshown", onPopupShown, false);
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ ppmm.addMessageListener("Webapps:Install", mmListener);
|
||||
// We call this here, even though the app is installed by the helper page,
|
||||
// because the helper page redirect would cause its install listener to unload
|
||||
// before it can confirm the install.
|
||||
confirmNextInstall();
|
||||
confirmNextPopup();
|
||||
|
||||
</script>
|
||||
|
||||
|
@ -43,7 +43,7 @@ runAll(steps);
|
||||
* the app itself is from a different origin (http://test1.example.com).
|
||||
*/
|
||||
function installAppFromOwnOrigin(next) {
|
||||
confirmNextInstall();
|
||||
confirmNextPopup();
|
||||
navigator.mozApps.install(url1, null).onsuccess = function onInstall() {
|
||||
app1 = this.result;
|
||||
next();
|
||||
@ -93,7 +93,9 @@ function getAll(next) {
|
||||
}
|
||||
|
||||
function uninstall(next) {
|
||||
confirmNextPopup();
|
||||
navigator.mozApps.mgmt.uninstall(app1).onsuccess = function onUninstallApp1() {
|
||||
confirmNextPopup();
|
||||
navigator.mozApps.mgmt.uninstall(app2).onsuccess = function onUninstallApp2() {
|
||||
next();
|
||||
};
|
||||
|
@ -76,11 +76,11 @@ function getNotInstalled(next) {
|
||||
|
||||
// Add an app to the appregistry
|
||||
function installApp(next) {
|
||||
confirmNextInstall();
|
||||
confirmNextPopup();
|
||||
navigator.mozApps.install(url, null).onsuccess = function onInstall() {
|
||||
app = this.result;
|
||||
next();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Call navigator.mozApps.mgmt.getNotInstalled and make sure there is one more.
|
||||
@ -128,6 +128,7 @@ function unmonkeyPatchDOMApplicationRegistry(next) {
|
||||
|
||||
// Remove the app from the appregistry
|
||||
function uninstallApp(next) {
|
||||
confirmNextPopup();
|
||||
window.navigator.mozApps.mgmt.uninstall(app).onsuccess = function onUninstall() {
|
||||
app = null;
|
||||
next();
|
||||
|
@ -45,7 +45,7 @@ function install(next) {
|
||||
var beforehand = Date.now();
|
||||
const fuzzySpan = 250;
|
||||
|
||||
confirmNextInstall();
|
||||
confirmNextPopup();
|
||||
navigator.mozApps.install(url, null).onsuccess = function onInstall() {
|
||||
app = this.result;
|
||||
|
||||
@ -84,6 +84,7 @@ function getSelf(next) {
|
||||
}
|
||||
|
||||
function uninstall(next) {
|
||||
confirmNextPopup();
|
||||
navigator.mozApps.mgmt.uninstall(app).onsuccess = function onUninstall() {
|
||||
// Try to retrieve the app we just uninstalled, to make sure it no longer
|
||||
// exists in the registry.
|
||||
|
@ -69,7 +69,7 @@ function invalidManifest(next) {
|
||||
function permissionDenied(next) {
|
||||
var url = "http://test/chrome/dom/tests/mochitest/webapps/apps/no_delegated_install.webapp";
|
||||
|
||||
confirmNextInstall();
|
||||
confirmNextPopup();
|
||||
var request = navigator.mozApps.install(url, null);
|
||||
|
||||
request.onerror = function onInstallError() {
|
||||
@ -79,6 +79,7 @@ function permissionDenied(next) {
|
||||
|
||||
request.onsuccess = function onInstall() {
|
||||
todo(false, "manifest without installs_allowed_from fails");
|
||||
confirmNextPopup();
|
||||
navigator.mozApps.mgmt.uninstall(this.result).onsuccess = function onUninstall() {
|
||||
next();
|
||||
};
|
||||
@ -97,6 +98,7 @@ function invalidContent(next) {
|
||||
|
||||
request.onsuccess = function onInstall() {
|
||||
ok(false, "manifest with bad content type should fail");
|
||||
confirmNextPopup();
|
||||
navigator.mozApps.mgmt.uninstall(this.result).onsuccess = function onUninstall() {
|
||||
next();
|
||||
};
|
||||
@ -206,6 +208,7 @@ function originNotAllowed(next) {
|
||||
|
||||
request.onsuccess = function onInstall() {
|
||||
ok(false, "test should fail because of installs_allowed_from");
|
||||
confirmNextPopup();
|
||||
navigator.mozApps.mgmt.uninstall(this.result).onsuccess = function onUninstall() {
|
||||
next();
|
||||
};
|
||||
@ -215,7 +218,7 @@ function originNotAllowed(next) {
|
||||
function originAllowed(next) {
|
||||
var url = "http://test/chrome/dom/tests/mochitest/webapps/apps/installs_allowed_from_chrome_mochitests.webapp";
|
||||
|
||||
confirmNextInstall();
|
||||
confirmNextPopup();
|
||||
var request = navigator.mozApps.install(url, null);
|
||||
|
||||
request.onerror = function onInstallError() {
|
||||
@ -225,6 +228,7 @@ function originAllowed(next) {
|
||||
|
||||
request.onsuccess = function onInstall() {
|
||||
ok(true, "test origin is in installs_allowed_from");
|
||||
confirmNextPopup();
|
||||
navigator.mozApps.mgmt.uninstall(this.result).onsuccess = function onUninstall() {
|
||||
next();
|
||||
};
|
||||
|
@ -22,12 +22,13 @@ SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var url = "http://test/chrome/dom/tests/mochitest/webapps/apps/utf8.webapp";
|
||||
|
||||
confirmNextInstall();
|
||||
confirmNextPopup();
|
||||
navigator.mozApps.install(url, null).onsuccess = function onInstall() {
|
||||
is(this.result.manifest.name, "TheBOM ゲゴケ゚セニツ゚ヅヂチ", "manifest.name");
|
||||
is(this.result.manifest.description, "This App is THE BOM, yo. ヅヂチ",
|
||||
"manifest.description");
|
||||
|
||||
confirmNextPopup();
|
||||
navigator.mozApps.mgmt.uninstall(this.result).onsuccess = function onUninstall() {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ function install(next) {
|
||||
var beforehand = Date.now();
|
||||
const fuzzySpan = 250;
|
||||
|
||||
confirmNextInstall();
|
||||
confirmNextPopup();
|
||||
navigator.mozApps.install(url, null).onsuccess = function onInstall() {
|
||||
app = this.result;
|
||||
|
||||
@ -84,6 +84,7 @@ function getSelf(next) {
|
||||
}
|
||||
|
||||
function uninstall(next) {
|
||||
confirmNextPopup();
|
||||
navigator.mozApps.mgmt.uninstall(app).onsuccess = function onUninstall() {
|
||||
// Try to retrieve the app we just uninstalled, to make sure it no longer
|
||||
// exists in the registry.
|
||||
|
643
dom/tethering/tests/marionette/head.js
Normal file
643
dom/tethering/tests/marionette/head.js
Normal file
@ -0,0 +1,643 @@
|
||||
/* 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/. */
|
||||
|
||||
const TYPE_WIFI = "wifi";
|
||||
const TYPE_BLUETOOTH = "bt";
|
||||
const TYPE_USB = "usb";
|
||||
|
||||
/**
|
||||
* General tethering setting.
|
||||
*/
|
||||
const TETHERING_SETTING_IP = "192.168.1.1";
|
||||
const TETHERING_SETTNG_PREFIX = "24";
|
||||
const TETHERING_SETTING_START_IP = "192.168.1.10";
|
||||
const TETHERING_SETTING_END_IP = "192.168.1.30";
|
||||
const TETHERING_SETTING_DNS1 = "8.8.8.8";
|
||||
const TETHERING_SETTING_DNS2 = "8.8.4.4";
|
||||
|
||||
/**
|
||||
* Wifi tethering setting.
|
||||
*/
|
||||
const TETHERING_SETTING_SSID = "FirefoxHotSpot";
|
||||
const TETHERING_SETTING_SECURITY = "open";
|
||||
const TETHERING_SETTING_KEY = "1234567890";
|
||||
|
||||
const SETTINGS_RIL_DATA_ENABLED = 'ril.data.enabled';
|
||||
|
||||
let Promise =
|
||||
SpecialPowers.Cu.import("resource://gre/modules/Promise.jsm").Promise;
|
||||
|
||||
let gTestSuite = (function() {
|
||||
let suite = {};
|
||||
|
||||
let tetheringManager;
|
||||
let pendingEmulatorShellCount = 0;
|
||||
|
||||
/**
|
||||
* A wrapper function of "is".
|
||||
*
|
||||
* Calls the marionette function "is" as well as throws an exception
|
||||
* if the givens values are not equal.
|
||||
*
|
||||
* @param value1
|
||||
* Any type of value to compare.
|
||||
*
|
||||
* @param value2
|
||||
* Any type of value to compare.
|
||||
*
|
||||
* @param message
|
||||
* Debug message for this check.
|
||||
*
|
||||
*/
|
||||
function isOrThrow(value1, value2, message) {
|
||||
is(value1, value2, message);
|
||||
if (value1 !== value2) {
|
||||
throw message;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send emulator shell command with safe guard.
|
||||
*
|
||||
* We should only call |finish()| after all emulator command transactions
|
||||
* end, so here comes with the pending counter. Resolve when the emulator
|
||||
* gives positive response, and reject otherwise.
|
||||
*
|
||||
* Fulfill params:
|
||||
* result -- an array of emulator response lines.
|
||||
* Reject params:
|
||||
* result -- an array of emulator response lines.
|
||||
*
|
||||
* @param aCommand
|
||||
* A string command to be passed to emulator through its telnet console.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function runEmulatorShellSafe(aCommand) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
++pendingEmulatorShellCount;
|
||||
runEmulatorShell(aCommand, function(aResult) {
|
||||
--pendingEmulatorShellCount;
|
||||
|
||||
ok(true, "Emulator shell response: " + JSON.stringify(aResult));
|
||||
if (Array.isArray(aResult)) {
|
||||
deferred.resolve(aResult);
|
||||
} else {
|
||||
deferred.reject(aResult);
|
||||
}
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for timeout.
|
||||
*
|
||||
* Resolve when the given duration elapsed. Never reject.
|
||||
*
|
||||
* Fulfill params: (none)
|
||||
*
|
||||
* @param aTimeoutMs
|
||||
* The duration after which the timeout event should occurs.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function waitForTimeout(aTimeoutMs) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
setTimeout(function() {
|
||||
deferred.resolve();
|
||||
}, aTimeoutMs);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get mozSettings value specified by @aKey.
|
||||
*
|
||||
* Resolve if that mozSettings value is retrieved successfully, reject
|
||||
* otherwise.
|
||||
*
|
||||
* Fulfill params:
|
||||
* The corresponding mozSettings value of the key.
|
||||
* Reject params: (none)
|
||||
*
|
||||
* @param aKey
|
||||
* A string.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function getSettings(aKey) {
|
||||
let request = navigator.mozSettings.createLock().get(aKey);
|
||||
|
||||
return wrapDomRequestAsPromise(request)
|
||||
.then(function resolve(aEvent) {
|
||||
ok(true, "getSettings(" + aKey + ") - success");
|
||||
return aEvent.target.result[aKey];
|
||||
}, function reject(aEvent) {
|
||||
ok(false, "getSettings(" + aKey + ") - error");
|
||||
throw aEvent.target.error;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set mozSettings values.
|
||||
*
|
||||
* Resolve if that mozSettings value is set successfully, reject otherwise.
|
||||
*
|
||||
* Fulfill params: (none)
|
||||
* Reject params: (none)
|
||||
*
|
||||
* @param aSettings
|
||||
* An object of format |{key1: value1, key2: value2, ...}|.
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function setSettings(aSettings) {
|
||||
let request = navigator.mozSettings.createLock().set(aSettings);
|
||||
|
||||
return wrapDomRequestAsPromise(request)
|
||||
.then(function resolve() {
|
||||
ok(true, "setSettings(" + JSON.stringify(aSettings) + ")");
|
||||
}, function reject(aEvent) {
|
||||
ok(false, "setSettings(" + JSON.stringify(aSettings) + ")");
|
||||
throw aEvent.target.error;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set mozSettings value with only one key.
|
||||
*
|
||||
* Resolve if that mozSettings value is set successfully, reject otherwise.
|
||||
*
|
||||
* Fulfill params: (none)
|
||||
* Reject params: (none)
|
||||
*
|
||||
* @param aKey
|
||||
* A string key.
|
||||
* @param aValue
|
||||
* An object value.
|
||||
* @param aAllowError [optional]
|
||||
* A boolean value. If set to true, an error response won't be treated
|
||||
* as test failure. Default: false.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function setSettings1(aKey, aValue, aAllowError) {
|
||||
let settings = {};
|
||||
settings[aKey] = aValue;
|
||||
return setSettings(settings, aAllowError);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap DOMRequest onsuccess/onerror events to Promise resolve/reject.
|
||||
*
|
||||
* Fulfill params: A DOMEvent.
|
||||
* Reject params: A DOMEvent.
|
||||
*
|
||||
* @param aRequest
|
||||
* A DOMRequest instance.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function wrapDomRequestAsPromise(aRequest) {
|
||||
let deffered = Promise.defer();
|
||||
|
||||
ok(aRequest instanceof DOMRequest,
|
||||
"aRequest is instanceof" + aRequest.constructor);
|
||||
|
||||
aRequest.onsuccess = function(aEvent) {
|
||||
deffered.resolve(aEvent);
|
||||
};
|
||||
aRequest.onerror = function(aEvent) {
|
||||
deffered.reject(aEvent);
|
||||
};
|
||||
|
||||
return deffered.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for one named MozMobileConnection event.
|
||||
*
|
||||
* Resolve if that named event occurs. Never reject.
|
||||
*
|
||||
* Fulfill params: the DOMEvent passed.
|
||||
*
|
||||
* @param aEventName
|
||||
* A string event name.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function waitForMobileConnectionEventOnce(aEventName, aServiceId) {
|
||||
aServiceId = aServiceId || 0;
|
||||
|
||||
let deferred = Promise.defer();
|
||||
let mobileconnection = navigator.mozMobileConnections[aServiceId];
|
||||
|
||||
mobileconnection.addEventListener(aEventName, function onevent(aEvent) {
|
||||
mobileconnection.removeEventListener(aEventName, onevent);
|
||||
|
||||
ok(true, "Mobile connection event '" + aEventName + "' got.");
|
||||
deferred.resolve(aEvent);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for RIL data being connected.
|
||||
*
|
||||
* This function will check |MozMobileConnection.data.connected| on
|
||||
* every 'datachange' event. Resolve when |MozMobileConnection.data.connected|
|
||||
* becomes the expected state. Never reject.
|
||||
*
|
||||
* Fulfill params: (none)
|
||||
* Reject params: (none)
|
||||
*
|
||||
* @param aConnected
|
||||
* Boolean that indicates the desired data state.
|
||||
*
|
||||
* @param aServiceId [optional]
|
||||
* A numeric DSDS service id. Default: 0.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function waitForRilDataConnected(aConnected, aServiceId) {
|
||||
aServiceId = aServiceId || 0;
|
||||
|
||||
return waitForMobileConnectionEventOnce('datachange', aServiceId)
|
||||
.then(function () {
|
||||
let mobileconnection = navigator.mozMobileConnections[aServiceId];
|
||||
if (mobileconnection.data.connected !== aConnected) {
|
||||
return waitForRilDataConnected(aConnected, aServiceId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify everything about routing when the wifi tethering is either on or off.
|
||||
*
|
||||
* We use two unix commands to verify the routing: 'netcfg' and 'ip route'.
|
||||
* For now the following two things will be checked:
|
||||
* 1) The default route interface should be 'rmnet0'.
|
||||
* 2) wlan0 is up and its ip is set to a private subnet.
|
||||
*
|
||||
* We also verify iptables output as netd's NatController will execute
|
||||
* $ iptables -t nat -A POSTROUTING -o rmnet0 -j MASQUERADE
|
||||
*
|
||||
* Resolve when the verification is successful and reject otherwise.
|
||||
*
|
||||
* Fulfill params: (none)
|
||||
* Reject params: String that indicates the reason of rejection.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function verifyTetheringRouting(aEnabled) {
|
||||
let netcfgResult = {};
|
||||
let ipRouteResult = {};
|
||||
|
||||
// Execute 'netcfg' and parse to |netcfgResult|, each key of which is the
|
||||
// interface name and value is { ip(string) }.
|
||||
function exeAndParseNetcfg() {
|
||||
return runEmulatorShellSafe(['netcfg'])
|
||||
.then(function (aLines) {
|
||||
// Sample output:
|
||||
//
|
||||
// lo UP 127.0.0.1/8 0x00000049 00:00:00:00:00:00
|
||||
// eth0 UP 10.0.2.15/24 0x00001043 52:54:00:12:34:56
|
||||
// rmnet1 DOWN 0.0.0.0/0 0x00001002 52:54:00:12:34:58
|
||||
// rmnet2 DOWN 0.0.0.0/0 0x00001002 52:54:00:12:34:59
|
||||
// rmnet3 DOWN 0.0.0.0/0 0x00001002 52:54:00:12:34:5a
|
||||
// wlan0 UP 192.168.1.1/24 0x00001043 52:54:00:12:34:5b
|
||||
// sit0 DOWN 0.0.0.0/0 0x00000080 00:00:00:00:00:00
|
||||
// rmnet0 UP 10.0.2.100/24 0x00001043 52:54:00:12:34:57
|
||||
//
|
||||
aLines.forEach(function (aLine) {
|
||||
let tokens = aLine.split(/\s+/);
|
||||
if (tokens.length < 5) {
|
||||
return;
|
||||
}
|
||||
let ifname = tokens[0];
|
||||
let ip = (tokens[2].split('/'))[0];
|
||||
netcfgResult[ifname] = { ip: ip };
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Execute 'ip route' and parse to |ipRouteResult|, each key of which is the
|
||||
// interface name and value is { src(string), default(boolean) }.
|
||||
function exeAndParseIpRoute() {
|
||||
return runEmulatorShellSafe(['ip', 'route'])
|
||||
.then(function (aLines) {
|
||||
// Sample output:
|
||||
//
|
||||
// 10.0.2.4 via 10.0.2.2 dev rmnet0
|
||||
// 10.0.2.3 via 10.0.2.2 dev rmnet0
|
||||
// 192.168.1.0/24 dev wlan0 proto kernel scope link src 192.168.1.1
|
||||
// 10.0.2.0/24 dev eth0 proto kernel scope link src 10.0.2.15
|
||||
// 10.0.2.0/24 dev rmnet0 proto kernel scope link src 10.0.2.100
|
||||
// default via 10.0.2.2 dev rmnet0
|
||||
// default via 10.0.2.2 dev eth0 metric 2
|
||||
//
|
||||
|
||||
// Parse source ip for each interface.
|
||||
aLines.forEach(function (aLine) {
|
||||
let tokens = aLine.trim().split(/\s+/);
|
||||
let srcIndex = tokens.indexOf('src');
|
||||
if (srcIndex < 0 || srcIndex + 1 >= tokens.length) {
|
||||
return;
|
||||
}
|
||||
let ifname = tokens[2];
|
||||
let src = tokens[srcIndex + 1];
|
||||
ipRouteResult[ifname] = { src: src, default: false };
|
||||
});
|
||||
|
||||
// Parse default interfaces.
|
||||
aLines.forEach(function (aLine) {
|
||||
let tokens = aLine.split(/\s+/);
|
||||
if (tokens.length < 2) {
|
||||
return;
|
||||
}
|
||||
if ('default' === tokens[0]) {
|
||||
let ifnameIndex = tokens.indexOf('dev');
|
||||
if (ifnameIndex < 0 || ifnameIndex + 1 >= tokens.length) {
|
||||
return;
|
||||
}
|
||||
let ifname = tokens[ifnameIndex + 1];
|
||||
if (ipRouteResult[ifname]) {
|
||||
ipRouteResult[ifname].default = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// Find MASQUERADE in POSTROUTING section. 'MASQUERADE' should be found
|
||||
// when tethering is enabled. 'MASQUERADE' shouldn't be found when tethering
|
||||
// is disabled.
|
||||
function verifyIptables() {
|
||||
return runEmulatorShellSafe(['iptables', '-t', 'nat', '-L', 'POSTROUTING'])
|
||||
.then(function(aLines) {
|
||||
// $ iptables -t nat -L POSTROUTING
|
||||
//
|
||||
// Sample output (tethering on):
|
||||
//
|
||||
// Chain POSTROUTING (policy ACCEPT)
|
||||
// target prot opt source destination
|
||||
// MASQUERADE all -- anywhere anywhere
|
||||
//
|
||||
let found = (function find_MASQUERADE() {
|
||||
// Skip first two lines.
|
||||
for (let i = 2; i < aLines.length; i++) {
|
||||
if (-1 !== aLines[i].indexOf('MASQUERADE')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
})();
|
||||
|
||||
if ((aEnabled && !found) || (!aEnabled && found)) {
|
||||
throw 'MASQUERADE' + (found ? '' : ' not') + ' found while tethering is ' +
|
||||
(aEnabled ? 'enabled' : 'disabled');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function verifyDefaultRouteAndIp(aExpectedWifiTetheringIp) {
|
||||
log(JSON.stringify(ipRouteResult));
|
||||
log(JSON.stringify(netcfgResult));
|
||||
|
||||
if (aEnabled) {
|
||||
isOrThrow(ipRouteResult['rmnet0'].src, netcfgResult['rmnet0'].ip, 'rmnet0.ip');
|
||||
isOrThrow(ipRouteResult['rmnet0'].default, true, 'rmnet0.default');
|
||||
|
||||
isOrThrow(ipRouteResult['wlan0'].src, netcfgResult['wlan0'].ip, 'wlan0.ip');
|
||||
isOrThrow(ipRouteResult['wlan0'].src, aExpectedWifiTetheringIp, 'expected ip');
|
||||
isOrThrow(ipRouteResult['wlan0'].default, false, 'wlan0.default');
|
||||
}
|
||||
}
|
||||
|
||||
return verifyIptables()
|
||||
.then(exeAndParseNetcfg)
|
||||
.then(exeAndParseIpRoute)
|
||||
.then(() => verifyDefaultRouteAndIp(TETHERING_SETTING_IP));
|
||||
}
|
||||
|
||||
/**
|
||||
* Request to enable/disable wifi tethering.
|
||||
*
|
||||
* Enable/disable wifi tethering by using setTetheringEnabled API
|
||||
* Resolve when the routing is verified to set up successfully in 20 seconds. The polling
|
||||
* period is 1 second.
|
||||
*
|
||||
* Fulfill params: (none)
|
||||
* Reject params: The error message.
|
||||
*
|
||||
* @param aEnabled
|
||||
* Boolean that indicates to enable or disable wifi tethering.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function setWifiTetheringEnabled(aEnabled) {
|
||||
let RETRY_INTERVAL_MS = 1000;
|
||||
let retryCnt = 20;
|
||||
|
||||
let config = {
|
||||
"ip" : TETHERING_SETTING_IP,
|
||||
"prefix" : TETHERING_SETTNG_PREFIX,
|
||||
"startIp" : TETHERING_SETTING_START_IP,
|
||||
"endIp" : TETHERING_SETTING_END_IP,
|
||||
"dns1" : TETHERING_SETTING_DNS1,
|
||||
"dns2" : TETHERING_SETTING_DNS2,
|
||||
"wifiConfig": {
|
||||
"ssid" : TETHERING_SETTING_SSID,
|
||||
"security" : TETHERING_SETTING_SECURITY
|
||||
}
|
||||
};
|
||||
|
||||
return tetheringManager.setTetheringEnabled(aEnabled, TYPE_WIFI, config)
|
||||
.then(function waitForRoutingVerified() {
|
||||
return verifyTetheringRouting(aEnabled)
|
||||
.then(null, function onreject(aReason) {
|
||||
|
||||
log('verifyTetheringRouting rejected due to ' + aReason +
|
||||
' (' + retryCnt + ')');
|
||||
|
||||
if (!retryCnt--) {
|
||||
throw aReason;
|
||||
}
|
||||
|
||||
return waitForTimeout(RETRY_INTERVAL_MS).then(waitForRoutingVerified);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure wifi is enabled/disabled.
|
||||
*
|
||||
* Issue a wifi enable/disable request if wifi is not in the desired state;
|
||||
* return a resolved promise otherwise.
|
||||
*
|
||||
* Fulfill params: (none)
|
||||
* Reject params: (none)
|
||||
*
|
||||
* @return a resolved promise or deferred promise.
|
||||
*/
|
||||
function ensureWifiEnabled(aEnabled) {
|
||||
let wifiManager = window.navigator.mozWifiManager;
|
||||
if (wifiManager.enabled === aEnabled) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
let request = wifiManager.setWifiEnabled(aEnabled);
|
||||
return wrapDomRequestAsPromise(request)
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure tethering manager exists.
|
||||
*
|
||||
* Check navigator property |mozTetheringManager| to ensure we could access
|
||||
* tethering related function.
|
||||
*
|
||||
* Fulfill params: (none)
|
||||
* Reject params: (none)
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function ensureTetheringManager() {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
tetheringManager = window.navigator.mozTetheringManager;
|
||||
|
||||
if (tetheringManager instanceof MozTetheringManager) {
|
||||
deferred.resolve();
|
||||
} else {
|
||||
log("navigator.mozTetheringManager is unavailable");
|
||||
deferred.reject();
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add required permissions for tethering. Never reject.
|
||||
*
|
||||
* The permissions required for wifi testing are 'wifi-manage' and 'settings-write'.
|
||||
* Never reject.
|
||||
*
|
||||
* Fulfill params: (none)
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function acquirePermission() {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
let permissions = [{ 'type': 'wifi-manage', 'allow': 1, 'context': window.document },
|
||||
{ 'type': 'settings-write', 'allow': 1, 'context': window.document },
|
||||
{ 'type': 'settings-read', 'allow': 1, 'context': window.document },
|
||||
{ 'type': 'mobileconnection', 'allow': 1, 'context': window.document }];
|
||||
|
||||
SpecialPowers.pushPermissions(permissions, function() {
|
||||
deferred.resolve();
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Common test routine.
|
||||
*
|
||||
* Start a test with the given test case chain. The test environment will be
|
||||
* settled down before the test. After the test, all the affected things will
|
||||
* be restored.
|
||||
*
|
||||
* Fulfill params: (none)
|
||||
* Reject params: (none)
|
||||
*
|
||||
* @param aTestCaseChain
|
||||
* The test case entry point, which can be a function or a promise.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
suite.startTest = function(aTestCaseChain) {
|
||||
function setUp() {
|
||||
return ensureTetheringManager()
|
||||
.then(acquirePermission);
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
waitFor(finish, function() {
|
||||
return pendingEmulatorShellCount === 0;
|
||||
});
|
||||
}
|
||||
|
||||
return setUp()
|
||||
.then(aTestCaseChain)
|
||||
.then(function onresolve() {
|
||||
tearDown();
|
||||
}, function onreject(aReason) {
|
||||
ok(false, 'Promise rejects during test' + (aReason ? '(' + aReason + ')' : ''));
|
||||
tearDown();
|
||||
});
|
||||
};
|
||||
|
||||
//---------------------------------------------------
|
||||
// Public test suite functions
|
||||
//---------------------------------------------------
|
||||
suite.ensureWifiEnabled = ensureWifiEnabled;
|
||||
suite.setWifiTetheringEnabled = setWifiTetheringEnabled;
|
||||
|
||||
/**
|
||||
* The common test routine for wifi tethering.
|
||||
*
|
||||
* Set 'ril.data.enabled' to true
|
||||
* before testing and restore it afterward. It will also verify 'ril.data.enabled'
|
||||
* and 'tethering.wifi.enabled' to be false in the beginning. Note that this routine
|
||||
* will NOT change the state of 'tethering.wifi.enabled' so the user should enable
|
||||
* than disable on his/her own. This routine will only check if tethering is turned
|
||||
* off after testing.
|
||||
*
|
||||
* Fulfill params: (none)
|
||||
* Reject params: (none)
|
||||
*
|
||||
* @param aTestCaseChain
|
||||
* The test case entry point, which can be a function or a promise.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
suite.startTetheringTest = function(aTestCaseChain) {
|
||||
let oriDataEnabled;
|
||||
function verifyInitialState() {
|
||||
return getSettings(SETTINGS_RIL_DATA_ENABLED)
|
||||
.then(enabled => initTetheringTestEnvironment(enabled));
|
||||
}
|
||||
|
||||
function initTetheringTestEnvironment(aEnabled) {
|
||||
oriDataEnabled = aEnabled;
|
||||
if (aEnabled) {
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
return Promise.all([waitForRilDataConnected(true),
|
||||
setSettings1(SETTINGS_RIL_DATA_ENABLED, true)]);
|
||||
}
|
||||
}
|
||||
|
||||
function restoreToInitialState() {
|
||||
return setSettings1(SETTINGS_RIL_DATA_ENABLED, oriDataEnabled);
|
||||
}
|
||||
|
||||
return suite.startTest(function() {
|
||||
return verifyInitialState()
|
||||
.then(aTestCaseChain)
|
||||
.then(restoreToInitialState, function onreject(aReason) {
|
||||
return restoreToInitialState()
|
||||
.then(() => { throw aReason; }); // Re-throw the orignal reject reason.
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return suite;
|
||||
})();
|
6
dom/tethering/tests/marionette/manifest.ini
Normal file
6
dom/tethering/tests/marionette/manifest.ini
Normal file
@ -0,0 +1,6 @@
|
||||
[DEFAULT]
|
||||
b2g = true
|
||||
browser = false
|
||||
qemu = true
|
||||
|
||||
[test_wifi_tethering_enabled.js]
|
@ -0,0 +1,11 @@
|
||||
/* 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/. */
|
||||
|
||||
MARIONETTE_TIMEOUT = 60000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
gTestSuite.startTetheringTest(function() {
|
||||
return gTestSuite.ensureWifiEnabled(false)
|
||||
.then(() => gTestSuite.setWifiTetheringEnabled(true));
|
||||
});
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user