2012-07-20 13:10:44 +04:00
|
|
|
/* Copyright 2012 Mozilla Foundation and Mozilla contributors
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
2011-12-05 11:58:27 +04:00
|
|
|
|
2012-01-10 02:28:47 +04:00
|
|
|
"use strict";
|
|
|
|
|
2011-12-05 11:58:27 +04:00
|
|
|
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
|
|
|
|
|
|
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
2011-12-24 09:02:52 +04:00
|
|
|
Cu.import("resource://gre/modules/Services.jsm");
|
2013-06-22 18:22:05 +04:00
|
|
|
Cu.import("resource://gre/modules/Sntp.jsm");
|
2013-09-30 13:24:54 +04:00
|
|
|
Cu.import("resource://gre/modules/systemlibs.js");
|
2013-11-21 18:09:14 +04:00
|
|
|
Cu.import("resource://gre/modules/Promise.jsm");
|
2014-02-18 18:41:36 +04:00
|
|
|
Cu.import("resource://gre/modules/FileUtils.jsm");
|
2011-12-05 11:58:27 +04:00
|
|
|
|
2014-05-15 20:01:36 +04:00
|
|
|
var RIL = {};
|
|
|
|
Cu.import("resource://gre/modules/ril_consts.js", RIL);
|
2012-01-10 02:28:47 +04:00
|
|
|
|
2013-12-21 00:56:35 +04:00
|
|
|
// Ril quirk to attach data registration on demand.
|
|
|
|
let RILQUIRKS_DATA_REGISTRATION_ON_DEMAND =
|
|
|
|
libcutils.property_get("ro.moz.ril.data_reg_on_demand", "false") == "true";
|
|
|
|
|
2014-05-05 11:12:14 +04:00
|
|
|
// Ril quirk to control the uicc/data subscription.
|
|
|
|
let RILQUIRKS_SUBSCRIPTION_CONTROL =
|
|
|
|
libcutils.property_get("ro.moz.ril.subscription_control", "false") == "true";
|
|
|
|
|
2014-01-15 18:40:49 +04:00
|
|
|
// Ril quirk to always turn the radio off for the client without SIM card
|
|
|
|
// except hw default client.
|
|
|
|
let RILQUIRKS_RADIO_OFF_WO_CARD =
|
|
|
|
libcutils.property_get("ro.moz.ril.radio_off_wo_card", "false") == "true";
|
|
|
|
|
2014-03-11 18:17:57 +04:00
|
|
|
// Ril quirk to enable IPv6 protocol/roaming protocol in APN settings.
|
|
|
|
let RILQUIRKS_HAVE_IPV6 =
|
|
|
|
libcutils.property_get("ro.moz.ril.ipv6", "false") == "true";
|
|
|
|
|
2012-01-20 00:53:32 +04:00
|
|
|
const RADIOINTERFACELAYER_CID =
|
2012-01-10 03:18:23 +04:00
|
|
|
Components.ID("{2d831c8d-6017-435b-a80c-e5d422810cea}");
|
2013-07-02 13:36:37 +04:00
|
|
|
const RADIOINTERFACE_CID =
|
|
|
|
Components.ID("{6a7c91f0-a2b3-4193-8562-8969296c0b54}");
|
2012-09-26 16:52:21 +04:00
|
|
|
const RILNETWORKINTERFACE_CID =
|
|
|
|
Components.ID("{3bdd52a9-3965-4130-b569-0ac5afed045e}");
|
2013-10-15 06:42:49 +04:00
|
|
|
const GSMICCINFO_CID =
|
|
|
|
Components.ID("{d90c4261-a99d-47bc-8b05-b057bb7e8f8a}");
|
|
|
|
const CDMAICCINFO_CID =
|
|
|
|
Components.ID("{39ba3c08-aacc-46d0-8c04-9b619c387061}");
|
2011-12-05 11:58:27 +04:00
|
|
|
|
2013-10-24 12:14:59 +04:00
|
|
|
const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown";
|
2012-04-20 01:33:25 +04:00
|
|
|
const kNetworkInterfaceStateChangedTopic = "network-interface-state-changed";
|
2014-03-10 07:36:42 +04:00
|
|
|
const kNetworkConnStateChangedTopic = "network-connection-state-changed";
|
2014-04-11 12:53:57 +04:00
|
|
|
const kNetworkActiveChangedTopic = "network-active-changed";
|
2013-09-07 15:09:54 +04:00
|
|
|
const kSmsReceivedObserverTopic = "sms-received";
|
|
|
|
const kSilentSmsReceivedObserverTopic = "silent-sms-received";
|
|
|
|
const kSmsSendingObserverTopic = "sms-sending";
|
|
|
|
const kSmsSentObserverTopic = "sms-sent";
|
|
|
|
const kSmsFailedObserverTopic = "sms-failed";
|
|
|
|
const kSmsDeliverySuccessObserverTopic = "sms-delivery-success";
|
|
|
|
const kSmsDeliveryErrorObserverTopic = "sms-delivery-error";
|
2012-04-25 00:46:42 +04:00
|
|
|
const kMozSettingsChangedObserverTopic = "mozsettings-changed";
|
2012-09-06 00:00:06 +04:00
|
|
|
const kSysMsgListenerReadyObserverTopic = "system-message-listener-ready";
|
2012-10-23 11:15:53 +04:00
|
|
|
const kSysClockChangeObserverTopic = "system-clock-change";
|
2013-06-06 11:28:59 +04:00
|
|
|
const kScreenStateChangedTopic = "screen-state-changed";
|
2013-10-24 12:14:59 +04:00
|
|
|
|
|
|
|
const kSettingsCellBroadcastSearchList = "ril.cellbroadcast.searchlist";
|
|
|
|
const kSettingsClockAutoUpdateEnabled = "time.clock.automatic-update.enabled";
|
|
|
|
const kSettingsClockAutoUpdateAvailable = "time.clock.automatic-update.available";
|
|
|
|
const kSettingsTimezoneAutoUpdateEnabled = "time.timezone.automatic-update.enabled";
|
|
|
|
const kSettingsTimezoneAutoUpdateAvailable = "time.timezone.automatic-update.available";
|
|
|
|
|
|
|
|
const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed";
|
|
|
|
|
|
|
|
const kPrefCellBroadcastDisabled = "ril.cellbroadcast.disabled";
|
2013-10-24 12:15:06 +04:00
|
|
|
const kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces";
|
2014-05-21 02:50:00 +04:00
|
|
|
const kPrefRilDebuggingEnabled = "ril.debugging.enabled";
|
2012-10-30 14:53:27 +04:00
|
|
|
|
2013-09-07 15:09:54 +04:00
|
|
|
const DOM_MOBILE_MESSAGE_DELIVERY_RECEIVED = "received";
|
|
|
|
const DOM_MOBILE_MESSAGE_DELIVERY_SENDING = "sending";
|
|
|
|
const DOM_MOBILE_MESSAGE_DELIVERY_SENT = "sent";
|
|
|
|
const DOM_MOBILE_MESSAGE_DELIVERY_ERROR = "error";
|
|
|
|
|
2013-09-07 10:19:57 +04:00
|
|
|
const RADIO_POWER_OFF_TIMEOUT = 30000;
|
2013-09-10 17:51:47 +04:00
|
|
|
const SMS_HANDLED_WAKELOCK_TIMEOUT = 5000;
|
2014-01-15 18:40:49 +04:00
|
|
|
const HW_DEFAULT_CLIENT_ID = 0;
|
2012-09-28 09:43:35 +04:00
|
|
|
|
|
|
|
const RIL_IPC_MOBILECONNECTION_MSG_NAMES = [
|
|
|
|
"RIL:GetRilContext",
|
2012-06-02 01:10:39 +04:00
|
|
|
"RIL:GetAvailableNetworks",
|
2012-06-20 02:52:06 +04:00
|
|
|
"RIL:SelectNetwork",
|
|
|
|
"RIL:SelectNetworkAuto",
|
2013-12-11 07:15:03 +04:00
|
|
|
"RIL:SetPreferredNetworkType",
|
|
|
|
"RIL:GetPreferredNetworkType",
|
2012-10-05 18:08:55 +04:00
|
|
|
"RIL:SendMMI",
|
|
|
|
"RIL:CancelMMI",
|
2013-09-07 15:32:23 +04:00
|
|
|
"RIL:RegisterMobileConnectionMsg",
|
2013-10-30 08:04:21 +04:00
|
|
|
"RIL:SetCallForwardingOptions",
|
|
|
|
"RIL:GetCallForwardingOptions",
|
|
|
|
"RIL:SetCallBarringOptions",
|
|
|
|
"RIL:GetCallBarringOptions",
|
2013-08-27 05:59:17 +04:00
|
|
|
"RIL:ChangeCallBarringPassword",
|
2013-10-30 08:04:21 +04:00
|
|
|
"RIL:SetCallWaitingOptions",
|
|
|
|
"RIL:GetCallWaitingOptions",
|
2013-07-18 01:18:29 +04:00
|
|
|
"RIL:SetCallingLineIdRestriction",
|
2013-06-10 11:47:03 +04:00
|
|
|
"RIL:GetCallingLineIdRestriction",
|
|
|
|
"RIL:SetRoamingPreference",
|
2013-08-14 16:50:36 +04:00
|
|
|
"RIL:GetRoamingPreference",
|
2013-08-14 12:22:38 +04:00
|
|
|
"RIL:ExitEmergencyCbMode",
|
2013-11-21 18:09:14 +04:00
|
|
|
"RIL:SetRadioEnabled",
|
2013-08-14 12:22:38 +04:00
|
|
|
"RIL:SetVoicePrivacyMode",
|
2014-01-08 10:10:58 +04:00
|
|
|
"RIL:GetVoicePrivacyMode",
|
|
|
|
"RIL:GetSupportedNetworkTypes"
|
2013-04-09 10:18:43 +04:00
|
|
|
];
|
|
|
|
|
2014-01-08 14:54:34 +04:00
|
|
|
const RIL_IPC_MOBILENETWORK_MSG_NAMES = [
|
|
|
|
"RIL:GetLastKnownNetwork",
|
|
|
|
"RIL:GetLastKnownHomeNetwork"
|
|
|
|
];
|
|
|
|
|
2013-04-09 10:18:43 +04:00
|
|
|
const RIL_IPC_ICCMANAGER_MSG_NAMES = [
|
2012-04-10 16:04:27 +04:00
|
|
|
"RIL:SendStkResponse",
|
2012-09-28 09:43:35 +04:00
|
|
|
"RIL:SendStkMenuSelection",
|
2012-11-28 12:16:20 +04:00
|
|
|
"RIL:SendStkTimerExpiration",
|
2012-09-11 06:34:36 +04:00
|
|
|
"RIL:SendStkEventDownload",
|
2013-04-11 11:12:09 +04:00
|
|
|
"RIL:GetCardLockState",
|
|
|
|
"RIL:UnlockCardLock",
|
|
|
|
"RIL:SetCardLock",
|
Bug 875710: Added getCardLockRetryCount to nsIIccProvider, r=vyang, sr=mounir
This patch adds getCardLockRetryCount to nsIIccProvider and its
implementations. This method allows callers to query the number
of remaining tries for unlocking a SIM-card lock. Supported locks
are 'pin', 'puk', 'pin2', 'puk2', 'nck', 'cck', and 'spck'. The
call returns a DOM request that returns the retry count in its
success handler, or signals an appropriate error.
Reading the retry count is an optional feature and may not be
supported for all lock types. In this case the DOM request receives
and error with the name GECKO_ERROR_NOT_SUPPORTED. For an invalid
lock type, the error name is GECKO_ERROR_GENERIC_FAILURE.
getCardLockRetryCount replaces retryCount in nsIDOMMobileConnection,
which is now deprecated.
--HG--
extra : rebase_source : d1d11612f836652dca85f7c701f09e7af962e3b7
2013-07-09 18:06:05 +04:00
|
|
|
"RIL:GetCardLockRetryCount",
|
2013-02-25 13:27:26 +04:00
|
|
|
"RIL:IccOpenChannel",
|
|
|
|
"RIL:IccExchangeAPDU",
|
|
|
|
"RIL:IccCloseChannel",
|
2013-03-06 06:51:40 +04:00
|
|
|
"RIL:ReadIccContacts",
|
2013-09-07 15:32:23 +04:00
|
|
|
"RIL:UpdateIccContact",
|
2014-01-27 22:22:00 +04:00
|
|
|
"RIL:RegisterIccMsg",
|
|
|
|
"RIL:MatchMvno"
|
2012-10-09 14:07:11 +04:00
|
|
|
];
|
|
|
|
|
|
|
|
const RIL_IPC_VOICEMAIL_MSG_NAMES = [
|
2013-09-07 15:32:23 +04:00
|
|
|
"RIL:RegisterVoicemailMsg",
|
2012-12-26 14:49:08 +04:00
|
|
|
"RIL:GetVoicemailInfo"
|
2012-04-24 19:44:42 +04:00
|
|
|
];
|
|
|
|
|
2013-09-07 15:32:23 +04:00
|
|
|
const RIL_IPC_CELLBROADCAST_MSG_NAMES = [
|
|
|
|
"RIL:RegisterCellBroadcastMsg"
|
|
|
|
];
|
|
|
|
|
2014-05-21 02:50:00 +04:00
|
|
|
// set to true in ril_consts.js to see debug messages
|
|
|
|
var DEBUG = RIL.DEBUG_RIL;
|
|
|
|
|
|
|
|
function updateDebugFlag() {
|
|
|
|
// Read debug setting from pref
|
|
|
|
let debugPref;
|
|
|
|
try {
|
|
|
|
debugPref = Services.prefs.getBoolPref(kPrefRilDebuggingEnabled);
|
|
|
|
} catch (e) {
|
|
|
|
debugPref = false;
|
|
|
|
}
|
|
|
|
DEBUG = RIL.DEBUG_RIL || debugPref;
|
|
|
|
}
|
|
|
|
updateDebugFlag();
|
|
|
|
|
|
|
|
function debug(s) {
|
|
|
|
dump("-*- RadioInterfaceLayer: " + s + "\n");
|
|
|
|
}
|
|
|
|
|
2013-09-07 15:09:54 +04:00
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "gPowerManagerService",
|
|
|
|
"@mozilla.org/power/powermanagerservice;1",
|
|
|
|
"nsIPowerManagerService");
|
|
|
|
|
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "gMobileMessageService",
|
|
|
|
"@mozilla.org/mobilemessage/mobilemessageservice;1",
|
|
|
|
"nsIMobileMessageService");
|
|
|
|
|
2013-07-30 02:50:22 +04:00
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "gSmsService",
|
2013-09-07 15:09:54 +04:00
|
|
|
"@mozilla.org/sms/smsservice;1",
|
|
|
|
"nsISmsService");
|
|
|
|
|
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "gMobileMessageDatabaseService",
|
|
|
|
"@mozilla.org/mobilemessage/rilmobilemessagedatabaseservice;1",
|
|
|
|
"nsIRilMobileMessageDatabaseService");
|
2013-09-07 01:28:10 +04:00
|
|
|
|
2013-09-07 15:32:23 +04:00
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
|
|
|
|
"@mozilla.org/parentprocessmessagemanager;1",
|
|
|
|
"nsIMessageBroadcaster");
|
|
|
|
|
2012-05-24 09:12:07 +04:00
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService",
|
|
|
|
"@mozilla.org/settingsService;1",
|
|
|
|
"nsISettingsService");
|
|
|
|
|
2012-08-31 18:45:32 +04:00
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger",
|
|
|
|
"@mozilla.org/system-message-internal;1",
|
|
|
|
"nsISystemMessagesInternal");
|
|
|
|
|
2012-09-26 16:52:21 +04:00
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager",
|
|
|
|
"@mozilla.org/network/manager;1",
|
|
|
|
"nsINetworkManager");
|
|
|
|
|
2012-09-28 10:02:57 +04:00
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "gTimeService",
|
|
|
|
"@mozilla.org/time/timeservice;1",
|
|
|
|
"nsITimeService");
|
|
|
|
|
2013-01-24 10:42:07 +04:00
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "gSystemWorkerManager",
|
|
|
|
"@mozilla.org/telephony/system-worker-manager;1",
|
|
|
|
"nsISystemWorkerManager");
|
|
|
|
|
2013-09-07 10:19:57 +04:00
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "gTelephonyProvider",
|
|
|
|
"@mozilla.org/telephony/telephonyprovider;1",
|
|
|
|
"nsIGonkTelephonyProvider");
|
|
|
|
|
2014-01-13 06:44:33 +04:00
|
|
|
XPCOMUtils.defineLazyGetter(this, "WAP", function() {
|
2013-09-07 15:09:54 +04:00
|
|
|
let wap = {};
|
|
|
|
Cu.import("resource://gre/modules/WapPushManager.js", wap);
|
|
|
|
return wap;
|
|
|
|
});
|
|
|
|
|
2014-01-13 06:44:33 +04:00
|
|
|
XPCOMUtils.defineLazyGetter(this, "PhoneNumberUtils", function() {
|
2013-09-07 15:09:54 +04:00
|
|
|
let ns = {};
|
|
|
|
Cu.import("resource://gre/modules/PhoneNumberUtils.jsm", ns);
|
|
|
|
return ns.PhoneNumberUtils;
|
|
|
|
});
|
|
|
|
|
2014-01-13 06:44:33 +04:00
|
|
|
XPCOMUtils.defineLazyGetter(this, "gMessageManager", function() {
|
2013-09-07 15:32:23 +04:00
|
|
|
return {
|
|
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIMessageListener,
|
|
|
|
Ci.nsIObserver]),
|
|
|
|
|
|
|
|
ril: null,
|
|
|
|
|
|
|
|
// Manage message targets in terms of topic. Only the authorized and
|
|
|
|
// registered contents can receive related messages.
|
|
|
|
targetsByTopic: {},
|
|
|
|
topics: [],
|
|
|
|
|
|
|
|
targetMessageQueue: [],
|
|
|
|
ready: false,
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
init: function(ril) {
|
2013-09-07 15:32:23 +04:00
|
|
|
this.ril = ril;
|
|
|
|
|
2013-10-24 12:14:59 +04:00
|
|
|
Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
|
2013-09-07 15:32:23 +04:00
|
|
|
Services.obs.addObserver(this, kSysMsgListenerReadyObserverTopic, false);
|
|
|
|
this._registerMessageListeners();
|
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
_shutdown: function() {
|
2013-09-07 15:32:23 +04:00
|
|
|
this.ril = null;
|
|
|
|
|
2013-10-24 12:14:59 +04:00
|
|
|
Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
|
2013-09-07 15:32:23 +04:00
|
|
|
this._unregisterMessageListeners();
|
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
_registerMessageListeners: function() {
|
2013-09-07 15:32:23 +04:00
|
|
|
ppmm.addMessageListener("child-process-shutdown", this);
|
|
|
|
for (let msgname of RIL_IPC_MOBILECONNECTION_MSG_NAMES) {
|
|
|
|
ppmm.addMessageListener(msgname, this);
|
|
|
|
}
|
2014-01-08 14:54:34 +04:00
|
|
|
for (let msgname of RIL_IPC_MOBILENETWORK_MSG_NAMES) {
|
|
|
|
ppmm.addMessageListener(msgname, this);
|
|
|
|
}
|
2013-09-07 15:32:23 +04:00
|
|
|
for (let msgName of RIL_IPC_ICCMANAGER_MSG_NAMES) {
|
|
|
|
ppmm.addMessageListener(msgName, this);
|
|
|
|
}
|
|
|
|
for (let msgname of RIL_IPC_VOICEMAIL_MSG_NAMES) {
|
|
|
|
ppmm.addMessageListener(msgname, this);
|
|
|
|
}
|
|
|
|
for (let msgname of RIL_IPC_CELLBROADCAST_MSG_NAMES) {
|
|
|
|
ppmm.addMessageListener(msgname, this);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
_unregisterMessageListeners: function() {
|
2013-09-07 15:32:23 +04:00
|
|
|
ppmm.removeMessageListener("child-process-shutdown", this);
|
|
|
|
for (let msgname of RIL_IPC_MOBILECONNECTION_MSG_NAMES) {
|
|
|
|
ppmm.removeMessageListener(msgname, this);
|
|
|
|
}
|
2014-01-08 14:54:34 +04:00
|
|
|
for (let msgname of RIL_IPC_MOBILENETWORK_MSG_NAMES) {
|
|
|
|
ppmm.removeMessageListener(msgname, this);
|
|
|
|
}
|
2013-09-07 15:32:23 +04:00
|
|
|
for (let msgName of RIL_IPC_ICCMANAGER_MSG_NAMES) {
|
|
|
|
ppmm.removeMessageListener(msgName, this);
|
|
|
|
}
|
|
|
|
for (let msgname of RIL_IPC_VOICEMAIL_MSG_NAMES) {
|
|
|
|
ppmm.removeMessageListener(msgname, this);
|
|
|
|
}
|
|
|
|
for (let msgname of RIL_IPC_CELLBROADCAST_MSG_NAMES) {
|
|
|
|
ppmm.removeMessageListener(msgname, this);
|
|
|
|
}
|
|
|
|
ppmm = null;
|
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
_registerMessageTarget: function(topic, target) {
|
2013-09-07 15:32:23 +04:00
|
|
|
let targets = this.targetsByTopic[topic];
|
|
|
|
if (!targets) {
|
|
|
|
targets = this.targetsByTopic[topic] = [];
|
|
|
|
let list = this.topics;
|
|
|
|
if (list.indexOf(topic) == -1) {
|
|
|
|
list.push(topic);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (targets.indexOf(target) != -1) {
|
|
|
|
if (DEBUG) debug("Already registered this target!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
targets.push(target);
|
|
|
|
if (DEBUG) debug("Registered " + topic + " target: " + target);
|
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
_unregisterMessageTarget: function(topic, target) {
|
2013-09-07 15:32:23 +04:00
|
|
|
if (topic == null) {
|
|
|
|
// Unregister the target for every topic when no topic is specified.
|
|
|
|
for (let type of this.topics) {
|
|
|
|
this._unregisterMessageTarget(type, target);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unregister the target for a specified topic.
|
|
|
|
let targets = this.targetsByTopic[topic];
|
|
|
|
if (!targets) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let index = targets.indexOf(target);
|
|
|
|
if (index != -1) {
|
|
|
|
targets.splice(index, 1);
|
|
|
|
if (DEBUG) debug("Unregistered " + topic + " target: " + target);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
_enqueueTargetMessage: function(topic, message, options) {
|
2013-09-07 15:32:23 +04:00
|
|
|
let msg = { topic : topic,
|
|
|
|
message : message,
|
|
|
|
options : options };
|
2013-11-28 14:10:38 +04:00
|
|
|
// Remove previous queued message with the same message type and client Id
|
|
|
|
// , only one message per (message type + client Id) is allowed in queue.
|
2013-09-07 15:32:23 +04:00
|
|
|
let messageQueue = this.targetMessageQueue;
|
|
|
|
for(let i = 0; i < messageQueue.length; i++) {
|
2013-11-28 14:10:38 +04:00
|
|
|
if (messageQueue[i].message === message &&
|
|
|
|
messageQueue[i].options.clientId === options.clientId) {
|
2013-09-07 15:32:23 +04:00
|
|
|
messageQueue.splice(i, 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
messageQueue.push(msg);
|
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
_sendTargetMessage: function(topic, message, options) {
|
2013-09-07 15:32:23 +04:00
|
|
|
if (!this.ready) {
|
|
|
|
this._enqueueTargetMessage(topic, message, options);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let targets = this.targetsByTopic[topic];
|
|
|
|
if (!targets) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let target of targets) {
|
|
|
|
target.sendAsyncMessage(message, options);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
_resendQueuedTargetMessage: function() {
|
2013-09-07 15:32:23 +04:00
|
|
|
this.ready = true;
|
|
|
|
|
|
|
|
// Here uses this._sendTargetMessage() to resend message, which will
|
|
|
|
// enqueue message if listener is not ready.
|
|
|
|
// So only resend after listener is ready, or it will cause infinate loop and
|
|
|
|
// hang the system.
|
|
|
|
|
|
|
|
// Dequeue and resend messages.
|
|
|
|
for each (let msg in this.targetMessageQueue) {
|
|
|
|
this._sendTargetMessage(msg.topic, msg.message, msg.options);
|
|
|
|
}
|
|
|
|
this.targetMessageQueue = null;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nsIMessageListener interface methods.
|
|
|
|
*/
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
receiveMessage: function(msg) {
|
2013-09-07 15:32:23 +04:00
|
|
|
if (DEBUG) debug("Received '" + msg.name + "' message from content process");
|
|
|
|
if (msg.name == "child-process-shutdown") {
|
|
|
|
// By the time we receive child-process-shutdown, the child process has
|
|
|
|
// already forgotten its permissions so we need to unregister the target
|
|
|
|
// for every permission.
|
|
|
|
this._unregisterMessageTarget(null, msg.target);
|
2013-09-14 02:12:30 +04:00
|
|
|
return null;
|
2013-09-07 15:32:23 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (RIL_IPC_MOBILECONNECTION_MSG_NAMES.indexOf(msg.name) != -1) {
|
|
|
|
if (!msg.target.assertPermission("mobileconnection")) {
|
|
|
|
if (DEBUG) {
|
|
|
|
debug("MobileConnection message " + msg.name +
|
|
|
|
" from a content process with no 'mobileconnection' privileges.");
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
2014-01-08 14:54:34 +04:00
|
|
|
} else if (RIL_IPC_MOBILENETWORK_MSG_NAMES.indexOf(msg.name) != -1) {
|
|
|
|
if (!msg.target.assertPermission("mobilenetwork")) {
|
|
|
|
if (DEBUG) {
|
|
|
|
debug("MobileNetwork message " + msg.name +
|
|
|
|
" from a content process with no 'mobilenetwork' privileges.");
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
2013-09-07 15:32:23 +04:00
|
|
|
} else if (RIL_IPC_ICCMANAGER_MSG_NAMES.indexOf(msg.name) != -1) {
|
|
|
|
if (!msg.target.assertPermission("mobileconnection")) {
|
|
|
|
if (DEBUG) {
|
|
|
|
debug("IccManager message " + msg.name +
|
|
|
|
" from a content process with no 'mobileconnection' privileges.");
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
} else if (RIL_IPC_VOICEMAIL_MSG_NAMES.indexOf(msg.name) != -1) {
|
|
|
|
if (!msg.target.assertPermission("voicemail")) {
|
|
|
|
if (DEBUG) {
|
|
|
|
debug("Voicemail message " + msg.name +
|
|
|
|
" from a content process with no 'voicemail' privileges.");
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
} else if (RIL_IPC_CELLBROADCAST_MSG_NAMES.indexOf(msg.name) != -1) {
|
|
|
|
if (!msg.target.assertPermission("cellbroadcast")) {
|
|
|
|
if (DEBUG) {
|
|
|
|
debug("Cell Broadcast message " + msg.name +
|
|
|
|
" from a content process with no 'cellbroadcast' privileges.");
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (DEBUG) debug("Ignoring unknown message type: " + msg.name);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (msg.name) {
|
|
|
|
case "RIL:RegisterMobileConnectionMsg":
|
|
|
|
this._registerMessageTarget("mobileconnection", msg.target);
|
2013-09-14 02:12:30 +04:00
|
|
|
return null;
|
2013-09-07 15:32:23 +04:00
|
|
|
case "RIL:RegisterIccMsg":
|
|
|
|
this._registerMessageTarget("icc", msg.target);
|
2013-09-14 02:12:30 +04:00
|
|
|
return null;
|
2013-09-07 15:32:23 +04:00
|
|
|
case "RIL:RegisterVoicemailMsg":
|
|
|
|
this._registerMessageTarget("voicemail", msg.target);
|
2013-09-14 02:12:30 +04:00
|
|
|
return null;
|
2013-09-07 15:32:23 +04:00
|
|
|
case "RIL:RegisterCellBroadcastMsg":
|
|
|
|
this._registerMessageTarget("cellbroadcast", msg.target);
|
2013-09-14 02:12:30 +04:00
|
|
|
return null;
|
2013-09-07 15:32:23 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
let clientId = msg.json.clientId || 0;
|
|
|
|
let radioInterface = this.ril.getRadioInterface(clientId);
|
|
|
|
if (!radioInterface) {
|
|
|
|
if (DEBUG) debug("No such radio interface: " + clientId);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2013-11-21 18:09:14 +04:00
|
|
|
if (msg.name === "RIL:SetRadioEnabled") {
|
|
|
|
// Special handler for SetRadioEnabled.
|
|
|
|
return gRadioEnabledController.receiveMessage(msg);
|
|
|
|
}
|
|
|
|
|
2013-09-07 15:32:23 +04:00
|
|
|
return radioInterface.receiveMessage(msg);
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nsIObserver interface methods.
|
|
|
|
*/
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
observe: function(subject, topic, data) {
|
2013-09-07 15:32:23 +04:00
|
|
|
switch (topic) {
|
|
|
|
case kSysMsgListenerReadyObserverTopic:
|
|
|
|
Services.obs.removeObserver(this, kSysMsgListenerReadyObserverTopic);
|
|
|
|
this._resendQueuedTargetMessage();
|
|
|
|
break;
|
2013-10-24 12:14:59 +04:00
|
|
|
case NS_XPCOM_SHUTDOWN_OBSERVER_ID:
|
2013-09-07 15:32:23 +04:00
|
|
|
this._shutdown();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
sendMobileConnectionMessage: function(message, clientId, data) {
|
2013-09-07 15:32:23 +04:00
|
|
|
this._sendTargetMessage("mobileconnection", message, {
|
|
|
|
clientId: clientId,
|
|
|
|
data: data
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
sendVoicemailMessage: function(message, clientId, data) {
|
2013-09-07 15:32:23 +04:00
|
|
|
this._sendTargetMessage("voicemail", message, {
|
|
|
|
clientId: clientId,
|
|
|
|
data: data
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
sendCellBroadcastMessage: function(message, clientId, data) {
|
2013-09-07 15:32:23 +04:00
|
|
|
this._sendTargetMessage("cellbroadcast", message, {
|
|
|
|
clientId: clientId,
|
|
|
|
data: data
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
sendIccMessage: function(message, clientId, data) {
|
2013-09-07 15:32:23 +04:00
|
|
|
this._sendTargetMessage("icc", message, {
|
|
|
|
clientId: clientId,
|
|
|
|
data: data
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
2013-07-02 13:36:40 +04:00
|
|
|
});
|
2011-12-05 11:58:27 +04:00
|
|
|
|
2014-01-13 06:44:33 +04:00
|
|
|
XPCOMUtils.defineLazyGetter(this, "gRadioEnabledController", function() {
|
2014-02-14 13:42:32 +04:00
|
|
|
let _ril = null;
|
|
|
|
let _pendingMessages = []; // For queueing "RIL =SetRadioEnabled" messages.
|
|
|
|
let _isProcessingPending = false;
|
|
|
|
let _timer = null;
|
|
|
|
let _request = null;
|
|
|
|
let _deactivatingDeferred = {};
|
|
|
|
let _initializedCardState = {};
|
|
|
|
let _allCardStateInitialized = !RILQUIRKS_RADIO_OFF_WO_CARD;
|
2013-11-21 18:09:14 +04:00
|
|
|
|
2014-02-14 13:42:32 +04:00
|
|
|
return {
|
2014-01-13 06:44:40 +04:00
|
|
|
init: function(ril) {
|
2014-02-14 13:42:32 +04:00
|
|
|
_ril = ril;
|
2013-11-21 18:09:14 +04:00
|
|
|
},
|
|
|
|
|
2014-02-14 13:42:32 +04:00
|
|
|
receiveCardState: function(clientId) {
|
|
|
|
if (_allCardStateInitialized) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (DEBUG) debug("RadioControl: receive cardState from " + clientId);
|
|
|
|
_initializedCardState[clientId] = true;
|
|
|
|
if (Object.keys(_initializedCardState).length == _ril.numRadioInterfaces) {
|
|
|
|
_allCardStateInitialized = true;
|
|
|
|
this._startProcessingPending();
|
2013-11-21 18:09:14 +04:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2014-02-14 13:42:32 +04:00
|
|
|
receiveMessage: function(msg) {
|
|
|
|
if (DEBUG) debug("RadioControl: receiveMessage: " + JSON.stringify(msg));
|
|
|
|
_pendingMessages.push(msg);
|
|
|
|
this._startProcessingPending();
|
|
|
|
},
|
|
|
|
|
2013-11-21 18:09:14 +04:00
|
|
|
isDeactivatingDataCalls: function() {
|
2014-02-14 13:42:32 +04:00
|
|
|
return _request !== null;
|
2013-11-21 18:09:14 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
finishDeactivatingDataCalls: function(clientId) {
|
2014-02-14 13:42:32 +04:00
|
|
|
if (DEBUG) debug("RadioControl: finishDeactivatingDataCalls: " + clientId);
|
|
|
|
let deferred = _deactivatingDeferred[clientId];
|
2013-11-21 18:09:14 +04:00
|
|
|
if (deferred) {
|
|
|
|
deferred.resolve();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2014-02-14 13:42:32 +04:00
|
|
|
_startProcessingPending: function() {
|
|
|
|
if (!_isProcessingPending) {
|
|
|
|
if (DEBUG) debug("RadioControl: start dequeue");
|
|
|
|
_isProcessingPending = true;
|
|
|
|
this._processNextMessage();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2013-11-21 18:09:14 +04:00
|
|
|
_processNextMessage: function() {
|
2014-02-14 13:42:32 +04:00
|
|
|
if (_pendingMessages.length === 0 || !_allCardStateInitialized) {
|
|
|
|
if (DEBUG) debug("RadioControl: stop dequeue");
|
|
|
|
_isProcessingPending = false;
|
2013-11-21 18:09:14 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-02-14 13:42:32 +04:00
|
|
|
let msg = _pendingMessages.shift();
|
2013-11-21 18:09:14 +04:00
|
|
|
this._handleMessage(msg);
|
|
|
|
},
|
|
|
|
|
2014-01-15 18:40:49 +04:00
|
|
|
_getNumCards: function() {
|
|
|
|
let numCards = 0;
|
2014-02-14 13:42:32 +04:00
|
|
|
for (let i = 0, N = _ril.numRadioInterfaces; i < N; ++i) {
|
2014-01-15 18:40:49 +04:00
|
|
|
if (this._isCardPresentAtClient(i)) {
|
|
|
|
numCards++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return numCards;
|
|
|
|
},
|
|
|
|
|
|
|
|
_isCardPresentAtClient: function(clientId) {
|
2014-02-14 13:42:32 +04:00
|
|
|
let cardState = _ril.getRadioInterface(clientId).rilContext.cardState;
|
2014-01-15 18:40:49 +04:00
|
|
|
return cardState !== RIL.GECKO_CARDSTATE_UNDETECTED &&
|
|
|
|
cardState !== RIL.GECKO_CARDSTATE_UNKNOWN;
|
|
|
|
},
|
|
|
|
|
|
|
|
_isRadioAbleToEnableAtClient: function(clientId, numCards) {
|
|
|
|
if (!RILQUIRKS_RADIO_OFF_WO_CARD) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We could only turn on the radio for clientId if
|
|
|
|
// 1. a SIM card is presented or
|
|
|
|
// 2. it is the default clientId and there is no any SIM card at any client.
|
|
|
|
|
|
|
|
if (this._isCardPresentAtClient(clientId)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
numCards = numCards == null ? this._getNumCards() : numCards;
|
|
|
|
if (clientId === HW_DEFAULT_CLIENT_ID && numCards === 0) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
},
|
|
|
|
|
2013-11-21 18:09:14 +04:00
|
|
|
_handleMessage: function(msg) {
|
2014-02-14 13:42:32 +04:00
|
|
|
if (DEBUG) debug("RadioControl: handleMessage: " + JSON.stringify(msg));
|
2014-01-15 18:40:49 +04:00
|
|
|
let clientId = msg.json.clientId || 0;
|
2014-02-14 13:42:32 +04:00
|
|
|
let radioInterface = _ril.getRadioInterface(clientId);
|
2013-11-21 18:09:14 +04:00
|
|
|
|
|
|
|
if (!radioInterface.isValidStateForSetRadioEnabled()) {
|
|
|
|
radioInterface.setRadioEnabledResponse(msg.target, msg.json.data,
|
|
|
|
"InvalidStateError");
|
|
|
|
this._processNextMessage();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (radioInterface.isDummyForSetRadioEnabled(msg.json.data)) {
|
|
|
|
radioInterface.setRadioEnabledResponse(msg.target, msg.json.data);
|
|
|
|
this._processNextMessage();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (msg.json.data.enabled) {
|
2014-01-15 18:40:49 +04:00
|
|
|
if (this._isRadioAbleToEnableAtClient(clientId)) {
|
|
|
|
radioInterface.receiveMessage(msg);
|
|
|
|
} else {
|
|
|
|
// Not really do it but respond success.
|
|
|
|
radioInterface.setRadioEnabledResponse(msg.target, msg.json.data);
|
|
|
|
}
|
|
|
|
|
2013-11-21 18:09:14 +04:00
|
|
|
this._processNextMessage();
|
|
|
|
} else {
|
2014-02-14 13:42:32 +04:00
|
|
|
_request = function() {
|
2013-11-21 18:09:14 +04:00
|
|
|
radioInterface.receiveMessage(msg);
|
2014-02-14 13:42:32 +04:00
|
|
|
};
|
2013-11-21 18:09:14 +04:00
|
|
|
|
2014-02-06 08:31:53 +04:00
|
|
|
// In 2G network, modem takes 35+ seconds to process deactivate data
|
|
|
|
// call request if device has active voice call (please see bug 964974
|
|
|
|
// for more details). Therefore we should hangup all active voice calls
|
|
|
|
// first. And considering some DSDS architecture, toggling one radio may
|
|
|
|
// toggle both, so we send hangUpAll to all clients.
|
2014-02-14 13:42:32 +04:00
|
|
|
for (let i = 0, N = _ril.numRadioInterfaces; i < N; ++i) {
|
|
|
|
let iface = _ril.getRadioInterface(i);
|
2014-02-06 08:31:53 +04:00
|
|
|
iface.workerMessenger.send("hangUpAll");
|
|
|
|
}
|
|
|
|
|
2013-11-21 18:09:14 +04:00
|
|
|
// In some DSDS architecture with only one modem, toggling one radio may
|
|
|
|
// toggle both. Therefore, for safely turning off, we should first
|
|
|
|
// explicitly deactivate all data calls from all clients.
|
|
|
|
this._deactivateDataCalls().then(() => {
|
2014-02-14 13:42:32 +04:00
|
|
|
if (DEBUG) debug("RadioControl: deactivation done");
|
2013-11-21 18:09:14 +04:00
|
|
|
this._executeRequest();
|
|
|
|
});
|
|
|
|
|
|
|
|
this._createTimer();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
_deactivateDataCalls: function() {
|
2014-02-14 13:42:32 +04:00
|
|
|
if (DEBUG) debug("RadioControl: deactivating data calls...");
|
|
|
|
_deactivatingDeferred = {};
|
2013-11-21 18:09:14 +04:00
|
|
|
|
|
|
|
let promise = Promise.resolve();
|
2014-02-14 13:42:32 +04:00
|
|
|
for (let i = 0, N = _ril.numRadioInterfaces; i < N; ++i) {
|
2013-11-21 18:09:14 +04:00
|
|
|
promise = promise.then(this._deactivateDataCallsForClient(i));
|
|
|
|
}
|
|
|
|
|
|
|
|
return promise;
|
|
|
|
},
|
|
|
|
|
|
|
|
_deactivateDataCallsForClient: function(clientId) {
|
2014-02-14 13:42:32 +04:00
|
|
|
return function() {
|
|
|
|
let deferred = _deactivatingDeferred[clientId] = Promise.defer();
|
2013-12-03 10:18:32 +04:00
|
|
|
let dataConnectionHandler = gDataConnectionManager.getConnectionHandler(clientId);
|
|
|
|
dataConnectionHandler.deactivateDataCalls();
|
2013-11-21 18:09:14 +04:00
|
|
|
return deferred.promise;
|
2014-02-14 13:42:32 +04:00
|
|
|
};
|
2013-11-21 18:09:14 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
_createTimer: function() {
|
2014-02-21 10:15:35 +04:00
|
|
|
if (!_timer) {
|
2014-02-14 13:42:32 +04:00
|
|
|
_timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
2013-11-21 18:09:14 +04:00
|
|
|
}
|
2014-02-14 13:42:32 +04:00
|
|
|
_timer.initWithCallback(this._executeRequest.bind(this),
|
|
|
|
RADIO_POWER_OFF_TIMEOUT,
|
|
|
|
Ci.nsITimer.TYPE_ONE_SHOT);
|
2013-11-21 18:09:14 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
_cancelTimer: function() {
|
2014-02-14 13:42:32 +04:00
|
|
|
if (_timer) {
|
|
|
|
_timer.cancel();
|
2013-11-21 18:09:14 +04:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
_executeRequest: function() {
|
2014-02-14 13:42:32 +04:00
|
|
|
if (typeof _request === "function") {
|
|
|
|
if (DEBUG) debug("RadioControl: executeRequest");
|
2013-11-21 18:09:14 +04:00
|
|
|
this._cancelTimer();
|
2014-02-14 13:42:32 +04:00
|
|
|
_request();
|
|
|
|
_request = null;
|
2013-11-21 18:09:14 +04:00
|
|
|
}
|
2013-12-13 20:46:23 +04:00
|
|
|
this._processNextMessage();
|
2014-01-15 18:40:49 +04:00
|
|
|
},
|
2013-11-21 18:09:14 +04:00
|
|
|
};
|
|
|
|
});
|
|
|
|
|
2013-08-22 13:18:13 +04:00
|
|
|
XPCOMUtils.defineLazyGetter(this, "gDataConnectionManager", function () {
|
|
|
|
return {
|
2013-12-03 10:18:32 +04:00
|
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
|
|
|
|
Ci.nsISettingsServiceCallback]),
|
2013-08-22 13:18:13 +04:00
|
|
|
|
|
|
|
_connectionHandlers: null,
|
|
|
|
|
2013-12-03 10:18:32 +04:00
|
|
|
// Flag to determine the data state to start with when we boot up. It
|
|
|
|
// corresponds to the 'ril.data.enabled' setting from the UI.
|
|
|
|
_dataEnabled: false,
|
|
|
|
|
|
|
|
// Flag to record the default client id for data call. It corresponds to
|
|
|
|
// the 'ril.data.defaultServiceId' setting from the UI.
|
|
|
|
_dataDefaultClientId: -1,
|
|
|
|
|
|
|
|
// Flag to record the current default client id for data call.
|
|
|
|
// It differs from _dataDefaultClientId in that it is set only when
|
|
|
|
// the switch of client id process is done.
|
|
|
|
_currentDataClientId: -1,
|
|
|
|
|
|
|
|
// Pending function to execute when we are notified that another data call has
|
|
|
|
// been disconnected.
|
|
|
|
_pendingDataCallRequest: null,
|
|
|
|
|
2013-08-22 13:18:13 +04:00
|
|
|
debug: function(s) {
|
|
|
|
dump("-*- DataConnectionManager: " + s + "\n");
|
|
|
|
},
|
|
|
|
|
|
|
|
init: function(ril) {
|
|
|
|
if (!ril) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this._connectionHandlers = [];
|
|
|
|
for (let clientId = 0; clientId < ril.numRadioInterfaces; clientId++) {
|
|
|
|
let radioInterface = ril.getRadioInterface(clientId);
|
|
|
|
this._connectionHandlers.push(
|
|
|
|
new DataConnectionHandler(clientId, radioInterface));
|
|
|
|
}
|
|
|
|
|
2013-12-03 10:18:32 +04:00
|
|
|
let lock = gSettingsService.createLock();
|
|
|
|
// Read the APN data from the settings DB.
|
|
|
|
lock.get("ril.data.apnSettings", this);
|
|
|
|
// Read the data enabled setting from DB.
|
|
|
|
lock.get("ril.data.enabled", this);
|
|
|
|
lock.get("ril.data.roaming_enabled", this);
|
|
|
|
// Read the default client id for data call.
|
|
|
|
lock.get("ril.data.defaultServiceId", this);
|
|
|
|
|
2013-08-22 13:18:13 +04:00
|
|
|
Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
|
2013-12-03 10:18:32 +04:00
|
|
|
Services.obs.addObserver(this, kMozSettingsChangedObserverTopic, false);
|
|
|
|
Services.obs.addObserver(this, kNetworkInterfaceStateChangedTopic, false);
|
2013-08-22 13:18:13 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
getConnectionHandler: function(clientId) {
|
|
|
|
return this._connectionHandlers[clientId];
|
|
|
|
},
|
|
|
|
|
2013-12-03 10:18:32 +04:00
|
|
|
_handleDataClientIdChange: function(newDefault) {
|
|
|
|
if (this._dataDefaultClientId === newDefault) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this._dataDefaultClientId = newDefault;
|
|
|
|
|
|
|
|
if (this._currentDataClientId == -1) {
|
|
|
|
// This is to handle boot up stage.
|
|
|
|
this._currentDataClientId = this._dataDefaultClientId;
|
|
|
|
let connHandler = this._connectionHandlers[this._currentDataClientId];
|
|
|
|
let radioInterface = connHandler.radioInterface;
|
2014-05-05 11:12:14 +04:00
|
|
|
if (RILQUIRKS_DATA_REGISTRATION_ON_DEMAND ||
|
|
|
|
RILQUIRKS_SUBSCRIPTION_CONTROL) {
|
2013-12-03 10:18:32 +04:00
|
|
|
radioInterface.setDataRegistration(true);
|
|
|
|
}
|
|
|
|
if (this._dataEnabled) {
|
|
|
|
let settings = connHandler.dataCallSettings;
|
|
|
|
settings.oldEnabled = settings.enabled;
|
|
|
|
settings.enabled = true;
|
|
|
|
connHandler.updateRILNetworkInterface();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let oldConnHandler = this._connectionHandlers[this._currentDataClientId];
|
|
|
|
let oldIface = oldConnHandler.radioInterface;
|
|
|
|
let oldSettings = oldConnHandler.dataCallSettings;
|
|
|
|
let newConnHandler = this._connectionHandlers[this._dataDefaultClientId];
|
|
|
|
let newIface = newConnHandler.radioInterface;
|
|
|
|
let newSettings = newConnHandler.dataCallSettings;
|
|
|
|
|
|
|
|
if (!this._dataEnabled) {
|
2014-05-05 11:12:14 +04:00
|
|
|
if (RILQUIRKS_DATA_REGISTRATION_ON_DEMAND ||
|
|
|
|
RILQUIRKS_SUBSCRIPTION_CONTROL) {
|
2013-12-03 10:18:32 +04:00
|
|
|
oldIface.setDataRegistration(false);
|
|
|
|
newIface.setDataRegistration(true);
|
|
|
|
}
|
|
|
|
this._currentDataClientId = this._dataDefaultClientId;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
oldSettings.oldEnabled = oldSettings.enabled;
|
|
|
|
oldSettings.enabled = false;
|
|
|
|
|
|
|
|
if (oldConnHandler.anyDataConnected()) {
|
|
|
|
this._pendingDataCallRequest = function () {
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("Executing pending data call request.");
|
|
|
|
}
|
2014-05-05 11:12:14 +04:00
|
|
|
if (RILQUIRKS_DATA_REGISTRATION_ON_DEMAND ||
|
|
|
|
RILQUIRKS_SUBSCRIPTION_CONTROL) {
|
2013-12-03 10:18:32 +04:00
|
|
|
newIface.setDataRegistration(true);
|
|
|
|
}
|
|
|
|
newSettings.oldEnabled = newSettings.enabled;
|
|
|
|
newSettings.enabled = this._dataEnabled;
|
|
|
|
|
|
|
|
this._currentDataClientId = this._dataDefaultClientId;
|
|
|
|
newConnHandler.updateRILNetworkInterface();
|
|
|
|
};
|
|
|
|
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("_handleDataClientIdChange: existing data call(s) active" +
|
|
|
|
", wait for them to get disconnected.");
|
|
|
|
}
|
|
|
|
oldConnHandler.deactivateDataCalls();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
newSettings.oldEnabled = newSettings.enabled;
|
|
|
|
newSettings.enabled = true;
|
|
|
|
|
|
|
|
this._currentDataClientId = this._dataDefaultClientId;
|
2014-05-05 11:12:14 +04:00
|
|
|
if (RILQUIRKS_DATA_REGISTRATION_ON_DEMAND ||
|
|
|
|
RILQUIRKS_SUBSCRIPTION_CONTROL) {
|
2013-12-03 10:18:32 +04:00
|
|
|
oldIface.setDataRegistration(false);
|
|
|
|
newIface.setDataRegistration(true);
|
|
|
|
}
|
|
|
|
newConnHandler.updateRILNetworkInterface();
|
|
|
|
},
|
|
|
|
|
2013-08-22 13:18:13 +04:00
|
|
|
_shutdown: function() {
|
|
|
|
for (let handler of this._connectionHandlers) {
|
|
|
|
handler.shutdown();
|
|
|
|
}
|
|
|
|
this._connectionHandlers = null;
|
|
|
|
Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
|
2013-12-03 10:18:32 +04:00
|
|
|
Services.obs.removeObserver(this, kMozSettingsChangedObserverTopic);
|
|
|
|
Services.obs.removeObserver(this, kNetworkInterfaceStateChangedTopic);
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nsISettingsServiceCallback
|
|
|
|
*/
|
|
|
|
handle: function(name, result) {
|
|
|
|
switch(name) {
|
|
|
|
case "ril.data.apnSettings":
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("'ril.data.apnSettings' is now " +
|
|
|
|
JSON.stringify(result));
|
|
|
|
}
|
|
|
|
if (!result) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
for (let clientId in this._connectionHandlers) {
|
|
|
|
let handler = this._connectionHandlers[clientId];
|
|
|
|
let apnSetting = result[clientId];
|
|
|
|
if (handler && apnSetting) {
|
|
|
|
handler.updateApnSettings(apnSetting);
|
|
|
|
handler.updateRILNetworkInterface();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case "ril.data.enabled":
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("'ril.data.enabled' is now " + result);
|
|
|
|
}
|
|
|
|
if (this._dataEnabled === result) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
this._dataEnabled = result;
|
|
|
|
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("Default id for data call: " + this._dataDefaultClientId);
|
|
|
|
}
|
|
|
|
if (this._dataDefaultClientId === -1) {
|
|
|
|
// We haven't got the default id for data from db.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
let connHandler = this._connectionHandlers[this._dataDefaultClientId];
|
|
|
|
let settings = connHandler.dataCallSettings;
|
|
|
|
settings.oldEnabled = settings.enabled;
|
|
|
|
settings.enabled = result;
|
|
|
|
connHandler.updateRILNetworkInterface();
|
|
|
|
break;
|
|
|
|
case "ril.data.roaming_enabled":
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("'ril.data.roaming_enabled' is now " + result);
|
|
|
|
this.debug("Default id for data call: " + this._dataDefaultClientId);
|
|
|
|
}
|
2014-04-08 22:55:00 +04:00
|
|
|
for (let clientId = 0; clientId < this._connectionHandlers.length; clientId++) {
|
|
|
|
let connHandler = this._connectionHandlers[clientId];
|
2013-12-03 10:18:32 +04:00
|
|
|
let settings = connHandler.dataCallSettings;
|
2014-04-08 22:55:00 +04:00
|
|
|
settings.roamingEnabled = Array.isArray(result) ? result[clientId] : result;
|
2013-12-03 10:18:32 +04:00
|
|
|
}
|
|
|
|
if (this._dataDefaultClientId === -1) {
|
|
|
|
// We haven't got the default id for data from db.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
this._connectionHandlers[this._dataDefaultClientId].updateRILNetworkInterface();
|
|
|
|
break;
|
|
|
|
case "ril.data.defaultServiceId":
|
|
|
|
result = result || 0;
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("'ril.data.defaultServiceId' is now " + result);
|
|
|
|
}
|
|
|
|
this._handleDataClientIdChange(result);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
handleError: function(errorMessage) {
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("There was an error while reading RIL settings.");
|
|
|
|
}
|
2013-08-22 13:18:13 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nsIObserver interface methods.
|
|
|
|
*/
|
|
|
|
observe: function(subject, topic, data) {
|
|
|
|
switch (topic) {
|
2013-12-03 10:18:32 +04:00
|
|
|
case kMozSettingsChangedObserverTopic:
|
|
|
|
let setting = JSON.parse(data);
|
|
|
|
this.handle(setting.key, setting.value);
|
|
|
|
break;
|
|
|
|
case kNetworkInterfaceStateChangedTopic:
|
|
|
|
let network = subject.QueryInterface(Ci.nsINetworkInterface);
|
|
|
|
// DSDS: setup pending data connection when switching the default id
|
|
|
|
// for data call. We can not use network.type to tell if it's
|
|
|
|
// NETWORK_TYPE_MOBILE, since the type is removed from
|
|
|
|
// RILNetworkInterface.connectedTypes on disconnect().
|
|
|
|
if (network.state == Ci.nsINetworkInterface.NETWORK_STATE_UNKNOWN) {
|
|
|
|
let connHandler = this._connectionHandlers[this._currentDataClientId];
|
|
|
|
let radioInterface = connHandler.radioInterface;
|
2014-02-10 10:42:11 +04:00
|
|
|
if (connHandler.allDataDisconnected() &&
|
2013-12-03 10:18:32 +04:00
|
|
|
typeof this._pendingDataCallRequest === "function") {
|
|
|
|
if (RILQUIRKS_DATA_REGISTRATION_ON_DEMAND) {
|
|
|
|
radioInterface.setDataRegistration(false);
|
|
|
|
}
|
|
|
|
if (DEBUG) {
|
2014-02-10 10:42:11 +04:00
|
|
|
this.debug("All data calls disconnected, setup pending data call.");
|
2013-12-03 10:18:32 +04:00
|
|
|
}
|
|
|
|
this._pendingDataCallRequest();
|
|
|
|
this._pendingDataCallRequest = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2013-08-22 13:18:13 +04:00
|
|
|
case NS_XPCOM_SHUTDOWN_OBSERVER_ID:
|
|
|
|
this._shutdown();
|
|
|
|
break;
|
|
|
|
}
|
2013-12-03 10:18:32 +04:00
|
|
|
},
|
|
|
|
};
|
|
|
|
});
|
|
|
|
|
|
|
|
// Initialize shared preference "ril.numRadioInterfaces" according to system
|
|
|
|
// property.
|
|
|
|
try {
|
|
|
|
Services.prefs.setIntPref(kPrefRilNumRadioInterfaces, (function() {
|
|
|
|
// When Gonk property "ro.moz.ril.numclients" is not set, return 1; if
|
|
|
|
// explicitly set to any number larger-equal than 0, return num; else, return
|
|
|
|
// 1 for compatibility.
|
|
|
|
try {
|
|
|
|
let numString = libcutils.property_get("ro.moz.ril.numclients", "1");
|
|
|
|
let num = parseInt(numString, 10);
|
|
|
|
if (num >= 0) {
|
|
|
|
return num;
|
|
|
|
}
|
|
|
|
} catch (e) {}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
})());
|
|
|
|
} catch (e) {}
|
|
|
|
|
|
|
|
function IccInfo() {}
|
|
|
|
IccInfo.prototype = {
|
|
|
|
iccType: null,
|
|
|
|
iccid: null,
|
|
|
|
mcc: null,
|
|
|
|
mnc: null,
|
|
|
|
spn: null,
|
|
|
|
isDisplayNetworkNameRequired: null,
|
|
|
|
isDisplaySpnRequired: null
|
|
|
|
};
|
|
|
|
|
|
|
|
function GsmIccInfo() {}
|
|
|
|
GsmIccInfo.prototype = {
|
|
|
|
__proto__: IccInfo.prototype,
|
|
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozGsmIccInfo]),
|
|
|
|
classID: GSMICCINFO_CID,
|
|
|
|
classInfo: XPCOMUtils.generateCI({
|
|
|
|
classID: GSMICCINFO_CID,
|
|
|
|
classDescription: "MozGsmIccInfo",
|
|
|
|
flags: Ci.nsIClassInfo.DOM_OBJECT,
|
|
|
|
interfaces: [Ci.nsIDOMMozGsmIccInfo]
|
|
|
|
}),
|
|
|
|
|
|
|
|
// nsIDOMMozGsmIccInfo
|
|
|
|
|
|
|
|
msisdn: null
|
|
|
|
};
|
|
|
|
|
|
|
|
function CdmaIccInfo() {}
|
|
|
|
CdmaIccInfo.prototype = {
|
|
|
|
__proto__: IccInfo.prototype,
|
|
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozCdmaIccInfo]),
|
|
|
|
classID: CDMAICCINFO_CID,
|
|
|
|
classInfo: XPCOMUtils.generateCI({
|
|
|
|
classID: CDMAICCINFO_CID,
|
|
|
|
classDescription: "MozCdmaIccInfo",
|
|
|
|
flags: Ci.nsIClassInfo.DOM_OBJECT,
|
|
|
|
interfaces: [Ci.nsIDOMMozCdmaIccInfo]
|
|
|
|
}),
|
|
|
|
|
|
|
|
// nsIDOMMozCdmaIccInfo
|
|
|
|
|
2014-04-07 11:29:04 +04:00
|
|
|
mdn: null,
|
|
|
|
prlVersion: 0
|
2013-12-03 10:18:32 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
function DataConnectionHandler(clientId, radioInterface) {
|
|
|
|
// Initial owning attributes.
|
|
|
|
this.clientId = clientId;
|
|
|
|
this.radioInterface = radioInterface;
|
|
|
|
this.dataCallSettings = {
|
|
|
|
oldEnabled: false,
|
|
|
|
enabled: false,
|
|
|
|
roamingEnabled: false
|
|
|
|
};
|
|
|
|
this._dataCallbacks = [];
|
|
|
|
|
|
|
|
// This matrix is used to keep all the APN settings.
|
|
|
|
// - |byApn| object makes it easier to get the corresponding APN setting
|
|
|
|
// via a given set of APN, user name and password.
|
|
|
|
// - |byType| object makes it easier to get the corresponding APN setting
|
|
|
|
// via a given APN type.
|
|
|
|
this.apnSettings = {
|
|
|
|
byType: {},
|
|
|
|
byApn: {}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
DataConnectionHandler.prototype = {
|
|
|
|
clientId: 0,
|
|
|
|
radioInterface: null,
|
|
|
|
// Data calls setting.
|
|
|
|
dataCallSettings: null,
|
|
|
|
apnSettings: null,
|
|
|
|
|
|
|
|
// Apn settings to be setup after data call are cleared.
|
|
|
|
_pendingApnSettings: null,
|
|
|
|
|
|
|
|
debug: function(s) {
|
|
|
|
dump("-*- DataConnectionHandler[" + this.clientId + "]: " + s + "\n");
|
|
|
|
},
|
|
|
|
|
|
|
|
shutdown: function() {
|
|
|
|
// Shutdown all RIL network interfaces
|
|
|
|
for (let [, apnSetting] of Iterator(this.apnSettings.byApn)) {
|
|
|
|
if (apnSetting.iface) {
|
|
|
|
apnSetting.iface.shutdown();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.clientId = null;
|
|
|
|
this.radioInterface = null;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if we get all necessary APN data.
|
|
|
|
*/
|
|
|
|
_validateApnSetting: function(apnSetting) {
|
|
|
|
return (apnSetting &&
|
|
|
|
apnSetting.apn &&
|
|
|
|
apnSetting.types &&
|
|
|
|
apnSetting.types.length);
|
|
|
|
},
|
|
|
|
|
|
|
|
_deliverDataCallCallback: function(name, args) {
|
|
|
|
// We need to worry about callback registration state mutations during the
|
|
|
|
// callback firing. The behaviour we want is to *not* call any callbacks
|
|
|
|
// that are added during the firing and to *not* call any callbacks that are
|
|
|
|
// removed during the firing. To address this, we make a copy of the
|
|
|
|
// callback list before dispatching and then double-check that each callback
|
|
|
|
// is still registered before calling it.
|
|
|
|
let callbacks = this._dataCallbacks.slice();
|
|
|
|
for (let callback of callbacks) {
|
|
|
|
if (this._dataCallbacks.indexOf(callback) == -1) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
try {
|
2014-03-29 11:18:13 +04:00
|
|
|
let handler = callback[name];
|
|
|
|
if (typeof handler !== "function") {
|
|
|
|
throw new Error("No handler for " + name);
|
|
|
|
}
|
2013-12-03 10:18:32 +04:00
|
|
|
handler.apply(callback, args);
|
|
|
|
} catch (e) {
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("callback handler for " + name + " threw an exception: " + e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This function will do the following steps:
|
|
|
|
* 1. Clear the cached APN settings in the RIL.
|
|
|
|
* 2. Combine APN, user name, and password as the key of |byApn| object to
|
|
|
|
* refer to the corresponding APN setting.
|
|
|
|
* 3. Use APN type as the index of |byType| object to refer to the
|
|
|
|
* corresponding APN setting.
|
|
|
|
* 4. Create RilNetworkInterface for each APN setting created at step 2.
|
|
|
|
*/
|
|
|
|
_setupApnSettings: function(newApnSettings) {
|
|
|
|
if (!newApnSettings) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (DEBUG) this.debug("setupApnSettings: " + JSON.stringify(newApnSettings));
|
|
|
|
|
|
|
|
// Unregister anything from iface and delete it.
|
|
|
|
for (let [, apnSetting] in Iterator(this.apnSettings.byApn)) {
|
|
|
|
if (apnSetting.iface.name in gNetworkManager.networkInterfaces) {
|
|
|
|
gNetworkManager.unregisterNetworkInterface(apnSetting.iface);
|
|
|
|
}
|
|
|
|
this.unregisterDataCallCallback(apnSetting.iface);
|
|
|
|
delete apnSetting.iface;
|
|
|
|
}
|
|
|
|
this.apnSettings.byApn = {};
|
|
|
|
this.apnSettings.byType = {};
|
|
|
|
|
|
|
|
// Cache the APN settings by APNs and by types in the RIL.
|
|
|
|
for (let inputApnSetting of newApnSettings) {
|
|
|
|
if (!this._validateApnSetting(inputApnSetting)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Combine APN, user name, and password as the key of |byApn| object to
|
|
|
|
// refer to the corresponding APN setting.
|
|
|
|
let apnKey = inputApnSetting.apn +
|
|
|
|
(inputApnSetting.user || "") +
|
|
|
|
(inputApnSetting.password || "");
|
|
|
|
|
|
|
|
if (!this.apnSettings.byApn[apnKey]) {
|
|
|
|
this.apnSettings.byApn[apnKey] = inputApnSetting;
|
|
|
|
} else {
|
|
|
|
this.apnSettings.byApn[apnKey].types =
|
|
|
|
this.apnSettings.byApn[apnKey].types.concat(inputApnSetting.types);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Use APN type as the index of |byType| object to refer to the
|
|
|
|
// corresponding APN setting.
|
|
|
|
for (let type of inputApnSetting.types) {
|
|
|
|
this.apnSettings.byType[type] = this.apnSettings.byApn[apnKey];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create RilNetworkInterface for each APN setting that just cached.
|
|
|
|
for (let [, apnSetting] in Iterator(this.apnSettings.byApn)) {
|
|
|
|
apnSetting.iface = new RILNetworkInterface(this, apnSetting);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if all data is disconnected.
|
|
|
|
*/
|
|
|
|
allDataDisconnected: function() {
|
|
|
|
for (let [, apnSetting] of Iterator(this.apnSettings.byApn)) {
|
|
|
|
let iface = apnSetting.iface;
|
|
|
|
if (iface && iface.state != RIL.GECKO_NETWORK_STATE_UNKNOWN &&
|
|
|
|
iface.state != RIL.GECKO_NETWORK_STATE_DISCONNECTED) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if there is any activated data connection.
|
|
|
|
*/
|
|
|
|
anyDataConnected: function() {
|
|
|
|
for (let [, apnSetting] of Iterator(this.apnSettings.byApn)) {
|
|
|
|
let iface = apnSetting.iface;
|
|
|
|
if (iface && iface.state == RIL.GECKO_NETWORK_STATE_CONNECTED) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
},
|
|
|
|
|
|
|
|
updateApnSettings: function(newApnSettings) {
|
|
|
|
if (!newApnSettings) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (this._pendingApnSettings) {
|
|
|
|
// Change of apn settings in process, just update to the newest.
|
|
|
|
this._pengingApnSettings = newApnSettings;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let isDeactivatingDataCalls = false;
|
|
|
|
// Clear the cached APN settings in the RIL.
|
|
|
|
for (let [, apnSetting] of Iterator(this.apnSettings.byApn)) {
|
|
|
|
// Clear all existing connections based on APN types.
|
|
|
|
for (let type of apnSetting.types) {
|
|
|
|
if (this.getDataCallStateByType(type) ==
|
|
|
|
RIL.GECKO_NETWORK_STATE_CONNECTED) {
|
|
|
|
this.deactivateDataCallByType(type);
|
|
|
|
isDeactivatingDataCalls = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (isDeactivatingDataCalls) {
|
|
|
|
// Defer apn settings setup until all data calls are cleared.
|
|
|
|
this._pendingApnSettings = newApnSettings;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this._setupApnSettings(newApnSettings);
|
|
|
|
},
|
|
|
|
|
|
|
|
updateRILNetworkInterface: function() {
|
|
|
|
let apnSetting = this.apnSettings.byType.default;
|
|
|
|
if (!this._validateApnSetting(apnSetting)) {
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("We haven't gotten completely the APN data.");
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This check avoids data call connection if the radio is not ready
|
|
|
|
// yet after toggling off airplane mode.
|
|
|
|
let rilContext = this.radioInterface.rilContext;
|
|
|
|
if (rilContext.radioState != RIL.GECKO_RADIOSTATE_READY) {
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("RIL is not ready for data connection: radio's not ready");
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We only watch at "ril.data.enabled" flag changes for connecting or
|
|
|
|
// disconnecting the data call. If the value of "ril.data.enabled" is
|
|
|
|
// true and any of the remaining flags change the setting application
|
|
|
|
// should turn this flag to false and then to true in order to reload
|
|
|
|
// the new values and reconnect the data call.
|
|
|
|
if (this.dataCallSettings.oldEnabled === this.dataCallSettings.enabled) {
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("No changes for ril.data.enabled flag. Nothing to do.");
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let defaultDataCallState = this.getDataCallStateByType("default");
|
|
|
|
if (defaultDataCallState == RIL.GECKO_NETWORK_STATE_CONNECTING ||
|
|
|
|
defaultDataCallState == RIL.GECKO_NETWORK_STATE_DISCONNECTING) {
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("Nothing to do during connecting/disconnecting in progress.");
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let dataInfo = rilContext.data;
|
|
|
|
let isRegistered =
|
|
|
|
dataInfo.state == RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED;
|
|
|
|
let haveDataConnection =
|
|
|
|
dataInfo.type != RIL.GECKO_MOBILE_CONNECTION_STATE_UNKNOWN;
|
|
|
|
if (!isRegistered || !haveDataConnection) {
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("RIL is not ready for data connection: Phone's not " +
|
|
|
|
"registered or doesn't have data connection.");
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let wifi_active = false;
|
|
|
|
if (gNetworkManager.active &&
|
|
|
|
gNetworkManager.active.type == Ci.nsINetworkInterface.NETWORK_TYPE_WIFI) {
|
|
|
|
wifi_active = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
let defaultDataCallConnected = defaultDataCallState ==
|
|
|
|
RIL.GECKO_NETWORK_STATE_CONNECTED;
|
|
|
|
if (defaultDataCallConnected &&
|
|
|
|
(!this.dataCallSettings.enabled ||
|
|
|
|
(dataInfo.roaming && !this.dataCallSettings.roamingEnabled))) {
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("Data call settings: disconnect data call.");
|
|
|
|
}
|
|
|
|
this.deactivateDataCallByType("default");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (defaultDataCallConnected && wifi_active) {
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("Disconnect data call when Wifi is connected.");
|
|
|
|
}
|
|
|
|
this.deactivateDataCallByType("default");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!this.dataCallSettings.enabled || defaultDataCallConnected) {
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("Data call settings: nothing to do.");
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (dataInfo.roaming && !this.dataCallSettings.roamingEnabled) {
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("We're roaming, but data roaming is disabled.");
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (wifi_active) {
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("Don't connect data call when Wifi is connected.");
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (this._pendingApnSettings) {
|
|
|
|
if (DEBUG) this.debug("We're changing apn settings, ignore any changes.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let detailedRadioState = rilContext.detailedRadioState;
|
|
|
|
if (gRadioEnabledController.isDeactivatingDataCalls() ||
|
|
|
|
detailedRadioState == RIL.GECKO_DETAILED_RADIOSTATE_ENABLING ||
|
|
|
|
detailedRadioState == RIL.GECKO_DETAILED_RADIOSTATE_DISABLING) {
|
|
|
|
// We're changing the radio power currently, ignore any changes.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("Data call settings: connect data call.");
|
|
|
|
}
|
|
|
|
this.setupDataCallByType("default");
|
|
|
|
},
|
|
|
|
|
|
|
|
getDataCallStateByType: function(apnType) {
|
|
|
|
let apnSetting = this.apnSettings.byType[apnType];
|
|
|
|
if (!apnSetting) {
|
|
|
|
return RIL.GECKO_NETWORK_STATE_UNKNOWN;
|
|
|
|
}
|
|
|
|
if (!apnSetting.iface.inConnectedTypes(apnType)) {
|
|
|
|
return RIL.GECKO_NETWORK_STATE_DISCONNECTED;
|
|
|
|
}
|
|
|
|
return apnSetting.iface.state;
|
|
|
|
},
|
|
|
|
|
|
|
|
setupDataCallByType: function(apnType) {
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("setupDataCallByType: " + apnType);
|
|
|
|
}
|
|
|
|
let apnSetting = this.apnSettings.byType[apnType];
|
|
|
|
if (!apnSetting) {
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("No apn setting for type: " + apnType);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let dataInfo = this.radioInterface.rilContext.data;
|
|
|
|
if (dataInfo.state != RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED ||
|
|
|
|
dataInfo.type == RIL.GECKO_MOBILE_CONNECTION_STATE_UNKNOWN) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
apnSetting.iface.connect(apnType);
|
|
|
|
// We just call connect() function, so this interface should be in
|
|
|
|
// connecting state. If this interface is already in connected state, we
|
|
|
|
// are sure that this interface have successfully established connection
|
|
|
|
// for other data call types before we call connect() function for current
|
|
|
|
// data call type. In this circumstance, we have to directly update the
|
|
|
|
// necessary data call and interface information to RILContentHelper
|
|
|
|
// and network manager for current data call type.
|
|
|
|
if (apnSetting.iface.connected) {
|
|
|
|
// Update the interface status via-registration if the interface has
|
|
|
|
// already been registered in the network manager.
|
|
|
|
if (apnSetting.iface.name in gNetworkManager.networkInterfaces) {
|
|
|
|
gNetworkManager.unregisterNetworkInterface(apnSetting.iface);
|
|
|
|
}
|
|
|
|
gNetworkManager.registerNetworkInterface(apnSetting.iface);
|
|
|
|
|
|
|
|
Services.obs.notifyObservers(apnSetting.iface,
|
|
|
|
kNetworkInterfaceStateChangedTopic,
|
|
|
|
null);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
deactivateDataCallByType: function(apnType) {
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("deactivateDataCallByType: " + apnType);
|
|
|
|
}
|
|
|
|
let apnSetting = this.apnSettings.byType[apnType];
|
|
|
|
if (!apnSetting) {
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("No apn setting for type: " + apnType);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
apnSetting.iface.disconnect(apnType);
|
|
|
|
// We just call disconnect() function, so this interface should be in
|
|
|
|
// disconnecting state. If this interface is still in connected state, we
|
|
|
|
// are sure that other data call types still need this connection of this
|
|
|
|
// interface. In this circumstance, we have to directly update the
|
|
|
|
// necessary data call and interface information to RILContentHelper
|
|
|
|
// and network manager for current data call type.
|
|
|
|
if (apnSetting.iface.connectedTypes.length && apnSetting.iface.connected) {
|
|
|
|
// Update the interface status via-registration if the interface has
|
|
|
|
// already been registered in the network manager.
|
|
|
|
if (apnSetting.iface.name in gNetworkManager.networkInterfaces) {
|
|
|
|
gNetworkManager.unregisterNetworkInterface(apnSetting.iface);
|
2013-10-24 12:15:06 +04:00
|
|
|
}
|
2013-12-03 10:18:32 +04:00
|
|
|
gNetworkManager.registerNetworkInterface(apnSetting.iface);
|
2013-10-24 12:15:06 +04:00
|
|
|
|
2013-12-03 10:18:32 +04:00
|
|
|
Services.obs.notifyObservers(apnSetting.iface,
|
|
|
|
kNetworkInterfaceStateChangedTopic,
|
|
|
|
null);
|
|
|
|
}
|
|
|
|
},
|
2013-10-24 12:15:06 +04:00
|
|
|
|
2013-12-03 10:18:32 +04:00
|
|
|
deactivateDataCalls: function() {
|
|
|
|
let dataDisconnecting = false;
|
|
|
|
for (let [, apnSetting] of Iterator(this.apnSettings.byApn)) {
|
|
|
|
for (let type of apnSetting.types) {
|
|
|
|
if (this.getDataCallStateByType(type) ==
|
|
|
|
RIL.GECKO_NETWORK_STATE_CONNECTED) {
|
|
|
|
this.deactivateDataCallByType(type);
|
|
|
|
dataDisconnecting = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-10-15 06:42:49 +04:00
|
|
|
|
2013-12-03 10:18:32 +04:00
|
|
|
// No data calls exist. It's safe to proceed the pending radio power off
|
|
|
|
// request.
|
|
|
|
if (gRadioEnabledController.isDeactivatingDataCalls() && !dataDisconnecting) {
|
|
|
|
gRadioEnabledController.finishDeactivatingDataCalls(this.clientId);
|
|
|
|
}
|
|
|
|
},
|
2013-10-15 06:42:49 +04:00
|
|
|
|
2013-12-03 10:18:32 +04:00
|
|
|
registerDataCallCallback: function(callback) {
|
|
|
|
if (this._dataCallbacks.indexOf(callback) != -1) {
|
|
|
|
throw new Error("Already registered this callback: " + callback);
|
|
|
|
}
|
|
|
|
this._dataCallbacks.push(callback);
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("Registering callback: " + callback);
|
|
|
|
}
|
|
|
|
},
|
2013-10-15 06:42:49 +04:00
|
|
|
|
2013-12-03 10:18:32 +04:00
|
|
|
unregisterDataCallCallback: function(callback) {
|
|
|
|
let index = this._dataCallbacks.indexOf(callback);
|
|
|
|
if (index != -1) {
|
|
|
|
this._dataCallbacks.splice(index, 1);
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("Unregistering callback: " + callback);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2013-10-15 06:42:49 +04:00
|
|
|
|
2013-12-03 10:18:32 +04:00
|
|
|
/**
|
|
|
|
* Handle data errors.
|
|
|
|
*/
|
|
|
|
handleDataCallError: function(message) {
|
|
|
|
// Notify data call error only for data APN
|
|
|
|
let apnSetting = this.apnSettings && this.apnSettings.byType.default;
|
|
|
|
if (apnSetting) {
|
|
|
|
if (message.apn == apnSetting.apn &&
|
|
|
|
apnSetting.iface.inConnectedTypes("default")) {
|
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:DataError",
|
|
|
|
this.clientId, message);
|
|
|
|
}
|
|
|
|
}
|
2013-10-15 06:42:49 +04:00
|
|
|
|
2013-12-03 10:18:32 +04:00
|
|
|
this._deliverDataCallCallback("dataCallError", [message]);
|
|
|
|
},
|
2013-10-15 06:42:49 +04:00
|
|
|
|
2013-12-03 10:18:32 +04:00
|
|
|
/**
|
|
|
|
* Handle data call state changes.
|
|
|
|
*/
|
|
|
|
handleDataCallState: function(datacall) {
|
|
|
|
this._deliverDataCallCallback("dataCallStateChanged", [datacall]);
|
2013-08-22 13:18:13 +04:00
|
|
|
|
2013-12-03 10:18:32 +04:00
|
|
|
// Process pending radio power off request after all data calls
|
|
|
|
// are disconnected.
|
|
|
|
if (datacall.state == RIL.GECKO_NETWORK_STATE_UNKNOWN &&
|
|
|
|
this.allDataDisconnected()) {
|
|
|
|
if (gRadioEnabledController.isDeactivatingDataCalls()) {
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("All data connections are disconnected.");
|
|
|
|
}
|
|
|
|
gRadioEnabledController.finishDeactivatingDataCalls(this.clientId);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this._pendingApnSettings) {
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("Setup pending apn settings.");
|
|
|
|
}
|
|
|
|
this._setupApnSettings(this._pendingApnSettings);
|
|
|
|
this._pendingApnSettings = null;
|
|
|
|
this.updateRILNetworkInterface();
|
|
|
|
}
|
|
|
|
}
|
2013-08-22 13:18:13 +04:00
|
|
|
},
|
|
|
|
};
|
2013-07-02 13:36:40 +04:00
|
|
|
|
2013-08-22 13:18:13 +04:00
|
|
|
function RadioInterfaceLayer() {
|
2014-02-17 15:35:12 +04:00
|
|
|
let workerMessenger = new WorkerMessenger();
|
|
|
|
workerMessenger.init();
|
2014-05-21 02:50:00 +04:00
|
|
|
this.setWorkerDebugFlag = workerMessenger.setDebugFlag.bind(workerMessenger);
|
2014-02-17 15:35:12 +04:00
|
|
|
|
2013-07-02 13:36:37 +04:00
|
|
|
let numIfaces = this.numRadioInterfaces;
|
2014-01-23 12:44:20 +04:00
|
|
|
if (DEBUG) debug(numIfaces + " interfaces");
|
2013-07-02 13:36:37 +04:00
|
|
|
this.radioInterfaces = [];
|
|
|
|
for (let clientId = 0; clientId < numIfaces; clientId++) {
|
2014-02-17 15:35:03 +04:00
|
|
|
this.radioInterfaces.push(new RadioInterface(clientId, workerMessenger));
|
2013-07-02 13:36:37 +04:00
|
|
|
}
|
2013-12-21 00:56:35 +04:00
|
|
|
|
|
|
|
Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
|
2014-05-21 02:50:00 +04:00
|
|
|
Services.prefs.addObserver(kPrefRilDebuggingEnabled, this, false);
|
2013-08-22 13:18:13 +04:00
|
|
|
|
|
|
|
gMessageManager.init(this);
|
|
|
|
gRadioEnabledController.init(this);
|
|
|
|
gDataConnectionManager.init(this);
|
2013-07-02 13:36:37 +04:00
|
|
|
}
|
|
|
|
RadioInterfaceLayer.prototype = {
|
|
|
|
|
|
|
|
classID: RADIOINTERFACELAYER_CID,
|
|
|
|
classInfo: XPCOMUtils.generateCI({classID: RADIOINTERFACELAYER_CID,
|
|
|
|
classDescription: "RadioInterfaceLayer",
|
|
|
|
interfaces: [Ci.nsIRadioInterfaceLayer]}),
|
|
|
|
|
|
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIRadioInterfaceLayer,
|
|
|
|
Ci.nsIObserver]),
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nsIObserver interface methods.
|
|
|
|
*/
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
observe: function(subject, topic, data) {
|
2013-12-21 00:56:35 +04:00
|
|
|
switch (topic) {
|
|
|
|
case NS_XPCOM_SHUTDOWN_OBSERVER_ID:
|
2013-12-03 10:18:32 +04:00
|
|
|
for (let radioInterface of this.radioInterfaces) {
|
|
|
|
radioInterface.shutdown();
|
2013-12-21 00:56:35 +04:00
|
|
|
}
|
2013-12-03 10:18:32 +04:00
|
|
|
this.radioInterfaces = null;
|
|
|
|
Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
|
2013-12-21 00:56:35 +04:00
|
|
|
break;
|
2014-05-21 02:50:00 +04:00
|
|
|
|
|
|
|
case NS_PREFBRANCH_PREFCHANGE_TOPIC_ID:
|
|
|
|
if (data === kPrefRilDebuggingEnabled) {
|
|
|
|
updateDebugFlag();
|
|
|
|
this.setWorkerDebugFlag(DEBUG);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2013-07-02 13:36:37 +04:00
|
|
|
},
|
2013-06-07 11:32:20 +04:00
|
|
|
|
2013-07-02 13:36:37 +04:00
|
|
|
/**
|
|
|
|
* nsIRadioInterfaceLayer interface methods.
|
|
|
|
*/
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
getRadioInterface: function(clientId) {
|
2013-07-02 13:36:37 +04:00
|
|
|
return this.radioInterfaces[clientId];
|
2013-11-02 14:17:35 +04:00
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
setMicrophoneMuted: function(muted) {
|
2013-11-27 11:45:31 +04:00
|
|
|
for (let clientId = 0; clientId < this.numRadioInterfaces; clientId++) {
|
|
|
|
let radioInterface = this.radioInterfaces[clientId];
|
|
|
|
radioInterface.workerMessenger.send("setMute", { muted: muted });
|
|
|
|
}
|
2013-07-02 13:36:37 +04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
XPCOMUtils.defineLazyGetter(RadioInterfaceLayer.prototype,
|
2014-01-13 06:44:33 +04:00
|
|
|
"numRadioInterfaces", function() {
|
2013-07-02 13:36:37 +04:00
|
|
|
try {
|
2013-10-24 12:15:06 +04:00
|
|
|
return Services.prefs.getIntPref(kPrefRilNumRadioInterfaces);
|
|
|
|
} catch(e) {}
|
2013-09-30 13:24:54 +04:00
|
|
|
|
|
|
|
return 1;
|
2013-07-02 13:36:37 +04:00
|
|
|
});
|
|
|
|
|
2014-02-17 15:35:03 +04:00
|
|
|
function WorkerMessenger() {
|
2013-08-13 16:14:10 +04:00
|
|
|
// Initial owning attributes.
|
2014-02-17 15:35:03 +04:00
|
|
|
this.radioInterfaces = [];
|
2013-08-13 16:14:10 +04:00
|
|
|
this.tokenCallbackMap = {};
|
|
|
|
|
|
|
|
this.worker = new ChromeWorker("resource://gre/modules/ril_worker.js");
|
|
|
|
this.worker.onerror = this.onerror.bind(this);
|
|
|
|
this.worker.onmessage = this.onmessage.bind(this);
|
|
|
|
}
|
|
|
|
WorkerMessenger.prototype = {
|
2014-02-17 15:35:03 +04:00
|
|
|
radioInterfaces: null,
|
2013-08-13 16:14:10 +04:00
|
|
|
worker: null,
|
|
|
|
|
|
|
|
// This gets incremented each time we send out a message.
|
|
|
|
token: 1,
|
|
|
|
|
|
|
|
// Maps tokens we send out with messages to the message callback.
|
|
|
|
tokenCallbackMap: null,
|
|
|
|
|
2014-02-17 15:35:02 +04:00
|
|
|
init: function() {
|
|
|
|
let options = {
|
|
|
|
debug: DEBUG,
|
|
|
|
cellBroadcastDisabled: false,
|
|
|
|
quirks: {
|
|
|
|
callstateExtraUint32:
|
|
|
|
libcutils.property_get("ro.moz.ril.callstate_extra_int", "false") === "true",
|
|
|
|
v5Legacy:
|
|
|
|
libcutils.property_get("ro.moz.ril.v5_legacy", "true") === "true",
|
|
|
|
requestUseDialEmergencyCall:
|
|
|
|
libcutils.property_get("ro.moz.ril.dial_emergency_call", "false") === "true",
|
|
|
|
simAppStateExtraFields:
|
|
|
|
libcutils.property_get("ro.moz.ril.simstate_extra_field", "false") === "true",
|
|
|
|
extraUint2ndCall:
|
|
|
|
libcutils.property_get("ro.moz.ril.extra_int_2nd_call", "false") == "true",
|
|
|
|
haveQueryIccLockRetryCount:
|
|
|
|
libcutils.property_get("ro.moz.ril.query_icc_count", "false") == "true",
|
|
|
|
sendStkProfileDownload:
|
|
|
|
libcutils.property_get("ro.moz.ril.send_stk_profile_dl", "false") == "true",
|
2014-05-05 11:12:14 +04:00
|
|
|
dataRegistrationOnDemand: RILQUIRKS_DATA_REGISTRATION_ON_DEMAND,
|
|
|
|
subscriptionControl: RILQUIRKS_SUBSCRIPTION_CONTROL
|
2014-02-17 15:35:02 +04:00
|
|
|
},
|
|
|
|
rilEmergencyNumbers: libcutils.property_get("ril.ecclist") ||
|
|
|
|
libcutils.property_get("ro.ril.ecclist")
|
|
|
|
};
|
|
|
|
|
|
|
|
try {
|
|
|
|
options.cellBroadcastDisabled =
|
|
|
|
Services.prefs.getBoolPref(kPrefCellBroadcastDisabled);
|
|
|
|
} catch(e) {}
|
|
|
|
|
2014-02-17 15:35:03 +04:00
|
|
|
this.send(null, "setInitialOptions", options);
|
|
|
|
},
|
|
|
|
|
2014-05-21 02:50:00 +04:00
|
|
|
setDebugFlag: function(aDebug) {
|
|
|
|
let options = { debug: aDebug };
|
|
|
|
this.send(null, "setDebugFlag", options);
|
|
|
|
},
|
|
|
|
|
2014-02-17 15:35:03 +04:00
|
|
|
debug: function(aClientId, aMessage) {
|
|
|
|
// We use the same debug subject with RadioInterface's here.
|
|
|
|
dump("-*- RadioInterface[" + aClientId + "]: " + aMessage + "\n");
|
2014-02-17 15:35:02 +04:00
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
onerror: function(event) {
|
2013-08-13 16:14:10 +04:00
|
|
|
if (DEBUG) {
|
2014-02-17 15:35:03 +04:00
|
|
|
this.debug("X", "Got an error: " + event.filename + ":" +
|
2013-08-13 16:14:10 +04:00
|
|
|
event.lineno + ": " + event.message + "\n");
|
|
|
|
}
|
|
|
|
event.preventDefault();
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Process the incoming message from the RIL worker.
|
|
|
|
*/
|
2014-01-13 06:44:40 +04:00
|
|
|
onmessage: function(event) {
|
2013-08-13 16:14:10 +04:00
|
|
|
let message = event.data;
|
2014-02-17 15:35:03 +04:00
|
|
|
let clientId = message.rilMessageClientId;
|
|
|
|
if (clientId === null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-08-13 16:14:10 +04:00
|
|
|
if (DEBUG) {
|
2014-02-17 15:35:03 +04:00
|
|
|
this.debug(clientId, "Received message from worker: " + JSON.stringify(message));
|
2013-08-13 16:14:10 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
let token = message.rilMessageToken;
|
|
|
|
if (token == null) {
|
|
|
|
// That's an unsolicited message. Pass to RadioInterface directly.
|
2014-02-17 15:35:03 +04:00
|
|
|
let radioInterface = this.radioInterfaces[clientId];
|
|
|
|
radioInterface.handleUnsolicitedWorkerMessage(message);
|
2013-08-13 16:14:10 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let callback = this.tokenCallbackMap[message.rilMessageToken];
|
|
|
|
if (!callback) {
|
2014-02-17 15:35:03 +04:00
|
|
|
if (DEBUG) this.debug(clientId, "Ignore orphan token: " + message.rilMessageToken);
|
2013-08-13 16:14:10 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let keep = false;
|
|
|
|
try {
|
|
|
|
keep = callback(message);
|
|
|
|
} catch(e) {
|
2014-02-17 15:35:03 +04:00
|
|
|
if (DEBUG) this.debug(clientId, "callback throws an exception: " + e);
|
2013-08-13 16:14:10 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!keep) {
|
|
|
|
delete this.tokenCallbackMap[message.rilMessageToken];
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2014-02-17 15:35:03 +04:00
|
|
|
registerClient: function(aClientId, aRadioInterface) {
|
|
|
|
if (DEBUG) this.debug(aClientId, "Starting RIL Worker");
|
|
|
|
|
|
|
|
// Keep a reference so that we can dispatch unsolicited messages to it.
|
|
|
|
this.radioInterfaces[aClientId] = aRadioInterface;
|
|
|
|
|
|
|
|
this.send(null, "registerClient", { clientId: aClientId });
|
|
|
|
gSystemWorkerManager.registerRilWorker(aClientId, this.worker);
|
|
|
|
},
|
|
|
|
|
2013-08-13 16:14:10 +04:00
|
|
|
/**
|
|
|
|
* Send arbitrary message to worker.
|
|
|
|
*
|
|
|
|
* @param rilMessageType
|
|
|
|
* A text message type.
|
|
|
|
* @param message [optional]
|
|
|
|
* An optional message object to send.
|
|
|
|
* @param callback [optional]
|
|
|
|
* An optional callback function which is called when worker replies
|
2013-11-21 18:09:14 +04:00
|
|
|
* with an message containing a "rilMessageToken" attribute of the
|
2013-08-13 16:14:10 +04:00
|
|
|
* same value we passed. This callback function accepts only one
|
|
|
|
* parameter -- the reply from worker. It also returns a boolean
|
|
|
|
* value true to keep current token-callback mapping and wait for
|
|
|
|
* another worker reply, or false to remove the mapping.
|
|
|
|
*/
|
2014-02-17 15:35:03 +04:00
|
|
|
send: function(clientId, rilMessageType, message, callback) {
|
2013-08-13 16:14:10 +04:00
|
|
|
message = message || {};
|
|
|
|
|
2014-02-17 15:35:03 +04:00
|
|
|
message.rilMessageClientId = clientId;
|
2013-08-13 16:14:10 +04:00
|
|
|
message.rilMessageToken = this.token;
|
|
|
|
this.token++;
|
|
|
|
|
|
|
|
if (callback) {
|
|
|
|
// Only create the map if callback is provided. For sending a request
|
|
|
|
// and intentionally leaving the callback undefined, that reply will
|
|
|
|
// be dropped in |this.onmessage| because of that orphan token.
|
|
|
|
//
|
|
|
|
// For sending a request that never replied at all, we're fine with this
|
|
|
|
// because no callback shall be passed and we leave nothing to be cleaned
|
|
|
|
// up later.
|
|
|
|
this.tokenCallbackMap[message.rilMessageToken] = callback;
|
|
|
|
}
|
|
|
|
|
|
|
|
message.rilMessageType = rilMessageType;
|
|
|
|
this.worker.postMessage(message);
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Send message to worker and return worker reply to RILContentHelper.
|
|
|
|
*
|
|
|
|
* @param msg
|
|
|
|
* A message object from ppmm.
|
|
|
|
* @param rilMessageType
|
|
|
|
* A text string for worker message type.
|
|
|
|
* @param ipcType [optinal]
|
2013-11-21 18:09:14 +04:00
|
|
|
* A text string for ipc message type. "msg.name" if omitted.
|
2013-08-13 16:14:10 +04:00
|
|
|
*
|
|
|
|
* @TODO: Bug 815526 - deprecate RILContentHelper.
|
|
|
|
*/
|
2014-02-17 15:35:03 +04:00
|
|
|
sendWithIPCMessage: function(clientId, msg, rilMessageType, ipcType) {
|
|
|
|
this.send(clientId, rilMessageType, msg.json.data, (function(reply) {
|
2013-08-13 16:14:10 +04:00
|
|
|
ipcType = ipcType || msg.name;
|
2013-09-30 04:56:00 +04:00
|
|
|
msg.target.sendAsyncMessage(ipcType, {
|
2014-02-17 15:35:03 +04:00
|
|
|
clientId: clientId,
|
2013-09-30 04:56:00 +04:00
|
|
|
data: reply
|
|
|
|
});
|
2013-08-13 16:14:10 +04:00
|
|
|
return false;
|
2013-09-30 04:56:00 +04:00
|
|
|
}).bind(this));
|
2013-08-13 16:14:10 +04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-02-17 15:35:03 +04:00
|
|
|
function RadioInterface(aClientId, aWorkerMessenger) {
|
2014-02-17 15:35:02 +04:00
|
|
|
this.clientId = aClientId;
|
2014-02-17 15:35:03 +04:00
|
|
|
this.workerMessenger = {
|
|
|
|
send: aWorkerMessenger.send.bind(aWorkerMessenger, aClientId),
|
|
|
|
sendWithIPCMessage:
|
|
|
|
aWorkerMessenger.sendWithIPCMessage.bind(aWorkerMessenger, aClientId),
|
|
|
|
};
|
|
|
|
aWorkerMessenger.registerClient(aClientId, this);
|
2013-07-02 13:36:37 +04:00
|
|
|
|
2014-01-08 10:10:58 +04:00
|
|
|
this.supportedNetworkTypes = this.getSupportedNetworkTypes();
|
|
|
|
|
2012-06-13 06:46:41 +04:00
|
|
|
this.rilContext = {
|
2012-03-21 03:18:41 +04:00
|
|
|
radioState: RIL.GECKO_RADIOSTATE_UNAVAILABLE,
|
2013-11-21 18:09:14 +04:00
|
|
|
detailedRadioState: null,
|
2013-02-01 17:17:48 +04:00
|
|
|
cardState: RIL.GECKO_CARDSTATE_UNKNOWN,
|
2013-03-29 06:56:07 +04:00
|
|
|
networkSelectionMode: RIL.GECKO_NETWORK_SELECTION_UNKNOWN,
|
2013-01-10 20:18:54 +04:00
|
|
|
iccInfo: null,
|
2013-01-11 13:20:12 +04:00
|
|
|
imsi: null,
|
2012-04-20 01:33:25 +04:00
|
|
|
|
2014-04-08 10:28:54 +04:00
|
|
|
// These objects implement the nsIMobileConnectionInfo interface,
|
2012-08-16 05:36:56 +04:00
|
|
|
// although the actual implementation lives in the content process. So are
|
|
|
|
// the child attributes `network` and `cell`, which implement
|
2014-04-08 10:28:54 +04:00
|
|
|
// nsIMobileNetworkInfo and nsIMobileCellInfo respectively.
|
2012-04-20 01:33:25 +04:00
|
|
|
voice: {connected: false,
|
|
|
|
emergencyCallsOnly: false,
|
|
|
|
roaming: false,
|
2012-06-13 01:05:50 +04:00
|
|
|
network: null,
|
2012-08-16 05:36:56 +04:00
|
|
|
cell: null,
|
2012-04-20 01:33:25 +04:00
|
|
|
type: null,
|
|
|
|
signalStrength: null,
|
|
|
|
relSignalStrength: null},
|
2012-06-13 06:46:41 +04:00
|
|
|
data: {connected: false,
|
2012-04-20 01:33:25 +04:00
|
|
|
emergencyCallsOnly: false,
|
|
|
|
roaming: false,
|
2012-06-13 01:05:50 +04:00
|
|
|
network: null,
|
2012-08-16 05:36:56 +04:00
|
|
|
cell: null,
|
2012-04-20 01:33:25 +04:00
|
|
|
type: null,
|
|
|
|
signalStrength: null,
|
|
|
|
relSignalStrength: null},
|
2011-12-07 10:57:19 +04:00
|
|
|
};
|
2012-05-24 09:12:07 +04:00
|
|
|
|
2012-12-26 14:49:08 +04:00
|
|
|
this.voicemailInfo = {
|
|
|
|
number: null,
|
|
|
|
displayName: null
|
|
|
|
};
|
|
|
|
|
2013-08-08 13:29:42 +04:00
|
|
|
this.operatorInfo = {};
|
|
|
|
|
2012-09-07 22:05:08 +04:00
|
|
|
let lock = gSettingsService.createLock();
|
2012-05-24 09:12:07 +04:00
|
|
|
|
2013-11-21 18:09:14 +04:00
|
|
|
// Read the "time.clock.automatic-update.enabled" setting to see if
|
2013-06-22 18:22:05 +04:00
|
|
|
// we need to adjust the system clock time by NITZ or SNTP.
|
2013-10-24 12:14:59 +04:00
|
|
|
lock.get(kSettingsClockAutoUpdateEnabled, this);
|
2012-09-28 10:02:57 +04:00
|
|
|
|
2013-11-21 18:09:14 +04:00
|
|
|
// Read the "time.timezone.automatic-update.enabled" setting to see if
|
2013-06-22 18:22:05 +04:00
|
|
|
// we need to adjust the system timezone by NITZ.
|
2013-10-24 12:14:59 +04:00
|
|
|
lock.get(kSettingsTimezoneAutoUpdateEnabled, this);
|
2013-06-22 18:22:05 +04:00
|
|
|
|
|
|
|
// Set "time.clock.automatic-update.available" to false when starting up.
|
|
|
|
this.setClockAutoUpdateAvailable(false);
|
|
|
|
|
|
|
|
// Set "time.timezone.automatic-update.available" to false when starting up.
|
|
|
|
this.setTimezoneAutoUpdateAvailable(false);
|
2013-01-25 14:06:24 +04:00
|
|
|
|
2012-12-04 06:41:39 +04:00
|
|
|
// Read the Cell Broadcast Search List setting, string of integers or integer
|
|
|
|
// ranges separated by comma, to set listening channels.
|
2013-10-24 12:14:59 +04:00
|
|
|
lock.get(kSettingsCellBroadcastSearchList, this);
|
2012-12-04 06:41:39 +04:00
|
|
|
|
2012-04-25 00:46:42 +04:00
|
|
|
Services.obs.addObserver(this, kMozSettingsChangedObserverTopic, false);
|
2012-10-23 11:15:53 +04:00
|
|
|
Services.obs.addObserver(this, kSysClockChangeObserverTopic, false);
|
2013-06-06 11:28:59 +04:00
|
|
|
Services.obs.addObserver(this, kScreenStateChangedTopic, false);
|
2012-04-20 01:33:25 +04:00
|
|
|
|
2014-03-10 07:36:42 +04:00
|
|
|
Services.obs.addObserver(this, kNetworkConnStateChangedTopic, false);
|
2014-04-11 12:53:57 +04:00
|
|
|
Services.obs.addObserver(this, kNetworkActiveChangedTopic, false);
|
2013-10-24 12:14:59 +04:00
|
|
|
Services.prefs.addObserver(kPrefCellBroadcastDisabled, this, false);
|
2013-09-07 15:09:54 +04:00
|
|
|
|
|
|
|
this.portAddressedSmsApps = {};
|
|
|
|
this.portAddressedSmsApps[WAP.WDP_PORT_PUSH] = this.handleSmsWdpPortPush.bind(this);
|
2013-06-22 18:22:05 +04:00
|
|
|
|
2014-03-12 20:27:00 +04:00
|
|
|
this._receivedSmsSegmentsMap = {};
|
|
|
|
|
2013-06-22 18:22:05 +04:00
|
|
|
this._sntp = new Sntp(this.setClockBySntp.bind(this),
|
2013-11-21 18:09:14 +04:00
|
|
|
Services.prefs.getIntPref("network.sntp.maxRetryCount"),
|
|
|
|
Services.prefs.getIntPref("network.sntp.refreshPeriod"),
|
|
|
|
Services.prefs.getIntPref("network.sntp.timeout"),
|
|
|
|
Services.prefs.getCharPref("network.sntp.pools").split(";"),
|
|
|
|
Services.prefs.getIntPref("network.sntp.port"));
|
2011-12-05 11:58:27 +04:00
|
|
|
}
|
2013-06-22 18:22:05 +04:00
|
|
|
|
2013-07-02 13:36:37 +04:00
|
|
|
RadioInterface.prototype = {
|
2011-12-05 11:58:27 +04:00
|
|
|
|
2013-07-02 13:36:37 +04:00
|
|
|
classID: RADIOINTERFACE_CID,
|
|
|
|
classInfo: XPCOMUtils.generateCI({classID: RADIOINTERFACE_CID,
|
|
|
|
classDescription: "RadioInterface",
|
|
|
|
interfaces: [Ci.nsIRadioInterface]}),
|
2011-12-05 11:58:27 +04:00
|
|
|
|
2013-07-02 13:36:37 +04:00
|
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIRadioInterface,
|
2012-05-24 09:12:07 +04:00
|
|
|
Ci.nsIObserver,
|
|
|
|
Ci.nsISettingsServiceCallback]),
|
2011-12-05 11:58:27 +04:00
|
|
|
|
2014-02-17 15:35:03 +04:00
|
|
|
// A private wrapped WorkerMessenger instance.
|
2013-08-13 16:14:10 +04:00
|
|
|
workerMessenger: null,
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
debug: function(s) {
|
2013-07-02 13:36:58 +04:00
|
|
|
dump("-*- RadioInterface[" + this.clientId + "]: " + s + "\n");
|
|
|
|
},
|
|
|
|
|
2013-12-03 10:18:32 +04:00
|
|
|
shutdown: function() {
|
|
|
|
// Release the CPU wake lock for handling the received SMS.
|
|
|
|
this._releaseSmsHandledWakeLock();
|
|
|
|
|
|
|
|
Services.obs.removeObserver(this, kMozSettingsChangedObserverTopic);
|
|
|
|
Services.obs.removeObserver(this, kSysClockChangeObserverTopic);
|
|
|
|
Services.obs.removeObserver(this, kScreenStateChangedTopic);
|
2014-03-10 07:36:42 +04:00
|
|
|
Services.obs.removeObserver(this, kNetworkConnStateChangedTopic);
|
2014-04-11 12:53:57 +04:00
|
|
|
Services.obs.removeObserver(this, kNetworkActiveChangedTopic);
|
2013-12-03 10:18:32 +04:00
|
|
|
},
|
|
|
|
|
2013-08-08 13:29:42 +04:00
|
|
|
/**
|
|
|
|
* A utility function to copy objects. The srcInfo may contain
|
2013-11-21 18:09:14 +04:00
|
|
|
* "rilMessageType", should ignore it.
|
2013-08-08 13:29:42 +04:00
|
|
|
*/
|
2014-01-13 06:44:40 +04:00
|
|
|
updateInfo: function(srcInfo, destInfo) {
|
2013-08-08 13:29:42 +04:00
|
|
|
for (let key in srcInfo) {
|
2013-11-21 18:09:14 +04:00
|
|
|
if (key === "rilMessageType") {
|
2013-08-08 13:29:42 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
destInfo[key] = srcInfo[key];
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2013-08-09 08:27:19 +04:00
|
|
|
/**
|
|
|
|
* A utility function to compare objects. The srcInfo may contain
|
2013-11-21 18:09:14 +04:00
|
|
|
* "rilMessageType", should ignore it.
|
2013-08-09 08:27:19 +04:00
|
|
|
*/
|
2014-01-13 06:44:40 +04:00
|
|
|
isInfoChanged: function(srcInfo, destInfo) {
|
2013-08-09 08:27:19 +04:00
|
|
|
if (!destInfo) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let key in srcInfo) {
|
2013-11-21 18:09:14 +04:00
|
|
|
if (key === "rilMessageType") {
|
2013-08-09 08:27:19 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (srcInfo[key] !== destInfo[key]) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
},
|
|
|
|
|
2014-01-08 10:10:58 +04:00
|
|
|
/**
|
|
|
|
* A utility function to get supportedNetworkTypes from system property
|
|
|
|
*/
|
|
|
|
getSupportedNetworkTypes: function() {
|
|
|
|
let key = "ro.moz.ril." + this.clientId + ".network_types";
|
|
|
|
let supportedNetworkTypes = libcutils.property_get(key, "").split(",");
|
|
|
|
for (let type of supportedNetworkTypes) {
|
|
|
|
// If the value in system property is not valid, use the default one which
|
|
|
|
// is defined in ril_consts.js.
|
|
|
|
if (RIL.GECKO_SUPPORTED_NETWORK_TYPES.indexOf(type) < 0) {
|
2014-01-23 12:44:20 +04:00
|
|
|
if (DEBUG) this.debug("Unknown network type: " + type);
|
2014-01-08 10:10:58 +04:00
|
|
|
supportedNetworkTypes =
|
|
|
|
RIL.GECKO_SUPPORTED_NETWORK_TYPES_DEFAULT.split(",");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (DEBUG) this.debug("Supported Network Types: " + supportedNetworkTypes);
|
|
|
|
return supportedNetworkTypes;
|
|
|
|
},
|
|
|
|
|
2012-04-20 01:33:25 +04:00
|
|
|
/**
|
|
|
|
* Process a message from the content process.
|
|
|
|
*/
|
2014-01-13 06:44:40 +04:00
|
|
|
receiveMessage: function(msg) {
|
2012-04-20 01:33:25 +04:00
|
|
|
switch (msg.name) {
|
2012-06-13 06:46:41 +04:00
|
|
|
case "RIL:GetRilContext":
|
2012-04-20 01:33:25 +04:00
|
|
|
// This message is sync.
|
2012-06-13 06:46:41 +04:00
|
|
|
return this.rilContext;
|
2014-01-08 14:54:34 +04:00
|
|
|
case "RIL:GetLastKnownNetwork":
|
|
|
|
// This message is sync.
|
|
|
|
return this._lastKnownNetwork;
|
|
|
|
case "RIL:GetLastKnownHomeNetwork":
|
|
|
|
// This message is sync.
|
|
|
|
return this._lastKnownHomeNetwork;
|
2012-06-02 01:10:39 +04:00
|
|
|
case "RIL:GetAvailableNetworks":
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "getAvailableNetworks");
|
2012-06-02 01:10:39 +04:00
|
|
|
break;
|
2012-06-20 02:52:06 +04:00
|
|
|
case "RIL:SelectNetwork":
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "selectNetwork");
|
2012-06-20 02:52:06 +04:00
|
|
|
break;
|
|
|
|
case "RIL:SelectNetworkAuto":
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "selectNetworkAuto");
|
2012-10-09 14:07:11 +04:00
|
|
|
break;
|
2013-12-11 07:15:03 +04:00
|
|
|
case "RIL:SetPreferredNetworkType":
|
|
|
|
this.setPreferredNetworkType(msg.target, msg.json.data);
|
|
|
|
break;
|
|
|
|
case "RIL:GetPreferredNetworkType":
|
|
|
|
this.getPreferredNetworkType(msg.target, msg.json.data);
|
|
|
|
break;
|
2013-04-11 11:12:09 +04:00
|
|
|
case "RIL:GetCardLockState":
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "iccGetCardLockState",
|
|
|
|
"RIL:CardLockResult");
|
2012-04-12 08:01:49 +04:00
|
|
|
break;
|
|
|
|
case "RIL:UnlockCardLock":
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "iccUnlockCardLock",
|
|
|
|
"RIL:CardLockResult");
|
2012-04-12 08:01:49 +04:00
|
|
|
break;
|
|
|
|
case "RIL:SetCardLock":
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "iccSetCardLock",
|
|
|
|
"RIL:CardLockResult");
|
2012-04-12 08:01:49 +04:00
|
|
|
break;
|
Bug 875710: Added getCardLockRetryCount to nsIIccProvider, r=vyang, sr=mounir
This patch adds getCardLockRetryCount to nsIIccProvider and its
implementations. This method allows callers to query the number
of remaining tries for unlocking a SIM-card lock. Supported locks
are 'pin', 'puk', 'pin2', 'puk2', 'nck', 'cck', and 'spck'. The
call returns a DOM request that returns the retry count in its
success handler, or signals an appropriate error.
Reading the retry count is an optional feature and may not be
supported for all lock types. In this case the DOM request receives
and error with the name GECKO_ERROR_NOT_SUPPORTED. For an invalid
lock type, the error name is GECKO_ERROR_GENERIC_FAILURE.
getCardLockRetryCount replaces retryCount in nsIDOMMobileConnection,
which is now deprecated.
--HG--
extra : rebase_source : d1d11612f836652dca85f7c701f09e7af962e3b7
2013-07-09 18:06:05 +04:00
|
|
|
case "RIL:GetCardLockRetryCount":
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "iccGetCardLockRetryCount",
|
|
|
|
"RIL:CardLockRetryCount");
|
Bug 875710: Added getCardLockRetryCount to nsIIccProvider, r=vyang, sr=mounir
This patch adds getCardLockRetryCount to nsIIccProvider and its
implementations. This method allows callers to query the number
of remaining tries for unlocking a SIM-card lock. Supported locks
are 'pin', 'puk', 'pin2', 'puk2', 'nck', 'cck', and 'spck'. The
call returns a DOM request that returns the retry count in its
success handler, or signals an appropriate error.
Reading the retry count is an optional feature and may not be
supported for all lock types. In this case the DOM request receives
and error with the name GECKO_ERROR_NOT_SUPPORTED. For an invalid
lock type, the error name is GECKO_ERROR_GENERIC_FAILURE.
getCardLockRetryCount replaces retryCount in nsIDOMMobileConnection,
which is now deprecated.
--HG--
extra : rebase_source : d1d11612f836652dca85f7c701f09e7af962e3b7
2013-07-09 18:06:05 +04:00
|
|
|
break;
|
2012-10-05 18:08:55 +04:00
|
|
|
case "RIL:SendMMI":
|
2013-08-13 16:14:13 +04:00
|
|
|
this.sendMMI(msg.target, msg.json.data);
|
2012-06-10 01:07:18 +04:00
|
|
|
break;
|
2012-10-05 18:08:55 +04:00
|
|
|
case "RIL:CancelMMI":
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "cancelUSSD");
|
2012-06-10 01:07:18 +04:00
|
|
|
break;
|
2012-04-10 16:04:27 +04:00
|
|
|
case "RIL:SendStkResponse":
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.send("sendStkTerminalResponse", msg.json.data);
|
2012-04-10 16:04:27 +04:00
|
|
|
break;
|
|
|
|
case "RIL:SendStkMenuSelection":
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.send("sendStkMenuSelection", msg.json.data);
|
2012-04-10 16:04:27 +04:00
|
|
|
break;
|
2012-11-28 12:16:20 +04:00
|
|
|
case "RIL:SendStkTimerExpiration":
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.send("sendStkTimerExpiration", msg.json.data);
|
2012-11-28 12:16:20 +04:00
|
|
|
break;
|
2012-09-11 06:34:36 +04:00
|
|
|
case "RIL:SendStkEventDownload":
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.send("sendStkEventDownload", msg.json.data);
|
2012-09-11 06:34:36 +04:00
|
|
|
break;
|
2013-02-25 13:27:26 +04:00
|
|
|
case "RIL:IccOpenChannel":
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "iccOpenChannel");
|
2013-02-25 13:27:26 +04:00
|
|
|
break;
|
|
|
|
case "RIL:IccCloseChannel":
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "iccCloseChannel");
|
2013-02-25 13:27:26 +04:00
|
|
|
break;
|
|
|
|
case "RIL:IccExchangeAPDU":
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "iccExchangeAPDU");
|
2013-02-25 13:27:26 +04:00
|
|
|
break;
|
2013-03-06 06:51:40 +04:00
|
|
|
case "RIL:ReadIccContacts":
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "readICCContacts");
|
2013-03-06 06:51:40 +04:00
|
|
|
break;
|
2013-03-25 07:09:01 +04:00
|
|
|
case "RIL:UpdateIccContact":
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "updateICCContact");
|
2012-10-09 14:07:11 +04:00
|
|
|
break;
|
2014-01-27 22:22:00 +04:00
|
|
|
case "RIL:MatchMvno":
|
|
|
|
this.matchMvno(msg.target, msg.json.data);
|
|
|
|
break;
|
2013-10-30 08:04:21 +04:00
|
|
|
case "RIL:SetCallForwardingOptions":
|
|
|
|
this.setCallForwardingOptions(msg.target, msg.json.data);
|
2012-10-31 17:58:39 +04:00
|
|
|
break;
|
2013-10-30 08:04:21 +04:00
|
|
|
case "RIL:GetCallForwardingOptions":
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "queryCallForwardStatus");
|
2012-10-31 17:58:39 +04:00
|
|
|
break;
|
2013-10-30 08:04:21 +04:00
|
|
|
case "RIL:SetCallBarringOptions":
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "setCallBarring");
|
2013-05-21 09:13:37 +04:00
|
|
|
break;
|
2013-10-30 08:04:21 +04:00
|
|
|
case "RIL:GetCallBarringOptions":
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "queryCallBarringStatus");
|
2013-05-21 09:13:37 +04:00
|
|
|
break;
|
2013-08-27 05:59:17 +04:00
|
|
|
case "RIL:ChangeCallBarringPassword":
|
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "changeCallBarringPassword");
|
|
|
|
break;
|
2013-10-30 08:04:21 +04:00
|
|
|
case "RIL:SetCallWaitingOptions":
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "setCallWaiting");
|
2013-04-18 16:18:50 +04:00
|
|
|
break;
|
2013-10-30 08:04:21 +04:00
|
|
|
case "RIL:GetCallWaitingOptions":
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "queryCallWaiting");
|
2012-12-04 06:40:47 +04:00
|
|
|
break;
|
2013-07-18 01:18:29 +04:00
|
|
|
case "RIL:SetCallingLineIdRestriction":
|
2013-08-13 16:14:13 +04:00
|
|
|
this.setCallingLineIdRestriction(msg.target, msg.json.data);
|
2013-07-18 01:18:29 +04:00
|
|
|
break;
|
|
|
|
case "RIL:GetCallingLineIdRestriction":
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "getCLIR");
|
2013-07-18 01:18:29 +04:00
|
|
|
break;
|
2013-08-14 16:50:36 +04:00
|
|
|
case "RIL:ExitEmergencyCbMode":
|
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "exitEmergencyCbMode");
|
|
|
|
break;
|
2013-11-21 18:09:14 +04:00
|
|
|
case "RIL:SetRadioEnabled":
|
|
|
|
this.setRadioEnabled(msg.target, msg.json.data);
|
|
|
|
break;
|
2012-12-26 14:49:08 +04:00
|
|
|
case "RIL:GetVoicemailInfo":
|
|
|
|
// This message is sync.
|
|
|
|
return this.voicemailInfo;
|
2013-06-10 11:47:03 +04:00
|
|
|
case "RIL:SetRoamingPreference":
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "setRoamingPreference");
|
2013-06-10 11:47:03 +04:00
|
|
|
break;
|
|
|
|
case "RIL:GetRoamingPreference":
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "queryRoamingPreference");
|
2013-06-10 11:47:03 +04:00
|
|
|
break;
|
2013-08-14 12:22:38 +04:00
|
|
|
case "RIL:SetVoicePrivacyMode":
|
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "setVoicePrivacyMode");
|
|
|
|
break;
|
|
|
|
case "RIL:GetVoicePrivacyMode":
|
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "queryVoicePrivacyMode");
|
|
|
|
break;
|
2014-01-08 10:10:58 +04:00
|
|
|
case "RIL:GetSupportedNetworkTypes":
|
|
|
|
// This message is sync.
|
|
|
|
return this.supportedNetworkTypes;
|
2012-04-20 01:33:25 +04:00
|
|
|
}
|
2013-09-14 02:12:30 +04:00
|
|
|
return null;
|
2012-04-20 01:33:25 +04:00
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
handleUnsolicitedWorkerMessage: function(message) {
|
2013-12-03 10:18:32 +04:00
|
|
|
let connHandler = gDataConnectionManager.getConnectionHandler(this.clientId);
|
2012-08-07 01:28:03 +04:00
|
|
|
switch (message.rilMessageType) {
|
2012-11-28 05:28:43 +04:00
|
|
|
case "callRing":
|
2013-09-07 10:19:57 +04:00
|
|
|
gTelephonyProvider.notifyCallRing();
|
2012-11-28 05:28:43 +04:00
|
|
|
break;
|
2012-01-10 02:28:47 +04:00
|
|
|
case "callStateChange":
|
2013-10-31 16:05:52 +04:00
|
|
|
gTelephonyProvider.notifyCallStateChanged(this.clientId, message.call);
|
2012-01-10 02:28:47 +04:00
|
|
|
break;
|
|
|
|
case "callDisconnected":
|
2013-10-31 16:05:52 +04:00
|
|
|
gTelephonyProvider.notifyCallDisconnected(this.clientId, message.call);
|
2012-01-10 02:28:47 +04:00
|
|
|
break;
|
2013-07-06 14:40:58 +04:00
|
|
|
case "conferenceCallStateChanged":
|
2013-09-07 10:19:57 +04:00
|
|
|
gTelephonyProvider.notifyConferenceCallStateChanged(message.state);
|
2013-07-06 14:40:58 +04:00
|
|
|
break;
|
2013-07-30 13:24:43 +04:00
|
|
|
case "cdmaCallWaiting":
|
2013-10-31 16:05:52 +04:00
|
|
|
gTelephonyProvider.notifyCdmaCallWaiting(this.clientId, message.number);
|
2013-07-30 13:24:43 +04:00
|
|
|
break;
|
2013-08-06 00:28:31 +04:00
|
|
|
case "suppSvcNotification":
|
2013-10-31 16:05:52 +04:00
|
|
|
gTelephonyProvider.notifySupplementaryService(this.clientId,
|
|
|
|
message.callIndex,
|
2013-09-07 10:19:57 +04:00
|
|
|
message.notification);
|
2013-08-06 00:28:31 +04:00
|
|
|
break;
|
2013-12-03 10:18:32 +04:00
|
|
|
case "datacallerror":
|
|
|
|
connHandler.handleDataCallError(message);
|
|
|
|
break;
|
|
|
|
case "datacallstatechange":
|
2014-03-29 11:18:16 +04:00
|
|
|
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
|
|
|
|
});
|
2013-12-03 10:18:32 +04:00
|
|
|
}
|
2014-03-29 11:18:16 +04:00
|
|
|
message.addresses = addresses;
|
2013-12-03 10:18:32 +04:00
|
|
|
connHandler.handleDataCallState(message);
|
|
|
|
break;
|
2013-08-14 16:50:36 +04:00
|
|
|
case "emergencyCbModeChange":
|
|
|
|
this.handleEmergencyCbModeChange(message);
|
|
|
|
break;
|
2012-06-20 02:52:06 +04:00
|
|
|
case "networkinfochanged":
|
|
|
|
this.updateNetworkInfo(message);
|
|
|
|
break;
|
|
|
|
case "networkselectionmodechange":
|
|
|
|
this.updateNetworkSelectionMode(message);
|
|
|
|
break;
|
2012-03-20 02:49:27 +04:00
|
|
|
case "voiceregistrationstatechange":
|
2012-04-20 01:33:25 +04:00
|
|
|
this.updateVoiceConnection(message);
|
2012-02-10 23:27:23 +04:00
|
|
|
break;
|
2012-03-20 02:49:27 +04:00
|
|
|
case "dataregistrationstatechange":
|
2012-04-20 01:33:25 +04:00
|
|
|
this.updateDataConnection(message);
|
2012-02-10 23:27:23 +04:00
|
|
|
break;
|
2011-12-05 11:58:27 +04:00
|
|
|
case "signalstrengthchange":
|
2012-04-20 01:33:25 +04:00
|
|
|
this.handleSignalStrengthChange(message);
|
2011-12-05 11:58:27 +04:00
|
|
|
break;
|
|
|
|
case "operatorchange":
|
2012-04-20 01:33:25 +04:00
|
|
|
this.handleOperatorChange(message);
|
2011-12-05 11:58:27 +04:00
|
|
|
break;
|
2013-08-27 16:25:54 +04:00
|
|
|
case "otastatuschange":
|
|
|
|
this.handleOtaStatus(message);
|
|
|
|
break;
|
2011-12-07 10:57:19 +04:00
|
|
|
case "radiostatechange":
|
2012-05-24 09:12:07 +04:00
|
|
|
this.handleRadioStateChange(message);
|
2011-12-05 11:58:27 +04:00
|
|
|
break;
|
|
|
|
case "cardstatechange":
|
2012-06-13 06:46:41 +04:00
|
|
|
this.rilContext.cardState = message.cardState;
|
2014-02-14 13:42:32 +04:00
|
|
|
gRadioEnabledController.receiveCardState(this.clientId);
|
2013-05-22 13:32:18 +04:00
|
|
|
gMessageManager.sendIccMessage("RIL:CardStateChanged",
|
|
|
|
this.clientId, message);
|
2011-12-05 11:58:27 +04:00
|
|
|
break;
|
2011-12-24 09:02:52 +04:00
|
|
|
case "sms-received":
|
2014-03-12 20:27:00 +04:00
|
|
|
this.handleSmsMultipart(message);
|
|
|
|
break;
|
2012-12-04 06:40:47 +04:00
|
|
|
case "cellbroadcast-received":
|
|
|
|
message.timestamp = Date.now();
|
2013-07-02 13:36:40 +04:00
|
|
|
gMessageManager.sendCellBroadcastMessage("RIL:CellBroadcastReceived",
|
|
|
|
this.clientId, message);
|
2012-12-04 06:40:47 +04:00
|
|
|
break;
|
2012-03-09 08:16:06 +04:00
|
|
|
case "nitzTime":
|
2012-09-28 10:02:57 +04:00
|
|
|
this.handleNitzTime(message);
|
2012-03-09 08:16:06 +04:00
|
|
|
break;
|
2012-04-18 14:07:29 +04:00
|
|
|
case "iccinfochange":
|
2013-03-25 07:09:01 +04:00
|
|
|
this.handleIccInfoChange(message);
|
2012-03-17 18:23:17 +04:00
|
|
|
break;
|
2013-01-11 13:20:12 +04:00
|
|
|
case "iccimsi":
|
|
|
|
this.rilContext.imsi = message.imsi;
|
|
|
|
break;
|
2012-07-21 04:19:38 +04:00
|
|
|
case "iccmbdn":
|
2013-03-25 07:09:01 +04:00
|
|
|
this.handleIccMbdn(message);
|
2012-07-21 04:19:38 +04:00
|
|
|
break;
|
2013-12-06 13:35:13 +04:00
|
|
|
case "iccmwis":
|
|
|
|
gMessageManager.sendVoicemailMessage("RIL:VoicemailNotification",
|
|
|
|
this.clientId, message.mwi);
|
|
|
|
break;
|
2014-05-08 07:47:24 +04:00
|
|
|
case "ussdreceived":
|
2012-06-10 01:07:18 +04:00
|
|
|
this.handleUSSDReceived(message);
|
|
|
|
break;
|
2012-04-10 16:04:27 +04:00
|
|
|
case "stkcommand":
|
|
|
|
this.handleStkProactiveCommand(message);
|
|
|
|
break;
|
|
|
|
case "stksessionend":
|
2013-07-02 13:36:40 +04:00
|
|
|
gMessageManager.sendIccMessage("RIL:StkSessionEnd", this.clientId, null);
|
2012-04-10 16:04:27 +04:00
|
|
|
break;
|
2013-08-14 16:50:36 +04:00
|
|
|
case "exitEmergencyCbMode":
|
|
|
|
this.handleExitEmergencyCbMode(message);
|
|
|
|
break;
|
2013-09-10 20:48:19 +04:00
|
|
|
case "cdma-info-rec-received":
|
|
|
|
if (DEBUG) this.debug("cdma-info-rec-received: " + JSON.stringify(message));
|
|
|
|
gSystemMessenger.broadcastMessage("cdma-info-rec-received", message);
|
|
|
|
break;
|
2012-01-10 02:28:47 +04:00
|
|
|
default:
|
2012-08-07 01:28:03 +04:00
|
|
|
throw new Error("Don't know about this message type: " +
|
|
|
|
message.rilMessageType);
|
2011-12-05 11:58:27 +04:00
|
|
|
}
|
2012-01-10 02:28:47 +04:00
|
|
|
},
|
|
|
|
|
2013-10-15 06:42:49 +04:00
|
|
|
/**
|
|
|
|
* Get phone number from iccInfo.
|
|
|
|
*
|
|
|
|
* If the icc card is gsm card, the phone number is in msisdn.
|
|
|
|
* @see nsIDOMMozGsmIccInfo
|
|
|
|
*
|
|
|
|
* Otherwise, the phone number is in mdn.
|
|
|
|
* @see nsIDOMMozCdmaIccInfo
|
|
|
|
*/
|
2014-01-13 06:44:40 +04:00
|
|
|
getPhoneNumber: function() {
|
2013-09-07 15:09:54 +04:00
|
|
|
let iccInfo = this.rilContext.iccInfo;
|
2013-10-15 06:42:49 +04:00
|
|
|
|
|
|
|
if (!iccInfo) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
// After moving SMS code out of RadioInterfaceLayer, we could use
|
|
|
|
// |iccInfo instanceof Ci.nsIDOMMozGsmIccInfo| here.
|
|
|
|
// TODO: Bug 873351 - B2G SMS: move SMS code out of RadioInterfaceLayer to
|
|
|
|
// SmsService
|
|
|
|
let number = (iccInfo instanceof GsmIccInfo) ? iccInfo.msisdn : iccInfo.mdn;
|
2013-09-07 15:09:54 +04:00
|
|
|
|
|
|
|
// Workaround an xpconnect issue with undefined string objects.
|
|
|
|
// See bug 808220
|
|
|
|
if (number === undefined || number === "undefined") {
|
|
|
|
return null;
|
|
|
|
}
|
2013-11-02 14:17:25 +04:00
|
|
|
|
2013-09-07 15:09:54 +04:00
|
|
|
return number;
|
|
|
|
},
|
|
|
|
|
2013-11-02 14:17:25 +04:00
|
|
|
/**
|
|
|
|
* A utility function to get the ICC ID of the SIM card (if installed).
|
|
|
|
*/
|
2014-01-13 06:44:40 +04:00
|
|
|
getIccId: function() {
|
2013-11-02 14:17:25 +04:00
|
|
|
let iccInfo = this.rilContext.iccInfo;
|
|
|
|
|
2014-03-05 07:10:46 +04:00
|
|
|
if (!iccInfo) {
|
2013-11-02 14:17:25 +04:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
let iccId = iccInfo.iccid;
|
|
|
|
|
|
|
|
// Workaround an xpconnect issue with undefined string objects.
|
|
|
|
// See bug 808220
|
|
|
|
if (iccId === undefined || iccId === "undefined") {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return iccId;
|
|
|
|
},
|
|
|
|
|
2014-01-27 22:22:00 +04:00
|
|
|
// 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.
|
|
|
|
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;
|
|
|
|
},
|
|
|
|
|
|
|
|
matchMvno: function(target, message) {
|
|
|
|
if (DEBUG) this.debug("matchMvno: " + JSON.stringify(message));
|
|
|
|
|
|
|
|
if (!message || !message.mvnoType || !message.mvnoData) {
|
|
|
|
message.errorMsg = RIL.GECKO_ERROR_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
// Currently we only support imsi matching.
|
|
|
|
if (message.mvnoType != "imsi") {
|
|
|
|
message.errorMsg = RIL.GECKO_ERROR_MODE_NOT_SUPPORTED;
|
|
|
|
}
|
|
|
|
// Fire error if mvnoType is imsi but imsi is not available.
|
|
|
|
if (!this.rilContext.imsi) {
|
|
|
|
message.errorMsg = RIL.GECKO_ERROR_GENERIC_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!message.errorMsg) {
|
|
|
|
message.result = this.isImsiMatches(message.mvnoData);
|
|
|
|
}
|
|
|
|
|
|
|
|
target.sendAsyncMessage("RIL:MatchMvno", {
|
|
|
|
clientId: this.clientId,
|
|
|
|
data: message
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
updateNetworkInfo: function(message) {
|
2012-06-20 02:52:06 +04:00
|
|
|
let voiceMessage = message[RIL.NETWORK_INFO_VOICE_REGISTRATION_STATE];
|
|
|
|
let dataMessage = message[RIL.NETWORK_INFO_DATA_REGISTRATION_STATE];
|
|
|
|
let operatorMessage = message[RIL.NETWORK_INFO_OPERATOR];
|
|
|
|
let selectionMessage = message[RIL.NETWORK_INFO_NETWORK_SELECTION_MODE];
|
2013-08-09 08:27:19 +04:00
|
|
|
let signalMessage = message[RIL.NETWORK_INFO_SIGNAL];
|
2012-06-20 02:52:06 +04:00
|
|
|
|
|
|
|
// Batch the *InfoChanged messages together
|
|
|
|
if (voiceMessage) {
|
2013-08-08 13:29:42 +04:00
|
|
|
this.updateVoiceConnection(voiceMessage, true);
|
2012-06-20 02:52:06 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (dataMessage) {
|
2013-08-08 13:29:42 +04:00
|
|
|
this.updateDataConnection(dataMessage, true);
|
2012-06-20 02:52:06 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (operatorMessage) {
|
2013-08-08 13:29:42 +04:00
|
|
|
this.handleOperatorChange(operatorMessage, true);
|
2012-06-20 02:52:06 +04:00
|
|
|
}
|
|
|
|
|
2013-08-09 08:27:19 +04:00
|
|
|
if (signalMessage) {
|
|
|
|
this.handleSignalStrengthChange(signalMessage, true);
|
|
|
|
}
|
|
|
|
|
2013-01-28 07:41:34 +04:00
|
|
|
let voice = this.rilContext.voice;
|
|
|
|
let data = this.rilContext.data;
|
|
|
|
|
2012-09-04 01:50:55 +04:00
|
|
|
this.checkRoamingBetweenOperators(voice);
|
|
|
|
this.checkRoamingBetweenOperators(data);
|
|
|
|
|
2013-08-09 08:27:19 +04:00
|
|
|
if (voiceMessage || operatorMessage || signalMessage) {
|
2013-07-02 13:36:40 +04:00
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:VoiceInfoChanged",
|
|
|
|
this.clientId, voice);
|
2012-06-20 02:52:06 +04:00
|
|
|
}
|
2013-08-09 08:27:19 +04:00
|
|
|
if (dataMessage || operatorMessage || signalMessage) {
|
2013-07-02 13:36:40 +04:00
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged",
|
|
|
|
this.clientId, data);
|
2012-06-20 02:52:06 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (selectionMessage) {
|
|
|
|
this.updateNetworkSelectionMode(selectionMessage);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2012-09-04 01:50:55 +04:00
|
|
|
/**
|
|
|
|
* Fix the roaming. RIL can report roaming in some case it is not
|
|
|
|
* really the case. See bug 787967
|
|
|
|
*
|
|
|
|
* @param registration The voiceMessage or dataMessage from which the
|
|
|
|
* roaming state will be changed (maybe, if needed).
|
|
|
|
*/
|
2014-01-13 06:44:40 +04:00
|
|
|
checkRoamingBetweenOperators: function(registration) {
|
2013-01-10 20:18:54 +04:00
|
|
|
let iccInfo = this.rilContext.iccInfo;
|
2014-01-23 13:28:24 +04:00
|
|
|
let operator = registration.network;
|
|
|
|
let state = registration.state;
|
|
|
|
|
|
|
|
if (!iccInfo || !operator ||
|
|
|
|
state != RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED) {
|
2012-09-04 01:50:55 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-01-10 20:18:54 +04:00
|
|
|
let spn = iccInfo.spn && iccInfo.spn.toLowerCase();
|
2012-10-05 02:30:06 +04:00
|
|
|
let longName = operator.longName && operator.longName.toLowerCase();
|
|
|
|
let shortName = operator.shortName && operator.shortName.toLowerCase();
|
2012-09-04 01:50:55 +04:00
|
|
|
|
|
|
|
let equalsLongName = longName && (spn == longName);
|
|
|
|
let equalsShortName = shortName && (spn == shortName);
|
2013-01-10 20:18:54 +04:00
|
|
|
let equalsMcc = iccInfo.mcc == operator.mcc;
|
2012-09-04 01:50:55 +04:00
|
|
|
|
|
|
|
registration.roaming = registration.roaming &&
|
|
|
|
!(equalsMcc && (equalsLongName || equalsShortName));
|
|
|
|
},
|
|
|
|
|
2012-06-20 02:52:06 +04:00
|
|
|
/**
|
2013-08-08 13:29:42 +04:00
|
|
|
* Handle data connection changes.
|
2012-06-20 02:52:06 +04:00
|
|
|
*
|
2013-08-08 13:29:42 +04:00
|
|
|
* @param newInfo The new voice connection information.
|
|
|
|
* @param batch When batch is true, the RIL:VoiceInfoChanged message will
|
|
|
|
* not be sent.
|
2012-06-20 02:52:06 +04:00
|
|
|
*/
|
2014-01-13 06:44:40 +04:00
|
|
|
updateVoiceConnection: function(newInfo, batch) {
|
2012-06-13 06:46:41 +04:00
|
|
|
let voiceInfo = this.rilContext.voice;
|
2012-08-07 23:11:48 +04:00
|
|
|
voiceInfo.state = newInfo.state;
|
|
|
|
voiceInfo.connected = newInfo.connected;
|
|
|
|
voiceInfo.roaming = newInfo.roaming;
|
|
|
|
voiceInfo.emergencyCallsOnly = newInfo.emergencyCallsOnly;
|
2013-06-07 12:50:10 +04:00
|
|
|
voiceInfo.type = newInfo.type;
|
2012-08-07 23:11:48 +04:00
|
|
|
|
|
|
|
// Make sure we also reset the operator and signal strength information
|
|
|
|
// if we drop off the network.
|
2013-08-08 13:29:42 +04:00
|
|
|
if (newInfo.state !== RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED) {
|
2013-07-04 07:48:48 +04:00
|
|
|
voiceInfo.cell = null;
|
2012-06-13 01:05:50 +04:00
|
|
|
voiceInfo.network = null;
|
2012-04-20 01:33:25 +04:00
|
|
|
voiceInfo.signalStrength = null;
|
|
|
|
voiceInfo.relSignalStrength = null;
|
2012-08-16 05:36:56 +04:00
|
|
|
} else {
|
2013-07-04 07:48:48 +04:00
|
|
|
voiceInfo.cell = newInfo.cell;
|
2013-08-08 13:29:42 +04:00
|
|
|
voiceInfo.network = this.operatorInfo;
|
2012-08-16 05:36:56 +04:00
|
|
|
}
|
|
|
|
|
2013-08-08 13:29:42 +04:00
|
|
|
if (!batch) {
|
2013-07-02 13:36:40 +04:00
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:VoiceInfoChanged",
|
|
|
|
this.clientId, voiceInfo);
|
2012-06-20 02:52:06 +04:00
|
|
|
}
|
2012-04-20 01:33:25 +04:00
|
|
|
},
|
|
|
|
|
2013-08-08 13:29:42 +04:00
|
|
|
/**
|
|
|
|
* Handle the data connection's state has changed.
|
|
|
|
*
|
|
|
|
* @param newInfo The new data connection information.
|
|
|
|
* @param batch When batch is true, the RIL:DataInfoChanged message will
|
|
|
|
* not be sent.
|
|
|
|
*/
|
2014-01-13 06:44:40 +04:00
|
|
|
updateDataConnection: function(newInfo, batch) {
|
2012-08-07 23:11:48 +04:00
|
|
|
let dataInfo = this.rilContext.data;
|
|
|
|
dataInfo.state = newInfo.state;
|
|
|
|
dataInfo.roaming = newInfo.roaming;
|
|
|
|
dataInfo.emergencyCallsOnly = newInfo.emergencyCallsOnly;
|
|
|
|
dataInfo.type = newInfo.type;
|
|
|
|
// For the data connection, the `connected` flag indicates whether
|
|
|
|
// there's an active data call.
|
2013-07-12 08:44:22 +04:00
|
|
|
dataInfo.connected = false;
|
2014-04-11 12:53:57 +04:00
|
|
|
if (gNetworkManager.active &&
|
|
|
|
gNetworkManager.active.type ===
|
|
|
|
Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE &&
|
|
|
|
gNetworkManager.active.serviceId === this.clientId) {
|
|
|
|
dataInfo.connected = true;
|
2013-07-12 08:44:22 +04:00
|
|
|
}
|
2012-08-07 23:11:48 +04:00
|
|
|
|
|
|
|
// Make sure we also reset the operator and signal strength information
|
|
|
|
// if we drop off the network.
|
2013-08-08 13:29:42 +04:00
|
|
|
if (newInfo.state !== RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED) {
|
2013-07-04 07:48:48 +04:00
|
|
|
dataInfo.cell = null;
|
2012-08-07 23:11:48 +04:00
|
|
|
dataInfo.network = null;
|
|
|
|
dataInfo.signalStrength = null;
|
|
|
|
dataInfo.relSignalStrength = null;
|
2012-08-16 05:36:56 +04:00
|
|
|
} else {
|
2013-07-04 07:48:48 +04:00
|
|
|
dataInfo.cell = newInfo.cell;
|
2013-08-08 13:29:42 +04:00
|
|
|
dataInfo.network = this.operatorInfo;
|
2012-08-16 05:36:56 +04:00
|
|
|
}
|
|
|
|
|
2013-08-08 13:29:42 +04:00
|
|
|
if (!batch) {
|
2013-07-02 13:36:40 +04:00
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged",
|
|
|
|
this.clientId, dataInfo);
|
2012-06-22 04:22:47 +04:00
|
|
|
}
|
2014-04-11 12:53:57 +04:00
|
|
|
|
|
|
|
let connHandler = gDataConnectionManager.getConnectionHandler(this.clientId);
|
2013-12-03 10:18:32 +04:00
|
|
|
connHandler.updateRILNetworkInterface();
|
2012-09-25 23:22:38 +04:00
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
getPreferredNetworkType: function(target, message) {
|
2013-12-11 07:15:03 +04:00
|
|
|
this.workerMessenger.send("getPreferredNetworkType", message, (function(response) {
|
|
|
|
target.sendAsyncMessage("RIL:GetPreferredNetworkType", {
|
|
|
|
clientId: this.clientId,
|
|
|
|
data: response
|
|
|
|
});
|
|
|
|
return false;
|
|
|
|
}).bind(this));
|
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
setPreferredNetworkType: function(target, message) {
|
2013-12-11 07:15:03 +04:00
|
|
|
this.workerMessenger.send("setPreferredNetworkType", message, (function(response) {
|
|
|
|
target.sendAsyncMessage("RIL:SetPreferredNetworkType", {
|
|
|
|
clientId: this.clientId,
|
|
|
|
data: response
|
|
|
|
});
|
|
|
|
return false;
|
|
|
|
}).bind(this));
|
|
|
|
},
|
|
|
|
|
2014-04-03 12:33:56 +04:00
|
|
|
setCellBroadcastSearchList: function(newSearchList) {
|
|
|
|
if ((newSearchList == this._cellBroadcastSearchList) ||
|
|
|
|
(newSearchList && this._cellBroadcastSearchList &&
|
|
|
|
newSearchList.gsm == this._cellBroadcastSearchList.gsm &&
|
|
|
|
newSearchList.cdma == this._cellBroadcastSearchList.cdma)) {
|
2012-12-04 06:41:39 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.send("setCellBroadcastSearchList",
|
2014-04-03 12:33:56 +04:00
|
|
|
{ searchList: newSearchList },
|
2013-08-13 16:14:13 +04:00
|
|
|
(function callback(response) {
|
|
|
|
if (!response.success) {
|
|
|
|
let lock = gSettingsService.createLock();
|
2013-10-24 12:14:59 +04:00
|
|
|
lock.set(kSettingsCellBroadcastSearchList,
|
2014-04-03 12:33:56 +04:00
|
|
|
this._cellBroadcastSearchList, null);
|
2013-08-13 16:14:13 +04:00
|
|
|
} else {
|
2014-04-03 12:33:56 +04:00
|
|
|
this._cellBroadcastSearchList = response.searchList;
|
2013-08-13 16:14:13 +04:00
|
|
|
}
|
2012-12-04 06:41:39 +04:00
|
|
|
|
2013-08-13 16:14:13 +04:00
|
|
|
return false;
|
|
|
|
}).bind(this));
|
2012-12-04 06:41:39 +04:00
|
|
|
},
|
|
|
|
|
2013-08-09 08:27:19 +04:00
|
|
|
/**
|
|
|
|
* Handle signal strength changes.
|
|
|
|
*
|
|
|
|
* @param message The new signal strength.
|
|
|
|
* @param batch When batch is true, the RIL:VoiceInfoChanged and
|
|
|
|
* RIL:DataInfoChanged message will not be sent.
|
|
|
|
*/
|
2014-01-13 06:44:40 +04:00
|
|
|
handleSignalStrengthChange: function(message, batch) {
|
2012-08-07 23:11:48 +04:00
|
|
|
let voiceInfo = this.rilContext.voice;
|
2013-08-09 08:27:19 +04:00
|
|
|
// If the voice is not registered, need not to update signal information.
|
|
|
|
if (voiceInfo.state === RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED &&
|
|
|
|
this.isInfoChanged(message.voice, voiceInfo)) {
|
|
|
|
this.updateInfo(message.voice, voiceInfo);
|
|
|
|
if (!batch) {
|
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:VoiceInfoChanged",
|
|
|
|
this.clientId, voiceInfo);
|
|
|
|
}
|
2012-08-07 23:11:48 +04:00
|
|
|
}
|
2012-04-20 01:33:25 +04:00
|
|
|
|
2012-08-07 23:11:48 +04:00
|
|
|
let dataInfo = this.rilContext.data;
|
2013-08-09 08:27:19 +04:00
|
|
|
// If the data is not registered, need not to update signal information.
|
|
|
|
if (dataInfo.state === RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED &&
|
|
|
|
this.isInfoChanged(message.data, dataInfo)) {
|
|
|
|
this.updateInfo(message.data, dataInfo);
|
|
|
|
if (!batch) {
|
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged",
|
|
|
|
this.clientId, dataInfo);
|
|
|
|
}
|
2012-08-07 23:11:48 +04:00
|
|
|
}
|
2012-04-20 01:33:25 +04:00
|
|
|
},
|
|
|
|
|
2013-08-08 13:29:42 +04:00
|
|
|
/**
|
|
|
|
* Handle operator information changes.
|
|
|
|
*
|
|
|
|
* @param message The new operator information.
|
|
|
|
* @param batch When batch is true, the RIL:VoiceInfoChanged and
|
|
|
|
* RIL:DataInfoChanged message will not be sent.
|
|
|
|
*/
|
2014-01-13 06:44:40 +04:00
|
|
|
handleOperatorChange: function(message, batch) {
|
2013-08-08 13:29:42 +04:00
|
|
|
let operatorInfo = this.operatorInfo;
|
2012-06-13 06:46:41 +04:00
|
|
|
let voice = this.rilContext.voice;
|
|
|
|
let data = this.rilContext.data;
|
2012-06-13 01:05:50 +04:00
|
|
|
|
2013-08-09 08:27:19 +04:00
|
|
|
if (this.isInfoChanged(message, operatorInfo)) {
|
2013-08-08 13:29:42 +04:00
|
|
|
this.updateInfo(message, operatorInfo);
|
|
|
|
|
2013-05-03 05:37:51 +04:00
|
|
|
// Update lastKnownNetwork
|
|
|
|
if (message.mcc && message.mnc) {
|
2014-01-08 14:54:34 +04:00
|
|
|
this._lastKnownNetwork = message.mcc + "-" + message.mnc;
|
2013-05-03 05:37:51 +04:00
|
|
|
}
|
|
|
|
|
2013-08-08 13:29:42 +04:00
|
|
|
// If the voice is unregistered, no need to send RIL:VoiceInfoChanged.
|
|
|
|
if (voice.network && !batch) {
|
2013-07-02 13:36:40 +04:00
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:VoiceInfoChanged",
|
|
|
|
this.clientId, voice);
|
2013-12-03 10:18:32 +04:00
|
|
|
}
|
2012-09-26 17:05:28 +04:00
|
|
|
|
2013-12-03 10:18:32 +04:00
|
|
|
// If the data is unregistered, no need to send RIL:DataInfoChanged.
|
|
|
|
if (data.network && !batch) {
|
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged",
|
|
|
|
this.clientId, data);
|
2013-07-02 13:36:58 +04:00
|
|
|
}
|
2013-01-23 08:05:34 +04:00
|
|
|
}
|
2013-12-03 10:18:32 +04:00
|
|
|
},
|
2013-01-08 20:21:14 +04:00
|
|
|
|
2013-12-03 10:18:32 +04:00
|
|
|
handleOtaStatus: function(message) {
|
|
|
|
if (message.status < 0 ||
|
|
|
|
RIL.CDMA_OTA_PROVISION_STATUS_TO_GECKO.length <= message.status) {
|
2013-01-08 20:21:14 +04:00
|
|
|
return;
|
|
|
|
}
|
2013-07-12 08:44:22 +04:00
|
|
|
|
2013-12-03 10:18:32 +04:00
|
|
|
let status = RIL.CDMA_OTA_PROVISION_STATUS_TO_GECKO[message.status];
|
2013-07-12 08:44:22 +04:00
|
|
|
|
2013-12-03 10:18:32 +04:00
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:OtaStatusChanged",
|
|
|
|
this.clientId, status);
|
|
|
|
},
|
|
|
|
|
|
|
|
_convertRadioState: function(state) {
|
|
|
|
switch (state) {
|
|
|
|
case RIL.GECKO_RADIOSTATE_OFF:
|
|
|
|
return RIL.GECKO_DETAILED_RADIOSTATE_DISABLED;
|
|
|
|
case RIL.GECKO_RADIOSTATE_READY:
|
|
|
|
return RIL.GECKO_DETAILED_RADIOSTATE_ENABLED;
|
|
|
|
default:
|
|
|
|
return RIL.GECKO_DETAILED_RADIOSTATE_UNKNOWN;
|
2013-01-23 08:05:34 +04:00
|
|
|
}
|
2013-12-03 10:18:32 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
handleRadioStateChange: function(message) {
|
|
|
|
let newState = message.radioState;
|
|
|
|
if (this.rilContext.radioState == newState) {
|
2014-01-29 17:20:10 +04:00
|
|
|
return;
|
|
|
|
}
|
2013-12-03 10:18:32 +04:00
|
|
|
this.rilContext.radioState = newState;
|
|
|
|
this.handleDetailedRadioStateChanged(this._convertRadioState(newState));
|
2013-11-26 22:58:28 +04:00
|
|
|
|
2013-12-03 10:18:32 +04:00
|
|
|
//TODO Should we notify this change as a card state change?
|
|
|
|
},
|
|
|
|
|
|
|
|
handleDetailedRadioStateChanged: function(state) {
|
|
|
|
if (this.rilContext.detailedRadioState == state) {
|
2012-10-05 05:19:21 +04:00
|
|
|
return;
|
|
|
|
}
|
2013-12-03 10:18:32 +04:00
|
|
|
this.rilContext.detailedRadioState = state;
|
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:RadioStateChanged",
|
|
|
|
this.clientId, state);
|
|
|
|
},
|
2012-08-30 23:41:46 +04:00
|
|
|
|
2013-12-03 10:18:32 +04:00
|
|
|
setDataRegistration: function(attach) {
|
|
|
|
this.workerMessenger.send("setDataRegistration", {attach: attach});
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* TODO: Bug 911713 - B2G NetworkManager: Move policy control logic to
|
|
|
|
* NetworkManager
|
|
|
|
*/
|
|
|
|
updateRILNetworkInterface: function() {
|
|
|
|
let connHandler = gDataConnectionManager.getConnectionHandler(this.clientId);
|
|
|
|
connHandler.updateRILNetworkInterface();
|
2012-08-01 18:54:04 +04:00
|
|
|
},
|
|
|
|
|
2012-06-20 02:52:06 +04:00
|
|
|
/**
|
|
|
|
* Update network selection mode
|
|
|
|
*/
|
2014-01-13 06:44:40 +04:00
|
|
|
updateNetworkSelectionMode: function(message) {
|
2013-07-02 13:36:58 +04:00
|
|
|
if (DEBUG) this.debug("updateNetworkSelectionMode: " + JSON.stringify(message));
|
2013-03-29 06:56:07 +04:00
|
|
|
this.rilContext.networkSelectionMode = message.mode;
|
2013-07-02 13:36:40 +04:00
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:NetworkSelectionModeChanged",
|
|
|
|
this.clientId, message);
|
2012-06-20 02:52:06 +04:00
|
|
|
},
|
|
|
|
|
2013-08-14 16:50:36 +04:00
|
|
|
/**
|
|
|
|
* Handle emergency callback mode change.
|
|
|
|
*/
|
2014-01-13 06:44:40 +04:00
|
|
|
handleEmergencyCbModeChange: function(message) {
|
2013-08-14 16:50:36 +04:00
|
|
|
if (DEBUG) this.debug("handleEmergencyCbModeChange: " + JSON.stringify(message));
|
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:EmergencyCbModeChanged",
|
|
|
|
this.clientId, message);
|
|
|
|
},
|
|
|
|
|
2013-09-07 15:09:54 +04:00
|
|
|
/**
|
|
|
|
* Handle WDP port push PDU. Constructor WDP bearer information and deliver
|
|
|
|
* to WapPushManager.
|
|
|
|
*
|
|
|
|
* @param message
|
|
|
|
* A SMS message.
|
|
|
|
*/
|
2014-01-13 06:44:40 +04:00
|
|
|
handleSmsWdpPortPush: function(message) {
|
2013-09-07 15:09:54 +04:00
|
|
|
if (message.encoding != RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("Got port addressed SMS but not encoded in 8-bit alphabet." +
|
|
|
|
" Drop!");
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let options = {
|
|
|
|
bearer: WAP.WDP_BEARER_GSM_SMS_GSM_MSISDN,
|
|
|
|
sourceAddress: message.sender,
|
2014-03-12 20:27:00 +04:00
|
|
|
sourcePort: message.originatorPort,
|
2013-09-07 15:09:54 +04:00
|
|
|
destinationAddress: this.rilContext.iccInfo.msisdn,
|
2014-03-12 20:27:00 +04:00
|
|
|
destinationPort: message.destinationPort,
|
2013-11-02 14:17:35 +04:00
|
|
|
serviceId: this.clientId
|
2013-09-07 15:09:54 +04:00
|
|
|
};
|
|
|
|
WAP.WapPushManager.receiveWdpPDU(message.fullData, message.fullData.length,
|
|
|
|
0, options);
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A helper to broadcast the system message to launch registered apps
|
|
|
|
* like Costcontrol, Notification and Message app... etc.
|
|
|
|
*
|
|
|
|
* @param aName
|
|
|
|
* The system message name.
|
|
|
|
* @param aDomMessage
|
|
|
|
* The nsIDOMMozSmsMessage object.
|
|
|
|
*/
|
2014-01-13 06:44:40 +04:00
|
|
|
broadcastSmsSystemMessage: function(aName, aDomMessage) {
|
2013-09-07 15:09:54 +04:00
|
|
|
if (DEBUG) this.debug("Broadcasting the SMS system message: " + aName);
|
|
|
|
|
|
|
|
// Sadly we cannot directly broadcast the aDomMessage object
|
|
|
|
// because the system message mechamism will rewrap the object
|
|
|
|
// based on the content window, which needs to know the properties.
|
|
|
|
gSystemMessenger.broadcastMessage(aName, {
|
2014-02-24 14:34:06 +04:00
|
|
|
iccId: aDomMessage.iccId,
|
2013-11-01 16:00:55 +04:00
|
|
|
type: aDomMessage.type,
|
|
|
|
id: aDomMessage.id,
|
|
|
|
threadId: aDomMessage.threadId,
|
|
|
|
delivery: aDomMessage.delivery,
|
|
|
|
deliveryStatus: aDomMessage.deliveryStatus,
|
|
|
|
sender: aDomMessage.sender,
|
|
|
|
receiver: aDomMessage.receiver,
|
|
|
|
body: aDomMessage.body,
|
|
|
|
messageClass: aDomMessage.messageClass,
|
|
|
|
timestamp: aDomMessage.timestamp,
|
2013-09-23 06:31:32 +04:00
|
|
|
sentTimestamp: aDomMessage.sentTimestamp,
|
2013-11-01 16:00:55 +04:00
|
|
|
deliveryTimestamp: aDomMessage.deliveryTimestamp,
|
|
|
|
read: aDomMessage.read
|
2013-09-07 15:09:54 +04:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2013-10-28 10:07:28 +04:00
|
|
|
// The following attributes/functions are used for acquiring/releasing the
|
|
|
|
// CPU wake lock when the RIL handles the received SMS. Note that we need
|
|
|
|
// a timer to bound the lock's life cycle to avoid exhausting the battery.
|
2013-09-10 17:51:47 +04:00
|
|
|
_smsHandledWakeLock: null,
|
|
|
|
_smsHandledWakeLockTimer: null,
|
2013-10-28 10:07:28 +04:00
|
|
|
|
2014-03-12 20:27:00 +04:00
|
|
|
_acquireSmsHandledWakeLock: function() {
|
2013-09-10 17:51:47 +04:00
|
|
|
if (!this._smsHandledWakeLock) {
|
|
|
|
if (DEBUG) this.debug("Acquiring a CPU wake lock for handling SMS.");
|
|
|
|
this._smsHandledWakeLock = gPowerManagerService.newWakeLock("cpu");
|
|
|
|
}
|
|
|
|
if (!this._smsHandledWakeLockTimer) {
|
|
|
|
if (DEBUG) this.debug("Creating a timer for releasing the CPU wake lock.");
|
|
|
|
this._smsHandledWakeLockTimer =
|
|
|
|
Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
|
|
|
}
|
|
|
|
if (DEBUG) this.debug("Setting the timer for releasing the CPU wake lock.");
|
|
|
|
this._smsHandledWakeLockTimer
|
2013-10-28 10:07:28 +04:00
|
|
|
.initWithCallback(this._releaseSmsHandledWakeLock.bind(this),
|
2013-09-10 17:51:47 +04:00
|
|
|
SMS_HANDLED_WAKELOCK_TIMEOUT,
|
|
|
|
Ci.nsITimer.TYPE_ONE_SHOT);
|
2014-03-12 20:27:00 +04:00
|
|
|
},
|
2013-09-10 17:51:47 +04:00
|
|
|
|
2014-03-12 20:27:00 +04:00
|
|
|
_releaseSmsHandledWakeLock: function() {
|
|
|
|
if (DEBUG) this.debug("Releasing the CPU wake lock for handling SMS.");
|
|
|
|
if (this._smsHandledWakeLockTimer) {
|
|
|
|
this._smsHandledWakeLockTimer.cancel();
|
|
|
|
}
|
|
|
|
if (this._smsHandledWakeLock) {
|
|
|
|
this._smsHandledWakeLock.unlock();
|
|
|
|
this._smsHandledWakeLock = null;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Hash map for received multipart sms fragments. Messages are hashed with
|
|
|
|
* its sender address and concatenation reference number. Three additional
|
|
|
|
* attributes `segmentMaxSeq`, `receivedSegments`, `segments` are inserted.
|
|
|
|
*/
|
|
|
|
_receivedSmsSegmentsMap: null,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Helper for processing received multipart SMS.
|
|
|
|
*
|
|
|
|
* @return null for handled segments, and an object containing full message
|
|
|
|
* body/data once all segments are received.
|
|
|
|
*/
|
|
|
|
_processReceivedSmsSegment: function(aSegment) {
|
|
|
|
|
|
|
|
// Directly replace full message body for single SMS.
|
|
|
|
if (!(aSegment.segmentMaxSeq && (aSegment.segmentMaxSeq > 1))) {
|
|
|
|
if (aSegment.encoding == RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
|
|
|
|
aSegment.fullData = aSegment.data;
|
|
|
|
} else {
|
|
|
|
aSegment.fullBody = aSegment.body;
|
|
|
|
}
|
|
|
|
return aSegment;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle Concatenation for Class 0 SMS
|
|
|
|
let hash = aSegment.sender + ":" +
|
|
|
|
aSegment.segmentRef + ":" +
|
|
|
|
aSegment.segmentMaxSeq;
|
|
|
|
let seq = aSegment.segmentSeq;
|
|
|
|
|
|
|
|
let options = this._receivedSmsSegmentsMap[hash];
|
|
|
|
if (!options) {
|
|
|
|
options = aSegment;
|
|
|
|
this._receivedSmsSegmentsMap[hash] = options;
|
|
|
|
|
|
|
|
options.receivedSegments = 0;
|
|
|
|
options.segments = [];
|
|
|
|
} else if (options.segments[seq]) {
|
|
|
|
// Duplicated segment?
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("Got duplicated segment no." + seq +
|
|
|
|
" of a multipart SMS: " + JSON.stringify(aSegment));
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (options.receivedSegments > 0) {
|
|
|
|
// Update received timestamp.
|
|
|
|
options.timestamp = aSegment.timestamp;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (options.encoding == RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
|
|
|
|
options.segments[seq] = aSegment.data;
|
|
|
|
} else {
|
|
|
|
options.segments[seq] = aSegment.body;
|
|
|
|
}
|
|
|
|
options.receivedSegments++;
|
|
|
|
|
|
|
|
// The port information is only available in 1st segment for CDMA WAP Push.
|
|
|
|
// If the segments of a WAP Push are not received in sequence
|
|
|
|
// (e.g., SMS with seq == 1 is not the 1st segment received by the device),
|
|
|
|
// we have to retrieve the port information from 1st segment and
|
|
|
|
// save it into the cached options.
|
|
|
|
if (aSegment.teleservice === RIL.PDU_CDMA_MSG_TELESERIVCIE_ID_WAP
|
|
|
|
&& seq === 1) {
|
|
|
|
if (!options.originatorPort && aSegment.originatorPort) {
|
|
|
|
options.originatorPort = aSegment.originatorPort;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!options.destinationPort && aSegment.destinationPort) {
|
|
|
|
options.destinationPort = aSegment.destinationPort;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (options.receivedSegments < options.segmentMaxSeq) {
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("Got segment no." + seq + " of a multipart SMS: " +
|
|
|
|
JSON.stringify(options));
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove from map
|
|
|
|
delete this._receivedSmsSegmentsMap[hash];
|
|
|
|
|
|
|
|
// Rebuild full body
|
|
|
|
if (options.encoding == RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
|
|
|
|
// Uint8Array doesn't have `concat`, so we have to merge all segements
|
|
|
|
// by hand.
|
|
|
|
let fullDataLen = 0;
|
|
|
|
for (let i = 1; i <= options.segmentMaxSeq; i++) {
|
|
|
|
fullDataLen += options.segments[i].length;
|
|
|
|
}
|
|
|
|
|
|
|
|
options.fullData = new Uint8Array(fullDataLen);
|
|
|
|
for (let d= 0, i = 1; i <= options.segmentMaxSeq; i++) {
|
|
|
|
let data = options.segments[i];
|
|
|
|
for (let j = 0; j < data.length; j++) {
|
|
|
|
options.fullData[d++] = data[j];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
options.fullBody = options.segments.join("");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove handy fields after completing the concatenation.
|
|
|
|
delete options.receivedSegments;
|
|
|
|
delete options.segments;
|
|
|
|
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("Got full multipart SMS: " + JSON.stringify(options));
|
|
|
|
}
|
|
|
|
|
|
|
|
return options;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Helper to create Savable SmsSegment.
|
|
|
|
*/
|
|
|
|
_createSavableSmsSegment: function(aMessage) {
|
|
|
|
// We precisely define what data fields to be stored into
|
|
|
|
// DB here for better data migration.
|
|
|
|
let segment = {};
|
|
|
|
segment.messageType = aMessage.messageType;
|
|
|
|
segment.teleservice = aMessage.teleservice;
|
|
|
|
segment.SMSC = aMessage.SMSC;
|
|
|
|
segment.sentTimestamp = aMessage.sentTimestamp;
|
|
|
|
segment.timestamp = Date.now();
|
|
|
|
segment.sender = aMessage.sender;
|
|
|
|
segment.pid = aMessage.pid;
|
|
|
|
segment.encoding = aMessage.encoding;
|
|
|
|
segment.messageClass = aMessage.messageClass;
|
|
|
|
segment.iccId = this.getIccId();
|
|
|
|
if (aMessage.header) {
|
|
|
|
segment.segmentRef = aMessage.header.segmentRef;
|
|
|
|
segment.segmentSeq = aMessage.header.segmentSeq;
|
|
|
|
segment.segmentMaxSeq = aMessage.header.segmentMaxSeq;
|
|
|
|
segment.originatorPort = aMessage.header.originatorPort;
|
|
|
|
segment.destinationPort = aMessage.header.destinationPort;
|
|
|
|
}
|
|
|
|
segment.mwiPresent = (aMessage.mwi)? true: false;
|
|
|
|
segment.mwiDiscard = (segment.mwiPresent)? aMessage.mwi.discard: false;
|
|
|
|
segment.mwiMsgCount = (segment.mwiPresent)? aMessage.mwi.msgCount: 0;
|
|
|
|
segment.mwiActive = (segment.mwiPresent)? aMessage.mwi.active: false;
|
|
|
|
segment.serviceCategory = aMessage.serviceCategory;
|
|
|
|
segment.language = aMessage.language;
|
|
|
|
segment.data = aMessage.data;
|
|
|
|
segment.body = aMessage.body;
|
|
|
|
|
|
|
|
return segment;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Helper to purge complete message.
|
|
|
|
*
|
|
|
|
* We remove unnessary fields defined in _createSavableSmsSegment() after
|
|
|
|
* completing the concatenation.
|
|
|
|
*/
|
|
|
|
_purgeCompleteSmsMessage: function(aMessage) {
|
|
|
|
// Purge concatenation info
|
|
|
|
delete aMessage.segmentRef;
|
|
|
|
delete aMessage.segmentSeq;
|
|
|
|
delete aMessage.segmentMaxSeq;
|
|
|
|
|
|
|
|
// Purge partial message body
|
|
|
|
delete aMessage.data;
|
|
|
|
delete aMessage.body;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* handle concatenation of received SMS.
|
|
|
|
*/
|
|
|
|
handleSmsMultipart: function(aMessage) {
|
|
|
|
if (DEBUG) this.debug("handleSmsMultipart: " + JSON.stringify(aMessage));
|
|
|
|
|
|
|
|
this._acquireSmsHandledWakeLock();
|
|
|
|
|
|
|
|
let segment = this._createSavableSmsSegment(aMessage);
|
|
|
|
|
|
|
|
let isMultipart = (segment.segmentMaxSeq && (segment.segmentMaxSeq > 1));
|
|
|
|
let messageClass = segment.messageClass;
|
|
|
|
|
|
|
|
let handleReceivedAndAck = function(aRvOfIncompleteMsg, aCompleteMessage) {
|
|
|
|
if (aCompleteMessage) {
|
|
|
|
this._purgeCompleteSmsMessage(aCompleteMessage);
|
|
|
|
if (this.handleSmsReceived(aCompleteMessage)) {
|
|
|
|
this.sendAckSms(Cr.NS_OK, aCompleteMessage);
|
|
|
|
}
|
|
|
|
// else Ack will be sent after further process in handleSmsReceived.
|
|
|
|
} else {
|
|
|
|
this.sendAckSms(aRvOfIncompleteMsg, segment);
|
|
|
|
}
|
|
|
|
}.bind(this);
|
|
|
|
|
|
|
|
// No need to access SmsSegmentStore for Class 0 SMS and Single SMS.
|
|
|
|
if (!isMultipart ||
|
|
|
|
(messageClass == RIL.GECKO_SMS_MESSAGE_CLASSES[RIL.PDU_DCS_MSG_CLASS_0])) {
|
|
|
|
// `When a mobile terminated message is class 0 and the MS has the
|
|
|
|
// capability of displaying short messages, the MS shall display the
|
|
|
|
// message immediately and send an acknowledgement to the SC when the
|
|
|
|
// message has successfully reached the MS irrespective of whether
|
|
|
|
// there is memory available in the (U)SIM or ME. The message shall
|
|
|
|
// not be automatically stored in the (U)SIM or ME.`
|
|
|
|
// ~ 3GPP 23.038 clause 4
|
|
|
|
|
|
|
|
handleReceivedAndAck(Cr.NS_OK, // ACK OK For Incomplete Class 0
|
|
|
|
this._processReceivedSmsSegment(segment));
|
|
|
|
} else {
|
|
|
|
gMobileMessageDatabaseService
|
|
|
|
.saveSmsSegment(segment, function notifyResult(aRv, aCompleteMessage) {
|
|
|
|
handleReceivedAndAck(aRv, // Ack according to the result after saving
|
|
|
|
aCompleteMessage);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
portAddressedSmsApps: null,
|
|
|
|
handleSmsReceived: function(message) {
|
|
|
|
if (DEBUG) this.debug("handleSmsReceived: " + JSON.stringify(message));
|
|
|
|
|
|
|
|
if (message.messageType == RIL.PDU_CDMA_MSG_TYPE_BROADCAST) {
|
|
|
|
gMessageManager.sendCellBroadcastMessage("RIL:CellBroadcastReceived",
|
|
|
|
this.clientId, message);
|
|
|
|
return true;
|
2013-09-07 15:09:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Dispatch to registered handler if application port addressing is
|
|
|
|
// available. Note that the destination port can possibly be zero when
|
|
|
|
// representing a UDP/TCP port.
|
2014-03-12 20:27:00 +04:00
|
|
|
if (message.destinationPort != null) {
|
|
|
|
let handler = this.portAddressedSmsApps[message.destinationPort];
|
2013-09-07 15:09:54 +04:00
|
|
|
if (handler) {
|
|
|
|
handler(message);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (message.encoding == RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
|
|
|
|
// Don't know how to handle binary data yet.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
message.type = "sms";
|
|
|
|
message.sender = message.sender || null;
|
2013-10-15 06:42:49 +04:00
|
|
|
message.receiver = this.getPhoneNumber();
|
2013-09-07 15:09:54 +04:00
|
|
|
message.body = message.fullBody = message.fullBody || null;
|
|
|
|
|
|
|
|
if (gSmsService.isSilentNumber(message.sender)) {
|
|
|
|
message.id = -1;
|
|
|
|
message.threadId = 0;
|
|
|
|
message.delivery = DOM_MOBILE_MESSAGE_DELIVERY_RECEIVED;
|
|
|
|
message.deliveryStatus = RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS;
|
|
|
|
message.read = false;
|
|
|
|
|
|
|
|
let domMessage =
|
|
|
|
gMobileMessageService.createSmsMessage(message.id,
|
|
|
|
message.threadId,
|
2013-11-02 14:17:25 +04:00
|
|
|
message.iccId,
|
2013-09-07 15:09:54 +04:00
|
|
|
message.delivery,
|
|
|
|
message.deliveryStatus,
|
|
|
|
message.sender,
|
|
|
|
message.receiver,
|
|
|
|
message.body,
|
|
|
|
message.messageClass,
|
|
|
|
message.timestamp,
|
2013-09-23 06:31:32 +04:00
|
|
|
message.sentTimestamp,
|
2013-11-01 16:00:55 +04:00
|
|
|
0,
|
2013-09-07 15:09:54 +04:00
|
|
|
message.read);
|
|
|
|
|
|
|
|
Services.obs.notifyObservers(domMessage,
|
|
|
|
kSilentSmsReceivedObserverTopic,
|
|
|
|
null);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-03-12 20:27:00 +04:00
|
|
|
if (message.mwiPresent) {
|
|
|
|
let mwi = {
|
|
|
|
discard: message.mwiDiscard,
|
|
|
|
msgCount: message.mwiMsgCount,
|
|
|
|
active: message.mwiActive
|
|
|
|
};
|
|
|
|
this.workerMessenger.send("updateMwis", { mwi: mwi });
|
|
|
|
|
2013-09-07 15:09:54 +04:00
|
|
|
mwi.returnNumber = message.sender;
|
|
|
|
mwi.returnMessage = message.fullBody;
|
|
|
|
gMessageManager.sendVoicemailMessage("RIL:VoicemailNotification",
|
|
|
|
this.clientId, mwi);
|
2013-12-06 07:18:17 +04:00
|
|
|
|
|
|
|
// Dicarded MWI comes without text body.
|
|
|
|
// Hence, we discard it here after notifying the MWI status.
|
2014-03-12 20:27:00 +04:00
|
|
|
if (message.mwiDiscard) {
|
2013-12-06 07:18:17 +04:00
|
|
|
return true;
|
|
|
|
}
|
2013-09-07 15:09:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
let notifyReceived = function notifyReceived(rv, domMessage) {
|
|
|
|
let success = Components.isSuccessCode(rv);
|
|
|
|
|
2014-03-12 20:27:00 +04:00
|
|
|
this.sendAckSms(rv, message);
|
2013-09-07 15:09:54 +04:00
|
|
|
|
|
|
|
if (!success) {
|
|
|
|
// At this point we could send a message to content to notify the user
|
|
|
|
// that storing an incoming SMS failed, most likely due to a full disk.
|
|
|
|
if (DEBUG) {
|
2013-11-26 22:58:41 +04:00
|
|
|
this.debug("Could not store SMS, error code " + rv);
|
2013-09-07 15:09:54 +04:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-11-01 13:55:54 +04:00
|
|
|
this.broadcastSmsSystemMessage(kSmsReceivedObserverTopic, domMessage);
|
2013-09-07 15:09:54 +04:00
|
|
|
Services.obs.notifyObservers(domMessage, kSmsReceivedObserverTopic, null);
|
|
|
|
}.bind(this);
|
|
|
|
|
|
|
|
if (message.messageClass != RIL.GECKO_SMS_MESSAGE_CLASSES[RIL.PDU_DCS_MSG_CLASS_0]) {
|
2013-11-26 22:58:41 +04:00
|
|
|
gMobileMessageDatabaseService.saveReceivedMessage(message,
|
|
|
|
notifyReceived);
|
2013-09-07 15:09:54 +04:00
|
|
|
} else {
|
|
|
|
message.id = -1;
|
|
|
|
message.threadId = 0;
|
|
|
|
message.delivery = DOM_MOBILE_MESSAGE_DELIVERY_RECEIVED;
|
|
|
|
message.deliveryStatus = RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS;
|
|
|
|
message.read = false;
|
|
|
|
|
|
|
|
let domMessage =
|
|
|
|
gMobileMessageService.createSmsMessage(message.id,
|
|
|
|
message.threadId,
|
2013-11-02 14:17:25 +04:00
|
|
|
message.iccId,
|
2013-09-07 15:09:54 +04:00
|
|
|
message.delivery,
|
|
|
|
message.deliveryStatus,
|
|
|
|
message.sender,
|
|
|
|
message.receiver,
|
|
|
|
message.body,
|
|
|
|
message.messageClass,
|
|
|
|
message.timestamp,
|
2013-09-23 06:31:32 +04:00
|
|
|
message.sentTimestamp,
|
2013-11-01 16:00:55 +04:00
|
|
|
0,
|
2013-09-07 15:09:54 +04:00
|
|
|
message.read);
|
|
|
|
|
|
|
|
notifyReceived(Cr.NS_OK, domMessage);
|
|
|
|
}
|
|
|
|
|
|
|
|
// SMS ACK will be sent in notifyReceived. Return false here.
|
|
|
|
return false;
|
|
|
|
},
|
|
|
|
|
2014-03-12 20:27:00 +04:00
|
|
|
/**
|
|
|
|
* Handle ACK response of received SMS.
|
|
|
|
*/
|
|
|
|
sendAckSms: function(aRv, aMessage) {
|
|
|
|
if (aMessage.messageClass === RIL.GECKO_SMS_MESSAGE_CLASSES[RIL.PDU_DCS_MSG_CLASS_2]) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let result = RIL.PDU_FCS_OK;
|
|
|
|
if (!Components.isSuccessCode(aRv)) {
|
|
|
|
if (DEBUG) this.debug("Failed to handle received sms: " + aRv);
|
|
|
|
result = (aRv === Cr.NS_ERROR_FILE_NO_DEVICE_SPACE)
|
|
|
|
? RIL.PDU_FCS_MEMORY_CAPACITY_EXCEEDED
|
|
|
|
: RIL.PDU_FCS_UNSPECIFIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.workerMessenger.send("ackSMS", { result: result });
|
|
|
|
|
|
|
|
},
|
|
|
|
|
2013-01-25 14:06:24 +04:00
|
|
|
/**
|
2013-06-22 18:22:05 +04:00
|
|
|
* Set the setting value of "time.clock.automatic-update.available".
|
|
|
|
*/
|
2014-01-13 06:44:40 +04:00
|
|
|
setClockAutoUpdateAvailable: function(value) {
|
2013-10-24 12:14:59 +04:00
|
|
|
gSettingsService.createLock().set(kSettingsClockAutoUpdateAvailable, value, null,
|
2013-06-22 18:22:05 +04:00
|
|
|
"fromInternalSetting");
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the setting value of "time.timezone.automatic-update.available".
|
2013-01-25 14:06:24 +04:00
|
|
|
*/
|
2014-01-13 06:44:40 +04:00
|
|
|
setTimezoneAutoUpdateAvailable: function(value) {
|
2013-10-24 12:14:59 +04:00
|
|
|
gSettingsService.createLock().set(kSettingsTimezoneAutoUpdateAvailable, value, null,
|
2013-01-25 14:06:24 +04:00
|
|
|
"fromInternalSetting");
|
|
|
|
},
|
|
|
|
|
2012-09-28 10:02:57 +04:00
|
|
|
/**
|
2013-06-22 18:22:05 +04:00
|
|
|
* Set the system clock by NITZ.
|
2012-09-28 10:02:57 +04:00
|
|
|
*/
|
2014-01-13 06:44:40 +04:00
|
|
|
setClockByNitz: function(message) {
|
2012-09-28 10:02:57 +04:00
|
|
|
// To set the system clock time. Note that there could be a time diff
|
|
|
|
// between when the NITZ was received and when the time is actually set.
|
|
|
|
gTimeService.set(
|
|
|
|
message.networkTimeInMS + (Date.now() - message.receiveTimeInMS));
|
2013-06-22 18:22:05 +04:00
|
|
|
},
|
2012-09-28 10:02:57 +04:00
|
|
|
|
2013-06-22 18:22:05 +04:00
|
|
|
/**
|
|
|
|
* Set the system time zone by NITZ.
|
|
|
|
*/
|
2014-01-13 06:44:40 +04:00
|
|
|
setTimezoneByNitz: function(message) {
|
2012-09-28 10:02:57 +04:00
|
|
|
// To set the sytem timezone. Note that we need to convert the time zone
|
|
|
|
// value to a UTC repesentation string in the format of "UTC(+/-)hh:mm".
|
2013-10-15 12:43:53 +04:00
|
|
|
// Ex, time zone -480 is "UTC+08:00"; time zone 630 is "UTC-10:30".
|
2012-09-28 10:02:57 +04:00
|
|
|
//
|
|
|
|
// We can unapply the DST correction if we want the raw time zone offset:
|
|
|
|
// message.networkTimeZoneInMinutes -= message.networkDSTInMinutes;
|
|
|
|
if (message.networkTimeZoneInMinutes != (new Date()).getTimezoneOffset()) {
|
|
|
|
let absTimeZoneInMinutes = Math.abs(message.networkTimeZoneInMinutes);
|
|
|
|
let timeZoneStr = "UTC";
|
2013-10-15 12:43:53 +04:00
|
|
|
timeZoneStr += (message.networkTimeZoneInMinutes > 0 ? "-" : "+");
|
2012-09-28 10:02:57 +04:00
|
|
|
timeZoneStr += ("0" + Math.floor(absTimeZoneInMinutes / 60)).slice(-2);
|
|
|
|
timeZoneStr += ":";
|
|
|
|
timeZoneStr += ("0" + absTimeZoneInMinutes % 60).slice(-2);
|
|
|
|
gSettingsService.createLock().set("time.timezone", timeZoneStr, null);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2012-10-23 11:15:53 +04:00
|
|
|
/**
|
|
|
|
* Handle the NITZ message.
|
|
|
|
*/
|
2014-01-13 06:44:40 +04:00
|
|
|
handleNitzTime: function(message) {
|
2013-01-25 14:06:24 +04:00
|
|
|
// Got the NITZ info received from the ril_worker.
|
2013-06-22 18:22:05 +04:00
|
|
|
this.setClockAutoUpdateAvailable(true);
|
|
|
|
this.setTimezoneAutoUpdateAvailable(true);
|
2013-01-25 14:06:24 +04:00
|
|
|
|
2012-10-23 11:15:53 +04:00
|
|
|
// Cache the latest NITZ message whenever receiving it.
|
|
|
|
this._lastNitzMessage = message;
|
|
|
|
|
2013-06-22 18:22:05 +04:00
|
|
|
// Set the received NITZ clock if the setting is enabled.
|
|
|
|
if (this._clockAutoUpdateEnabled) {
|
|
|
|
this.setClockByNitz(message);
|
|
|
|
}
|
|
|
|
// Set the received NITZ timezone if the setting is enabled.
|
|
|
|
if (this._timezoneAutoUpdateEnabled) {
|
|
|
|
this.setTimezoneByNitz(message);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the system clock by SNTP.
|
|
|
|
*/
|
2014-01-13 06:44:40 +04:00
|
|
|
setClockBySntp: function(offset) {
|
2013-06-22 18:22:05 +04:00
|
|
|
// Got the SNTP info.
|
|
|
|
this.setClockAutoUpdateAvailable(true);
|
|
|
|
if (!this._clockAutoUpdateEnabled) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (this._lastNitzMessage) {
|
2014-01-23 12:44:20 +04:00
|
|
|
if (DEBUG) debug("SNTP: NITZ available, discard SNTP");
|
2013-06-22 18:22:05 +04:00
|
|
|
return;
|
2012-10-23 11:15:53 +04:00
|
|
|
}
|
2013-06-22 18:22:05 +04:00
|
|
|
gTimeService.set(Date.now() + offset);
|
2012-10-23 11:15:53 +04:00
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
handleIccMbdn: function(message) {
|
2012-12-26 14:49:08 +04:00
|
|
|
let voicemailInfo = this.voicemailInfo;
|
2012-11-23 08:09:01 +04:00
|
|
|
|
2012-12-26 14:49:08 +04:00
|
|
|
voicemailInfo.number = message.number;
|
|
|
|
voicemailInfo.displayName = message.alphaId;
|
2012-11-23 08:09:01 +04:00
|
|
|
|
2013-07-02 13:36:40 +04:00
|
|
|
gMessageManager.sendVoicemailMessage("RIL:VoicemailInfoChanged",
|
|
|
|
this.clientId, voicemailInfo);
|
2012-11-23 08:09:01 +04:00
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
handleIccInfoChange: function(message) {
|
2013-10-15 06:42:49 +04:00
|
|
|
let oldSpn = this.rilContext.iccInfo ? this.rilContext.iccInfo.spn : null;
|
2013-01-10 20:18:54 +04:00
|
|
|
|
2013-10-15 06:42:49 +04:00
|
|
|
if (!message || !message.iccType) {
|
|
|
|
// 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 {
|
|
|
|
this.rilContext.iccInfo = new GsmIccInfo();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!this.isInfoChanged(message, this.rilContext.iccInfo)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.updateInfo(message, this.rilContext.iccInfo);
|
2012-09-04 01:43:59 +04:00
|
|
|
}
|
2013-10-15 06:42:49 +04:00
|
|
|
|
2012-09-04 01:43:59 +04:00
|
|
|
// RIL:IccInfoChanged corresponds to a DOM event that gets fired only
|
2013-08-12 10:59:17 +04:00
|
|
|
// when iccInfo has changed.
|
2013-05-30 15:14:39 +04:00
|
|
|
gMessageManager.sendIccMessage("RIL:IccInfoChanged",
|
2013-08-12 10:59:17 +04:00
|
|
|
this.clientId,
|
|
|
|
message.iccType ? message : null);
|
2013-01-04 12:44:20 +04:00
|
|
|
|
2013-07-19 00:17:41 +04:00
|
|
|
// Update lastKnownSimMcc.
|
|
|
|
if (message.mcc) {
|
|
|
|
try {
|
|
|
|
Services.prefs.setCharPref("ril.lastKnownSimMcc",
|
|
|
|
message.mcc.toString());
|
|
|
|
} catch (e) {}
|
|
|
|
}
|
|
|
|
|
2013-05-03 05:37:51 +04:00
|
|
|
// Update lastKnownHomeNetwork.
|
|
|
|
if (message.mcc && message.mnc) {
|
2014-01-08 14:54:34 +04:00
|
|
|
this._lastKnownHomeNetwork = message.mcc + "-" + message.mnc;
|
2013-05-03 05:37:51 +04:00
|
|
|
}
|
|
|
|
|
2013-01-04 12:44:20 +04:00
|
|
|
// If spn becomes available, we should check roaming again.
|
2013-01-08 16:40:00 +04:00
|
|
|
if (!oldSpn && message.spn) {
|
2013-01-04 12:44:20 +04:00
|
|
|
let voice = this.rilContext.voice;
|
|
|
|
let data = this.rilContext.data;
|
|
|
|
let voiceRoaming = voice.roaming;
|
|
|
|
let dataRoaming = data.roaming;
|
|
|
|
this.checkRoamingBetweenOperators(voice);
|
|
|
|
this.checkRoamingBetweenOperators(data);
|
|
|
|
if (voiceRoaming != voice.roaming) {
|
2013-07-02 13:36:40 +04:00
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:VoiceInfoChanged",
|
|
|
|
this.clientId, voice);
|
2013-01-04 12:44:20 +04:00
|
|
|
}
|
|
|
|
if (dataRoaming != data.roaming) {
|
2013-07-02 13:36:40 +04:00
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged",
|
|
|
|
this.clientId, data);
|
2013-01-04 12:44:20 +04:00
|
|
|
}
|
|
|
|
}
|
2012-09-04 01:43:59 +04:00
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
handleUSSDReceived: function(ussd) {
|
2014-05-08 07:47:24 +04:00
|
|
|
gSystemMessenger.broadcastMessage("ussd-received",
|
|
|
|
{message: ussd.message,
|
|
|
|
sessionEnded: ussd.sessionEnded,
|
|
|
|
serviceId: this.clientId});
|
2013-07-02 13:36:40 +04:00
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:USSDReceived",
|
|
|
|
this.clientId, ussd);
|
2012-06-10 01:07:18 +04:00
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
handleStkProactiveCommand: function(message) {
|
2013-07-02 13:36:58 +04:00
|
|
|
if (DEBUG) this.debug("handleStkProactiveCommand " + JSON.stringify(message));
|
2013-11-25 14:10:34 +04:00
|
|
|
let iccId = this.rilContext.iccInfo && this.rilContext.iccInfo.iccid;
|
|
|
|
if (iccId) {
|
|
|
|
gSystemMessenger.broadcastMessage("icc-stkcommand",
|
|
|
|
{iccId: iccId,
|
|
|
|
command: message});
|
|
|
|
}
|
2013-07-02 13:36:40 +04:00
|
|
|
gMessageManager.sendIccMessage("RIL:StkCommand", this.clientId, message);
|
2012-04-10 16:04:27 +04:00
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
handleExitEmergencyCbMode: function(message) {
|
2013-08-14 16:50:36 +04:00
|
|
|
if (DEBUG) this.debug("handleExitEmergencyCbMode: " + JSON.stringify(message));
|
|
|
|
gMessageManager.sendRequestResults("RIL:ExitEmergencyCbMode", message);
|
|
|
|
},
|
|
|
|
|
2012-04-20 01:33:25 +04:00
|
|
|
// nsIObserver
|
2012-03-13 03:45:57 +04:00
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
observe: function(subject, topic, data) {
|
2012-04-25 00:46:42 +04:00
|
|
|
switch (topic) {
|
|
|
|
case kMozSettingsChangedObserverTopic:
|
|
|
|
let setting = JSON.parse(data);
|
2013-01-25 14:06:24 +04:00
|
|
|
this.handleSettingsChange(setting.key, setting.value, setting.message);
|
2012-04-25 00:46:42 +04:00
|
|
|
break;
|
2013-10-24 12:14:59 +04:00
|
|
|
case NS_PREFBRANCH_PREFCHANGE_TOPIC_ID:
|
|
|
|
if (data === kPrefCellBroadcastDisabled) {
|
2013-06-07 11:32:24 +04:00
|
|
|
let value = false;
|
|
|
|
try {
|
2013-10-24 12:14:59 +04:00
|
|
|
value = Services.prefs.getBoolPref(kPrefCellBroadcastDisabled);
|
2013-06-07 11:32:24 +04:00
|
|
|
} catch(e) {}
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.send("setCellBroadcastDisabled",
|
|
|
|
{ disabled: value });
|
2013-06-07 11:32:24 +04:00
|
|
|
}
|
|
|
|
break;
|
2012-10-23 11:15:53 +04:00
|
|
|
case kSysClockChangeObserverTopic:
|
2013-06-22 18:22:05 +04:00
|
|
|
let offset = parseInt(data, 10);
|
2012-10-23 11:15:53 +04:00
|
|
|
if (this._lastNitzMessage) {
|
2013-06-22 18:22:05 +04:00
|
|
|
this._lastNitzMessage.receiveTimeInMS += offset;
|
|
|
|
}
|
|
|
|
this._sntp.updateOffset(offset);
|
|
|
|
break;
|
2014-03-10 07:36:42 +04:00
|
|
|
case kNetworkConnStateChangedTopic:
|
2013-06-22 18:22:05 +04:00
|
|
|
let network = subject.QueryInterface(Ci.nsINetworkInterface);
|
2013-10-29 12:13:06 +04:00
|
|
|
if (network.state != Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// SNTP can only update when we have mobile or Wifi connections.
|
|
|
|
if (network.type != Ci.nsINetworkInterface.NETWORK_TYPE_WIFI &&
|
|
|
|
network.type != Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the network comes from RIL, make sure the RIL service is matched.
|
|
|
|
if (subject instanceof Ci.nsIRilNetworkInterface) {
|
|
|
|
network = subject.QueryInterface(Ci.nsIRilNetworkInterface);
|
|
|
|
if (network.serviceId != this.clientId) {
|
|
|
|
return;
|
2013-06-22 18:22:05 +04:00
|
|
|
}
|
2012-10-23 11:15:53 +04:00
|
|
|
}
|
2013-10-29 12:13:06 +04:00
|
|
|
|
|
|
|
// SNTP won't update unless the SNTP is already expired.
|
|
|
|
if (this._sntp.isExpired()) {
|
|
|
|
this._sntp.request();
|
|
|
|
}
|
2012-04-25 00:46:42 +04:00
|
|
|
break;
|
2014-04-11 12:53:57 +04:00
|
|
|
case kNetworkActiveChangedTopic:
|
|
|
|
let dataInfo = this.rilContext.data;
|
|
|
|
let connected = false;
|
|
|
|
if (gNetworkManager.active &&
|
|
|
|
gNetworkManager.active.type ===
|
|
|
|
Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE &&
|
|
|
|
gNetworkManager.active.serviceId === this.clientId) {
|
|
|
|
connected = true;
|
|
|
|
}
|
|
|
|
if (dataInfo.connected !== connected) {
|
|
|
|
dataInfo.connected = connected;
|
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged",
|
|
|
|
this.clientId, dataInfo);
|
|
|
|
}
|
|
|
|
break;
|
2013-06-06 11:28:59 +04:00
|
|
|
case kScreenStateChangedTopic:
|
2013-08-14 14:11:47 +04:00
|
|
|
this.workerMessenger.send("setScreenState", { on: (data === "on") });
|
2013-06-06 11:28:59 +04:00
|
|
|
break;
|
2012-04-20 01:33:25 +04:00
|
|
|
}
|
2012-03-13 03:45:57 +04:00
|
|
|
},
|
|
|
|
|
2014-01-08 10:10:58 +04:00
|
|
|
supportedNetworkTypes: null,
|
|
|
|
|
2013-06-22 18:22:05 +04:00
|
|
|
// Flag to determine whether to update system clock automatically. It
|
2013-11-21 18:09:14 +04:00
|
|
|
// corresponds to the "time.clock.automatic-update.enabled" setting.
|
2013-06-22 18:22:05 +04:00
|
|
|
_clockAutoUpdateEnabled: null,
|
|
|
|
|
|
|
|
// Flag to determine whether to update system timezone automatically. It
|
2013-11-21 18:09:14 +04:00
|
|
|
// corresponds to the "time.clock.automatic-update.enabled" setting.
|
2013-06-22 18:22:05 +04:00
|
|
|
_timezoneAutoUpdateEnabled: null,
|
2012-09-28 17:08:04 +04:00
|
|
|
|
2012-10-23 11:15:53 +04:00
|
|
|
// Remember the last NITZ message so that we can set the time based on
|
|
|
|
// the network immediately when users enable network-based time.
|
|
|
|
_lastNitzMessage: null,
|
|
|
|
|
2013-06-22 18:22:05 +04:00
|
|
|
// Object that handles SNTP.
|
|
|
|
_sntp: null,
|
|
|
|
|
2012-12-04 06:41:39 +04:00
|
|
|
// Cell Broadcast settings values.
|
2014-04-03 12:33:56 +04:00
|
|
|
_cellBroadcastSearchList: null,
|
2012-12-04 06:41:39 +04:00
|
|
|
|
2014-01-08 14:54:34 +04:00
|
|
|
// Operator's mcc-mnc.
|
|
|
|
_lastKnownNetwork: null,
|
|
|
|
|
|
|
|
// ICC's mcc-mnc.
|
|
|
|
_lastKnownHomeNetwork: null,
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
handleSettingsChange: function(aName, aResult, aMessage) {
|
2013-01-25 14:06:24 +04:00
|
|
|
// Don't allow any content processes to modify the setting
|
2013-06-22 18:22:05 +04:00
|
|
|
// "time.clock.automatic-update.available" except for the chrome process.
|
2013-10-24 12:14:59 +04:00
|
|
|
if (aName === kSettingsClockAutoUpdateAvailable &&
|
2013-06-22 18:22:05 +04:00
|
|
|
aMessage !== "fromInternalSetting") {
|
|
|
|
let isClockAutoUpdateAvailable = this._lastNitzMessage !== null ||
|
|
|
|
this._sntp.isAvailable();
|
|
|
|
if (aResult !== isClockAutoUpdateAvailable) {
|
2014-01-23 12:44:20 +04:00
|
|
|
if (DEBUG) {
|
|
|
|
debug("Content processes cannot modify 'time.clock.automatic-update.available'. Restore!");
|
|
|
|
}
|
2013-06-22 18:22:05 +04:00
|
|
|
// Restore the setting to the current value.
|
|
|
|
this.setClockAutoUpdateAvailable(isClockAutoUpdateAvailable);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Don't allow any content processes to modify the setting
|
|
|
|
// "time.timezone.automatic-update.available" except for the chrome
|
|
|
|
// process.
|
2013-10-24 12:14:59 +04:00
|
|
|
if (aName === kSettingsTimezoneAutoUpdateAvailable &&
|
2013-06-22 18:22:05 +04:00
|
|
|
aMessage !== "fromInternalSetting") {
|
|
|
|
let isTimezoneAutoUpdateAvailable = this._lastNitzMessage !== null;
|
|
|
|
if (aResult !== isTimezoneAutoUpdateAvailable) {
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("Content processes cannot modify 'time.timezone.automatic-update.available'. Restore!");
|
|
|
|
}
|
|
|
|
// Restore the setting to the current value.
|
|
|
|
this.setTimezoneAutoUpdateAvailable(isTimezoneAutoUpdateAvailable);
|
2013-07-02 13:36:58 +04:00
|
|
|
}
|
2013-01-25 14:06:24 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
this.handle(aName, aResult);
|
|
|
|
},
|
|
|
|
|
2012-09-28 10:02:57 +04:00
|
|
|
// nsISettingsServiceCallback
|
2014-01-13 06:44:40 +04:00
|
|
|
handle: function(aName, aResult) {
|
2012-08-01 18:54:04 +04:00
|
|
|
switch(aName) {
|
2013-10-24 12:14:59 +04:00
|
|
|
case kSettingsClockAutoUpdateEnabled:
|
2013-06-22 18:22:05 +04:00
|
|
|
this._clockAutoUpdateEnabled = aResult;
|
|
|
|
if (!this._clockAutoUpdateEnabled) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the latest cached NITZ time if it's available.
|
|
|
|
if (this._lastNitzMessage) {
|
|
|
|
this.setClockByNitz(this._lastNitzMessage);
|
|
|
|
} else if (gNetworkManager.active && gNetworkManager.active.state ==
|
|
|
|
Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED) {
|
|
|
|
// Set the latest cached SNTP time if it's available.
|
|
|
|
if (!this._sntp.isExpired()) {
|
|
|
|
this.setClockBySntp(this._sntp.getOffset());
|
|
|
|
} else {
|
|
|
|
// Or refresh the SNTP.
|
|
|
|
this._sntp.request();
|
|
|
|
}
|
2014-02-18 18:41:36 +04:00
|
|
|
} else {
|
|
|
|
// Set a sane minimum time.
|
|
|
|
let buildTime = libcutils.property_get("ro.build.date.utc", "0") * 1000;
|
|
|
|
let file = FileUtils.File("/system/b2g/b2g");
|
|
|
|
if (file.lastModifiedTime > buildTime) {
|
|
|
|
buildTime = file.lastModifiedTime;
|
|
|
|
}
|
|
|
|
if (buildTime > Date.now()) {
|
|
|
|
gTimeService.set(buildTime);
|
|
|
|
}
|
2013-06-22 18:22:05 +04:00
|
|
|
}
|
|
|
|
break;
|
2013-10-24 12:14:59 +04:00
|
|
|
case kSettingsTimezoneAutoUpdateEnabled:
|
2013-06-22 18:22:05 +04:00
|
|
|
this._timezoneAutoUpdateEnabled = aResult;
|
2012-10-23 11:15:53 +04:00
|
|
|
|
2013-06-22 18:22:05 +04:00
|
|
|
if (this._timezoneAutoUpdateEnabled) {
|
|
|
|
// Apply the latest cached NITZ for timezone if it's available.
|
|
|
|
if (this._timezoneAutoUpdateEnabled && this._lastNitzMessage) {
|
|
|
|
this.setTimezoneByNitz(this._lastNitzMessage);
|
|
|
|
}
|
2012-10-23 11:15:53 +04:00
|
|
|
}
|
2012-09-28 10:02:57 +04:00
|
|
|
break;
|
2013-10-24 12:14:59 +04:00
|
|
|
case kSettingsCellBroadcastSearchList:
|
2013-07-02 13:36:58 +04:00
|
|
|
if (DEBUG) {
|
2014-04-03 12:33:56 +04:00
|
|
|
this.debug("'" + kSettingsCellBroadcastSearchList +
|
|
|
|
"' is now " + JSON.stringify(aResult));
|
2013-07-02 13:36:58 +04:00
|
|
|
}
|
2014-04-03 12:33:56 +04:00
|
|
|
// TODO: Set searchlist for Multi-SIM. See Bug 921326.
|
|
|
|
let result = Array.isArray(aResult) ? aResult[0] : aResult;
|
|
|
|
this.setCellBroadcastSearchList(result);
|
2012-12-04 06:41:39 +04:00
|
|
|
break;
|
2013-06-10 06:41:14 +04:00
|
|
|
}
|
2012-05-24 09:12:07 +04:00
|
|
|
},
|
2012-09-05 13:36:01 +04:00
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
handleError: function(aErrorMessage) {
|
2013-12-03 10:18:32 +04:00
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("There was an error while reading RIL settings.");
|
|
|
|
}
|
2012-05-24 09:12:07 +04:00
|
|
|
},
|
|
|
|
|
2013-07-02 13:36:37 +04:00
|
|
|
// nsIRadioInterface
|
2011-12-05 11:58:27 +04:00
|
|
|
|
2012-06-13 06:46:41 +04:00
|
|
|
rilContext: null,
|
2011-12-05 11:58:27 +04:00
|
|
|
|
2012-04-24 19:44:42 +04:00
|
|
|
// Handle phone functions of nsIRILContentHelper
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
_sendCfStateChanged: function(message) {
|
2013-08-13 16:14:13 +04:00
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:CfStateChanged",
|
|
|
|
this.clientId, message);
|
2012-06-02 01:10:39 +04:00
|
|
|
},
|
|
|
|
|
2014-04-24 10:46:27 +04:00
|
|
|
_sendClirModeChanged: function(message) {
|
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:ClirModeChanged",
|
|
|
|
this.clientId, message);
|
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
sendMMI: function(target, message) {
|
2013-07-02 13:36:58 +04:00
|
|
|
if (DEBUG) this.debug("SendMMI " + JSON.stringify(message));
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.send("sendMMI", message, (function(response) {
|
|
|
|
if (response.isSetCallForward) {
|
|
|
|
this._sendCfStateChanged(response);
|
2014-04-22 14:46:59 +04:00
|
|
|
} else if (response.isSetCLIR && response.success) {
|
2014-04-24 10:46:27 +04:00
|
|
|
this._sendClirModeChanged(response.clirMode);
|
2013-08-13 16:14:13 +04:00
|
|
|
}
|
2013-02-25 13:27:26 +04:00
|
|
|
|
2013-09-30 04:56:00 +04:00
|
|
|
target.sendAsyncMessage("RIL:SendMMI", {
|
|
|
|
clientId: this.clientId,
|
|
|
|
data: response
|
|
|
|
});
|
2013-08-13 16:14:13 +04:00
|
|
|
return false;
|
|
|
|
}).bind(this));
|
2013-02-25 13:27:26 +04:00
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
setCallForwardingOptions: function(target, message) {
|
2013-10-30 08:04:21 +04:00
|
|
|
if (DEBUG) this.debug("setCallForwardingOptions: " + JSON.stringify(message));
|
2012-10-31 17:58:39 +04:00
|
|
|
message.serviceClass = RIL.ICC_SERVICE_CLASS_VOICE;
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.send("setCallForward", message, (function(response) {
|
|
|
|
this._sendCfStateChanged(response);
|
2013-10-30 08:04:21 +04:00
|
|
|
target.sendAsyncMessage("RIL:SetCallForwardingOptions", {
|
2013-09-30 04:56:00 +04:00
|
|
|
clientId: this.clientId,
|
|
|
|
data: response
|
|
|
|
});
|
2013-08-13 16:14:13 +04:00
|
|
|
return false;
|
|
|
|
}).bind(this));
|
2013-04-18 16:18:50 +04:00
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:44 +04:00
|
|
|
setCallingLineIdRestriction: function(target, message) {
|
2013-07-18 01:18:29 +04:00
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("setCallingLineIdRestriction: " + JSON.stringify(message));
|
|
|
|
}
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.send("setCLIR", message, (function(response) {
|
2014-04-22 14:46:59 +04:00
|
|
|
if (response.success) {
|
2014-04-24 10:46:27 +04:00
|
|
|
this._sendClirModeChanged(response.clirMode);
|
2014-04-22 14:46:59 +04:00
|
|
|
}
|
2013-09-30 04:56:00 +04:00
|
|
|
target.sendAsyncMessage("RIL:SetCallingLineIdRestriction", {
|
|
|
|
clientId: this.clientId,
|
|
|
|
data: response
|
|
|
|
});
|
2013-08-23 16:42:20 +04:00
|
|
|
return false;
|
2013-08-13 16:14:13 +04:00
|
|
|
}).bind(this));
|
2013-07-18 01:18:29 +04:00
|
|
|
},
|
|
|
|
|
2013-11-21 18:09:14 +04:00
|
|
|
isValidStateForSetRadioEnabled: function() {
|
2013-11-26 22:58:28 +04:00
|
|
|
let state = this.rilContext.detailedRadioState;
|
|
|
|
return state == RIL.GECKO_DETAILED_RADIOSTATE_ENABLED ||
|
|
|
|
state == RIL.GECKO_DETAILED_RADIOSTATE_DISABLED;
|
2013-11-21 18:09:14 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
isDummyForSetRadioEnabled: function(message) {
|
2013-11-26 22:58:28 +04:00
|
|
|
let state = this.rilContext.detailedRadioState;
|
|
|
|
return (state == RIL.GECKO_DETAILED_RADIOSTATE_ENABLED && message.enabled) ||
|
|
|
|
(state == RIL.GECKO_DETAILED_RADIOSTATE_DISABLED && !message.enabled);
|
2013-11-21 18:09:14 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
setRadioEnabledResponse: function(target, message, errorMsg) {
|
|
|
|
if (errorMsg) {
|
|
|
|
message.errorMsg = errorMsg;
|
|
|
|
}
|
|
|
|
|
|
|
|
target.sendAsyncMessage("RIL:SetRadioEnabled", {
|
|
|
|
clientId: this.clientId,
|
|
|
|
data: message
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
setRadioEnabled: function(target, message) {
|
2013-11-21 18:09:14 +04:00
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("setRadioEnabled: " + JSON.stringify(message));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!this.isValidStateForSetRadioEnabled()) {
|
|
|
|
this.setRadioEnabledResponse(target, message, "InvalidStateError");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.isDummyForSetRadioEnabled(message)) {
|
|
|
|
this.setRadioEnabledResponse(target, message);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let callback = (function(response) {
|
2014-01-02 19:39:26 +04:00
|
|
|
if (response.errorMsg) {
|
|
|
|
// Request fails. Rollback to the original radiostate.
|
|
|
|
let state = message.enabled ? RIL.GECKO_DETAILED_RADIOSTATE_DISABLED
|
|
|
|
: RIL.GECKO_DETAILED_RADIOSTATE_ENABLED;
|
|
|
|
this.handleDetailedRadioStateChanged(state);
|
|
|
|
}
|
2013-11-21 18:09:14 +04:00
|
|
|
this.setRadioEnabledResponse(target, response);
|
|
|
|
return false;
|
|
|
|
}).bind(this);
|
|
|
|
|
|
|
|
this.setRadioEnabledInternal(message, callback);
|
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
setRadioEnabledInternal: function(message, callback) {
|
2013-11-21 18:09:14 +04:00
|
|
|
let state = message.enabled ? RIL.GECKO_DETAILED_RADIOSTATE_ENABLING
|
|
|
|
: RIL.GECKO_DETAILED_RADIOSTATE_DISABLING;
|
|
|
|
this.handleDetailedRadioStateChanged(state);
|
|
|
|
this.workerMessenger.send("setRadioEnabled", message, callback);
|
|
|
|
},
|
|
|
|
|
2013-09-07 15:09:54 +04:00
|
|
|
/**
|
|
|
|
* List of tuples of national language identifier pairs.
|
|
|
|
*
|
|
|
|
* TODO: Support static/runtime settings, see bug 733331.
|
|
|
|
*/
|
|
|
|
enabledGsmTableTuples: [
|
|
|
|
[RIL.PDU_NL_IDENTIFIER_DEFAULT, RIL.PDU_NL_IDENTIFIER_DEFAULT],
|
|
|
|
],
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Use 16-bit reference number for concatenated outgoint messages.
|
|
|
|
*
|
|
|
|
* TODO: Support static/runtime settings, see bug 733331.
|
|
|
|
*/
|
|
|
|
segmentRef16Bit: false,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get valid SMS concatenation reference number.
|
|
|
|
*/
|
|
|
|
_segmentRef: 0,
|
|
|
|
get nextSegmentRef() {
|
|
|
|
let ref = this._segmentRef++;
|
|
|
|
|
|
|
|
this._segmentRef %= (this.segmentRef16Bit ? 65535 : 255);
|
|
|
|
|
|
|
|
// 0 is not a valid SMS concatenation reference number.
|
|
|
|
return ref + 1;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Calculate encoded length using specified locking/single shift table
|
|
|
|
*
|
|
|
|
* @param message
|
|
|
|
* message string to be encoded.
|
|
|
|
* @param langTable
|
|
|
|
* locking shift table string.
|
|
|
|
* @param langShiftTable
|
|
|
|
* single shift table string.
|
|
|
|
* @param strict7BitEncoding
|
|
|
|
* Optional. Enable Latin characters replacement with corresponding
|
|
|
|
* ones in GSM SMS 7-bit default alphabet.
|
|
|
|
*
|
|
|
|
* @return encoded length in septets.
|
|
|
|
*
|
|
|
|
* @note that the algorithm used in this function must match exactly with
|
|
|
|
* GsmPDUHelper#writeStringAsSeptets.
|
|
|
|
*/
|
2014-01-13 06:44:40 +04:00
|
|
|
_countGsm7BitSeptets: function(message, langTable, langShiftTable, strict7BitEncoding) {
|
2013-09-07 15:09:54 +04:00
|
|
|
let length = 0;
|
|
|
|
for (let msgIndex = 0; msgIndex < message.length; msgIndex++) {
|
|
|
|
let c = message.charAt(msgIndex);
|
|
|
|
if (strict7BitEncoding) {
|
|
|
|
c = RIL.GSM_SMS_STRICT_7BIT_CHARMAP[c] || c;
|
|
|
|
}
|
|
|
|
|
|
|
|
let septet = langTable.indexOf(c);
|
|
|
|
|
|
|
|
// According to 3GPP TS 23.038, section 6.1.1 General notes, "The
|
|
|
|
// characters marked '1)' are not used but are displayed as a space."
|
|
|
|
if (septet == RIL.PDU_NL_EXTENDED_ESCAPE) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (septet >= 0) {
|
|
|
|
length++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
septet = langShiftTable.indexOf(c);
|
|
|
|
if (septet < 0) {
|
|
|
|
if (!strict7BitEncoding) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bug 816082, when strict7BitEncoding is enabled, we should replace
|
|
|
|
// characters that can't be encoded with GSM 7-Bit alphabets with '*'.
|
2013-11-21 18:09:14 +04:00
|
|
|
c = "*";
|
2013-09-07 15:09:54 +04:00
|
|
|
if (langTable.indexOf(c) >= 0) {
|
|
|
|
length++;
|
|
|
|
} else if (langShiftTable.indexOf(c) >= 0) {
|
|
|
|
length += 2;
|
|
|
|
} else {
|
|
|
|
// We can't even encode a '*' character with current configuration.
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// According to 3GPP TS 23.038 B.2, "This code represents a control
|
|
|
|
// character and therefore must not be used for language specific
|
|
|
|
// characters."
|
|
|
|
if (septet == RIL.PDU_NL_RESERVED_CONTROL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The character is not found in locking shfit table, but could be
|
|
|
|
// encoded as <escape><char> with single shift table. Note that it's
|
|
|
|
// still possible for septet to has the value of PDU_NL_EXTENDED_ESCAPE,
|
|
|
|
// but we can display it as a space in this case as said in previous
|
|
|
|
// comment.
|
|
|
|
length += 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
return length;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Calculate user data length of specified message string encoded in GSM 7Bit
|
|
|
|
* alphabets.
|
|
|
|
*
|
|
|
|
* @param message
|
|
|
|
* a message string to be encoded.
|
|
|
|
* @param strict7BitEncoding
|
|
|
|
* Optional. Enable Latin characters replacement with corresponding
|
|
|
|
* ones in GSM SMS 7-bit default alphabet.
|
|
|
|
*
|
|
|
|
* @return null or an options object with attributes `dcs`,
|
|
|
|
* `userDataHeaderLength`, `encodedFullBodyLength`, `langIndex`,
|
|
|
|
* `langShiftIndex`, `segmentMaxSeq` set.
|
|
|
|
*
|
|
|
|
* @see #_calculateUserDataLength().
|
|
|
|
*/
|
2014-01-13 06:44:40 +04:00
|
|
|
_calculateUserDataLength7Bit: function(message, strict7BitEncoding) {
|
2013-09-07 15:09:54 +04:00
|
|
|
let options = null;
|
|
|
|
let minUserDataSeptets = Number.MAX_VALUE;
|
|
|
|
for (let i = 0; i < this.enabledGsmTableTuples.length; i++) {
|
|
|
|
let [langIndex, langShiftIndex] = this.enabledGsmTableTuples[i];
|
|
|
|
|
|
|
|
const langTable = RIL.PDU_NL_LOCKING_SHIFT_TABLES[langIndex];
|
|
|
|
const langShiftTable = RIL.PDU_NL_SINGLE_SHIFT_TABLES[langShiftIndex];
|
|
|
|
|
|
|
|
let bodySeptets = this._countGsm7BitSeptets(message,
|
|
|
|
langTable,
|
|
|
|
langShiftTable,
|
|
|
|
strict7BitEncoding);
|
|
|
|
if (bodySeptets < 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
let headerLen = 0;
|
|
|
|
if (langIndex != RIL.PDU_NL_IDENTIFIER_DEFAULT) {
|
|
|
|
headerLen += 3; // IEI + len + langIndex
|
|
|
|
}
|
|
|
|
if (langShiftIndex != RIL.PDU_NL_IDENTIFIER_DEFAULT) {
|
|
|
|
headerLen += 3; // IEI + len + langShiftIndex
|
|
|
|
}
|
|
|
|
|
|
|
|
// Calculate full user data length, note the extra byte is for header len
|
|
|
|
let headerSeptets = Math.ceil((headerLen ? headerLen + 1 : 0) * 8 / 7);
|
|
|
|
let segmentSeptets = RIL.PDU_MAX_USER_DATA_7BIT;
|
|
|
|
if ((bodySeptets + headerSeptets) > segmentSeptets) {
|
|
|
|
headerLen += this.segmentRef16Bit ? 6 : 5;
|
|
|
|
headerSeptets = Math.ceil((headerLen + 1) * 8 / 7);
|
|
|
|
segmentSeptets -= headerSeptets;
|
|
|
|
}
|
|
|
|
|
|
|
|
let segments = Math.ceil(bodySeptets / segmentSeptets);
|
|
|
|
let userDataSeptets = bodySeptets + headerSeptets * segments;
|
|
|
|
if (userDataSeptets >= minUserDataSeptets) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
minUserDataSeptets = userDataSeptets;
|
|
|
|
|
|
|
|
options = {
|
|
|
|
dcs: RIL.PDU_DCS_MSG_CODING_7BITS_ALPHABET,
|
|
|
|
encodedFullBodyLength: bodySeptets,
|
|
|
|
userDataHeaderLength: headerLen,
|
|
|
|
langIndex: langIndex,
|
|
|
|
langShiftIndex: langShiftIndex,
|
|
|
|
segmentMaxSeq: segments,
|
|
|
|
segmentChars: segmentSeptets,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
return options;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Calculate user data length of specified message string encoded in UCS2.
|
|
|
|
*
|
|
|
|
* @param message
|
|
|
|
* a message string to be encoded.
|
|
|
|
*
|
|
|
|
* @return an options object with attributes `dcs`, `userDataHeaderLength`,
|
|
|
|
* `encodedFullBodyLength`, `segmentMaxSeq` set.
|
|
|
|
*
|
|
|
|
* @see #_calculateUserDataLength().
|
|
|
|
*/
|
2014-01-13 06:44:40 +04:00
|
|
|
_calculateUserDataLengthUCS2: function(message) {
|
2013-09-07 15:09:54 +04:00
|
|
|
let bodyChars = message.length;
|
|
|
|
let headerLen = 0;
|
|
|
|
let headerChars = Math.ceil((headerLen ? headerLen + 1 : 0) / 2);
|
|
|
|
let segmentChars = RIL.PDU_MAX_USER_DATA_UCS2;
|
|
|
|
if ((bodyChars + headerChars) > segmentChars) {
|
|
|
|
headerLen += this.segmentRef16Bit ? 6 : 5;
|
|
|
|
headerChars = Math.ceil((headerLen + 1) / 2);
|
|
|
|
segmentChars -= headerChars;
|
|
|
|
}
|
|
|
|
|
|
|
|
let segments = Math.ceil(bodyChars / segmentChars);
|
|
|
|
|
|
|
|
return {
|
|
|
|
dcs: RIL.PDU_DCS_MSG_CODING_16BITS_ALPHABET,
|
|
|
|
encodedFullBodyLength: bodyChars * 2,
|
|
|
|
userDataHeaderLength: headerLen,
|
|
|
|
segmentMaxSeq: segments,
|
|
|
|
segmentChars: segmentChars,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Calculate user data length and its encoding.
|
|
|
|
*
|
|
|
|
* @param message
|
|
|
|
* a message string to be encoded.
|
|
|
|
* @param strict7BitEncoding
|
|
|
|
* Optional. Enable Latin characters replacement with corresponding
|
|
|
|
* ones in GSM SMS 7-bit default alphabet.
|
|
|
|
*
|
|
|
|
* @return an options object with some or all of following attributes set:
|
|
|
|
*
|
|
|
|
* @param dcs
|
|
|
|
* Data coding scheme. One of the PDU_DCS_MSG_CODING_*BITS_ALPHABET
|
|
|
|
* constants.
|
|
|
|
* @param userDataHeaderLength
|
|
|
|
* Length of embedded user data header, in bytes. The whole header
|
|
|
|
* size will be userDataHeaderLength + 1; 0 for no header.
|
|
|
|
* @param encodedFullBodyLength
|
|
|
|
* Length of the message body when encoded with the given DCS. For
|
|
|
|
* UCS2, in bytes; for 7-bit, in septets.
|
|
|
|
* @param langIndex
|
|
|
|
* Table index used for normal 7-bit encoded character lookup.
|
|
|
|
* @param langShiftIndex
|
|
|
|
* Table index used for escaped 7-bit encoded character lookup.
|
|
|
|
* @param segmentMaxSeq
|
|
|
|
* Max sequence number of a multi-part messages, or 1 for single one.
|
|
|
|
* This number might not be accurate for a multi-part message until
|
|
|
|
* it's processed by #_fragmentText() again.
|
|
|
|
*/
|
2014-01-13 06:44:40 +04:00
|
|
|
_calculateUserDataLength: function(message, strict7BitEncoding) {
|
2013-09-07 15:09:54 +04:00
|
|
|
let options = this._calculateUserDataLength7Bit(message, strict7BitEncoding);
|
|
|
|
if (!options) {
|
|
|
|
options = this._calculateUserDataLengthUCS2(message);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (DEBUG) this.debug("_calculateUserDataLength: " + JSON.stringify(options));
|
|
|
|
return options;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fragment GSM 7-Bit encodable string for transmission.
|
|
|
|
*
|
|
|
|
* @param text
|
|
|
|
* text string to be fragmented.
|
|
|
|
* @param langTable
|
|
|
|
* locking shift table string.
|
|
|
|
* @param langShiftTable
|
|
|
|
* single shift table string.
|
|
|
|
* @param segmentSeptets
|
|
|
|
* Number of available spetets per segment.
|
|
|
|
* @param strict7BitEncoding
|
|
|
|
* Optional. Enable Latin characters replacement with corresponding
|
|
|
|
* ones in GSM SMS 7-bit default alphabet.
|
|
|
|
*
|
|
|
|
* @return an array of objects. See #_fragmentText() for detailed definition.
|
|
|
|
*/
|
2014-01-13 06:44:40 +04:00
|
|
|
_fragmentText7Bit: function(text, langTable, langShiftTable, segmentSeptets, strict7BitEncoding) {
|
2013-09-07 15:09:54 +04:00
|
|
|
let ret = [];
|
|
|
|
let body = "", len = 0;
|
2014-01-18 18:13:35 +04:00
|
|
|
// If the message is empty, we only push the empty message to ret.
|
|
|
|
if (text.length === 0) {
|
|
|
|
ret.push({
|
|
|
|
body: text,
|
|
|
|
encodedBodyLength: text.length,
|
|
|
|
});
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-09-07 15:09:54 +04:00
|
|
|
for (let i = 0, inc = 0; i < text.length; i++) {
|
|
|
|
let c = text.charAt(i);
|
|
|
|
if (strict7BitEncoding) {
|
|
|
|
c = RIL.GSM_SMS_STRICT_7BIT_CHARMAP[c] || c;
|
|
|
|
}
|
|
|
|
|
|
|
|
let septet = langTable.indexOf(c);
|
|
|
|
if (septet == RIL.PDU_NL_EXTENDED_ESCAPE) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (septet >= 0) {
|
|
|
|
inc = 1;
|
|
|
|
} else {
|
|
|
|
septet = langShiftTable.indexOf(c);
|
|
|
|
if (septet == RIL.PDU_NL_RESERVED_CONTROL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
inc = 2;
|
|
|
|
if (septet < 0) {
|
|
|
|
if (!strict7BitEncoding) {
|
|
|
|
throw new Error("Given text cannot be encoded with GSM 7-bit Alphabet!");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bug 816082, when strict7BitEncoding is enabled, we should replace
|
|
|
|
// characters that can't be encoded with GSM 7-Bit alphabets with '*'.
|
2013-11-21 18:09:14 +04:00
|
|
|
c = "*";
|
2013-09-07 15:09:54 +04:00
|
|
|
if (langTable.indexOf(c) >= 0) {
|
|
|
|
inc = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((len + inc) > segmentSeptets) {
|
|
|
|
ret.push({
|
|
|
|
body: body,
|
|
|
|
encodedBodyLength: len,
|
|
|
|
});
|
|
|
|
body = c;
|
|
|
|
len = inc;
|
|
|
|
} else {
|
|
|
|
body += c;
|
|
|
|
len += inc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (len) {
|
|
|
|
ret.push({
|
|
|
|
body: body,
|
|
|
|
encodedBodyLength: len,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fragment UCS2 encodable string for transmission.
|
|
|
|
*
|
|
|
|
* @param text
|
|
|
|
* text string to be fragmented.
|
|
|
|
* @param segmentChars
|
|
|
|
* Number of available characters per segment.
|
|
|
|
*
|
|
|
|
* @return an array of objects. See #_fragmentText() for detailed definition.
|
|
|
|
*/
|
2014-01-13 06:44:40 +04:00
|
|
|
_fragmentTextUCS2: function(text, segmentChars) {
|
2013-09-07 15:09:54 +04:00
|
|
|
let ret = [];
|
2014-01-18 18:13:35 +04:00
|
|
|
// If the message is empty, we only push the empty message to ret.
|
|
|
|
if (text.length === 0) {
|
|
|
|
ret.push({
|
|
|
|
body: text,
|
|
|
|
encodedBodyLength: text.length,
|
|
|
|
});
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-09-07 15:09:54 +04:00
|
|
|
for (let offset = 0; offset < text.length; offset += segmentChars) {
|
|
|
|
let str = text.substr(offset, segmentChars);
|
|
|
|
ret.push({
|
|
|
|
body: str,
|
|
|
|
encodedBodyLength: str.length * 2,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fragment string for transmission.
|
|
|
|
*
|
|
|
|
* Fragment input text string into an array of objects that contains
|
|
|
|
* attributes `body`, substring for this segment, `encodedBodyLength`,
|
|
|
|
* length of the encoded segment body in septets.
|
|
|
|
*
|
|
|
|
* @param text
|
|
|
|
* Text string to be fragmented.
|
|
|
|
* @param options
|
|
|
|
* Optional pre-calculated option object. The output array will be
|
|
|
|
* stored at options.segments if there are multiple segments.
|
|
|
|
* @param strict7BitEncoding
|
|
|
|
* Optional. Enable Latin characters replacement with corresponding
|
|
|
|
* ones in GSM SMS 7-bit default alphabet.
|
|
|
|
*
|
|
|
|
* @return Populated options object.
|
|
|
|
*/
|
2014-01-13 06:44:40 +04:00
|
|
|
_fragmentText: function(text, options, strict7BitEncoding) {
|
2013-09-07 15:09:54 +04:00
|
|
|
if (!options) {
|
|
|
|
options = this._calculateUserDataLength(text, strict7BitEncoding);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (options.dcs == RIL.PDU_DCS_MSG_CODING_7BITS_ALPHABET) {
|
|
|
|
const langTable = RIL.PDU_NL_LOCKING_SHIFT_TABLES[options.langIndex];
|
|
|
|
const langShiftTable = RIL.PDU_NL_SINGLE_SHIFT_TABLES[options.langShiftIndex];
|
|
|
|
options.segments = this._fragmentText7Bit(text,
|
|
|
|
langTable, langShiftTable,
|
|
|
|
options.segmentChars,
|
|
|
|
strict7BitEncoding);
|
|
|
|
} else {
|
|
|
|
options.segments = this._fragmentTextUCS2(text,
|
|
|
|
options.segmentChars);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Re-sync options.segmentMaxSeq with actual length of returning array.
|
|
|
|
options.segmentMaxSeq = options.segments.length;
|
|
|
|
|
|
|
|
return options;
|
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
getSegmentInfoForText: function(text, request) {
|
2013-09-07 15:09:54 +04:00
|
|
|
let strict7BitEncoding;
|
|
|
|
try {
|
|
|
|
strict7BitEncoding = Services.prefs.getBoolPref("dom.sms.strict7BitEncoding");
|
|
|
|
} catch (e) {
|
|
|
|
strict7BitEncoding = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
let options = this._fragmentText(text, null, strict7BitEncoding);
|
|
|
|
let charsInLastSegment;
|
|
|
|
if (options.segmentMaxSeq) {
|
|
|
|
let lastSegment = options.segments[options.segmentMaxSeq - 1];
|
|
|
|
charsInLastSegment = lastSegment.encodedBodyLength;
|
|
|
|
if (options.dcs == RIL.PDU_DCS_MSG_CODING_16BITS_ALPHABET) {
|
|
|
|
// In UCS2 encoding, encodedBodyLength is in octets.
|
|
|
|
charsInLastSegment /= 2;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
charsInLastSegment = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
let result = gMobileMessageService
|
|
|
|
.createSmsSegmentInfo(options.segmentMaxSeq,
|
|
|
|
options.segmentChars,
|
|
|
|
options.segmentChars - charsInLastSegment);
|
|
|
|
request.notifySegmentInfoForTextGot(result);
|
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
getSmscAddress: function(request) {
|
2013-09-16 06:12:40 +04:00
|
|
|
this.workerMessenger.send("getSmscAddress",
|
|
|
|
null,
|
|
|
|
(function(response) {
|
|
|
|
if (!response.errorMsg) {
|
|
|
|
request.notifyGetSmscAddress(response.smscAddress);
|
|
|
|
} else {
|
|
|
|
request.notifyGetSmscAddressFailed(response.errorMsg);
|
|
|
|
}
|
|
|
|
}).bind(this));
|
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
sendSMS: function(number, message, silent, request) {
|
2013-09-07 15:09:54 +04:00
|
|
|
let strict7BitEncoding;
|
|
|
|
try {
|
|
|
|
strict7BitEncoding = Services.prefs.getBoolPref("dom.sms.strict7BitEncoding");
|
|
|
|
} catch (e) {
|
|
|
|
strict7BitEncoding = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
let options = this._fragmentText(message, null, strict7BitEncoding);
|
|
|
|
options.number = PhoneNumberUtils.normalize(number);
|
|
|
|
let requestStatusReport;
|
|
|
|
try {
|
|
|
|
requestStatusReport =
|
|
|
|
Services.prefs.getBoolPref("dom.sms.requestStatusReport");
|
|
|
|
} catch (e) {
|
|
|
|
requestStatusReport = true;
|
|
|
|
}
|
|
|
|
options.requestStatusReport = requestStatusReport && !silent;
|
|
|
|
if (options.segmentMaxSeq > 1) {
|
|
|
|
options.segmentRef16Bit = this.segmentRef16Bit;
|
|
|
|
options.segmentRef = this.nextSegmentRef;
|
|
|
|
}
|
|
|
|
|
|
|
|
let notifyResult = (function notifyResult(rv, domMessage) {
|
2014-02-20 08:21:11 +04:00
|
|
|
if (!Components.isSuccessCode(rv)) {
|
|
|
|
if (DEBUG) this.debug("Error! Fail to save sending message! rv = " + rv);
|
|
|
|
request.notifySendMessageFailed(
|
2014-05-21 16:42:54 +04:00
|
|
|
gMobileMessageDatabaseService.translateCrErrorToMessageCallbackError(rv));
|
2014-02-20 08:21:11 +04:00
|
|
|
Services.obs.notifyObservers(domMessage, kSmsFailedObserverTopic, null);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-09-07 15:09:54 +04:00
|
|
|
if (!silent) {
|
|
|
|
Services.obs.notifyObservers(domMessage, kSmsSendingObserverTopic, null);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the radio is disabled or the SIM card is not ready, just directly
|
|
|
|
// return with the corresponding error code.
|
|
|
|
let errorCode;
|
|
|
|
if (!PhoneNumberUtils.isPlainPhoneNumber(options.number)) {
|
|
|
|
if (DEBUG) this.debug("Error! Address is invalid when sending SMS: " +
|
|
|
|
options.number);
|
|
|
|
errorCode = Ci.nsIMobileMessageCallback.INVALID_ADDRESS_ERROR;
|
2013-11-21 18:09:14 +04:00
|
|
|
} else if (this.rilContext.detailedRadioState ==
|
|
|
|
RIL.GECKO_DETAILED_RADIOSTATE_DISABLED) {
|
2013-09-07 15:09:54 +04:00
|
|
|
if (DEBUG) this.debug("Error! Radio is disabled when sending SMS.");
|
|
|
|
errorCode = Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR;
|
|
|
|
} else if (this.rilContext.cardState != "ready") {
|
|
|
|
if (DEBUG) this.debug("Error! SIM card is not ready when sending SMS.");
|
|
|
|
errorCode = Ci.nsIMobileMessageCallback.NO_SIM_CARD_ERROR;
|
|
|
|
}
|
|
|
|
if (errorCode) {
|
|
|
|
if (silent) {
|
2014-05-21 16:42:54 +04:00
|
|
|
request.notifySendMessageFailed(errorCode);
|
2013-09-07 15:09:54 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
gMobileMessageDatabaseService
|
|
|
|
.setMessageDeliveryByMessageId(domMessage.id,
|
|
|
|
null,
|
|
|
|
DOM_MOBILE_MESSAGE_DELIVERY_ERROR,
|
|
|
|
RIL.GECKO_SMS_DELIVERY_STATUS_ERROR,
|
|
|
|
null,
|
|
|
|
function notifyResult(rv, domMessage) {
|
|
|
|
// TODO bug 832140 handle !Components.isSuccessCode(rv)
|
2014-05-21 16:42:54 +04:00
|
|
|
request.notifySendMessageFailed(errorCode);
|
2013-09-07 15:09:54 +04:00
|
|
|
Services.obs.notifyObservers(domMessage, kSmsFailedObserverTopic, null);
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Keep current SMS message info for sent/delivered notifications
|
|
|
|
let context = {
|
|
|
|
request: request,
|
|
|
|
sms: domMessage,
|
|
|
|
requestStatusReport: options.requestStatusReport,
|
|
|
|
silent: silent
|
|
|
|
};
|
|
|
|
|
|
|
|
// This is the entry point starting to send SMS.
|
|
|
|
this.workerMessenger.send("sendSMS", options,
|
|
|
|
(function(context, response) {
|
|
|
|
if (response.errorMsg) {
|
|
|
|
// Failed to send SMS out.
|
|
|
|
let error = Ci.nsIMobileMessageCallback.UNKNOWN_ERROR;
|
|
|
|
switch (response.errorMsg) {
|
|
|
|
case RIL.ERROR_RADIO_NOT_AVAILABLE:
|
|
|
|
error = Ci.nsIMobileMessageCallback.NO_SIGNAL_ERROR;
|
|
|
|
break;
|
2013-09-09 17:48:07 +04:00
|
|
|
case RIL.ERROR_FDN_CHECK_FAILURE:
|
|
|
|
error = Ci.nsIMobileMessageCallback.FDN_CHECK_ERROR;
|
|
|
|
break;
|
2013-09-07 15:09:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (context.silent) {
|
2014-05-21 16:42:54 +04:00
|
|
|
context.request.notifySendMessageFailed(error);
|
2013-09-07 15:09:54 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
gMobileMessageDatabaseService
|
|
|
|
.setMessageDeliveryByMessageId(context.sms.id,
|
|
|
|
null,
|
|
|
|
DOM_MOBILE_MESSAGE_DELIVERY_ERROR,
|
|
|
|
RIL.GECKO_SMS_DELIVERY_STATUS_ERROR,
|
|
|
|
null,
|
|
|
|
function notifyResult(rv, domMessage) {
|
|
|
|
// TODO bug 832140 handle !Components.isSuccessCode(rv)
|
2014-05-21 16:42:54 +04:00
|
|
|
context.request.notifySendMessageFailed(error);
|
2013-09-07 15:09:54 +04:00
|
|
|
Services.obs.notifyObservers(domMessage, kSmsFailedObserverTopic, null);
|
|
|
|
});
|
|
|
|
return false;
|
|
|
|
} // End of send failure.
|
|
|
|
|
|
|
|
if (response.deliveryStatus) {
|
|
|
|
// Message delivery.
|
|
|
|
gMobileMessageDatabaseService
|
|
|
|
.setMessageDeliveryByMessageId(context.sms.id,
|
|
|
|
null,
|
|
|
|
context.sms.delivery,
|
|
|
|
response.deliveryStatus,
|
|
|
|
null,
|
2013-11-01 18:45:57 +04:00
|
|
|
(function notifyResult(rv, domMessage) {
|
2013-09-07 15:09:54 +04:00
|
|
|
// TODO bug 832140 handle !Components.isSuccessCode(rv)
|
2013-11-01 13:55:54 +04:00
|
|
|
|
|
|
|
let topic = (response.deliveryStatus ==
|
|
|
|
RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS)
|
2013-09-07 15:09:54 +04:00
|
|
|
? kSmsDeliverySuccessObserverTopic
|
|
|
|
: kSmsDeliveryErrorObserverTopic;
|
2013-11-01 13:55:54 +04:00
|
|
|
|
2013-11-21 18:09:14 +04:00
|
|
|
// Broadcasting a "sms-delivery-success" system message to open apps.
|
2013-11-01 13:55:54 +04:00
|
|
|
if (topic == kSmsDeliverySuccessObserverTopic) {
|
|
|
|
this.broadcastSmsSystemMessage(topic, domMessage);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Notifying observers the delivery status is updated.
|
2013-09-07 15:09:54 +04:00
|
|
|
Services.obs.notifyObservers(domMessage, topic, null);
|
2013-11-01 18:45:57 +04:00
|
|
|
}).bind(this));
|
2013-09-07 15:09:54 +04:00
|
|
|
|
|
|
|
// Send transaction has ended completely.
|
|
|
|
return false;
|
|
|
|
} // End of message delivery.
|
|
|
|
|
|
|
|
// Message sent.
|
|
|
|
if (context.silent) {
|
2013-11-01 16:00:55 +04:00
|
|
|
// There is no way to modify nsIDOMMozSmsMessage attributes as they
|
|
|
|
// are read only so we just create a new sms instance to send along
|
|
|
|
// with the notification.
|
2013-09-07 15:09:54 +04:00
|
|
|
let sms = context.sms;
|
|
|
|
context.request.notifyMessageSent(
|
|
|
|
gMobileMessageService.createSmsMessage(sms.id,
|
|
|
|
sms.threadId,
|
2013-11-02 14:17:25 +04:00
|
|
|
sms.iccId,
|
2013-09-07 15:09:54 +04:00
|
|
|
DOM_MOBILE_MESSAGE_DELIVERY_SENT,
|
|
|
|
sms.deliveryStatus,
|
|
|
|
sms.sender,
|
|
|
|
sms.receiver,
|
|
|
|
sms.body,
|
|
|
|
sms.messageClass,
|
|
|
|
sms.timestamp,
|
2013-09-23 06:31:32 +04:00
|
|
|
Date.now(),
|
2013-11-01 16:00:55 +04:00
|
|
|
0,
|
2013-09-07 15:09:54 +04:00
|
|
|
sms.read));
|
|
|
|
// We don't wait for SMS-DELIVER-REPORT for silent one.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
gMobileMessageDatabaseService
|
|
|
|
.setMessageDeliveryByMessageId(context.sms.id,
|
|
|
|
null,
|
|
|
|
DOM_MOBILE_MESSAGE_DELIVERY_SENT,
|
|
|
|
context.sms.deliveryStatus,
|
|
|
|
null,
|
|
|
|
(function notifyResult(rv, domMessage) {
|
|
|
|
// TODO bug 832140 handle !Components.isSuccessCode(rv)
|
|
|
|
|
|
|
|
if (context.requestStatusReport) {
|
|
|
|
context.sms = domMessage;
|
|
|
|
}
|
|
|
|
|
2013-11-01 13:55:54 +04:00
|
|
|
this.broadcastSmsSystemMessage(kSmsSentObserverTopic, domMessage);
|
2013-09-07 15:09:54 +04:00
|
|
|
context.request.notifyMessageSent(domMessage);
|
|
|
|
Services.obs.notifyObservers(domMessage, kSmsSentObserverTopic, null);
|
|
|
|
}).bind(this));
|
|
|
|
|
|
|
|
// Only keep current context if we have requested for delivery report.
|
|
|
|
return context.requestStatusReport;
|
|
|
|
}).bind(this, context)); // End of |workerMessenger.send| callback.
|
|
|
|
}).bind(this); // End of DB saveSendingMessage callback.
|
|
|
|
|
|
|
|
let sendingMessage = {
|
|
|
|
type: "sms",
|
2013-10-15 06:42:49 +04:00
|
|
|
sender: this.getPhoneNumber(),
|
2013-09-07 15:09:54 +04:00
|
|
|
receiver: number,
|
|
|
|
body: message,
|
|
|
|
deliveryStatusRequested: options.requestStatusReport,
|
2013-11-02 14:17:25 +04:00
|
|
|
timestamp: Date.now(),
|
|
|
|
iccId: this.getIccId()
|
2013-09-07 15:09:54 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
if (silent) {
|
|
|
|
let delivery = DOM_MOBILE_MESSAGE_DELIVERY_SENDING;
|
2013-09-23 06:31:32 +04:00
|
|
|
let deliveryStatus = RIL.GECKO_SMS_DELIVERY_STATUS_PENDING;
|
2013-09-07 15:09:54 +04:00
|
|
|
let domMessage =
|
|
|
|
gMobileMessageService.createSmsMessage(-1, // id
|
|
|
|
0, // threadId
|
2013-11-02 14:17:25 +04:00
|
|
|
sendingMessage.iccId,
|
2013-09-07 15:09:54 +04:00
|
|
|
delivery,
|
|
|
|
deliveryStatus,
|
|
|
|
sendingMessage.sender,
|
|
|
|
sendingMessage.receiver,
|
|
|
|
sendingMessage.body,
|
|
|
|
"normal", // message class
|
|
|
|
sendingMessage.timestamp,
|
2013-11-01 16:00:55 +04:00
|
|
|
0,
|
2013-09-23 06:31:32 +04:00
|
|
|
0,
|
2013-09-07 15:09:54 +04:00
|
|
|
false);
|
|
|
|
notifyResult(Cr.NS_OK, domMessage);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-11-21 18:09:14 +04:00
|
|
|
let id = gMobileMessageDatabaseService.saveSendingMessage(
|
|
|
|
sendingMessage, notifyResult);
|
2013-09-07 15:09:54 +04:00
|
|
|
},
|
|
|
|
|
2013-12-03 10:18:32 +04:00
|
|
|
// TODO: Bug 928861 - B2G NetworkManager: Provide a more generic function
|
|
|
|
// for connecting
|
2014-01-13 06:44:40 +04:00
|
|
|
setupDataCallByType: function(apntype) {
|
2013-12-03 10:18:32 +04:00
|
|
|
let connHandler = gDataConnectionManager.getConnectionHandler(this.clientId);
|
|
|
|
connHandler.setupDataCallByType(apntype);
|
2013-06-28 05:46:00 +04:00
|
|
|
},
|
2013-01-23 08:05:34 +04:00
|
|
|
|
2013-12-03 10:18:32 +04:00
|
|
|
// TODO: Bug 928861 - B2G NetworkManager: Provide a more generic function
|
|
|
|
// for connecting
|
2014-01-13 06:44:40 +04:00
|
|
|
deactivateDataCallByType: function(apntype) {
|
2013-12-03 10:18:32 +04:00
|
|
|
let connHandler = gDataConnectionManager.getConnectionHandler(this.clientId);
|
|
|
|
connHandler.deactivateDataCallByType(apntype);
|
2013-06-28 05:46:00 +04:00
|
|
|
},
|
|
|
|
|
2013-12-03 10:18:32 +04:00
|
|
|
// TODO: Bug 904514 - [meta] NetworkManager enhancement
|
2014-01-13 06:44:40 +04:00
|
|
|
getDataCallStateByType: function(apntype) {
|
2013-12-03 10:18:32 +04:00
|
|
|
let connHandler = gDataConnectionManager.getConnectionHandler(this.clientId);
|
|
|
|
return connHandler.getDataCallStateByType(apntype);
|
2012-09-26 16:57:37 +04:00
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
setupDataCall: function(radioTech, apn, user, passwd, chappap, pdptype) {
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.send("setupDataCall", { radioTech: radioTech,
|
|
|
|
apn: apn,
|
|
|
|
user: user,
|
|
|
|
passwd: passwd,
|
|
|
|
chappap: chappap,
|
|
|
|
pdptype: pdptype });
|
2012-01-18 05:34:09 +04:00
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
deactivateDataCall: function(cid, reason) {
|
2013-08-13 16:14:13 +04:00
|
|
|
this.workerMessenger.send("deactivateDataCall", { cid: cid,
|
|
|
|
reason: reason });
|
2012-12-28 07:11:36 +04:00
|
|
|
},
|
2013-09-07 10:19:57 +04:00
|
|
|
|
2014-01-13 06:44:44 +04:00
|
|
|
sendWorkerMessage: function(rilMessageType, message, callback) {
|
2014-02-21 13:46:58 +04:00
|
|
|
if (callback) {
|
|
|
|
this.workerMessenger.send(rilMessageType, message, function(response) {
|
|
|
|
return callback.handleResponse(response);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
this.workerMessenger.send(rilMessageType, message);
|
|
|
|
}
|
2013-09-07 10:19:57 +04:00
|
|
|
}
|
2012-04-12 08:01:49 +04:00
|
|
|
};
|
2012-03-13 03:46:08 +04:00
|
|
|
|
2013-12-03 10:18:32 +04:00
|
|
|
function RILNetworkInterface(dataConnectionHandler, apnSetting) {
|
|
|
|
this.dataConnectionHandler = dataConnectionHandler;
|
2013-07-12 08:44:22 +04:00
|
|
|
this.apnSetting = apnSetting;
|
2013-08-20 15:31:10 +04:00
|
|
|
this.connectedTypes = [];
|
2014-03-29 11:18:22 +04:00
|
|
|
|
|
|
|
this.ips = [];
|
|
|
|
this.prefixLengths = [];
|
|
|
|
this.dnses = [];
|
|
|
|
this.gateways = [];
|
2012-09-26 16:52:21 +04:00
|
|
|
}
|
2012-03-13 03:46:08 +04:00
|
|
|
|
2012-09-26 16:52:21 +04:00
|
|
|
RILNetworkInterface.prototype = {
|
|
|
|
classID: RILNETWORKINTERFACE_CID,
|
|
|
|
classInfo: XPCOMUtils.generateCI({classID: RILNETWORKINTERFACE_CID,
|
|
|
|
classDescription: "RILNetworkInterface",
|
|
|
|
interfaces: [Ci.nsINetworkInterface,
|
2014-03-29 11:18:12 +04:00
|
|
|
Ci.nsIRilNetworkInterface]}),
|
2012-04-20 01:33:25 +04:00
|
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInterface,
|
2014-03-29 11:18:12 +04:00
|
|
|
Ci.nsIRilNetworkInterface]),
|
2012-03-13 03:46:08 +04:00
|
|
|
|
2012-04-20 01:33:25 +04:00
|
|
|
// nsINetworkInterface
|
2012-03-13 03:46:08 +04:00
|
|
|
|
2012-04-20 01:33:25 +04:00
|
|
|
NETWORK_STATE_UNKNOWN: Ci.nsINetworkInterface.NETWORK_STATE_UNKNOWN,
|
|
|
|
NETWORK_STATE_CONNECTING: Ci.nsINetworkInterface.CONNECTING,
|
|
|
|
NETWORK_STATE_CONNECTED: Ci.nsINetworkInterface.CONNECTED,
|
|
|
|
NETWORK_STATE_DISCONNECTING: Ci.nsINetworkInterface.DISCONNECTING,
|
|
|
|
NETWORK_STATE_DISCONNECTED: Ci.nsINetworkInterface.DISCONNECTED,
|
2012-03-13 03:46:08 +04:00
|
|
|
|
2012-08-30 20:57:33 +04:00
|
|
|
NETWORK_TYPE_WIFI: Ci.nsINetworkInterface.NETWORK_TYPE_WIFI,
|
|
|
|
NETWORK_TYPE_MOBILE: Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE,
|
|
|
|
NETWORK_TYPE_MOBILE_MMS: Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS,
|
|
|
|
NETWORK_TYPE_MOBILE_SUPL: Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_SUPL,
|
2014-02-25 20:08:00 +04:00
|
|
|
NETWORK_TYPE_MOBILE_IMS: Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_IMS,
|
2014-02-28 14:04:59 +04:00
|
|
|
NETWORK_TYPE_MOBILE_DUN: Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_DUN,
|
2013-06-28 05:46:00 +04:00
|
|
|
// The network manager should only need to add the host route for "other"
|
|
|
|
// types, which is the same handling method as the supl type. So let the
|
|
|
|
// definition of other types to be the same as the one of supl type.
|
|
|
|
NETWORK_TYPE_MOBILE_OTHERS: Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_SUPL,
|
2012-04-20 01:33:25 +04:00
|
|
|
|
2012-06-02 01:09:59 +04:00
|
|
|
/**
|
|
|
|
* Standard values for the APN connection retry process
|
|
|
|
* Retry funcion: time(secs) = A * numer_of_retries^2 + B
|
|
|
|
*/
|
|
|
|
NETWORK_APNRETRY_FACTOR: 8,
|
|
|
|
NETWORK_APNRETRY_ORIGIN: 3,
|
|
|
|
NETWORK_APNRETRY_MAXRETRIES: 10,
|
|
|
|
|
|
|
|
// Event timer for connection retries
|
|
|
|
timer: null,
|
|
|
|
|
2013-11-02 14:17:58 +04:00
|
|
|
/**
|
|
|
|
* nsINetworkInterface Implementation
|
|
|
|
*/
|
|
|
|
|
|
|
|
state: Ci.nsINetworkInterface.NETWORK_STATE_UNKNOWN,
|
|
|
|
|
2013-06-28 05:46:00 +04:00
|
|
|
get type() {
|
|
|
|
if (this.connectedTypes.indexOf("default") != -1) {
|
|
|
|
return this.NETWORK_TYPE_MOBILE;
|
|
|
|
}
|
|
|
|
if (this.connectedTypes.indexOf("mms") != -1) {
|
|
|
|
return this.NETWORK_TYPE_MOBILE_MMS;
|
|
|
|
}
|
|
|
|
if (this.connectedTypes.indexOf("supl") != -1) {
|
|
|
|
return this.NETWORK_TYPE_MOBILE_SUPL;
|
|
|
|
}
|
2014-02-25 20:08:00 +04:00
|
|
|
if (this.connectedTypes.indexOf("ims") != -1) {
|
|
|
|
return this.NETWORK_TYPE_MOBILE_IMS;
|
|
|
|
}
|
2014-02-28 14:04:59 +04:00
|
|
|
if (this.connectedTypes.indexOf("dun") != -1) {
|
|
|
|
return this.NETWORK_TYPE_MOBILE_DUN;
|
|
|
|
}
|
|
|
|
|
2013-06-28 05:46:00 +04:00
|
|
|
return this.NETWORK_TYPE_MOBILE_OTHERS;
|
|
|
|
},
|
2012-04-20 01:33:25 +04:00
|
|
|
|
|
|
|
name: null,
|
|
|
|
|
2014-03-29 11:18:22 +04:00
|
|
|
ips: null,
|
2012-08-14 05:54:42 +04:00
|
|
|
|
2014-03-29 11:18:22 +04:00
|
|
|
prefixLengths: null,
|
2012-08-14 05:54:42 +04:00
|
|
|
|
2014-03-29 11:18:22 +04:00
|
|
|
gateways: null,
|
2012-08-14 05:54:42 +04:00
|
|
|
|
2014-03-29 11:18:22 +04:00
|
|
|
dnses: null,
|
2012-08-14 05:54:42 +04:00
|
|
|
|
2013-07-12 08:44:22 +04:00
|
|
|
get httpProxyHost() {
|
2013-11-21 18:09:14 +04:00
|
|
|
return this.apnSetting.proxy || "";
|
2013-07-12 08:44:22 +04:00
|
|
|
},
|
2012-08-01 18:55:43 +04:00
|
|
|
|
2013-07-12 08:44:22 +04:00
|
|
|
get httpProxyPort() {
|
2013-11-21 18:09:14 +04:00
|
|
|
return this.apnSetting.port || "";
|
2013-07-12 08:44:22 +04:00
|
|
|
},
|
2012-08-01 18:55:43 +04:00
|
|
|
|
2013-11-02 14:17:58 +04:00
|
|
|
/**
|
|
|
|
* nsIRilNetworkInterface Implementation
|
|
|
|
*/
|
|
|
|
|
2013-10-22 14:43:03 +04:00
|
|
|
get serviceId() {
|
2013-12-03 10:18:32 +04:00
|
|
|
return this.dataConnectionHandler.clientId;
|
2013-10-22 14:43:03 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
get iccId() {
|
2013-12-03 10:18:32 +04:00
|
|
|
let iccInfo = this.dataConnectionHandler.radioInterface.rilContext.iccInfo;
|
2013-10-22 14:43:03 +04:00
|
|
|
return iccInfo && iccInfo.iccid;
|
|
|
|
},
|
|
|
|
|
2013-11-02 14:17:58 +04:00
|
|
|
get mmsc() {
|
|
|
|
if (!this.inConnectedTypes("mms")) {
|
|
|
|
if (DEBUG) this.debug("Error! Only MMS network can get MMSC.");
|
|
|
|
throw Cr.NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
let mmsc = this.apnSetting.mmsc;
|
|
|
|
if (!mmsc) {
|
|
|
|
try {
|
|
|
|
mmsc = Services.prefs.getCharPref("ril.mms.mmsc");
|
|
|
|
} catch (e) {
|
|
|
|
mmsc = "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return mmsc;
|
|
|
|
},
|
|
|
|
|
|
|
|
get mmsProxy() {
|
|
|
|
if (!this.inConnectedTypes("mms")) {
|
|
|
|
if (DEBUG) this.debug("Error! Only MMS network can get MMS proxy.");
|
|
|
|
throw Cr.NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
let proxy = this.apnSetting.mmsproxy;
|
|
|
|
if (!proxy) {
|
|
|
|
try {
|
|
|
|
proxy = Services.prefs.getCharPref("ril.mms.mmsproxy");
|
|
|
|
} catch (e) {
|
|
|
|
proxy = "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return proxy;
|
|
|
|
},
|
|
|
|
|
|
|
|
get mmsPort() {
|
|
|
|
if (!this.inConnectedTypes("mms")) {
|
|
|
|
if (DEBUG) this.debug("Error! Only MMS network can get MMS port.");
|
|
|
|
throw Cr.NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
let port = this.apnSetting.mmsport;
|
|
|
|
if (!port) {
|
|
|
|
try {
|
|
|
|
port = Services.prefs.getIntPref("ril.mms.mmsport");
|
|
|
|
} catch (e) {
|
|
|
|
port = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return port;
|
|
|
|
},
|
|
|
|
|
2014-03-29 11:18:22 +04:00
|
|
|
getAddresses: function (ips, prefixLengths) {
|
|
|
|
ips.value = this.ips.slice();
|
|
|
|
prefixLengths.value = this.prefixLengths.slice();
|
|
|
|
|
|
|
|
return this.ips.length;
|
|
|
|
},
|
|
|
|
|
|
|
|
getGateways: function (count) {
|
|
|
|
if (count) {
|
|
|
|
count.value = this.gateways.length;
|
|
|
|
}
|
|
|
|
return this.gateways.slice();
|
|
|
|
},
|
|
|
|
|
|
|
|
getDnses: function (count) {
|
|
|
|
if (count) {
|
|
|
|
count.value = this.dnses.length;
|
|
|
|
}
|
|
|
|
return this.dnses.slice();
|
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
debug: function(s) {
|
2013-12-03 10:18:32 +04:00
|
|
|
dump("-*- RILNetworkInterface[" + this.dataConnectionHandler.clientId + ":" +
|
2013-07-02 13:36:58 +04:00
|
|
|
this.type + "]: " + s + "\n");
|
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
dataCallError: function(message) {
|
2013-07-12 08:44:22 +04:00
|
|
|
if (message.apn != this.apnSetting.apn) {
|
2012-09-26 16:52:21 +04:00
|
|
|
return;
|
|
|
|
}
|
2013-07-02 13:36:58 +04:00
|
|
|
if (DEBUG) this.debug("Data call error on APN: " + message.apn);
|
2012-09-26 16:52:21 +04:00
|
|
|
this.reset();
|
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
dataCallStateChanged: function(datacall) {
|
2012-12-14 07:13:31 +04:00
|
|
|
if (this.cid && this.cid != datacall.cid) {
|
|
|
|
// If data call for this connection existed but cid mismatched,
|
|
|
|
// it means this datacall state change is not for us.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// If data call for this connection does not exist, it could be state
|
|
|
|
// change for new data call. We only update data call state change
|
|
|
|
// if APN name matched.
|
2013-07-12 08:44:22 +04:00
|
|
|
if (!this.cid && datacall.apn != this.apnSetting.apn) {
|
2012-09-26 16:52:21 +04:00
|
|
|
return;
|
|
|
|
}
|
2013-07-02 13:36:58 +04:00
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("Data call ID: " + datacall.cid + ", interface name: " +
|
|
|
|
datacall.ifname + ", APN name: " + datacall.apn);
|
|
|
|
}
|
2012-03-13 03:46:08 +04:00
|
|
|
if (this.connecting &&
|
2012-06-22 09:53:12 +04:00
|
|
|
(datacall.state == RIL.GECKO_NETWORK_STATE_CONNECTING ||
|
|
|
|
datacall.state == RIL.GECKO_NETWORK_STATE_CONNECTED)) {
|
2012-03-13 03:46:08 +04:00
|
|
|
this.connecting = false;
|
2012-06-22 09:53:12 +04:00
|
|
|
this.cid = datacall.cid;
|
|
|
|
this.name = datacall.ifname;
|
2014-03-29 11:18:22 +04:00
|
|
|
for (let entry of datacall.addresses) {
|
|
|
|
this.ips.push(entry.address);
|
|
|
|
this.prefixLengths.push(entry.prefixLength);
|
2012-08-26 06:29:07 +04:00
|
|
|
}
|
2014-03-29 11:18:22 +04:00
|
|
|
this.gateways = datacall.gateways.slice();
|
|
|
|
this.dnses = datacall.dnses.slice();
|
2012-04-20 01:33:25 +04:00
|
|
|
if (!this.registeredAsNetworkInterface) {
|
2012-09-26 16:52:21 +04:00
|
|
|
gNetworkManager.registerNetworkInterface(this);
|
2012-04-20 01:33:25 +04:00
|
|
|
this.registeredAsNetworkInterface = true;
|
|
|
|
}
|
2012-03-13 03:46:08 +04:00
|
|
|
}
|
2012-12-14 07:13:31 +04:00
|
|
|
// In current design, we don't update status of secondary APN if it shares
|
|
|
|
// same APN name with the default APN. In this condition, this.cid will
|
|
|
|
// not be set and we don't want to update its status.
|
|
|
|
if (this.cid == null) {
|
2012-03-13 03:46:08 +04:00
|
|
|
return;
|
|
|
|
}
|
2013-09-18 14:07:14 +04:00
|
|
|
|
2012-06-22 09:53:12 +04:00
|
|
|
if (this.state == datacall.state) {
|
2013-11-21 18:09:14 +04:00
|
|
|
if (datacall.state != RIL.GECKO_NETWORK_STATE_CONNECTED) {
|
2013-09-18 14:07:14 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
// State remains connected, check for minor changes.
|
|
|
|
let changed = false;
|
2014-03-29 11:18:22 +04:00
|
|
|
if (this.ips.length != datacall.addresses.length) {
|
2013-09-18 14:07:14 +04:00
|
|
|
changed = true;
|
2014-03-29 11:18:22 +04:00
|
|
|
this.ips = [];
|
|
|
|
this.prefixLengths = [];
|
|
|
|
for (let entry of datacall.addresses) {
|
|
|
|
this.ips.push(entry.address);
|
|
|
|
this.prefixLengths.push(entry.prefixLength);
|
|
|
|
}
|
2013-09-18 14:07:14 +04:00
|
|
|
}
|
2014-03-29 11:18:22 +04:00
|
|
|
|
|
|
|
let reduceFunc = function(aRhs, aChanged, aElement, aIndex) {
|
|
|
|
return aChanged || (aElement != aRhs[aIndex]);
|
|
|
|
};
|
|
|
|
for (let field of ["gateways", "dnses"]) {
|
|
|
|
let lhs = this[field], rhs = datacall[field];
|
|
|
|
if (lhs.length != rhs.length ||
|
|
|
|
lhs.reduce(reduceFunc.bind(null, rhs), false)) {
|
|
|
|
changed = true;
|
|
|
|
this[field] = rhs.slice();
|
|
|
|
}
|
2013-09-18 14:07:14 +04:00
|
|
|
}
|
2014-03-29 11:18:22 +04:00
|
|
|
|
2013-09-18 14:07:14 +04:00
|
|
|
if (changed) {
|
|
|
|
if (DEBUG) this.debug("Notify for data call minor changes.");
|
|
|
|
Services.obs.notifyObservers(this,
|
|
|
|
kNetworkInterfaceStateChangedTopic,
|
|
|
|
null);
|
|
|
|
}
|
2012-03-13 03:46:08 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-06-22 09:53:12 +04:00
|
|
|
this.state = datacall.state;
|
2012-09-26 16:52:21 +04:00
|
|
|
|
2013-11-22 19:16:31 +04:00
|
|
|
Services.obs.notifyObservers(this,
|
|
|
|
kNetworkInterfaceStateChangedTopic,
|
|
|
|
null);
|
|
|
|
|
2014-01-23 13:05:04 +04:00
|
|
|
if ((this.state == RIL.GECKO_NETWORK_STATE_UNKNOWN ||
|
|
|
|
this.state == RIL.GECKO_NETWORK_STATE_DISCONNECTED) &&
|
2013-07-12 08:44:22 +04:00
|
|
|
this.registeredAsNetworkInterface) {
|
2012-09-26 16:52:21 +04:00
|
|
|
gNetworkManager.unregisterNetworkInterface(this);
|
|
|
|
this.registeredAsNetworkInterface = false;
|
2012-12-14 07:13:31 +04:00
|
|
|
this.cid = null;
|
2013-06-28 05:46:00 +04:00
|
|
|
this.connectedTypes = [];
|
2014-03-29 11:18:22 +04:00
|
|
|
|
|
|
|
this.ips = [];
|
|
|
|
this.prefixLengths = [];
|
|
|
|
this.dnses = [];
|
|
|
|
this.gateways = [];
|
2012-09-26 16:52:21 +04:00
|
|
|
}
|
2014-01-23 13:05:04 +04:00
|
|
|
|
|
|
|
// In case the data setting changed while the datacall was being started or
|
|
|
|
// ended, let's re-check the setting and potentially adjust the datacall
|
|
|
|
// state again.
|
2013-12-03 10:18:32 +04:00
|
|
|
let apnSettings = this.dataConnectionHandler.apnSettings;
|
|
|
|
if (apnSettings.byType.default &&
|
|
|
|
(apnSettings.byType.default.apn == this.apnSetting.apn)) {
|
|
|
|
this.dataConnectionHandler.updateRILNetworkInterface();
|
2014-01-23 13:05:04 +04:00
|
|
|
}
|
2012-03-13 03:46:08 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
// Helpers
|
|
|
|
|
2012-04-20 01:33:25 +04:00
|
|
|
cid: null,
|
|
|
|
registeredAsDataCallCallback: false,
|
|
|
|
registeredAsNetworkInterface: false,
|
|
|
|
connecting: false,
|
2013-08-20 15:31:10 +04:00
|
|
|
apnSetting: null,
|
2012-04-20 01:33:25 +04:00
|
|
|
|
2012-06-02 01:09:59 +04:00
|
|
|
// APN failed connections. Retry counter
|
|
|
|
apnRetryCounter: 0,
|
|
|
|
|
2013-08-20 15:31:10 +04:00
|
|
|
connectedTypes: null,
|
2013-06-28 05:46:00 +04:00
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
inConnectedTypes: function(type) {
|
2013-06-28 05:46:00 +04:00
|
|
|
return this.connectedTypes.indexOf(type) != -1;
|
|
|
|
},
|
|
|
|
|
2012-04-25 00:46:42 +04:00
|
|
|
get connected() {
|
|
|
|
return this.state == RIL.GECKO_NETWORK_STATE_CONNECTED;
|
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
connect: function(apntype) {
|
2013-06-28 05:46:00 +04:00
|
|
|
if (apntype && !this.inConnectedTypes(apntype)) {
|
|
|
|
this.connectedTypes.push(apntype);
|
|
|
|
}
|
|
|
|
|
2012-08-28 18:37:43 +04:00
|
|
|
if (this.connecting || this.connected) {
|
2012-03-13 03:46:08 +04:00
|
|
|
return;
|
|
|
|
}
|
2012-08-01 18:54:04 +04:00
|
|
|
|
2013-06-28 05:46:00 +04:00
|
|
|
// When the retry mechanism is running in background and someone calls
|
|
|
|
// disconnect(), this.connectedTypes.length has chances to become 0.
|
|
|
|
if (!this.connectedTypes.length) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-03-13 03:46:08 +04:00
|
|
|
if (!this.registeredAsDataCallCallback) {
|
2013-12-03 10:18:32 +04:00
|
|
|
this.dataConnectionHandler.registerDataCallCallback(this);
|
2012-03-13 03:46:08 +04:00
|
|
|
this.registeredAsDataCallCallback = true;
|
|
|
|
}
|
|
|
|
|
2013-07-12 08:44:22 +04:00
|
|
|
if (!this.apnSetting.apn) {
|
2013-07-02 13:36:58 +04:00
|
|
|
if (DEBUG) this.debug("APN name is empty, nothing to do.");
|
2012-09-26 16:57:37 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-07-02 13:36:58 +04:00
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("Going to set up data connection with APN " +
|
2013-07-12 08:44:22 +04:00
|
|
|
this.apnSetting.apn);
|
2013-07-02 13:36:58 +04:00
|
|
|
}
|
2013-12-03 10:18:32 +04:00
|
|
|
let radioInterface = this.dataConnectionHandler.radioInterface;
|
|
|
|
let radioTechType = radioInterface.rilContext.data.type;
|
2013-01-24 06:07:17 +04:00
|
|
|
let radioTechnology = RIL.GECKO_RADIO_TECH.indexOf(radioTechType);
|
2013-07-12 08:44:22 +04:00
|
|
|
let authType = RIL.RIL_DATACALL_AUTH_TO_GECKO.indexOf(this.apnSetting.authtype);
|
2013-05-06 12:58:56 +04:00
|
|
|
// Use the default authType if the value in database is invalid.
|
|
|
|
// For the case that user might not select the authentication type.
|
|
|
|
if (authType == -1) {
|
2013-07-02 13:36:58 +04:00
|
|
|
if (DEBUG) {
|
2013-07-12 08:44:22 +04:00
|
|
|
this.debug("Invalid authType " + this.apnSetting.authtype);
|
2013-07-02 13:36:58 +04:00
|
|
|
}
|
2013-05-06 12:58:56 +04:00
|
|
|
authType = RIL.RIL_DATACALL_AUTH_TO_GECKO.indexOf(RIL.GECKO_DATACALL_AUTH_DEFAULT);
|
|
|
|
}
|
2014-03-11 18:17:57 +04:00
|
|
|
let pdpType = RIL.GECKO_DATACALL_PDP_TYPE_IP;
|
|
|
|
if (RILQUIRKS_HAVE_IPV6) {
|
|
|
|
pdpType = !radioInterface.rilContext.data.roaming
|
|
|
|
? this.apnSetting.protocol
|
|
|
|
: this.apnSetting.roaming_protocol;
|
|
|
|
if (RIL.RIL_DATACALL_PDP_TYPES.indexOf(pdpType) < 0) {
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("Invalid pdpType '" + pdpType + "', using '" +
|
|
|
|
RIL.GECKO_DATACALL_PDP_TYPE_DEFAULT + "'");
|
|
|
|
}
|
|
|
|
pdpType = RIL.GECKO_DATACALL_PDP_TYPE_DEFAULT;
|
|
|
|
}
|
|
|
|
}
|
2013-12-03 10:18:32 +04:00
|
|
|
radioInterface.setupDataCall(radioTechnology,
|
|
|
|
this.apnSetting.apn,
|
|
|
|
this.apnSetting.user,
|
|
|
|
this.apnSetting.password,
|
|
|
|
authType,
|
2014-03-11 18:17:57 +04:00
|
|
|
pdpType);
|
2012-03-13 03:46:08 +04:00
|
|
|
this.connecting = true;
|
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
reset: function() {
|
2012-06-02 01:09:59 +04:00
|
|
|
let apnRetryTimer;
|
|
|
|
this.connecting = false;
|
|
|
|
// We will retry the connection in increasing times
|
|
|
|
// based on the function: time = A * numer_of_retries^2 + B
|
|
|
|
if (this.apnRetryCounter >= this.NETWORK_APNRETRY_MAXRETRIES) {
|
|
|
|
this.apnRetryCounter = 0;
|
|
|
|
this.timer = null;
|
2013-06-28 05:46:00 +04:00
|
|
|
this.connectedTypes = [];
|
2013-07-02 13:36:58 +04:00
|
|
|
if (DEBUG) this.debug("Too many APN Connection retries - STOP retrying");
|
2012-06-02 01:09:59 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
apnRetryTimer = this.NETWORK_APNRETRY_FACTOR *
|
|
|
|
(this.apnRetryCounter * this.apnRetryCounter) +
|
|
|
|
this.NETWORK_APNRETRY_ORIGIN;
|
|
|
|
this.apnRetryCounter++;
|
2013-07-02 13:36:58 +04:00
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("Data call - APN Connection Retry Timer (secs-counter): " +
|
|
|
|
apnRetryTimer + "-" + this.apnRetryCounter);
|
|
|
|
}
|
2012-06-02 01:09:59 +04:00
|
|
|
|
|
|
|
if (this.timer == null) {
|
|
|
|
// Event timer for connection retries
|
|
|
|
this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
|
|
|
}
|
|
|
|
this.timer.initWithCallback(this, apnRetryTimer * 1000,
|
|
|
|
Ci.nsITimer.TYPE_ONE_SHOT);
|
|
|
|
},
|
|
|
|
|
2014-01-13 06:44:40 +04:00
|
|
|
disconnect: function(apntype) {
|
2013-06-28 05:46:00 +04:00
|
|
|
let index = this.connectedTypes.indexOf(apntype);
|
|
|
|
if (index != -1) {
|
|
|
|
this.connectedTypes.splice(index, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.connectedTypes.length) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-04-25 00:46:42 +04:00
|
|
|
if (this.state == RIL.GECKO_NETWORK_STATE_DISCONNECTING ||
|
2013-07-12 08:44:22 +04:00
|
|
|
this.state == RIL.GECKO_NETWORK_STATE_DISCONNECTED ||
|
|
|
|
this.state == RIL.GECKO_NETWORK_STATE_UNKNOWN) {
|
2012-04-25 00:46:42 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
let reason = RIL.DATACALL_DEACTIVATE_NO_REASON;
|
2013-07-02 13:36:58 +04:00
|
|
|
if (DEBUG) this.debug("Going to disconnet data connection " + this.cid);
|
2013-12-03 10:18:32 +04:00
|
|
|
this.dataConnectionHandler.radioInterface.deactivateDataCall(this.cid,
|
|
|
|
reason);
|
2012-03-13 03:46:08 +04:00
|
|
|
},
|
|
|
|
|
2012-06-02 01:09:59 +04:00
|
|
|
// Entry method for timer events. Used to reconnect to a failed APN
|
|
|
|
notify: function(timer) {
|
2012-09-26 16:52:21 +04:00
|
|
|
this.connect();
|
2012-06-02 01:09:59 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
shutdown: function() {
|
|
|
|
this.timer = null;
|
|
|
|
}
|
|
|
|
|
2012-03-13 03:46:08 +04:00
|
|
|
};
|
|
|
|
|
2012-10-31 20:13:28 +04:00
|
|
|
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([RadioInterfaceLayer]);
|