Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
263 lines
7.3 KiB
JavaScript
263 lines
7.3 KiB
JavaScript
'use strict';
|
|
|
|
/* global SettingsListener, SettingsURL, CallscreenWindow, applications */
|
|
/* global Service, LazyLoader, toneUpgrader */
|
|
/* r=? dialer+system peers for changes in this file. */
|
|
|
|
(function(exports) {
|
|
/**
|
|
*
|
|
* The delay between an incoming phone call and the first ring or vibration
|
|
* needs to be as short as possible.
|
|
*
|
|
* This simple module keeps the ringtone (blob) around and starts alerting the
|
|
* user as soon as a new incoming call is detected via the mozTelephony API.
|
|
* And it opens an AttentionWindow with the preloaded callscreen app inside.
|
|
*
|
|
* We also listen for the sleep and volumedown hardware buttons to provide
|
|
* the user with an easy way to stop the ringing.
|
|
*
|
|
* @example
|
|
* var dialerAgent = new DialerAgent();
|
|
* dialerAgent.start(); // Attach the event listeners.
|
|
* dialerAgent.stop(); // Deattach the event listeners.
|
|
*
|
|
* @class DialerAgent
|
|
* @requires SettingsListener
|
|
* @requires SettingsURL
|
|
* @requires Service
|
|
* @requires LazyLoader
|
|
*
|
|
**/
|
|
|
|
var DialerAgent = function DialerAgent() {
|
|
var telephony = navigator.mozTelephony;
|
|
if (!telephony) {
|
|
return;
|
|
}
|
|
|
|
this._telephony = telephony;
|
|
|
|
this._started = false;
|
|
this._shouldVibrate = true;
|
|
this._alerting = false;
|
|
this._vibrateInterval = null;
|
|
|
|
var player = new Audio();
|
|
this._player = player;
|
|
// XXX: This will need to be updated for bug 961967
|
|
// (audio competing in system app)
|
|
player.mozAudioChannelType = 'ringer';
|
|
player.preload = 'metadata';
|
|
player.loop = true;
|
|
this.freeCallscreenWindow = this.freeCallscreenWindow.bind(this);
|
|
this.makeFakeNotification = this.makeFakeNotification.bind(this);
|
|
};
|
|
|
|
DialerAgent.prototype.freeCallscreenWindow = function() {
|
|
/* Free the callscreen window unless there are active calls or the
|
|
* callscreen is visible. */
|
|
if (this._callscreenWindow && !this.onCall() &&
|
|
!this._callscreenWindow.isVisible()) {
|
|
this._callscreenWindow.free();
|
|
}
|
|
};
|
|
|
|
DialerAgent.prototype.start = function da_start() {
|
|
if (!this._telephony) {
|
|
return;
|
|
}
|
|
|
|
if (this._started) {
|
|
throw 'Instance should not be start()\'ed twice.';
|
|
}
|
|
this._started = true;
|
|
|
|
SettingsListener.observe('audio.volume.notification', 7, function(value) {
|
|
this._playRing();
|
|
}.bind(this));
|
|
|
|
SettingsListener.observe('dialer.ringtone', '', function(value) {
|
|
LazyLoader.load(['shared/js/settings_url.js']).then(function() {
|
|
var phoneSoundURL = new SettingsURL();
|
|
|
|
this._player.pause();
|
|
this._player.src = phoneSoundURL.set(value);
|
|
this._playRing();
|
|
}.bind(this)).catch((err) => {
|
|
console.error(err);
|
|
});
|
|
}.bind(this));
|
|
|
|
// We have new default ringtones in 2.0, so check if the version is upgraded
|
|
// then execute the necessary migration.
|
|
if (Service.query('justUpgraded')) {
|
|
LazyLoader.load('js/tone_upgrader.js').then(() => {
|
|
toneUpgrader.perform('ringtone');
|
|
});
|
|
}
|
|
|
|
SettingsListener.observe('vibration.enabled', true, function(value) {
|
|
this._shouldVibrate = !!value;
|
|
}.bind(this));
|
|
|
|
this._telephony.addEventListener('callschanged', this);
|
|
|
|
window.addEventListener('sleep', this);
|
|
window.addEventListener('wake', this);
|
|
window.addEventListener('volumedown', this);
|
|
window.addEventListener('mozmemorypressure', this.freeCallscreenWindow);
|
|
|
|
this._callscreenWindow = new CallscreenWindow();
|
|
this._callscreenWindow.hide();
|
|
|
|
if (applications && applications.ready) {
|
|
this.makeFakeNotification();
|
|
} else {
|
|
window.addEventListener('applicationready', this.makeFakeNotification);
|
|
}
|
|
|
|
Service.registerState('onCall', this);
|
|
|
|
return this;
|
|
};
|
|
|
|
DialerAgent.prototype.makeFakeNotification = function() {
|
|
window.removeEventListener('applicationready', this.makeFakeNotification);
|
|
this._callscreenWindow && this._callscreenWindow.makeNotification();
|
|
};
|
|
|
|
DialerAgent.prototype.stop = function da_stop() {
|
|
if (!this._started) {
|
|
return;
|
|
}
|
|
this._started = false;
|
|
|
|
this._telephony.removeEventListener('callschanged', this);
|
|
|
|
window.removeEventListener('sleep', this);
|
|
window.removeEventListener('wake', this);
|
|
window.removeEventListener('volumedown', this);
|
|
window.removeEventListener('mozmemorypressure', this.freeCallscreenWindow);
|
|
|
|
Service.unregisterState('onCall', this);
|
|
|
|
// TODO: should remove the settings listener once the helper
|
|
// allows it.
|
|
// See bug 981373.
|
|
};
|
|
|
|
DialerAgent.prototype.handleEvent = function da_handleEvent(evt) {
|
|
if (evt.type === 'volumedown') {
|
|
this._stopAlerting();
|
|
return;
|
|
}
|
|
|
|
if ((evt.type === 'sleep') && this._alerting) {
|
|
this._stopAlerting();
|
|
return;
|
|
}
|
|
|
|
if ((evt.type === 'sleep') && this.onCall()) {
|
|
// Hangup all calls
|
|
this._telephony.calls.forEach(call => call.hangUp());
|
|
|
|
if (this._telephony.conferenceGroup.calls.length > 0) {
|
|
this._telephony.conferenceGroup.hangUp();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if ((evt.type === 'wake') && this.onCall()) {
|
|
Service.request('turnScreenOn');
|
|
return;
|
|
}
|
|
|
|
if (evt.type !== 'callschanged') {
|
|
return;
|
|
}
|
|
|
|
var calls = this._telephony.calls;
|
|
if (calls.length === 0) {
|
|
Service.request('turnScreenOn');
|
|
return;
|
|
}
|
|
|
|
var calling = calls.some(function(call) {
|
|
if (call.state === 'incoming' || call.state === 'dialing') {
|
|
return true;
|
|
}
|
|
});
|
|
|
|
if (calling) {
|
|
this.openCallscreen();
|
|
}
|
|
|
|
var incomingCall = calls[calls.length - 1];
|
|
if (this._alerting || incomingCall.state !== 'incoming') {
|
|
return;
|
|
}
|
|
|
|
var self = this;
|
|
|
|
self._startAlerting();
|
|
|
|
incomingCall.addEventListener('statechange', function callStateChange() {
|
|
incomingCall.removeEventListener('statechange', callStateChange);
|
|
|
|
self._stopAlerting();
|
|
});
|
|
};
|
|
|
|
DialerAgent.prototype._playRing = function da_playRing () {
|
|
// Notice that, even we are in the vibration mode, we would still play the
|
|
// silence ringer. That is because when the incoming call is coming, other
|
|
// playing sound should be paused. Therefore, we need to a silence ringer
|
|
// to compete for the audio output.
|
|
if (this._alerting) {
|
|
this._player.play();
|
|
}
|
|
};
|
|
|
|
DialerAgent.prototype._startAlerting = function da_startAlerting() {
|
|
this._alerting = true;
|
|
|
|
if ('vibrate' in navigator && this._shouldVibrate) {
|
|
this._vibrateInterval = window.setInterval(function vibrate() {
|
|
navigator.vibrate([200]);
|
|
}, 600);
|
|
navigator.vibrate([200]);
|
|
}
|
|
|
|
this._playRing();
|
|
};
|
|
|
|
DialerAgent.prototype._stopAlerting = function da_stopAlerting() {
|
|
var player = this._player;
|
|
|
|
this._alerting = false;
|
|
if (player && player.readyState > player.HAVE_NOTHING) {
|
|
player.pause();
|
|
player.currentTime = 0;
|
|
}
|
|
|
|
window.clearInterval(this._vibrateInterval);
|
|
};
|
|
|
|
DialerAgent.prototype.openCallscreen = function() {
|
|
if (this._callscreenWindow) {
|
|
this._callscreenWindow.ensure();
|
|
this._callscreenWindow.requestOpen();
|
|
}
|
|
};
|
|
|
|
DialerAgent.prototype.onCall = function() {
|
|
var numOpenLines = this._telephony.calls.length +
|
|
(this._telephony.conferenceGroup.calls.length ? 1 : 0);
|
|
|
|
return (numOpenLines > 0);
|
|
};
|
|
|
|
exports.DialerAgent = DialerAgent;
|
|
}(window));
|