mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:30:27 +00:00
import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1140330 - Clear JSHint warning in RILContentHelper.js. r=hsinyi (e9d488f8f) - Bug 1155142 - Part 1: Move All IccInfo-related Implementation to IccService to deprecate rilContext. r=echen (79c4edb86) - Bug 1155142 - Part 2: Refactor RIL-related Modules. r=kchen (f98c9e4e6) - Bug 1155142 - Part 3: Refactor MobileIdentityManager. r=ferjm (530b9a25e) - Bug 1114901 - Part 1: introduce nsI(Gonk)DataCallInterfaceService and nsIDataCallManager. r=hsinyi,echen (4f941a2ba) - Bug 1114901 - Part 2: (Gonk)DataCallInterfaceService implementation. r=echen (a7b965106) - Bug 1044721 - Part 1: Add setSmscAddress API in MozMobileMessageManager Web IDL interface, and corresponding implementation in MobileMessageManager class. r=hsinyi (d75e7d34d) - Bug 1044721 - Part 2: Update nsIMobileMessageCallback interface and implementation to support Promise and setSmscAddress. r=btseng (7bdae2eb7) - Bug 1069186 - determine LTE signal level based on rsrp and rssnr. r=edgar (25c7ad339) - Bug 1146799 - B2G RIL: Pull out the TelephonyRequestQueue from RilWorker. r=aknow (ed758026a) - Bug 1130292 - Allow to receive WAP Push in which reserved port numbers is used. r=echen (71a163e0a) - Bug 1139835 - Parse response parcel of OPEN_CHANNEL as int list. r=hsinyi (416cd7c43) - Bug 1137088: B2G RIL: move data call related handling out of ril_worker. r=echen (221e01130) - Bug 1027546 - Part 1: Restore the service class (ril_worker.js). r=aknow (5e0a9a4ae) - Bug 1137093 - Part 01: Pass number instead of callIndex in notifySupplementaryService. r=hsinyi (f60cce375) - Bug 1137093 - Part 02: Move from ril_worker to TelephonyService: hangup and reject. r=hsinyi (4f626592b) - Bug 1137093 - Part 03: Move from ril_worker to TelephonyService: answer. r=hsinyi (046035101) - Bug 1137093 - Part 04: Refactor _switchActiveCall. r=hsinyi (1da5886cb) - Bug 1137093 - Part 05: Refactor _dialInCallMMI. r=hsinyi (f204a859c) - Bug 1135268 - Part 1: Fix incall MMI issue. r=hsinyi (eec6f1d95) - Bug 1135268 - Part 2: Test case. r=hsinyi (8dba4dd16) - Bug 1137093 - Part 06: Refactor _isActive. r=hsinyi (bc469dffd) - Bug 1137093 - Part 07: Use notifyCurrentCalls (idl). r=hsinyi (31d97ca81) - Bug 1137093 - Part 08: Use notifyCurrentCalls (ril). r=hsinyi (120365c8a) - Bug 1137093 - Part 09: Modify test case. r=hsinyi (6234e9069)
This commit is contained in:
@@ -493,6 +493,8 @@
|
||||
@RESPATH@/components/MobileMessageDatabaseService.js
|
||||
@RESPATH@/components/MobileMessageDatabaseService.manifest
|
||||
#ifndef DISABLE_MOZ_RIL_GEOLOC
|
||||
@RESPATH@/components/DataCallInterfaceService.js
|
||||
@RESPATH@/components/DataCallInterfaceService.manifest
|
||||
@RESPATH@/components/MobileConnectionService.js
|
||||
@RESPATH@/components/MobileConnectionService.manifest
|
||||
@RESPATH@/components/RadioInterfaceLayer.js
|
||||
|
||||
+1
-10
@@ -15,9 +15,6 @@
|
||||
// Service instantiation
|
||||
#include "ipc/IccIPCService.h"
|
||||
#if defined(MOZ_WIDGET_GONK) && defined(MOZ_B2G_RIL)
|
||||
// TODO: Bug 815526, deprecate RILContentHelper.
|
||||
#include "nsIRadioInterfaceLayer.h"
|
||||
#include "nsRadioInterfaceLayer.h"
|
||||
#include "nsIGonkIccService.h"
|
||||
#endif
|
||||
#include "nsXULAppAPI.h" // For XRE_GetProcessType()
|
||||
@@ -150,13 +147,7 @@ NS_CreateIccService()
|
||||
service = new mozilla::dom::icc::IccIPCService();
|
||||
#if defined(MOZ_WIDGET_GONK) && defined(MOZ_B2G_RIL)
|
||||
} else {
|
||||
// TODO: Bug 815526, deprecate RILContentHelper.
|
||||
nsCOMPtr <nsIRadioInterfaceLayer> ril =
|
||||
do_GetService(NS_RADIOINTERFACELAYER_CONTRACTID);
|
||||
nsCOMPtr <nsIRadioInterfaceLayer_new> ril_new(do_QueryInterface(ril));
|
||||
|
||||
service = (ril_new) ? do_GetService(GONK_ICC_SERVICE_CONTRACTID)
|
||||
: do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
|
||||
service = do_GetService(GONK_ICC_SERVICE_CONTRACTID);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "gRadioInterfaceLayer",
|
||||
"@mozilla.org/ril;1",
|
||||
"nsIRadioInterfaceLayer");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gMobileConnectionService",
|
||||
"@mozilla.org/mobileconnection/mobileconnectionservice;1",
|
||||
"nsIGonkMobileConnectionService");
|
||||
|
||||
let DEBUG = RIL.DEBUG_RIL;
|
||||
function debug(s) {
|
||||
dump("IccService: " + s);
|
||||
@@ -73,7 +77,7 @@ function IccService() {
|
||||
|
||||
let numClients = gRadioInterfaceLayer.numRadioInterfaces;
|
||||
for (let i = 0; i < numClients; i++) {
|
||||
this._iccs.push(new Icc(gRadioInterfaceLayer.getRadioInterface(i)));
|
||||
this._iccs.push(new Icc(i));
|
||||
}
|
||||
|
||||
this._updateDebugFlag();
|
||||
@@ -145,7 +149,7 @@ IccService.prototype = {
|
||||
}
|
||||
|
||||
let icc = this.getIccByServiceId(aServiceId);
|
||||
icc._imsi = aImsi;
|
||||
icc.imsi = aImsi || null;
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -166,15 +170,16 @@ IccService.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
function Icc(aRadioInterface) {
|
||||
this._radioInterface = aRadioInterface;
|
||||
function Icc(aClientId) {
|
||||
this._clientId = aClientId;
|
||||
this._radioInterface = gRadioInterfaceLayer.getRadioInterface(aClientId);
|
||||
this._listeners = [];
|
||||
}
|
||||
Icc.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIIcc]),
|
||||
|
||||
_clientId: 0,
|
||||
_radioInterface: null,
|
||||
_imsi: null,
|
||||
_listeners: null,
|
||||
|
||||
_updateCardState: function(aCardState) {
|
||||
@@ -192,24 +197,52 @@ Icc.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
@@ -233,6 +266,23 @@ Icc.prototype = {
|
||||
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) {
|
||||
@@ -305,6 +355,7 @@ Icc.prototype = {
|
||||
*/
|
||||
iccInfo: null,
|
||||
cardState: Ci.nsIIcc.CARD_STATE_UNKNOWN,
|
||||
imsi: null,
|
||||
|
||||
registerListener: function(aListener) {
|
||||
if (this._listeners.indexOf(aListener) >= 0) {
|
||||
@@ -379,7 +430,7 @@ Icc.prototype = {
|
||||
|
||||
switch (aMvnoType) {
|
||||
case Ci.nsIIcc.CARD_MVNO_TYPE_IMSI:
|
||||
let imsi = this._imsi;
|
||||
let imsi = this.imsi;
|
||||
if (!imsi) {
|
||||
aCallback.notifyError(RIL.GECKO_ERROR_GENERIC_FAILURE);
|
||||
break;
|
||||
|
||||
@@ -97,7 +97,7 @@ NS_CreateIccService();
|
||||
/**
|
||||
* XPCOM component that provides the access to the selected ICC.
|
||||
*/
|
||||
[scriptable, uuid(38a5bbe2-add6-11e4-ba9e-e390d1d19195)]
|
||||
[scriptable, uuid(20a99186-e4cb-11e4-a5f9-938abcf7c826)]
|
||||
interface nsIIcc : nsISupports
|
||||
{
|
||||
/**
|
||||
@@ -214,6 +214,11 @@ interface nsIIcc : nsISupports
|
||||
*/
|
||||
readonly attribute unsigned long cardState;
|
||||
|
||||
/**
|
||||
* IMSI of this ICC.
|
||||
*/
|
||||
readonly attribute DOMString imsi;
|
||||
|
||||
/**
|
||||
* Get the status of an ICC lock (e.g. the PIN lock).
|
||||
*
|
||||
|
||||
@@ -184,6 +184,13 @@ IccChild::GetCardState(uint32_t* aCardState)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
IccChild::GetImsi(nsAString & aImsi)
|
||||
{
|
||||
NS_WARNING("IMSI shall not directly be fetched in child process.");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
IccChild::GetCardLockEnabled(uint32_t aLockType,
|
||||
nsIIccCallback* aRequestReply)
|
||||
|
||||
@@ -56,6 +56,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager",
|
||||
"@mozilla.org/network/manager;1",
|
||||
"nsINetworkManager");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gIccService",
|
||||
"@mozilla.org/icc/iccservice;1",
|
||||
"nsIIccService");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gRadioInterfaceLayer", function() {
|
||||
let ril = { numRadioInterfaces: 0 };
|
||||
try {
|
||||
@@ -387,9 +391,8 @@ MobileConnectionProvider.prototype = {
|
||||
* really the case. See bug 787967
|
||||
*/
|
||||
_checkRoamingBetweenOperators: function(aNetworkInfo) {
|
||||
// TODO: Bug 864489 - B2G RIL: use ipdl as IPC in MozIccManager
|
||||
// Should get iccInfo from GonkIccProvider.
|
||||
let iccInfo = this._radioInterface.rilContext.iccInfo;
|
||||
let icc = gIccService.getIccByServiceId(this._clientId);
|
||||
let iccInfo = icc ? icc.iccInfo : null;
|
||||
let operator = aNetworkInfo.network;
|
||||
let state = aNetworkInfo.state;
|
||||
|
||||
|
||||
@@ -20,18 +20,6 @@ const TEST_DATA = [
|
||||
relSignalStrength: null
|
||||
}
|
||||
},
|
||||
// Valid rxlev with max value.
|
||||
{
|
||||
input: {
|
||||
rxlev: 63,
|
||||
rsrp: 65535,
|
||||
rssnr: 65535
|
||||
},
|
||||
expect: {
|
||||
signalStrength: -48,
|
||||
relSignalStrength: 100
|
||||
}
|
||||
},
|
||||
// Valid rxlev.
|
||||
{
|
||||
input: {
|
||||
@@ -40,7 +28,7 @@ const TEST_DATA = [
|
||||
rssnr: 65535
|
||||
},
|
||||
expect: {
|
||||
signalStrength: -99,
|
||||
signalStrength: null,
|
||||
relSignalStrength: 100
|
||||
}
|
||||
},
|
||||
@@ -52,9 +40,57 @@ const TEST_DATA = [
|
||||
rssnr: 65535
|
||||
},
|
||||
expect: {
|
||||
signalStrength: -111,
|
||||
signalStrength: null,
|
||||
relSignalStrength: 0
|
||||
}
|
||||
},
|
||||
// Valid rxlev with max value.
|
||||
{
|
||||
input: {
|
||||
rxlev: 63,
|
||||
rsrp: 65535,
|
||||
rssnr: 65535
|
||||
},
|
||||
expect: {
|
||||
signalStrength: null,
|
||||
relSignalStrength: 100
|
||||
}
|
||||
},
|
||||
// Valid rsrp.
|
||||
{
|
||||
input: {
|
||||
rxlev: 31,
|
||||
rsrp: 50,
|
||||
rssnr: 65535
|
||||
},
|
||||
expect: {
|
||||
signalStrength: 50,
|
||||
relSignalStrength: 100
|
||||
}
|
||||
},
|
||||
// Valid rssnr.
|
||||
{
|
||||
input: {
|
||||
rxlev: 31,
|
||||
rsrp: 65535,
|
||||
rssnr: 100
|
||||
},
|
||||
expect: {
|
||||
signalStrength: null,
|
||||
relSignalStrength: 81
|
||||
}
|
||||
},
|
||||
// Valid rsrp and rssnr.
|
||||
{
|
||||
input: {
|
||||
rxlev: 31,
|
||||
rsrp: 100,
|
||||
rssnr: 30
|
||||
},
|
||||
expect: {
|
||||
signalStrength: 100,
|
||||
relSignalStrength: 37
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsTArrayHelpers.h"
|
||||
#include "DOMMobileMessageError.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@@ -81,6 +82,11 @@ MobileMessageCallback::MobileMessageCallback(DOMRequest* aDOMRequest)
|
||||
{
|
||||
}
|
||||
|
||||
MobileMessageCallback::MobileMessageCallback(Promise* aPromise)
|
||||
: mPromise(aPromise)
|
||||
{
|
||||
}
|
||||
|
||||
MobileMessageCallback::~MobileMessageCallback()
|
||||
{
|
||||
}
|
||||
@@ -281,6 +287,21 @@ MobileMessageCallback::NotifyGetSmscAddressFailed(int32_t aError)
|
||||
return NotifyError(aError);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MobileMessageCallback::NotifySetSmscAddress()
|
||||
{
|
||||
mPromise->MaybeResolve(JS::UndefinedHandleValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MobileMessageCallback::NotifySetSmscAddressFailed(int32_t aError)
|
||||
{
|
||||
const nsAString& errorStr = ConvertErrorCodeToErrorString(aError);
|
||||
mPromise->MaybeRejectBrokenly(errorStr);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mobilemessage
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "DOMRequest.h"
|
||||
|
||||
class Promise;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace mobilemessage {
|
||||
@@ -22,11 +24,13 @@ public:
|
||||
NS_DECL_NSIMOBILEMESSAGECALLBACK
|
||||
|
||||
explicit MobileMessageCallback(DOMRequest* aDOMRequest);
|
||||
explicit MobileMessageCallback(Promise* aPromise);
|
||||
|
||||
private:
|
||||
~MobileMessageCallback();
|
||||
|
||||
nsRefPtr<DOMRequest> mDOMRequest;
|
||||
nsRefPtr<Promise> mPromise;
|
||||
|
||||
nsresult NotifySuccess(JS::Handle<JS::Value> aResult, bool aAsync = false);
|
||||
nsresult NotifySuccess(nsISupports *aMessage, bool aAsync = false);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "mozilla/dom/MozMmsEvent.h"
|
||||
#include "mozilla/dom/MozMobileMessageManagerBinding.h"
|
||||
#include "mozilla/dom/MozSmsEvent.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Services.h"
|
||||
@@ -704,6 +705,72 @@ MobileMessageManager::GetSmscAddress(const Optional<uint32_t>& aServiceId,
|
||||
return request.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
MobileMessageManager::SetSmscAddress(const SmscAddress& aSmscAddress,
|
||||
const Optional<uint32_t>& aServiceId,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
|
||||
if (!smsService) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Use the default one unless |serviceId| is available.
|
||||
uint32_t serviceId;
|
||||
nsresult rv;
|
||||
if (aServiceId.WasPassed()) {
|
||||
serviceId = aServiceId.Value();
|
||||
} else {
|
||||
rv = smsService->GetSmsDefaultServiceId(&serviceId);
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(rv);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
|
||||
if (!global) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<Promise> promise = Promise::Create(global, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!aSmscAddress.mAddress.WasPassed()) {
|
||||
NS_WARNING("SmscAddress.address is a mandatory field and can not be omitted.");
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
nsString address = aSmscAddress.mAddress.Value();
|
||||
TypeOfNumber ton = aSmscAddress.mTypeOfAddress.mTypeOfNumber;
|
||||
NumberPlanIdentification npi =
|
||||
aSmscAddress.mTypeOfAddress.mNumberPlanIdentification;
|
||||
|
||||
// If the address begins with +, set TON to international no matter what has
|
||||
// passed in.
|
||||
if (!address.IsEmpty() && address[0] == '+') {
|
||||
ton = TypeOfNumber::International;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIMobileMessageCallback> msgCallback =
|
||||
new MobileMessageCallback(promise);
|
||||
|
||||
rv = smsService->SetSmscAddress(serviceId, address,
|
||||
static_cast<uint32_t>(ton), static_cast<uint32_t>(npi), msgCallback);
|
||||
if (NS_FAILED(rv)) {
|
||||
promise->MaybeReject(rv);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
class nsISmsService;
|
||||
class nsIDOMMozSmsMessage;
|
||||
class nsIDOMMozMmsMessage;
|
||||
class Promise;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@@ -25,6 +26,7 @@ struct MmsSendParameters;
|
||||
struct MobileMessageFilter;
|
||||
class OwningLongOrMozSmsMessageOrMozMmsMessage;
|
||||
struct SmsSendParameters;
|
||||
struct SmscAddress;
|
||||
|
||||
class MobileMessageManager final : public DOMEventTargetHelper
|
||||
, public nsIObserver
|
||||
@@ -116,6 +118,11 @@ public:
|
||||
GetSmscAddress(const Optional<uint32_t>& aServiceId,
|
||||
ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise>
|
||||
SetSmscAddress(const SmscAddress& aSmscAddress,
|
||||
const Optional<uint32_t>& aServiceId,
|
||||
ErrorResult& aRv);
|
||||
|
||||
IMPL_EVENT_HANDLER(received)
|
||||
IMPL_EVENT_HANDLER(retrieving)
|
||||
IMPL_EVENT_HANDLER(sending)
|
||||
|
||||
@@ -139,6 +139,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "gpps",
|
||||
"@mozilla.org/network/protocol-proxy-service;1",
|
||||
"nsIProtocolProxyService");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gIccService",
|
||||
"@mozilla.org/icc/iccservice;1",
|
||||
"nsIIccService");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gUUIDGenerator",
|
||||
"@mozilla.org/uuid-generator;1",
|
||||
"nsIUUIDGenerator");
|
||||
@@ -348,7 +352,7 @@ MmsConnection.prototype = {
|
||||
// Get the proper IccInfo based on the current card type.
|
||||
try {
|
||||
let iccInfo = null;
|
||||
let baseIccInfo = this.radioInterface.rilContext.iccInfo;
|
||||
let baseIccInfo = this.getIccInfo();
|
||||
if (baseIccInfo.iccType === 'ruim' || baseIccInfo.iccType === 'csim') {
|
||||
iccInfo = baseIccInfo.QueryInterface(Ci.nsICdmaIccInfo);
|
||||
number = iccInfo.mdn;
|
||||
@@ -366,11 +370,27 @@ MmsConnection.prototype = {
|
||||
return number;
|
||||
},
|
||||
|
||||
/**
|
||||
* A utility function to get IccInfo of the SIM card (if installed).
|
||||
*/
|
||||
getIccInfo: function() {
|
||||
let icc = gIccService.getIccByServiceId(this.serviceId);
|
||||
return icc ? icc.iccInfo : null;
|
||||
},
|
||||
|
||||
/**
|
||||
* A utility function to get CardState of the SIM card (if installed).
|
||||
*/
|
||||
getCardState: function() {
|
||||
let icc = gIccService.getIccByServiceId(this.serviceId);
|
||||
return icc ? icc.cardState : Ci.nsIIcc.CARD_STATE_UNKNOWN;
|
||||
},
|
||||
|
||||
/**
|
||||
* A utility function to get the ICC ID of the SIM card (if installed).
|
||||
*/
|
||||
getIccId: function() {
|
||||
let iccInfo = this.radioInterface.rilContext.iccInfo;
|
||||
let iccInfo = this.getIccInfo();
|
||||
|
||||
if (!iccInfo) {
|
||||
return null;
|
||||
@@ -405,8 +425,7 @@ MmsConnection.prototype = {
|
||||
if (getRadioDisabledState()) {
|
||||
if (DEBUG) debug("Error! Radio is disabled when sending MMS.");
|
||||
errorStatus = _HTTP_STATUS_RADIO_DISABLED;
|
||||
} else if (this.radioInterface.rilContext.cardState !=
|
||||
Ci.nsIIcc.CARD_STATE_READY) {
|
||||
} else if (this.getCardState() != Ci.nsIIcc.CARD_STATE_READY) {
|
||||
if (DEBUG) debug("Error! SIM card is not ready when sending MMS.");
|
||||
errorStatus = _HTTP_STATUS_NO_SIM_CARD;
|
||||
}
|
||||
|
||||
@@ -71,9 +71,13 @@ XPCOMUtils.defineLazyGetter(this, "gWAP", function() {
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gCellBroadcastService",
|
||||
"@mozilla.org/cellbroadcast/gonkservice;1",
|
||||
"@mozilla.org/cellbroadcast/cellbroadcastservice;1",
|
||||
"nsIGonkCellBroadcastService");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gIccService",
|
||||
"@mozilla.org/icc/iccservice;1",
|
||||
"nsIIccService");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gMobileConnectionService",
|
||||
"@mozilla.org/mobileconnection/mobileconnectionservice;1",
|
||||
"nsIMobileConnectionService");
|
||||
@@ -150,7 +154,7 @@ SmsService.prototype = {
|
||||
// Get the proper IccInfo based on the current card type.
|
||||
try {
|
||||
let iccInfo = null;
|
||||
let baseIccInfo = gRadioInterfaces[aServiceId].rilContext.iccInfo;
|
||||
let baseIccInfo = this._getIccInfo(aServiceId);
|
||||
if (baseIccInfo.iccType === 'ruim' || baseIccInfo.iccType === 'csim') {
|
||||
iccInfo = baseIccInfo.QueryInterface(Ci.nsICdmaIccInfo);
|
||||
number = iccInfo.mdn;
|
||||
@@ -168,8 +172,18 @@ SmsService.prototype = {
|
||||
return number;
|
||||
},
|
||||
|
||||
_getIccInfo: function(aServiceId) {
|
||||
let icc = gIccService.getIccByServiceId(aServiceId);
|
||||
return icc ? icc.iccInfo : null;
|
||||
},
|
||||
|
||||
_getCardState: function(aServiceId) {
|
||||
let icc = gIccService.getIccByServiceId(aServiceId);
|
||||
return icc ? icc.cardState : Ci.nsIIcc.CARD_STATE_UNKNOWN;
|
||||
},
|
||||
|
||||
_getIccId: function(aServiceId) {
|
||||
let iccInfo = gRadioInterfaces[aServiceId].rilContext.iccInfo;
|
||||
let iccInfo = this._getIccInfo(aServiceId);
|
||||
|
||||
if (!iccInfo) {
|
||||
return null;
|
||||
@@ -878,8 +892,7 @@ SmsService.prototype = {
|
||||
radioState == Ci.nsIMobileConnection.MOBILE_RADIO_STATE_DISABLED) {
|
||||
if (DEBUG) debug("Error! Radio is disabled when sending SMS.");
|
||||
errorCode = Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR;
|
||||
} else if (gRadioInterfaces[aServiceId].rilContext.cardState !=
|
||||
Ci.nsIIcc.CARD_STATE_READY) {
|
||||
} else if (this._getCardState(aServiceId) != Ci.nsIIcc.CARD_STATE_READY) {
|
||||
if (DEBUG) debug("Error! SIM card is not ready when sending SMS.");
|
||||
errorCode = Ci.nsIMobileMessageCallback.NO_SIM_CARD_ERROR;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[scriptable, uuid(35279dbc-9f1d-419f-b17a-230fcf49f0c7)]
|
||||
[scriptable, uuid(b1367554-51c6-4153-b20a-effec50ca827)]
|
||||
interface nsIMobileMessageCallback : nsISupports
|
||||
{
|
||||
/**
|
||||
@@ -54,4 +54,6 @@ interface nsIMobileMessageCallback : nsISupports
|
||||
*/
|
||||
void notifyGetSmscAddress(in DOMString aSmscAddress);
|
||||
void notifyGetSmscAddressFailed(in long error);
|
||||
void notifySetSmscAddress();
|
||||
void notifySetSmscAddressFailed(in long error);
|
||||
};
|
||||
|
||||
@@ -69,6 +69,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "messenger",
|
||||
"@mozilla.org/system-message-internal;1",
|
||||
"nsISystemMessagesInternal");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gIccService",
|
||||
"@mozilla.org/icc/iccservice;1",
|
||||
"nsIIccService");
|
||||
|
||||
this.NetworkStatsService = {
|
||||
init: function() {
|
||||
debug("Service started");
|
||||
@@ -253,11 +257,12 @@ this.NetworkStatsService = {
|
||||
let networks = {};
|
||||
let numRadioInterfaces = gRil.numRadioInterfaces;
|
||||
for (let i = 0; i < numRadioInterfaces; i++) {
|
||||
let icc = gIccService.getIccByServiceId(i);
|
||||
let radioInterface = gRil.getRadioInterface(i);
|
||||
if (radioInterface.rilContext.iccInfo) {
|
||||
let netId = this.getNetworkId(radioInterface.rilContext.iccInfo.iccid,
|
||||
if (icc && icc.iccInfo) {
|
||||
let netId = this.getNetworkId(icc.iccInfo.iccid,
|
||||
NET_TYPE_MOBILE);
|
||||
networks[netId] = { id : radioInterface.rilContext.iccInfo.iccid,
|
||||
networks[netId] = { id : icc.iccInfo.iccid,
|
||||
type: NET_TYPE_MOBILE };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,274 @@
|
||||
/* 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/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
const DATACALLINTERFACE_CONTRACTID = "@mozilla.org/datacall/interface;1";
|
||||
const DATACALLINTERFACESERVICE_CONTRACTID =
|
||||
"@mozilla.org/datacall/interfaceservice;1";
|
||||
const DATACALLINTERFACE_CID =
|
||||
Components.ID("{ff669306-4390-462a-989b-ba37fc42153f}");
|
||||
const DATACALLINTERFACESERVICE_CID =
|
||||
Components.ID("{e23e9337-592d-40b9-8cef-7bd47c28b72e}");
|
||||
|
||||
const TOPIC_XPCOM_SHUTDOWN = "xpcom-shutdown";
|
||||
const TOPIC_PREF_CHANGED = "nsPref:changed";
|
||||
const PREF_RIL_DEBUG_ENABLED = "ril.debugging.enabled";
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "RIL", function () {
|
||||
let obj = {};
|
||||
Cu.import("resource://gre/modules/ril_consts.js", obj);
|
||||
return obj;
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gRil",
|
||||
"@mozilla.org/ril;1",
|
||||
"nsIRadioInterfaceLayer");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gMobileConnectionService",
|
||||
"@mozilla.org/mobileconnection/mobileconnectionservice;1",
|
||||
"nsIMobileConnectionService");
|
||||
|
||||
var DEBUG = RIL.DEBUG_RIL;
|
||||
|
||||
function updateDebugFlag() {
|
||||
// Read debug setting from pref
|
||||
let debugPref;
|
||||
try {
|
||||
debugPref = Services.prefs.getBoolPref(PREF_RIL_DEBUG_ENABLED);
|
||||
} catch (e) {
|
||||
debugPref = false;
|
||||
}
|
||||
DEBUG = debugPref || RIL.DEBUG_RIL;
|
||||
}
|
||||
updateDebugFlag();
|
||||
|
||||
function DataCall(aAttributes) {
|
||||
for (let key in aAttributes) {
|
||||
if (key === "pdpType") {
|
||||
// Convert pdp type into constant int value.
|
||||
this[key] = RIL.RIL_DATACALL_PDP_TYPES.indexOf(aAttributes[key]);
|
||||
continue;
|
||||
}
|
||||
|
||||
this[key] = aAttributes[key];
|
||||
}
|
||||
}
|
||||
DataCall.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCall]),
|
||||
|
||||
failCause: Ci.nsIDataCallInterface.DATACALL_FAIL_NONE,
|
||||
suggestedRetryTime: -1,
|
||||
cid: -1,
|
||||
active: -1,
|
||||
pdpType: -1,
|
||||
ifname: null,
|
||||
addreses: null,
|
||||
dnses: null,
|
||||
gateways: null
|
||||
};
|
||||
|
||||
function DataCallInterfaceService() {
|
||||
this._dataCallInterfaces = [];
|
||||
|
||||
let numClients = gRil.numRadioInterfaces;
|
||||
for (let i = 0; i < numClients; i++) {
|
||||
this._dataCallInterfaces.push(new DataCallInterface(i));
|
||||
}
|
||||
|
||||
Services.obs.addObserver(this, TOPIC_XPCOM_SHUTDOWN, false);
|
||||
Services.prefs.addObserver(PREF_RIL_DEBUG_ENABLED, this, false);
|
||||
}
|
||||
DataCallInterfaceService.prototype = {
|
||||
classID: DATACALLINTERFACESERVICE_CID,
|
||||
classInfo: XPCOMUtils.generateCI({
|
||||
classID: DATACALLINTERFACESERVICE_CID,
|
||||
contractID: DATACALLINTERFACESERVICE_CONTRACTID,
|
||||
classDescription: "Data Call Interface Service",
|
||||
interfaces: [Ci.nsIDataCallInterfaceService,
|
||||
Ci.nsIGonkDataCallInterfaceService]
|
||||
}),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCallInterfaceService,
|
||||
Ci.nsIGonkDataCallInterfaceService],
|
||||
Ci.nsIObserver),
|
||||
|
||||
// An array of DataCallInterface instances.
|
||||
_dataCallInterfaces: null,
|
||||
|
||||
debug: function(aMessage) {
|
||||
dump("-*- DataCallInterfaceService: " + aMessage + "\n");
|
||||
},
|
||||
|
||||
// nsIDataCallInterfaceService
|
||||
|
||||
getDataCallInterface: function(aClientId) {
|
||||
let dataCallInterface = this._dataCallInterfaces[aClientId];
|
||||
if (!dataCallInterface) {
|
||||
throw Cr.NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
return dataCallInterface;
|
||||
},
|
||||
|
||||
// nsIGonkDataCallInterfaceService
|
||||
|
||||
notifyDataCallListChanged: function(aClientId, aCount, aDataCalls) {
|
||||
let dataCallInterface = this.getDataCallInterface(aClientId);
|
||||
dataCallInterface.handleDataCallListChanged(aCount, aDataCalls);
|
||||
},
|
||||
|
||||
// nsIObserver
|
||||
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
switch (aTopic) {
|
||||
case TOPIC_PREF_CHANGED:
|
||||
if (aData === PREF_RIL_DEBUG_ENABLED) {
|
||||
updateDebugFlag();
|
||||
}
|
||||
break;
|
||||
case TOPIC_XPCOM_SHUTDOWN:
|
||||
Services.prefs.removeObserver(PREF_RIL_DEBUG_ENABLED, this);
|
||||
Services.obs.removeObserver(this, TOPIC_XPCOM_SHUTDOWN);
|
||||
break;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
function DataCallInterface(aClientId) {
|
||||
this._clientId = aClientId;
|
||||
this._radioInterface = gRil.getRadioInterface(aClientId);
|
||||
this._listeners = [];
|
||||
|
||||
if (DEBUG) this.debug("DataCallInterface: " + aClientId);
|
||||
}
|
||||
DataCallInterface.prototype = {
|
||||
classID: DATACALLINTERFACE_CID,
|
||||
classInfo: XPCOMUtils.generateCI({classID: DATACALLINTERFACE_CID,
|
||||
contractID: DATACALLINTERFACE_CONTRACTID,
|
||||
classDescription: "Data Call Interface",
|
||||
interfaces: [Ci.nsIDataCallInterface]}),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCallInterface]),
|
||||
|
||||
debug: function(aMessage) {
|
||||
dump("-*- DataCallInterface[" + this._clientId + "]: " + aMessage + "\n");
|
||||
},
|
||||
|
||||
_clientId: -1,
|
||||
|
||||
_radioInterface: null,
|
||||
|
||||
_listeners: null,
|
||||
|
||||
// nsIDataCallInterface
|
||||
|
||||
setupDataCall: function(aApn, aUsername, aPassword, aAuthType, aPdpType,
|
||||
aCallback) {
|
||||
let connection =
|
||||
gMobileConnectionService.getItemByServiceId(this._clientId);
|
||||
let dataInfo = connection && connection.data;
|
||||
let radioTechType = dataInfo.type;
|
||||
let radioTechnology = RIL.GECKO_RADIO_TECH.indexOf(radioTechType);
|
||||
// Convert pdp type into string value.
|
||||
let pdpType = RIL.RIL_DATACALL_PDP_TYPES[aPdpType];
|
||||
|
||||
this._radioInterface.sendWorkerMessage("setupDataCall", {
|
||||
radioTech: radioTechnology,
|
||||
apn: aApn,
|
||||
user: aUsername,
|
||||
passwd: aPassword,
|
||||
chappap: aAuthType,
|
||||
pdptype: pdpType
|
||||
}, (aResponse) => {
|
||||
if (aResponse.errorMsg) {
|
||||
aCallback.notifyError(aResponse.errorMsg);
|
||||
} else {
|
||||
let dataCall = new DataCall(aResponse);
|
||||
aCallback.notifySetupDataCallSuccess(dataCall);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
deactivateDataCall: function(aCid, aReason, aCallback) {
|
||||
this._radioInterface.sendWorkerMessage("deactivateDataCall", {
|
||||
cid: aCid,
|
||||
reason: aReason
|
||||
}, (aResponse) => {
|
||||
if (aResponse.errorMsg) {
|
||||
aCallback.notifyError(aResponse.errorMsg);
|
||||
} else {
|
||||
aCallback.notifySuccess();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getDataCallList: function(aCallback) {
|
||||
this._radioInterface.sendWorkerMessage("getDataCallList", null,
|
||||
(aResponse) => {
|
||||
if (aResponse.errorMsg) {
|
||||
aCallback.notifyError(aResponse.errorMsg);
|
||||
} else {
|
||||
let dataCalls = aResponse.datacalls.map(
|
||||
dataCall => new DataCall(dataCall));
|
||||
aCallback.notifyGetDataCallListSuccess(dataCalls.length, dataCalls);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setDataRegistration: function(aAttach, aCallback) {
|
||||
this._radioInterface.sendWorkerMessage("setDataRegistration", {
|
||||
attach: aAttach
|
||||
}, (aResponse) => {
|
||||
if (aResponse.errorMsg) {
|
||||
aCallback.notifyError(aResponse.errorMsg);
|
||||
} else {
|
||||
aCallback.notifySuccess();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
handleDataCallListChanged: function(aCount, aDataCalls) {
|
||||
this._notifyAllListeners("notifyDataCallListChanged", [aCount, aDataCalls]);
|
||||
},
|
||||
|
||||
_notifyAllListeners: function(aMethodName, aArgs) {
|
||||
let listeners = this._listeners.slice();
|
||||
for (let listener of listeners) {
|
||||
if (this._listeners.indexOf(listener) == -1) {
|
||||
// Listener has been unregistered in previous run.
|
||||
continue;
|
||||
}
|
||||
|
||||
let handler = listener[aMethodName];
|
||||
try {
|
||||
handler.apply(listener, aArgs);
|
||||
} catch (e) {
|
||||
if (DEBUG) {
|
||||
this.debug("listener for " + aMethodName + " threw an exception: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
registerListener: function(aListener) {
|
||||
if (this._listeners.indexOf(aListener) >= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._listeners.push(aListener);
|
||||
},
|
||||
|
||||
unregisterListener: function(aListener) {
|
||||
let index = this._listeners.indexOf(aListener);
|
||||
if (index >= 0) {
|
||||
this._listeners.splice(index, 1);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([DataCallInterfaceService]);
|
||||
@@ -0,0 +1,6 @@
|
||||
# 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/.
|
||||
|
||||
component {e23e9337-592d-40b9-8cef-7bd47c28b72e} DataCallInterfaceService.js
|
||||
contract @mozilla.org/datacall/interfaceservice;1 {e23e9337-592d-40b9-8cef-7bd47c28b72e}
|
||||
@@ -43,6 +43,7 @@
|
||||
#include "nsIMobileCellInfo.h"
|
||||
#include "nsIMobileNetworkInfo.h"
|
||||
#include "nsIRadioInterfaceLayer.h"
|
||||
#include "nsIIccService.h"
|
||||
#endif
|
||||
|
||||
#ifdef AGPS_TYPE_INVALID
|
||||
@@ -476,31 +477,35 @@ GonkGPSGeolocationProvider::RequestSetID(uint32_t flags)
|
||||
|
||||
AGpsSetIDType type = AGPS_SETID_TYPE_NONE;
|
||||
|
||||
nsCOMPtr<nsIRilContext> rilCtx;
|
||||
mRadioInterface->GetRilContext(getter_AddRefs(rilCtx));
|
||||
nsCOMPtr<nsIIccService> iccService =
|
||||
do_GetService(ICC_SERVICE_CONTRACTID);
|
||||
NS_ENSURE_TRUE_VOID(iccService);
|
||||
|
||||
if (rilCtx) {
|
||||
nsAutoString id;
|
||||
if (flags & AGPS_RIL_REQUEST_SETID_IMSI) {
|
||||
type = AGPS_SETID_TYPE_IMSI;
|
||||
rilCtx->GetImsi(id);
|
||||
}
|
||||
nsCOMPtr<nsIIcc> icc;
|
||||
iccService->GetIccByServiceId(mRilDataServiceId, getter_AddRefs(icc));
|
||||
NS_ENSURE_TRUE_VOID(icc);
|
||||
|
||||
if (flags & AGPS_RIL_REQUEST_SETID_MSISDN) {
|
||||
nsCOMPtr<nsIIccInfo> iccInfo;
|
||||
rilCtx->GetIccInfo(getter_AddRefs(iccInfo));
|
||||
if (iccInfo) {
|
||||
nsCOMPtr<nsIGsmIccInfo> gsmIccInfo = do_QueryInterface(iccInfo);
|
||||
if (gsmIccInfo) {
|
||||
type = AGPS_SETID_TYPE_MSISDN;
|
||||
gsmIccInfo->GetMsisdn(id);
|
||||
}
|
||||
nsAutoString id;
|
||||
|
||||
if (flags & AGPS_RIL_REQUEST_SETID_IMSI) {
|
||||
type = AGPS_SETID_TYPE_IMSI;
|
||||
icc->GetImsi(id);
|
||||
}
|
||||
|
||||
if (flags & AGPS_RIL_REQUEST_SETID_MSISDN) {
|
||||
nsCOMPtr<nsIIccInfo> iccInfo;
|
||||
icc->GetIccInfo(getter_AddRefs(iccInfo));
|
||||
if (iccInfo) {
|
||||
nsCOMPtr<nsIGsmIccInfo> gsmIccInfo = do_QueryInterface(iccInfo);
|
||||
if (gsmIccInfo) {
|
||||
type = AGPS_SETID_TYPE_MSISDN;
|
||||
gsmIccInfo->GetMsisdn(id);
|
||||
}
|
||||
}
|
||||
|
||||
NS_ConvertUTF16toUTF8 idBytes(id);
|
||||
mAGpsRilInterface->set_set_id(type, idBytes.get());
|
||||
}
|
||||
|
||||
NS_ConvertUTF16toUTF8 idBytes(id);
|
||||
mAGpsRilInterface->set_set_id(type, idBytes.get());
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -21,6 +21,7 @@ Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
/* global RIL */
|
||||
XPCOMUtils.defineLazyGetter(this, "RIL", function () {
|
||||
let obj = {};
|
||||
Cu.import("resource://gre/modules/ril_consts.js", obj);
|
||||
@@ -43,11 +44,6 @@ const RILCONTENTHELPER_CID =
|
||||
Components.ID("{472816e1-1fd6-4405-996c-806f9ea68174}");
|
||||
|
||||
const RIL_IPC_MSG_NAMES = [
|
||||
"RIL:CardStateChanged",
|
||||
"RIL:IccInfoChanged",
|
||||
"RIL:GetCardLockResult",
|
||||
"RIL:SetUnlockCardLockResult",
|
||||
"RIL:CardLockRetryCount",
|
||||
"RIL:StkCommand",
|
||||
"RIL:StkSessionEnd",
|
||||
"RIL:IccOpenChannel",
|
||||
@@ -55,18 +51,19 @@ const RIL_IPC_MSG_NAMES = [
|
||||
"RIL:IccExchangeAPDU",
|
||||
"RIL:ReadIccContacts",
|
||||
"RIL:UpdateIccContact",
|
||||
"RIL:MatchMvno",
|
||||
"RIL:GetServiceState"
|
||||
];
|
||||
|
||||
/* global cpmm */
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
"@mozilla.org/childprocessmessagemanager;1",
|
||||
"nsISyncMessageSender");
|
||||
|
||||
/* global UUIDGenerator */
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "UUIDGenerator",
|
||||
"@mozilla.org/uuid-generator;1",
|
||||
"nsIUUIDGenerator");
|
||||
|
||||
/* global gNumRadioInterfaces */
|
||||
XPCOMUtils.defineLazyGetter(this, "gNumRadioInterfaces", function() {
|
||||
let appInfo = Cc["@mozilla.org/xre/app-info;1"];
|
||||
let isParentProcess = !appInfo || appInfo.getService(Ci.nsIXULRuntime)
|
||||
@@ -77,69 +74,20 @@ XPCOMUtils.defineLazyGetter(this, "gNumRadioInterfaces", function() {
|
||||
try {
|
||||
ril = Cc["@mozilla.org/ril;1"].getService(Ci.nsIRadioInterfaceLayer);
|
||||
} catch(e) {}
|
||||
return ril.numRadioInterfaces
|
||||
return ril.numRadioInterfaces;
|
||||
}
|
||||
|
||||
return Services.prefs.getIntPref(kPrefRilNumRadioInterfaces);
|
||||
});
|
||||
|
||||
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 RILContentHelper() {
|
||||
this.updateDebugFlag();
|
||||
|
||||
this.numClients = gNumRadioInterfaces;
|
||||
if (DEBUG) debug("Number of clients: " + this.numClients);
|
||||
|
||||
this._iccs = [];
|
||||
this.rilContexts = [];
|
||||
for (let clientId = 0; clientId < this.numClients; clientId++) {
|
||||
this._iccs.push(new Icc(this, clientId));
|
||||
this.rilContexts[clientId] = {
|
||||
cardState: Ci.nsIIcc.CARD_STATE_UNKNOWN,
|
||||
iccInfo: null
|
||||
};
|
||||
}
|
||||
|
||||
this.initDOMRequestHelper(/* aWindow */ null, RIL_IPC_MSG_NAMES);
|
||||
this._windowsMap = [];
|
||||
this._requestMap = [];
|
||||
this._iccListeners = [];
|
||||
this._iccChannelCallback = [];
|
||||
|
||||
@@ -152,14 +100,12 @@ RILContentHelper.prototype = {
|
||||
__proto__: DOMRequestIpcHelper.prototype,
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIIccProvider,
|
||||
Ci.nsIIccService,
|
||||
Ci.nsIObserver,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
classID: RILCONTENTHELPER_CID,
|
||||
classInfo: XPCOMUtils.generateCI({classID: RILCONTENTHELPER_CID,
|
||||
classDescription: "RILContentHelper",
|
||||
interfaces: [Ci.nsIIccProvider,
|
||||
Ci.nsIIccService]}),
|
||||
interfaces: [Ci.nsIIccProvider]}),
|
||||
|
||||
updateDebugFlag: function() {
|
||||
try {
|
||||
@@ -168,71 +114,8 @@ RILContentHelper.prototype = {
|
||||
} 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();
|
||||
}
|
||||
}
|
||||
|
||||
this.updateInfo(newInfo, rilContext.iccInfo);
|
||||
},
|
||||
|
||||
_windowsMap: null,
|
||||
|
||||
_requestMap: 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
|
||||
*/
|
||||
@@ -564,61 +447,6 @@ RILContentHelper.prototype = {
|
||||
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._deliverIccEvent(clientId,
|
||||
"notifyCardStateChanged",
|
||||
null);
|
||||
}
|
||||
break;
|
||||
case "RIL:IccInfoChanged":
|
||||
this.updateIccInfo(clientId, data);
|
||||
this._deliverIccEvent(clientId,
|
||||
"notifyIccInfoChanged",
|
||||
null);
|
||||
break;
|
||||
case "RIL:GetCardLockResult": {
|
||||
let requestId = data.requestId;
|
||||
let callback = this._requestMap[requestId];
|
||||
delete this._requestMap[requestId];
|
||||
|
||||
if (data.errorMsg) {
|
||||
callback.notifyError(data.errorMsg);
|
||||
break;
|
||||
}
|
||||
|
||||
callback.notifySuccessWithBoolean(data.enabled);
|
||||
break;
|
||||
}
|
||||
case "RIL:SetUnlockCardLockResult": {
|
||||
let requestId = data.requestId;
|
||||
let callback = this._requestMap[requestId];
|
||||
delete this._requestMap[requestId];
|
||||
|
||||
if (data.errorMsg) {
|
||||
let retryCount =
|
||||
(data.retryCount !== undefined) ? data.retryCount : -1;
|
||||
callback.notifyCardLockError(data.errorMsg, retryCount);
|
||||
break;
|
||||
}
|
||||
|
||||
callback.notifySuccess();
|
||||
break;
|
||||
}
|
||||
case "RIL:CardLockRetryCount": {
|
||||
let requestId = data.requestId;
|
||||
let callback = this._requestMap[requestId];
|
||||
delete this._requestMap[requestId];
|
||||
|
||||
if (data.errorMsg) {
|
||||
callback.notifyError(data.errorMsg);
|
||||
break;
|
||||
}
|
||||
|
||||
callback.notifyGetCardLockRetryCount(data.retryCount);
|
||||
break;
|
||||
}
|
||||
case "RIL:StkCommand":
|
||||
this._deliverEvent(clientId, "_iccListeners", "notifyStkCommand",
|
||||
[JSON.stringify(data)]);
|
||||
@@ -641,30 +469,6 @@ RILContentHelper.prototype = {
|
||||
case "RIL:UpdateIccContact":
|
||||
this.handleUpdateIccContact(data);
|
||||
break;
|
||||
case "RIL:MatchMvno": {
|
||||
let requestId = data.requestId;
|
||||
let callback = this._requestMap[requestId];
|
||||
delete this._requestMap[requestId];
|
||||
|
||||
if (data.errorMsg) {
|
||||
callback.notifyError(data.errorMsg);
|
||||
break;
|
||||
}
|
||||
callback.notifySuccessWithBoolean(data.result);
|
||||
break;
|
||||
}
|
||||
case "RIL:GetServiceState": {
|
||||
let requestId = data.requestId;
|
||||
let callback = this._requestMap[requestId];
|
||||
delete this._requestMap[requestId];
|
||||
|
||||
if (data.errorMsg) {
|
||||
callback.notifyError(data.errorMsg);
|
||||
break;
|
||||
}
|
||||
callback.notifySuccessWithBoolean(data.result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -791,235 +595,6 @@ RILContentHelper.prototype = {
|
||||
if (DEBUG) debug("listener for " + name + " threw an exception: " + e);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* nsIIccService interface.
|
||||
*/
|
||||
|
||||
_iccs: null, // An array of Icc instances.
|
||||
|
||||
getIccByServiceId: function(serviceId) {
|
||||
let icc = this._iccs[serviceId];
|
||||
if (!icc) {
|
||||
throw Cr.NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
return icc;
|
||||
},
|
||||
|
||||
/**
|
||||
* Bridge APIs from nsIIccService to nsIIccProvider
|
||||
*/
|
||||
|
||||
_deliverIccEvent: function(clientId, name, args) {
|
||||
let icc = this._iccs[clientId];
|
||||
if (!icc) {
|
||||
if (DEBUG) debug("_deliverIccEvent: Invalid clientId: " + clientId);
|
||||
return;
|
||||
}
|
||||
|
||||
icc.deliverListenerEvent(name, args);
|
||||
},
|
||||
|
||||
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, mvnoType, mvnoData, callback) {
|
||||
let requestId = UUIDGenerator.generateUUID().toString();
|
||||
this._requestMap[requestId] = callback;
|
||||
|
||||
cpmm.sendAsyncMessage("RIL:MatchMvno", {
|
||||
clientId: clientId,
|
||||
data: {
|
||||
requestId: requestId,
|
||||
mvnoType: mvnoType,
|
||||
mvnoData: mvnoData
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getCardLockEnabled: function(clientId, lockType, callback) {
|
||||
let requestId = UUIDGenerator.generateUUID().toString();
|
||||
this._requestMap[requestId] = callback;
|
||||
|
||||
cpmm.sendAsyncMessage("RIL:GetCardLockEnabled", {
|
||||
clientId: clientId,
|
||||
data: {
|
||||
lockType: lockType,
|
||||
requestId: requestId
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
unlockCardLock: function(clientId, lockType, password, newPin, callback) {
|
||||
let requestId = UUIDGenerator.generateUUID().toString();
|
||||
this._requestMap[requestId] = callback;
|
||||
|
||||
cpmm.sendAsyncMessage("RIL:UnlockCardLock", {
|
||||
clientId: clientId,
|
||||
data: {
|
||||
lockType: lockType,
|
||||
password: password,
|
||||
newPin: newPin,
|
||||
requestId: requestId
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setCardLockEnabled: function(clientId, lockType, password, enabled, callback) {
|
||||
let requestId = UUIDGenerator.generateUUID().toString();
|
||||
this._requestMap[requestId] = callback;
|
||||
|
||||
cpmm.sendAsyncMessage("RIL:SetCardLockEnabled", {
|
||||
clientId: clientId,
|
||||
data: {
|
||||
lockType: lockType,
|
||||
password: password,
|
||||
enabled: enabled,
|
||||
requestId: requestId
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
changeCardLockPassword: function(clientId, lockType, password, newPassword,
|
||||
callback) {
|
||||
let requestId = UUIDGenerator.generateUUID().toString();
|
||||
this._requestMap[requestId] = callback;
|
||||
|
||||
cpmm.sendAsyncMessage("RIL:ChangeCardLockPassword", {
|
||||
clientId: clientId,
|
||||
data: {
|
||||
lockType: lockType,
|
||||
password: password,
|
||||
newPassword: newPassword,
|
||||
requestId: requestId
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getCardLockRetryCount: function(clientId, lockType, callback) {
|
||||
let requestId = UUIDGenerator.generateUUID().toString();
|
||||
this._requestMap[requestId] = callback;
|
||||
|
||||
cpmm.sendAsyncMessage("RIL:GetCardLockRetryCount", {
|
||||
clientId: clientId,
|
||||
data: {
|
||||
lockType: lockType,
|
||||
requestId: requestId
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getServiceStateEnabled: function(clientId, service, callback) {
|
||||
let requestId = UUIDGenerator.generateUUID().toString();
|
||||
this._requestMap[requestId] = callback;
|
||||
|
||||
cpmm.sendAsyncMessage("RIL:GetServiceState", {
|
||||
clientId: clientId,
|
||||
data: {
|
||||
requestId: requestId,
|
||||
service: service
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function Icc(aIccProvider, aClientId) {
|
||||
this._iccProvider = aIccProvider;
|
||||
this._clientId = aClientId;
|
||||
this._listeners = [];
|
||||
}
|
||||
Icc.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIIcc]),
|
||||
|
||||
_iccProvider: null,
|
||||
_clientId: -1,
|
||||
_listeners: null,
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* nsIIcc interface.
|
||||
*/
|
||||
registerListener: function(aListener) {
|
||||
if (this._listeners.indexOf(aListener) >= 0) {
|
||||
throw Cr.NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
this._listeners.push(aListener);
|
||||
cpmm.sendAsyncMessage("RIL:RegisterIccMsg");
|
||||
},
|
||||
|
||||
unregisterListener: function(aListener) {
|
||||
let index = this._listeners.indexOf(aListener);
|
||||
if (index >= 0) {
|
||||
this._listeners.splice(index, 1);
|
||||
}
|
||||
},
|
||||
|
||||
get iccInfo() {
|
||||
return this._iccProvider.getIccInfo(this._clientId);
|
||||
},
|
||||
|
||||
get cardState() {
|
||||
return this._iccProvider.getCardState(this._clientId);
|
||||
},
|
||||
|
||||
getCardLockEnabled: function(aLockType, aCallback) {
|
||||
this._iccProvider.getCardLockEnabled(this._clientId, aLockType, aCallback);
|
||||
},
|
||||
|
||||
unlockCardLock: function(aLockType, aPassword, aNewPin, aCallback) {
|
||||
this._iccProvider.unlockCardLock(this._clientId, aLockType,
|
||||
aPassword, aNewPin, aCallback);
|
||||
},
|
||||
|
||||
setCardLockEnabled: function(aLockType, aPassword, aEnabled, aCallback) {
|
||||
this._iccProvider.setCardLockEnabled(this._clientId, aLockType,
|
||||
aPassword, aEnabled, aCallback);
|
||||
},
|
||||
|
||||
changeCardLockPassword: function(aLockType, aPassword, aNewPassword, aCallback) {
|
||||
this._iccProvider.changeCardLockPassword(this._clientId, aLockType,
|
||||
aPassword, aNewPassword, aCallback);
|
||||
},
|
||||
|
||||
getCardLockRetryCount: function(aLockType, aCallback) {
|
||||
this._iccProvider.getCardLockRetryCount(this._clientId, aLockType, aCallback);
|
||||
},
|
||||
|
||||
matchMvno: function(aMvnoType, aMvnoData, aCallback) {
|
||||
this._iccProvider.matchMvno(this._clientId, aMvnoType, aMvnoData, aCallback);
|
||||
},
|
||||
|
||||
getServiceStateEnabled: function(aService, aCallback) {
|
||||
this._iccProvider.getServiceStateEnabled(this._clientId, aService, aCallback);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -47,6 +47,9 @@ let RILQUIRKS_RADIO_OFF_WO_CARD =
|
||||
let RILQUIRKS_HAVE_IPV6 =
|
||||
libcutils.property_get("ro.moz.ril.ipv6", "false") == "true";
|
||||
|
||||
let RILQUIRKS_SIGNAL_EXTRA_INT32 =
|
||||
libcutils.property_get("ro.moz.ril.signal_extra_int", "false") == "true";
|
||||
|
||||
const RADIOINTERFACELAYER_CID =
|
||||
Components.ID("{2d831c8d-6017-435b-a80c-e5d422810cea}");
|
||||
const RADIOINTERFACE_CID =
|
||||
@@ -86,24 +89,16 @@ const NETWORK_TYPE_MOBILE_DUN = Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_DUN;
|
||||
|
||||
// TODO: Bug 815526, deprecate RILContentHelper.
|
||||
const RIL_IPC_ICCMANAGER_MSG_NAMES = [
|
||||
"RIL:GetRilContext",
|
||||
"RIL:SendStkResponse",
|
||||
"RIL:SendStkMenuSelection",
|
||||
"RIL:SendStkTimerExpiration",
|
||||
"RIL:SendStkEventDownload",
|
||||
"RIL:GetCardLockEnabled",
|
||||
"RIL:UnlockCardLock",
|
||||
"RIL:SetCardLockEnabled",
|
||||
"RIL:ChangeCardLockPassword",
|
||||
"RIL:GetCardLockRetryCount",
|
||||
"RIL:IccOpenChannel",
|
||||
"RIL:IccExchangeAPDU",
|
||||
"RIL:IccCloseChannel",
|
||||
"RIL:ReadIccContacts",
|
||||
"RIL:UpdateIccContact",
|
||||
"RIL:RegisterIccMsg",
|
||||
"RIL:MatchMvno",
|
||||
"RIL:GetServiceState"
|
||||
];
|
||||
|
||||
// set to true in ril_consts.js to see debug messages
|
||||
@@ -166,7 +161,7 @@ XPCOMUtils.defineLazyServiceGetter(this, "gMobileConnectionService",
|
||||
"nsIGonkMobileConnectionService");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gCellBroadcastService",
|
||||
"@mozilla.org/cellbroadcast/gonkservice;1",
|
||||
"@mozilla.org/cellbroadcast/cellbroadcastservice;1",
|
||||
"nsIGonkCellBroadcastService");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gIccMessenger",
|
||||
@@ -878,44 +873,6 @@ try {
|
||||
})());
|
||||
} catch (e) {}
|
||||
|
||||
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 DataConnectionHandler(clientId, radioInterface) {
|
||||
// Initial owning attributes.
|
||||
this.clientId = clientId;
|
||||
@@ -987,42 +944,13 @@ DataConnectionHandler.prototype = {
|
||||
},
|
||||
|
||||
_compareDataCallOptions: function(dataCall, newDataCall) {
|
||||
return dataCall.apnProfile.apn == newDataCall.apn &&
|
||||
dataCall.apnProfile.user == newDataCall.user &&
|
||||
dataCall.apnProfile.password == newDataCall.passwd &&
|
||||
return dataCall.apnProfile.apn == newDataCall.apnProfile.apn &&
|
||||
dataCall.apnProfile.user == newDataCall.apnProfile.user &&
|
||||
dataCall.apnProfile.password == newDataCall.apnProfile.passwd &&
|
||||
dataCall.chappap == newDataCall.chappap &&
|
||||
dataCall.pdptype == newDataCall.pdptype;
|
||||
},
|
||||
|
||||
_deliverDataCallMessage: function(name, args) {
|
||||
for (let i = 0; i < this._dataCalls.length; i++) {
|
||||
let datacall = this._dataCalls[i];
|
||||
// Send message only to the DataCall that matches the data call options.
|
||||
// Currently, args always contain only one datacall info.
|
||||
if (!this._compareDataCallOptions(datacall, args[0])) {
|
||||
continue;
|
||||
}
|
||||
// Do not deliver message to DataCall that contains cid but mistmaches
|
||||
// with the cid in the current message.
|
||||
if (args[0].cid !== undefined && datacall.linkInfo.cid != null &&
|
||||
args[0].cid != datacall.linkInfo.cid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
let handler = datacall[name];
|
||||
if (typeof handler !== "function") {
|
||||
throw new Error("No handler for " + name);
|
||||
}
|
||||
handler.apply(datacall, args);
|
||||
} catch (e) {
|
||||
if (DEBUG) {
|
||||
this.debug("Handler for " + name + " threw an exception: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This function will do the following steps:
|
||||
* 1. Clear the cached APN settings in the RIL.
|
||||
@@ -1334,10 +1262,62 @@ DataConnectionHandler.prototype = {
|
||||
return dataDisconnecting;
|
||||
},
|
||||
|
||||
_findDataCallByCid: function(cid) {
|
||||
if (cid === undefined || cid < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (let i = 0; i < this._dataCalls.length; i++) {
|
||||
let datacall = this._dataCalls[i];
|
||||
if (datacall.linkInfo.cid != null &&
|
||||
datacall.linkInfo.cid === cid) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle data errors.
|
||||
* Handle unsolicidated data call list changed, called from RadioInterface.
|
||||
*/
|
||||
handleDataCallError: function(message) {
|
||||
handleDataCallListChanged: function(dataCallList) {
|
||||
let currentDataCalls = this._dataCalls.slice();
|
||||
for (let i = 0; i < dataCallList.length; i++) {
|
||||
let dataCall = dataCallList[i];
|
||||
let index = this._findDataCallByCid(dataCall.cid);
|
||||
if (index == -1) {
|
||||
if (DEBUG) {
|
||||
this.debug("Unexpected new data call: " + JSON.stringify(dataCall));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
currentDataCalls[index].onDataCallChanged(dataCall);
|
||||
currentDataCalls[index] = null;
|
||||
}
|
||||
|
||||
// If there is any CONNECTED DataCall left in currentDataCalls, means that
|
||||
// it is missing in dataCallList, we should send a DISCONNECTED event to
|
||||
// notify about this.
|
||||
for (let i = 0; i < currentDataCalls.length; i++) {
|
||||
let currentDataCall = currentDataCalls[i];
|
||||
if (currentDataCall && currentDataCall.linkInfo.cid != null &&
|
||||
currentDataCall.state == RIL.GECKO_NETWORK_STATE_CONNECTED) {
|
||||
if (DEBUG) {
|
||||
this.debug("Expected data call missing: " + JSON.stringify(
|
||||
currentDataCall.apnProfile) + ", must have been DISCONNECTED.");
|
||||
}
|
||||
currentDataCall.onDataCallChanged({
|
||||
state: RIL.GECKO_NETWORK_STATE_DISCONNECTED
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Notify about data call setup error, called from DataCall.
|
||||
*/
|
||||
notifyDataCallError: function(message) {
|
||||
// Notify data call error only for data APN
|
||||
let networkInterface = this.dataNetworkInterfaces.get(NETWORK_TYPE_MOBILE);
|
||||
if (networkInterface && networkInterface.enabled) {
|
||||
@@ -1345,7 +1325,7 @@ DataConnectionHandler.prototype = {
|
||||
// If there is a cid, compare cid; otherwise it is probably an error on
|
||||
// data call setup.
|
||||
if (message.cid !== undefined) {
|
||||
if (message.cid == dataCall.linkInfo.cid) {
|
||||
if (message.linkInfo.cid == dataCall.linkInfo.cid) {
|
||||
gMobileConnectionService.notifyDataError(this.clientId, message);
|
||||
}
|
||||
} else {
|
||||
@@ -1354,23 +1334,20 @@ DataConnectionHandler.prototype = {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._deliverDataCallMessage("dataCallError", [message]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle data call state changes.
|
||||
* Notify about data call changed, called from DataCall.
|
||||
*/
|
||||
handleDataCallState: function(datacall) {
|
||||
this._deliverDataCallMessage("dataCallStateChanged", [datacall]);
|
||||
|
||||
notifyDataCallChanged: function(updatedDataCall) {
|
||||
// Process pending radio power off request after all data calls
|
||||
// are disconnected.
|
||||
if (datacall.state == RIL.GECKO_NETWORK_STATE_DISCONNECTED &&
|
||||
if (updatedDataCall.state == RIL.GECKO_NETWORK_STATE_DISCONNECTED ||
|
||||
updatedDataCall.state == RIL.GECKO_NETWORK_STATE_UNKNOWN &&
|
||||
this.allDataDisconnected()) {
|
||||
if (gRadioEnabledController.isDeactivatingDataCalls()) {
|
||||
if (DEBUG) {
|
||||
this.debug("All data connections are disconnected.");
|
||||
this.debug("All data calls are disconnected.");
|
||||
}
|
||||
gRadioEnabledController.finishDeactivatingDataCalls(this.clientId);
|
||||
}
|
||||
@@ -1418,7 +1395,6 @@ RadioInterfaceLayer.prototype = {
|
||||
interfaces: [Ci.nsIRadioInterfaceLayer]}),
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIRadioInterfaceLayer,
|
||||
Ci.nsIRadioInterfaceLayer_new, // TODO: Bug 815526, deprecate RILContentHelper.
|
||||
Ci.nsIObserver]),
|
||||
|
||||
/**
|
||||
@@ -1519,7 +1495,8 @@ WorkerMessenger.prototype = {
|
||||
sendStkProfileDownload:
|
||||
libcutils.property_get("ro.moz.ril.send_stk_profile_dl", "false") == "true",
|
||||
dataRegistrationOnDemand: RILQUIRKS_DATA_REGISTRATION_ON_DEMAND,
|
||||
subscriptionControl: RILQUIRKS_SUBSCRIPTION_CONTROL
|
||||
subscriptionControl: RILQUIRKS_SUBSCRIPTION_CONTROL,
|
||||
signalExtraInt: RILQUIRKS_SIGNAL_EXTRA_INT32
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1665,12 +1642,6 @@ function RadioInterface(aClientId, aWorkerMessenger) {
|
||||
};
|
||||
aWorkerMessenger.registerClient(aClientId, this);
|
||||
|
||||
this.rilContext = {
|
||||
cardState: Ci.nsIIcc.CARD_STATE_UNKNOWN,
|
||||
iccInfo: null,
|
||||
imsi: null
|
||||
};
|
||||
|
||||
this.operatorInfo = {};
|
||||
|
||||
let lock = gSettingsService.createLock();
|
||||
@@ -1728,42 +1699,14 @@ RadioInterface.prototype = {
|
||||
Services.obs.removeObserver(this, kNetworkConnStateChangedTopic);
|
||||
},
|
||||
|
||||
/**
|
||||
* A utility function to copy objects. The srcInfo may contain
|
||||
* "rilMessageType", should ignore it.
|
||||
*/
|
||||
updateInfo: function(srcInfo, destInfo) {
|
||||
for (let key in srcInfo) {
|
||||
if (key === "rilMessageType") {
|
||||
continue;
|
||||
}
|
||||
destInfo[key] = srcInfo[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;
|
||||
getIccInfo: function() {
|
||||
let icc = gIccService.getIccByServiceId(this.clientId);
|
||||
return icc ? icc.iccInfo : null;
|
||||
},
|
||||
|
||||
isCardPresent: function() {
|
||||
let cardState = this.rilContext.cardState;
|
||||
let icc = gIccService.getIccByServiceId(this.clientId);
|
||||
let cardState = icc ? icc.cardState : Ci.nsIIcc.CARD_STATE_UNKNOWN;
|
||||
return cardState !== Ci.nsIIcc.CARD_STATE_UNDETECTED &&
|
||||
cardState !== Ci.nsIIcc.CARD_STATE_UNKNOWN;
|
||||
},
|
||||
@@ -1775,29 +1718,6 @@ RadioInterface.prototype = {
|
||||
*/
|
||||
receiveMessage: function(msg) {
|
||||
switch (msg.name) {
|
||||
case "RIL:GetRilContext":
|
||||
// This message is sync.
|
||||
return this.rilContext;
|
||||
case "RIL:GetCardLockEnabled":
|
||||
this.workerMessenger.sendWithIPCMessage(msg, "iccGetCardLockEnabled",
|
||||
"RIL:GetCardLockResult");
|
||||
break;
|
||||
case "RIL:UnlockCardLock":
|
||||
this.workerMessenger.sendWithIPCMessage(msg, "iccUnlockCardLock",
|
||||
"RIL:SetUnlockCardLockResult");
|
||||
break;
|
||||
case "RIL:SetCardLockEnabled":
|
||||
this.workerMessenger.sendWithIPCMessage(msg, "iccSetCardLockEnabled",
|
||||
"RIL:SetUnlockCardLockResult");
|
||||
break;
|
||||
case "RIL:ChangeCardLockPassword":
|
||||
this.workerMessenger.sendWithIPCMessage(msg, "iccChangeCardLockPassword",
|
||||
"RIL:SetUnlockCardLockResult");
|
||||
break;
|
||||
case "RIL:GetCardLockRetryCount":
|
||||
this.workerMessenger.sendWithIPCMessage(msg, "iccGetCardLockRetryCount",
|
||||
"RIL:CardLockRetryCount");
|
||||
break;
|
||||
case "RIL:SendStkResponse":
|
||||
this.workerMessenger.send("sendStkTerminalResponse", msg.json.data);
|
||||
break;
|
||||
@@ -1825,12 +1745,6 @@ RadioInterface.prototype = {
|
||||
case "RIL:UpdateIccContact":
|
||||
this.workerMessenger.sendWithIPCMessage(msg, "updateICCContact");
|
||||
break;
|
||||
case "RIL:MatchMvno":
|
||||
this.matchMvno(msg.target, msg.json.data);
|
||||
break;
|
||||
case "RIL:GetServiceState":
|
||||
this.workerMessenger.sendWithIPCMessage(msg, "getIccServiceState");
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
@@ -1838,20 +1752,11 @@ RadioInterface.prototype = {
|
||||
handleUnsolicitedWorkerMessage: function(message) {
|
||||
let connHandler = gDataConnectionManager.getConnectionHandler(this.clientId);
|
||||
switch (message.rilMessageType) {
|
||||
case "audioStateChanged":
|
||||
gTelephonyService.notifyAudioStateChanged(this.clientId, message.state);
|
||||
break;
|
||||
case "callRing":
|
||||
gTelephonyService.notifyCallRing();
|
||||
break;
|
||||
case "callStateChange":
|
||||
gTelephonyService.notifyCallStateChanged(this.clientId, message.call);
|
||||
break;
|
||||
case "callDisconnected":
|
||||
gTelephonyService.notifyCallDisconnected(this.clientId, message.call);
|
||||
break;
|
||||
case "conferenceCallStateChanged":
|
||||
gTelephonyService.notifyConferenceCallStateChanged(message.state);
|
||||
case "currentCalls":
|
||||
gTelephonyService.notifyCurrentCalls(this.clientId, message.calls);
|
||||
break;
|
||||
case "cdmaCallWaiting":
|
||||
gTelephonyService.notifyCdmaCallWaiting(this.clientId,
|
||||
@@ -1859,29 +1764,15 @@ RadioInterface.prototype = {
|
||||
break;
|
||||
case "suppSvcNotification":
|
||||
gTelephonyService.notifySupplementaryService(this.clientId,
|
||||
message.callIndex,
|
||||
message.number,
|
||||
message.notification);
|
||||
break;
|
||||
case "ussdreceived":
|
||||
gTelephonyService.notifyUssdReceived(this.clientId, message.message,
|
||||
message.sessionEnded);
|
||||
break;
|
||||
case "datacallerror":
|
||||
connHandler.handleDataCallError(message);
|
||||
break;
|
||||
case "datacallstatechange":
|
||||
let addresses = [];
|
||||
for (let i = 0; i < message.addresses.length; i++) {
|
||||
let [address, prefixLength] = message.addresses[i].split("/");
|
||||
// From AOSP hardware/ril/include/telephony/ril.h, that address prefix
|
||||
// is said to be OPTIONAL, but we never met such case before.
|
||||
addresses.push({
|
||||
address: address,
|
||||
prefixLength: prefixLength ? parseInt(prefixLength, 10) : 0
|
||||
});
|
||||
}
|
||||
message.addresses = addresses;
|
||||
connHandler.handleDataCallState(message);
|
||||
case "datacalllistchanged":
|
||||
connHandler.handleDataCallListChanged(message.datacalls);
|
||||
break;
|
||||
case "emergencyCbModeChange":
|
||||
gMobileConnectionService.notifyEmergencyCallbackModeChanged(this.clientId,
|
||||
@@ -1923,13 +1814,9 @@ RadioInterface.prototype = {
|
||||
message.radioState);
|
||||
break;
|
||||
case "cardstatechange":
|
||||
this.rilContext.cardState = message.cardState;
|
||||
gRadioEnabledController.receiveCardState(this.clientId);
|
||||
gIccService.notifyCardStateChanged(this.clientId,
|
||||
this.rilContext.cardState);
|
||||
// TODO: Bug 815526, deprecate RILContentHelper.
|
||||
gMessageManager.sendIccMessage("RIL:CardStateChanged",
|
||||
this.clientId, message);
|
||||
message.cardState);
|
||||
gRadioEnabledController.receiveCardState(this.clientId);
|
||||
break;
|
||||
case "sms-received":
|
||||
this.handleSmsReceived(message);
|
||||
@@ -1941,11 +1828,11 @@ RadioInterface.prototype = {
|
||||
this.handleNitzTime(message);
|
||||
break;
|
||||
case "iccinfochange":
|
||||
this.handleIccInfoChange(message);
|
||||
gIccService.notifyIccInfoChanged(this.clientId,
|
||||
message.iccid ? message : null);
|
||||
break;
|
||||
case "iccimsi":
|
||||
this.rilContext.imsi = message.imsi;
|
||||
gIccService.notifyImsiChanged(this.clientId, this.rilContext.imsi);
|
||||
gIccService.notifyImsiChanged(this.clientId, message.imsi);
|
||||
break;
|
||||
case "iccmbdn":
|
||||
this.handleIccMbdn(message);
|
||||
@@ -1969,85 +1856,6 @@ RadioInterface.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
// Matches the mvnoData pattern with imsi. Characters 'x' and 'X' are skipped
|
||||
// and not compared. E.g., if the mvnoData passed is '310260x10xxxxxx',
|
||||
// then the function returns true only if imsi has the same first 6 digits,
|
||||
// 8th and 9th digit.
|
||||
// TODO: Bug 815526, deprecate RILContentHelper.
|
||||
isImsiMatches: function(mvnoData) {
|
||||
let imsi = this.rilContext.imsi;
|
||||
|
||||
// This should not be an error, but a mismatch.
|
||||
if (mvnoData.length > imsi.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < mvnoData.length; i++) {
|
||||
let c = mvnoData[i];
|
||||
if ((c !== 'x') && (c !== 'X') && (c !== imsi[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
// TODO: Bug 815526, deprecate RILContentHelper.
|
||||
matchMvno: function(target, message) {
|
||||
if (DEBUG) this.debug("matchMvno: " + JSON.stringify(message));
|
||||
|
||||
if (!message || !message.mvnoData) {
|
||||
message.errorMsg = RIL.GECKO_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (!message.errorMsg) {
|
||||
switch (message.mvnoType) {
|
||||
case RIL.GECKO_CARDMVNO_TYPE_IMSI:
|
||||
if (!this.rilContext.imsi) {
|
||||
message.errorMsg = RIL.GECKO_ERROR_GENERIC_FAILURE;
|
||||
break;
|
||||
}
|
||||
message.result = this.isImsiMatches(message.mvnoData);
|
||||
break;
|
||||
case RIL.GECKO_CARDMVNO_TYPE_SPN:
|
||||
let spn = this.rilContext.iccInfo && this.rilContext.iccInfo.spn;
|
||||
if (!spn) {
|
||||
message.errorMsg = RIL.GECKO_ERROR_GENERIC_FAILURE;
|
||||
break;
|
||||
}
|
||||
message.result = spn == message.mvnoData;
|
||||
break;
|
||||
case RIL.GECKO_CARDMVNO_TYPE_GID:
|
||||
this.workerMessenger.send("getGID1", null, (function(response) {
|
||||
let gid = response.gid1;
|
||||
let mvnoDataLength = message.mvnoData.length;
|
||||
|
||||
if (!gid) {
|
||||
message.errorMsg = RIL.GECKO_ERROR_GENERIC_FAILURE;
|
||||
} else if (mvnoDataLength > gid.length) {
|
||||
message.result = false;
|
||||
} else {
|
||||
message.result =
|
||||
gid.substring(0, mvnoDataLength).toLowerCase() ==
|
||||
message.mvnoData.toLowerCase();
|
||||
}
|
||||
|
||||
target.sendAsyncMessage("RIL:MatchMvno", {
|
||||
clientId: this.clientId,
|
||||
data: message
|
||||
});
|
||||
}).bind(this));
|
||||
return;
|
||||
default:
|
||||
message.errorMsg = RIL.GECKO_ERROR_MODE_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
target.sendAsyncMessage("RIL:MatchMvno", {
|
||||
clientId: this.clientId,
|
||||
data: message
|
||||
});
|
||||
},
|
||||
|
||||
setDataRegistration: function(attach) {
|
||||
let deferred = Promise.defer();
|
||||
this.workerMessenger.send("setDataRegistration",
|
||||
@@ -2226,71 +2034,12 @@ RadioInterface.prototype = {
|
||||
null, null);
|
||||
},
|
||||
|
||||
handleIccInfoChange: function(message) {
|
||||
let oldSpn = this.rilContext.iccInfo ? this.rilContext.iccInfo.spn : null;
|
||||
|
||||
// TODO: Bug 815526, deprecate RILContentHelper:
|
||||
// Move the logic of updating iccInfo to IccService.js.
|
||||
if (!message || !message.iccid) {
|
||||
// If iccInfo is already `null`, don't have to clear it and send
|
||||
// RIL:IccInfoChanged.
|
||||
if (!this.rilContext.iccInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Card is not detected, clear iccInfo to null.
|
||||
this.rilContext.iccInfo = null;
|
||||
} else {
|
||||
if (!this.rilContext.iccInfo) {
|
||||
if (message.iccType === "ruim" || message.iccType === "csim") {
|
||||
this.rilContext.iccInfo = new CdmaIccInfo();
|
||||
} else if (message.iccType === "sim" || message.iccType === "usim") {
|
||||
this.rilContext.iccInfo = new GsmIccInfo();
|
||||
} else {
|
||||
this.rilContext.iccInfo = new IccInfo();
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.isInfoChanged(message, this.rilContext.iccInfo)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateInfo(message, this.rilContext.iccInfo);
|
||||
}
|
||||
|
||||
// RIL:IccInfoChanged corresponds to a DOM event that gets fired only
|
||||
// when iccInfo has changed.
|
||||
// TODO: Bug 815526, deprecate RILContentHelper.
|
||||
gMessageManager.sendIccMessage("RIL:IccInfoChanged",
|
||||
this.clientId,
|
||||
message.iccid ? message : null);
|
||||
gIccService.notifyIccInfoChanged(this.clientId,
|
||||
message.iccid ? message : null);
|
||||
|
||||
// Update lastKnownHomeNetwork.
|
||||
if (message.mcc && message.mnc) {
|
||||
let lastKnownHomeNetwork = message.mcc + "-" + message.mnc;
|
||||
// Append spn information if available.
|
||||
if (message.spn) {
|
||||
lastKnownHomeNetwork += "-" + message.spn;
|
||||
}
|
||||
|
||||
gMobileConnectionService.notifyLastHomeNetworkChanged(this.clientId,
|
||||
lastKnownHomeNetwork);
|
||||
}
|
||||
|
||||
// If spn becomes available, we should check roaming again.
|
||||
if (!oldSpn && message.spn) {
|
||||
gMobileConnectionService.notifySpnAvailable(this.clientId);
|
||||
}
|
||||
},
|
||||
|
||||
handleStkProactiveCommand: function(message) {
|
||||
if (DEBUG) this.debug("handleStkProactiveCommand " + JSON.stringify(message));
|
||||
let iccId = this.rilContext.iccInfo && this.rilContext.iccInfo.iccid;
|
||||
if (iccId) {
|
||||
let iccInfo = this.getIccInfo();
|
||||
if (iccInfo && iccInfo.iccid) {
|
||||
gIccMessenger
|
||||
.notifyStkProactiveCommand(iccId,
|
||||
.notifyStkProactiveCommand(iccInfo.iccid,
|
||||
gStkCmdFactory.createCommand(message));
|
||||
}
|
||||
// TODO: Bug 815526, deprecate RILContentHelper.
|
||||
@@ -2588,8 +2337,6 @@ RadioInterface.prototype = {
|
||||
|
||||
// nsIRadioInterface
|
||||
|
||||
rilContext: null,
|
||||
|
||||
// TODO: Bug 928861 - B2G NetworkManager: Provide a more generic function
|
||||
// for connecting
|
||||
setupDataCallByType: function(networkType) {
|
||||
@@ -2642,8 +2389,7 @@ function DataCall(clientId, apnSetting) {
|
||||
this.linkInfo = {
|
||||
cid: null,
|
||||
ifname: null,
|
||||
ips: [],
|
||||
prefixLengths: [],
|
||||
addresses: [],
|
||||
dnses: [],
|
||||
gateways: []
|
||||
};
|
||||
@@ -2675,98 +2421,169 @@ DataCall.prototype = {
|
||||
// Holds the authentication type sent to ril worker.
|
||||
chappap: null,
|
||||
|
||||
dataCallError: function(message) {
|
||||
if (DEBUG) {
|
||||
this.debug("Data call error on APN " + message.apn + ": " +
|
||||
message.errorMsg + " (" + message.status + "), retry time: " +
|
||||
message.suggestedRetryTime);
|
||||
}
|
||||
this.state = RIL.GECKO_NETWORK_STATE_DISCONNECTED;
|
||||
|
||||
if (this.requestedNetworkIfaces.length === 0) {
|
||||
if (DEBUG) this.debug("This DataCall is not requested anymore.");
|
||||
return;
|
||||
/**
|
||||
* @return "deactivate" if <ifname> changes or one of the currentDataCall
|
||||
* addresses is missing in updatedDataCall, or "identical" if no
|
||||
* changes found, or "changed" otherwise.
|
||||
*/
|
||||
_compareDataCallLink: function(updatedDataCall, currentDataCall) {
|
||||
// If network interface is changed, report as "deactivate".
|
||||
if (updatedDataCall.ifname != currentDataCall.ifname) {
|
||||
return "deactivate";
|
||||
}
|
||||
|
||||
// For suggestedRetryTime, the value of INT32_MAX(0x7fffffff) means no retry.
|
||||
if (message.suggestedRetryTime === INT32_MAX ||
|
||||
this.isPermanentFail(message.status, message.errorMsg)) {
|
||||
if (DEBUG) this.debug("Data call error: no retry needed.");
|
||||
return;
|
||||
// If any existing address is missing, report as "deactivate".
|
||||
for (let i = 0; i < currentDataCall.addresses.length; i++) {
|
||||
let address = currentDataCall.addresses[i];
|
||||
if (updatedDataCall.addresses.indexOf(address) < 0) {
|
||||
return "deactivate";
|
||||
}
|
||||
}
|
||||
|
||||
this.retry(message.suggestedRetryTime);
|
||||
if (currentDataCall.addresses.length != updatedDataCall.addresses.length) {
|
||||
// Since now all |currentDataCall.addresses| are found in
|
||||
// |updatedDataCall.addresses|, this means one or more new addresses are
|
||||
// reported.
|
||||
return "changed";
|
||||
}
|
||||
|
||||
let fields = ["gateways", "dnses"];
|
||||
for (let i = 0; i < fields.length; i++) {
|
||||
// Compare <datacall>.<field>.
|
||||
let field = fields[i];
|
||||
let lhs = updatedDataCall[field], rhs = currentDataCall[field];
|
||||
if (lhs.length != rhs.length) {
|
||||
return "changed";
|
||||
}
|
||||
for (let i = 0; i < lhs.length; i++) {
|
||||
if (lhs[i] != rhs[i]) {
|
||||
return "changed";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "identical";
|
||||
},
|
||||
|
||||
dataCallStateChanged: function(datacall) {
|
||||
if (DEBUG) {
|
||||
this.debug("Data call ID: " + datacall.cid + ", interface name: " +
|
||||
datacall.ifname + ", APN name: " + datacall.apn + ", state: " +
|
||||
datacall.state);
|
||||
onSetupDataCallResult: function(dataCall) {
|
||||
if (dataCall.status && dataCall.status != RIL.DATACALL_FAIL_NONE) {
|
||||
dataCall.errorMsg =
|
||||
RIL.RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[dataCall.status];
|
||||
}
|
||||
|
||||
if (this.state == datacall.state &&
|
||||
datacall.state != RIL.GECKO_NETWORK_STATE_CONNECTED) {
|
||||
if (dataCall.errorMsg) {
|
||||
if (DEBUG) {
|
||||
this.debug("SetupDataCall error for apn " + dataCall.apn + ": " +
|
||||
dataCall.errorMsg + " (" + dataCall.status + "), retry time: " +
|
||||
dataCall.suggestedRetryTime);
|
||||
}
|
||||
|
||||
this.state = RIL.GECKO_NETWORK_STATE_DISCONNECTED;
|
||||
|
||||
if (this.requestedNetworkIfaces.length === 0) {
|
||||
if (DEBUG) this.debug("This DataCall is not requested anymore.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Let DataConnectionHandler notify MobileConnectionService
|
||||
let connHandler = gDataConnectionManager.getConnectionHandler(this.clientId);
|
||||
connHandler.notifyDataCallError(this);
|
||||
|
||||
// For suggestedRetryTime, the value of INT32_MAX(0x7fffffff) means no retry.
|
||||
if (dataCall.suggestedRetryTime === INT32_MAX ||
|
||||
this.isPermanentFail(dataCall.status, dataCall.errorMsg)) {
|
||||
if (DEBUG) this.debug("Data call error: no retry needed.");
|
||||
return;
|
||||
}
|
||||
|
||||
this.retry(dataCall.suggestedRetryTime);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (datacall.state) {
|
||||
case RIL.GECKO_NETWORK_STATE_CONNECTED:
|
||||
if (this.state == RIL.GECKO_NETWORK_STATE_CONNECTING) {
|
||||
this.apnRetryCounter = 0;
|
||||
this.linkInfo.cid = datacall.cid;
|
||||
this.apnRetryCounter = 0;
|
||||
this.linkInfo.cid = dataCall.cid;
|
||||
|
||||
if (this.requestedNetworkIfaces.length === 0) {
|
||||
if (DEBUG) {
|
||||
this.debug("State is connected, but no network interface requested" +
|
||||
" this DataCall");
|
||||
}
|
||||
if (this.requestedNetworkIfaces.length === 0) {
|
||||
if (DEBUG) {
|
||||
this.debug("State is connected, but no network interface requested" +
|
||||
" this DataCall");
|
||||
}
|
||||
this.deactivate();
|
||||
return;
|
||||
}
|
||||
|
||||
this.linkInfo.ifname = dataCall.ifname;
|
||||
this.linkInfo.addresses = dataCall.addresses.slice();
|
||||
this.linkInfo.gateways = dataCall.gateways.slice();
|
||||
this.linkInfo.dnses = dataCall.dnses.slice();
|
||||
this.state = dataCall.state;
|
||||
|
||||
// Notify DataConnectionHandler about data call connected.
|
||||
let connHandler = gDataConnectionManager.getConnectionHandler(this.clientId);
|
||||
connHandler.notifyDataCallChanged(this);
|
||||
|
||||
for (let i = 0; i < this.requestedNetworkIfaces.length; i++) {
|
||||
this.requestedNetworkIfaces[i].notifyRILNetworkInterface();
|
||||
}
|
||||
},
|
||||
|
||||
onDeactivateDataCallResult: function() {
|
||||
this.reset();
|
||||
|
||||
if (this.requestedNetworkIfaces.length > 0) {
|
||||
if (DEBUG) {
|
||||
this.debug("State is disconnected/unknown, but this DataCall is" +
|
||||
" requested.");
|
||||
}
|
||||
this.setup();
|
||||
return;
|
||||
}
|
||||
|
||||
// Notify DataConnectionHandler about data call disconnected.
|
||||
let connHandler = gDataConnectionManager.getConnectionHandler(this.clientId);
|
||||
connHandler.notifyDataCallChanged(this);
|
||||
},
|
||||
|
||||
onDataCallChanged: function(updatedDataCall) {
|
||||
if (DEBUG) {
|
||||
this.debug("onDataCallChanged: " + JSON.stringify(updatedDataCall));
|
||||
}
|
||||
|
||||
if (this.state == updatedDataCall.state &&
|
||||
updatedDataCall.state != RIL.GECKO_NETWORK_STATE_CONNECTED) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (updatedDataCall.state) {
|
||||
case RIL.GECKO_NETWORK_STATE_CONNECTED:
|
||||
if (this.state == RIL.GECKO_NETWORK_STATE_CONNECTED) {
|
||||
let result =
|
||||
this._compareDataCallLink(updatedDataCall, this.linkInfo);
|
||||
|
||||
if (result == "identical") {
|
||||
if (DEBUG) this.debug("No changes in data call.");
|
||||
return;
|
||||
}
|
||||
if (result == "deactivate") {
|
||||
if (DEBUG) this.debug("Data link changed, cleanup.");
|
||||
this.deactivate();
|
||||
return;
|
||||
}
|
||||
|
||||
this.linkInfo.ifname = datacall.ifname;
|
||||
for (let entry of datacall.addresses) {
|
||||
this.linkInfo.ips.push(entry.address);
|
||||
this.linkInfo.prefixLengths.push(entry.prefixLength);
|
||||
}
|
||||
this.linkInfo.gateways = datacall.gateways.slice();
|
||||
this.linkInfo.dnses = datacall.dnses.slice();
|
||||
|
||||
} else if (this.state == RIL.GECKO_NETWORK_STATE_CONNECTED) {
|
||||
// configuration changed.
|
||||
let changed = false;
|
||||
if (this.linkInfo.ips.length != datacall.addresses.length) {
|
||||
changed = true;
|
||||
this.linkInfo.ips = [];
|
||||
this.linkInfo.prefixLengths = [];
|
||||
for (let entry of datacall.addresses) {
|
||||
this.linkInfo.ips.push(entry.address);
|
||||
this.linkInfo.prefixLengths.push(entry.prefixLength);
|
||||
}
|
||||
// Minor change, just update and notify.
|
||||
if (DEBUG) {
|
||||
this.debug("Data link minor change, just update and notify.");
|
||||
}
|
||||
|
||||
let reduceFunc = function(aRhs, aChanged, aElement, aIndex) {
|
||||
return aChanged || (aElement != aRhs[aIndex]);
|
||||
};
|
||||
for (let field of ["gateways", "dnses"]) {
|
||||
let lhs = this.linkInfo[field], rhs = datacall[field];
|
||||
if (lhs.length != rhs.length ||
|
||||
lhs.reduce(reduceFunc.bind(null, rhs), false)) {
|
||||
changed = true;
|
||||
this.linkInfo[field] = rhs.slice();
|
||||
}
|
||||
}
|
||||
if (!changed) {
|
||||
return;
|
||||
}
|
||||
this.linkInfo.addresses = updatedDataCall.addresses.slice();
|
||||
this.linkInfo.gateways = updatedDataCall.gateways.slice();
|
||||
this.linkInfo.dnses = updatedDataCall.dnses.slice();
|
||||
}
|
||||
break;
|
||||
case RIL.GECKO_NETWORK_STATE_DISCONNECTED:
|
||||
case RIL.GECKO_NETWORK_STATE_UNKNOWN:
|
||||
if (this.state == RIL.GECKO_NETWORK_STATE_CONNECTED) {
|
||||
// Notify first on unexpected data call disconnection.
|
||||
this.state = datacall.state;
|
||||
this.state = updatedDataCall.state;
|
||||
for (let i = 0; i < this.requestedNetworkIfaces.length; i++) {
|
||||
this.requestedNetworkIfaces[i].notifyRILNetworkInterface();
|
||||
}
|
||||
@@ -2784,7 +2601,12 @@ DataCall.prototype = {
|
||||
break;
|
||||
}
|
||||
|
||||
this.state = datacall.state;
|
||||
this.state = updatedDataCall.state;
|
||||
|
||||
// Notify DataConnectionHandler about data call changed.
|
||||
let connHandler = gDataConnectionManager.getConnectionHandler(this.clientId);
|
||||
connHandler.notifyDataCallChanged(this);
|
||||
|
||||
for (let i = 0; i < this.requestedNetworkIfaces.length; i++) {
|
||||
this.requestedNetworkIfaces[i].notifyRILNetworkInterface();
|
||||
}
|
||||
@@ -2851,8 +2673,7 @@ DataCall.prototype = {
|
||||
reset: function() {
|
||||
this.linkInfo.cid = null;
|
||||
this.linkInfo.ifname = null;
|
||||
this.linkInfo.ips = [];
|
||||
this.linkInfo.prefixLengths = [];
|
||||
this.linkInfo.addresses = [];
|
||||
this.linkInfo.dnses = [];
|
||||
this.linkInfo.gateways = [];
|
||||
|
||||
@@ -2946,7 +2767,7 @@ DataCall.prototype = {
|
||||
passwd: this.apnProfile.password,
|
||||
chappap: authType,
|
||||
pdptype: pdpType
|
||||
});
|
||||
}, this.onSetupDataCallResult.bind(this));
|
||||
this.state = RIL.GECKO_NETWORK_STATE_CONNECTING;
|
||||
},
|
||||
|
||||
@@ -3031,7 +2852,8 @@ DataCall.prototype = {
|
||||
radioInterface.sendWorkerMessage("deactivateDataCall", {
|
||||
cid: this.linkInfo.cid,
|
||||
reason: reason
|
||||
});
|
||||
}, this.onDeactivateDataCallResult.bind(this));
|
||||
|
||||
this.state = RIL.GECKO_NETWORK_STATE_DISCONNECTING;
|
||||
},
|
||||
|
||||
@@ -3101,29 +2923,37 @@ RILNetworkInterface.prototype = {
|
||||
return this.apnSetting.port || "";
|
||||
},
|
||||
|
||||
getAddresses: function(ips, prefixLengths) {
|
||||
let linkInfo = this.dataCall.linkInfo;
|
||||
getAddresses: function(aIps, aPrefixLengths) {
|
||||
let addresses = this.dataCall.linkInfo.addresses;
|
||||
|
||||
ips.value = linkInfo.ips.slice();
|
||||
prefixLengths.value = linkInfo.prefixLengths.slice();
|
||||
let ips = [];
|
||||
let prefixLengths = [];
|
||||
for (let i = 0; i < addresses.length; i++) {
|
||||
let [ip, prefixLength] = addresses[i].split("/");
|
||||
ips.push(ip);
|
||||
prefixLengths.push();
|
||||
}
|
||||
|
||||
return linkInfo.ips.length;
|
||||
aIps.value = ips.slice();
|
||||
aPrefixLengths.value = prefixLengths.slice();
|
||||
|
||||
return aIps.length;
|
||||
},
|
||||
|
||||
getGateways: function(count) {
|
||||
getGateways: function(aCount) {
|
||||
let linkInfo = this.dataCall.linkInfo;
|
||||
|
||||
if (count) {
|
||||
count.value = linkInfo.gateways.length;
|
||||
if (aCount) {
|
||||
aCount.value = linkInfo.gateways.length;
|
||||
}
|
||||
return linkInfo.gateways.slice();
|
||||
},
|
||||
|
||||
getDnses: function(count) {
|
||||
getDnses: function(aCount) {
|
||||
let linkInfo = this.dataCall.linkInfo;
|
||||
|
||||
if (count) {
|
||||
count.value = linkInfo.dnses.length;
|
||||
if (aCount) {
|
||||
aCount.value = linkInfo.dnses.length;
|
||||
}
|
||||
return linkInfo.dnses.slice();
|
||||
},
|
||||
@@ -3137,8 +2967,8 @@ RILNetworkInterface.prototype = {
|
||||
},
|
||||
|
||||
get iccId() {
|
||||
let iccInfo = this.dataConnectionHandler.radioInterface.rilContext.iccInfo;
|
||||
return iccInfo && iccInfo.iccid;
|
||||
let iccInfo = this.dataConnectionHandler.radioInterface.getIccInfo();
|
||||
return iccInfo ? iccInfo.iccid : null;
|
||||
},
|
||||
|
||||
get mmsc() {
|
||||
|
||||
@@ -88,6 +88,9 @@ EXTRA_JS_MODULES += [
|
||||
|
||||
if CONFIG['MOZ_B2G_RIL']:
|
||||
XPIDL_SOURCES += [
|
||||
'nsIDataCallInterfaceService.idl',
|
||||
'nsIDataCallManager.idl',
|
||||
'nsIGonkDataCallInterfaceService.idl',
|
||||
'nsIRadioInterfaceLayer.idl',
|
||||
]
|
||||
EXTRA_COMPONENTS += [
|
||||
@@ -100,10 +103,13 @@ if CONFIG['MOZ_B2G_RIL']:
|
||||
'ril_consts.js',
|
||||
'ril_worker.js',
|
||||
'ril_worker_buf_object.js',
|
||||
'ril_worker_telephony_request_queue.js',
|
||||
'RILSystemMessenger.jsm',
|
||||
]
|
||||
if not CONFIG['DISABLE_MOZ_RIL_GEOLOC']:
|
||||
EXTRA_COMPONENTS += [
|
||||
'DataCallInterfaceService.js',
|
||||
'DataCallInterfaceService.manifest',
|
||||
'RadioInterfaceLayer.js',
|
||||
'RadioInterfaceLayer.manifest',
|
||||
]
|
||||
|
||||
@@ -0,0 +1,257 @@
|
||||
/* 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/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[scriptable, uuid(d27ce247-9c7c-4582-826b-125e8275e9c2)]
|
||||
interface nsIDataCall : nsISupports
|
||||
{
|
||||
/**
|
||||
* Data call fail cause. One of the nsIDataCallInterface.DATACALL_FAIL_*
|
||||
* values.
|
||||
*/
|
||||
readonly attribute long failCause;
|
||||
|
||||
/**
|
||||
* If failCause != nsIDataCallInterface.DATACALL_FAIL_NONE, this field
|
||||
* indicates the suggested retry back-off timer. The unit is milliseconds.
|
||||
*/
|
||||
readonly attribute long suggestedRetryTime;
|
||||
|
||||
/**
|
||||
* Context ID, uniquely identifies this call.
|
||||
*/
|
||||
readonly attribute long cid;
|
||||
|
||||
/**
|
||||
* Data call network state. One of the nsIDataCallInterface.DATACALL_STATE_*
|
||||
* values.
|
||||
*/
|
||||
readonly attribute long active;
|
||||
|
||||
/**
|
||||
* Data call connection type. One of the
|
||||
* nsIDataCallInterface.DATACALL_PDP_TYPE_* values.
|
||||
*/
|
||||
readonly attribute long pdpType;
|
||||
|
||||
/**
|
||||
* The network interface name.
|
||||
*/
|
||||
readonly attribute DOMString ifname;
|
||||
|
||||
/**
|
||||
* A space-delimited list of addresses with optional "/" prefix length.
|
||||
*/
|
||||
readonly attribute DOMString addresses;
|
||||
|
||||
/**
|
||||
* A space-delimited list of DNS server addresses.
|
||||
*/
|
||||
readonly attribute DOMString dnses;
|
||||
|
||||
/**
|
||||
* A space-delimited list of default gateway addresses.
|
||||
*/
|
||||
readonly attribute DOMString gateways;
|
||||
};
|
||||
|
||||
[scriptable, uuid(e119c54b-9354-4ad6-a1ee-18608bde9320)]
|
||||
interface nsIDataCallInterfaceListener : nsISupports
|
||||
{
|
||||
/**
|
||||
* Notify data call interface listeners about unsolicited data call state
|
||||
* changes.
|
||||
*/
|
||||
void notifyDataCallListChanged(in uint32_t count,
|
||||
[array, size_is(count)] in nsIDataCall
|
||||
dataCalls);
|
||||
};
|
||||
|
||||
[scriptable, uuid(db0b640a-3b3a-4f48-84dc-256e176876c2)]
|
||||
interface nsIDataCallCallback : nsISupports
|
||||
{
|
||||
/**
|
||||
* Called when setupDataCall() returns succesfully.
|
||||
*/
|
||||
void notifySetupDataCallSuccess(in nsIDataCall dataCall);
|
||||
|
||||
/**
|
||||
* Called when getDataCallList() returns succesfully.
|
||||
*/
|
||||
void notifyGetDataCallListSuccess(in uint32_t count,
|
||||
[array, size_is(count)] in nsIDataCall
|
||||
dataCalls);
|
||||
/**
|
||||
* Called when request returns succesfully.
|
||||
*/
|
||||
void notifySuccess();
|
||||
|
||||
/**
|
||||
* Called when request returns error.
|
||||
*/
|
||||
void notifyError(in AString errorMsg);
|
||||
};
|
||||
|
||||
[scriptable, uuid(ec219021-8623-4b9f-aba5-4db58c60684f)]
|
||||
interface nsIDataCallInterface : nsISupports
|
||||
{
|
||||
/**
|
||||
* Data fail causes, defined in TS 24.008.
|
||||
*/
|
||||
const long DATACALL_FAIL_NONE = 0;
|
||||
const long DATACALL_FAIL_OPERATOR_BARRED = 0x08;
|
||||
const long DATACALL_FAIL_INSUFFICIENT_RESOURCES = 0x1A;
|
||||
const long DATACALL_FAIL_MISSING_UKNOWN_APN = 0x1B;
|
||||
const long DATACALL_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C;
|
||||
const long DATACALL_FAIL_USER_AUTHENTICATION = 0x1D;
|
||||
const long DATACALL_FAIL_ACTIVATION_REJECT_GGSN = 0x1E;
|
||||
const long DATACALL_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F;
|
||||
const long DATACALL_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20;
|
||||
const long DATACALL_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21;
|
||||
const long DATACALL_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22;
|
||||
const long DATACALL_FAIL_NSAPI_IN_USE = 0x23;
|
||||
const long DATACALL_FAIL_ONLY_IPV4_ALLOWED = 0x32;
|
||||
const long DATACALL_FAIL_ONLY_IPV6_ALLOWED = 0x33;
|
||||
const long DATACALL_FAIL_ONLY_SINGLE_BEARER_ALLOWED = 0x34;
|
||||
const long DATACALL_FAIL_PROTOCOL_ERRORS = 0x6F;
|
||||
/* Not mentioned in the specification */
|
||||
const long DATACALL_FAIL_VOICE_REGISTRATION_FAIL = -1;
|
||||
const long DATACALL_FAIL_DATA_REGISTRATION_FAIL = -2;
|
||||
const long DATACALL_FAIL_SIGNAL_LOST = -3;
|
||||
const long DATACALL_FAIL_PREF_RADIO_TECH_CHANGED = -4;
|
||||
const long DATACALL_FAIL_RADIO_POWER_OFF = -5;
|
||||
const long DATACALL_FAIL_TETHERED_CALL_ACTIVE = -6;
|
||||
const long DATACALL_FAIL_ERROR_UNSPECIFIED = 0xFFFF;
|
||||
|
||||
/**
|
||||
* Data call network state.
|
||||
*/
|
||||
const long DATACALL_STATE_INACTIVE = 0;
|
||||
const long DATACALL_STATE_ACTIVE_DOWN = 1;
|
||||
const long DATACALL_STATE_ACTIVE_UP = 2;
|
||||
|
||||
/**
|
||||
* Data call authentication type. Must match the values in ril_consts
|
||||
* RIL_DATACALL_AUTH_TO_GECKO array.
|
||||
*/
|
||||
const long DATACALL_AUTH_NONE = 0;
|
||||
const long DATACALL_AUTH_PAP = 1;
|
||||
const long DATACALL_AUTH_CHAP = 2;
|
||||
const long DATACALL_AUTH_PAP_OR_CHAP = 3;
|
||||
|
||||
/**
|
||||
* Data call protocol type. Must match the values in ril_consts
|
||||
* RIL_DATACALL_PDP_TYPES array.
|
||||
*/
|
||||
const long DATACALL_PDP_TYPE_IPV4 = 0;
|
||||
const long DATACALL_PDP_TYPE_IPV4V6 = 1;
|
||||
const long DATACALL_PDP_TYPE_IPV6 = 2;
|
||||
|
||||
/**
|
||||
* Reason for deactivating data call.
|
||||
*/
|
||||
const long DATACALL_DEACTIVATE_NO_REASON = 0;
|
||||
const long DATACALL_DEACTIVATE_RADIO_SHUTDOWN = 1;
|
||||
|
||||
/**
|
||||
* Setup data call.
|
||||
*
|
||||
* @param apn
|
||||
* Apn to connect to.
|
||||
* @param username
|
||||
* Username for apn.
|
||||
* @param password
|
||||
* Password for apn.
|
||||
* @param authType
|
||||
* Authentication type. One of the DATACALL_AUTH_* values.
|
||||
* @param pdpType
|
||||
* Connection type. One of the DATACALL_PDP_TYPE_* values.
|
||||
* @param nsIDataCallCallback
|
||||
* Called when request is finished.
|
||||
*
|
||||
* If successful, the notifySetupDataCallSuccess() will be called with the
|
||||
* new nsIDataCall.
|
||||
*
|
||||
* Otherwise, the notifyError() will be called, and the error will be either
|
||||
* 'RadioNotAvailable', 'OpNotAllowedBeforeRegToNw',
|
||||
* 'OpNotAllowedDuringVoiceCall', 'RequestNotSupported' or 'GenericFailure'.
|
||||
*/
|
||||
void setupDataCall(in AString apn, in AString username,
|
||||
in AString password, in long authType,
|
||||
in long pdpType,
|
||||
in nsIDataCallCallback callback);
|
||||
|
||||
/**
|
||||
* Deactivate data call.
|
||||
*
|
||||
* @param cid
|
||||
* Context id.
|
||||
* @param reason
|
||||
* Disconnect Reason. One of the DATACALL_DEACTIVATE_* values.
|
||||
* @param nsIDataCallCallback
|
||||
* Called when request is finished.
|
||||
*
|
||||
* If successful, the notifySuccess() will be called.
|
||||
*
|
||||
* Otherwise, the notifyError() will be called, and the error will be either
|
||||
* 'RadioNotAvailable' or 'GenericFailure'.
|
||||
*/
|
||||
void deactivateDataCall(in long cid,
|
||||
in long reason,
|
||||
in nsIDataCallCallback callback);
|
||||
|
||||
/**
|
||||
* Get current data call list.
|
||||
*
|
||||
* @param nsIDataCallCallback
|
||||
* Called when request is finished.
|
||||
*
|
||||
* If successful, the notifyGetDataCallListSuccess() will be called with the
|
||||
* list of nsIDataCall(s).
|
||||
*
|
||||
* Otherwise, the notifyError() will be called, and the error will be either
|
||||
* 'RadioNotAvailable' or 'GenericFailure'.
|
||||
*/
|
||||
void getDataCallList(in nsIDataCallCallback callback);
|
||||
|
||||
/**
|
||||
* Set data registration state.
|
||||
*
|
||||
* @param attach
|
||||
* whether to attach data registration or not.
|
||||
* @param nsIDataCallCallback
|
||||
* Called when request is finished.
|
||||
*
|
||||
* If successful, the notifySuccess() will be called.
|
||||
*
|
||||
* Otherwise, the notifyError() will be called, and the error will be either
|
||||
* 'RadioNotAvailable', 'SubscriptionNotAvailable' or 'GenericFailure'.
|
||||
*/
|
||||
void setDataRegistration(in boolean attach,
|
||||
in nsIDataCallCallback callback);
|
||||
|
||||
/**
|
||||
* Register to receive unsolicited events from this nsIDataCallInterface.
|
||||
*/
|
||||
void registerListener(in nsIDataCallInterfaceListener listener);
|
||||
|
||||
/**
|
||||
* Unregister to stop receiving unsolicited events from this
|
||||
* nsIDataCallInterface.
|
||||
*/
|
||||
void unregisterListener(in nsIDataCallInterfaceListener listener);
|
||||
};
|
||||
|
||||
[scriptable, uuid(64700406-7429-4743-a6ae-f82e9877fd0d)]
|
||||
interface nsIDataCallInterfaceService : nsISupports
|
||||
{
|
||||
/**
|
||||
* Get the corresponding data call interface.
|
||||
*
|
||||
* @param clientId
|
||||
* clientId of the data call interface to get.
|
||||
*/
|
||||
nsIDataCallInterface getDataCallInterface(in long clientId);
|
||||
};
|
||||
@@ -0,0 +1,68 @@
|
||||
/* 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/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
#include "nsINetworkManager.idl"
|
||||
|
||||
[scriptable, uuid(e48d290b-ea3b-4987-9333-2e01f64c92ba)]
|
||||
interface nsIRilNetworkInterface : nsINetworkInterface
|
||||
{
|
||||
readonly attribute unsigned long serviceId;
|
||||
readonly attribute DOMString iccId;
|
||||
|
||||
/* The following attributes are for MMS proxy settings. */
|
||||
readonly attribute DOMString mmsc; // Empty string if not set.
|
||||
readonly attribute DOMString mmsProxy; // Empty string if not set.
|
||||
readonly attribute long mmsPort; // -1 if not set.
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(cb2f0f5b-67f4-4c14-93e8-01e66b630464)]
|
||||
interface nsIDeactivateDataCallsCallback : nsISupports
|
||||
{
|
||||
/**
|
||||
* Callback function used to notify when all data calls are disconnected.
|
||||
*/
|
||||
void notifyDataCallsDisconnected();
|
||||
};
|
||||
|
||||
[scriptable, uuid(e3feec20-36b4-47de-a7a5-e32a65f20186)]
|
||||
interface nsIDataCallHandler : nsISupports
|
||||
{
|
||||
/**
|
||||
* PDP APIs
|
||||
*
|
||||
* @param networkType
|
||||
* Mobile network type, that is,
|
||||
* nsINetworkInterface.NETWORK_TYPE_MOBILE or one of the
|
||||
* nsINetworkInterface.NETWORK_TYPE_MOBILE_* values.
|
||||
*/
|
||||
void setupDataCallByType(in long networkType);
|
||||
void deactivateDataCallByType(in long networkType);
|
||||
long getDataCallStateByType(in long networkType);
|
||||
|
||||
/**
|
||||
* Deactivate all data calls.
|
||||
*
|
||||
* @param callback
|
||||
* Callback to notify when all data calls are disconnected.
|
||||
*/
|
||||
void deactivateDataCalls(in nsIDeactivateDataCallsCallback callback);
|
||||
|
||||
/**
|
||||
* Called to reconsider data call state.
|
||||
*/
|
||||
void updateRILNetworkInterface();
|
||||
};
|
||||
|
||||
[scriptable, uuid(aac54873-5771-4093-a72b-fe39967c6607)]
|
||||
interface nsIDataCallManager : nsISupports
|
||||
{
|
||||
/**
|
||||
* Get the corresponding data call handler.
|
||||
*
|
||||
* @param clientId
|
||||
* clientId of the data call handler to get.
|
||||
*/
|
||||
nsIDataCallHandler getDataCallHandler(in unsigned long clientId);
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
/* 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/. */
|
||||
|
||||
#include "nsIDataCallInterfaceService.idl"
|
||||
|
||||
[scriptable, uuid(f008d00c-e2b8-49b2-8f88-19111577938e)]
|
||||
interface nsIGonkDataCallInterfaceService : nsIDataCallInterfaceService
|
||||
{
|
||||
/**
|
||||
* Called by RadioInterface or lower layer to notify about data call list
|
||||
* changes.
|
||||
*/
|
||||
void notifyDataCallListChanged(in unsigned long clientId,
|
||||
in uint32_t count,
|
||||
[array, size_is(count)] in nsIDataCall
|
||||
dataCalls);
|
||||
};
|
||||
@@ -3,48 +3,20 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
#include "nsINetworkManager.idl"
|
||||
|
||||
interface nsIIccInfo;
|
||||
interface nsIMobileConnectionInfo;
|
||||
interface nsIMobileMessageCallback;
|
||||
|
||||
[scriptable, uuid(6e0f45b8-410e-11e3-8c8e-b715b2cd0128)]
|
||||
interface nsIRilNetworkInterface : nsINetworkInterface
|
||||
{
|
||||
readonly attribute unsigned long serviceId;
|
||||
readonly attribute DOMString iccId;
|
||||
|
||||
/* The following attributes are for MMS proxy settings. */
|
||||
readonly attribute DOMString mmsc; // Empty string if not set.
|
||||
readonly attribute DOMString mmsProxy; // Empty string if not set.
|
||||
readonly attribute long mmsPort; // -1 if not set.
|
||||
};
|
||||
|
||||
[scriptable, uuid(4441e660-4ad0-11e4-916c-0800200c9a66)]
|
||||
interface nsIRilContext : nsISupports
|
||||
{
|
||||
/**
|
||||
* One of the nsIIcc.CARD_STATE_* values.
|
||||
*/
|
||||
readonly attribute unsigned long cardState;
|
||||
|
||||
readonly attribute DOMString imsi;
|
||||
|
||||
readonly attribute nsIIccInfo iccInfo;
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(3bc96351-53b0-47a1-a888-c74c64b60f25)]
|
||||
interface nsIRilSendWorkerMessageCallback : nsISupports
|
||||
{
|
||||
boolean handleResponse(in jsval response);
|
||||
};
|
||||
|
||||
[scriptable, uuid(fe01c648-867a-11e4-915f-033b36e8177b)]
|
||||
[scriptable, uuid(1a3ef88a-e4d1-11e4-8512-176220f2b32b)]
|
||||
interface nsIRadioInterface : nsISupports
|
||||
{
|
||||
readonly attribute nsIRilContext rilContext;
|
||||
|
||||
/**
|
||||
* PDP APIs
|
||||
*
|
||||
@@ -79,13 +51,3 @@ interface nsIRadioInterfaceLayer : nsISupports
|
||||
|
||||
void setMicrophoneMuted(in boolean muted);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Helper Interface to define new APIs of nsIRadioInterfaceLayer during
|
||||
* ril-interfaces frozen phase.
|
||||
*/
|
||||
[scriptable, uuid(f8ec63da-c22e-11e4-89f3-b767dae42a13)]
|
||||
interface nsIRadioInterfaceLayer_new : nsIRadioInterfaceLayer
|
||||
{
|
||||
};
|
||||
|
||||
@@ -494,11 +494,6 @@ this.CELL_INFO_TYPE_CDMA = 2;
|
||||
this.CELL_INFO_TYPE_LTE = 3;
|
||||
this.CELL_INFO_TYPE_WCDMA = 4;
|
||||
|
||||
// Order matters.
|
||||
this.AUDIO_STATE_NO_CALL = 0;
|
||||
this.AUDIO_STATE_INCOMING = 1;
|
||||
this.AUDIO_STATE_IN_CALL = 2;
|
||||
|
||||
this.CALL_STATE_UNKNOWN = -1;
|
||||
this.CALL_STATE_ACTIVE = 0;
|
||||
this.CALL_STATE_HOLDING = 1;
|
||||
|
||||
+163
-808
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,157 @@
|
||||
/* global DEBUG, DEBUG_WORKER */
|
||||
/* global REQUEST_GET_CURRENT_CALLS */
|
||||
/* global REQUEST_ANSWER, REQUEST_CONFERENCE, REQUEST_DIAL */
|
||||
/* global REQUEST_DIAL_EMERGENCY_CALL, REQUEST_HANGUP */
|
||||
/* global REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND */
|
||||
/* global REQUEST_HANGUP_WAITING_OR_BACKGROUND */
|
||||
/* global REQUEST_SEPARATE_CONNECTION */
|
||||
/* global REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, REQUEST_UDUB */
|
||||
|
||||
"use strict";
|
||||
|
||||
(function(exports) {
|
||||
|
||||
const TELEPHONY_REQUESTS = [
|
||||
REQUEST_GET_CURRENT_CALLS,
|
||||
REQUEST_ANSWER,
|
||||
REQUEST_CONFERENCE,
|
||||
REQUEST_DIAL,
|
||||
REQUEST_DIAL_EMERGENCY_CALL,
|
||||
REQUEST_HANGUP,
|
||||
REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND,
|
||||
REQUEST_HANGUP_WAITING_OR_BACKGROUND,
|
||||
REQUEST_SEPARATE_CONNECTION,
|
||||
REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE,
|
||||
REQUEST_UDUB
|
||||
];
|
||||
|
||||
// Set to true in ril_consts.js to see debug messages
|
||||
let DEBUG = DEBUG_WORKER;
|
||||
|
||||
/**
|
||||
* Queue entry; only used in the queue.
|
||||
*/
|
||||
let TelephonyRequestEntry = function(request, callback) {
|
||||
this.request = request;
|
||||
this.callback = callback;
|
||||
};
|
||||
|
||||
let TelephonyRequestQueue = function(ril) {
|
||||
this.ril = ril;
|
||||
this.currentQueue = null; // Point to the current running queue.
|
||||
|
||||
this.queryQueue = [];
|
||||
this.controlQueue = [];
|
||||
};
|
||||
|
||||
TelephonyRequestQueue.prototype._getQueue = function(request) {
|
||||
return (request === REQUEST_GET_CURRENT_CALLS) ? this.queryQueue
|
||||
: this.controlQueue;
|
||||
};
|
||||
|
||||
TelephonyRequestQueue.prototype._getAnotherQueue = function(queue) {
|
||||
return (this.queryQueue === queue) ? this.controlQueue : this.queryQueue;
|
||||
};
|
||||
|
||||
TelephonyRequestQueue.prototype._find = function(queue, request) {
|
||||
for (let i = 0; i < queue.length; ++i) {
|
||||
if (queue[i].request === request) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
|
||||
TelephonyRequestQueue.prototype._startQueue = function(queue) {
|
||||
if (queue.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We only need to keep one entry for queryQueue.
|
||||
if (queue === this.queryQueue) {
|
||||
queue.splice(1, queue.length - 1);
|
||||
}
|
||||
|
||||
this.currentQueue = queue;
|
||||
for (let entry of queue) {
|
||||
this._executeEntry(entry);
|
||||
}
|
||||
};
|
||||
|
||||
TelephonyRequestQueue.prototype._executeEntry = function(entry) {
|
||||
if (DEBUG) {
|
||||
this.debug("execute " + this._getRequestName(entry.request));
|
||||
}
|
||||
entry.callback();
|
||||
};
|
||||
|
||||
TelephonyRequestQueue.prototype._getRequestName = function(request) {
|
||||
let method = this.ril[request];
|
||||
return (typeof method === 'function') ? method.name : "";
|
||||
};
|
||||
|
||||
TelephonyRequestQueue.prototype.debug = function(msg) {
|
||||
this.ril.context.debug("[TeleQ] " + msg);
|
||||
};
|
||||
|
||||
TelephonyRequestQueue.prototype.isValidRequest = function(request) {
|
||||
return TELEPHONY_REQUESTS.indexOf(request) !== -1;
|
||||
};
|
||||
|
||||
TelephonyRequestQueue.prototype.push = function(request, callback) {
|
||||
if (!this.isValidRequest(request)) {
|
||||
if (DEBUG) {
|
||||
this.debug("Error: " + this._getRequestName(request) +
|
||||
" is not a telephony request");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
this.debug("push " + this._getRequestName(request));
|
||||
}
|
||||
let entry = new TelephonyRequestEntry(request, callback);
|
||||
let queue = this._getQueue(request);
|
||||
queue.push(entry);
|
||||
|
||||
// Try to run the request.
|
||||
if (this.currentQueue === queue) {
|
||||
this._executeEntry(entry);
|
||||
} else if (!this.currentQueue) {
|
||||
this._startQueue(queue);
|
||||
}
|
||||
};
|
||||
|
||||
TelephonyRequestQueue.prototype.pop = function(request) {
|
||||
if (!this.isValidRequest(request)) {
|
||||
if (DEBUG) {
|
||||
this.debug("Error: " + this._getRequestName(request) +
|
||||
" is not a telephony request");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
this.debug("pop " + this._getRequestName(request));
|
||||
}
|
||||
let queue = this._getQueue(request);
|
||||
let index = this._find(queue, request);
|
||||
if (index === -1) {
|
||||
throw new Error("Cannot find the request in telephonyRequestQueue.");
|
||||
} else {
|
||||
queue.splice(index, 1);
|
||||
}
|
||||
|
||||
if (queue.length === 0) {
|
||||
this.currentQueue = null;
|
||||
this._startQueue(this._getAnotherQueue(queue));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Before we make sure to form it as a module would not add extra
|
||||
// overhead of module loading, we need to define it in this way
|
||||
// rather than 'module.exports' it as a module component.
|
||||
exports.TelephonyRequestQueue = TelephonyRequestQueue;
|
||||
})(self); // in worker self is the global
|
||||
|
||||
@@ -78,18 +78,6 @@ this.DialNumberUtils = {
|
||||
return new RegExp("^" + fullmmi + optionalDialString + "$");
|
||||
})(),
|
||||
|
||||
_isPoundString: function(aString) {
|
||||
return aString && aString[aString.length - 1] === "#";
|
||||
},
|
||||
|
||||
_isShortString: function(aString) {
|
||||
if (!aString || this.isEmergency(aString) || aString.length > 2 ||
|
||||
(aString.length == 2 && aString[0] === "1")) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check parse the given string as an MMI code.
|
||||
*
|
||||
@@ -117,12 +105,6 @@ this.DialNumberUtils = {
|
||||
};
|
||||
}
|
||||
|
||||
if (this._isPoundString(aString) || this._isShortString(aString)) {
|
||||
return {
|
||||
fullMMI: aString
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -157,6 +157,26 @@ TelephonyCallInfo.prototype = {
|
||||
isMergeable: true
|
||||
};
|
||||
|
||||
function Call(aClientId, aCallIndex) {
|
||||
this.clientId = aClientId;
|
||||
this.callIndex = aCallIndex;
|
||||
}
|
||||
Call.prototype = {
|
||||
clientId: 0,
|
||||
callIndex: 0,
|
||||
state: nsITelephonyService.CALL_STATE_UNKNOWN,
|
||||
number: "",
|
||||
numberPresentation: nsITelephonyService.CALL_PRESENTATION_ALLOWED,
|
||||
name: "",
|
||||
namePresentation: nsITelephonyService.CALL_PRESENTATION_ALLOWED,
|
||||
isOutgoing: true,
|
||||
isEmergency: false,
|
||||
isConference: false,
|
||||
isSwitchable: true,
|
||||
isMergeable: true,
|
||||
started: null
|
||||
};
|
||||
|
||||
function TelephonyService() {
|
||||
this._numClients = gRadioInterfaceLayer.numRadioInterfaces;
|
||||
this._listeners = [];
|
||||
@@ -165,7 +185,7 @@ function TelephonyService() {
|
||||
this._cachedDialRequest = null;
|
||||
this._currentCalls = {};
|
||||
this._currentConferenceState = nsITelephonyService.CALL_STATE_UNKNOWN;
|
||||
this._audioStates = {};
|
||||
this._audioStates = [];
|
||||
|
||||
this._cdmaCallWaitingNumber = null;
|
||||
|
||||
@@ -178,8 +198,9 @@ function TelephonyService() {
|
||||
Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
|
||||
|
||||
for (let i = 0; i < this._numClients; ++i) {
|
||||
this._audioStates[i] = nsITelephonyAudioService.PHONE_STATE_NORMAL;
|
||||
this._currentCalls[i] = {};
|
||||
this._enumerateCallsForClient(i);
|
||||
this._audioStates[i] = RIL.AUDIO_STATE_NO_CALL;
|
||||
}
|
||||
}
|
||||
TelephonyService.prototype = {
|
||||
@@ -285,18 +306,39 @@ TelephonyService.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_updateAudioState: function(aAudioState) {
|
||||
switch (aAudioState) {
|
||||
case RIL.AUDIO_STATE_NO_CALL:
|
||||
gAudioService.setPhoneState(nsITelephonyAudioService.PHONE_STATE_NORMAL);
|
||||
break;
|
||||
case RIL.AUDIO_STATE_INCOMING:
|
||||
gAudioService.setPhoneState(nsITelephonyAudioService.PHONE_STATE_RINGTONE);
|
||||
break;
|
||||
case RIL.AUDIO_STATE_IN_CALL:
|
||||
gAudioService.setPhoneState(nsITelephonyAudioService.PHONE_STATE_IN_CALL);
|
||||
break;
|
||||
_computeAudioStateForClient: function(aClientId) {
|
||||
let indexes = Object.keys(this._currentCalls[aClientId]);
|
||||
if (!indexes.length) {
|
||||
return nsITelephonyAudioService.PHONE_STATE_NORMAL;
|
||||
}
|
||||
|
||||
let firstCall = this._currentCalls[aClientId][indexes[0]];
|
||||
if (indexes.length === 1 &&
|
||||
firstCall.state === nsITelephonyService.CALL_STATE_INCOMING) {
|
||||
return nsITelephonyAudioService.PHONE_STATE_RINGTONE;
|
||||
}
|
||||
|
||||
return nsITelephonyAudioService.PHONE_STATE_IN_CALL;
|
||||
},
|
||||
|
||||
_updateAudioState: function(aClientId) {
|
||||
this._audioStates[aClientId] = this._computeAudioStateForClient(aClientId);
|
||||
|
||||
if (this._audioStates.some(state => state === nsITelephonyAudioService.PHONE_STATE_IN_CALL)) {
|
||||
gAudioService.setPhoneState(nsITelephonyAudioService.PHONE_STATE_IN_CALL);
|
||||
} else if (this._audioStates.some(state => state === nsITelephonyAudioService.PHONE_STATE_RINGTONE)) {
|
||||
gAudioService.setPhoneState(nsITelephonyAudioService.PHONE_STATE_RINGTONE);
|
||||
} else {
|
||||
gAudioService.setPhoneState(nsITelephonyAudioService.PHONE_STATE_NORMAL);
|
||||
}
|
||||
},
|
||||
|
||||
_formatInternationalNumber: function(aNumber, aToa) {
|
||||
if (aNumber && aToa == RIL.TOA_INTERNATIONAL && aNumber[0] != "+") {
|
||||
return "+" + aNumber;
|
||||
}
|
||||
|
||||
return aNumber;
|
||||
},
|
||||
|
||||
_convertRILCallState: function(aState) {
|
||||
@@ -359,17 +401,17 @@ TelephonyService.prototype = {
|
||||
_enumerateCallsForClient: function(aClientId) {
|
||||
if (DEBUG) debug("Enumeration of calls for client " + aClientId);
|
||||
|
||||
this._sendToRilWorker(aClientId, "enumerateCalls", null, response => {
|
||||
if (!this._currentCalls[aClientId]) {
|
||||
this._currentCalls[aClientId] = {};
|
||||
this._sendToRilWorker(aClientId, "getCurrentCalls", null, response => {
|
||||
if (response.errorMsg) {
|
||||
return;
|
||||
}
|
||||
for (let call of response.calls) {
|
||||
call.clientId = aClientId;
|
||||
call.state = this._convertRILCallState(call.state);
|
||||
call.isSwitchable = true;
|
||||
call.isMergeable = true;
|
||||
|
||||
this._currentCalls[aClientId][call.callIndex] = call;
|
||||
// Clear all.
|
||||
this._currentCalls[aClientId] = {};
|
||||
|
||||
for (let i in response.calls) {
|
||||
let call = this._currentCalls[aClientId][i] = new Call(aClientId, i);
|
||||
this._updateCallFromRil(call, response.calls[i]);
|
||||
}
|
||||
});
|
||||
},
|
||||
@@ -474,18 +516,23 @@ TelephonyService.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Get arbitrary one of active call.
|
||||
* Is there an active call?
|
||||
*/
|
||||
_getOneActiveCall: function(aClientId) {
|
||||
_isActive: function(aClientId) {
|
||||
for (let index in this._currentCalls[aClientId]) {
|
||||
let call = this._currentCalls[aClientId][index];
|
||||
if (call.state === nsITelephonyService.CALL_STATE_CONNECTED) {
|
||||
return call;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Dial number. Perform call setup or SS procedure accordingly.
|
||||
*
|
||||
* @see 3GPP TS 22.030 Figure 3.5.3.2
|
||||
*/
|
||||
dial: function(aClientId, aNumber, aIsDialEmergency, aCallback) {
|
||||
if (DEBUG) debug("Dialing " + (aIsDialEmergency ? "emergency " : "") + aNumber);
|
||||
|
||||
@@ -505,16 +552,21 @@ TelephonyService.prototype = {
|
||||
|
||||
let isEmergencyNumber = gDialNumberUtils.isEmergency(aNumber);
|
||||
|
||||
// Should be radio on except it's an emergency number.
|
||||
if (!(this._isRadioOn(aClientId) || isEmergencyNumber)) {
|
||||
aCallback.notifyError(DIAL_ERROR_RADIO_NOT_AVAILABLE);
|
||||
// DialEmergency accepts only emergency number.
|
||||
if (aIsDialEmergency && !isEmergencyNumber) {
|
||||
if (!this._isRadioOn(aClientId)) {
|
||||
if (DEBUG) debug("Error: Radio is off. Drop.");
|
||||
aCallback.notifyError(DIAL_ERROR_RADIO_NOT_AVAILABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (DEBUG) debug("Error: Dial a non-emergency by dialEmergency. Drop.");
|
||||
aCallback.notifyError(DIAL_ERROR_BAD_NUMBER);
|
||||
return;
|
||||
}
|
||||
|
||||
// DialEmergency accepts only emergency number.
|
||||
if (aIsDialEmergency && !isEmergencyNumber) {
|
||||
if (DEBUG) debug("Error: Dail a non-emergency by dialEmergency. Drop.");
|
||||
aCallback.notifyError(DIAL_ERROR_BAD_NUMBER);
|
||||
if (isEmergencyNumber) {
|
||||
this._dialCall(aClientId, aNumber, undefined, aCallback);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -524,47 +576,56 @@ TelephonyService.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._hasCalls(aClientId)) {
|
||||
this._dialInCallMMI(aClientId, aNumber, aCallback);
|
||||
return;
|
||||
}
|
||||
|
||||
let mmi = gDialNumberUtils.parseMMI(aNumber);
|
||||
if (!mmi) {
|
||||
this._dialCall(aClientId, aNumber, undefined, aCallback);
|
||||
} else if (this._isTemporaryCLIR(mmi)) {
|
||||
this._dialCall(aClientId, mmi.dialNumber,
|
||||
this._procedureToCLIRMode(mmi.procedure), aCallback);
|
||||
if (mmi) {
|
||||
if (this._isTemporaryCLIR(mmi)) {
|
||||
this._dialCall(aClientId, mmi.dialNumber,
|
||||
this._procedureToCLIRMode(mmi.procedure), aCallback);
|
||||
} else {
|
||||
this._dialMMI(aClientId, mmi, aCallback);
|
||||
}
|
||||
} else {
|
||||
this._dialMMI(aClientId, mmi, aCallback);
|
||||
if (aNumber[aNumber.length - 1] === "#") { // # string
|
||||
this._dialMMI(aClientId, {fullMMI: aNumber}, aCallback);
|
||||
} else if (aNumber.length <= 2) { // short string
|
||||
if (this._hasCalls(aClientId)) {
|
||||
this._dialInCallMMI(aClientId, aNumber, aCallback);
|
||||
} else if (aNumber.length === 2 && aNumber[0] === "1") {
|
||||
this._dialCall(aClientId, aNumber, undefined, aCallback);
|
||||
} else {
|
||||
this._dialMMI(aClientId, {fullMMI: aNumber}, aCallback);
|
||||
}
|
||||
} else {
|
||||
this._dialCall(aClientId, aNumber, undefined, aCallback);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Handling of supplementary services within a call as 3GPP TS 22.030 6.5.5
|
||||
_dialInCallMMI: function(aClientId, aNumber, aCallback) {
|
||||
let mmiCallback = response => {
|
||||
aCallback.notifyDialMMI(RIL.MMI_KS_SC_CALL);
|
||||
if (!response.success) {
|
||||
aCallback.notifyDialMMIError(RIL.MMI_ERROR_KS_ERROR);
|
||||
} else {
|
||||
aCallback.notifyDialMMISuccess(RIL.MMI_SM_KS_CALL_CONTROL);
|
||||
}
|
||||
let mmiCallback = {
|
||||
notifyError: () => aCallback.notifyDialMMIError(RIL.MMI_ERROR_KS_ERROR),
|
||||
notifySuccess: () => aCallback.notifyDialMMISuccess(RIL.MMI_SM_KS_CALL_CONTROL)
|
||||
};
|
||||
|
||||
if (aNumber === "0") {
|
||||
this._sendToRilWorker(aClientId, "hangUpBackground", null, mmiCallback);
|
||||
aCallback.notifyDialMMI(RIL.MMI_KS_SC_CALL);
|
||||
this._hangUpBackground(aClientId, mmiCallback);
|
||||
} else if (aNumber === "1") {
|
||||
this._sendToRilWorker(aClientId, "hangUpForeground", null, mmiCallback);
|
||||
aCallback.notifyDialMMI(RIL.MMI_KS_SC_CALL);
|
||||
this._hangUpForeground(aClientId, mmiCallback);
|
||||
} else if (aNumber[0] === "1" && aNumber.length === 2) {
|
||||
this._sendToRilWorker(aClientId, "hangUpCall",
|
||||
{ callIndex: parseInt(aNumber[1]) }, mmiCallback);
|
||||
aCallback.notifyDialMMI(RIL.MMI_KS_SC_CALL);
|
||||
this.hangUpCall(aClientId, parseInt(aNumber[1]), mmiCallback);
|
||||
} else if (aNumber === "2") {
|
||||
this._sendToRilWorker(aClientId, "switchActiveCall", null, mmiCallback);
|
||||
aCallback.notifyDialMMI(RIL.MMI_KS_SC_CALL);
|
||||
this._switchActiveCall(aClientId, mmiCallback);
|
||||
} else if (aNumber[0] === "2" && aNumber.length === 2) {
|
||||
this._sendToRilWorker(aClientId, "separateCall",
|
||||
{ callIndex: parseInt(aNumber[1]) }, mmiCallback);
|
||||
aCallback.notifyDialMMI(RIL.MMI_KS_SC_CALL);
|
||||
this._separateCallGsm(aClientId, parseInt(aNumber[1]), mmiCallback);
|
||||
} else if (aNumber === "3") {
|
||||
this._sendToRilWorker(aClientId, "conferenceCall", null, mmiCallback);
|
||||
aCallback.notifyDialMMI(RIL.MMI_KS_SC_CALL);
|
||||
this._conferenceCallGsm(aClientId, mmiCallback);
|
||||
} else {
|
||||
this._dialCall(aClientId, aNumber, undefined, aCallback);
|
||||
}
|
||||
@@ -594,9 +655,19 @@ TelephonyService.prototype = {
|
||||
}
|
||||
|
||||
let isEmergency = gDialNumberUtils.isEmergency(aNumber);
|
||||
if (!isEmergency && this._isEmergencyOnly()) {
|
||||
if (DEBUG) debug("Error: Dail a normal call when emergencyCallsOnly. Drop");
|
||||
aCallback.notifyError(DIAL_ERROR_BAD_NUMBER);
|
||||
|
||||
if (!isEmergency) {
|
||||
if (!this._isRadioOn(aClientId)) {
|
||||
if (DEBUG) debug("Error: Dial a normal call when radio off. Drop");
|
||||
aCallback.notifyError(DIAL_ERROR_RADIO_NOT_AVAILABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._isEmergencyOnly()) {
|
||||
if (DEBUG) debug("Error: Dial a normal call when emergencyCallsOnly. Drop");
|
||||
aCallback.notifyError(DIAL_ERROR_BAD_NUMBER);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (isEmergency) {
|
||||
@@ -616,8 +687,7 @@ TelephonyService.prototype = {
|
||||
};
|
||||
|
||||
// No active call. Dial it out directly.
|
||||
let activeCall = this._getOneActiveCall(aClientId);
|
||||
if (!activeCall) {
|
||||
if (!this._isActive(aClientId)) {
|
||||
this._sendDialCallRequest(aClientId, options, aCallback);
|
||||
return;
|
||||
}
|
||||
@@ -637,7 +707,7 @@ TelephonyService.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
let autoHoldCallback = {
|
||||
this._switchActiveCall(aClientId, {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsITelephonyCallback]),
|
||||
|
||||
notifySuccess: () => {
|
||||
@@ -652,13 +722,7 @@ TelephonyService.prototype = {
|
||||
if (DEBUG) debug("Error: Fail to automatically hold the active call.");
|
||||
aCallback.notifyError(aErrorMsg);
|
||||
}
|
||||
};
|
||||
|
||||
if (activeCall.isConference) {
|
||||
this.holdConference(aClientId, autoHoldCallback);
|
||||
} else {
|
||||
this.holdCall(aClientId, activeCall.callIndex, autoHoldCallback);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_dialCdmaThreeWayCall: function(aClientId, aNumber, aCallback) {
|
||||
@@ -673,30 +737,30 @@ TelephonyService.prototype = {
|
||||
aCallback.notifyDialCallSuccess(aClientId, CDMA_SECOND_CALL_INDEX,
|
||||
aNumber);
|
||||
|
||||
let childCall = {
|
||||
callIndex: CDMA_SECOND_CALL_INDEX,
|
||||
state: RIL.CALL_STATE_DIALING,
|
||||
number: aNumber,
|
||||
isOutgoing: true,
|
||||
isEmergency: false,
|
||||
isConference: false,
|
||||
isSwitchable: false,
|
||||
isMergeable: true,
|
||||
parentId: CDMA_FIRST_CALL_INDEX
|
||||
};
|
||||
let childCall = this._currentCalls[aClientId][CDMA_SECOND_CALL_INDEX] =
|
||||
new Call(aClientId, CDMA_SECOND_CALL_INDEX);
|
||||
|
||||
childCall.parentId = CDMA_FIRST_CALL_INDEX;
|
||||
childCall.state = nsITelephonyService.CALL_STATE_DIALING;
|
||||
childCall.number = aNumber;
|
||||
childCall.isOutgoing = true;
|
||||
childCall.isEmergency = gDialNumberUtils.isEmergency(aNumber);
|
||||
childCall.isConference = false;
|
||||
childCall.isSwitchable = false;
|
||||
childCall.isMergeable = true;
|
||||
|
||||
// Manual update call state according to the request response.
|
||||
this.notifyCallStateChanged(aClientId, childCall);
|
||||
this._handleCallStateChanged(aClientId, childCall);
|
||||
|
||||
childCall.state = RIL.CALL_STATE_ACTIVE;
|
||||
this.notifyCallStateChanged(aClientId, childCall);
|
||||
childCall.state = nsITelephonyService.CALL_STATE_CONNECTED;
|
||||
this._handleCallStateChanged(aClientId, childCall);
|
||||
|
||||
let parentCall = this._currentCalls[aClientId][childCall.parentId];
|
||||
parentCall.childId = CDMA_SECOND_CALL_INDEX;
|
||||
parentCall.state = RIL.CALL_STATE_HOLDING;
|
||||
parentCall.state = nsITelephonyService.CALL_STATE_HELD;
|
||||
parentCall.isSwitchable = false;
|
||||
parentCall.isMergeable = true;
|
||||
this.notifyCallStateChanged(aClientId, parentCall);
|
||||
this._handleCallStateChanged(aClientId, parentCall);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -707,12 +771,15 @@ TelephonyService.prototype = {
|
||||
this._isDialing = false;
|
||||
|
||||
if (!response.success) {
|
||||
aCallback.notifyError(response.errorMsg);
|
||||
return;
|
||||
this._sendToRilWorker(aClientId, "getFailCause", null, response => {
|
||||
aCallback.notifyError(response.failCause);
|
||||
});
|
||||
} else {
|
||||
this._ongoingDial = {
|
||||
clientId: aClientId,
|
||||
callback: aCallback
|
||||
};
|
||||
}
|
||||
|
||||
aCallback.notifyDialCallSuccess(aClientId, response.callIndex,
|
||||
response.number);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -859,6 +926,76 @@ TelephonyService.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_getCallsWithState: function(aClientId, aState) {
|
||||
let calls = [];
|
||||
for (let i in this._currentCalls[aClientId]) {
|
||||
let call = this._currentCalls[aClientId][i];
|
||||
if (call.state === aState) {
|
||||
calls.push(call);
|
||||
}
|
||||
}
|
||||
return calls;
|
||||
},
|
||||
|
||||
/**
|
||||
* Update call information from RIL.
|
||||
*
|
||||
* @return Boolean to indicate whether the data is changed.
|
||||
*/
|
||||
_updateCallFromRil: function(aCall, aRilCall) {
|
||||
aRilCall.state = this._convertRILCallState(aRilCall.state);
|
||||
aRilCall.number = this._formatInternationalNumber(aRilCall.number,
|
||||
aRilCall.toa);
|
||||
|
||||
if (!aCall.started &&
|
||||
aCall.state == nsITelephonyService.CALL_STATE_CONNECTED) {
|
||||
aCall.started = new Date().getTime();
|
||||
}
|
||||
|
||||
let change = false;
|
||||
const key = ["state", "number", "numberPresentation", "name",
|
||||
"namePresentation"];
|
||||
|
||||
for (let k of key) {
|
||||
if (aCall[k] != aRilCall[k]) {
|
||||
aCall[k] = aRilCall[k];
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
|
||||
aCall.isOutgoing = !aRilCall.isMT;
|
||||
aCall.isEmergency = gDialNumberUtils.isEmergency(aCall.number);
|
||||
|
||||
return change;
|
||||
},
|
||||
|
||||
/**
|
||||
* Identify the conference group.
|
||||
* Return the conference state and a array of calls in group.
|
||||
*
|
||||
* TODO: handle multi-sim case.
|
||||
*/
|
||||
_detectConference: function(aClientId) {
|
||||
// There are some difficuties to identify the conference by |.isMpty| from RIL
|
||||
// so we don't rely on this flag.
|
||||
// - |.isMpty| becomes false when the conference call is put on hold.
|
||||
// - |.isMpty| may remain true when other participants left the conference.
|
||||
|
||||
// All the calls in the conference should have the same state and it is
|
||||
// either CONNECTED or HELD. That means, if we find a group of call with
|
||||
// the same state and its size is larger than 2, it must be a conference.
|
||||
let connectedCalls = this._getCallsWithState(aClientId, nsITelephonyService.CALL_STATE_CONNECTED);
|
||||
let heldCalls = this._getCallsWithState(aClientId, nsITelephonyService.CALL_STATE_HELD);
|
||||
|
||||
if (connectedCalls.length >= 2) {
|
||||
return [nsITelephonyService.CALL_STATE_CONNECTED, connectedCalls];
|
||||
} else if (heldCalls.length >= 2) {
|
||||
return [nsITelephonyService.CALL_STATE_HELD, heldCalls];
|
||||
}
|
||||
|
||||
return [nsITelephonyService.CALL_STATE_UNKNOWN, null];
|
||||
},
|
||||
|
||||
sendTones: function(aClientId, aDtmfChars, aPauseDuration, aToneDuration,
|
||||
aCallback) {
|
||||
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
@@ -898,12 +1035,63 @@ TelephonyService.prototype = {
|
||||
},
|
||||
|
||||
answerCall: function(aClientId, aCallIndex, aCallback) {
|
||||
this._sendToRilWorker(aClientId, "answerCall", { callIndex: aCallIndex },
|
||||
this._defaultCallbackHandler.bind(this, aCallback));
|
||||
let call = this._currentCalls[aClientId][aCallIndex];
|
||||
if (!call || call.state != nsITelephonyService.CALL_STATE_INCOMING) {
|
||||
aCallback.notifyError(RIL.GECKO_ERROR_GENERIC_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
let callNum = Object.keys(this._currentCalls[aClientId]).length;
|
||||
if (callNum !== 1) {
|
||||
this._switchActiveCall(aClientId, aCallback);
|
||||
} else {
|
||||
this._sendToRilWorker(aClientId, "answerCall", null,
|
||||
this._defaultCallbackHandler.bind(this, aCallback));
|
||||
}
|
||||
},
|
||||
|
||||
rejectCall: function(aClientId, aCallIndex, aCallback) {
|
||||
this._sendToRilWorker(aClientId, "rejectCall", { callIndex: aCallIndex },
|
||||
if (this._isCdmaClient(aClientId)) {
|
||||
this._hangUpBackground(aClientId, aCallback);
|
||||
return;
|
||||
}
|
||||
|
||||
let call = this._currentCalls[aClientId][aCallIndex];
|
||||
if (!call || call.state != nsITelephonyService.CALL_STATE_INCOMING) {
|
||||
aCallback.notifyError(RIL.GECKO_ERROR_GENERIC_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
let callNum = Object.keys(this._currentCalls[aClientId]).length;
|
||||
if (callNum !== 1) {
|
||||
this._hangUpBackground(aClientId, aCallback);
|
||||
} else {
|
||||
this._sendToRilWorker(aClientId, "udub", null,
|
||||
this._defaultCallbackHandler.bind(this, aCallback));
|
||||
}
|
||||
},
|
||||
|
||||
_hangUpForeground: function(aClientId, aCallback) {
|
||||
let calls = this._getCallsWithState(aClientId, nsITelephonyService.CALL_STATE_CONNECTED);
|
||||
calls.forEach(call => call.hangUpLocal = true);
|
||||
|
||||
this._sendToRilWorker(aClientId, "hangUpForeground", null,
|
||||
this._defaultCallbackHandler.bind(this, aCallback));
|
||||
},
|
||||
|
||||
_hangUpBackground: function(aClientId, aCallback) {
|
||||
// When both a held and a waiting call exist, the request shall apply to
|
||||
// the waiting call.
|
||||
let waitingCalls = this._getCallsWithState(aClientId, nsITelephonyService.CALL_STATE_INCOMING);
|
||||
let heldCalls = this._getCallsWithState(aClientId, nsITelephonyService.CALL_STATE_HELD);
|
||||
|
||||
if (waitingCalls.length) {
|
||||
waitingCalls.forEach(call => call.hangUpLocal = true);
|
||||
} else {
|
||||
heldCalls.forEach(call => call.hangUpLocal = true);
|
||||
}
|
||||
|
||||
this._sendToRilWorker(aClientId, "hangUpBackground", null,
|
||||
this._defaultCallbackHandler.bind(this, aCallback));
|
||||
},
|
||||
|
||||
@@ -912,6 +1100,13 @@ TelephonyService.prototype = {
|
||||
// the parent call, we send 'parentId' to RIL.
|
||||
aCallIndex = this._currentCalls[aClientId][aCallIndex].parentId || aCallIndex;
|
||||
|
||||
let call = this._currentCalls[aClientId][aCallIndex];
|
||||
if (call.state === nsITelephonyService.CALL_STATE_HELD) {
|
||||
this._hangUpBackground(aClientId, aCallback);
|
||||
return;
|
||||
}
|
||||
|
||||
call.hangUpLocal = true;
|
||||
this._sendToRilWorker(aClientId, "hangUpCall", { callIndex: aCallIndex },
|
||||
this._defaultCallbackHandler.bind(this, aCallback));
|
||||
},
|
||||
@@ -937,6 +1132,10 @@ TelephonyService.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
this._switchActiveCall(aClientId, aCallback);
|
||||
},
|
||||
|
||||
_switchActiveCall: function(aClientId, aCallback) {
|
||||
this._sendToRilWorker(aClientId, "switchActiveCall", null,
|
||||
this._defaultCallbackHandler.bind(this, aCallback));
|
||||
},
|
||||
@@ -996,11 +1195,11 @@ TelephonyService.prototype = {
|
||||
|
||||
for (let index in this._currentCalls[aClientId]) {
|
||||
let call = this._currentCalls[aClientId][index];
|
||||
call.state = RIL.CALL_STATE_ACTIVE;
|
||||
call.state = nsITelephonyService.CALL_STATE_CONNECTED;
|
||||
call.isConference = true;
|
||||
this.notifyCallStateChanged(aClientId, call);
|
||||
this._handleCallStateChanged(aClientId, call);
|
||||
}
|
||||
this.notifyConferenceCallStateChanged(RIL.CALL_STATE_ACTIVE);
|
||||
this._handleConferenceCallStateChanged(nsITelephonyService.CALL_STATE_CONNECTED);
|
||||
|
||||
aCallback.notifySuccess();
|
||||
});
|
||||
@@ -1048,7 +1247,7 @@ TelephonyService.prototype = {
|
||||
}
|
||||
|
||||
let childCall = this._currentCalls[aClientId][CDMA_SECOND_CALL_INDEX];
|
||||
this.notifyCallDisconnected(aClientId, childCall);
|
||||
this._handleCallDisconnected(aClientId, childCall);
|
||||
|
||||
aCallback.notifySuccess();
|
||||
});
|
||||
@@ -1091,8 +1290,7 @@ TelephonyService.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
this._sendToRilWorker(aClientId, "switchActiveCall", null,
|
||||
this._defaultCallbackHandler.bind(this, aCallback));
|
||||
this._switchActiveCall(aClientId, aCallback);
|
||||
},
|
||||
|
||||
holdConference: function(aClientId, aCallback) {
|
||||
@@ -1133,26 +1331,13 @@ TelephonyService.prototype = {
|
||||
* nsIGonkTelephonyService interface.
|
||||
*/
|
||||
|
||||
notifyAudioStateChanged: function(aClientId, aState) {
|
||||
this._audioStates[aClientId] = aState;
|
||||
|
||||
let audioState = aState;
|
||||
for (let i = 0; i < this._numClients; ++i) {
|
||||
audioState = Math.max(audioState, this._audioStates[i]);
|
||||
}
|
||||
|
||||
this._updateAudioState(audioState);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle call disconnects by updating our current state and the audio system.
|
||||
*/
|
||||
notifyCallDisconnected: function(aClientId, aCall) {
|
||||
_handleCallDisconnected: function(aClientId, aCall) {
|
||||
if (DEBUG) debug("handleCallDisconnected: " + JSON.stringify(aCall));
|
||||
|
||||
aCall.clientId = aClientId;
|
||||
aCall.state = nsITelephonyService.CALL_STATE_DISCONNECTED;
|
||||
aCall.isEmergency = gDialNumberUtils.isEmergency(aCall.number);
|
||||
let duration = ("started" in aCall && typeof aCall.started == "number") ?
|
||||
new Date().getTime() - aCall.started : 0;
|
||||
|
||||
@@ -1172,7 +1357,7 @@ TelephonyService.prototype = {
|
||||
if (childId) {
|
||||
// Child cannot live without parent.
|
||||
let childCall = this._currentCalls[aClientId][childId];
|
||||
this.notifyCallDisconnected(aClientId, childCall);
|
||||
this._handleCallDisconnected(aClientId, childCall);
|
||||
} else {
|
||||
let parentId = this._currentCalls[aClientId][aCall.callIndex].parentId;
|
||||
if (parentId) {
|
||||
@@ -1187,12 +1372,12 @@ TelephonyService.prototype = {
|
||||
parentCall.isSwitchable = true;
|
||||
parentCall.isMergeable = true;
|
||||
aCall.isConference = false;
|
||||
this.notifyCallStateChanged(aClientId, parentCall, true);
|
||||
this._handleCallStateChanged(aClientId, parentCall);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!aCall.failCause ||
|
||||
if (aCall.hangUpLocal || !aCall.failCause ||
|
||||
aCall.failCause === RIL.GECKO_CALL_ERROR_NORMAL_CALL_CLEARING) {
|
||||
let callInfo = new TelephonyCallInfo(aCall);
|
||||
this._notifyAllListeners("callStateChanged", [callInfo]);
|
||||
@@ -1200,10 +1385,11 @@ TelephonyService.prototype = {
|
||||
this._notifyAllListeners("notifyError",
|
||||
[aClientId, aCall.callIndex, aCall.failCause]);
|
||||
}
|
||||
|
||||
delete this._currentCalls[aClientId][aCall.callIndex];
|
||||
|
||||
if (manualConfStateChange) {
|
||||
this.notifyConferenceCallStateChanged(RIL.CALL_STATE_UNKNOWN);
|
||||
this._handleConferenceCallStateChanged(nsITelephonyService.CALL_STATE_UNKNOWN);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1222,56 +1408,125 @@ TelephonyService.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle call state changes by updating our current state and the audio
|
||||
* system.
|
||||
* Handle current calls reported from RIL.
|
||||
*
|
||||
* @param aCalls call from RIL, which contains:
|
||||
* state, callIndex, toa, isMT, number, numberPresentation, name,
|
||||
* namePresentation.
|
||||
*/
|
||||
notifyCallStateChanged: function(aClientId, aCall, aSkipStateConversion) {
|
||||
if (DEBUG) debug("handleCallStateChange: " + JSON.stringify(aCall));
|
||||
notifyCurrentCalls: function(aClientId, aCalls) {
|
||||
// Check whether there is a removed call.
|
||||
let hasRemovedCalls = () => {
|
||||
let newIndexes = new Set(Object.keys(aCalls));
|
||||
for (let i in this._currentCalls[aClientId]) {
|
||||
if (!newIndexes.has(i)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if (!aSkipStateConversion) {
|
||||
aCall.state = this._convertRILCallState(aCall.state);
|
||||
// If there are removedCalls, we should fetch the failCause first.
|
||||
if (!hasRemovedCalls()) {
|
||||
this._handleCurrentCalls(aClientId, aCalls);
|
||||
} else {
|
||||
this._sendToRilWorker(aClientId, "getFailCause", null, response => {
|
||||
this._handleCurrentCalls(aClientId, aCalls, response.failCause);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_handleCurrentCalls: function(aClientId, aCalls,
|
||||
aFailCause = RIL.GECKO_CALL_ERROR_NORMAL_CALL_CLEARING) {
|
||||
if (DEBUG) debug("handleCurrentCalls: " + JSON.stringify(aCalls) +
|
||||
", failCause: " + aFailCause);
|
||||
|
||||
let changedCalls = new Set();
|
||||
let removedCalls = new Set();
|
||||
|
||||
let allIndexes = new Set([...Object.keys(this._currentCalls[aClientId]),
|
||||
...Object.keys(aCalls)]);
|
||||
|
||||
for (let i of allIndexes) {
|
||||
let call = this._currentCalls[aClientId][i];
|
||||
let rilCall = aCalls[i];
|
||||
|
||||
// Determine the change of call.
|
||||
if (call && !rilCall) { // removed.
|
||||
removedCalls.add(call);
|
||||
} else if (call && rilCall) { // changed.
|
||||
if (this._updateCallFromRil(call, rilCall)) {
|
||||
changedCalls.add(call);
|
||||
}
|
||||
} else { // !call && rilCall. added.
|
||||
this._currentCalls[aClientId][i] = call = new Call(aClientId, i);
|
||||
this._updateCallFromRil(call, rilCall);
|
||||
changedCalls.add(call);
|
||||
|
||||
// Handle ongoingDial.
|
||||
if (this._ongoingDial && this._ongoingDial.clientId === aClientId &&
|
||||
call.state !== nsITelephonyService.CALL_STATE_INCOMING) {
|
||||
this._ongoingDial.callback.notifyDialCallSuccess(aClientId, i,
|
||||
call.number);
|
||||
this._ongoingDial = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For correct conference detection, we should mark removedCalls as
|
||||
// DISCONNECTED first.
|
||||
removedCalls.forEach(call => {
|
||||
call.state = nsITelephonyService.CALL_STATE_DISCONNECTED;
|
||||
call.failCause = aFailCause;
|
||||
this._handleCallDisconnected(aClientId, call);
|
||||
});
|
||||
|
||||
// Detect conference and update isConference flag.
|
||||
let [newConferenceState, conferenceCalls] = this._detectConference(aClientId);
|
||||
if (DEBUG) debug("Conference state: " + newConferenceState);
|
||||
|
||||
let conference = new Set(conferenceCalls);
|
||||
for (let i in this._currentCalls[aClientId]) {
|
||||
let call = this._currentCalls[aClientId][i];
|
||||
let isConference = conference.has(call);
|
||||
if (call.isConference != isConference) {
|
||||
call.isConference = isConference;
|
||||
changedCalls.add(call);
|
||||
}
|
||||
}
|
||||
|
||||
changedCalls.forEach(call => this._handleCallStateChanged(aClientId, call));
|
||||
|
||||
// Should handle conferenceCallStateChange after callStateChanged and
|
||||
// callDisconnected.
|
||||
if (newConferenceState != this._currentConferenceState) {
|
||||
this._handleConferenceCallStateChanged(newConferenceState);
|
||||
}
|
||||
|
||||
this._updateAudioState(aClientId);
|
||||
|
||||
// Handle cached dial request.
|
||||
if (this._cachedDialRequest && !this._isActive(aClientId)) {
|
||||
if (DEBUG) debug("All calls held. Perform the cached dial request.");
|
||||
|
||||
let request = this._cachedDialRequest;
|
||||
this._sendDialCallRequest(request.clientId, request.options,
|
||||
request.callback);
|
||||
this._cachedDialRequest = null;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle call state changes.
|
||||
*/
|
||||
_handleCallStateChanged: function(aClientId, aCall) {
|
||||
if (DEBUG) debug("handleCallStateChange: " + JSON.stringify(aCall));
|
||||
|
||||
if (aCall.state == nsITelephonyService.CALL_STATE_DIALING) {
|
||||
gTelephonyMessenger.notifyNewCall();
|
||||
}
|
||||
|
||||
aCall.clientId = aClientId;
|
||||
|
||||
function pick(arg, defaultValue) {
|
||||
return typeof arg !== 'undefined' ? arg : defaultValue;
|
||||
}
|
||||
|
||||
let call = this._currentCalls[aClientId][aCall.callIndex];
|
||||
if (call) {
|
||||
call.state = aCall.state;
|
||||
call.number = aCall.number;
|
||||
call.isConference = aCall.isConference;
|
||||
call.isEmergency = gDialNumberUtils.isEmergency(aCall.number);
|
||||
call.isSwitchable = pick(aCall.isSwitchable, call.isSwitchable);
|
||||
call.isMergeable = pick(aCall.isMergeable, call.isMergeable);
|
||||
} else {
|
||||
call = aCall;
|
||||
call.isEmergency = pick(aCall.isEmergency, gDialNumberUtils.isEmergency(aCall.number));
|
||||
call.isSwitchable = pick(aCall.isSwitchable, true);
|
||||
call.isMergeable = pick(aCall.isMergeable, true);
|
||||
call.name = pick(aCall.name, "");
|
||||
call.numberPresentaation = pick(aCall.numberPresentation, nsITelephonyService.CALL_PRESENTATION_ALLOWED);
|
||||
call.namePresentaation = pick(aCall.namePresentation, nsITelephonyService.CALL_PRESENTATION_ALLOWED);
|
||||
|
||||
this._currentCalls[aClientId][aCall.callIndex] = call;
|
||||
}
|
||||
|
||||
// Handle cached dial request.
|
||||
if (this._cachedDialRequest && !this._getOneActiveCall(aClientId)) {
|
||||
if (DEBUG) debug("All calls held. Perform the cached dial request.");
|
||||
|
||||
let request = this._cachedDialRequest;
|
||||
this._sendDialCallRequest(request.clientId, request.options, request.callback);
|
||||
this._cachedDialRequest = null;
|
||||
}
|
||||
|
||||
let callInfo = new TelephonyCallInfo(call);
|
||||
let callInfo = new TelephonyCallInfo(aCall);
|
||||
this._notifyAllListeners("callStateChanged", [callInfo]);
|
||||
},
|
||||
|
||||
@@ -1284,7 +1539,7 @@ TelephonyService.prototype = {
|
||||
if (call) {
|
||||
// TODO: Bug 977503 - B2G RIL: [CDMA] update callNumber when a waiting
|
||||
// call comes after a 3way call.
|
||||
this.notifyCallDisconnected(aClientId, call);
|
||||
this._handleCallDisconnected(aClientId, call);
|
||||
}
|
||||
|
||||
this._cdmaCallWaitingNumber = aCall.number;
|
||||
@@ -1296,17 +1551,37 @@ TelephonyService.prototype = {
|
||||
aCall.namePresentation]);
|
||||
},
|
||||
|
||||
notifySupplementaryService: function(aClientId, aCallIndex, aNotification) {
|
||||
notifySupplementaryService: function(aClientId, aNumber, aNotification) {
|
||||
let notification = this._convertRILSuppSvcNotification(aNotification);
|
||||
|
||||
// Get the target call object for this notification.
|
||||
let callIndex = -1;
|
||||
|
||||
let indexes = Object.keys(this.currentCalls);
|
||||
if (indexes.length === 1) {
|
||||
// Only one call exists. This should be the target.
|
||||
callIndex = indexes[0];
|
||||
} else {
|
||||
// Find the call in |currentCalls| by the given number.
|
||||
if (aNumber) {
|
||||
for (let i in this._currentCalls) {
|
||||
let call = this._currentCalls[aClientId][i];
|
||||
if (call.number === aNumber) {
|
||||
callIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._notifyAllListeners("supplementaryServiceNotification",
|
||||
[aClientId, aCallIndex, notification]);
|
||||
[aClientId, callIndex, notification]);
|
||||
},
|
||||
|
||||
notifyConferenceCallStateChanged: function(aState) {
|
||||
_handleConferenceCallStateChanged: function(aState) {
|
||||
if (DEBUG) debug("handleConferenceCallStateChanged: " + aState);
|
||||
this._currentConferenceState = this._convertRILCallState(aState);
|
||||
this._notifyAllListeners("conferenceCallStateChanged",
|
||||
[this._currentConferenceState]);
|
||||
this._currentConferenceState = aState;
|
||||
this._notifyAllListeners("conferenceCallStateChanged", [aState]);
|
||||
},
|
||||
|
||||
notifyUssdReceived: function(aClientId, aMessage, aSessionEnded) {
|
||||
|
||||
@@ -10,25 +10,18 @@
|
||||
"@mozilla.org/telephony/gonktelephonyservice;1"
|
||||
%}
|
||||
|
||||
[scriptable, uuid(eab4b7b4-bf78-4c44-8182-ca305e70f971)]
|
||||
[scriptable, uuid(d287e11a-0a65-4456-b481-c63d62afdb5d)]
|
||||
interface nsIGonkTelephonyService : nsITelephonyService
|
||||
{
|
||||
void notifyAudioStateChanged(in unsigned long clientId, in short state);
|
||||
|
||||
void notifyCallDisconnected(in unsigned long clientId, in jsval call);
|
||||
|
||||
void notifyCallRing();
|
||||
|
||||
void notifyCallStateChanged(in unsigned long clientId, in jsval call,
|
||||
[optional] in boolean skipStateConversion);
|
||||
void notifyCurrentCalls(in unsigned long clientId, in jsval calls);
|
||||
|
||||
void notifyCdmaCallWaiting(in unsigned long clientId, in jsval waitingCall);
|
||||
|
||||
void notifySupplementaryService(in unsigned long clientId, in long callIndex,
|
||||
void notifySupplementaryService(in unsigned long clientId, in AString number,
|
||||
in AString notification);
|
||||
|
||||
void notifyConferenceCallStateChanged(in short state);
|
||||
|
||||
void notifyUssdReceived(in unsigned long clientId, in DOMString message,
|
||||
in boolean sessionEnded);
|
||||
};
|
||||
|
||||
@@ -25,6 +25,7 @@ qemu = true
|
||||
[test_incall_mmi_call_hold.js]
|
||||
[test_incall_mmi_call_waiting.js]
|
||||
[test_incall_mmi_conference.js]
|
||||
[test_incall_mmi_imei.js]
|
||||
[test_incoming_already_connected.js]
|
||||
[test_incoming_already_held.js]
|
||||
[test_incoming_answer_hangup_oncallschanged.js]
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
MARIONETTE_TIMEOUT = 60000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
const number = "0900000001";
|
||||
let outCall;
|
||||
|
||||
function getIMEI() {
|
||||
log("Test *#06# ...");
|
||||
|
||||
return gSendMMI("*#06#").then(aResult => {
|
||||
ok(aResult.success, "success");
|
||||
is(aResult.serviceCode, "scImei", "Service code IMEI");
|
||||
// IMEI is hardcoded as "000000000000000".
|
||||
// See it here {B2G_HOME}/external/qemu/telephony/android_modem.c
|
||||
// (The aResult of +CGSN).
|
||||
is(aResult.statusMessage, "000000000000000", "Emulator IMEI");
|
||||
is(aResult.additionalInformation, undefined, "No additional information");
|
||||
});
|
||||
}
|
||||
|
||||
function testInCallMMI_IMEI() {
|
||||
log('= testInCallMMI_IMEI =');
|
||||
|
||||
return gDial(number)
|
||||
.then(call => outCall = call)
|
||||
.then(() => gRemoteAnswer(outCall))
|
||||
.then(() => getIMEI())
|
||||
.then(() => gRemoteHangUpCalls([outCall]));
|
||||
}
|
||||
|
||||
startTest(function() {
|
||||
testInCallMMI_IMEI()
|
||||
.catch(error => ok(false, "Promise reject: " + error))
|
||||
.then(finish);
|
||||
});
|
||||
@@ -16,7 +16,7 @@ function testDialOutInvalidNumber() {
|
||||
return telephony.dial(number).then(call => {
|
||||
outCall = call;
|
||||
ok(outCall);
|
||||
is(outCall.id.number, number);
|
||||
is(outCall.id.number, ""); // Emulator returns empty number for this call.
|
||||
is(outCall.state, "dialing");
|
||||
|
||||
is(outCall, telephony.active);
|
||||
|
||||
@@ -65,6 +65,7 @@ startTestWithPermissions(['mobileconnection'], function() {
|
||||
.then(() => testDial_EmergencyNumber())
|
||||
.then(() => testDialEmergency_NormalNumber())
|
||||
.then(() => testDialEmergency_EmergencyNumber())
|
||||
.catch(error => ok(false, "Promise reject: " + error))
|
||||
.then(() => setRadioEnabledAll(true))
|
||||
.catch(error => ok(false, "Promise reject: " + error))
|
||||
.then(finish);
|
||||
|
||||
@@ -30,44 +30,6 @@ add_test(function test_parseMMI_undefined() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_parseMMI_one_digit_short_code() {
|
||||
let mmi = parseMMI("1");
|
||||
|
||||
equal(mmi.fullMMI, "1");
|
||||
equal(mmi.procedure, undefined);
|
||||
equal(mmi.serviceCode, undefined);
|
||||
equal(mmi.sia, undefined);
|
||||
equal(mmi.sib, undefined);
|
||||
equal(mmi.sic, undefined);
|
||||
equal(mmi.pwd, undefined);
|
||||
equal(mmi.dialNumber, undefined);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_parseMMI_invalid_short_code() {
|
||||
let mmi = parseMMI("11");
|
||||
|
||||
equal(mmi, null);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_parseMMI_short_code() {
|
||||
let mmi = parseMMI("21");
|
||||
|
||||
equal(mmi.fullMMI, "21");
|
||||
equal(mmi.procedure, undefined);
|
||||
equal(mmi.serviceCode, undefined);
|
||||
equal(mmi.sia, undefined);
|
||||
equal(mmi.sib, undefined);
|
||||
equal(mmi.sic, undefined);
|
||||
equal(mmi.pwd, undefined);
|
||||
equal(mmi.dialNumber, undefined);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_parseMMI_dial_string() {
|
||||
let mmi = parseMMI("12345");
|
||||
|
||||
@@ -79,14 +41,7 @@ add_test(function test_parseMMI_dial_string() {
|
||||
add_test(function test_parseMMI_USSD_without_asterisk_prefix() {
|
||||
let mmi = parseMMI("123#");
|
||||
|
||||
equal(mmi.fullMMI, "123#");
|
||||
equal(mmi.procedure, undefined);
|
||||
equal(mmi.serviceCode, undefined);
|
||||
equal(mmi.sia, undefined);
|
||||
equal(mmi.sib, undefined);
|
||||
equal(mmi.sic, undefined);
|
||||
equal(mmi.pwd, undefined);
|
||||
equal(mmi.dialNumber, undefined);
|
||||
equal(mmi, null);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
@@ -109,14 +64,7 @@ add_test(function test_parseMMI_USSD() {
|
||||
add_test(function test_parseMMI_USSD_with_two_sharps() {
|
||||
let mmi = parseMMI("*225#4384903113430962#");
|
||||
|
||||
equal(mmi.fullMMI, "*225#4384903113430962#");
|
||||
equal(mmi.procedure, undefined);
|
||||
equal(mmi.serviceCode, undefined);
|
||||
equal(mmi.sia, undefined);
|
||||
equal(mmi.sib, undefined);
|
||||
equal(mmi.sic, undefined);
|
||||
equal(mmi.pwd, undefined);
|
||||
equal(mmi.dialNumber, undefined);
|
||||
equal(mmi, null);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
@@ -37,9 +37,9 @@ XPCOMUtils.defineLazyGetter(this, "CP", function () {
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger",
|
||||
"@mozilla.org/system-message-internal;1",
|
||||
"nsISystemMessagesInternal");
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gRIL",
|
||||
"@mozilla.org/ril;1",
|
||||
"nsIRadioInterfaceLayer");
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gIccService",
|
||||
"@mozilla.org/icc/iccservice;1",
|
||||
"nsIIccService");
|
||||
|
||||
/**
|
||||
* Helpers for WAP PDU processing.
|
||||
@@ -104,7 +104,8 @@ this.WapPushManager = {
|
||||
let mac = params && params.mac;
|
||||
authInfo = CP.Authenticator.check(data.array.subarray(data.offset),
|
||||
sec, mac, function getNetworkPin() {
|
||||
let imsi = gRIL.getRadioInterface(options.serviceId).rilContext.imsi;
|
||||
let icc = gIccService.getIccByServiceId(options.serviceId);
|
||||
let imsi = icc ? icc.imsi : null;
|
||||
return CP.Authenticator.formatImsi(imsi);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -75,6 +75,45 @@ dictionary MobileMessageFilter
|
||||
[EnforceRange] unsigned long long? threadId = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* TON defined in |Table 10.5.118: Called party BCD number| of 3GPP TS 24.008.
|
||||
* It's used in SM-RL originator / destination address element as defined in
|
||||
* |8.2.5.2 Destination address element| of 3GPP TS 24.011.
|
||||
*/
|
||||
enum TypeOfNumber { "unknown", "international", "national", "network-specific",
|
||||
"dedicated-access-short-code" };
|
||||
|
||||
/**
|
||||
* NPI defined in |Table 10.5.118: Called party BCD number| of 3GPP TS 24.008.
|
||||
* It's used in SM-RL originator / destination address element as defined in
|
||||
* |8.2.5.2 Destination address element| of 3GPP TS 24.011.
|
||||
*/
|
||||
enum NumberPlanIdentification { "unknown", "isdn", "data", "telex", "national",
|
||||
"private" };
|
||||
|
||||
/**
|
||||
* Type of address used in SmscAddress.
|
||||
*
|
||||
* As described in |3.1 Parameters Definitions| of 3GPP TS 27.005, the default
|
||||
* value of <tosca> should be 129 (typeOfNumber=unknown,
|
||||
* numberPlanIdentification=isdn) if the number does not begin with '+'.
|
||||
*
|
||||
* |setSmscAddress| updates typeOfNumber to international automatically if the
|
||||
* given number begins with '+'.
|
||||
*/
|
||||
dictionary TypeOfAddress {
|
||||
TypeOfNumber typeOfNumber = "unknown";
|
||||
NumberPlanIdentification numberPlanIdentification = "isdn";
|
||||
};
|
||||
|
||||
/**
|
||||
* SMSC address.
|
||||
*/
|
||||
dictionary SmscAddress {
|
||||
DOMString address;
|
||||
TypeOfAddress typeOfAddress;
|
||||
};
|
||||
|
||||
[Pref="dom.sms.enabled",
|
||||
CheckAnyPermissions="sms",
|
||||
AvailableIn="CertifiedApps"]
|
||||
@@ -157,6 +196,22 @@ interface MozMobileMessageManager : EventTarget
|
||||
[Throws]
|
||||
DOMRequest getSmscAddress(optional unsigned long serviceId);
|
||||
|
||||
/**
|
||||
* Set the SMSC address.
|
||||
*
|
||||
* @param smscAddress
|
||||
* SMSC address to use.
|
||||
* Reject if smscAddress.address does not present.
|
||||
* @param serviceId (optional)
|
||||
* The ID of the RIL service which needs to be specified under
|
||||
* the multi-sim scenario.
|
||||
* @return a Promise
|
||||
* Resolve if success. Otherwise, reject with error cause.
|
||||
*/
|
||||
[NewObject]
|
||||
Promise<void> setSmscAddress(optional SmscAddress smscAddress,
|
||||
optional unsigned long serviceId);
|
||||
|
||||
attribute EventHandler onreceived;
|
||||
attribute EventHandler onretrieving;
|
||||
attribute EventHandler onsending;
|
||||
|
||||
@@ -171,13 +171,13 @@ this.MobileIdentityManager = {
|
||||
this._iccInfo = [];
|
||||
|
||||
for (let i = 0; i < this.ril.numRadioInterfaces; i++) {
|
||||
let rilContext = this.ril.getRadioInterface(i).rilContext;
|
||||
if (!rilContext) {
|
||||
log.warn("Tried to get the RIL context for an invalid service ID " + i);
|
||||
let icc = this.iccService.getIccByServiceId(i);
|
||||
if (!icc) {
|
||||
log.warn("Tried to get the Icc instance for an invalid service ID " + i);
|
||||
continue;
|
||||
}
|
||||
|
||||
let info = rilContext.iccInfo;
|
||||
let info = icc.iccInfo;
|
||||
if (!info || !info.iccid ||
|
||||
!info.mcc || !info.mcc.length ||
|
||||
!info.mnc || !info.mnc.length) {
|
||||
@@ -185,6 +185,20 @@ this.MobileIdentityManager = {
|
||||
continue;
|
||||
}
|
||||
|
||||
// GSM SIMs may have MSISDN while CDMA SIMs may have MDN
|
||||
let phoneNumber = null;
|
||||
try {
|
||||
if (info.iccType === "sim" || info.iccType === "usim") {
|
||||
let gsmInfo = info.QueryInterface(Ci.nsIGsmIccInfo);
|
||||
phoneNumber = gsmInfo.msisdn;
|
||||
} else if (info.iccType === "ruim" || info.iccType === "csim") {
|
||||
let cdmaInfo = info.QueryInterface(Ci.nsICdmaIccInfo);
|
||||
phoneNumber = cdmaInfo.mdn;
|
||||
}
|
||||
} catch (e) {
|
||||
log.error("Failed to retrieve phoneNumber: " + e);
|
||||
}
|
||||
|
||||
let connection = this.mobileConnectionService.getItemByServiceId(i);
|
||||
let voice = connection && connection.voice;
|
||||
let data = connection && connection.data;
|
||||
@@ -208,18 +222,14 @@ this.MobileIdentityManager = {
|
||||
iccId: info.iccid,
|
||||
mcc: info.mcc,
|
||||
mnc: info.mnc,
|
||||
// GSM SIMs may have MSISDN while CDMA SIMs may have MDN
|
||||
msisdn: info.msisdn || info.mdn || null,
|
||||
msisdn: phoneNumber,
|
||||
operator: operator,
|
||||
roaming: voice && voice.roaming
|
||||
});
|
||||
|
||||
// We need to subscribe to ICC change notifications so we can refresh
|
||||
// the cache if any change is observed.
|
||||
let icc = this.iccService.getIccByServiceId(i);
|
||||
if (icc) {
|
||||
icc.registerListener(iccListener);
|
||||
}
|
||||
icc.registerListener(iccListener);
|
||||
}
|
||||
|
||||
return this._iccInfo;
|
||||
|
||||
@@ -46,16 +46,37 @@ const MCC = "aMcc";
|
||||
const ANOTHER_MCC = "anotherMcc";
|
||||
const OPERATOR = "aOperator";
|
||||
const ANOTHER_OPERATOR = "anotherOperator";
|
||||
const ICC_INFO = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIGsmIccInfo,
|
||||
Ci.nsIIccInfo]),
|
||||
iccType: "usim",
|
||||
iccid: ICC_ID,
|
||||
mcc: MCC,
|
||||
mnc: MNC,
|
||||
msisdn: PHONE_NUMBER,
|
||||
operator: OPERATOR
|
||||
};
|
||||
const ANOTHER_ICC_INFO = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIGsmIccInfo,
|
||||
Ci.nsIIccInfo]),
|
||||
iccType: "usim",
|
||||
iccid: ANOTHER_ICC_ID,
|
||||
mcc: ANOTHER_MCC,
|
||||
mnc: ANOTHER_MNC,
|
||||
msisdn: ANOTHER_PHONE_NUMBER,
|
||||
operator: ANOTHER_OPERATOR
|
||||
};
|
||||
const INVALID_ICC_INFO = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIGsmIccInfo,
|
||||
Ci.nsIIccInfo]),
|
||||
iccType: "usim",
|
||||
iccid: null,
|
||||
mcc: "",
|
||||
mnc: "",
|
||||
msisdn: "",
|
||||
operator: ""
|
||||
};
|
||||
const RADIO_INTERFACE = {
|
||||
rilContext: {
|
||||
iccInfo: {
|
||||
iccid: ICC_ID,
|
||||
mcc: MCC,
|
||||
mnc: MNC,
|
||||
msisdn: PHONE_NUMBER,
|
||||
operator: OPERATOR
|
||||
}
|
||||
},
|
||||
voice: {
|
||||
network: {
|
||||
shortName: OPERATOR
|
||||
@@ -69,15 +90,6 @@ const RADIO_INTERFACE = {
|
||||
}
|
||||
};
|
||||
const ANOTHER_RADIO_INTERFACE = {
|
||||
rilContext: {
|
||||
iccInfo: {
|
||||
iccid: ANOTHER_ICC_ID,
|
||||
mcc: ANOTHER_MCC,
|
||||
mnc: ANOTHER_MNC,
|
||||
msisdn: ANOTHER_PHONE_NUMBER,
|
||||
operator: ANOTHER_OPERATOR
|
||||
}
|
||||
},
|
||||
voice: {
|
||||
network: {
|
||||
shortName: ANOTHER_OPERATOR
|
||||
@@ -92,15 +104,6 @@ const ANOTHER_RADIO_INTERFACE = {
|
||||
};
|
||||
|
||||
const INVALID_RADIO_INTERFACE = {
|
||||
rilContext: {
|
||||
iccInfo: {
|
||||
iccid: null,
|
||||
mcc: "",
|
||||
mnc: "",
|
||||
msisdn: "",
|
||||
operator: ""
|
||||
}
|
||||
},
|
||||
voice: {
|
||||
network: {
|
||||
shortName: ""
|
||||
|
||||
@@ -1003,33 +1003,35 @@ add_test(function() {
|
||||
};
|
||||
|
||||
MobileIdentityManager._iccService = {
|
||||
_iccs: [],
|
||||
_listeners: [],
|
||||
_iccInfos: [ICC_INFO, ANOTHER_ICC_INFO],
|
||||
getIccByServiceId: function(aClientId) {
|
||||
let self = this;
|
||||
this_iccs.push({
|
||||
return {
|
||||
get iccInfo() {
|
||||
return self._iccInfos[aClientId];
|
||||
},
|
||||
registerListener: function(aIccListener) {
|
||||
self._listeners.push(aIccListener);
|
||||
},
|
||||
unregisterListener: function() {
|
||||
self._listeners.pop();
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
let ui = new MockUi();
|
||||
ui.startFlow = function() {
|
||||
// At this point we've already built the ICC cache.
|
||||
let interfaces = MobileIdentityManager._ril._interfaces;
|
||||
for (let i = 0; i < interfaces.length; i++) {
|
||||
let interfaceIccInfo = interfaces[i].rilContext.iccInfo;
|
||||
let mockIccInfo = [ICC_INFO, ANOTHER_ICC_INFO];
|
||||
for (let i = 0; i < mockIccInfo.length; i++) {
|
||||
let mIdIccInfo = MobileIdentityManager._iccInfo[i];
|
||||
do_check_eq(interfaceIccInfo.iccid, mIdIccInfo.iccId);
|
||||
do_check_eq(interfaceIccInfo.mcc, mIdIccInfo.mcc);
|
||||
do_check_eq(interfaceIccInfo.mnc, mIdIccInfo.mnc);
|
||||
do_check_eq(interfaceIccInfo.msisdn, mIdIccInfo.msisdn);
|
||||
do_check_eq(interfaceIccInfo.operator, mIdIccInfo.operator);
|
||||
do_check_eq(mockIccInfo[i].iccid, mIdIccInfo.iccId);
|
||||
do_check_eq(mockIccInfo[i].mcc, mIdIccInfo.mcc);
|
||||
do_check_eq(mockIccInfo[i].mnc, mIdIccInfo.mnc);
|
||||
do_check_eq(mockIccInfo[i].msisdn, mIdIccInfo.msisdn);
|
||||
do_check_eq(mockIccInfo[i].operator, mIdIccInfo.operator);
|
||||
}
|
||||
|
||||
// We should have listeners for each valid icc.
|
||||
@@ -1111,18 +1113,21 @@ add_test(function() {
|
||||
};
|
||||
|
||||
MobileIdentityManager._iccService = {
|
||||
_iccs: [],
|
||||
_listeners: [],
|
||||
_iccInfos: [INVALID_ICC_INFO],
|
||||
getIccByServiceId: function(aClientId) {
|
||||
let self = this;
|
||||
this_iccs.push({
|
||||
return {
|
||||
get iccInfo() {
|
||||
return self._iccInfos[aClientId];
|
||||
},
|
||||
registerListener: function(aIccListener) {
|
||||
self._listeners.push(aIccListener);
|
||||
},
|
||||
unregisterListener: function() {
|
||||
self._listeners.pop();
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user