mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 889737 - Part 09: Dial MMI (ril). r=vicamo
This commit is contained in:
parent
bbd007d9bd
commit
0488a241d4
@ -25,6 +25,8 @@ const MOBILENETWORKINFO_CID =
|
|||||||
Components.ID("{a6c8416c-09b4-46d1-bf29-6520d677d085}");
|
Components.ID("{a6c8416c-09b4-46d1-bf29-6520d677d085}");
|
||||||
const MOBILECELLINFO_CID =
|
const MOBILECELLINFO_CID =
|
||||||
Components.ID("{0635d9ab-997e-4cdf-84e7-c1883752dff3}");
|
Components.ID("{0635d9ab-997e-4cdf-84e7-c1883752dff3}");
|
||||||
|
const TELEPHONYCALLBACK_CID =
|
||||||
|
Components.ID("{6e1af17e-37f3-11e4-aed3-60a44c237d2b}");
|
||||||
|
|
||||||
const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown";
|
const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown";
|
||||||
const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed";
|
const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed";
|
||||||
@ -44,6 +46,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "gRadioInterfaceLayer",
|
|||||||
"@mozilla.org/ril;1",
|
"@mozilla.org/ril;1",
|
||||||
"nsIRadioInterfaceLayer");
|
"nsIRadioInterfaceLayer");
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyServiceGetter(this, "gGonkTelephonyService",
|
||||||
|
"@mozilla.org/telephony/telephonyservice;1",
|
||||||
|
"nsIGonkTelephonyService");
|
||||||
|
|
||||||
let DEBUG = RIL.DEBUG_RIL;
|
let DEBUG = RIL.DEBUG_RIL;
|
||||||
function debug(s) {
|
function debug(s) {
|
||||||
dump("MobileConnectionService: " + s + "\n");
|
dump("MobileConnectionService: " + s + "\n");
|
||||||
@ -134,6 +140,41 @@ MMIResult.prototype = {
|
|||||||
additionalInformation: 'r'},
|
additionalInformation: 'r'},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrap a MobileConnectionCallback to a TelephonyCallback.
|
||||||
|
*/
|
||||||
|
function TelephonyCallback(aCallback) {
|
||||||
|
this.callback = aCallback;
|
||||||
|
}
|
||||||
|
TelephonyCallback.prototype = {
|
||||||
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsITelephonyCallback]),
|
||||||
|
classID: TELEPHONYCALLBACK_CID,
|
||||||
|
|
||||||
|
notifyDialMMI: function(mmiServiceCode) {
|
||||||
|
this.serviceCode = mmiServiceCode;
|
||||||
|
},
|
||||||
|
|
||||||
|
notifyDialMMISuccess: function(result) {
|
||||||
|
this.callback.notifySendCancelMmiSuccess(result);
|
||||||
|
},
|
||||||
|
|
||||||
|
notifyDialMMIError: function(error) {
|
||||||
|
this.callback.notifyError(error, "", this.serviceCode);
|
||||||
|
},
|
||||||
|
|
||||||
|
notifyDialMMIErrorWithInfo: function(error, info) {
|
||||||
|
this.callback.notifyError(error, "", this.serviceCode, info);
|
||||||
|
},
|
||||||
|
|
||||||
|
notifyDialError: function() {
|
||||||
|
throw Cr.NS_ERROR_UNEXPECTED;
|
||||||
|
},
|
||||||
|
|
||||||
|
notifyDialSuccess: function() {
|
||||||
|
throw Cr.NS_ERROR_UNEXPECTED;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
function MobileConnectionProvider(aClientId, aRadioInterface) {
|
function MobileConnectionProvider(aClientId, aRadioInterface) {
|
||||||
this._clientId = aClientId;
|
this._clientId = aClientId;
|
||||||
this._radioInterface = aRadioInterface;
|
this._radioInterface = aRadioInterface;
|
||||||
@ -188,7 +229,7 @@ MobileConnectionProvider.prototype = {
|
|||||||
key = "ro.telephony.default_network";
|
key = "ro.telephony.default_network";
|
||||||
let indexString = libcutils.property_get(key, "");
|
let indexString = libcutils.property_get(key, "");
|
||||||
let index = parseInt(indexString, 10);
|
let index = parseInt(indexString, 10);
|
||||||
if (DEBUG) this._debug("Fallback to " + key + ": " + index)
|
if (DEBUG) this._debug("Fallback to " + key + ": " + index);
|
||||||
|
|
||||||
let networkTypes = RIL.RIL_PREFERRED_NETWORK_TYPE_TO_GECKO[index];
|
let networkTypes = RIL.RIL_PREFERRED_NETWORK_TYPE_TO_GECKO[index];
|
||||||
supportedNetworkTypes = networkTypes ?
|
supportedNetworkTypes = networkTypes ?
|
||||||
@ -382,10 +423,7 @@ MobileConnectionProvider.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
_rulesToCallForwardingOptions: function(aRules) {
|
_rulesToCallForwardingOptions: function(aRules) {
|
||||||
for (let i = 0; i < aRules.length; i++) {
|
return aRules.map(rule => new CallForwardingOptions(rule));
|
||||||
let info = new CallForwardingOptions(aRules[i]);
|
|
||||||
aRules[i] = info;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_dispatchNotifyError: function(aCallback, aErrorMsg) {
|
_dispatchNotifyError: function(aCallback, aErrorMsg) {
|
||||||
@ -515,6 +553,13 @@ MobileConnectionProvider.prototype = {
|
|||||||
this.deliverListenerEvent("notifyRadioStateChanged");
|
this.deliverListenerEvent("notifyRadioStateChanged");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
notifyCFStateChanged: function(aAction, aReason, aNumber, aTimeSeconds,
|
||||||
|
aServiceClass) {
|
||||||
|
this.deliverListenerEvent("notifyCFStateChanged",
|
||||||
|
[true, aAction, aReason, aNumber, aTimeSeconds,
|
||||||
|
aServiceClass]);
|
||||||
|
},
|
||||||
|
|
||||||
getSupportedNetworkTypes: function(aTypes) {
|
getSupportedNetworkTypes: function(aTypes) {
|
||||||
aTypes.value = this.supportedNetworkTypes.slice();
|
aTypes.value = this.supportedNetworkTypes.slice();
|
||||||
return aTypes.value.length;
|
return aTypes.value.length;
|
||||||
@ -680,49 +725,8 @@ MobileConnectionProvider.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
sendMMI: function(aMmi, aCallback) {
|
sendMMI: function(aMmi, aCallback) {
|
||||||
this._radioInterface.sendWorkerMessage("sendMMI", {mmi: aMmi},
|
let telephonyCallback = new TelephonyCallback(aCallback);
|
||||||
(function(aResponse) {
|
gGonkTelephonyService.dialMMI(this._clientId, aMmi, telephonyCallback);
|
||||||
aResponse.serviceCode = aResponse.mmiServiceCode || "";
|
|
||||||
// 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 (aResponse.serviceCode === RIL.MMI_KS_SC_IMEI &&
|
|
||||||
!aResponse.statusMessage) {
|
|
||||||
aResponse.errorMsg = aResponse.errorMsg ||
|
|
||||||
RIL.GECKO_ERROR_GENERIC_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aResponse.errorMsg) {
|
|
||||||
if (aResponse.additionalInformation) {
|
|
||||||
aCallback.notifyError(aResponse.errorMsg, "",
|
|
||||||
aResponse.serviceCode,
|
|
||||||
aResponse.additionalInformation);
|
|
||||||
} else {
|
|
||||||
aCallback.notifyError(aResponse.errorMsg, "",
|
|
||||||
aResponse.serviceCode);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aResponse.isSetCallForward) {
|
|
||||||
this.deliverListenerEvent("notifyCFStateChanged",
|
|
||||||
[!aResponse.errorMsg, aResponse.action,
|
|
||||||
aResponse.reason, aResponse.number,
|
|
||||||
aResponse.timeSeconds, aResponse.serviceClass]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 (aResponse.serviceCode === RIL.MMI_KS_SC_CALL_FORWARDING &&
|
|
||||||
aResponse.additionalInformation) {
|
|
||||||
this._rulesToCallForwardingOptions(aResponse.additionalInformation);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mmiResult = new MMIResult(aResponse);
|
|
||||||
aCallback.notifySendCancelMmiSuccess(mmiResult);
|
|
||||||
return false;
|
|
||||||
}).bind(this));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
cancelMMI: function(aCallback) {
|
cancelMMI: function(aCallback) {
|
||||||
@ -762,11 +766,9 @@ MobileConnectionProvider.prototype = {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.deliverListenerEvent("notifyCFStateChanged",
|
this.notifyCFStateChanged(aResponse.action, aResponse.reason,
|
||||||
[!aResponse.errorMsg, aResponse.action,
|
aResponse.number, aResponse.timeSeconds,
|
||||||
aResponse.reason, aResponse.number,
|
aResponse.serviceClass);
|
||||||
aResponse.timeSeconds, aResponse.serviceClass]);
|
|
||||||
|
|
||||||
aCallback.notifySuccess();
|
aCallback.notifySuccess();
|
||||||
return false;
|
return false;
|
||||||
}).bind(this));
|
}).bind(this));
|
||||||
@ -786,9 +788,8 @@ MobileConnectionProvider.prototype = {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let infos = aResponse.rules;
|
aCallback.notifyGetCallForwardingSuccess(
|
||||||
this._rulesToCallForwardingOptions(infos);
|
this._rulesToCallForwardingOptions(aResponse.rules));
|
||||||
aCallback.notifyGetCallForwardingSuccess(infos);
|
|
||||||
return false;
|
return false;
|
||||||
}).bind(this));
|
}).bind(this));
|
||||||
},
|
},
|
||||||
@ -1216,6 +1217,17 @@ MobileConnectionService.prototype = {
|
|||||||
provider.deliverListenerEvent("notifyLastKnownHomeNetworkChanged");
|
provider.deliverListenerEvent("notifyLastKnownHomeNetworkChanged");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
notifyCFStateChanged: function(aClientId, aAction, aReason, aNumber,
|
||||||
|
aTimeSeconds, aServiceClass) {
|
||||||
|
if (DEBUG) {
|
||||||
|
debug("notifyCFStateChanged for " + aClientId);
|
||||||
|
}
|
||||||
|
|
||||||
|
let provider = this.getItemByServiceId(aClientId);
|
||||||
|
provider.notifyCFStateChanged(aAction, aReason, aNumber, aTimeSeconds,
|
||||||
|
aServiceClass);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nsIObserver interface.
|
* nsIObserver interface.
|
||||||
*/
|
*/
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
"@mozilla.org/mobileconnection/gonkmobileconnectionservice;1"
|
"@mozilla.org/mobileconnection/gonkmobileconnectionservice;1"
|
||||||
%}
|
%}
|
||||||
|
|
||||||
[scriptable, uuid(e54fa0a4-d357-48ef-9a1e-ffc9705b44b1)]
|
[scriptable, uuid(b0310517-e7f6-4fa5-a52e-fa6ff35c8fc1)]
|
||||||
interface nsIGonkMobileConnectionService : nsIMobileConnectionService
|
interface nsIGonkMobileConnectionService : nsIMobileConnectionService
|
||||||
{
|
{
|
||||||
void notifyNetworkInfoChanged(in unsigned long clientId, in jsval networkInfo);
|
void notifyNetworkInfoChanged(in unsigned long clientId, in jsval networkInfo);
|
||||||
@ -46,4 +46,11 @@ interface nsIGonkMobileConnectionService : nsIMobileConnectionService
|
|||||||
|
|
||||||
void notifyLastHomeNetworkChanged(in unsigned long clientId,
|
void notifyLastHomeNetworkChanged(in unsigned long clientId,
|
||||||
in DOMString network);
|
in DOMString network);
|
||||||
|
|
||||||
|
void notifyCFStateChanged(in unsigned long clientId,
|
||||||
|
in unsigned short action,
|
||||||
|
in unsigned short reason,
|
||||||
|
in DOMString number,
|
||||||
|
in unsigned short timeSeconds,
|
||||||
|
in unsigned short serviceClass);
|
||||||
};
|
};
|
||||||
|
@ -33,7 +33,7 @@ function testInvalidMMICode() {
|
|||||||
ok(true, MMI_CODE + " fail");
|
ok(true, MMI_CODE + " fail");
|
||||||
is(aError.name, "emMmiError", "MMI error name");
|
is(aError.name, "emMmiError", "MMI error name");
|
||||||
is(aError.message, "", "No message");
|
is(aError.message, "", "No message");
|
||||||
is(aError.serviceCode, "", "No serviceCode");
|
is(aError.serviceCode, "scUssd", "Service code USSD");
|
||||||
is(aError.additionalInformation, null, "No additional information");
|
is(aError.additionalInformation, null, "No additional information");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -57,20 +57,6 @@ const EMERGENCY_CB_MODE_TIMEOUT_MS = 300000; // 5 mins = 300000 ms.
|
|||||||
|
|
||||||
const ICC_MAX_LINEAR_FIXED_RECORDS = 0xfe;
|
const ICC_MAX_LINEAR_FIXED_RECORDS = 0xfe;
|
||||||
|
|
||||||
// MMI match groups
|
|
||||||
const MMI_MATCH_GROUP_FULL_MMI = 1;
|
|
||||||
const MMI_MATCH_GROUP_PROCEDURE = 2;
|
|
||||||
const MMI_MATCH_GROUP_SERVICE_CODE = 3;
|
|
||||||
const MMI_MATCH_GROUP_SIA = 4;
|
|
||||||
const MMI_MATCH_GROUP_SIB = 5;
|
|
||||||
const MMI_MATCH_GROUP_SIC = 6;
|
|
||||||
const MMI_MATCH_GROUP_PWD_CONFIRM = 7;
|
|
||||||
const MMI_MATCH_GROUP_DIALING_NUMBER = 8;
|
|
||||||
|
|
||||||
const MMI_MAX_LENGTH_SHORT_CODE = 2;
|
|
||||||
|
|
||||||
const MMI_END_OF_USSD = "#";
|
|
||||||
|
|
||||||
const GET_CURRENT_CALLS_RETRY_MAX = 3;
|
const GET_CURRENT_CALLS_RETRY_MAX = 3;
|
||||||
|
|
||||||
let RILQUIRKS_CALLSTATE_EXTRA_UINT32;
|
let RILQUIRKS_CALLSTATE_EXTRA_UINT32;
|
||||||
@ -2402,208 +2388,11 @@ RilObject.prototype = {
|
|||||||
{callback: callback});
|
{callback: callback});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse the dial number to extract its mmi code part.
|
|
||||||
*
|
|
||||||
* @param number
|
|
||||||
* Phone number to be parsed
|
|
||||||
*/
|
|
||||||
parseMMIFromDialNumber: function(options) {
|
|
||||||
// We don't have to parse mmi in cdma.
|
|
||||||
if (!this._isCdma) {
|
|
||||||
options.mmi = this._parseMMI(options.number);
|
|
||||||
}
|
|
||||||
this.sendChromeMessage(options);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper to parse MMI/USSD string. TS.22.030 Figure 3.5.3.2.
|
|
||||||
*/
|
|
||||||
_parseMMI: function(mmiString) {
|
|
||||||
if (!mmiString || !mmiString.length) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
let matches = this._getMMIRegExp().exec(mmiString);
|
|
||||||
if (matches) {
|
|
||||||
return {
|
|
||||||
fullMMI: matches[MMI_MATCH_GROUP_FULL_MMI],
|
|
||||||
procedure: matches[MMI_MATCH_GROUP_PROCEDURE],
|
|
||||||
serviceCode: matches[MMI_MATCH_GROUP_SERVICE_CODE],
|
|
||||||
sia: matches[MMI_MATCH_GROUP_SIA],
|
|
||||||
sib: matches[MMI_MATCH_GROUP_SIB],
|
|
||||||
sic: matches[MMI_MATCH_GROUP_SIC],
|
|
||||||
pwd: matches[MMI_MATCH_GROUP_PWD_CONFIRM],
|
|
||||||
dialNumber: matches[MMI_MATCH_GROUP_DIALING_NUMBER]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._isPoundString(mmiString) || this._isMMIShortString(mmiString)) {
|
|
||||||
return {
|
|
||||||
fullMMI: mmiString
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build the regex to parse MMI string.
|
|
||||||
*
|
|
||||||
* The resulting groups after matching will be:
|
|
||||||
* 1 = full MMI string that might be used as a USSD request.
|
|
||||||
* 2 = MMI procedure.
|
|
||||||
* 3 = Service code.
|
|
||||||
* 4 = SIA.
|
|
||||||
* 5 = SIB.
|
|
||||||
* 6 = SIC.
|
|
||||||
* 7 = Password registration.
|
|
||||||
* 8 = Dialing number.
|
|
||||||
*
|
|
||||||
* @see TS.22.030 Figure 3.5.3.2.
|
|
||||||
*/
|
|
||||||
_buildMMIRegExp: function() {
|
|
||||||
// The general structure of the codes is as follows:
|
|
||||||
// - Activation (*SC*SI#).
|
|
||||||
// - Deactivation (#SC*SI#).
|
|
||||||
// - Interrogation (*#SC*SI#).
|
|
||||||
// - Registration (**SC*SI#).
|
|
||||||
// - Erasure (##SC*SI#).
|
|
||||||
//
|
|
||||||
// where SC = Service Code (2 or 3 digits) and SI = Supplementary Info
|
|
||||||
// (variable length).
|
|
||||||
|
|
||||||
// MMI procedure, which could be *, #, *#, **, ##
|
|
||||||
let procedure = "(\\*[*#]?|##?)";
|
|
||||||
|
|
||||||
// MMI Service code, which is a 2 or 3 digits that uniquely specifies the
|
|
||||||
// Supplementary Service associated with the MMI code.
|
|
||||||
let serviceCode = "(\\d{2,3})";
|
|
||||||
|
|
||||||
// MMI Supplementary Information SIA, SIB and SIC. SIA may comprise e.g. a
|
|
||||||
// PIN code or Directory Number, SIB may be used to specify the tele or
|
|
||||||
// bearer service and SIC to specify the value of the "No Reply Condition
|
|
||||||
// Timer". Where a particular service request does not require any SI,
|
|
||||||
// "*SI" is not entered. The use of SIA, SIB and SIC is optional and shall
|
|
||||||
// be entered in any of the following formats:
|
|
||||||
// - *SIA*SIB*SIC#
|
|
||||||
// - *SIA*SIB#
|
|
||||||
// - *SIA**SIC#
|
|
||||||
// - *SIA#
|
|
||||||
// - **SIB*SIC#
|
|
||||||
// - ***SIC#
|
|
||||||
//
|
|
||||||
// Also catch the additional NEW_PASSWORD for the case of a password
|
|
||||||
// registration procedure. Ex:
|
|
||||||
// - * 03 * ZZ * OLD_PASSWORD * NEW_PASSWORD * NEW_PASSWORD #
|
|
||||||
// - ** 03 * ZZ * OLD_PASSWORD * NEW_PASSWORD * NEW_PASSWORD #
|
|
||||||
// - * 03 ** OLD_PASSWORD * NEW_PASSWORD * NEW_PASSWORD #
|
|
||||||
// - ** 03 ** OLD_PASSWORD * NEW_PASSWORD * NEW_PASSWORD #
|
|
||||||
let si = "\\*([^*#]*)";
|
|
||||||
let allSi = "";
|
|
||||||
for (let i = 0; i < 4; ++i) {
|
|
||||||
allSi = "(?:" + si + allSi + ")?";
|
|
||||||
}
|
|
||||||
|
|
||||||
let fullmmi = "(" + procedure + serviceCode + allSi + "#)";
|
|
||||||
|
|
||||||
// dial string after the #.
|
|
||||||
let dialString = "([^#]*)";
|
|
||||||
|
|
||||||
return new RegExp(fullmmi + dialString);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provide the regex to parse MMI string.
|
|
||||||
*/
|
|
||||||
_getMMIRegExp: function() {
|
|
||||||
if (!this._mmiRegExp) {
|
|
||||||
this._mmiRegExp = this._buildMMIRegExp();
|
|
||||||
}
|
|
||||||
|
|
||||||
return this._mmiRegExp;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper to parse # string. TS.22.030 Figure 3.5.3.2.
|
|
||||||
*/
|
|
||||||
_isPoundString: function(mmiString) {
|
|
||||||
return (mmiString.charAt(mmiString.length - 1) === MMI_END_OF_USSD);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper to parse short string. TS.22.030 Figure 3.5.3.2.
|
|
||||||
*/
|
|
||||||
_isMMIShortString: function(mmiString) {
|
|
||||||
if (mmiString.length > 2) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Should take care of checking if the string is an emergency number
|
|
||||||
// in Bug 889737. See Bug 1023141 for more background.
|
|
||||||
|
|
||||||
// In a call case.
|
|
||||||
if (Object.getOwnPropertyNames(this.currentCalls).length > 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Input string is 2 digits starting with a "1"
|
|
||||||
if ((mmiString.length == 2) && (mmiString.charAt(0) === '1')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
_serviceCodeToKeyString: function(serviceCode) {
|
|
||||||
switch (serviceCode) {
|
|
||||||
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;
|
|
||||||
default:
|
|
||||||
return MMI_KS_SC_USSD;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
sendMMI: function(options) {
|
sendMMI: function(options) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
this.context.debug("SendMMI " + JSON.stringify(options));
|
this.context.debug("SendMMI " + JSON.stringify(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mmi = this._parseMMI(options.mmi);
|
|
||||||
if (DEBUG) {
|
|
||||||
this.context.debug("MMI " + JSON.stringify(mmi));
|
|
||||||
}
|
|
||||||
|
|
||||||
let _sendMMIError = (function(errorMsg) {
|
let _sendMMIError = (function(errorMsg) {
|
||||||
options.success = false;
|
options.success = false;
|
||||||
options.errorMsg = errorMsg;
|
options.errorMsg = errorMsg;
|
||||||
@ -2611,14 +2400,12 @@ RilObject.prototype = {
|
|||||||
}).bind(this);
|
}).bind(this);
|
||||||
|
|
||||||
// It's neither a valid mmi code nor an ongoing ussd.
|
// It's neither a valid mmi code nor an ongoing ussd.
|
||||||
|
let mmi = options.mmi;
|
||||||
if (!mmi && !this._ussdSession) {
|
if (!mmi && !this._ussdSession) {
|
||||||
_sendMMIError(MMI_ERROR_KS_ERROR);
|
_sendMMIError(MMI_ERROR_KS_ERROR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
options.mmiServiceCode = mmi ?
|
|
||||||
this._serviceCodeToKeyString(mmi.serviceCode) : MMI_KS_SC_USSD;
|
|
||||||
|
|
||||||
function _isValidPINPUKRequest() {
|
function _isValidPINPUKRequest() {
|
||||||
// The only allowed MMI procedure for ICC PIN, PIN2, PUK and PUK2 handling
|
// The only allowed MMI procedure for ICC PIN, PIN2, PUK and PUK2 handling
|
||||||
// is "Registration" (**).
|
// is "Registration" (**).
|
||||||
@ -3576,36 +3363,34 @@ RilObject.prototype = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mmiServiceCode = options.mmiServiceCode;
|
let serviceCode = options.mmi.serviceCode;
|
||||||
|
|
||||||
if (options.success) {
|
if (options.success) {
|
||||||
switch (mmiServiceCode) {
|
switch (serviceCode) {
|
||||||
case MMI_KS_SC_PIN:
|
case MMI_SC_PIN:
|
||||||
options.statusMessage = MMI_SM_KS_PIN_CHANGED;
|
options.statusMessage = MMI_SM_KS_PIN_CHANGED;
|
||||||
break;
|
break;
|
||||||
case MMI_KS_SC_PIN2:
|
case MMI_SC_PIN2:
|
||||||
options.statusMessage = MMI_SM_KS_PIN2_CHANGED;
|
options.statusMessage = MMI_SM_KS_PIN2_CHANGED;
|
||||||
break;
|
break;
|
||||||
case MMI_KS_SC_PUK:
|
case MMI_SC_PUK:
|
||||||
options.statusMessage = MMI_SM_KS_PIN_UNBLOCKED;
|
options.statusMessage = MMI_SM_KS_PIN_UNBLOCKED;
|
||||||
break;
|
break;
|
||||||
case MMI_KS_SC_PUK2:
|
case MMI_SC_PUK2:
|
||||||
options.statusMessage = MMI_SM_KS_PIN2_UNBLOCKED;
|
options.statusMessage = MMI_SM_KS_PIN2_UNBLOCKED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (options.retryCount <= 0) {
|
if (options.retryCount <= 0) {
|
||||||
if (mmiServiceCode === MMI_KS_SC_PUK) {
|
if (serviceCode === MMI_SC_PUK) {
|
||||||
options.errorMsg = MMI_ERROR_KS_SIM_BLOCKED;
|
options.errorMsg = MMI_ERROR_KS_SIM_BLOCKED;
|
||||||
} else if (mmiServiceCode === MMI_KS_SC_PIN) {
|
} else if (serviceCode === MMI_SC_PIN) {
|
||||||
options.errorMsg = MMI_ERROR_KS_NEEDS_PUK;
|
options.errorMsg = MMI_ERROR_KS_NEEDS_PUK;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (mmiServiceCode === MMI_KS_SC_PIN ||
|
if (serviceCode === MMI_SC_PIN || serviceCode === MMI_SC_PIN2) {
|
||||||
mmiServiceCode === MMI_KS_SC_PIN2) {
|
|
||||||
options.errorMsg = MMI_ERROR_KS_BAD_PIN;
|
options.errorMsg = MMI_ERROR_KS_BAD_PIN;
|
||||||
} else if (mmiServiceCode === MMI_KS_SC_PUK ||
|
} else if (serviceCode === MMI_SC_PUK || serviceCode === MMI_SC_PUK2) {
|
||||||
mmiServiceCode === MMI_KS_SC_PUK2) {
|
|
||||||
options.errorMsg = MMI_ERROR_KS_BAD_PUK;
|
options.errorMsg = MMI_ERROR_KS_BAD_PUK;
|
||||||
}
|
}
|
||||||
if (options.retryCount !== undefined) {
|
if (options.retryCount !== undefined) {
|
||||||
@ -6030,7 +5815,7 @@ RilObject.prototype[REQUEST_QUERY_CALL_FORWARD_STATUS] =
|
|||||||
this.sendChromeMessage(options);
|
this.sendChromeMessage(options);
|
||||||
};
|
};
|
||||||
RilObject.prototype[REQUEST_SET_CALL_FORWARD] =
|
RilObject.prototype[REQUEST_SET_CALL_FORWARD] =
|
||||||
function REQUEST_SET_CALL_FORWARD(length, options) {
|
function REQUEST_SET_CALL_FORWARD(length, options) {
|
||||||
options.success = (options.rilRequestError === 0);
|
options.success = (options.rilRequestError === 0);
|
||||||
if (!options.success) {
|
if (!options.success) {
|
||||||
options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
|
options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
|
||||||
|
@ -54,6 +54,16 @@ const AUDIO_STATE_NAME = [
|
|||||||
|
|
||||||
const DEFAULT_EMERGENCY_NUMBERS = ["112", "911"];
|
const DEFAULT_EMERGENCY_NUMBERS = ["112", "911"];
|
||||||
|
|
||||||
|
// MMI match groups
|
||||||
|
const MMI_MATCH_GROUP_FULL_MMI = 1;
|
||||||
|
const MMI_MATCH_GROUP_PROCEDURE = 2;
|
||||||
|
const MMI_MATCH_GROUP_SERVICE_CODE = 3;
|
||||||
|
const MMI_MATCH_GROUP_SIA = 4;
|
||||||
|
const MMI_MATCH_GROUP_SIB = 5;
|
||||||
|
const MMI_MATCH_GROUP_SIC = 6;
|
||||||
|
const MMI_MATCH_GROUP_PWD_CONFIRM = 7;
|
||||||
|
const MMI_MATCH_GROUP_DIALING_NUMBER = 8;
|
||||||
|
|
||||||
let DEBUG;
|
let DEBUG;
|
||||||
function debug(s) {
|
function debug(s) {
|
||||||
dump("TelephonyService: " + s + "\n");
|
dump("TelephonyService: " + s + "\n");
|
||||||
@ -99,15 +109,52 @@ XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger",
|
|||||||
"@mozilla.org/system-message-internal;1",
|
"@mozilla.org/system-message-internal;1",
|
||||||
"nsISystemMessagesInternal");
|
"nsISystemMessagesInternal");
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyServiceGetter(this, "gGonkMobileConnectionService",
|
||||||
|
"@mozilla.org/mobileconnection/mobileconnectionservice;1",
|
||||||
|
"nsIGonkMobileConnectionService");
|
||||||
|
|
||||||
XPCOMUtils.defineLazyGetter(this, "gPhoneNumberUtils", function() {
|
XPCOMUtils.defineLazyGetter(this, "gPhoneNumberUtils", function() {
|
||||||
let ns = {};
|
let ns = {};
|
||||||
Cu.import("resource://gre/modules/PhoneNumberUtils.jsm", ns);
|
Cu.import("resource://gre/modules/PhoneNumberUtils.jsm", ns);
|
||||||
return ns.PhoneNumberUtils;
|
return ns.PhoneNumberUtils;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function MMIResult(aMmiServiceCode, aOptions) {
|
||||||
|
this.serviceCode = aMmiServiceCode;
|
||||||
|
this.statusMessage = aOptions.statusMessage;
|
||||||
|
this.additionalInformation = aOptions.additionalInformation;
|
||||||
|
}
|
||||||
|
MMIResult.prototype = {
|
||||||
|
__exposedProps__ : {serviceCode: 'r',
|
||||||
|
statusMessage: 'r',
|
||||||
|
additionalInformation: 'r'},
|
||||||
|
};
|
||||||
|
|
||||||
|
function CallForwardingOptions(aOptions) {
|
||||||
|
this.active = aOptions.active;
|
||||||
|
this.action = aOptions.action;
|
||||||
|
this.reason = aOptions.reason;
|
||||||
|
this.number = aOptions.number;
|
||||||
|
this.timeSeconds = aOptions.timeSeconds;
|
||||||
|
this.serviceClass = aOptions.serviceClass;
|
||||||
|
}
|
||||||
|
CallForwardingOptions.prototype = {
|
||||||
|
__exposedProps__ : {active: 'r',
|
||||||
|
action: 'r',
|
||||||
|
reason: 'r',
|
||||||
|
number: 'r',
|
||||||
|
timeSeconds: 'r',
|
||||||
|
serviceClass: 'r'},
|
||||||
|
};
|
||||||
|
|
||||||
function TelephonyService() {
|
function TelephonyService() {
|
||||||
this._numClients = gRadioInterfaceLayer.numRadioInterfaces;
|
this._numClients = gRadioInterfaceLayer.numRadioInterfaces;
|
||||||
this._listeners = [];
|
this._listeners = [];
|
||||||
|
|
||||||
|
this._mmiRegExp = null;
|
||||||
|
|
||||||
|
this._isDialing = false;
|
||||||
|
this._cachedDialRequest = null;
|
||||||
this._currentCalls = {};
|
this._currentCalls = {};
|
||||||
|
|
||||||
this._cdmaCallWaitingNumber = null;
|
this._cdmaCallWaitingNumber = null;
|
||||||
@ -300,6 +347,10 @@ TelephonyService.prototype = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_rulesToCallForwardingOptions: function(aRules) {
|
||||||
|
return aRules.map(rule => new CallForwardingOptions(rule));
|
||||||
|
},
|
||||||
|
|
||||||
_updateDebugFlag: function() {
|
_updateDebugFlag: function() {
|
||||||
try {
|
try {
|
||||||
DEBUG = RIL.DEBUG_RIL ||
|
DEBUG = RIL.DEBUG_RIL ||
|
||||||
@ -499,36 +550,51 @@ TelephonyService.prototype = {
|
|||||||
this.notifyCallStateChanged(aClientId, parentCall);
|
this.notifyCallStateChanged(aClientId, parentCall);
|
||||||
},
|
},
|
||||||
|
|
||||||
_composeDialRequest: function(aClientId, aNumber) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this._sendToRilWorker(aClientId, "parseMMIFromDialNumber",
|
|
||||||
{number: aNumber}, response => {
|
|
||||||
let options = {};
|
|
||||||
let mmi = response.mmi;
|
|
||||||
|
|
||||||
if (!mmi) {
|
|
||||||
resolve({
|
|
||||||
number: aNumber
|
|
||||||
});
|
|
||||||
} else if (this._isTemporaryCLIR(mmi)) {
|
|
||||||
resolve({
|
|
||||||
number: mmi.dialNumber,
|
|
||||||
clirMode: this._getTemporaryCLIRMode(mmi.procedure)
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
reject(DIAL_ERROR_BAD_NUMBER);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
cachedDialRequest: null,
|
|
||||||
isDialing: false,
|
|
||||||
|
|
||||||
dial: function(aClientId, aNumber, aIsDialEmergency, aCallback) {
|
dial: function(aClientId, aNumber, aIsDialEmergency, aCallback) {
|
||||||
if (DEBUG) debug("Dialing " + (aIsDialEmergency ? "emergency " : "") + aNumber);
|
if (DEBUG) debug("Dialing " + (aIsDialEmergency ? "emergency " : "") + aNumber);
|
||||||
|
|
||||||
if (this.isDialing) {
|
// We don't try to be too clever here, as the phone is probably in the
|
||||||
|
// locked state. Let's just check if it's a number without normalizing
|
||||||
|
if (!aIsDialEmergency) {
|
||||||
|
aNumber = gPhoneNumberUtils.normalize(aNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate the number.
|
||||||
|
// Note: isPlainPhoneNumber also accepts USSD and SS numbers
|
||||||
|
if (!gPhoneNumberUtils.isPlainPhoneNumber(aNumber)) {
|
||||||
|
if (DEBUG) debug("Error: Number '" + aNumber + "' is not viable. Drop.");
|
||||||
|
aCallback.notifyDialError(DIAL_ERROR_BAD_NUMBER);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mmi = this._parseMMI(aClientId, aNumber);
|
||||||
|
if (!mmi) {
|
||||||
|
this._dialCall(aClientId,
|
||||||
|
{ number: aNumber,
|
||||||
|
isDialEmergency: aIsDialEmergency }, aCallback);
|
||||||
|
} else if (this._isTemporaryCLIR(mmi)) {
|
||||||
|
this._dialCall(aClientId,
|
||||||
|
{ number: mmi.dialNumber,
|
||||||
|
clirMode: this._getTemporaryCLIRMode(mmi.procedure),
|
||||||
|
isDialEmergency: aIsDialEmergency }, aCallback);
|
||||||
|
} else {
|
||||||
|
// Reject MMI code from dialEmergency api.
|
||||||
|
if (aIsDialEmergency) {
|
||||||
|
aCallback.notifyDialError(DIAL_ERROR_BAD_NUMBER);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._dialMMI(aClientId, mmi, aCallback);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param aOptions.number
|
||||||
|
* @param aOptions.clirMode (optional)
|
||||||
|
* @param aOptions.isDialEmergency
|
||||||
|
*/
|
||||||
|
_dialCall: function(aClientId, aOptions, aCallback) {
|
||||||
|
if (this._isDialing) {
|
||||||
if (DEBUG) debug("Error: Already has a dialing call.");
|
if (DEBUG) debug("Error: Already has a dialing call.");
|
||||||
aCallback.notifyDialError(DIAL_ERROR_INVALID_STATE_ERROR);
|
aCallback.notifyDialError(DIAL_ERROR_INVALID_STATE_ERROR);
|
||||||
return;
|
return;
|
||||||
@ -549,63 +615,43 @@ TelephonyService.prototype = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't try to be too clever here, as the phone is probably in the
|
aOptions.isEmergency = this._isEmergencyNumber(aOptions.number);
|
||||||
// locked state. Let's just check if it's a number without normalizing
|
if (aOptions.isEmergency) {
|
||||||
if (!aIsDialEmergency) {
|
// Automatically select a proper clientId for emergency call.
|
||||||
aNumber = gPhoneNumberUtils.normalize(aNumber);
|
aClientId = gRadioInterfaceLayer.getClientIdForEmergencyCall() ;
|
||||||
}
|
if (aClientId === -1) {
|
||||||
|
if (DEBUG) debug("Error: No client is avaialble for emergency call.");
|
||||||
// Validate the number.
|
aCallback.notifyDialError(DIAL_ERROR_INVALID_STATE_ERROR);
|
||||||
// Note: isPlainPhoneNumber also accepts USSD and SS numbers
|
return;
|
||||||
if (!gPhoneNumberUtils.isPlainPhoneNumber(aNumber)) {
|
|
||||||
if (DEBUG) debug("Error: Number '" + aNumber + "' is not viable. Drop.");
|
|
||||||
aCallback.notifyDialError(DIAL_ERROR_BAD_NUMBER);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._composeDialRequest(aClientId, aNumber).then(options => {
|
|
||||||
options.isEmergency = this._isEmergencyNumber(options.number);
|
|
||||||
options.isDialEmergency = aIsDialEmergency;
|
|
||||||
|
|
||||||
if (options.isEmergency) {
|
|
||||||
// Automatically select a proper clientId for emergency call.
|
|
||||||
aClientId = gRadioInterfaceLayer.getClientIdForEmergencyCall() ;
|
|
||||||
if (aClientId === -1) {
|
|
||||||
if (DEBUG) debug("Error: No client is avaialble for emergency call.");
|
|
||||||
aCallback.notifyDialError(DIAL_ERROR_INVALID_STATE_ERROR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Before we dial, we have to hold the active call first.
|
// Before we dial, we have to hold the active call first.
|
||||||
let activeCall = this._getOneActiveCall(aClientId);
|
let activeCall = this._getOneActiveCall(aClientId);
|
||||||
if (!activeCall) {
|
if (!activeCall) {
|
||||||
this._dialInternal(aClientId, options, aCallback);
|
this._sendDialCallRequest(aClientId, aOptions, aCallback);
|
||||||
|
} else {
|
||||||
|
if (DEBUG) debug("There is an active call. Hold it first before dial.");
|
||||||
|
|
||||||
|
this._cachedDialRequest = {
|
||||||
|
clientId: aClientId,
|
||||||
|
options: aOptions,
|
||||||
|
callback: aCallback
|
||||||
|
};
|
||||||
|
|
||||||
|
if (activeCall.isConference) {
|
||||||
|
this.holdConference(aClientId);
|
||||||
} else {
|
} else {
|
||||||
if (DEBUG) debug("There is an active call. Hold it first before dial.");
|
this.holdCall(aClientId, activeCall.callIndex);
|
||||||
|
|
||||||
this.cachedDialRequest = {
|
|
||||||
clientId: aClientId,
|
|
||||||
options: options,
|
|
||||||
callback: aCallback
|
|
||||||
};
|
|
||||||
|
|
||||||
if (activeCall.isConference) {
|
|
||||||
this.holdConference(aClientId);
|
|
||||||
} else {
|
|
||||||
this.holdCall(aClientId, activeCall.callIndex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, cause => {
|
}
|
||||||
aCallback.notifyDialError(DIAL_ERROR_BAD_NUMBER);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_dialInternal: function(aClientId, aOptions, aCallback) {
|
_sendDialCallRequest: function(aClientId, aOptions, aCallback) {
|
||||||
this.isDialing = true;
|
this._isDialing = true;
|
||||||
|
|
||||||
this._sendToRilWorker(aClientId, "dial", aOptions, response => {
|
this._sendToRilWorker(aClientId, "dial", aOptions, response => {
|
||||||
this.isDialing = false;
|
this._isDialing = false;
|
||||||
|
|
||||||
if (!response.success) {
|
if (!response.success) {
|
||||||
aCallback.notifyDialError(response.errorMsg);
|
aCallback.notifyDialError(response.errorMsg);
|
||||||
@ -625,6 +671,235 @@ TelephonyService.prototype = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param aMmi
|
||||||
|
* Parsed MMI structure.
|
||||||
|
*/
|
||||||
|
_dialMMI: function(aClientId, aMmi, aCallback) {
|
||||||
|
let mmiServiceCode = aMmi ?
|
||||||
|
this._serviceCodeToKeyString(aMmi.serviceCode) : RIL.MMI_KS_SC_USSD;
|
||||||
|
|
||||||
|
aCallback.notifyDialMMI(mmiServiceCode);
|
||||||
|
|
||||||
|
this._sendToRilWorker(aClientId, "sendMMI", { mmi: aMmi }, response => {
|
||||||
|
if (DEBUG) debug("MMI response: " + JSON.stringify(response));
|
||||||
|
|
||||||
|
if (!response.success) {
|
||||||
|
if (response.additionalInformation != null) {
|
||||||
|
aCallback.notifyDialMMIErrorWithInfo(response.errorMsg,
|
||||||
|
response.additionalInformation);
|
||||||
|
} else {
|
||||||
|
aCallback.notifyDialMMIError(response.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) {
|
||||||
|
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) {
|
||||||
|
response.additionalInformation =
|
||||||
|
this._rulesToCallForwardingOptions(response.additionalInformation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = new MMIResult(mmiServiceCode, response);
|
||||||
|
aCallback.notifyDialMMISuccess(result);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the regex to parse MMI string. TS.22.030
|
||||||
|
*
|
||||||
|
* The resulting groups after matching will be:
|
||||||
|
* 1 = full MMI string that might be used as a USSD request.
|
||||||
|
* 2 = MMI procedure.
|
||||||
|
* 3 = Service code.
|
||||||
|
* 4 = SIA.
|
||||||
|
* 5 = SIB.
|
||||||
|
* 6 = SIC.
|
||||||
|
* 7 = Password registration.
|
||||||
|
* 8 = Dialing number.
|
||||||
|
*/
|
||||||
|
_buildMMIRegExp: function() {
|
||||||
|
// The general structure of the codes is as follows:
|
||||||
|
// - Activation (*SC*SI#).
|
||||||
|
// - Deactivation (#SC*SI#).
|
||||||
|
// - Interrogation (*#SC*SI#).
|
||||||
|
// - Registration (**SC*SI#).
|
||||||
|
// - Erasure (##SC*SI#).
|
||||||
|
//
|
||||||
|
// where SC = Service Code (2 or 3 digits) and SI = Supplementary Info
|
||||||
|
// (variable length).
|
||||||
|
|
||||||
|
// Procedure, which could be *, #, *#, **, ##
|
||||||
|
let procedure = "(\\*[*#]?|##?)";
|
||||||
|
|
||||||
|
// Service code, which is a 2 or 3 digits that uniquely specifies the
|
||||||
|
// Supplementary Service associated with the MMI code.
|
||||||
|
let serviceCode = "(\\d{2,3})";
|
||||||
|
|
||||||
|
// Supplementary Information SIA, SIB and SIC. SIA may comprise e.g. a PIN
|
||||||
|
// code or Directory Number, SIB may be used to specify the tele or bearer
|
||||||
|
// service and SIC to specify the value of the "No Reply Condition Timer".
|
||||||
|
// Where a particular service request does not require any SI, "*SI" is
|
||||||
|
// not entered. The use of SIA, SIB and SIC is optional and shall be
|
||||||
|
// entered in any of the following formats:
|
||||||
|
// - *SIA*SIB*SIC#
|
||||||
|
// - *SIA*SIB#
|
||||||
|
// - *SIA**SIC#
|
||||||
|
// - *SIA#
|
||||||
|
// - **SIB*SIC#
|
||||||
|
// - ***SIC#
|
||||||
|
//
|
||||||
|
// Also catch the additional NEW_PASSWORD for the case of a password
|
||||||
|
// registration procedure. Ex:
|
||||||
|
// - * 03 * ZZ * OLD_PASSWORD * NEW_PASSWORD * NEW_PASSWORD #
|
||||||
|
// - ** 03 * ZZ * OLD_PASSWORD * NEW_PASSWORD * NEW_PASSWORD #
|
||||||
|
// - * 03 ** OLD_PASSWORD * NEW_PASSWORD * NEW_PASSWORD #
|
||||||
|
// - ** 03 ** OLD_PASSWORD * NEW_PASSWORD * NEW_PASSWORD #
|
||||||
|
let si = "\\*([^*#]*)";
|
||||||
|
let allSi = "";
|
||||||
|
for (let i = 0; i < 4; ++i) {
|
||||||
|
allSi = "(?:" + si + allSi + ")?";
|
||||||
|
}
|
||||||
|
|
||||||
|
let fullmmi = "(" + procedure + serviceCode + allSi + "#)";
|
||||||
|
|
||||||
|
// Dial string after the #.
|
||||||
|
let dialString = "([^#]*)";
|
||||||
|
|
||||||
|
return new RegExp(fullmmi + dialString);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide the regex to parse MMI string.
|
||||||
|
*/
|
||||||
|
_getMMIRegExp: function() {
|
||||||
|
if (!this._mmiRegExp) {
|
||||||
|
this._mmiRegExp = this._buildMMIRegExp();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._mmiRegExp;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to parse # string. TS.22.030 Figure 3.5.3.2.
|
||||||
|
*/
|
||||||
|
_isPoundString: function(aMmiString) {
|
||||||
|
return (aMmiString.charAt(aMmiString.length - 1) === "#");
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to parse short string. TS.22.030 Figure 3.5.3.2.
|
||||||
|
*/
|
||||||
|
_isShortString: function(aClientId, aMmiString) {
|
||||||
|
if (aMmiString.length > 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In a call case.
|
||||||
|
if (Object.getOwnPropertyNames(this._currentCalls[aClientId]).length > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input string is
|
||||||
|
// - emergency number or
|
||||||
|
// - 2 digits starting with a "1"
|
||||||
|
if (this._isEmergencyNumber(aMmiString) ||
|
||||||
|
(aMmiString.length == 2) && (aMmiString.charAt(0) === '1')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to parse MMI/USSD string. TS.22.030 Figure 3.5.3.2.
|
||||||
|
*/
|
||||||
|
_parseMMI: function(aClientId, aMmiString) {
|
||||||
|
let matches = this._getMMIRegExp().exec(aMmiString);
|
||||||
|
if (matches) {
|
||||||
|
return {
|
||||||
|
fullMMI: matches[MMI_MATCH_GROUP_FULL_MMI],
|
||||||
|
procedure: matches[MMI_MATCH_GROUP_PROCEDURE],
|
||||||
|
serviceCode: matches[MMI_MATCH_GROUP_SERVICE_CODE],
|
||||||
|
sia: matches[MMI_MATCH_GROUP_SIA],
|
||||||
|
sib: matches[MMI_MATCH_GROUP_SIB],
|
||||||
|
sic: matches[MMI_MATCH_GROUP_SIC],
|
||||||
|
pwd: matches[MMI_MATCH_GROUP_PWD_CONFIRM],
|
||||||
|
dialNumber: matches[MMI_MATCH_GROUP_DIALING_NUMBER]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._isPoundString(aMmiString) ||
|
||||||
|
this._isShortString(aClientId, aMmiString)) {
|
||||||
|
return {
|
||||||
|
fullMMI: aMmiString
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
|
_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;
|
||||||
|
default:
|
||||||
|
return RIL.MMI_KS_SC_USSD;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
hangUp: function(aClientId, aCallIndex) {
|
hangUp: function(aClientId, aCallIndex) {
|
||||||
let parentId = this._currentCalls[aClientId][aCallIndex].parentId;
|
let parentId = this._currentCalls[aClientId][aCallIndex].parentId;
|
||||||
if (parentId) {
|
if (parentId) {
|
||||||
@ -932,12 +1207,12 @@ TelephonyService.prototype = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle cached dial request.
|
// Handle cached dial request.
|
||||||
if (this.cachedDialRequest && !this._getOneActiveCall()) {
|
if (this._cachedDialRequest && !this._getOneActiveCall()) {
|
||||||
if (DEBUG) debug("All calls held. Perform the cached dial request.");
|
if (DEBUG) debug("All calls held. Perform the cached dial request.");
|
||||||
|
|
||||||
let request = this.cachedDialRequest;
|
let request = this._cachedDialRequest;
|
||||||
this._dialInternal(request.clientId, request.options, request.callback);
|
this._sendDialCallRequest(request.clientId, request.options, request.callback);
|
||||||
this.cachedDialRequest = null;
|
this._cachedDialRequest = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._notifyAllListeners("callStateChanged", [aClientId,
|
this._notifyAllListeners("callStateChanged", [aClientId,
|
||||||
@ -987,6 +1262,11 @@ TelephonyService.prototype = {
|
|||||||
this._notifyAllListeners("conferenceCallStateChanged", [aState]);
|
this._notifyAllListeners("conferenceCallStateChanged", [aState]);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
dialMMI: function(aClientId, aMmiString, aCallback) {
|
||||||
|
let mmi = this._parseMMI(aClientId, aMmiString);
|
||||||
|
this._dialMMI(aClientId, mmi, aCallback);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nsIObserver interface.
|
* nsIObserver interface.
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user