зеркало из https://github.com/mozilla/gecko-dev.git
747 строки
21 KiB
JavaScript
747 строки
21 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
"use strict";
|
|
|
|
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
|
|
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
Cu.import("resource://gre/modules/Services.jsm");
|
|
|
|
var RIL = {};
|
|
Cu.import("resource://gre/modules/ril_consts.js", RIL);
|
|
|
|
const GONK_ICCSERVICE_CONTRACTID = "@mozilla.org/icc/gonkiccservice;1";
|
|
const GONK_ICCSERVICE_CID = Components.ID("{df854256-9554-11e4-a16c-c39e8d106c26}");
|
|
|
|
const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown";
|
|
const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed";
|
|
|
|
const kPrefRilDebuggingEnabled = "ril.debugging.enabled";
|
|
const kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces";
|
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "gRadioInterfaceLayer",
|
|
"@mozilla.org/ril;1",
|
|
"nsIRadioInterfaceLayer");
|
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "gMobileConnectionService",
|
|
"@mozilla.org/mobileconnection/mobileconnectionservice;1",
|
|
"nsIGonkMobileConnectionService");
|
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "gIccMessenger",
|
|
"@mozilla.org/ril/system-messenger-helper;1",
|
|
"nsIIccMessenger");
|
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "gStkCmdFactory",
|
|
"@mozilla.org/icc/stkcmdfactory;1",
|
|
"nsIStkCmdFactory");
|
|
|
|
var DEBUG = RIL.DEBUG_RIL;
|
|
function debug(s) {
|
|
dump("IccService: " + s);
|
|
}
|
|
|
|
function IccInfo() {}
|
|
IccInfo.prototype = {
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIIccInfo]),
|
|
|
|
// nsIIccInfo
|
|
|
|
iccType: null,
|
|
iccid: null,
|
|
mcc: null,
|
|
mnc: null,
|
|
spn: null,
|
|
isDisplayNetworkNameRequired: false,
|
|
isDisplaySpnRequired: false
|
|
};
|
|
|
|
function GsmIccInfo() {}
|
|
GsmIccInfo.prototype = {
|
|
__proto__: IccInfo.prototype,
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIGsmIccInfo,
|
|
Ci.nsIIccInfo]),
|
|
|
|
// nsIGsmIccInfo
|
|
|
|
msisdn: null
|
|
};
|
|
|
|
function CdmaIccInfo() {}
|
|
CdmaIccInfo.prototype = {
|
|
__proto__: IccInfo.prototype,
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsICdmaIccInfo,
|
|
Ci.nsIIccInfo]),
|
|
|
|
// nsICdmaIccInfo
|
|
|
|
mdn: null,
|
|
prlVersion: 0
|
|
};
|
|
|
|
function IccContact(aContact) {
|
|
this.id = aContact.contactId || null;
|
|
this._names = [];
|
|
this._numbers = [];
|
|
this._emails = [];
|
|
|
|
if (aContact.alphaId) {
|
|
this._names.push(aContact.alphaId);
|
|
}
|
|
|
|
if (aContact.number) {
|
|
this._numbers.push(aContact.number);
|
|
}
|
|
|
|
let anrLen = aContact.anr ? aContact.anr.length : 0;
|
|
for (let i = 0; i < anrLen; i++) {
|
|
this._numbers.push(aContact.anr[i]);
|
|
}
|
|
|
|
if (aContact.email) {
|
|
this._emails.push(aContact.email);
|
|
}
|
|
}
|
|
IccContact.prototype = {
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIIccContact]),
|
|
|
|
_names: null,
|
|
_numbers: null,
|
|
_emails: null,
|
|
|
|
// nsIIccContact
|
|
|
|
id: null,
|
|
|
|
getNames: function(aCount) {
|
|
if (!this._names) {
|
|
if (aCount) {
|
|
aCount.value = 0;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
if (aCount) {
|
|
aCount.value = this._names.length;
|
|
}
|
|
|
|
return this._names.slice();
|
|
},
|
|
|
|
getNumbers: function(aCount) {
|
|
if (!this._numbers) {
|
|
if (aCount) {
|
|
aCount.value = 0;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
if (aCount) {
|
|
aCount.value = this._numbers.length;
|
|
}
|
|
|
|
return this._numbers.slice();
|
|
},
|
|
|
|
getEmails: function(aCount) {
|
|
if (!this._emails) {
|
|
if (aCount) {
|
|
aCount.value = 0;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
if (aCount) {
|
|
aCount.value = this._emails.length;
|
|
}
|
|
|
|
return this._emails.slice();
|
|
},
|
|
};
|
|
|
|
function IccService() {
|
|
this._iccs = [];
|
|
|
|
let numClients = gRadioInterfaceLayer.numRadioInterfaces;
|
|
for (let i = 0; i < numClients; i++) {
|
|
this._iccs.push(new Icc(i));
|
|
}
|
|
|
|
this._updateDebugFlag();
|
|
|
|
Services.prefs.addObserver(kPrefRilDebuggingEnabled, this, false);
|
|
Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
|
|
}
|
|
IccService.prototype = {
|
|
classID: GONK_ICCSERVICE_CID,
|
|
|
|
classInfo: XPCOMUtils.generateCI({classID: GONK_ICCSERVICE_CID,
|
|
contractID: GONK_ICCSERVICE_CONTRACTID,
|
|
classDescription: "IccService",
|
|
interfaces: [Ci.nsIIccService,
|
|
Ci.nsIGonkIccService],
|
|
flags: Ci.nsIClassInfo.SINGLETON}),
|
|
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIIccService,
|
|
Ci.nsIGonkIccService,
|
|
Ci.nsIObserver]),
|
|
|
|
// An array of Icc instances.
|
|
_iccs: null,
|
|
|
|
_updateDebugFlag: function() {
|
|
try {
|
|
DEBUG = DEBUG ||
|
|
Services.prefs.getBoolPref(kPrefRilDebuggingEnabled);
|
|
} catch (e) {}
|
|
},
|
|
|
|
/**
|
|
* nsIIccService interface.
|
|
*/
|
|
getIccByServiceId: function(aServiceId) {
|
|
let icc = this._iccs[aServiceId];
|
|
if (!icc) {
|
|
throw Cr.NS_ERROR_UNEXPECTED;
|
|
}
|
|
|
|
return icc;
|
|
},
|
|
|
|
/**
|
|
* nsIGonkIccService interface.
|
|
*/
|
|
notifyStkCommand: function(aServiceId, aStkcommand) {
|
|
if (DEBUG) {
|
|
debug("notifyStkCommand for service Id: " + aServiceId);
|
|
}
|
|
|
|
let icc = this.getIccByServiceId(aServiceId);
|
|
|
|
if (!icc.iccInfo || !icc.iccInfo.iccid) {
|
|
debug("Warning: got STK command when iccid is invalid.");
|
|
return;
|
|
}
|
|
|
|
gIccMessenger.notifyStkProactiveCommand(icc.iccInfo.iccid, aStkcommand);
|
|
|
|
icc._deliverListenerEvent("notifyStkCommand", [aStkcommand]);
|
|
},
|
|
|
|
notifyStkSessionEnd: function(aServiceId) {
|
|
if (DEBUG) {
|
|
debug("notifyStkSessionEnd for service Id: " + aServiceId);
|
|
}
|
|
|
|
this.getIccByServiceId(aServiceId)
|
|
._deliverListenerEvent("notifyStkSessionEnd");
|
|
},
|
|
|
|
notifyCardStateChanged: function(aServiceId, aCardState) {
|
|
if (DEBUG) {
|
|
debug("notifyCardStateChanged for service Id: " + aServiceId +
|
|
", CardState: " + aCardState);
|
|
}
|
|
|
|
this.getIccByServiceId(aServiceId)._updateCardState(aCardState);
|
|
},
|
|
|
|
notifyIccInfoChanged: function(aServiceId, aIccInfo) {
|
|
if (DEBUG) {
|
|
debug("notifyIccInfoChanged for service Id: " + aServiceId +
|
|
", IccInfo: " + JSON.stringify(aIccInfo));
|
|
}
|
|
|
|
this.getIccByServiceId(aServiceId)._updateIccInfo(aIccInfo);
|
|
},
|
|
|
|
notifyImsiChanged: function(aServiceId, aImsi) {
|
|
if (DEBUG) {
|
|
debug("notifyImsiChanged for service Id: " + aServiceId +
|
|
", Imsi: " + aImsi);
|
|
}
|
|
|
|
let icc = this.getIccByServiceId(aServiceId);
|
|
icc.imsi = aImsi || null;
|
|
},
|
|
|
|
/**
|
|
* nsIObserver interface.
|
|
*/
|
|
observe: function(aSubject, aTopic, aData) {
|
|
switch (aTopic) {
|
|
case NS_PREFBRANCH_PREFCHANGE_TOPIC_ID:
|
|
if (aData === kPrefRilDebuggingEnabled) {
|
|
this._updateDebugFlag();
|
|
}
|
|
break;
|
|
case NS_XPCOM_SHUTDOWN_OBSERVER_ID:
|
|
Services.prefs.removeObserver(kPrefRilDebuggingEnabled, this);
|
|
Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
|
|
function Icc(aClientId) {
|
|
this._clientId = aClientId;
|
|
this._radioInterface = gRadioInterfaceLayer.getRadioInterface(aClientId);
|
|
this._listeners = [];
|
|
}
|
|
Icc.prototype = {
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIIcc]),
|
|
|
|
_clientId: 0,
|
|
_radioInterface: null,
|
|
_listeners: null,
|
|
|
|
_updateCardState: function(aCardState) {
|
|
if (this.cardState != aCardState) {
|
|
this.cardState = aCardState;
|
|
}
|
|
|
|
this._deliverListenerEvent("notifyCardStateChanged");
|
|
},
|
|
|
|
// An utility function to copy objects.
|
|
_updateInfo: function(aSrcInfo, aDestInfo) {
|
|
for (let key in aSrcInfo) {
|
|
aDestInfo[key] = aSrcInfo[key];
|
|
}
|
|
},
|
|
|
|
/**
|
|
* A utility function to compare objects. The srcInfo may contain
|
|
* "rilMessageType", should ignore it.
|
|
*/
|
|
_isInfoChanged: function(srcInfo, destInfo) {
|
|
if (!destInfo) {
|
|
return true;
|
|
}
|
|
|
|
for (let key in srcInfo) {
|
|
if (key === "rilMessageType") {
|
|
continue;
|
|
}
|
|
if (srcInfo[key] !== destInfo[key]) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
},
|
|
|
|
/**
|
|
* We need to consider below cases when update iccInfo:
|
|
* 1. Should clear iccInfo to null if there is no card detected.
|
|
* 2. Need to create corresponding object based on iccType.
|
|
*/
|
|
_updateIccInfo: function(aIccInfo) {
|
|
let oldSpn = this.iccInfo ? this.iccInfo.spn : null;
|
|
|
|
// Card is not detected, clear iccInfo to null.
|
|
if (!aIccInfo || !aIccInfo.iccid) {
|
|
if (this.iccInfo) {
|
|
if (DEBUG) {
|
|
debug("Card is not detected, clear iccInfo to null.");
|
|
}
|
|
this.imsi = null;
|
|
this.iccInfo = null;
|
|
this._deliverListenerEvent("notifyIccInfoChanged");
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (!this._isInfoChanged(aIccInfo, this.iccInfo)) {
|
|
return;
|
|
}
|
|
|
|
// If iccInfo is null, new corresponding object based on iccType.
|
|
if (!this.iccInfo ||
|
|
this.iccInfo.iccType != aIccInfo.iccType) {
|
|
if (aIccInfo.iccType === "ruim" || aIccInfo.iccType === "csim") {
|
|
this.iccInfo = new CdmaIccInfo();
|
|
} else if (aIccInfo.iccType === "sim" || aIccInfo.iccType === "usim") {
|
|
this.iccInfo = new GsmIccInfo();
|
|
} else {
|
|
this.iccInfo = new IccInfo();
|
|
}
|
|
}
|
|
|
|
this._updateInfo(aIccInfo, this.iccInfo);
|
|
|
|
this._deliverListenerEvent("notifyIccInfoChanged");
|
|
|
|
// Update lastKnownSimMcc.
|
|
if (aIccInfo.mcc) {
|
|
try {
|
|
Services.prefs.setCharPref("ril.lastKnownSimMcc",
|
|
aIccInfo.mcc.toString());
|
|
} catch (e) {}
|
|
}
|
|
|
|
// Update lastKnownHomeNetwork.
|
|
if (aIccInfo.mcc && aIccInfo.mnc) {
|
|
let lastKnownHomeNetwork = aIccInfo.mcc + "-" + aIccInfo.mnc;
|
|
// Append spn information if available.
|
|
if (aIccInfo.spn) {
|
|
lastKnownHomeNetwork += "-" + aIccInfo.spn;
|
|
}
|
|
|
|
gMobileConnectionService.notifyLastHomeNetworkChanged(this._clientId,
|
|
lastKnownHomeNetwork);
|
|
}
|
|
|
|
// If spn becomes available, we should check roaming again.
|
|
if (!oldSpn && aIccInfo.spn) {
|
|
gMobileConnectionService.notifySpnAvailable(this._clientId);
|
|
}
|
|
},
|
|
|
|
_deliverListenerEvent: function(aName, aArgs) {
|
|
let listeners = this._listeners.slice();
|
|
for (let listener of listeners) {
|
|
if (this._listeners.indexOf(listener) === -1) {
|
|
continue;
|
|
}
|
|
let handler = listener[aName];
|
|
if (typeof handler != "function") {
|
|
throw new Error("No handler for " + aName);
|
|
}
|
|
try {
|
|
handler.apply(listener, aArgs);
|
|
} catch (e) {
|
|
if (DEBUG) {
|
|
debug("listener for " + aName + " threw an exception: " + e);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
_modifyCardLock: function(aOperation, aOptions, aCallback) {
|
|
this._radioInterface.sendWorkerMessage(aOperation,
|
|
aOptions,
|
|
(aResponse) => {
|
|
if (aResponse.errorMsg) {
|
|
let retryCount =
|
|
(aResponse.retryCount !== undefined) ? aResponse.retryCount : -1;
|
|
aCallback.notifyCardLockError(aResponse.errorMsg, retryCount);
|
|
return;
|
|
}
|
|
|
|
aCallback.notifySuccess();
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Helper to match the MVNO pattern with IMSI.
|
|
*
|
|
* Note: Characters 'x' and 'X' in MVNO are skipped and not compared.
|
|
* E.g., if the aMvnoData passed is '310260x10xxxxxx', then the
|
|
* function returns true only if imsi has the same first 6 digits, 8th
|
|
* and 9th digit.
|
|
*
|
|
* @param aMvnoData
|
|
* MVNO pattern.
|
|
* @param aImsi
|
|
* IMSI of this ICC.
|
|
*
|
|
* @return true if matched.
|
|
*/
|
|
_isImsiMatches: function(aMvnoData, aImsi) {
|
|
// This should not be an error, but a mismatch.
|
|
if (aMvnoData.length > aImsi.length) {
|
|
return false;
|
|
}
|
|
|
|
for (let i = 0; i < aMvnoData.length; i++) {
|
|
let c = aMvnoData[i];
|
|
if ((c !== 'x') && (c !== 'X') && (c !== aImsi[i])) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
},
|
|
|
|
/**
|
|
* nsIIcc interface.
|
|
*/
|
|
iccInfo: null,
|
|
cardState: Ci.nsIIcc.CARD_STATE_UNKNOWN,
|
|
imsi: null,
|
|
|
|
registerListener: function(aListener) {
|
|
if (this._listeners.indexOf(aListener) >= 0) {
|
|
throw Cr.NS_ERROR_UNEXPECTED;
|
|
}
|
|
|
|
this._listeners.push(aListener);
|
|
},
|
|
|
|
unregisterListener: function(aListener) {
|
|
let index = this._listeners.indexOf(aListener);
|
|
if (index >= 0) {
|
|
this._listeners.splice(index, 1);
|
|
}
|
|
},
|
|
|
|
getCardLockEnabled: function(aLockType, aCallback) {
|
|
this._radioInterface.sendWorkerMessage("iccGetCardLockEnabled",
|
|
{ lockType: aLockType },
|
|
(aResponse) => {
|
|
if (aResponse.errorMsg) {
|
|
aCallback.notifyError(aResponse.errorMsg);
|
|
return;
|
|
}
|
|
|
|
aCallback.notifySuccessWithBoolean(aResponse.enabled);
|
|
});
|
|
},
|
|
|
|
unlockCardLock: function(aLockType, aPassword, aNewPin, aCallback) {
|
|
this._modifyCardLock("iccUnlockCardLock",
|
|
{ lockType: aLockType,
|
|
password: aPassword,
|
|
newPin: aNewPin },
|
|
aCallback);
|
|
},
|
|
|
|
setCardLockEnabled: function(aLockType, aPassword, aEnabled, aCallback) {
|
|
this._modifyCardLock("iccSetCardLockEnabled",
|
|
{ lockType: aLockType,
|
|
password: aPassword,
|
|
enabled: aEnabled },
|
|
aCallback);
|
|
},
|
|
|
|
changeCardLockPassword: function(aLockType, aPassword, aNewPassword, aCallback) {
|
|
this._modifyCardLock("iccChangeCardLockPassword",
|
|
{ lockType: aLockType,
|
|
password: aPassword,
|
|
newPassword: aNewPassword, },
|
|
aCallback);
|
|
},
|
|
|
|
getCardLockRetryCount: function(aLockType, aCallback) {
|
|
this._radioInterface.sendWorkerMessage("iccGetCardLockRetryCount",
|
|
{ lockType: aLockType },
|
|
(aResponse) => {
|
|
if (aResponse.errorMsg) {
|
|
aCallback.notifyError(aResponse.errorMsg);
|
|
return;
|
|
}
|
|
|
|
aCallback.notifyGetCardLockRetryCount(aResponse.retryCount);
|
|
});
|
|
},
|
|
|
|
matchMvno: function(aMvnoType, aMvnoData, aCallback) {
|
|
if (!aMvnoData) {
|
|
aCallback.notifyError(RIL.GECKO_ERROR_INVALID_PARAMETER);
|
|
return;
|
|
}
|
|
|
|
switch (aMvnoType) {
|
|
case Ci.nsIIcc.CARD_MVNO_TYPE_IMSI:
|
|
let imsi = this.imsi;
|
|
if (!imsi) {
|
|
aCallback.notifyError(RIL.GECKO_ERROR_GENERIC_FAILURE);
|
|
break;
|
|
}
|
|
aCallback.notifySuccessWithBoolean(
|
|
this._isImsiMatches(aMvnoData, imsi));
|
|
break;
|
|
case Ci.nsIIcc.CARD_MVNO_TYPE_SPN:
|
|
let spn = this.iccInfo && this.iccInfo.spn;
|
|
if (!spn) {
|
|
aCallback.notifyError(RIL.GECKO_ERROR_GENERIC_FAILURE);
|
|
break;
|
|
}
|
|
aCallback.notifySuccessWithBoolean(spn == aMvnoData);
|
|
break;
|
|
case Ci.nsIIcc.CARD_MVNO_TYPE_GID:
|
|
this._radioInterface.sendWorkerMessage("getGID1",
|
|
null,
|
|
(aResponse) => {
|
|
let gid = aResponse.gid1;
|
|
let mvnoDataLength = aMvnoData.length;
|
|
|
|
if (!gid) {
|
|
aCallback.notifyError(RIL.GECKO_ERROR_GENERIC_FAILURE);
|
|
} else if (mvnoDataLength > gid.length) {
|
|
aCallback.notifySuccessWithBoolean(false);
|
|
} else {
|
|
let result =
|
|
gid.substring(0, mvnoDataLength).toLowerCase() ==
|
|
aMvnoData.toLowerCase();
|
|
aCallback.notifySuccessWithBoolean(result);
|
|
}
|
|
});
|
|
break;
|
|
default:
|
|
aCallback.notifyError(RIL.GECKO_ERROR_MODE_NOT_SUPPORTED);
|
|
break;
|
|
}
|
|
},
|
|
|
|
getServiceStateEnabled: function(aService, aCallback) {
|
|
this._radioInterface.sendWorkerMessage("getIccServiceState",
|
|
{ service: aService },
|
|
(aResponse) => {
|
|
if (aResponse.errorMsg) {
|
|
aCallback.notifyError(aResponse.errorMsg);
|
|
return;
|
|
}
|
|
|
|
aCallback.notifySuccessWithBoolean(aResponse.result);
|
|
});
|
|
},
|
|
|
|
iccOpenChannel: function(aAid, aCallback) {
|
|
this._radioInterface.sendWorkerMessage("iccOpenChannel",
|
|
{ aid: aAid },
|
|
(aResponse) => {
|
|
if (aResponse.errorMsg) {
|
|
aCallback.notifyError(aResponse.errorMsg);
|
|
return;
|
|
}
|
|
|
|
aCallback.notifyOpenChannelSuccess(aResponse.channel);
|
|
});
|
|
},
|
|
|
|
iccExchangeAPDU: function(aChannel, aCla, aIns, aP1, aP2, aP3, aData, aCallback) {
|
|
if (!aData) {
|
|
if (DEBUG) debug('data is not set , aP3 : ' + aP3);
|
|
}
|
|
|
|
let apdu = {
|
|
cla: aCla,
|
|
command: aIns,
|
|
p1: aP1,
|
|
p2: aP2,
|
|
p3: aP3,
|
|
data: aData
|
|
};
|
|
|
|
this._radioInterface.sendWorkerMessage("iccExchangeAPDU",
|
|
{ channel: aChannel, apdu: apdu },
|
|
(aResponse) => {
|
|
if (aResponse.errorMsg) {
|
|
aCallback.notifyError(aResponse.errorMsg);
|
|
return;
|
|
}
|
|
|
|
aCallback.notifyExchangeAPDUResponse(aResponse.sw1,
|
|
aResponse.sw2,
|
|
aResponse.simResponse);
|
|
});
|
|
},
|
|
|
|
iccCloseChannel: function(aChannel, aCallback) {
|
|
this._radioInterface.sendWorkerMessage("iccCloseChannel",
|
|
{ channel: aChannel },
|
|
(aResponse) => {
|
|
if (aResponse.errorMsg) {
|
|
aCallback.notifyError(aResponse.errorMsg);
|
|
return;
|
|
}
|
|
|
|
aCallback.notifyCloseChannelSuccess();
|
|
});
|
|
},
|
|
|
|
sendStkResponse: function(aCommand, aResponse) {
|
|
let response = gStkCmdFactory.createResponseMessage(aResponse);
|
|
response.command = gStkCmdFactory.createCommandMessage(aCommand);
|
|
this._radioInterface.sendWorkerMessage("sendStkTerminalResponse", response);
|
|
},
|
|
|
|
sendStkMenuSelection: function(aItemIdentifier, aHelpRequested) {
|
|
this._radioInterface
|
|
.sendWorkerMessage("sendStkMenuSelection", {
|
|
itemIdentifier: aItemIdentifier,
|
|
helpRequested: aHelpRequested
|
|
});
|
|
},
|
|
|
|
sendStkTimerExpiration: function(aTimerId, aTimerValue) {
|
|
this._radioInterface
|
|
.sendWorkerMessage("sendStkTimerExpiration",{
|
|
timer: {
|
|
timerId: aTimerId,
|
|
timerValue: aTimerValue
|
|
}
|
|
});
|
|
},
|
|
|
|
sendStkEventDownload: function(aEvent) {
|
|
this._radioInterface
|
|
.sendWorkerMessage("sendStkEventDownload",
|
|
{ event: gStkCmdFactory.createEventMessage(aEvent) });
|
|
},
|
|
|
|
readContacts: function(aContactType, aCallback) {
|
|
this._radioInterface
|
|
.sendWorkerMessage("readICCContacts",
|
|
{ contactType: aContactType },
|
|
(aResponse) => {
|
|
if (aResponse.errorMsg) {
|
|
aCallback.notifyError(aResponse.errorMsg);
|
|
return;
|
|
}
|
|
|
|
let iccContacts = [];
|
|
|
|
aResponse.contacts.forEach(c => iccContacts.push(new IccContact(c)));
|
|
|
|
aCallback.notifyRetrievedIccContacts(iccContacts, iccContacts.length);
|
|
});
|
|
},
|
|
|
|
updateContact: function(aContactType, aContact, aPin2, aCallback) {
|
|
let iccContact = { contactId: aContact.id };
|
|
let count = { value: 0 };
|
|
let names = aContact.getNames(count);
|
|
if (count.value > 0) {
|
|
iccContact.alphaId = names[0];
|
|
}
|
|
|
|
let numbers = aContact.getNumbers(count);
|
|
if (count.value > 0) {
|
|
iccContact.number = numbers[0];
|
|
|
|
let anrArray = numbers.slice(1);
|
|
let length = anrArray.length;
|
|
if (length > 0) {
|
|
iccContact.anr = [];
|
|
for (let i = 0; i < length; i++) {
|
|
iccContact.anr.push(anrArray[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
let emails = aContact.getEmails(count);
|
|
if (count.value > 0) {
|
|
iccContact.email = emails[0];
|
|
}
|
|
|
|
this._radioInterface
|
|
.sendWorkerMessage("updateICCContact",
|
|
{ contactType: aContactType,
|
|
contact: iccContact,
|
|
pin2: aPin2 },
|
|
(aResponse) => {
|
|
if (aResponse.errorMsg) {
|
|
aCallback.notifyError(aResponse.errorMsg);
|
|
return;
|
|
}
|
|
|
|
aCallback.notifyUpdatedIccContact(new IccContact(aResponse.contact));
|
|
});
|
|
},
|
|
};
|
|
|
|
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([IccService]);
|