Bug 1011472 - Add audio alert for incoming call r=florian,standard8

This commit is contained in:
Adam Roach [:abr]
2014-06-26 18:55:03 -05:00
parent c809ffde16
commit c7c126a64c
6 changed files with 120 additions and 8 deletions

View File

@@ -1512,6 +1512,7 @@ pref("image.mem.max_decoded_image_kb", 256000);
#ifdef MOZ_LOOP
pref("loop.server", "https://loop.services.mozilla.com");
pref("loop.do_not_disturb", false);
pref("loop.ringtone", "chrome://browser/content/loop/shared/sounds/Firefox-Long.ogg");
#endif
// serverURL to be assigned by services team

View File

@@ -24,6 +24,9 @@ this.EXPORTED_SYMBOLS = ["injectLoopAPI"];
* @param {nsIDOMWindow} targetWindow The content window to attach the API.
*/
function injectLoopAPI(targetWindow) {
let ringer;
let ringerStopper;
let api = {
/**
* Sets and gets the "do not disturb" mode activation flag.
@@ -149,6 +152,50 @@ function injectLoopAPI(targetWindow) {
value: function(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.
hookWindowCloseForPanelClose(targetWindow);
}
function getChromeWindow(contentWin) {
return contentWin.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
}

View File

@@ -53,8 +53,7 @@ loop.conversation = (function(OT, mozL10n) {
*/
handleDecline: function(event) {
event.preventDefault();
// XXX For now, we just close the window.
window.close();
this.model.trigger("decline");
}
});
@@ -95,6 +94,7 @@ loop.conversation = (function(OT, mozL10n) {
routes: {
"incoming/:version": "incoming",
"call/accept": "accept",
"call/decline": "decline",
"call/ongoing": "conversation",
"call/ended": "ended"
},
@@ -120,10 +120,14 @@ loop.conversation = (function(OT, mozL10n) {
* by the router from the URL.
*/
incoming: function(loopVersion) {
window.navigator.mozLoop.startAlerting();
this._conversation.set({loopVersion: loopVersion});
this._conversation.once("accept", function() {
this.navigate("call/accept", {trigger: true});
}.bind(this));
this._conversation.once("decline", function() {
this.navigate("call/decline", {trigger: true});
}.bind(this));
this.loadView(new IncomingCallView({model: this._conversation}));
},
@@ -131,12 +135,22 @@ loop.conversation = (function(OT, mozL10n) {
* Accepts an incoming call.
*/
accept: function() {
window.navigator.mozLoop.stopAlerting();
this._conversation.initiate({
baseServerUrl: window.navigator.mozLoop.serverUrl,
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
* route should be navigated to first.

View File

@@ -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/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/sounds/Firefox-Long.ogg (content/shared/sounds/Firefox-Long.ogg)
content/browser/loop/libs/l10n.js (content/libs/l10n.js)
content/browser/loop/js/desktopRouter.js (content/js/desktopRouter.js)
content/browser/loop/js/conversation.js (content/js/conversation.js)

View File

@@ -26,6 +26,12 @@ describe("loop.conversation", function() {
window.navigator.mozLoop = {
get serverUrl() {
return "http://example.com";
},
startAlerting: function() {
},
stopAlerting: function() {
}
};
});
@@ -119,6 +125,13 @@ describe("loop.conversation", function() {
sinon.assert.calledWithExactly(router.loadView,
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() {
@@ -131,6 +144,13 @@ describe("loop.conversation", function() {
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() {
@@ -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() {
// XXX When the call is ended gracefully, we should check that we
// close connections nicely
@@ -254,13 +293,14 @@ describe("loop.conversation", function() {
});
describe("#handleDecline", function() {
it("should close the window", function() {
sandbox.stub(window, "close");
it("should trigger an 'decline' conversation model event" ,
function(done) {
conversation.once("decline", function() {
done();
});
view.handleDecline({preventDefault: sandbox.spy()});
sinon.assert.calledOnce(window.close);
});
view.handleDecline({preventDefault: sandbox.spy()});
});
});
});
});