VulpesOS/gaia/apps/communications/dialer/js/dialer.js
OverSu b38dea0597 Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
2026-09-30 23:13:03 +02:00

437 lines
13 KiB
JavaScript
Executable file

'use strict';
/* global CallLog, CallLogDBManager, Contacts, KeypadManager, LazyLoader,
MmiManager, Notification, NotificationHelper, SettingsListener,
SimSettingsHelper, SuggestionBar, TelephonyHelper, Utils, Voicemail,
MozActivity, Navigation */
var NavbarManager = {
init: function nm_init() {
Navigation.show('keypad');
document.getElementById('views').addEventListener(
'click',
function(e) {
var destination = e.target.dataset &&
e.target.dataset.destination;
if (!destination) {
return;
}
Navigation.show(destination);
}
);
},
hide: function() {
var views = document.getElementById('views');
views.classList.add('hide-toolbar');
},
show: function() {
var views = document.getElementById('views');
views.classList.remove('hide-toolbar');
},
};
var CallHandler = (function callHandler() {
var COMMS_APP_ORIGIN = document.location.protocol + '//' +
document.location.host;
var FB_SYNC_ERROR_PARAM = 'isSyncError';
/* === Settings === */
var engineeringModeKey = null;
/* === WebActivity === */
function handleActivity(activity) {
// Workaround here until the bug 787415 is fixed
// Gecko is sending an activity event in every multiple entry point
// instead only the one that the href match.
if (activity.source.name != 'dial') {
return;
}
var number = activity.source.data.number;
if (number) {
KeypadManager.updatePhoneNumber(number, 'begin', false);
if (Navigation.currentView != 'keypad') {
Navigation.showKeypad();
}
} else {
if (Navigation.currentView != 'contacts') {
Navigation.showContacts();
}
}
}
/* === Notifications support === */
/**
* Retrieves the parameters from an URL and forms an object with them.
*
* @param {String} input A string holding the parameters attached to an URL.
* @return {Object} An object built using the parameters.
*/
function deserializeParameters(input) {
var rparams = /([^?=&]+)(?:=([^&]*))?/g;
var parsed = {};
input.replace(rparams, function($0, $1, $2) {
parsed[$1] = decodeURIComponent($2);
});
return parsed;
}
function handleNotification(evt) {
if (!evt.clicked) {
return;
}
navigator.mozApps.getSelf().onsuccess = function gotSelf(selfEvt) {
var app = selfEvt.target.result;
app.launch('dialer');
var location = document.createElement('a');
location.href = evt.imageURL;
if (location.search.indexOf(FB_SYNC_ERROR_PARAM) !== -1) {
Navigation.showContacts();
} else if (location.search.indexOf('ussdMessage') !== -1) {
var params = deserializeParameters(evt.imageURL);
Notification.get({ tag: evt.tag }).then(function(notifications) {
for (var i = 0; i < notifications.length; i++) {
notifications[i].close();
}
});
MmiManager.handleMMIReceived(evt.body, /* sessionEnded */ true,
params.cardIndex);
} else {
Navigation.showCalllog();
}
};
}
/* === Telephony Call Ended Support === */
function sendNotification(number, serviceId) {
LazyLoader.load('/shared/js/dialer/utils.js', function() {
Contacts.findByNumber(number, function lookup(contact, matchingTel) {
var title;
if (navigator.mozIccManager.iccIds.length > 1) {
title = { id: 'missedCallMultiSims', args: { n: serviceId + 1 } };
} else {
title = 'missedCall';
}
var body;
if (!number) {
body = 'from-withheld-number';
} else if (contact) {
var primaryInfo = Utils.getPhoneNumberPrimaryInfo(matchingTel,
contact);
if (primaryInfo) {
if (primaryInfo !== matchingTel.value) {
// primaryInfo is an object here
body = {
id: 'from-contact',
args: { contact: primaryInfo.toString() }
};
} else {
body = { id: 'from-number', args: { number: primaryInfo } };
}
} else {
body = 'from-withheld-number';
}
} else {
body = { id: 'from-number', args: { number: number } };
}
navigator.mozApps.getSelf().onsuccess = function getSelfCB(evt) {
var app = evt.target.result;
var iconURL = NotificationHelper.getIconURI(app, 'dialer');
var clickCB = function() {
app.launch('dialer');
Navigation.showCalllog();
};
NotificationHelper.send(title, {
bodyL10n: body,
icon: iconURL
}).then(function(notification) {
notification.addEventListener('click', clickCB);
});
};
});
});
}
function callEnded(data) {
var highPriorityWakeLock = navigator.requestWakeLock('high-priority');
var number = data.number;
var incoming = data.direction === 'incoming';
// Missed call when not rejected by user
if (incoming && !data.duration && !data.hangUpLocal) {
sendNotification(number, data.serviceId);
}
Voicemail.check(number, data.serviceId).then(function(isVoicemailNumber) {
var entry = {
date: Date.now() - parseInt(data.duration),
duration: data.duration,
type: incoming ? 'incoming' : 'dialing',
number: number,
serviceId: data.serviceId,
emergency: data.emergency || false,
voicemail: isVoicemailNumber,
status: (incoming && data.duration > 0) ? 'connected' : null
};
// Store and display the call that ended
CallLogDBManager.add(entry, function(logEntry) {
CallLog.appendGroup(logEntry);
// A CDMA call can contain two calls. If it only has one call,
// we have nothing left to do and release the lock.
if (!data.secondNumber) {
highPriorityWakeLock.unlock();
return;
}
_addSecondCdmaCall(data, isVoicemailNumber, highPriorityWakeLock);
});
});
}
function _addSecondCdmaCall(data, isVoicemailNumber, wakeLock) {
var entryCdmaSecond = {
date: Date.now() - parseInt(data.duration),
duration: data.duration,
type: 'incoming',
number: data.secondNumber,
serviceId: data.serviceId,
emergency: false,
voicemail: isVoicemailNumber,
status: 'connected'
};
CallLogDBManager.add(entryCdmaSecond, function(logGroupCdmaSecondCall) {
CallLog.appendGroup(logGroupCdmaSecondCall);
wakeLock.unlock();
});
}
/* === postMessage support === */
function handleMessage(evt) {
if (evt.origin !== COMMS_APP_ORIGIN) {
return;
}
var data = evt.data;
if (!data.type) {
return;
}
if (data.type === 'contactsiframe') {
handleContactsIframeRequest(data.message);
} else if (data.type === 'hide-navbar') {
NavbarManager.hide();
} else if (data.type === 'show-navbar') {
NavbarManager.show();
}
}
window.addEventListener('message', handleMessage);
function handleContactsIframeRequest(message) {
switch (message) {
case 'back':
var contactsIframe = document.getElementById('iframe-contacts');
// disable the function of receiving the messages posted from the iframe
contactsIframe.contentWindow.history.pushState(null, null,
'/contacts/index.html');
Navigation.showCalllog();
break;
}
}
/* === Bluetooth Support === */
function btCommandHandler(message) {
var command = message.command;
var isAtd = command.startsWith('ATD');
// Not a dialing request
if (command !== 'BLDN' && !isAtd) {
return;
}
// Dialing a specific number
if (isAtd && command[3] !== '>') {
var phoneNumber = command.substring(3);
LazyLoader.load(['/shared/js/sim_settings_helper.js'], function() {
SimSettingsHelper.getCardIndexFrom('outgoingCall',
function(defaultCardIndex) {
if (defaultCardIndex === SimSettingsHelper.ALWAYS_ASK_OPTION_VALUE) {
LazyLoader.load(['/shared/js/component_utils.js',
'/shared/elements/gaia_sim_picker/script.js'],
function() {
var simPicker = document.getElementById('sim-picker');
simPicker.getOrPick(defaultCardIndex, phoneNumber, function(ci) {
CallHandler.call(phoneNumber, ci);
});
// Show the dialer so the user can select the SIM.
navigator.mozApps.getSelf().onsuccess = function(selfEvt) {
var app = selfEvt.target.result;
app.launch('dialer');
};
});
} else {
CallHandler.call(phoneNumber, defaultCardIndex);
}
});
});
return;
}
// Dialing from the call log
// ATD>3 means we have to call the 3rd recent number.
var position = isAtd ? parseInt(command.substring(4), 10) : 1;
CallLogDBManager.getGroupAtPosition(
position, 'lastEntryDate', true, 'dialing',
function(result) {
if (result && (typeof result === 'object') && result.number) {
LazyLoader.load(['/shared/js/sim_settings_helper.js'], function() {
SimSettingsHelper.getCardIndexFrom('outgoingCall', function(ci) {
// If the default outgoing call SIM is set to "Always ask", or is
// unset, we place this call on the SIM that was used the last time
// we were in a phone call with this number/contact.
if (ci === undefined || ci === null ||
ci == SimSettingsHelper.ALWAYS_ASK_OPTION_VALUE) {
ci = result.serviceId;
}
CallHandler.call(result.number, ci);
});
});
} else {
console.log('Could not get the group at: ' + position +
'. Error: ' + result);
}
});
}
/* === Calls === */
function call(number, cardIndex) {
if (engineeringModeKey && number === engineeringModeKey) {
var activity = new MozActivity({
name: 'internal-system-engineering-mode'
});
activity.onerror = function() {
console.log('Could not launch engineering mode');
};
return;
}
if (MmiManager.isImei(number)) {
MmiManager.showImei();
// Clearing the code from the dialer screen gives the user immediate
// feedback.
KeypadManager.updatePhoneNumber('', 'begin', true);
SuggestionBar.clear();
return;
}
var connected, disconnected;
connected = disconnected = function clearPhoneView() {
KeypadManager.updatePhoneNumber('', 'begin', true);
};
var oncall = function() {
SuggestionBar.hideOverlay();
SuggestionBar.clear();
};
LazyLoader.load(['/dialer/js/telephony_helper.js'], function() {
TelephonyHelper.call(
number, cardIndex, oncall, connected, disconnected
).catch(function() {
KeypadManager.updatePhoneNumber(number, 'begin', false);
});
});
}
/* === MMI === */
function onUssdReceived(evt) {
var lock = null;
var safetyId;
function releaseWakeLock() {
if (lock) {
lock.unlock();
lock = null;
clearTimeout(safetyId);
}
}
if (document.hidden) {
lock = navigator.requestWakeLock('high-priority');
safetyId = setTimeout(releaseWakeLock, 30000);
document.addEventListener('visibilitychange', releaseWakeLock);
}
if (!document.hidden || evt.session) {
MmiManager.handleMMIReceived(evt.message, evt.session, evt.serviceId);
} else if (evt.message) {
/* If the dialer is not visible and the session ends with this message
* then this is most likely an unsollicited message. To prevent
* interrupting the user we post a notification for it instead of
* displaying the dialer UI. */
MmiManager.sendNotification(evt.message, evt.serviceId)
.then(releaseWakeLock);
} else {
releaseWakeLock();
}
}
function init() {
LazyLoader.load(['/shared/js/mobile_operator.js',
'/dialer/js/mmi.js',
'/dialer/js/mmi_ui.js',
'/shared/style/progress_activity.css',
'/dialer/style/mmi.css'], function() {
if (window.navigator.mozSetMessageHandler) {
window.navigator.mozSetMessageHandler('telephony-call-ended',
callEnded);
window.navigator.mozSetMessageHandler('activity', handleActivity);
window.navigator.mozSetMessageHandler('notification',
handleNotification);
window.navigator.mozSetMessageHandler('bluetooth-dialer-command',
btCommandHandler);
window.navigator.mozSetMessageHandler('ussd-received', onUssdReceived);
}
});
LazyLoader.load('/shared/js/settings_listener.js', function() {
SettingsListener.observe('engineering-mode.key', null, function(value) {
engineeringModeKey = value || null;
});
});
}
return {
init: init,
call: call
};
})();
// Listening to the keyboard being shown
// Waiting for issue 787444 being fixed
window.onresize = function(e) {
if (window.innerHeight < 440) {
NavbarManager.hide();
} else {
NavbarManager.show();
}
};