Bug 1011472 - Add audio alert for incoming call r=florian,standard8
This commit is contained in:
@@ -1512,6 +1512,7 @@ pref("image.mem.max_decoded_image_kb", 256000);
|
|||||||
#ifdef MOZ_LOOP
|
#ifdef MOZ_LOOP
|
||||||
pref("loop.server", "https://loop.services.mozilla.com");
|
pref("loop.server", "https://loop.services.mozilla.com");
|
||||||
pref("loop.do_not_disturb", false);
|
pref("loop.do_not_disturb", false);
|
||||||
|
pref("loop.ringtone", "chrome://browser/content/loop/shared/sounds/Firefox-Long.ogg");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// serverURL to be assigned by services team
|
// serverURL to be assigned by services team
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ this.EXPORTED_SYMBOLS = ["injectLoopAPI"];
|
|||||||
* @param {nsIDOMWindow} targetWindow The content window to attach the API.
|
* @param {nsIDOMWindow} targetWindow The content window to attach the API.
|
||||||
*/
|
*/
|
||||||
function injectLoopAPI(targetWindow) {
|
function injectLoopAPI(targetWindow) {
|
||||||
|
let ringer;
|
||||||
|
let ringerStopper;
|
||||||
|
|
||||||
let api = {
|
let api = {
|
||||||
/**
|
/**
|
||||||
* Sets and gets the "do not disturb" mode activation flag.
|
* Sets and gets the "do not disturb" mode activation flag.
|
||||||
@@ -149,6 +152,50 @@ function injectLoopAPI(targetWindow) {
|
|||||||
value: function(prefName) {
|
value: function(prefName) {
|
||||||
return MozLoopService.getLoopCharPref(prefName);
|
return MozLoopService.getLoopCharPref(prefName);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts alerting the user about an incoming call
|
||||||
|
*/
|
||||||
|
startAlerting: {
|
||||||
|
enumerable: true,
|
||||||
|
configurable: true,
|
||||||
|
writable: true,
|
||||||
|
value: function() {
|
||||||
|
let chromeWindow = getChromeWindow(targetWindow);
|
||||||
|
chromeWindow.getAttention();
|
||||||
|
ringer = new chromeWindow.Audio();
|
||||||
|
ringer.src = Services.prefs.getCharPref("loop.ringtone");
|
||||||
|
ringer.loop = true;
|
||||||
|
ringer.load();
|
||||||
|
ringer.play();
|
||||||
|
targetWindow.document.addEventListener("visibilitychange",
|
||||||
|
ringerStopper = function(event) {
|
||||||
|
if (event.currentTarget.hidden) {
|
||||||
|
api.stopAlerting.value();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops alerting the user about an incoming call
|
||||||
|
*/
|
||||||
|
stopAlerting: {
|
||||||
|
enumerable: true,
|
||||||
|
configurable: true,
|
||||||
|
writable: true,
|
||||||
|
value: function() {
|
||||||
|
if (ringerStopper) {
|
||||||
|
targetWindow.document.removeEventListener("visibilitychange",
|
||||||
|
ringerStopper);
|
||||||
|
ringerStopper = null;
|
||||||
|
}
|
||||||
|
if (ringer) {
|
||||||
|
ringer.pause();
|
||||||
|
ringer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -168,3 +215,12 @@ function injectLoopAPI(targetWindow) {
|
|||||||
// Handle window.close correctly on the panel and chatbox.
|
// Handle window.close correctly on the panel and chatbox.
|
||||||
hookWindowCloseForPanelClose(targetWindow);
|
hookWindowCloseForPanelClose(targetWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getChromeWindow(contentWin) {
|
||||||
|
return contentWin.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsIWebNavigation)
|
||||||
|
.QueryInterface(Ci.nsIDocShellTreeItem)
|
||||||
|
.rootTreeItem
|
||||||
|
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsIDOMWindow);
|
||||||
|
}
|
||||||
|
|||||||
@@ -53,8 +53,7 @@ loop.conversation = (function(OT, mozL10n) {
|
|||||||
*/
|
*/
|
||||||
handleDecline: function(event) {
|
handleDecline: function(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
// XXX For now, we just close the window.
|
this.model.trigger("decline");
|
||||||
window.close();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -95,6 +94,7 @@ loop.conversation = (function(OT, mozL10n) {
|
|||||||
routes: {
|
routes: {
|
||||||
"incoming/:version": "incoming",
|
"incoming/:version": "incoming",
|
||||||
"call/accept": "accept",
|
"call/accept": "accept",
|
||||||
|
"call/decline": "decline",
|
||||||
"call/ongoing": "conversation",
|
"call/ongoing": "conversation",
|
||||||
"call/ended": "ended"
|
"call/ended": "ended"
|
||||||
},
|
},
|
||||||
@@ -120,10 +120,14 @@ loop.conversation = (function(OT, mozL10n) {
|
|||||||
* by the router from the URL.
|
* by the router from the URL.
|
||||||
*/
|
*/
|
||||||
incoming: function(loopVersion) {
|
incoming: function(loopVersion) {
|
||||||
|
window.navigator.mozLoop.startAlerting();
|
||||||
this._conversation.set({loopVersion: loopVersion});
|
this._conversation.set({loopVersion: loopVersion});
|
||||||
this._conversation.once("accept", function() {
|
this._conversation.once("accept", function() {
|
||||||
this.navigate("call/accept", {trigger: true});
|
this.navigate("call/accept", {trigger: true});
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
this._conversation.once("decline", function() {
|
||||||
|
this.navigate("call/decline", {trigger: true});
|
||||||
|
}.bind(this));
|
||||||
this.loadView(new IncomingCallView({model: this._conversation}));
|
this.loadView(new IncomingCallView({model: this._conversation}));
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -131,12 +135,22 @@ loop.conversation = (function(OT, mozL10n) {
|
|||||||
* Accepts an incoming call.
|
* Accepts an incoming call.
|
||||||
*/
|
*/
|
||||||
accept: function() {
|
accept: function() {
|
||||||
|
window.navigator.mozLoop.stopAlerting();
|
||||||
this._conversation.initiate({
|
this._conversation.initiate({
|
||||||
baseServerUrl: window.navigator.mozLoop.serverUrl,
|
baseServerUrl: window.navigator.mozLoop.serverUrl,
|
||||||
outgoing: false
|
outgoing: false
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declines an incoming call.
|
||||||
|
*/
|
||||||
|
decline: function() {
|
||||||
|
window.navigator.mozLoop.stopAlerting();
|
||||||
|
// XXX For now, we just close the window
|
||||||
|
window.close();
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* conversation is the route when the conversation is active. The start
|
* conversation is the route when the conversation is active. The start
|
||||||
* route should be navigated to first.
|
* route should be navigated to first.
|
||||||
|
|||||||
BIN
browser/components/loop/content/shared/sounds/Firefox-Long.ogg
Normal file
BIN
browser/components/loop/content/shared/sounds/Firefox-Long.ogg
Normal file
Binary file not shown.
@@ -21,6 +21,7 @@ browser.jar:
|
|||||||
content/browser/loop/shared/libs/sjcl-dev20140604.js (content/shared/libs/sjcl-dev20140604.js)
|
content/browser/loop/shared/libs/sjcl-dev20140604.js (content/shared/libs/sjcl-dev20140604.js)
|
||||||
content/browser/loop/shared/libs/token.js (content/shared/libs/token.js)
|
content/browser/loop/shared/libs/token.js (content/shared/libs/token.js)
|
||||||
content/browser/loop/shared/libs/hawk-browser-2.2.1.js (content/shared/libs/hawk-browser-2.2.1.js)
|
content/browser/loop/shared/libs/hawk-browser-2.2.1.js (content/shared/libs/hawk-browser-2.2.1.js)
|
||||||
|
content/browser/loop/shared/sounds/Firefox-Long.ogg (content/shared/sounds/Firefox-Long.ogg)
|
||||||
content/browser/loop/libs/l10n.js (content/libs/l10n.js)
|
content/browser/loop/libs/l10n.js (content/libs/l10n.js)
|
||||||
content/browser/loop/js/desktopRouter.js (content/js/desktopRouter.js)
|
content/browser/loop/js/desktopRouter.js (content/js/desktopRouter.js)
|
||||||
content/browser/loop/js/conversation.js (content/js/conversation.js)
|
content/browser/loop/js/conversation.js (content/js/conversation.js)
|
||||||
|
|||||||
@@ -26,6 +26,12 @@ describe("loop.conversation", function() {
|
|||||||
window.navigator.mozLoop = {
|
window.navigator.mozLoop = {
|
||||||
get serverUrl() {
|
get serverUrl() {
|
||||||
return "http://example.com";
|
return "http://example.com";
|
||||||
|
},
|
||||||
|
|
||||||
|
startAlerting: function() {
|
||||||
|
},
|
||||||
|
|
||||||
|
stopAlerting: function() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -119,6 +125,13 @@ describe("loop.conversation", function() {
|
|||||||
sinon.assert.calledWithExactly(router.loadView,
|
sinon.assert.calledWithExactly(router.loadView,
|
||||||
sinon.match.instanceOf(loop.conversation.IncomingCallView));
|
sinon.match.instanceOf(loop.conversation.IncomingCallView));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should start alerting", function() {
|
||||||
|
sandbox.stub(window.navigator.mozLoop, "startAlerting");
|
||||||
|
router.incoming("fakeVersion");
|
||||||
|
|
||||||
|
sinon.assert.calledOnce(window.navigator.mozLoop.startAlerting);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#accept", function() {
|
describe("#accept", function() {
|
||||||
@@ -131,6 +144,13 @@ describe("loop.conversation", function() {
|
|||||||
outgoing: false
|
outgoing: false
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should stop alerting", function() {
|
||||||
|
sandbox.stub(window.navigator.mozLoop, "stopAlerting");
|
||||||
|
router.accept();
|
||||||
|
|
||||||
|
sinon.assert.calledOnce(window.navigator.mozLoop.stopAlerting);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#conversation", function() {
|
describe("#conversation", function() {
|
||||||
@@ -163,6 +183,25 @@ describe("loop.conversation", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("#decline", function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
sandbox.stub(window, "close");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should close the window", function() {
|
||||||
|
router.decline();
|
||||||
|
|
||||||
|
sinon.assert.calledOnce(window.close);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should stop alerting", function() {
|
||||||
|
sandbox.stub(window.navigator.mozLoop, "stopAlerting");
|
||||||
|
router.decline();
|
||||||
|
|
||||||
|
sinon.assert.calledOnce(window.navigator.mozLoop.stopAlerting);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("#ended", function() {
|
describe("#ended", function() {
|
||||||
// XXX When the call is ended gracefully, we should check that we
|
// XXX When the call is ended gracefully, we should check that we
|
||||||
// close connections nicely
|
// close connections nicely
|
||||||
@@ -254,13 +293,14 @@ describe("loop.conversation", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("#handleDecline", function() {
|
describe("#handleDecline", function() {
|
||||||
it("should close the window", function() {
|
it("should trigger an 'decline' conversation model event" ,
|
||||||
sandbox.stub(window, "close");
|
function(done) {
|
||||||
|
conversation.once("decline", function() {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
view.handleDecline({preventDefault: sandbox.spy()});
|
view.handleDecline({preventDefault: sandbox.spy()});
|
||||||
|
});
|
||||||
sinon.assert.calledOnce(window.close);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user