merge mozilla-inbound to mozilla-central a=merge
@ -1124,8 +1124,23 @@ pref("dom.mozSettings.allowForceReadOnly", false);
|
||||
// RequestSync API is enabled by default on B2G.
|
||||
pref("dom.requestSync.enabled", true);
|
||||
|
||||
// Use vsync aligned rendering
|
||||
// Only enable for kit kat and above devices
|
||||
// kit kat == 19, L = 21, 20 is kit-kat for wearables
|
||||
// 15 is for the ICS emulators which will fallback to software vsync
|
||||
#if ANDROID_VERSION == 19 || ANDROID_VERSION == 21 || ANDROID_VERSION == 15
|
||||
pref("gfx.vsync.hw-vsync.enabled", true);
|
||||
pref("gfx.vsync.compositor", true);
|
||||
pref("gfx.touch.resample", true);
|
||||
#else
|
||||
pref("gfx.vsync.hw-vsync.enabled", false);
|
||||
pref("gfx.vsync.compositor", false);
|
||||
pref("gfx.touch.resample", false);
|
||||
#endif
|
||||
|
||||
// Bug 1147753 - Weird issues with vsync refresh driver on L devices
|
||||
// so disable them on L, but enable on KK and ICS
|
||||
#if ANDROID_VERSION == 19 || ANDROID_VERSION == 15
|
||||
pref("gfx.vsync.refreshdriver", true);
|
||||
#else
|
||||
pref("gfx.vsync.refreshdriver", false);
|
||||
#endif
|
||||
|
@ -51,6 +51,7 @@ MOZ_APP_ID={3c2e2abc-06d4-11e1-ac3b-374f68613e61}
|
||||
|
||||
MOZ_TIME_MANAGER=1
|
||||
|
||||
MOZ_SIMPLEPUSH=1
|
||||
MOZ_PAY=1
|
||||
MOZ_TOOLKIT_SEARCH=
|
||||
MOZ_PLACES=
|
||||
|
@ -1017,6 +1017,7 @@ pref("urlclassifier.downloadAllowTable", "goog-downloadwhite-digest256");
|
||||
#endif
|
||||
|
||||
pref("browser.geolocation.warning.infoURL", "https://www.mozilla.org/%LOCALE%/firefox/geolocation/");
|
||||
pref("browser.push.warning.infoURL", "https://www.mozilla.org/%LOCALE%/firefox/push/");
|
||||
|
||||
pref("browser.EULA.version", 3);
|
||||
pref("browser.rights.version", 3);
|
||||
@ -1716,9 +1717,6 @@ pref("loop.contacts.gravatars.promo", true);
|
||||
pref("loop.browserSharing.showInfoBar", true);
|
||||
pref("loop.contextInConverations.enabled", false);
|
||||
|
||||
// serverURL to be assigned by services team
|
||||
pref("services.push.serverURL", "wss://push.services.mozilla.com/");
|
||||
|
||||
pref("social.sidebar.unload_timeout_ms", 10000);
|
||||
|
||||
// activation from inside of share panel is possible if activationPanelEnabled
|
||||
@ -1883,6 +1881,7 @@ pref("dom.ipc.reportProcessHangs", true);
|
||||
// Enable ReadingList browser UI by default.
|
||||
pref("browser.readinglist.enabled", true);
|
||||
pref("browser.readinglist.sidebarEverOpened", false);
|
||||
|
||||
// Enable the readinglist engine by default.
|
||||
pref("readinglist.scheduler.enabled", true);
|
||||
pref("readinglist.server", "https://readinglist.services.mozilla.com/v1");
|
||||
|
@ -780,6 +780,7 @@
|
||||
<image id="default-notification-icon" class="notification-anchor-icon" role="button"/>
|
||||
<image id="identity-notification-icon" class="notification-anchor-icon" role="button"/>
|
||||
<image id="geo-notification-icon" class="notification-anchor-icon" role="button"/>
|
||||
<image id="push-notification-icon" class="notification-anchor-icon" role="button"/>
|
||||
<image id="addons-notification-icon" class="notification-anchor-icon" role="button"/>
|
||||
<image id="indexedDB-notification-icon" class="notification-anchor-icon" role="button"/>
|
||||
<image id="password-notification-icon" class="notification-anchor-icon" role="button"/>
|
||||
|
@ -12,7 +12,7 @@ support-files =
|
||||
[browser_newtab_bug725996.js]
|
||||
[browser_newtab_bug734043.js]
|
||||
[browser_newtab_bug735987.js]
|
||||
skip-if = os == "mac" # Intermittent failures, bug 898317
|
||||
skip-if = (os == 'mac' && os_version == '10.10') # bug 1122478 - newtab drag-drop tests fail on OS X 10.10
|
||||
[browser_newtab_bug752841.js]
|
||||
[browser_newtab_bug765628.js]
|
||||
[browser_newtab_bug876313.js]
|
||||
@ -21,9 +21,9 @@ skip-if = os == "mac" # Intermittent failures, bug 898317
|
||||
[browser_newtab_bug998387.js]
|
||||
[browser_newtab_disable.js]
|
||||
[browser_newtab_drag_drop.js]
|
||||
skip-if = os == "win" && debug || (os == 'mac' && os_version == '10.10') # bug 1097056; test fails in --run-by-dir mode on win8 x64 debug; Bug 1122479 - newtab drag-drop tests fail on OS X 10.10
|
||||
skip-if = os == "win" || (os == 'mac' && os_version == '10.10') # Bug 1152810 - can't do simulateDrop(0,0) on Windows; Bug 1122478 - newtab drag-drop tests fail on OS X 10.10
|
||||
[browser_newtab_drag_drop_ext.js]
|
||||
skip-if = (os == 'mac' && os_version == '10.10') # bug 1122479 - newtab drag-drop tests fail on OS X 10.10
|
||||
skip-if = (os == 'mac' && os_version == '10.10') # bug 1122478 - newtab drag-drop tests fail on OS X 10.10
|
||||
[browser_newtab_drop_preview.js]
|
||||
[browser_newtab_enhanced.js]
|
||||
[browser_newtab_focus.js]
|
||||
|
@ -495,33 +495,81 @@ function simulateExternalDrop(aDestIndex) {
|
||||
* @param aCallback The function that is called when we're done.
|
||||
*/
|
||||
function startAndCompleteDragOperation(aSource, aDest, aCallback) {
|
||||
// Start by pressing the left mouse button.
|
||||
synthesizeNativeMouseLDown(aSource);
|
||||
// The implementation of this function varies by platform because each
|
||||
// platform has particular quirks that we need to deal with
|
||||
|
||||
// Move the mouse in 5px steps until the drag operation starts.
|
||||
let offset = 0;
|
||||
let interval = setInterval(() => {
|
||||
synthesizeNativeMouseDrag(aSource, offset += 5);
|
||||
}, 10);
|
||||
|
||||
// When the drag operation has started we'll move
|
||||
// the dragged element to its target position.
|
||||
aSource.addEventListener("dragstart", function onDragStart() {
|
||||
aSource.removeEventListener("dragstart", onDragStart);
|
||||
clearInterval(interval);
|
||||
|
||||
// Place the cursor above the drag target.
|
||||
synthesizeNativeMouseMove(aDest);
|
||||
});
|
||||
|
||||
// As soon as the dragged element hovers the target, we'll drop it.
|
||||
aDest.addEventListener("dragenter", function onDragEnter() {
|
||||
aDest.removeEventListener("dragenter", onDragEnter);
|
||||
|
||||
// Finish the drop operation.
|
||||
if (isMac) {
|
||||
// On OS X once the drag starts, Cocoa manages the drag session and
|
||||
// gives us a limited amount of time to complete the drag operation. In
|
||||
// some cases as soon as the first mouse-move event is received (the one
|
||||
// that starts the drag session), Cocoa becomes blind to subsequent mouse
|
||||
// events and completes the drag session all by itself. Therefore it is
|
||||
// important that the first mouse-move we send is already positioned at
|
||||
// the destination.
|
||||
synthesizeNativeMouseLDown(aSource);
|
||||
synthesizeNativeMouseDrag(aDest);
|
||||
// In some tests, aSource and aDest are at the same position, so to ensure
|
||||
// a drag session is created (instead of it just turning into a click) we
|
||||
// move the mouse 10 pixels away and then back.
|
||||
synthesizeNativeMouseDrag(aDest, 10);
|
||||
synthesizeNativeMouseDrag(aDest);
|
||||
// Finally, release the drag and have it run the callback when done.
|
||||
synthesizeNativeMouseLUp(aDest);
|
||||
aCallback();
|
||||
});
|
||||
} else if (isWindows) {
|
||||
// on Windows once the drag is initiated, Windows doesn't spin our
|
||||
// message loop at all, so with async event synthesization the async
|
||||
// messages never get processed while a drag is in progress. So if
|
||||
// we did a mousedown followed by a mousemove, we would never be able
|
||||
// to successfully dispatch the mouseup. Instead, we just skip the move
|
||||
// entirely, so and just generate the up at the destination. This way
|
||||
// Windows does the drag and also terminates it right away. Note that
|
||||
// this only works for tests where aSource and aDest are sufficiently
|
||||
// far to trigger a drag, otherwise it may just end up doing a click.
|
||||
synthesizeNativeMouseLDown(aSource);
|
||||
synthesizeNativeMouseLUp(aDest);
|
||||
aCallback();
|
||||
} else if (isLinux) {
|
||||
// Start by pressing the left mouse button.
|
||||
synthesizeNativeMouseLDown(aSource);
|
||||
|
||||
// Move the mouse in 5px steps until the drag operation starts.
|
||||
// Note that we need to do this with pauses in between otherwise the
|
||||
// synthesized events get coalesced somewhere in the guts of GTK. In order
|
||||
// to successfully initiate a drag session in the case where aSource and
|
||||
// aDest are at the same position, we synthesize a bunch of drags until
|
||||
// we know the drag session has started, and then move to the destination.
|
||||
let offset = 0;
|
||||
let interval = setInterval(() => {
|
||||
synthesizeNativeMouseDrag(aSource, offset += 5);
|
||||
}, 10);
|
||||
|
||||
// When the drag operation has started we'll move
|
||||
// the dragged element to its target position.
|
||||
aSource.addEventListener("dragstart", function onDragStart() {
|
||||
aSource.removeEventListener("dragstart", onDragStart);
|
||||
clearInterval(interval);
|
||||
|
||||
// Place the cursor above the drag target.
|
||||
synthesizeNativeMouseMove(aDest);
|
||||
});
|
||||
|
||||
// As soon as the dragged element hovers the target, we'll drop it.
|
||||
// Note that we need to actually wait for the dragenter event here, because
|
||||
// the mousemove synthesization is "more async" than the mouseup
|
||||
// synthesization - they use different gdk APIs. If we don't wait, the
|
||||
// up could get processed before the moves, dropping the item in the
|
||||
// wrong position.
|
||||
aDest.addEventListener("dragenter", function onDragEnter() {
|
||||
aDest.removeEventListener("dragenter", onDragEnter);
|
||||
|
||||
// Finish the drop operation.
|
||||
synthesizeNativeMouseLUp(aDest, null);
|
||||
aCallback();
|
||||
});
|
||||
} else {
|
||||
throw "Unsupported platform";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2393,6 +2393,42 @@ ContentPermissionPrompt.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_promptPush : function(aRequest) {
|
||||
var browserBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
|
||||
var requestingURI = aRequest.principal.URI;
|
||||
|
||||
var message = browserBundle.formatStringFromName("push.enablePush",
|
||||
[requestingURI.host], 1);
|
||||
|
||||
var actions = [
|
||||
{
|
||||
stringId: "push.alwaysAllow",
|
||||
action: Ci.nsIPermissionManager.ALLOW_ACTION,
|
||||
expireType: null,
|
||||
callback: function() {}
|
||||
},
|
||||
{
|
||||
stringId: "push.allowForSession",
|
||||
action: Ci.nsIPermissionManager.ALLOW_ACTION,
|
||||
expireType: Ci.nsIPermissionManager.EXPIRE_SESSION,
|
||||
callback: function() {}
|
||||
},
|
||||
{
|
||||
stringId: "push.alwaysBlock",
|
||||
action: Ci.nsIPermissionManager.DENY_ACTION,
|
||||
expireType: null,
|
||||
callback: function() {}
|
||||
}]
|
||||
|
||||
var options = {
|
||||
learnMoreURL: Services.urlFormatter.formatURLPref("browser.push.warning.infoURL"),
|
||||
};
|
||||
|
||||
this._showPrompt(aRequest, message, "push", actions, "push",
|
||||
"push-notification-icon", options);
|
||||
|
||||
},
|
||||
|
||||
_promptGeo : function(aRequest) {
|
||||
var secHistogram = Services.telemetry.getHistogramById("SECURITY_UI");
|
||||
var requestingURI = aRequest.principal.URI;
|
||||
@ -2517,7 +2553,6 @@ ContentPermissionPrompt.prototype = {
|
||||
},
|
||||
|
||||
prompt: function CPP_prompt(request) {
|
||||
|
||||
// Only allow exactly one permission rquest here.
|
||||
let types = request.types.QueryInterface(Ci.nsIArray);
|
||||
if (types.length != 1) {
|
||||
@ -2529,6 +2564,7 @@ ContentPermissionPrompt.prototype = {
|
||||
const kFeatureKeys = { "geolocation" : "geo",
|
||||
"desktop-notification" : "desktop-notification",
|
||||
"pointerLock" : "pointerLock",
|
||||
"push" : "push"
|
||||
};
|
||||
|
||||
// Make sure that we support the request.
|
||||
@ -2579,6 +2615,9 @@ ContentPermissionPrompt.prototype = {
|
||||
case "pointerLock":
|
||||
this._promptPointerLock(request, autoAllow);
|
||||
break;
|
||||
case "push":
|
||||
this._promptPush(request);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -336,7 +336,16 @@ let PermissionDefaults = {
|
||||
let value = (aValue != this.DENY);
|
||||
Services.prefs.setBoolPref("full-screen-api.enabled", value);
|
||||
},
|
||||
|
||||
get push() {
|
||||
if (!Services.prefs.getBoolPref("dom.push.enabled")) {
|
||||
return this.DENY;
|
||||
}
|
||||
return this.UNKNOWN;
|
||||
},
|
||||
set push(aValue) {
|
||||
let value = (aValue != this.DENY);
|
||||
Services.prefs.setBoolPref("dom.push.enabled", value);
|
||||
},
|
||||
get camera() this.UNKNOWN,
|
||||
get microphone() this.UNKNOWN
|
||||
};
|
||||
@ -378,12 +387,12 @@ let AboutPermissions = {
|
||||
* Potential future additions: "sts/use", "sts/subd"
|
||||
*/
|
||||
_supportedPermissions: ["password", "cookie", "geo", "indexedDB", "popup",
|
||||
"fullscreen", "camera", "microphone"],
|
||||
"fullscreen", "camera", "microphone", "push"],
|
||||
|
||||
/**
|
||||
* Permissions that don't have a global "Allow" option.
|
||||
*/
|
||||
_noGlobalAllow: ["geo", "indexedDB", "fullscreen", "camera", "microphone"],
|
||||
_noGlobalAllow: ["geo", "indexedDB", "fullscreen", "camera", "microphone", "push"],
|
||||
|
||||
/**
|
||||
* Permissions that don't have a global "Deny" option.
|
||||
@ -408,9 +417,11 @@ let AboutPermissions = {
|
||||
Services.prefs.addObserver("signon.rememberSignons", this, false);
|
||||
Services.prefs.addObserver("network.cookie.", this, false);
|
||||
Services.prefs.addObserver("geo.enabled", this, false);
|
||||
Services.prefs.addObserver("dom.push.enabled", this, false);
|
||||
Services.prefs.addObserver("dom.indexedDB.enabled", this, false);
|
||||
Services.prefs.addObserver("dom.disable_open_during_load", this, false);
|
||||
Services.prefs.addObserver("full-screen-api.enabled", this, false);
|
||||
Services.prefs.addObserver("dom.push.enabled", this, false);
|
||||
|
||||
Services.obs.addObserver(this, "perm-changed", false);
|
||||
Services.obs.addObserver(this, "passwordmgr-storage-changed", false);
|
||||
@ -429,9 +440,11 @@ let AboutPermissions = {
|
||||
Services.prefs.removeObserver("signon.rememberSignons", this, false);
|
||||
Services.prefs.removeObserver("network.cookie.", this, false);
|
||||
Services.prefs.removeObserver("geo.enabled", this, false);
|
||||
Services.prefs.removeObserver("dom.push.enabled", this, false);
|
||||
Services.prefs.removeObserver("dom.indexedDB.enabled", this, false);
|
||||
Services.prefs.removeObserver("dom.disable_open_during_load", this, false);
|
||||
Services.prefs.removeObserver("full-screen-api.enabled", this, false);
|
||||
Services.prefs.removeObserver("dom.push.enabled", this, false);
|
||||
|
||||
Services.obs.removeObserver(this, "perm-changed");
|
||||
Services.obs.removeObserver(this, "passwordmgr-storage-changed");
|
||||
|
@ -252,8 +252,28 @@
|
||||
</menulist>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
||||
</hbox>
|
||||
|
||||
<!-- Push Notifications -->
|
||||
<hbox id="push-pref-item"
|
||||
class="pref-item" align="top">
|
||||
<image class="pref-icon" type="push"/>
|
||||
<vbox>
|
||||
<label class="pref-title" value="&push.label;"/>
|
||||
<hbox align="center">
|
||||
<menulist id="push-menulist"
|
||||
class="pref-menulist"
|
||||
type="push"
|
||||
oncommand="AboutPermissions.onPermissionCommand(event);">
|
||||
<menupopup>
|
||||
<menuitem id="push-0" value="0" label="&permission.alwaysAsk;"/>
|
||||
<menuitem id="push-1" value="1" label="&permission.allow;"/>
|
||||
<menuitem id="push-2" value="2" label="&permission.block;"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
||||
|
@ -23,6 +23,7 @@ const TEST_PERMS = {
|
||||
"password": PERM_ALLOW,
|
||||
"cookie": PERM_ALLOW,
|
||||
"geo": PERM_UNKNOWN,
|
||||
"push": PERM_DENY,
|
||||
"indexedDB": PERM_UNKNOWN,
|
||||
"popup": PERM_DENY,
|
||||
"fullscreen" : PERM_UNKNOWN,
|
||||
@ -37,7 +38,7 @@ const NO_GLOBAL_ALLOW = [
|
||||
];
|
||||
|
||||
// number of managed permissions in the interface
|
||||
const TEST_PERMS_COUNT = 8;
|
||||
const TEST_PERMS_COUNT = 9;
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
@ -366,6 +366,15 @@ webNotifications.neverShow=Always Block Notifications
|
||||
webNotifications.neverShow.accesskey=N
|
||||
webNotifications.showFromSite=Would you like to show notifications from %S?
|
||||
|
||||
# Push Notifications
|
||||
push.allowForSession=Allow for Session
|
||||
push.allowForSession.accesskey=S
|
||||
push.alwaysAllow=Always Allow Push Notifications
|
||||
push.alwaysAllow.accesskey=A
|
||||
push.alwaysBlock=Always Block Push Notifications
|
||||
push.alwaysBlock.accesskey=B
|
||||
push.enablePush=Would you like to allow Push Notifications for %S?
|
||||
|
||||
# Pointer lock UI
|
||||
|
||||
pointerLock.allow2=Hide pointer
|
||||
|
@ -42,5 +42,7 @@
|
||||
<!ENTITY popup.label "Open Pop-up Windows">
|
||||
|
||||
<!ENTITY fullscreen.label "Fullscreen">
|
||||
|
||||
<!ENTITY push.label "Receive Push Notifications">
|
||||
<!ENTITY camera.label "Use the Camera">
|
||||
<!ENTITY microphone.label "Use the Microphone">
|
||||
|
@ -18,4 +18,4 @@ permission.geo.label = Access Your Location
|
||||
permission.indexedDB.label = Maintain Offline Storage
|
||||
permission.fullscreen.label = Enter Fullscreen
|
||||
permission.pointerLock.label = Hide the Mouse Pointer
|
||||
|
||||
permission.push.label = Receive Push Notifications
|
||||
|
@ -190,5 +190,9 @@ let gPermissionObject = {
|
||||
|
||||
"pointerLock": {
|
||||
exactHostMatch: true
|
||||
},
|
||||
|
||||
"push": {
|
||||
exactHostMatch: true
|
||||
}
|
||||
};
|
||||
|
BIN
browser/themes/linux/Push-16.png
Normal file
After Width: | Height: | Size: 606 B |
BIN
browser/themes/linux/Push-64.png
Normal file
After Width: | Height: | Size: 7.9 KiB |
@ -33,6 +33,8 @@ browser.jar:
|
||||
skin/classic/browser/fullscreen-darknoise.png
|
||||
skin/classic/browser/Geolocation-16.png
|
||||
skin/classic/browser/Geolocation-64.png
|
||||
skin/classic/browser/Push-16.png
|
||||
skin/classic/browser/Push-64.png
|
||||
skin/classic/browser/heartbeat-icon.svg (../shared/heartbeat-icon.svg)
|
||||
skin/classic/browser/heartbeat-star-lit.svg (../shared/heartbeat-star-lit.svg)
|
||||
skin/classic/browser/heartbeat-star-off.svg (../shared/heartbeat-star-off.svg)
|
||||
|
@ -79,6 +79,9 @@
|
||||
.pref-icon[type="geo"] {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-64.png);
|
||||
}
|
||||
.pref-icon[type="push"] {
|
||||
list-style-image: url(chrome://browser/skin/Push-64.png);
|
||||
}
|
||||
.pref-icon[type="indexedDB"] {
|
||||
list-style-image: url(chrome://global/skin/icons/question-64.png);
|
||||
}
|
||||
|
BIN
browser/themes/osx/Push-16.png
Normal file
After Width: | Height: | Size: 312 B |
BIN
browser/themes/osx/Push-16@2x.png
Normal file
After Width: | Height: | Size: 666 B |
BIN
browser/themes/osx/Push-64.png
Normal file
After Width: | Height: | Size: 8.3 KiB |
BIN
browser/themes/osx/Push-64@2x.png
Normal file
After Width: | Height: | Size: 26 KiB |
@ -35,6 +35,10 @@ browser.jar:
|
||||
skin/classic/browser/Geolocation-16@2x.png
|
||||
skin/classic/browser/Geolocation-64.png
|
||||
skin/classic/browser/Geolocation-64@2x.png
|
||||
skin/classic/browser/Push-16.png
|
||||
skin/classic/browser/Push-16@2x.png
|
||||
skin/classic/browser/Push-64.png
|
||||
skin/classic/browser/Push-64@2x.png
|
||||
skin/classic/browser/heartbeat-icon.svg (../shared/heartbeat-icon.svg)
|
||||
skin/classic/browser/heartbeat-star-lit.svg (../shared/heartbeat-star-lit.svg)
|
||||
skin/classic/browser/heartbeat-star-off.svg (../shared/heartbeat-star-off.svg)
|
||||
|
@ -89,6 +89,9 @@
|
||||
.pref-icon[type="geo"] {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-64.png);
|
||||
}
|
||||
.pref-icon[type="push"] {
|
||||
list-style-image: url(chrome://browser/skin/Push-64.png);
|
||||
}
|
||||
.pref-icon[type="indexedDB"] {
|
||||
list-style-image: url(chrome://global/skin/icons/question-64.png);
|
||||
}
|
||||
|
@ -14,6 +14,10 @@
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="push"] {
|
||||
list-style-image: url(chrome://browser/skin/Push-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="xpinstall-disabled"],
|
||||
.popup-notification-icon[popupid="addon-progress"],
|
||||
.popup-notification-icon[popupid="addon-install-blocked"],
|
||||
@ -119,6 +123,10 @@
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-16.png);
|
||||
}
|
||||
|
||||
#push-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/Push-16.png);
|
||||
}
|
||||
|
||||
#addons-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
|
||||
}
|
||||
@ -290,6 +298,10 @@
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-16@2x.png);
|
||||
}
|
||||
|
||||
#push-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/Push-16@2x.png);
|
||||
}
|
||||
|
||||
.indexedDB-notification-icon,
|
||||
#indexedDB-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/question-32.png);
|
||||
@ -396,6 +408,10 @@
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-64@2x.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="push"] {
|
||||
list-style-image: url(chrome://browser/skin/Push-64@2x.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="web-notifications"] {
|
||||
list-style-image: url(chrome://browser/skin/notification-64@2x.png);
|
||||
}
|
||||
|
BIN
browser/themes/windows/Push-16.png
Normal file
After Width: | Height: | Size: 704 B |
BIN
browser/themes/windows/Push-64.png
Normal file
After Width: | Height: | Size: 8.2 KiB |
@ -32,6 +32,8 @@ browser.jar:
|
||||
skin/classic/browser/fullscreen-darknoise.png
|
||||
skin/classic/browser/Geolocation-16.png
|
||||
skin/classic/browser/Geolocation-64.png
|
||||
skin/classic/browser/Push-16.png
|
||||
skin/classic/browser/Push-64.png
|
||||
skin/classic/browser/heartbeat-icon.svg (../shared/heartbeat-icon.svg)
|
||||
skin/classic/browser/heartbeat-star-lit.svg (../shared/heartbeat-star-lit.svg)
|
||||
skin/classic/browser/heartbeat-star-off.svg (../shared/heartbeat-star-off.svg)
|
||||
|
@ -82,6 +82,9 @@
|
||||
.pref-icon[type="geo"] {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-64.png);
|
||||
}
|
||||
.pref-icon[type="push"] {
|
||||
list-style-image: url(chrome://browser/skin/Push-64.png);
|
||||
}
|
||||
.pref-icon[type="indexedDB"] {
|
||||
list-style-image: url(chrome://global/skin/icons/question-64.png);
|
||||
}
|
||||
|
10
configure.in
@ -3942,6 +3942,7 @@ MOZ_ANDROID_MLS_STUMBLER=
|
||||
MOZ_ANDROID_SHARE_OVERLAY=
|
||||
ACCESSIBILITY=1
|
||||
MOZ_TIME_MANAGER=
|
||||
MOZ_SIMPLEPUSH=
|
||||
MOZ_PAY=
|
||||
MOZ_AUDIO_CHANNEL_MANAGER=
|
||||
NSS_NO_LIBPKIX=
|
||||
@ -7525,6 +7526,15 @@ if test -n "$MOZ_B2G_CAMERA"; then
|
||||
fi
|
||||
AC_SUBST(MOZ_B2G_CAMERA)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Enable Support for SimplePush (Gonk usually)
|
||||
dnl This will disable the Push API.
|
||||
dnl ========================================================
|
||||
if test -n "$MOZ_SIMPLEPUSH"; then
|
||||
AC_DEFINE(MOZ_SIMPLEPUSH)
|
||||
fi
|
||||
AC_SUBST(MOZ_SIMPLEPUSH)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Enable Support for Payment API
|
||||
dnl ========================================================
|
||||
|
@ -200,8 +200,6 @@
|
||||
#include "nsIBrowserSearchService.h"
|
||||
#endif
|
||||
|
||||
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
|
||||
|
||||
#if defined(DEBUG_bryner) || defined(DEBUG_chb)
|
||||
//#define DEBUG_DOCSHELL_FOCUS
|
||||
#define DEBUG_PAGE_CACHE
|
||||
@ -222,9 +220,6 @@ static bool gAddedPreferencesVarCache = false;
|
||||
|
||||
bool nsDocShell::sUseErrorPages = false;
|
||||
|
||||
// Number of documents currently loading
|
||||
static int32_t gNumberOfDocumentsLoading = 0;
|
||||
|
||||
// Global count of existing docshells.
|
||||
static int32_t gDocShellCount = 0;
|
||||
|
||||
@ -255,18 +250,6 @@ static PRLogModuleInfo* gDocShellLeakLog;
|
||||
const char kBrandBundleURL[] = "chrome://branding/locale/brand.properties";
|
||||
const char kAppstringsBundleURL[] = "chrome://global/locale/appstrings.properties";
|
||||
|
||||
static void
|
||||
FavorPerformanceHint(bool aPerfOverStarvation)
|
||||
{
|
||||
nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
|
||||
if (appShell) {
|
||||
appShell->FavorPerformanceHint(
|
||||
aPerfOverStarvation,
|
||||
Preferences::GetUint("docshell.event_starvation_delay_hint",
|
||||
NS_EVENT_STARVATION_DELAY_HINT));
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// <a ping> support
|
||||
//*****************************************************************************
|
||||
@ -7541,14 +7524,6 @@ nsDocShell::EndPageLoad(nsIWebProgress* aProgress,
|
||||
mIsExecutingOnLoadHandler = false;
|
||||
|
||||
mEODForCurrentDocument = true;
|
||||
|
||||
// If all documents have completed their loading
|
||||
// favor native event dispatch priorities
|
||||
// over performance
|
||||
if (--gNumberOfDocumentsLoading == 0) {
|
||||
// Hint to use normal native event dispatch priorities
|
||||
FavorPerformanceHint(false);
|
||||
}
|
||||
}
|
||||
/* Check if the httpChannel has any cache-control related response headers,
|
||||
* like no-store, no-cache. If so, update SHEntry so that
|
||||
@ -8678,12 +8653,6 @@ nsDocShell::RestoreFromHistory()
|
||||
mSavingOldViewer = false;
|
||||
mEODForCurrentDocument = false;
|
||||
|
||||
// Tell the event loop to favor plevents over user events, see comments
|
||||
// in CreateContentViewer.
|
||||
if (++gNumberOfDocumentsLoading == 1) {
|
||||
FavorPerformanceHint(true);
|
||||
}
|
||||
|
||||
if (oldCv && newCv) {
|
||||
newCv->SetMinFontSize(minFontSize);
|
||||
newCv->SetTextZoom(textZoom);
|
||||
@ -9096,16 +9065,6 @@ nsDocShell::CreateContentViewer(const nsACString& aContentType,
|
||||
}
|
||||
}
|
||||
|
||||
// Give hint to native plevent dispatch mechanism. If a document
|
||||
// is loading the native plevent dispatch mechanism should favor
|
||||
// performance over normal native event dispatch priorities.
|
||||
if (++gNumberOfDocumentsLoading == 1) {
|
||||
// Hint to favor performance for the plevent notification mechanism.
|
||||
// We want the pages to load as fast as possible even if its means
|
||||
// native messages might be starved.
|
||||
FavorPerformanceHint(true);
|
||||
}
|
||||
|
||||
if (onLocationChangeNeeded) {
|
||||
FireOnLocationChange(this, aRequest, mCurrentURI, 0);
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ public:
|
||||
void Notify(const hal::SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo) override;
|
||||
|
||||
// Implementing hal::SystemClockChangeObserver
|
||||
void Notify(const int64_t& aClockDeltaMS);
|
||||
void Notify(const int64_t& aClockDeltaMS) override;
|
||||
|
||||
private:
|
||||
virtual ~AlarmHalService();
|
||||
|
@ -201,7 +201,6 @@ nsContentSink::Init(nsIDocument* aDoc,
|
||||
|
||||
if (sEnablePerfMode != 0) {
|
||||
mDynamicLowerValue = sEnablePerfMode == 1;
|
||||
FavorPerformanceHint(!mDynamicLowerValue, 0);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -1408,15 +1407,6 @@ nsContentSink::DidProcessATokenImpl()
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void
|
||||
nsContentSink::FavorPerformanceHint(bool perfOverStarvation, uint32_t starvationDelay)
|
||||
{
|
||||
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
|
||||
nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
|
||||
if (appShell)
|
||||
appShell->FavorPerformanceHint(perfOverStarvation, starvationDelay);
|
||||
}
|
||||
|
||||
void
|
||||
nsContentSink::BeginUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
|
||||
{
|
||||
@ -1494,12 +1484,6 @@ nsContentSink::DropParserAndPerfHint(void)
|
||||
// reference.
|
||||
nsRefPtr<nsParserBase> kungFuDeathGrip(mParser.forget());
|
||||
|
||||
if (mDynamicLowerValue) {
|
||||
// Reset the performance hint which was set to FALSE
|
||||
// when mDynamicLowerValue was set.
|
||||
FavorPerformanceHint(true, 0);
|
||||
}
|
||||
|
||||
if (!mRunsToCompletion) {
|
||||
mDocument->UnblockOnload(true);
|
||||
}
|
||||
@ -1537,7 +1521,6 @@ nsContentSink::WillParseImpl(void)
|
||||
(currentTime - lastEventTime) < uint32_t(sInteractiveTime));
|
||||
|
||||
if (mDynamicLowerValue != newDynLower) {
|
||||
FavorPerformanceHint(!newDynLower, 0);
|
||||
mDynamicLowerValue = newDynLower;
|
||||
}
|
||||
}
|
||||
|
@ -239,8 +239,6 @@ public:
|
||||
static void NotifyDocElementCreated(nsIDocument* aDoc);
|
||||
|
||||
protected:
|
||||
void
|
||||
FavorPerformanceHint(bool perfOverStarvation, uint32_t starvationDelay);
|
||||
|
||||
inline int32_t GetNotificationInterval()
|
||||
{
|
||||
|
@ -973,6 +973,18 @@ nsFrameLoader::SwapWithOtherRemoteLoader(nsFrameLoader* aOther,
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIBrowserDOMWindow> otherBrowserDOMWindow =
|
||||
aOther->mRemoteBrowser->GetBrowserDOMWindow();
|
||||
nsCOMPtr<nsIBrowserDOMWindow> browserDOMWindow =
|
||||
mRemoteBrowser->GetBrowserDOMWindow();
|
||||
|
||||
if (!otherBrowserDOMWindow || !browserDOMWindow) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
aOther->mRemoteBrowser->SetBrowserDOMWindow(browserDOMWindow);
|
||||
mRemoteBrowser->SetBrowserDOMWindow(otherBrowserDOMWindow);
|
||||
|
||||
// Native plugin windows used by this remote content need to be reparented.
|
||||
const nsTArray<mozilla::plugins::PPluginWidgetParent*>& plugins =
|
||||
aOther->mRemoteBrowser->ManagedPPluginWidgetParent();
|
||||
|
@ -922,6 +922,18 @@ DOMInterfaces = {
|
||||
'headerFile': 'HTMLPropertiesCollection.h',
|
||||
},
|
||||
|
||||
'PushEvent': {
|
||||
'headerFile': 'ServiceWorkerEvents.h',
|
||||
'nativeType': 'mozilla::dom::workers::PushEvent',
|
||||
'workers': True
|
||||
},
|
||||
|
||||
'PushMessageData': {
|
||||
'headerFile': 'ServiceWorkerEvents.h',
|
||||
'nativeType': 'mozilla::dom::workers::PushMessageData',
|
||||
'workers': True
|
||||
},
|
||||
|
||||
'Range': {
|
||||
'nativeType': 'nsRange',
|
||||
'binaryNames': {
|
||||
|
@ -111,6 +111,10 @@ if CONFIG['MOZ_BUILD_APP'] in ['browser', 'mobile/android', 'xulrunner']:
|
||||
# This is needed for Window.webidl
|
||||
DEFINES['HAVE_SIDEBAR'] = True
|
||||
|
||||
|
||||
if CONFIG['MOZ_SIMPLEPUSH']:
|
||||
DEFINES['MOZ_SIMPLEPUSH'] = True
|
||||
|
||||
PYTHON_UNIT_TESTS += [
|
||||
'mozwebidlcodegen/test/test_mozwebidlcodegen.py',
|
||||
]
|
||||
|
8
dom/cache/test/mochitest/vary.sjs
vendored
@ -1,5 +1,9 @@
|
||||
function handleRequest(request, response) {
|
||||
response.setStatusLine(request.httpVersion, 200, "OK");
|
||||
response.setHeader("Vary", request.getHeader("WhatToVary"));
|
||||
response.write(request.getHeader("WhatToVary"));
|
||||
var header = "no WhatToVary header";
|
||||
if (request.hasHeader("WhatToVary")) {
|
||||
header = request.getHeader("WhatToVary");
|
||||
response.setHeader("Vary", header);
|
||||
}
|
||||
response.write(header);
|
||||
}
|
||||
|
@ -6587,6 +6587,9 @@ private:
|
||||
|
||||
virtual void
|
||||
SendResults() override;
|
||||
|
||||
virtual void
|
||||
ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
};
|
||||
|
||||
class OpenDatabaseOp::VersionChangeOp final
|
||||
@ -17660,6 +17663,18 @@ OpenDatabaseOp::SendResults()
|
||||
FinishSendResults();
|
||||
}
|
||||
|
||||
void
|
||||
OpenDatabaseOp::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
NoteActorDestroyed();
|
||||
|
||||
if (mDatabase && aWhy != Deletion) {
|
||||
mDatabase->Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
OpenDatabaseOp::ConnectionClosedCallback()
|
||||
{
|
||||
|
@ -33,7 +33,7 @@ interface nsIServiceWorkerInfo : nsISupports
|
||||
readonly attribute DOMString waitingCacheName;
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(861b55e9-d6ac-47cf-a528-8590e9b44de6)]
|
||||
[scriptable, builtinclass, uuid(3cd3acce-8c80-4fcc-9265-067ebe8cab92)]
|
||||
interface nsIServiceWorkerManager : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -121,6 +121,9 @@ interface nsIServiceWorkerManager : nsISupports
|
||||
// This is meant to be used only by about:serviceworkers. It returns an array
|
||||
// of nsIServiceWorkerInfo.
|
||||
nsIArray getAllRegistrations();
|
||||
|
||||
void sendPushEvent(in ACString scope, in DOMString data);
|
||||
void sendPushSubscriptionChangedEvent(in ACString scope);
|
||||
};
|
||||
|
||||
%{ C++
|
||||
|
@ -179,6 +179,7 @@
|
||||
#include "mozilla/dom/time/DateCacheCleaner.h"
|
||||
#include "mozilla/dom/voicemail/VoicemailIPCService.h"
|
||||
#include "mozilla/net/NeckoMessageUtils.h"
|
||||
#include "mozilla/widget/PuppetBidiKeyboard.h"
|
||||
#include "mozilla/RemoteSpellCheckEngineChild.h"
|
||||
#include "GMPServiceChild.h"
|
||||
|
||||
@ -200,6 +201,7 @@ using namespace mozilla::ipc;
|
||||
using namespace mozilla::layers;
|
||||
using namespace mozilla::net;
|
||||
using namespace mozilla::jsipc;
|
||||
using namespace mozilla::widget;
|
||||
#if defined(MOZ_WIDGET_GONK)
|
||||
using namespace mozilla::system;
|
||||
#endif
|
||||
@ -793,12 +795,14 @@ ContentChild::InitXPCOM()
|
||||
if (NS_FAILED(svc->RegisterListener(mConsoleListener)))
|
||||
NS_WARNING("Couldn't register console listener for child process");
|
||||
|
||||
bool isOffline;
|
||||
bool isOffline, isLangRTL;
|
||||
ClipboardCapabilities clipboardCaps;
|
||||
DomainPolicyClone domainPolicy;
|
||||
|
||||
SendGetXPCOMProcessAttributes(&isOffline, &mAvailableDictionaries, &clipboardCaps, &domainPolicy);
|
||||
SendGetXPCOMProcessAttributes(&isOffline, &isLangRTL, &mAvailableDictionaries,
|
||||
&clipboardCaps, &domainPolicy);
|
||||
RecvSetOffline(isOffline);
|
||||
RecvBidiKeyboardNotify(isLangRTL);
|
||||
|
||||
if (domainPolicy.active()) {
|
||||
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
|
||||
@ -1222,6 +1226,18 @@ ContentChild::RecvSpeakerManagerNotify()
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::RecvBidiKeyboardNotify(const bool& aIsLangRTL)
|
||||
{
|
||||
// bidi is always of type PuppetBidiKeyboard* (because in the child, the only
|
||||
// possible implementation of nsIBidiKeyboard is PuppetBidiKeyboard).
|
||||
PuppetBidiKeyboard* bidi = static_cast<PuppetBidiKeyboard*>(nsContentUtils::GetBidiKeyboard());
|
||||
if (bidi) {
|
||||
bidi->SetIsLangRTL(aIsLangRTL);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static CancelableTask* sFirstIdleTask;
|
||||
|
||||
static void FirstIdle(void)
|
||||
@ -2897,6 +2913,9 @@ NS_EXPORT void
|
||||
AfterNuwaFork()
|
||||
{
|
||||
SetCurrentProcessPrivileges(base::PRIVILEGES_DEFAULT);
|
||||
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
|
||||
mozilla::SandboxEarlyInit(XRE_GetProcessType(), /* isNuwa: */ false);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // MOZ_NUWA_PROCESS
|
||||
|
@ -299,6 +299,8 @@ public:
|
||||
|
||||
virtual bool RecvSpeakerManagerNotify() override;
|
||||
|
||||
virtual bool RecvBidiKeyboardNotify(const bool& isLangRTL) override;
|
||||
|
||||
virtual bool RecvNotifyVisited(const URIParams& aURI) override;
|
||||
// auto remove when alertfinished is received.
|
||||
nsresult AddRemoteAlertObserver(const nsString& aData, nsIObserver* aObserver);
|
||||
|
@ -151,6 +151,8 @@
|
||||
#include "private/pprio.h"
|
||||
#include "ContentProcessManager.h"
|
||||
|
||||
#include "nsIBidiKeyboard.h"
|
||||
|
||||
#if defined(ANDROID) || defined(LINUX)
|
||||
#include "nsSystemInfo.h"
|
||||
#endif
|
||||
@ -2817,11 +2819,11 @@ ContentParent::RecvAddNewProcess(const uint32_t& aPid,
|
||||
}
|
||||
|
||||
// Update offline settings.
|
||||
bool isOffline;
|
||||
bool isOffline, isLangRTL;
|
||||
InfallibleTArray<nsString> unusedDictionaries;
|
||||
ClipboardCapabilities clipboardCaps;
|
||||
DomainPolicyClone domainPolicy;
|
||||
RecvGetXPCOMProcessAttributes(&isOffline, &unusedDictionaries,
|
||||
RecvGetXPCOMProcessAttributes(&isOffline, &isLangRTL, &unusedDictionaries,
|
||||
&clipboardCaps, &domainPolicy);
|
||||
mozilla::unused << content->SendSetOffline(isOffline);
|
||||
MOZ_ASSERT(!clipboardCaps.supportsSelectionClipboard() &&
|
||||
@ -3164,6 +3166,7 @@ ContentParent::RecvGetProcessAttributes(ContentParentId* aCpId,
|
||||
|
||||
bool
|
||||
ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline,
|
||||
bool* aIsLangRTL,
|
||||
InfallibleTArray<nsString>* dictionaries,
|
||||
ClipboardCapabilities* clipboardCaps,
|
||||
DomainPolicyClone* domainPolicy)
|
||||
@ -3173,6 +3176,13 @@ ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline,
|
||||
DebugOnly<nsresult> rv = io->GetOffline(aIsOffline);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting offline?");
|
||||
|
||||
nsIBidiKeyboard* bidi = nsContentUtils::GetBidiKeyboard();
|
||||
|
||||
*aIsLangRTL = false;
|
||||
if (bidi) {
|
||||
bidi->IsLangRTL(aIsLangRTL);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISpellChecker> spellChecker(do_GetService(NS_SPELLCHECKER_CONTRACTID));
|
||||
MOZ_ASSERT(spellChecker, "No spell checker?");
|
||||
|
||||
|
@ -535,6 +535,7 @@ private:
|
||||
bool* aIsForApp,
|
||||
bool* aIsForBrowser) override;
|
||||
virtual bool RecvGetXPCOMProcessAttributes(bool* aIsOffline,
|
||||
bool* aIsLangRTL,
|
||||
InfallibleTArray<nsString>* dictionaries,
|
||||
ClipboardCapabilities* clipboardCaps,
|
||||
DomainPolicyClone* domainPolicy)
|
||||
|
@ -456,6 +456,12 @@ child:
|
||||
|
||||
async SpeakerManagerNotify();
|
||||
|
||||
/**
|
||||
* Communication between the PuppetBidiKeyboard and the actual
|
||||
* BidiKeyboard hosted by the parent
|
||||
*/
|
||||
async BidiKeyboardNotify(bool isLangRTL);
|
||||
|
||||
async DataStoreNotify(uint32_t aAppId, nsString aName,
|
||||
nsString aManifestURL);
|
||||
|
||||
@ -616,7 +622,7 @@ parent:
|
||||
sync GetProcessAttributes()
|
||||
returns (ContentParentId cpId, bool isForApp, bool isForBrowser);
|
||||
sync GetXPCOMProcessAttributes()
|
||||
returns (bool isOffline, nsString[] dictionaries,
|
||||
returns (bool isOffline, bool isLangRTL, nsString[] dictionaries,
|
||||
ClipboardCapabilities clipboardCaps,
|
||||
DomainPolicyClone domainPolicy);
|
||||
|
||||
|
@ -9,5 +9,6 @@ toolkit.jar:
|
||||
content/global/BrowserElementChildPreload.js (../browser-element/BrowserElementChildPreload.js)
|
||||
content/global/BrowserElementPanning.js (../browser-element/BrowserElementPanning.js)
|
||||
* content/global/BrowserElementPanningAPZDisabled.js (../browser-element/BrowserElementPanningAPZDisabled.js)
|
||||
content/global/PushServiceChildPreload.js (../push/PushServiceChildPreload.js)
|
||||
content/global/preload.js (preload.js)
|
||||
content/global/post-fork-preload.js (post-fork-preload.js)
|
||||
|
@ -164,7 +164,6 @@ struct AudioChunk {
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A list of audio samples consisting of a sequence of slices of SharedBuffers.
|
||||
* The audio rate is determined by the track, not stored in this class.
|
||||
@ -207,17 +206,18 @@ public:
|
||||
"Dropping samples");
|
||||
uint32_t outSize = (c.mDuration * aOutRate + aInRate - 1) / aInRate;
|
||||
for (uint32_t i = 0; i < channels; i++) {
|
||||
const T* in = static_cast<const T*>(c.mChannelData[i]);
|
||||
T* out = output[i].AppendElements(outSize);
|
||||
uint32_t outFrames = outSize;
|
||||
|
||||
#if !defined(MOZILLA_XPCOMRT_API)
|
||||
// FIXME Bug 1126414 - XPCOMRT does not support dom::WebAudioUtils::SpeexResamplerProcess
|
||||
const T* in = static_cast<const T*>(c.mChannelData[i]);
|
||||
dom::WebAudioUtils::SpeexResamplerProcess(aResampler, i,
|
||||
in, &inFrames,
|
||||
out, &outFrames);
|
||||
MOZ_ASSERT(inFrames == c.mDuration);
|
||||
#endif // !defined(MOZILLA_XPCOMRT_API)
|
||||
|
||||
bufferPtrs[i] = out;
|
||||
output[i].SetLength(outFrames);
|
||||
}
|
||||
|
@ -157,7 +157,6 @@ MP4Reader::MP4Reader(AbstractMediaDecoder* aDecoder)
|
||||
, mDemuxerInitialized(false)
|
||||
, mFoundSPSForTelemetry(false)
|
||||
, mIsEncrypted(false)
|
||||
, mAreDecodersSetup(false)
|
||||
, mIndexReady(false)
|
||||
, mLastSeenEnd(-1)
|
||||
, mDemuxerMonitor("MP4 Demuxer")
|
||||
@ -294,12 +293,6 @@ private:
|
||||
};
|
||||
#endif // MOZ_EME
|
||||
|
||||
void MP4Reader::RequestCodecResource() {
|
||||
if (mVideo.mDecoder) {
|
||||
mVideo.mDecoder->AllocateMediaResources();
|
||||
}
|
||||
}
|
||||
|
||||
bool MP4Reader::IsWaitingMediaResources() {
|
||||
return mVideo.mDecoder && mVideo.mDecoder->IsWaitingMediaResources();
|
||||
}
|
||||
@ -357,14 +350,6 @@ MP4Reader::IsSupportedVideoMimeType(const nsACString& aMimeType)
|
||||
mPlatform->SupportsMimeType(aMimeType);
|
||||
}
|
||||
|
||||
void
|
||||
MP4Reader::PreReadMetadata()
|
||||
{
|
||||
if (mPlatform) {
|
||||
RequestCodecResource();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MP4Reader::InitDemuxer()
|
||||
{
|
||||
@ -408,7 +393,6 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
|
||||
} else if (mPlatform && !IsWaitingMediaResources()) {
|
||||
*aInfo = mInfo;
|
||||
*aTags = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (HasAudio()) {
|
||||
@ -461,7 +445,7 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
|
||||
*aInfo = mInfo;
|
||||
*aTags = nullptr;
|
||||
|
||||
if (!IsWaitingMediaResources() && !IsWaitingOnCDMResource()) {
|
||||
if (!IsWaitingOnCDMResource()) {
|
||||
NS_ENSURE_TRUE(EnsureDecodersSetup(), NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
@ -471,11 +455,28 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool MP4Reader::CheckIfDecoderSetup()
|
||||
{
|
||||
if (!mDemuxerInitialized) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (HasAudio() && !mAudio.mDecoder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (HasVideo() && !mVideo.mDecoder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MP4Reader::EnsureDecodersSetup()
|
||||
{
|
||||
if (mAreDecodersSetup) {
|
||||
return !!mPlatform;
|
||||
if (CheckIfDecoderSetup()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mIsEncrypted) {
|
||||
@ -507,8 +508,11 @@ MP4Reader::EnsureDecodersSetup()
|
||||
return false;
|
||||
#endif
|
||||
} else {
|
||||
mPlatform = PlatformDecoderModule::Create();
|
||||
NS_ENSURE_TRUE(mPlatform, false);
|
||||
// mPlatform doesn't need to be recreated when resuming from dormant.
|
||||
if (!mPlatform) {
|
||||
mPlatform = PlatformDecoderModule::Create();
|
||||
NS_ENSURE_TRUE(mPlatform, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (HasAudio()) {
|
||||
@ -549,7 +553,6 @@ MP4Reader::EnsureDecodersSetup()
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
}
|
||||
|
||||
mAreDecodersSetup = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1125,13 +1128,8 @@ MP4Reader::GetBuffered(dom::TimeRanges* aBuffered)
|
||||
|
||||
bool MP4Reader::IsDormantNeeded()
|
||||
{
|
||||
#if defined(MP4_READER_DORMANT)
|
||||
return
|
||||
#if defined(MP4_READER_DORMANT_HEURISTIC)
|
||||
mDormantEnabled &&
|
||||
#endif
|
||||
mVideo.mDecoder &&
|
||||
mVideo.mDecoder->IsDormantNeeded();
|
||||
return mDormantEnabled;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
@ -1146,7 +1144,8 @@ void MP4Reader::ReleaseMediaResources()
|
||||
container->ClearCurrentFrame();
|
||||
}
|
||||
if (mVideo.mDecoder) {
|
||||
mVideo.mDecoder->ReleaseMediaResources();
|
||||
mVideo.mDecoder->Shutdown();
|
||||
mVideo.mDecoder = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,12 +28,6 @@ typedef std::deque<nsRefPtr<MediaRawData>> MediaSampleQueue;
|
||||
class MP4Stream;
|
||||
|
||||
#if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN) || defined(MOZ_APPLEMEDIA) || defined(MOZ_FFMPEG)
|
||||
#define MP4_READER_DORMANT
|
||||
#else
|
||||
#undef MP4_READER_DORMANT
|
||||
#endif
|
||||
|
||||
#if defined(XP_WIN) || defined(MOZ_APPLEMEDIA) || defined(MOZ_FFMPEG)
|
||||
#define MP4_READER_DORMANT_HEURISTIC
|
||||
#else
|
||||
#undef MP4_READER_DORMANT_HEURISTIC
|
||||
@ -61,11 +55,6 @@ public:
|
||||
virtual bool HasAudio() override;
|
||||
virtual bool HasVideo() override;
|
||||
|
||||
// PreReadMetadata() is called by MediaDecoderStateMachine::DecodeMetadata()
|
||||
// before checking hardware resource. In Gonk, it requests hardware codec so
|
||||
// MediaDecoderStateMachine could go to DORMANT state if the hardware codec is
|
||||
// not available.
|
||||
virtual void PreReadMetadata() override;
|
||||
virtual nsresult ReadMetadata(MediaInfo* aInfo,
|
||||
MetadataTags** aTags) override;
|
||||
|
||||
@ -106,6 +95,8 @@ private:
|
||||
|
||||
bool EnsureDecodersSetup();
|
||||
|
||||
bool CheckIfDecoderSetup();
|
||||
|
||||
// Sends input to decoder for aTrack, and output to the state machine,
|
||||
// if necessary.
|
||||
void Update(TrackType aTrack);
|
||||
@ -137,7 +128,6 @@ private:
|
||||
bool IsSupportedAudioMimeType(const nsACString& aMimeType);
|
||||
bool IsSupportedVideoMimeType(const nsACString& aMimeType);
|
||||
void NotifyResourcesStatusChanged();
|
||||
void RequestCodecResource();
|
||||
virtual bool IsWaitingOnCDMResource() override;
|
||||
|
||||
Microseconds GetNextKeyframeTime();
|
||||
@ -289,8 +279,6 @@ private:
|
||||
// Synchronized by decoder monitor.
|
||||
bool mIsEncrypted;
|
||||
|
||||
bool mAreDecodersSetup;
|
||||
|
||||
bool mIndexReady;
|
||||
int64_t mLastSeenEnd;
|
||||
Monitor mDemuxerMonitor;
|
||||
|
@ -256,11 +256,6 @@ public:
|
||||
virtual bool IsWaitingMediaResources() {
|
||||
return false;
|
||||
};
|
||||
virtual bool IsDormantNeeded() {
|
||||
return false;
|
||||
};
|
||||
virtual void AllocateMediaResources() {}
|
||||
virtual void ReleaseMediaResources() {}
|
||||
virtual bool IsHardwareAccelerated() const { return false; }
|
||||
|
||||
// ConfigurationChanged will be called to inform the video or audio decoder
|
||||
|
@ -142,11 +142,6 @@ SharedDecoderManager::Select(SharedDecoderProxy* aProxy)
|
||||
|
||||
mActiveProxy = aProxy;
|
||||
mActiveCallback = aProxy->mCallback;
|
||||
|
||||
if (mDecoderReleasedResources) {
|
||||
mDecoder->AllocateMediaResources();
|
||||
mDecoderReleasedResources = false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -176,14 +171,6 @@ SharedDecoderManager::DrainComplete()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SharedDecoderManager::ReleaseMediaResources()
|
||||
{
|
||||
mDecoderReleasedResources = true;
|
||||
mDecoder->ReleaseMediaResources();
|
||||
mActiveProxy = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
SharedDecoderManager::Shutdown()
|
||||
{
|
||||
@ -262,20 +249,6 @@ SharedDecoderProxy::IsWaitingMediaResources()
|
||||
return mManager->mActiveProxy != nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
SharedDecoderProxy::IsDormantNeeded()
|
||||
{
|
||||
return mManager->mDecoder->IsDormantNeeded();
|
||||
}
|
||||
|
||||
void
|
||||
SharedDecoderProxy::ReleaseMediaResources()
|
||||
{
|
||||
if (mManager->mActiveProxy == this) {
|
||||
mManager->ReleaseMediaResources();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
SharedDecoderProxy::IsHardwareAccelerated() const
|
||||
{
|
||||
|
@ -74,8 +74,6 @@ public:
|
||||
virtual nsresult Drain() override;
|
||||
virtual nsresult Shutdown() override;
|
||||
virtual bool IsWaitingMediaResources() override;
|
||||
virtual bool IsDormantNeeded() override;
|
||||
virtual void ReleaseMediaResources() override;
|
||||
virtual bool IsHardwareAccelerated() const override;
|
||||
|
||||
friend class SharedDecoderManager;
|
||||
|
@ -27,9 +27,6 @@ PRLogModuleInfo* GetAppleMediaLog() {
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// This defines the resolution height over which VDA will be prefered.
|
||||
#define VDA_RESOLUTION_THRESHOLD 720
|
||||
|
||||
bool AppleDecoderModule::sInitialized = false;
|
||||
bool AppleDecoderModule::sIsVTAvailable = false;
|
||||
bool AppleDecoderModule::sIsVTHWAvailable = false;
|
||||
@ -160,9 +157,7 @@ AppleDecoderModule::CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aC
|
||||
{
|
||||
nsRefPtr<MediaDataDecoder> decoder;
|
||||
|
||||
if (sIsVDAAvailable &&
|
||||
(!sIsVTHWAvailable || sForceVDA ||
|
||||
aConfig.image_height >= VDA_RESOLUTION_THRESHOLD)) {
|
||||
if (sIsVDAAvailable && (!sIsVTHWAvailable || sForceVDA)) {
|
||||
decoder =
|
||||
AppleVDADecoder::CreateVDADecoder(aConfig,
|
||||
aVideoTaskQueue,
|
||||
|
@ -73,10 +73,15 @@ GonkAudioDecoderManager::Init(MediaDataDecoderCallback* aCallback)
|
||||
mLooper->setName("GonkAudioDecoderManager");
|
||||
mLooper->start();
|
||||
|
||||
mDecoder = MediaCodecProxy::CreateByType(mLooper, "audio/mp4a-latm", false, false, nullptr);
|
||||
mDecoder = MediaCodecProxy::CreateByType(mLooper, "audio/mp4a-latm", false, nullptr);
|
||||
if (!mDecoder.get()) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!mDecoder->AskMediaCodecAndWait())
|
||||
{
|
||||
mDecoder = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
sp<AMessage> format = new AMessage;
|
||||
// Fixed values
|
||||
GADM_LOG("Init Audio channel no:%d, sample-rate:%d", mAudioChannels, mAudioRate);
|
||||
|
@ -137,15 +137,23 @@ GonkMediaDataDecoder::~GonkMediaDataDecoder()
|
||||
nsresult
|
||||
GonkMediaDataDecoder::Init()
|
||||
{
|
||||
mDecoder = mManager->Init(mCallback);
|
||||
sp<MediaCodecProxy> decoder;
|
||||
decoder = mManager->Init(mCallback);
|
||||
mDecoder = decoder;
|
||||
mDrainComplete = false;
|
||||
return mDecoder.get() ? NS_OK : NS_ERROR_UNEXPECTED;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkMediaDataDecoder::Shutdown()
|
||||
{
|
||||
if (!mDecoder.get()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mDecoder->stop();
|
||||
mDecoder->ReleaseMediaResources();
|
||||
mDecoder = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
@ -256,19 +264,10 @@ GonkMediaDataDecoder::Drain()
|
||||
|
||||
bool
|
||||
GonkMediaDataDecoder::IsWaitingMediaResources() {
|
||||
return mDecoder->IsWaitingResources();
|
||||
}
|
||||
|
||||
void
|
||||
GonkMediaDataDecoder::AllocateMediaResources()
|
||||
{
|
||||
mManager->AllocateMediaResources();
|
||||
}
|
||||
|
||||
void
|
||||
GonkMediaDataDecoder::ReleaseMediaResources()
|
||||
{
|
||||
mManager->ReleaseMediaResources();
|
||||
if (!mDecoder.get()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -44,10 +44,6 @@ public:
|
||||
// in the overrided function.
|
||||
virtual nsresult Flush();
|
||||
|
||||
virtual void AllocateMediaResources() {}
|
||||
|
||||
virtual void ReleaseMediaResources() {}
|
||||
|
||||
// It should be called in MediaTash thread.
|
||||
bool HasQueuedSample() {
|
||||
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
|
||||
@ -100,12 +96,6 @@ public:
|
||||
|
||||
virtual bool IsWaitingMediaResources() override;
|
||||
|
||||
virtual bool IsDormantNeeded() { return true;}
|
||||
|
||||
virtual void AllocateMediaResources() override;
|
||||
|
||||
virtual void ReleaseMediaResources() override;
|
||||
|
||||
private:
|
||||
|
||||
// Called on the task queue. Inserts the sample into the decoder, and
|
||||
|
@ -43,10 +43,6 @@ using namespace android;
|
||||
typedef android::MediaCodecProxy MediaCodecProxy;
|
||||
|
||||
namespace mozilla {
|
||||
enum {
|
||||
kNotifyCodecReserved = 'core',
|
||||
kNotifyCodecCanceled = 'coca',
|
||||
};
|
||||
|
||||
GonkVideoDecoderManager::GonkVideoDecoderManager(
|
||||
MediaTaskQueue* aTaskQueue,
|
||||
@ -112,13 +108,17 @@ GonkVideoDecoderManager::Init(MediaDataDecoderCallback* aCallback)
|
||||
if (mLooper->start() != OK || mManagerLooper->start() != OK ) {
|
||||
return nullptr;
|
||||
}
|
||||
mDecoder = MediaCodecProxy::CreateByType(mLooper, "video/avc", false, true, mVideoListener);
|
||||
mDecoder = MediaCodecProxy::CreateByType(mLooper, "video/avc", false, mVideoListener);
|
||||
mDecoder->AskMediaCodecAndWait();
|
||||
|
||||
uint32_t capability = MediaCodecProxy::kEmptyCapability;
|
||||
if (mDecoder->getCapability(&capability) == OK && (capability &
|
||||
MediaCodecProxy::kCanExposeGraphicBuffer)) {
|
||||
mNativeWindow = new GonkNativeWindow();
|
||||
}
|
||||
|
||||
mReaderCallback->NotifyResourcesStatusChanged();
|
||||
|
||||
return mDecoder;
|
||||
}
|
||||
|
||||
@ -488,15 +488,10 @@ GonkVideoDecoderManager::Flush()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
GonkVideoDecoderManager::AllocateMediaResources()
|
||||
{
|
||||
mDecoder->RequestMediaResources();
|
||||
}
|
||||
|
||||
void
|
||||
GonkVideoDecoderManager::codecReserved()
|
||||
{
|
||||
GVDM_LOG("codecReserved");
|
||||
sp<AMessage> format = new AMessage;
|
||||
sp<Surface> surface;
|
||||
|
||||
@ -509,24 +504,12 @@ GonkVideoDecoderManager::codecReserved()
|
||||
}
|
||||
mDecoder->configure(format, surface, nullptr, 0);
|
||||
mDecoder->Prepare();
|
||||
|
||||
if (mHandler != nullptr) {
|
||||
// post kNotifyCodecReserved to Looper thread.
|
||||
sp<AMessage> notify = new AMessage(kNotifyCodecReserved, mHandler->id());
|
||||
notify->post();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GonkVideoDecoderManager::codecCanceled()
|
||||
{
|
||||
mDecoder = nullptr;
|
||||
if (mHandler != nullptr) {
|
||||
// post kNotifyCodecCanceled to Looper thread.
|
||||
sp<AMessage> notify = new AMessage(kNotifyCodecCanceled, mHandler->id());
|
||||
notify->post();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Called on GonkVideoDecoderManager::mManagerLooper thread.
|
||||
@ -534,21 +517,6 @@ void
|
||||
GonkVideoDecoderManager::onMessageReceived(const sp<AMessage> &aMessage)
|
||||
{
|
||||
switch (aMessage->what()) {
|
||||
case kNotifyCodecReserved:
|
||||
{
|
||||
// Our decode may have acquired the hardware resource that it needs
|
||||
// to start. Notify the state machine to resume loading metadata.
|
||||
GVDM_LOG("CodecReserved!");
|
||||
mReaderCallback->NotifyResourcesStatusChanged();
|
||||
break;
|
||||
}
|
||||
|
||||
case kNotifyCodecCanceled:
|
||||
{
|
||||
mReaderCallback->ReleaseMediaResources();
|
||||
break;
|
||||
}
|
||||
|
||||
case kNotifyPostReleaseBuffer:
|
||||
{
|
||||
ReleaseAllPendingVideoBuffers();
|
||||
|
@ -51,8 +51,6 @@ public:
|
||||
|
||||
virtual nsresult Flush() override;
|
||||
|
||||
virtual void AllocateMediaResources();
|
||||
|
||||
virtual void ReleaseMediaResources();
|
||||
|
||||
static void RecycleCallback(TextureClient* aClient, void* aClosure);
|
||||
@ -146,7 +144,6 @@ private:
|
||||
|
||||
android::sp<MediaCodecProxy> mDecoder;
|
||||
nsRefPtr<layers::ImageContainer> mImageContainer;
|
||||
MediaDataDecoderCallback* mCallback;
|
||||
|
||||
android::MediaBuffer* mVideoBuffer;
|
||||
|
||||
@ -179,7 +176,6 @@ private:
|
||||
Vector<android::MediaBuffer*> mPendingVideoBuffers;
|
||||
// The lock protects mPendingVideoBuffers.
|
||||
Mutex mPendingVideoBuffersLock;
|
||||
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -66,13 +66,6 @@ WMFMediaDataDecoder::ProcessShutdown()
|
||||
mDecoder = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
WMFMediaDataDecoder::ProcessReleaseDecoder()
|
||||
{
|
||||
mMFTManager->Shutdown();
|
||||
mDecoder = nullptr;
|
||||
}
|
||||
|
||||
// Inserts data into the decoder's pipeline.
|
||||
nsresult
|
||||
WMFMediaDataDecoder::Input(MediaRawData* aSample)
|
||||
@ -157,24 +150,6 @@ WMFMediaDataDecoder::Drain()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
WMFMediaDataDecoder::AllocateMediaResources()
|
||||
{
|
||||
mDecoder = mMFTManager->Init();
|
||||
}
|
||||
|
||||
void
|
||||
WMFMediaDataDecoder::ReleaseMediaResources()
|
||||
{
|
||||
DebugOnly<nsresult> rv = mTaskQueue->FlushAndDispatch(
|
||||
NS_NewRunnableMethod(this, &WMFMediaDataDecoder::ProcessReleaseDecoder));
|
||||
#ifdef DEBUG
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("WMFMediaDataDecoder::ReleaseMediaResources() dispatch of task failed!");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
WMFMediaDataDecoder::IsHardwareAccelerated() const {
|
||||
return mMFTManager && mMFTManager->IsHardwareAccelerated();
|
||||
|
@ -70,9 +70,6 @@ public:
|
||||
virtual nsresult Shutdown() override;
|
||||
|
||||
virtual bool IsWaitingMediaResources() { return false; };
|
||||
virtual bool IsDormantNeeded() { return true; };
|
||||
virtual void AllocateMediaResources() override;
|
||||
virtual void ReleaseMediaResources() override;
|
||||
virtual bool IsHardwareAccelerated() const override;
|
||||
|
||||
private:
|
||||
@ -90,7 +87,6 @@ private:
|
||||
void ProcessDrain();
|
||||
|
||||
void ProcessShutdown();
|
||||
void ProcessReleaseDecoder();
|
||||
|
||||
RefPtr<FlushableMediaTaskQueue> mTaskQueue;
|
||||
MediaDataDecoderCallback* mCallback;
|
||||
|
@ -122,40 +122,6 @@ H264Converter::IsWaitingMediaResources()
|
||||
return MediaDataDecoder::IsWaitingMediaResources();
|
||||
}
|
||||
|
||||
bool
|
||||
H264Converter::IsDormantNeeded()
|
||||
{
|
||||
if (mNeedAVCC) {
|
||||
return true;
|
||||
}
|
||||
return mDecoder ?
|
||||
mDecoder->IsDormantNeeded() : MediaDataDecoder::IsDormantNeeded();
|
||||
}
|
||||
|
||||
void
|
||||
H264Converter::AllocateMediaResources()
|
||||
{
|
||||
if (mNeedAVCC) {
|
||||
// Nothing to do, decoder will be allocated on the fly when required.
|
||||
return;
|
||||
}
|
||||
if (mDecoder) {
|
||||
mDecoder->AllocateMediaResources();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
H264Converter::ReleaseMediaResources()
|
||||
{
|
||||
if (mNeedAVCC) {
|
||||
Shutdown();
|
||||
return;
|
||||
}
|
||||
if (mDecoder) {
|
||||
mDecoder->ReleaseMediaResources();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
H264Converter::IsHardwareAccelerated() const
|
||||
{
|
||||
@ -219,7 +185,7 @@ H264Converter::CheckForSPSChange(MediaRawData* aSample)
|
||||
// The SPS has changed, signal to flush the current decoder and create a
|
||||
// new one.
|
||||
mDecoder->Flush();
|
||||
ReleaseMediaResources();
|
||||
Shutdown();
|
||||
return CreateDecoderAndInit(aSample);
|
||||
}
|
||||
|
||||
|
@ -35,9 +35,6 @@ public:
|
||||
virtual nsresult Drain() override;
|
||||
virtual nsresult Shutdown() override;
|
||||
virtual bool IsWaitingMediaResources() override;
|
||||
virtual bool IsDormantNeeded() override;
|
||||
virtual void AllocateMediaResources() override;
|
||||
virtual void ReleaseMediaResources() override;
|
||||
virtual bool IsHardwareAccelerated() const override;
|
||||
|
||||
// Return true if mimetype is H.264.
|
||||
|
@ -78,42 +78,38 @@ sp<MediaCodecProxy>
|
||||
MediaCodecProxy::CreateByType(sp<ALooper> aLooper,
|
||||
const char *aMime,
|
||||
bool aEncoder,
|
||||
bool aAsync,
|
||||
wp<CodecResourceListener> aListener)
|
||||
{
|
||||
sp<MediaCodecProxy> codec = new MediaCodecProxy(aLooper, aMime, aEncoder, aAsync, aListener);
|
||||
if ((!aAsync && codec->allocated()) || codec->requestResource()) {
|
||||
return codec;
|
||||
}
|
||||
return nullptr;
|
||||
sp<MediaCodecProxy> codec = new MediaCodecProxy(aLooper,
|
||||
aMime,
|
||||
aEncoder,
|
||||
aListener);
|
||||
return codec;
|
||||
}
|
||||
|
||||
MediaCodecProxy::MediaCodecProxy(sp<ALooper> aLooper,
|
||||
const char *aMime,
|
||||
bool aEncoder,
|
||||
bool aAsync,
|
||||
wp<CodecResourceListener> aListener)
|
||||
: mCodecLooper(aLooper)
|
||||
, mCodecMime(aMime)
|
||||
, mCodecEncoder(aEncoder)
|
||||
, mListener(aListener)
|
||||
, mMediaCodecLock("MediaCodecProxy::mMediaCodecLock")
|
||||
, mPendingRequestMediaResource(false)
|
||||
{
|
||||
MOZ_ASSERT(mCodecLooper != nullptr, "ALooper should not be nullptr.");
|
||||
if (aAsync) {
|
||||
mResourceHandler = new MediaResourceHandler(this);
|
||||
} else {
|
||||
allocateCodec();
|
||||
}
|
||||
mResourceHandler = new MediaResourceHandler(this);
|
||||
}
|
||||
|
||||
MediaCodecProxy::~MediaCodecProxy()
|
||||
{
|
||||
releaseCodec();
|
||||
cancelResource();
|
||||
SetMediaCodecFree();
|
||||
}
|
||||
|
||||
bool
|
||||
MediaCodecProxy::requestResource()
|
||||
MediaCodecProxy::AskMediaCodecAndWait()
|
||||
{
|
||||
if (mResourceHandler == nullptr) {
|
||||
return false;
|
||||
@ -124,30 +120,39 @@ MediaCodecProxy::requestResource()
|
||||
? IMediaResourceManagerService::HW_VIDEO_ENCODER
|
||||
: IMediaResourceManagerService::HW_VIDEO_DECODER);
|
||||
} else if (strncasecmp(mCodecMime.get(), "audio/", 6) == 0) {
|
||||
mResourceHandler->requestResource(mCodecEncoder
|
||||
? IMediaResourceManagerService::HW_AUDIO_ENCODER
|
||||
: IMediaResourceManagerService::HW_AUDIO_DECODER);
|
||||
if (allocateCodec()) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
mozilla::MonitorAutoLock mon(mMediaCodecLock);
|
||||
mPendingRequestMediaResource = true;
|
||||
|
||||
while (mPendingRequestMediaResource) {
|
||||
mMediaCodecLock.Wait();
|
||||
}
|
||||
MCP_LOG("AskMediaCodecAndWait complete");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
MediaCodecProxy::RequestMediaResources()
|
||||
{
|
||||
requestResource();
|
||||
}
|
||||
|
||||
void
|
||||
MediaCodecProxy::cancelResource()
|
||||
MediaCodecProxy::SetMediaCodecFree()
|
||||
{
|
||||
if (mResourceHandler == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
mozilla::MonitorAutoLock mon(mMediaCodecLock);
|
||||
if (mPendingRequestMediaResource) {
|
||||
mPendingRequestMediaResource = false;
|
||||
mon.NotifyAll();
|
||||
}
|
||||
|
||||
mResourceHandler->cancelResource();
|
||||
mResourceHandler = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -462,13 +467,19 @@ MediaCodecProxy::getCapability(uint32_t *aCapability)
|
||||
void
|
||||
MediaCodecProxy::resourceReserved()
|
||||
{
|
||||
MCP_LOG("resourceReserved");
|
||||
// Create MediaCodec
|
||||
releaseCodec();
|
||||
if (!allocateCodec()) {
|
||||
cancelResource();
|
||||
SetMediaCodecFree();
|
||||
return;
|
||||
}
|
||||
|
||||
// Notify initialization waiting.
|
||||
mozilla::MonitorAutoLock mon(mMediaCodecLock);
|
||||
mPendingRequestMediaResource = false;
|
||||
mon.NotifyAll();
|
||||
|
||||
// Notification
|
||||
sp<CodecResourceListener> listener = mListener.promote();
|
||||
if (listener != nullptr) {
|
||||
@ -476,20 +487,6 @@ MediaCodecProxy::resourceReserved()
|
||||
}
|
||||
}
|
||||
|
||||
// Called on a Binder thread
|
||||
void
|
||||
MediaCodecProxy::resourceCanceled()
|
||||
{
|
||||
// Release MediaCodec
|
||||
releaseCodec();
|
||||
|
||||
// Notification
|
||||
sp<CodecResourceListener> listener = mListener.promote();
|
||||
if (listener != nullptr) {
|
||||
listener->codecCanceled();
|
||||
}
|
||||
}
|
||||
|
||||
bool MediaCodecProxy::Prepare()
|
||||
{
|
||||
|
||||
@ -611,23 +608,10 @@ status_t MediaCodecProxy::Output(MediaBuffer** aBuffer, int64_t aTimeoutUs)
|
||||
return err;
|
||||
}
|
||||
|
||||
bool MediaCodecProxy::IsWaitingResources()
|
||||
{
|
||||
if (mResourceHandler.get()) {
|
||||
return mResourceHandler->IsWaitingResource();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MediaCodecProxy::IsDormantNeeded()
|
||||
{
|
||||
return mCodecLooper.get() ? true : false;
|
||||
}
|
||||
|
||||
void MediaCodecProxy::ReleaseMediaResources()
|
||||
{
|
||||
releaseCodec();
|
||||
cancelResource();
|
||||
SetMediaCodecFree();
|
||||
}
|
||||
|
||||
void MediaCodecProxy::ReleaseMediaBuffer(MediaBuffer* aBuffer) {
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <stagefright/MediaBuffer.h>
|
||||
#include <utils/threads.h>
|
||||
#include "MediaResourceHandler.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
|
||||
namespace android {
|
||||
// This class is intended to be a proxy for MediaCodec with codec resource
|
||||
@ -55,7 +56,6 @@ public:
|
||||
static sp<MediaCodecProxy> CreateByType(sp<ALooper> aLooper,
|
||||
const char *aMime,
|
||||
bool aEncoder,
|
||||
bool aAsync=false,
|
||||
wp<CodecResourceListener> aListener=nullptr);
|
||||
|
||||
// MediaCodec methods
|
||||
@ -129,22 +129,26 @@ public:
|
||||
int64_t aTimestampUsecs, uint64_t flags);
|
||||
status_t Output(MediaBuffer** aBuffer, int64_t aTimeoutUs);
|
||||
bool Prepare();
|
||||
bool IsWaitingResources();
|
||||
bool IsDormantNeeded();
|
||||
void RequestMediaResources();
|
||||
void ReleaseMediaResources();
|
||||
// This updates mOutputBuffer when receiving INFO_OUTPUT_BUFFERS_CHANGED event.
|
||||
bool UpdateOutputBuffers();
|
||||
|
||||
void ReleaseMediaBuffer(MediaBuffer* abuffer);
|
||||
|
||||
// It asks for the OMX codec and blocked until the resource is grant to be
|
||||
// allocated.
|
||||
bool AskMediaCodecAndWait();
|
||||
|
||||
// Free the OMX codec so others can allocate it.
|
||||
void SetMediaCodecFree();
|
||||
|
||||
protected:
|
||||
virtual ~MediaCodecProxy();
|
||||
|
||||
// MediaResourceHandler::EventListener::resourceReserved()
|
||||
virtual void resourceReserved();
|
||||
// MediaResourceHandler::EventListener::resourceCanceled()
|
||||
virtual void resourceCanceled();
|
||||
virtual void resourceCanceled() {}
|
||||
|
||||
private:
|
||||
// Forbidden
|
||||
@ -156,14 +160,8 @@ private:
|
||||
MediaCodecProxy(sp<ALooper> aLooper,
|
||||
const char *aMime,
|
||||
bool aEncoder,
|
||||
bool aAsync,
|
||||
wp<CodecResourceListener> aListener);
|
||||
|
||||
// Request Resource
|
||||
bool requestResource();
|
||||
// Cancel Resource
|
||||
void cancelResource();
|
||||
|
||||
// Allocate Codec Resource
|
||||
bool allocateCodec();
|
||||
// Release Codec Resource
|
||||
@ -188,6 +186,8 @@ private:
|
||||
Vector<sp<ABuffer> > mInputBuffers;
|
||||
Vector<sp<ABuffer> > mOutputBuffers;
|
||||
|
||||
mozilla::Monitor mMediaCodecLock;
|
||||
bool mPendingRequestMediaResource;
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
@ -1322,7 +1322,7 @@ MediaCodecReader::CreateMediaCodec(sp<ALooper>& aLooper,
|
||||
|
||||
const char* mime;
|
||||
if (sourceFormat->findCString(kKeyMIMEType, &mime)) {
|
||||
aTrack.mCodec = MediaCodecProxy::CreateByType(aLooper, mime, false, aAsync, aListener);
|
||||
aTrack.mCodec = MediaCodecProxy::CreateByType(aLooper, mime, false, aListener);
|
||||
}
|
||||
|
||||
if (aTrack.mCodec == nullptr) {
|
||||
|
@ -221,8 +221,11 @@ MediaEngineGonkVideoSource::Start(SourceMediaStream* aStream, TrackID aID)
|
||||
|
||||
ReentrantMonitorAutoEnter sync(mCallbackMonitor);
|
||||
|
||||
MOZ_ASSERT(mCameraControl, "mCameraControl is nullptr");
|
||||
if (mState == kStarted) {
|
||||
return NS_OK;
|
||||
} else if (!mCameraControl) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mTrackID = aID;
|
||||
mImageContainer = layers::LayerManager::CreateImageContainer();
|
||||
|
@ -77,7 +77,6 @@ DIRS += [
|
||||
'notification',
|
||||
'offline',
|
||||
'power',
|
||||
'push',
|
||||
'quota',
|
||||
'security',
|
||||
'settings',
|
||||
@ -137,6 +136,11 @@ if CONFIG['MOZ_GAMEPAD']:
|
||||
if CONFIG['MOZ_NFC']:
|
||||
DIRS += ['nfc']
|
||||
|
||||
if CONFIG['MOZ_SIMPLEPUSH']:
|
||||
DIRS += ['simplepush']
|
||||
else:
|
||||
DIRS += ['push']
|
||||
|
||||
if CONFIG['MOZ_SECUREELEMENT']:
|
||||
DIRS += ['secureelement']
|
||||
|
||||
|
301
dom/push/Push.js
@ -4,8 +4,8 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
// Don't modify this, instead set services.push.debug.
|
||||
let gDebuggingEnabled = false;
|
||||
// Don't modify this, instead set dom.push.debug.
|
||||
let gDebuggingEnabled = true;
|
||||
|
||||
function debug(s) {
|
||||
if (gDebuggingEnabled)
|
||||
@ -21,6 +21,94 @@ Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
|
||||
Cu.import("resource://gre/modules/AppsUtils.jsm");
|
||||
|
||||
const PUSH_SUBSCRIPTION_CID = Components.ID("{CA86B665-BEDA-4212-8D0F-5C9F65270B58}");
|
||||
|
||||
function PushSubscription(pushEndpoint, scope, pageURL) {
|
||||
debug("PushSubscription Constructor");
|
||||
this._pushEndpoint = pushEndpoint;
|
||||
this._scope = scope;
|
||||
this._pageURL = pageURL;
|
||||
}
|
||||
|
||||
PushSubscription.prototype = {
|
||||
__proto__: DOMRequestIpcHelper.prototype,
|
||||
|
||||
contractID: "@mozilla.org/push/PushSubscription;1",
|
||||
|
||||
classID : PUSH_SUBSCRIPTION_CID,
|
||||
|
||||
QueryInterface : XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer,
|
||||
Ci.nsISupportsWeakReference,
|
||||
Ci.nsIObserver]),
|
||||
|
||||
init: function(aWindow) {
|
||||
debug("PushSubscription init()");
|
||||
|
||||
this.initDOMRequestHelper(aWindow, [
|
||||
"PushService:Unregister:OK",
|
||||
"PushService:Unregister:KO",
|
||||
]);
|
||||
|
||||
this._cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
|
||||
.getService(Ci.nsISyncMessageSender);
|
||||
},
|
||||
|
||||
__init: function(endpoint, scope, pageURL) {
|
||||
this._pushEndpoint = endpoint;
|
||||
this._scope = scope;
|
||||
this._pageURL = pageURL;
|
||||
},
|
||||
|
||||
get endpoint() {
|
||||
return this._pushEndpoint;
|
||||
},
|
||||
|
||||
get subscriptionId() {
|
||||
// TODO bug 1149271. Not sure what this is about.
|
||||
return "The twins of Mammon quarrelled.";
|
||||
},
|
||||
|
||||
unsubscribe: function() {
|
||||
debug("unsubscribe! ")
|
||||
|
||||
let promiseInit = function(resolve, reject) {
|
||||
let resolverId = this.getPromiseResolverId({resolve: resolve,
|
||||
reject: reject });
|
||||
|
||||
this._cpmm.sendAsyncMessage("Push:Unregister", {
|
||||
pageURL: this._pageURL,
|
||||
scope: this._scope,
|
||||
pushEndpoint: this._pushEndpoint,
|
||||
requestID: resolverId
|
||||
});
|
||||
}.bind(this);
|
||||
|
||||
return this.createPromise(promiseInit);
|
||||
},
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
debug("push subscription receiveMessage(): " + JSON.stringify(aMessage))
|
||||
|
||||
let json = aMessage.data;
|
||||
let resolver = this.takePromiseResolver(json.requestID);
|
||||
if (resolver == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (aMessage.name) {
|
||||
case "PushService:Unregister:OK":
|
||||
resolver.resolve(false);
|
||||
break;
|
||||
case "PushService:Unregister:KO":
|
||||
resolver.reject(true);
|
||||
break;
|
||||
default:
|
||||
debug("NOT IMPLEMENTED! receiveMessage for " + aMessage.name);
|
||||
}
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
const PUSH_CID = Components.ID("{cde1d019-fad8-4044-b141-65fb4fb7a245}");
|
||||
|
||||
/**
|
||||
@ -47,101 +135,186 @@ Push.prototype = {
|
||||
// Set debug first so that all debugging actually works.
|
||||
// NOTE: We don't add an observer here like in PushService. Flipping the
|
||||
// pref will require a reload of the app/page, which seems acceptable.
|
||||
gDebuggingEnabled = Services.prefs.getBoolPref("services.push.debug");
|
||||
gDebuggingEnabled = Services.prefs.getBoolPref("dom.push.debug");
|
||||
debug("init()");
|
||||
|
||||
let principal = aWindow.document.nodePrincipal;
|
||||
let appsService = Cc["@mozilla.org/AppsService;1"]
|
||||
.getService(Ci.nsIAppsService);
|
||||
|
||||
this._manifestURL = appsService.getManifestURLByLocalId(principal.appId);
|
||||
this._pageURL = principal.URI;
|
||||
this._pageURL = aWindow.document.nodePrincipal.URI;
|
||||
this._window = aWindow;
|
||||
|
||||
this.initDOMRequestHelper(aWindow, [
|
||||
"PushService:Register:OK",
|
||||
"PushService:Register:KO",
|
||||
"PushService:Unregister:OK",
|
||||
"PushService:Unregister:KO",
|
||||
"PushService:Registrations:OK",
|
||||
"PushService:Registrations:KO"
|
||||
"PushService:Registration:OK",
|
||||
"PushService:Registration:KO"
|
||||
]);
|
||||
|
||||
this._cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
|
||||
.getService(Ci.nsISyncMessageSender);
|
||||
},
|
||||
|
||||
setScope: function(scope){
|
||||
debug('setScope ' + scope);
|
||||
this._scope = scope;
|
||||
},
|
||||
|
||||
askPermission: function (aAllowCallback, aCancelCallback) {
|
||||
debug("askPermission");
|
||||
|
||||
let principal = this._window.document.nodePrincipal;
|
||||
let type = "push";
|
||||
let permValue =
|
||||
Services.perms.testExactPermissionFromPrincipal(principal, type);
|
||||
|
||||
debug("Existing permission " + permValue);
|
||||
|
||||
if (permValue == Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
aAllowCallback();
|
||||
return;
|
||||
}
|
||||
|
||||
if (permValue == Ci.nsIPermissionManager.DENY_ACTION) {
|
||||
aCancelCallback();
|
||||
return;
|
||||
}
|
||||
|
||||
// Create an array with a single nsIContentPermissionType element.
|
||||
type = {
|
||||
type: "push",
|
||||
access: null,
|
||||
options: [],
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionType])
|
||||
};
|
||||
let typeArray = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
|
||||
typeArray.appendElement(type, false);
|
||||
|
||||
// create a nsIContentPermissionRequest
|
||||
let request = {
|
||||
types: typeArray,
|
||||
principal: principal,
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionRequest]),
|
||||
allow: function() {
|
||||
aAllowCallback();
|
||||
},
|
||||
cancel: function() {
|
||||
aCancelCallback();
|
||||
},
|
||||
window: this._window
|
||||
};
|
||||
|
||||
debug("asking the window utils about permission...")
|
||||
// Using askPermission from nsIDOMWindowUtils that takes care of the
|
||||
// remoting if needed.
|
||||
let windowUtils = this._window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
windowUtils.askPermission(request);
|
||||
},
|
||||
|
||||
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
debug("receiveMessage()");
|
||||
let request = this.getRequest(aMessage.data.requestID);
|
||||
debug("push receiveMessage(): " + JSON.stringify(aMessage))
|
||||
|
||||
let json = aMessage.data;
|
||||
if (!request) {
|
||||
debug("No request " + json.requestID);
|
||||
let resolver = this.takePromiseResolver(json.requestID);
|
||||
|
||||
if (!resolver) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (aMessage.name) {
|
||||
case "PushService:Register:OK":
|
||||
Services.DOMRequest.fireSuccess(request, json.pushEndpoint);
|
||||
{
|
||||
let subscription = new this._window.PushSubscription(json.pushEndpoint,
|
||||
this._scope,
|
||||
this._pageURL.spec);
|
||||
resolver.resolve(subscription);
|
||||
break;
|
||||
}
|
||||
case "PushService:Register:KO":
|
||||
Services.DOMRequest.fireError(request, json.error);
|
||||
resolver.reject(null);
|
||||
break;
|
||||
case "PushService:Unregister:OK":
|
||||
Services.DOMRequest.fireSuccess(request, json.pushEndpoint);
|
||||
case "PushService:Registration:OK":
|
||||
{
|
||||
let subscription = null;
|
||||
try {
|
||||
subscription = new this._window.PushSubscription(json.registration.pushEndpoint,
|
||||
this._scope, this._pageURL.spec);
|
||||
} catch(error) {
|
||||
}
|
||||
resolver.resolve(subscription);
|
||||
break;
|
||||
case "PushService:Unregister:KO":
|
||||
Services.DOMRequest.fireError(request, json.error);
|
||||
break;
|
||||
case "PushService:Registrations:OK":
|
||||
Services.DOMRequest.fireSuccess(request, json.registrations);
|
||||
break;
|
||||
case "PushService:Registrations:KO":
|
||||
Services.DOMRequest.fireError(request, json.error);
|
||||
}
|
||||
case "PushService:Registration:KO":
|
||||
resolver.reject(null);
|
||||
break;
|
||||
default:
|
||||
debug("NOT IMPLEMENTED! receiveMessage for " + aMessage.name);
|
||||
}
|
||||
},
|
||||
|
||||
register: function() {
|
||||
debug("register()");
|
||||
let req = this.createRequest();
|
||||
if (!Services.prefs.getBoolPref("services.push.connection.enabled")) {
|
||||
// If push socket is disabled by the user, immediately error rather than
|
||||
// timing out.
|
||||
Services.DOMRequest.fireErrorAsync(req, "NetworkError");
|
||||
return req;
|
||||
}
|
||||
subscribe: function() {
|
||||
debug("subscribe()");
|
||||
let p = this.createPromise(function(resolve, reject) {
|
||||
let resolverId = this.getPromiseResolverId({ resolve: resolve, reject: reject });
|
||||
|
||||
this._cpmm.sendAsyncMessage("Push:Register", {
|
||||
pageURL: this._pageURL.spec,
|
||||
manifestURL: this._manifestURL,
|
||||
requestID: this.getRequestId(req)
|
||||
});
|
||||
return req;
|
||||
this.askPermission(
|
||||
function() {
|
||||
this._cpmm.sendAsyncMessage("Push:Register", {
|
||||
pageURL: this._pageURL.spec,
|
||||
scope: this._scope,
|
||||
requestID: resolverId
|
||||
});
|
||||
}.bind(this),
|
||||
|
||||
function() {
|
||||
reject("denied");
|
||||
}
|
||||
);
|
||||
}.bind(this));
|
||||
return p;
|
||||
},
|
||||
|
||||
unregister: function(aPushEndpoint) {
|
||||
debug("unregister(" + aPushEndpoint + ")");
|
||||
let req = this.createRequest();
|
||||
this._cpmm.sendAsyncMessage("Push:Unregister", {
|
||||
pageURL: this._pageURL.spec,
|
||||
manifestURL: this._manifestURL,
|
||||
requestID: this.getRequestId(req),
|
||||
pushEndpoint: aPushEndpoint
|
||||
});
|
||||
return req;
|
||||
getSubscription: function() {
|
||||
debug("getSubscription()" + this._scope);
|
||||
|
||||
let p = this.createPromise(function(resolve, reject) {
|
||||
|
||||
let resolverId = this.getPromiseResolverId({ resolve: resolve, reject: reject });
|
||||
|
||||
this.askPermission(
|
||||
function() {
|
||||
this._cpmm.sendAsyncMessage("Push:Registration", {
|
||||
pageURL: this._pageURL.spec,
|
||||
scope: this._scope,
|
||||
requestID: resolverId
|
||||
});
|
||||
}.bind(this),
|
||||
|
||||
function() {
|
||||
reject("denied");
|
||||
}
|
||||
);
|
||||
}.bind(this));
|
||||
return p;
|
||||
},
|
||||
|
||||
registrations: function() {
|
||||
debug("registrations()");
|
||||
let req = this.createRequest();
|
||||
this._cpmm.sendAsyncMessage("Push:Registrations", {
|
||||
manifestURL: this._manifestURL,
|
||||
requestID: this.getRequestId(req)
|
||||
});
|
||||
return req;
|
||||
}
|
||||
hasPermission: function() {
|
||||
debug("getSubscription()" + this._scope);
|
||||
|
||||
let p = this.createPromise(function(resolve, reject) {
|
||||
let permissionManager = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager);
|
||||
let permission = permissionManager.testExactPermission(this._pageURL, "push");
|
||||
|
||||
let pushPermissionStatus = "default";
|
||||
if (permission == Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
pushPermissionStatus = "granted";
|
||||
} else if (permission == Ci.nsIPermissionManager.DENY_ACTION) {
|
||||
pushPermissionStatus = "denied";
|
||||
}
|
||||
resolve(pushPermissionStatus);
|
||||
}.bind(this));
|
||||
return p;
|
||||
},
|
||||
}
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([Push]);
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([Push, PushSubscription]);
|
||||
|
@ -2,6 +2,9 @@
|
||||
component {cde1d019-fad8-4044-b141-65fb4fb7a245} Push.js
|
||||
contract @mozilla.org/push/PushManager;1 {cde1d019-fad8-4044-b141-65fb4fb7a245}
|
||||
|
||||
component {CA86B665-BEDA-4212-8D0F-5C9F65270B58} Push.js
|
||||
contract @mozilla.org/push/PushSubscription;1 {CA86B665-BEDA-4212-8D0F-5C9F65270B58}
|
||||
|
||||
# Component to initialize PushService on startup.
|
||||
component {4b8caa3b-3c58-4f3c-a7f5-7bd9cb24c11d} PushServiceLauncher.js
|
||||
contract @mozilla.org/push/ServiceLauncher;1 {4b8caa3b-3c58-4f3c-a7f5-7bd9cb24c11d}
|
||||
|
@ -5,8 +5,8 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
// Don't modify this, instead set services.push.debug.
|
||||
let gDebuggingEnabled = false;
|
||||
// Don't modify this, instead set dom.push.debug.
|
||||
let gDebuggingEnabled = true;
|
||||
|
||||
function debug(s) {
|
||||
if (gDebuggingEnabled)
|
||||
@ -41,7 +41,7 @@ var threadManager = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadM
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["PushService"];
|
||||
|
||||
const prefs = new Preferences("services.push.");
|
||||
const prefs = new Preferences("dom.push.");
|
||||
// Set debug first so that all debugging actually works.
|
||||
gDebuggingEnabled = prefs.get("debug");
|
||||
|
||||
@ -54,7 +54,7 @@ const kUDP_WAKEUP_WS_STATUS_CODE = 4774; // WebSocket Close status code sent
|
||||
// wake client up using UDP.
|
||||
|
||||
const kCHILD_PROCESS_MESSAGES = ["Push:Register", "Push:Unregister",
|
||||
"Push:Registrations"];
|
||||
"Push:Registration"];
|
||||
|
||||
const kWS_MAX_WENTDOWN = 2;
|
||||
|
||||
@ -79,10 +79,9 @@ this.PushDB.prototype = {
|
||||
// index to fetch records based on endpoints. used by unregister
|
||||
objectStore.createIndex("pushEndpoint", "pushEndpoint", { unique: true });
|
||||
|
||||
// index to fetch records per manifest, so we can identify endpoints
|
||||
// associated with an app. Since an app can have multiple endpoints
|
||||
// uniqueness cannot be enforced
|
||||
objectStore.createIndex("manifestURL", "manifestURL", { unique: false });
|
||||
// index to fetch records per scope, so we can identify endpoints
|
||||
// associated with an app.
|
||||
objectStore.createIndex("scope", "scope", { unique: true });
|
||||
},
|
||||
|
||||
/*
|
||||
@ -94,7 +93,7 @@ this.PushDB.prototype = {
|
||||
* Callback function to invoke when there was an error.
|
||||
*/
|
||||
put: function(aChannelRecord, aSuccessCb, aErrorCb) {
|
||||
debug("put()");
|
||||
debug("put()" + JSON.stringify(aChannelRecord));
|
||||
|
||||
this.newTxn(
|
||||
"readwrite",
|
||||
@ -173,30 +172,20 @@ this.PushDB.prototype = {
|
||||
);
|
||||
},
|
||||
|
||||
getAllByManifestURL: function(aManifestURL, aSuccessCb, aErrorCb) {
|
||||
debug("getAllByManifestURL()");
|
||||
if (!aManifestURL) {
|
||||
if (typeof aErrorCb == "function") {
|
||||
aErrorCb("PushDB.getAllByManifestURL: Got undefined aManifestURL");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let self = this;
|
||||
getByScope: function(aScope, aSuccessCb, aErrorCb) {
|
||||
debug("getByScope() " + aScope);
|
||||
|
||||
this.newTxn(
|
||||
"readonly",
|
||||
kPUSHDB_STORE_NAME,
|
||||
function txnCb(aTxn, aStore) {
|
||||
let index = aStore.index("manifestURL");
|
||||
let range = IDBKeyRange.only(aManifestURL);
|
||||
aTxn.result = [];
|
||||
index.openCursor(range).onsuccess = function(event) {
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
debug(cursor.value.manifestURL + " " + cursor.value.channelID);
|
||||
aTxn.result.push(cursor.value);
|
||||
cursor.continue();
|
||||
}
|
||||
aTxn.result = undefined;
|
||||
|
||||
let index = aStore.index("scope");
|
||||
index.get(aScope).onsuccess = function setTxnResult(aEvent) {
|
||||
aTxn.result = aEvent.target.result;
|
||||
debug("Fetch successful " + aEvent.target.result);
|
||||
}
|
||||
},
|
||||
aSuccessCb,
|
||||
@ -325,17 +314,17 @@ this.PushService = {
|
||||
}
|
||||
break;
|
||||
case "nsPref:changed":
|
||||
if (aData == "services.push.serverURL") {
|
||||
debug("services.push.serverURL changed! websocket. new value " +
|
||||
if (aData == "dom.push.serverURL") {
|
||||
debug("dom.push.serverURL changed! websocket. new value " +
|
||||
prefs.get("serverURL"));
|
||||
this._shutdownWS();
|
||||
} else if (aData == "services.push.connection.enabled") {
|
||||
} else if (aData == "dom.push.connection.enabled") {
|
||||
if (prefs.get("connection.enabled")) {
|
||||
this._startListeningIfChannelsPresent();
|
||||
} else {
|
||||
this._shutdownWS();
|
||||
}
|
||||
} else if (aData == "services.push.debug") {
|
||||
} else if (aData == "dom.push.debug") {
|
||||
gDebuggingEnabled = prefs.get("debug");
|
||||
}
|
||||
break;
|
||||
@ -382,35 +371,30 @@ this.PushService = {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only remove push registrations for apps.
|
||||
if (data.browserOnly) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO 1149274. We should support site permissions as well as a way to go from manifest
|
||||
// url to 'all scopes registered for push in this app'
|
||||
let appsService = Cc["@mozilla.org/AppsService;1"]
|
||||
.getService(Ci.nsIAppsService);
|
||||
let manifestURL = appsService.getManifestURLByLocalId(data.appId);
|
||||
if (!manifestURL) {
|
||||
debug("webapps-clear-data: No manifest URL found for " + data.appId);
|
||||
let scope = appsService.getScopeByLocalId(data.appId);
|
||||
if (!scope) {
|
||||
debug("webapps-clear-data: No scope found for " + data.appId);
|
||||
return;
|
||||
}
|
||||
|
||||
this._db.getAllByManifestURL(manifestURL, function(records) {
|
||||
debug("Got " + records.length);
|
||||
for (let i = 0; i < records.length; i++) {
|
||||
this._db.delete(records[i].channelID, null, function() {
|
||||
debug("webapps-clear-data: " + manifestURL +
|
||||
" Could not delete entry " + records[i].channelID);
|
||||
});
|
||||
this._db.getByScope(scope, function(record) {
|
||||
this._db.delete(records.channelID, null, function() {
|
||||
debug("webapps-clear-data: " + scope +
|
||||
" Could not delete entry " + records.channelID);
|
||||
|
||||
// courtesy, but don't establish a connection
|
||||
// just for it
|
||||
if (this._ws) {
|
||||
debug("Had a connection, so telling the server");
|
||||
this._send("unregister", {channelID: records[i].channelID});
|
||||
this._send("unregister", {channelID: records.channelID});
|
||||
}
|
||||
}
|
||||
}.bind(this), function() {
|
||||
debug("webapps-clear-data: Error in getAllByManifestURL(" + manifestURL + ")");
|
||||
}.bind(this), function() {
|
||||
debug("webapps-clear-data: Error in getByScope(" + scope + ")");
|
||||
});
|
||||
});
|
||||
|
||||
break;
|
||||
@ -465,7 +449,7 @@ this.PushService = {
|
||||
* 1) the gap between the maximum working ping and the first ping that
|
||||
* gives an error (timeout) OR
|
||||
* 2) we have reached the pref of the maximum value we allow for a ping
|
||||
* (services.push.adaptive.upperLimit)
|
||||
* (dom.push.adaptive.upperLimit)
|
||||
*/
|
||||
_recalculatePing: true,
|
||||
|
||||
@ -512,6 +496,11 @@ this.PushService = {
|
||||
if (!prefs.get("enabled"))
|
||||
return null;
|
||||
|
||||
var globalMM = Cc["@mozilla.org/globalmessagemanager;1"]
|
||||
.getService(Ci.nsIFrameScriptLoader);
|
||||
|
||||
globalMM.loadFrameScript("chrome://global/content/PushServiceChildPreload.js", true);
|
||||
|
||||
this._db = new PushDB();
|
||||
|
||||
let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"]
|
||||
@ -672,7 +661,7 @@ this.PushService = {
|
||||
* This algorithm tries to search the best value between a disconnection and a
|
||||
* valid ping, to ensure better battery life and network resources usage.
|
||||
*
|
||||
* The value is saved in services.push.pingInterval
|
||||
* The value is saved in dom.push.pingInterval
|
||||
* @param wsWentDown [Boolean] if the WebSocket was closed or it is still alive
|
||||
*
|
||||
*/
|
||||
@ -842,7 +831,7 @@ this.PushService = {
|
||||
|
||||
let serverURL = prefs.get("serverURL");
|
||||
if (!serverURL) {
|
||||
debug("No services.push.serverURL found!");
|
||||
debug("No dom.push.serverURL found!");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -850,7 +839,7 @@ this.PushService = {
|
||||
try {
|
||||
uri = Services.io.newURI(serverURL, null, null);
|
||||
} catch(e) {
|
||||
debug("Error creating valid URI from services.push.serverURL (" +
|
||||
debug("Error creating valid URI from dom.push.serverURL (" +
|
||||
serverURL + ")");
|
||||
return;
|
||||
}
|
||||
@ -1090,7 +1079,7 @@ this.PushService = {
|
||||
debug("got new UAID: all re-register");
|
||||
|
||||
this._notifyAllAppsRegister()
|
||||
.then(this._dropRegistrations.bind(this))
|
||||
.then(this._dropRegistration.bind(this))
|
||||
.then(finishHandshake.bind(this));
|
||||
|
||||
return;
|
||||
@ -1279,35 +1268,32 @@ this.PushService = {
|
||||
},
|
||||
|
||||
// Fires a push-register system message to all applications that have
|
||||
// registrations.
|
||||
// registration.
|
||||
_notifyAllAppsRegister: function() {
|
||||
debug("notifyAllAppsRegister()");
|
||||
let deferred = Promise.defer();
|
||||
|
||||
// records are objects describing the registrations as stored in IndexedDB.
|
||||
// records are objects describing the registration as stored in IndexedDB.
|
||||
function wakeupRegisteredApps(records) {
|
||||
// Pages to be notified.
|
||||
// wakeupTable[manifestURL] -> [ pageURL ]
|
||||
// wakeupTable[scope] -> [ pageURL ]
|
||||
let wakeupTable = {};
|
||||
for (let i = 0; i < records.length; i++) {
|
||||
let record = records[i];
|
||||
if (!(record.manifestURL in wakeupTable))
|
||||
wakeupTable[record.manifestURL] = [];
|
||||
if (!(record.scope in wakeupTable))
|
||||
wakeupTable[record.scope] = [];
|
||||
|
||||
wakeupTable[record.manifestURL].push(record.pageURL);
|
||||
wakeupTable[record.scope].push(record.pageURL);
|
||||
}
|
||||
|
||||
let messenger = Cc["@mozilla.org/system-message-internal;1"]
|
||||
.getService(Ci.nsISystemMessagesInternal);
|
||||
// TODO -- test needed. E10s support needed.
|
||||
|
||||
for (let manifestURL in wakeupTable) {
|
||||
wakeupTable[manifestURL].forEach(function(pageURL) {
|
||||
messenger.sendMessage('push-register', {},
|
||||
Services.io.newURI(pageURL, null, null),
|
||||
Services.io.newURI(manifestURL, null, null));
|
||||
let globalMM = Cc['@mozilla.org/globalmessagemanager;1'].getService(Ci.nsIMessageListenerManager);
|
||||
for (let scope in wakeupTable) {
|
||||
wakeupTable[scope].forEach(function(pageURL) {
|
||||
globalMM.broadcastAsyncMessage('pushsubscriptionchanged', aPushRecord.scope);
|
||||
});
|
||||
}
|
||||
|
||||
deferred.resolve();
|
||||
}
|
||||
|
||||
@ -1317,22 +1303,36 @@ this.PushService = {
|
||||
},
|
||||
|
||||
_notifyApp: function(aPushRecord) {
|
||||
if (!aPushRecord || !aPushRecord.pageURL || !aPushRecord.manifestURL) {
|
||||
debug("notifyApp() something is undefined. Dropping notification");
|
||||
if (!aPushRecord || !aPushRecord.pageURL || !aPushRecord.scope) {
|
||||
debug("notifyApp() something is undefined. Dropping notification: "
|
||||
+ JSON.stringify(aPushRecord) );
|
||||
return;
|
||||
}
|
||||
|
||||
debug("notifyApp() " + aPushRecord.pageURL +
|
||||
" " + aPushRecord.manifestURL);
|
||||
" " + aPushRecord.scope);
|
||||
let pageURI = Services.io.newURI(aPushRecord.pageURL, null, null);
|
||||
let manifestURI = Services.io.newURI(aPushRecord.manifestURL, null, null);
|
||||
let scopeURI = Services.io.newURI(aPushRecord.scope, null, null);
|
||||
let message = {
|
||||
pushEndpoint: aPushRecord.pushEndpoint,
|
||||
version: aPushRecord.version
|
||||
};
|
||||
let messenger = Cc["@mozilla.org/system-message-internal;1"]
|
||||
.getService(Ci.nsISystemMessagesInternal);
|
||||
messenger.sendMessage('push', message, pageURI, manifestURI);
|
||||
|
||||
// If permission has been revoked, trash the message.
|
||||
if(Services.perms.testExactPermission(scopeURI, "push") != Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
debug("Does not have permission for push.")
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO data.
|
||||
let data = {
|
||||
payload: "Short as life is, we make it still shorter by the careless waste of time.",
|
||||
scope: aPushRecord.scope
|
||||
};
|
||||
|
||||
let globalMM = Cc['@mozilla.org/globalmessagemanager;1']
|
||||
.getService(Ci.nsIMessageListenerManager);
|
||||
globalMM.broadcastAsyncMessage('push', data);
|
||||
},
|
||||
|
||||
_updatePushRecord: function(aPushRecord) {
|
||||
@ -1342,7 +1342,7 @@ this.PushService = {
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
_dropRegistrations: function() {
|
||||
_dropRegistration: function() {
|
||||
let deferred = Promise.defer();
|
||||
this._db.drop(deferred.resolve, deferred.reject);
|
||||
return deferred.promise;
|
||||
@ -1365,9 +1365,8 @@ this.PushService = {
|
||||
* Called on message from the child process. aPageRecord is an object sent by
|
||||
* navigator.push, identifying the sending page and other fields.
|
||||
*/
|
||||
register: function(aPageRecord, aMessageManager) {
|
||||
debug("register()");
|
||||
|
||||
_registerWithServer: function(aPageRecord, aMessageManager) {
|
||||
let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"]
|
||||
.getService(Ci.nsIUUIDGenerator);
|
||||
// generateUUID() gives a UUID surrounded by {...}, slice them off.
|
||||
@ -1384,7 +1383,26 @@ this.PushService = {
|
||||
},
|
||||
function(message) {
|
||||
aMessageManager.sendAsyncMessage("PushService:Register:KO", message);
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
register: function(aPageRecord, aMessageManager) {
|
||||
debug("register(): " + JSON.stringify(aPageRecord));
|
||||
|
||||
this._db.getByScope(aPageRecord.scope,
|
||||
function(aPageRecord, aMessageManager, pushRecord) {
|
||||
if (pushRecord == null) {
|
||||
this._registerWithServer(aPageRecord, aMessageManager);
|
||||
}
|
||||
else {
|
||||
this._onRegistrationSuccess(aPageRecord, aMessageManager, pushRecord);
|
||||
}
|
||||
}.bind(this, aPageRecord, aMessageManager),
|
||||
function () {
|
||||
debug("getByScope failed");
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1421,10 +1439,12 @@ this.PushService = {
|
||||
channelID: data.channelID,
|
||||
pushEndpoint: data.pushEndpoint,
|
||||
pageURL: aPageRecord.pageURL,
|
||||
manifestURL: aPageRecord.manifestURL,
|
||||
scope: aPageRecord.scope,
|
||||
version: null
|
||||
};
|
||||
|
||||
debug("scope in _onRegisterSuccess: " + aPageRecord.scope)
|
||||
|
||||
this._updatePushRecord(record)
|
||||
.then(
|
||||
function() {
|
||||
@ -1436,7 +1456,7 @@ this.PushService = {
|
||||
this._send("unregister", {channelID: record.channelID});
|
||||
message["error"] = error;
|
||||
deferred.reject(message);
|
||||
}
|
||||
}.bind(this)
|
||||
);
|
||||
|
||||
return deferred.promise;
|
||||
@ -1479,7 +1499,7 @@ this.PushService = {
|
||||
* data is cheap, reliable notification is not.
|
||||
*/
|
||||
unregister: function(aPageRecord, aMessageManager) {
|
||||
debug("unregister()");
|
||||
debug("unregister() " + JSON.stringify(aPageRecord));
|
||||
|
||||
let fail = function(error) {
|
||||
debug("unregister() fail() error " + error);
|
||||
@ -1495,7 +1515,7 @@ this.PushService = {
|
||||
}
|
||||
|
||||
// Non-owner tried to unregister, say success, but don't do anything.
|
||||
if (record.manifestURL !== aPageRecord.manifestURL) {
|
||||
if (record.scope !== aPageRecord.scope) {
|
||||
aMessageManager.sendAsyncMessage("PushService:Unregister:OK", {
|
||||
requestID: aPageRecord.requestID,
|
||||
pushEndpoint: aPageRecord.pushEndpoint
|
||||
@ -1518,38 +1538,35 @@ this.PushService = {
|
||||
/**
|
||||
* Called on message from the child process
|
||||
*/
|
||||
registrations: function(aPageRecord, aMessageManager) {
|
||||
debug("registrations()");
|
||||
|
||||
if (aPageRecord.manifestURL) {
|
||||
this._db.getAllByManifestURL(aPageRecord.manifestURL,
|
||||
this._onRegistrationsSuccess.bind(this, aPageRecord, aMessageManager),
|
||||
this._onRegistrationsError.bind(this, aPageRecord, aMessageManager));
|
||||
}
|
||||
else {
|
||||
this._onRegistrationsError(aPageRecord, aMessageManager);
|
||||
}
|
||||
registration: function(aPageRecord, aMessageManager) {
|
||||
debug("registration()");
|
||||
this._db.getByScope(aPageRecord.scope,
|
||||
this._onRegistrationSuccess.bind(this, aPageRecord, aMessageManager),
|
||||
this._onRegistrationError.bind(this, aPageRecord, aMessageManager));
|
||||
},
|
||||
|
||||
_onRegistrationsSuccess: function(aPageRecord,
|
||||
aMessageManager,
|
||||
pushRecords) {
|
||||
let registrations = [];
|
||||
pushRecords.forEach(function(pushRecord) {
|
||||
registrations.push({
|
||||
__exposedProps__: { pushEndpoint: 'r', version: 'r' },
|
||||
pushEndpoint: pushRecord.pushEndpoint,
|
||||
version: pushRecord.version
|
||||
});
|
||||
});
|
||||
aMessageManager.sendAsyncMessage("PushService:Registrations:OK", {
|
||||
_onRegistrationSuccess: function(aPageRecord,
|
||||
aMessageManager,
|
||||
pushRecord) {
|
||||
|
||||
|
||||
let registration = null;
|
||||
|
||||
if (pushRecord) {
|
||||
registration = {
|
||||
pushEndpoint: pushRecord.pushEndpoint,
|
||||
version: pushRecord.version
|
||||
};
|
||||
}
|
||||
|
||||
aMessageManager.sendAsyncMessage("PushService:Registration:OK", {
|
||||
requestID: aPageRecord.requestID,
|
||||
registrations: registrations
|
||||
registration: registration
|
||||
});
|
||||
},
|
||||
|
||||
_onRegistrationsError: function(aPageRecord, aMessageManager) {
|
||||
aMessageManager.sendAsyncMessage("PushService:Registrations:KO", {
|
||||
_onRegistrationError: function(aPageRecord, aMessageManager) {
|
||||
aMessageManager.sendAsyncMessage("PushService:Registration:KO", {
|
||||
requestID: aPageRecord.requestID,
|
||||
error: "Database error"
|
||||
});
|
||||
@ -1733,7 +1750,7 @@ this.PushService = {
|
||||
|
||||
this._udpServer = Cc["@mozilla.org/network/udp-socket;1"]
|
||||
.createInstance(Ci.nsIUDPSocket);
|
||||
this._udpServer.init(-1, false, Services.scriptSecurityManager.getSystemPrincipal());
|
||||
this._udpServer.init(-1, false);
|
||||
this._udpServer.asyncListen(this);
|
||||
debug("listenForUDPWakeup listening on " + this._udpServer.port);
|
||||
|
||||
|
18
dom/push/PushServiceChildPreload.js
Normal file
@ -0,0 +1,18 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this,
|
||||
"swm",
|
||||
"@mozilla.org/serviceworkers/manager;1",
|
||||
"nsIServiceWorkerManager");
|
||||
|
||||
addMessageListener("push", function (aMessage) {
|
||||
swm.sendPushEvent(aMessage.data.scope, aMessage.data.payload);
|
||||
});
|
||||
|
||||
addMessageListener("pushsubscriptionchanged", function (aMessage) {
|
||||
swm.sendPushSubscriptionChangedEvent(aMessage.data);
|
||||
});
|
@ -30,11 +30,18 @@ PushServiceLauncher.prototype = {
|
||||
break;
|
||||
case "final-ui-startup":
|
||||
Services.obs.removeObserver(this, "final-ui-startup");
|
||||
if (!Services.prefs.getBoolPref("services.push.enabled")) {
|
||||
if (!Services.prefs.getBoolPref("dom.push.enabled")) {
|
||||
return;
|
||||
}
|
||||
Cu.import("resource://gre/modules/PushService.jsm");
|
||||
PushService.init();
|
||||
|
||||
let isParent = Cc["@mozilla.org/xre/runtime;1"]
|
||||
.getService(Ci.nsIXULRuntime)
|
||||
.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
|
||||
|
||||
if (isParent) {
|
||||
Cu.import("resource://gre/modules/PushService.jsm");
|
||||
PushService.init();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -12,3 +12,7 @@ EXTRA_COMPONENTS += [
|
||||
EXTRA_JS_MODULES += [
|
||||
'PushService.jsm',
|
||||
]
|
||||
|
||||
MOCHITEST_MANIFESTS += [
|
||||
'test/mochitest.ini',
|
||||
]
|
||||
|
27
dom/push/test/frame.html
Normal file
@ -0,0 +1,27 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
<script>
|
||||
|
||||
|
||||
function waitOnPushMessage(pushSubscription)
|
||||
{
|
||||
var p = new Promise(function(res, rej) {
|
||||
navigator.serviceWorker.onmessage = function(e) {
|
||||
if (e.data.type == "finished") {
|
||||
parent.ok(e.data.okay == "yes", "Got a push message.");
|
||||
res(pushSubscription);
|
||||
}
|
||||
};
|
||||
});
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
15
dom/push/test/mochitest.ini
Normal file
@ -0,0 +1,15 @@
|
||||
[DEFAULT]
|
||||
subsuite = push
|
||||
support-files =
|
||||
worker.js
|
||||
push-server.sjs
|
||||
frame.html
|
||||
|
||||
[test_has_permissions.html]
|
||||
skip-if = os == "android" || toolkit == "gonk"
|
||||
[test_permissions.html]
|
||||
skip-if = os == "android" || toolkit == "gonk"
|
||||
[test_register.html]
|
||||
skip-if = os == "android" || toolkit == "gonk"
|
||||
[test_multiple_register.html]
|
||||
skip-if = os == "android" || toolkit == "gonk"
|
26
dom/push/test/push-server.sjs
Normal file
@ -0,0 +1,26 @@
|
||||
function debug(str) {
|
||||
// dump("@@@ push-server " + str + "\n");
|
||||
}
|
||||
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
debug("handling request!");
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
let params = request.getHeader("X-Push-Server");
|
||||
debug("params = " + params);
|
||||
|
||||
let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
|
||||
xhr.open("PUT", params);
|
||||
xhr.send();
|
||||
xhr.onload = function(e) {
|
||||
debug("xhr : " + this.status);
|
||||
}
|
||||
xhr.onerror = function(e) {
|
||||
debug("xhr error: " + e);
|
||||
}
|
||||
|
||||
response.setStatusLine(request.httpVersion, "200", "OK");
|
||||
}
|
76
dom/push/test/test_has_permissions.html
Normal file
@ -0,0 +1,76 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
Bug 1038811: Push tests.
|
||||
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 1038811</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
</head>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1038811">Mozilla Bug 1038811</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
function debug(str) {
|
||||
// console.log(str + "\n");
|
||||
}
|
||||
|
||||
function start() {
|
||||
return navigator.serviceWorker.register("worker.js" + "?" + (Math.random()), {scope: "."})
|
||||
.then((swr) => registration = swr);
|
||||
}
|
||||
|
||||
function unregister() {
|
||||
return registration.unregister().then(function(result) {
|
||||
ok(result, "Unregister should return true.");
|
||||
});
|
||||
}
|
||||
|
||||
function hasPermission(swr) {
|
||||
var p = new Promise(function(res, rej) {
|
||||
swr.pushManager.hasPermission().then(
|
||||
function(status) {
|
||||
debug("status: " + status);
|
||||
ok(true, "hasPermission() returned a status");
|
||||
res(swr);
|
||||
}, function(error) {
|
||||
ok(false, "hasPermission failed.");
|
||||
res(swr);
|
||||
}
|
||||
);
|
||||
});
|
||||
return p;
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
start()
|
||||
.then(hasPermission)
|
||||
.then(unregister)
|
||||
.catch(function(e) {
|
||||
ok(false, "Some test failed with error " + e);
|
||||
}).then(SimpleTest.finish);
|
||||
}
|
||||
|
||||
SpecialPowers.addPermission('push', false, document);
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true]
|
||||
]}, runTest);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
128
dom/push/test/test_multiple_register.html
Normal file
@ -0,0 +1,128 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
Bug 1038811: Push tests.
|
||||
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 1038811</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
</head>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1038811">Mozilla Bug 1038811</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
function debug(str) {
|
||||
// console.log(str + "\n");
|
||||
}
|
||||
|
||||
function start() {
|
||||
return navigator.serviceWorker.register("worker.js" + "?" + (Math.random()), {scope: "."})
|
||||
.then((swr) => registration = swr);
|
||||
}
|
||||
|
||||
function unregister() {
|
||||
return registration.unregister().then(function(result) {
|
||||
ok(result, "Unregister should return true.");
|
||||
});
|
||||
}
|
||||
|
||||
function setupPushNotification(swr) {
|
||||
var p = new Promise(function(res, rej) {
|
||||
swr.pushManager.subscribe().then(
|
||||
function(pushSubscription) {
|
||||
ok(true, "successful registered for push notification");
|
||||
res({swr: swr, pushSubscription: pushSubscription});
|
||||
}, function(error) {
|
||||
ok(false, "could not register for push notification");
|
||||
res(null);
|
||||
}
|
||||
);
|
||||
});
|
||||
return p;
|
||||
}
|
||||
|
||||
function setupSecondEndpoint(result) {
|
||||
var p = new Promise(function(res, rej) {
|
||||
result.swr.pushManager.subscribe().then(
|
||||
function(pushSubscription) {
|
||||
ok(result.pushSubscription.endpoint == pushSubscription.endpoint, "setupSecondEndpoint - Got the same endpoint back.");
|
||||
res(result);
|
||||
}, function(error) {
|
||||
ok(false, "could not register for push notification");
|
||||
res(null);
|
||||
}
|
||||
);
|
||||
});
|
||||
return p;
|
||||
}
|
||||
|
||||
function getEndpointExpectNull(swr) {
|
||||
var p = new Promise(function(res, rej) {
|
||||
swr.pushManager.getSubscription().then(
|
||||
function(pushSubscription) {
|
||||
ok(pushSubscription == null, "getEndpoint should return null when app not subscribed.");
|
||||
res(swr);
|
||||
}, function(error) {
|
||||
ok(false, "could not register for push notification");
|
||||
res(null);
|
||||
}
|
||||
);
|
||||
});
|
||||
return p;
|
||||
}
|
||||
|
||||
function getEndpoint(result) {
|
||||
var p = new Promise(function(res, rej) {
|
||||
result.swr.pushManager.getSubscription().then(
|
||||
function(pushSubscription) {
|
||||
ok(result.pushSubscription.endpoint == pushSubscription.endpoint, "getEndpoint - Got the same endpoint back.");
|
||||
|
||||
res(pushSubscription);
|
||||
}, function(error) {
|
||||
ok(false, "could not register for push notification");
|
||||
res(null);
|
||||
}
|
||||
);
|
||||
});
|
||||
return p;
|
||||
}
|
||||
|
||||
function unregisterPushNotification(pushSubscription) {
|
||||
return pushSubscription.unsubscribe();
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
start()
|
||||
.then(getEndpointExpectNull)
|
||||
.then(setupPushNotification)
|
||||
.then(setupSecondEndpoint)
|
||||
.then(getEndpoint)
|
||||
.then(unregisterPushNotification)
|
||||
.then(unregister)
|
||||
.catch(function(e) {
|
||||
ok(false, "Some test failed with error " + e);
|
||||
}).then(SimpleTest.finish);
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true]
|
||||
]}, runTest);
|
||||
SpecialPowers.addPermission('push', true, document);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
91
dom/push/test/test_permissions.html
Normal file
@ -0,0 +1,91 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
Bug 1038811: Push tests.
|
||||
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 1038811</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
</head>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1038811">Mozilla Bug 1038811</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
function debug(str) {
|
||||
// console.log(str + "\n");
|
||||
}
|
||||
|
||||
function start() {
|
||||
return navigator.serviceWorker.register("worker.js" + "?" + (Math.random()), {scope: "."})
|
||||
.then((swr) => registration = swr);
|
||||
}
|
||||
|
||||
function unregister() {
|
||||
return registration.unregister().then(function(result) {
|
||||
ok(result, "Unregister should return true.");
|
||||
});
|
||||
}
|
||||
|
||||
function setupPushNotification(swr) {
|
||||
var p = new Promise(function(res, rej) {
|
||||
swr.pushManager.subscribe().then(
|
||||
function(pushSubscription) {
|
||||
ok(false, "subscribe() should fail because no permission for push");
|
||||
res(swr);
|
||||
}, function(error) {
|
||||
ok(true, "subscribe() could not register for push notification");
|
||||
res(swr);
|
||||
}
|
||||
);
|
||||
});
|
||||
return p;
|
||||
}
|
||||
|
||||
function getEndpoint(swr) {
|
||||
var p = new Promise(function(res, rej) {
|
||||
swr.pushManager.getSubscription().then(
|
||||
function(pushSubscription) {
|
||||
ok(false, "getSubscription() should fail because no permission for push");
|
||||
res(swr);
|
||||
}, function(error) {
|
||||
ok(true, "getSubscription() could not register for push notification");
|
||||
res(swr);
|
||||
}
|
||||
);
|
||||
});
|
||||
return p;
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
start()
|
||||
.then(setupPushNotification)
|
||||
.then(getEndpoint)
|
||||
.then(unregister)
|
||||
.catch(function(e) {
|
||||
ok(false, "Some test failed with error " + e);
|
||||
}).then(SimpleTest.finish);
|
||||
}
|
||||
|
||||
SpecialPowers.addPermission('push', false, document);
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true]
|
||||
]}, runTest);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
123
dom/push/test/test_register.html
Normal file
@ -0,0 +1,123 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
Bug 1038811: Push tests.
|
||||
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 1038811</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
</head>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1038811">Mozilla Bug 1038811</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
function debug(str) {
|
||||
// console.log(str + "\n");
|
||||
}
|
||||
|
||||
var controlledFrame;
|
||||
function createControlledIFrame(swr) {
|
||||
var p = new Promise(function(res, rej) {
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.id = "controlledFrame";
|
||||
iframe.src = "http://mochi.test:8888/tests/dom/push/test/frame.html";
|
||||
|
||||
iframe.onload = function() {
|
||||
res(swr)
|
||||
}
|
||||
controlledFrame = iframe;
|
||||
document.body.appendChild(iframe);
|
||||
});
|
||||
return p;
|
||||
}
|
||||
|
||||
function sendPushToPushServer(pushEndpoint) {
|
||||
// Work around CORS for now.
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', "http://mochi.test:8888/tests/dom/push/test/push-server.sjs", true);
|
||||
xhr.setRequestHeader("X-Push-Server", pushEndpoint);
|
||||
xhr.onload = function(e) {
|
||||
debug("xhr : " + this.status);
|
||||
}
|
||||
xhr.onerror = function(e) {
|
||||
debug("xhr error: " + e);
|
||||
}
|
||||
xhr.send("version=24601");
|
||||
}
|
||||
|
||||
var registration;
|
||||
|
||||
function start() {
|
||||
return navigator.serviceWorker.register("worker.js" + "?" + (Math.random()), {scope: "."})
|
||||
.then((swr) => registration = swr);
|
||||
}
|
||||
|
||||
function unregister() {
|
||||
return registration.unregister().then(function(result) {
|
||||
ok(result, "Unregister should return true.");
|
||||
});
|
||||
}
|
||||
|
||||
function setupPushNotification(swr) {
|
||||
var p = new Promise(function(res, rej) {
|
||||
swr.pushManager.subscribe().then(
|
||||
function(pushSubscription) {
|
||||
ok(true, "successful registered for push notification");
|
||||
res(pushSubscription);
|
||||
}, function(error) {
|
||||
ok(false, "could not register for push notification");
|
||||
res(null);
|
||||
}
|
||||
);
|
||||
});
|
||||
return p;
|
||||
}
|
||||
|
||||
function unregisterPushNotification(pushSubscription) {
|
||||
controlledFrame.parentNode.removeChild(controlledFrame);
|
||||
controlledFrame = null;
|
||||
return pushSubscription.unsubscribe();
|
||||
}
|
||||
|
||||
function waitForPushNotification(pushSubscription) {
|
||||
var p = controlledFrame.contentWindow.waitOnPushMessage();
|
||||
sendPushToPushServer(pushSubscription.endpoint);
|
||||
return p.then(function() {
|
||||
return pushSubscription;
|
||||
});
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
start()
|
||||
.then(createControlledIFrame)
|
||||
.then(setupPushNotification)
|
||||
.then(waitForPushNotification)
|
||||
.then(unregisterPushNotification)
|
||||
.then(unregister)
|
||||
.catch(function(e) {
|
||||
ok(false, "Some test failed with error " + e);
|
||||
}).then(SimpleTest.finish);
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true]
|
||||
]}, runTest);
|
||||
SpecialPowers.addPermission('push', true, document);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
16
dom/push/test/worker.js
Normal file
@ -0,0 +1,16 @@
|
||||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
addEventListener("push", function(event) {
|
||||
|
||||
self.clients.matchAll().then(function(result) {
|
||||
if (event instanceof PushEvent &&
|
||||
event.data instanceof PushMessageData &&
|
||||
event.data.text().length > 0) {
|
||||
|
||||
result[0].postMessage({type: "finished", okay: "yes"});
|
||||
return;
|
||||
}
|
||||
result[0].postMessage({type: "finished", okay: "no"});
|
||||
});
|
||||
});
|
147
dom/simplepush/Push.js
Normal file
@ -0,0 +1,147 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Don't modify this, instead set services.push.debug.
|
||||
let gDebuggingEnabled = false;
|
||||
|
||||
function debug(s) {
|
||||
if (gDebuggingEnabled)
|
||||
dump("-*- Push.js: " + s + "\n");
|
||||
}
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
|
||||
Cu.import("resource://gre/modules/AppsUtils.jsm");
|
||||
|
||||
const PUSH_CID = Components.ID("{cde1d019-fad8-4044-b141-65fb4fb7a245}");
|
||||
|
||||
/**
|
||||
* The Push component runs in the child process and exposes the SimplePush API
|
||||
* to the web application. The PushService running in the parent process is the
|
||||
* one actually performing all operations.
|
||||
*/
|
||||
function Push() {
|
||||
debug("Push Constructor");
|
||||
}
|
||||
|
||||
Push.prototype = {
|
||||
__proto__: DOMRequestIpcHelper.prototype,
|
||||
|
||||
contractID: "@mozilla.org/push/PushManager;1",
|
||||
|
||||
classID : PUSH_CID,
|
||||
|
||||
QueryInterface : XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer,
|
||||
Ci.nsISupportsWeakReference,
|
||||
Ci.nsIObserver]),
|
||||
|
||||
init: function(aWindow) {
|
||||
// Set debug first so that all debugging actually works.
|
||||
// NOTE: We don't add an observer here like in PushService. Flipping the
|
||||
// pref will require a reload of the app/page, which seems acceptable.
|
||||
gDebuggingEnabled = Services.prefs.getBoolPref("services.push.debug");
|
||||
debug("init()");
|
||||
|
||||
let principal = aWindow.document.nodePrincipal;
|
||||
let appsService = Cc["@mozilla.org/AppsService;1"]
|
||||
.getService(Ci.nsIAppsService);
|
||||
|
||||
this._manifestURL = appsService.getManifestURLByLocalId(principal.appId);
|
||||
this._pageURL = principal.URI;
|
||||
|
||||
this.initDOMRequestHelper(aWindow, [
|
||||
"PushService:Register:OK",
|
||||
"PushService:Register:KO",
|
||||
"PushService:Unregister:OK",
|
||||
"PushService:Unregister:KO",
|
||||
"PushService:Registrations:OK",
|
||||
"PushService:Registrations:KO"
|
||||
]);
|
||||
|
||||
this._cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
|
||||
.getService(Ci.nsISyncMessageSender);
|
||||
},
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
debug("receiveMessage()");
|
||||
let request = this.getRequest(aMessage.data.requestID);
|
||||
let json = aMessage.data;
|
||||
if (!request) {
|
||||
debug("No request " + json.requestID);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (aMessage.name) {
|
||||
case "PushService:Register:OK":
|
||||
Services.DOMRequest.fireSuccess(request, json.pushEndpoint);
|
||||
break;
|
||||
case "PushService:Register:KO":
|
||||
Services.DOMRequest.fireError(request, json.error);
|
||||
break;
|
||||
case "PushService:Unregister:OK":
|
||||
Services.DOMRequest.fireSuccess(request, json.pushEndpoint);
|
||||
break;
|
||||
case "PushService:Unregister:KO":
|
||||
Services.DOMRequest.fireError(request, json.error);
|
||||
break;
|
||||
case "PushService:Registrations:OK":
|
||||
Services.DOMRequest.fireSuccess(request, json.registrations);
|
||||
break;
|
||||
case "PushService:Registrations:KO":
|
||||
Services.DOMRequest.fireError(request, json.error);
|
||||
break;
|
||||
default:
|
||||
debug("NOT IMPLEMENTED! receiveMessage for " + aMessage.name);
|
||||
}
|
||||
},
|
||||
|
||||
register: function() {
|
||||
debug("register()");
|
||||
let req = this.createRequest();
|
||||
if (!Services.prefs.getBoolPref("services.push.connection.enabled")) {
|
||||
// If push socket is disabled by the user, immediately error rather than
|
||||
// timing out.
|
||||
Services.DOMRequest.fireErrorAsync(req, "NetworkError");
|
||||
return req;
|
||||
}
|
||||
|
||||
this._cpmm.sendAsyncMessage("Push:Register", {
|
||||
pageURL: this._pageURL.spec,
|
||||
manifestURL: this._manifestURL,
|
||||
requestID: this.getRequestId(req)
|
||||
});
|
||||
return req;
|
||||
},
|
||||
|
||||
unregister: function(aPushEndpoint) {
|
||||
debug("unregister(" + aPushEndpoint + ")");
|
||||
let req = this.createRequest();
|
||||
this._cpmm.sendAsyncMessage("Push:Unregister", {
|
||||
pageURL: this._pageURL.spec,
|
||||
manifestURL: this._manifestURL,
|
||||
requestID: this.getRequestId(req),
|
||||
pushEndpoint: aPushEndpoint
|
||||
});
|
||||
return req;
|
||||
},
|
||||
|
||||
registrations: function() {
|
||||
debug("registrations()");
|
||||
let req = this.createRequest();
|
||||
this._cpmm.sendAsyncMessage("Push:Registrations", {
|
||||
manifestURL: this._manifestURL,
|
||||
requestID: this.getRequestId(req)
|
||||
});
|
||||
return req;
|
||||
}
|
||||
}
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([Push]);
|
8
dom/simplepush/Push.manifest
Normal file
@ -0,0 +1,8 @@
|
||||
# DOM API
|
||||
component {cde1d019-fad8-4044-b141-65fb4fb7a245} Push.js
|
||||
contract @mozilla.org/push/PushManager;1 {cde1d019-fad8-4044-b141-65fb4fb7a245}
|
||||
|
||||
# Component to initialize PushService on startup.
|
||||
component {4b8caa3b-3c58-4f3c-a7f5-7bd9cb24c11d} PushServiceLauncher.js
|
||||
contract @mozilla.org/push/ServiceLauncher;1 {4b8caa3b-3c58-4f3c-a7f5-7bd9cb24c11d}
|
||||
category app-startup PushServiceLauncher @mozilla.org/push/ServiceLauncher;1
|
1892
dom/simplepush/PushService.jsm
Normal file
43
dom/simplepush/PushServiceLauncher.js
Normal file
@ -0,0 +1,43 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function PushServiceLauncher() {
|
||||
};
|
||||
|
||||
PushServiceLauncher.prototype = {
|
||||
classID: Components.ID("{4b8caa3b-3c58-4f3c-a7f5-7bd9cb24c11d}"),
|
||||
|
||||
contractID: "@mozilla.org/push/ServiceLauncher;1",
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
|
||||
observe: function observe(subject, topic, data) {
|
||||
switch (topic) {
|
||||
case "app-startup":
|
||||
Services.obs.addObserver(this, "final-ui-startup", true);
|
||||
break;
|
||||
case "final-ui-startup":
|
||||
Services.obs.removeObserver(this, "final-ui-startup");
|
||||
if (!Services.prefs.getBoolPref("services.push.enabled")) {
|
||||
return;
|
||||
}
|
||||
Cu.import("resource://gre/modules/PushService.jsm");
|
||||
PushService.init();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PushServiceLauncher]);
|
14
dom/simplepush/moz.build
Normal file
@ -0,0 +1,14 @@
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'Push.js',
|
||||
'Push.manifest',
|
||||
'PushServiceLauncher.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'PushService.jsm',
|
||||
]
|
@ -874,6 +874,8 @@ var interfaceNamesInGlobalScope =
|
||||
"Promise",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"PropertyNodeList",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "PushManager", pref: "dom.push.enabled"},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"RadioNodeList",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
@ -910,6 +912,8 @@ var interfaceNamesInGlobalScope =
|
||||
{name: "ServiceWorker", pref: "dom.serviceWorkers.enabled"},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "ServiceWorkerContainer", pref: "dom.serviceWorkers.enabled"},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "ServiceWorkerRegistration", pref: "dom.serviceWorkers.enabled"},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"SettingsLock",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
@ -65,7 +65,7 @@ function tests(aEnabled) {
|
||||
expectSuccess([1000, 1000.1]);
|
||||
|
||||
// The following loop shouldn't cause us to crash. See bug 701716.
|
||||
for (var i = 0; i < 10000; i++) {
|
||||
for (var i = 0; i < 1000; i++) {
|
||||
navigator.vibrate([100, 100]);
|
||||
}
|
||||
ok(true, "Didn't crash after issuing a lot of vibrate() calls.");
|
||||
|
@ -51,9 +51,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=633602
|
||||
var firstCall = !unLockedCoords;
|
||||
if (!firstCall) {
|
||||
todo(false, "mousemove is fired twice.");
|
||||
} else {
|
||||
isUnlocked = !document.mozPointerLockElement;
|
||||
}
|
||||
|
||||
isUnlocked = !document.mozPointerLockElement;
|
||||
unLockedCoords = {
|
||||
screenX: e.screenX,
|
||||
screenY: e.screenY,
|
||||
|
19
dom/webidl/PushEvent.webidl
Normal file
@ -0,0 +1,19 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* https://w3c.github.io/push-api/
|
||||
*/
|
||||
|
||||
[Constructor(DOMString type, optional PushEventInit eventInitDict), Exposed=ServiceWorker]
|
||||
interface PushEvent : ExtendableEvent {
|
||||
readonly attribute PushMessageData data;
|
||||
};
|
||||
|
||||
typedef USVString PushMessageDataInit;
|
||||
|
||||
dictionary PushEventInit : ExtendableEventInit {
|
||||
PushMessageDataInit data;
|
||||
};
|
@ -2,15 +2,27 @@
|
||||
/* 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/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* https://w3c.github.io/push-api/
|
||||
*/
|
||||
|
||||
[NoInterfaceObject,
|
||||
NavigatorProperty="push",
|
||||
JSImplementation="@mozilla.org/push/PushManager;1",
|
||||
CheckPermissions="push",
|
||||
Pref="services.push.enabled"]
|
||||
[JSImplementation="@mozilla.org/push/PushManager;1",
|
||||
Pref="dom.push.enabled"]
|
||||
interface PushManager {
|
||||
DOMRequest register();
|
||||
DOMRequest unregister(DOMString pushEndpoint);
|
||||
DOMRequest registrations();
|
||||
Promise<PushSubscription> subscribe();
|
||||
Promise<PushSubscription?> getSubscription();
|
||||
Promise<PushPermissionStatus> hasPermission();
|
||||
|
||||
// We need a setter in the bindings so that the C++ can use it,
|
||||
// but we don't want it exposed to client JS. WebPushMethodHider
|
||||
// always returns false.
|
||||
[Func="ServiceWorkerRegistration::WebPushMethodHider"] void setScope(DOMString scope);
|
||||
};
|
||||
|
||||
enum PushPermissionStatus
|
||||
{
|
||||
"granted",
|
||||
"denied",
|
||||
"default"
|
||||
};
|
||||
|
17
dom/webidl/PushMessageData.webidl
Normal file
@ -0,0 +1,17 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* https://w3c.github.io/push-api/
|
||||
*/
|
||||
|
||||
[Exposed=ServiceWorker]
|
||||
interface PushMessageData
|
||||
{
|
||||
ArrayBuffer arrayBuffer();
|
||||
Blob blob();
|
||||
object json();
|
||||
USVString text();
|
||||
};
|
17
dom/webidl/PushSubscription.webidl
Normal file
@ -0,0 +1,17 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* https://w3c.github.io/push-api/
|
||||
*/
|
||||
|
||||
[JSImplementation="@mozilla.org/push/PushSubscription;1",
|
||||
Constructor(DOMString pushEndpoint, DOMString scope, DOMString pageURL), ChromeOnly]
|
||||
interface PushSubscription
|
||||
{
|
||||
readonly attribute USVString endpoint;
|
||||
readonly attribute DOMString subscriptionId;
|
||||
Promise<boolean> unsubscribe();
|
||||
};
|
@ -27,7 +27,7 @@ interface ServiceWorkerContainer : EventTarget {
|
||||
Promise<ServiceWorkerRegistration> getRegistration(optional USVString documentURL = "");
|
||||
|
||||
[Throws]
|
||||
Promise<sequence<ServiceWorkerRegistration>> getRegistrations();
|
||||
Promise<sequence<ServiceWorkerRegistration>> getRegistrations();
|
||||
|
||||
attribute EventHandler oncontrollerchange;
|
||||
attribute EventHandler onreloadpage;
|
||||
|
@ -23,3 +23,10 @@ interface ServiceWorkerRegistration : EventTarget {
|
||||
// event
|
||||
attribute EventHandler onupdatefound;
|
||||
};
|
||||
|
||||
partial interface ServiceWorkerRegistration {
|
||||
#ifndef MOZ_SIMPLEPUSH
|
||||
[Throws, Pref="dom.push.enabled"]
|
||||
readonly attribute PushManager pushManager;
|
||||
#endif
|
||||
};
|
||||
|
15
dom/webidl/SimplePushManager.webidl
Normal file
@ -0,0 +1,15 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
[NavigatorProperty="push",
|
||||
JSImplementation="@mozilla.org/push/PushManager;1",
|
||||
CheckPermissions="push",
|
||||
Pref="services.push.enabled"]
|
||||
interface SimplePushManager {
|
||||
DOMRequest register();
|
||||
DOMRequest unregister(DOMString pushEndpoint);
|
||||
DOMRequest registrations();
|
||||
};
|
@ -11,6 +11,7 @@ GENERATED_WEBIDL_FILES = [
|
||||
PREPROCESSED_WEBIDL_FILES = [
|
||||
'HTMLMediaElement.webidl',
|
||||
'Navigator.webidl',
|
||||
'ServiceWorkerRegistration.webidl',
|
||||
'Window.webidl',
|
||||
]
|
||||
|
||||
@ -353,7 +354,6 @@ WEBIDL_FILES = [
|
||||
'ProfileTimelineMarker.webidl',
|
||||
'Promise.webidl',
|
||||
'PromiseDebugging.webidl',
|
||||
'PushManager.webidl',
|
||||
'RadioNodeList.webidl',
|
||||
'Range.webidl',
|
||||
'Rect.webidl',
|
||||
@ -382,7 +382,6 @@ WEBIDL_FILES = [
|
||||
'ServiceWorker.webidl',
|
||||
'ServiceWorkerContainer.webidl',
|
||||
'ServiceWorkerGlobalScope.webidl',
|
||||
'ServiceWorkerRegistration.webidl',
|
||||
'SettingChangeNotification.webidl',
|
||||
'SettingsManager.webidl',
|
||||
'ShadowRoot.webidl',
|
||||
@ -661,6 +660,19 @@ if CONFIG['MOZ_B2G_BT']:
|
||||
'BluetoothManager.webidl',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_SIMPLEPUSH']:
|
||||
WEBIDL_FILES += [
|
||||
'SimplePushManager.webidl'
|
||||
]
|
||||
else:
|
||||
WEBIDL_FILES += [
|
||||
'PushEvent.webidl',
|
||||
'PushManager.webidl',
|
||||
'PushManager.webidl',
|
||||
'PushMessageData.webidl',
|
||||
'PushSubscription.webidl',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_NFC']:
|
||||
WEBIDL_FILES += [
|
||||
'MozIsoDepTech.webidl',
|
||||
|
@ -200,6 +200,6 @@ ServiceWorkerClients::Claim()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
promise->MaybeReject(NS_ERROR_NOT_AVAILABLE);
|
||||
promise->MaybeResolve(JS::UndefinedHandleValue);
|
||||
return promise.forget();
|
||||
}
|
||||
|
@ -370,4 +370,59 @@ NS_INTERFACE_MAP_END_INHERITING(ExtendableEvent)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(InstallEvent, ExtendableEvent, mActiveWorker)
|
||||
|
||||
#ifndef MOZ_SIMPLEPUSH
|
||||
|
||||
PushMessageData::PushMessageData(const nsAString& aData)
|
||||
: mData(aData)
|
||||
{
|
||||
}
|
||||
|
||||
PushMessageData::~PushMessageData()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS0(PushMessageData);
|
||||
|
||||
|
||||
void
|
||||
PushMessageData::Json(JSContext* cx, JS::MutableHandle<JSObject*> aRetval)
|
||||
{
|
||||
//todo bug 1149195. Don't be lazy.
|
||||
NS_ABORT();
|
||||
}
|
||||
|
||||
void
|
||||
PushMessageData::Text(nsAString& aData)
|
||||
{
|
||||
aData = mData;
|
||||
}
|
||||
|
||||
void
|
||||
PushMessageData::ArrayBuffer(JSContext* cx, JS::MutableHandle<JSObject*> aRetval)
|
||||
{
|
||||
//todo bug 1149195. Don't be lazy.
|
||||
NS_ABORT();
|
||||
}
|
||||
|
||||
mozilla::dom::File*
|
||||
PushMessageData::Blob()
|
||||
{
|
||||
//todo bug 1149195. Don't be lazy.
|
||||
NS_ABORT();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PushEvent::PushEvent(EventTarget* aOwner)
|
||||
: ExtendableEvent(aOwner)
|
||||
{
|
||||
}
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(PushEvent)
|
||||
NS_INTERFACE_MAP_END_INHERITING(ExtendableEvent)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(PushEvent, ExtendableEvent)
|
||||
NS_IMPL_RELEASE_INHERITED(PushEvent, ExtendableEvent)
|
||||
|
||||
#endif /* ! MOZ_SIMPLEPUSH */
|
||||
|
||||
END_WORKERS_NAMESPACE
|
||||
|
@ -12,6 +12,12 @@
|
||||
#include "mozilla/dom/InstallEventBinding.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/Response.h"
|
||||
|
||||
#ifndef MOZ_SIMPLEPUSH
|
||||
#include "mozilla/dom/PushEventBinding.h"
|
||||
#include "mozilla/dom/PushMessageDataBinding.h"
|
||||
#endif
|
||||
|
||||
#include "nsProxyRelease.h"
|
||||
|
||||
class nsIInterceptedChannel;
|
||||
@ -216,5 +222,91 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef MOZ_SIMPLEPUSH
|
||||
|
||||
class PushMessageData final : public nsISupports,
|
||||
public nsWrapperCache
|
||||
{
|
||||
nsString mData;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
|
||||
{
|
||||
return mozilla::dom::PushMessageDataBinding_workers::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
nsISupports* GetParentObject() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Json(JSContext* cx, JS::MutableHandle<JSObject*> aRetval);
|
||||
void Text(nsAString& aData);
|
||||
void ArrayBuffer(JSContext* cx, JS::MutableHandle<JSObject*> aRetval);
|
||||
mozilla::dom::File* Blob();
|
||||
|
||||
explicit PushMessageData(const nsAString& aData);
|
||||
private:
|
||||
~PushMessageData();
|
||||
|
||||
};
|
||||
|
||||
class PushEvent final : public ExtendableEvent
|
||||
{
|
||||
nsString mData;
|
||||
nsMainThreadPtrHandle<ServiceWorker> mServiceWorker;
|
||||
|
||||
protected:
|
||||
explicit PushEvent(mozilla::dom::EventTarget* aOwner);
|
||||
~PushEvent() {}
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_FORWARD_TO_EVENT
|
||||
|
||||
virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
|
||||
{
|
||||
return mozilla::dom::PushEventBinding_workers::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
static already_AddRefed<PushEvent>
|
||||
Constructor(mozilla::dom::EventTarget* aOwner,
|
||||
const nsAString& aType,
|
||||
const PushEventInit& aOptions)
|
||||
{
|
||||
nsRefPtr<PushEvent> e = new PushEvent(aOwner);
|
||||
bool trusted = e->Init(aOwner);
|
||||
e->InitEvent(aType, aOptions.mBubbles, aOptions.mCancelable);
|
||||
e->SetTrusted(trusted);
|
||||
if(aOptions.mData.WasPassed()){
|
||||
e->mData = aOptions.mData.Value();
|
||||
}
|
||||
return e.forget();
|
||||
}
|
||||
|
||||
static already_AddRefed<PushEvent>
|
||||
Constructor(const GlobalObject& aGlobal,
|
||||
const nsAString& aType,
|
||||
const PushEventInit& aOptions,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<EventTarget> owner = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
return Constructor(owner, aType, aOptions);
|
||||
}
|
||||
|
||||
void PostInit(nsMainThreadPtrHandle<ServiceWorker>& aServiceWorker)
|
||||
{
|
||||
mServiceWorker = aServiceWorker;
|
||||
}
|
||||
|
||||
already_AddRefed<PushMessageData> Data()
|
||||
{
|
||||
nsRefPtr<PushMessageData> data = new PushMessageData(mData);
|
||||
return data.forget();
|
||||
}
|
||||
};
|
||||
#endif /* ! MOZ_SIMPLEPUSH */
|
||||
|
||||
END_WORKERS_NAMESPACE
|
||||
#endif /* mozilla_dom_workers_serviceworkerevents_h__ */
|
||||
|