dom/system/gonk/RILContentHelper.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* Copyright 2012 Mozilla Foundation and Mozilla contributors
     2  *
     3  * Licensed under the Apache License, Version 2.0 (the "License");
     4  * you may not use this file except in compliance with the License.
     5  * You may obtain a copy of the License at
     6  *
     7  *     http://www.apache.org/licenses/LICENSE-2.0
     8  *
     9  * Unless required by applicable law or agreed to in writing, software
    10  * distributed under the License is distributed on an "AS IS" BASIS,
    11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  * See the License for the specific language governing permissions and
    13  * limitations under the License.
    14  */
    16 "use strict";
    18 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
    20 Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
    21 Cu.import("resource://gre/modules/Services.jsm");
    22 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
    24 var RIL = {};
    25 Cu.import("resource://gre/modules/ril_consts.js", RIL);
    27 const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown";
    29 const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed";
    31 const kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces";
    32 const kPrefRilDebuggingEnabled = "ril.debugging.enabled";
    33 const kPrefVoicemailDefaultServiceId = "dom.voicemail.defaultServiceId";
    35 let DEBUG;
    36 function debug(s) {
    37   dump("-*- RILContentHelper: " + s + "\n");
    38 }
    40 const RILCONTENTHELPER_CID =
    41   Components.ID("{472816e1-1fd6-4405-996c-806f9ea68174}");
    42 const GSMICCINFO_CID =
    43   Components.ID("{e0fa785b-ad3f-46ed-bc56-fcb0d6fe4fa8}");
    44 const CDMAICCINFO_CID =
    45   Components.ID("{3d1f844f-9ec5-48fb-8907-aed2e5421709}");
    46 const MOBILECONNECTIONINFO_CID =
    47   Components.ID("{a35cfd39-2d93-4489-ac7d-396475dacb27}");
    48 const MOBILENETWORKINFO_CID =
    49   Components.ID("{a6c8416c-09b4-46d1-bf29-6520d677d085}");
    50 const MOBILECELLINFO_CID =
    51   Components.ID("{ae724dd4-ccaf-4006-98f1-6ce66a092464}");
    52 const VOICEMAILSTATUS_CID=
    53   Components.ID("{5467f2eb-e214-43ea-9b89-67711241ec8e}");
    54 const MOBILECFINFO_CID=
    55   Components.ID("{a4756f16-e728-4d9f-8baa-8464f894888a}");
    56 const CELLBROADCASTMESSAGE_CID =
    57   Components.ID("{29474c96-3099-486f-bb4a-3c9a1da834e4}");
    58 const CELLBROADCASTETWSINFO_CID =
    59   Components.ID("{59f176ee-9dcd-4005-9d47-f6be0cd08e17}");
    60 const DOMMMIERROR_CID =
    61   Components.ID("{6b204c42-7928-4e71-89ad-f90cd82aff96}");
    62 const ICCCARDLOCKERROR_CID =
    63   Components.ID("{08a71987-408c-44ff-93fd-177c0a85c3dd}");
    65 const RIL_IPC_MSG_NAMES = [
    66   "RIL:CardStateChanged",
    67   "RIL:IccInfoChanged",
    68   "RIL:VoiceInfoChanged",
    69   "RIL:DataInfoChanged",
    70   "RIL:GetAvailableNetworks",
    71   "RIL:NetworkSelectionModeChanged",
    72   "RIL:SelectNetwork",
    73   "RIL:SelectNetworkAuto",
    74   "RIL:SetPreferredNetworkType",
    75   "RIL:GetPreferredNetworkType",
    76   "RIL:EmergencyCbModeChanged",
    77   "RIL:VoicemailNotification",
    78   "RIL:VoicemailInfoChanged",
    79   "RIL:CardLockResult",
    80   "RIL:CardLockRetryCount",
    81   "RIL:USSDReceived",
    82   "RIL:SendMMI",
    83   "RIL:CancelMMI",
    84   "RIL:StkCommand",
    85   "RIL:StkSessionEnd",
    86   "RIL:DataError",
    87   "RIL:SetCallForwardingOptions",
    88   "RIL:GetCallForwardingOptions",
    89   "RIL:SetCallBarringOptions",
    90   "RIL:GetCallBarringOptions",
    91   "RIL:ChangeCallBarringPassword",
    92   "RIL:SetCallWaitingOptions",
    93   "RIL:GetCallWaitingOptions",
    94   "RIL:SetCallingLineIdRestriction",
    95   "RIL:GetCallingLineIdRestriction",
    96   "RIL:CellBroadcastReceived",
    97   "RIL:CfStateChanged",
    98   "RIL:IccOpenChannel",
    99   "RIL:IccCloseChannel",
   100   "RIL:IccExchangeAPDU",
   101   "RIL:ReadIccContacts",
   102   "RIL:UpdateIccContact",
   103   "RIL:SetRoamingPreference",
   104   "RIL:GetRoamingPreference",
   105   "RIL:ExitEmergencyCbMode",
   106   "RIL:SetRadioEnabled",
   107   "RIL:RadioStateChanged",
   108   "RIL:SetVoicePrivacyMode",
   109   "RIL:GetVoicePrivacyMode",
   110   "RIL:OtaStatusChanged",
   111   "RIL:MatchMvno"
   112 ];
   114 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
   115                                    "@mozilla.org/childprocessmessagemanager;1",
   116                                    "nsISyncMessageSender");
   118 XPCOMUtils.defineLazyGetter(this, "gNumRadioInterfaces", function() {
   119   let appInfo = Cc["@mozilla.org/xre/app-info;1"];
   120   let isParentProcess = !appInfo || appInfo.getService(Ci.nsIXULRuntime)
   121                           .processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
   123   if (isParentProcess) {
   124     let ril = Cc["@mozilla.org/ril;1"].getService(Ci.nsIRadioInterfaceLayer);
   125     return ril.numRadioInterfaces;
   126   }
   128   return Services.prefs.getIntPref(kPrefRilNumRadioInterfaces);
   129 });
   131 function MobileIccCardLockResult(options) {
   132   this.lockType = options.lockType;
   133   this.enabled = options.enabled;
   134   this.retryCount = options.retryCount;
   135   this.success = options.success;
   136 }
   137 MobileIccCardLockResult.prototype = {
   138   __exposedProps__ : {lockType: 'r',
   139                       enabled: 'r',
   140                       retryCount: 'r',
   141                       success: 'r'}
   142 };
   144 function MobileIccCardLockRetryCount(options) {
   145   this.lockType = options.lockType;
   146   this.retryCount = options.retryCount;
   147   this.success = options.success;
   148 }
   149 MobileIccCardLockRetryCount.prototype = {
   150   __exposedProps__ : {lockType: 'r',
   151                       retryCount: 'r',
   152                       success: 'r'}
   153 };
   155 function IccInfo() {}
   156 IccInfo.prototype = {
   157   iccType: null,
   158   iccid: null,
   159   mcc: null,
   160   mnc: null,
   161   spn: null,
   162   isDisplayNetworkNameRequired: null,
   163   isDisplaySpnRequired: null
   164 };
   166 function GsmIccInfo() {}
   167 GsmIccInfo.prototype = {
   168   __proto__: IccInfo.prototype,
   169   QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozGsmIccInfo]),
   170   classID: GSMICCINFO_CID,
   171   classInfo: XPCOMUtils.generateCI({
   172     classID:          GSMICCINFO_CID,
   173     classDescription: "MozGsmIccInfo",
   174     flags:            Ci.nsIClassInfo.DOM_OBJECT,
   175     interfaces:       [Ci.nsIDOMMozGsmIccInfo]
   176   }),
   178   // nsIDOMMozGsmIccInfo
   180   msisdn: null
   181 };
   183 function CdmaIccInfo() {}
   184 CdmaIccInfo.prototype = {
   185   __proto__: IccInfo.prototype,
   186   QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozCdmaIccInfo]),
   187   classID: CDMAICCINFO_CID,
   188   classInfo: XPCOMUtils.generateCI({
   189     classID:          CDMAICCINFO_CID,
   190     classDescription: "MozCdmaIccInfo",
   191     flags:            Ci.nsIClassInfo.DOM_OBJECT,
   192     interfaces:       [Ci.nsIDOMMozCdmaIccInfo]
   193   }),
   195   // nsIDOMMozCdmaIccInfo
   197   mdn: null,
   198   prlVersion: 0
   199 };
   201 function VoicemailInfo() {}
   202 VoicemailInfo.prototype = {
   203   number: null,
   204   displayName: null
   205 };
   207 function MobileConnectionInfo() {}
   208 MobileConnectionInfo.prototype = {
   209   QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozMobileConnectionInfo]),
   210   classID:        MOBILECONNECTIONINFO_CID,
   211   classInfo:      XPCOMUtils.generateCI({
   212     classID:          MOBILECONNECTIONINFO_CID,
   213     classDescription: "MobileConnectionInfo",
   214     flags:            Ci.nsIClassInfo.DOM_OBJECT,
   215     interfaces:       [Ci.nsIDOMMozMobileConnectionInfo]
   216   }),
   218   // nsIDOMMozMobileConnectionInfo
   220   connected: false,
   221   state: null,
   222   emergencyCallsOnly: false,
   223   roaming: false,
   224   network: null,
   225   cell: null,
   226   type: null,
   227   signalStrength: null,
   228   relSignalStrength: null
   229 };
   231 function MobileNetworkInfo() {}
   232 MobileNetworkInfo.prototype = {
   233   __exposedProps__ : {shortName: 'r',
   234                       longName: 'r',
   235                       mcc: 'r',
   236                       mnc: 'r',
   237                       state: 'r'},
   239   QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozMobileNetworkInfo]),
   240   classID:        MOBILENETWORKINFO_CID,
   241   classInfo:      XPCOMUtils.generateCI({
   242     classID:          MOBILENETWORKINFO_CID,
   243     classDescription: "MobileNetworkInfo",
   244     flags:            Ci.nsIClassInfo.DOM_OBJECT,
   245     interfaces:       [Ci.nsIDOMMozMobileNetworkInfo]
   246   }),
   248   // nsIDOMMozMobileNetworkInfo
   250   shortName: null,
   251   longName: null,
   252   mcc: null,
   253   mnc: null,
   254   state: null
   255 };
   257 function MobileCellInfo() {}
   258 MobileCellInfo.prototype = {
   259   QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozMobileCellInfo]),
   260   classID:        MOBILECELLINFO_CID,
   261   classInfo:      XPCOMUtils.generateCI({
   262     classID:          MOBILECELLINFO_CID,
   263     classDescription: "MobileCellInfo",
   264     flags:            Ci.nsIClassInfo.DOM_OBJECT,
   265     interfaces:       [Ci.nsIDOMMozMobileCellInfo]
   266   }),
   268   // nsIDOMMozMobileCellInfo
   270   gsmLocationAreaCode: -1,
   271   gsmCellId: -1,
   272   cdmaBaseStationId: -1,
   273   cdmaBaseStationLatitude: -2147483648,
   274   cdmaBaseStationLongitude: -2147483648,
   275   cdmaSystemId: -1,
   276   cdmaNetworkId: -1
   277 };
   279 function VoicemailStatus(clientId) {
   280   this.serviceId = clientId;
   281 }
   282 VoicemailStatus.prototype = {
   283   QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozVoicemailStatus]),
   284   classID:        VOICEMAILSTATUS_CID,
   285   classInfo:      XPCOMUtils.generateCI({
   286     classID:          VOICEMAILSTATUS_CID,
   287     classDescription: "VoicemailStatus",
   288     flags:            Ci.nsIClassInfo.DOM_OBJECT,
   289     interfaces:       [Ci.nsIDOMMozVoicemailStatus]
   290   }),
   292   // nsIDOMMozVoicemailStatus
   294   serviceId: -1,
   295   hasMessages: false,
   296   messageCount: -1, // Count unknown.
   297   returnNumber: null,
   298   returnMessage: null
   299 };
   301 function MobileCFInfo() {}
   302 MobileCFInfo.prototype = {
   303   __exposedProps__ : {active: 'r',
   304                       action: 'r',
   305                       reason: 'r',
   306                       number: 'r',
   307                       timeSeconds: 'r',
   308                       serviceClass: 'r'},
   309   QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozMobileCFInfo]),
   310   classID:        MOBILECFINFO_CID,
   311   classInfo:      XPCOMUtils.generateCI({
   312     classID:          MOBILECFINFO_CID,
   313     classDescription: "MobileCFInfo",
   314     flags:            Ci.nsIClassInfo.DOM_OBJECT,
   315     interfaces:       [Ci.nsIDOMMozMobileCFInfo]
   316   }),
   318   // nsIDOMMozMobileCFInfo
   320   active: false,
   321   action: -1,
   322   reason: -1,
   323   number: null,
   324   timeSeconds: 0,
   325   serviceClass: -1
   326 };
   328 function CellBroadcastMessage(pdu) {
   329   this.gsmGeographicalScope = RIL.CB_GSM_GEOGRAPHICAL_SCOPE_NAMES[pdu.geographicalScope];
   330   this.messageCode = pdu.messageCode;
   331   this.messageId = pdu.messageId;
   332   this.language = pdu.language;
   333   this.body = pdu.fullBody;
   334   this.messageClass = pdu.messageClass;
   335   this.timestamp = new Date(pdu.timestamp);
   337   if (pdu.etws != null) {
   338     this.etws = new CellBroadcastEtwsInfo(pdu.etws);
   339   }
   341   this.cdmaServiceCategory = pdu.serviceCategory;
   342 }
   343 CellBroadcastMessage.prototype = {
   344   QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozCellBroadcastMessage]),
   345   classID:        CELLBROADCASTMESSAGE_CID,
   346   classInfo:      XPCOMUtils.generateCI({
   347     classID:          CELLBROADCASTMESSAGE_CID,
   348     classDescription: "CellBroadcastMessage",
   349     flags:            Ci.nsIClassInfo.DOM_OBJECT,
   350     interfaces:       [Ci.nsIDOMMozCellBroadcastMessage]
   351   }),
   353   // nsIDOMMozCellBroadcastMessage
   355   gsmGeographicalScope: null,
   356   messageCode: null,
   357   messageId: null,
   358   language: null,
   359   body: null,
   360   messageClass: null,
   361   timestamp: null,
   363   etws: null,
   364   cdmaServiceCategory: null
   365 };
   367 function CellBroadcastEtwsInfo(etwsInfo) {
   368   if (etwsInfo.warningType != null) {
   369     this.warningType = RIL.CB_ETWS_WARNING_TYPE_NAMES[etwsInfo.warningType];
   370   }
   371   this.emergencyUserAlert = etwsInfo.emergencyUserAlert;
   372   this.popup = etwsInfo.popup;
   373 }
   374 CellBroadcastEtwsInfo.prototype = {
   375   QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozCellBroadcastEtwsInfo]),
   376   classID:        CELLBROADCASTETWSINFO_CID,
   377   classInfo:      XPCOMUtils.generateCI({
   378     classID:          CELLBROADCASTETWSINFO_CID,
   379     classDescription: "CellBroadcastEtwsInfo",
   380     flags:            Ci.nsIClassInfo.DOM_OBJECT,
   381     interfaces:       [Ci.nsIDOMMozCellBroadcastEtwsInfo]
   382   }),
   384   // nsIDOMMozCellBroadcastEtwsInfo
   386   warningType: null,
   387   emergencyUserAlert: null,
   388   popup: null
   389 };
   391 function CallBarringOptions(options) {
   392   this.program = options.program;
   393   this.enabled = options.enabled;
   394   this.password = options.password;
   395   this.serviceClass = options.serviceClass;
   396 }
   397 CallBarringOptions.prototype = {
   398   __exposedProps__ : {program: 'r',
   399                       enabled: 'r',
   400                       password: 'r',
   401                       serviceClass: 'r'}
   402 };
   404 function DOMMMIResult(result) {
   405   this.serviceCode = result.serviceCode;
   406   this.statusMessage = result.statusMessage;
   407   this.additionalInformation = result.additionalInformation;
   408 }
   409 DOMMMIResult.prototype = {
   410   __exposedProps__: {serviceCode: 'r',
   411                      statusMessage: 'r',
   412                      additionalInformation: 'r'}
   413 };
   415 function DOMCLIRStatus(option) {
   416   this.n = option.n;
   417   this.m = option.m;
   418 }
   419 DOMCLIRStatus.prototype = {
   420   __exposedProps__ : {n: 'r',
   421                       m: 'r'}
   422 };
   424 function DOMMMIError() {
   425 }
   426 DOMMMIError.prototype = {
   427   classDescription: "DOMMMIError",
   428   classID:          DOMMMIERROR_CID,
   429   contractID:       "@mozilla.org/dom/mmi-error;1",
   430   QueryInterface:   XPCOMUtils.generateQI([Ci.nsISupports]),
   431   __init: function(serviceCode, name, message, additionalInformation) {
   432     this.__DOM_IMPL__.init(name, message);
   433     this.serviceCode = serviceCode;
   434     this.additionalInformation = additionalInformation;
   435   },
   436 };
   438 function IccCardLockError() {
   439 }
   440 IccCardLockError.prototype = {
   441   classDescription: "IccCardLockError",
   442   classID:          ICCCARDLOCKERROR_CID,
   443   contractID:       "@mozilla.org/dom/icccardlock-error;1",
   444   QueryInterface:   XPCOMUtils.generateQI([Ci.nsISupports]),
   445   __init: function(lockType, errorMsg, retryCount) {
   446     this.__DOM_IMPL__.init(errorMsg);
   447     this.lockType = lockType;
   448     this.retryCount = retryCount;
   449   },
   450 };
   452 function RILContentHelper() {
   453   this.updateDebugFlag();
   455   this.numClients = gNumRadioInterfaces;
   456   if (DEBUG) debug("Number of clients: " + this.numClients);
   458   this.rilContexts = [];
   459   this.voicemailInfos = [];
   460   this.voicemailStatuses = [];
   461   for (let clientId = 0; clientId < this.numClients; clientId++) {
   462     this.rilContexts[clientId] = {
   463       cardState:            RIL.GECKO_CARDSTATE_UNKNOWN,
   464       networkSelectionMode: RIL.GECKO_NETWORK_SELECTION_UNKNOWN,
   465       radioState:           null,
   466       iccInfo:              null,
   467       voiceConnectionInfo:  new MobileConnectionInfo(),
   468       dataConnectionInfo:   new MobileConnectionInfo()
   469     };
   471     this.voicemailInfos[clientId] = new VoicemailInfo();
   472   }
   474   this.voicemailDefaultServiceId = this.getVoicemailDefaultServiceId();
   476   this.initDOMRequestHelper(/* aWindow */ null, RIL_IPC_MSG_NAMES);
   477   this._windowsMap = [];
   478   this._selectingNetworks = [];
   479   this._mobileConnectionListeners = [];
   480   this._cellBroadcastListeners = [];
   481   this._voicemailListeners = [];
   482   this._iccListeners = [];
   484   Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
   486   Services.prefs.addObserver(kPrefRilDebuggingEnabled, this, false);
   487   Services.prefs.addObserver(kPrefVoicemailDefaultServiceId, this, false);
   488 }
   490 RILContentHelper.prototype = {
   491   __proto__: DOMRequestIpcHelper.prototype,
   493   QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileConnectionProvider,
   494                                          Ci.nsICellBroadcastProvider,
   495                                          Ci.nsIVoicemailProvider,
   496                                          Ci.nsIIccProvider,
   497                                          Ci.nsIObserver,
   498                                          Ci.nsISupportsWeakReference,
   499                                          Ci.nsIObserver]),
   500   classID:   RILCONTENTHELPER_CID,
   501   classInfo: XPCOMUtils.generateCI({classID: RILCONTENTHELPER_CID,
   502                                     classDescription: "RILContentHelper",
   503                                     interfaces: [Ci.nsIMobileConnectionProvider,
   504                                                  Ci.nsICellBroadcastProvider,
   505                                                  Ci.nsIVoicemailProvider,
   506                                                  Ci.nsIIccProvider]}),
   508   updateDebugFlag: function() {
   509     try {
   510       DEBUG = RIL.DEBUG_CONTENT_HELPER ||
   511               Services.prefs.getBoolPref(kPrefRilDebuggingEnabled);
   512     } catch (e) {}
   513   },
   515   // An utility function to copy objects.
   516   updateInfo: function(srcInfo, destInfo) {
   517     for (let key in srcInfo) {
   518       destInfo[key] = srcInfo[key];
   519     }
   520   },
   522   updateConnectionInfo: function(srcInfo, destInfo) {
   523     for (let key in srcInfo) {
   524       if ((key != "network") && (key != "cell")) {
   525         destInfo[key] = srcInfo[key];
   526       }
   527     }
   529     let srcCell = srcInfo.cell;
   530     if (!srcCell) {
   531       destInfo.cell = null;
   532     } else {
   533       let cell = destInfo.cell;
   534       if (!cell) {
   535         cell = destInfo.cell = new MobileCellInfo();
   536       }
   538       this.updateInfo(srcCell, cell);
   539     }
   541     let srcNetwork = srcInfo.network;
   542     if (!srcNetwork) {
   543       destInfo.network= null;
   544       return;
   545     }
   547     let network = destInfo.network;
   548     if (!network) {
   549       network = destInfo.network = new MobileNetworkInfo();
   550     }
   552     this.updateInfo(srcNetwork, network);
   553   },
   555   /**
   556    * We need to consider below cases when update iccInfo:
   557    * 1. Should clear iccInfo to null if there is no card detected.
   558    * 2. Need to create corresponding object based on iccType.
   559    */
   560   updateIccInfo: function(clientId, newInfo) {
   561     let rilContext = this.rilContexts[clientId];
   563     // Card is not detected, clear iccInfo to null.
   564     if (!newInfo || !newInfo.iccType || !newInfo.iccid) {
   565       if (rilContext.iccInfo) {
   566         rilContext.iccInfo = null;
   567         this._deliverEvent(clientId,
   568                            "_mobileConnectionListeners",
   569                            "notifyIccChanged",
   570                            null);
   571       }
   572       return;
   573     }
   575     // If iccInfo is null, new corresponding object based on iccType.
   576     if (!rilContext.iccInfo) {
   577       if (newInfo.iccType === "ruim" || newInfo.iccType === "csim") {
   578         rilContext.iccInfo = new CdmaIccInfo();
   579       } else {
   580         rilContext.iccInfo = new GsmIccInfo();
   581       }
   582     }
   583     let changed = (rilContext.iccInfo.iccid != newInfo.iccid) ?
   584       true : false;
   586     this.updateInfo(newInfo, rilContext.iccInfo);
   588     // Deliver event after info is updated.
   589     if (changed) {
   590       this._deliverEvent(clientId,
   591                          "_mobileConnectionListeners",
   592                          "notifyIccChanged",
   593                          null);
   594     }
   595   },
   597   _windowsMap: null,
   599   rilContexts: null,
   601   getRilContext: function(clientId) {
   602     // Update ril contexts by sending IPC message to chrome only when the first
   603     // time we require it. The information will be updated by following info
   604     // changed messages.
   605     this.getRilContext = function getRilContext(clientId) {
   606       return this.rilContexts[clientId];
   607     };
   609     for (let cId = 0; cId < this.numClients; cId++) {
   610       let rilContext =
   611         cpmm.sendSyncMessage("RIL:GetRilContext", {clientId: cId})[0];
   612       if (!rilContext) {
   613         if (DEBUG) debug("Received null rilContext from chrome process.");
   614         continue;
   615       }
   616       this.rilContexts[cId].cardState = rilContext.cardState;
   617       this.rilContexts[cId].networkSelectionMode = rilContext.networkSelectionMode;
   618       this.rilContexts[cId].radioState = rilContext.detailedRadioState;
   619       this.updateIccInfo(cId, rilContext.iccInfo);
   620       this.updateConnectionInfo(rilContext.voice, this.rilContexts[cId].voiceConnectionInfo);
   621       this.updateConnectionInfo(rilContext.data, this.rilContexts[cId].dataConnectionInfo);
   622     }
   624     return this.rilContexts[clientId];
   625   },
   627   /**
   628    * nsIIccProvider
   629    */
   631   getIccInfo: function(clientId) {
   632     let context = this.getRilContext(clientId);
   633     return context && context.iccInfo;
   634   },
   636   getCardState: function(clientId) {
   637     let context = this.getRilContext(clientId);
   638     return context && context.cardState;
   639   },
   641   matchMvno: function(clientId, window, mvnoType, mvnoData) {
   642     if (window == null) {
   643       throw Components.Exception("Can't get window object",
   644                                   Cr.NS_ERROR_UNEXPECTED);
   645     }
   647     let request = Services.DOMRequest.createRequest(window);
   648     let requestId = this.getRequestId(request);
   650     cpmm.sendAsyncMessage("RIL:MatchMvno", {
   651       clientId: clientId,
   652       data: {
   653         requestId: requestId,
   654         mvnoType: mvnoType,
   655         mvnoData: mvnoData
   656       }
   657     });
   658     return request;
   659   },
   661   /**
   662    * nsIMobileConnectionProvider
   663    */
   665   getLastKnownNetwork: function(clientId) {
   666     return cpmm.sendSyncMessage("RIL:GetLastKnownNetwork", {
   667       clientId: clientId
   668     })[0];
   669   },
   671   getLastKnownHomeNetwork: function(clientId) {
   672     return cpmm.sendSyncMessage("RIL:GetLastKnownHomeNetwork", {
   673       clientId: clientId
   674     })[0];
   675   },
   677   getVoiceConnectionInfo: function(clientId) {
   678     let context = this.getRilContext(clientId);
   679     return context && context.voiceConnectionInfo;
   680   },
   682   getDataConnectionInfo: function(clientId) {
   683     let context = this.getRilContext(clientId);
   684     return context && context.dataConnectionInfo;
   685   },
   687   getIccId: function(clientId) {
   688     let context = this.getRilContext(clientId);
   689     return context && context.iccInfo && context.iccInfo.iccid;
   690   },
   692   getNetworkSelectionMode: function(clientId) {
   693     let context = this.getRilContext(clientId);
   694     return context && context.networkSelectionMode;
   695   },
   697   getRadioState: function(clientId) {
   698     let context = this.getRilContext(clientId);
   699     return context && context.radioState;
   700   },
   702   getSupportedNetworkTypes: function(clientId) {
   703     return cpmm.sendSyncMessage("RIL:GetSupportedNetworkTypes", {
   704       clientId: clientId
   705     })[0];
   706   },
   708   /**
   709    * The networks that are currently trying to be selected (or "automatic").
   710    * This helps ensure that only one network per client is selected at a time.
   711    */
   712   _selectingNetworks: null,
   714   getNetworks: function(clientId, window) {
   715     if (window == null) {
   716       throw Components.Exception("Can't get window object",
   717                                   Cr.NS_ERROR_UNEXPECTED);
   718     }
   720     let request = Services.DOMRequest.createRequest(window);
   721     let requestId = this.getRequestId(request);
   723     cpmm.sendAsyncMessage("RIL:GetAvailableNetworks", {
   724       clientId: clientId,
   725       data: {
   726         requestId: requestId
   727       }
   728     });
   729     return request;
   730   },
   732   selectNetwork: function(clientId, window, network) {
   733     if (window == null) {
   734       throw Components.Exception("Can't get window object",
   735                                   Cr.NS_ERROR_UNEXPECTED);
   736     }
   738     if (this._selectingNetworks[clientId]) {
   739       throw new Error("Already selecting a network: " + this._selectingNetworks[clientId]);
   740     }
   742     if (!network) {
   743       throw new Error("Invalid network provided: " + network);
   744     }
   746     if (isNaN(parseInt(network.mnc, 10))) {
   747       throw new Error("Invalid network MNC: " + network.mnc);
   748     }
   750     if (isNaN(parseInt(network.mcc, 10))) {
   751       throw new Error("Invalid network MCC: " + network.mcc);
   752     }
   754     let request = Services.DOMRequest.createRequest(window);
   755     let requestId = this.getRequestId(request);
   757     if (this.rilContexts[clientId].networkSelectionMode == RIL.GECKO_NETWORK_SELECTION_MANUAL &&
   758         this.rilContexts[clientId].voiceConnectionInfo.network === network) {
   760       // Already manually selected this network, so schedule
   761       // onsuccess to be fired on the next tick
   762       this.dispatchFireRequestSuccess(requestId, null);
   763       return request;
   764     }
   766     this._selectingNetworks[clientId] = network;
   768     cpmm.sendAsyncMessage("RIL:SelectNetwork", {
   769       clientId: clientId,
   770       data: {
   771         requestId: requestId,
   772         mnc: network.mnc,
   773         mcc: network.mcc
   774       }
   775     });
   777     return request;
   778   },
   780   selectNetworkAutomatically: function(clientId, window) {
   782     if (window == null) {
   783       throw Components.Exception("Can't get window object",
   784                                   Cr.NS_ERROR_UNEXPECTED);
   785     }
   787     if (this._selectingNetworks[clientId]) {
   788       throw new Error("Already selecting a network: " + this._selectingNetworks[clientId]);
   789     }
   791     let request = Services.DOMRequest.createRequest(window);
   792     let requestId = this.getRequestId(request);
   794     if (this.rilContexts[clientId].networkSelectionMode == RIL.GECKO_NETWORK_SELECTION_AUTOMATIC) {
   795       // Already using automatic selection mode, so schedule
   796       // onsuccess to be be fired on the next tick
   797       this.dispatchFireRequestSuccess(requestId, null);
   798       return request;
   799     }
   801     this._selectingNetworks[clientId] = "automatic";
   802     cpmm.sendAsyncMessage("RIL:SelectNetworkAuto", {
   803       clientId: clientId,
   804       data: {
   805         requestId: requestId
   806       }
   807     });
   808     return request;
   809   },
   811   setPreferredNetworkType: function(clientId, window, type) {
   812     if (window == null) {
   813       throw Components.Exception("Can't get window object",
   814                                   Cr.NS_ERROR_UNEXPECTED);
   815     }
   817     let request = Services.DOMRequest.createRequest(window);
   818     let requestId = this.getRequestId(request);
   820     cpmm.sendAsyncMessage("RIL:SetPreferredNetworkType", {
   821       clientId: clientId,
   822       data: {
   823         requestId: requestId,
   824         type: type
   825       }
   826     });
   827     return request;
   828   },
   830   getPreferredNetworkType: function(clientId, window) {
   831     if (window == null) {
   832       throw Components.Exception("Can't get window object",
   833                                   Cr.NS_ERROR_UNEXPECTED);
   834     }
   836     let request = Services.DOMRequest.createRequest(window);
   837     let requestId = this.getRequestId(request);
   839     cpmm.sendAsyncMessage("RIL:GetPreferredNetworkType", {
   840       clientId: clientId,
   841       data: {
   842         requestId: requestId
   843       }
   844     });
   845     return request;
   846   },
   848   setRoamingPreference: function(clientId, window, mode) {
   849     if (window == null) {
   850       throw Components.Exception("Can't get window object",
   851                                   Cr.NS_ERROR_UNEXPECTED);
   852     }
   854     let request = Services.DOMRequest.createRequest(window);
   855     let requestId = this.getRequestId(request);
   857     if (!mode) {
   858       this.dispatchFireRequestError(requestId,
   859                                     RIL.GECKO_ERROR_INVALID_PARAMETER);
   860       return request;
   861     }
   863     cpmm.sendAsyncMessage("RIL:SetRoamingPreference", {
   864       clientId: clientId,
   865       data: {
   866         requestId: requestId,
   867         mode: mode
   868       }
   869     });
   870     return request;
   871   },
   873   getRoamingPreference: function(clientId, window) {
   874     if (window == null) {
   875       throw Components.Exception("Can't get window object",
   876                                   Cr.NS_ERROR_UNEXPECTED);
   877     }
   879     let request = Services.DOMRequest.createRequest(window);
   880     let requestId = this.getRequestId(request);
   882     cpmm.sendAsyncMessage("RIL:GetRoamingPreference", {
   883       clientId: clientId,
   884       data: {
   885         requestId: requestId
   886       }
   887     });
   888     return request;
   889   },
   891   setVoicePrivacyMode: function(clientId, window, enabled) {
   892     if (window == null) {
   893       throw Components.Exception("Can't get window object",
   894                                   Cr.NS_ERROR_UNEXPECTED);
   895     }
   897     let request = Services.DOMRequest.createRequest(window);
   898     let requestId = this.getRequestId(request);
   900     cpmm.sendAsyncMessage("RIL:SetVoicePrivacyMode", {
   901       clientId: clientId,
   902       data: {
   903         requestId: requestId,
   904         enabled: enabled
   905       }
   906     });
   907     return request;
   908   },
   910   getVoicePrivacyMode: function(clientId, window) {
   911     if (window == null) {
   912       throw Components.Exception("Can't get window object",
   913                                   Cr.NS_ERROR_UNEXPECTED);
   914     }
   916     let request = Services.DOMRequest.createRequest(window);
   917     let requestId = this.getRequestId(request);
   919     cpmm.sendAsyncMessage("RIL:GetVoicePrivacyMode", {
   920       clientId: clientId,
   921       data: {
   922         requestId: requestId
   923       }
   924     });
   925     return request;
   926   },
   928   getCardLockState: function(clientId, window, lockType) {
   929     if (window == null) {
   930       throw Components.Exception("Can't get window object",
   931                                   Cr.NS_ERROR_UNEXPECTED);
   932     }
   933     let request = Services.DOMRequest.createRequest(window);
   934     let requestId = this.getRequestId(request);
   935     this._windowsMap[requestId] = window;
   937     cpmm.sendAsyncMessage("RIL:GetCardLockState", {
   938       clientId: clientId,
   939       data: {
   940         lockType: lockType,
   941         requestId: requestId
   942       }
   943     });
   944     return request;
   945   },
   947   unlockCardLock: function(clientId, window, info) {
   948     if (window == null) {
   949       throw Components.Exception("Can't get window object",
   950                                   Cr.NS_ERROR_UNEXPECTED);
   951     }
   952     let request = Services.DOMRequest.createRequest(window);
   953     info.requestId = this.getRequestId(request);
   954     this._windowsMap[info.requestId] = window;
   956     cpmm.sendAsyncMessage("RIL:UnlockCardLock", {
   957       clientId: clientId,
   958       data: info
   959     });
   960     return request;
   961   },
   963   setCardLock: function(clientId, window, info) {
   964     if (window == null) {
   965       throw Components.Exception("Can't get window object",
   966                                   Cr.NS_ERROR_UNEXPECTED);
   967     }
   968     let request = Services.DOMRequest.createRequest(window);
   969     info.requestId = this.getRequestId(request);
   970     this._windowsMap[info.requestId] = window;
   972     cpmm.sendAsyncMessage("RIL:SetCardLock", {
   973       clientId: clientId,
   974       data: info
   975     });
   976     return request;
   977   },
   979   getCardLockRetryCount: function(clientId, window, lockType) {
   980     if (window == null) {
   981       throw Components.Exception("Can't get window object",
   982                                   Cr.NS_ERROR_UNEXPECTED);
   983     }
   984     let request = Services.DOMRequest.createRequest(window);
   985     let requestId = this.getRequestId(request);
   986     cpmm.sendAsyncMessage("RIL:GetCardLockRetryCount", {
   987       clientId: clientId,
   988       data: {
   989         lockType: lockType,
   990         requestId: requestId
   991       }
   992     });
   993     return request;
   994   },
   996   sendMMI: function(clientId, window, mmi) {
   997     if (DEBUG) debug("Sending MMI " + mmi);
   998     if (!window) {
   999       throw Components.Exception("Can't get window object",
  1000                                  Cr.NS_ERROR_UNEXPECTED);
  1002     let request = Services.DOMRequest.createRequest(window);
  1003     let requestId = this.getRequestId(request);
  1004     // We need to save the global window to get the proper MMIError
  1005     // constructor once we get the reply from the parent process.
  1006     this._windowsMap[requestId] = window;
  1008     cpmm.sendAsyncMessage("RIL:SendMMI", {
  1009       clientId: clientId,
  1010       data: {
  1011         mmi: mmi,
  1012         requestId: requestId
  1014     });
  1015     return request;
  1016   },
  1018   cancelMMI: function(clientId, window) {
  1019     if (DEBUG) debug("Cancel MMI");
  1020     if (!window) {
  1021       throw Components.Exception("Can't get window object",
  1022                                  Cr.NS_ERROR_UNEXPECTED);
  1024     let request = Services.DOMRequest.createRequest(window);
  1025     let requestId = this.getRequestId(request);
  1026     cpmm.sendAsyncMessage("RIL:CancelMMI", {
  1027       clientId: clientId,
  1028       data: {
  1029         requestId: requestId
  1031     });
  1032     return request;
  1033   },
  1035   sendStkResponse: function(clientId, window, command, response) {
  1036     if (window == null) {
  1037       throw Components.Exception("Can't get window object",
  1038                                   Cr.NS_ERROR_UNEXPECTED);
  1040     response.command = command;
  1041     cpmm.sendAsyncMessage("RIL:SendStkResponse", {
  1042       clientId: clientId,
  1043       data: response
  1044     });
  1045   },
  1047   sendStkMenuSelection: function(clientId, window, itemIdentifier,
  1048                                  helpRequested) {
  1049     if (window == null) {
  1050       throw Components.Exception("Can't get window object",
  1051                                   Cr.NS_ERROR_UNEXPECTED);
  1053     cpmm.sendAsyncMessage("RIL:SendStkMenuSelection", {
  1054       clientId: clientId,
  1055       data: {
  1056         itemIdentifier: itemIdentifier,
  1057         helpRequested: helpRequested
  1059     });
  1060   },
  1062   sendStkTimerExpiration: function(clientId, window, timer) {
  1063     if (window == null) {
  1064       throw Components.Exception("Can't get window object",
  1065                                   Cr.NS_ERROR_UNEXPECTED);
  1067     cpmm.sendAsyncMessage("RIL:SendStkTimerExpiration", {
  1068       clientId: clientId,
  1069       data: {
  1070         timer: timer
  1072     });
  1073   },
  1075   sendStkEventDownload: function(clientId, window, event) {
  1076     if (window == null) {
  1077       throw Components.Exception("Can't get window object",
  1078                                   Cr.NS_ERROR_UNEXPECTED);
  1080     cpmm.sendAsyncMessage("RIL:SendStkEventDownload", {
  1081       clientId: clientId,
  1082       data: {
  1083         event: event
  1085     });
  1086   },
  1088   iccOpenChannel: function(clientId, window, aid) {
  1089     if (window == null) {
  1090       throw Components.Exception("Can't get window object",
  1091                                   Cr.NS_ERROR_UNEXPECTED);
  1094     let request = Services.DOMRequest.createRequest(window);
  1095     let requestId = this.getRequestId(request);
  1097     cpmm.sendAsyncMessage("RIL:IccOpenChannel", {
  1098       clientId: clientId,
  1099       data: {
  1100         requestId: requestId,
  1101         aid: aid
  1103     });
  1104     return request;
  1105   },
  1107   iccExchangeAPDU: function(clientId, window, channel, apdu) {
  1108     if (window == null) {
  1109       throw Components.Exception("Can't get window object",
  1110                                   Cr.NS_ERROR_UNEXPECTED);
  1113     let request = Services.DOMRequest.createRequest(window);
  1114     let requestId = this.getRequestId(request);
  1116     //Potentially you need serialization here and can't pass the jsval through
  1117     cpmm.sendAsyncMessage("RIL:IccExchangeAPDU", {
  1118       clientId: clientId,
  1119       data: {
  1120         requestId: requestId,
  1121         channel: channel,
  1122         apdu: apdu
  1124     });
  1125     return request;
  1126   },
  1128   iccCloseChannel: function(clientId, window, channel) {
  1129     if (window == null) {
  1130       throw Components.Exception("Can't get window object",
  1131                                   Cr.NS_ERROR_UNEXPECTED);
  1134     let request = Services.DOMRequest.createRequest(window);
  1135     let requestId = this.getRequestId(request);
  1137     cpmm.sendAsyncMessage("RIL:IccCloseChannel", {
  1138       clientId: clientId,
  1139       data: {
  1140         requestId: requestId,
  1141         channel: channel
  1143     });
  1144     return request;
  1145   },
  1147   readContacts: function(clientId, window, contactType) {
  1148     if (window == null) {
  1149       throw Components.Exception("Can't get window object",
  1150                                   Cr.NS_ERROR_UNEXPECTED);
  1153     let request = Services.DOMRequest.createRequest(window);
  1154     let requestId = this.getRequestId(request);
  1155     this._windowsMap[requestId] = window;
  1157     cpmm.sendAsyncMessage("RIL:ReadIccContacts", {
  1158       clientId: clientId,
  1159       data: {
  1160         requestId: requestId,
  1161         contactType: contactType
  1163     });
  1164     return request;
  1165   },
  1167   updateContact: function(clientId, window, contactType, contact, pin2) {
  1168     if (window == null) {
  1169       throw Components.Exception("Can't get window object",
  1170                                   Cr.NS_ERROR_UNEXPECTED);
  1173     let request = Services.DOMRequest.createRequest(window);
  1174     let requestId = this.getRequestId(request);
  1175     this._windowsMap[requestId] = window;
  1177     // Parsing nsDOMContact to Icc Contact format
  1178     let iccContact = {};
  1180     if (Array.isArray(contact.name) && contact.name[0]) {
  1181       iccContact.alphaId = contact.name[0];
  1184     if (Array.isArray(contact.tel)) {
  1185       iccContact.number = contact.tel[0] && contact.tel[0].value;
  1186       let telArray = contact.tel.slice(1);
  1187       let length = telArray.length;
  1188       if (length > 0) {
  1189         iccContact.anr = [];
  1191       for (let i = 0; i < telArray.length; i++) {
  1192         iccContact.anr.push(telArray[i].value);
  1196     if (Array.isArray(contact.email) && contact.email[0]) {
  1197       iccContact.email = contact.email[0].value;
  1200     iccContact.contactId = contact.id;
  1202     cpmm.sendAsyncMessage("RIL:UpdateIccContact", {
  1203       clientId: clientId,
  1204       data: {
  1205         requestId: requestId,
  1206         contactType: contactType,
  1207         contact: iccContact,
  1208         pin2: pin2
  1210     });
  1212     return request;
  1213   },
  1215   getCallForwardingOption: function(clientId, window, reason) {
  1216     if (window == null) {
  1217       throw Components.Exception("Can't get window object",
  1218                                   Cr.NS_ERROR_UNEXPECTED);
  1220     let request = Services.DOMRequest.createRequest(window);
  1221     let requestId = this.getRequestId(request);
  1223     if (!this._isValidCFReason(reason)){
  1224       this.dispatchFireRequestError(requestId,
  1225                                     RIL.GECKO_ERROR_INVALID_PARAMETER);
  1226       return request;
  1229     cpmm.sendAsyncMessage("RIL:GetCallForwardingOptions", {
  1230       clientId: clientId,
  1231       data: {
  1232         requestId: requestId,
  1233         reason: reason
  1235     });
  1237     return request;
  1238   },
  1240   setCallForwardingOption: function(clientId, window, cfInfo) {
  1241     if (window == null) {
  1242       throw Components.Exception("Can't get window object",
  1243                                   Cr.NS_ERROR_UNEXPECTED);
  1245     let request = Services.DOMRequest.createRequest(window);
  1246     let requestId = this.getRequestId(request);
  1248     if (!cfInfo ||
  1249         !this._isValidCFReason(cfInfo.reason) ||
  1250         !this._isValidCFAction(cfInfo.action)){
  1251       this.dispatchFireRequestError(requestId,
  1252                                     RIL.GECKO_ERROR_INVALID_PARAMETER);
  1253       return request;
  1256     cpmm.sendAsyncMessage("RIL:SetCallForwardingOptions", {
  1257       clientId: clientId,
  1258       data: {
  1259         requestId: requestId,
  1260         active: cfInfo.active,
  1261         action: cfInfo.action,
  1262         reason: cfInfo.reason,
  1263         number: cfInfo.number,
  1264         timeSeconds: cfInfo.timeSeconds
  1266     });
  1268     return request;
  1269   },
  1271   getCallBarringOption: function(clientId, window, option) {
  1272     if (window == null) {
  1273       throw Components.Exception("Can't get window object",
  1274                                   Cr.NS_ERROR_UNEXPECTED);
  1276     let request = Services.DOMRequest.createRequest(window);
  1277     let requestId = this.getRequestId(request);
  1279     if (DEBUG) debug("getCallBarringOption: " + JSON.stringify(option));
  1280     if (!this._isValidCallBarringOptions(option)) {
  1281       this.dispatchFireRequestError(requestId,
  1282                                     RIL.GECKO_ERROR_INVALID_PARAMETER);
  1283       return request;
  1286     cpmm.sendAsyncMessage("RIL:GetCallBarringOptions", {
  1287       clientId: clientId,
  1288       data: {
  1289         requestId: requestId,
  1290         program: option.program,
  1291         password: option.password,
  1292         serviceClass: option.serviceClass
  1294     });
  1295     return request;
  1296   },
  1298   setCallBarringOption: function(clientId, window, option) {
  1299     if (window == null) {
  1300       throw Components.Exception("Can't get window object",
  1301                                   Cr.NS_ERROR_UNEXPECTED);
  1303     let request = Services.DOMRequest.createRequest(window);
  1304     let requestId = this.getRequestId(request);
  1306     if (DEBUG) debug("setCallBarringOption: " + JSON.stringify(option));
  1307     if (!this._isValidCallBarringOptions(option, true)) {
  1308       this.dispatchFireRequestError(requestId,
  1309                                     RIL.GECKO_ERROR_INVALID_PARAMETER);
  1310       return request;
  1313     cpmm.sendAsyncMessage("RIL:SetCallBarringOptions", {
  1314       clientId: clientId,
  1315       data: {
  1316         requestId: requestId,
  1317         program: option.program,
  1318         enabled: option.enabled,
  1319         password: option.password,
  1320         serviceClass: option.serviceClass
  1322     });
  1323     return request;
  1324   },
  1326   changeCallBarringPassword: function(clientId, window, info) {
  1327     if (window == null) {
  1328       throw Components.Exception("Can't get window object",
  1329                                   Cr.NS_ERROR_UNEXPECTED);
  1331     let request = Services.DOMRequest.createRequest(window);
  1332     let requestId = this.getRequestId(request);
  1334     // Checking valid PIN for supplementary services. See TS.22.004 clause 5.2.
  1335     if (info.pin == null || !info.pin.match(/^\d{4}$/) ||
  1336         info.newPin == null || !info.newPin.match(/^\d{4}$/)) {
  1337       this.dispatchFireRequestError(requestId, "InvalidPassword");
  1338       return request;
  1341     if (DEBUG) debug("changeCallBarringPassword: " + JSON.stringify(info));
  1342     info.requestId = requestId;
  1343     cpmm.sendAsyncMessage("RIL:ChangeCallBarringPassword", {
  1344       clientId: clientId,
  1345       data: info
  1346     });
  1348     return request;
  1349   },
  1351   getCallWaitingOption: function(clientId, window) {
  1352     if (window == null) {
  1353       throw Components.Exception("Can't get window object",
  1354                                   Cr.NS_ERROR_UNEXPECTED);
  1356     let request = Services.DOMRequest.createRequest(window);
  1357     let requestId = this.getRequestId(request);
  1359     cpmm.sendAsyncMessage("RIL:GetCallWaitingOptions", {
  1360       clientId: clientId,
  1361       data: {
  1362         requestId: requestId
  1364     });
  1366     return request;
  1367   },
  1369   setCallWaitingOption: function(clientId, window, enabled) {
  1370     if (window == null) {
  1371       throw Components.Exception("Can't get window object",
  1372                                   Cr.NS_ERROR_UNEXPECTED);
  1374     let request = Services.DOMRequest.createRequest(window);
  1375     let requestId = this.getRequestId(request);
  1377     cpmm.sendAsyncMessage("RIL:SetCallWaitingOptions", {
  1378       clientId: clientId,
  1379       data: {
  1380         requestId: requestId,
  1381         enabled: enabled
  1383     });
  1385     return request;
  1386   },
  1388   getCallingLineIdRestriction: function(clientId, window) {
  1389     if (window == null) {
  1390       throw Components.Exception("Can't get window object",
  1391                                   Cr.NS_ERROR_UNEXPECTED);
  1393     let request = Services.DOMRequest.createRequest(window);
  1394     let requestId = this.getRequestId(request);
  1396     cpmm.sendAsyncMessage("RIL:GetCallingLineIdRestriction", {
  1397       clientId: clientId,
  1398       data: {
  1399         requestId: requestId
  1401     });
  1403     return request;
  1404   },
  1406   setCallingLineIdRestriction: function(clientId, window, clirMode) {
  1408     if (window == null) {
  1409       throw Components.Exception("Can't get window object",
  1410                                   Cr.NS_ERROR_UNEXPECTED);
  1412     let request = Services.DOMRequest.createRequest(window);
  1413     let requestId = this.getRequestId(request);
  1415     cpmm.sendAsyncMessage("RIL:SetCallingLineIdRestriction", {
  1416       clientId: clientId,
  1417       data: {
  1418         requestId: requestId,
  1419         clirMode: clirMode
  1421     });
  1423     return request;
  1424   },
  1426   exitEmergencyCbMode: function(clientId, window) {
  1427     if (window == null) {
  1428       throw Components.Exception("Can't get window object",
  1429                                   Cr.NS_ERROR_UNEXPECTED);
  1431     let request = Services.DOMRequest.createRequest(window);
  1432     let requestId = this.getRequestId(request);
  1434     cpmm.sendAsyncMessage("RIL:ExitEmergencyCbMode", {
  1435       clientId: clientId,
  1436       data: {
  1437         requestId: requestId,
  1439     });
  1441     return request;
  1442   },
  1444   setRadioEnabled: function(clientId, window, enabled) {
  1445     if (window == null) {
  1446       throw Components.Exception("Can't get window object",
  1447                                   Cr.NS_ERROR_UNEXPECTED);
  1449     let request = Services.DOMRequest.createRequest(window);
  1450     let requestId = this.getRequestId(request);
  1452     cpmm.sendAsyncMessage("RIL:SetRadioEnabled", {
  1453       clientId: clientId,
  1454       data: {
  1455         requestId: requestId,
  1456         enabled: enabled,
  1458     });
  1460     return request;
  1461   },
  1463   _mobileConnectionListeners: null,
  1464   _cellBroadcastListeners: null,
  1465   _voicemailListeners: null,
  1466   _iccListeners: null,
  1468   voicemailInfos: null,
  1469   voicemailStatuses: null,
  1471   voicemailDefaultServiceId: 0,
  1472   getVoicemailDefaultServiceId: function() {
  1473     let id = Services.prefs.getIntPref(kPrefVoicemailDefaultServiceId);
  1475     if (id >= gNumRadioInterfaces || id < 0) {
  1476       id = 0;
  1479     return id;
  1480   },
  1482   getVoicemailInfo: function(clientId) {
  1483     // Get voicemail infomation by IPC only on first time.
  1484     this.getVoicemailInfo = function getVoicemailInfo(clientId) {
  1485       return this.voicemailInfos[clientId];
  1486     };
  1488     for (let cId = 0; cId < gNumRadioInterfaces; cId++) {
  1489       let voicemailInfo =
  1490         cpmm.sendSyncMessage("RIL:GetVoicemailInfo", {clientId: cId})[0];
  1491       if (voicemailInfo) {
  1492         this.updateInfo(voicemailInfo, this.voicemailInfos[cId]);
  1496     return this.voicemailInfos[clientId];
  1497   },
  1499   getVoicemailNumber: function(clientId) {
  1500     return this.getVoicemailInfo(clientId).number;
  1501   },
  1503   getVoicemailDisplayName: function(clientId) {
  1504     return this.getVoicemailInfo(clientId).displayName;
  1505   },
  1507   getVoicemailStatus: function(clientId) {
  1508     return this.voicemailStatuses[clientId];
  1509   },
  1511   registerListener: function(listenerType, clientId, listener) {
  1512     if (!this[listenerType]) {
  1513       return;
  1515     let listeners = this[listenerType][clientId];
  1516     if (!listeners) {
  1517       listeners = this[listenerType][clientId] = [];
  1520     if (listeners.indexOf(listener) != -1) {
  1521       throw new Error("Already registered this listener!");
  1524     listeners.push(listener);
  1525     if (DEBUG) debug("Registered " + listenerType + " listener: " + listener);
  1526   },
  1528   unregisterListener: function(listenerType, clientId, listener) {
  1529     if (!this[listenerType]) {
  1530       return;
  1532     let listeners = this[listenerType][clientId];
  1533     if (!listeners) {
  1534       return;
  1537     let index = listeners.indexOf(listener);
  1538     if (index != -1) {
  1539       listeners.splice(index, 1);
  1540       if (DEBUG) debug("Unregistered listener: " + listener);
  1542   },
  1544   registerMobileConnectionMsg: function(clientId, listener) {
  1545     if (DEBUG) debug("Registering for mobile connection related messages");
  1546     this.registerListener("_mobileConnectionListeners", clientId, listener);
  1547     cpmm.sendAsyncMessage("RIL:RegisterMobileConnectionMsg");
  1548   },
  1550   unregisterMobileConnectionMsg: function(clientId, listener) {
  1551     this.unregisterListener("_mobileConnectionListeners", clientId, listener);
  1552   },
  1554   registerVoicemailMsg: function(listener) {
  1555     if (DEBUG) debug("Registering for voicemail-related messages");
  1556     // To follow the listener registration scheme, we add a dummy clientId 0.
  1557     // All voicemail events are routed to listener for client id 0.
  1558     // See |handleVoicemailNotification|.
  1559     this.registerListener("_voicemailListeners", 0, listener);
  1560     cpmm.sendAsyncMessage("RIL:RegisterVoicemailMsg");
  1561   },
  1563   unregisterVoicemailMsg: function(listener) {
  1564     // To follow the listener unregistration scheme, we add a dummy clientId 0.
  1565     // All voicemail events are routed to listener for client id 0.
  1566     // See |handleVoicemailNotification|.
  1567     this.unregisterListener("_voicemailListeners", 0, listener);
  1568   },
  1570   registerCellBroadcastMsg: function(listener) {
  1571     if (DEBUG) debug("Registering for Cell Broadcast related messages");
  1572     //TODO: Bug 921326 - Cellbroadcast API: support multiple sim cards
  1573     this.registerListener("_cellBroadcastListeners", 0, listener);
  1574     cpmm.sendAsyncMessage("RIL:RegisterCellBroadcastMsg");
  1575   },
  1577   unregisterCellBroadcastMsg: function(listener) {
  1578     //TODO: Bug 921326 - Cellbroadcast API: support multiple sim cards
  1579     this.unregisterListener("_cellBroadcastListeners", 0, listener);
  1580   },
  1582   registerIccMsg: function(clientId, listener) {
  1583     if (DEBUG) debug("Registering for ICC related messages");
  1584     this.registerListener("_iccListeners", clientId, listener);
  1585     cpmm.sendAsyncMessage("RIL:RegisterIccMsg");
  1586   },
  1588   unregisterIccMsg: function(clientId, listener) {
  1589     this.unregisterListener("_iccListeners", clientId, listener);
  1590   },
  1592   // nsIObserver
  1594   observe: function(subject, topic, data) {
  1595     switch (topic) {
  1596       case NS_PREFBRANCH_PREFCHANGE_TOPIC_ID:
  1597         if (data == kPrefRilDebuggingEnabled) {
  1598           this.updateDebugFlag();
  1599         } else if (data == kPrefVoicemailDefaultServiceId) {
  1600           this.voicemailDefaultServiceId = this.getVoicemailDefaultServiceId();
  1602         break;
  1604       case NS_XPCOM_SHUTDOWN_OBSERVER_ID:
  1605         this.destroyDOMRequestHelper();
  1606         Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
  1607         break;
  1609   },
  1611   // nsIMessageListener
  1613   fireRequestSuccess: function(requestId, result) {
  1614     let request = this.takeRequest(requestId);
  1615     if (!request) {
  1616       if (DEBUG) {
  1617         debug("not firing success for id: " + requestId +
  1618               ", result: " + JSON.stringify(result));
  1620       return;
  1623     if (DEBUG) {
  1624       debug("fire request success, id: " + requestId +
  1625             ", result: " + JSON.stringify(result));
  1627     Services.DOMRequest.fireSuccess(request, result);
  1628   },
  1630   dispatchFireRequestSuccess: function(requestId, result) {
  1631     let currentThread = Services.tm.currentThread;
  1633     currentThread.dispatch(this.fireRequestSuccess.bind(this, requestId, result),
  1634                            Ci.nsIThread.DISPATCH_NORMAL);
  1635   },
  1637   fireRequestError: function(requestId, error) {
  1638     let request = this.takeRequest(requestId);
  1639     if (!request) {
  1640       if (DEBUG) {
  1641         debug("not firing error for id: " + requestId +
  1642               ", error: " + JSON.stringify(error));
  1644       return;
  1647     if (DEBUG) {
  1648       debug("fire request error, id: " + requestId +
  1649             ", result: " + JSON.stringify(error));
  1651     Services.DOMRequest.fireError(request, error);
  1652   },
  1654   dispatchFireRequestError: function(requestId, error) {
  1655     let currentThread = Services.tm.currentThread;
  1657     currentThread.dispatch(this.fireRequestError.bind(this, requestId, error),
  1658                            Ci.nsIThread.DISPATCH_NORMAL);
  1659   },
  1661   fireRequestDetailedError: function(requestId, detailedError) {
  1662     let request = this.takeRequest(requestId);
  1663     if (!request) {
  1664       if (DEBUG) {
  1665         debug("not firing detailed error for id: " + requestId +
  1666               ", detailedError: " + JSON.stringify(detailedError));
  1668       return;
  1671     Services.DOMRequest.fireDetailedError(request, detailedError);
  1672   },
  1674   receiveMessage: function(msg) {
  1675     let request;
  1676     if (DEBUG) {
  1677       debug("Received message '" + msg.name + "': " + JSON.stringify(msg.json));
  1680     let data = msg.json.data;
  1681     let clientId = msg.json.clientId;
  1682     switch (msg.name) {
  1683       case "RIL:CardStateChanged":
  1684         if (this.rilContexts[clientId].cardState != data.cardState) {
  1685           this.rilContexts[clientId].cardState = data.cardState;
  1686           this._deliverEvent(clientId,
  1687                              "_iccListeners",
  1688                              "notifyCardStateChanged",
  1689                              null);
  1691         break;
  1692       case "RIL:IccInfoChanged":
  1693         this.updateIccInfo(clientId, data);
  1694         this._deliverEvent(clientId,
  1695                            "_iccListeners",
  1696                            "notifyIccInfoChanged",
  1697                            null);
  1698         break;
  1699       case "RIL:VoiceInfoChanged":
  1700         this.updateConnectionInfo(data,
  1701                                   this.rilContexts[clientId].voiceConnectionInfo);
  1702         this._deliverEvent(clientId,
  1703                            "_mobileConnectionListeners",
  1704                            "notifyVoiceChanged",
  1705                            null);
  1706         break;
  1707       case "RIL:DataInfoChanged":
  1708         this.updateConnectionInfo(data,
  1709                                   this.rilContexts[clientId].dataConnectionInfo);
  1710         this._deliverEvent(clientId,
  1711                            "_mobileConnectionListeners",
  1712                            "notifyDataChanged",
  1713                            null);
  1714         break;
  1715       case "RIL:OtaStatusChanged":
  1716         this._deliverEvent(clientId,
  1717                            "_mobileConnectionListeners",
  1718                            "notifyOtaStatusChanged",
  1719                            [data]);
  1720         break;
  1721       case "RIL:GetAvailableNetworks":
  1722         this.handleGetAvailableNetworks(data);
  1723         break;
  1724       case "RIL:NetworkSelectionModeChanged":
  1725         this.rilContexts[clientId].networkSelectionMode = data.mode;
  1726         break;
  1727       case "RIL:SelectNetwork":
  1728         this.handleSelectNetwork(clientId, data,
  1729                                  RIL.GECKO_NETWORK_SELECTION_MANUAL);
  1730         break;
  1731       case "RIL:SelectNetworkAuto":
  1732         this.handleSelectNetwork(clientId, data,
  1733                                  RIL.GECKO_NETWORK_SELECTION_AUTOMATIC);
  1734         break;
  1735       case "RIL:SetPreferredNetworkType":
  1736         this.handleSimpleRequest(data.requestId, data.errorMsg, null);
  1737         break;
  1738       case "RIL:GetPreferredNetworkType":
  1739         this.handleSimpleRequest(data.requestId, data.errorMsg, data.type);
  1740         break;
  1741       case "RIL:VoicemailNotification":
  1742         this.handleVoicemailNotification(clientId, data);
  1743         break;
  1744       case "RIL:VoicemailInfoChanged":
  1745         this.updateInfo(data, this.voicemailInfos[clientId]);
  1746         break;
  1747       case "RIL:CardLockResult": {
  1748         let requestId = data.requestId;
  1749         let requestWindow = this._windowsMap[requestId];
  1750         delete this._windowsMap[requestId];
  1752         if (data.success) {
  1753           let result = new MobileIccCardLockResult(data);
  1754           this.fireRequestSuccess(requestId, result);
  1755         } else {
  1756           if (data.rilMessageType == "iccSetCardLock" ||
  1757               data.rilMessageType == "iccUnlockCardLock") {
  1758             let cardLockError = new requestWindow.IccCardLockError(data.lockType,
  1759                                                                    data.errorMsg,
  1760                                                                    data.retryCount);
  1761             this.fireRequestDetailedError(requestId, cardLockError);
  1762           } else {
  1763             this.fireRequestError(requestId, data.errorMsg);
  1766         break;
  1768       case "RIL:CardLockRetryCount":
  1769         if (data.success) {
  1770           let result = new MobileIccCardLockRetryCount(data);
  1771           this.fireRequestSuccess(data.requestId, result);
  1772         } else {
  1773           this.fireRequestError(data.requestId, data.errorMsg);
  1775         break;
  1776       case "RIL:USSDReceived":
  1777         this._deliverEvent(clientId,
  1778                            "_mobileConnectionListeners",
  1779                            "notifyUssdReceived",
  1780                            [data.message, data.sessionEnded]);
  1781         break;
  1782       case "RIL:SendMMI":
  1783       case "RIL:CancelMMI":
  1784         this.handleSendCancelMMI(data);
  1785         break;
  1786       case "RIL:StkCommand":
  1787         this._deliverEvent(clientId, "_iccListeners", "notifyStkCommand",
  1788                            [JSON.stringify(data)]);
  1789         break;
  1790       case "RIL:StkSessionEnd":
  1791         this._deliverEvent(clientId, "_iccListeners", "notifyStkSessionEnd", null);
  1792         break;
  1793       case "RIL:IccOpenChannel":
  1794         this.handleSimpleRequest(data.requestId, data.errorMsg,
  1795                                  data.channel);
  1796         break;
  1797       case "RIL:IccCloseChannel":
  1798         this.handleSimpleRequest(data.requestId, data.errorMsg, null);
  1799         break;
  1800       case "RIL:IccExchangeAPDU":
  1801         this.handleIccExchangeAPDU(data);
  1802         break;
  1803       case "RIL:ReadIccContacts":
  1804         this.handleReadIccContacts(data);
  1805         break;
  1806       case "RIL:UpdateIccContact":
  1807         this.handleUpdateIccContact(data);
  1808         break;
  1809       case "RIL:MatchMvno":
  1810         this.handleSimpleRequest(data.requestId, data.errorMsg, data.result);
  1811         break;
  1812       case "RIL:DataError":
  1813         this.updateConnectionInfo(data, this.rilContexts[clientId].dataConnectionInfo);
  1814         this._deliverEvent(clientId, "_mobileConnectionListeners", "notifyDataError",
  1815                            [data.errorMsg]);
  1816         break;
  1817       case "RIL:GetCallForwardingOptions":
  1818         this.handleGetCallForwardingOptions(data);
  1819         break;
  1820       case "RIL:SetCallForwardingOptions":
  1821         this.handleSimpleRequest(data.requestId, data.errorMsg, null);
  1822         break;
  1823       case "RIL:GetCallBarringOptions":
  1824         this.handleGetCallBarringOptions(data);
  1825         break;
  1826       case "RIL:SetCallBarringOptions":
  1827         this.handleSimpleRequest(data.requestId, data.errorMsg, null);
  1828         break;
  1829       case "RIL:ChangeCallBarringPassword":
  1830         this.handleSimpleRequest(data.requestId, data.errorMsg, null);
  1831         break;
  1832       case "RIL:GetCallWaitingOptions":
  1833         this.handleSimpleRequest(data.requestId, data.errorMsg,
  1834                                  data.enabled);
  1835         break;
  1836       case "RIL:SetCallWaitingOptions":
  1837         this.handleSimpleRequest(data.requestId, data.errorMsg, null);
  1838         break;
  1839       case "RIL:CfStateChanged":
  1840         this._deliverEvent(clientId,
  1841                            "_mobileConnectionListeners",
  1842                            "notifyCFStateChange",
  1843                            [data.success, data.action,
  1844                             data.reason, data.number,
  1845                             data.timeSeconds, data.serviceClass]);
  1846         break;
  1847       case "RIL:GetCallingLineIdRestriction":
  1848         this.handleGetCallingLineIdRestriction(data);
  1849         break;
  1850       case "RIL:SetCallingLineIdRestriction":
  1851         this.handleSimpleRequest(data.requestId, data.errorMsg, null);
  1852         break;
  1853       case "RIL:CellBroadcastReceived": {
  1854         let message = new CellBroadcastMessage(data);
  1855         this._deliverEvent(clientId,
  1856                            "_cellBroadcastListeners",
  1857                            "notifyMessageReceived",
  1858                            [message]);
  1859         break;
  1861       case "RIL:SetRoamingPreference":
  1862         this.handleSimpleRequest(data.requestId, data.errorMsg, null);
  1863         break;
  1864       case "RIL:GetRoamingPreference":
  1865         this.handleSimpleRequest(data.requestId, data.errorMsg,
  1866                                  data.mode);
  1867         break;
  1868       case "RIL:ExitEmergencyCbMode":
  1869         this.handleExitEmergencyCbMode(data);
  1870         break;
  1871       case "RIL:EmergencyCbModeChanged":
  1872         this._deliverEvent(clientId,
  1873                            "_mobileConnectionListeners",
  1874                            "notifyEmergencyCbModeChanged",
  1875                            [data.active, data.timeoutMs]);
  1876         break;
  1877       case "RIL:SetRadioEnabled":
  1878         this.handleSimpleRequest(data.requestId, data.errorMsg, null);
  1879         break;
  1880       case "RIL:RadioStateChanged":
  1881         this.rilContexts[clientId].radioState = data;
  1882         this._deliverEvent(clientId,
  1883                            "_mobileConnectionListeners",
  1884                            "notifyRadioStateChanged",
  1885                            null);
  1886         break;
  1887       case "RIL:SetVoicePrivacyMode":
  1888         this.handleSimpleRequest(data.requestId, data.errorMsg, null);
  1889         break;
  1890       case "RIL:GetVoicePrivacyMode":
  1891         this.handleSimpleRequest(data.requestId, data.errorMsg,
  1892                                  data.enabled);
  1893         break;
  1895   },
  1897   handleSimpleRequest: function(requestId, errorMsg, result) {
  1898     if (errorMsg) {
  1899       this.fireRequestError(requestId, errorMsg);
  1900     } else {
  1901       this.fireRequestSuccess(requestId, result);
  1903   },
  1905   handleGetAvailableNetworks: function(message) {
  1906     if (DEBUG) debug("handleGetAvailableNetworks: " + JSON.stringify(message));
  1907     if (message.errorMsg) {
  1908       if (DEBUG) {
  1909         debug("Received error from getAvailableNetworks: " + message.errorMsg);
  1911       this.fireRequestError(message.requestId, message.errorMsg);
  1912       return;
  1915     let networks = message.networks;
  1916     for (let i = 0; i < networks.length; i++) {
  1917       let network = networks[i];
  1918       let info = new MobileNetworkInfo();
  1919       this.updateInfo(network, info);
  1920       networks[i] = info;
  1923     this.fireRequestSuccess(message.requestId, networks);
  1924   },
  1926   handleSelectNetwork: function(clientId, message, mode) {
  1927     this._selectingNetworks[clientId] = null;
  1928     this.rilContexts[clientId].networkSelectionMode = mode;
  1930     if (message.errorMsg) {
  1931       this.fireRequestError(message.requestId, message.errorMsg);
  1932     } else {
  1933       this.fireRequestSuccess(message.requestId, null);
  1935   },
  1937   handleIccExchangeAPDU: function(message) {
  1938     if (message.errorMsg) {
  1939       this.fireRequestError(message.requestId, message.errorMsg);
  1940     } else {
  1941       var result = [message.sw1, message.sw2, message.simResponse];
  1942       this.fireRequestSuccess(message.requestId, result);
  1944   },
  1946   handleReadIccContacts: function(message) {
  1947     if (message.errorMsg) {
  1948       this.fireRequestError(message.requestId, message.errorMsg);
  1949       return;
  1952     let window = this._windowsMap[message.requestId];
  1953     delete this._windowsMap[message.requestId];
  1954     let contacts = message.contacts;
  1955     let result = contacts.map(function(c) {
  1956       let prop = {name: [c.alphaId], tel: [{value: c.number}]};
  1958       if (c.email) {
  1959         prop.email = [{value: c.email}];
  1962       // ANR - Additional Number
  1963       let anrLen = c.anr ? c.anr.length : 0;
  1964       for (let i = 0; i < anrLen; i++) {
  1965         prop.tel.push({value: c.anr[i]});
  1968       let contact = new window.mozContact(prop);
  1969       contact.id = c.contactId;
  1970       return contact;
  1971     });
  1973     this.fireRequestSuccess(message.requestId, result);
  1974   },
  1976   handleUpdateIccContact: function(message) {
  1977     if (message.errorMsg) {
  1978       this.fireRequestError(message.requestId, message.errorMsg);
  1979       return;
  1982     let window = this._windowsMap[message.requestId];
  1983     delete this._windowsMap[message.requestId];
  1984     let iccContact = message.contact;
  1985     let prop = {name: [iccContact.alphaId], tel: [{value: iccContact.number}]};
  1986     if (iccContact.email) {
  1987       prop.email = [{value: iccContact.email}];
  1990     // ANR - Additional Number
  1991     let anrLen = iccContact.anr ? iccContact.anr.length : 0;
  1992     for (let i = 0; i < anrLen; i++) {
  1993       prop.tel.push({value: iccContact.anr[i]});
  1996     let contact = new window.mozContact(prop);
  1997     contact.id = iccContact.contactId;
  1999     this.fireRequestSuccess(message.requestId, contact);
  2000   },
  2002   handleVoicemailNotification: function(clientId, message) {
  2003     let changed = false;
  2004     if (!this.voicemailStatuses[clientId]) {
  2005       this.voicemailStatuses[clientId] = new VoicemailStatus(clientId);
  2008     let voicemailStatus = this.voicemailStatuses[clientId];
  2009     if (voicemailStatus.hasMessages != message.active) {
  2010       changed = true;
  2011       voicemailStatus.hasMessages = message.active;
  2014     if (voicemailStatus.messageCount != message.msgCount) {
  2015       changed = true;
  2016       voicemailStatus.messageCount = message.msgCount;
  2017     } else if (message.msgCount == -1) {
  2018       // For MWI using DCS the message count is not available
  2019       changed = true;
  2022     if (voicemailStatus.returnNumber != message.returnNumber) {
  2023       changed = true;
  2024       voicemailStatus.returnNumber = message.returnNumber;
  2027     if (voicemailStatus.returnMessage != message.returnMessage) {
  2028       changed = true;
  2029       voicemailStatus.returnMessage = message.returnMessage;
  2032     if (changed) {
  2033       // To follow the event delivering scheme, we add a dummy clientId 0.
  2034       // All voicemail events are routed to listener for client id 0.
  2035       this._deliverEvent(0,
  2036                          "_voicemailListeners",
  2037                          "notifyStatusChanged",
  2038                          [voicemailStatus]);
  2040   },
  2042   _cfRulesToMobileCfInfo: function(rules) {
  2043     for (let i = 0; i < rules.length; i++) {
  2044       let rule = rules[i];
  2045       let info = new MobileCFInfo();
  2046       this.updateInfo(rule, info);
  2047       rules[i] = info;
  2049   },
  2051   handleGetCallForwardingOptions: function(message) {
  2052     if (message.errorMsg) {
  2053       this.fireRequestError(message.requestId, message.errorMsg);
  2054       return;
  2057     this._cfRulesToMobileCfInfo(message.rules);
  2058     this.fireRequestSuccess(message.requestId, message.rules);
  2059   },
  2061   handleGetCallBarringOptions: function(message) {
  2062     if (!message.success) {
  2063       this.fireRequestError(message.requestId, message.errorMsg);
  2064     } else {
  2065       let options = new CallBarringOptions(message);
  2066       this.fireRequestSuccess(message.requestId, options);
  2068   },
  2070   handleGetCallingLineIdRestriction: function(message) {
  2071     if (message.errorMsg) {
  2072       this.fireRequestError(message.requestId, message.errorMsg);
  2073       return;
  2076     let status = new DOMCLIRStatus(message);
  2077     this.fireRequestSuccess(message.requestId, status);
  2078   },
  2080   handleExitEmergencyCbMode: function(message) {
  2081     let requestId = message.requestId;
  2082     let request = this.takeRequest(requestId);
  2083     if (!request) {
  2084       return;
  2087     if (!message.success) {
  2088       Services.DOMRequest.fireError(request, message.errorMsg);
  2089       return;
  2091     Services.DOMRequest.fireSuccess(request, null);
  2092   },
  2094   handleSendCancelMMI: function(message) {
  2095     if (DEBUG) debug("handleSendCancelMMI " + JSON.stringify(message));
  2096     let request = this.takeRequest(message.requestId);
  2097     let requestWindow = this._windowsMap[message.requestId];
  2098     delete this._windowsMap[message.requestId];
  2099     if (!request) {
  2100       return;
  2103     let success = message.success;
  2105     // We expect to have an IMEI at this point if the request was supposed
  2106     // to query for the IMEI, so getting a successful reply from the RIL
  2107     // without containing an actual IMEI number is considered an error.
  2108     if (message.mmiServiceCode === RIL.MMI_KS_SC_IMEI &&
  2109         !message.statusMessage) {
  2110         message.errorMsg = message.errorMsg ?
  2111           message.errorMsg : RIL.GECKO_ERROR_GENERIC_FAILURE;
  2112         success = false;
  2115     // MMI query call forwarding options request returns a set of rules that
  2116     // will be exposed in the form of an array of nsIDOMMozMobileCFInfo
  2117     // instances.
  2118     if (message.mmiServiceCode === RIL.MMI_KS_SC_CALL_FORWARDING &&
  2119         message.additionalInformation) {
  2120       this._cfRulesToMobileCfInfo(message.additionalInformation);
  2123     let result = {
  2124       serviceCode: message.mmiServiceCode,
  2125       additionalInformation: message.additionalInformation
  2126     };
  2128     if (success) {
  2129       result.statusMessage = message.statusMessage;
  2130       let mmiResult = new DOMMMIResult(result);
  2131       Services.DOMRequest.fireSuccess(request, mmiResult);
  2132     } else {
  2133       let mmiError = new requestWindow.DOMMMIError(result.serviceCode,
  2134                                                    message.errorMsg,
  2135                                                    null,
  2136                                                    result.additionalInformation);
  2137       Services.DOMRequest.fireDetailedError(request, mmiError);
  2139   },
  2141   _deliverEvent: function(clientId, listenerType, name, args) {
  2142     if (!this[listenerType]) {
  2143       return;
  2145     let thisListeners = this[listenerType][clientId];
  2146     if (!thisListeners) {
  2147       return;
  2150     let listeners = thisListeners.slice();
  2151     for (let listener of listeners) {
  2152       if (thisListeners.indexOf(listener) == -1) {
  2153         continue;
  2155       let handler = listener[name];
  2156       if (typeof handler != "function") {
  2157         throw new Error("No handler for " + name);
  2159       try {
  2160         handler.apply(listener, args);
  2161       } catch (e) {
  2162         if (DEBUG) debug("listener for " + name + " threw an exception: " + e);
  2165   },
  2167   /**
  2168    * Helper for guarding us again invalid reason values for call forwarding.
  2169    */
  2170   _isValidCFReason: function(reason) {
  2171     switch (reason) {
  2172       case Ci.nsIDOMMozMobileCFInfo.CALL_FORWARD_REASON_UNCONDITIONAL:
  2173       case Ci.nsIDOMMozMobileCFInfo.CALL_FORWARD_REASON_MOBILE_BUSY:
  2174       case Ci.nsIDOMMozMobileCFInfo.CALL_FORWARD_REASON_NO_REPLY:
  2175       case Ci.nsIDOMMozMobileCFInfo.CALL_FORWARD_REASON_NOT_REACHABLE:
  2176       case Ci.nsIDOMMozMobileCFInfo.CALL_FORWARD_REASON_ALL_CALL_FORWARDING:
  2177       case Ci.nsIDOMMozMobileCFInfo.CALL_FORWARD_REASON_ALL_CONDITIONAL_CALL_FORWARDING:
  2178         return true;
  2179       default:
  2180         return false;
  2182   },
  2184   /**
  2185    * Helper for guarding us again invalid action values for call forwarding.
  2186    */
  2187   _isValidCFAction: function(action) {
  2188     switch (action) {
  2189       case Ci.nsIDOMMozMobileCFInfo.CALL_FORWARD_ACTION_DISABLE:
  2190       case Ci.nsIDOMMozMobileCFInfo.CALL_FORWARD_ACTION_ENABLE:
  2191       case Ci.nsIDOMMozMobileCFInfo.CALL_FORWARD_ACTION_REGISTRATION:
  2192       case Ci.nsIDOMMozMobileCFInfo.CALL_FORWARD_ACTION_ERASURE:
  2193         return true;
  2194       default:
  2195         return false;
  2197   },
  2199   /**
  2200    * Helper for guarding us against invalid program values for call barring.
  2201    */
  2202   _isValidCallBarringProgram: function(program) {
  2203     switch (program) {
  2204       case Ci.nsIDOMMozMobileConnection.CALL_BARRING_PROGRAM_ALL_OUTGOING:
  2205       case Ci.nsIDOMMozMobileConnection.CALL_BARRING_PROGRAM_OUTGOING_INTERNATIONAL:
  2206       case Ci.nsIDOMMozMobileConnection.CALL_BARRING_PROGRAM_OUTGOING_INTERNATIONAL_EXCEPT_HOME:
  2207       case Ci.nsIDOMMozMobileConnection.CALL_BARRING_PROGRAM_ALL_INCOMING:
  2208       case Ci.nsIDOMMozMobileConnection.CALL_BARRING_PROGRAM_INCOMING_ROAMING:
  2209         return true;
  2210       default:
  2211         return false;
  2213   },
  2215   /**
  2216    * Helper for guarding us against invalid options for call barring.
  2217    */
  2218   _isValidCallBarringOptions: function(options, usedForSetting) {
  2219     if (!options ||
  2220         options.serviceClass == null ||
  2221         !this._isValidCallBarringProgram(options.program)) {
  2222       return false;
  2225     // For setting callbarring options, |enabled| and |password| are required.
  2226     if (usedForSetting && (options.enabled == null || options.password == null)) {
  2227       return false;
  2230     return true;
  2232 };
  2234 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([RILContentHelper,
  2235                                                      DOMMMIError,
  2236                                                      IccCardLockError]);

mercurial