Merge m-c to fx-team. a=merge

This commit is contained in:
Ryan VanderMeulen 2014-08-25 16:27:23 -04:00
commit ff3f93c106
166 changed files with 4081 additions and 1956 deletions

View File

@ -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

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -4,6 +4,6 @@
"remote": "",
"branch": ""
},
"revision": "75d8e419442b5810145a888944ab0ab4f75bbcc9",
"revision": "5efa211f0198ab15798b456445f163d57e735cdb",
"repo_path": "/integration/gaia-central"
}

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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):

View File

@ -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.

View File

@ -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]);
}
}

View File

@ -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=

View File

@ -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

View File

@ -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,

View File

@ -98,6 +98,12 @@ public:
return false;
}
virtual bool KillChild()
{
// By default, does nothing.
return false;
}
protected:
bool BuildClonedMessageDataForParent(nsIContentParent* aParent,
const StructuredCloneData& aData,

View File

@ -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();

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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)) {

View File

@ -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>

View File

@ -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();">

View File

@ -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();">

View File

@ -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();">

View File

@ -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();">

View File

@ -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();">

View File

@ -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();">

View File

@ -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">

View File

@ -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";

View File

@ -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>

View File

@ -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();">

View File

@ -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

View File

@ -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

View File

@ -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() {

View File

@ -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;
},

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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';

View File

@ -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/");

View File

@ -140,6 +140,9 @@ function runTest() {
SpecialPowers.autoConfirmAppInstall(continueTest);
yield undefined;
SpecialPowers.autoConfirmAppUninstall(continueTest);
yield undefined;
setState("setVersion", 1, continueTest);
yield undefined;

View File

@ -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);
},

View File

@ -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;

View File

@ -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";

View File

@ -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;

View File

@ -190,7 +190,9 @@
// No confirmation needed when an app is installed
function() {
SpecialPowers.autoConfirmAppInstall(runTest);
SpecialPowers.autoConfirmAppInstall(() => {
SpecialPowers.autoConfirmAppUninstall(runTest);
});
},
// Installing the app

View File

@ -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;

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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;

View 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

View 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

View File

@ -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();
}
}

View File

@ -51,7 +51,7 @@ UNIFIED_SOURCES += [
'WebGLContextExtensions.cpp',
'WebGLContextFramebufferOperations.cpp',
'WebGLContextGL.cpp',
'WebGLContextLossTimer.cpp',
'WebGLContextLossHandler.cpp',
'WebGLContextReporter.cpp',
'WebGLContextState.cpp',
'WebGLContextUtils.cpp',

View File

@ -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;

View File

@ -95,7 +95,8 @@
// No confirmation needed when an app is installed
function() {
SpecialPowers.autoConfirmAppInstall(runTest);
SpecialPowers.autoConfirmAppInstall(() =>
SpecialPowers.autoConfirmAppUninstall(runTest));
},
// Installing the app

View File

@ -95,7 +95,8 @@
// No confirmation needed when an app is installed
function() {
SpecialPowers.autoConfirmAppInstall(runTest);
SpecialPowers.autoConfirmAppInstall(() =>
SpecialPowers.autoConfirmAppUninstall(runTest));
},
// Installing the app

View File

@ -95,7 +95,8 @@
// No confirmation needed when an app is installed
function() {
SpecialPowers.autoConfirmAppInstall(runTest);
SpecialPowers.autoConfirmAppInstall(() =>
SpecialPowers.autoConfirmAppUninstall(runTest));
},
// Installing the app

View File

@ -96,7 +96,8 @@
// No confirmation needed when an app is installed
function() {
SpecialPowers.autoConfirmAppInstall(runTest);
SpecialPowers.autoConfirmAppInstall(() =>
SpecialPowers.autoConfirmAppUninstall(runTest));
},
// Installing the app

View File

@ -95,7 +95,8 @@
// No confirmation needed when an app is installed
function() {
SpecialPowers.autoConfirmAppInstall(runTest);
SpecialPowers.autoConfirmAppInstall(() =>
SpecialPowers.autoConfirmAppUninstall(runTest));
},
// Installing the app

View File

@ -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
];

View File

@ -100,7 +100,8 @@
// No confirmation needed when an app is installed
function() {
SpecialPowers.autoConfirmAppInstall(runTest);
SpecialPowers.autoConfirmAppInstall(() =>
SpecialPowers.autoConfirmAppUninstall(runTest));
},
// Installing the app1

View File

@ -92,7 +92,8 @@
// No confirmation needed when an app is installed
function() {
SpecialPowers.autoConfirmAppInstall(runTest);
SpecialPowers.autoConfirmAppInstall(() =>
SpecialPowers.autoConfirmAppUninstall(runTest));
},
// Installing the app1

View File

@ -102,7 +102,8 @@
// No confirmation needed when an app is installed
function() {
SpecialPowers.autoConfirmAppInstall(runTest);
SpecialPowers.autoConfirmAppInstall(() =>
SpecialPowers.autoConfirmAppUninstall(runTest));
},
// Installing the app

View File

@ -138,7 +138,8 @@
// No confirmation needed when an app is installed
function() {
SpecialPowers.autoConfirmAppInstall(runTest);
SpecialPowers.autoConfirmAppInstall(() =>
SpecialPowers.autoConfirmAppUninstall(runTest));
},
// Installing the app1

View File

@ -95,7 +95,8 @@
// No confirmation needed when an app is installed
function() {
SpecialPowers.autoConfirmAppInstall(runTest);
SpecialPowers.autoConfirmAppInstall(() =>
SpecialPowers.autoConfirmAppUninstall(runTest));
},
// Installing the app

View File

@ -95,7 +95,8 @@
// No confirmation needed when an app is installed
function() {
SpecialPowers.autoConfirmAppInstall(runTest);
SpecialPowers.autoConfirmAppInstall(() =>
SpecialPowers.autoConfirmAppUninstall(runTest));
},
// Installing the app

View File

@ -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() {

View File

@ -96,7 +96,8 @@
// No confirmation needed when an app is installed
function() {
SpecialPowers.autoConfirmAppInstall(runTest);
SpecialPowers.autoConfirmAppInstall(() =>
SpecialPowers.autoConfirmAppUninstall(runTest));
},
// Installing the app

View File

@ -124,7 +124,8 @@
// No confirmation needed when an app is installed
function() {
SpecialPowers.autoConfirmAppInstall(runTest);
SpecialPowers.autoConfirmAppInstall(() =>
SpecialPowers.autoConfirmAppUninstall(runTest));
},
// Installing the apps

View File

@ -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;

View File

@ -94,7 +94,8 @@
// No confirmation needed when an app is installed
function() {
SpecialPowers.autoConfirmAppInstall(runTest);
SpecialPowers.autoConfirmAppInstall(() =>
SpecialPowers.autoConfirmAppUninstall(runTest));
},
// Installing the app

View File

@ -94,7 +94,8 @@
// No confirmation needed when an app is installed
function() {
SpecialPowers.autoConfirmAppInstall(runTest);
SpecialPowers.autoConfirmAppInstall(() =>
SpecialPowers.autoConfirmAppUninstall(runTest));
},
// Installing the app

View File

@ -95,7 +95,8 @@
// No confirmation needed when an app is installed
function() {
SpecialPowers.autoConfirmAppInstall(runTest);
SpecialPowers.autoConfirmAppInstall(() =>
SpecialPowers.autoConfirmAppUninstall(runTest));
},
// Installing the app

View File

@ -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();
}

View File

@ -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)

View File

@ -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);

View File

@ -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));
},

View File

@ -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!

View File

@ -183,7 +183,9 @@ function browserLoadEvent() {
addLoadEvent(() =>
SpecialPowers.pushPrefEnv({set: [['dom.mozBrowserFramesEnabled', true]]}, () =>
SpecialPowers.autoConfirmAppInstall(runTest)
SpecialPowers.autoConfirmAppInstall(() =>
SpecialPowers.autoConfirmAppUninstall(runTest)
)
)
);

View File

@ -197,7 +197,9 @@ function checks() {
addLoadEvent(() =>
SpecialPowers.pushPrefEnv({set: [['dom.mozBrowserFramesEnabled', true]]}, () =>
SpecialPowers.autoConfirmAppInstall(runTest)
SpecialPowers.autoConfirmAppInstall(() =>
SpecialPowers.autoConfirmAppUninstall(runTest)
)
)
);

View File

@ -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.

View File

@ -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);
}

View File

@ -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>

View File

@ -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();
};

View File

@ -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();

View File

@ -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.

View File

@ -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();
};

View File

@ -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();
}

View File

@ -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.

View 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;
})();

View File

@ -0,0 +1,6 @@
[DEFAULT]
b2g = true
browser = false
qemu = true
[test_wifi_tethering_enabled.js]

View File

@ -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