Thu, 22 Jan 2015 13:21:57 +0100
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);
1001 }
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
1013 }
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);
1023 }
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
1030 }
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);
1039 }
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);
1052 }
1053 cpmm.sendAsyncMessage("RIL:SendStkMenuSelection", {
1054 clientId: clientId,
1055 data: {
1056 itemIdentifier: itemIdentifier,
1057 helpRequested: helpRequested
1058 }
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);
1066 }
1067 cpmm.sendAsyncMessage("RIL:SendStkTimerExpiration", {
1068 clientId: clientId,
1069 data: {
1070 timer: timer
1071 }
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);
1079 }
1080 cpmm.sendAsyncMessage("RIL:SendStkEventDownload", {
1081 clientId: clientId,
1082 data: {
1083 event: event
1084 }
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);
1092 }
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
1102 }
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);
1111 }
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
1123 }
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);
1132 }
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
1142 }
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);
1151 }
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
1162 }
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);
1171 }
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];
1182 }
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 = [];
1190 }
1191 for (let i = 0; i < telArray.length; i++) {
1192 iccContact.anr.push(telArray[i].value);
1193 }
1194 }
1196 if (Array.isArray(contact.email) && contact.email[0]) {
1197 iccContact.email = contact.email[0].value;
1198 }
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
1209 }
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);
1219 }
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;
1227 }
1229 cpmm.sendAsyncMessage("RIL:GetCallForwardingOptions", {
1230 clientId: clientId,
1231 data: {
1232 requestId: requestId,
1233 reason: reason
1234 }
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);
1244 }
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;
1254 }
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
1265 }
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);
1275 }
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;
1284 }
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
1293 }
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);
1302 }
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;
1311 }
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
1321 }
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);
1330 }
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;
1339 }
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);
1355 }
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
1363 }
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);
1373 }
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
1382 }
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);
1392 }
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
1400 }
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);
1411 }
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
1420 }
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);
1430 }
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,
1438 }
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);
1448 }
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,
1457 }
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;
1477 }
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]);
1493 }
1494 }
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;
1514 }
1515 let listeners = this[listenerType][clientId];
1516 if (!listeners) {
1517 listeners = this[listenerType][clientId] = [];
1518 }
1520 if (listeners.indexOf(listener) != -1) {
1521 throw new Error("Already registered this listener!");
1522 }
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;
1531 }
1532 let listeners = this[listenerType][clientId];
1533 if (!listeners) {
1534 return;
1535 }
1537 let index = listeners.indexOf(listener);
1538 if (index != -1) {
1539 listeners.splice(index, 1);
1540 if (DEBUG) debug("Unregistered listener: " + listener);
1541 }
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();
1601 }
1602 break;
1604 case NS_XPCOM_SHUTDOWN_OBSERVER_ID:
1605 this.destroyDOMRequestHelper();
1606 Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
1607 break;
1608 }
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));
1619 }
1620 return;
1621 }
1623 if (DEBUG) {
1624 debug("fire request success, id: " + requestId +
1625 ", result: " + JSON.stringify(result));
1626 }
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));
1643 }
1644 return;
1645 }
1647 if (DEBUG) {
1648 debug("fire request error, id: " + requestId +
1649 ", result: " + JSON.stringify(error));
1650 }
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));
1667 }
1668 return;
1669 }
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));
1678 }
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);
1690 }
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);
1764 }
1765 }
1766 break;
1767 }
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);
1774 }
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;
1860 }
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;
1894 }
1895 },
1897 handleSimpleRequest: function(requestId, errorMsg, result) {
1898 if (errorMsg) {
1899 this.fireRequestError(requestId, errorMsg);
1900 } else {
1901 this.fireRequestSuccess(requestId, result);
1902 }
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);
1910 }
1911 this.fireRequestError(message.requestId, message.errorMsg);
1912 return;
1913 }
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;
1921 }
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);
1934 }
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);
1943 }
1944 },
1946 handleReadIccContacts: function(message) {
1947 if (message.errorMsg) {
1948 this.fireRequestError(message.requestId, message.errorMsg);
1949 return;
1950 }
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}];
1960 }
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]});
1966 }
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;
1980 }
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}];
1988 }
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]});
1994 }
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);
2006 }
2008 let voicemailStatus = this.voicemailStatuses[clientId];
2009 if (voicemailStatus.hasMessages != message.active) {
2010 changed = true;
2011 voicemailStatus.hasMessages = message.active;
2012 }
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;
2020 }
2022 if (voicemailStatus.returnNumber != message.returnNumber) {
2023 changed = true;
2024 voicemailStatus.returnNumber = message.returnNumber;
2025 }
2027 if (voicemailStatus.returnMessage != message.returnMessage) {
2028 changed = true;
2029 voicemailStatus.returnMessage = message.returnMessage;
2030 }
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]);
2039 }
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;
2048 }
2049 },
2051 handleGetCallForwardingOptions: function(message) {
2052 if (message.errorMsg) {
2053 this.fireRequestError(message.requestId, message.errorMsg);
2054 return;
2055 }
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);
2067 }
2068 },
2070 handleGetCallingLineIdRestriction: function(message) {
2071 if (message.errorMsg) {
2072 this.fireRequestError(message.requestId, message.errorMsg);
2073 return;
2074 }
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;
2085 }
2087 if (!message.success) {
2088 Services.DOMRequest.fireError(request, message.errorMsg);
2089 return;
2090 }
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;
2101 }
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;
2113 }
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);
2121 }
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);
2138 }
2139 },
2141 _deliverEvent: function(clientId, listenerType, name, args) {
2142 if (!this[listenerType]) {
2143 return;
2144 }
2145 let thisListeners = this[listenerType][clientId];
2146 if (!thisListeners) {
2147 return;
2148 }
2150 let listeners = thisListeners.slice();
2151 for (let listener of listeners) {
2152 if (thisListeners.indexOf(listener) == -1) {
2153 continue;
2154 }
2155 let handler = listener[name];
2156 if (typeof handler != "function") {
2157 throw new Error("No handler for " + name);
2158 }
2159 try {
2160 handler.apply(listener, args);
2161 } catch (e) {
2162 if (DEBUG) debug("listener for " + name + " threw an exception: " + e);
2163 }
2164 }
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;
2181 }
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;
2196 }
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;
2212 }
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;
2223 }
2225 // For setting callbarring options, |enabled| and |password| are required.
2226 if (usedForSetting && (options.enabled == null || options.password == null)) {
2227 return false;
2228 }
2230 return true;
2231 }
2232 };
2234 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([RILContentHelper,
2235 DOMMMIError,
2236 IccCardLockError]);