michael@0: /* Copyright 2012 Mozilla Foundation and Mozilla contributors michael@0: * michael@0: * Licensed under the Apache License, Version 2.0 (the "License"); michael@0: * you may not use this file except in compliance with the License. michael@0: * You may obtain a copy of the License at michael@0: * michael@0: * http://www.apache.org/licenses/LICENSE-2.0 michael@0: * michael@0: * Unless required by applicable law or agreed to in writing, software michael@0: * distributed under the License is distributed on an "AS IS" BASIS, michael@0: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. michael@0: * See the License for the specific language governing permissions and michael@0: * limitations under the License. michael@0: */ michael@0: michael@0: "use strict"; michael@0: michael@0: const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; michael@0: michael@0: Cu.import("resource://gre/modules/DOMRequestHelper.jsm"); michael@0: Cu.import("resource://gre/modules/Services.jsm"); michael@0: Cu.import("resource://gre/modules/XPCOMUtils.jsm"); michael@0: michael@0: var RIL = {}; michael@0: Cu.import("resource://gre/modules/ril_consts.js", RIL); michael@0: michael@0: const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown"; michael@0: michael@0: const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed"; michael@0: michael@0: const kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces"; michael@0: const kPrefRilDebuggingEnabled = "ril.debugging.enabled"; michael@0: const kPrefVoicemailDefaultServiceId = "dom.voicemail.defaultServiceId"; michael@0: michael@0: let DEBUG; michael@0: function debug(s) { michael@0: dump("-*- RILContentHelper: " + s + "\n"); michael@0: } michael@0: michael@0: const RILCONTENTHELPER_CID = michael@0: Components.ID("{472816e1-1fd6-4405-996c-806f9ea68174}"); michael@0: const GSMICCINFO_CID = michael@0: Components.ID("{e0fa785b-ad3f-46ed-bc56-fcb0d6fe4fa8}"); michael@0: const CDMAICCINFO_CID = michael@0: Components.ID("{3d1f844f-9ec5-48fb-8907-aed2e5421709}"); michael@0: const MOBILECONNECTIONINFO_CID = michael@0: Components.ID("{a35cfd39-2d93-4489-ac7d-396475dacb27}"); michael@0: const MOBILENETWORKINFO_CID = michael@0: Components.ID("{a6c8416c-09b4-46d1-bf29-6520d677d085}"); michael@0: const MOBILECELLINFO_CID = michael@0: Components.ID("{ae724dd4-ccaf-4006-98f1-6ce66a092464}"); michael@0: const VOICEMAILSTATUS_CID= michael@0: Components.ID("{5467f2eb-e214-43ea-9b89-67711241ec8e}"); michael@0: const MOBILECFINFO_CID= michael@0: Components.ID("{a4756f16-e728-4d9f-8baa-8464f894888a}"); michael@0: const CELLBROADCASTMESSAGE_CID = michael@0: Components.ID("{29474c96-3099-486f-bb4a-3c9a1da834e4}"); michael@0: const CELLBROADCASTETWSINFO_CID = michael@0: Components.ID("{59f176ee-9dcd-4005-9d47-f6be0cd08e17}"); michael@0: const DOMMMIERROR_CID = michael@0: Components.ID("{6b204c42-7928-4e71-89ad-f90cd82aff96}"); michael@0: const ICCCARDLOCKERROR_CID = michael@0: Components.ID("{08a71987-408c-44ff-93fd-177c0a85c3dd}"); michael@0: michael@0: const RIL_IPC_MSG_NAMES = [ michael@0: "RIL:CardStateChanged", michael@0: "RIL:IccInfoChanged", michael@0: "RIL:VoiceInfoChanged", michael@0: "RIL:DataInfoChanged", michael@0: "RIL:GetAvailableNetworks", michael@0: "RIL:NetworkSelectionModeChanged", michael@0: "RIL:SelectNetwork", michael@0: "RIL:SelectNetworkAuto", michael@0: "RIL:SetPreferredNetworkType", michael@0: "RIL:GetPreferredNetworkType", michael@0: "RIL:EmergencyCbModeChanged", michael@0: "RIL:VoicemailNotification", michael@0: "RIL:VoicemailInfoChanged", michael@0: "RIL:CardLockResult", michael@0: "RIL:CardLockRetryCount", michael@0: "RIL:USSDReceived", michael@0: "RIL:SendMMI", michael@0: "RIL:CancelMMI", michael@0: "RIL:StkCommand", michael@0: "RIL:StkSessionEnd", michael@0: "RIL:DataError", michael@0: "RIL:SetCallForwardingOptions", michael@0: "RIL:GetCallForwardingOptions", michael@0: "RIL:SetCallBarringOptions", michael@0: "RIL:GetCallBarringOptions", michael@0: "RIL:ChangeCallBarringPassword", michael@0: "RIL:SetCallWaitingOptions", michael@0: "RIL:GetCallWaitingOptions", michael@0: "RIL:SetCallingLineIdRestriction", michael@0: "RIL:GetCallingLineIdRestriction", michael@0: "RIL:CellBroadcastReceived", michael@0: "RIL:CfStateChanged", michael@0: "RIL:IccOpenChannel", michael@0: "RIL:IccCloseChannel", michael@0: "RIL:IccExchangeAPDU", michael@0: "RIL:ReadIccContacts", michael@0: "RIL:UpdateIccContact", michael@0: "RIL:SetRoamingPreference", michael@0: "RIL:GetRoamingPreference", michael@0: "RIL:ExitEmergencyCbMode", michael@0: "RIL:SetRadioEnabled", michael@0: "RIL:RadioStateChanged", michael@0: "RIL:SetVoicePrivacyMode", michael@0: "RIL:GetVoicePrivacyMode", michael@0: "RIL:OtaStatusChanged", michael@0: "RIL:MatchMvno" michael@0: ]; michael@0: michael@0: XPCOMUtils.defineLazyServiceGetter(this, "cpmm", michael@0: "@mozilla.org/childprocessmessagemanager;1", michael@0: "nsISyncMessageSender"); michael@0: michael@0: XPCOMUtils.defineLazyGetter(this, "gNumRadioInterfaces", function() { michael@0: let appInfo = Cc["@mozilla.org/xre/app-info;1"]; michael@0: let isParentProcess = !appInfo || appInfo.getService(Ci.nsIXULRuntime) michael@0: .processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT; michael@0: michael@0: if (isParentProcess) { michael@0: let ril = Cc["@mozilla.org/ril;1"].getService(Ci.nsIRadioInterfaceLayer); michael@0: return ril.numRadioInterfaces; michael@0: } michael@0: michael@0: return Services.prefs.getIntPref(kPrefRilNumRadioInterfaces); michael@0: }); michael@0: michael@0: function MobileIccCardLockResult(options) { michael@0: this.lockType = options.lockType; michael@0: this.enabled = options.enabled; michael@0: this.retryCount = options.retryCount; michael@0: this.success = options.success; michael@0: } michael@0: MobileIccCardLockResult.prototype = { michael@0: __exposedProps__ : {lockType: 'r', michael@0: enabled: 'r', michael@0: retryCount: 'r', michael@0: success: 'r'} michael@0: }; michael@0: michael@0: function MobileIccCardLockRetryCount(options) { michael@0: this.lockType = options.lockType; michael@0: this.retryCount = options.retryCount; michael@0: this.success = options.success; michael@0: } michael@0: MobileIccCardLockRetryCount.prototype = { michael@0: __exposedProps__ : {lockType: 'r', michael@0: retryCount: 'r', michael@0: success: 'r'} michael@0: }; michael@0: michael@0: function IccInfo() {} michael@0: IccInfo.prototype = { michael@0: iccType: null, michael@0: iccid: null, michael@0: mcc: null, michael@0: mnc: null, michael@0: spn: null, michael@0: isDisplayNetworkNameRequired: null, michael@0: isDisplaySpnRequired: null michael@0: }; michael@0: michael@0: function GsmIccInfo() {} michael@0: GsmIccInfo.prototype = { michael@0: __proto__: IccInfo.prototype, michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozGsmIccInfo]), michael@0: classID: GSMICCINFO_CID, michael@0: classInfo: XPCOMUtils.generateCI({ michael@0: classID: GSMICCINFO_CID, michael@0: classDescription: "MozGsmIccInfo", michael@0: flags: Ci.nsIClassInfo.DOM_OBJECT, michael@0: interfaces: [Ci.nsIDOMMozGsmIccInfo] michael@0: }), michael@0: michael@0: // nsIDOMMozGsmIccInfo michael@0: michael@0: msisdn: null michael@0: }; michael@0: michael@0: function CdmaIccInfo() {} michael@0: CdmaIccInfo.prototype = { michael@0: __proto__: IccInfo.prototype, michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozCdmaIccInfo]), michael@0: classID: CDMAICCINFO_CID, michael@0: classInfo: XPCOMUtils.generateCI({ michael@0: classID: CDMAICCINFO_CID, michael@0: classDescription: "MozCdmaIccInfo", michael@0: flags: Ci.nsIClassInfo.DOM_OBJECT, michael@0: interfaces: [Ci.nsIDOMMozCdmaIccInfo] michael@0: }), michael@0: michael@0: // nsIDOMMozCdmaIccInfo michael@0: michael@0: mdn: null, michael@0: prlVersion: 0 michael@0: }; michael@0: michael@0: function VoicemailInfo() {} michael@0: VoicemailInfo.prototype = { michael@0: number: null, michael@0: displayName: null michael@0: }; michael@0: michael@0: function MobileConnectionInfo() {} michael@0: MobileConnectionInfo.prototype = { michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozMobileConnectionInfo]), michael@0: classID: MOBILECONNECTIONINFO_CID, michael@0: classInfo: XPCOMUtils.generateCI({ michael@0: classID: MOBILECONNECTIONINFO_CID, michael@0: classDescription: "MobileConnectionInfo", michael@0: flags: Ci.nsIClassInfo.DOM_OBJECT, michael@0: interfaces: [Ci.nsIDOMMozMobileConnectionInfo] michael@0: }), michael@0: michael@0: // nsIDOMMozMobileConnectionInfo michael@0: michael@0: connected: false, michael@0: state: null, michael@0: emergencyCallsOnly: false, michael@0: roaming: false, michael@0: network: null, michael@0: cell: null, michael@0: type: null, michael@0: signalStrength: null, michael@0: relSignalStrength: null michael@0: }; michael@0: michael@0: function MobileNetworkInfo() {} michael@0: MobileNetworkInfo.prototype = { michael@0: __exposedProps__ : {shortName: 'r', michael@0: longName: 'r', michael@0: mcc: 'r', michael@0: mnc: 'r', michael@0: state: 'r'}, michael@0: michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozMobileNetworkInfo]), michael@0: classID: MOBILENETWORKINFO_CID, michael@0: classInfo: XPCOMUtils.generateCI({ michael@0: classID: MOBILENETWORKINFO_CID, michael@0: classDescription: "MobileNetworkInfo", michael@0: flags: Ci.nsIClassInfo.DOM_OBJECT, michael@0: interfaces: [Ci.nsIDOMMozMobileNetworkInfo] michael@0: }), michael@0: michael@0: // nsIDOMMozMobileNetworkInfo michael@0: michael@0: shortName: null, michael@0: longName: null, michael@0: mcc: null, michael@0: mnc: null, michael@0: state: null michael@0: }; michael@0: michael@0: function MobileCellInfo() {} michael@0: MobileCellInfo.prototype = { michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozMobileCellInfo]), michael@0: classID: MOBILECELLINFO_CID, michael@0: classInfo: XPCOMUtils.generateCI({ michael@0: classID: MOBILECELLINFO_CID, michael@0: classDescription: "MobileCellInfo", michael@0: flags: Ci.nsIClassInfo.DOM_OBJECT, michael@0: interfaces: [Ci.nsIDOMMozMobileCellInfo] michael@0: }), michael@0: michael@0: // nsIDOMMozMobileCellInfo michael@0: michael@0: gsmLocationAreaCode: -1, michael@0: gsmCellId: -1, michael@0: cdmaBaseStationId: -1, michael@0: cdmaBaseStationLatitude: -2147483648, michael@0: cdmaBaseStationLongitude: -2147483648, michael@0: cdmaSystemId: -1, michael@0: cdmaNetworkId: -1 michael@0: }; michael@0: michael@0: function VoicemailStatus(clientId) { michael@0: this.serviceId = clientId; michael@0: } michael@0: VoicemailStatus.prototype = { michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozVoicemailStatus]), michael@0: classID: VOICEMAILSTATUS_CID, michael@0: classInfo: XPCOMUtils.generateCI({ michael@0: classID: VOICEMAILSTATUS_CID, michael@0: classDescription: "VoicemailStatus", michael@0: flags: Ci.nsIClassInfo.DOM_OBJECT, michael@0: interfaces: [Ci.nsIDOMMozVoicemailStatus] michael@0: }), michael@0: michael@0: // nsIDOMMozVoicemailStatus michael@0: michael@0: serviceId: -1, michael@0: hasMessages: false, michael@0: messageCount: -1, // Count unknown. michael@0: returnNumber: null, michael@0: returnMessage: null michael@0: }; michael@0: michael@0: function MobileCFInfo() {} michael@0: MobileCFInfo.prototype = { michael@0: __exposedProps__ : {active: 'r', michael@0: action: 'r', michael@0: reason: 'r', michael@0: number: 'r', michael@0: timeSeconds: 'r', michael@0: serviceClass: 'r'}, michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozMobileCFInfo]), michael@0: classID: MOBILECFINFO_CID, michael@0: classInfo: XPCOMUtils.generateCI({ michael@0: classID: MOBILECFINFO_CID, michael@0: classDescription: "MobileCFInfo", michael@0: flags: Ci.nsIClassInfo.DOM_OBJECT, michael@0: interfaces: [Ci.nsIDOMMozMobileCFInfo] michael@0: }), michael@0: michael@0: // nsIDOMMozMobileCFInfo michael@0: michael@0: active: false, michael@0: action: -1, michael@0: reason: -1, michael@0: number: null, michael@0: timeSeconds: 0, michael@0: serviceClass: -1 michael@0: }; michael@0: michael@0: function CellBroadcastMessage(pdu) { michael@0: this.gsmGeographicalScope = RIL.CB_GSM_GEOGRAPHICAL_SCOPE_NAMES[pdu.geographicalScope]; michael@0: this.messageCode = pdu.messageCode; michael@0: this.messageId = pdu.messageId; michael@0: this.language = pdu.language; michael@0: this.body = pdu.fullBody; michael@0: this.messageClass = pdu.messageClass; michael@0: this.timestamp = new Date(pdu.timestamp); michael@0: michael@0: if (pdu.etws != null) { michael@0: this.etws = new CellBroadcastEtwsInfo(pdu.etws); michael@0: } michael@0: michael@0: this.cdmaServiceCategory = pdu.serviceCategory; michael@0: } michael@0: CellBroadcastMessage.prototype = { michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozCellBroadcastMessage]), michael@0: classID: CELLBROADCASTMESSAGE_CID, michael@0: classInfo: XPCOMUtils.generateCI({ michael@0: classID: CELLBROADCASTMESSAGE_CID, michael@0: classDescription: "CellBroadcastMessage", michael@0: flags: Ci.nsIClassInfo.DOM_OBJECT, michael@0: interfaces: [Ci.nsIDOMMozCellBroadcastMessage] michael@0: }), michael@0: michael@0: // nsIDOMMozCellBroadcastMessage michael@0: michael@0: gsmGeographicalScope: null, michael@0: messageCode: null, michael@0: messageId: null, michael@0: language: null, michael@0: body: null, michael@0: messageClass: null, michael@0: timestamp: null, michael@0: michael@0: etws: null, michael@0: cdmaServiceCategory: null michael@0: }; michael@0: michael@0: function CellBroadcastEtwsInfo(etwsInfo) { michael@0: if (etwsInfo.warningType != null) { michael@0: this.warningType = RIL.CB_ETWS_WARNING_TYPE_NAMES[etwsInfo.warningType]; michael@0: } michael@0: this.emergencyUserAlert = etwsInfo.emergencyUserAlert; michael@0: this.popup = etwsInfo.popup; michael@0: } michael@0: CellBroadcastEtwsInfo.prototype = { michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozCellBroadcastEtwsInfo]), michael@0: classID: CELLBROADCASTETWSINFO_CID, michael@0: classInfo: XPCOMUtils.generateCI({ michael@0: classID: CELLBROADCASTETWSINFO_CID, michael@0: classDescription: "CellBroadcastEtwsInfo", michael@0: flags: Ci.nsIClassInfo.DOM_OBJECT, michael@0: interfaces: [Ci.nsIDOMMozCellBroadcastEtwsInfo] michael@0: }), michael@0: michael@0: // nsIDOMMozCellBroadcastEtwsInfo michael@0: michael@0: warningType: null, michael@0: emergencyUserAlert: null, michael@0: popup: null michael@0: }; michael@0: michael@0: function CallBarringOptions(options) { michael@0: this.program = options.program; michael@0: this.enabled = options.enabled; michael@0: this.password = options.password; michael@0: this.serviceClass = options.serviceClass; michael@0: } michael@0: CallBarringOptions.prototype = { michael@0: __exposedProps__ : {program: 'r', michael@0: enabled: 'r', michael@0: password: 'r', michael@0: serviceClass: 'r'} michael@0: }; michael@0: michael@0: function DOMMMIResult(result) { michael@0: this.serviceCode = result.serviceCode; michael@0: this.statusMessage = result.statusMessage; michael@0: this.additionalInformation = result.additionalInformation; michael@0: } michael@0: DOMMMIResult.prototype = { michael@0: __exposedProps__: {serviceCode: 'r', michael@0: statusMessage: 'r', michael@0: additionalInformation: 'r'} michael@0: }; michael@0: michael@0: function DOMCLIRStatus(option) { michael@0: this.n = option.n; michael@0: this.m = option.m; michael@0: } michael@0: DOMCLIRStatus.prototype = { michael@0: __exposedProps__ : {n: 'r', michael@0: m: 'r'} michael@0: }; michael@0: michael@0: function DOMMMIError() { michael@0: } michael@0: DOMMMIError.prototype = { michael@0: classDescription: "DOMMMIError", michael@0: classID: DOMMMIERROR_CID, michael@0: contractID: "@mozilla.org/dom/mmi-error;1", michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]), michael@0: __init: function(serviceCode, name, message, additionalInformation) { michael@0: this.__DOM_IMPL__.init(name, message); michael@0: this.serviceCode = serviceCode; michael@0: this.additionalInformation = additionalInformation; michael@0: }, michael@0: }; michael@0: michael@0: function IccCardLockError() { michael@0: } michael@0: IccCardLockError.prototype = { michael@0: classDescription: "IccCardLockError", michael@0: classID: ICCCARDLOCKERROR_CID, michael@0: contractID: "@mozilla.org/dom/icccardlock-error;1", michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]), michael@0: __init: function(lockType, errorMsg, retryCount) { michael@0: this.__DOM_IMPL__.init(errorMsg); michael@0: this.lockType = lockType; michael@0: this.retryCount = retryCount; michael@0: }, michael@0: }; michael@0: michael@0: function RILContentHelper() { michael@0: this.updateDebugFlag(); michael@0: michael@0: this.numClients = gNumRadioInterfaces; michael@0: if (DEBUG) debug("Number of clients: " + this.numClients); michael@0: michael@0: this.rilContexts = []; michael@0: this.voicemailInfos = []; michael@0: this.voicemailStatuses = []; michael@0: for (let clientId = 0; clientId < this.numClients; clientId++) { michael@0: this.rilContexts[clientId] = { michael@0: cardState: RIL.GECKO_CARDSTATE_UNKNOWN, michael@0: networkSelectionMode: RIL.GECKO_NETWORK_SELECTION_UNKNOWN, michael@0: radioState: null, michael@0: iccInfo: null, michael@0: voiceConnectionInfo: new MobileConnectionInfo(), michael@0: dataConnectionInfo: new MobileConnectionInfo() michael@0: }; michael@0: michael@0: this.voicemailInfos[clientId] = new VoicemailInfo(); michael@0: } michael@0: michael@0: this.voicemailDefaultServiceId = this.getVoicemailDefaultServiceId(); michael@0: michael@0: this.initDOMRequestHelper(/* aWindow */ null, RIL_IPC_MSG_NAMES); michael@0: this._windowsMap = []; michael@0: this._selectingNetworks = []; michael@0: this._mobileConnectionListeners = []; michael@0: this._cellBroadcastListeners = []; michael@0: this._voicemailListeners = []; michael@0: this._iccListeners = []; michael@0: michael@0: Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); michael@0: michael@0: Services.prefs.addObserver(kPrefRilDebuggingEnabled, this, false); michael@0: Services.prefs.addObserver(kPrefVoicemailDefaultServiceId, this, false); michael@0: } michael@0: michael@0: RILContentHelper.prototype = { michael@0: __proto__: DOMRequestIpcHelper.prototype, michael@0: michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileConnectionProvider, michael@0: Ci.nsICellBroadcastProvider, michael@0: Ci.nsIVoicemailProvider, michael@0: Ci.nsIIccProvider, michael@0: Ci.nsIObserver, michael@0: Ci.nsISupportsWeakReference, michael@0: Ci.nsIObserver]), michael@0: classID: RILCONTENTHELPER_CID, michael@0: classInfo: XPCOMUtils.generateCI({classID: RILCONTENTHELPER_CID, michael@0: classDescription: "RILContentHelper", michael@0: interfaces: [Ci.nsIMobileConnectionProvider, michael@0: Ci.nsICellBroadcastProvider, michael@0: Ci.nsIVoicemailProvider, michael@0: Ci.nsIIccProvider]}), michael@0: michael@0: updateDebugFlag: function() { michael@0: try { michael@0: DEBUG = RIL.DEBUG_CONTENT_HELPER || michael@0: Services.prefs.getBoolPref(kPrefRilDebuggingEnabled); michael@0: } catch (e) {} michael@0: }, michael@0: michael@0: // An utility function to copy objects. michael@0: updateInfo: function(srcInfo, destInfo) { michael@0: for (let key in srcInfo) { michael@0: destInfo[key] = srcInfo[key]; michael@0: } michael@0: }, michael@0: michael@0: updateConnectionInfo: function(srcInfo, destInfo) { michael@0: for (let key in srcInfo) { michael@0: if ((key != "network") && (key != "cell")) { michael@0: destInfo[key] = srcInfo[key]; michael@0: } michael@0: } michael@0: michael@0: let srcCell = srcInfo.cell; michael@0: if (!srcCell) { michael@0: destInfo.cell = null; michael@0: } else { michael@0: let cell = destInfo.cell; michael@0: if (!cell) { michael@0: cell = destInfo.cell = new MobileCellInfo(); michael@0: } michael@0: michael@0: this.updateInfo(srcCell, cell); michael@0: } michael@0: michael@0: let srcNetwork = srcInfo.network; michael@0: if (!srcNetwork) { michael@0: destInfo.network= null; michael@0: return; michael@0: } michael@0: michael@0: let network = destInfo.network; michael@0: if (!network) { michael@0: network = destInfo.network = new MobileNetworkInfo(); michael@0: } michael@0: michael@0: this.updateInfo(srcNetwork, network); michael@0: }, michael@0: michael@0: /** michael@0: * We need to consider below cases when update iccInfo: michael@0: * 1. Should clear iccInfo to null if there is no card detected. michael@0: * 2. Need to create corresponding object based on iccType. michael@0: */ michael@0: updateIccInfo: function(clientId, newInfo) { michael@0: let rilContext = this.rilContexts[clientId]; michael@0: michael@0: // Card is not detected, clear iccInfo to null. michael@0: if (!newInfo || !newInfo.iccType || !newInfo.iccid) { michael@0: if (rilContext.iccInfo) { michael@0: rilContext.iccInfo = null; michael@0: this._deliverEvent(clientId, michael@0: "_mobileConnectionListeners", michael@0: "notifyIccChanged", michael@0: null); michael@0: } michael@0: return; michael@0: } michael@0: michael@0: // If iccInfo is null, new corresponding object based on iccType. michael@0: if (!rilContext.iccInfo) { michael@0: if (newInfo.iccType === "ruim" || newInfo.iccType === "csim") { michael@0: rilContext.iccInfo = new CdmaIccInfo(); michael@0: } else { michael@0: rilContext.iccInfo = new GsmIccInfo(); michael@0: } michael@0: } michael@0: let changed = (rilContext.iccInfo.iccid != newInfo.iccid) ? michael@0: true : false; michael@0: michael@0: this.updateInfo(newInfo, rilContext.iccInfo); michael@0: michael@0: // Deliver event after info is updated. michael@0: if (changed) { michael@0: this._deliverEvent(clientId, michael@0: "_mobileConnectionListeners", michael@0: "notifyIccChanged", michael@0: null); michael@0: } michael@0: }, michael@0: michael@0: _windowsMap: null, michael@0: michael@0: rilContexts: null, michael@0: michael@0: getRilContext: function(clientId) { michael@0: // Update ril contexts by sending IPC message to chrome only when the first michael@0: // time we require it. The information will be updated by following info michael@0: // changed messages. michael@0: this.getRilContext = function getRilContext(clientId) { michael@0: return this.rilContexts[clientId]; michael@0: }; michael@0: michael@0: for (let cId = 0; cId < this.numClients; cId++) { michael@0: let rilContext = michael@0: cpmm.sendSyncMessage("RIL:GetRilContext", {clientId: cId})[0]; michael@0: if (!rilContext) { michael@0: if (DEBUG) debug("Received null rilContext from chrome process."); michael@0: continue; michael@0: } michael@0: this.rilContexts[cId].cardState = rilContext.cardState; michael@0: this.rilContexts[cId].networkSelectionMode = rilContext.networkSelectionMode; michael@0: this.rilContexts[cId].radioState = rilContext.detailedRadioState; michael@0: this.updateIccInfo(cId, rilContext.iccInfo); michael@0: this.updateConnectionInfo(rilContext.voice, this.rilContexts[cId].voiceConnectionInfo); michael@0: this.updateConnectionInfo(rilContext.data, this.rilContexts[cId].dataConnectionInfo); michael@0: } michael@0: michael@0: return this.rilContexts[clientId]; michael@0: }, michael@0: michael@0: /** michael@0: * nsIIccProvider michael@0: */ michael@0: michael@0: getIccInfo: function(clientId) { michael@0: let context = this.getRilContext(clientId); michael@0: return context && context.iccInfo; michael@0: }, michael@0: michael@0: getCardState: function(clientId) { michael@0: let context = this.getRilContext(clientId); michael@0: return context && context.cardState; michael@0: }, michael@0: michael@0: matchMvno: function(clientId, window, mvnoType, mvnoData) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: let requestId = this.getRequestId(request); michael@0: michael@0: cpmm.sendAsyncMessage("RIL:MatchMvno", { michael@0: clientId: clientId, michael@0: data: { michael@0: requestId: requestId, michael@0: mvnoType: mvnoType, michael@0: mvnoData: mvnoData michael@0: } michael@0: }); michael@0: return request; michael@0: }, michael@0: michael@0: /** michael@0: * nsIMobileConnectionProvider michael@0: */ michael@0: michael@0: getLastKnownNetwork: function(clientId) { michael@0: return cpmm.sendSyncMessage("RIL:GetLastKnownNetwork", { michael@0: clientId: clientId michael@0: })[0]; michael@0: }, michael@0: michael@0: getLastKnownHomeNetwork: function(clientId) { michael@0: return cpmm.sendSyncMessage("RIL:GetLastKnownHomeNetwork", { michael@0: clientId: clientId michael@0: })[0]; michael@0: }, michael@0: michael@0: getVoiceConnectionInfo: function(clientId) { michael@0: let context = this.getRilContext(clientId); michael@0: return context && context.voiceConnectionInfo; michael@0: }, michael@0: michael@0: getDataConnectionInfo: function(clientId) { michael@0: let context = this.getRilContext(clientId); michael@0: return context && context.dataConnectionInfo; michael@0: }, michael@0: michael@0: getIccId: function(clientId) { michael@0: let context = this.getRilContext(clientId); michael@0: return context && context.iccInfo && context.iccInfo.iccid; michael@0: }, michael@0: michael@0: getNetworkSelectionMode: function(clientId) { michael@0: let context = this.getRilContext(clientId); michael@0: return context && context.networkSelectionMode; michael@0: }, michael@0: michael@0: getRadioState: function(clientId) { michael@0: let context = this.getRilContext(clientId); michael@0: return context && context.radioState; michael@0: }, michael@0: michael@0: getSupportedNetworkTypes: function(clientId) { michael@0: return cpmm.sendSyncMessage("RIL:GetSupportedNetworkTypes", { michael@0: clientId: clientId michael@0: })[0]; michael@0: }, michael@0: michael@0: /** michael@0: * The networks that are currently trying to be selected (or "automatic"). michael@0: * This helps ensure that only one network per client is selected at a time. michael@0: */ michael@0: _selectingNetworks: null, michael@0: michael@0: getNetworks: function(clientId, window) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: let requestId = this.getRequestId(request); michael@0: michael@0: cpmm.sendAsyncMessage("RIL:GetAvailableNetworks", { michael@0: clientId: clientId, michael@0: data: { michael@0: requestId: requestId michael@0: } michael@0: }); michael@0: return request; michael@0: }, michael@0: michael@0: selectNetwork: function(clientId, window, network) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: michael@0: if (this._selectingNetworks[clientId]) { michael@0: throw new Error("Already selecting a network: " + this._selectingNetworks[clientId]); michael@0: } michael@0: michael@0: if (!network) { michael@0: throw new Error("Invalid network provided: " + network); michael@0: } michael@0: michael@0: if (isNaN(parseInt(network.mnc, 10))) { michael@0: throw new Error("Invalid network MNC: " + network.mnc); michael@0: } michael@0: michael@0: if (isNaN(parseInt(network.mcc, 10))) { michael@0: throw new Error("Invalid network MCC: " + network.mcc); michael@0: } michael@0: michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: let requestId = this.getRequestId(request); michael@0: michael@0: if (this.rilContexts[clientId].networkSelectionMode == RIL.GECKO_NETWORK_SELECTION_MANUAL && michael@0: this.rilContexts[clientId].voiceConnectionInfo.network === network) { michael@0: michael@0: // Already manually selected this network, so schedule michael@0: // onsuccess to be fired on the next tick michael@0: this.dispatchFireRequestSuccess(requestId, null); michael@0: return request; michael@0: } michael@0: michael@0: this._selectingNetworks[clientId] = network; michael@0: michael@0: cpmm.sendAsyncMessage("RIL:SelectNetwork", { michael@0: clientId: clientId, michael@0: data: { michael@0: requestId: requestId, michael@0: mnc: network.mnc, michael@0: mcc: network.mcc michael@0: } michael@0: }); michael@0: michael@0: return request; michael@0: }, michael@0: michael@0: selectNetworkAutomatically: function(clientId, window) { michael@0: michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: michael@0: if (this._selectingNetworks[clientId]) { michael@0: throw new Error("Already selecting a network: " + this._selectingNetworks[clientId]); michael@0: } michael@0: michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: let requestId = this.getRequestId(request); michael@0: michael@0: if (this.rilContexts[clientId].networkSelectionMode == RIL.GECKO_NETWORK_SELECTION_AUTOMATIC) { michael@0: // Already using automatic selection mode, so schedule michael@0: // onsuccess to be be fired on the next tick michael@0: this.dispatchFireRequestSuccess(requestId, null); michael@0: return request; michael@0: } michael@0: michael@0: this._selectingNetworks[clientId] = "automatic"; michael@0: cpmm.sendAsyncMessage("RIL:SelectNetworkAuto", { michael@0: clientId: clientId, michael@0: data: { michael@0: requestId: requestId michael@0: } michael@0: }); michael@0: return request; michael@0: }, michael@0: michael@0: setPreferredNetworkType: function(clientId, window, type) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: let requestId = this.getRequestId(request); michael@0: michael@0: cpmm.sendAsyncMessage("RIL:SetPreferredNetworkType", { michael@0: clientId: clientId, michael@0: data: { michael@0: requestId: requestId, michael@0: type: type michael@0: } michael@0: }); michael@0: return request; michael@0: }, michael@0: michael@0: getPreferredNetworkType: function(clientId, window) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: let requestId = this.getRequestId(request); michael@0: michael@0: cpmm.sendAsyncMessage("RIL:GetPreferredNetworkType", { michael@0: clientId: clientId, michael@0: data: { michael@0: requestId: requestId michael@0: } michael@0: }); michael@0: return request; michael@0: }, michael@0: michael@0: setRoamingPreference: function(clientId, window, mode) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: let requestId = this.getRequestId(request); michael@0: michael@0: if (!mode) { michael@0: this.dispatchFireRequestError(requestId, michael@0: RIL.GECKO_ERROR_INVALID_PARAMETER); michael@0: return request; michael@0: } michael@0: michael@0: cpmm.sendAsyncMessage("RIL:SetRoamingPreference", { michael@0: clientId: clientId, michael@0: data: { michael@0: requestId: requestId, michael@0: mode: mode michael@0: } michael@0: }); michael@0: return request; michael@0: }, michael@0: michael@0: getRoamingPreference: function(clientId, window) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: let requestId = this.getRequestId(request); michael@0: michael@0: cpmm.sendAsyncMessage("RIL:GetRoamingPreference", { michael@0: clientId: clientId, michael@0: data: { michael@0: requestId: requestId michael@0: } michael@0: }); michael@0: return request; michael@0: }, michael@0: michael@0: setVoicePrivacyMode: function(clientId, window, enabled) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: let requestId = this.getRequestId(request); michael@0: michael@0: cpmm.sendAsyncMessage("RIL:SetVoicePrivacyMode", { michael@0: clientId: clientId, michael@0: data: { michael@0: requestId: requestId, michael@0: enabled: enabled michael@0: } michael@0: }); michael@0: return request; michael@0: }, michael@0: michael@0: getVoicePrivacyMode: function(clientId, window) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: let requestId = this.getRequestId(request); michael@0: michael@0: cpmm.sendAsyncMessage("RIL:GetVoicePrivacyMode", { michael@0: clientId: clientId, michael@0: data: { michael@0: requestId: requestId michael@0: } michael@0: }); michael@0: return request; michael@0: }, michael@0: michael@0: getCardLockState: function(clientId, window, lockType) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: let requestId = this.getRequestId(request); michael@0: this._windowsMap[requestId] = window; michael@0: michael@0: cpmm.sendAsyncMessage("RIL:GetCardLockState", { michael@0: clientId: clientId, michael@0: data: { michael@0: lockType: lockType, michael@0: requestId: requestId michael@0: } michael@0: }); michael@0: return request; michael@0: }, michael@0: michael@0: unlockCardLock: function(clientId, window, info) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: info.requestId = this.getRequestId(request); michael@0: this._windowsMap[info.requestId] = window; michael@0: michael@0: cpmm.sendAsyncMessage("RIL:UnlockCardLock", { michael@0: clientId: clientId, michael@0: data: info michael@0: }); michael@0: return request; michael@0: }, michael@0: michael@0: setCardLock: function(clientId, window, info) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: info.requestId = this.getRequestId(request); michael@0: this._windowsMap[info.requestId] = window; michael@0: michael@0: cpmm.sendAsyncMessage("RIL:SetCardLock", { michael@0: clientId: clientId, michael@0: data: info michael@0: }); michael@0: return request; michael@0: }, michael@0: michael@0: getCardLockRetryCount: function(clientId, window, lockType) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: let requestId = this.getRequestId(request); michael@0: cpmm.sendAsyncMessage("RIL:GetCardLockRetryCount", { michael@0: clientId: clientId, michael@0: data: { michael@0: lockType: lockType, michael@0: requestId: requestId michael@0: } michael@0: }); michael@0: return request; michael@0: }, michael@0: michael@0: sendMMI: function(clientId, window, mmi) { michael@0: if (DEBUG) debug("Sending MMI " + mmi); michael@0: if (!window) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: let requestId = this.getRequestId(request); michael@0: // We need to save the global window to get the proper MMIError michael@0: // constructor once we get the reply from the parent process. michael@0: this._windowsMap[requestId] = window; michael@0: michael@0: cpmm.sendAsyncMessage("RIL:SendMMI", { michael@0: clientId: clientId, michael@0: data: { michael@0: mmi: mmi, michael@0: requestId: requestId michael@0: } michael@0: }); michael@0: return request; michael@0: }, michael@0: michael@0: cancelMMI: function(clientId, window) { michael@0: if (DEBUG) debug("Cancel MMI"); michael@0: if (!window) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: let requestId = this.getRequestId(request); michael@0: cpmm.sendAsyncMessage("RIL:CancelMMI", { michael@0: clientId: clientId, michael@0: data: { michael@0: requestId: requestId michael@0: } michael@0: }); michael@0: return request; michael@0: }, michael@0: michael@0: sendStkResponse: function(clientId, window, command, response) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: response.command = command; michael@0: cpmm.sendAsyncMessage("RIL:SendStkResponse", { michael@0: clientId: clientId, michael@0: data: response michael@0: }); michael@0: }, michael@0: michael@0: sendStkMenuSelection: function(clientId, window, itemIdentifier, michael@0: helpRequested) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: cpmm.sendAsyncMessage("RIL:SendStkMenuSelection", { michael@0: clientId: clientId, michael@0: data: { michael@0: itemIdentifier: itemIdentifier, michael@0: helpRequested: helpRequested michael@0: } michael@0: }); michael@0: }, michael@0: michael@0: sendStkTimerExpiration: function(clientId, window, timer) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: cpmm.sendAsyncMessage("RIL:SendStkTimerExpiration", { michael@0: clientId: clientId, michael@0: data: { michael@0: timer: timer michael@0: } michael@0: }); michael@0: }, michael@0: michael@0: sendStkEventDownload: function(clientId, window, event) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: cpmm.sendAsyncMessage("RIL:SendStkEventDownload", { michael@0: clientId: clientId, michael@0: data: { michael@0: event: event michael@0: } michael@0: }); michael@0: }, michael@0: michael@0: iccOpenChannel: function(clientId, window, aid) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: let requestId = this.getRequestId(request); michael@0: michael@0: cpmm.sendAsyncMessage("RIL:IccOpenChannel", { michael@0: clientId: clientId, michael@0: data: { michael@0: requestId: requestId, michael@0: aid: aid michael@0: } michael@0: }); michael@0: return request; michael@0: }, michael@0: michael@0: iccExchangeAPDU: function(clientId, window, channel, apdu) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: let requestId = this.getRequestId(request); michael@0: michael@0: //Potentially you need serialization here and can't pass the jsval through michael@0: cpmm.sendAsyncMessage("RIL:IccExchangeAPDU", { michael@0: clientId: clientId, michael@0: data: { michael@0: requestId: requestId, michael@0: channel: channel, michael@0: apdu: apdu michael@0: } michael@0: }); michael@0: return request; michael@0: }, michael@0: michael@0: iccCloseChannel: function(clientId, window, channel) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: let requestId = this.getRequestId(request); michael@0: michael@0: cpmm.sendAsyncMessage("RIL:IccCloseChannel", { michael@0: clientId: clientId, michael@0: data: { michael@0: requestId: requestId, michael@0: channel: channel michael@0: } michael@0: }); michael@0: return request; michael@0: }, michael@0: michael@0: readContacts: function(clientId, window, contactType) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: let requestId = this.getRequestId(request); michael@0: this._windowsMap[requestId] = window; michael@0: michael@0: cpmm.sendAsyncMessage("RIL:ReadIccContacts", { michael@0: clientId: clientId, michael@0: data: { michael@0: requestId: requestId, michael@0: contactType: contactType michael@0: } michael@0: }); michael@0: return request; michael@0: }, michael@0: michael@0: updateContact: function(clientId, window, contactType, contact, pin2) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: let requestId = this.getRequestId(request); michael@0: this._windowsMap[requestId] = window; michael@0: michael@0: // Parsing nsDOMContact to Icc Contact format michael@0: let iccContact = {}; michael@0: michael@0: if (Array.isArray(contact.name) && contact.name[0]) { michael@0: iccContact.alphaId = contact.name[0]; michael@0: } michael@0: michael@0: if (Array.isArray(contact.tel)) { michael@0: iccContact.number = contact.tel[0] && contact.tel[0].value; michael@0: let telArray = contact.tel.slice(1); michael@0: let length = telArray.length; michael@0: if (length > 0) { michael@0: iccContact.anr = []; michael@0: } michael@0: for (let i = 0; i < telArray.length; i++) { michael@0: iccContact.anr.push(telArray[i].value); michael@0: } michael@0: } michael@0: michael@0: if (Array.isArray(contact.email) && contact.email[0]) { michael@0: iccContact.email = contact.email[0].value; michael@0: } michael@0: michael@0: iccContact.contactId = contact.id; michael@0: michael@0: cpmm.sendAsyncMessage("RIL:UpdateIccContact", { michael@0: clientId: clientId, michael@0: data: { michael@0: requestId: requestId, michael@0: contactType: contactType, michael@0: contact: iccContact, michael@0: pin2: pin2 michael@0: } michael@0: }); michael@0: michael@0: return request; michael@0: }, michael@0: michael@0: getCallForwardingOption: function(clientId, window, reason) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: let requestId = this.getRequestId(request); michael@0: michael@0: if (!this._isValidCFReason(reason)){ michael@0: this.dispatchFireRequestError(requestId, michael@0: RIL.GECKO_ERROR_INVALID_PARAMETER); michael@0: return request; michael@0: } michael@0: michael@0: cpmm.sendAsyncMessage("RIL:GetCallForwardingOptions", { michael@0: clientId: clientId, michael@0: data: { michael@0: requestId: requestId, michael@0: reason: reason michael@0: } michael@0: }); michael@0: michael@0: return request; michael@0: }, michael@0: michael@0: setCallForwardingOption: function(clientId, window, cfInfo) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: let requestId = this.getRequestId(request); michael@0: michael@0: if (!cfInfo || michael@0: !this._isValidCFReason(cfInfo.reason) || michael@0: !this._isValidCFAction(cfInfo.action)){ michael@0: this.dispatchFireRequestError(requestId, michael@0: RIL.GECKO_ERROR_INVALID_PARAMETER); michael@0: return request; michael@0: } michael@0: michael@0: cpmm.sendAsyncMessage("RIL:SetCallForwardingOptions", { michael@0: clientId: clientId, michael@0: data: { michael@0: requestId: requestId, michael@0: active: cfInfo.active, michael@0: action: cfInfo.action, michael@0: reason: cfInfo.reason, michael@0: number: cfInfo.number, michael@0: timeSeconds: cfInfo.timeSeconds michael@0: } michael@0: }); michael@0: michael@0: return request; michael@0: }, michael@0: michael@0: getCallBarringOption: function(clientId, window, option) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: let requestId = this.getRequestId(request); michael@0: michael@0: if (DEBUG) debug("getCallBarringOption: " + JSON.stringify(option)); michael@0: if (!this._isValidCallBarringOptions(option)) { michael@0: this.dispatchFireRequestError(requestId, michael@0: RIL.GECKO_ERROR_INVALID_PARAMETER); michael@0: return request; michael@0: } michael@0: michael@0: cpmm.sendAsyncMessage("RIL:GetCallBarringOptions", { michael@0: clientId: clientId, michael@0: data: { michael@0: requestId: requestId, michael@0: program: option.program, michael@0: password: option.password, michael@0: serviceClass: option.serviceClass michael@0: } michael@0: }); michael@0: return request; michael@0: }, michael@0: michael@0: setCallBarringOption: function(clientId, window, option) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: let requestId = this.getRequestId(request); michael@0: michael@0: if (DEBUG) debug("setCallBarringOption: " + JSON.stringify(option)); michael@0: if (!this._isValidCallBarringOptions(option, true)) { michael@0: this.dispatchFireRequestError(requestId, michael@0: RIL.GECKO_ERROR_INVALID_PARAMETER); michael@0: return request; michael@0: } michael@0: michael@0: cpmm.sendAsyncMessage("RIL:SetCallBarringOptions", { michael@0: clientId: clientId, michael@0: data: { michael@0: requestId: requestId, michael@0: program: option.program, michael@0: enabled: option.enabled, michael@0: password: option.password, michael@0: serviceClass: option.serviceClass michael@0: } michael@0: }); michael@0: return request; michael@0: }, michael@0: michael@0: changeCallBarringPassword: function(clientId, window, info) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: let requestId = this.getRequestId(request); michael@0: michael@0: // Checking valid PIN for supplementary services. See TS.22.004 clause 5.2. michael@0: if (info.pin == null || !info.pin.match(/^\d{4}$/) || michael@0: info.newPin == null || !info.newPin.match(/^\d{4}$/)) { michael@0: this.dispatchFireRequestError(requestId, "InvalidPassword"); michael@0: return request; michael@0: } michael@0: michael@0: if (DEBUG) debug("changeCallBarringPassword: " + JSON.stringify(info)); michael@0: info.requestId = requestId; michael@0: cpmm.sendAsyncMessage("RIL:ChangeCallBarringPassword", { michael@0: clientId: clientId, michael@0: data: info michael@0: }); michael@0: michael@0: return request; michael@0: }, michael@0: michael@0: getCallWaitingOption: function(clientId, window) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: let requestId = this.getRequestId(request); michael@0: michael@0: cpmm.sendAsyncMessage("RIL:GetCallWaitingOptions", { michael@0: clientId: clientId, michael@0: data: { michael@0: requestId: requestId michael@0: } michael@0: }); michael@0: michael@0: return request; michael@0: }, michael@0: michael@0: setCallWaitingOption: function(clientId, window, enabled) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: let requestId = this.getRequestId(request); michael@0: michael@0: cpmm.sendAsyncMessage("RIL:SetCallWaitingOptions", { michael@0: clientId: clientId, michael@0: data: { michael@0: requestId: requestId, michael@0: enabled: enabled michael@0: } michael@0: }); michael@0: michael@0: return request; michael@0: }, michael@0: michael@0: getCallingLineIdRestriction: function(clientId, window) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: let requestId = this.getRequestId(request); michael@0: michael@0: cpmm.sendAsyncMessage("RIL:GetCallingLineIdRestriction", { michael@0: clientId: clientId, michael@0: data: { michael@0: requestId: requestId michael@0: } michael@0: }); michael@0: michael@0: return request; michael@0: }, michael@0: michael@0: setCallingLineIdRestriction: function(clientId, window, clirMode) { michael@0: michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: let requestId = this.getRequestId(request); michael@0: michael@0: cpmm.sendAsyncMessage("RIL:SetCallingLineIdRestriction", { michael@0: clientId: clientId, michael@0: data: { michael@0: requestId: requestId, michael@0: clirMode: clirMode michael@0: } michael@0: }); michael@0: michael@0: return request; michael@0: }, michael@0: michael@0: exitEmergencyCbMode: function(clientId, window) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: let requestId = this.getRequestId(request); michael@0: michael@0: cpmm.sendAsyncMessage("RIL:ExitEmergencyCbMode", { michael@0: clientId: clientId, michael@0: data: { michael@0: requestId: requestId, michael@0: } michael@0: }); michael@0: michael@0: return request; michael@0: }, michael@0: michael@0: setRadioEnabled: function(clientId, window, enabled) { michael@0: if (window == null) { michael@0: throw Components.Exception("Can't get window object", michael@0: Cr.NS_ERROR_UNEXPECTED); michael@0: } michael@0: let request = Services.DOMRequest.createRequest(window); michael@0: let requestId = this.getRequestId(request); michael@0: michael@0: cpmm.sendAsyncMessage("RIL:SetRadioEnabled", { michael@0: clientId: clientId, michael@0: data: { michael@0: requestId: requestId, michael@0: enabled: enabled, michael@0: } michael@0: }); michael@0: michael@0: return request; michael@0: }, michael@0: michael@0: _mobileConnectionListeners: null, michael@0: _cellBroadcastListeners: null, michael@0: _voicemailListeners: null, michael@0: _iccListeners: null, michael@0: michael@0: voicemailInfos: null, michael@0: voicemailStatuses: null, michael@0: michael@0: voicemailDefaultServiceId: 0, michael@0: getVoicemailDefaultServiceId: function() { michael@0: let id = Services.prefs.getIntPref(kPrefVoicemailDefaultServiceId); michael@0: michael@0: if (id >= gNumRadioInterfaces || id < 0) { michael@0: id = 0; michael@0: } michael@0: michael@0: return id; michael@0: }, michael@0: michael@0: getVoicemailInfo: function(clientId) { michael@0: // Get voicemail infomation by IPC only on first time. michael@0: this.getVoicemailInfo = function getVoicemailInfo(clientId) { michael@0: return this.voicemailInfos[clientId]; michael@0: }; michael@0: michael@0: for (let cId = 0; cId < gNumRadioInterfaces; cId++) { michael@0: let voicemailInfo = michael@0: cpmm.sendSyncMessage("RIL:GetVoicemailInfo", {clientId: cId})[0]; michael@0: if (voicemailInfo) { michael@0: this.updateInfo(voicemailInfo, this.voicemailInfos[cId]); michael@0: } michael@0: } michael@0: michael@0: return this.voicemailInfos[clientId]; michael@0: }, michael@0: michael@0: getVoicemailNumber: function(clientId) { michael@0: return this.getVoicemailInfo(clientId).number; michael@0: }, michael@0: michael@0: getVoicemailDisplayName: function(clientId) { michael@0: return this.getVoicemailInfo(clientId).displayName; michael@0: }, michael@0: michael@0: getVoicemailStatus: function(clientId) { michael@0: return this.voicemailStatuses[clientId]; michael@0: }, michael@0: michael@0: registerListener: function(listenerType, clientId, listener) { michael@0: if (!this[listenerType]) { michael@0: return; michael@0: } michael@0: let listeners = this[listenerType][clientId]; michael@0: if (!listeners) { michael@0: listeners = this[listenerType][clientId] = []; michael@0: } michael@0: michael@0: if (listeners.indexOf(listener) != -1) { michael@0: throw new Error("Already registered this listener!"); michael@0: } michael@0: michael@0: listeners.push(listener); michael@0: if (DEBUG) debug("Registered " + listenerType + " listener: " + listener); michael@0: }, michael@0: michael@0: unregisterListener: function(listenerType, clientId, listener) { michael@0: if (!this[listenerType]) { michael@0: return; michael@0: } michael@0: let listeners = this[listenerType][clientId]; michael@0: if (!listeners) { michael@0: return; michael@0: } michael@0: michael@0: let index = listeners.indexOf(listener); michael@0: if (index != -1) { michael@0: listeners.splice(index, 1); michael@0: if (DEBUG) debug("Unregistered listener: " + listener); michael@0: } michael@0: }, michael@0: michael@0: registerMobileConnectionMsg: function(clientId, listener) { michael@0: if (DEBUG) debug("Registering for mobile connection related messages"); michael@0: this.registerListener("_mobileConnectionListeners", clientId, listener); michael@0: cpmm.sendAsyncMessage("RIL:RegisterMobileConnectionMsg"); michael@0: }, michael@0: michael@0: unregisterMobileConnectionMsg: function(clientId, listener) { michael@0: this.unregisterListener("_mobileConnectionListeners", clientId, listener); michael@0: }, michael@0: michael@0: registerVoicemailMsg: function(listener) { michael@0: if (DEBUG) debug("Registering for voicemail-related messages"); michael@0: // To follow the listener registration scheme, we add a dummy clientId 0. michael@0: // All voicemail events are routed to listener for client id 0. michael@0: // See |handleVoicemailNotification|. michael@0: this.registerListener("_voicemailListeners", 0, listener); michael@0: cpmm.sendAsyncMessage("RIL:RegisterVoicemailMsg"); michael@0: }, michael@0: michael@0: unregisterVoicemailMsg: function(listener) { michael@0: // To follow the listener unregistration scheme, we add a dummy clientId 0. michael@0: // All voicemail events are routed to listener for client id 0. michael@0: // See |handleVoicemailNotification|. michael@0: this.unregisterListener("_voicemailListeners", 0, listener); michael@0: }, michael@0: michael@0: registerCellBroadcastMsg: function(listener) { michael@0: if (DEBUG) debug("Registering for Cell Broadcast related messages"); michael@0: //TODO: Bug 921326 - Cellbroadcast API: support multiple sim cards michael@0: this.registerListener("_cellBroadcastListeners", 0, listener); michael@0: cpmm.sendAsyncMessage("RIL:RegisterCellBroadcastMsg"); michael@0: }, michael@0: michael@0: unregisterCellBroadcastMsg: function(listener) { michael@0: //TODO: Bug 921326 - Cellbroadcast API: support multiple sim cards michael@0: this.unregisterListener("_cellBroadcastListeners", 0, listener); michael@0: }, michael@0: michael@0: registerIccMsg: function(clientId, listener) { michael@0: if (DEBUG) debug("Registering for ICC related messages"); michael@0: this.registerListener("_iccListeners", clientId, listener); michael@0: cpmm.sendAsyncMessage("RIL:RegisterIccMsg"); michael@0: }, michael@0: michael@0: unregisterIccMsg: function(clientId, listener) { michael@0: this.unregisterListener("_iccListeners", clientId, listener); michael@0: }, michael@0: michael@0: // nsIObserver michael@0: michael@0: observe: function(subject, topic, data) { michael@0: switch (topic) { michael@0: case NS_PREFBRANCH_PREFCHANGE_TOPIC_ID: michael@0: if (data == kPrefRilDebuggingEnabled) { michael@0: this.updateDebugFlag(); michael@0: } else if (data == kPrefVoicemailDefaultServiceId) { michael@0: this.voicemailDefaultServiceId = this.getVoicemailDefaultServiceId(); michael@0: } michael@0: break; michael@0: michael@0: case NS_XPCOM_SHUTDOWN_OBSERVER_ID: michael@0: this.destroyDOMRequestHelper(); michael@0: Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID); michael@0: break; michael@0: } michael@0: }, michael@0: michael@0: // nsIMessageListener michael@0: michael@0: fireRequestSuccess: function(requestId, result) { michael@0: let request = this.takeRequest(requestId); michael@0: if (!request) { michael@0: if (DEBUG) { michael@0: debug("not firing success for id: " + requestId + michael@0: ", result: " + JSON.stringify(result)); michael@0: } michael@0: return; michael@0: } michael@0: michael@0: if (DEBUG) { michael@0: debug("fire request success, id: " + requestId + michael@0: ", result: " + JSON.stringify(result)); michael@0: } michael@0: Services.DOMRequest.fireSuccess(request, result); michael@0: }, michael@0: michael@0: dispatchFireRequestSuccess: function(requestId, result) { michael@0: let currentThread = Services.tm.currentThread; michael@0: michael@0: currentThread.dispatch(this.fireRequestSuccess.bind(this, requestId, result), michael@0: Ci.nsIThread.DISPATCH_NORMAL); michael@0: }, michael@0: michael@0: fireRequestError: function(requestId, error) { michael@0: let request = this.takeRequest(requestId); michael@0: if (!request) { michael@0: if (DEBUG) { michael@0: debug("not firing error for id: " + requestId + michael@0: ", error: " + JSON.stringify(error)); michael@0: } michael@0: return; michael@0: } michael@0: michael@0: if (DEBUG) { michael@0: debug("fire request error, id: " + requestId + michael@0: ", result: " + JSON.stringify(error)); michael@0: } michael@0: Services.DOMRequest.fireError(request, error); michael@0: }, michael@0: michael@0: dispatchFireRequestError: function(requestId, error) { michael@0: let currentThread = Services.tm.currentThread; michael@0: michael@0: currentThread.dispatch(this.fireRequestError.bind(this, requestId, error), michael@0: Ci.nsIThread.DISPATCH_NORMAL); michael@0: }, michael@0: michael@0: fireRequestDetailedError: function(requestId, detailedError) { michael@0: let request = this.takeRequest(requestId); michael@0: if (!request) { michael@0: if (DEBUG) { michael@0: debug("not firing detailed error for id: " + requestId + michael@0: ", detailedError: " + JSON.stringify(detailedError)); michael@0: } michael@0: return; michael@0: } michael@0: michael@0: Services.DOMRequest.fireDetailedError(request, detailedError); michael@0: }, michael@0: michael@0: receiveMessage: function(msg) { michael@0: let request; michael@0: if (DEBUG) { michael@0: debug("Received message '" + msg.name + "': " + JSON.stringify(msg.json)); michael@0: } michael@0: michael@0: let data = msg.json.data; michael@0: let clientId = msg.json.clientId; michael@0: switch (msg.name) { michael@0: case "RIL:CardStateChanged": michael@0: if (this.rilContexts[clientId].cardState != data.cardState) { michael@0: this.rilContexts[clientId].cardState = data.cardState; michael@0: this._deliverEvent(clientId, michael@0: "_iccListeners", michael@0: "notifyCardStateChanged", michael@0: null); michael@0: } michael@0: break; michael@0: case "RIL:IccInfoChanged": michael@0: this.updateIccInfo(clientId, data); michael@0: this._deliverEvent(clientId, michael@0: "_iccListeners", michael@0: "notifyIccInfoChanged", michael@0: null); michael@0: break; michael@0: case "RIL:VoiceInfoChanged": michael@0: this.updateConnectionInfo(data, michael@0: this.rilContexts[clientId].voiceConnectionInfo); michael@0: this._deliverEvent(clientId, michael@0: "_mobileConnectionListeners", michael@0: "notifyVoiceChanged", michael@0: null); michael@0: break; michael@0: case "RIL:DataInfoChanged": michael@0: this.updateConnectionInfo(data, michael@0: this.rilContexts[clientId].dataConnectionInfo); michael@0: this._deliverEvent(clientId, michael@0: "_mobileConnectionListeners", michael@0: "notifyDataChanged", michael@0: null); michael@0: break; michael@0: case "RIL:OtaStatusChanged": michael@0: this._deliverEvent(clientId, michael@0: "_mobileConnectionListeners", michael@0: "notifyOtaStatusChanged", michael@0: [data]); michael@0: break; michael@0: case "RIL:GetAvailableNetworks": michael@0: this.handleGetAvailableNetworks(data); michael@0: break; michael@0: case "RIL:NetworkSelectionModeChanged": michael@0: this.rilContexts[clientId].networkSelectionMode = data.mode; michael@0: break; michael@0: case "RIL:SelectNetwork": michael@0: this.handleSelectNetwork(clientId, data, michael@0: RIL.GECKO_NETWORK_SELECTION_MANUAL); michael@0: break; michael@0: case "RIL:SelectNetworkAuto": michael@0: this.handleSelectNetwork(clientId, data, michael@0: RIL.GECKO_NETWORK_SELECTION_AUTOMATIC); michael@0: break; michael@0: case "RIL:SetPreferredNetworkType": michael@0: this.handleSimpleRequest(data.requestId, data.errorMsg, null); michael@0: break; michael@0: case "RIL:GetPreferredNetworkType": michael@0: this.handleSimpleRequest(data.requestId, data.errorMsg, data.type); michael@0: break; michael@0: case "RIL:VoicemailNotification": michael@0: this.handleVoicemailNotification(clientId, data); michael@0: break; michael@0: case "RIL:VoicemailInfoChanged": michael@0: this.updateInfo(data, this.voicemailInfos[clientId]); michael@0: break; michael@0: case "RIL:CardLockResult": { michael@0: let requestId = data.requestId; michael@0: let requestWindow = this._windowsMap[requestId]; michael@0: delete this._windowsMap[requestId]; michael@0: michael@0: if (data.success) { michael@0: let result = new MobileIccCardLockResult(data); michael@0: this.fireRequestSuccess(requestId, result); michael@0: } else { michael@0: if (data.rilMessageType == "iccSetCardLock" || michael@0: data.rilMessageType == "iccUnlockCardLock") { michael@0: let cardLockError = new requestWindow.IccCardLockError(data.lockType, michael@0: data.errorMsg, michael@0: data.retryCount); michael@0: this.fireRequestDetailedError(requestId, cardLockError); michael@0: } else { michael@0: this.fireRequestError(requestId, data.errorMsg); michael@0: } michael@0: } michael@0: break; michael@0: } michael@0: case "RIL:CardLockRetryCount": michael@0: if (data.success) { michael@0: let result = new MobileIccCardLockRetryCount(data); michael@0: this.fireRequestSuccess(data.requestId, result); michael@0: } else { michael@0: this.fireRequestError(data.requestId, data.errorMsg); michael@0: } michael@0: break; michael@0: case "RIL:USSDReceived": michael@0: this._deliverEvent(clientId, michael@0: "_mobileConnectionListeners", michael@0: "notifyUssdReceived", michael@0: [data.message, data.sessionEnded]); michael@0: break; michael@0: case "RIL:SendMMI": michael@0: case "RIL:CancelMMI": michael@0: this.handleSendCancelMMI(data); michael@0: break; michael@0: case "RIL:StkCommand": michael@0: this._deliverEvent(clientId, "_iccListeners", "notifyStkCommand", michael@0: [JSON.stringify(data)]); michael@0: break; michael@0: case "RIL:StkSessionEnd": michael@0: this._deliverEvent(clientId, "_iccListeners", "notifyStkSessionEnd", null); michael@0: break; michael@0: case "RIL:IccOpenChannel": michael@0: this.handleSimpleRequest(data.requestId, data.errorMsg, michael@0: data.channel); michael@0: break; michael@0: case "RIL:IccCloseChannel": michael@0: this.handleSimpleRequest(data.requestId, data.errorMsg, null); michael@0: break; michael@0: case "RIL:IccExchangeAPDU": michael@0: this.handleIccExchangeAPDU(data); michael@0: break; michael@0: case "RIL:ReadIccContacts": michael@0: this.handleReadIccContacts(data); michael@0: break; michael@0: case "RIL:UpdateIccContact": michael@0: this.handleUpdateIccContact(data); michael@0: break; michael@0: case "RIL:MatchMvno": michael@0: this.handleSimpleRequest(data.requestId, data.errorMsg, data.result); michael@0: break; michael@0: case "RIL:DataError": michael@0: this.updateConnectionInfo(data, this.rilContexts[clientId].dataConnectionInfo); michael@0: this._deliverEvent(clientId, "_mobileConnectionListeners", "notifyDataError", michael@0: [data.errorMsg]); michael@0: break; michael@0: case "RIL:GetCallForwardingOptions": michael@0: this.handleGetCallForwardingOptions(data); michael@0: break; michael@0: case "RIL:SetCallForwardingOptions": michael@0: this.handleSimpleRequest(data.requestId, data.errorMsg, null); michael@0: break; michael@0: case "RIL:GetCallBarringOptions": michael@0: this.handleGetCallBarringOptions(data); michael@0: break; michael@0: case "RIL:SetCallBarringOptions": michael@0: this.handleSimpleRequest(data.requestId, data.errorMsg, null); michael@0: break; michael@0: case "RIL:ChangeCallBarringPassword": michael@0: this.handleSimpleRequest(data.requestId, data.errorMsg, null); michael@0: break; michael@0: case "RIL:GetCallWaitingOptions": michael@0: this.handleSimpleRequest(data.requestId, data.errorMsg, michael@0: data.enabled); michael@0: break; michael@0: case "RIL:SetCallWaitingOptions": michael@0: this.handleSimpleRequest(data.requestId, data.errorMsg, null); michael@0: break; michael@0: case "RIL:CfStateChanged": michael@0: this._deliverEvent(clientId, michael@0: "_mobileConnectionListeners", michael@0: "notifyCFStateChange", michael@0: [data.success, data.action, michael@0: data.reason, data.number, michael@0: data.timeSeconds, data.serviceClass]); michael@0: break; michael@0: case "RIL:GetCallingLineIdRestriction": michael@0: this.handleGetCallingLineIdRestriction(data); michael@0: break; michael@0: case "RIL:SetCallingLineIdRestriction": michael@0: this.handleSimpleRequest(data.requestId, data.errorMsg, null); michael@0: break; michael@0: case "RIL:CellBroadcastReceived": { michael@0: let message = new CellBroadcastMessage(data); michael@0: this._deliverEvent(clientId, michael@0: "_cellBroadcastListeners", michael@0: "notifyMessageReceived", michael@0: [message]); michael@0: break; michael@0: } michael@0: case "RIL:SetRoamingPreference": michael@0: this.handleSimpleRequest(data.requestId, data.errorMsg, null); michael@0: break; michael@0: case "RIL:GetRoamingPreference": michael@0: this.handleSimpleRequest(data.requestId, data.errorMsg, michael@0: data.mode); michael@0: break; michael@0: case "RIL:ExitEmergencyCbMode": michael@0: this.handleExitEmergencyCbMode(data); michael@0: break; michael@0: case "RIL:EmergencyCbModeChanged": michael@0: this._deliverEvent(clientId, michael@0: "_mobileConnectionListeners", michael@0: "notifyEmergencyCbModeChanged", michael@0: [data.active, data.timeoutMs]); michael@0: break; michael@0: case "RIL:SetRadioEnabled": michael@0: this.handleSimpleRequest(data.requestId, data.errorMsg, null); michael@0: break; michael@0: case "RIL:RadioStateChanged": michael@0: this.rilContexts[clientId].radioState = data; michael@0: this._deliverEvent(clientId, michael@0: "_mobileConnectionListeners", michael@0: "notifyRadioStateChanged", michael@0: null); michael@0: break; michael@0: case "RIL:SetVoicePrivacyMode": michael@0: this.handleSimpleRequest(data.requestId, data.errorMsg, null); michael@0: break; michael@0: case "RIL:GetVoicePrivacyMode": michael@0: this.handleSimpleRequest(data.requestId, data.errorMsg, michael@0: data.enabled); michael@0: break; michael@0: } michael@0: }, michael@0: michael@0: handleSimpleRequest: function(requestId, errorMsg, result) { michael@0: if (errorMsg) { michael@0: this.fireRequestError(requestId, errorMsg); michael@0: } else { michael@0: this.fireRequestSuccess(requestId, result); michael@0: } michael@0: }, michael@0: michael@0: handleGetAvailableNetworks: function(message) { michael@0: if (DEBUG) debug("handleGetAvailableNetworks: " + JSON.stringify(message)); michael@0: if (message.errorMsg) { michael@0: if (DEBUG) { michael@0: debug("Received error from getAvailableNetworks: " + message.errorMsg); michael@0: } michael@0: this.fireRequestError(message.requestId, message.errorMsg); michael@0: return; michael@0: } michael@0: michael@0: let networks = message.networks; michael@0: for (let i = 0; i < networks.length; i++) { michael@0: let network = networks[i]; michael@0: let info = new MobileNetworkInfo(); michael@0: this.updateInfo(network, info); michael@0: networks[i] = info; michael@0: } michael@0: michael@0: this.fireRequestSuccess(message.requestId, networks); michael@0: }, michael@0: michael@0: handleSelectNetwork: function(clientId, message, mode) { michael@0: this._selectingNetworks[clientId] = null; michael@0: this.rilContexts[clientId].networkSelectionMode = mode; michael@0: michael@0: if (message.errorMsg) { michael@0: this.fireRequestError(message.requestId, message.errorMsg); michael@0: } else { michael@0: this.fireRequestSuccess(message.requestId, null); michael@0: } michael@0: }, michael@0: michael@0: handleIccExchangeAPDU: function(message) { michael@0: if (message.errorMsg) { michael@0: this.fireRequestError(message.requestId, message.errorMsg); michael@0: } else { michael@0: var result = [message.sw1, message.sw2, message.simResponse]; michael@0: this.fireRequestSuccess(message.requestId, result); michael@0: } michael@0: }, michael@0: michael@0: handleReadIccContacts: function(message) { michael@0: if (message.errorMsg) { michael@0: this.fireRequestError(message.requestId, message.errorMsg); michael@0: return; michael@0: } michael@0: michael@0: let window = this._windowsMap[message.requestId]; michael@0: delete this._windowsMap[message.requestId]; michael@0: let contacts = message.contacts; michael@0: let result = contacts.map(function(c) { michael@0: let prop = {name: [c.alphaId], tel: [{value: c.number}]}; michael@0: michael@0: if (c.email) { michael@0: prop.email = [{value: c.email}]; michael@0: } michael@0: michael@0: // ANR - Additional Number michael@0: let anrLen = c.anr ? c.anr.length : 0; michael@0: for (let i = 0; i < anrLen; i++) { michael@0: prop.tel.push({value: c.anr[i]}); michael@0: } michael@0: michael@0: let contact = new window.mozContact(prop); michael@0: contact.id = c.contactId; michael@0: return contact; michael@0: }); michael@0: michael@0: this.fireRequestSuccess(message.requestId, result); michael@0: }, michael@0: michael@0: handleUpdateIccContact: function(message) { michael@0: if (message.errorMsg) { michael@0: this.fireRequestError(message.requestId, message.errorMsg); michael@0: return; michael@0: } michael@0: michael@0: let window = this._windowsMap[message.requestId]; michael@0: delete this._windowsMap[message.requestId]; michael@0: let iccContact = message.contact; michael@0: let prop = {name: [iccContact.alphaId], tel: [{value: iccContact.number}]}; michael@0: if (iccContact.email) { michael@0: prop.email = [{value: iccContact.email}]; michael@0: } michael@0: michael@0: // ANR - Additional Number michael@0: let anrLen = iccContact.anr ? iccContact.anr.length : 0; michael@0: for (let i = 0; i < anrLen; i++) { michael@0: prop.tel.push({value: iccContact.anr[i]}); michael@0: } michael@0: michael@0: let contact = new window.mozContact(prop); michael@0: contact.id = iccContact.contactId; michael@0: michael@0: this.fireRequestSuccess(message.requestId, contact); michael@0: }, michael@0: michael@0: handleVoicemailNotification: function(clientId, message) { michael@0: let changed = false; michael@0: if (!this.voicemailStatuses[clientId]) { michael@0: this.voicemailStatuses[clientId] = new VoicemailStatus(clientId); michael@0: } michael@0: michael@0: let voicemailStatus = this.voicemailStatuses[clientId]; michael@0: if (voicemailStatus.hasMessages != message.active) { michael@0: changed = true; michael@0: voicemailStatus.hasMessages = message.active; michael@0: } michael@0: michael@0: if (voicemailStatus.messageCount != message.msgCount) { michael@0: changed = true; michael@0: voicemailStatus.messageCount = message.msgCount; michael@0: } else if (message.msgCount == -1) { michael@0: // For MWI using DCS the message count is not available michael@0: changed = true; michael@0: } michael@0: michael@0: if (voicemailStatus.returnNumber != message.returnNumber) { michael@0: changed = true; michael@0: voicemailStatus.returnNumber = message.returnNumber; michael@0: } michael@0: michael@0: if (voicemailStatus.returnMessage != message.returnMessage) { michael@0: changed = true; michael@0: voicemailStatus.returnMessage = message.returnMessage; michael@0: } michael@0: michael@0: if (changed) { michael@0: // To follow the event delivering scheme, we add a dummy clientId 0. michael@0: // All voicemail events are routed to listener for client id 0. michael@0: this._deliverEvent(0, michael@0: "_voicemailListeners", michael@0: "notifyStatusChanged", michael@0: [voicemailStatus]); michael@0: } michael@0: }, michael@0: michael@0: _cfRulesToMobileCfInfo: function(rules) { michael@0: for (let i = 0; i < rules.length; i++) { michael@0: let rule = rules[i]; michael@0: let info = new MobileCFInfo(); michael@0: this.updateInfo(rule, info); michael@0: rules[i] = info; michael@0: } michael@0: }, michael@0: michael@0: handleGetCallForwardingOptions: function(message) { michael@0: if (message.errorMsg) { michael@0: this.fireRequestError(message.requestId, message.errorMsg); michael@0: return; michael@0: } michael@0: michael@0: this._cfRulesToMobileCfInfo(message.rules); michael@0: this.fireRequestSuccess(message.requestId, message.rules); michael@0: }, michael@0: michael@0: handleGetCallBarringOptions: function(message) { michael@0: if (!message.success) { michael@0: this.fireRequestError(message.requestId, message.errorMsg); michael@0: } else { michael@0: let options = new CallBarringOptions(message); michael@0: this.fireRequestSuccess(message.requestId, options); michael@0: } michael@0: }, michael@0: michael@0: handleGetCallingLineIdRestriction: function(message) { michael@0: if (message.errorMsg) { michael@0: this.fireRequestError(message.requestId, message.errorMsg); michael@0: return; michael@0: } michael@0: michael@0: let status = new DOMCLIRStatus(message); michael@0: this.fireRequestSuccess(message.requestId, status); michael@0: }, michael@0: michael@0: handleExitEmergencyCbMode: function(message) { michael@0: let requestId = message.requestId; michael@0: let request = this.takeRequest(requestId); michael@0: if (!request) { michael@0: return; michael@0: } michael@0: michael@0: if (!message.success) { michael@0: Services.DOMRequest.fireError(request, message.errorMsg); michael@0: return; michael@0: } michael@0: Services.DOMRequest.fireSuccess(request, null); michael@0: }, michael@0: michael@0: handleSendCancelMMI: function(message) { michael@0: if (DEBUG) debug("handleSendCancelMMI " + JSON.stringify(message)); michael@0: let request = this.takeRequest(message.requestId); michael@0: let requestWindow = this._windowsMap[message.requestId]; michael@0: delete this._windowsMap[message.requestId]; michael@0: if (!request) { michael@0: return; michael@0: } michael@0: michael@0: let success = message.success; michael@0: michael@0: // We expect to have an IMEI at this point if the request was supposed michael@0: // to query for the IMEI, so getting a successful reply from the RIL michael@0: // without containing an actual IMEI number is considered an error. michael@0: if (message.mmiServiceCode === RIL.MMI_KS_SC_IMEI && michael@0: !message.statusMessage) { michael@0: message.errorMsg = message.errorMsg ? michael@0: message.errorMsg : RIL.GECKO_ERROR_GENERIC_FAILURE; michael@0: success = false; michael@0: } michael@0: michael@0: // MMI query call forwarding options request returns a set of rules that michael@0: // will be exposed in the form of an array of nsIDOMMozMobileCFInfo michael@0: // instances. michael@0: if (message.mmiServiceCode === RIL.MMI_KS_SC_CALL_FORWARDING && michael@0: message.additionalInformation) { michael@0: this._cfRulesToMobileCfInfo(message.additionalInformation); michael@0: } michael@0: michael@0: let result = { michael@0: serviceCode: message.mmiServiceCode, michael@0: additionalInformation: message.additionalInformation michael@0: }; michael@0: michael@0: if (success) { michael@0: result.statusMessage = message.statusMessage; michael@0: let mmiResult = new DOMMMIResult(result); michael@0: Services.DOMRequest.fireSuccess(request, mmiResult); michael@0: } else { michael@0: let mmiError = new requestWindow.DOMMMIError(result.serviceCode, michael@0: message.errorMsg, michael@0: null, michael@0: result.additionalInformation); michael@0: Services.DOMRequest.fireDetailedError(request, mmiError); michael@0: } michael@0: }, michael@0: michael@0: _deliverEvent: function(clientId, listenerType, name, args) { michael@0: if (!this[listenerType]) { michael@0: return; michael@0: } michael@0: let thisListeners = this[listenerType][clientId]; michael@0: if (!thisListeners) { michael@0: return; michael@0: } michael@0: michael@0: let listeners = thisListeners.slice(); michael@0: for (let listener of listeners) { michael@0: if (thisListeners.indexOf(listener) == -1) { michael@0: continue; michael@0: } michael@0: let handler = listener[name]; michael@0: if (typeof handler != "function") { michael@0: throw new Error("No handler for " + name); michael@0: } michael@0: try { michael@0: handler.apply(listener, args); michael@0: } catch (e) { michael@0: if (DEBUG) debug("listener for " + name + " threw an exception: " + e); michael@0: } michael@0: } michael@0: }, michael@0: michael@0: /** michael@0: * Helper for guarding us again invalid reason values for call forwarding. michael@0: */ michael@0: _isValidCFReason: function(reason) { michael@0: switch (reason) { michael@0: case Ci.nsIDOMMozMobileCFInfo.CALL_FORWARD_REASON_UNCONDITIONAL: michael@0: case Ci.nsIDOMMozMobileCFInfo.CALL_FORWARD_REASON_MOBILE_BUSY: michael@0: case Ci.nsIDOMMozMobileCFInfo.CALL_FORWARD_REASON_NO_REPLY: michael@0: case Ci.nsIDOMMozMobileCFInfo.CALL_FORWARD_REASON_NOT_REACHABLE: michael@0: case Ci.nsIDOMMozMobileCFInfo.CALL_FORWARD_REASON_ALL_CALL_FORWARDING: michael@0: case Ci.nsIDOMMozMobileCFInfo.CALL_FORWARD_REASON_ALL_CONDITIONAL_CALL_FORWARDING: michael@0: return true; michael@0: default: michael@0: return false; michael@0: } michael@0: }, michael@0: michael@0: /** michael@0: * Helper for guarding us again invalid action values for call forwarding. michael@0: */ michael@0: _isValidCFAction: function(action) { michael@0: switch (action) { michael@0: case Ci.nsIDOMMozMobileCFInfo.CALL_FORWARD_ACTION_DISABLE: michael@0: case Ci.nsIDOMMozMobileCFInfo.CALL_FORWARD_ACTION_ENABLE: michael@0: case Ci.nsIDOMMozMobileCFInfo.CALL_FORWARD_ACTION_REGISTRATION: michael@0: case Ci.nsIDOMMozMobileCFInfo.CALL_FORWARD_ACTION_ERASURE: michael@0: return true; michael@0: default: michael@0: return false; michael@0: } michael@0: }, michael@0: michael@0: /** michael@0: * Helper for guarding us against invalid program values for call barring. michael@0: */ michael@0: _isValidCallBarringProgram: function(program) { michael@0: switch (program) { michael@0: case Ci.nsIDOMMozMobileConnection.CALL_BARRING_PROGRAM_ALL_OUTGOING: michael@0: case Ci.nsIDOMMozMobileConnection.CALL_BARRING_PROGRAM_OUTGOING_INTERNATIONAL: michael@0: case Ci.nsIDOMMozMobileConnection.CALL_BARRING_PROGRAM_OUTGOING_INTERNATIONAL_EXCEPT_HOME: michael@0: case Ci.nsIDOMMozMobileConnection.CALL_BARRING_PROGRAM_ALL_INCOMING: michael@0: case Ci.nsIDOMMozMobileConnection.CALL_BARRING_PROGRAM_INCOMING_ROAMING: michael@0: return true; michael@0: default: michael@0: return false; michael@0: } michael@0: }, michael@0: michael@0: /** michael@0: * Helper for guarding us against invalid options for call barring. michael@0: */ michael@0: _isValidCallBarringOptions: function(options, usedForSetting) { michael@0: if (!options || michael@0: options.serviceClass == null || michael@0: !this._isValidCallBarringProgram(options.program)) { michael@0: return false; michael@0: } michael@0: michael@0: // For setting callbarring options, |enabled| and |password| are required. michael@0: if (usedForSetting && (options.enabled == null || options.password == null)) { michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: }; michael@0: michael@0: this.NSGetFactory = XPCOMUtils.generateNSGetFactory([RILContentHelper, michael@0: DOMMMIError, michael@0: IccCardLockError]);