'use strict'; /* global LazyLoader, ConfirmDialog, MmiManager, TelephonyCall, TelephonyMessages */ /* exported TelephonyHelper */ var TelephonyHelper = (function() { // DTMF control digit separator length (ms) as defined in GSM ETSI GSM 02.07 const DTMF_SEPARATOR_PAUSE_DURATION = 3000; var confirmLoaded = false; var loadTelephonyMessages = function(callback) { LazyLoader.load(['/shared/js/dialer/telephony_messages.js'], callback); }; var call = function t_call(number, cardIndex, oncall, onconnected, ondisconnected) { var sanitizedNumber = number.replace(/(\s|-|\.|\(|\))/g, ''); if (!isValid(sanitizedNumber)) { loadTelephonyMessages(function() { TelephonyMessages.displayMessage('BadNumber'); }); return Promise.reject(); } // The platform adapter owns network checks on Tundra and Android. if (window.VulpesPlatformDial) { return window.VulpesPlatformDial(sanitizedNumber.split(',')[0]).then(function(obj) { if (window.TelephonyCall && obj instanceof TelephonyCall) { installHandlers(obj, sanitizedNumber, false, cardIndex, oncall, onconnected, ondisconnected); } else if (oncall) { oncall(); } return obj; }); } var conn = navigator.mozMobileConnections && navigator.mozMobileConnections[cardIndex]; if (!conn || !conn.voice) { // No voice connection, the call won't make it loadTelephonyMessages(function() { TelephonyMessages.displayMessage('NoNetwork'); }); return Promise.reject(); } return startDial( cardIndex, conn, sanitizedNumber, oncall, onconnected, ondisconnected ); }; function getNumberAsDtmfToneGroups(number) { return number.split(','); } function playDtmfToneGroups(dtmfToneGroups, cardIndex) { var length; // Remove the dialed number from the beginning of the array. dtmfToneGroups = dtmfToneGroups.slice(1); length = dtmfToneGroups.length; // Remove the latest entries from dtmfToneGroups corresponding to ',' // characters not to play those pauses. var lastCommaIndex = length - 1; while (dtmfToneGroups[lastCommaIndex] === '') { lastCommaIndex--; } dtmfToneGroups = dtmfToneGroups.slice(0, ++lastCommaIndex); length = dtmfToneGroups.length; var promise = Promise.resolve(), counter = 0, pauses; // Traverse the dtmfToneGroups array. while (counter < length) { // Reset the number of pauses before each group of tones. pauses = 1; while (dtmfToneGroups[counter] === '') { // Add a new pause for each '' in the dtmfToneGroups array. pauses++; counter++; } // Send a new group of tones as well as the pauses to play before it. promise = promise.then(playDtmfToneGroup.bind(null, dtmfToneGroups[counter++], pauses, cardIndex)); } return promise; } function playDtmfToneGroup(toneGroup, pauses, cardIndex) { return navigator.mozTelephony.sendTones( toneGroup, DTMF_SEPARATOR_PAUSE_DURATION * pauses, null /* tone duration */, cardIndex ); } function startDial(cardIndex, conn, sanitizedNumber, oncall, onconnected, ondisconnected) { var telephony = navigator.mozTelephony; if (!telephony) { return Promise.reject(); } var emergencyOnly = conn.voice.emergencyCallsOnly; var hasCard = (conn.iccId !== null); var callPromise; var baseNumber = getNumberAsDtmfToneGroups(sanitizedNumber)[0]; if (emergencyOnly) { loadConfirm(function() { ConfirmDialog.show( 'connectingEllipsis', '', { title: 'emergencyDialogBtnOk', callback: function() { ConfirmDialog.hide(); } } ); document.addEventListener('visibilitychange', function hideDialog() { document.removeEventListener('visibilitychange', hideDialog); /* In tests this event can happen after the ConfirmDialog mock has * been removed so check that it's still there. */ ConfirmDialog && ConfirmDialog.hide(); }); }); // If the mobileConnection has a sim card we let gecko take the // default service, otherwise we force the first slot. cardIndex = hasCard ? undefined : 0; callPromise = telephony.dialEmergency(baseNumber); } else { callPromise = telephony.dial(baseNumber, cardIndex); } callPromise.then(function(obj) { if (obj instanceof TelephonyCall) { installHandlers(obj, sanitizedNumber, emergencyOnly, cardIndex, oncall, onconnected, ondisconnected); } else { /* This is an MMICall object, manually invoke the handlers to provide * feedback to the user, the rest of the UX will be dealt with by the * MMI manager. */ oncall(); onconnected(); MmiManager.handleDialing(conn, sanitizedNumber, obj.result); } }, function(errorName) { loadTelephonyMessages(function() { var messageType = emergencyOnly ? TelephonyMessages.NO_NETWORK : TelephonyMessages.REGULAR_CALL; TelephonyMessages.handleError( errorName, sanitizedNumber, messageType); }); }); return callPromise; } function installHandlers(call, number, emergencyOnly, cardIndex, oncall, onconnected, ondisconnected) { if (oncall) { oncall(); } var dtmfToneGroups = getNumberAsDtmfToneGroups(number); if (dtmfToneGroups.length > 1) { call.addEventListener('connected', function dtmfToneGroupPlayer() { call.removeEventListener('connected', dtmfToneGroupPlayer); playDtmfToneGroups(dtmfToneGroups, cardIndex); }); } call.addEventListener('connected', onconnected); call.addEventListener('disconnected', function handleDisconnect(evt) { if (evt.call.disconnectedReason) { loadTelephonyMessages(function() { TelephonyMessages.handleDisconnect( evt.call.disconnectedReason, number, emergencyOnly ); }); } ondisconnected && ondisconnected(); }); } var isValid = function t_isValid(sanitizedNumber) { var validExp = /^(?!,)([0-9#+*,]){1,50}$/; return validExp.test(sanitizedNumber); }; var loadConfirm = function t_loadConfirm(cb) { if (confirmLoaded) { cb(); return; } var confMsg = document.getElementById('confirmation-message'); LazyLoader.load(['/shared/js/confirm.js', confMsg], function() { confirmLoaded = true; cb(); }); }; var getInUseSim = function t_getInUseSim() { var telephony = navigator.mozTelephony; if (telephony) { var isInCall = !!telephony.calls.length; var isInConference = !!telephony.conferenceGroup && !!telephony.conferenceGroup.calls.length; if (isInCall || isInConference) { return isInCall ? navigator.mozTelephony.calls[0].serviceId : navigator.mozTelephony.conferenceGroup.calls[0].serviceId; } } return null; }; window.TelephonyHelper = TelephonyHelper; return { call: call, getInUseSim: getInUseSim }; })();