diff --git a/dom/system/gonk/ril_worker.js b/dom/system/gonk/ril_worker.js index 29bb1a7be2fc..79479efbc248 100644 --- a/dom/system/gonk/ril_worker.js +++ b/dom/system/gonk/ril_worker.js @@ -244,16 +244,6 @@ RilObject.prototype = { */ this._pendingNetworkInfo = {rilMessageType: "networkinfochanged"}; - /** - * USSD session flag. - * Only one USSD session may exist at a time, and the session is assumed - * to exist until: - * a) There's a call to cancelUSSD() - * b) The implementation sends a UNSOLICITED_ON_USSD with a type code - * of "0" (USSD-Notify/no further action) or "2" (session terminated) - */ - this._ussdSession = null; - /** * Cell Broadcast Search Lists. */ @@ -1845,67 +1835,13 @@ RilObject.prototype = { this.context.Buf.simpleRequest(REQUEST_LAST_CALL_FAIL_CAUSE, options); }, - sendMMI: function(options) { - if (DEBUG) { - this.context.debug("SendMMI " + JSON.stringify(options)); - } - - let _sendMMIError = (function(errorMsg) { - options.errorMsg = errorMsg; - this.sendChromeMessage(options); - }).bind(this); - - // It's neither a valid mmi code nor an ongoing ussd. - let mmi = options.mmi; - if (!mmi && !this._ussdSession) { - _sendMMIError(MMI_ERROR_KS_ERROR); - return; - } - - let _isRadioAvailable = (function() { - if (this.radioState !== GECKO_RADIOSTATE_ENABLED) { - _sendMMIError(GECKO_ERROR_RADIO_NOT_AVAILABLE); - return false; - } - return true; - }).bind(this); - - // If the MMI code is not a known code, it is treated as an ussd. - if (!_isRadioAvailable()) { - return; - } - - options.ussd = mmi.fullMMI; - - if (this._ussdSession) { - if (DEBUG) this.context.debug("Cancel existing ussd session."); - this.cachedUSSDRequest = options; - this.cancelUSSD({}); - return; - } - - this.sendUSSD(options, false); - }, - - /** - * Cache the request for send out a new ussd when there is an existing - * session. We should do cancelUSSD first. - */ - cachedUSSDRequest : null, - /** * Send USSD. * * @param ussd * String containing the USSD code. */ - sendUSSD: function(options, checkSession = true) { - if (checkSession && !this._ussdSession) { - options.errorMsg = GECKO_ERROR_GENERIC_FAILURE; - this.sendChromeMessage(options); - return; - } - + sendUSSD: function(options) { let Buf = this.context.Buf; Buf.newParcel(REQUEST_SEND_USSD, options); Buf.writeString(options.ussd); @@ -4360,24 +4296,12 @@ RilObject.prototype[REQUEST_SEND_USSD] = function REQUEST_SEND_USSD(length, opti if (DEBUG) { this.context.debug("REQUEST_SEND_USSD " + JSON.stringify(options)); } - this._ussdSession = !options.errorMsg; this.sendChromeMessage(options); }; RilObject.prototype[REQUEST_CANCEL_USSD] = function REQUEST_CANCEL_USSD(length, options) { if (DEBUG) { this.context.debug("REQUEST_CANCEL_USSD" + JSON.stringify(options)); } - - this._ussdSession = !!options.errorMsg; - - // The cancelUSSD is triggered by ril_worker itself. - if (this.cachedUSSDRequest) { - if (DEBUG) this.context.debug("Send out the cached ussd request"); - this.sendUSSD(this.cachedUSSDRequest); - this.cachedUSSDRequest = null; - return; - } - this.sendChromeMessage(options); }; RilObject.prototype[REQUEST_GET_CLIR] = function REQUEST_GET_CLIR(length, options) { @@ -5166,18 +5090,12 @@ RilObject.prototype[UNSOLICITED_ON_USSD] = function UNSOLICITED_ON_USSD() { this.context.debug("On USSD. Type Code: " + typeCode + " Message: " + message); } - let oldSession = this._ussdSession; - - // Per ril.h the USSD session is assumed to persist if the type code is "1". - this._ussdSession = typeCode == "1"; - - if (!oldSession && !this._ussdSession && !message) { - return; - } - this.sendChromeMessage({rilMessageType: "ussdreceived", message: message, - sessionEnded: !this._ussdSession}); + // Per ril.h the USSD session is assumed to persist if + // the type code is "1", otherwise the current session + // (if any) is assumed to have terminated. + sessionEnded: typeCode !== "1"}); }; RilObject.prototype[UNSOLICITED_ON_USSD_REQUEST] = null; RilObject.prototype[UNSOLICITED_NITZ_TIME_RECEIVED] = function UNSOLICITED_NITZ_TIME_RECEIVED() { diff --git a/dom/system/gonk/tests/test_ril_worker_mmi.js b/dom/system/gonk/tests/test_ril_worker_mmi.js deleted file mode 100644 index de52c2e61af0..000000000000 --- a/dom/system/gonk/tests/test_ril_worker_mmi.js +++ /dev/null @@ -1,118 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -function createMMIOptions(procedure, serviceCode, sia, sib, sic) { - let mmi = { - fullMMI: Array.slice(arguments).join("*") + "#", - procedure: procedure, - serviceCode: serviceCode, - sia: sia, - sib: sib, - sic: sic - }; - - return mmi; -} - -function testSendMMI(mmi, error) { - let workerhelper = newInterceptWorker(); - let worker = workerhelper.worker; - let context = worker.ContextPool._contexts[0]; - - do_print("worker.postMessage " + worker.postMessage); - - context.RIL.radioState = GECKO_RADIOSTATE_ENABLED; - context.RIL.sendMMI({rilMessageType: "sendMMI", mmi: mmi}); - - let postedMessage = workerhelper.postedMessage; - - equal(postedMessage.rilMessageType, "sendMMI"); - equal(postedMessage.errorMsg, error); -} - -/** - * sendMMI tests. - */ - -add_test(function test_sendMMI_null() { - testSendMMI(null, MMI_ERROR_KS_ERROR); - - run_next_test(); -}); - -add_test(function test_sendMMI_short_code() { - let workerhelper = newInterceptWorker(); - let worker = workerhelper.worker; - let context = worker.ContextPool._contexts[0]; - - let ussdOptions; - - context.RIL.sendUSSD = function fakeSendUSSD(options){ - ussdOptions = options; - context.RIL[REQUEST_SEND_USSD](0, {}); - }; - - context.RIL.radioState = GECKO_RADIOSTATE_ENABLED; - context.RIL.sendMMI({mmi: {fullMMI: "**"}}); - - let postedMessage = workerhelper.postedMessage; - equal(ussdOptions.ussd, "**"); - equal(postedMessage.errorMsg, undefined); - ok(context.RIL._ussdSession); - - run_next_test(); -}); - -add_test(function test_sendMMI_USSD() { - let workerhelper = newInterceptWorker(); - let worker = workerhelper.worker; - let context = worker.ContextPool._contexts[0]; - let ussdOptions; - - context.RIL.sendUSSD = function fakeSendUSSD(options) { - ussdOptions = options; - context.RIL[REQUEST_SEND_USSD](0, {}); - }; - - context.RIL.radioState = GECKO_RADIOSTATE_ENABLED; - context.RIL.sendMMI({mmi: createMMIOptions("*", "123")}); - - let postedMessage = workerhelper.postedMessage; - - equal(ussdOptions.ussd, "**123#"); - equal(postedMessage.errorMsg, undefined); - ok(context.RIL._ussdSession); - - run_next_test(); -}); - -add_test(function test_sendMMI_USSD_error() { - let workerhelper = newInterceptWorker(); - let worker = workerhelper.worker; - let context = worker.ContextPool._contexts[0]; - let ussdOptions; - - context.RIL.sendUSSD = function fakeSendUSSD(options){ - ussdOptions = options; - context.RIL[REQUEST_SEND_USSD](0, { - errorMsg: GECKO_ERROR_GENERIC_FAILURE - }); - }; - - context.RIL.radioState = GECKO_RADIOSTATE_ENABLED; - context.RIL.sendMMI({mmi: createMMIOptions("*", "123")}); - - let postedMessage = workerhelper.postedMessage; - - equal(ussdOptions.ussd, "**123#"); - equal(postedMessage.errorMsg, GECKO_ERROR_GENERIC_FAILURE); - ok(!context.RIL._ussdSession); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/xpcshell.ini b/dom/system/gonk/tests/xpcshell.ini index 661dd16d1963..6af3d7437f06 100644 --- a/dom/system/gonk/tests/xpcshell.ini +++ b/dom/system/gonk/tests/xpcshell.ini @@ -23,7 +23,6 @@ skip-if = true [test_ril_worker_sms_gsmpduhelper.js] [test_ril_worker_sms_segment_info.js] [test_ril_worker_smsc_address.js] -[test_ril_worker_mmi.js] [test_ril_worker_cf.js] [test_ril_worker_cellbroadcast_config.js] [test_ril_worker_cellbroadcast.js] diff --git a/dom/telephony/gonk/TelephonyService.js b/dom/telephony/gonk/TelephonyService.js index eab339d67d5c..aa09586510ce 100644 --- a/dom/telephony/gonk/TelephonyService.js +++ b/dom/telephony/gonk/TelephonyService.js @@ -230,6 +230,7 @@ function TelephonyService() { this._currentCalls = {}; this._currentConferenceState = nsITelephonyService.CALL_STATE_UNKNOWN; this._audioStates = []; + this._ussdSessions = []; this._cdmaCallWaitingNumber = null; @@ -243,6 +244,7 @@ function TelephonyService() { for (let i = 0; i < this._numClients; ++i) { this._audioStates[i] = nsITelephonyAudioService.PHONE_STATE_NORMAL; + this._ussdSessions[i] = false; this._currentCalls[i] = {}; this._enumerateCallsForClient(i); } @@ -265,6 +267,15 @@ TelephonyService.prototype = { _callRingWakeLock: null, _callRingWakeLockTimer: null, + /** + * USSD session flags. + * Only one USSD session may exist at a time, and the session is assumed + * to exist until: + * a) There's a call to cancelUSSD() + * b) Receiving a session end unsolicited event. + */ + _ussdSessions: null, + _acquireCallRingWakeLock: function() { if (!this._callRingWakeLock) { if (DEBUG) debug("Acquiring a CPU wake lock for handling incoming call."); @@ -916,53 +927,25 @@ TelephonyService.prototype = { this._callWaitingMMI(aClientId, aMmi, aCallback); break; - // Fall back to "sendMMI". + // Handle unknown MMI code as USSD. default: - this._sendMMI(aClientId, aMmi, aCallback); + if (!this._isRadioOn(aClientId)) { + aCallback.notifyDialMMIError(RIL.GECKO_ERROR_RADIO_NOT_AVAILABLE); + return; + } + + this._sendUSSDInternal(aClientId, aMmi.fullMMI, aResponse => { + if (aResponse.errorMsg) { + aCallback.notifyDialMMIError(aResponse.errorMsg); + return; + } + + aCallback.notifyDialMMISuccess(""); + }); break; } }, - _sendMMI: function(aClientId, aMmi, aCallback) { - this._sendToRilWorker(aClientId, "sendMMI", - { mmi: aMmi }, response => { - if (DEBUG) debug("MMI response: " + JSON.stringify(response)); - - if (response.errorMsg) { - if (response.additionalInformation != null) { - aCallback.notifyDialMMIErrorWithInfo(response.errorMsg, - response.additionalInformation); - } else { - aCallback.notifyDialMMIError(response.errorMsg); - } - return; - } - - // No additional information - if (response.additionalInformation === undefined) { - aCallback.notifyDialMMISuccess(response.statusMessage); - return; - } - - // Additional information is an integer. - if (!isNaN(parseInt(response.additionalInformation, 10))) { - aCallback.notifyDialMMISuccessWithInteger( - response.statusMessage, response.additionalInformation); - return; - } - - // Additional information is an array of strings. - let array = response.additionalInformation; - if (Array.isArray(array) && array.length > 0 && typeof array[0] === "string") { - aCallback.notifyDialMMISuccessWithStrings(response.statusMessage, - array.length, array); - return; - } - - aCallback.notifyDialMMISuccess(response.statusMessage); - }); - }, - /** * Handle call forwarding MMI code. * @@ -2015,13 +1998,42 @@ TelephonyService.prototype = { }, sendUSSD: function(aClientId, aUssd, aCallback) { - this._sendToRilWorker(aClientId, "sendUSSD", { ussd: aUssd }, - this._defaultCallbackHandler.bind(this, aCallback)); + this._sendUSSDInternal(aClientId, aUssd, + this._defaultCallbackHandler.bind(this, aCallback)); + }, + + _sendUSSDInternal: function(aClientId, aUssd, aCallback) { + if (!this._ussdSessions[aClientId]) { + this._sendToRilWorker(aClientId, "sendUSSD", { ussd: aUssd }, aResponse => { + this._ussdSessions[aClientId] = !aResponse.errorMsg; + aCallback(aResponse); + }); + return; + } + + // Cancel the previous ussd session first. + this._cancelUSSDInternal(aClientId, aResponse => { + // Fail to cancel ussd session, report error instead of sending ussd + // request. + if (aResponse.errorMsg) { + aCallback(aResponse); + return; + } + + this._sendUSSDInternal(aClientId, aUssd, aCallback); + }); }, cancelUSSD: function(aClientId, aCallback) { - this._sendToRilWorker(aClientId, "cancelUSSD", {}, - this._defaultCallbackHandler.bind(this, aCallback)); + this._cancelUSSDInternal(aClientId, + this._defaultCallbackHandler.bind(this, aCallback)); + }, + + _cancelUSSDInternal: function(aClientId, aCallback) { + this._sendToRilWorker(aClientId, "cancelUSSD", {}, aResponse => { + this._ussdSessions[aClientId] = !!aResponse.errorMsg; + aCallback(aResponse); + }); }, get microphoneMuted() { @@ -2289,6 +2301,13 @@ TelephonyService.prototype = { aMessage + " (sessionEnded : " + aSessionEnded + ")"); } + let oldSession = this._ussdSessions[aClientId]; + this._ussdSessions[aClientId] = !aSessionEnded; + + if (!oldSession && !this._ussdSessions[aClientId] && !aMessage) { + return; + } + gTelephonyMessenger.notifyUssdReceived(aClientId, aMessage, aSessionEnded); },