diff --git a/b2g/installer/package-manifest.in b/b2g/installer/package-manifest.in index 42af31c5530..7f8cc6c1f8d 100644 --- a/b2g/installer/package-manifest.in +++ b/b2g/installer/package-manifest.in @@ -441,6 +441,8 @@ @BINPATH@/components/RILContentHelper.js @BINPATH@/components/TelephonyService.js @BINPATH@/components/TelephonyService.manifest +@BINPATH@/components/MobileConnectionGonkService.js +@BINPATH@/components/MobileConnectionGonkService.manifest #endif // MOZ_WIDGET_GONK && MOZ_B2G_RIL #ifndef MOZ_WIDGET_GONK diff --git a/dom/mobileconnection/gonk/MobileConnectionGonkService.js b/dom/mobileconnection/gonk/MobileConnectionGonkService.js new file mode 100644 index 00000000000..dcc54b046c4 --- /dev/null +++ b/dom/mobileconnection/gonk/MobileConnectionGonkService.js @@ -0,0 +1,1548 @@ +/* -*- Mode: js; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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"; + +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; + +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/systemlibs.js"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); + +var RIL = {}; +Cu.import("resource://gre/modules/ril_consts.js", RIL); + +const MOBILECONNECTIONGONKSERVICE_CONTRACTID = + "@mozilla.org/mobileconnection/mobileconnectiongonkservice;1"; + +const MOBILECONNECTIONGONKSERVICE_CID = + Components.ID("{05e20430-fe65-4984-8df9-a6a504b24a91}"); +const MOBILENETWORKINFO_CID = + Components.ID("{a6c8416c-09b4-46d1-bf29-6520d677d085}"); +const MOBILECELLINFO_CID = + Components.ID("{0635d9ab-997e-4cdf-84e7-c1883752dff3}"); + +const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown"; +const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed"; +const NS_NETWORK_ACTIVE_CHANGED_TOPIC_ID = "network-active-changed"; + +const kPrefRilDebuggingEnabled = "ril.debugging.enabled"; + +XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger", + "@mozilla.org/system-message-internal;1", + "nsISystemMessagesInternal"); + +XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager", + "@mozilla.org/network/manager;1", + "nsINetworkManager"); + +XPCOMUtils.defineLazyServiceGetter(this, "gRadioInterfaceLayer", + "@mozilla.org/ril;1", + "nsIRadioInterfaceLayer"); + +let DEBUG = RIL.DEBUG_RIL; +function debug(s) { + dump("MobileConnectionGonkService: " + s + "\n"); +} + +function MobileNetworkInfo() { + this.shortName = null; + this.longName = null; + this.mcc = null; + this.mnc = null; + this.stat = null; +} +MobileNetworkInfo.prototype = { + QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileNetworkInfo]), + classID: MOBILENETWORKINFO_CID, + classInfo: XPCOMUtils.generateCI({ + classID: MOBILENETWORKINFO_CID, + classDescription: "MobileNetworkInfo", + interfaces: [Ci.nsIMobileNetworkInfo] + }) +}; + +function MobileCellInfo() { + this.gsmLocationAreaCode = -1; + this.gsmCellId = -1; + this.cdmaBaseStationId = -1; + this.cdmaBaseStationLatitude = -2147483648; + this.cdmaBaseStationLongitude = -2147483648; + this.cdmaSystemId = -1; + this.cdmaNetworkId = -1; +} +MobileCellInfo.prototype = { + QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileCellInfo]), + classID: MOBILECELLINFO_CID, + classInfo: XPCOMUtils.generateCI({ + classID: MOBILECELLINFO_CID, + classDescription: "MobileCellInfo", + interfaces: [Ci.nsIMobileCellInfo] + }) +}; + +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 MMIResult(aOptions) { + this.serviceCode = aOptions.serviceCode; + this.statusMessage = aOptions.statusMessage; + this.additionalInformation = aOptions.additionalInformation; +} +MMIResult.prototype = { + __exposedProps__ : {serviceCode: 'r', + statusMessage: 'r', + additionalInformation: 'r'}, +}; + +function MobileConnectionProvider(aClientId, aRadioInterface) { + this._clientId = aClientId; + this._radioInterface = aRadioInterface; + this._operatorInfo = {}; + // An array of nsIMobileConnectionListener instances. + this._listeners = []; + + this.supportedNetworkTypes = this._getSupportedNetworkTypes(); + // These objects implement the nsIMobileConnectionInfo interface, + // although the actual implementation lives in the content process. So are + // the child attributes `network` and `cell`, which implement + // nsIMobileNetworkInfo and nsIMobileCellInfo respectively. + this.voiceInfo = {connected: false, + emergencyCallsOnly: false, + roaming: false, + network: null, + cell: null, + type: null, + signalStrength: null, + relSignalStrength: null}; + this.dataInfo = {connected: false, + emergencyCallsOnly: false, + roaming: false, + network: null, + cell: null, + type: null, + signalStrength: null, + relSignalStrength: null}; +} +MobileConnectionProvider.prototype = { + _clientId: null, + _radioInterface: null, + _operatorInfo: null, + _listeners: null, + + /** + * The networks that are currently trying to be selected (or "automatic"). + * This helps ensure that only one network per client is selected at a time. + */ + _selectingNetwork: null, + + voiceInfo: null, + dataInfo: null, + iccId: null, + networkSelectMode: null, + radioState: null, + lastKnownNetwork: null, + lastKnownHomeNetwork: null, + supportedNetworkTypes: null, + + /** + * A utility function to dump debug message. + */ + _debug: function(aMessage) { + dump("MobileConnectionProvider[" + this._clientId + "]: " + aMessage + "\n"); + }, + + /** + * A utility function to get supportedNetworkTypes from system property. + */ + _getSupportedNetworkTypes: function() { + let key = "ro.moz.ril." + this._clientId + ".network_types"; + let supportedNetworkTypes = libcutils.property_get(key, "").split(","); + for (let type of supportedNetworkTypes) { + // If the value in system property is not valid, use the default one which + // is defined in ril_consts.js. + if (RIL.GECKO_SUPPORTED_NETWORK_TYPES.indexOf(type) < 0) { + if (DEBUG) { + this._debug("Unknown network type: " + type); + } + supportedNetworkTypes = + RIL.GECKO_SUPPORTED_NETWORK_TYPES_DEFAULT.split(","); + break; + } + } + if (DEBUG) { + this._debug("Supported Network Types: " + supportedNetworkTypes); + } + return supportedNetworkTypes; + }, + + /** + * Helper for guarding us against invalid reason values for call forwarding. + */ + _isValidCallForwardingReason: function(aReason) { + switch (aReason) { + case Ci.nsIMobileConnectionService.CALL_FORWARD_REASON_UNCONDITIONAL: + case Ci.nsIMobileConnectionService.CALL_FORWARD_REASON_MOBILE_BUSY: + case Ci.nsIMobileConnectionService.CALL_FORWARD_REASON_NO_REPLY: + case Ci.nsIMobileConnectionService.CALL_FORWARD_REASON_NOT_REACHABLE: + case Ci.nsIMobileConnectionService.CALL_FORWARD_REASON_ALL_CALL_FORWARDING: + case Ci.nsIMobileConnectionService.CALL_FORWARD_REASON_ALL_CONDITIONAL_CALL_FORWARDING: + return true; + default: + return false; + } + }, + + /** + * Helper for guarding us against invalid action values for call forwarding. + */ + _isValidCallForwardingAction: function(aAction) { + switch (aAction) { + case Ci.nsIMobileConnectionService.CALL_FORWARD_ACTION_DISABLE: + case Ci.nsIMobileConnectionService.CALL_FORWARD_ACTION_ENABLE: + case Ci.nsIMobileConnectionService.CALL_FORWARD_ACTION_REGISTRATION: + case Ci.nsIMobileConnectionService.CALL_FORWARD_ACTION_ERASURE: + return true; + default: + return false; + } + }, + + /** + * Helper for guarding us against invalid program values for call barring. + */ + _isValidCallBarringProgram: function(aProgram) { + switch (aProgram) { + case Ci.nsIMobileConnectionService.CALL_BARRING_PROGRAM_ALL_OUTGOING: + case Ci.nsIMobileConnectionService.CALL_BARRING_PROGRAM_OUTGOING_INTERNATIONAL: + case Ci.nsIMobileConnectionService.CALL_BARRING_PROGRAM_OUTGOING_INTERNATIONAL_EXCEPT_HOME: + case Ci.nsIMobileConnectionService.CALL_BARRING_PROGRAM_ALL_INCOMING: + case Ci.nsIMobileConnectionService.CALL_BARRING_PROGRAM_INCOMING_ROAMING: + return true; + default: + return false; + } + }, + + /** + * Helper for guarding us against invalid options for call barring. + */ + _isValidCallBarringOptions: function(aOptions, aUsedForSetting) { + if (!aOptions || aOptions.serviceClass == null || + !this._isValidCallBarringProgram(aOptions.program)) { + return false; + } + + // For setting callbarring options, |enabled| and |password| are required. + if (aUsedForSetting && + (aOptions.enabled == null || aOptions.password == null)) { + return false; + } + + return true; + }, + + /** + * Helper for guarding us against invalid mode for clir. + */ + _isValidClirMode: function(aMode) { + switch (aMode) { + case Ci.nsIMobileConnectionService.CLIR_DEFAULT: + case Ci.nsIMobileConnectionService.CLIR_INVOCATION: + case Ci.nsIMobileConnectionService.CLIR_SUPPRESSION: + return true; + default: + return false; + } + }, + + /** + * Fix the roaming. RIL can report roaming in some case it is not + * really the case. See bug 787967 + */ + _checkRoamingBetweenOperators: function(aNetworkInfo) { + // TODO: Bug 864489 - B2G RIL: use ipdl as IPC in MozIccManager + // Should get iccInfo from IccGonkProvider. + let iccInfo = this._radioInterface.rilContext.iccInfo; + let operator = aNetworkInfo.network; + let state = aNetworkInfo.state; + + if (!iccInfo || !operator || + state !== RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED) { + return false; + } + + let spn = iccInfo.spn && iccInfo.spn.toLowerCase(); + let longName = operator.longName && operator.longName.toLowerCase(); + let shortName = operator.shortName && operator.shortName.toLowerCase(); + + let equalsLongName = longName && (spn == longName); + let equalsShortName = shortName && (spn == shortName); + let equalsMcc = iccInfo.mcc == operator.mcc; + + let newRoaming = aNetworkInfo.roaming && + !(equalsMcc && (equalsLongName || equalsShortName)); + if (newRoaming === aNetworkInfo.roaming) { + return false; + } + + aNetworkInfo.roaming = newRoaming; + return true; + }, + + _updateInfo: function(aDestInfo, aSrcInfo) { + let isUpdated = false; + for (let key in aSrcInfo) { + // For updating MobileConnectionInfo + if (key === "cell" && aSrcInfo.cell) { + if (!aDestInfo.cell) { + aDestInfo.cell = new MobileCellInfo(); + } + isUpdated = this._updateInfo(aDestInfo.cell, aSrcInfo.cell) || isUpdated; + } else if (aDestInfo[key] !== aSrcInfo[key]) { + isUpdated = true; + aDestInfo[key] = aSrcInfo[key]; + } + } + return isUpdated; + }, + + _rulesToCallForwardingOptions: function(aRules) { + for (let i = 0; i < aRules.length; i++) { + let info = new CallForwardingOptions(aRules[i]); + aRules[i] = info; + } + }, + + _dispatchNotifyError: function(aCallback, aErrorMsg) { + Services.tm.currentThread.dispatch(() => aCallback.notifyError(aErrorMsg), + Ci.nsIThread.DISPATCH_NORMAL); + }, + + registerListener: function(aListener) { + if (this._listeners.indexOf(aListener) >= 0) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + this._listeners.push(aListener); + }, + + unregisterListener: function(aListener) { + let index = this._listeners.indexOf(aListener); + if (index >= 0) { + this._listeners.splice(index, 1); + } + }, + + deliverListenerEvent: function(aName, aArgs) { + let listeners = this._listeners.slice(); + for (let listener of listeners) { + if (listeners.indexOf(listener) === -1) { + continue; + } + let handler = listener[aName]; + if (typeof handler != "function") { + throw new Error("No handler for " + aName); + } + try { + handler.apply(listener, aArgs); + } catch (e) { + if (DEBUG) { + this._debug("listener for " + aName + " threw an exception: " + e); + } + } + } + }, + + updateVoiceInfo: function(aNewInfo, aBatch = false) { + let isUpdated = this._updateInfo(this.voiceInfo, aNewInfo); + + // Make sure we also reset the operator and signal strength information + // if we drop off the network. + if (this.voiceInfo.state !== RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED) { + this.voiceInfo.cell = null; + this.voiceInfo.network = null; + this.voiceInfo.signalStrength = null; + this.voiceInfo.relSignalStrength = null; + } else { + this.voiceInfo.network = this._operatorInfo; + } + + // Check roaming state + isUpdated = this._checkRoamingBetweenOperators(this.voiceInfo) || isUpdated; + + if (isUpdated && !aBatch) { + this.deliverListenerEvent("notifyVoiceChanged"); + } + }, + + updateDataInfo: function(aNewInfo, aBatch = false) { + let isUpdated = false; + + // For the data connection, the `connected` flag indicates whether + // there's an active data call. We get correct `connected` state here. + let active = gNetworkManager.active; + aNewInfo.connected = false; + if (active && + active.type === Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE && + active.serviceId === this._clientId) { + aNewInfo.connected = true; + } + + isUpdated = this._updateInfo(this.dataInfo, aNewInfo); + + // Make sure we also reset the operator and signal strength information + // if we drop off the network. + if (this.dataInfo.state !== RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED) { + this.dataInfo.cell = null; + this.dataInfo.network = null; + this.dataInfo.signalStrength = null; + this.dataInfo.relSignalStrength = null; + } else { + this.dataInfo.network = this._operatorInfo; + } + + // Check roaming state + isUpdated = this._checkRoamingBetweenOperators(this.dataInfo) || isUpdated; + + if (isUpdated && !aBatch) { + this.deliverListenerEvent("notifyDataChanged"); + } + }, + + updateOperatorInfo: function(aNewInfo, aBatch = false) { + let isUpdated = this._updateInfo(this._operatorInfo, aNewInfo); + + // Update lastKnownNetwork + if (this._operatorInfo.mcc && this._operatorInfo.mnc) { + let network = this._operatorInfo.mcc + "-" + this._operatorInfo.mnc; + if (this.lastKnownNetwork !== network) { + if (DEBUG) { + this._debug("lastKnownNetwork now is " + network); + } + + this.lastKnownNetwork = network; + this.deliverListenerEvent("notifyLastKnownNetworkChanged"); + } + } + + // If the voice is unregistered, no need to send notification. + if (this.voiceInfo.state !== RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED && + isUpdated && !aBatch) { + this.deliverListenerEvent("notifyVoiceChanged"); + } + + // If the data is unregistered, no need to send notification. + if (this.dataInfo.state !== RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED && + isUpdated && !aBatch) { + this.deliverListenerEvent("notifyDataChanged"); + } + }, + + updateSignalInfo: function(aNewInfo, aBatch = false) { + // If the voice is not registered, no need to update signal information. + if (this.voiceInfo.state === RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED) { + if (this._updateInfo(this.voiceInfo, aNewInfo.voice) && !aBatch) { + this.deliverListenerEvent("notifyVoiceChanged"); + } + } + + // If the data is not registered, no need to update signal information. + if (this.dataInfo.state === RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED) { + if (this._updateInfo(this.dataInfo, aNewInfo.data) && !aBatch) { + this.deliverListenerEvent("notifyDataChanged"); + } + } + }, + + updateIccId: function(aIccId) { + if (this.iccId === aIccId) { + return; + } + + this.iccId = aIccId; + this.deliverListenerEvent("notifyIccChanged"); + }, + + updateRadioState: function(aRadioState) { + if (this.radioState === aRadioState) { + return; + } + + this.radioState = aRadioState; + this.deliverListenerEvent("notifyRadioStateChanged"); + }, + + getNetworks: function(aCallback) { + this._radioInterface.sendWorkerMessage("getAvailableNetworks", null, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + let networks = aResponse.networks; + for (let i = 0; i < networks.length; i++) { + let info = new MobileNetworkInfo(); + this._updateInfo(info, networks[i]); + networks[i] = info; + } + + aCallback.notifyGetNetworksSuccess(networks.length, networks); + return false; + }).bind(this)); + }, + + selectNetwork: function(aNetwork, aCallback) { + if (!aNetwork || + isNaN(parseInt(aNetwork.mcc, 10)) || + isNaN(parseInt(aNetwork.mnc, 10))) { + this._dispatchNotifyError(aCallback, RIL.GECKO_ERROR_INVALID_PARAMETER); + return; + } + + if (this._selectingNetwork) { + this._dispatchNotifyError(aCallback, "AlreadySelectingANetwork"); + return; + } + + let options = {mcc: aNetwork.mcc, mnc: aNetwork.mnc}; + this._selectingNetwork = options; + this._radioInterface.sendWorkerMessage("selectNetwork", options, + (function(aResponse) { + this._selectingNetwork = null; + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifySuccess(); + return false; + }).bind(this)); + }, + + selectNetworkAutomatically: function(aCallback) { + if (this._selectingNetwork) { + this._dispatchNotifyError(aCallback, "AlreadySelectingANetwork"); + return; + } + + this._selectingNetwork = "automatic"; + this._radioInterface.sendWorkerMessage("selectNetworkAuto", null, + (function(aResponse) { + this._selectingNetwork = null; + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifySuccess(); + return false; + }).bind(this)); + }, + + setPreferredNetworkType: function(aType, aCallback) { + if (this.radioState !== RIL.GECKO_RADIOSTATE_ENABLED) { + this._dispatchNotifyError(aCallback, RIL.GECKO_ERROR_RADIO_NOT_AVAILABLE); + return; + } + + this._radioInterface.sendWorkerMessage("setPreferredNetworkType", + {type: aType}, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifySuccess(); + return false; + }).bind(this)); + }, + + getPreferredNetworkType: function(aCallback) { + if (this.radioState !== RIL.GECKO_RADIOSTATE_ENABLED) { + this._dispatchNotifyError(aCallback, RIL.GECKO_ERROR_RADIO_NOT_AVAILABLE); + return; + } + + this._radioInterface.sendWorkerMessage("getPreferredNetworkType", null, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifySuccessWithString(aResponse.type); + return false; + }).bind(this)); + }, + + setRoamingPreference: function(aMode, aCallback) { + this._radioInterface.sendWorkerMessage("setRoamingPreference", + {mode: aMode}, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifySuccess(); + return false; + }).bind(this)); + }, + + getRoamingPreference: function(aCallback) { + this._radioInterface.sendWorkerMessage("queryRoamingPreference", null, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifySuccessWithString(aResponse.mode); + return false; + }).bind(this)); + }, + + setVoicePrivacyMode: function(aEnabled, aCallback) { + this._radioInterface.sendWorkerMessage("setVoicePrivacyMode", + {enabled: aEnabled}, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifySuccess(); + return false; + }).bind(this)); + }, + + getVoicePrivacyMode: function(aCallback) { + this._radioInterface.sendWorkerMessage("queryVoicePrivacyMode", null, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifySuccessWithBoolean(aResponse.enabled); + return false; + }).bind(this)); + }, + + sendMMI: function(aMmi, aCallback) { + this._radioInterface.sendWorkerMessage("sendMMI", {mmi: aMmi}, + (function(aResponse) { + 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) { + this._radioInterface.sendWorkerMessage("cancelUSSD", null, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifySuccess(); + return false; + }).bind(this)); + }, + + setCallForwarding: function(aOptions, aCallback) { + if (!aOptions || + !this._isValidCallForwardingReason(aOptions.reason) || + !this._isValidCallForwardingAction(aOptions.action)){ + this._dispatchNotifyError(aCallback, RIL.GECKO_ERROR_INVALID_PARAMETER); + return; + } + + let options = { + active: aOptions.active, + action: aOptions.action, + reason: aOptions.reason, + number: aOptions.number, + timeSeconds: aOptions.timeSeconds, + serviceClass: RIL.ICC_SERVICE_CLASS_VOICE + }; + + this._radioInterface.sendWorkerMessage("setCallForward", options, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + this.deliverListenerEvent("notifyCFStateChanged", + [!aResponse.errorMsg, aResponse.action, + aResponse.reason, aResponse.number, + aResponse.timeSeconds, aResponse.serviceClass]); + + aCallback.notifySuccess(); + return false; + }).bind(this)); + }, + + getCallForwarding: function(aReason, aCallback) { + if (!this._isValidCallForwardingReason(aReason)){ + this._dispatchNotifyError(aCallback, RIL.GECKO_ERROR_INVALID_PARAMETER); + return; + } + + this._radioInterface.sendWorkerMessage("queryCallForwardStatus", + {reason: aReason}, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + let infos = aResponse.rules; + this._rulesToCallForwardingOptions(infos); + aCallback.notifyGetCallForwardingSuccess(infos); + return false; + }).bind(this)); + }, + + setCallBarring: function(aOptions, aCallback) { + if (!this._isValidCallBarringOptions(aOptions, true)) { + this._dispatchNotifyError(aCallback, RIL.GECKO_ERROR_INVALID_PARAMETER); + return; + } + + let options = { + program: aOptions.program, + enabled: aOptions.enabled, + password: aOptions.password, + serviceClass: aOptions.serviceClass + }; + + this._radioInterface.sendWorkerMessage("setCallBarring", options, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifySuccess(); + return false; + }).bind(this)); + }, + + getCallBarring: function(aOptions, aCallback) { + if (!this._isValidCallBarringOptions(aOptions)) { + this._dispatchNotifyError(aCallback, RIL.GECKO_ERROR_INVALID_PARAMETER); + return; + } + + let options = { + program: aOptions.program, + password: aOptions.password, + serviceClass: aOptions.serviceClass + }; + + this._radioInterface.sendWorkerMessage("queryCallBarringStatus", options, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifyGetCallBarringSuccess(aResponse.program, + aResponse.enabled, + aResponse.serviceClass); + return false; + }).bind(this)); + }, + + changeCallBarringPassword: function(aOptions, aCallback) { + // Checking valid PIN for supplementary services. See TS.22.004 clause 5.2. + if (aOptions.pin == null || !aOptions.pin.match(/^\d{4}$/) || + aOptions.newPin == null || !aOptions.newPin.match(/^\d{4}$/)) { + this._dispatchNotifyError(aCallback, "InvalidPassword"); + return; + } + + let options = { + pin: aOptions.pin, + newPin: aOptions.newPin + }; + + this._radioInterface.sendWorkerMessage("changeCallBarringPassword", options, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifySuccess(); + return false; + }).bind(this)); + }, + + setCallWaiting: function(aEnabled, aCallback) { + this._radioInterface.sendWorkerMessage("setCallWaiting", + {enabled: aEnabled}, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifySuccess(); + return false; + }).bind(this)); + }, + + getCallWaiting: function(aCallback) { + this._radioInterface.sendWorkerMessage("queryCallWaiting", null, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifySuccessWithBoolean(aResponse.enabled); + return false; + }).bind(this)); + }, + + setCallingLineIdRestriction: function(aMode, aCallback) { + if (!this._isValidClirMode(aMode)) { + this._dispatchNotifyError(aCallback, RIL.GECKO_ERROR_INVALID_PARAMETER); + return; + } + + if (this.radioState !== RIL.GECKO_RADIOSTATE_ENABLED) { + this._dispatchNotifyError(aCallback, RIL.GECKO_ERROR_RADIO_NOT_AVAILABLE); + return; + } + + this._radioInterface.sendWorkerMessage("setCLIR", {clirMode: aMode}, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + this.deliverListenerEvent("notifyClirModeChanged", [aResponse.mode]); + aCallback.notifySuccess(); + return false; + }).bind(this)); + }, + + getCallingLineIdRestriction: function(aCallback) { + if (this.radioState !== RIL.GECKO_RADIOSTATE_ENABLED) { + this._dispatchNotifyError(aCallback, RIL.GECKO_ERROR_RADIO_NOT_AVAILABLE); + return; + } + + this._radioInterface.sendWorkerMessage("getCLIR", null, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifyGetClirStatusSuccess(aResponse.n, aResponse.m); + return false; + }).bind(this)); + }, + + exitEmergencyCbMode: function(aCallback) { + this._radioInterface.sendWorkerMessage("exitEmergencyCbMode", null, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifySuccess(); + return false; + }).bind(this)); + }, + + setRadioEnabled: function(aEnabled, aCallback) { + this._radioInterface.sendWorkerMessage("setRadioEnabled", + {enabled: aEnabled}, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return true; + } + + aCallback.notifySuccess(); + return true; + }).bind(this)); + }, +}; + +function MobileConnectionGonkService() { + this._providers = []; + + let numClients = gRadioInterfaceLayer.numRadioInterfaces; + for (let i = 0; i < numClients; i++) { + let radioInterface = gRadioInterfaceLayer.getRadioInterface(i); + let provider = new MobileConnectionProvider(i, radioInterface); + this._providers.push(provider); + } + + Services.prefs.addObserver(kPrefRilDebuggingEnabled, this, false); + Services.obs.addObserver(this, NS_NETWORK_ACTIVE_CHANGED_TOPIC_ID, false); + Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); + + debug("init complete"); +} +MobileConnectionGonkService.prototype = { + classID: MOBILECONNECTIONGONKSERVICE_CID, + classInfo: XPCOMUtils.generateCI({classID: MOBILECONNECTIONGONKSERVICE_CID, + contractID: MOBILECONNECTIONGONKSERVICE_CONTRACTID, + classDescription: "MobileConnectionGonkService", + interfaces: [Ci.nsIMobileConnectionGonkService, + Ci.nsIMobileConnectionService], + flags: Ci.nsIClassInfo.SINGLETON}), + QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileConnectionGonkService, + Ci.nsIMobileConnectionService, + Ci.nsIObserver]), + + // An array of MobileConnectionProvider instances. + _providers: null, + + _shutdown: function() { + Services.prefs.removeObserver(kPrefRilDebuggingEnabled, this); + Services.obs.removeObserver(this, NS_NETWORK_ACTIVE_CHANGED_TOPIC_ID); + Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID); + }, + + _updateDebugFlag: function() { + try { + DEBUG = RIL.DEBUG_RIL || + Services.prefs.getBoolPref(kPrefRilDebuggingEnabled); + } catch (e) {} + }, + + /** + * nsIMobileConnectionService interface. + */ + registerListener: function(aClientId, aListener) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.registerListener(aListener); + }, + + unregisterListener: function(aClientId, aListener) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.unregisterListener(aListener); + }, + + getVoiceConnectionInfo: function(aClientId) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + return provider.voiceInfo; + }, + + getDataConnectionInfo: function(aClientId) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + return provider.dataInfo; + }, + + getIccId: function(aClientId) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + return provider.iccId; + }, + + getNetworkSelectionMode: function(aClientId) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + return provider.networkSelectMode; + }, + + getRadioState: function(aClientId) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + return provider.radioState; + }, + + getLastKnownNetwork: function(aClientId) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + return provider.lastKnownNetwork; + }, + + getLastKnownHomeNetwork: function(aClientId) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + return provider.lastKnownHomeNetwork; + }, + + getSupportedNetworkTypes: function(aClientId) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + return provider.supportedNetworkTypes; + }, + + getNetworks: function(aClientId, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.getNetworks(aCallback); + }, + + selectNetwork: function(aClientId, aNetwork, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.selectNetwork(aNetwork, aCallback); + }, + + selectNetworkAutomatically: function(aClientId, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.selectNetworkAutomatically(aCallback); + }, + + setPreferredNetworkType: function(aClientId, aType, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.setPreferredNetworkType(aType, aCallback); + }, + + getPreferredNetworkType: function(aClientId, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.getPreferredNetworkType(aCallback); + }, + + setRoamingPreference: function(aClientId, aMode, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.setRoamingPreference(aMode, aCallback); + }, + + getRoamingPreference: function(aClientId, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.getRoamingPreference(aCallback); + }, + + setVoicePrivacyMode: function(aClientId, aEnabled, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.setVoicePrivacyMode(aEnabled, aCallback); + }, + + getVoicePrivacyMode: function(aClientId, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.getVoicePrivacyMode(aCallback); + }, + + sendMMI: function(aClientId, aMmi, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.sendMMI(aMmi, aCallback); + }, + + cancelMMI: function(aClientId, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.cancelMMI(aCallback); + }, + + setCallForwarding: function(aClientId, aOptions, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.setCallForwarding(aOptions, aCallback); + }, + + getCallForwarding: function(aClientId, aReason, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.getCallForwarding(aReason, aCallback); + }, + + setCallBarring: function(aClientId, aOptions, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.setCallBarring(aOptions, aCallback); + }, + + getCallBarring: function(aClientId, aOptions, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.getCallBarring(aOptions, aCallback); + }, + + changeCallBarringPassword: function(aClientId, aOptions, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.changeCallBarringPassword(aOptions, aCallback); + }, + + setCallWaiting: function(aClientId, aEnabled, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.setCallWaiting(aEnabled, aCallback); + }, + + getCallWaiting: function(aClientId, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.getCallWaiting(aCallback); + }, + + setCallingLineIdRestriction: function(aClientId, aMode, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.setCallingLineIdRestriction(aMode, aCallback); + }, + + getCallingLineIdRestriction: function(aClientId, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.getCallingLineIdRestriction(aCallback); + }, + + exitEmergencyCbMode: function(aClientId, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.exitEmergencyCbMode(aCallback); + }, + + setRadioEnabled: function(aClientId, aEnabled, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.setRadioEnabled(aEnabled, aCallback); + }, + + /** + * nsIMobileConnectionGonkService interface. + */ + notifyVoiceInfoChanged: function(aClientId, aVoiceInfo) { + if (DEBUG) { + debug("notifyVoiceInfoChanged for " + aClientId + ": " + + JSON.stringify(aVoiceInfo)); + } + + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.updateVoiceInfo(aVoiceInfo); + }, + + notifyDataInfoChanged: function(aClientId, aDataInfo) { + if (DEBUG) { + debug("notifyDataInfoChanged for " + aClientId + ": " + + JSON.stringify(aDataInfo)); + } + + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.updateDataInfo(aDataInfo); + }, + + notifyUssdReceived: function(aClientId, aMessage, aSessionEnded) { + if (DEBUG) { + debug("notifyUssdReceived for " + aClientId + ": " + + JSON.stringify(ussd)); + } + + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.deliverListenerEvent("notifyUssdReceived", + [aMessage, aSessionEnded]); + + let info = { + message: aMessage, + sessionEnded: aSessionEnded, + serviceId: aClientId + }; + + gSystemMessenger.broadcastMessage("ussd-received", info); + }, + + notifyDataError: function(aClientId, aMessage) { + if (DEBUG) { + debug("notifyDataError for " + aClientId + ": " + aMessage); + } + + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.deliverListenerEvent("notifyDataError", [aMessage]); + }, + + notifyEmergencyCallbackModeChanged: function(aClientId, aActive, aTimeoutMs) { + if (DEBUG) { + debug("notifyEmergencyCbModeChanged for " + aClientId + ": " + + JSON.stringify({active: aActive, timeoutMs: aTimeoutMs})); + } + + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.deliverListenerEvent("notifyEmergencyCbModeChanged", + [aActive, aTimeoutMs]); + }, + + notifyOtaStatusChanged: function(aClientId, aStatus) { + if (DEBUG) { + debug("notifyOtaStatusChanged for " + aClientId + ": " + aStatus); + } + + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.deliverListenerEvent("notifyOtaStatusChanged", [aStatus]); + }, + + notifyIccChanged: function(aClientId, aIccId) { + if (DEBUG) { + debug("notifyIccChanged for " + aClientId + ": " + aIccId); + } + + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.updateIccId(aIccId); + }, + + notifyRadioStateChanged: function(aClientId, aRadioState) { + if (DEBUG) { + debug("notifyRadioStateChanged for " + aClientId + ": " + aRadioState); + } + + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.updateRadioState(aRadioState); + }, + + notifyNetworkInfoChanged: function(aClientId, aNetworkInfo) { + if (DEBUG) { + debug("notifyNetworkInfoChanged for " + aClientId + ": " + + JSON.stringify(aNetworkInfo)); + } + + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + let isVoiceUpdated = false; + let isDataUpdated = false; + let operatorMessage = aNetworkInfo[RIL.NETWORK_INFO_OPERATOR]; + let voiceMessage = aNetworkInfo[RIL.NETWORK_INFO_VOICE_REGISTRATION_STATE]; + let dataMessage = aNetworkInfo[RIL.NETWORK_INFO_DATA_REGISTRATION_STATE]; + let signalMessage = aNetworkInfo[RIL.NETWORK_INFO_SIGNAL]; + let selectionMessage = aNetworkInfo[RIL.NETWORK_INFO_NETWORK_SELECTION_MODE]; + + // Batch the *InfoChanged messages together + if (operatorMessage) { + provider.updateOperatorInfo(operatorMessage, true); + } + + if (voiceMessage) { + provider.updateVoiceInfo(voiceMessage, true); + } + + if (dataMessage) { + provider.updateDataInfo(dataMessage, true); + } + + if (signalMessage) { + provider.updateSignalInfo(signalMessage, true); + } + + if (selectionMessage) { + this.notifyNetworkSelectModeChanged(aClientId, selectionMessage.mode); + } + + if (voiceMessage || operatorMessage || signalMessage) { + provider.deliverListenerEvent("notifyVoiceChanged"); + } + + if (dataMessage || operatorMessage || signalMessage) { + provider.deliverListenerEvent("notifyDataChanged"); + } + }, + + notifySignalStrengthChanged: function(aClientId, aSignal) { + if (DEBUG) { + debug("notifySignalStrengthChanged for " + aClientId + ": " + + JSON.stringify(aSignal)); + } + + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.updateSignalInfo(aSignal); + }, + + notifyOperatorChanged: function(aClientId, aOperator) { + if (DEBUG) { + debug("notifyOperatorChanged for " + aClientId + ": " + + JSON.stringify(aOperator)); + } + + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.updateOperatorInfo(aOperator); + }, + + notifyNetworkSelectModeChanged: function(aClientId, aMode) { + if (DEBUG) { + debug("notifyNetworkSelectModeChanged for " + aClientId + ": " + aMode); + } + + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + if (provider.networkSelectMode === aMode) { + return; + } + + provider.networkSelectMode = aMode; + provider.deliverListenerEvent("notifyNetworkSelectionModeChanged"); + }, + + notifySpnAvailable: function(aClientId) { + if (DEBUG) { + debug("notifySpnAvailable for " + aClientId); + } + + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + // Update voice roaming state + provider.updateVoiceInfo({}); + + // Update data roaming state + provider.updateDataInfo({}); + }, + + notifyLastHomeNetworkChanged: function(aClientId, aNetwork) { + if (DEBUG) { + debug("notifyLastHomeNetworkChanged for " + aClientId + ": " + aNetwork); + } + + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + if (provider.lastKnownHomeNetwork === aNetwork) { + return; + } + + provider.lastKnownHomeNetwork = aNetwork; + provider.deliverListenerEvent("notifyLastKnownHomeNetworkChanged"); + }, + + /** + * nsIObserver interface. + */ + observe: function(aSubject, aTopic, aData) { + switch (aTopic) { + case NS_NETWORK_ACTIVE_CHANGED_TOPIC_ID: + for (let i = 0; i < this._providers.length; i++) { + let provider = this._providers[i]; + // Update connected flag only. + provider.updateDataInfo({}); + } + break; + case NS_PREFBRANCH_PREFCHANGE_TOPIC_ID: + if (aData === kPrefRilDebuggingEnabled) { + this._updateDebugFlag(); + } + break; + case NS_XPCOM_SHUTDOWN_OBSERVER_ID: + this._shutdown(); + break; + } + } +}; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([MobileConnectionGonkService]); diff --git a/dom/mobileconnection/gonk/MobileConnectionGonkService.manifest b/dom/mobileconnection/gonk/MobileConnectionGonkService.manifest new file mode 100644 index 00000000000..927226e4d71 --- /dev/null +++ b/dom/mobileconnection/gonk/MobileConnectionGonkService.manifest @@ -0,0 +1,2 @@ +component {05e20430-fe65-4984-8df9-a6a504b24a91} MobileConnectionGonkService.js +contract @mozilla.org/mobileconnection/mobileconnectiongonkservice;1 {05e20430-fe65-4984-8df9-a6a504b24a91} diff --git a/dom/mobileconnection/moz.build b/dom/mobileconnection/moz.build index 2d0e2ecd72b..4ac266523da 100644 --- a/dom/mobileconnection/moz.build +++ b/dom/mobileconnection/moz.build @@ -44,6 +44,12 @@ IPDL_SOURCES += [ 'ipc/PMobileConnectionTypes.ipdlh', ] +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': + EXTRA_COMPONENTS += [ + 'gonk/MobileConnectionGonkService.js', + 'gonk/MobileConnectionGonkService.manifest', + ] + FAIL_ON_WARNINGS = True include('/ipc/chromium/chromium-config.mozbuild') diff --git a/dom/system/gonk/RILContentHelper.js b/dom/system/gonk/RILContentHelper.js index f1a7d09206c..8d9d9e65d71 100644 --- a/dom/system/gonk/RILContentHelper.js +++ b/dom/system/gonk/RILContentHelper.js @@ -48,16 +48,8 @@ const GSMICCINFO_CID = Components.ID("{e0fa785b-ad3f-46ed-bc56-fcb0d6fe4fa8}"); const CDMAICCINFO_CID = Components.ID("{3d1f844f-9ec5-48fb-8907-aed2e5421709}"); -const MOBILECONNECTIONINFO_CID = - Components.ID("{a35cfd39-2d93-4489-ac7d-396475dacb27}"); -const MOBILENETWORKINFO_CID = - Components.ID("{a6c8416c-09b4-46d1-bf29-6520d677d085}"); -const MOBILECELLINFO_CID = - Components.ID("{ae724dd4-ccaf-4006-98f1-6ce66a092464}"); const VOICEMAILSTATUS_CID= Components.ID("{5467f2eb-e214-43ea-9b89-67711241ec8e}"); -const MOBILECFINFO_CID= - Components.ID("{a4756f16-e728-4d9f-8baa-8464f894888a}"); const CELLBROADCASTMESSAGE_CID = Components.ID("{29474c96-3099-486f-bb4a-3c9a1da834e4}"); const CELLBROADCASTETWSINFO_CID = @@ -68,51 +60,19 @@ const ICCCARDLOCKERROR_CID = const RIL_IPC_MSG_NAMES = [ "RIL:CardStateChanged", "RIL:IccInfoChanged", - "RIL:VoiceInfoChanged", - "RIL:DataInfoChanged", - "RIL:GetAvailableNetworks", - "RIL:NetworkSelectionModeChanged", - "RIL:SelectNetwork", - "RIL:SelectNetworkAuto", - "RIL:SetPreferredNetworkType", - "RIL:GetPreferredNetworkType", - "RIL:EmergencyCbModeChanged", "RIL:VoicemailNotification", "RIL:VoicemailInfoChanged", "RIL:CardLockResult", "RIL:CardLockRetryCount", - "RIL:USSDReceived", - "RIL:SendMMI", - "RIL:CancelMMI", "RIL:StkCommand", "RIL:StkSessionEnd", - "RIL:DataError", - "RIL:SetCallForwardingOptions", - "RIL:GetCallForwardingOptions", - "RIL:SetCallBarringOptions", - "RIL:GetCallBarringOptions", - "RIL:ChangeCallBarringPassword", - "RIL:SetCallWaitingOptions", - "RIL:GetCallWaitingOptions", - "RIL:SetCallingLineIdRestriction", - "RIL:GetCallingLineIdRestriction", "RIL:CellBroadcastReceived", - "RIL:CfStateChanged", "RIL:IccOpenChannel", "RIL:IccCloseChannel", "RIL:IccExchangeAPDU", "RIL:ReadIccContacts", "RIL:UpdateIccContact", - "RIL:SetRoamingPreference", - "RIL:GetRoamingPreference", - "RIL:ExitEmergencyCbMode", - "RIL:SetRadioEnabled", - "RIL:RadioStateChanged", - "RIL:SetVoicePrivacyMode", - "RIL:GetVoicePrivacyMode", - "RIL:OtaStatusChanged", - "RIL:MatchMvno", - "RIL:ClirModeChanged" + "RIL:MatchMvno" ]; XPCOMUtils.defineLazyServiceGetter(this, "cpmm", @@ -219,69 +179,6 @@ VoicemailInfo.prototype = { displayName: null }; -function MobileConnectionInfo() {} -MobileConnectionInfo.prototype = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileConnectionInfo]), - classID: MOBILECONNECTIONINFO_CID, - classInfo: XPCOMUtils.generateCI({ - classID: MOBILECONNECTIONINFO_CID, - classDescription: "MobileConnectionInfo", - interfaces: [Ci.nsIMobileConnectionInfo] - }), - - // nsIMobileConnectionInfo - - connected: false, - state: null, - emergencyCallsOnly: false, - roaming: false, - network: null, - cell: null, - type: null, - signalStrength: null, - relSignalStrength: null -}; - -function MobileNetworkInfo() {} -MobileNetworkInfo.prototype = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileNetworkInfo]), - classID: MOBILENETWORKINFO_CID, - classInfo: XPCOMUtils.generateCI({ - classID: MOBILENETWORKINFO_CID, - classDescription: "MobileNetworkInfo", - interfaces: [Ci.nsIMobileNetworkInfo] - }), - - // nsIMobileNetworkInfo - - shortName: null, - longName: null, - mcc: null, - mnc: null, - state: null -}; - -function MobileCellInfo() {} -MobileCellInfo.prototype = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileCellInfo]), - classID: MOBILECELLINFO_CID, - classInfo: XPCOMUtils.generateCI({ - classID: MOBILECELLINFO_CID, - classDescription: "MobileCellInfo", - interfaces: [Ci.nsIMobileCellInfo] - }), - - // nsIMobileCellInfo - - gsmLocationAreaCode: -1, - gsmCellId: -1, - cdmaBaseStationId: -1, - cdmaBaseStationLatitude: -2147483648, - cdmaBaseStationLongitude: -2147483648, - cdmaSystemId: -1, - cdmaNetworkId: -1 -}; - function VoicemailStatus(clientId) { this.serviceId = clientId; } @@ -297,23 +194,6 @@ VoicemailStatus.prototype = { returnMessage: null }; -function MobileCallForwardingInfo(options) { - this.active = options.active; - this.action = options.action; - this.reason = options.reason; - this.number = options.number; - this.timeSeconds = options.timeSeconds; - this.serviceClass = options.serviceClass; -} -MobileCallForwardingInfo.prototype = { - __exposedProps__ : {active: 'r', - action: 'r', - reason: 'r', - number: 'r', - timeSeconds: 'r', - serviceClass: 'r'} -}; - function CellBroadcastMessage(clientId, pdu) { this.serviceId = clientId; this.gsmGeographicalScope = RIL.CB_GSM_GEOGRAPHICAL_SCOPE_NAMES[pdu.geographicalScope]; @@ -379,39 +259,6 @@ CellBroadcastEtwsInfo.prototype = { popup: null }; -function CallBarringOptions(options) { - this.program = options.program; - this.enabled = options.enabled; - this.password = options.password; - this.serviceClass = options.serviceClass; -} -CallBarringOptions.prototype = { - __exposedProps__ : {program: 'r', - enabled: 'r', - password: 'r', - serviceClass: 'r'} -}; - -function DOMMMIResult(result) { - this.serviceCode = result.serviceCode; - this.statusMessage = result.statusMessage; - this.additionalInformation = result.additionalInformation; -} -DOMMMIResult.prototype = { - __exposedProps__: {serviceCode: 'r', - statusMessage: 'r', - additionalInformation: 'r'} -}; - -function DOMCLIRStatus(option) { - this.n = option.n; - this.m = option.m; -} -DOMCLIRStatus.prototype = { - __exposedProps__ : {n: 'r', - m: 'r'} -}; - function IccCardLockError() { } IccCardLockError.prototype = { @@ -438,11 +285,7 @@ function RILContentHelper() { for (let clientId = 0; clientId < this.numClients; clientId++) { this.rilContexts[clientId] = { cardState: RIL.GECKO_CARDSTATE_UNKNOWN, - networkSelectionMode: RIL.GECKO_NETWORK_SELECTION_UNKNOWN, - radioState: null, - iccInfo: null, - voiceConnectionInfo: new MobileConnectionInfo(), - dataConnectionInfo: new MobileConnectionInfo() + iccInfo: null }; this.voicemailInfos[clientId] = new VoicemailInfo(); @@ -452,7 +295,6 @@ function RILContentHelper() { this.initDOMRequestHelper(/* aWindow */ null, RIL_IPC_MSG_NAMES); this._windowsMap = []; - this._mobileConnectionListeners = []; this._cellBroadcastListeners = []; this._voicemailListeners = []; this._iccListeners = []; @@ -466,18 +308,15 @@ function RILContentHelper() { RILContentHelper.prototype = { __proto__: DOMRequestIpcHelper.prototype, - QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileConnectionProvider, - Ci.nsICellBroadcastProvider, + QueryInterface: XPCOMUtils.generateQI([Ci.nsICellBroadcastProvider, Ci.nsIVoicemailProvider, Ci.nsIIccProvider, Ci.nsIObserver, - Ci.nsISupportsWeakReference, - Ci.nsIObserver]), + Ci.nsISupportsWeakReference]), classID: RILCONTENTHELPER_CID, classInfo: XPCOMUtils.generateCI({classID: RILCONTENTHELPER_CID, classDescription: "RILContentHelper", - interfaces: [Ci.nsIMobileConnectionProvider, - Ci.nsICellBroadcastProvider, + interfaces: [Ci.nsICellBroadcastProvider, Ci.nsIVoicemailProvider, Ci.nsIIccProvider]}), @@ -495,39 +334,6 @@ RILContentHelper.prototype = { } }, - updateConnectionInfo: function(srcInfo, destInfo) { - for (let key in srcInfo) { - if ((key != "network") && (key != "cell")) { - destInfo[key] = srcInfo[key]; - } - } - - let srcCell = srcInfo.cell; - if (!srcCell) { - destInfo.cell = null; - } else { - let cell = destInfo.cell; - if (!cell) { - cell = destInfo.cell = new MobileCellInfo(); - } - - this.updateInfo(srcCell, cell); - } - - let srcNetwork = srcInfo.network; - if (!srcNetwork) { - destInfo.network= null; - return; - } - - let network = destInfo.network; - if (!network) { - network = destInfo.network = new MobileNetworkInfo(); - } - - this.updateInfo(srcNetwork, network); - }, - /** * We need to consider below cases when update iccInfo: * 1. Should clear iccInfo to null if there is no card detected. @@ -540,10 +346,6 @@ RILContentHelper.prototype = { if (!newInfo || !newInfo.iccid) { if (rilContext.iccInfo) { rilContext.iccInfo = null; - this._deliverEvent(clientId, - "_mobileConnectionListeners", - "notifyIccChanged", - null); } return; } @@ -562,14 +364,6 @@ RILContentHelper.prototype = { true : false; this.updateInfo(newInfo, rilContext.iccInfo); - - // Deliver event after info is updated. - if (changed) { - this._deliverEvent(clientId, - "_mobileConnectionListeners", - "notifyIccChanged", - null); - } }, _windowsMap: null, @@ -592,11 +386,7 @@ RILContentHelper.prototype = { continue; } this.rilContexts[cId].cardState = rilContext.cardState; - this.rilContexts[cId].networkSelectionMode = rilContext.networkSelectionMode; - this.rilContexts[cId].radioState = rilContext.detailedRadioState; this.updateIccInfo(cId, rilContext.iccInfo); - this.updateConnectionInfo(rilContext.voice, this.rilContexts[cId].voiceConnectionInfo); - this.updateConnectionInfo(rilContext.data, this.rilContexts[cId].dataConnectionInfo); } return this.rilContexts[clientId]; @@ -636,265 +426,6 @@ RILContentHelper.prototype = { return request; }, - /** - * nsIMobileConnectionProvider - */ - - getLastKnownNetwork: function(clientId) { - return cpmm.sendSyncMessage("RIL:GetLastKnownNetwork", { - clientId: clientId - })[0]; - }, - - getLastKnownHomeNetwork: function(clientId) { - return cpmm.sendSyncMessage("RIL:GetLastKnownHomeNetwork", { - clientId: clientId - })[0]; - }, - - getVoiceConnectionInfo: function(clientId) { - let context = this.getRilContext(clientId); - return context && context.voiceConnectionInfo; - }, - - getDataConnectionInfo: function(clientId) { - let context = this.getRilContext(clientId); - return context && context.dataConnectionInfo; - }, - - getIccId: function(clientId) { - let context = this.getRilContext(clientId); - return context && context.iccInfo && context.iccInfo.iccid; - }, - - getNetworkSelectionMode: function(clientId) { - let context = this.getRilContext(clientId); - return context && context.networkSelectionMode; - }, - - getRadioState: function(clientId) { - let context = this.getRilContext(clientId); - return context && context.radioState; - }, - - getSupportedNetworkTypes: function(clientId) { - return cpmm.sendSyncMessage("RIL:GetSupportedNetworkTypes", { - clientId: clientId - })[0]; - }, - - getNetworks: function(clientId, window) { - if (window == null) { - throw Components.Exception("Can't get window object", - Cr.NS_ERROR_UNEXPECTED); - } - - let request = Services.DOMRequest.createRequest(window); - let requestId = this.getRequestId(request); - // We need to save the global window to get the proper MobileNetworkInfo - // constructor once we get the reply from the parent process. - this._windowsMap[requestId] = window; - - cpmm.sendAsyncMessage("RIL:GetAvailableNetworks", { - clientId: clientId, - data: { - requestId: requestId - } - }); - return request; - }, - - selectNetwork: function(clientId, window, network) { - if (window == null) { - throw Components.Exception("Can't get window object", - Cr.NS_ERROR_UNEXPECTED); - } - - let request = Services.DOMRequest.createRequest(window); - let requestId = this.getRequestId(request); - - if (!network || - isNaN(parseInt(network.mcc, 10)) || isNaN(parseInt(network.mnc, 10))) { - this.dispatchFireRequestError(RIL.GECKO_ERROR_INVALID_PARAMETER); - return request; - } - - if (this.rilContexts[clientId].networkSelectionMode == RIL.GECKO_NETWORK_SELECTION_MANUAL && - this.rilContexts[clientId].voiceConnectionInfo.network === network) { - // Already manually selected this network, so schedule - // onsuccess to be fired on the next tick - this.dispatchFireRequestSuccess(requestId, null); - return request; - } - - cpmm.sendAsyncMessage("RIL:SelectNetwork", { - clientId: clientId, - data: { - requestId: requestId, - mnc: network.mnc, - mcc: network.mcc - } - }); - - return request; - }, - - selectNetworkAutomatically: function(clientId, window) { - if (window == null) { - throw Components.Exception("Can't get window object", - Cr.NS_ERROR_UNEXPECTED); - } - - let request = Services.DOMRequest.createRequest(window); - let requestId = this.getRequestId(request); - - if (this.rilContexts[clientId].networkSelectionMode == RIL.GECKO_NETWORK_SELECTION_AUTOMATIC) { - // Already using automatic selection mode, so schedule - // onsuccess to be be fired on the next tick - this.dispatchFireRequestSuccess(requestId, null); - return request; - } - - cpmm.sendAsyncMessage("RIL:SelectNetworkAuto", { - clientId: clientId, - data: { - requestId: requestId - } - }); - return request; - }, - - setPreferredNetworkType: function(clientId, window, type) { - if (window == null) { - throw Components.Exception("Can't get window object", - Cr.NS_ERROR_UNEXPECTED); - } - - let request = Services.DOMRequest.createRequest(window); - let requestId = this.getRequestId(request); - - let radioState = this.rilContexts[clientId].radioState; - if (radioState !== RIL.GECKO_DETAILED_RADIOSTATE_ENABLED) { - this.dispatchFireRequestError(requestId, - RIL.GECKO_ERROR_RADIO_NOT_AVAILABLE); - return request; - } - - cpmm.sendAsyncMessage("RIL:SetPreferredNetworkType", { - clientId: clientId, - data: { - requestId: requestId, - type: type - } - }); - return request; - }, - - getPreferredNetworkType: function(clientId, window) { - if (window == null) { - throw Components.Exception("Can't get window object", - Cr.NS_ERROR_UNEXPECTED); - } - - let request = Services.DOMRequest.createRequest(window); - let requestId = this.getRequestId(request); - - let radioState = this.rilContexts[clientId].radioState; - if (radioState !== RIL.GECKO_DETAILED_RADIOSTATE_ENABLED) { - this.dispatchFireRequestError(requestId, - RIL.GECKO_ERROR_RADIO_NOT_AVAILABLE); - return request; - } - - cpmm.sendAsyncMessage("RIL:GetPreferredNetworkType", { - clientId: clientId, - data: { - requestId: requestId - } - }); - return request; - }, - - setRoamingPreference: function(clientId, window, mode) { - if (window == null) { - throw Components.Exception("Can't get window object", - Cr.NS_ERROR_UNEXPECTED); - } - - let request = Services.DOMRequest.createRequest(window); - let requestId = this.getRequestId(request); - - if (!mode) { - this.dispatchFireRequestError(requestId, - RIL.GECKO_ERROR_INVALID_PARAMETER); - return request; - } - - cpmm.sendAsyncMessage("RIL:SetRoamingPreference", { - clientId: clientId, - data: { - requestId: requestId, - mode: mode - } - }); - return request; - }, - - getRoamingPreference: function(clientId, window) { - if (window == null) { - throw Components.Exception("Can't get window object", - Cr.NS_ERROR_UNEXPECTED); - } - - let request = Services.DOMRequest.createRequest(window); - let requestId = this.getRequestId(request); - - cpmm.sendAsyncMessage("RIL:GetRoamingPreference", { - clientId: clientId, - data: { - requestId: requestId - } - }); - return request; - }, - - setVoicePrivacyMode: function(clientId, window, enabled) { - if (window == null) { - throw Components.Exception("Can't get window object", - Cr.NS_ERROR_UNEXPECTED); - } - - let request = Services.DOMRequest.createRequest(window); - let requestId = this.getRequestId(request); - - cpmm.sendAsyncMessage("RIL:SetVoicePrivacyMode", { - clientId: clientId, - data: { - requestId: requestId, - enabled: enabled - } - }); - return request; - }, - - getVoicePrivacyMode: function(clientId, window) { - if (window == null) { - throw Components.Exception("Can't get window object", - Cr.NS_ERROR_UNEXPECTED); - } - - let request = Services.DOMRequest.createRequest(window); - let requestId = this.getRequestId(request); - - cpmm.sendAsyncMessage("RIL:GetVoicePrivacyMode", { - clientId: clientId, - data: { - requestId: requestId - } - }); - return request; - }, - getCardLockState: function(clientId, window, lockType) { if (window == null) { throw Components.Exception("Can't get window object", @@ -963,45 +494,6 @@ RILContentHelper.prototype = { return request; }, - sendMMI: function(clientId, window, mmi) { - if (DEBUG) debug("Sending MMI " + mmi); - if (!window) { - throw Components.Exception("Can't get window object", - Cr.NS_ERROR_UNEXPECTED); - } - let request = Services.DOMRequest.createRequest(window); - let requestId = this.getRequestId(request); - // We need to save the global window to get the proper MMIError - // constructor once we get the reply from the parent process. - this._windowsMap[requestId] = window; - - cpmm.sendAsyncMessage("RIL:SendMMI", { - clientId: clientId, - data: { - mmi: mmi, - requestId: requestId - } - }); - return request; - }, - - cancelMMI: function(clientId, window) { - if (DEBUG) debug("Cancel MMI"); - if (!window) { - throw Components.Exception("Can't get window object", - Cr.NS_ERROR_UNEXPECTED); - } - let request = Services.DOMRequest.createRequest(window); - let requestId = this.getRequestId(request); - cpmm.sendAsyncMessage("RIL:CancelMMI", { - clientId: clientId, - data: { - requestId: requestId - } - }); - return request; - }, - sendStkResponse: function(clientId, window, command, response) { if (window == null) { throw Components.Exception("Can't get window object", @@ -1182,273 +674,6 @@ RILContentHelper.prototype = { return request; }, - getCallForwarding: function(clientId, window, reason) { - if (window == null) { - throw Components.Exception("Can't get window object", - Cr.NS_ERROR_UNEXPECTED); - } - let request = Services.DOMRequest.createRequest(window); - let requestId = this.getRequestId(request); - - if (!this._isValidCallForwardingReason(reason)) { - this.dispatchFireRequestError(requestId, - RIL.GECKO_ERROR_INVALID_PARAMETER); - return request; - } - - cpmm.sendAsyncMessage("RIL:GetCallForwardingOptions", { - clientId: clientId, - data: { - requestId: requestId, - reason: reason - } - }); - - return request; - }, - - setCallForwarding: function(clientId, window, options) { - if (window == null) { - throw Components.Exception("Can't get window object", - Cr.NS_ERROR_UNEXPECTED); - } - let request = Services.DOMRequest.createRequest(window); - let requestId = this.getRequestId(request); - - if (!options || - !this._isValidCallForwardingReason(options.reason) || - !this._isValidCallForwardingAction(options.action)) { - this.dispatchFireRequestError(requestId, - RIL.GECKO_ERROR_INVALID_PARAMETER); - return request; - } - - cpmm.sendAsyncMessage("RIL:SetCallForwardingOptions", { - clientId: clientId, - data: { - requestId: requestId, - action: options.action, - reason: options.reason, - number: options.number, - timeSeconds: options.timeSeconds - } - }); - - return request; - }, - - getCallBarring: function(clientId, window, options) { - if (window == null) { - throw Components.Exception("Can't get window object", - Cr.NS_ERROR_UNEXPECTED); - } - let request = Services.DOMRequest.createRequest(window); - let requestId = this.getRequestId(request); - - if (DEBUG) debug("getCallBarring: " + JSON.stringify(options)); - if (!this._isValidCallBarringOptions(options)) { - this.dispatchFireRequestError(requestId, - RIL.GECKO_ERROR_INVALID_PARAMETER); - return request; - } - - cpmm.sendAsyncMessage("RIL:GetCallBarringOptions", { - clientId: clientId, - data: { - requestId: requestId, - program: options.program, - password: options.password, - serviceClass: options.serviceClass - } - }); - return request; - }, - - setCallBarring: function(clientId, window, options) { - if (window == null) { - throw Components.Exception("Can't get window object", - Cr.NS_ERROR_UNEXPECTED); - } - let request = Services.DOMRequest.createRequest(window); - let requestId = this.getRequestId(request); - - if (DEBUG) debug("setCallBarringOptions: " + JSON.stringify(options)); - if (!this._isValidCallBarringOptions(options, true)) { - this.dispatchFireRequestError(requestId, - RIL.GECKO_ERROR_INVALID_PARAMETER); - return request; - } - - cpmm.sendAsyncMessage("RIL:SetCallBarringOptions", { - clientId: clientId, - data: { - requestId: requestId, - program: options.program, - enabled: options.enabled, - password: options.password, - serviceClass: options.serviceClass - } - }); - return request; - }, - - changeCallBarringPassword: function(clientId, window, info) { - if (window == null) { - throw Components.Exception("Can't get window object", - Cr.NS_ERROR_UNEXPECTED); - } - let request = Services.DOMRequest.createRequest(window); - let requestId = this.getRequestId(request); - - // Checking valid PIN for supplementary services. See TS.22.004 clause 5.2. - if (info.pin == null || !info.pin.match(/^\d{4}$/) || - info.newPin == null || !info.newPin.match(/^\d{4}$/)) { - this.dispatchFireRequestError(requestId, "InvalidPassword"); - return request; - } - - if (DEBUG) debug("changeCallBarringPassword: " + JSON.stringify(info)); - info.requestId = requestId; - cpmm.sendAsyncMessage("RIL:ChangeCallBarringPassword", { - clientId: clientId, - data: info - }); - - return request; - }, - - getCallWaiting: function(clientId, window) { - if (window == null) { - throw Components.Exception("Can't get window object", - Cr.NS_ERROR_UNEXPECTED); - } - let request = Services.DOMRequest.createRequest(window); - let requestId = this.getRequestId(request); - - cpmm.sendAsyncMessage("RIL:GetCallWaitingOptions", { - clientId: clientId, - data: { - requestId: requestId - } - }); - - return request; - }, - - setCallWaiting: function(clientId, window, enabled) { - if (window == null) { - throw Components.Exception("Can't get window object", - Cr.NS_ERROR_UNEXPECTED); - } - let request = Services.DOMRequest.createRequest(window); - let requestId = this.getRequestId(request); - - cpmm.sendAsyncMessage("RIL:SetCallWaitingOptions", { - clientId: clientId, - data: { - requestId: requestId, - enabled: enabled - } - }); - - return request; - }, - - getCallingLineIdRestriction: function(clientId, window) { - if (window == null) { - throw Components.Exception("Can't get window object", - Cr.NS_ERROR_UNEXPECTED); - } - let request = Services.DOMRequest.createRequest(window); - let requestId = this.getRequestId(request); - - let radioState = this.rilContexts[clientId].radioState; - if (radioState !== RIL.GECKO_DETAILED_RADIOSTATE_ENABLED) { - this.dispatchFireRequestError(requestId, - RIL.GECKO_ERROR_RADIO_NOT_AVAILABLE); - return request; - } - - cpmm.sendAsyncMessage("RIL:GetCallingLineIdRestriction", { - clientId: clientId, - data: { - requestId: requestId - } - }); - - return request; - }, - - setCallingLineIdRestriction: function(clientId, window, clirMode) { - if (window == null) { - throw Components.Exception("Can't get window object", - Cr.NS_ERROR_UNEXPECTED); - } - let request = Services.DOMRequest.createRequest(window); - let requestId = this.getRequestId(request); - - let radioState = this.rilContexts[clientId].radioState; - if (radioState !== RIL.GECKO_DETAILED_RADIOSTATE_ENABLED) { - this.dispatchFireRequestError(requestId, - RIL.GECKO_ERROR_RADIO_NOT_AVAILABLE); - return request; - } - - if (!this._isValidClirMode(clirMode)) { - this.dispatchFireRequestError(requestId, - RIL.GECKO_ERROR_INVALID_PARAMETER); - return request; - } - - cpmm.sendAsyncMessage("RIL:SetCallingLineIdRestriction", { - clientId: clientId, - data: { - requestId: requestId, - clirMode: clirMode - } - }); - - return request; - }, - - exitEmergencyCbMode: function(clientId, window) { - if (window == null) { - throw Components.Exception("Can't get window object", - Cr.NS_ERROR_UNEXPECTED); - } - let request = Services.DOMRequest.createRequest(window); - let requestId = this.getRequestId(request); - - cpmm.sendAsyncMessage("RIL:ExitEmergencyCbMode", { - clientId: clientId, - data: { - requestId: requestId, - } - }); - - return request; - }, - - setRadioEnabled: function(clientId, window, enabled) { - if (window == null) { - throw Components.Exception("Can't get window object", - Cr.NS_ERROR_UNEXPECTED); - } - let request = Services.DOMRequest.createRequest(window); - let requestId = this.getRequestId(request); - - cpmm.sendAsyncMessage("RIL:SetRadioEnabled", { - clientId: clientId, - data: { - requestId: requestId, - enabled: enabled, - } - }); - - return request; - }, - - _mobileConnectionListeners: null, _cellBroadcastListeners: null, _voicemailListeners: null, _iccListeners: null, @@ -1529,16 +754,6 @@ RILContentHelper.prototype = { } }, - registerMobileConnectionMsg: function(clientId, listener) { - if (DEBUG) debug("Registering for mobile connection related messages"); - this.registerListener("_mobileConnectionListeners", clientId, listener); - cpmm.sendAsyncMessage("RIL:RegisterMobileConnectionMsg"); - }, - - unregisterMobileConnectionMsg: function(clientId, listener) { - this.unregisterListener("_mobileConnectionListeners", clientId, listener); - }, - registerVoicemailMsg: function(listener) { if (DEBUG) debug("Registering for voicemail-related messages"); // To follow the listener registration scheme, we add a dummy clientId 0. @@ -1688,46 +903,6 @@ RILContentHelper.prototype = { "notifyIccInfoChanged", null); break; - case "RIL:VoiceInfoChanged": - this.updateConnectionInfo(data, - this.rilContexts[clientId].voiceConnectionInfo); - this._deliverEvent(clientId, - "_mobileConnectionListeners", - "notifyVoiceChanged", - null); - break; - case "RIL:DataInfoChanged": - this.updateConnectionInfo(data, - this.rilContexts[clientId].dataConnectionInfo); - this._deliverEvent(clientId, - "_mobileConnectionListeners", - "notifyDataChanged", - null); - break; - case "RIL:OtaStatusChanged": - this._deliverEvent(clientId, - "_mobileConnectionListeners", - "notifyOtaStatusChanged", - [data]); - break; - case "RIL:GetAvailableNetworks": - this.handleGetAvailableNetworks(data); - break; - case "RIL:NetworkSelectionModeChanged": - this.rilContexts[clientId].networkSelectionMode = data.mode; - break; - case "RIL:SelectNetwork": - this.handleSimpleRequest(data.requestId, data.errorMsg, null); - break; - case "RIL:SelectNetworkAuto": - this.handleSimpleRequest(data.requestId, data.errorMsg, null); - break; - case "RIL:SetPreferredNetworkType": - this.handleSimpleRequest(data.requestId, data.errorMsg, null); - break; - case "RIL:GetPreferredNetworkType": - this.handleSimpleRequest(data.requestId, data.errorMsg, data.type); - break; case "RIL:VoicemailNotification": this.handleVoicemailNotification(clientId, data); break; @@ -1763,16 +938,6 @@ RILContentHelper.prototype = { this.fireRequestError(data.requestId, data.errorMsg); } break; - case "RIL:USSDReceived": - this._deliverEvent(clientId, - "_mobileConnectionListeners", - "notifyUssdReceived", - [data.message, data.sessionEnded]); - break; - case "RIL:SendMMI": - case "RIL:CancelMMI": - this.handleSendCancelMMI(data); - break; case "RIL:StkCommand": this._deliverEvent(clientId, "_iccListeners", "notifyStkCommand", [JSON.stringify(data)]); @@ -1799,47 +964,6 @@ RILContentHelper.prototype = { case "RIL:MatchMvno": this.handleSimpleRequest(data.requestId, data.errorMsg, data.result); break; - case "RIL:DataError": - this.updateConnectionInfo(data, this.rilContexts[clientId].dataConnectionInfo); - this._deliverEvent(clientId, "_mobileConnectionListeners", "notifyDataError", - [data.errorMsg]); - break; - case "RIL:GetCallForwardingOptions": - this.handleGetCallForwardingOptions(data); - break; - case "RIL:SetCallForwardingOptions": - this.handleSimpleRequest(data.requestId, data.errorMsg, null); - break; - case "RIL:GetCallBarringOptions": - this.handleGetCallBarringOptions(data); - break; - case "RIL:SetCallBarringOptions": - this.handleSimpleRequest(data.requestId, data.errorMsg, null); - break; - case "RIL:ChangeCallBarringPassword": - this.handleSimpleRequest(data.requestId, data.errorMsg, null); - break; - case "RIL:GetCallWaitingOptions": - this.handleSimpleRequest(data.requestId, data.errorMsg, - data.enabled); - break; - case "RIL:SetCallWaitingOptions": - this.handleSimpleRequest(data.requestId, data.errorMsg, null); - break; - case "RIL:CfStateChanged": - this._deliverEvent(clientId, - "_mobileConnectionListeners", - "notifyCFStateChange", - [data.success, data.action, - data.reason, data.number, - data.timeSeconds, data.serviceClass]); - break; - case "RIL:GetCallingLineIdRestriction": - this.handleGetCallingLineIdRestriction(data); - break; - case "RIL:SetCallingLineIdRestriction": - this.handleSimpleRequest(data.requestId, data.errorMsg, null); - break; case "RIL:CellBroadcastReceived": { // All CBS messages are to routed the listener for clientId 0 and // provide the |clientId| info by |CellBroadcastMessage.serviceId|. @@ -1850,45 +974,6 @@ RILContentHelper.prototype = { [message]); break; } - case "RIL:SetRoamingPreference": - this.handleSimpleRequest(data.requestId, data.errorMsg, null); - break; - case "RIL:GetRoamingPreference": - this.handleSimpleRequest(data.requestId, data.errorMsg, - data.mode); - break; - case "RIL:ExitEmergencyCbMode": - this.handleExitEmergencyCbMode(data); - break; - case "RIL:EmergencyCbModeChanged": - this._deliverEvent(clientId, - "_mobileConnectionListeners", - "notifyEmergencyCbModeChanged", - [data.active, data.timeoutMs]); - break; - case "RIL:SetRadioEnabled": - this.handleSimpleRequest(data.requestId, data.errorMsg, null); - break; - case "RIL:RadioStateChanged": - this.rilContexts[clientId].radioState = data; - this._deliverEvent(clientId, - "_mobileConnectionListeners", - "notifyRadioStateChanged", - null); - break; - case "RIL:SetVoicePrivacyMode": - this.handleSimpleRequest(data.requestId, data.errorMsg, null); - break; - case "RIL:GetVoicePrivacyMode": - this.handleSimpleRequest(data.requestId, data.errorMsg, - data.enabled); - break; - case "RIL:ClirModeChanged": - this._deliverEvent(clientId, - "_mobileConnectionListeners", - "notifyClirModeChanged", - [data]); - break; } }, @@ -1900,34 +985,6 @@ RILContentHelper.prototype = { } }, - handleGetAvailableNetworks: function(message) { - if (DEBUG) debug("handleGetAvailableNetworks: " + JSON.stringify(message)); - if (message.errorMsg) { - if (DEBUG) { - debug("Received error from getAvailableNetworks: " + message.errorMsg); - } - this.fireRequestError(message.requestId, message.errorMsg); - return; - } - - let requestId = message.requestId; - let requestWindow = this._windowsMap[requestId]; - delete this._windowsMap[requestId]; - - let networks = message.networks; - for (let i = 0; i < networks.length; i++) { - let network = networks[i]; - let info = new requestWindow.MozMobileNetworkInfo(network.shortName, - network.longName, - network.mcc, - network.mnc, - network.state); - networks[i] = info; - } - - this.fireRequestSuccess(message.requestId, networks); - }, - handleIccExchangeAPDU: function(message) { if (message.errorMsg) { this.fireRequestError(message.requestId, message.errorMsg); @@ -2033,102 +1090,6 @@ RILContentHelper.prototype = { } }, - _cfRulesToMobileCfInfo: function(rules) { - for (let i = 0; i < rules.length; i++) { - rules[i] = new MobileCallForwardingInfo(rules[i]); - } - }, - - handleGetCallForwardingOptions: function(message) { - if (message.errorMsg) { - this.fireRequestError(message.requestId, message.errorMsg); - return; - } - - this._cfRulesToMobileCfInfo(message.rules); - this.fireRequestSuccess(message.requestId, message.rules); - }, - - handleGetCallBarringOptions: function(message) { - if (!message.success) { - this.fireRequestError(message.requestId, message.errorMsg); - } else { - let options = new CallBarringOptions(message); - this.fireRequestSuccess(message.requestId, options); - } - }, - - handleGetCallingLineIdRestriction: function(message) { - if (message.errorMsg) { - this.fireRequestError(message.requestId, message.errorMsg); - return; - } - - let status = new DOMCLIRStatus(message); - this.fireRequestSuccess(message.requestId, status); - }, - - handleExitEmergencyCbMode: function(message) { - let requestId = message.requestId; - let request = this.takeRequest(requestId); - if (!request) { - return; - } - - if (!message.success) { - Services.DOMRequest.fireError(request, message.errorMsg); - return; - } - Services.DOMRequest.fireSuccess(request, null); - }, - - handleSendCancelMMI: function(message) { - if (DEBUG) debug("handleSendCancelMMI " + JSON.stringify(message)); - let request = this.takeRequest(message.requestId); - let requestWindow = this._windowsMap[message.requestId]; - delete this._windowsMap[message.requestId]; - if (!request) { - return; - } - - let success = message.success; - - // 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 (message.mmiServiceCode === RIL.MMI_KS_SC_IMEI && - !message.statusMessage) { - message.errorMsg = message.errorMsg ? - message.errorMsg : RIL.GECKO_ERROR_GENERIC_FAILURE; - success = false; - } - - // 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 (message.mmiServiceCode === RIL.MMI_KS_SC_CALL_FORWARDING && - message.additionalInformation) { - this._cfRulesToMobileCfInfo(message.additionalInformation); - } - - let result = { - serviceCode: message.mmiServiceCode || "", - additionalInformation: message.additionalInformation - }; - - if (success) { - result.statusMessage = message.statusMessage; - let mmiResult = new DOMMMIResult(result); - Services.DOMRequest.fireSuccess(request, mmiResult); - } else { - let mmiError = new requestWindow.DOMMMIError(result.serviceCode, - message.errorMsg, - "", - result.additionalInformation); - Services.DOMRequest.fireDetailedError(request, mmiError); - } - }, - _deliverEvent: function(clientId, listenerType, name, args) { if (!this[listenerType]) { return; @@ -2153,86 +1114,6 @@ RILContentHelper.prototype = { if (DEBUG) debug("listener for " + name + " threw an exception: " + e); } } - }, - - /** - * Helper for guarding us against invalid reason values for call forwarding. - */ - _isValidCallForwardingReason: function(reason) { - switch (reason) { - case Ci.nsIMobileConnectionProvider.CALL_FORWARD_REASON_UNCONDITIONAL: - case Ci.nsIMobileConnectionProvider.CALL_FORWARD_REASON_MOBILE_BUSY: - case Ci.nsIMobileConnectionProvider.CALL_FORWARD_REASON_NO_REPLY: - case Ci.nsIMobileConnectionProvider.CALL_FORWARD_REASON_NOT_REACHABLE: - case Ci.nsIMobileConnectionProvider.CALL_FORWARD_REASON_ALL_CALL_FORWARDING: - case Ci.nsIMobileConnectionProvider.CALL_FORWARD_REASON_ALL_CONDITIONAL_CALL_FORWARDING: - return true; - default: - return false; - } - }, - - /** - * Helper for guarding us against invalid action values for call forwarding. - */ - _isValidCallForwardingAction: function(action) { - switch (action) { - case Ci.nsIMobileConnectionProvider.CALL_FORWARD_ACTION_DISABLE: - case Ci.nsIMobileConnectionProvider.CALL_FORWARD_ACTION_ENABLE: - case Ci.nsIMobileConnectionProvider.CALL_FORWARD_ACTION_REGISTRATION: - case Ci.nsIMobileConnectionProvider.CALL_FORWARD_ACTION_ERASURE: - return true; - default: - return false; - } - }, - - /** - * Helper for guarding us against invalid program values for call barring. - */ - _isValidCallBarringProgram: function(program) { - switch (program) { - case Ci.nsIMobileConnectionProvider.CALL_BARRING_PROGRAM_ALL_OUTGOING: - case Ci.nsIMobileConnectionProvider.CALL_BARRING_PROGRAM_OUTGOING_INTERNATIONAL: - case Ci.nsIMobileConnectionProvider.CALL_BARRING_PROGRAM_OUTGOING_INTERNATIONAL_EXCEPT_HOME: - case Ci.nsIMobileConnectionProvider.CALL_BARRING_PROGRAM_ALL_INCOMING: - case Ci.nsIMobileConnectionProvider.CALL_BARRING_PROGRAM_INCOMING_ROAMING: - return true; - default: - return false; - } - }, - - /** - * Helper for guarding us against invalid options for call barring. - */ - _isValidCallBarringOptions: function(options, usedForSetting) { - if (!options || - options.serviceClass == null || - !this._isValidCallBarringProgram(options.program)) { - return false; - } - - // For setting callbarring options, |enabled| and |password| are required. - if (usedForSetting && (options.enabled == null || options.password == null)) { - return false; - } - - return true; - }, - - /** - * Helper for guarding us against invalid mode for clir. - */ - _isValidClirMode: function(mode) { - switch (mode) { - case Ci.nsIMobileConnectionProvider.CLIR_DEFAULT: - case Ci.nsIMobileConnectionProvider.CLIR_INVOCATION: - case Ci.nsIMobileConnectionProvider.CLIR_SUPPRESSION: - return true; - default: - return false; - } } }; diff --git a/dom/system/gonk/RadioInterfaceLayer.js b/dom/system/gonk/RadioInterfaceLayer.js index b27bcd0df5b..ae68cb14024 100644 --- a/dom/system/gonk/RadioInterfaceLayer.js +++ b/dom/system/gonk/RadioInterfaceLayer.js @@ -72,7 +72,6 @@ const LTECELLINFO_CID = const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown"; const kNetworkConnStateChangedTopic = "network-connection-state-changed"; -const kNetworkActiveChangedTopic = "network-active-changed"; const kSmsReceivedObserverTopic = "sms-received"; const kSilentSmsReceivedObserverTopic = "silent-sms-received"; const kSmsSendingObserverTopic = "sms-sending"; @@ -109,40 +108,8 @@ const HW_DEFAULT_CLIENT_ID = 0; const INT32_MAX = 2147483647; const UNKNOWN_RSSI = 99; -const RIL_IPC_MOBILECONNECTION_MSG_NAMES = [ - "RIL:GetRilContext", - "RIL:GetAvailableNetworks", - "RIL:SelectNetwork", - "RIL:SelectNetworkAuto", - "RIL:SetPreferredNetworkType", - "RIL:GetPreferredNetworkType", - "RIL:SendMMI", - "RIL:CancelMMI", - "RIL:RegisterMobileConnectionMsg", - "RIL:SetCallForwardingOptions", - "RIL:GetCallForwardingOptions", - "RIL:SetCallBarringOptions", - "RIL:GetCallBarringOptions", - "RIL:ChangeCallBarringPassword", - "RIL:SetCallWaitingOptions", - "RIL:GetCallWaitingOptions", - "RIL:SetCallingLineIdRestriction", - "RIL:GetCallingLineIdRestriction", - "RIL:SetRoamingPreference", - "RIL:GetRoamingPreference", - "RIL:ExitEmergencyCbMode", - "RIL:SetRadioEnabled", - "RIL:SetVoicePrivacyMode", - "RIL:GetVoicePrivacyMode", - "RIL:GetSupportedNetworkTypes" -]; - -const RIL_IPC_MOBILENETWORK_MSG_NAMES = [ - "RIL:GetLastKnownNetwork", - "RIL:GetLastKnownHomeNetwork" -]; - const RIL_IPC_ICCMANAGER_MSG_NAMES = [ + "RIL:GetRilContext", "RIL:SendStkResponse", "RIL:SendStkMenuSelection", "RIL:SendStkTimerExpiration", @@ -232,6 +199,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "gTelephonyService", "@mozilla.org/telephony/telephonyservice;1", "nsIGonkTelephonyService"); +XPCOMUtils.defineLazyServiceGetter(this, "gMobileConnectionService", + "@mozilla.org/mobileconnection/mobileconnectionservice;1", + "nsIMobileConnectionGonkService"); + XPCOMUtils.defineLazyGetter(this, "WAP", function() { let wap = {}; Cu.import("resource://gre/modules/WapPushManager.js", wap); @@ -276,12 +247,6 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function() { _registerMessageListeners: function() { ppmm.addMessageListener("child-process-shutdown", this); - for (let msgname of RIL_IPC_MOBILECONNECTION_MSG_NAMES) { - ppmm.addMessageListener(msgname, this); - } - for (let msgname of RIL_IPC_MOBILENETWORK_MSG_NAMES) { - ppmm.addMessageListener(msgname, this); - } for (let msgName of RIL_IPC_ICCMANAGER_MSG_NAMES) { ppmm.addMessageListener(msgName, this); } @@ -295,12 +260,6 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function() { _unregisterMessageListeners: function() { ppmm.removeMessageListener("child-process-shutdown", this); - for (let msgname of RIL_IPC_MOBILECONNECTION_MSG_NAMES) { - ppmm.removeMessageListener(msgname, this); - } - for (let msgname of RIL_IPC_MOBILENETWORK_MSG_NAMES) { - ppmm.removeMessageListener(msgname, this); - } for (let msgName of RIL_IPC_ICCMANAGER_MSG_NAMES) { ppmm.removeMessageListener(msgName, this); } @@ -417,23 +376,7 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function() { return null; } - if (RIL_IPC_MOBILECONNECTION_MSG_NAMES.indexOf(msg.name) != -1) { - if (!msg.target.assertPermission("mobileconnection")) { - if (DEBUG) { - debug("MobileConnection message " + msg.name + - " from a content process with no 'mobileconnection' privileges."); - } - return null; - } - } else if (RIL_IPC_MOBILENETWORK_MSG_NAMES.indexOf(msg.name) != -1) { - if (!msg.target.assertPermission("mobilenetwork")) { - if (DEBUG) { - debug("MobileNetwork message " + msg.name + - " from a content process with no 'mobilenetwork' privileges."); - } - return null; - } - } else if (RIL_IPC_ICCMANAGER_MSG_NAMES.indexOf(msg.name) != -1) { + if (RIL_IPC_ICCMANAGER_MSG_NAMES.indexOf(msg.name) != -1) { if (!msg.target.assertPermission("mobileconnection")) { if (DEBUG) { debug("IccManager message " + msg.name + @@ -463,9 +406,6 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function() { } switch (msg.name) { - case "RIL:RegisterMobileConnectionMsg": - this._registerMessageTarget("mobileconnection", msg.target); - return null; case "RIL:RegisterIccMsg": this._registerMessageTarget("icc", msg.target); return null; @@ -484,11 +424,6 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function() { return null; } - if (msg.name === "RIL:SetRadioEnabled") { - // Special handler for SetRadioEnabled. - return gRadioEnabledController.receiveMessage(msg); - } - return radioInterface.receiveMessage(msg); }, @@ -540,7 +475,7 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function() { XPCOMUtils.defineLazyGetter(this, "gRadioEnabledController", function() { let _ril = null; - let _pendingMessages = []; // For queueing "RIL =SetRadioEnabled" messages. + let _pendingMessages = []; // For queueing "setRadioEnabled" message. let _isProcessingPending = false; let _timer = null; let _request = null; @@ -566,9 +501,14 @@ XPCOMUtils.defineLazyGetter(this, "gRadioEnabledController", function() { } }, - receiveMessage: function(msg) { - if (DEBUG) debug("RadioControl: receiveMessage: " + JSON.stringify(msg)); - _pendingMessages.push(msg); + setRadioEnabled: function(clientId, data, callback) { + if (DEBUG) debug("setRadioEnabled: " + clientId + ": " + JSON.stringify(data)); + let message = { + clientId: clientId, + data: data, + callback: callback + }; + _pendingMessages.push(message); this._startProcessingPending(); }, @@ -584,6 +524,10 @@ XPCOMUtils.defineLazyGetter(this, "gRadioEnabledController", function() { } }, + notifyRadioStateChanged: function(clientId, radioState) { + gMobileConnectionService.notifyRadioStateChanged(clientId, radioState); + }, + _startProcessingPending: function() { if (!_isProcessingPending) { if (DEBUG) debug("RadioControl: start dequeue"); @@ -616,7 +560,7 @@ XPCOMUtils.defineLazyGetter(this, "gRadioEnabledController", function() { _isCardPresentAtClient: function(clientId) { let cardState = _ril.getRadioInterface(clientId).rilContext.cardState; return cardState !== RIL.GECKO_CARDSTATE_UNDETECTED && - cardState !== RIL.GECKO_CARDSTATE_UNKNOWN; + cardState !== RIL.GECKO_CARDSTATE_UNKNOWN; }, _isRadioAbleToEnableAtClient: function(clientId, numCards) { @@ -640,37 +584,47 @@ XPCOMUtils.defineLazyGetter(this, "gRadioEnabledController", function() { return false; }, - _handleMessage: function(msg) { - if (DEBUG) debug("RadioControl: handleMessage: " + JSON.stringify(msg)); - let clientId = msg.json.clientId || 0; + _isValidStateForSetRadioEnabled: function(clientId) { + let radioState = gMobileConnectionService.getRadioState(clientId); + return radioState == RIL.GECKO_RADIOSTATE_ENABLED || + radioState == RIL.GECKO_RADIOSTATE_DISABLED; + }, + + _isDummyForSetRadioEnabled: function(clientId, data) { + let radioState = gMobileConnectionService.getRadioState(clientId); + return (radioState == RIL.GECKO_RADIOSTATE_ENABLED && data.enabled) || + (radioState == RIL.GECKO_RADIOSTATE_DISABLED && !data.enabled); + }, + + _handleMessage: function(message) { + if (DEBUG) debug("RadioControl: handleMessage: " + JSON.stringify(message)); + let clientId = message.clientId || 0; let radioInterface = _ril.getRadioInterface(clientId); - if (!radioInterface.isValidStateForSetRadioEnabled()) { - radioInterface.setRadioEnabledResponse(msg.target, msg.json.data, - "InvalidStateError"); + if (!this._isValidStateForSetRadioEnabled(clientId)) { + message.data.errorMsg = "InvalidStateError"; + message.callback(message.data); this._processNextMessage(); return; } - if (radioInterface.isDummyForSetRadioEnabled(msg.json.data)) { - radioInterface.setRadioEnabledResponse(msg.target, msg.json.data); + if (this._isDummyForSetRadioEnabled(clientId, message.data)) { + message.callback(message.data); this._processNextMessage(); return; } - if (msg.json.data.enabled) { + if (message.data.enabled) { if (this._isRadioAbleToEnableAtClient(clientId)) { - radioInterface.receiveMessage(msg); + this._setRadioEnabledInternal(message); } else { // Not really do it but respond success. - radioInterface.setRadioEnabledResponse(msg.target, msg.json.data); + message.callback(message.data); } this._processNextMessage(); } else { - _request = function() { - radioInterface.receiveMessage(msg); - }; + _request = this._setRadioEnabledInternal.bind(this, message); // In 2G network, modem takes 35+ seconds to process deactivate data // call request if device has active voice call (please see bug 964974 @@ -694,6 +648,27 @@ XPCOMUtils.defineLazyGetter(this, "gRadioEnabledController", function() { } }, + _setRadioEnabledInternal: function(message) { + let clientId = message.clientId || 0; + let enabled = message.data.enabled || false; + let radioInterface = _ril.getRadioInterface(clientId); + + this.notifyRadioStateChanged(clientId, + enabled ? RIL.GECKO_RADIOSTATE_ENABLING + : RIL.GECKO_RADIOSTATE_DISABLING); + radioInterface.workerMessenger.send("setRadioEnabled", message.data, + (function(response) { + if (response.errorMsg) { + // Request fails. Rollback to the original radioState. + this.notifyRadioStateChanged(clientId, + enabled ? RIL.GECKO_RADIOSTATE_DISABLED + : RIL.GECKO_RADIOSTATE_ENABLED); + } + message.callback(response); + return false; + }).bind(this)); + }, + _deactivateDataCalls: function() { if (DEBUG) debug("RadioControl: deactivating data calls..."); _deactivatingDeferred = {}; @@ -1429,8 +1404,8 @@ DataConnectionHandler.prototype = { // This check avoids data call connection if the radio is not ready // yet after toggling off airplane mode. - let rilContext = this.radioInterface.rilContext; - if (rilContext.radioState != RIL.GECKO_RADIOSTATE_READY) { + let radioState = gMobileConnectionService.getRadioState(this.clientId); + if (radioState != RIL.GECKO_RADIOSTATE_ENABLED) { if (DEBUG) { this.debug("RIL is not ready for data connection: radio's not ready"); } @@ -1449,7 +1424,7 @@ DataConnectionHandler.prototype = { return; } - let dataInfo = rilContext.data; + let dataInfo = gMobileConnectionService.getDataConnectionInfo(this.clientId); let isRegistered = dataInfo.state == RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED; let haveDataConnection = @@ -1512,10 +1487,9 @@ DataConnectionHandler.prototype = { return; } - let detailedRadioState = rilContext.detailedRadioState; if (gRadioEnabledController.isDeactivatingDataCalls() || - detailedRadioState == RIL.GECKO_DETAILED_RADIOSTATE_ENABLING || - detailedRadioState == RIL.GECKO_DETAILED_RADIOSTATE_DISABLING) { + radioState == RIL.GECKO_RADIOSTATE_ENABLING || + radioState == RIL.GECKO_RADIOSTATE_DISABLING) { // We're changing the radio power currently, ignore any changes. return; } @@ -1589,8 +1563,7 @@ DataConnectionHandler.prototype = { if (networkInterface && networkInterface.enabled) { let apnSetting = networkInterface.apnSetting; if (message.apn == apnSetting.apn) { - gMessageManager.sendMobileConnectionMessage("RIL:DataError", - this.clientId, message); + gMobileConnectionService.notifyDataError(this.clientId, message); } } @@ -1899,36 +1872,10 @@ function RadioInterface(aClientId, aWorkerMessenger) { }; aWorkerMessenger.registerClient(aClientId, this); - this.supportedNetworkTypes = this.getSupportedNetworkTypes(); - this.rilContext = { - radioState: RIL.GECKO_RADIOSTATE_UNAVAILABLE, - detailedRadioState: null, cardState: RIL.GECKO_CARDSTATE_UNKNOWN, - networkSelectionMode: RIL.GECKO_NETWORK_SELECTION_UNKNOWN, iccInfo: null, - imsi: null, - - // These objects implement the nsIMobileConnectionInfo interface, - // although the actual implementation lives in the content process. So are - // the child attributes `network` and `cell`, which implement - // nsIMobileNetworkInfo and nsIMobileCellInfo respectively. - voice: {connected: false, - emergencyCallsOnly: false, - roaming: false, - network: null, - cell: null, - type: null, - signalStrength: null, - relSignalStrength: null}, - data: {connected: false, - emergencyCallsOnly: false, - roaming: false, - network: null, - cell: null, - type: null, - signalStrength: null, - relSignalStrength: null}, + imsi: null }; this.voicemailInfo = { @@ -1985,7 +1932,6 @@ function RadioInterface(aClientId, aWorkerMessenger) { Services.obs.addObserver(this, kScreenStateChangedTopic, false); Services.obs.addObserver(this, kNetworkConnStateChangedTopic, false); - Services.obs.addObserver(this, kNetworkActiveChangedTopic, false); this.portAddressedSmsApps = {}; this.portAddressedSmsApps[WAP.WDP_PORT_PUSH] = this.handleSmsWdpPortPush.bind(this); @@ -2026,7 +1972,6 @@ RadioInterface.prototype = { Services.obs.removeObserver(this, kSysClockChangeObserverTopic); Services.obs.removeObserver(this, kScreenStateChangedTopic); Services.obs.removeObserver(this, kNetworkConnStateChangedTopic); - Services.obs.removeObserver(this, kNetworkActiveChangedTopic); }, /** @@ -2063,26 +2008,6 @@ RadioInterface.prototype = { return false; }, - /** - * A utility function to get supportedNetworkTypes from system property - */ - getSupportedNetworkTypes: function() { - let key = "ro.moz.ril." + this.clientId + ".network_types"; - let supportedNetworkTypes = libcutils.property_get(key, "").split(","); - for (let type of supportedNetworkTypes) { - // If the value in system property is not valid, use the default one which - // is defined in ril_consts.js. - if (RIL.GECKO_SUPPORTED_NETWORK_TYPES.indexOf(type) < 0) { - if (DEBUG) this.debug("Unknown network type: " + type); - supportedNetworkTypes = - RIL.GECKO_SUPPORTED_NETWORK_TYPES_DEFAULT.split(","); - break; - } - } - if (DEBUG) this.debug("Supported Network Types: " + supportedNetworkTypes); - return supportedNetworkTypes; - }, - /** * Process a message from the content process. */ @@ -2091,27 +2016,6 @@ RadioInterface.prototype = { case "RIL:GetRilContext": // This message is sync. return this.rilContext; - case "RIL:GetLastKnownNetwork": - // This message is sync. - return this._lastKnownNetwork; - case "RIL:GetLastKnownHomeNetwork": - // This message is sync. - return this._lastKnownHomeNetwork; - case "RIL:GetAvailableNetworks": - this.workerMessenger.sendWithIPCMessage(msg, "getAvailableNetworks"); - break; - case "RIL:SelectNetwork": - this.selectNetwork(msg.target, msg.json.data); - break; - case "RIL:SelectNetworkAuto": - this.selectNetworkAuto(msg.target, msg.json.data); - break; - case "RIL:SetPreferredNetworkType": - this.setPreferredNetworkType(msg.target, msg.json.data); - break; - case "RIL:GetPreferredNetworkType": - this.getPreferredNetworkType(msg.target, msg.json.data); - break; case "RIL:GetCardLockState": this.workerMessenger.sendWithIPCMessage(msg, "iccGetCardLockState", "RIL:CardLockResult"); @@ -2128,12 +2032,6 @@ RadioInterface.prototype = { this.workerMessenger.sendWithIPCMessage(msg, "iccGetCardLockRetryCount", "RIL:CardLockRetryCount"); break; - case "RIL:SendMMI": - this.sendMMI(msg.target, msg.json.data); - break; - case "RIL:CancelMMI": - this.workerMessenger.sendWithIPCMessage(msg, "cancelUSSD"); - break; case "RIL:SendStkResponse": this.workerMessenger.send("sendStkTerminalResponse", msg.json.data); break; @@ -2164,57 +2062,9 @@ RadioInterface.prototype = { case "RIL:MatchMvno": this.matchMvno(msg.target, msg.json.data); break; - case "RIL:SetCallForwardingOptions": - this.setCallForwardingOptions(msg.target, msg.json.data); - break; - case "RIL:GetCallForwardingOptions": - this.workerMessenger.sendWithIPCMessage(msg, "queryCallForwardStatus"); - break; - case "RIL:SetCallBarringOptions": - this.workerMessenger.sendWithIPCMessage(msg, "setCallBarring"); - break; - case "RIL:GetCallBarringOptions": - this.workerMessenger.sendWithIPCMessage(msg, "queryCallBarringStatus"); - break; - case "RIL:ChangeCallBarringPassword": - this.workerMessenger.sendWithIPCMessage(msg, "changeCallBarringPassword"); - break; - case "RIL:SetCallWaitingOptions": - this.workerMessenger.sendWithIPCMessage(msg, "setCallWaiting"); - break; - case "RIL:GetCallWaitingOptions": - this.workerMessenger.sendWithIPCMessage(msg, "queryCallWaiting"); - break; - case "RIL:SetCallingLineIdRestriction": - this.setCallingLineIdRestriction(msg.target, msg.json.data); - break; - case "RIL:GetCallingLineIdRestriction": - this.workerMessenger.sendWithIPCMessage(msg, "getCLIR"); - break; - case "RIL:ExitEmergencyCbMode": - this.workerMessenger.sendWithIPCMessage(msg, "exitEmergencyCbMode"); - break; - case "RIL:SetRadioEnabled": - this.setRadioEnabled(msg.target, msg.json.data); - break; case "RIL:GetVoicemailInfo": // This message is sync. return this.voicemailInfo; - case "RIL:SetRoamingPreference": - this.workerMessenger.sendWithIPCMessage(msg, "setRoamingPreference"); - break; - case "RIL:GetRoamingPreference": - this.workerMessenger.sendWithIPCMessage(msg, "queryRoamingPreference"); - break; - case "RIL:SetVoicePrivacyMode": - this.workerMessenger.sendWithIPCMessage(msg, "setVoicePrivacyMode"); - break; - case "RIL:GetVoicePrivacyMode": - this.workerMessenger.sendWithIPCMessage(msg, "queryVoicePrivacyMode"); - break; - case "RIL:GetSupportedNetworkTypes": - // This message is sync. - return this.supportedNetworkTypes; } return null; }, @@ -2239,8 +2089,8 @@ RadioInterface.prototype = { break; case "suppSvcNotification": gTelephonyService.notifySupplementaryService(this.clientId, - message.callIndex, - message.notification); + message.callIndex, + message.notification); break; case "datacallerror": connHandler.handleDataCallError(message); @@ -2260,31 +2110,45 @@ RadioInterface.prototype = { connHandler.handleDataCallState(message); break; case "emergencyCbModeChange": - this.handleEmergencyCbModeChange(message); + gMobileConnectionService.notifyEmergencyCallbackModeChanged(this.clientId, + message); break; case "networkinfochanged": - this.updateNetworkInfo(message); + gMobileConnectionService.notifyNetworkInfoChanged(this.clientId, + message); + connHandler.updateRILNetworkInterface(); break; case "networkselectionmodechange": - this.updateNetworkSelectionMode(message); + gMobileConnectionService.notifyNetworkSelectModeChanged(this.clientId, + message.mode); break; case "voiceregistrationstatechange": - this.updateVoiceConnection(message); + gMobileConnectionService.notifyVoiceInfoChanged(this.clientId, message); break; case "dataregistrationstatechange": - this.updateDataConnection(message); + gMobileConnectionService.notifyDataInfoChanged(this.clientId, message); + connHandler.updateRILNetworkInterface(); break; case "signalstrengthchange": - this.handleSignalStrengthChange(message); + gMobileConnectionService.notifySignalStrengthChanged(this.clientId, + message); break; case "operatorchange": - this.handleOperatorChange(message); + gMobileConnectionService.notifyOperatorChanged(this.clientId, message); break; case "otastatuschange": - this.handleOtaStatus(message); + gMobileConnectionService.notifyOtaStatusChanged(this.clientId, message.status); break; case "radiostatechange": - this.handleRadioStateChange(message); + // gRadioEnabledController should know the radio state for each client, + // so notify gRadioEnabledController here. + gRadioEnabledController.notifyRadioStateChanged(this.clientId, + message.radioState); + break; + case "ussdreceived": + gMobileConnectionService.notifyUssdReceived(this.clientId, + message.message, + message.sessionEnded); break; case "cardstatechange": this.rilContext.cardState = message.cardState; @@ -2317,18 +2181,12 @@ RadioInterface.prototype = { gMessageManager.sendVoicemailMessage("RIL:VoicemailNotification", this.clientId, message.mwi); break; - case "ussdreceived": - this.handleUSSDReceived(message); - break; case "stkcommand": this.handleStkProactiveCommand(message); break; case "stksessionend": gMessageManager.sendIccMessage("RIL:StkSessionEnd", this.clientId, null); break; - case "exitEmergencyCbMode": - this.handleExitEmergencyCbMode(message); - break; case "cdma-info-rec-received": if (DEBUG) this.debug("cdma-info-rec-received: " + JSON.stringify(message)); gSystemMessenger.broadcastMessage("cdma-info-rec-received", message); @@ -2468,223 +2326,6 @@ RadioInterface.prototype = { }); }, - updateNetworkInfo: function(message) { - let voiceMessage = message[RIL.NETWORK_INFO_VOICE_REGISTRATION_STATE]; - let dataMessage = message[RIL.NETWORK_INFO_DATA_REGISTRATION_STATE]; - let operatorMessage = message[RIL.NETWORK_INFO_OPERATOR]; - let selectionMessage = message[RIL.NETWORK_INFO_NETWORK_SELECTION_MODE]; - let signalMessage = message[RIL.NETWORK_INFO_SIGNAL]; - - // Batch the *InfoChanged messages together - if (voiceMessage) { - this.updateVoiceConnection(voiceMessage, true); - } - - if (dataMessage) { - this.updateDataConnection(dataMessage, true); - } - - if (operatorMessage) { - this.handleOperatorChange(operatorMessage, true); - } - - if (signalMessage) { - this.handleSignalStrengthChange(signalMessage, true); - } - - let voice = this.rilContext.voice; - let data = this.rilContext.data; - - this.checkRoamingBetweenOperators(voice); - this.checkRoamingBetweenOperators(data); - - if (voiceMessage || operatorMessage || signalMessage) { - gMessageManager.sendMobileConnectionMessage("RIL:VoiceInfoChanged", - this.clientId, voice); - } - if (dataMessage || operatorMessage || signalMessage) { - gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged", - this.clientId, data); - } - - if (selectionMessage) { - this.updateNetworkSelectionMode(selectionMessage); - } - }, - - /** - * Fix the roaming. RIL can report roaming in some case it is not - * really the case. See bug 787967 - * - * @param registration The voiceMessage or dataMessage from which the - * roaming state will be changed (maybe, if needed). - */ - checkRoamingBetweenOperators: function(registration) { - let iccInfo = this.rilContext.iccInfo; - let operator = registration.network; - let state = registration.state; - - if (!iccInfo || !operator || - state != RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED) { - return; - } - - let spn = iccInfo.spn && iccInfo.spn.toLowerCase(); - let longName = operator.longName && operator.longName.toLowerCase(); - let shortName = operator.shortName && operator.shortName.toLowerCase(); - - let equalsLongName = longName && (spn == longName); - let equalsShortName = shortName && (spn == shortName); - let equalsMcc = iccInfo.mcc == operator.mcc; - - registration.roaming = registration.roaming && - !(equalsMcc && (equalsLongName || equalsShortName)); - }, - - /** - * Handle data connection changes. - * - * @param newInfo The new voice connection information. - * @param batch When batch is true, the RIL:VoiceInfoChanged message will - * not be sent. - */ - updateVoiceConnection: function(newInfo, batch) { - let voiceInfo = this.rilContext.voice; - voiceInfo.state = newInfo.state; - voiceInfo.connected = newInfo.connected; - voiceInfo.roaming = newInfo.roaming; - voiceInfo.emergencyCallsOnly = newInfo.emergencyCallsOnly; - voiceInfo.type = newInfo.type; - - // Make sure we also reset the operator and signal strength information - // if we drop off the network. - if (newInfo.state !== RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED) { - voiceInfo.cell = null; - voiceInfo.network = null; - voiceInfo.signalStrength = null; - voiceInfo.relSignalStrength = null; - } else { - voiceInfo.cell = newInfo.cell; - voiceInfo.network = this.operatorInfo; - } - - if (!batch) { - gMessageManager.sendMobileConnectionMessage("RIL:VoiceInfoChanged", - this.clientId, voiceInfo); - } - }, - - /** - * Handle the data connection's state has changed. - * - * @param newInfo The new data connection information. - * @param batch When batch is true, the RIL:DataInfoChanged message will - * not be sent. - */ - updateDataConnection: function(newInfo, batch) { - let dataInfo = this.rilContext.data; - dataInfo.state = newInfo.state; - dataInfo.roaming = newInfo.roaming; - dataInfo.emergencyCallsOnly = newInfo.emergencyCallsOnly; - dataInfo.type = newInfo.type; - // For the data connection, the `connected` flag indicates whether - // there's an active data call. - dataInfo.connected = false; - if (gNetworkManager.active && - gNetworkManager.active.type === - Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE && - gNetworkManager.active.serviceId === this.clientId) { - dataInfo.connected = true; - } - - // Make sure we also reset the operator and signal strength information - // if we drop off the network. - if (newInfo.state !== RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED) { - dataInfo.cell = null; - dataInfo.network = null; - dataInfo.signalStrength = null; - dataInfo.relSignalStrength = null; - } else { - dataInfo.cell = newInfo.cell; - dataInfo.network = this.operatorInfo; - } - - if (!batch) { - gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged", - this.clientId, dataInfo); - } - - let connHandler = gDataConnectionManager.getConnectionHandler(this.clientId); - connHandler.updateRILNetworkInterface(); - }, - - getPreferredNetworkType: function(target, message) { - this.workerMessenger.send("getPreferredNetworkType", message, (function(response) { - target.sendAsyncMessage("RIL:GetPreferredNetworkType", { - clientId: this.clientId, - data: response - }); - return false; - }).bind(this)); - }, - - setPreferredNetworkType: function(target, message) { - this.workerMessenger.send("setPreferredNetworkType", message, (function(response) { - target.sendAsyncMessage("RIL:SetPreferredNetworkType", { - clientId: this.clientId, - data: response - }); - return false; - }).bind(this)); - }, - - /** - * The network that is currently trying to be selected (or "automatic"). - * This helps ensure that only one network per client is selected at a time. - */ - _selectingNetwork: null, - - selectNetwork: function(target, message) { - if (this._selectingNetwork) { - message.errorMsg = "AlreadySelectingANetwork"; - target.sendAsyncMessage("RIL:SelectNetwork", { - clientId: this.clientId, - data: message - }); - return; - } - - this._selectingNetwork = message; - this.workerMessenger.send("selectNetwork", message, (function(response) { - this._selectingNetwork = null; - target.sendAsyncMessage("RIL:SelectNetwork", { - clientId: this.clientId, - data: response - }); - return false; - }).bind(this)); - }, - - selectNetworkAuto: function(target, message) { - if (this._selectingNetwork) { - message.errorMsg = "AlreadySelectingANetwork"; - target.sendAsyncMessage("RIL:SelectNetworkAuto", { - clientId: this.clientId, - data: message - }); - return; - } - - this._selectingNetwork = "automatic"; - this.workerMessenger.send("selectNetworkAuto", message, (function(response) { - this._selectingNetwork = null; - target.sendAsyncMessage("RIL:SelectNetworkAuto", { - clientId: this.clientId, - data: response - }); - }).bind(this)); - }, - setCellBroadcastSearchList: function(settings) { let newSearchList = Array.isArray(settings) ? settings[this.clientId] : settings; @@ -2715,114 +2356,6 @@ RadioInterface.prototype = { }).bind(this)); }, - /** - * Handle signal strength changes. - * - * @param message The new signal strength. - * @param batch When batch is true, the RIL:VoiceInfoChanged and - * RIL:DataInfoChanged message will not be sent. - */ - handleSignalStrengthChange: function(message, batch) { - let voiceInfo = this.rilContext.voice; - // If the voice is not registered, need not to update signal information. - if (voiceInfo.state === RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED && - this.isInfoChanged(message.voice, voiceInfo)) { - this.updateInfo(message.voice, voiceInfo); - if (!batch) { - gMessageManager.sendMobileConnectionMessage("RIL:VoiceInfoChanged", - this.clientId, voiceInfo); - } - } - - let dataInfo = this.rilContext.data; - // If the data is not registered, need not to update signal information. - if (dataInfo.state === RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED && - this.isInfoChanged(message.data, dataInfo)) { - this.updateInfo(message.data, dataInfo); - if (!batch) { - gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged", - this.clientId, dataInfo); - } - } - }, - - /** - * Handle operator information changes. - * - * @param message The new operator information. - * @param batch When batch is true, the RIL:VoiceInfoChanged and - * RIL:DataInfoChanged message will not be sent. - */ - handleOperatorChange: function(message, batch) { - let operatorInfo = this.operatorInfo; - let voice = this.rilContext.voice; - let data = this.rilContext.data; - - if (this.isInfoChanged(message, operatorInfo)) { - this.updateInfo(message, operatorInfo); - - // Update lastKnownNetwork - if (message.mcc && message.mnc) { - this._lastKnownNetwork = message.mcc + "-" + message.mnc; - } - - // If the voice is unregistered, no need to send RIL:VoiceInfoChanged. - if (voice.network && !batch) { - gMessageManager.sendMobileConnectionMessage("RIL:VoiceInfoChanged", - this.clientId, voice); - } - - // If the data is unregistered, no need to send RIL:DataInfoChanged. - if (data.network && !batch) { - gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged", - this.clientId, data); - } - } - }, - - handleOtaStatus: function(message) { - if (message.status < 0 || - RIL.CDMA_OTA_PROVISION_STATUS_TO_GECKO.length <= message.status) { - return; - } - - let status = RIL.CDMA_OTA_PROVISION_STATUS_TO_GECKO[message.status]; - - gMessageManager.sendMobileConnectionMessage("RIL:OtaStatusChanged", - this.clientId, status); - }, - - _convertRadioState: function(state) { - switch (state) { - case RIL.GECKO_RADIOSTATE_OFF: - return RIL.GECKO_DETAILED_RADIOSTATE_DISABLED; - case RIL.GECKO_RADIOSTATE_READY: - return RIL.GECKO_DETAILED_RADIOSTATE_ENABLED; - default: - return RIL.GECKO_DETAILED_RADIOSTATE_UNKNOWN; - } - }, - - handleRadioStateChange: function(message) { - let newState = message.radioState; - if (this.rilContext.radioState == newState) { - return; - } - this.rilContext.radioState = newState; - this.handleDetailedRadioStateChanged(this._convertRadioState(newState)); - - //TODO Should we notify this change as a card state change? - }, - - handleDetailedRadioStateChanged: function(state) { - if (this.rilContext.detailedRadioState == state) { - return; - } - this.rilContext.detailedRadioState = state; - gMessageManager.sendMobileConnectionMessage("RIL:RadioStateChanged", - this.clientId, state); - }, - setDataRegistration: function(attach) { let deferred = Promise.defer(); this.workerMessenger.send("setDataRegistration", @@ -2844,25 +2377,6 @@ RadioInterface.prototype = { connHandler.updateRILNetworkInterface(); }, - /** - * Update network selection mode - */ - updateNetworkSelectionMode: function(message) { - if (DEBUG) this.debug("updateNetworkSelectionMode: " + JSON.stringify(message)); - this.rilContext.networkSelectionMode = message.mode; - gMessageManager.sendMobileConnectionMessage("RIL:NetworkSelectionModeChanged", - this.clientId, message); - }, - - /** - * Handle emergency callback mode change. - */ - handleEmergencyCbModeChange: function(message) { - if (DEBUG) this.debug("handleEmergencyCbModeChange: " + JSON.stringify(message)); - gMessageManager.sendMobileConnectionMessage("RIL:EmergencyCbModeChanged", - this.clientId, message); - }, - /** * Handle WDP port push PDU. Constructor WDP bearer information and deliver * to WapPushManager. @@ -3488,6 +3002,11 @@ RadioInterface.prototype = { this.clientId, message.iccid ? message : null); + // In bug 864489, icc related code will be move to IccGonkProvider, we may + // need a better way to notify icc change to MobileConnectionGonkProvider. + gMobileConnectionService.notifyIccChanged(this.clientId, + message.iccid || null); + // Update lastKnownSimMcc. if (message.mcc) { try { @@ -3498,41 +3017,22 @@ RadioInterface.prototype = { // Update lastKnownHomeNetwork. if (message.mcc && message.mnc) { - this._lastKnownHomeNetwork = message.mcc + "-" + message.mnc; + let lastKnownHomeNetwork = message.mcc + "-" + message.mnc; // Append spn information if available. if (message.spn) { - this._lastKnownHomeNetwork += "-" + message.spn; + lastKnownHomeNetwork += "-" + message.spn; } + + gMobileConnectionService.notifyLastHomeNetworkChanged(this.clientId, + lastKnownHomeNetwork); } // If spn becomes available, we should check roaming again. if (!oldSpn && message.spn) { - let voice = this.rilContext.voice; - let data = this.rilContext.data; - let voiceRoaming = voice.roaming; - let dataRoaming = data.roaming; - this.checkRoamingBetweenOperators(voice); - this.checkRoamingBetweenOperators(data); - if (voiceRoaming != voice.roaming) { - gMessageManager.sendMobileConnectionMessage("RIL:VoiceInfoChanged", - this.clientId, voice); - } - if (dataRoaming != data.roaming) { - gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged", - this.clientId, data); - } + gMobileConnectionService.notifySpnAvailable(this.clientId); } }, - handleUSSDReceived: function(ussd) { - gSystemMessenger.broadcastMessage("ussd-received", - {message: ussd.message, - sessionEnded: ussd.sessionEnded, - serviceId: this.clientId}); - gMessageManager.sendMobileConnectionMessage("RIL:USSDReceived", - this.clientId, ussd); - }, - handleStkProactiveCommand: function(message) { if (DEBUG) this.debug("handleStkProactiveCommand " + JSON.stringify(message)); let iccId = this.rilContext.iccInfo && this.rilContext.iccInfo.iccid; @@ -3544,11 +3044,6 @@ RadioInterface.prototype = { gMessageManager.sendIccMessage("RIL:StkCommand", this.clientId, message); }, - handleExitEmergencyCbMode: function(message) { - if (DEBUG) this.debug("handleExitEmergencyCbMode: " + JSON.stringify(message)); - gMessageManager.sendRequestResults("RIL:ExitEmergencyCbMode", message); - }, - // nsIObserver observe: function(subject, topic, data) { @@ -3589,29 +3084,12 @@ RadioInterface.prototype = { this._sntp.request(); } break; - case kNetworkActiveChangedTopic: - let dataInfo = this.rilContext.data; - let connected = false; - if (gNetworkManager.active && - gNetworkManager.active.type === - Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE && - gNetworkManager.active.serviceId === this.clientId) { - connected = true; - } - if (dataInfo.connected !== connected) { - dataInfo.connected = connected; - gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged", - this.clientId, dataInfo); - } - break; case kScreenStateChangedTopic: this.workerMessenger.send("setScreenState", { on: (data === "on") }); break; } }, - supportedNetworkTypes: null, - // Flag to determine whether to update system clock automatically. It // corresponds to the "time.clock.automatic-update.enabled" setting. _clockAutoUpdateEnabled: null, @@ -3630,12 +3108,6 @@ RadioInterface.prototype = { // Cell Broadcast settings values. _cellBroadcastSearchList: null, - // Operator's mcc-mnc. - _lastKnownNetwork: null, - - // ICC's mcc-mnc. - _lastKnownHomeNetwork: null, - handleSettingsChange: function(aName, aResult, aIsInternalSetting) { // Don't allow any content processes to modify the setting // "time.clock.automatic-update.available" except for the chrome process. @@ -3745,123 +3217,6 @@ RadioInterface.prototype = { rilContext: null, - // Handle phone functions of nsIRILContentHelper - - _sendCfStateChanged: function(message) { - gMessageManager.sendMobileConnectionMessage("RIL:CfStateChanged", - this.clientId, message); - }, - - _sendClirModeChanged: function(message) { - gMessageManager.sendMobileConnectionMessage("RIL:ClirModeChanged", - this.clientId, message); - }, - - sendMMI: function(target, message) { - if (DEBUG) this.debug("SendMMI " + JSON.stringify(message)); - this.workerMessenger.send("sendMMI", message, (function(response) { - if (response.isSetCallForward) { - this._sendCfStateChanged(response); - } else if (response.isSetCLIR && response.success) { - this._sendClirModeChanged(response.clirMode); - } - - target.sendAsyncMessage("RIL:SendMMI", { - clientId: this.clientId, - data: response - }); - return false; - }).bind(this)); - }, - - setCallForwardingOptions: function(target, message) { - if (DEBUG) this.debug("setCallForwardingOptions: " + JSON.stringify(message)); - message.serviceClass = RIL.ICC_SERVICE_CLASS_VOICE; - this.workerMessenger.send("setCallForward", message, (function(response) { - this._sendCfStateChanged(response); - target.sendAsyncMessage("RIL:SetCallForwardingOptions", { - clientId: this.clientId, - data: response - }); - return false; - }).bind(this)); - }, - - setCallingLineIdRestriction: function(target, message) { - if (DEBUG) { - this.debug("setCallingLineIdRestriction: " + JSON.stringify(message)); - } - this.workerMessenger.send("setCLIR", message, (function(response) { - if (response.success) { - this._sendClirModeChanged(response.clirMode); - } - target.sendAsyncMessage("RIL:SetCallingLineIdRestriction", { - clientId: this.clientId, - data: response - }); - return false; - }).bind(this)); - }, - - isValidStateForSetRadioEnabled: function() { - let state = this.rilContext.detailedRadioState; - return state == RIL.GECKO_DETAILED_RADIOSTATE_ENABLED || - state == RIL.GECKO_DETAILED_RADIOSTATE_DISABLED; - }, - - isDummyForSetRadioEnabled: function(message) { - let state = this.rilContext.detailedRadioState; - return (state == RIL.GECKO_DETAILED_RADIOSTATE_ENABLED && message.enabled) || - (state == RIL.GECKO_DETAILED_RADIOSTATE_DISABLED && !message.enabled); - }, - - setRadioEnabledResponse: function(target, message, errorMsg) { - if (errorMsg) { - message.errorMsg = errorMsg; - } - - target.sendAsyncMessage("RIL:SetRadioEnabled", { - clientId: this.clientId, - data: message - }); - }, - - setRadioEnabled: function(target, message) { - if (DEBUG) { - this.debug("setRadioEnabled: " + JSON.stringify(message)); - } - - if (!this.isValidStateForSetRadioEnabled()) { - this.setRadioEnabledResponse(target, message, "InvalidStateError"); - return; - } - - if (this.isDummyForSetRadioEnabled(message)) { - this.setRadioEnabledResponse(target, message); - return; - } - - let callback = (function(response) { - if (response.errorMsg) { - // Request fails. Rollback to the original radiostate. - let state = message.enabled ? RIL.GECKO_DETAILED_RADIOSTATE_DISABLED - : RIL.GECKO_DETAILED_RADIOSTATE_ENABLED; - this.handleDetailedRadioStateChanged(state); - } - this.setRadioEnabledResponse(target, response); - return false; - }).bind(this); - - this.setRadioEnabledInternal(message, callback); - }, - - setRadioEnabledInternal: function(message, callback) { - let state = message.enabled ? RIL.GECKO_DETAILED_RADIOSTATE_ENABLING - : RIL.GECKO_DETAILED_RADIOSTATE_DISABLING; - this.handleDetailedRadioStateChanged(state); - this.workerMessenger.send("setRadioEnabled", message, callback); - }, - /** * List of tuples of national language identifier pairs. * @@ -4350,12 +3705,12 @@ RadioInterface.prototype = { // If the radio is disabled or the SIM card is not ready, just directly // return with the corresponding error code. let errorCode; + let radioState = gMobileConnectionService.getRadioState(this.clientId); if (!PhoneNumberUtils.isPlainPhoneNumber(options.number)) { if (DEBUG) this.debug("Error! Address is invalid when sending SMS: " + options.number); errorCode = Ci.nsIMobileMessageCallback.INVALID_ADDRESS_ERROR; - } else if (this.rilContext.detailedRadioState == - RIL.GECKO_DETAILED_RADIOSTATE_DISABLED) { + } else if (radioState == RIL.GECKO_RADIOSTATE_DISABLED) { if (DEBUG) this.debug("Error! Radio is disabled when sending SMS."); errorCode = Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR; } else if (this.rilContext.cardState != "ready") { @@ -4574,6 +3929,14 @@ RadioInterface.prototype = { }, sendWorkerMessage: function(rilMessageType, message, callback) { + // Special handler for setRadioEnabled. + if (rilMessageType === "setRadioEnabled") { + // Forward it to gRadioEnabledController. + gRadioEnabledController.setRadioEnabled(this.clientId, message, + callback.handleResponse); + return; + } + if (callback) { this.workerMessenger.send(rilMessageType, message, function(response) { return callback.handleResponse(response); @@ -4852,7 +4215,7 @@ DataCall.prototype = { } let radioInterface = this.gRIL.getRadioInterface(this.clientId); - let dataInfo = radioInterface.rilContext.data; + let dataInfo = gMobileConnectionService.getDataConnectionInfo(this.clientId); if (dataInfo.state != RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED || dataInfo.type == RIL.GECKO_MOBILE_CONNECTION_STATE_UNKNOWN) { return; @@ -4871,7 +4234,7 @@ DataCall.prototype = { } let pdpType = RIL.GECKO_DATACALL_PDP_TYPE_IP; if (RILQUIRKS_HAVE_IPV6) { - pdpType = !radioInterface.rilContext.data.roaming + pdpType = !dataInfo.roaming ? this.apnProfile.protocol : this.apnProfile.roaming_protocol; if (RIL.RIL_DATACALL_PDP_TYPES.indexOf(pdpType) < 0) { diff --git a/dom/system/gonk/ril_consts.js b/dom/system/gonk/ril_consts.js index 08c596f158c..75b21f41925 100644 --- a/dom/system/gonk/ril_consts.js +++ b/dom/system/gonk/ril_consts.js @@ -2478,15 +2478,11 @@ this.CALL_FAIL_IMEI_NOT_ACCEPTED = 243; this.CALL_FAIL_ERROR_UNSPECIFIED = 0xffff; // Other Gecko-specific constants -this.GECKO_RADIOSTATE_UNAVAILABLE = null; -this.GECKO_RADIOSTATE_OFF = "off"; -this.GECKO_RADIOSTATE_READY = "ready"; - -this.GECKO_DETAILED_RADIOSTATE_UNKNOWN = null; -this.GECKO_DETAILED_RADIOSTATE_ENABLING = "enabling"; -this.GECKO_DETAILED_RADIOSTATE_ENABLED = "enabled"; -this.GECKO_DETAILED_RADIOSTATE_DISABLING = "disabling"; -this.GECKO_DETAILED_RADIOSTATE_DISABLED = "disabled"; +this.GECKO_RADIOSTATE_UNKNOWN = null; +this.GECKO_RADIOSTATE_ENABLING = "enabling"; +this.GECKO_RADIOSTATE_ENABLED = "enabled"; +this.GECKO_RADIOSTATE_DISABLING = "disabling"; +this.GECKO_RADIOSTATE_DISABLED = "disabled"; this.GECKO_CARDSTATE_UNINITIALIZED = "uninitialized"; this.GECKO_CARDSTATE_UNDETECTED = null; @@ -2723,14 +2719,14 @@ this.GECKO_RADIO_TECH = [ this.GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN = -1; -// Call forwarding action. Must be in sync with nsIMobileConnectionProvider interface +// Call forwarding action. Must be in sync with nsIMobileConnectionService interface this.CALL_FORWARD_ACTION_DISABLE = 0; this.CALL_FORWARD_ACTION_ENABLE = 1; this.CALL_FORWARD_ACTION_QUERY_STATUS = 2; this.CALL_FORWARD_ACTION_REGISTRATION = 3; this.CALL_FORWARD_ACTION_ERASURE = 4; -// Call forwarding reason. Must be in sync with nsIMobileConnectionProvider interface +// Call forwarding reason. Must be in sync with nsIMobileConnectionService interface this.CALL_FORWARD_REASON_UNCONDITIONAL = 0; this.CALL_FORWARD_REASON_MOBILE_BUSY = 1; this.CALL_FORWARD_REASON_NO_REPLY = 2; @@ -2738,7 +2734,7 @@ this.CALL_FORWARD_REASON_NOT_REACHABLE = 3; this.CALL_FORWARD_REASON_ALL_CALL_FORWARDING = 4; this.CALL_FORWARD_REASON_ALL_CONDITIONAL_CALL_FORWARDING = 5; -// Call barring program. Must be in sync with nsIMobileConnectionProvider interface +// Call barring program. Must be in sync with nsIMobileConnectionService interface this.CALL_BARRING_PROGRAM_ALL_OUTGOING = 0; this.CALL_BARRING_PROGRAM_OUTGOING_INTERNATIONAL = 1; this.CALL_BARRING_PROGRAM_OUTGOING_INTERNATIONAL_EXCEPT_HOME = 2; @@ -2752,7 +2748,7 @@ CALL_BARRING_PROGRAM_TO_FACILITY[CALL_BARRING_PROGRAM_OUTGOING_INTERNATIONAL_EXC CALL_BARRING_PROGRAM_TO_FACILITY[CALL_BARRING_PROGRAM_ALL_INCOMING] = ICC_CB_FACILITY_BAIC; CALL_BARRING_PROGRAM_TO_FACILITY[CALL_BARRING_PROGRAM_INCOMING_ROAMING] = ICC_CB_FACILITY_BAICr; -// CLIR constants. Must be in sync with nsIMobileConnectionProvider interface +// CLIR constants. Must be in sync with nsIMobileConnectionService interface this.CLIR_DEFAULT = 0; this.CLIR_INVOCATION = 1; this.CLIR_SUPPRESSION = 2; diff --git a/dom/system/gonk/ril_worker.js b/dom/system/gonk/ril_worker.js index bb5df03ced4..e9c2459babe 100644 --- a/dom/system/gonk/ril_worker.js +++ b/dom/system/gonk/ril_worker.js @@ -426,7 +426,7 @@ RilObject.prototype = { /** * One of the RADIO_STATE_* constants. */ - this.radioState = GECKO_RADIOSTATE_UNAVAILABLE; + this.radioState = GECKO_RADIOSTATE_UNKNOWN; /** * True if we are on a CDMA phone. @@ -1649,7 +1649,7 @@ RilObject.prototype = { this.sendChromeMessage(options); }).bind(this, options); - let isRadioOff = (this.radioState === GECKO_RADIOSTATE_OFF); + let isRadioOff = (this.radioState === GECKO_RADIOSTATE_DISABLED); if (options.isEmergency) { if (isRadioOff) { @@ -2648,7 +2648,7 @@ RilObject.prototype = { } let _isRadioAvailable = (function() { - if (this.radioState !== GECKO_RADIOSTATE_READY) { + if (this.radioState !== GECKO_RADIOSTATE_ENABLED) { _sendMMIError(GECKO_ERROR_RADIO_NOT_AVAILABLE); return false; } @@ -3488,7 +3488,7 @@ RilObject.prototype = { // Note: setUiccSubscription works abnormally when RADIO is OFF, // which causes SMS function broken in Flame. // See bug 1008557 for detailed info. - this.radioState === GECKO_RADIOSTATE_READY) { + this.radioState === GECKO_RADIOSTATE_ENABLED) { for (let i = 0; i < iccStatus.apps.length; i++) { this.setUiccSubscription({appIndex: i, enabled: true}); } @@ -6808,11 +6808,11 @@ RilObject.prototype[UNSOLICITED_RESPONSE_RADIO_STATE_CHANGED] = function UNSOLIC let radioState = this.context.Buf.readInt32(); let newState; if (radioState == RADIO_STATE_UNAVAILABLE) { - newState = GECKO_RADIOSTATE_UNAVAILABLE; + newState = GECKO_RADIOSTATE_UNKNOWN; } else if (radioState == RADIO_STATE_OFF) { - newState = GECKO_RADIOSTATE_OFF; + newState = GECKO_RADIOSTATE_DISABLED; } else { - newState = GECKO_RADIOSTATE_READY; + newState = GECKO_RADIOSTATE_ENABLED; } if (DEBUG) { @@ -6847,9 +6847,9 @@ RilObject.prototype[UNSOLICITED_RESPONSE_RADIO_STATE_CHANGED] = function UNSOLIC break; } - if ((this.radioState == GECKO_RADIOSTATE_UNAVAILABLE || - this.radioState == GECKO_RADIOSTATE_OFF) && - newState == GECKO_RADIOSTATE_READY) { + if ((this.radioState == GECKO_RADIOSTATE_UNKNOWN || + this.radioState == GECKO_RADIOSTATE_DISABLED) && + newState == GECKO_RADIOSTATE_ENABLED) { // The radio became available, let's get its info. if (!this._waitingRadioTech) { if (this._isCdma) { @@ -7094,7 +7094,11 @@ RilObject.prototype[UNSOLICITED_CDMA_CALL_WAITING] = function UNSOLICITED_CDMA_C waitingCall: call}); }; RilObject.prototype[UNSOLICITED_CDMA_OTA_PROVISION_STATUS] = function UNSOLICITED_CDMA_OTA_PROVISION_STATUS() { - let status = this.context.Buf.readInt32List()[0]; + let status = + CDMA_OTA_PROVISION_STATUS_TO_GECKO[this.context.Buf.readInt32List()[0]]; + if (!status) { + return; + } this.sendChromeMessage({rilMessageType: "otastatuschange", status: status}); }; @@ -14700,7 +14704,7 @@ ICCUtilsHelperObject.prototype = { return null; } - if (!iccInfoPriv.OPL) { + if (!this.isICCServiceAvailable("OPL")) { // When OPL is not present: // According to 3GPP TS 31.102 Sec. 4.2.58 and 3GPP TS 51.011 Sec. 10.3.41, // If EF_OPL is not present, the first record in this EF is used for the diff --git a/layout/build/nsLayoutModule.cpp b/layout/build/nsLayoutModule.cpp index 701f3a5ee58..195bf2a7350 100644 --- a/layout/build/nsLayoutModule.cpp +++ b/layout/build/nsLayoutModule.cpp @@ -129,6 +129,9 @@ using mozilla::system::nsVolumeService; #include "nsIMobileConnectionService.h" #include "mozilla/dom/mobileconnection/MobileConnectionIPCService.h" using mozilla::dom::mobileconnection::MobileConnectionIPCService; +#ifdef MOZ_WIDGET_GONK +#include "nsIMobileConnectionGonkService.h" +#endif #endif #include "AudioChannelAgent.h" @@ -945,6 +948,10 @@ nsIMobileConnectionServiceConstructor(nsISupports *aOuter, REFNSIID aIID, if (XRE_GetProcessType() == GeckoProcessType_Content) { service = MobileConnectionIPCService::GetSingleton(); + } else { +#ifdef MOZ_WIDGET_GONK + service = do_CreateInstance(NS_MOBILECONNECTION_GONK_SERVICE_CONTRACTID); +#endif } if (!service) {