|
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 */ |
|
15 |
|
16 "use strict"; |
|
17 |
|
18 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; |
|
19 |
|
20 Cu.import("resource://gre/modules/DOMRequestHelper.jsm"); |
|
21 Cu.import("resource://gre/modules/Services.jsm"); |
|
22 Cu.import("resource://gre/modules/XPCOMUtils.jsm"); |
|
23 |
|
24 var RIL = {}; |
|
25 Cu.import("resource://gre/modules/ril_consts.js", RIL); |
|
26 |
|
27 const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown"; |
|
28 |
|
29 const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed"; |
|
30 |
|
31 const kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces"; |
|
32 const kPrefRilDebuggingEnabled = "ril.debugging.enabled"; |
|
33 const kPrefVoicemailDefaultServiceId = "dom.voicemail.defaultServiceId"; |
|
34 |
|
35 let DEBUG; |
|
36 function debug(s) { |
|
37 dump("-*- RILContentHelper: " + s + "\n"); |
|
38 } |
|
39 |
|
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}"); |
|
64 |
|
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 ]; |
|
113 |
|
114 XPCOMUtils.defineLazyServiceGetter(this, "cpmm", |
|
115 "@mozilla.org/childprocessmessagemanager;1", |
|
116 "nsISyncMessageSender"); |
|
117 |
|
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; |
|
122 |
|
123 if (isParentProcess) { |
|
124 let ril = Cc["@mozilla.org/ril;1"].getService(Ci.nsIRadioInterfaceLayer); |
|
125 return ril.numRadioInterfaces; |
|
126 } |
|
127 |
|
128 return Services.prefs.getIntPref(kPrefRilNumRadioInterfaces); |
|
129 }); |
|
130 |
|
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 }; |
|
143 |
|
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 }; |
|
154 |
|
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 }; |
|
165 |
|
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 }), |
|
177 |
|
178 // nsIDOMMozGsmIccInfo |
|
179 |
|
180 msisdn: null |
|
181 }; |
|
182 |
|
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 }), |
|
194 |
|
195 // nsIDOMMozCdmaIccInfo |
|
196 |
|
197 mdn: null, |
|
198 prlVersion: 0 |
|
199 }; |
|
200 |
|
201 function VoicemailInfo() {} |
|
202 VoicemailInfo.prototype = { |
|
203 number: null, |
|
204 displayName: null |
|
205 }; |
|
206 |
|
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 }), |
|
217 |
|
218 // nsIDOMMozMobileConnectionInfo |
|
219 |
|
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 }; |
|
230 |
|
231 function MobileNetworkInfo() {} |
|
232 MobileNetworkInfo.prototype = { |
|
233 __exposedProps__ : {shortName: 'r', |
|
234 longName: 'r', |
|
235 mcc: 'r', |
|
236 mnc: 'r', |
|
237 state: 'r'}, |
|
238 |
|
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 }), |
|
247 |
|
248 // nsIDOMMozMobileNetworkInfo |
|
249 |
|
250 shortName: null, |
|
251 longName: null, |
|
252 mcc: null, |
|
253 mnc: null, |
|
254 state: null |
|
255 }; |
|
256 |
|
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 }), |
|
267 |
|
268 // nsIDOMMozMobileCellInfo |
|
269 |
|
270 gsmLocationAreaCode: -1, |
|
271 gsmCellId: -1, |
|
272 cdmaBaseStationId: -1, |
|
273 cdmaBaseStationLatitude: -2147483648, |
|
274 cdmaBaseStationLongitude: -2147483648, |
|
275 cdmaSystemId: -1, |
|
276 cdmaNetworkId: -1 |
|
277 }; |
|
278 |
|
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 }), |
|
291 |
|
292 // nsIDOMMozVoicemailStatus |
|
293 |
|
294 serviceId: -1, |
|
295 hasMessages: false, |
|
296 messageCount: -1, // Count unknown. |
|
297 returnNumber: null, |
|
298 returnMessage: null |
|
299 }; |
|
300 |
|
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 }), |
|
317 |
|
318 // nsIDOMMozMobileCFInfo |
|
319 |
|
320 active: false, |
|
321 action: -1, |
|
322 reason: -1, |
|
323 number: null, |
|
324 timeSeconds: 0, |
|
325 serviceClass: -1 |
|
326 }; |
|
327 |
|
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); |
|
336 |
|
337 if (pdu.etws != null) { |
|
338 this.etws = new CellBroadcastEtwsInfo(pdu.etws); |
|
339 } |
|
340 |
|
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 }), |
|
352 |
|
353 // nsIDOMMozCellBroadcastMessage |
|
354 |
|
355 gsmGeographicalScope: null, |
|
356 messageCode: null, |
|
357 messageId: null, |
|
358 language: null, |
|
359 body: null, |
|
360 messageClass: null, |
|
361 timestamp: null, |
|
362 |
|
363 etws: null, |
|
364 cdmaServiceCategory: null |
|
365 }; |
|
366 |
|
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 }), |
|
383 |
|
384 // nsIDOMMozCellBroadcastEtwsInfo |
|
385 |
|
386 warningType: null, |
|
387 emergencyUserAlert: null, |
|
388 popup: null |
|
389 }; |
|
390 |
|
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 }; |
|
403 |
|
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 }; |
|
414 |
|
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 }; |
|
423 |
|
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 }; |
|
437 |
|
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 }; |
|
451 |
|
452 function RILContentHelper() { |
|
453 this.updateDebugFlag(); |
|
454 |
|
455 this.numClients = gNumRadioInterfaces; |
|
456 if (DEBUG) debug("Number of clients: " + this.numClients); |
|
457 |
|
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 }; |
|
470 |
|
471 this.voicemailInfos[clientId] = new VoicemailInfo(); |
|
472 } |
|
473 |
|
474 this.voicemailDefaultServiceId = this.getVoicemailDefaultServiceId(); |
|
475 |
|
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 = []; |
|
483 |
|
484 Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); |
|
485 |
|
486 Services.prefs.addObserver(kPrefRilDebuggingEnabled, this, false); |
|
487 Services.prefs.addObserver(kPrefVoicemailDefaultServiceId, this, false); |
|
488 } |
|
489 |
|
490 RILContentHelper.prototype = { |
|
491 __proto__: DOMRequestIpcHelper.prototype, |
|
492 |
|
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]}), |
|
507 |
|
508 updateDebugFlag: function() { |
|
509 try { |
|
510 DEBUG = RIL.DEBUG_CONTENT_HELPER || |
|
511 Services.prefs.getBoolPref(kPrefRilDebuggingEnabled); |
|
512 } catch (e) {} |
|
513 }, |
|
514 |
|
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 }, |
|
521 |
|
522 updateConnectionInfo: function(srcInfo, destInfo) { |
|
523 for (let key in srcInfo) { |
|
524 if ((key != "network") && (key != "cell")) { |
|
525 destInfo[key] = srcInfo[key]; |
|
526 } |
|
527 } |
|
528 |
|
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 } |
|
537 |
|
538 this.updateInfo(srcCell, cell); |
|
539 } |
|
540 |
|
541 let srcNetwork = srcInfo.network; |
|
542 if (!srcNetwork) { |
|
543 destInfo.network= null; |
|
544 return; |
|
545 } |
|
546 |
|
547 let network = destInfo.network; |
|
548 if (!network) { |
|
549 network = destInfo.network = new MobileNetworkInfo(); |
|
550 } |
|
551 |
|
552 this.updateInfo(srcNetwork, network); |
|
553 }, |
|
554 |
|
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]; |
|
562 |
|
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 } |
|
574 |
|
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; |
|
585 |
|
586 this.updateInfo(newInfo, rilContext.iccInfo); |
|
587 |
|
588 // Deliver event after info is updated. |
|
589 if (changed) { |
|
590 this._deliverEvent(clientId, |
|
591 "_mobileConnectionListeners", |
|
592 "notifyIccChanged", |
|
593 null); |
|
594 } |
|
595 }, |
|
596 |
|
597 _windowsMap: null, |
|
598 |
|
599 rilContexts: null, |
|
600 |
|
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 }; |
|
608 |
|
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 } |
|
623 |
|
624 return this.rilContexts[clientId]; |
|
625 }, |
|
626 |
|
627 /** |
|
628 * nsIIccProvider |
|
629 */ |
|
630 |
|
631 getIccInfo: function(clientId) { |
|
632 let context = this.getRilContext(clientId); |
|
633 return context && context.iccInfo; |
|
634 }, |
|
635 |
|
636 getCardState: function(clientId) { |
|
637 let context = this.getRilContext(clientId); |
|
638 return context && context.cardState; |
|
639 }, |
|
640 |
|
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 } |
|
646 |
|
647 let request = Services.DOMRequest.createRequest(window); |
|
648 let requestId = this.getRequestId(request); |
|
649 |
|
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 }, |
|
660 |
|
661 /** |
|
662 * nsIMobileConnectionProvider |
|
663 */ |
|
664 |
|
665 getLastKnownNetwork: function(clientId) { |
|
666 return cpmm.sendSyncMessage("RIL:GetLastKnownNetwork", { |
|
667 clientId: clientId |
|
668 })[0]; |
|
669 }, |
|
670 |
|
671 getLastKnownHomeNetwork: function(clientId) { |
|
672 return cpmm.sendSyncMessage("RIL:GetLastKnownHomeNetwork", { |
|
673 clientId: clientId |
|
674 })[0]; |
|
675 }, |
|
676 |
|
677 getVoiceConnectionInfo: function(clientId) { |
|
678 let context = this.getRilContext(clientId); |
|
679 return context && context.voiceConnectionInfo; |
|
680 }, |
|
681 |
|
682 getDataConnectionInfo: function(clientId) { |
|
683 let context = this.getRilContext(clientId); |
|
684 return context && context.dataConnectionInfo; |
|
685 }, |
|
686 |
|
687 getIccId: function(clientId) { |
|
688 let context = this.getRilContext(clientId); |
|
689 return context && context.iccInfo && context.iccInfo.iccid; |
|
690 }, |
|
691 |
|
692 getNetworkSelectionMode: function(clientId) { |
|
693 let context = this.getRilContext(clientId); |
|
694 return context && context.networkSelectionMode; |
|
695 }, |
|
696 |
|
697 getRadioState: function(clientId) { |
|
698 let context = this.getRilContext(clientId); |
|
699 return context && context.radioState; |
|
700 }, |
|
701 |
|
702 getSupportedNetworkTypes: function(clientId) { |
|
703 return cpmm.sendSyncMessage("RIL:GetSupportedNetworkTypes", { |
|
704 clientId: clientId |
|
705 })[0]; |
|
706 }, |
|
707 |
|
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, |
|
713 |
|
714 getNetworks: function(clientId, window) { |
|
715 if (window == null) { |
|
716 throw Components.Exception("Can't get window object", |
|
717 Cr.NS_ERROR_UNEXPECTED); |
|
718 } |
|
719 |
|
720 let request = Services.DOMRequest.createRequest(window); |
|
721 let requestId = this.getRequestId(request); |
|
722 |
|
723 cpmm.sendAsyncMessage("RIL:GetAvailableNetworks", { |
|
724 clientId: clientId, |
|
725 data: { |
|
726 requestId: requestId |
|
727 } |
|
728 }); |
|
729 return request; |
|
730 }, |
|
731 |
|
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 } |
|
737 |
|
738 if (this._selectingNetworks[clientId]) { |
|
739 throw new Error("Already selecting a network: " + this._selectingNetworks[clientId]); |
|
740 } |
|
741 |
|
742 if (!network) { |
|
743 throw new Error("Invalid network provided: " + network); |
|
744 } |
|
745 |
|
746 if (isNaN(parseInt(network.mnc, 10))) { |
|
747 throw new Error("Invalid network MNC: " + network.mnc); |
|
748 } |
|
749 |
|
750 if (isNaN(parseInt(network.mcc, 10))) { |
|
751 throw new Error("Invalid network MCC: " + network.mcc); |
|
752 } |
|
753 |
|
754 let request = Services.DOMRequest.createRequest(window); |
|
755 let requestId = this.getRequestId(request); |
|
756 |
|
757 if (this.rilContexts[clientId].networkSelectionMode == RIL.GECKO_NETWORK_SELECTION_MANUAL && |
|
758 this.rilContexts[clientId].voiceConnectionInfo.network === network) { |
|
759 |
|
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 } |
|
765 |
|
766 this._selectingNetworks[clientId] = network; |
|
767 |
|
768 cpmm.sendAsyncMessage("RIL:SelectNetwork", { |
|
769 clientId: clientId, |
|
770 data: { |
|
771 requestId: requestId, |
|
772 mnc: network.mnc, |
|
773 mcc: network.mcc |
|
774 } |
|
775 }); |
|
776 |
|
777 return request; |
|
778 }, |
|
779 |
|
780 selectNetworkAutomatically: function(clientId, window) { |
|
781 |
|
782 if (window == null) { |
|
783 throw Components.Exception("Can't get window object", |
|
784 Cr.NS_ERROR_UNEXPECTED); |
|
785 } |
|
786 |
|
787 if (this._selectingNetworks[clientId]) { |
|
788 throw new Error("Already selecting a network: " + this._selectingNetworks[clientId]); |
|
789 } |
|
790 |
|
791 let request = Services.DOMRequest.createRequest(window); |
|
792 let requestId = this.getRequestId(request); |
|
793 |
|
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 } |
|
800 |
|
801 this._selectingNetworks[clientId] = "automatic"; |
|
802 cpmm.sendAsyncMessage("RIL:SelectNetworkAuto", { |
|
803 clientId: clientId, |
|
804 data: { |
|
805 requestId: requestId |
|
806 } |
|
807 }); |
|
808 return request; |
|
809 }, |
|
810 |
|
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 } |
|
816 |
|
817 let request = Services.DOMRequest.createRequest(window); |
|
818 let requestId = this.getRequestId(request); |
|
819 |
|
820 cpmm.sendAsyncMessage("RIL:SetPreferredNetworkType", { |
|
821 clientId: clientId, |
|
822 data: { |
|
823 requestId: requestId, |
|
824 type: type |
|
825 } |
|
826 }); |
|
827 return request; |
|
828 }, |
|
829 |
|
830 getPreferredNetworkType: function(clientId, window) { |
|
831 if (window == null) { |
|
832 throw Components.Exception("Can't get window object", |
|
833 Cr.NS_ERROR_UNEXPECTED); |
|
834 } |
|
835 |
|
836 let request = Services.DOMRequest.createRequest(window); |
|
837 let requestId = this.getRequestId(request); |
|
838 |
|
839 cpmm.sendAsyncMessage("RIL:GetPreferredNetworkType", { |
|
840 clientId: clientId, |
|
841 data: { |
|
842 requestId: requestId |
|
843 } |
|
844 }); |
|
845 return request; |
|
846 }, |
|
847 |
|
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 } |
|
853 |
|
854 let request = Services.DOMRequest.createRequest(window); |
|
855 let requestId = this.getRequestId(request); |
|
856 |
|
857 if (!mode) { |
|
858 this.dispatchFireRequestError(requestId, |
|
859 RIL.GECKO_ERROR_INVALID_PARAMETER); |
|
860 return request; |
|
861 } |
|
862 |
|
863 cpmm.sendAsyncMessage("RIL:SetRoamingPreference", { |
|
864 clientId: clientId, |
|
865 data: { |
|
866 requestId: requestId, |
|
867 mode: mode |
|
868 } |
|
869 }); |
|
870 return request; |
|
871 }, |
|
872 |
|
873 getRoamingPreference: function(clientId, window) { |
|
874 if (window == null) { |
|
875 throw Components.Exception("Can't get window object", |
|
876 Cr.NS_ERROR_UNEXPECTED); |
|
877 } |
|
878 |
|
879 let request = Services.DOMRequest.createRequest(window); |
|
880 let requestId = this.getRequestId(request); |
|
881 |
|
882 cpmm.sendAsyncMessage("RIL:GetRoamingPreference", { |
|
883 clientId: clientId, |
|
884 data: { |
|
885 requestId: requestId |
|
886 } |
|
887 }); |
|
888 return request; |
|
889 }, |
|
890 |
|
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 } |
|
896 |
|
897 let request = Services.DOMRequest.createRequest(window); |
|
898 let requestId = this.getRequestId(request); |
|
899 |
|
900 cpmm.sendAsyncMessage("RIL:SetVoicePrivacyMode", { |
|
901 clientId: clientId, |
|
902 data: { |
|
903 requestId: requestId, |
|
904 enabled: enabled |
|
905 } |
|
906 }); |
|
907 return request; |
|
908 }, |
|
909 |
|
910 getVoicePrivacyMode: function(clientId, window) { |
|
911 if (window == null) { |
|
912 throw Components.Exception("Can't get window object", |
|
913 Cr.NS_ERROR_UNEXPECTED); |
|
914 } |
|
915 |
|
916 let request = Services.DOMRequest.createRequest(window); |
|
917 let requestId = this.getRequestId(request); |
|
918 |
|
919 cpmm.sendAsyncMessage("RIL:GetVoicePrivacyMode", { |
|
920 clientId: clientId, |
|
921 data: { |
|
922 requestId: requestId |
|
923 } |
|
924 }); |
|
925 return request; |
|
926 }, |
|
927 |
|
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; |
|
936 |
|
937 cpmm.sendAsyncMessage("RIL:GetCardLockState", { |
|
938 clientId: clientId, |
|
939 data: { |
|
940 lockType: lockType, |
|
941 requestId: requestId |
|
942 } |
|
943 }); |
|
944 return request; |
|
945 }, |
|
946 |
|
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; |
|
955 |
|
956 cpmm.sendAsyncMessage("RIL:UnlockCardLock", { |
|
957 clientId: clientId, |
|
958 data: info |
|
959 }); |
|
960 return request; |
|
961 }, |
|
962 |
|
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; |
|
971 |
|
972 cpmm.sendAsyncMessage("RIL:SetCardLock", { |
|
973 clientId: clientId, |
|
974 data: info |
|
975 }); |
|
976 return request; |
|
977 }, |
|
978 |
|
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 }, |
|
995 |
|
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; |
|
1007 |
|
1008 cpmm.sendAsyncMessage("RIL:SendMMI", { |
|
1009 clientId: clientId, |
|
1010 data: { |
|
1011 mmi: mmi, |
|
1012 requestId: requestId |
|
1013 } |
|
1014 }); |
|
1015 return request; |
|
1016 }, |
|
1017 |
|
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 }, |
|
1034 |
|
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 }, |
|
1046 |
|
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 }, |
|
1061 |
|
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 }, |
|
1074 |
|
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 }, |
|
1087 |
|
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 } |
|
1093 |
|
1094 let request = Services.DOMRequest.createRequest(window); |
|
1095 let requestId = this.getRequestId(request); |
|
1096 |
|
1097 cpmm.sendAsyncMessage("RIL:IccOpenChannel", { |
|
1098 clientId: clientId, |
|
1099 data: { |
|
1100 requestId: requestId, |
|
1101 aid: aid |
|
1102 } |
|
1103 }); |
|
1104 return request; |
|
1105 }, |
|
1106 |
|
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 } |
|
1112 |
|
1113 let request = Services.DOMRequest.createRequest(window); |
|
1114 let requestId = this.getRequestId(request); |
|
1115 |
|
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 }, |
|
1127 |
|
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 } |
|
1133 |
|
1134 let request = Services.DOMRequest.createRequest(window); |
|
1135 let requestId = this.getRequestId(request); |
|
1136 |
|
1137 cpmm.sendAsyncMessage("RIL:IccCloseChannel", { |
|
1138 clientId: clientId, |
|
1139 data: { |
|
1140 requestId: requestId, |
|
1141 channel: channel |
|
1142 } |
|
1143 }); |
|
1144 return request; |
|
1145 }, |
|
1146 |
|
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 } |
|
1152 |
|
1153 let request = Services.DOMRequest.createRequest(window); |
|
1154 let requestId = this.getRequestId(request); |
|
1155 this._windowsMap[requestId] = window; |
|
1156 |
|
1157 cpmm.sendAsyncMessage("RIL:ReadIccContacts", { |
|
1158 clientId: clientId, |
|
1159 data: { |
|
1160 requestId: requestId, |
|
1161 contactType: contactType |
|
1162 } |
|
1163 }); |
|
1164 return request; |
|
1165 }, |
|
1166 |
|
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 } |
|
1172 |
|
1173 let request = Services.DOMRequest.createRequest(window); |
|
1174 let requestId = this.getRequestId(request); |
|
1175 this._windowsMap[requestId] = window; |
|
1176 |
|
1177 // Parsing nsDOMContact to Icc Contact format |
|
1178 let iccContact = {}; |
|
1179 |
|
1180 if (Array.isArray(contact.name) && contact.name[0]) { |
|
1181 iccContact.alphaId = contact.name[0]; |
|
1182 } |
|
1183 |
|
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 } |
|
1195 |
|
1196 if (Array.isArray(contact.email) && contact.email[0]) { |
|
1197 iccContact.email = contact.email[0].value; |
|
1198 } |
|
1199 |
|
1200 iccContact.contactId = contact.id; |
|
1201 |
|
1202 cpmm.sendAsyncMessage("RIL:UpdateIccContact", { |
|
1203 clientId: clientId, |
|
1204 data: { |
|
1205 requestId: requestId, |
|
1206 contactType: contactType, |
|
1207 contact: iccContact, |
|
1208 pin2: pin2 |
|
1209 } |
|
1210 }); |
|
1211 |
|
1212 return request; |
|
1213 }, |
|
1214 |
|
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); |
|
1222 |
|
1223 if (!this._isValidCFReason(reason)){ |
|
1224 this.dispatchFireRequestError(requestId, |
|
1225 RIL.GECKO_ERROR_INVALID_PARAMETER); |
|
1226 return request; |
|
1227 } |
|
1228 |
|
1229 cpmm.sendAsyncMessage("RIL:GetCallForwardingOptions", { |
|
1230 clientId: clientId, |
|
1231 data: { |
|
1232 requestId: requestId, |
|
1233 reason: reason |
|
1234 } |
|
1235 }); |
|
1236 |
|
1237 return request; |
|
1238 }, |
|
1239 |
|
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); |
|
1247 |
|
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 } |
|
1255 |
|
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 }); |
|
1267 |
|
1268 return request; |
|
1269 }, |
|
1270 |
|
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); |
|
1278 |
|
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 } |
|
1285 |
|
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 }, |
|
1297 |
|
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); |
|
1305 |
|
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 } |
|
1312 |
|
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 }, |
|
1325 |
|
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); |
|
1333 |
|
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 } |
|
1340 |
|
1341 if (DEBUG) debug("changeCallBarringPassword: " + JSON.stringify(info)); |
|
1342 info.requestId = requestId; |
|
1343 cpmm.sendAsyncMessage("RIL:ChangeCallBarringPassword", { |
|
1344 clientId: clientId, |
|
1345 data: info |
|
1346 }); |
|
1347 |
|
1348 return request; |
|
1349 }, |
|
1350 |
|
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); |
|
1358 |
|
1359 cpmm.sendAsyncMessage("RIL:GetCallWaitingOptions", { |
|
1360 clientId: clientId, |
|
1361 data: { |
|
1362 requestId: requestId |
|
1363 } |
|
1364 }); |
|
1365 |
|
1366 return request; |
|
1367 }, |
|
1368 |
|
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); |
|
1376 |
|
1377 cpmm.sendAsyncMessage("RIL:SetCallWaitingOptions", { |
|
1378 clientId: clientId, |
|
1379 data: { |
|
1380 requestId: requestId, |
|
1381 enabled: enabled |
|
1382 } |
|
1383 }); |
|
1384 |
|
1385 return request; |
|
1386 }, |
|
1387 |
|
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); |
|
1395 |
|
1396 cpmm.sendAsyncMessage("RIL:GetCallingLineIdRestriction", { |
|
1397 clientId: clientId, |
|
1398 data: { |
|
1399 requestId: requestId |
|
1400 } |
|
1401 }); |
|
1402 |
|
1403 return request; |
|
1404 }, |
|
1405 |
|
1406 setCallingLineIdRestriction: function(clientId, window, clirMode) { |
|
1407 |
|
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); |
|
1414 |
|
1415 cpmm.sendAsyncMessage("RIL:SetCallingLineIdRestriction", { |
|
1416 clientId: clientId, |
|
1417 data: { |
|
1418 requestId: requestId, |
|
1419 clirMode: clirMode |
|
1420 } |
|
1421 }); |
|
1422 |
|
1423 return request; |
|
1424 }, |
|
1425 |
|
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); |
|
1433 |
|
1434 cpmm.sendAsyncMessage("RIL:ExitEmergencyCbMode", { |
|
1435 clientId: clientId, |
|
1436 data: { |
|
1437 requestId: requestId, |
|
1438 } |
|
1439 }); |
|
1440 |
|
1441 return request; |
|
1442 }, |
|
1443 |
|
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); |
|
1451 |
|
1452 cpmm.sendAsyncMessage("RIL:SetRadioEnabled", { |
|
1453 clientId: clientId, |
|
1454 data: { |
|
1455 requestId: requestId, |
|
1456 enabled: enabled, |
|
1457 } |
|
1458 }); |
|
1459 |
|
1460 return request; |
|
1461 }, |
|
1462 |
|
1463 _mobileConnectionListeners: null, |
|
1464 _cellBroadcastListeners: null, |
|
1465 _voicemailListeners: null, |
|
1466 _iccListeners: null, |
|
1467 |
|
1468 voicemailInfos: null, |
|
1469 voicemailStatuses: null, |
|
1470 |
|
1471 voicemailDefaultServiceId: 0, |
|
1472 getVoicemailDefaultServiceId: function() { |
|
1473 let id = Services.prefs.getIntPref(kPrefVoicemailDefaultServiceId); |
|
1474 |
|
1475 if (id >= gNumRadioInterfaces || id < 0) { |
|
1476 id = 0; |
|
1477 } |
|
1478 |
|
1479 return id; |
|
1480 }, |
|
1481 |
|
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 }; |
|
1487 |
|
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 } |
|
1495 |
|
1496 return this.voicemailInfos[clientId]; |
|
1497 }, |
|
1498 |
|
1499 getVoicemailNumber: function(clientId) { |
|
1500 return this.getVoicemailInfo(clientId).number; |
|
1501 }, |
|
1502 |
|
1503 getVoicemailDisplayName: function(clientId) { |
|
1504 return this.getVoicemailInfo(clientId).displayName; |
|
1505 }, |
|
1506 |
|
1507 getVoicemailStatus: function(clientId) { |
|
1508 return this.voicemailStatuses[clientId]; |
|
1509 }, |
|
1510 |
|
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 } |
|
1519 |
|
1520 if (listeners.indexOf(listener) != -1) { |
|
1521 throw new Error("Already registered this listener!"); |
|
1522 } |
|
1523 |
|
1524 listeners.push(listener); |
|
1525 if (DEBUG) debug("Registered " + listenerType + " listener: " + listener); |
|
1526 }, |
|
1527 |
|
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 } |
|
1536 |
|
1537 let index = listeners.indexOf(listener); |
|
1538 if (index != -1) { |
|
1539 listeners.splice(index, 1); |
|
1540 if (DEBUG) debug("Unregistered listener: " + listener); |
|
1541 } |
|
1542 }, |
|
1543 |
|
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 }, |
|
1549 |
|
1550 unregisterMobileConnectionMsg: function(clientId, listener) { |
|
1551 this.unregisterListener("_mobileConnectionListeners", clientId, listener); |
|
1552 }, |
|
1553 |
|
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 }, |
|
1562 |
|
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 }, |
|
1569 |
|
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 }, |
|
1576 |
|
1577 unregisterCellBroadcastMsg: function(listener) { |
|
1578 //TODO: Bug 921326 - Cellbroadcast API: support multiple sim cards |
|
1579 this.unregisterListener("_cellBroadcastListeners", 0, listener); |
|
1580 }, |
|
1581 |
|
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 }, |
|
1587 |
|
1588 unregisterIccMsg: function(clientId, listener) { |
|
1589 this.unregisterListener("_iccListeners", clientId, listener); |
|
1590 }, |
|
1591 |
|
1592 // nsIObserver |
|
1593 |
|
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; |
|
1603 |
|
1604 case NS_XPCOM_SHUTDOWN_OBSERVER_ID: |
|
1605 this.destroyDOMRequestHelper(); |
|
1606 Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID); |
|
1607 break; |
|
1608 } |
|
1609 }, |
|
1610 |
|
1611 // nsIMessageListener |
|
1612 |
|
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 } |
|
1622 |
|
1623 if (DEBUG) { |
|
1624 debug("fire request success, id: " + requestId + |
|
1625 ", result: " + JSON.stringify(result)); |
|
1626 } |
|
1627 Services.DOMRequest.fireSuccess(request, result); |
|
1628 }, |
|
1629 |
|
1630 dispatchFireRequestSuccess: function(requestId, result) { |
|
1631 let currentThread = Services.tm.currentThread; |
|
1632 |
|
1633 currentThread.dispatch(this.fireRequestSuccess.bind(this, requestId, result), |
|
1634 Ci.nsIThread.DISPATCH_NORMAL); |
|
1635 }, |
|
1636 |
|
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 } |
|
1646 |
|
1647 if (DEBUG) { |
|
1648 debug("fire request error, id: " + requestId + |
|
1649 ", result: " + JSON.stringify(error)); |
|
1650 } |
|
1651 Services.DOMRequest.fireError(request, error); |
|
1652 }, |
|
1653 |
|
1654 dispatchFireRequestError: function(requestId, error) { |
|
1655 let currentThread = Services.tm.currentThread; |
|
1656 |
|
1657 currentThread.dispatch(this.fireRequestError.bind(this, requestId, error), |
|
1658 Ci.nsIThread.DISPATCH_NORMAL); |
|
1659 }, |
|
1660 |
|
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 } |
|
1670 |
|
1671 Services.DOMRequest.fireDetailedError(request, detailedError); |
|
1672 }, |
|
1673 |
|
1674 receiveMessage: function(msg) { |
|
1675 let request; |
|
1676 if (DEBUG) { |
|
1677 debug("Received message '" + msg.name + "': " + JSON.stringify(msg.json)); |
|
1678 } |
|
1679 |
|
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]; |
|
1751 |
|
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 }, |
|
1896 |
|
1897 handleSimpleRequest: function(requestId, errorMsg, result) { |
|
1898 if (errorMsg) { |
|
1899 this.fireRequestError(requestId, errorMsg); |
|
1900 } else { |
|
1901 this.fireRequestSuccess(requestId, result); |
|
1902 } |
|
1903 }, |
|
1904 |
|
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 } |
|
1914 |
|
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 } |
|
1922 |
|
1923 this.fireRequestSuccess(message.requestId, networks); |
|
1924 }, |
|
1925 |
|
1926 handleSelectNetwork: function(clientId, message, mode) { |
|
1927 this._selectingNetworks[clientId] = null; |
|
1928 this.rilContexts[clientId].networkSelectionMode = mode; |
|
1929 |
|
1930 if (message.errorMsg) { |
|
1931 this.fireRequestError(message.requestId, message.errorMsg); |
|
1932 } else { |
|
1933 this.fireRequestSuccess(message.requestId, null); |
|
1934 } |
|
1935 }, |
|
1936 |
|
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 }, |
|
1945 |
|
1946 handleReadIccContacts: function(message) { |
|
1947 if (message.errorMsg) { |
|
1948 this.fireRequestError(message.requestId, message.errorMsg); |
|
1949 return; |
|
1950 } |
|
1951 |
|
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}]}; |
|
1957 |
|
1958 if (c.email) { |
|
1959 prop.email = [{value: c.email}]; |
|
1960 } |
|
1961 |
|
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 } |
|
1967 |
|
1968 let contact = new window.mozContact(prop); |
|
1969 contact.id = c.contactId; |
|
1970 return contact; |
|
1971 }); |
|
1972 |
|
1973 this.fireRequestSuccess(message.requestId, result); |
|
1974 }, |
|
1975 |
|
1976 handleUpdateIccContact: function(message) { |
|
1977 if (message.errorMsg) { |
|
1978 this.fireRequestError(message.requestId, message.errorMsg); |
|
1979 return; |
|
1980 } |
|
1981 |
|
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 } |
|
1989 |
|
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 } |
|
1995 |
|
1996 let contact = new window.mozContact(prop); |
|
1997 contact.id = iccContact.contactId; |
|
1998 |
|
1999 this.fireRequestSuccess(message.requestId, contact); |
|
2000 }, |
|
2001 |
|
2002 handleVoicemailNotification: function(clientId, message) { |
|
2003 let changed = false; |
|
2004 if (!this.voicemailStatuses[clientId]) { |
|
2005 this.voicemailStatuses[clientId] = new VoicemailStatus(clientId); |
|
2006 } |
|
2007 |
|
2008 let voicemailStatus = this.voicemailStatuses[clientId]; |
|
2009 if (voicemailStatus.hasMessages != message.active) { |
|
2010 changed = true; |
|
2011 voicemailStatus.hasMessages = message.active; |
|
2012 } |
|
2013 |
|
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 } |
|
2021 |
|
2022 if (voicemailStatus.returnNumber != message.returnNumber) { |
|
2023 changed = true; |
|
2024 voicemailStatus.returnNumber = message.returnNumber; |
|
2025 } |
|
2026 |
|
2027 if (voicemailStatus.returnMessage != message.returnMessage) { |
|
2028 changed = true; |
|
2029 voicemailStatus.returnMessage = message.returnMessage; |
|
2030 } |
|
2031 |
|
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 }, |
|
2041 |
|
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 }, |
|
2050 |
|
2051 handleGetCallForwardingOptions: function(message) { |
|
2052 if (message.errorMsg) { |
|
2053 this.fireRequestError(message.requestId, message.errorMsg); |
|
2054 return; |
|
2055 } |
|
2056 |
|
2057 this._cfRulesToMobileCfInfo(message.rules); |
|
2058 this.fireRequestSuccess(message.requestId, message.rules); |
|
2059 }, |
|
2060 |
|
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 }, |
|
2069 |
|
2070 handleGetCallingLineIdRestriction: function(message) { |
|
2071 if (message.errorMsg) { |
|
2072 this.fireRequestError(message.requestId, message.errorMsg); |
|
2073 return; |
|
2074 } |
|
2075 |
|
2076 let status = new DOMCLIRStatus(message); |
|
2077 this.fireRequestSuccess(message.requestId, status); |
|
2078 }, |
|
2079 |
|
2080 handleExitEmergencyCbMode: function(message) { |
|
2081 let requestId = message.requestId; |
|
2082 let request = this.takeRequest(requestId); |
|
2083 if (!request) { |
|
2084 return; |
|
2085 } |
|
2086 |
|
2087 if (!message.success) { |
|
2088 Services.DOMRequest.fireError(request, message.errorMsg); |
|
2089 return; |
|
2090 } |
|
2091 Services.DOMRequest.fireSuccess(request, null); |
|
2092 }, |
|
2093 |
|
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 } |
|
2102 |
|
2103 let success = message.success; |
|
2104 |
|
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 } |
|
2114 |
|
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 } |
|
2122 |
|
2123 let result = { |
|
2124 serviceCode: message.mmiServiceCode, |
|
2125 additionalInformation: message.additionalInformation |
|
2126 }; |
|
2127 |
|
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 }, |
|
2140 |
|
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 } |
|
2149 |
|
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 }, |
|
2166 |
|
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 }, |
|
2183 |
|
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 }, |
|
2198 |
|
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 }, |
|
2214 |
|
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 } |
|
2224 |
|
2225 // For setting callbarring options, |enabled| and |password| are required. |
|
2226 if (usedForSetting && (options.enabled == null || options.password == null)) { |
|
2227 return false; |
|
2228 } |
|
2229 |
|
2230 return true; |
|
2231 } |
|
2232 }; |
|
2233 |
|
2234 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([RILContentHelper, |
|
2235 DOMMMIError, |
|
2236 IccCardLockError]); |