From 48960dace815887b4c9175a195d7901d8e765c71 Mon Sep 17 00:00:00 2001 From: "Szu-Yu Chen [:aknow]" Date: Fri, 23 Jan 2015 18:34:13 +0800 Subject: [PATCH] Bug 1123580 - Reorganize mmi parsing related code. r=hsinyi --- dom/telephony/gonk/DialNumberUtils.jsm | 128 +++++++++++++ dom/telephony/gonk/TelephonyService.js | 182 ++----------------- dom/telephony/moz.build | 3 + dom/telephony/test/xpcshell/test_parseMMI.js | 5 +- 4 files changed, 144 insertions(+), 174 deletions(-) create mode 100644 dom/telephony/gonk/DialNumberUtils.jsm diff --git a/dom/telephony/gonk/DialNumberUtils.jsm b/dom/telephony/gonk/DialNumberUtils.jsm new file mode 100644 index 000000000000..7fd15163da9f --- /dev/null +++ b/dom/telephony/gonk/DialNumberUtils.jsm @@ -0,0 +1,128 @@ +/* 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/. */ + +"use strict"; + +this.EXPORTED_SYMBOLS = ["DialNumberUtils"]; + +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; + +Cu.import("resource://gre/modules/systemlibs.js"); + +const DEFAULT_EMERGENCY_NUMBERS = ["112", "911"]; + +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; + +this.DialNumberUtils = { + /** + * Check a given number against the list of emergency numbers provided by the + * RIL. + */ + isEmergency: function(aNumber) { + // Check ril provided numbers first. + let numbers = libcutils.property_get("ril.ecclist") || + libcutils.property_get("ro.ril.ecclist"); + if (numbers) { + numbers = numbers.split(","); + } else { + // No ecclist system property, so use our own list. + numbers = DEFAULT_EMERGENCY_NUMBERS; + } + return numbers.indexOf(aNumber) != -1; + }, + + _mmiRegExp: (function() { + // 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. + // 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 optionalDialString = "([^#]+)?"; + + return new RegExp("^" + fullmmi + optionalDialString + "$"); + })(), + + _isPoundString: function(aString) { + return aString && aString[aString.length - 1] === "#"; + }, + + _isShortString: function(aString) { + if (!aString || this.isEmergency(aString) || aString.length > 2 || + (aString.length == 2 && aString[0] === "1")) { + return false; + } + return true; + }, + + /** + * Check parse the given string as an MMI code. + * + * An MMI code should be: + * - 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). + */ + parseMMI: function(aString) { + let matches = this._mmiRegExp.exec(aString); + 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(aString) || this._isShortString(aString)) { + return { + fullMMI: aString + }; + } + + return null; + } +}; diff --git a/dom/telephony/gonk/TelephonyService.js b/dom/telephony/gonk/TelephonyService.js index 1e62af845a92..acc46231f024 100644 --- a/dom/telephony/gonk/TelephonyService.js +++ b/dom/telephony/gonk/TelephonyService.js @@ -10,7 +10,6 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/Promise.jsm"); -Cu.import("resource://gre/modules/systemlibs.js"); XPCOMUtils.defineLazyGetter(this, "RIL", function () { let obj = {}; @@ -48,20 +47,9 @@ const DIAL_ERROR_INVALID_STATE_ERROR = "InvalidStateError"; const DIAL_ERROR_OTHER_CONNECTION_IN_USE = "OtherConnectionInUse"; const DIAL_ERROR_BAD_NUMBER = RIL.GECKO_CALL_ERROR_BAD_NUMBER; -const DEFAULT_EMERGENCY_NUMBERS = ["112", "911"]; const TONES_GAP_DURATION = 70; -// 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; function debug(s) { dump("TelephonyService: " + s + "\n"); @@ -93,6 +81,12 @@ XPCOMUtils.defineLazyGetter(this, "gPhoneNumberUtils", function() { return ns.PhoneNumberUtils; }); +XPCOMUtils.defineLazyGetter(this, "gDialNumberUtils", function() { + let ns = {}; + Cu.import("resource://gre/modules/DialNumberUtils.jsm", ns); + return ns.DialNumberUtils; +}); + function MobileCallForwardingOptions(aOptions) { for (let key in aOptions) { this[key] = aOptions[key]; @@ -160,8 +154,6 @@ function TelephonyService() { this._numClients = gRadioInterfaceLayer.numRadioInterfaces; this._listeners = []; - this._mmiRegExp = null; - this._isDialing = false; this._cachedDialRequest = null; this._currentCalls = {}; @@ -343,26 +335,6 @@ TelephonyService.prototype = { }); }, - /** - * Check a given number against the list of emergency numbers provided by the - * RIL. - * - * @param aNumber - * The number to look up. - */ - _isEmergencyNumber: function(aNumber) { - // Check ril provided numbers first. - let numbers = libcutils.property_get("ril.ecclist") || - libcutils.property_get("ro.ril.ecclist"); - if (numbers) { - numbers = numbers.split(","); - } else { - // No ecclist system property, so use our own list. - numbers = DEFAULT_EMERGENCY_NUMBERS; - } - return numbers.indexOf(aNumber) != -1; - }, - /** * Checks whether to temporarily suppress caller id for the call. * @@ -553,7 +525,7 @@ TelephonyService.prototype = { isDialEmergency: aIsDialEmergency }, aCallback); } } else { - let mmi = this._parseMMI(aNumber); + let mmi = gDialNumberUtils.parseMMI(aNumber); if (!mmi) { this._dialCall(aClientId, { number: aNumber, @@ -602,7 +574,7 @@ TelephonyService.prototype = { return; } - aOptions.isEmergency = this._isEmergencyNumber(aOptions.number); + aOptions.isEmergency = gDialNumberUtils.isEmergency(aOptions.number); if (aOptions.isEmergency) { // Automatically select a proper clientId for emergency call. aClientId = gRadioInterfaceLayer.getClientIdForEmergencyCall() ; @@ -750,138 +722,6 @@ TelephonyService.prototype = { }); }, - /** - * 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 optionalDialString = "([^#]+)?"; - - return new RegExp("^" + fullmmi + optionalDialString + "$"); - }, - - /** - * 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(aMmiString) { - if (aMmiString.length > 2) { - return false; - } - - // 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(aMmiString) { - if (!aMmiString) { - return null; - } - - 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(aMmiString)) { - return { - fullMMI: aMmiString - }; - } - - return null; - }, - _serviceCodeToKeyString: function(aServiceCode) { switch (aServiceCode) { case RIL.MMI_SC_CFU: @@ -1178,7 +1018,7 @@ TelephonyService.prototype = { aCall.clientId = aClientId; aCall.state = nsITelephonyService.CALL_STATE_DISCONNECTED; - aCall.isEmergency = this._isEmergencyNumber(aCall.number); + aCall.isEmergency = gDialNumberUtils.isEmergency(aCall.number); let duration = ("started" in aCall && typeof aCall.started == "number") ? new Date().getTime() - aCall.started : 0; @@ -1273,12 +1113,12 @@ TelephonyService.prototype = { call.state = aCall.state; call.number = aCall.number; call.isConference = aCall.isConference; - call.isEmergency = this._isEmergencyNumber(aCall.number); + call.isEmergency = gDialNumberUtils.isEmergency(aCall.number); call.isSwitchable = pick(aCall.isSwitchable, call.isSwitchable); call.isMergeable = pick(aCall.isMergeable, call.isMergeable); } else { call = aCall; - call.isEmergency = pick(aCall.isEmergency, this._isEmergencyNumber(aCall.number)); + call.isEmergency = pick(aCall.isEmergency, gDialNumberUtils.isEmergency(aCall.number)); call.isSwitchable = pick(aCall.isSwitchable, true); call.isMergeable = pick(aCall.isMergeable, true); call.name = pick(aCall.name, ""); diff --git a/dom/telephony/moz.build b/dom/telephony/moz.build index e2dbba00f6cb..f21b695446ac 100644 --- a/dom/telephony/moz.build +++ b/dom/telephony/moz.build @@ -66,6 +66,9 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and CONFIG['MOZ_B2G_RIL']: 'gonk/TelephonyService.js', 'gonk/TelephonyService.manifest', ] + EXTRA_JS_MODULES += [ + 'gonk/DialNumberUtils.jsm' + ] FAIL_ON_WARNINGS = True include('/ipc/chromium/chromium-config.mozbuild') diff --git a/dom/telephony/test/xpcshell/test_parseMMI.js b/dom/telephony/test/xpcshell/test_parseMMI.js index 9ed9d08fa4a8..ca02a65d459a 100644 --- a/dom/telephony/test/xpcshell/test_parseMMI.js +++ b/dom/telephony/test/xpcshell/test_parseMMI.js @@ -4,15 +4,14 @@ subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); let NS = {}; -subscriptLoader.loadSubScript("resource://gre/components/TelephonyService.js", - NS); +subscriptLoader.loadSubScript("resource://gre/modules/DialNumberUtils.jsm", NS); function run_test() { run_next_test(); } function parseMMI(mmiString) { - return NS.TelephonyService.prototype._parseMMI(mmiString); + return NS.DialNumberUtils.parseMMI(mmiString); } add_test(function test_parseMMI_empty() {