diff --git a/b2g/config/aries/sources.xml b/b2g/config/aries/sources.xml
index 28017c456aac..62f2befb61e3 100644
--- a/b2g/config/aries/sources.xml
+++ b/b2g/config/aries/sources.xml
@@ -15,7 +15,7 @@
-
+
@@ -23,7 +23,7 @@
-
+
diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml
index 13e4774ead69..33becd992411 100644
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -15,7 +15,7 @@
-
+
@@ -23,7 +23,7 @@
-
+
diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml
index dcc227a7fe1e..622788c408ca 100644
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -19,7 +19,7 @@
-
+
diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml
index 8f917efbaa10..0568fb0743af 100644
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -17,10 +17,10 @@
-
+
-
+
diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml
index 37cbdb424350..0321294e710f 100644
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -15,7 +15,7 @@
-
+
@@ -23,7 +23,7 @@
-
+
diff --git a/b2g/config/emulator-l/sources.xml b/b2g/config/emulator-l/sources.xml
index e2011c3167e0..ea19e322a22b 100644
--- a/b2g/config/emulator-l/sources.xml
+++ b/b2g/config/emulator-l/sources.xml
@@ -15,7 +15,7 @@
-
+
@@ -23,7 +23,7 @@
-
+
diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml
index dcc227a7fe1e..622788c408ca 100644
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -19,7 +19,7 @@
-
+
diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml
index c4f231c93902..70c8751ce694 100644
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -15,7 +15,7 @@
-
+
@@ -23,7 +23,7 @@
-
+
diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json
index fa5d5470e56e..db467fe77dee 100644
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
{
"git": {
- "git_revision": "77bc0d940bde2a5d2d4dfadfcccc6d8d77456d36",
+ "git_revision": "8c009877aff6b8b2f4a60756e2d09c0182393721",
"remote": "https://git.mozilla.org/releases/gaia.git",
"branch": ""
},
- "revision": "dfd4a9e8f31e64d427030d3612a48f7dbcada5d3",
+ "revision": "494ef969c9ddbf15fc8a094c2da7bc46d08b1fc3",
"repo_path": "integration/gaia-central"
}
diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml
index 3c3f35308c4f..47885ccc7465 100644
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -17,10 +17,10 @@
-
+
-
+
diff --git a/b2g/config/nexus-5-l/sources.xml b/b2g/config/nexus-5-l/sources.xml
index 4c57228ad75f..196aa9015986 100644
--- a/b2g/config/nexus-5-l/sources.xml
+++ b/b2g/config/nexus-5-l/sources.xml
@@ -15,7 +15,7 @@
-
+
@@ -23,7 +23,7 @@
-
+
diff --git a/dom/system/gonk/SystemWorkerManager.cpp b/dom/system/gonk/SystemWorkerManager.cpp
index a5622f57c995..4ae4baac50ef 100644
--- a/dom/system/gonk/SystemWorkerManager.cpp
+++ b/dom/system/gonk/SystemWorkerManager.cpp
@@ -119,7 +119,7 @@ SystemWorkerManager::Shutdown()
ShutdownAutoMounter();
#ifdef MOZ_B2G_RIL
- RilConsumer::Shutdown();
+ RilWorker::Shutdown();
#endif
nsCOMPtr wifi(do_QueryInterface(mWifiWorker));
@@ -201,7 +201,7 @@ SystemWorkerManager::RegisterRilWorker(unsigned int aClientId,
return NS_ERROR_FAILURE;
}
- return RilConsumer::Register(aClientId, wctd);
+ return RilWorker::Register(aClientId, wctd);
#endif // MOZ_B2G_RIL
}
diff --git a/dom/system/gonk/ril_consts.js b/dom/system/gonk/ril_consts.js
index 7c2f5f082f93..d446b8de7cd9 100644
--- a/dom/system/gonk/ril_consts.js
+++ b/dom/system/gonk/ril_consts.js
@@ -2976,151 +2976,6 @@ CALL_BARRING_PROGRAM_TO_FACILITY[CALL_BARRING_PROGRAM_ALL_SERVICE] = ICC_CB_FACI
CALL_BARRING_PROGRAM_TO_FACILITY[CALL_BARRING_PROGRAM_OUTGOING_SERVICE] = ICC_CB_FACILITY_BA_MO;
CALL_BARRING_PROGRAM_TO_FACILITY[CALL_BARRING_PROGRAM_INCOMING_SERVICE] = ICC_CB_FACILITY_BA_MT;
-// CLIR constants. Must be in sync with nsIMobileConnectionService interface
-this.CLIR_DEFAULT = 0;
-this.CLIR_INVOCATION = 1;
-this.CLIR_SUPPRESSION = 2;
-
-// MMI procedure as defined in TS.22.030 6.5.2
-this.MMI_PROCEDURE_ACTIVATION = "*";
-this.MMI_PROCEDURE_DEACTIVATION = "#";
-this.MMI_PROCEDURE_INTERROGATION = "*#";
-this.MMI_PROCEDURE_REGISTRATION = "**";
-this.MMI_PROCEDURE_ERASURE = "##";
-
-this.MMI_PROC_TO_CF_ACTION = {};
-MMI_PROC_TO_CF_ACTION[MMI_PROCEDURE_ACTIVATION] = CALL_FORWARD_ACTION_ENABLE;
-MMI_PROC_TO_CF_ACTION[MMI_PROCEDURE_DEACTIVATION] = CALL_FORWARD_ACTION_DISABLE;
-MMI_PROC_TO_CF_ACTION[MMI_PROCEDURE_INTERROGATION] = CALL_FORWARD_ACTION_QUERY_STATUS;
-MMI_PROC_TO_CF_ACTION[MMI_PROCEDURE_REGISTRATION] = CALL_FORWARD_ACTION_REGISTRATION;
-MMI_PROC_TO_CF_ACTION[MMI_PROCEDURE_ERASURE] = CALL_FORWARD_ACTION_ERASURE;
-
-// MMI call forwarding service codes as defined in TS.22.030 Annex B
-this.MMI_SC_CFU = "21";
-this.MMI_SC_CF_BUSY = "67";
-this.MMI_SC_CF_NO_REPLY = "61";
-this.MMI_SC_CF_NOT_REACHABLE = "62";
-this.MMI_SC_CF_ALL = "002";
-this.MMI_SC_CF_ALL_CONDITIONAL = "004";
-
-this.MMI_SC_TO_CF_REASON = {};
-MMI_SC_TO_CF_REASON[MMI_SC_CFU] = CALL_FORWARD_REASON_UNCONDITIONAL;
-MMI_SC_TO_CF_REASON[MMI_SC_CF_BUSY] = CALL_FORWARD_REASON_MOBILE_BUSY;
-MMI_SC_TO_CF_REASON[MMI_SC_CF_NO_REPLY] = CALL_FORWARD_REASON_NO_REPLY;
-MMI_SC_TO_CF_REASON[MMI_SC_CF_NOT_REACHABLE] = CALL_FORWARD_REASON_NOT_REACHABLE;
-MMI_SC_TO_CF_REASON[MMI_SC_CF_ALL] = CALL_FORWARD_REASON_ALL_CALL_FORWARDING;
-MMI_SC_TO_CF_REASON[MMI_SC_CF_ALL_CONDITIONAL] = CALL_FORWARD_REASON_ALL_CONDITIONAL_CALL_FORWARDING;
-
-// MMI service codes for PIN/PIN2/PUK/PUK2 management as defined in TS.22.030
-// sec 6.6
-this.MMI_SC_PIN = "04";
-this.MMI_SC_PIN2 = "042";
-this.MMI_SC_PUK = "05";
-this.MMI_SC_PUK2 = "052";
-
-// MMI service code for IMEI presentation as defined in TS.22.030 sec 6.7
-this.MMI_SC_IMEI = "06";
-
-// MMI called line presentation service codes
-this.MMI_SC_CLIP = "30";
-this.MMI_SC_CLIR = "31";
-
-// MMI call waiting service code
-this.MMI_SC_CALL_WAITING = "43";
-
-// MMI service code for registration new password as defined in TS 22.030 6.5.4
-this.MMI_SC_CHANGE_PASSWORD = "03";
-this.MMI_ZZ_BARRING_SERVICE = "330";
-
-// MMI call barring service codes
-this.MMI_SC_BAOC = "33";
-this.MMI_SC_BAOIC = "331";
-this.MMI_SC_BAOICxH = "332";
-this.MMI_SC_BAIC = "35";
-this.MMI_SC_BAICr = "351";
-this.MMI_SC_BA_ALL = "330";
-this.MMI_SC_BA_MO = "333";
-this.MMI_SC_BA_MT = "353";
-
-this.MMI_SC_TO_CB_FACILITY = {};
-
-MMI_SC_TO_CB_FACILITY[MMI_SC_BAOC] = ICC_CB_FACILITY_BAOC;
-MMI_SC_TO_CB_FACILITY[MMI_SC_BAOIC] = ICC_CB_FACILITY_BAOIC;
-MMI_SC_TO_CB_FACILITY[MMI_SC_BAOICxH] = ICC_CB_FACILITY_BAOICxH;
-MMI_SC_TO_CB_FACILITY[MMI_SC_BAIC] = ICC_CB_FACILITY_BAIC;
-MMI_SC_TO_CB_FACILITY[MMI_SC_BAICr] = ICC_CB_FACILITY_BAICr;
-MMI_SC_TO_CB_FACILITY[MMI_SC_BA_ALL] = ICC_CB_FACILITY_BA_ALL;
-MMI_SC_TO_CB_FACILITY[MMI_SC_BA_MO] = ICC_CB_FACILITY_BA_MO;
-MMI_SC_TO_CB_FACILITY[MMI_SC_BA_MT] = ICC_CB_FACILITY_BA_MT;
-
-// MMI service code key strings.
-this.MMI_KS_SC_CALL_BARRING = "scCallBarring";
-this.MMI_KS_SC_CALL_FORWARDING = "scCallForwarding";
-this.MMI_KS_SC_CLIP = "scClip";
-this.MMI_KS_SC_CLIR = "scClir";
-this.MMI_KS_SC_PWD = "scPwd";
-this.MMI_KS_SC_CALL_WAITING = "scCallWaiting";
-this.MMI_KS_SC_PIN = "scPin";
-this.MMI_KS_SC_PIN2 = "scPin2";
-this.MMI_KS_SC_PUK = "scPuk";
-this.MMI_KS_SC_PUK2 = "scPuk2";
-this.MMI_KS_SC_CHANGE_PASSWORD = "scChangePassword";
-this.MMI_KS_SC_IMEI = "scImei";
-this.MMI_KS_SC_USSD = "scUssd";
-this.MMI_KS_SC_CALL = "scCall";
-
-// MMI error messages key strings.
-this.MMI_ERROR_KS_ERROR = "emMmiError";
-this.MMI_ERROR_KS_NOT_SUPPORTED = "emMmiErrorNotSupported";
-this.MMI_ERROR_KS_INVALID_ACTION = "emMmiErrorInvalidAction";
-this.MMI_ERROR_KS_MISMATCH_PIN = "emMmiErrorMismatchPin";
-this.MMI_ERROR_KS_MISMATCH_PASSWORD = "emMmiErrorMismatchPassword";
-this.MMI_ERROR_KS_BAD_PIN = "emMmiErrorBadPin";
-this.MMI_ERROR_KS_BAD_PUK = "emMmiErrorBadPuk";
-this.MMI_ERROR_KS_INVALID_PIN = "emMmiErrorInvalidPin";
-this.MMI_ERROR_KS_INVALID_PASSWORD = "emMmiErrorInvalidPassword";
-this.MMI_ERROR_KS_NEEDS_PUK = "emMmiErrorNeedsPuk";
-this.MMI_ERROR_KS_SIM_BLOCKED = "emMmiErrorSimBlocked";
-
-// MMI status message.
-this.MMI_SM_KS_PASSWORD_CHANGED = "smPasswordChanged";
-this.MMI_SM_KS_PIN_CHANGED = "smPinChanged";
-this.MMI_SM_KS_PIN2_CHANGED = "smPin2Changed";
-this.MMI_SM_KS_PIN_UNBLOCKED = "smPinUnblocked";
-this.MMI_SM_KS_PIN2_UNBLOCKED = "smPin2Unblocked";
-this.MMI_SM_KS_SERVICE_ENABLED = "smServiceEnabled";
-this.MMI_SM_KS_SERVICE_ENABLED_FOR = "smServiceEnabledFor";
-this.MMI_SM_KS_SERVICE_DISABLED = "smServiceDisabled";
-this.MMI_SM_KS_SERVICE_REGISTERED = "smServiceRegistered";
-this.MMI_SM_KS_SERVICE_ERASED = "smServiceErased";
-this.MMI_SM_KS_SERVICE_INTERROGATED = "smServiceInterrogated";
-this.MMI_SM_KS_SERVICE_NOT_PROVISIONED = "smServiceNotProvisioned";
-this.MMI_SM_KS_CLIR_PERMANENT = "smClirPermanent";
-this.MMI_SM_KS_CLIR_DEFAULT_ON_NEXT_CALL_ON = "smClirDefaultOnNextCallOn";
-this.MMI_SM_KS_CLIR_DEFAULT_ON_NEXT_CALL_OFF = "smClirDefaultOnNextCallOff";
-this.MMI_SM_KS_CLIR_DEFAULT_OFF_NEXT_CALL_ON = "smClirDefaultOffNextCallOn";
-this.MMI_SM_KS_CLIR_DEFAULT_OFF_NEXT_CALL_OFF = "smClirDefaultOffNextCallOff";
-this.MMI_SM_KS_CALL_CONTROL = "smCallControl";
-
-// MMI Service class
-this.MMI_KS_SERVICE_CLASS_VOICE = "serviceClassVoice";
-this.MMI_KS_SERVICE_CLASS_DATA = "serviceClassData";
-this.MMI_KS_SERVICE_CLASS_FAX = "serviceClassFax";
-this.MMI_KS_SERVICE_CLASS_SMS = "serviceClassSms";
-this.MMI_KS_SERVICE_CLASS_DATA_SYNC = "serviceClassDataSync";
-this.MMI_KS_SERVICE_CLASS_DATA_ASYNC = "serviceClassDataAsync";
-this.MMI_KS_SERVICE_CLASS_PACKET = "serviceClassPacket";
-this.MMI_KS_SERVICE_CLASS_PAD = "serviceClassPad";
-
-this.MMI_KS_SERVICE_CLASS_MAPPING = {};
-MMI_KS_SERVICE_CLASS_MAPPING[ICC_SERVICE_CLASS_VOICE] = MMI_KS_SERVICE_CLASS_VOICE;
-MMI_KS_SERVICE_CLASS_MAPPING[ICC_SERVICE_CLASS_DATA] = MMI_KS_SERVICE_CLASS_DATA;
-MMI_KS_SERVICE_CLASS_MAPPING[ICC_SERVICE_CLASS_FAX] = MMI_KS_SERVICE_CLASS_FAX;
-MMI_KS_SERVICE_CLASS_MAPPING[ICC_SERVICE_CLASS_SMS] = MMI_KS_SERVICE_CLASS_SMS;
-MMI_KS_SERVICE_CLASS_MAPPING[ICC_SERVICE_CLASS_DATA_SYNC] = MMI_KS_SERVICE_CLASS_DATA_SYNC;
-MMI_KS_SERVICE_CLASS_MAPPING[ICC_SERVICE_CLASS_DATA_ASYNC] = MMI_KS_SERVICE_CLASS_DATA_ASYNC;
-MMI_KS_SERVICE_CLASS_MAPPING[ICC_SERVICE_CLASS_PACKET] = MMI_KS_SERVICE_CLASS_PACKET;
-MMI_KS_SERVICE_CLASS_MAPPING[ICC_SERVICE_CLASS_PAD] = MMI_KS_SERVICE_CLASS_PAD;
/**
* CDMA PDU constants
*/
diff --git a/dom/system/gonk/ril_worker.js b/dom/system/gonk/ril_worker.js
index a3dfa8279e86..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.
*/
@@ -870,60 +860,6 @@ RilObject.prototype = {
Buf.sendParcel();
},
- /**
- * Query call waiting status via MMI.
- */
- _handleQueryMMICallWaiting: function(options) {
- let Buf = this.context.Buf;
-
- function callback(options) {
- options.length = Buf.readInt32();
- options.enabled = (Buf.readInt32() === 1);
- let services = Buf.readInt32();
- if (options.enabled) {
- options.statusMessage = MMI_SM_KS_SERVICE_ENABLED_FOR;
- let serviceClass = [];
- for (let serviceClassMask = 1;
- serviceClassMask <= ICC_SERVICE_CLASS_MAX;
- serviceClassMask <<= 1) {
- if ((serviceClassMask & services) !== 0) {
- serviceClass.push(MMI_KS_SERVICE_CLASS_MAPPING[serviceClassMask]);
- }
- }
- options.additionalInformation = serviceClass;
- } else {
- options.statusMessage = MMI_SM_KS_SERVICE_DISABLED;
- }
-
- // Prevent DataCloneError when sending chrome messages.
- delete options.callback;
- this.sendChromeMessage(options);
- }
-
- options.callback = callback;
- this.queryCallWaiting(options);
- },
-
- /**
- * Set call waiting status via MMI.
- */
- _handleSetMMICallWaiting: function(options) {
- function callback(options) {
- if (options.enabled) {
- options.statusMessage = MMI_SM_KS_SERVICE_ENABLED;
- } else {
- options.statusMessage = MMI_SM_KS_SERVICE_DISABLED;
- }
-
- // Prevent DataCloneError when sending chrome messages.
- delete options.callback;
- this.sendChromeMessage(options);
- }
-
- options.callback = callback;
- this.setCallWaiting(options);
- },
-
/**
* Query call waiting status.
*
@@ -957,9 +893,6 @@ RilObject.prototype = {
/**
* Queries current CLIP status.
- *
- * (MMI request for code "*#30#")
- *
*/
queryCLIP: function(options) {
this.context.Buf.simpleRequest(REQUEST_QUERY_CLIP, options);
@@ -1239,6 +1172,15 @@ RilObject.prototype = {
},
getIMEI: function(options) {
+ // A device's IMEI can't change, so we only need to request it once.
+ if (this.IMEI) {
+ if (options && options.rilMessageType) {
+ options.imei = this.IMEI;
+ this.sendChromeMessage(options);
+ }
+ return;
+ }
+
this.context.Buf.simpleRequest(REQUEST_GET_IMEI, options);
},
@@ -1893,325 +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;
- }
-
- function _isValidPINPUKRequest() {
- // The only allowed MMI procedure for ICC PIN, PIN2, PUK and PUK2 handling
- // is "Registration" (**).
- if (mmi.procedure != MMI_PROCEDURE_REGISTRATION ) {
- _sendMMIError(MMI_ERROR_KS_INVALID_ACTION);
- return false;
- }
-
- if (!mmi.sia || !mmi.sib || !mmi.sic) {
- _sendMMIError(MMI_ERROR_KS_ERROR);
- return false;
- }
-
- if (mmi.sia.length < 4 || mmi.sia.length > 8 ||
- mmi.sib.length < 4 || mmi.sib.length > 8 ||
- mmi.sic.length < 4 || mmi.sic.length > 8) {
- _sendMMIError(MMI_ERROR_KS_INVALID_PIN);
- return false;
- }
-
- if (mmi.sib != mmi.sic) {
- _sendMMIError(MMI_ERROR_KS_MISMATCH_PIN);
- return false;
- }
-
- return true;
- }
-
- function _isValidChangePasswordRequest() {
- if (mmi.procedure !== MMI_PROCEDURE_REGISTRATION &&
- mmi.procedure !== MMI_PROCEDURE_ACTIVATION) {
- _sendMMIError(MMI_ERROR_KS_INVALID_ACTION);
- return false;
- }
-
- if (mmi.sia !== "" && mmi.sia !== MMI_ZZ_BARRING_SERVICE) {
- _sendMMIError(MMI_ERROR_KS_NOT_SUPPORTED);
- return false;
- }
-
- let validPassword = si => /^[0-9]{4}$/.test(si);
- if (!validPassword(mmi.sib) || !validPassword(mmi.sic) ||
- !validPassword(mmi.pwd)) {
- _sendMMIError(MMI_ERROR_KS_INVALID_PASSWORD);
- return false;
- }
-
- if (mmi.sic != mmi.pwd) {
- _sendMMIError(MMI_ERROR_KS_MISMATCH_PASSWORD);
- return false;
- }
-
- return true;
- }
-
- let _isRadioAvailable = (function() {
- if (this.radioState !== GECKO_RADIOSTATE_ENABLED) {
- _sendMMIError(GECKO_ERROR_RADIO_NOT_AVAILABLE);
- return false;
- }
- return true;
- }).bind(this);
-
- // We check if the MMI service code is supported and in that case we
- // trigger the appropriate RIL request if possible.
- let sc = mmi.serviceCode;
- switch (sc) {
- // Call forwarding
- case MMI_SC_CFU:
- case MMI_SC_CF_BUSY:
- case MMI_SC_CF_NO_REPLY:
- case MMI_SC_CF_NOT_REACHABLE:
- case MMI_SC_CF_ALL:
- case MMI_SC_CF_ALL_CONDITIONAL:
- if (!_isRadioAvailable()) {
- return;
- }
- // Call forwarding requires at least an action, given by the MMI
- // procedure, and a reason, given by the MMI service code, but there
- // is no way that we get this far without a valid procedure or service
- // code.
- options.action = MMI_PROC_TO_CF_ACTION[mmi.procedure];
- options.reason = MMI_SC_TO_CF_REASON[sc];
- options.number = mmi.sia;
- options.serviceClass = this._siToServiceClass(mmi.sib);
- if (options.action == CALL_FORWARD_ACTION_QUERY_STATUS) {
- this.queryCallForwardStatus(options);
- return;
- }
-
- options.isSetCallForward = true;
- options.timeSeconds = mmi.sic;
- this.setCallForward(options);
- return;
-
- // Change the current ICC PIN number.
- case MMI_SC_PIN:
- // As defined in TS.122.030 6.6.2 to change the ICC PIN we should expect
- // an MMI code of the form **04*OLD_PIN*NEW_PIN*NEW_PIN#, where old PIN
- // should be entered as the SIA parameter and the new PIN as SIB and
- // SIC.
- if (!_isRadioAvailable() || !_isValidPINPUKRequest()) {
- return;
- }
-
- options.password = mmi.sia;
- options.newPassword = mmi.sib;
- this.changeICCPIN(options);
- return;
-
- // Change the current ICC PIN2 number.
- case MMI_SC_PIN2:
- // As defined in TS.122.030 6.6.2 to change the ICC PIN2 we should
- // enter and MMI code of the form **042*OLD_PIN2*NEW_PIN2*NEW_PIN2#,
- // where the old PIN2 should be entered as the SIA parameter and the
- // new PIN2 as SIB and SIC.
- if (!_isRadioAvailable() || !_isValidPINPUKRequest()) {
- return;
- }
-
- options.password = mmi.sia;
- options.newPassword = mmi.sib;
- this.changeICCPIN2(options);
- return;
-
- // Unblock ICC PIN.
- case MMI_SC_PUK:
- // As defined in TS.122.030 6.6.3 to unblock the ICC PIN we should
- // enter an MMI code of the form **05*PUK*NEW_PIN*NEW_PIN#, where PUK
- // should be entered as the SIA parameter and the new PIN as SIB and
- // SIC.
- if (!_isRadioAvailable() || !_isValidPINPUKRequest()) {
- return;
- }
-
- options.password = mmi.sia;
- options.newPin = mmi.sib;
- this.enterICCPUK(options);
- return;
-
- // Unblock ICC PIN2.
- case MMI_SC_PUK2:
- // As defined in TS.122.030 6.6.3 to unblock the ICC PIN2 we should
- // enter an MMI code of the form **052*PUK2*NEW_PIN2*NEW_PIN2#, where
- // PUK2 should be entered as the SIA parameter and the new PIN2 as SIB
- // and SIC.
- if (!_isRadioAvailable() || !_isValidPINPUKRequest()) {
- return;
- }
-
- options.password = mmi.sia;
- options.newPin = mmi.sib;
- this.enterICCPUK2(options);
- return;
-
- // IMEI
- case MMI_SC_IMEI:
- // A device's IMEI can't change, so we only need to request it once.
- if (this.IMEI == null) {
- this.getIMEI(options);
- return;
- }
- // If we already had the device's IMEI, we just send it to chrome.
- options.statusMessage = this.IMEI;
- this.sendChromeMessage(options);
- return;
-
- // CLIP
- case MMI_SC_CLIP:
- options.procedure = mmi.procedure;
- if (options.procedure === MMI_PROCEDURE_INTERROGATION) {
- this.queryCLIP(options);
- } else {
- _sendMMIError(MMI_ERROR_KS_NOT_SUPPORTED);
- }
- return;
-
- // CLIR (non-temporary ones)
- // TODO: Both dial() and sendMMI() functions should be unified at some
- // point in the future. In the mean time we handle temporary CLIR MMI
- // commands through the dial() function. Please see bug 889737.
- case MMI_SC_CLIR:
- options.procedure = mmi.procedure;
- switch (options.procedure) {
- case MMI_PROCEDURE_INTERROGATION:
- this.getCLIR(options);
- return;
- case MMI_PROCEDURE_ACTIVATION:
- options.clirMode = CLIR_INVOCATION;
- break;
- case MMI_PROCEDURE_DEACTIVATION:
- options.clirMode = CLIR_SUPPRESSION;
- break;
- default:
- _sendMMIError(MMI_ERROR_KS_NOT_SUPPORTED);
- return;
- }
- options.isSetCLIR = true;
- this.setCLIR(options);
- return;
-
- // Change call barring password
- case MMI_SC_CHANGE_PASSWORD:
- if (!_isRadioAvailable() || !_isValidChangePasswordRequest()) {
- return;
- }
-
- options.pin = mmi.sib;
- options.newPin = mmi.sic;
- this.changeCallBarringPassword(options);
- return;
-
- // Call barring
- case MMI_SC_BAOC:
- case MMI_SC_BAOIC:
- case MMI_SC_BAOICxH:
- case MMI_SC_BAIC:
- case MMI_SC_BAICr:
- case MMI_SC_BA_ALL:
- case MMI_SC_BA_MO:
- case MMI_SC_BA_MT:
- options.password = mmi.sia || "";
- options.serviceClass = this._siToServiceClass(mmi.sib);
- options.facility = MMI_SC_TO_CB_FACILITY[sc];
- options.procedure = mmi.procedure;
- if (mmi.procedure === MMI_PROCEDURE_INTERROGATION) {
- this.queryICCFacilityLock(options);
- return;
- }
- if (mmi.procedure === MMI_PROCEDURE_ACTIVATION) {
- options.enabled = 1;
- } else if (mmi.procedure === MMI_PROCEDURE_DEACTIVATION) {
- options.enabled = 0;
- } else {
- _sendMMIError(MMI_ERROR_KS_NOT_SUPPORTED);
- return;
- }
- this.setICCFacilityLock(options);
- return;
-
- // Call waiting
- case MMI_SC_CALL_WAITING:
- if (!_isRadioAvailable()) {
- return;
- }
-
-
- if (mmi.procedure === MMI_PROCEDURE_INTERROGATION) {
- this._handleQueryMMICallWaiting(options);
- return;
- }
-
- if (mmi.procedure === MMI_PROCEDURE_ACTIVATION) {
- options.enabled = true;
- } else if (mmi.procedure === MMI_PROCEDURE_DEACTIVATION) {
- options.enabled = false;
- } else {
- _sendMMIError(MMI_ERROR_KS_NOT_SUPPORTED);
- return;
- }
-
- options.serviceClass = this._siToServiceClass(mmi.sia);
- this._handleSetMMICallWaiting(options);
- return;
- }
-
- // 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);
@@ -2935,47 +2565,6 @@ RilObject.prototype = {
*/
_processEnterAndChangeICCResponses: function(length, options) {
options.retryCount = length ? this.context.Buf.readInt32List()[0] : -1;
- if (options.rilMessageType != "sendMMI") {
- this.sendChromeMessage(options);
- return;
- }
-
- let serviceCode = options.mmi.serviceCode;
-
- if (!options.errorMsg) {
- switch (serviceCode) {
- case MMI_SC_PIN:
- options.statusMessage = MMI_SM_KS_PIN_CHANGED;
- break;
- case MMI_SC_PIN2:
- options.statusMessage = MMI_SM_KS_PIN2_CHANGED;
- break;
- case MMI_SC_PUK:
- options.statusMessage = MMI_SM_KS_PIN_UNBLOCKED;
- break;
- case MMI_SC_PUK2:
- options.statusMessage = MMI_SM_KS_PIN2_UNBLOCKED;
- break;
- }
- } else {
- if (options.retryCount <= 0) {
- if (serviceCode === MMI_SC_PUK) {
- options.errorMsg = MMI_ERROR_KS_SIM_BLOCKED;
- } else if (serviceCode === MMI_SC_PIN) {
- options.errorMsg = MMI_ERROR_KS_NEEDS_PUK;
- }
- } else {
- if (serviceCode === MMI_SC_PIN || serviceCode === MMI_SC_PIN2) {
- options.errorMsg = MMI_ERROR_KS_BAD_PIN;
- } else if (serviceCode === MMI_SC_PUK || serviceCode === MMI_SC_PUK2) {
- options.errorMsg = MMI_ERROR_KS_BAD_PUK;
- }
- if (options.retryCount !== undefined) {
- options.additionalInformation = options.retryCount;
- }
- }
- }
-
this.sendChromeMessage(options);
},
@@ -3584,44 +3173,6 @@ RilObject.prototype = {
return toa;
},
- /**
- * Helper for translating basic service group to call forwarding service class
- * parameter.
- */
- _siToServiceClass: function(si) {
- if (!si) {
- return ICC_SERVICE_CLASS_NONE;
- }
-
- let serviceCode = parseInt(si, 10);
- switch (serviceCode) {
- case 10:
- return ICC_SERVICE_CLASS_SMS + ICC_SERVICE_CLASS_FAX + ICC_SERVICE_CLASS_VOICE;
- case 11:
- return ICC_SERVICE_CLASS_VOICE;
- case 12:
- return ICC_SERVICE_CLASS_SMS + ICC_SERVICE_CLASS_FAX;
- case 13:
- return ICC_SERVICE_CLASS_FAX;
- case 16:
- return ICC_SERVICE_CLASS_SMS;
- case 19:
- return ICC_SERVICE_CLASS_FAX + ICC_SERVICE_CLASS_VOICE;
- case 21:
- return ICC_SERVICE_CLASS_PAD + ICC_SERVICE_CLASS_DATA_ASYNC;
- case 22:
- return ICC_SERVICE_CLASS_PACKET + ICC_SERVICE_CLASS_DATA_SYNC;
- case 25:
- return ICC_SERVICE_CLASS_DATA_ASYNC;
- case 26:
- return ICC_SERVICE_CLASS_DATA_SYNC + SERVICE_CLASS_VOICE;
- case 99:
- return ICC_SERVICE_CLASS_PACKET;
- default:
- return ICC_SERVICE_CLASS_NONE;
- }
- },
-
/**
* @param message A decoded SMS-DELIVER message.
*
@@ -4745,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) {
@@ -4781,66 +4320,6 @@ RilObject.prototype[REQUEST_GET_CLIR] = function REQUEST_GET_CLIR(length, option
options.n = Buf.readInt32(); // Will be TS 27.007 +CLIR parameter 'n'.
options.m = Buf.readInt32(); // Will be TS 27.007 +CLIR parameter 'm'.
-
- if (options.rilMessageType === "sendMMI") {
- // TS 27.007 +CLIR parameter 'm'.
- switch (options.m) {
- // CLIR not provisioned.
- case 0:
- options.statusMessage = MMI_SM_KS_SERVICE_NOT_PROVISIONED;
- break;
- // CLIR provisioned in permanent mode.
- case 1:
- options.statusMessage = MMI_SM_KS_CLIR_PERMANENT;
- break;
- // Unknown (e.g. no network, etc.).
- case 2:
- options.errorMsg = MMI_ERROR_KS_ERROR;
- break;
- // CLIR temporary mode presentation restricted.
- case 3:
- // TS 27.007 +CLIR parameter 'n'.
- switch (options.n) {
- // Default.
- case 0:
- // CLIR invocation.
- case 1:
- options.statusMessage = MMI_SM_KS_CLIR_DEFAULT_ON_NEXT_CALL_ON;
- break;
- // CLIR suppression.
- case 2:
- options.statusMessage = MMI_SM_KS_CLIR_DEFAULT_ON_NEXT_CALL_OFF;
- break;
- default:
- options.errorMsg = GECKO_ERROR_GENERIC_FAILURE;
- break;
- }
- break;
- // CLIR temporary mode presentation allowed.
- case 4:
- // TS 27.007 +CLIR parameter 'n'.
- switch (options.n) {
- // Default.
- case 0:
- // CLIR suppression.
- case 2:
- options.statusMessage = MMI_SM_KS_CLIR_DEFAULT_OFF_NEXT_CALL_OFF;
- break;
- // CLIR invocation.
- case 1:
- options.statusMessage = MMI_SM_KS_CLIR_DEFAULT_OFF_NEXT_CALL_ON;
- break;
- default:
- options.errorMsg = GECKO_ERROR_GENERIC_FAILURE;
- break;
- }
- break;
- default:
- options.errorMsg = GECKO_ERROR_GENERIC_FAILURE;
- break;
- }
- }
-
this.sendChromeMessage(options);
};
RilObject.prototype[REQUEST_SET_CLIR] = function REQUEST_SET_CLIR(length, options) {
@@ -4849,16 +4328,6 @@ RilObject.prototype[REQUEST_SET_CLIR] = function REQUEST_SET_CLIR(length, option
return;
}
- if (!options.errorMsg && options.rilMessageType === "sendMMI") {
- switch (options.procedure) {
- case MMI_PROCEDURE_ACTIVATION:
- options.statusMessage = MMI_SM_KS_SERVICE_ENABLED;
- break;
- case MMI_PROCEDURE_DEACTIVATION:
- options.statusMessage = MMI_SM_KS_SERVICE_DISABLED;
- break;
- }
- }
this.sendChromeMessage(options);
};
@@ -4891,52 +4360,19 @@ RilObject.prototype[REQUEST_QUERY_CALL_FORWARD_STATUS] =
rules[i] = rule;
}
options.rules = rules;
- if (options.rilMessageType === "sendMMI") {
- options.statusMessage = MMI_SM_KS_SERVICE_INTERROGATED;
- // MMI query call forwarding options request returns a set of rules that
- // will be exposed in the form of an array of MozCallForwardingOptions
- // instances.
- options.additionalInformation = rules;
- }
this.sendChromeMessage(options);
};
RilObject.prototype[REQUEST_SET_CALL_FORWARD] =
function REQUEST_SET_CALL_FORWARD(length, options) {
- if (!options.errorMsg && options.rilMessageType === "sendMMI") {
- switch (options.action) {
- case CALL_FORWARD_ACTION_ENABLE:
- options.statusMessage = MMI_SM_KS_SERVICE_ENABLED;
- break;
- case CALL_FORWARD_ACTION_DISABLE:
- options.statusMessage = MMI_SM_KS_SERVICE_DISABLED;
- break;
- case CALL_FORWARD_ACTION_REGISTRATION:
- options.statusMessage = MMI_SM_KS_SERVICE_REGISTERED;
- break;
- case CALL_FORWARD_ACTION_ERASURE:
- options.statusMessage = MMI_SM_KS_SERVICE_ERASED;
- break;
- }
- }
this.sendChromeMessage(options);
};
RilObject.prototype[REQUEST_QUERY_CALL_WAITING] =
function REQUEST_QUERY_CALL_WAITING(length, options) {
if (options.errorMsg) {
- if (options.callback) {
- // Prevent DataCloneError when sending chrome messages.
- delete options.callback;
- }
-
this.sendChromeMessage(options);
return;
}
- if (options.callback) {
- options.callback.call(this, options);
- return;
- }
-
let Buf = this.context.Buf;
let results = Buf.readInt32List();
let enabled = (results[0] === 1);
@@ -4945,37 +4381,23 @@ RilObject.prototype[REQUEST_QUERY_CALL_WAITING] =
};
RilObject.prototype[REQUEST_SET_CALL_WAITING] = function REQUEST_SET_CALL_WAITING(length, options) {
- if (options.errorMsg) {
- if (options.callback) {
- // Prevent DataCloneError when sending chrome messages.
- delete options.callback;
- }
-
- this.sendChromeMessage(options);
- return;
- }
-
- if (options.callback) {
- options.callback.call(this, options);
- return;
- }
-
this.sendChromeMessage(options);
};
RilObject.prototype[REQUEST_SMS_ACKNOWLEDGE] = null;
RilObject.prototype[REQUEST_GET_IMEI] = function REQUEST_GET_IMEI(length, options) {
this.IMEI = this.context.Buf.readString();
- let rilMessageType = options.rilMessageType;
- // So far we only send the IMEI back to chrome if it was requested via MMI.
- if (rilMessageType !== "sendMMI") {
- return;
- }
- if (!options.errorMsg && this.IMEI == null) {
- options.errorMsg = GECKO_ERROR_GENERIC_FAILURE;
+ // If the request wasn't made by ril_worker itself, we send the IMEI back to
+ // chrome.
+ if (options.rilMessageType) {
+ if (options.errorMsg) {
+ this.sendChromeMessage(options);
+ return;
+ }
+
+ options.imei = this.IMEI;
+ this.sendChromeMessage(options);
}
- options.statusMessage = this.IMEI;
- this.sendChromeMessage(options);
};
RilObject.prototype[REQUEST_GET_IMEISV] = function REQUEST_GET_IMEISV(length, options) {
if (options.errorMsg) {
@@ -5003,57 +4425,22 @@ RilObject.prototype[REQUEST_QUERY_FACILITY_LOCK] = function REQUEST_QUERY_FACILI
}
// Buf.readInt32List()[0] for Call Barring is a bit vector of services.
- let services = this.context.Buf.readInt32List()[0];
-
+ options.serviceClass = this.context.Buf.readInt32List()[0];
if (options.queryServiceClass) {
- options.enabled = (services & options.queryServiceClass) ? true : false;
+ options.enabled = (options.serviceClass & options.queryServiceClass) ? true : false;
options.serviceClass = options.queryServiceClass;
} else {
- options.enabled = services ? true : false;
+ options.enabled = options.serviceClass ? true : false;
}
- if (options.rilMessageType === "sendMMI") {
- if (!options.enabled) {
- options.statusMessage = MMI_SM_KS_SERVICE_DISABLED;
- } else {
- options.statusMessage = MMI_SM_KS_SERVICE_ENABLED_FOR;
- let serviceClass = [];
- for (let serviceClassMask = 1;
- serviceClassMask <= ICC_SERVICE_CLASS_MAX;
- serviceClassMask <<= 1) {
- if ((serviceClassMask & services) !== 0) {
- serviceClass.push(MMI_KS_SERVICE_CLASS_MAPPING[serviceClassMask]);
- }
- }
-
- options.additionalInformation = serviceClass;
- }
- }
this.sendChromeMessage(options);
};
RilObject.prototype[REQUEST_SET_FACILITY_LOCK] = function REQUEST_SET_FACILITY_LOCK(length, options) {
options.retryCount = length ? this.context.Buf.readInt32List()[0] : -1;
-
- if (!options.errorMsg && (options.rilMessageType === "sendMMI")) {
- switch (options.procedure) {
- case MMI_PROCEDURE_ACTIVATION:
- options.statusMessage = MMI_SM_KS_SERVICE_ENABLED;
- break;
- case MMI_PROCEDURE_DEACTIVATION:
- options.statusMessage = MMI_SM_KS_SERVICE_DISABLED;
- break;
- }
- }
this.sendChromeMessage(options);
};
RilObject.prototype[REQUEST_CHANGE_BARRING_PASSWORD] =
function REQUEST_CHANGE_BARRING_PASSWORD(length, options) {
- if (options.rilMessageType != "sendMMI") {
- this.sendChromeMessage(options);
- return;
- }
-
- options.statusMessage = MMI_SM_KS_PASSWORD_CHANGED;
this.sendChromeMessage(options);
};
RilObject.prototype[REQUEST_QUERY_NETWORK_SELECTION_MODE] = function REQUEST_QUERY_NETWORK_SELECTION_MODE(length, options) {
@@ -5129,25 +4516,7 @@ RilObject.prototype[REQUEST_QUERY_CLIP] = function REQUEST_QUERY_CLIP(length, op
return;
}
- // options.provisioned informs about the called party receives the calling
- // party's address information:
- // 0 for CLIP not provisioned
- // 1 for CLIP provisioned
- // 2 for unknown
options.provisioned = Buf.readInt32();
- if (options.rilMessageType === "sendMMI") {
- switch (options.provisioned) {
- case 0:
- options.statusMessage = MMI_SM_KS_SERVICE_DISABLED;
- break;
- case 1:
- options.statusMessage = MMI_SM_KS_SERVICE_ENABLED;
- break;
- default:
- options.errorMsg = MMI_ERROR_KS_ERROR;
- break;
- }
- }
this.sendChromeMessage(options);
};
RilObject.prototype[REQUEST_LAST_DATA_CALL_FAIL_CAUSE] = null;
@@ -5721,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 80ecf228aebd..000000000000
--- a/dom/system/gonk/tests/test_ril_worker_mmi.js
+++ /dev/null
@@ -1,513 +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_change_PIN() {
- let workerhelper = newInterceptWorker();
- let worker = workerhelper.worker;
- let context = worker.ContextPool._contexts[0];
-
- context.RIL.changeICCPIN = function fakeChangeICCPIN(options) {
- context.RIL[REQUEST_ENTER_SIM_PIN](0, {});
- };
-
- context.RIL.radioState = GECKO_RADIOSTATE_ENABLED;
- context.RIL.sendMMI({mmi: createMMIOptions("**", "04", "1234", "4567",
- "4567")});
-
- let postedMessage = workerhelper.postedMessage;
-
- equal(postedMessage.errorMsg, undefined);
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_change_PIN_no_new_PIN() {
- testSendMMI(createMMIOptions("**", "04", "1234", "", "4567"),
- MMI_ERROR_KS_ERROR);
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_change_PIN_no_old_PIN() {
- testSendMMI(createMMIOptions("**", "04", "", "1234", "4567"),
- MMI_ERROR_KS_ERROR);
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_change_PIN_wrong_procedure() {
- testSendMMI(createMMIOptions("*", "04", "1234", "4567", "4567"),
- MMI_ERROR_KS_INVALID_ACTION);
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_change_PIN_new_PIN_mismatch() {
- testSendMMI(createMMIOptions("**", "04", "4567", "1234", "4567"),
- MMI_ERROR_KS_MISMATCH_PIN);
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_change_PIN2() {
- let workerhelper = newInterceptWorker();
- let worker = workerhelper.worker;
- let context = worker.ContextPool._contexts[0];
-
- context.RIL.changeICCPIN2 = function fakeChangeICCPIN2(options) {
- context.RIL[REQUEST_ENTER_SIM_PIN2](0, {});
- };
-
- context.RIL.radioState = GECKO_RADIOSTATE_ENABLED;
- context.RIL.sendMMI({mmi: createMMIOptions("**", "042", "1234", "4567",
- "4567")});
-
- let postedMessage = workerhelper.postedMessage;
-
- equal(postedMessage.errorMsg, undefined);
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_change_PIN2_no_new_PIN2() {
- testSendMMI(createMMIOptions("**", "042", "1234", "", "4567"),
- MMI_ERROR_KS_ERROR);
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_change_PIN2_no_old_PIN2() {
- testSendMMI(createMMIOptions("**", "042", "", "1234", "4567"),
- MMI_ERROR_KS_ERROR);
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_change_PIN2_wrong_procedure() {
- testSendMMI(createMMIOptions("*", "042", "1234", "4567", "4567"),
- MMI_ERROR_KS_INVALID_ACTION);
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_change_PIN2_new_PIN2_mismatch() {
- testSendMMI(createMMIOptions("**", "042", "4567", "1234", "4567"),
- MMI_ERROR_KS_MISMATCH_PIN);
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_unblock_PIN() {
- let workerhelper = newInterceptWorker();
- let worker = workerhelper.worker;
- let context = worker.ContextPool._contexts[0];
-
- context.RIL.enterICCPUK = function fakeEnterICCPUK(options) {
- context.RIL[REQUEST_ENTER_SIM_PUK](0, {});
- };
-
- context.RIL.radioState = GECKO_RADIOSTATE_ENABLED;
- context.RIL.sendMMI({mmi: createMMIOptions("**", "05", "1234", "4567",
- "4567")});
-
- let postedMessage = workerhelper.postedMessage;
-
- equal(postedMessage.errorMsg, undefined);
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_unblock_PIN_no_new_PIN() {
- testSendMMI(createMMIOptions("**", "05", "1234", "", "4567"),
- MMI_ERROR_KS_ERROR);
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_unblock_PIN_no_PUK() {
- testSendMMI(createMMIOptions("**", "05", "", "1234", "4567"),
- MMI_ERROR_KS_ERROR);
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_unblock_PIN_wrong_procedure() {
- testSendMMI(createMMIOptions("*", "05", "1234", "4567", "4567"),
- MMI_ERROR_KS_INVALID_ACTION);
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_unblock_PIN_new_PIN_mismatch() {
- testSendMMI(createMMIOptions("**", "05", "4567", "1234", "4567"),
- MMI_ERROR_KS_MISMATCH_PIN);
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_unblock_PIN2() {
- let workerhelper = newInterceptWorker();
- let worker = workerhelper.worker;
- let context = worker.ContextPool._contexts[0];
-
- context.RIL.enterICCPUK2 = function fakeEnterICCPUK2(options) {
- context.RIL[REQUEST_ENTER_SIM_PUK2](0, {});
- };
-
- context.RIL.radioState = GECKO_RADIOSTATE_ENABLED;
- context.RIL.sendMMI({mmi: createMMIOptions("**", "052", "1234", "4567",
- "4567")});
-
- let postedMessage = workerhelper.postedMessage;
-
- equal(postedMessage.errorMsg, undefined);
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_unblock_PIN2_no_new_PIN2() {
- testSendMMI(createMMIOptions("**", "052", "1234", "", "4567"),
- MMI_ERROR_KS_ERROR);
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_unblock_PIN2_no_PUK2() {
- testSendMMI(createMMIOptions("**", "052", "", "1234", "4567"),
- MMI_ERROR_KS_ERROR);
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_unblock_PIN2_wrong_procedure() {
- testSendMMI(createMMIOptions("*", "052", "1234", "4567", "4567"),
- MMI_ERROR_KS_INVALID_ACTION);
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_unblock_PIN2_new_PIN_mismatch() {
- testSendMMI(createMMIOptions("**", "052", "4567", "1234", "4567"),
- MMI_ERROR_KS_MISMATCH_PIN);
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_get_IMEI() {
- let workerhelper = newInterceptWorker();
- let worker = workerhelper.worker;
- let context = worker.ContextPool._contexts[0];
- let mmiOptions;
-
- context.RIL.getIMEI = function getIMEI(options) {
- mmiOptions = options;
- context.RIL[REQUEST_SEND_USSD](0, {});
- };
-
- context.RIL.sendMMI({mmi: createMMIOptions("*#", "06")});
-
- let postedMessage = workerhelper.postedMessage;
-
- notEqual(mmiOptions.mmi, null);
- equal(postedMessage.errorMsg, undefined);
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_get_IMEI_error() {
- let workerhelper = newInterceptWorker();
- let worker = workerhelper.worker;
- let context = worker.ContextPool._contexts[0];
- let mmiOptions;
-
- context.RIL.getIMEI = function getIMEI(options){
- mmiOptions = options;
- context.RIL[REQUEST_SEND_USSD](0, {
- errorMsg: GECKO_ERROR_RADIO_NOT_AVAILABLE
- });
- };
-
- context.RIL.sendMMI({mmi: createMMIOptions("*#", "06")});
-
- let postedMessage = workerhelper.postedMessage;
-
- notEqual(mmiOptions.mmi, null);
- equal (postedMessage.errorMsg, GECKO_ERROR_RADIO_NOT_AVAILABLE);
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_call_barring_BAIC_interrogation_voice() {
- let workerhelper = newInterceptWorker();
- let worker = workerhelper.worker;
- let context = worker.ContextPool._contexts[0];
-
- context.Buf.readInt32List = function fakeReadUint32List() {
- return [1];
- };
-
- context.RIL.queryICCFacilityLock =
- function fakeQueryICCFacilityLock(options) {
- context.RIL[REQUEST_QUERY_FACILITY_LOCK](1, {
- rilMessageType: "sendMMI"
- });
- };
-
- context.RIL.radioState = GECKO_RADIOSTATE_ENABLED;
- context.RIL.sendMMI({mmi: createMMIOptions("*#", "33")});
-
- let postedMessage = workerhelper.postedMessage;
-
- equal(postedMessage.errorMsg, undefined);
- ok(postedMessage.enabled);
- equal(postedMessage.statusMessage, MMI_SM_KS_SERVICE_ENABLED_FOR);
- ok(Array.isArray(postedMessage.additionalInformation));
- equal(postedMessage.additionalInformation[0], "serviceClassVoice");
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_call_barring_BAIC_activation() {
- let workerhelper = newInterceptWorker();
- let worker = workerhelper.worker;
- let context = worker.ContextPool._contexts[0];
- let mmiOptions;
-
- context.RIL.setICCFacilityLock =
- function fakeSetICCFacilityLock(options) {
- mmiOptions = options;
- context.RIL[REQUEST_SET_FACILITY_LOCK](0, {
- rilMessageType: "sendMMI",
- procedure: MMI_PROCEDURE_ACTIVATION
- });
- };
-
- context.RIL.radioState = GECKO_RADIOSTATE_ENABLED;
- context.RIL.sendMMI({mmi: createMMIOptions("*", "33")});
-
- let postedMessage = workerhelper.postedMessage;
-
- equal(mmiOptions.procedure, MMI_PROCEDURE_ACTIVATION);
- equal(postedMessage.errorMsg, undefined);
- equal(postedMessage.statusMessage, MMI_SM_KS_SERVICE_ENABLED);
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_call_barring_BAIC_deactivation() {
- let workerhelper = newInterceptWorker();
- let worker = workerhelper.worker;
- let context = worker.ContextPool._contexts[0];
- let mmiOptions;
-
- context.RIL.setICCFacilityLock =
- function fakeSetICCFacilityLock(options) {
- mmiOptions = options;
- context.RIL[REQUEST_SET_FACILITY_LOCK](0, {
- rilMessageType: "sendMMI",
- procedure: MMI_PROCEDURE_DEACTIVATION
- });
- };
-
- context.RIL.radioState = GECKO_RADIOSTATE_ENABLED;
- context.RIL.sendMMI({mmi: createMMIOptions("#", "33")});
-
- let postedMessage = workerhelper.postedMessage;
-
- equal(mmiOptions.procedure, MMI_PROCEDURE_DEACTIVATION);
- equal(postedMessage.errorMsg, undefined);
- equal(postedMessage.statusMessage, MMI_SM_KS_SERVICE_DISABLED);
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_call_barring_BAIC_procedure_not_supported() {
- testSendMMI(createMMIOptions("**", "33", "0000"), MMI_ERROR_KS_NOT_SUPPORTED);
-
- 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();
-});
-
-function setCallWaitingSuccess(mmi) {
- let workerhelper = newInterceptWorker();
- let worker = workerhelper.worker;
- let context = worker.ContextPool._contexts[0];
-
- context.RIL.setCallWaiting = function fakeSetCallWaiting(options) {
- context.RIL[REQUEST_SET_CALL_WAITING](0, {});
- };
-
- context.RIL.radioState = GECKO_RADIOSTATE_ENABLED;
- context.RIL.sendMMI({mmi: mmi});
-
- let postedMessage = workerhelper.postedMessage;
-
- equal(postedMessage.errorMsg, undefined);
-}
-
-add_test(function test_sendMMI_call_waiting_activation() {
- setCallWaitingSuccess(createMMIOptions("*", "43", "10"));
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_call_waiting_deactivation() {
- setCallWaitingSuccess(createMMIOptions("#", "43"));
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_call_waiting_registration() {
- testSendMMI(createMMIOptions("**", "43"), MMI_ERROR_KS_NOT_SUPPORTED);
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_call_waiting_erasure() {
- testSendMMI(createMMIOptions("##", "43"), MMI_ERROR_KS_NOT_SUPPORTED);
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_call_waiting_interrogation() {
- let workerhelper = newInterceptWorker();
- let worker = workerhelper.worker;
- let context = worker.ContextPool._contexts[0];
-
- context.Buf.readInt32 = function fakeReadUint32() {
- return context.Buf.int32Array.pop();
- };
-
- context.RIL.queryCallWaiting = function fakeQueryCallWaiting(options) {
- context.Buf.int32Array = [
- 7, // serviceClass
- 1, // enabled
- 2 // length
- ];
- context.RIL[REQUEST_QUERY_CALL_WAITING](1, {});
- };
-
- context.RIL.radioState = GECKO_RADIOSTATE_ENABLED;
- context.RIL.sendMMI({mmi: createMMIOptions("*#", "43")});
-
- let postedMessage = workerhelper.postedMessage;
-
- equal(postedMessage.errorMsg, undefined);
- equal(postedMessage.serviceClass, 7);
- run_next_test();
-});
diff --git a/dom/system/gonk/tests/test_ril_worker_mmi_cf.js b/dom/system/gonk/tests/test_ril_worker_mmi_cf.js
deleted file mode 100644
index 1362b313ef0b..000000000000
--- a/dom/system/gonk/tests/test_ril_worker_mmi_cf.js
+++ /dev/null
@@ -1,156 +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 setCallForwardSuccess(procedure, serviceCode, sia, sib, sic) {
- let workerhelper = newInterceptWorker();
- let worker = workerhelper.worker;
- let context = worker.ContextPool._contexts[0];
-
- context.RIL.setCallForward = function fakeSetCallForward(options) {
- context.RIL[REQUEST_SET_CALL_FORWARD](0, {});
- };
-
- context.RIL.radioState = GECKO_RADIOSTATE_ENABLED;
- context.RIL.sendMMI({mmi: createMMIOptions(procedure, serviceCode, sia, sib,
- sic)});
-
- let postedMessage = workerhelper.postedMessage;
-
- equal(postedMessage.errorMsg, undefined);
-}
-
-add_test(function test_sendMMI_call_forwarding_activation() {
- setCallForwardSuccess("*", "21", "12345", "99", "10");
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_call_forwarding_deactivation() {
- setCallForwardSuccess("#", "21", "12345", "99", "10");
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_call_forwarding_interrogation() {
- let workerhelper = newInterceptWorker();
- let worker = workerhelper.worker;
- let context = worker.ContextPool._contexts[0];
-
- context.Buf.readInt32 = function fakeReadUint32() {
- return context.Buf.int32Array.pop();
- };
-
- context.Buf.readString = function fakeReadString() {
- return "+34666222333";
- };
-
- context.RIL.queryCallForwardStatus = function fakeQueryCallForward(options) {
- context.Buf.int32Array = [
- 0, // rules.timeSeconds
- 145, // rules.toa
- 49, // rules.serviceClass
- CALL_FORWARD_REASON_UNCONDITIONAL, // rules.reason
- 1, // rules.active
- 1 // rulesLength
- ];
- context.RIL[REQUEST_QUERY_CALL_FORWARD_STATUS](1, {});
- };
-
- context.RIL.radioState = GECKO_RADIOSTATE_ENABLED;
- context.RIL.sendMMI({mmi: createMMIOptions("*#", "21")});
-
- let postedMessage = workerhelper.postedMessage;
-
- equal(postedMessage.errorMsg, undefined);
- ok(Array.isArray(postedMessage.rules));
- equal(postedMessage.rules.length, 1);
- ok(postedMessage.rules[0].active);
- equal(postedMessage.rules[0].reason, CALL_FORWARD_REASON_UNCONDITIONAL);
- equal(postedMessage.rules[0].number, "+34666222333");
- run_next_test();
-});
-
-add_test(function test_sendMMI_call_forwarding_interrogation_no_rules() {
- let workerhelper = newInterceptWorker();
- let worker = workerhelper.worker;
- let context = worker.ContextPool._contexts[0];
-
- context.Buf.readInt32 = function fakeReadUint32() {
- return 0;
- };
-
- context.RIL.queryCallForwardStatus = function fakeQueryCallForward(options) {
- context.RIL[REQUEST_QUERY_CALL_FORWARD_STATUS](1, {});
- };
-
- context.RIL.radioState = GECKO_RADIOSTATE_ENABLED;
- context.RIL.sendMMI({mmi: createMMIOptions("*#", "21")});
-
- let postedMessage = workerhelper.postedMessage;
-
- equal(postedMessage.errorMsg, GECKO_ERROR_GENERIC_FAILURE);
-
- run_next_test();
-});
-
-
-add_test(function test_sendMMI_call_forwarding_registration() {
- setCallForwardSuccess("**", "21", "12345", "99", "10");
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_call_forwarding_erasure() {
- setCallForwardSuccess("##", "21", "12345", "99");
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_call_forwarding_CFB() {
- setCallForwardSuccess("*", "67", "12345", "99", "10");
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_call_forwarding_CFNRy() {
- setCallForwardSuccess("*", "61", "12345", "99", "10");
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_call_forwarding_CFNRc() {
- setCallForwardSuccess("*", "62", "12345", "99", "10");
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_call_forwarding_CFAll() {
- setCallForwardSuccess("*", "004", "12345", "99", "10");
-
- run_next_test();
-});
-
-add_test(function test_sendMMI_call_forwarding_CFAllConditional() {
- setCallForwardSuccess("*", "002", "12345", "99", "10");
-
- run_next_test();
-});
diff --git a/dom/system/gonk/tests/xpcshell.ini b/dom/system/gonk/tests/xpcshell.ini
index 97acee85db8c..6af3d7437f06 100644
--- a/dom/system/gonk/tests/xpcshell.ini
+++ b/dom/system/gonk/tests/xpcshell.ini
@@ -23,8 +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_mmi_cf.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 bb3b6d9cf982..9b5b33ecc98d 100644
--- a/dom/telephony/gonk/TelephonyService.js
+++ b/dom/telephony/gonk/TelephonyService.js
@@ -23,8 +23,6 @@ const GONK_TELEPHONYSERVICE_CONTRACTID =
const GONK_TELEPHONYSERVICE_CID =
Components.ID("{67d26434-d063-4d28-9f48-5b3189788155}");
-const MOBILECALLFORWARDINGOPTIONS_CID =
- Components.ID("{79b5988b-9436-48d8-a652-88fa033f146c}");
const TELEPHONYCALLINFO_CID =
Components.ID("{d9e8b358-a02c-4cf3-9fc7-816c2e8d46e4}");
@@ -54,6 +52,173 @@ const DIAL_ERROR_RADIO_NOT_AVAILABLE = RIL.GECKO_ERROR_RADIO_NOT_AVAILABLE;
const TONES_GAP_DURATION = 70;
+// Consts for MMI.
+// MMI procedure as defined in TS.22.030 6.5.2
+const MMI_PROCEDURE_ACTIVATION = "*";
+const MMI_PROCEDURE_DEACTIVATION = "#";
+const MMI_PROCEDURE_INTERROGATION = "*#";
+const MMI_PROCEDURE_REGISTRATION = "**";
+const MMI_PROCEDURE_ERASURE = "##";
+
+// MMI call forwarding service codes as defined in TS.22.030 Annex B
+const MMI_SC_CFU = "21";
+const MMI_SC_CF_BUSY = "67";
+const MMI_SC_CF_NO_REPLY = "61";
+const MMI_SC_CF_NOT_REACHABLE = "62";
+const MMI_SC_CF_ALL = "002";
+const MMI_SC_CF_ALL_CONDITIONAL = "004";
+
+// MMI service codes for PIN/PIN2/PUK/PUK2 management as defined in TS.22.030
+// sec 6.6
+const MMI_SC_PIN = "04";
+const MMI_SC_PIN2 = "042";
+const MMI_SC_PUK = "05";
+const MMI_SC_PUK2 = "052";
+
+// MMI service code for IMEI presentation as defined in TS.22.030 sec 6.7
+const MMI_SC_IMEI = "06";
+
+// MMI call waiting service code
+const MMI_SC_CALL_WAITING = "43";
+
+// MMI service code for registration new password as defined in TS 22.030 6.5.4
+const MMI_SC_CHANGE_PASSWORD = "03";
+const MMI_ZZ_BARRING_SERVICE = "330";
+
+// MMI call barring service codes
+const MMI_SC_BAOC = "33";
+const MMI_SC_BAOIC = "331";
+const MMI_SC_BAOICxH = "332";
+const MMI_SC_BAIC = "35";
+const MMI_SC_BAICr = "351";
+const MMI_SC_BA_ALL = "330";
+const MMI_SC_BA_MO = "333";
+const MMI_SC_BA_MT = "353";
+
+// MMI called line presentation service codes
+const MMI_SC_CLIP = "30";
+const MMI_SC_CLIR = "31";
+
+// MMI service code key strings.
+const MMI_KS_SC_CALL_BARRING = "scCallBarring";
+const MMI_KS_SC_CALL_FORWARDING = "scCallForwarding";
+const MMI_KS_SC_CLIP = "scClip";
+const MMI_KS_SC_CLIR = "scClir";
+const MMI_KS_SC_PWD = "scPwd";
+const MMI_KS_SC_CALL_WAITING = "scCallWaiting";
+const MMI_KS_SC_PIN = "scPin";
+const MMI_KS_SC_PIN2 = "scPin2";
+const MMI_KS_SC_PUK = "scPuk";
+const MMI_KS_SC_PUK2 = "scPuk2";
+const MMI_KS_SC_CHANGE_PASSWORD = "scChangePassword";
+const MMI_KS_SC_IMEI = "scImei";
+const MMI_KS_SC_USSD = "scUssd";
+const MMI_KS_SC_CALL = "scCall";
+
+// MMI error messages key strings.
+const MMI_ERROR_KS_ERROR = "emMmiError";
+const MMI_ERROR_KS_NOT_SUPPORTED = "emMmiErrorNotSupported";
+const MMI_ERROR_KS_INVALID_ACTION = "emMmiErrorInvalidAction";
+const MMI_ERROR_KS_MISMATCH_PIN = "emMmiErrorMismatchPin";
+const MMI_ERROR_KS_MISMATCH_PASSWORD = "emMmiErrorMismatchPassword";
+const MMI_ERROR_KS_BAD_PIN = "emMmiErrorBadPin";
+const MMI_ERROR_KS_BAD_PUK = "emMmiErrorBadPuk";
+const MMI_ERROR_KS_INVALID_PIN = "emMmiErrorInvalidPin";
+const MMI_ERROR_KS_INVALID_PASSWORD = "emMmiErrorInvalidPassword";
+const MMI_ERROR_KS_NEEDS_PUK = "emMmiErrorNeedsPuk";
+const MMI_ERROR_KS_SIM_BLOCKED = "emMmiErrorSimBlocked";
+
+// MMI status message.
+const MMI_SM_KS_PASSWORD_CHANGED = "smPasswordChanged";
+const MMI_SM_KS_PIN_CHANGED = "smPinChanged";
+const MMI_SM_KS_PIN2_CHANGED = "smPin2Changed";
+const MMI_SM_KS_PIN_UNBLOCKED = "smPinUnblocked";
+const MMI_SM_KS_PIN2_UNBLOCKED = "smPin2Unblocked";
+const MMI_SM_KS_SERVICE_ENABLED = "smServiceEnabled";
+const MMI_SM_KS_SERVICE_ENABLED_FOR = "smServiceEnabledFor";
+const MMI_SM_KS_SERVICE_DISABLED = "smServiceDisabled";
+const MMI_SM_KS_SERVICE_REGISTERED = "smServiceRegistered";
+const MMI_SM_KS_SERVICE_ERASED = "smServiceErased";
+const MMI_SM_KS_SERVICE_INTERROGATED = "smServiceInterrogated";
+const MMI_SM_KS_SERVICE_NOT_PROVISIONED = "smServiceNotProvisioned";
+const MMI_SM_KS_CLIR_PERMANENT = "smClirPermanent";
+const MMI_SM_KS_CLIR_DEFAULT_ON_NEXT_CALL_ON = "smClirDefaultOnNextCallOn";
+const MMI_SM_KS_CLIR_DEFAULT_ON_NEXT_CALL_OFF = "smClirDefaultOnNextCallOff";
+const MMI_SM_KS_CLIR_DEFAULT_OFF_NEXT_CALL_ON = "smClirDefaultOffNextCallOn";
+const MMI_SM_KS_CLIR_DEFAULT_OFF_NEXT_CALL_OFF = "smClirDefaultOffNextCallOff";
+const MMI_SM_KS_CALL_CONTROL = "smCallControl";
+
+// MMI Service class
+const MMI_KS_SERVICE_CLASS_VOICE = "serviceClassVoice";
+const MMI_KS_SERVICE_CLASS_DATA = "serviceClassData";
+const MMI_KS_SERVICE_CLASS_FAX = "serviceClassFax";
+const MMI_KS_SERVICE_CLASS_SMS = "serviceClassSms";
+const MMI_KS_SERVICE_CLASS_DATA_SYNC = "serviceClassDataSync";
+const MMI_KS_SERVICE_CLASS_DATA_ASYNC = "serviceClassDataAsync";
+const MMI_KS_SERVICE_CLASS_PACKET = "serviceClassPacket";
+const MMI_KS_SERVICE_CLASS_PAD = "serviceClassPad";
+
+const MMI_PROC_TO_CF_ACTION = {};
+MMI_PROC_TO_CF_ACTION[MMI_PROCEDURE_ACTIVATION] = Ci.nsIMobileConnection.CALL_FORWARD_ACTION_ENABLE;
+MMI_PROC_TO_CF_ACTION[MMI_PROCEDURE_DEACTIVATION] = Ci.nsIMobileConnection.CALL_FORWARD_ACTION_DISABLE;
+MMI_PROC_TO_CF_ACTION[MMI_PROCEDURE_INTERROGATION] = Ci.nsIMobileConnection.CALL_FORWARD_ACTION_QUERY_STATUS;
+MMI_PROC_TO_CF_ACTION[MMI_PROCEDURE_REGISTRATION] = Ci.nsIMobileConnection.CALL_FORWARD_ACTION_REGISTRATION;
+MMI_PROC_TO_CF_ACTION[MMI_PROCEDURE_ERASURE] = Ci.nsIMobileConnection.CALL_FORWARD_ACTION_ERASURE;
+
+const MMI_SC_TO_CF_REASON = {};
+MMI_SC_TO_CF_REASON[MMI_SC_CFU] = Ci.nsIMobileConnection.CALL_FORWARD_REASON_UNCONDITIONAL;
+MMI_SC_TO_CF_REASON[MMI_SC_CF_BUSY] = Ci.nsIMobileConnection.CALL_FORWARD_REASON_MOBILE_BUSY;
+MMI_SC_TO_CF_REASON[MMI_SC_CF_NO_REPLY] = Ci.nsIMobileConnection.CALL_FORWARD_REASON_NO_REPLY;
+MMI_SC_TO_CF_REASON[MMI_SC_CF_NOT_REACHABLE] = Ci.nsIMobileConnection.CALL_FORWARD_REASON_NOT_REACHABLE;
+MMI_SC_TO_CF_REASON[MMI_SC_CF_ALL] = Ci.nsIMobileConnection.CALL_FORWARD_REASON_ALL_CALL_FORWARDING;
+MMI_SC_TO_CF_REASON[MMI_SC_CF_ALL_CONDITIONAL] = Ci.nsIMobileConnection.CALL_FORWARD_REASON_ALL_CONDITIONAL_CALL_FORWARDING;
+
+const MMI_SC_TO_LOCK_TYPE = {};
+MMI_SC_TO_LOCK_TYPE[MMI_SC_PIN] = Ci.nsIIcc.CARD_LOCK_TYPE_PIN;
+MMI_SC_TO_LOCK_TYPE[MMI_SC_PIN2] = Ci.nsIIcc.CARD_LOCK_TYPE_PIN2;
+MMI_SC_TO_LOCK_TYPE[MMI_SC_PUK] = Ci.nsIIcc.CARD_LOCK_TYPE_PUK;
+MMI_SC_TO_LOCK_TYPE[MMI_SC_PUK2] = Ci.nsIIcc.CARD_LOCK_TYPE_PUK2;
+
+const MMI_PROC_TO_CLIR_ACTION = {};
+MMI_PROC_TO_CLIR_ACTION[MMI_PROCEDURE_ACTIVATION] = Ci.nsIMobileConnection.CLIR_INVOCATION;
+MMI_PROC_TO_CLIR_ACTION[MMI_PROCEDURE_DEACTIVATION] = Ci.nsIMobileConnection.CLIR_SUPPRESSION;
+
+const MMI_SC_TO_CB_PROGRAM = {};
+MMI_SC_TO_CB_PROGRAM[MMI_SC_BAOC] = Ci.nsIMobileConnection.CALL_BARRING_PROGRAM_ALL_OUTGOING;
+MMI_SC_TO_CB_PROGRAM[MMI_SC_BAOIC] = Ci.nsIMobileConnection.CALL_BARRING_PROGRAM_OUTGOING_INTERNATIONAL;
+MMI_SC_TO_CB_PROGRAM[MMI_SC_BAOICxH] = Ci.nsIMobileConnection.CALL_BARRING_PROGRAM_OUTGOING_INTERNATIONAL_EXCEPT_HOME;
+MMI_SC_TO_CB_PROGRAM[MMI_SC_BAIC] = Ci.nsIMobileConnection.CALL_BARRING_PROGRAM_ALL_INCOMING;
+MMI_SC_TO_CB_PROGRAM[MMI_SC_BAICr] = Ci.nsIMobileConnection.CALL_BARRING_PROGRAM_INCOMING_ROAMING;
+MMI_SC_TO_CB_PROGRAM[MMI_SC_BA_ALL] = Ci.nsIMobileConnection.CALL_BARRING_PROGRAM_ALL_SERVICE;
+MMI_SC_TO_CB_PROGRAM[MMI_SC_BA_MO] = Ci.nsIMobileConnection.CALL_BARRING_PROGRAM_OUTGOING_SERVICE;
+MMI_SC_TO_CB_PROGRAM[MMI_SC_BA_MT] = Ci.nsIMobileConnection.CALL_BARRING_PROGRAM_INCOMING_SERVICE;
+
+const CF_ACTION_TO_STATUS_MESSAGE = {};
+CF_ACTION_TO_STATUS_MESSAGE[Ci.nsIMobileConnection.CALL_FORWARD_ACTION_ENABLE] = MMI_SM_KS_SERVICE_ENABLED;
+CF_ACTION_TO_STATUS_MESSAGE[Ci.nsIMobileConnection.CALL_FORWARD_ACTION_DISABLE] = MMI_SM_KS_SERVICE_DISABLED;
+CF_ACTION_TO_STATUS_MESSAGE[Ci.nsIMobileConnection.CALL_FORWARD_ACTION_REGISTRATION] = MMI_SM_KS_SERVICE_REGISTERED;
+CF_ACTION_TO_STATUS_MESSAGE[Ci.nsIMobileConnection.CALL_FORWARD_ACTION_ERASURE] = MMI_SM_KS_SERVICE_ERASED;
+
+const LOCK_TYPE_TO_STATUS_MESSAGE = {};
+LOCK_TYPE_TO_STATUS_MESSAGE[Ci.nsIIcc.CARD_LOCK_TYPE_PIN] = MMI_SM_KS_PIN_CHANGED;
+LOCK_TYPE_TO_STATUS_MESSAGE[Ci.nsIIcc.CARD_LOCK_TYPE_PIN2] = MMI_SM_KS_PIN2_CHANGED;
+LOCK_TYPE_TO_STATUS_MESSAGE[Ci.nsIIcc.CARD_LOCK_TYPE_PUK] = MMI_SM_KS_PIN_UNBLOCKED;
+LOCK_TYPE_TO_STATUS_MESSAGE[Ci.nsIIcc.CARD_LOCK_TYPE_PUK2] = MMI_SM_KS_PIN2_UNBLOCKED;
+
+const CLIR_ACTION_TO_STATUS_MESSAGE = {};
+CLIR_ACTION_TO_STATUS_MESSAGE[Ci.nsIMobileConnection.CLIR_INVOCATION] = MMI_SM_KS_SERVICE_ENABLED;
+CLIR_ACTION_TO_STATUS_MESSAGE[Ci.nsIMobileConnection.CLIR_SUPPRESSION] = MMI_SM_KS_SERVICE_DISABLED;
+
+const MMI_KS_SERVICE_CLASS_MAPPING = {};
+MMI_KS_SERVICE_CLASS_MAPPING[Ci.nsIMobileConnection.ICC_SERVICE_CLASS_VOICE] = MMI_KS_SERVICE_CLASS_VOICE;
+MMI_KS_SERVICE_CLASS_MAPPING[Ci.nsIMobileConnection.ICC_SERVICE_CLASS_DATA] = MMI_KS_SERVICE_CLASS_DATA;
+MMI_KS_SERVICE_CLASS_MAPPING[Ci.nsIMobileConnection.ICC_SERVICE_CLASS_FAX] = MMI_KS_SERVICE_CLASS_FAX;
+MMI_KS_SERVICE_CLASS_MAPPING[Ci.nsIMobileConnection.ICC_SERVICE_CLASS_SMS] = MMI_KS_SERVICE_CLASS_SMS;
+MMI_KS_SERVICE_CLASS_MAPPING[Ci.nsIMobileConnection.ICC_SERVICE_CLASS_DATA_SYNC] = MMI_KS_SERVICE_CLASS_DATA_SYNC;
+MMI_KS_SERVICE_CLASS_MAPPING[Ci.nsIMobileConnection.ICC_SERVICE_CLASS_DATA_ASYNC] = MMI_KS_SERVICE_CLASS_DATA_ASYNC;
+MMI_KS_SERVICE_CLASS_MAPPING[Ci.nsIMobileConnection.ICC_SERVICE_CLASS_PACKET] = MMI_KS_SERVICE_CLASS_PACKET;
+MMI_KS_SERVICE_CLASS_MAPPING[Ci.nsIMobileConnection.ICC_SERVICE_CLASS_PAD] = MMI_KS_SERVICE_CLASS_PAD;
+
let DEBUG;
function debug(s) {
dump("TelephonyService: " + s + "\n");
@@ -88,6 +253,12 @@ XPCOMUtils.defineLazyServiceGetter(this, "gGonkMobileConnectionService",
"@mozilla.org/mobileconnection/mobileconnectionservice;1",
"nsIGonkMobileConnectionService");
+/* global gIccService */
+XPCOMUtils.defineLazyServiceGetter(this, "gIccService",
+ "@mozilla.org/icc/iccservice;1",
+ "nsIIccService");
+
+
/* global PhoneNumberUtils */
XPCOMUtils.defineLazyModuleGetter(this, "PhoneNumberUtils",
"resource://gre/modules/PhoneNumberUtils.jsm");
@@ -96,30 +267,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "PhoneNumberUtils",
XPCOMUtils.defineLazyModuleGetter(this, "DialNumberUtils",
"resource://gre/modules/DialNumberUtils.jsm");
-function MobileCallForwardingOptions(aOptions) {
- for (let key in aOptions) {
- this[key] = aOptions[key];
- }
-}
-MobileCallForwardingOptions.prototype = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileCallForwardingOptions]),
- classID: MOBILECALLFORWARDINGOPTIONS_CID,
- classInfo: XPCOMUtils.generateCI({
- classID: MOBILECALLFORWARDINGOPTIONS_CID,
- classDescription: "MobileCallForwardingOptions",
- interfaces: [Ci.nsIMobileCallForwardingOptions]
- }),
-
- // nsIMobileForwardingOptions
-
- active: false,
- action: nsIMobileConnection.CALL_FORWARD_ACTION_UNKNOWN,
- reason: nsIMobileConnection.CALL_FORWARD_REASON_UNKNOWN,
- number: null,
- timeSeconds: -1,
- serviceClass: nsIMobileConnection.ICC_SERVICE_CLASS_NONE
-};
-
function TelephonyCallInfo(aCall) {
this.clientId = aCall.clientId;
this.callIndex = aCall.callIndex;
@@ -213,6 +360,7 @@ function TelephonyService() {
this._currentCalls = {};
this._currentConferenceState = nsITelephonyService.CALL_STATE_UNKNOWN;
this._audioStates = [];
+ this._ussdSessions = [];
this._cdmaCallWaitingNumber = null;
@@ -226,6 +374,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);
}
@@ -248,6 +397,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.");
@@ -403,10 +561,6 @@ TelephonyService.prototype = {
}
},
- _rulesToCallForwardingOptions: function(aRules) {
- return aRules.map(rule => new MobileCallForwardingOptions(rule));
- },
-
_updateDebugFlag: function() {
try {
DEBUG = RIL.DEBUG_RIL ||
@@ -451,7 +605,7 @@ TelephonyService.prototype = {
* MMI full object.
*/
_isTemporaryCLIR: function(aMmi) {
- return (aMmi && aMmi.serviceCode === RIL.MMI_SC_CLIR) && aMmi.dialNumber;
+ return (aMmi && aMmi.serviceCode === MMI_SC_CLIR) && aMmi.dialNumber;
},
/**
@@ -464,12 +618,12 @@ TelephonyService.prototype = {
// In temporary mode, MMI_PROCEDURE_ACTIVATION means allowing CLI
// presentation, i.e. CLIR_SUPPRESSION. See TS 22.030, Annex B.
switch (aProcedure) {
- case RIL.MMI_PROCEDURE_ACTIVATION:
- return RIL.CLIR_SUPPRESSION;
- case RIL.MMI_PROCEDURE_DEACTIVATION:
- return RIL.CLIR_INVOCATION;
+ case MMI_PROCEDURE_ACTIVATION:
+ return Ci.nsIMobileConnection.CLIR_SUPPRESSION;
+ case MMI_PROCEDURE_DEACTIVATION:
+ return Ci.nsIMobileConnection.CLIR_INVOCATION;
default:
- return RIL.CLIR_DEFAULT;
+ return Ci.nsIMobileConnection.CLIR_DEFAULT;
}
},
@@ -633,27 +787,27 @@ TelephonyService.prototype = {
// Handling of supplementary services within a call as 3GPP TS 22.030 6.5.5
_dialInCallMMI: function(aClientId, aNumber, aCallback) {
let mmiCallback = {
- notifyError: () => aCallback.notifyDialMMIError(RIL.MMI_ERROR_KS_ERROR),
- notifySuccess: () => aCallback.notifyDialMMISuccess(RIL.MMI_SM_KS_CALL_CONTROL)
+ notifyError: () => aCallback.notifyDialMMIError(MMI_ERROR_KS_ERROR),
+ notifySuccess: () => aCallback.notifyDialMMISuccess(MMI_SM_KS_CALL_CONTROL)
};
if (aNumber === "0") {
- aCallback.notifyDialMMI(RIL.MMI_KS_SC_CALL);
+ aCallback.notifyDialMMI(MMI_KS_SC_CALL);
this._hangUpBackground(aClientId, mmiCallback);
} else if (aNumber === "1") {
- aCallback.notifyDialMMI(RIL.MMI_KS_SC_CALL);
+ aCallback.notifyDialMMI(MMI_KS_SC_CALL);
this._hangUpForeground(aClientId, mmiCallback);
} else if (aNumber[0] === "1" && aNumber.length === 2) {
- aCallback.notifyDialMMI(RIL.MMI_KS_SC_CALL);
+ aCallback.notifyDialMMI(MMI_KS_SC_CALL);
this.hangUpCall(aClientId, parseInt(aNumber[1]), mmiCallback);
} else if (aNumber === "2") {
- aCallback.notifyDialMMI(RIL.MMI_KS_SC_CALL);
+ aCallback.notifyDialMMI(MMI_KS_SC_CALL);
this._switchActiveCall(aClientId, mmiCallback);
} else if (aNumber[0] === "2" && aNumber.length === 2) {
- aCallback.notifyDialMMI(RIL.MMI_KS_SC_CALL);
+ aCallback.notifyDialMMI(MMI_KS_SC_CALL);
this._separateCallGsm(aClientId, parseInt(aNumber[1]), mmiCallback);
} else if (aNumber === "3") {
- aCallback.notifyDialMMI(RIL.MMI_KS_SC_CALL);
+ aCallback.notifyDialMMI(MMI_KS_SC_CALL);
this._conferenceCallGsm(aClientId, mmiCallback);
} else {
this._dialCall(aClientId, aNumber, undefined, aCallback);
@@ -844,126 +998,670 @@ TelephonyService.prototype = {
* Parsed MMI structure.
* @param aCallback
* A nsITelephonyDialCallback object.
- * @param aStartNewSession
- * True to start a new session for ussd request.
*/
_dialMMI: function(aClientId, aMmi, aCallback) {
let mmiServiceCode = aMmi ?
- this._serviceCodeToKeyString(aMmi.serviceCode) : RIL.MMI_KS_SC_USSD;
+ this._serviceCodeToKeyString(aMmi.serviceCode) : MMI_KS_SC_USSD;
aCallback.notifyDialMMI(mmiServiceCode);
- this._sendToRilWorker(aClientId, "sendMMI",
- { mmi: aMmi }, response => {
- if (DEBUG) debug("MMI response: " + JSON.stringify(response));
+ if (mmiServiceCode !== RIL.MMI_KS_SC_IMEI && !this._isRadioOn(aClientId)) {
+ aCallback.notifyDialMMIError(DIAL_ERROR_RADIO_NOT_AVAILABLE);
+ return;
+ }
- if (response.errorMsg) {
- if (response.additionalInformation != null) {
- aCallback.notifyDialMMIErrorWithInfo(response.errorMsg,
- response.additionalInformation);
- } else {
- aCallback.notifyDialMMIError(response.errorMsg);
+ // We check if the MMI service code is supported and in that case we
+ // trigger the appropriate RIL request if possible.
+ switch (mmiServiceCode) {
+ // Call Forwarding
+ case MMI_KS_SC_CALL_FORWARDING:
+ this._callForwardingMMI(aClientId, aMmi, aCallback);
+ break;
+
+ // Change the current ICC PIN number.
+ case MMI_KS_SC_PIN:
+ // Change the current ICC PIN2 number.
+ case MMI_KS_SC_PIN2:
+ this._iccChangeLockMMI(aClientId, aMmi, aCallback);
+ break;
+
+ // Unblock ICC PUK.
+ case MMI_KS_SC_PUK:
+ // Unblock ICC PUN2.
+ case MMI_KS_SC_PUK2:
+ this._iccUnlockMMI(aClientId, aMmi, aCallback);
+ break;
+
+ // IMEI
+ case MMI_KS_SC_IMEI:
+ this._getImeiMMI(aClientId, aMmi, aCallback);
+ break;
+
+ // CLIP
+ case MMI_KS_SC_CLIP:
+ this._clipMMI(aClientId, aMmi, aCallback);
+ break;
+
+ // CLIR (non-temporary ones)
+ case MMI_KS_SC_CLIR:
+ this._clirMMI(aClientId, aMmi, aCallback);
+ break;
+
+ // Change call barring password
+ case MMI_KS_SC_CHANGE_PASSWORD:
+ this._callBarringPasswordMMI(aClientId, aMmi, aCallback);
+ break;
+
+ // Call barring
+ case MMI_KS_SC_CALL_BARRING:
+ this._callBarringMMI(aClientId, aMmi, aCallback);
+ break;
+
+ // Call waiting
+ case MMI_KS_SC_CALL_WAITING:
+ this._callWaitingMMI(aClientId, aMmi, aCallback);
+ break;
+
+ // Handle unknown MMI code as USSD.
+ default:
+ this._sendUSSDInternal(aClientId, aMmi.fullMMI, aResponse => {
+ if (aResponse.errorMsg) {
+ aCallback.notifyDialMMIError(aResponse.errorMsg);
+ return;
+ }
+
+ aCallback.notifyDialMMISuccess("");
+ });
+ break;
+ }
+ },
+
+ /**
+ * Handle call forwarding MMI code.
+ *
+ * @param aClientId
+ * Client id.
+ * @param aMmi
+ * Parsed MMI structure.
+ * @param aCallback
+ * A nsITelephonyDialCallback object.
+ */
+ _callForwardingMMI: function(aClientId, aMmi, aCallback) {
+ let connection = gGonkMobileConnectionService.getItemByServiceId(aClientId);
+ let action = MMI_PROC_TO_CF_ACTION[aMmi.procedure];
+ let reason = MMI_SC_TO_CF_REASON[aMmi.serviceCode];
+
+ if (action === Ci.nsIMobileConnection.CALL_FORWARD_ACTION_QUERY_STATUS) {
+ connection.getCallForwarding(reason, {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileConnectionCallback]),
+ notifyGetCallForwardingSuccess: function(aCount, aResults) {
+ aCallback.notifyDialMMISuccessWithCallForwardingOptions(
+ MMI_SM_KS_SERVICE_INTERROGATED, aCount, aResults);
+ },
+ notifyError: function(aErrorMsg) {
+ aCallback.notifyDialMMIError(aErrorMsg);
+ },
+ });
+ } else {
+ let number = aMmi.sia;
+ let serviceClass = this._siToServiceClass(aMmi.sib);
+ let timeSeconds = aMmi.sic;
+ connection.setCallForwarding(action, reason, number, timeSeconds,
+ serviceClass, {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileConnectionCallback]),
+ notifySuccess: function() {
+ aCallback.notifyDialMMISuccess(CF_ACTION_TO_STATUS_MESSAGE[action]);
+ },
+ notifyError: function(aErrorMsg) {
+ aCallback.notifyDialMMIError(aErrorMsg);
+ },
+ });
+ }
+ },
+
+ /**
+ * Handle icc change lock MMI code.
+ *
+ * @param aClientId
+ * Client id.
+ * @param aMmi
+ * Parsed MMI structure.
+ * @param aCallback
+ * A nsITelephonyDialCallback object.
+ */
+ _iccChangeLockMMI: function(aClientId, aMmi, aCallback) {
+ let errorMsg = this._getIccLockMMIError(aMmi);
+ if (errorMsg) {
+ aCallback.notifyDialMMIError(errorMsg);
+ return;
+ }
+
+ let icc = gIccService.getIccByServiceId(aClientId);
+ let lockType = MMI_SC_TO_LOCK_TYPE[aMmi.serviceCode];
+
+ icc.changeCardLockPassword(lockType, aMmi.sia, aMmi.sib, {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIIccCallback]),
+ notifySuccess: function() {
+ aCallback.notifyDialMMISuccess(LOCK_TYPE_TO_STATUS_MESSAGE[lockType]);
+ },
+ notifyCardLockError: function(aErrorMsg, aRetryCount) {
+ if (aRetryCount <= 0) {
+ if (lockType === Ci.nsIIcc.CARD_LOCK_TYPE_PIN) {
+ aErrorMsg = MMI_ERROR_KS_NEEDS_PUK;
+ }
+
+ aCallback.notifyDialMMIError(aErrorMsg);
+ return;
}
+
+ aCallback.notifyDialMMIErrorWithInfo(MMI_ERROR_KS_BAD_PIN,
+ aRetryCount);
+ },
+ });
+ },
+
+ /**
+ * Handle icc unlock lock MMI code.
+ *
+ * @param aClientId
+ * Client id.
+ * @param aMmi
+ * Parsed MMI structure.
+ * @param aCallback
+ * A nsITelephonyDialCallback object.
+ */
+ _iccUnlockMMI: function(aClientId, aMmi, aCallback) {
+ let errorMsg = this._getIccLockMMIError(aMmi);
+ if (errorMsg) {
+ aCallback.notifyDialMMIError(errorMsg);
+ return;
+ }
+
+ let icc = gIccService.getIccByServiceId(aClientId);
+ let lockType = MMI_SC_TO_LOCK_TYPE[aMmi.serviceCode];
+
+ icc.unlockCardLock(lockType, aMmi.sia, aMmi.sib, {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIIccCallback]),
+ notifySuccess: function() {
+ aCallback.notifyDialMMISuccess(LOCK_TYPE_TO_STATUS_MESSAGE[lockType]);
+ },
+ notifyCardLockError: function(aErrorMsg, aRetryCount) {
+ if (aRetryCount <= 0) {
+ if (lockType === Ci.nsIIcc.CARD_LOCK_TYPE_PUK) {
+ aErrorMsg = MMI_ERROR_KS_SIM_BLOCKED;
+ }
+
+ aCallback.notifyDialMMIError(aErrorMsg);
+ return;
+ }
+
+ aCallback.notifyDialMMIErrorWithInfo(MMI_ERROR_KS_BAD_PUK,
+ aRetryCount);
+ },
+ });
+ },
+
+ /**
+ * Handle IMEI MMI code.
+ *
+ * @param aClientId
+ * Client id.
+ * @param aMmi
+ * Parsed MMI structure.
+ * @param aCallback
+ * A nsITelephonyDialCallback object.
+ */
+ _getImeiMMI: function(aClientId, aMmi, aCallback) {
+ this._sendToRilWorker(aClientId, "getIMEI", {}, aResponse => {
+ if (aResponse.errorMsg) {
+ aCallback.notifyDialMMIError(aResponse.errorMsg);
return;
}
// We expect to have an IMEI at this point if the request was supposed
// to query for the IMEI, so getting a successful reply from the RIL
- // without containing an actual IMEI number is considered an error.
- if (mmiServiceCode === RIL.MMI_KS_SC_IMEI &&
- !response.statusMessage) {
+ // without containing an actual IMEI number is considered an error.
+ if (!aResponse.imei) {
aCallback.notifyDialMMIError(RIL.GECKO_ERROR_GENERIC_FAILURE);
return;
}
- // MMI query call forwarding options request returns a set of rules that
- // will be exposed in the form of an array of MozCallForwardingOptions
- // instances.
- if (mmiServiceCode === RIL.MMI_KS_SC_CALL_FORWARDING) {
- if (response.isSetCallForward) {
- gGonkMobileConnectionService.notifyCFStateChanged(aClientId,
- response.action,
- response.reason,
- response.number,
- response.timeSeconds,
- response.serviceClass);
- }
-
- if (response.additionalInformation != null) {
- let callForwardingOptions =
- this._rulesToCallForwardingOptions(response.additionalInformation);
- aCallback.notifyDialMMISuccessWithCallForwardingOptions(
- response.statusMessage, callForwardingOptions.length, callForwardingOptions);
- 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);
+ aCallback.notifyDialMMISuccess(aResponse.imei);
});
},
+ /**
+ * Handle CLIP MMI code.
+ *
+ * @param aClientId
+ * Client id.
+ * @param aMmi
+ * Parsed MMI structure.
+ * @param aCallback
+ * A nsITelephonyDialCallback object.
+ */
+ _clipMMI: function(aClientId, aMmi, aCallback) {
+ if (aMmi.procedure !== MMI_PROCEDURE_INTERROGATION) {
+ aCallback.notifyDialMMIError(MMI_ERROR_KS_NOT_SUPPORTED);
+ return;
+ }
+
+ this._sendToRilWorker(aClientId, "queryCLIP", {}, aResponse => {
+ if (aResponse.errorMsg) {
+ aCallback.notifyDialMMIError(aResponse.errorMsg);
+ return;
+ }
+
+ // aResponse.provisioned informs about the called party receives the
+ // calling party's address information:
+ // 0 for CLIP not provisioned
+ // 1 for CLIP provisioned
+ // 2 for unknown
+ switch (aResponse.provisioned) {
+ case 0:
+ aCallback.notifyDialMMISuccess(MMI_SM_KS_SERVICE_DISABLED);
+ break;
+ case 1:
+ aCallback.notifyDialMMISuccess(MMI_SM_KS_SERVICE_ENABLED);
+ break;
+ default:
+ aCallback.notifyDialMMIError(MMI_ERROR_KS_ERROR);
+ break;
+ }
+ });
+ },
+
+ /**
+ * Handle CLIR MMI code.
+ *
+ * @param aClientId
+ * Client id.
+ * @param aMmi
+ * Parsed MMI structure.
+ * @param aCallback
+ * A nsITelephonyDialCallback object.
+ */
+ _clirMMI: function(aClientId, aMmi, aCallback) {
+ let connection = gGonkMobileConnectionService.getItemByServiceId(aClientId);
+ switch (aMmi.procedure) {
+ case MMI_PROCEDURE_INTERROGATION:
+ connection.getCallingLineIdRestriction({
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileConnectionCallback]),
+ notifyGetClirStatusSuccess: function(aN, aM) {
+ let errorMsg;
+ let statusMessage;
+ // TS 27.007 +CLIR parameter 'm'.
+ switch (aM) {
+ // CLIR not provisioned.
+ case 0:
+ statusMessage = MMI_SM_KS_SERVICE_NOT_PROVISIONED;
+ break;
+ // CLIR provisioned in permanent mode.
+ case 1:
+ statusMessage = MMI_SM_KS_CLIR_PERMANENT;
+ break;
+ // Unknown (e.g. no network, etc.).
+ case 2:
+ errorMsg = MMI_ERROR_KS_ERROR;
+ break;
+ // CLIR temporary mode presentation restricted.
+ case 3:
+ // TS 27.007 +CLIR parameter 'n'.
+ switch (aN) {
+ // Default.
+ case 0:
+ // CLIR invocation.
+ case 1:
+ statusMessage = MMI_SM_KS_CLIR_DEFAULT_ON_NEXT_CALL_ON;
+ break;
+ // CLIR suppression.
+ case 2:
+ statusMessage = MMI_SM_KS_CLIR_DEFAULT_ON_NEXT_CALL_OFF;
+ break;
+ default:
+ errorMsg = RIL.GECKO_ERROR_GENERIC_FAILURE;
+ break;
+ }
+ break;
+ // CLIR temporary mode presentation allowed.
+ case 4:
+ // TS 27.007 +CLIR parameter 'n'.
+ switch (aN) {
+ // Default.
+ case 0:
+ // CLIR suppression.
+ case 2:
+ statusMessage = MMI_SM_KS_CLIR_DEFAULT_OFF_NEXT_CALL_OFF;
+ break;
+ // CLIR invocation.
+ case 1:
+ statusMessage = MMI_SM_KS_CLIR_DEFAULT_OFF_NEXT_CALL_ON;
+ break;
+ default:
+ errorMsg = RIL.GECKO_ERROR_GENERIC_FAILURE;
+ break;
+ }
+ break;
+ default:
+ errorMsg = RIL.GECKO_ERROR_GENERIC_FAILURE;
+ break;
+ }
+
+ if (errorMsg) {
+ aCallback.notifyDialMMIError(errorMsg);
+ return;
+ }
+
+ aCallback.notifyDialMMISuccess(statusMessage);
+ },
+ notifyError: function(aErrorMsg) {
+ aCallback.notifyDialMMIError(aErrorMsg);
+ },
+ });
+ break;
+ case MMI_PROCEDURE_ACTIVATION:
+ case MMI_PROCEDURE_DEACTIVATION: {
+ let clirMode = MMI_PROC_TO_CLIR_ACTION[aMmi.procedure];
+ connection.setCallingLineIdRestriction(clirMode, {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileConnectionCallback]),
+ notifySuccess: function() {
+ aCallback.notifyDialMMISuccess(CLIR_ACTION_TO_STATUS_MESSAGE[clirMode]);
+ },
+ notifyError: function(aErrorMsg) {
+ aCallback.notifyDialMMIError(aErrorMsg);
+ },
+ });
+ break;
+ }
+ default:
+ aCallback.notifyDialMMIError(MMI_ERROR_KS_NOT_SUPPORTED);
+ break;
+ }
+ },
+
+ /**
+ * Handle change call barring password MMI code.
+ *
+ * @param aClientId
+ * Client id.
+ * @param aMmi
+ * Parsed MMI structure.
+ * @param aCallback
+ * A nsITelephonyDialCallback object.
+ */
+ _callBarringPasswordMMI: function(aClientId, aMmi, aCallback) {
+ if (aMmi.procedure !== MMI_PROCEDURE_REGISTRATION &&
+ aMmi.procedure !== MMI_PROCEDURE_ACTIVATION) {
+ aCallback.notifyDialMMIError(MMI_ERROR_KS_INVALID_ACTION);
+ return;
+ }
+
+ if (aMmi.sia !== "" && aMmi.sia !== MMI_ZZ_BARRING_SERVICE) {
+ aCallback.notifyDialMMIError(MMI_ERROR_KS_NOT_SUPPORTED);
+ return;
+ }
+
+ let validPassword = aSi => /^[0-9]{4}$/.test(aSi);
+ if (!validPassword(aMmi.sib) || !validPassword(aMmi.sic) ||
+ !validPassword(aMmi.pwd)) {
+ aCallback.notifyDialMMIError(MMI_ERROR_KS_INVALID_PASSWORD);
+ return;
+ }
+
+ if (aMmi.sic !== aMmi.pwd) {
+ aCallback.notifyDialMMIError(MMI_ERROR_KS_MISMATCH_PASSWORD);
+ return;
+ }
+
+ let connection = gGonkMobileConnectionService.getItemByServiceId(aClientId);
+ connection.changeCallBarringPassword(aMmi.sib, aMmi.sic, {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileConnectionCallback]),
+ notifySuccess: function() {
+ aCallback.notifyDialMMISuccess(MMI_SM_KS_PASSWORD_CHANGED);
+ },
+ notifyError: function(aErrorMsg) {
+ aCallback.notifyDialMMIError(aErrorMsg);
+ },
+ });
+ },
+
+ /**
+ * Handle call barring MMI code.
+ *
+ * @param aClientId
+ * Client id.
+ * @param aMmi
+ * Parsed MMI structure.
+ * @param aCallback
+ * A nsITelephonyDialCallback object.
+ */
+ _callBarringMMI: function(aClientId, aMmi, aCallback) {
+ let connection = gGonkMobileConnectionService.getItemByServiceId(aClientId);
+ let program = MMI_SC_TO_CB_PROGRAM[aMmi.serviceCode];
+ let password = aMmi.sia || "";
+ let serviceClass = this._siToServiceClass(aMmi.sib);
+
+ switch (aMmi.procedure) {
+ case MMI_PROCEDURE_INTERROGATION:
+ connection.getCallBarring(program, password, serviceClass, {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileConnectionCallback]),
+ notifyGetCallBarringSuccess: function(aProgram, aEnabled, aServiceClass) {
+ if (!aEnabled) {
+ aCallback.notifyDialMMISuccess(MMI_SM_KS_SERVICE_DISABLED);
+ return;
+ }
+
+ let services = this._serviceClassToStringArray(aServiceClass);
+ aCallback.notifyDialMMISuccessWithStrings(MMI_SM_KS_SERVICE_ENABLED_FOR,
+ services.length, services);
+ }.bind(this),
+ notifyError: function(aErrorMsg) {
+ aCallback.notifyDialMMIError(aErrorMsg);
+ },
+ });
+ break;
+ case MMI_PROCEDURE_ACTIVATION:
+ case MMI_PROCEDURE_DEACTIVATION: {
+ let enabled = (aMmi.procedure === MMI_PROCEDURE_ACTIVATION);
+ connection.setCallBarring(program, enabled, password, serviceClass, {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileConnectionCallback]),
+ notifySuccess: function() {
+ aCallback.notifyDialMMISuccess(
+ enabled ? MMI_SM_KS_SERVICE_ENABLED
+ : MMI_SM_KS_SERVICE_DISABLED
+ );
+ },
+ notifyError: function(aErrorMsg) {
+ aCallback.notifyDialMMIError(aErrorMsg);
+ },
+ });
+ break;
+ }
+ default:
+ aCallback.notifyDialMMIError(MMI_ERROR_KS_NOT_SUPPORTED);
+ break;
+ }
+ },
+
+ /**
+ * Handle call waiting MMI code.
+ *
+ * @param aClientId
+ * Client id.
+ * @param aMmi
+ * Parsed MMI structure.
+ * @param aCallback
+ * A nsITelephonyDialCallback object.
+ */
+ _callWaitingMMI: function(aClientId, aMmi, aCallback) {
+ let connection = gGonkMobileConnectionService.getItemByServiceId(aClientId);
+
+ switch (aMmi.procedure) {
+ case MMI_PROCEDURE_INTERROGATION:
+ connection.getCallWaiting({
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileConnectionCallback]),
+ notifyGetCallWaitingSuccess: function(aServiceClass) {
+ if (aServiceClass === Ci.nsIMobileConnection.ICC_SERVICE_CLASS_NONE) {
+ aCallback.notifyDialMMISuccess(MMI_SM_KS_SERVICE_DISABLED);
+ return;
+ }
+
+ let services = this._serviceClassToStringArray(aServiceClass);
+ aCallback.notifyDialMMISuccessWithStrings(MMI_SM_KS_SERVICE_ENABLED_FOR,
+ services.length, services);
+ }.bind(this),
+ notifyError: function(aErrorMsg) {
+ aCallback.notifyDialMMIError(aErrorMsg);
+ },
+ });
+ break;
+ case MMI_PROCEDURE_ACTIVATION:
+ case MMI_PROCEDURE_DEACTIVATION: {
+ let enabled = (aMmi.procedure === MMI_PROCEDURE_ACTIVATION);
+ let serviceClass = this._siToServiceClass(aMmi.sia);
+ connection.setCallWaiting(enabled, serviceClass, {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileConnectionCallback]),
+ notifySuccess: function() {
+ aCallback.notifyDialMMISuccess(
+ enabled ? MMI_SM_KS_SERVICE_ENABLED
+ : MMI_SM_KS_SERVICE_DISABLED
+ );
+ },
+ notifyError: function(aErrorMsg) {
+ aCallback.notifyDialMMIError(aErrorMsg);
+ },
+ });
+ break;
+ }
+ default:
+ aCallback.notifyDialMMIError(MMI_ERROR_KS_NOT_SUPPORTED);
+ break;
+ }
+ },
+
_serviceCodeToKeyString: function(aServiceCode) {
switch (aServiceCode) {
- case RIL.MMI_SC_CFU:
- case RIL.MMI_SC_CF_BUSY:
- case RIL.MMI_SC_CF_NO_REPLY:
- case RIL.MMI_SC_CF_NOT_REACHABLE:
- case RIL.MMI_SC_CF_ALL:
- case RIL.MMI_SC_CF_ALL_CONDITIONAL:
- return RIL.MMI_KS_SC_CALL_FORWARDING;
- case RIL.MMI_SC_PIN:
- return RIL.MMI_KS_SC_PIN;
- case RIL.MMI_SC_PIN2:
- return RIL.MMI_KS_SC_PIN2;
- case RIL.MMI_SC_PUK:
- return RIL.MMI_KS_SC_PUK;
- case RIL.MMI_SC_PUK2:
- return RIL.MMI_KS_SC_PUK2;
- case RIL.MMI_SC_IMEI:
- return RIL.MMI_KS_SC_IMEI;
- case RIL.MMI_SC_CLIP:
- return RIL.MMI_KS_SC_CLIP;
- case RIL.MMI_SC_CLIR:
- return RIL.MMI_KS_SC_CLIR;
- case RIL.MMI_SC_BAOC:
- case RIL.MMI_SC_BAOIC:
- case RIL.MMI_SC_BAOICxH:
- case RIL.MMI_SC_BAIC:
- case RIL.MMI_SC_BAICr:
- case RIL.MMI_SC_BA_ALL:
- case RIL.MMI_SC_BA_MO:
- case RIL.MMI_SC_BA_MT:
- return RIL.MMI_KS_SC_CALL_BARRING;
- case RIL.MMI_SC_CALL_WAITING:
- return RIL.MMI_KS_SC_CALL_WAITING;
- case RIL.MMI_SC_CHANGE_PASSWORD:
- return RIL.MMI_KS_SC_CHANGE_PASSWORD;
+ case MMI_SC_CFU:
+ case MMI_SC_CF_BUSY:
+ case MMI_SC_CF_NO_REPLY:
+ case MMI_SC_CF_NOT_REACHABLE:
+ case MMI_SC_CF_ALL:
+ case MMI_SC_CF_ALL_CONDITIONAL:
+ return MMI_KS_SC_CALL_FORWARDING;
+ case MMI_SC_PIN:
+ return MMI_KS_SC_PIN;
+ case MMI_SC_PIN2:
+ return MMI_KS_SC_PIN2;
+ case MMI_SC_PUK:
+ return MMI_KS_SC_PUK;
+ case MMI_SC_PUK2:
+ return MMI_KS_SC_PUK2;
+ case MMI_SC_IMEI:
+ return MMI_KS_SC_IMEI;
+ case MMI_SC_CLIP:
+ return MMI_KS_SC_CLIP;
+ case MMI_SC_CLIR:
+ return MMI_KS_SC_CLIR;
+ case MMI_SC_BAOC:
+ case MMI_SC_BAOIC:
+ case MMI_SC_BAOICxH:
+ case MMI_SC_BAIC:
+ case MMI_SC_BAICr:
+ case MMI_SC_BA_ALL:
+ case MMI_SC_BA_MO:
+ case MMI_SC_BA_MT:
+ return MMI_KS_SC_CALL_BARRING;
+ case MMI_SC_CALL_WAITING:
+ return MMI_KS_SC_CALL_WAITING;
+ case MMI_SC_CHANGE_PASSWORD:
+ return MMI_KS_SC_CHANGE_PASSWORD;
default:
- return RIL.MMI_KS_SC_USSD;
+ return MMI_KS_SC_USSD;
}
},
+ /**
+ * Helper for translating basic service group to service class parameter.
+ */
+ _siToServiceClass: function(aSi) {
+ if (!aSi) {
+ return Ci.nsIMobileConnection.ICC_SERVICE_CLASS_NONE;
+ }
+
+ let serviceCode = parseInt(aSi, 10);
+ switch (serviceCode) {
+ case 10:
+ return Ci.nsIMobileConnection.ICC_SERVICE_CLASS_SMS +
+ Ci.nsIMobileConnection.ICC_SERVICE_CLASS_FAX +
+ Ci.nsIMobileConnection.ICC_SERVICE_CLASS_VOICE;
+ case 11:
+ return Ci.nsIMobileConnection.ICC_SERVICE_CLASS_VOICE;
+ case 12:
+ return Ci.nsIMobileConnection.ICC_SERVICE_CLASS_SMS +
+ Ci.nsIMobileConnection.ICC_SERVICE_CLASS_FAX;
+ case 13:
+ return Ci.nsIMobileConnection.ICC_SERVICE_CLASS_FAX;
+ case 16:
+ return Ci.nsIMobileConnection.ICC_SERVICE_CLASS_SMS;
+ case 19:
+ return Ci.nsIMobileConnection.ICC_SERVICE_CLASS_FAX +
+ Ci.nsIMobileConnection.ICC_SERVICE_CLASS_VOICE;
+ case 21:
+ return Ci.nsIMobileConnection.ICC_SERVICE_CLASS_PAD +
+ Ci.nsIMobileConnection.ICC_SERVICE_CLASS_DATA_ASYNC;
+ case 22:
+ return Ci.nsIMobileConnection.ICC_SERVICE_CLASS_PACKET +
+ Ci.nsIMobileConnection.ICC_SERVICE_CLASS_DATA_SYNC;
+ case 25:
+ return Ci.nsIMobileConnection.ICC_SERVICE_CLASS_DATA_ASYNC;
+ case 26:
+ return Ci.nsIMobileConnection.ICC_SERVICE_CLASS_DATA_SYNC +
+ Ci.nsIMobileConnection.ICC_SERVICE_CLASS_VOICE;
+ case 99:
+ return Ci.nsIMobileConnection.ICC_SERVICE_CLASS_PACKET;
+ default:
+ return Ci.nsIMobileConnection.ICC_SERVICE_CLASS_NONE;
+ }
+ },
+
+ _serviceClassToStringArray: function(aServiceClass) {
+ let services = [];
+ for (let mask = Ci.nsIMobileConnection.ICC_SERVICE_CLASS_VOICE;
+ mask <= Ci.nsIMobileConnection.ICC_SERVICE_CLASS_MAX;
+ mask <<= 1) {
+ if (mask & aServiceClass) {
+ services.push(MMI_KS_SERVICE_CLASS_MAPPING[mask]);
+ }
+ }
+ return services;
+ },
+
+ _getIccLockMMIError: function(aMmi) {
+ // As defined in TS.122.030 6.6.2 to change the ICC PIN we should expect
+ // an MMI code of the form **04*OLD_PIN*NEW_PIN*NEW_PIN#, where old PIN
+ // should be entered as the SIA parameter and the new PIN as SIB and
+ // SIC.
+ if (aMmi.procedure !== MMI_PROCEDURE_REGISTRATION) {
+ return MMI_ERROR_KS_INVALID_ACTION;
+ }
+
+ if (!aMmi.sia || !aMmi.sib || !aMmi.sic) {
+ return MMI_ERROR_KS_ERROR;
+ }
+
+ if (aMmi.sia.length < 4 || aMmi.sia.length > 8 ||
+ aMmi.sib.length < 4 || aMmi.sib.length > 8 ||
+ aMmi.sic.length < 4 || aMmi.sic.length > 8) {
+ return MMI_ERROR_KS_INVALID_PIN;
+ }
+
+ if (aMmi.sib != aMmi.sic) {
+ return MMI_ERROR_KS_MISMATCH_PIN;
+ }
+
+ return null;
+ },
+
/**
* The default callback handler for call operations.
*
@@ -1405,13 +2103,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() {
@@ -1679,6 +2406,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);
},
diff --git a/dom/telephony/test/marionette/manifest.ini b/dom/telephony/test/marionette/manifest.ini
index 028cde75dbbb..a3b16ccddd23 100644
--- a/dom/telephony/test/marionette/manifest.ini
+++ b/dom/telephony/test/marionette/manifest.ini
@@ -33,11 +33,18 @@ qemu = true
[test_incoming_answer_hangup_oncallschanged.js]
[test_incoming_basic_operations.js]
[test_incoming_onstatechange.js]
-[test_mmi.js]
+[test_mmi_call_barring.js]
[test_mmi_call_forwarding.js]
+[test_mmi_call_waiting.js]
[test_mmi_change_barring_password.js]
[test_mmi_change_pin.js]
+[test_mmi_change_pin2.js]
+[test_mmi_clip.js]
+[test_mmi_clir.js]
+[test_mmi_imei.js]
[test_mmi_unlock_puk.js]
+[test_mmi_unlock_puk2.js]
+[test_mmi_ussd.js]
[test_multiple_hold.js]
[test_outgoing_already_held.js]
[test_outgoing_answer_hangup_oncallschanged.js]
diff --git a/dom/telephony/test/marionette/test_mmi_call_barring.js b/dom/telephony/test/marionette/test_mmi_call_barring.js
new file mode 100644
index 000000000000..742204cfe69f
--- /dev/null
+++ b/dom/telephony/test/marionette/test_mmi_call_barring.js
@@ -0,0 +1,98 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = "head.js";
+
+// Password is hardcoded as "0000" by default in emulator.
+const PASSWORD = "0000";
+// Emulator doesn't support BA_ALL(330), BA_MO(333), BA_MT(353).
+const CB_TYPES = ["33", "331", "332", "35", "351"];
+const CB_TYPES_UNSUPPORTED = ["330", "333", "353"];
+// Basic Service - 10: Voice + Fax + SMS.
+const BS = "10";
+const MMI_SERVICE_CLASS = ["serviceClassVoice", "serviceClassFax",
+ "serviceClassSms"];
+// Call barring doesn't support Registration (**) and Erasure (##) operation.
+const OPERATION_UNSUPPORTED = ["**", "##"];
+
+function sendCbMMI(aOperation, aType, aExpectedSuccess, aExpectedStatusMessage) {
+ let mmi = aOperation + aType + "*" + PASSWORD + "*" + BS + "#";
+ log("Test " + mmi + " ...");
+
+ return gSendMMI(mmi)
+ .then((aResult) => {
+ is(aResult.success, aExpectedSuccess, "Check success");
+ is(aResult.serviceCode, "scCallBarring", "Check serviceCode");
+ is(aResult.statusMessage, aExpectedStatusMessage, "Check statusMessage");
+ return aResult;
+ });
+}
+
+function testCallBarring(aEnabled) {
+ let promise = Promise.resolve();
+
+ CB_TYPES.forEach(function(aType) {
+ promise = promise
+ // Test setting call barring.
+ .then(() => sendCbMMI(aEnabled ? "*" : "#", aType, true,
+ aEnabled ? "smServiceEnabled" : "smServiceDisabled"))
+ // Test getting call barring.
+ .then(() => sendCbMMI("*#", aType, true,
+ aEnabled ? "smServiceEnabledFor": "smServiceDisabled"))
+ .then(aResult => {
+ if (aEnabled) {
+ is(aResult.additionalInformation.length, MMI_SERVICE_CLASS.length,
+ "Check additionalInformation.length");
+ for (let i = 0; i < MMI_SERVICE_CLASS.length; i++) {
+ is(aResult.additionalInformation[i], MMI_SERVICE_CLASS[i],
+ "Check additionalInformation[" + i + "]");
+ }
+ }
+ });
+ });
+
+ return promise;
+}
+
+function testUnsupportType() {
+ let promise = Promise.resolve();
+
+ CB_TYPES_UNSUPPORTED.forEach(function(aType) {
+ promise = promise
+ // Test setting call barring.
+ .then(() => sendCbMMI("*", aType, false, "RequestNotSupported"))
+ // Test getting call barring.
+ .then(() => sendCbMMI("*#", aType, false, "RequestNotSupported"));
+ });
+
+ return promise;
+}
+
+function testUnsupportedOperation() {
+ let promise = Promise.resolve();
+
+ let types = CB_TYPES.concat(CB_TYPES_UNSUPPORTED);
+ types.forEach(function(aType) {
+ OPERATION_UNSUPPORTED.forEach(function(aOperation) {
+ promise = promise
+ .then(() => sendCbMMI(aOperation, aType, false,
+ "emMmiErrorNotSupported"));
+ });
+ });
+
+ return promise;
+}
+
+// Start test.
+startTest(function() {
+ // Activate call barring service.
+ return testCallBarring(true)
+ // Deactivate call barring service.
+ .then(() => testCallBarring(false))
+ .then(() => testUnsupportType())
+ .then(() => testUnsupportedOperation())
+
+ .catch(error => ok(false, "Promise reject: " + error))
+ .then(finish);;
+});
diff --git a/dom/telephony/test/marionette/test_mmi_call_waiting.js b/dom/telephony/test/marionette/test_mmi_call_waiting.js
new file mode 100644
index 000000000000..e26eb291aa39
--- /dev/null
+++ b/dom/telephony/test/marionette/test_mmi_call_waiting.js
@@ -0,0 +1,44 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = "head.js";
+
+const TEST_DATA = [
+ // [mmi, expectedError]
+ // Currently emulator doesn't support REQUEST_QUERY_CALL_WAITING, so we expect
+ // to get a 'RequestNotSupported' error here.
+ ["*#43*10#", "RequestNotSupported"],
+ // Currently emulator doesn't support REQUEST_SET_CALL_WAITING, so we expect
+ // to get a 'RequestNotSupported' error here.
+ ["*43*10#", "RequestNotSupported"],
+ ["#43*10#", "RequestNotSupported"],
+ // Unsupported Call Waiting MMI code.
+ ["**43*10#", "emMmiErrorNotSupported"],
+ ["##43*10#", "emMmiErrorNotSupported"],
+];
+
+function testCallWaiting(aMmi, aExpectedError) {
+ log("Test " + aMmi + " ...");
+
+ return gSendMMI(aMmi).then(aResult => {
+ // Since emulator doesn't support call waiting, so we expect the result is
+ // always failed.
+ ok(!aResult.success, "Check success");
+ is(aResult.serviceCode, "scCallWaiting", "Check serviceCode");
+ is(aResult.statusMessage, aExpectedError, "Check statusMessage");
+ });
+}
+
+// Start test
+startTest(function() {
+ let promise = Promise.resolve();
+
+ TEST_DATA.forEach(function(aData) {
+ promise = promise.then(() => testCallWaiting(aData[0], aData[1]));
+ });
+
+ return promise
+ .catch(aError => ok(false, "Promise reject: " + aError))
+ .then(finish);
+});
diff --git a/dom/telephony/test/marionette/test_mmi_change_pin2.js b/dom/telephony/test/marionette/test_mmi_change_pin2.js
new file mode 100644
index 000000000000..c073b98310eb
--- /dev/null
+++ b/dom/telephony/test/marionette/test_mmi_change_pin2.js
@@ -0,0 +1,105 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = "head.js";
+
+const TEST_DATA = [
+ // Test passing no pin2.
+ {
+ pin2: "",
+ newPin2: "0000",
+ newPin2Again: "1111",
+ expectedError: {
+ name: "emMmiError",
+ additionalInformation: null
+ }
+ },
+ // Test passing no newPin2.
+ {
+ pin2: "0000",
+ newPin2: "",
+ newPin2Again: "",
+ expectedError: {
+ name: "emMmiError",
+ additionalInformation: null
+ }
+ },
+ // Test passing mismatched newPin2.
+ {
+ pin2: "0000",
+ newPin2: "0000",
+ newPin2Again: "1111",
+ expectedError: {
+ name: "emMmiErrorMismatchPin",
+ additionalInformation: null
+ }
+ },
+ // Test passing invalid pin2 (< 4 digit).
+ {
+ pin2: "123",
+ newPin2: "0000",
+ newPin2Again: "0000",
+ expectedError: {
+ name: "emMmiErrorInvalidPin",
+ additionalInformation: null
+ }
+ },
+ // Test passing invalid newPin2 (> 8 digit).
+ {
+ pin2: "0000",
+ newPin2: "123456789",
+ newPin2Again: "123456789",
+ expectedError: {
+ name: "emMmiErrorInvalidPin",
+ additionalInformation: null
+ }
+ },
+ // Test passing valid pin2 and newPin2. But currently emulator doesn't support
+ // REQUEST_CHANGE_SIM_PIN2, so we expect to get a 'RequestNotSupported' error
+ // here.
+ {
+ pin2: "0000",
+ newPin2: "0000",
+ newPin2Again: "0000",
+ expectedError: {
+ name: "RequestNotSupported",
+ additionalInformation: null
+ }
+ },
+];
+
+function testChangePin2(aPin2, aNewPin2, aNewPin2Again, aExpectedError) {
+ let MMI_CODE = "**042*" + aPin2 + "*" + aNewPin2 + "*" + aNewPin2Again + "#";
+ log("Test " + MMI_CODE);
+
+ return gSendMMI(MMI_CODE).then(aResult => {
+ is(aResult.success, !aExpectedError, "check success");
+ is(aResult.serviceCode, "scPin2", "Check service code");
+
+ if (aResult.success) {
+ is(aResult.statusMessage, "smPin2Changed", "Check status message");
+ is(aResult.additionalInformation, undefined, "Check additional information");
+ } else {
+ is(aResult.statusMessage, aExpectedError.name, "Check name");
+ is(aResult.additionalInformation, aExpectedError.additionalInformation,
+ "Check additional information");
+ }
+ });
+}
+
+// Start test
+startTest(function() {
+ let promise = Promise.resolve();
+ for (let i = 0; i < TEST_DATA.length; i++) {
+ let data = TEST_DATA[i];
+ promise = promise.then(() => testChangePin2(data.pin2,
+ data.newPin2,
+ data.newPin2Again,
+ data.expectedError));
+ }
+
+ return promise
+ .catch(error => ok(false, "Promise reject: " + error))
+ .then(finish);
+});
diff --git a/dom/telephony/test/marionette/test_mmi_clip.js b/dom/telephony/test/marionette/test_mmi_clip.js
new file mode 100644
index 000000000000..c878c3eb765d
--- /dev/null
+++ b/dom/telephony/test/marionette/test_mmi_clip.js
@@ -0,0 +1,42 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = "head.js";
+
+const TEST_DATA = [
+ // [mmi, expectedError]
+ // Currently emulator doesn't support REQUEST_QUERY_CLIP, so we expect to
+ // get a 'RequestNotSupported' error here.
+ ["*#30#", "RequestNotSupported"],
+ // Unsupported CLIP MMI code.
+ ["*30#", "emMmiErrorNotSupported"],
+ ["#30#", "emMmiErrorNotSupported"],
+ ["**30#", "emMmiErrorNotSupported"],
+ ["##30#", "emMmiErrorNotSupported"],
+];
+
+function testCLIP(aMmi, aExpectedError) {
+ log("Test " + aMmi + " ...");
+
+ return gSendMMI(aMmi).then(aResult => {
+ // Since emulator doesn't support clip, so we expect the result is always
+ // failed.
+ ok(!aResult.success, "Check success");
+ is(aResult.serviceCode, "scClip", "Check serviceCode");
+ is(aResult.statusMessage, aExpectedError, "Check statusMessage");
+ });
+}
+
+// Start test
+startTest(function() {
+ let promise = Promise.resolve();
+
+ TEST_DATA.forEach(function(aData) {
+ promise = promise.then(() => testCLIP(aData[0], aData[1]));
+ });
+
+ return promise
+ .catch(aError => ok(false, "Promise reject: " + aError))
+ .then(finish);
+});
diff --git a/dom/telephony/test/marionette/test_mmi_clir.js b/dom/telephony/test/marionette/test_mmi_clir.js
new file mode 100644
index 000000000000..ff384276de33
--- /dev/null
+++ b/dom/telephony/test/marionette/test_mmi_clir.js
@@ -0,0 +1,44 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = "head.js";
+
+const TEST_DATA = [
+ // [mmi, expectedError]
+ // Currently emulator doesn't support REQUEST_GET_CLIR, so we expect to get a
+ // 'RequestNotSupported' error here.
+ ["*#31#", "RequestNotSupported"],
+ // Currently emulator doesn't support REQUEST_SET_CLIR, so we expect to get a
+ // 'RequestNotSupported' error here.
+ ["*31#", "RequestNotSupported"],
+ ["#31#", "RequestNotSupported"],
+ // Unsupported CLIR MMI code.
+ ["**31#", "emMmiErrorNotSupported"],
+ ["##31#", "emMmiErrorNotSupported"],
+];
+
+function testCLIR(aMmi, aExpectedError) {
+ log("Test " + aMmi + " ...");
+
+ return gSendMMI(aMmi).then(aResult => {
+ // Since emulator doesn't support clip, so we expect the result is always
+ // failed.
+ ok(!aResult.success, "Check success");
+ is(aResult.serviceCode, "scClir", "Check serviceCode");
+ is(aResult.statusMessage, aExpectedError, "Check statusMessage");
+ });
+}
+
+// Start test
+startTest(function() {
+ let promise = Promise.resolve();
+
+ TEST_DATA.forEach(function(aData) {
+ promise = promise.then(() => testCLIR(aData[0], aData[1]));
+ });
+
+ return promise
+ .catch(aError => ok(false, "Promise reject: " + aError))
+ .then(finish);
+});
diff --git a/dom/telephony/test/marionette/test_mmi.js b/dom/telephony/test/marionette/test_mmi_imei.js
similarity index 100%
rename from dom/telephony/test/marionette/test_mmi.js
rename to dom/telephony/test/marionette/test_mmi_imei.js
diff --git a/dom/telephony/test/marionette/test_mmi_unlock_puk2.js b/dom/telephony/test/marionette/test_mmi_unlock_puk2.js
new file mode 100644
index 000000000000..fe52939e7f61
--- /dev/null
+++ b/dom/telephony/test/marionette/test_mmi_unlock_puk2.js
@@ -0,0 +1,44 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = "head.js";
+
+function sendUnlockPuk2Mmi(aPuk2, aNewPin2, aNewPin2Again) {
+ let MMI_CODE = "**052*" + aPuk2 + "*" + aNewPin2 + "*" + aNewPin2Again + "#";
+ log("Test " + MMI_CODE);
+
+ return gSendMMI(MMI_CODE);
+}
+
+function testUnlockPuk2MmiError(aPuk2, aNewPin2, aNewPin2Again, aErrorName) {
+ return sendUnlockPuk2Mmi(aPuk2, aNewPin2, aNewPin2Again)
+ .then((aResult) => {
+ ok(!aResult.success, "Check success");
+ is(aResult.serviceCode, "scPuk2", "Check service code");
+ is(aResult.statusMessage, aErrorName, "Check statusMessage");
+ is(aResult.additionalInformation, null, "Check additional information");
+ });
+}
+
+// Start test
+startTest(function() {
+ return Promise.resolve()
+ // Test passing no puk2.
+ .then(() => testUnlockPuk2MmiError("", "1111", "2222", "emMmiError"))
+ // Test passing no newPin2.
+ .then(() => testUnlockPuk2MmiError("11111111", "", "", "emMmiError"))
+ // Test passing mismatched newPin2.
+ .then(() => testUnlockPuk2MmiError("11111111", "1111", "2222",
+ "emMmiErrorMismatchPin"))
+ // Test passing invalid puk2 (> 8 digit).
+ .then(() => testUnlockPuk2MmiError("123456789", "0000", "0000",
+ "emMmiErrorInvalidPin"))
+ // Test passing valid puk2 and newPin2. But currently emulator doesn't
+ // support RIL_REQUEST_ENTER_SIM_PUK2, so we expect to get a
+ // 'RequestNotSupported' error here.
+ .then(() => testUnlockPuk2MmiError("11111111", "0000", "0000",
+ "RequestNotSupported"))
+ .catch(error => ok(false, "Promise reject: " + error))
+ .then(finish);
+});
diff --git a/dom/telephony/test/marionette/test_mmi_ussd.js b/dom/telephony/test/marionette/test_mmi_ussd.js
new file mode 100644
index 000000000000..52a5e2575a3c
--- /dev/null
+++ b/dom/telephony/test/marionette/test_mmi_ussd.js
@@ -0,0 +1,25 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = "head.js";
+
+function testUSSD() {
+ log("Test *#1234# ...");
+
+ return gSendMMI("*#1234#").then(aResult => {
+ // Since emulator doesn't support sending USSD, so we expect the result is
+ // always failed.
+ ok(!aResult.success, "Check success");
+ is(aResult.serviceCode, "scUssd", "Check serviceCode");
+ is(aResult.statusMessage, "RequestNotSupported", "Check statusMessage");
+ is(aResult.additionalInformation, undefined, "No additional information");
+ });
+}
+
+// Start test
+startTest(function() {
+ return testUSSD()
+ .catch(error => ok(false, "Promise reject: " + error))
+ .then(finish);
+});
diff --git a/dom/telephony/test/xpcshell/test_parseMMI.js b/dom/telephony/test/xpcshell/test_parseMMI.js
index 566bf80053a7..74ffed2546f4 100644
--- a/dom/telephony/test/xpcshell/test_parseMMI.js
+++ b/dom/telephony/test/xpcshell/test_parseMMI.js
@@ -1,7 +1,8 @@
/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
-subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
+let TS = {};
+subscriptLoader.loadSubScript("resource://gre/components/TelephonyService.js", TS);
let NS = {};
subscriptLoader.loadSubScript("resource://gre/modules/DialNumberUtils.jsm", NS);
@@ -50,7 +51,7 @@ add_test(function test_parseMMI_USSD() {
let mmi = parseMMI("*123#");
equal(mmi.fullMMI, "*123#");
- equal(mmi.procedure, MMI_PROCEDURE_ACTIVATION);
+ equal(mmi.procedure, TS.MMI_PROCEDURE_ACTIVATION);
equal(mmi.serviceCode, "123");
equal(mmi.sia, undefined);
equal(mmi.sib, undefined);
@@ -73,7 +74,7 @@ add_test(function test_parseMMI_sia() {
let mmi = parseMMI("*123*1#");
equal(mmi.fullMMI, "*123*1#");
- equal(mmi.procedure, MMI_PROCEDURE_ACTIVATION);
+ equal(mmi.procedure, TS.MMI_PROCEDURE_ACTIVATION);
equal(mmi.serviceCode, "123");
equal(mmi.sia, "1");
equal(mmi.sib, undefined);
@@ -88,7 +89,7 @@ add_test(function test_parseMMI_sib() {
let mmi = parseMMI("*123**1#");
equal(mmi.fullMMI, "*123**1#");
- equal(mmi.procedure, MMI_PROCEDURE_ACTIVATION);
+ equal(mmi.procedure, TS.MMI_PROCEDURE_ACTIVATION);
equal(mmi.serviceCode, "123");
equal(mmi.sia, "");
equal(mmi.sib, "1");
@@ -103,7 +104,7 @@ add_test(function test_parseMMI_sic() {
let mmi = parseMMI("*123***1#");
equal(mmi.fullMMI, "*123***1#");
- equal(mmi.procedure, MMI_PROCEDURE_ACTIVATION);
+ equal(mmi.procedure, TS.MMI_PROCEDURE_ACTIVATION);
equal(mmi.serviceCode, "123");
equal(mmi.sia, "");
equal(mmi.sib, "");
@@ -118,7 +119,7 @@ add_test(function test_parseMMI_sia_sib() {
let mmi = parseMMI("*123*1*1#");
equal(mmi.fullMMI, "*123*1*1#");
- equal(mmi.procedure, MMI_PROCEDURE_ACTIVATION);
+ equal(mmi.procedure, TS.MMI_PROCEDURE_ACTIVATION);
equal(mmi.serviceCode, "123");
equal(mmi.sia, "1");
equal(mmi.sib, "1");
@@ -133,7 +134,7 @@ add_test(function test_parseMMI_sia_sic() {
let mmi = parseMMI("*123*1**1#");
equal(mmi.fullMMI, "*123*1**1#");
- equal(mmi.procedure, MMI_PROCEDURE_ACTIVATION);
+ equal(mmi.procedure, TS.MMI_PROCEDURE_ACTIVATION);
equal(mmi.serviceCode, "123");
equal(mmi.sia, "1");
equal(mmi.sib, "");
@@ -148,7 +149,7 @@ add_test(function test_parseMMI_sib_sic() {
let mmi = parseMMI("*123**1*1#");
equal(mmi.fullMMI, "*123**1*1#");
- equal(mmi.procedure, MMI_PROCEDURE_ACTIVATION);
+ equal(mmi.procedure, TS.MMI_PROCEDURE_ACTIVATION);
equal(mmi.serviceCode, "123");
equal(mmi.sia, "");
equal(mmi.sib, "1");
@@ -163,7 +164,7 @@ add_test(function test_parseMMI_pwd() {
let mmi = parseMMI("*123****1#");
equal(mmi.fullMMI, "*123****1#");
- equal(mmi.procedure, MMI_PROCEDURE_ACTIVATION);
+ equal(mmi.procedure, TS.MMI_PROCEDURE_ACTIVATION);
equal(mmi.serviceCode, "123");
equal(mmi.sia, "");
equal(mmi.sib, "");
@@ -178,7 +179,7 @@ add_test(function test_parseMMI_dial_number() {
let mmi = parseMMI("*123#345");
equal(mmi.fullMMI, "*123#");
- equal(mmi.procedure, MMI_PROCEDURE_ACTIVATION);
+ equal(mmi.procedure, TS.MMI_PROCEDURE_ACTIVATION);
equal(mmi.serviceCode, "123");
equal(mmi.sia, undefined);
equal(mmi.sib, undefined);
@@ -198,7 +199,7 @@ add_test(function test_parseMMI_activation() {
let mmi = parseMMI("*00*12*34*56#");
equal(mmi.fullMMI, "*00*12*34*56#");
- equal(mmi.procedure, MMI_PROCEDURE_ACTIVATION);
+ equal(mmi.procedure, TS.MMI_PROCEDURE_ACTIVATION);
equal(mmi.serviceCode, "00");
equal(mmi.sia, "12");
equal(mmi.sib, "34");
@@ -213,7 +214,7 @@ add_test(function test_parseMMI_deactivation() {
let mmi = parseMMI("#00*12*34*56#");
equal(mmi.fullMMI, "#00*12*34*56#");
- equal(mmi.procedure, MMI_PROCEDURE_DEACTIVATION);
+ equal(mmi.procedure, TS.MMI_PROCEDURE_DEACTIVATION);
equal(mmi.serviceCode, "00");
equal(mmi.sia, "12");
equal(mmi.sib, "34");
@@ -228,7 +229,7 @@ add_test(function test_parseMMI_interrogation() {
let mmi = parseMMI("*#00*12*34*56#");
equal(mmi.fullMMI, "*#00*12*34*56#");
- equal(mmi.procedure, MMI_PROCEDURE_INTERROGATION);
+ equal(mmi.procedure, TS.MMI_PROCEDURE_INTERROGATION);
equal(mmi.serviceCode, "00");
equal(mmi.sia, "12");
equal(mmi.sib, "34");
@@ -243,7 +244,7 @@ add_test(function test_parseMMI_registration() {
let mmi = parseMMI("**00*12*34*56#");
equal(mmi.fullMMI, "**00*12*34*56#");
- equal(mmi.procedure, MMI_PROCEDURE_REGISTRATION);
+ equal(mmi.procedure, TS.MMI_PROCEDURE_REGISTRATION);
equal(mmi.serviceCode, "00");
equal(mmi.sia, "12");
equal(mmi.sib, "34");
@@ -258,7 +259,7 @@ add_test(function test_parseMMI_erasure() {
let mmi = parseMMI("##00*12*34*56#");
equal(mmi.fullMMI, "##00*12*34*56#");
- equal(mmi.procedure, MMI_PROCEDURE_ERASURE);
+ equal(mmi.procedure, TS.MMI_PROCEDURE_ERASURE);
equal(mmi.serviceCode, "00");
equal(mmi.sia, "12");
equal(mmi.sib, "34");
diff --git a/ipc/ril/Ril.cpp b/ipc/ril/Ril.cpp
index 66c7a8d4c39c..01fbaa5e0f10 100644
--- a/ipc/ril/Ril.cpp
+++ b/ipc/ril/Ril.cpp
@@ -5,13 +5,22 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/ipc/Ril.h"
-
#include
#include
#include
-#include // For gethostbyname.
+#include "jsfriendapi.h"
+#include "mozilla/ArrayUtils.h"
+#include "mozilla/dom/ScriptSettings.h"
+#include "mozilla/dom/workers/Workers.h"
+#include "mozilla/ipc/RilSocket.h"
+#include "mozilla/ipc/RilSocketConsumer.h"
+#include "nsThreadUtils.h" // For NS_IsMainThread.
+#include "RilConnector.h"
+#ifdef CHROMIUM_LOG
#undef CHROMIUM_LOG
+#endif
+
#if defined(MOZ_WIDGET_GONK)
#include
#define CHROMIUM_LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk", args)
@@ -19,189 +28,95 @@
#define CHROMIUM_LOG(args...) printf(args);
#endif
-#include "jsfriendapi.h"
-#include "mozilla/ArrayUtils.h"
-#include "nsTArray.h"
-#include "nsThreadUtils.h" // For NS_IsMainThread.
-#include "RilConnector.h"
+namespace mozilla {
+namespace ipc {
-USING_WORKERS_NAMESPACE
-using namespace mozilla::ipc;
+USING_WORKERS_NAMESPACE;
+using namespace JS;
-namespace {
+class RilConsumer;
static const char RIL_SOCKET_NAME[] = "/dev/socket/rilproxy";
-static nsTArray> sRilConsumers;
+static nsTArray> sRilConsumers;
-class ConnectWorkerToRIL final : public WorkerTask
+//
+// RilConsumer
+//
+
+class RilConsumer final : public RilSocketConsumer
{
public:
- bool RunTask(JSContext* aCx) override;
-};
+ RilConsumer();
-class SendRilSocketDataTask final : public nsRunnable
-{
-public:
- SendRilSocketDataTask(unsigned long aClientId,
- UnixSocketRawData* aRawData)
- : mRawData(aRawData)
- , mClientId(aClientId)
- { }
+ nsresult ConnectWorkerToRIL(JSContext* aCx);
- NS_IMETHOD Run() override
- {
- MOZ_ASSERT(NS_IsMainThread());
+ nsresult Register(unsigned long aClientId,
+ WorkerCrossThreadDispatcher* aDispatcher);
+ void Unregister();
- if (sRilConsumers.Length() <= mClientId || !sRilConsumers[mClientId]) {
- // Probably shutting down.
- delete mRawData;
- return NS_OK;
- }
+ // Methods for |RilSocketConsumer|
+ //
- sRilConsumers[mClientId]->Send(mRawData);
- return NS_OK;
- }
+ void ReceiveSocketData(JSContext* aCx,
+ int aIndex,
+ nsAutoPtr& aBuffer) override;
+ void OnConnectSuccess(int aIndex) override;
+ void OnConnectError(int aIndex) override;
+ void OnDisconnect(int aIndex) override;
+
+protected:
+ static bool PostRILMessage(JSContext* aCx, unsigned aArgc, Value* aVp);
+
+ nsresult Send(JSContext* aCx, const CallArgs& aArgs);
+ nsresult Receive(JSContext* aCx,
+ uint32_t aClientId,
+ const UnixSocketBuffer* aBuffer);
+ void Close();
private:
- UnixSocketRawData* mRawData;
- unsigned long mClientId;
+ nsRefPtr mSocket;
+ nsCString mAddress;
+ bool mShutdown;
};
-static bool
-PostToRIL(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
-{
- JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
- NS_ASSERTION(!NS_IsMainThread(), "Expecting to be on the worker thread");
+RilConsumer::RilConsumer()
+ : mShutdown(false)
+{ }
- if (args.length() != 2) {
- JS_ReportError(aCx, "Expecting two arguments with the RIL message");
- return false;
- }
-
- int clientId = args[0].toInt32();
- JS::Value v = args[1];
-
- UnixSocketRawData* raw = nullptr;
-
- if (v.isString()) {
- JSAutoByteString abs;
- JS::Rooted str(aCx, v.toString());
- if (!abs.encodeUtf8(aCx, str)) {
- return false;
- }
-
- raw = new UnixSocketRawData(abs.ptr(), abs.length());
- } else if (!v.isPrimitive()) {
- JSObject* obj = v.toObjectOrNull();
- if (!JS_IsTypedArrayObject(obj)) {
- JS_ReportError(aCx, "Object passed in wasn't a typed array");
- return false;
- }
-
- uint32_t type = JS_GetArrayBufferViewType(obj);
- if (type != js::Scalar::Int8 &&
- type != js::Scalar::Uint8 &&
- type != js::Scalar::Uint8Clamped) {
- JS_ReportError(aCx, "Typed array data is not octets");
- return false;
- }
-
- JS::AutoCheckCannotGC nogc;
- size_t size = JS_GetTypedArrayByteLength(obj);
- void* data = JS_GetArrayBufferViewData(obj, nogc);
- raw = new UnixSocketRawData(data, size);
- } else {
- JS_ReportError(
- aCx, "Incorrect argument. Expecting a string or a typed array");
- return false;
- }
-
- if (!raw) {
- JS_ReportError(aCx, "Unable to post to RIL");
- return false;
- }
-
- nsRefPtr task = new SendRilSocketDataTask(clientId,
- raw);
- NS_DispatchToMainThread(task);
- return true;
-}
-
-bool
-ConnectWorkerToRIL::RunTask(JSContext* aCx)
+nsresult
+RilConsumer::ConnectWorkerToRIL(JSContext* aCx)
{
// Set up the postRILMessage on the function for worker -> RIL thread
// communication.
- NS_ASSERTION(!NS_IsMainThread(), "Expecting to be on the worker thread");
NS_ASSERTION(!JS_IsRunning(aCx), "Are we being called somehow?");
- JS::Rooted workerGlobal(aCx, JS::CurrentGlobalOrNull(aCx));
+ Rooted workerGlobal(aCx, CurrentGlobalOrNull(aCx));
// Check whether |postRILMessage| has been defined. No one but this class
// should ever define |postRILMessage| in a RIL worker.
- JS::Rooted val(aCx);
+ Rooted val(aCx);
if (!JS_GetProperty(aCx, workerGlobal, "postRILMessage", &val)) {
JS_ReportPendingException(aCx);
- return false;
+ return NS_ERROR_FAILURE;
}
// Make sure that |postRILMessage| is a function.
if (JSTYPE_FUNCTION == JS_TypeOfValue(aCx, val)) {
- return true;
+ return NS_OK;
}
- return !!JS_DefineFunction(aCx, workerGlobal, "postRILMessage",
- PostToRIL, 2, 0);
+ JSFunction* postRILMessage = JS_DefineFunction(aCx, workerGlobal,
+ "postRILMessage",
+ PostRILMessage, 2, 0);
+ if (NS_WARN_IF(!postRILMessage)) {
+ return NS_ERROR_FAILURE;
+ }
+ return NS_OK;
}
-class DispatchRILEvent final : public WorkerTask
-{
-public:
- DispatchRILEvent(unsigned long aClient, UnixSocketBuffer* aBuffer)
- : mClientId(aClient)
- , mBuffer(aBuffer)
- { }
-
- bool RunTask(JSContext* aCx) override;
-
-private:
- unsigned long mClientId;
- nsAutoPtr mBuffer;
-};
-
-bool
-DispatchRILEvent::RunTask(JSContext* aCx)
-{
- JS::Rooted obj(aCx, JS::CurrentGlobalOrNull(aCx));
-
- JS::Rooted array(aCx,
- JS_NewUint8Array(aCx, mBuffer->GetSize()));
- if (!array) {
- return false;
- }
- {
- JS::AutoCheckCannotGC nogc;
- memcpy(JS_GetArrayBufferViewData(array, nogc),
- mBuffer->GetData(), mBuffer->GetSize());
- }
-
- JS::AutoValueArray<2> args(aCx);
- args[0].setNumber((uint32_t)mClientId);
- args[1].setObject(*array);
-
- JS::Rooted rval(aCx);
- return JS_CallFunctionName(aCx, obj, "onRILMessage", args, &rval);
-}
-
-} // namespace
-
-namespace mozilla {
-namespace ipc {
-
-RilConsumer::RilConsumer(unsigned long aClientId,
- WorkerCrossThreadDispatcher* aDispatcher)
- : mDispatcher(aDispatcher)
- , mShutdown(false)
+nsresult
+RilConsumer::Register(unsigned long aClientId,
+ WorkerCrossThreadDispatcher* aDispatcher)
{
// Only append client id after RIL_SOCKET_NAME when it's not connected to
// the first(0) rilproxy for compatibility.
@@ -214,60 +129,131 @@ RilConsumer::RilConsumer(unsigned long aClientId,
mAddress = addr_un.sun_path;
}
- mSocket = new StreamSocket(this, aClientId);
- mSocket->Connect(new RilConnector(mAddress, aClientId));
-}
+ mSocket = new RilSocket(aDispatcher, this, aClientId);
-nsresult
-RilConsumer::Register(unsigned int aClientId,
- WorkerCrossThreadDispatcher* aDispatcher)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- sRilConsumers.EnsureLengthAtLeast(aClientId + 1);
-
- if (sRilConsumers[aClientId]) {
- NS_WARNING("RilConsumer already registered");
- return NS_ERROR_FAILURE;
+ nsresult rv = mSocket->Connect(new RilConnector(mAddress, aClientId));
+ if (NS_FAILED(rv)) {
+ return rv;
}
- nsRefPtr connection = new ConnectWorkerToRIL();
- if (!aDispatcher->PostTask(connection)) {
- NS_WARNING("Failed to connect worker to ril");
- return NS_ERROR_UNEXPECTED;
- }
-
- // Now that we're set up, connect ourselves to the RIL thread.
- sRilConsumers[aClientId] = new RilConsumer(aClientId, aDispatcher);
return NS_OK;
}
void
-RilConsumer::Shutdown()
+RilConsumer::Unregister()
{
- MOZ_ASSERT(NS_IsMainThread());
-
- for (unsigned long i = 0; i < sRilConsumers.Length(); i++) {
- nsAutoPtr instance(sRilConsumers[i]);
- if (!instance) {
- continue;
- }
-
- instance->mShutdown = true;
- instance->Close();
- instance = nullptr;
- }
+ mShutdown = true;
+ Close();
}
-void
-RilConsumer::Send(UnixSocketRawData* aRawData)
+bool
+RilConsumer::PostRILMessage(JSContext* aCx, unsigned aArgc, Value* aVp)
{
- if (!mSocket || mSocket->GetConnectionStatus() != SOCKET_CONNECTED) {
- // Probably shutting down.
- delete aRawData;
- return;
+ CallArgs args = CallArgsFromVp(aArgc, aVp);
+
+ if (args.length() != 2) {
+ JS_ReportError(aCx, "Expecting two arguments with the RIL message");
+ return false;
}
- mSocket->SendSocketData(aRawData);
+
+ int clientId = args[0].toInt32();
+
+ if ((ssize_t)sRilConsumers.Length() <= clientId || !sRilConsumers[clientId]) {
+ // Probably shutting down.
+ return true;
+ }
+
+ nsresult rv = sRilConsumers[clientId]->Send(aCx, args);
+ if (NS_FAILED(rv)) {
+ return false;
+ }
+
+ return true;
+}
+
+nsresult
+RilConsumer::Send(JSContext* aCx, const CallArgs& aArgs)
+{
+ if (NS_WARN_IF(!mSocket) ||
+ NS_WARN_IF(mSocket->GetConnectionStatus() == SOCKET_DISCONNECTED)) {
+ // Probably shutting down.
+ return NS_OK;
+ }
+
+ nsAutoPtr raw;
+
+ Value v = aArgs[1];
+
+ if (v.isString()) {
+ JSAutoByteString abs;
+ Rooted str(aCx, v.toString());
+ if (!abs.encodeUtf8(aCx, str)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ raw = new UnixSocketRawData(abs.ptr(), abs.length());
+ } else if (!v.isPrimitive()) {
+ JSObject* obj = v.toObjectOrNull();
+ if (!JS_IsTypedArrayObject(obj)) {
+ JS_ReportError(aCx, "Object passed in wasn't a typed array");
+ return NS_ERROR_FAILURE;
+ }
+
+ uint32_t type = JS_GetArrayBufferViewType(obj);
+ if (type != js::Scalar::Int8 &&
+ type != js::Scalar::Uint8 &&
+ type != js::Scalar::Uint8Clamped) {
+ JS_ReportError(aCx, "Typed array data is not octets");
+ return NS_ERROR_FAILURE;
+ }
+
+ AutoCheckCannotGC nogc;
+ size_t size = JS_GetTypedArrayByteLength(obj);
+ void* data = JS_GetArrayBufferViewData(obj, nogc);
+ raw = new UnixSocketRawData(data, size);
+ } else {
+ JS_ReportError(
+ aCx, "Incorrect argument. Expecting a string or a typed array");
+ return NS_ERROR_FAILURE;
+ }
+
+ if (!raw) {
+ JS_ReportError(aCx, "Unable to post to RIL");
+ return NS_ERROR_FAILURE;
+ }
+
+ mSocket->SendSocketData(raw.forget());
+
+ return NS_OK;
+}
+
+nsresult
+RilConsumer::Receive(JSContext* aCx,
+ uint32_t aClientId,
+ const UnixSocketBuffer* aBuffer)
+{
+ MOZ_ASSERT(aBuffer);
+
+ Rooted obj(aCx, CurrentGlobalOrNull(aCx));
+
+ Rooted array(aCx, JS_NewUint8Array(aCx, aBuffer->GetSize()));
+ if (NS_WARN_IF(!array)) {
+ return NS_ERROR_FAILURE;
+ }
+ {
+ AutoCheckCannotGC nogc;
+ memcpy(JS_GetArrayBufferViewData(array, nogc),
+ aBuffer->GetData(), aBuffer->GetSize());
+ }
+
+ AutoValueArray<2> args(aCx);
+ args[0].setNumber(aClientId);
+ args[1].setObject(*array);
+
+ Rooted rval(aCx);
+ JS_CallFunctionName(aCx, obj, "onRILMessage", args, &rval);
+
+ return NS_OK;
}
void
@@ -279,16 +265,14 @@ RilConsumer::Close()
}
}
-// |StreamSocketConnector|
+// |RilSocketConnector|
void
-RilConsumer::ReceiveSocketData(int aIndex,
+RilConsumer::ReceiveSocketData(JSContext* aCx,
+ int aIndex,
nsAutoPtr& aBuffer)
{
- MOZ_ASSERT(NS_IsMainThread());
-
- nsRefPtr dre(new DispatchRILEvent(aIndex, aBuffer.forget()));
- mDispatcher->PostTask(dre);
+ Receive(aCx, (uint32_t)aIndex, aBuffer);
}
void
@@ -316,5 +300,140 @@ RilConsumer::OnDisconnect(int aIndex)
mSocket->GetSuggestedConnectDelayMs());
}
+//
+// RilWorker
+//
+
+nsTArray> RilWorker::sRilWorkers;
+
+nsresult
+RilWorker::Register(unsigned int aClientId,
+ WorkerCrossThreadDispatcher* aDispatcher)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ sRilWorkers.EnsureLengthAtLeast(aClientId + 1);
+
+ if (sRilWorkers[aClientId]) {
+ NS_WARNING("RilWorkers already registered");
+ return NS_ERROR_FAILURE;
+ }
+
+ // Now that we're set up, connect ourselves to the RIL thread.
+ sRilWorkers[aClientId] = new RilWorker(aDispatcher);
+
+ nsresult rv = sRilWorkers[aClientId]->RegisterConsumer(aClientId);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ return NS_OK;
+}
+
+void
+RilWorker::Shutdown()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ for (size_t i = 0; i < sRilWorkers.Length(); ++i) {
+ if (!sRilWorkers[i]) {
+ continue;
+ }
+ sRilWorkers[i]->UnregisterConsumer(i);
+ sRilWorkers[i] = nullptr;
+ }
+}
+
+RilWorker::RilWorker(WorkerCrossThreadDispatcher* aDispatcher)
+ : mDispatcher(aDispatcher)
+{
+ MOZ_ASSERT(mDispatcher);
+}
+
+class RilWorker::RegisterConsumerTask : public WorkerTask
+{
+public:
+ RegisterConsumerTask(unsigned int aClientId,
+ WorkerCrossThreadDispatcher* aDispatcher)
+ : mClientId(aClientId)
+ , mDispatcher(aDispatcher)
+ {
+ MOZ_ASSERT(mDispatcher);
+ }
+
+ bool RunTask(JSContext* aCx) override
+ {
+ sRilConsumers.EnsureLengthAtLeast(mClientId + 1);
+
+ MOZ_ASSERT(!sRilConsumers[mClientId]);
+
+ nsAutoPtr rilConsumer(new RilConsumer());
+
+ nsresult rv = rilConsumer->ConnectWorkerToRIL(aCx);
+ if (NS_FAILED(rv)) {
+ return false;
+ }
+
+ rv = rilConsumer->Register(mClientId, mDispatcher);
+ if (NS_FAILED(rv)) {
+ return false;
+ }
+ sRilConsumers[mClientId] = rilConsumer;
+
+ return true;
+ }
+
+private:
+ unsigned int mClientId;
+ nsRefPtr mDispatcher;
+};
+
+nsresult
+RilWorker::RegisterConsumer(unsigned int aClientId)
+{
+ nsRefPtr task = new RegisterConsumerTask(aClientId,
+ mDispatcher);
+ if (!mDispatcher->PostTask(task)) {
+ NS_WARNING("Failed to post register-consumer task.");
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ return NS_OK;
+}
+
+class RilWorker::UnregisterConsumerTask : public WorkerTask
+{
+public:
+ UnregisterConsumerTask(unsigned int aClientId)
+ : mClientId(aClientId)
+ { }
+
+ bool RunTask(JSContext* aCx) override
+ {
+ MOZ_ASSERT(mClientId < sRilConsumers.Length());
+ MOZ_ASSERT(sRilConsumers[mClientId]);
+
+ sRilConsumers[mClientId]->Unregister();
+ sRilConsumers[mClientId] = nullptr;
+
+ return true;
+ }
+
+private:
+ unsigned int mClientId;
+};
+
+void
+RilWorker::UnregisterConsumer(unsigned int aClientId)
+{
+ nsRefPtr task =
+ new UnregisterConsumerTask(aClientId);
+
+ if (!mDispatcher->PostTask(task)) {
+ NS_WARNING("Failed to post unregister-consumer task.");
+ return;
+ }
+}
+
} // namespace ipc
} // namespace mozilla
diff --git a/ipc/ril/Ril.h b/ipc/ril/Ril.h
index 5d0ae62eff02..e51728db0727 100644
--- a/ipc/ril/Ril.h
+++ b/ipc/ril/Ril.h
@@ -7,42 +7,45 @@
#ifndef mozilla_ipc_Ril_h
#define mozilla_ipc_Ril_h 1
-#include
-#include
-#include
+#include "nsAutoPtr.h"
+#include "nsError.h"
+#include "nsTArray.h"
namespace mozilla {
+
+namespace dom {
+namespace workers {
+
+class WorkerCrossThreadDispatcher;
+
+} // namespace workers
+} // namespace dom
+
namespace ipc {
-class RilConsumer final : public StreamSocketConsumer
+class RilConsumer;
+
+class RilWorker final
{
public:
static nsresult Register(
unsigned int aClientId,
mozilla::dom::workers::WorkerCrossThreadDispatcher* aDispatcher);
+
static void Shutdown();
- void Send(UnixSocketRawData* aRawData);
-
private:
- RilConsumer(unsigned long aClientId,
- mozilla::dom::workers::WorkerCrossThreadDispatcher* aDispatcher);
+ class RegisterConsumerTask;
+ class UnregisterConsumerTask;
- void Close();
+ RilWorker(mozilla::dom::workers::WorkerCrossThreadDispatcher* aDispatcher);
- // Methods for |StreamSocketConsumer|
- //
+ nsresult RegisterConsumer(unsigned int aClientId);
+ void UnregisterConsumer(unsigned int aClientId);
- void ReceiveSocketData(int aIndex,
- nsAutoPtr& aBuffer) override;
- void OnConnectSuccess(int aIndex) override;
- void OnConnectError(int aIndex) override;
- void OnDisconnect(int aIndex) override;
+ static nsTArray> sRilWorkers;
- nsRefPtr mSocket;
nsRefPtr mDispatcher;
- nsCString mAddress;
- bool mShutdown;
};
} // namespace ipc
diff --git a/ipc/ril/RilSocket.cpp b/ipc/ril/RilSocket.cpp
new file mode 100644
index 000000000000..48db874dc1a1
--- /dev/null
+++ b/ipc/ril/RilSocket.cpp
@@ -0,0 +1,433 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "RilSocket.h"
+#include
+#include "mozilla/dom/workers/Workers.h"
+#include "mozilla/ipc/UnixSocketConnector.h"
+#include "mozilla/RefPtr.h"
+#include "nsXULAppAPI.h"
+#include "RilSocketConsumer.h"
+
+static const size_t MAX_READ_SIZE = 1 << 16;
+
+namespace mozilla {
+namespace ipc {
+
+USING_WORKERS_NAMESPACE
+
+//
+// RilSocketIO
+//
+
+class RilSocketIO final : public ConnectionOrientedSocketIO
+{
+public:
+ class ConnectTask;
+ class DelayedConnectTask;
+ class ReceiveTask;
+
+ RilSocketIO(WorkerCrossThreadDispatcher* aDispatcher,
+ MessageLoop* aConsumerLoop,
+ MessageLoop* aIOLoop,
+ RilSocket* aRilSocket,
+ UnixSocketConnector* aConnector);
+ ~RilSocketIO();
+
+ RilSocket* GetRilSocket();
+ DataSocket* GetDataSocket();
+
+ // Delayed-task handling
+ //
+
+ void SetDelayedConnectTask(CancelableTask* aTask);
+ void ClearDelayedConnectTask();
+ void CancelDelayedConnectTask();
+
+ // Methods for |DataSocket|
+ //
+
+ nsresult QueryReceiveBuffer(UnixSocketIOBuffer** aBuffer) override;
+ void ConsumeBuffer() override;
+ void DiscardBuffer() override;
+
+ // Methods for |SocketIOBase|
+ //
+
+ SocketBase* GetSocketBase() override;
+
+ bool IsShutdownOnConsumerThread() const override;
+ bool IsShutdownOnIOThread() const override;
+
+ void ShutdownOnConsumerThread() override;
+ void ShutdownOnIOThread() override;
+
+private:
+ /**
+ * Cross-thread dispatcher for the RIL worker
+ */
+ nsRefPtr mDispatcher;
+
+ /**
+ * Consumer pointer. Non-thread safe RefPtr, so should only be manipulated
+ * directly from consumer thread. All non-consumer-thread accesses should
+ * happen with mIO as container.
+ */
+ RefPtr mRilSocket;
+
+ /**
+ * If true, do not requeue whatever task we're running
+ */
+ bool mShuttingDownOnIOThread;
+
+ /**
+ * Task member for delayed connect task. Should only be access on consumer
+ * thread.
+ */
+ CancelableTask* mDelayedConnectTask;
+
+ /**
+ * I/O buffer for received data
+ */
+ nsAutoPtr mBuffer;
+};
+
+RilSocketIO::RilSocketIO(WorkerCrossThreadDispatcher* aDispatcher,
+ MessageLoop* aConsumerLoop,
+ MessageLoop* aIOLoop,
+ RilSocket* aRilSocket,
+ UnixSocketConnector* aConnector)
+ : ConnectionOrientedSocketIO(aConsumerLoop, aIOLoop, aConnector)
+ , mDispatcher(aDispatcher)
+ , mRilSocket(aRilSocket)
+ , mShuttingDownOnIOThread(false)
+ , mDelayedConnectTask(nullptr)
+{
+ MOZ_ASSERT(mDispatcher);
+ MOZ_ASSERT(mRilSocket);
+}
+
+RilSocketIO::~RilSocketIO()
+{
+ MOZ_ASSERT(IsConsumerThread());
+ MOZ_ASSERT(IsShutdownOnConsumerThread());
+}
+
+RilSocket*
+RilSocketIO::GetRilSocket()
+{
+ return mRilSocket.get();
+}
+
+DataSocket*
+RilSocketIO::GetDataSocket()
+{
+ return mRilSocket.get();
+}
+
+void
+RilSocketIO::SetDelayedConnectTask(CancelableTask* aTask)
+{
+ MOZ_ASSERT(IsConsumerThread());
+
+ mDelayedConnectTask = aTask;
+}
+
+void
+RilSocketIO::ClearDelayedConnectTask()
+{
+ MOZ_ASSERT(IsConsumerThread());
+
+ mDelayedConnectTask = nullptr;
+}
+
+void
+RilSocketIO::CancelDelayedConnectTask()
+{
+ MOZ_ASSERT(IsConsumerThread());
+
+ if (!mDelayedConnectTask) {
+ return;
+ }
+
+ mDelayedConnectTask->Cancel();
+ ClearDelayedConnectTask();
+}
+
+// |DataSocketIO|
+
+nsresult
+RilSocketIO::QueryReceiveBuffer(UnixSocketIOBuffer** aBuffer)
+{
+ MOZ_ASSERT(aBuffer);
+
+ if (!mBuffer) {
+ mBuffer = new UnixSocketRawData(MAX_READ_SIZE);
+ }
+ *aBuffer = mBuffer.get();
+
+ return NS_OK;
+}
+
+/**
+ * |ReceiveTask| transfers data received on the I/O thread
+ * to an instance of |RilSocket| on the consumer thread.
+ */
+class RilSocketIO::ReceiveTask final : public WorkerTask
+{
+public:
+ ReceiveTask(RilSocketIO* aIO, UnixSocketBuffer* aBuffer)
+ : mIO(aIO)
+ , mBuffer(aBuffer)
+ {
+ MOZ_ASSERT(mIO);
+ }
+
+ bool RunTask(JSContext* aCx) override
+ {
+ // Dispatched via WCTD, but still needs to run on the consumer thread
+ MOZ_ASSERT(mIO->IsConsumerThread());
+
+ if (NS_WARN_IF(mIO->IsShutdownOnConsumerThread())) {
+ // Since we've already explicitly closed and the close
+ // happened before this, this isn't really an error.
+ return true;
+ }
+
+ RilSocket* rilSocket = mIO->GetRilSocket();
+ MOZ_ASSERT(rilSocket);
+
+ rilSocket->ReceiveSocketData(aCx, mBuffer);
+
+ return true;
+ }
+
+private:
+ RilSocketIO* mIO;
+ nsAutoPtr mBuffer;
+};
+
+void
+RilSocketIO::ConsumeBuffer()
+{
+ nsRefPtr task = new ReceiveTask(this, mBuffer.forget());
+ NS_WARN_IF(!mDispatcher->PostTask(task));
+}
+
+void
+RilSocketIO::DiscardBuffer()
+{
+ // Nothing to do.
+}
+
+// |SocketIOBase|
+
+SocketBase*
+RilSocketIO::GetSocketBase()
+{
+ return GetDataSocket();
+}
+
+bool
+RilSocketIO::IsShutdownOnConsumerThread() const
+{
+ MOZ_ASSERT(IsConsumerThread());
+
+ return mRilSocket == nullptr;
+}
+
+bool
+RilSocketIO::IsShutdownOnIOThread() const
+{
+ return mShuttingDownOnIOThread;
+}
+
+void
+RilSocketIO::ShutdownOnConsumerThread()
+{
+ MOZ_ASSERT(IsConsumerThread());
+ MOZ_ASSERT(!IsShutdownOnConsumerThread());
+
+ mRilSocket = nullptr;
+}
+
+void
+RilSocketIO::ShutdownOnIOThread()
+{
+ MOZ_ASSERT(!IsConsumerThread());
+ MOZ_ASSERT(!mShuttingDownOnIOThread);
+
+ Close(); // will also remove fd from I/O loop
+ mShuttingDownOnIOThread = true;
+}
+
+//
+// Socket tasks
+//
+
+class RilSocketIO::ConnectTask final
+ : public SocketIOTask
+{
+public:
+ ConnectTask(RilSocketIO* aIO)
+ : SocketIOTask(aIO)
+ { }
+
+ void Run() override
+ {
+ MOZ_ASSERT(!GetIO()->IsConsumerThread());
+ MOZ_ASSERT(!IsCanceled());
+
+ GetIO()->Connect();
+ }
+};
+
+class RilSocketIO::DelayedConnectTask final
+ : public SocketIOTask
+{
+public:
+ DelayedConnectTask(RilSocketIO* aIO)
+ : SocketIOTask(aIO)
+ { }
+
+ void Run() override
+ {
+ MOZ_ASSERT(GetIO()->IsConsumerThread());
+
+ if (IsCanceled()) {
+ return;
+ }
+
+ RilSocketIO* io = GetIO();
+ if (io->IsShutdownOnConsumerThread()) {
+ return;
+ }
+
+ io->ClearDelayedConnectTask();
+ io->GetIOLoop()->PostTask(FROM_HERE, new ConnectTask(io));
+ }
+};
+
+//
+// RilSocket
+//
+
+RilSocket::RilSocket(WorkerCrossThreadDispatcher* aDispatcher,
+ RilSocketConsumer* aConsumer, int aIndex)
+ : mIO(nullptr)
+ , mDispatcher(aDispatcher)
+ , mConsumer(aConsumer)
+ , mIndex(aIndex)
+{
+ MOZ_ASSERT(mDispatcher);
+ MOZ_ASSERT(mConsumer);
+}
+
+RilSocket::~RilSocket()
+{
+ MOZ_ASSERT(!mIO);
+}
+
+void
+RilSocket::ReceiveSocketData(JSContext* aCx,
+ nsAutoPtr& aBuffer)
+{
+ mConsumer->ReceiveSocketData(aCx, mIndex, aBuffer);
+}
+
+nsresult
+RilSocket::Connect(UnixSocketConnector* aConnector, int aDelayMs,
+ MessageLoop* aConsumerLoop, MessageLoop* aIOLoop)
+{
+ MOZ_ASSERT(!mIO);
+
+ mIO = new RilSocketIO(mDispatcher, aConsumerLoop, aIOLoop, this, aConnector);
+ SetConnectionStatus(SOCKET_CONNECTING);
+
+ if (aDelayMs > 0) {
+ RilSocketIO::DelayedConnectTask* connectTask =
+ new RilSocketIO::DelayedConnectTask(mIO);
+ mIO->SetDelayedConnectTask(connectTask);
+ MessageLoop::current()->PostDelayedTask(FROM_HERE, connectTask, aDelayMs);
+ } else {
+ aIOLoop->PostTask(FROM_HERE, new RilSocketIO::ConnectTask(mIO));
+ }
+
+ return NS_OK;
+}
+
+nsresult
+RilSocket::Connect(UnixSocketConnector* aConnector, int aDelayMs)
+{
+ return Connect(aConnector, aDelayMs,
+ MessageLoop::current(), XRE_GetIOMessageLoop());
+}
+
+// |ConnectionOrientedSocket|
+
+nsresult
+RilSocket::PrepareAccept(UnixSocketConnector* aConnector,
+ MessageLoop* aConsumerLoop,
+ MessageLoop* aIOLoop,
+ ConnectionOrientedSocketIO*& aIO)
+{
+ MOZ_CRASH("|RilSocket| does not support accepting connections.");
+}
+
+// |DataSocket|
+
+void
+RilSocket::SendSocketData(UnixSocketIOBuffer* aBuffer)
+{
+ MOZ_ASSERT(mIO);
+ MOZ_ASSERT(mIO->IsConsumerThread());
+ MOZ_ASSERT(!mIO->IsShutdownOnConsumerThread());
+
+ mIO->GetIOLoop()->PostTask(
+ FROM_HERE,
+ new SocketIOSendTask(mIO, aBuffer));
+}
+
+// |SocketBase|
+
+void
+RilSocket::Close()
+{
+ MOZ_ASSERT(mIO);
+ MOZ_ASSERT(mIO->IsConsumerThread());
+
+ mIO->CancelDelayedConnectTask();
+
+ // From this point on, we consider |mIO| as being deleted. We sever
+ // the relationship here so any future calls to |Connect| will create
+ // a new I/O object.
+ mIO->ShutdownOnConsumerThread();
+ mIO->GetIOLoop()->PostTask(FROM_HERE, new SocketIOShutdownTask(mIO));
+ mIO = nullptr;
+
+ NotifyDisconnect();
+}
+
+void
+RilSocket::OnConnectSuccess()
+{
+ mConsumer->OnConnectSuccess(mIndex);
+}
+
+void
+RilSocket::OnConnectError()
+{
+ mConsumer->OnConnectError(mIndex);
+}
+
+void
+RilSocket::OnDisconnect()
+{
+ mConsumer->OnDisconnect(mIndex);
+}
+
+} // namespace ipc
+} // namespace mozilla
diff --git a/ipc/ril/RilSocket.h b/ipc/ril/RilSocket.h
new file mode 100644
index 000000000000..e1ca8f75cd8c
--- /dev/null
+++ b/ipc/ril/RilSocket.h
@@ -0,0 +1,110 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_ipc_RilSocket_h
+#define mozilla_ipc_RilSocket_h
+
+#include "mozilla/ipc/ConnectionOrientedSocket.h"
+
+class JSContext;
+class MessageLoop;
+
+namespace mozilla {
+namespace dom {
+namespace workers {
+
+class WorkerCrossThreadDispatcher;
+
+} // namespace workers
+} // namespace dom
+} // namespace mozilla
+
+namespace mozilla {
+namespace ipc {
+
+class RilSocketConsumer;
+class RilSocketIO;
+class UnixSocketConnector;
+
+class RilSocket final : public ConnectionOrientedSocket
+{
+public:
+ /**
+ * Constructs an instance of |RilSocket|.
+ *
+ * @param aDispatcher The dispatcher class for the received messages.
+ * @param aConsumer The consumer for the socket.
+ * @param aIndex An arbitrary index.
+ */
+ RilSocket(mozilla::dom::workers::WorkerCrossThreadDispatcher* aDispatcher,
+ RilSocketConsumer* aConsumer, int aIndex);
+
+ /**
+ * Method to be called whenever data is received. RIL-worker only.
+ *
+ * @param aCx The RIL worker's JS context.
+ * @param aBuffer Data received from the socket.
+ */
+ void ReceiveSocketData(JSContext* aCx, nsAutoPtr& aBuffer);
+
+ /**
+ * Starts a task on the socket that will try to connect to a socket in a
+ * non-blocking manner.
+ *
+ * @param aConnector Connector object for socket type specific functions
+ * @param aDelayMs Time delay in milliseconds.
+ * @param aConsumerLoop The socket's consumer thread.
+ * @param aIOLoop The socket's I/O thread.
+ * @return NS_OK on success, or an XPCOM error code otherwise.
+ */
+ nsresult Connect(UnixSocketConnector* aConnector, int aDelayMs,
+ MessageLoop* aConsumerLoop, MessageLoop* aIOLoop);
+
+ /**
+ * Starts a task on the socket that will try to connect to a socket in a
+ * non-blocking manner.
+ *
+ * @param aConnector Connector object for socket type specific functions
+ * @param aDelayMs Time delay in milliseconds.
+ * @return NS_OK on success, or an XPCOM error code otherwise.
+ */
+ nsresult Connect(UnixSocketConnector* aConnector, int aDelayMs = 0);
+
+ // Methods for |ConnectionOrientedSocket|
+ //
+
+ nsresult PrepareAccept(UnixSocketConnector* aConnector,
+ MessageLoop* aConsumerLoop,
+ MessageLoop* aIOLoop,
+ ConnectionOrientedSocketIO*& aIO) override;
+
+ // Methods for |DataSocket|
+ //
+
+ void SendSocketData(UnixSocketIOBuffer* aBuffer) override;
+
+ // Methods for |SocketBase|
+ //
+
+ void Close() override;
+ void OnConnectSuccess() override;
+ void OnConnectError() override;
+ void OnDisconnect() override;
+
+protected:
+ virtual ~RilSocket();
+
+private:
+ RilSocketIO* mIO;
+ nsRefPtr mDispatcher;
+ RilSocketConsumer* mConsumer;
+ int mIndex;
+};
+
+} // namespace ipc
+} // namepsace mozilla
+
+#endif // mozilla_ipc_RilSocket_h
diff --git a/ipc/ril/RilSocketConsumer.cpp b/ipc/ril/RilSocketConsumer.cpp
new file mode 100644
index 000000000000..a8a7418872f6
--- /dev/null
+++ b/ipc/ril/RilSocketConsumer.cpp
@@ -0,0 +1,20 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "RilSocketConsumer.h"
+
+namespace mozilla {
+namespace ipc {
+
+//
+// RilSocketConsumer
+//
+
+RilSocketConsumer::~RilSocketConsumer()
+{ }
+
+}
+}
diff --git a/ipc/ril/RilSocketConsumer.h b/ipc/ril/RilSocketConsumer.h
new file mode 100644
index 000000000000..510517b4ad28
--- /dev/null
+++ b/ipc/ril/RilSocketConsumer.h
@@ -0,0 +1,64 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_ipc_RilSocketConsumer_h
+#define mozilla_ipc_RilSocketConsumer_h
+
+#include "nsAutoPtr.h"
+
+class JSContext;
+
+namespace mozilla {
+namespace ipc {
+
+class UnixSocketBuffer;
+
+/**
+ * |RilSocketConsumer| handles socket events and received data.
+ */
+class RilSocketConsumer
+{
+public:
+ /**
+ * Method to be called whenever data is received. RIL-worker only.
+ *
+ * @param aCx The RIL worker's JS context.
+ * @param aIndex The index that has been given to the stream socket.
+ * @param aBuffer Data received from the socket.
+ */
+ virtual void ReceiveSocketData(JSContext* aCx,
+ int aIndex,
+ nsAutoPtr& aBuffer) = 0;
+
+ /**
+ * Callback for socket success. Consumer-thread only.
+ *
+ * @param aIndex The index that has been given to the stream socket.
+ */
+ virtual void OnConnectSuccess(int aIndex) = 0;
+
+ /**
+ * Callback for socket errors. Consumer-thread only.
+ *
+ * @param aIndex The index that has been given to the stream socket.
+ */
+ virtual void OnConnectError(int aIndex) = 0;
+
+ /**
+ * Callback for socket disconnect. Consumer-thread only.
+ *
+ * @param aIndex The index that has been given to the stream socket.
+ */
+ virtual void OnDisconnect(int aIndex) = 0;
+
+protected:
+ virtual ~RilSocketConsumer();
+};
+
+}
+}
+
+#endif
diff --git a/ipc/ril/moz.build b/ipc/ril/moz.build
index 4e7018bcb6af..215d9e2ac624 100644
--- a/ipc/ril/moz.build
+++ b/ipc/ril/moz.build
@@ -6,11 +6,15 @@
EXPORTS.mozilla.ipc += [
'Ril.h',
+ 'RilSocket.h',
+ 'RilSocketConsumer.h'
]
SOURCES += [
'Ril.cpp',
- 'RilConnector.cpp'
+ 'RilConnector.cpp',
+ 'RilSocket.cpp',
+ 'RilSocketConsumer.cpp'
]
include('/ipc/chromium/chromium-config.mozbuild')