mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
2c9ce1520b
Backed out changeset e72a0297d488 (bug 843452) Backed out changeset 73f62ce4190f (bug 843452) Backed out changeset 6d4a49ebd9fc (bug 843452) Backed out changeset ac93e396669f (bug 843452) Backed out changeset cf4fc721821e (bug 843452) Backed out changeset 9a94ea71d232 (bug 843452) Backed out changeset b95ff097374d (bug 843452) Backed out changeset 8d6428a93500 (bug 843452) Backed out changeset e31b86ef0e80 (bug 843452) Backed out changeset bd4efde535cd (bug 843452) Backed out changeset 02bbcd8ac571 (bug 843452) Backed out changeset f7f41bf82b22 (bug 843452) Backed out changeset 20f42764cd38 (bug 843452) Backed out changeset 82f8670f5c17 (bug 843452) Backed out changeset 52f25f1278e3 (bug 843452) Backed out changeset 181337820a7c (bug 843452) Backed out changeset 9bd12641af03 (bug 843452) --HG-- rename : dom/mobileconnection/interfaces/nsIMobileConnectionService.idl => dom/mobileconnection/interfaces/nsIMobileConnectionProvider.idl
1122 lines
34 KiB
JavaScript
1122 lines
34 KiB
JavaScript
/* Copyright 2012 Mozilla Foundation and Mozilla contributors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
|
|
|
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
|
|
Cu.import("resource://gre/modules/Services.jsm");
|
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
|
|
XPCOMUtils.defineLazyGetter(this, "RIL", function () {
|
|
let obj = {};
|
|
Cu.import("resource://gre/modules/ril_consts.js", obj);
|
|
return obj;
|
|
});
|
|
|
|
const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown";
|
|
|
|
const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed";
|
|
|
|
const kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces";
|
|
const kPrefRilDebuggingEnabled = "ril.debugging.enabled";
|
|
const kPrefVoicemailDefaultServiceId = "dom.voicemail.defaultServiceId";
|
|
|
|
let DEBUG;
|
|
function debug(s) {
|
|
dump("-*- RILContentHelper: " + s + "\n");
|
|
}
|
|
|
|
const RILCONTENTHELPER_CID =
|
|
Components.ID("{472816e1-1fd6-4405-996c-806f9ea68174}");
|
|
const ICCINFO_CID =
|
|
Components.ID("{39d64d90-26a6-11e4-8c21-0800200c9a66}");
|
|
const GSMICCINFO_CID =
|
|
Components.ID("{e0fa785b-ad3f-46ed-bc56-fcb0d6fe4fa8}");
|
|
const CDMAICCINFO_CID =
|
|
Components.ID("{3d1f844f-9ec5-48fb-8907-aed2e5421709}");
|
|
const VOICEMAILSTATUS_CID=
|
|
Components.ID("{5467f2eb-e214-43ea-9b89-67711241ec8e}");
|
|
const CELLBROADCASTMESSAGE_CID =
|
|
Components.ID("{29474c96-3099-486f-bb4a-3c9a1da834e4}");
|
|
const CELLBROADCASTETWSINFO_CID =
|
|
Components.ID("{59f176ee-9dcd-4005-9d47-f6be0cd08e17}");
|
|
const ICCCARDLOCKERROR_CID =
|
|
Components.ID("{08a71987-408c-44ff-93fd-177c0a85c3dd}");
|
|
|
|
const RIL_IPC_MSG_NAMES = [
|
|
"RIL:CardStateChanged",
|
|
"RIL:IccInfoChanged",
|
|
"RIL:VoicemailNotification",
|
|
"RIL:VoicemailInfoChanged",
|
|
"RIL:CardLockResult",
|
|
"RIL:CardLockRetryCount",
|
|
"RIL:StkCommand",
|
|
"RIL:StkSessionEnd",
|
|
"RIL:CellBroadcastReceived",
|
|
"RIL:IccOpenChannel",
|
|
"RIL:IccCloseChannel",
|
|
"RIL:IccExchangeAPDU",
|
|
"RIL:ReadIccContacts",
|
|
"RIL:UpdateIccContact",
|
|
"RIL:MatchMvno"
|
|
];
|
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
|
"@mozilla.org/childprocessmessagemanager;1",
|
|
"nsISyncMessageSender");
|
|
|
|
XPCOMUtils.defineLazyGetter(this, "gNumRadioInterfaces", function() {
|
|
let appInfo = Cc["@mozilla.org/xre/app-info;1"];
|
|
let isParentProcess = !appInfo || appInfo.getService(Ci.nsIXULRuntime)
|
|
.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
|
|
|
|
if (isParentProcess) {
|
|
let ril = Cc["@mozilla.org/ril;1"].getService(Ci.nsIRadioInterfaceLayer);
|
|
return ril.numRadioInterfaces;
|
|
}
|
|
|
|
return Services.prefs.getIntPref(kPrefRilNumRadioInterfaces);
|
|
});
|
|
|
|
function MobileIccCardLockResult(options) {
|
|
this.lockType = options.lockType;
|
|
this.enabled = options.enabled;
|
|
this.retryCount = options.retryCount;
|
|
this.success = options.success;
|
|
}
|
|
MobileIccCardLockResult.prototype = {
|
|
__exposedProps__ : {lockType: 'r',
|
|
enabled: 'r',
|
|
retryCount: 'r',
|
|
success: 'r'}
|
|
};
|
|
|
|
function MobileIccCardLockRetryCount(options) {
|
|
this.lockType = options.lockType;
|
|
this.retryCount = options.retryCount;
|
|
this.success = options.success;
|
|
}
|
|
MobileIccCardLockRetryCount.prototype = {
|
|
__exposedProps__ : {lockType: 'r',
|
|
retryCount: 'r',
|
|
success: 'r'}
|
|
};
|
|
|
|
function IccInfo() {}
|
|
IccInfo.prototype = {
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozIccInfo]),
|
|
classID: ICCINFO_CID,
|
|
classInfo: XPCOMUtils.generateCI({
|
|
classID: ICCINFO_CID,
|
|
classDescription: "MozIccInfo",
|
|
flags: Ci.nsIClassInfo.DOM_OBJECT,
|
|
interfaces: [Ci.nsIDOMMozIccInfo]
|
|
}),
|
|
|
|
// nsIDOMMozIccInfo
|
|
|
|
iccType: null,
|
|
iccid: null,
|
|
mcc: null,
|
|
mnc: null,
|
|
spn: null,
|
|
isDisplayNetworkNameRequired: null,
|
|
isDisplaySpnRequired: null
|
|
};
|
|
|
|
function GsmIccInfo() {}
|
|
GsmIccInfo.prototype = {
|
|
__proto__: IccInfo.prototype,
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozGsmIccInfo]),
|
|
classID: GSMICCINFO_CID,
|
|
classInfo: XPCOMUtils.generateCI({
|
|
classID: GSMICCINFO_CID,
|
|
classDescription: "MozGsmIccInfo",
|
|
flags: Ci.nsIClassInfo.DOM_OBJECT,
|
|
interfaces: [Ci.nsIDOMMozGsmIccInfo]
|
|
}),
|
|
|
|
// nsIDOMMozGsmIccInfo
|
|
|
|
msisdn: null
|
|
};
|
|
|
|
function CdmaIccInfo() {}
|
|
CdmaIccInfo.prototype = {
|
|
__proto__: IccInfo.prototype,
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozCdmaIccInfo]),
|
|
classID: CDMAICCINFO_CID,
|
|
classInfo: XPCOMUtils.generateCI({
|
|
classID: CDMAICCINFO_CID,
|
|
classDescription: "MozCdmaIccInfo",
|
|
flags: Ci.nsIClassInfo.DOM_OBJECT,
|
|
interfaces: [Ci.nsIDOMMozCdmaIccInfo]
|
|
}),
|
|
|
|
// nsIDOMMozCdmaIccInfo
|
|
|
|
mdn: null,
|
|
prlVersion: 0
|
|
};
|
|
|
|
function VoicemailInfo() {}
|
|
VoicemailInfo.prototype = {
|
|
number: null,
|
|
displayName: null
|
|
};
|
|
|
|
function VoicemailStatus(clientId) {
|
|
this.serviceId = clientId;
|
|
}
|
|
VoicemailStatus.prototype = {
|
|
QueryInterface: XPCOMUtils.generateQI([]),
|
|
classID: VOICEMAILSTATUS_CID,
|
|
contractID: "@mozilla.org/voicemailstatus;1",
|
|
|
|
serviceId: -1,
|
|
hasMessages: false,
|
|
messageCount: -1, // Count unknown.
|
|
returnNumber: null,
|
|
returnMessage: null
|
|
};
|
|
|
|
function CellBroadcastMessage(clientId, pdu) {
|
|
this.serviceId = clientId;
|
|
this.gsmGeographicalScope = RIL.CB_GSM_GEOGRAPHICAL_SCOPE_NAMES[pdu.geographicalScope];
|
|
this.messageCode = pdu.messageCode;
|
|
this.messageId = pdu.messageId;
|
|
this.language = pdu.language;
|
|
this.body = pdu.fullBody;
|
|
this.messageClass = pdu.messageClass;
|
|
this.timestamp = pdu.timestamp;
|
|
|
|
if (pdu.etws != null) {
|
|
this.etws = new CellBroadcastEtwsInfo(pdu.etws);
|
|
}
|
|
|
|
this.cdmaServiceCategory = pdu.serviceCategory;
|
|
}
|
|
CellBroadcastMessage.prototype = {
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozCellBroadcastMessage]),
|
|
classID: CELLBROADCASTMESSAGE_CID,
|
|
classInfo: XPCOMUtils.generateCI({
|
|
classID: CELLBROADCASTMESSAGE_CID,
|
|
classDescription: "CellBroadcastMessage",
|
|
flags: Ci.nsIClassInfo.DOM_OBJECT,
|
|
interfaces: [Ci.nsIDOMMozCellBroadcastMessage]
|
|
}),
|
|
|
|
// nsIDOMMozCellBroadcastMessage
|
|
serviceId: -1,
|
|
|
|
gsmGeographicalScope: null,
|
|
messageCode: null,
|
|
messageId: null,
|
|
language: null,
|
|
body: null,
|
|
messageClass: null,
|
|
timestamp: null,
|
|
|
|
etws: null,
|
|
cdmaServiceCategory: null
|
|
};
|
|
|
|
function CellBroadcastEtwsInfo(etwsInfo) {
|
|
if (etwsInfo.warningType != null) {
|
|
this.warningType = RIL.CB_ETWS_WARNING_TYPE_NAMES[etwsInfo.warningType];
|
|
}
|
|
this.emergencyUserAlert = etwsInfo.emergencyUserAlert;
|
|
this.popup = etwsInfo.popup;
|
|
}
|
|
CellBroadcastEtwsInfo.prototype = {
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozCellBroadcastEtwsInfo]),
|
|
classID: CELLBROADCASTETWSINFO_CID,
|
|
classInfo: XPCOMUtils.generateCI({
|
|
classID: CELLBROADCASTETWSINFO_CID,
|
|
classDescription: "CellBroadcastEtwsInfo",
|
|
flags: Ci.nsIClassInfo.DOM_OBJECT,
|
|
interfaces: [Ci.nsIDOMMozCellBroadcastEtwsInfo]
|
|
}),
|
|
|
|
// nsIDOMMozCellBroadcastEtwsInfo
|
|
|
|
warningType: null,
|
|
emergencyUserAlert: null,
|
|
popup: null
|
|
};
|
|
|
|
function IccCardLockError() {
|
|
}
|
|
IccCardLockError.prototype = {
|
|
classDescription: "IccCardLockError",
|
|
classID: ICCCARDLOCKERROR_CID,
|
|
contractID: "@mozilla.org/dom/icccardlock-error;1",
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
|
|
__init: function(lockType, errorMsg, retryCount) {
|
|
this.__DOM_IMPL__.init(errorMsg);
|
|
this.lockType = lockType;
|
|
this.retryCount = retryCount;
|
|
},
|
|
};
|
|
|
|
function RILContentHelper() {
|
|
this.updateDebugFlag();
|
|
|
|
this.numClients = gNumRadioInterfaces;
|
|
if (DEBUG) debug("Number of clients: " + this.numClients);
|
|
|
|
this.rilContexts = [];
|
|
this.voicemailInfos = [];
|
|
this.voicemailStatuses = [];
|
|
for (let clientId = 0; clientId < this.numClients; clientId++) {
|
|
this.rilContexts[clientId] = {
|
|
cardState: RIL.GECKO_CARDSTATE_UNKNOWN,
|
|
iccInfo: null
|
|
};
|
|
|
|
this.voicemailInfos[clientId] = new VoicemailInfo();
|
|
}
|
|
|
|
this.voicemailDefaultServiceId = this.getVoicemailDefaultServiceId();
|
|
|
|
this.initDOMRequestHelper(/* aWindow */ null, RIL_IPC_MSG_NAMES);
|
|
this._windowsMap = [];
|
|
this._cellBroadcastListeners = [];
|
|
this._voicemailListeners = [];
|
|
this._iccListeners = [];
|
|
|
|
Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
|
|
|
|
Services.prefs.addObserver(kPrefRilDebuggingEnabled, this, false);
|
|
Services.prefs.addObserver(kPrefVoicemailDefaultServiceId, this, false);
|
|
}
|
|
|
|
RILContentHelper.prototype = {
|
|
__proto__: DOMRequestIpcHelper.prototype,
|
|
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsICellBroadcastProvider,
|
|
Ci.nsIVoicemailProvider,
|
|
Ci.nsIIccProvider,
|
|
Ci.nsIObserver,
|
|
Ci.nsISupportsWeakReference]),
|
|
classID: RILCONTENTHELPER_CID,
|
|
classInfo: XPCOMUtils.generateCI({classID: RILCONTENTHELPER_CID,
|
|
classDescription: "RILContentHelper",
|
|
interfaces: [Ci.nsICellBroadcastProvider,
|
|
Ci.nsIVoicemailProvider,
|
|
Ci.nsIIccProvider]}),
|
|
|
|
updateDebugFlag: function() {
|
|
try {
|
|
DEBUG = RIL.DEBUG_CONTENT_HELPER ||
|
|
Services.prefs.getBoolPref(kPrefRilDebuggingEnabled);
|
|
} catch (e) {}
|
|
},
|
|
|
|
// An utility function to copy objects.
|
|
updateInfo: function(srcInfo, destInfo) {
|
|
for (let key in srcInfo) {
|
|
destInfo[key] = srcInfo[key];
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 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(clientId, newInfo) {
|
|
let rilContext = this.rilContexts[clientId];
|
|
|
|
// Card is not detected, clear iccInfo to null.
|
|
if (!newInfo || !newInfo.iccid) {
|
|
if (rilContext.iccInfo) {
|
|
rilContext.iccInfo = null;
|
|
}
|
|
return;
|
|
}
|
|
|
|
// If iccInfo is null, new corresponding object based on iccType.
|
|
if (!rilContext.iccInfo) {
|
|
if (newInfo.iccType === "ruim" || newInfo.iccType === "csim") {
|
|
rilContext.iccInfo = new CdmaIccInfo();
|
|
} else if (newInfo.iccType === "sim" || newInfo.iccType === "usim") {
|
|
rilContext.iccInfo = new GsmIccInfo();
|
|
} else {
|
|
rilContext.iccInfo = new IccInfo();
|
|
}
|
|
}
|
|
let changed = (rilContext.iccInfo.iccid != newInfo.iccid) ?
|
|
true : false;
|
|
|
|
this.updateInfo(newInfo, rilContext.iccInfo);
|
|
},
|
|
|
|
_windowsMap: null,
|
|
|
|
rilContexts: null,
|
|
|
|
getRilContext: function(clientId) {
|
|
// Update ril contexts by sending IPC message to chrome only when the first
|
|
// time we require it. The information will be updated by following info
|
|
// changed messages.
|
|
this.getRilContext = function getRilContext(clientId) {
|
|
return this.rilContexts[clientId];
|
|
};
|
|
|
|
for (let cId = 0; cId < this.numClients; cId++) {
|
|
let rilContext =
|
|
cpmm.sendSyncMessage("RIL:GetRilContext", {clientId: cId})[0];
|
|
if (!rilContext) {
|
|
if (DEBUG) debug("Received null rilContext from chrome process.");
|
|
continue;
|
|
}
|
|
this.rilContexts[cId].cardState = rilContext.cardState;
|
|
this.updateIccInfo(cId, rilContext.iccInfo);
|
|
}
|
|
|
|
return this.rilContexts[clientId];
|
|
},
|
|
|
|
/**
|
|
* nsIIccProvider
|
|
*/
|
|
|
|
getIccInfo: function(clientId) {
|
|
let context = this.getRilContext(clientId);
|
|
return context && context.iccInfo;
|
|
},
|
|
|
|
getCardState: function(clientId) {
|
|
let context = this.getRilContext(clientId);
|
|
return context && context.cardState;
|
|
},
|
|
|
|
matchMvno: function(clientId, window, mvnoType, mvnoData) {
|
|
if (window == null) {
|
|
throw Components.Exception("Can't get window object",
|
|
Cr.NS_ERROR_UNEXPECTED);
|
|
}
|
|
|
|
let request = Services.DOMRequest.createRequest(window);
|
|
let requestId = this.getRequestId(request);
|
|
|
|
cpmm.sendAsyncMessage("RIL:MatchMvno", {
|
|
clientId: clientId,
|
|
data: {
|
|
requestId: requestId,
|
|
mvnoType: mvnoType,
|
|
mvnoData: mvnoData
|
|
}
|
|
});
|
|
return request;
|
|
},
|
|
|
|
getCardLockState: function(clientId, window, lockType) {
|
|
if (window == null) {
|
|
throw Components.Exception("Can't get window object",
|
|
Cr.NS_ERROR_UNEXPECTED);
|
|
}
|
|
let request = Services.DOMRequest.createRequest(window);
|
|
let requestId = this.getRequestId(request);
|
|
this._windowsMap[requestId] = window;
|
|
|
|
cpmm.sendAsyncMessage("RIL:GetCardLockState", {
|
|
clientId: clientId,
|
|
data: {
|
|
lockType: lockType,
|
|
requestId: requestId
|
|
}
|
|
});
|
|
return request;
|
|
},
|
|
|
|
unlockCardLock: function(clientId, window, info) {
|
|
if (window == null) {
|
|
throw Components.Exception("Can't get window object",
|
|
Cr.NS_ERROR_UNEXPECTED);
|
|
}
|
|
let request = Services.DOMRequest.createRequest(window);
|
|
info.requestId = this.getRequestId(request);
|
|
this._windowsMap[info.requestId] = window;
|
|
|
|
cpmm.sendAsyncMessage("RIL:UnlockCardLock", {
|
|
clientId: clientId,
|
|
data: info
|
|
});
|
|
return request;
|
|
},
|
|
|
|
setCardLock: function(clientId, window, info) {
|
|
if (window == null) {
|
|
throw Components.Exception("Can't get window object",
|
|
Cr.NS_ERROR_UNEXPECTED);
|
|
}
|
|
let request = Services.DOMRequest.createRequest(window);
|
|
info.requestId = this.getRequestId(request);
|
|
this._windowsMap[info.requestId] = window;
|
|
|
|
cpmm.sendAsyncMessage("RIL:SetCardLock", {
|
|
clientId: clientId,
|
|
data: info
|
|
});
|
|
return request;
|
|
},
|
|
|
|
getCardLockRetryCount: function(clientId, window, lockType) {
|
|
if (window == null) {
|
|
throw Components.Exception("Can't get window object",
|
|
Cr.NS_ERROR_UNEXPECTED);
|
|
}
|
|
let request = Services.DOMRequest.createRequest(window);
|
|
let requestId = this.getRequestId(request);
|
|
cpmm.sendAsyncMessage("RIL:GetCardLockRetryCount", {
|
|
clientId: clientId,
|
|
data: {
|
|
lockType: lockType,
|
|
requestId: requestId
|
|
}
|
|
});
|
|
return request;
|
|
},
|
|
|
|
sendStkResponse: function(clientId, window, command, response) {
|
|
if (window == null) {
|
|
throw Components.Exception("Can't get window object",
|
|
Cr.NS_ERROR_UNEXPECTED);
|
|
}
|
|
response.command = command;
|
|
cpmm.sendAsyncMessage("RIL:SendStkResponse", {
|
|
clientId: clientId,
|
|
data: response
|
|
});
|
|
},
|
|
|
|
sendStkMenuSelection: function(clientId, window, itemIdentifier,
|
|
helpRequested) {
|
|
if (window == null) {
|
|
throw Components.Exception("Can't get window object",
|
|
Cr.NS_ERROR_UNEXPECTED);
|
|
}
|
|
cpmm.sendAsyncMessage("RIL:SendStkMenuSelection", {
|
|
clientId: clientId,
|
|
data: {
|
|
itemIdentifier: itemIdentifier,
|
|
helpRequested: helpRequested
|
|
}
|
|
});
|
|
},
|
|
|
|
sendStkTimerExpiration: function(clientId, window, timer) {
|
|
if (window == null) {
|
|
throw Components.Exception("Can't get window object",
|
|
Cr.NS_ERROR_UNEXPECTED);
|
|
}
|
|
cpmm.sendAsyncMessage("RIL:SendStkTimerExpiration", {
|
|
clientId: clientId,
|
|
data: {
|
|
timer: timer
|
|
}
|
|
});
|
|
},
|
|
|
|
sendStkEventDownload: function(clientId, window, event) {
|
|
if (window == null) {
|
|
throw Components.Exception("Can't get window object",
|
|
Cr.NS_ERROR_UNEXPECTED);
|
|
}
|
|
cpmm.sendAsyncMessage("RIL:SendStkEventDownload", {
|
|
clientId: clientId,
|
|
data: {
|
|
event: event
|
|
}
|
|
});
|
|
},
|
|
|
|
iccOpenChannel: function(clientId, window, aid) {
|
|
if (window == null) {
|
|
throw Components.Exception("Can't get window object",
|
|
Cr.NS_ERROR_UNEXPECTED);
|
|
}
|
|
|
|
let request = Services.DOMRequest.createRequest(window);
|
|
let requestId = this.getRequestId(request);
|
|
|
|
cpmm.sendAsyncMessage("RIL:IccOpenChannel", {
|
|
clientId: clientId,
|
|
data: {
|
|
requestId: requestId,
|
|
aid: aid
|
|
}
|
|
});
|
|
return request;
|
|
},
|
|
|
|
iccExchangeAPDU: function(clientId, window, channel, apdu) {
|
|
if (window == null) {
|
|
throw Components.Exception("Can't get window object",
|
|
Cr.NS_ERROR_UNEXPECTED);
|
|
}
|
|
|
|
let request = Services.DOMRequest.createRequest(window);
|
|
let requestId = this.getRequestId(request);
|
|
|
|
//Potentially you need serialization here and can't pass the jsval through
|
|
cpmm.sendAsyncMessage("RIL:IccExchangeAPDU", {
|
|
clientId: clientId,
|
|
data: {
|
|
requestId: requestId,
|
|
channel: channel,
|
|
apdu: apdu
|
|
}
|
|
});
|
|
return request;
|
|
},
|
|
|
|
iccCloseChannel: function(clientId, window, channel) {
|
|
if (window == null) {
|
|
throw Components.Exception("Can't get window object",
|
|
Cr.NS_ERROR_UNEXPECTED);
|
|
}
|
|
|
|
let request = Services.DOMRequest.createRequest(window);
|
|
let requestId = this.getRequestId(request);
|
|
|
|
cpmm.sendAsyncMessage("RIL:IccCloseChannel", {
|
|
clientId: clientId,
|
|
data: {
|
|
requestId: requestId,
|
|
channel: channel
|
|
}
|
|
});
|
|
return request;
|
|
},
|
|
|
|
readContacts: function(clientId, window, contactType) {
|
|
if (window == null) {
|
|
throw Components.Exception("Can't get window object",
|
|
Cr.NS_ERROR_UNEXPECTED);
|
|
}
|
|
|
|
let request = Services.DOMRequest.createRequest(window);
|
|
let requestId = this.getRequestId(request);
|
|
this._windowsMap[requestId] = window;
|
|
|
|
cpmm.sendAsyncMessage("RIL:ReadIccContacts", {
|
|
clientId: clientId,
|
|
data: {
|
|
requestId: requestId,
|
|
contactType: contactType
|
|
}
|
|
});
|
|
return request;
|
|
},
|
|
|
|
updateContact: function(clientId, window, contactType, contact, pin2) {
|
|
if (window == null) {
|
|
throw Components.Exception("Can't get window object",
|
|
Cr.NS_ERROR_UNEXPECTED);
|
|
}
|
|
|
|
let request = Services.DOMRequest.createRequest(window);
|
|
let requestId = this.getRequestId(request);
|
|
this._windowsMap[requestId] = window;
|
|
|
|
// Parsing nsDOMContact to Icc Contact format
|
|
let iccContact = {};
|
|
|
|
if (Array.isArray(contact.name) && contact.name[0]) {
|
|
iccContact.alphaId = contact.name[0];
|
|
}
|
|
|
|
if (Array.isArray(contact.tel)) {
|
|
iccContact.number = contact.tel[0] && contact.tel[0].value;
|
|
let telArray = contact.tel.slice(1);
|
|
let length = telArray.length;
|
|
if (length > 0) {
|
|
iccContact.anr = [];
|
|
}
|
|
for (let i = 0; i < telArray.length; i++) {
|
|
iccContact.anr.push(telArray[i].value);
|
|
}
|
|
}
|
|
|
|
if (Array.isArray(contact.email) && contact.email[0]) {
|
|
iccContact.email = contact.email[0].value;
|
|
}
|
|
|
|
iccContact.contactId = contact.id;
|
|
|
|
cpmm.sendAsyncMessage("RIL:UpdateIccContact", {
|
|
clientId: clientId,
|
|
data: {
|
|
requestId: requestId,
|
|
contactType: contactType,
|
|
contact: iccContact,
|
|
pin2: pin2
|
|
}
|
|
});
|
|
|
|
return request;
|
|
},
|
|
|
|
_cellBroadcastListeners: null,
|
|
_voicemailListeners: null,
|
|
_iccListeners: null,
|
|
|
|
voicemailInfos: null,
|
|
voicemailStatuses: null,
|
|
|
|
voicemailDefaultServiceId: 0,
|
|
getVoicemailDefaultServiceId: function() {
|
|
let id = Services.prefs.getIntPref(kPrefVoicemailDefaultServiceId);
|
|
|
|
if (id >= gNumRadioInterfaces || id < 0) {
|
|
id = 0;
|
|
}
|
|
|
|
return id;
|
|
},
|
|
|
|
getVoicemailInfo: function(clientId) {
|
|
// Get voicemail infomation by IPC only on first time.
|
|
this.getVoicemailInfo = function getVoicemailInfo(clientId) {
|
|
return this.voicemailInfos[clientId];
|
|
};
|
|
|
|
for (let cId = 0; cId < gNumRadioInterfaces; cId++) {
|
|
let voicemailInfo =
|
|
cpmm.sendSyncMessage("RIL:GetVoicemailInfo", {clientId: cId})[0];
|
|
if (voicemailInfo) {
|
|
this.updateInfo(voicemailInfo, this.voicemailInfos[cId]);
|
|
}
|
|
}
|
|
|
|
return this.voicemailInfos[clientId];
|
|
},
|
|
|
|
getVoicemailNumber: function(clientId) {
|
|
return this.getVoicemailInfo(clientId).number;
|
|
},
|
|
|
|
getVoicemailDisplayName: function(clientId) {
|
|
return this.getVoicemailInfo(clientId).displayName;
|
|
},
|
|
|
|
getVoicemailStatus: function(clientId) {
|
|
return this.voicemailStatuses[clientId];
|
|
},
|
|
|
|
registerListener: function(listenerType, clientId, listener) {
|
|
if (!this[listenerType]) {
|
|
return;
|
|
}
|
|
let listeners = this[listenerType][clientId];
|
|
if (!listeners) {
|
|
listeners = this[listenerType][clientId] = [];
|
|
}
|
|
|
|
if (listeners.indexOf(listener) != -1) {
|
|
throw new Error("Already registered this listener!");
|
|
}
|
|
|
|
listeners.push(listener);
|
|
if (DEBUG) debug("Registered " + listenerType + " listener: " + listener);
|
|
},
|
|
|
|
unregisterListener: function(listenerType, clientId, listener) {
|
|
if (!this[listenerType]) {
|
|
return;
|
|
}
|
|
let listeners = this[listenerType][clientId];
|
|
if (!listeners) {
|
|
return;
|
|
}
|
|
|
|
let index = listeners.indexOf(listener);
|
|
if (index != -1) {
|
|
listeners.splice(index, 1);
|
|
if (DEBUG) debug("Unregistered listener: " + listener);
|
|
}
|
|
},
|
|
|
|
registerVoicemailMsg: function(listener) {
|
|
if (DEBUG) debug("Registering for voicemail-related messages");
|
|
// To follow the listener registration scheme, we add a dummy clientId 0.
|
|
// All voicemail events are routed to listener for client id 0.
|
|
// See |handleVoicemailNotification|.
|
|
this.registerListener("_voicemailListeners", 0, listener);
|
|
cpmm.sendAsyncMessage("RIL:RegisterVoicemailMsg");
|
|
},
|
|
|
|
unregisterVoicemailMsg: function(listener) {
|
|
// To follow the listener unregistration scheme, we add a dummy clientId 0.
|
|
// All voicemail events are routed to listener for client id 0.
|
|
// See |handleVoicemailNotification|.
|
|
this.unregisterListener("_voicemailListeners", 0, listener);
|
|
},
|
|
|
|
registerCellBroadcastMsg: function(listener) {
|
|
if (DEBUG) debug("Registering for Cell Broadcast related messages");
|
|
// Instead of registering multiple listeners for Multi-SIM, we reuse
|
|
// clientId 0 to route all CBS messages to single listener and provide the
|
|
// |clientId| info by |CellBroadcastMessage.serviceId|.
|
|
this.registerListener("_cellBroadcastListeners", 0, listener);
|
|
cpmm.sendAsyncMessage("RIL:RegisterCellBroadcastMsg");
|
|
},
|
|
|
|
unregisterCellBroadcastMsg: function(listener) {
|
|
// Instead of unregistering multiple listeners for Multi-SIM, we reuse
|
|
// clientId 0 to route all CBS messages to single listener and provide the
|
|
// |clientId| info by |CellBroadcastMessage.serviceId|.
|
|
this.unregisterListener("_cellBroadcastListeners", 0, listener);
|
|
},
|
|
|
|
registerIccMsg: function(clientId, listener) {
|
|
if (DEBUG) debug("Registering for ICC related messages");
|
|
this.registerListener("_iccListeners", clientId, listener);
|
|
cpmm.sendAsyncMessage("RIL:RegisterIccMsg");
|
|
},
|
|
|
|
unregisterIccMsg: function(clientId, listener) {
|
|
this.unregisterListener("_iccListeners", clientId, listener);
|
|
},
|
|
|
|
// nsIObserver
|
|
|
|
observe: function(subject, topic, data) {
|
|
switch (topic) {
|
|
case NS_PREFBRANCH_PREFCHANGE_TOPIC_ID:
|
|
if (data == kPrefRilDebuggingEnabled) {
|
|
this.updateDebugFlag();
|
|
} else if (data == kPrefVoicemailDefaultServiceId) {
|
|
this.voicemailDefaultServiceId = this.getVoicemailDefaultServiceId();
|
|
}
|
|
break;
|
|
|
|
case NS_XPCOM_SHUTDOWN_OBSERVER_ID:
|
|
this.destroyDOMRequestHelper();
|
|
Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
|
|
break;
|
|
}
|
|
},
|
|
|
|
// nsIMessageListener
|
|
|
|
fireRequestSuccess: function(requestId, result) {
|
|
let request = this.takeRequest(requestId);
|
|
if (!request) {
|
|
if (DEBUG) {
|
|
debug("not firing success for id: " + requestId +
|
|
", result: " + JSON.stringify(result));
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (DEBUG) {
|
|
debug("fire request success, id: " + requestId +
|
|
", result: " + JSON.stringify(result));
|
|
}
|
|
Services.DOMRequest.fireSuccess(request, result);
|
|
},
|
|
|
|
dispatchFireRequestSuccess: function(requestId, result) {
|
|
let currentThread = Services.tm.currentThread;
|
|
|
|
currentThread.dispatch(this.fireRequestSuccess.bind(this, requestId, result),
|
|
Ci.nsIThread.DISPATCH_NORMAL);
|
|
},
|
|
|
|
fireRequestError: function(requestId, error) {
|
|
let request = this.takeRequest(requestId);
|
|
if (!request) {
|
|
if (DEBUG) {
|
|
debug("not firing error for id: " + requestId +
|
|
", error: " + JSON.stringify(error));
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (DEBUG) {
|
|
debug("fire request error, id: " + requestId +
|
|
", result: " + JSON.stringify(error));
|
|
}
|
|
Services.DOMRequest.fireError(request, error);
|
|
},
|
|
|
|
dispatchFireRequestError: function(requestId, error) {
|
|
let currentThread = Services.tm.currentThread;
|
|
|
|
currentThread.dispatch(this.fireRequestError.bind(this, requestId, error),
|
|
Ci.nsIThread.DISPATCH_NORMAL);
|
|
},
|
|
|
|
fireRequestDetailedError: function(requestId, detailedError) {
|
|
let request = this.takeRequest(requestId);
|
|
if (!request) {
|
|
if (DEBUG) {
|
|
debug("not firing detailed error for id: " + requestId +
|
|
", detailedError: " + JSON.stringify(detailedError));
|
|
}
|
|
return;
|
|
}
|
|
|
|
Services.DOMRequest.fireDetailedError(request, detailedError);
|
|
},
|
|
|
|
receiveMessage: function(msg) {
|
|
let request;
|
|
if (DEBUG) {
|
|
debug("Received message '" + msg.name + "': " + JSON.stringify(msg.json));
|
|
}
|
|
|
|
let data = msg.json.data;
|
|
let clientId = msg.json.clientId;
|
|
switch (msg.name) {
|
|
case "RIL:CardStateChanged":
|
|
if (this.rilContexts[clientId].cardState != data.cardState) {
|
|
this.rilContexts[clientId].cardState = data.cardState;
|
|
this._deliverEvent(clientId,
|
|
"_iccListeners",
|
|
"notifyCardStateChanged",
|
|
null);
|
|
}
|
|
break;
|
|
case "RIL:IccInfoChanged":
|
|
this.updateIccInfo(clientId, data);
|
|
this._deliverEvent(clientId,
|
|
"_iccListeners",
|
|
"notifyIccInfoChanged",
|
|
null);
|
|
break;
|
|
case "RIL:VoicemailNotification":
|
|
this.handleVoicemailNotification(clientId, data);
|
|
break;
|
|
case "RIL:VoicemailInfoChanged":
|
|
this.updateInfo(data, this.voicemailInfos[clientId]);
|
|
break;
|
|
case "RIL:CardLockResult": {
|
|
let requestId = data.requestId;
|
|
let requestWindow = this._windowsMap[requestId];
|
|
delete this._windowsMap[requestId];
|
|
|
|
if (data.success) {
|
|
let result = new MobileIccCardLockResult(data);
|
|
this.fireRequestSuccess(requestId, result);
|
|
} else {
|
|
if (data.rilMessageType == "iccSetCardLock" ||
|
|
data.rilMessageType == "iccUnlockCardLock") {
|
|
let cardLockError = new requestWindow.IccCardLockError(data.lockType,
|
|
data.errorMsg,
|
|
data.retryCount);
|
|
this.fireRequestDetailedError(requestId, cardLockError);
|
|
} else {
|
|
this.fireRequestError(requestId, data.errorMsg);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case "RIL:CardLockRetryCount":
|
|
if (data.success) {
|
|
let result = new MobileIccCardLockRetryCount(data);
|
|
this.fireRequestSuccess(data.requestId, result);
|
|
} else {
|
|
this.fireRequestError(data.requestId, data.errorMsg);
|
|
}
|
|
break;
|
|
case "RIL:StkCommand":
|
|
this._deliverEvent(clientId, "_iccListeners", "notifyStkCommand",
|
|
[JSON.stringify(data)]);
|
|
break;
|
|
case "RIL:StkSessionEnd":
|
|
this._deliverEvent(clientId, "_iccListeners", "notifyStkSessionEnd", null);
|
|
break;
|
|
case "RIL:IccOpenChannel":
|
|
this.handleSimpleRequest(data.requestId, data.errorMsg,
|
|
data.channel);
|
|
break;
|
|
case "RIL:IccCloseChannel":
|
|
this.handleSimpleRequest(data.requestId, data.errorMsg, null);
|
|
break;
|
|
case "RIL:IccExchangeAPDU":
|
|
this.handleIccExchangeAPDU(data);
|
|
break;
|
|
case "RIL:ReadIccContacts":
|
|
this.handleReadIccContacts(data);
|
|
break;
|
|
case "RIL:UpdateIccContact":
|
|
this.handleUpdateIccContact(data);
|
|
break;
|
|
case "RIL:MatchMvno":
|
|
this.handleSimpleRequest(data.requestId, data.errorMsg, data.result);
|
|
break;
|
|
case "RIL:CellBroadcastReceived": {
|
|
// All CBS messages are to routed the listener for clientId 0 and
|
|
// provide the |clientId| info by |CellBroadcastMessage.serviceId|.
|
|
let message = new CellBroadcastMessage(clientId, data);
|
|
this._deliverEvent(0, // route to clientId 0.
|
|
"_cellBroadcastListeners",
|
|
"notifyMessageReceived",
|
|
[message]);
|
|
break;
|
|
}
|
|
}
|
|
},
|
|
|
|
handleSimpleRequest: function(requestId, errorMsg, result) {
|
|
if (errorMsg) {
|
|
this.fireRequestError(requestId, errorMsg);
|
|
} else {
|
|
this.fireRequestSuccess(requestId, result);
|
|
}
|
|
},
|
|
|
|
handleIccExchangeAPDU: function(message) {
|
|
if (message.errorMsg) {
|
|
this.fireRequestError(message.requestId, message.errorMsg);
|
|
} else {
|
|
var result = [message.sw1, message.sw2, message.simResponse];
|
|
this.fireRequestSuccess(message.requestId, result);
|
|
}
|
|
},
|
|
|
|
handleReadIccContacts: function(message) {
|
|
if (message.errorMsg) {
|
|
this.fireRequestError(message.requestId, message.errorMsg);
|
|
return;
|
|
}
|
|
|
|
let window = this._windowsMap[message.requestId];
|
|
delete this._windowsMap[message.requestId];
|
|
let contacts = message.contacts;
|
|
let result = contacts.map(function(c) {
|
|
let prop = {name: [c.alphaId], tel: [{value: c.number}]};
|
|
|
|
if (c.email) {
|
|
prop.email = [{value: c.email}];
|
|
}
|
|
|
|
// ANR - Additional Number
|
|
let anrLen = c.anr ? c.anr.length : 0;
|
|
for (let i = 0; i < anrLen; i++) {
|
|
prop.tel.push({value: c.anr[i]});
|
|
}
|
|
|
|
let contact = new window.mozContact(prop);
|
|
contact.id = c.contactId;
|
|
return contact;
|
|
});
|
|
|
|
this.fireRequestSuccess(message.requestId, result);
|
|
},
|
|
|
|
handleUpdateIccContact: function(message) {
|
|
if (message.errorMsg) {
|
|
this.fireRequestError(message.requestId, message.errorMsg);
|
|
return;
|
|
}
|
|
|
|
let window = this._windowsMap[message.requestId];
|
|
delete this._windowsMap[message.requestId];
|
|
let iccContact = message.contact;
|
|
let prop = {name: [iccContact.alphaId], tel: [{value: iccContact.number}]};
|
|
if (iccContact.email) {
|
|
prop.email = [{value: iccContact.email}];
|
|
}
|
|
|
|
// ANR - Additional Number
|
|
let anrLen = iccContact.anr ? iccContact.anr.length : 0;
|
|
for (let i = 0; i < anrLen; i++) {
|
|
prop.tel.push({value: iccContact.anr[i]});
|
|
}
|
|
|
|
let contact = new window.mozContact(prop);
|
|
contact.id = iccContact.contactId;
|
|
|
|
this.fireRequestSuccess(message.requestId, contact);
|
|
},
|
|
|
|
handleVoicemailNotification: function(clientId, message) {
|
|
let changed = false;
|
|
if (!this.voicemailStatuses[clientId]) {
|
|
this.voicemailStatuses[clientId] = new VoicemailStatus(clientId);
|
|
}
|
|
|
|
let voicemailStatus = this.voicemailStatuses[clientId];
|
|
if (voicemailStatus.hasMessages != message.active) {
|
|
changed = true;
|
|
voicemailStatus.hasMessages = message.active;
|
|
}
|
|
|
|
if (voicemailStatus.messageCount != message.msgCount) {
|
|
changed = true;
|
|
voicemailStatus.messageCount = message.msgCount;
|
|
} else if (message.msgCount == -1) {
|
|
// For MWI using DCS the message count is not available
|
|
changed = true;
|
|
}
|
|
|
|
if (voicemailStatus.returnNumber != message.returnNumber) {
|
|
changed = true;
|
|
voicemailStatus.returnNumber = message.returnNumber;
|
|
}
|
|
|
|
if (voicemailStatus.returnMessage != message.returnMessage) {
|
|
changed = true;
|
|
voicemailStatus.returnMessage = message.returnMessage;
|
|
}
|
|
|
|
if (changed) {
|
|
// To follow the event delivering scheme, we add a dummy clientId 0.
|
|
// All voicemail events are routed to listener for client id 0.
|
|
this._deliverEvent(0,
|
|
"_voicemailListeners",
|
|
"notifyStatusChanged",
|
|
[voicemailStatus]);
|
|
}
|
|
},
|
|
|
|
_deliverEvent: function(clientId, listenerType, name, args) {
|
|
if (!this[listenerType]) {
|
|
return;
|
|
}
|
|
let thisListeners = this[listenerType][clientId];
|
|
if (!thisListeners) {
|
|
return;
|
|
}
|
|
|
|
let listeners = thisListeners.slice();
|
|
for (let listener of listeners) {
|
|
if (thisListeners.indexOf(listener) == -1) {
|
|
continue;
|
|
}
|
|
let handler = listener[name];
|
|
if (typeof handler != "function") {
|
|
throw new Error("No handler for " + name);
|
|
}
|
|
try {
|
|
handler.apply(listener, args);
|
|
} catch (e) {
|
|
if (DEBUG) debug("listener for " + name + " threw an exception: " + e);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([RILContentHelper,
|
|
IccCardLockError]);
|