2012-07-20 09:10:44 +00: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 07:58:27 +00:00
|
|
|
|
2012-01-09 22:28:47 +00:00
|
|
|
"use strict";
|
|
|
|
|
2011-12-05 07:58:27 +00:00
|
|
|
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
|
|
|
|
|
|
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
2011-12-24 05:02:52 +00:00
|
|
|
Cu.import("resource://gre/modules/Services.jsm");
|
2013-06-22 14:22:05 +00:00
|
|
|
Cu.import("resource://gre/modules/Sntp.jsm");
|
2013-09-30 09:24:54 +00:00
|
|
|
Cu.import("resource://gre/modules/systemlibs.js");
|
2013-11-21 14:09:14 +00:00
|
|
|
Cu.import("resource://gre/modules/Promise.jsm");
|
2011-12-05 07:58:27 +00:00
|
|
|
|
2012-01-09 22:28:47 +00:00
|
|
|
var RIL = {};
|
|
|
|
Cu.import("resource://gre/modules/ril_consts.js", RIL);
|
|
|
|
|
2012-06-19 22:52:06 +00:00
|
|
|
// set to true in ril_consts.js to see debug messages
|
2012-11-14 10:25:35 +00:00
|
|
|
var DEBUG = RIL.DEBUG_RIL;
|
|
|
|
|
|
|
|
// Read debug setting from pref
|
|
|
|
let debugPref = false;
|
|
|
|
try {
|
|
|
|
debugPref = Services.prefs.getBoolPref("ril.debugging.enabled");
|
|
|
|
} catch(e) {
|
|
|
|
debugPref = false;
|
|
|
|
}
|
|
|
|
DEBUG = RIL.DEBUG_RIL || debugPref;
|
2011-12-05 07:58:27 +00:00
|
|
|
|
2013-07-02 09:36:58 +00:00
|
|
|
function debug(s) {
|
|
|
|
dump("-*- RadioInterfaceLayer: " + s + "\n");
|
2013-07-31 08:03:57 +00:00
|
|
|
}
|
2013-06-10 02:41:14 +00:00
|
|
|
|
2013-12-20 20:56:35 +00: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-01-15 14:40:49 +00: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";
|
|
|
|
|
2012-01-19 20:53:32 +00:00
|
|
|
const RADIOINTERFACELAYER_CID =
|
2012-01-09 23:18:23 +00:00
|
|
|
Components.ID("{2d831c8d-6017-435b-a80c-e5d422810cea}");
|
2013-07-02 09:36:37 +00:00
|
|
|
const RADIOINTERFACE_CID =
|
|
|
|
Components.ID("{6a7c91f0-a2b3-4193-8562-8969296c0b54}");
|
2012-09-26 12:52:21 +00:00
|
|
|
const RILNETWORKINTERFACE_CID =
|
|
|
|
Components.ID("{3bdd52a9-3965-4130-b569-0ac5afed045e}");
|
2013-10-15 02:42:49 +00:00
|
|
|
const GSMICCINFO_CID =
|
|
|
|
Components.ID("{d90c4261-a99d-47bc-8b05-b057bb7e8f8a}");
|
|
|
|
const CDMAICCINFO_CID =
|
|
|
|
Components.ID("{39ba3c08-aacc-46d0-8c04-9b619c387061}");
|
2011-12-05 07:58:27 +00:00
|
|
|
|
2013-10-24 08:14:59 +00:00
|
|
|
const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown";
|
2012-04-19 21:33:25 +00:00
|
|
|
const kNetworkInterfaceStateChangedTopic = "network-interface-state-changed";
|
2013-09-07 11:09:54 +00: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-24 20:46:42 +00:00
|
|
|
const kMozSettingsChangedObserverTopic = "mozsettings-changed";
|
2012-09-05 20:00:06 +00:00
|
|
|
const kSysMsgListenerReadyObserverTopic = "system-message-listener-ready";
|
2012-10-23 07:15:53 +00:00
|
|
|
const kSysClockChangeObserverTopic = "system-clock-change";
|
2013-06-06 07:28:59 +00:00
|
|
|
const kScreenStateChangedTopic = "screen-state-changed";
|
2013-10-24 08:14:59 +00: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";
|
|
|
|
const kPrefClirModePreference = "ril.clirMode";
|
2013-10-24 08:15:06 +00:00
|
|
|
const kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces";
|
2012-10-30 10:53:27 +00:00
|
|
|
|
2013-09-07 11:09:54 +00: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 06:19:57 +00:00
|
|
|
const RADIO_POWER_OFF_TIMEOUT = 30000;
|
2013-09-10 13:51:47 +00:00
|
|
|
const SMS_HANDLED_WAKELOCK_TIMEOUT = 5000;
|
2014-01-15 14:40:49 +00:00
|
|
|
const HW_DEFAULT_CLIENT_ID = 0;
|
2012-09-28 05:43:35 +00:00
|
|
|
|
|
|
|
const RIL_IPC_MOBILECONNECTION_MSG_NAMES = [
|
|
|
|
"RIL:GetRilContext",
|
2012-06-01 21:10:39 +00:00
|
|
|
"RIL:GetAvailableNetworks",
|
2012-06-19 22:52:06 +00:00
|
|
|
"RIL:SelectNetwork",
|
|
|
|
"RIL:SelectNetworkAuto",
|
2013-12-11 03:15:03 +00:00
|
|
|
"RIL:SetPreferredNetworkType",
|
|
|
|
"RIL:GetPreferredNetworkType",
|
2012-10-05 14:08:55 +00:00
|
|
|
"RIL:SendMMI",
|
|
|
|
"RIL:CancelMMI",
|
2013-09-07 11:32:23 +00:00
|
|
|
"RIL:RegisterMobileConnectionMsg",
|
2013-10-30 04:04:21 +00:00
|
|
|
"RIL:SetCallForwardingOptions",
|
|
|
|
"RIL:GetCallForwardingOptions",
|
|
|
|
"RIL:SetCallBarringOptions",
|
|
|
|
"RIL:GetCallBarringOptions",
|
2013-08-27 01:59:17 +00:00
|
|
|
"RIL:ChangeCallBarringPassword",
|
2013-10-30 04:04:21 +00:00
|
|
|
"RIL:SetCallWaitingOptions",
|
|
|
|
"RIL:GetCallWaitingOptions",
|
2013-07-17 21:18:29 +00:00
|
|
|
"RIL:SetCallingLineIdRestriction",
|
2013-06-10 07:47:03 +00:00
|
|
|
"RIL:GetCallingLineIdRestriction",
|
|
|
|
"RIL:SetRoamingPreference",
|
2013-08-14 12:50:36 +00:00
|
|
|
"RIL:GetRoamingPreference",
|
2013-08-14 08:22:38 +00:00
|
|
|
"RIL:ExitEmergencyCbMode",
|
2013-11-21 14:09:14 +00:00
|
|
|
"RIL:SetRadioEnabled",
|
2013-08-14 08:22:38 +00:00
|
|
|
"RIL:SetVoicePrivacyMode",
|
2014-01-08 06:10:58 +00:00
|
|
|
"RIL:GetVoicePrivacyMode",
|
|
|
|
"RIL:GetSupportedNetworkTypes"
|
2013-04-09 06:18:43 +00:00
|
|
|
];
|
|
|
|
|
2014-01-08 10:54:34 +00:00
|
|
|
const RIL_IPC_MOBILENETWORK_MSG_NAMES = [
|
|
|
|
"RIL:GetLastKnownNetwork",
|
|
|
|
"RIL:GetLastKnownHomeNetwork"
|
|
|
|
];
|
|
|
|
|
2013-04-09 06:18:43 +00:00
|
|
|
const RIL_IPC_ICCMANAGER_MSG_NAMES = [
|
2012-04-10 12:04:27 +00:00
|
|
|
"RIL:SendStkResponse",
|
2012-09-28 05:43:35 +00:00
|
|
|
"RIL:SendStkMenuSelection",
|
2012-11-28 08:16:20 +00:00
|
|
|
"RIL:SendStkTimerExpiration",
|
2012-09-11 02:34:36 +00:00
|
|
|
"RIL:SendStkEventDownload",
|
2013-04-11 07:12:09 +00: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 14:06:05 +00:00
|
|
|
"RIL:GetCardLockRetryCount",
|
2013-02-25 09:27:26 +00:00
|
|
|
"RIL:IccOpenChannel",
|
|
|
|
"RIL:IccExchangeAPDU",
|
|
|
|
"RIL:IccCloseChannel",
|
2013-03-06 02:51:40 +00:00
|
|
|
"RIL:ReadIccContacts",
|
2013-09-07 11:32:23 +00:00
|
|
|
"RIL:UpdateIccContact",
|
2014-01-27 18:22:00 +00:00
|
|
|
"RIL:RegisterIccMsg",
|
|
|
|
"RIL:MatchMvno"
|
2012-10-09 10:07:11 +00:00
|
|
|
];
|
|
|
|
|
|
|
|
const RIL_IPC_VOICEMAIL_MSG_NAMES = [
|
2013-09-07 11:32:23 +00:00
|
|
|
"RIL:RegisterVoicemailMsg",
|
2012-12-26 10:49:08 +00:00
|
|
|
"RIL:GetVoicemailInfo"
|
2012-04-24 15:44:42 +00:00
|
|
|
];
|
|
|
|
|
2013-09-07 11:32:23 +00:00
|
|
|
const RIL_IPC_CELLBROADCAST_MSG_NAMES = [
|
|
|
|
"RIL:RegisterCellBroadcastMsg"
|
|
|
|
];
|
|
|
|
|
2013-09-07 11:09:54 +00:00
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "gPowerManagerService",
|
|
|
|
"@mozilla.org/power/powermanagerservice;1",
|
|
|
|
"nsIPowerManagerService");
|
|
|
|
|
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "gMobileMessageService",
|
|
|
|
"@mozilla.org/mobilemessage/mobilemessageservice;1",
|
|
|
|
"nsIMobileMessageService");
|
|
|
|
|
2013-07-29 22:50:22 +00:00
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "gSmsService",
|
2013-09-07 11:09:54 +00:00
|
|
|
"@mozilla.org/sms/smsservice;1",
|
|
|
|
"nsISmsService");
|
|
|
|
|
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "gMobileMessageDatabaseService",
|
|
|
|
"@mozilla.org/mobilemessage/rilmobilemessagedatabaseservice;1",
|
|
|
|
"nsIRilMobileMessageDatabaseService");
|
2013-09-06 21:28:10 +00:00
|
|
|
|
2013-09-07 11:32:23 +00:00
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
|
|
|
|
"@mozilla.org/parentprocessmessagemanager;1",
|
|
|
|
"nsIMessageBroadcaster");
|
|
|
|
|
2012-05-24 05:12:07 +00:00
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService",
|
|
|
|
"@mozilla.org/settingsService;1",
|
|
|
|
"nsISettingsService");
|
|
|
|
|
2012-08-31 14:45:32 +00:00
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger",
|
|
|
|
"@mozilla.org/system-message-internal;1",
|
|
|
|
"nsISystemMessagesInternal");
|
|
|
|
|
2012-09-26 12:52:21 +00:00
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager",
|
|
|
|
"@mozilla.org/network/manager;1",
|
|
|
|
"nsINetworkManager");
|
|
|
|
|
2012-09-28 06:02:57 +00:00
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "gTimeService",
|
|
|
|
"@mozilla.org/time/timeservice;1",
|
|
|
|
"nsITimeService");
|
|
|
|
|
2013-01-24 06:42:07 +00:00
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "gSystemWorkerManager",
|
|
|
|
"@mozilla.org/telephony/system-worker-manager;1",
|
|
|
|
"nsISystemWorkerManager");
|
|
|
|
|
2013-09-07 06:19:57 +00:00
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "gTelephonyProvider",
|
|
|
|
"@mozilla.org/telephony/telephonyprovider;1",
|
|
|
|
"nsIGonkTelephonyProvider");
|
|
|
|
|
2014-01-13 02:44:33 +00:00
|
|
|
XPCOMUtils.defineLazyGetter(this, "WAP", function() {
|
2013-09-07 11:09:54 +00:00
|
|
|
let wap = {};
|
|
|
|
Cu.import("resource://gre/modules/WapPushManager.js", wap);
|
|
|
|
return wap;
|
|
|
|
});
|
|
|
|
|
2014-01-13 02:44:33 +00:00
|
|
|
XPCOMUtils.defineLazyGetter(this, "PhoneNumberUtils", function() {
|
2013-09-07 11:09:54 +00:00
|
|
|
let ns = {};
|
|
|
|
Cu.import("resource://gre/modules/PhoneNumberUtils.jsm", ns);
|
|
|
|
return ns.PhoneNumberUtils;
|
|
|
|
});
|
|
|
|
|
2014-01-13 02:44:33 +00:00
|
|
|
XPCOMUtils.defineLazyGetter(this, "gMessageManager", function() {
|
2013-09-07 11:32:23 +00: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 02:44:40 +00:00
|
|
|
init: function(ril) {
|
2013-09-07 11:32:23 +00:00
|
|
|
this.ril = ril;
|
|
|
|
|
2013-10-24 08:14:59 +00:00
|
|
|
Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
|
2013-09-07 11:32:23 +00:00
|
|
|
Services.obs.addObserver(this, kSysMsgListenerReadyObserverTopic, false);
|
|
|
|
this._registerMessageListeners();
|
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
_shutdown: function() {
|
2013-09-07 11:32:23 +00:00
|
|
|
this.ril = null;
|
|
|
|
|
2013-10-24 08:14:59 +00:00
|
|
|
Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
|
2013-09-07 11:32:23 +00:00
|
|
|
this._unregisterMessageListeners();
|
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
_registerMessageListeners: function() {
|
2013-09-07 11:32:23 +00:00
|
|
|
ppmm.addMessageListener("child-process-shutdown", this);
|
|
|
|
for (let msgname of RIL_IPC_MOBILECONNECTION_MSG_NAMES) {
|
|
|
|
ppmm.addMessageListener(msgname, this);
|
|
|
|
}
|
2014-01-08 10:54:34 +00:00
|
|
|
for (let msgname of RIL_IPC_MOBILENETWORK_MSG_NAMES) {
|
|
|
|
ppmm.addMessageListener(msgname, this);
|
|
|
|
}
|
2013-09-07 11:32:23 +00: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 02:44:40 +00:00
|
|
|
_unregisterMessageListeners: function() {
|
2013-09-07 11:32:23 +00:00
|
|
|
ppmm.removeMessageListener("child-process-shutdown", this);
|
|
|
|
for (let msgname of RIL_IPC_MOBILECONNECTION_MSG_NAMES) {
|
|
|
|
ppmm.removeMessageListener(msgname, this);
|
|
|
|
}
|
2014-01-08 10:54:34 +00:00
|
|
|
for (let msgname of RIL_IPC_MOBILENETWORK_MSG_NAMES) {
|
|
|
|
ppmm.removeMessageListener(msgname, this);
|
|
|
|
}
|
2013-09-07 11:32:23 +00: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 02:44:40 +00:00
|
|
|
_registerMessageTarget: function(topic, target) {
|
2013-09-07 11:32:23 +00: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 02:44:40 +00:00
|
|
|
_unregisterMessageTarget: function(topic, target) {
|
2013-09-07 11:32:23 +00: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 02:44:40 +00:00
|
|
|
_enqueueTargetMessage: function(topic, message, options) {
|
2013-09-07 11:32:23 +00:00
|
|
|
let msg = { topic : topic,
|
|
|
|
message : message,
|
|
|
|
options : options };
|
2013-11-28 10:10:38 +00: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 11:32:23 +00:00
|
|
|
let messageQueue = this.targetMessageQueue;
|
|
|
|
for(let i = 0; i < messageQueue.length; i++) {
|
2013-11-28 10:10:38 +00:00
|
|
|
if (messageQueue[i].message === message &&
|
|
|
|
messageQueue[i].options.clientId === options.clientId) {
|
2013-09-07 11:32:23 +00:00
|
|
|
messageQueue.splice(i, 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
messageQueue.push(msg);
|
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
_sendTargetMessage: function(topic, message, options) {
|
2013-09-07 11:32:23 +00: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 02:44:40 +00:00
|
|
|
_resendQueuedTargetMessage: function() {
|
2013-09-07 11:32:23 +00: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 02:44:40 +00:00
|
|
|
receiveMessage: function(msg) {
|
2013-09-07 11:32:23 +00: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-13 22:12:30 +00:00
|
|
|
return null;
|
2013-09-07 11:32:23 +00: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 10:54:34 +00: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 11:32:23 +00: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-13 22:12:30 +00:00
|
|
|
return null;
|
2013-09-07 11:32:23 +00:00
|
|
|
case "RIL:RegisterIccMsg":
|
|
|
|
this._registerMessageTarget("icc", msg.target);
|
2013-09-13 22:12:30 +00:00
|
|
|
return null;
|
2013-09-07 11:32:23 +00:00
|
|
|
case "RIL:RegisterVoicemailMsg":
|
|
|
|
this._registerMessageTarget("voicemail", msg.target);
|
2013-09-13 22:12:30 +00:00
|
|
|
return null;
|
2013-09-07 11:32:23 +00:00
|
|
|
case "RIL:RegisterCellBroadcastMsg":
|
|
|
|
this._registerMessageTarget("cellbroadcast", msg.target);
|
2013-09-13 22:12:30 +00:00
|
|
|
return null;
|
2013-09-07 11:32:23 +00: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 14:09:14 +00:00
|
|
|
if (msg.name === "RIL:SetRadioEnabled") {
|
|
|
|
// Special handler for SetRadioEnabled.
|
|
|
|
return gRadioEnabledController.receiveMessage(msg);
|
|
|
|
}
|
|
|
|
|
2013-09-07 11:32:23 +00:00
|
|
|
return radioInterface.receiveMessage(msg);
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nsIObserver interface methods.
|
|
|
|
*/
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
observe: function(subject, topic, data) {
|
2013-09-07 11:32:23 +00:00
|
|
|
switch (topic) {
|
|
|
|
case kSysMsgListenerReadyObserverTopic:
|
|
|
|
Services.obs.removeObserver(this, kSysMsgListenerReadyObserverTopic);
|
|
|
|
this._resendQueuedTargetMessage();
|
|
|
|
break;
|
2013-10-24 08:14:59 +00:00
|
|
|
case NS_XPCOM_SHUTDOWN_OBSERVER_ID:
|
2013-09-07 11:32:23 +00:00
|
|
|
this._shutdown();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
sendMobileConnectionMessage: function(message, clientId, data) {
|
2013-09-07 11:32:23 +00:00
|
|
|
this._sendTargetMessage("mobileconnection", message, {
|
|
|
|
clientId: clientId,
|
|
|
|
data: data
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
sendVoicemailMessage: function(message, clientId, data) {
|
2013-09-07 11:32:23 +00:00
|
|
|
this._sendTargetMessage("voicemail", message, {
|
|
|
|
clientId: clientId,
|
|
|
|
data: data
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
sendCellBroadcastMessage: function(message, clientId, data) {
|
2013-09-07 11:32:23 +00:00
|
|
|
this._sendTargetMessage("cellbroadcast", message, {
|
|
|
|
clientId: clientId,
|
|
|
|
data: data
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
sendIccMessage: function(message, clientId, data) {
|
2013-09-07 11:32:23 +00:00
|
|
|
this._sendTargetMessage("icc", message, {
|
|
|
|
clientId: clientId,
|
|
|
|
data: data
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
2013-07-02 09:36:40 +00:00
|
|
|
});
|
2011-12-05 07:58:27 +00:00
|
|
|
|
2014-01-13 02:44:33 +00:00
|
|
|
XPCOMUtils.defineLazyGetter(this, "gRadioEnabledController", function() {
|
2013-11-21 14:09:14 +00:00
|
|
|
return {
|
|
|
|
ril: null,
|
|
|
|
pendingMessages: [], // For queueing "RIL:SetRadioEnabled" messages.
|
|
|
|
timer: null,
|
|
|
|
request: null,
|
|
|
|
deactivatingDeferred: {},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
init: function(ril) {
|
2013-11-21 14:09:14 +00:00
|
|
|
this.ril = ril;
|
|
|
|
},
|
|
|
|
|
|
|
|
receiveMessage: function(msg) {
|
|
|
|
if (DEBUG) debug("setRadioEnabled: receiveMessage: " + JSON.stringify(msg));
|
|
|
|
this.pendingMessages.push(msg);
|
2013-12-13 16:46:23 +00:00
|
|
|
if (this.pendingMessages.length === 1 && !this.isDeactivatingDataCalls()) {
|
2013-11-21 14:09:14 +00:00
|
|
|
this._processNextMessage();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
isDeactivatingDataCalls: function() {
|
|
|
|
return this.request !== null;
|
|
|
|
},
|
|
|
|
|
|
|
|
finishDeactivatingDataCalls: function(clientId) {
|
|
|
|
if (DEBUG) debug("setRadioEnabled: finishDeactivatingDataCalls: " + clientId);
|
|
|
|
let deferred = this.deactivatingDeferred[clientId];
|
|
|
|
if (deferred) {
|
|
|
|
deferred.resolve();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
_processNextMessage: function() {
|
|
|
|
if (this.pendingMessages.length === 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let msg = this.pendingMessages.shift();
|
|
|
|
this._handleMessage(msg);
|
|
|
|
},
|
|
|
|
|
2014-01-15 14:40:49 +00:00
|
|
|
_getNumCards: function() {
|
|
|
|
let numCards = 0;
|
|
|
|
for (let i = 0, N = this.ril.numRadioInterfaces; i < N; ++i) {
|
|
|
|
if (this._isCardPresentAtClient(i)) {
|
|
|
|
numCards++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return numCards;
|
|
|
|
},
|
|
|
|
|
|
|
|
_isCardPresentAtClient: function(clientId) {
|
|
|
|
let cardState = this.ril.getRadioInterface(clientId).rilContext.cardState;
|
|
|
|
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 14:09:14 +00:00
|
|
|
_handleMessage: function(msg) {
|
|
|
|
if (DEBUG) debug("setRadioEnabled: handleMessage: " + JSON.stringify(msg));
|
2014-01-15 14:40:49 +00:00
|
|
|
let clientId = msg.json.clientId || 0;
|
|
|
|
let radioInterface = this.ril.getRadioInterface(clientId);
|
2013-11-21 14:09:14 +00: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 14:40:49 +00: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 14:09:14 +00:00
|
|
|
this._processNextMessage();
|
|
|
|
} else {
|
|
|
|
this.request = (function() {
|
|
|
|
radioInterface.receiveMessage(msg);
|
|
|
|
}).bind(this);
|
|
|
|
|
|
|
|
// 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(() => {
|
|
|
|
if (DEBUG) debug("setRadioEnabled: deactivation done");
|
|
|
|
this._executeRequest();
|
|
|
|
});
|
|
|
|
|
|
|
|
this._createTimer();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
_deactivateDataCalls: function() {
|
|
|
|
if (DEBUG) debug("setRadioEnabled: deactivating data calls...");
|
|
|
|
this.deactivatingDeferred = {};
|
|
|
|
|
|
|
|
let promise = Promise.resolve();
|
|
|
|
for (let i = 0, N = this.ril.numRadioInterfaces; i < N; ++i) {
|
|
|
|
promise = promise.then(this._deactivateDataCallsForClient(i));
|
|
|
|
}
|
|
|
|
|
|
|
|
return promise;
|
|
|
|
},
|
|
|
|
|
|
|
|
_deactivateDataCallsForClient: function(clientId) {
|
|
|
|
return (function() {
|
|
|
|
let deferred = this.deactivatingDeferred[clientId] = Promise.defer();
|
|
|
|
this.ril.getRadioInterface(clientId).deactivateDataCalls();
|
|
|
|
return deferred.promise;
|
|
|
|
}).bind(this);
|
|
|
|
},
|
|
|
|
|
|
|
|
_createTimer: function() {
|
|
|
|
if (!this.timer) {
|
|
|
|
this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
|
|
|
}
|
|
|
|
this.timer.initWithCallback(this._executeRequest, RADIO_POWER_OFF_TIMEOUT,
|
|
|
|
Ci.nsITimer.TYPE_ONE_SHOT);
|
|
|
|
},
|
|
|
|
|
|
|
|
_cancelTimer: function() {
|
|
|
|
if (this.timer) {
|
|
|
|
this.timer.cancel();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
_executeRequest: function() {
|
|
|
|
if (typeof this.request === "function") {
|
|
|
|
if (DEBUG) debug("setRadioEnabled: executeRequest");
|
|
|
|
this._cancelTimer();
|
|
|
|
this.request();
|
|
|
|
this.request = null;
|
|
|
|
}
|
2013-12-13 16:46:23 +00:00
|
|
|
this._processNextMessage();
|
2014-01-15 14:40:49 +00:00
|
|
|
},
|
2013-11-21 14:09:14 +00:00
|
|
|
};
|
|
|
|
});
|
|
|
|
|
2013-08-22 09:18:13 +00:00
|
|
|
XPCOMUtils.defineLazyGetter(this, "gDataConnectionManager", function () {
|
|
|
|
return {
|
|
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
|
|
|
|
|
|
|
|
_connectionHandlers: null,
|
|
|
|
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
|
|
|
Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
|
|
|
|
},
|
|
|
|
|
|
|
|
getConnectionHandler: function(clientId) {
|
|
|
|
return this._connectionHandlers[clientId];
|
|
|
|
},
|
|
|
|
|
|
|
|
_shutdown: function() {
|
|
|
|
for (let handler of this._connectionHandlers) {
|
|
|
|
handler.shutdown();
|
|
|
|
}
|
|
|
|
this._connectionHandlers = null;
|
|
|
|
Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nsIObserver interface methods.
|
|
|
|
*/
|
|
|
|
observe: function(subject, topic, data) {
|
|
|
|
switch (topic) {
|
|
|
|
case NS_XPCOM_SHUTDOWN_OBSERVER_ID:
|
|
|
|
this._shutdown();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
};
|
|
|
|
});
|
|
|
|
|
2013-11-21 14:09:14 +00:00
|
|
|
// Initialize shared preference "ril.numRadioInterfaces" according to system
|
2013-10-24 08:15:06 +00:00
|
|
|
// property.
|
|
|
|
try {
|
2014-01-13 02:44:33 +00:00
|
|
|
Services.prefs.setIntPref(kPrefRilNumRadioInterfaces, (function() {
|
2013-10-24 08:15:06 +00:00
|
|
|
// 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) {}
|
|
|
|
|
2013-10-15 02:42:49 +00:00
|
|
|
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
|
|
|
|
|
2013-11-04 08:39:27 +00:00
|
|
|
mdn: null
|
2013-10-15 02:42:49 +00:00
|
|
|
};
|
|
|
|
|
2013-08-22 09:18:13 +00:00
|
|
|
function DataConnectionHandler(clientId, radioInterface) {
|
|
|
|
// Initial owning attributes.
|
|
|
|
this.clientId = clientId;
|
|
|
|
this.radioInterface = radioInterface;
|
|
|
|
}
|
|
|
|
DataConnectionHandler.prototype = {
|
|
|
|
clientId: 0,
|
|
|
|
radioInterface: null,
|
|
|
|
|
|
|
|
debug: function(s) {
|
|
|
|
dump("-*- DataConnectionHandler[" + this.clientId + "]: " + s + "\n");
|
|
|
|
},
|
|
|
|
|
|
|
|
shutdown: function() {
|
|
|
|
this.clientId = null;
|
|
|
|
this.radioInterface = null;
|
|
|
|
},
|
|
|
|
};
|
2013-07-02 09:36:40 +00:00
|
|
|
|
2013-08-22 09:18:13 +00:00
|
|
|
function RadioInterfaceLayer() {
|
2013-07-02 09:36:37 +00:00
|
|
|
let options = {
|
|
|
|
debug: debugPref,
|
2013-07-31 07:56:43 +00:00
|
|
|
cellBroadcastDisabled: false,
|
2014-01-13 18:16:05 +00:00
|
|
|
clirMode: RIL.CLIR_DEFAULT,
|
|
|
|
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",
|
|
|
|
dataRegistrationOnDemand:
|
|
|
|
libcutils.property_get("ro.moz.ril.data_reg_on_demand", "false") == "true"
|
|
|
|
},
|
|
|
|
rilEmergencyNumbers: libcutils.property_get("ril.ecclist") ||
|
|
|
|
libcutils.property_get("ro.ril.ecclist")
|
2013-07-02 09:36:37 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
try {
|
|
|
|
options.cellBroadcastDisabled =
|
2013-10-24 08:14:59 +00:00
|
|
|
Services.prefs.getBoolPref(kPrefCellBroadcastDisabled);
|
2013-07-02 09:36:37 +00:00
|
|
|
} catch(e) {}
|
|
|
|
|
2013-07-31 07:56:43 +00:00
|
|
|
try {
|
2013-10-24 08:14:59 +00:00
|
|
|
options.clirMode = Services.prefs.getIntPref(kPrefClirModePreference);
|
2013-07-31 07:56:43 +00:00
|
|
|
} catch(e) {}
|
|
|
|
|
2013-07-02 09:36:37 +00:00
|
|
|
let numIfaces = this.numRadioInterfaces;
|
2014-01-23 08:44:20 +00:00
|
|
|
if (DEBUG) debug(numIfaces + " interfaces");
|
2013-07-02 09:36:37 +00:00
|
|
|
this.radioInterfaces = [];
|
|
|
|
for (let clientId = 0; clientId < numIfaces; clientId++) {
|
|
|
|
options.clientId = clientId;
|
|
|
|
this.radioInterfaces.push(new RadioInterface(options));
|
|
|
|
}
|
2013-12-20 20:56:35 +00:00
|
|
|
|
|
|
|
// TODO: Move 'ril.data.*' settings handler to DataConnectionManager,
|
|
|
|
// see bug 905568.
|
|
|
|
let lock = gSettingsService.createLock();
|
|
|
|
// Read the data enabled setting from DB.
|
|
|
|
lock.get("ril.data.enabled", this);
|
|
|
|
// Read the default client id for data call.
|
|
|
|
lock.get("ril.data.defaultServiceId", this);
|
|
|
|
|
|
|
|
Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
|
|
|
|
Services.obs.addObserver(this, kMozSettingsChangedObserverTopic, false);
|
|
|
|
Services.obs.addObserver(this, kNetworkInterfaceStateChangedTopic, false);
|
2013-08-22 09:18:13 +00:00
|
|
|
|
|
|
|
gMessageManager.init(this);
|
|
|
|
gRadioEnabledController.init(this);
|
|
|
|
gDataConnectionManager.init(this);
|
2013-07-02 09:36:37 +00:00
|
|
|
}
|
|
|
|
RadioInterfaceLayer.prototype = {
|
|
|
|
|
|
|
|
classID: RADIOINTERFACELAYER_CID,
|
|
|
|
classInfo: XPCOMUtils.generateCI({classID: RADIOINTERFACELAYER_CID,
|
|
|
|
classDescription: "RadioInterfaceLayer",
|
|
|
|
interfaces: [Ci.nsIRadioInterfaceLayer]}),
|
|
|
|
|
|
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIRadioInterfaceLayer,
|
|
|
|
Ci.nsIObserver]),
|
|
|
|
|
2013-12-20 20:56:35 +00: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: null,
|
|
|
|
|
|
|
|
// 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-07-02 09:36:37 +00:00
|
|
|
/**
|
|
|
|
* nsIObserver interface methods.
|
|
|
|
*/
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
observe: function(subject, topic, data) {
|
2013-12-20 20:56:35 +00:00
|
|
|
switch (topic) {
|
|
|
|
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 oldRadioInterface =
|
|
|
|
this.radioInterfaces[this._currentDataClientId];
|
2014-01-29 13:20:26 +00:00
|
|
|
if (oldRadioInterface.allDataDisconnected() &&
|
2013-12-20 20:56:35 +00:00
|
|
|
typeof this._pendingDataCallRequest === "function") {
|
2013-12-20 20:56:35 +00:00
|
|
|
if (RILQUIRKS_DATA_REGISTRATION_ON_DEMAND) {
|
|
|
|
oldRadioInterface.setDataRegistration(false);
|
|
|
|
}
|
2013-12-20 20:56:35 +00:00
|
|
|
if (DEBUG) debug("All data calls disconnected, setup pending data call.");
|
|
|
|
this._pendingDataCallRequest();
|
|
|
|
this._pendingDataCallRequest = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case NS_XPCOM_SHUTDOWN_OBSERVER_ID:
|
|
|
|
Services.obs.removeObserver(this, TOPIC_XPCOM_SHUTDOWN);
|
|
|
|
Services.obs.removeObserver(this, kMozSettingsChangedObserverTopic);
|
|
|
|
Services.obs.removeObserver(this, kNetworkInterfaceStateChangedTopic);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
// nsISettingsServiceCallback
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
handle: function(name, result) {
|
2013-12-20 20:56:35 +00:00
|
|
|
switch(name) {
|
|
|
|
// TODO: Move 'ril.data.*' settings handler to DataConnectionManager,
|
|
|
|
// see bug 905568.
|
|
|
|
case "ril.data.enabled":
|
|
|
|
if (DEBUG) debug("'ril.data.enabled' is now " + result);
|
|
|
|
if (this._dataEnabled == result) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
this._dataEnabled = result;
|
|
|
|
|
|
|
|
if (DEBUG) 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 radioInterface = this.radioInterfaces[this._dataDefaultClientId];
|
|
|
|
radioInterface.dataCallSettings.oldEnabled = radioInterface.dataCallSettings.enabled;
|
|
|
|
radioInterface.dataCallSettings.enabled = result;
|
|
|
|
radioInterface.updateRILNetworkInterface();
|
|
|
|
break;
|
|
|
|
case "ril.data.defaultServiceId":
|
|
|
|
result = result ? result : 0;
|
|
|
|
if (DEBUG) debug("'ril.data.defaultServiceId' is now " + result);
|
|
|
|
if (this._dataDefaultClientId == result) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
this._dataDefaultClientId = result;
|
|
|
|
this.handleDataClientIdChange();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
handleError: function(errorMessage) {
|
2013-12-20 20:56:35 +00:00
|
|
|
if (DEBUG) {
|
|
|
|
debug("There was an error while reading RIL settings: " + errorMessage);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
handleDataClientIdChange: function() {
|
2013-12-20 20:56:35 +00:00
|
|
|
if (this._currentDataClientId == -1) {
|
|
|
|
// This is to handle boot up stage.
|
|
|
|
this._currentDataClientId = this._dataDefaultClientId;
|
2013-12-20 20:56:35 +00:00
|
|
|
if (RILQUIRKS_DATA_REGISTRATION_ON_DEMAND) {
|
|
|
|
let radioInterface = this.radioInterfaces[this._currentDataClientId];
|
|
|
|
radioInterface.setDataRegistration(true);
|
|
|
|
}
|
2013-12-20 20:56:35 +00:00
|
|
|
if (this._dataEnabled) {
|
|
|
|
let radioInterface = this.radioInterfaces[this._currentDataClientId];
|
|
|
|
radioInterface.dataCallSettings.oldEnabled =
|
|
|
|
radioInterface.dataCallSettings.enabled;
|
|
|
|
radioInterface.dataCallSettings.enabled = true;
|
|
|
|
radioInterface.updateRILNetworkInterface();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!this._dataEnabled) {
|
2013-12-20 20:56:35 +00:00
|
|
|
if (RILQUIRKS_DATA_REGISTRATION_ON_DEMAND) {
|
|
|
|
let oldRadioInterface = this.radioInterfaces[this._currentDataClientId];
|
|
|
|
let newRadioInterface = this.radioInterfaces[this._dataDefaultClientId];
|
|
|
|
oldRadioInterface.setDataRegistration(false);
|
|
|
|
newRadioInterface.setDataRegistration(true);
|
|
|
|
}
|
2013-12-20 20:56:35 +00:00
|
|
|
this._currentDataClientId = this._dataDefaultClientId;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let oldRadioInterface = this.radioInterfaces[this._currentDataClientId];
|
|
|
|
oldRadioInterface.dataCallSettings.oldEnabled =
|
|
|
|
oldRadioInterface.dataCallSettings.enabled;
|
|
|
|
oldRadioInterface.dataCallSettings.enabled = false;
|
|
|
|
|
|
|
|
if (oldRadioInterface.anyDataConnected()) {
|
2014-01-13 02:44:33 +00:00
|
|
|
this._pendingDataCallRequest = function() {
|
2013-12-20 20:56:35 +00:00
|
|
|
if (DEBUG) debug("Executing pending data call request.");
|
|
|
|
let newRadioInterface = this.radioInterfaces[this._dataDefaultClientId];
|
2013-12-20 20:56:35 +00:00
|
|
|
if (RILQUIRKS_DATA_REGISTRATION_ON_DEMAND) {
|
|
|
|
newRadioInterface.setDataRegistration(true);
|
|
|
|
}
|
2013-12-20 20:56:35 +00:00
|
|
|
newRadioInterface.dataCallSettings.oldEnabled =
|
|
|
|
newRadioInterface.dataCallSettings.enabled;
|
|
|
|
newRadioInterface.dataCallSettings.enabled = this._dataEnabled;
|
|
|
|
|
|
|
|
this._currentDataClientId = this._dataDefaultClientId;
|
|
|
|
newRadioInterface.updateRILNetworkInterface();
|
|
|
|
};
|
|
|
|
|
|
|
|
if (DEBUG) {
|
|
|
|
debug("handleDataClientIdChange: existing data call(s) active,"
|
|
|
|
+ " wait for them to get disconnected.");
|
|
|
|
}
|
|
|
|
oldRadioInterface.deactivateDataCalls();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let newRadioInterface = this.radioInterfaces[this._dataDefaultClientId];
|
|
|
|
newRadioInterface.dataCallSettings.oldEnabled =
|
|
|
|
newRadioInterface.dataCallSettings.enabled;
|
|
|
|
newRadioInterface.dataCallSettings.enabled = true;
|
|
|
|
|
|
|
|
this._currentDataClientId = this._dataDefaultClientId;
|
2013-12-20 20:56:35 +00:00
|
|
|
if (RILQUIRKS_DATA_REGISTRATION_ON_DEMAND) {
|
|
|
|
oldRadioInterface.setDataRegistration(false);
|
|
|
|
newRadioInterface.setDataRegistration(true);
|
|
|
|
}
|
2013-12-20 20:56:35 +00:00
|
|
|
newRadioInterface.updateRILNetworkInterface();
|
2013-07-02 09:36:37 +00:00
|
|
|
},
|
2013-06-07 07:32:20 +00:00
|
|
|
|
2013-07-02 09:36:37 +00:00
|
|
|
/**
|
|
|
|
* nsIRadioInterfaceLayer interface methods.
|
|
|
|
*/
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
getRadioInterface: function(clientId) {
|
2013-07-02 09:36:37 +00:00
|
|
|
return this.radioInterfaces[clientId];
|
2013-11-02 10:17:35 +00:00
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
getClientIdByIccId: function(iccId) {
|
2013-11-02 10:17:35 +00:00
|
|
|
if (!iccId) {
|
|
|
|
throw Cr.NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let clientId = 0; clientId < this.numRadioInterfaces; clientId++) {
|
|
|
|
let radioInterface = this.radioInterfaces[clientId];
|
|
|
|
if (radioInterface.rilContext.iccInfo.iccid == iccId) {
|
|
|
|
return clientId;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
throw Cr.NS_ERROR_NOT_AVAILABLE;
|
2013-11-27 07:45:31 +00:00
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
setMicrophoneMuted: function(muted) {
|
2013-11-27 07:45:31 +00:00
|
|
|
for (let clientId = 0; clientId < this.numRadioInterfaces; clientId++) {
|
|
|
|
let radioInterface = this.radioInterfaces[clientId];
|
|
|
|
radioInterface.workerMessenger.send("setMute", { muted: muted });
|
|
|
|
}
|
2013-07-02 09:36:37 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
XPCOMUtils.defineLazyGetter(RadioInterfaceLayer.prototype,
|
2014-01-13 02:44:33 +00:00
|
|
|
"numRadioInterfaces", function() {
|
2013-07-02 09:36:37 +00:00
|
|
|
try {
|
2013-10-24 08:15:06 +00:00
|
|
|
return Services.prefs.getIntPref(kPrefRilNumRadioInterfaces);
|
|
|
|
} catch(e) {}
|
2013-09-30 09:24:54 +00:00
|
|
|
|
|
|
|
return 1;
|
2013-07-02 09:36:37 +00:00
|
|
|
});
|
|
|
|
|
2013-08-13 12:14:10 +00:00
|
|
|
function WorkerMessenger(radioInterface, options) {
|
|
|
|
// Initial owning attributes.
|
|
|
|
this.radioInterface = radioInterface;
|
|
|
|
this.tokenCallbackMap = {};
|
|
|
|
|
|
|
|
// Add a convenient alias to |radioInterface.debug()|.
|
|
|
|
this.debug = radioInterface.debug.bind(radioInterface);
|
|
|
|
|
|
|
|
if (DEBUG) this.debug("Starting RIL Worker[" + options.clientId + "]");
|
|
|
|
this.worker = new ChromeWorker("resource://gre/modules/ril_worker.js");
|
|
|
|
this.worker.onerror = this.onerror.bind(this);
|
|
|
|
this.worker.onmessage = this.onmessage.bind(this);
|
|
|
|
|
|
|
|
this.send("setInitialOptions", options);
|
|
|
|
|
|
|
|
gSystemWorkerManager.registerRilWorker(options.clientId, this.worker);
|
|
|
|
}
|
|
|
|
WorkerMessenger.prototype = {
|
|
|
|
radioInterface: null,
|
|
|
|
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-01-13 02:44:40 +00:00
|
|
|
onerror: function(event) {
|
2013-08-13 12:14:10 +00:00
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("Got an error: " + event.filename + ":" +
|
|
|
|
event.lineno + ": " + event.message + "\n");
|
|
|
|
}
|
|
|
|
event.preventDefault();
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Process the incoming message from the RIL worker.
|
|
|
|
*/
|
2014-01-13 02:44:40 +00:00
|
|
|
onmessage: function(event) {
|
2013-08-13 12:14:10 +00:00
|
|
|
let message = event.data;
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("Received message from worker: " + JSON.stringify(message));
|
|
|
|
}
|
|
|
|
|
|
|
|
let token = message.rilMessageToken;
|
|
|
|
if (token == null) {
|
|
|
|
// That's an unsolicited message. Pass to RadioInterface directly.
|
|
|
|
this.radioInterface.handleUnsolicitedWorkerMessage(message);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let callback = this.tokenCallbackMap[message.rilMessageToken];
|
|
|
|
if (!callback) {
|
|
|
|
if (DEBUG) this.debug("Ignore orphan token: " + message.rilMessageToken);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let keep = false;
|
|
|
|
try {
|
|
|
|
keep = callback(message);
|
|
|
|
} catch(e) {
|
|
|
|
if (DEBUG) this.debug("callback throws an exception: " + e);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!keep) {
|
|
|
|
delete this.tokenCallbackMap[message.rilMessageToken];
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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 14:09:14 +00:00
|
|
|
* with an message containing a "rilMessageToken" attribute of the
|
2013-08-13 12:14:10 +00: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-01-13 02:44:40 +00:00
|
|
|
send: function(rilMessageType, message, callback) {
|
2013-08-13 12:14:10 +00:00
|
|
|
message = message || {};
|
|
|
|
|
|
|
|
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 14:09:14 +00:00
|
|
|
* A text string for ipc message type. "msg.name" if omitted.
|
2013-08-13 12:14:10 +00:00
|
|
|
*
|
|
|
|
* @TODO: Bug 815526 - deprecate RILContentHelper.
|
|
|
|
*/
|
2014-01-13 02:44:40 +00:00
|
|
|
sendWithIPCMessage: function(msg, rilMessageType, ipcType) {
|
2013-09-30 00:56:00 +00:00
|
|
|
this.send(rilMessageType, msg.json.data, (function(reply) {
|
2013-08-13 12:14:10 +00:00
|
|
|
ipcType = ipcType || msg.name;
|
2013-09-30 00:56:00 +00:00
|
|
|
msg.target.sendAsyncMessage(ipcType, {
|
|
|
|
clientId: this.radioInterface.clientId,
|
|
|
|
data: reply
|
|
|
|
});
|
2013-08-13 12:14:10 +00:00
|
|
|
return false;
|
2013-09-30 00:56:00 +00:00
|
|
|
}).bind(this));
|
2013-08-13 12:14:10 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-07-02 09:36:37 +00:00
|
|
|
function RadioInterface(options) {
|
|
|
|
this.clientId = options.clientId;
|
2013-08-13 12:14:10 +00:00
|
|
|
this.workerMessenger = new WorkerMessenger(this, options);
|
2013-07-02 09:36:37 +00:00
|
|
|
|
2013-07-12 04:44:22 +00:00
|
|
|
this.dataCallSettings = {
|
|
|
|
oldEnabled: false,
|
|
|
|
enabled: false,
|
|
|
|
roamingEnabled: false
|
|
|
|
};
|
|
|
|
|
2013-11-02 10:17:45 +00:00
|
|
|
// 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.
|
2013-07-12 04:44:22 +00:00
|
|
|
this.apnSettings = {
|
2013-11-02 10:17:45 +00:00
|
|
|
byType: {},
|
|
|
|
byApn: {}
|
2013-07-12 04:44:22 +00:00
|
|
|
};
|
2012-09-26 12:52:21 +00:00
|
|
|
|
2014-01-08 06:10:58 +00:00
|
|
|
this.supportedNetworkTypes = this.getSupportedNetworkTypes();
|
|
|
|
|
2012-06-13 02:46:41 +00:00
|
|
|
this.rilContext = {
|
2012-03-20 23:18:41 +00:00
|
|
|
radioState: RIL.GECKO_RADIOSTATE_UNAVAILABLE,
|
2013-11-21 14:09:14 +00:00
|
|
|
detailedRadioState: null,
|
2013-02-01 13:17:48 +00:00
|
|
|
cardState: RIL.GECKO_CARDSTATE_UNKNOWN,
|
2013-03-29 02:56:07 +00:00
|
|
|
networkSelectionMode: RIL.GECKO_NETWORK_SELECTION_UNKNOWN,
|
2013-01-10 16:18:54 +00:00
|
|
|
iccInfo: null,
|
2013-01-11 09:20:12 +00:00
|
|
|
imsi: null,
|
2012-04-19 21:33:25 +00:00
|
|
|
|
|
|
|
// These objects implement the nsIDOMMozMobileConnectionInfo interface,
|
2012-08-16 01:36:56 +00:00
|
|
|
// although the actual implementation lives in the content process. So are
|
|
|
|
// the child attributes `network` and `cell`, which implement
|
|
|
|
// nsIDOMMozMobileNetworkInfo and nsIDOMMozMobileCellInfo respectively.
|
2012-04-19 21:33:25 +00:00
|
|
|
voice: {connected: false,
|
|
|
|
emergencyCallsOnly: false,
|
|
|
|
roaming: false,
|
2012-06-12 21:05:50 +00:00
|
|
|
network: null,
|
2012-08-16 01:36:56 +00:00
|
|
|
cell: null,
|
2012-04-19 21:33:25 +00:00
|
|
|
type: null,
|
|
|
|
signalStrength: null,
|
|
|
|
relSignalStrength: null},
|
2012-06-13 02:46:41 +00:00
|
|
|
data: {connected: false,
|
2012-04-19 21:33:25 +00:00
|
|
|
emergencyCallsOnly: false,
|
|
|
|
roaming: false,
|
2012-06-12 21:05:50 +00:00
|
|
|
network: null,
|
2012-08-16 01:36:56 +00:00
|
|
|
cell: null,
|
2012-04-19 21:33:25 +00:00
|
|
|
type: null,
|
|
|
|
signalStrength: null,
|
|
|
|
relSignalStrength: null},
|
2011-12-07 06:57:19 +00:00
|
|
|
};
|
2012-05-24 05:12:07 +00:00
|
|
|
|
2012-12-26 10:49:08 +00:00
|
|
|
this.voicemailInfo = {
|
|
|
|
number: null,
|
|
|
|
displayName: null
|
|
|
|
};
|
|
|
|
|
2013-08-08 09:29:42 +00:00
|
|
|
this.operatorInfo = {};
|
|
|
|
|
2012-09-07 18:05:08 +00:00
|
|
|
let lock = gSettingsService.createLock();
|
2012-05-24 05:12:07 +00:00
|
|
|
|
2012-09-28 03:45:06 +00:00
|
|
|
// Read preferred network type from the setting DB.
|
|
|
|
lock.get("ril.radio.preferredNetworkType", this);
|
|
|
|
|
2012-09-26 12:57:37 +00:00
|
|
|
// Read the APN data from the settings DB.
|
2012-09-07 18:05:08 +00:00
|
|
|
lock.get("ril.data.roaming_enabled", this);
|
2013-07-12 04:44:22 +00:00
|
|
|
lock.get("ril.data.apnSettings", this);
|
2012-09-26 12:57:37 +00:00
|
|
|
|
2013-11-21 14:09:14 +00:00
|
|
|
// Read the "time.clock.automatic-update.enabled" setting to see if
|
2013-06-22 14:22:05 +00:00
|
|
|
// we need to adjust the system clock time by NITZ or SNTP.
|
2013-10-24 08:14:59 +00:00
|
|
|
lock.get(kSettingsClockAutoUpdateEnabled, this);
|
2012-09-28 06:02:57 +00:00
|
|
|
|
2013-11-21 14:09:14 +00:00
|
|
|
// Read the "time.timezone.automatic-update.enabled" setting to see if
|
2013-06-22 14:22:05 +00:00
|
|
|
// we need to adjust the system timezone by NITZ.
|
2013-10-24 08:14:59 +00:00
|
|
|
lock.get(kSettingsTimezoneAutoUpdateEnabled, this);
|
2013-06-22 14:22:05 +00: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 10:06:24 +00:00
|
|
|
|
2012-12-04 02:41:39 +00:00
|
|
|
// Read the Cell Broadcast Search List setting, string of integers or integer
|
|
|
|
// ranges separated by comma, to set listening channels.
|
2013-10-24 08:14:59 +00:00
|
|
|
lock.get(kSettingsCellBroadcastSearchList, this);
|
2012-12-04 02:41:39 +00:00
|
|
|
|
2013-10-24 08:14:59 +00:00
|
|
|
Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
|
2012-04-24 20:46:42 +00:00
|
|
|
Services.obs.addObserver(this, kMozSettingsChangedObserverTopic, false);
|
2012-10-23 07:15:53 +00:00
|
|
|
Services.obs.addObserver(this, kSysClockChangeObserverTopic, false);
|
2013-06-06 07:28:59 +00:00
|
|
|
Services.obs.addObserver(this, kScreenStateChangedTopic, false);
|
2012-04-19 21:33:25 +00:00
|
|
|
|
2013-06-22 14:22:05 +00:00
|
|
|
Services.obs.addObserver(this, kNetworkInterfaceStateChangedTopic, false);
|
2013-10-24 08:14:59 +00:00
|
|
|
Services.prefs.addObserver(kPrefCellBroadcastDisabled, this, false);
|
2013-09-07 11:09:54 +00:00
|
|
|
|
|
|
|
this.portAddressedSmsApps = {};
|
|
|
|
this.portAddressedSmsApps[WAP.WDP_PORT_PUSH] = this.handleSmsWdpPortPush.bind(this);
|
2013-06-22 14:22:05 +00:00
|
|
|
|
|
|
|
this._sntp = new Sntp(this.setClockBySntp.bind(this),
|
2013-11-21 14:09:14 +00: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 07:58:27 +00:00
|
|
|
}
|
2013-06-22 14:22:05 +00:00
|
|
|
|
2013-07-02 09:36:37 +00:00
|
|
|
RadioInterface.prototype = {
|
2011-12-05 07:58:27 +00:00
|
|
|
|
2013-07-02 09:36:37 +00:00
|
|
|
classID: RADIOINTERFACE_CID,
|
|
|
|
classInfo: XPCOMUtils.generateCI({classID: RADIOINTERFACE_CID,
|
|
|
|
classDescription: "RadioInterface",
|
|
|
|
interfaces: [Ci.nsIRadioInterface]}),
|
2011-12-05 07:58:27 +00:00
|
|
|
|
2013-07-02 09:36:37 +00:00
|
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIRadioInterface,
|
2012-05-24 05:12:07 +00:00
|
|
|
Ci.nsIObserver,
|
|
|
|
Ci.nsISettingsServiceCallback]),
|
2011-12-05 07:58:27 +00:00
|
|
|
|
2013-08-13 12:14:10 +00:00
|
|
|
// A private WorkerMessenger instance.
|
|
|
|
workerMessenger: null,
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
debug: function(s) {
|
2013-07-02 09:36:58 +00:00
|
|
|
dump("-*- RadioInterface[" + this.clientId + "]: " + s + "\n");
|
|
|
|
},
|
|
|
|
|
2013-08-08 09:29:42 +00:00
|
|
|
/**
|
|
|
|
* A utility function to copy objects. The srcInfo may contain
|
2013-11-21 14:09:14 +00:00
|
|
|
* "rilMessageType", should ignore it.
|
2013-08-08 09:29:42 +00:00
|
|
|
*/
|
2014-01-13 02:44:40 +00:00
|
|
|
updateInfo: function(srcInfo, destInfo) {
|
2013-08-08 09:29:42 +00:00
|
|
|
for (let key in srcInfo) {
|
2013-11-21 14:09:14 +00:00
|
|
|
if (key === "rilMessageType") {
|
2013-08-08 09:29:42 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
destInfo[key] = srcInfo[key];
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2013-08-09 04:27:19 +00:00
|
|
|
/**
|
|
|
|
* A utility function to compare objects. The srcInfo may contain
|
2013-11-21 14:09:14 +00:00
|
|
|
* "rilMessageType", should ignore it.
|
2013-08-09 04:27:19 +00:00
|
|
|
*/
|
2014-01-13 02:44:40 +00:00
|
|
|
isInfoChanged: function(srcInfo, destInfo) {
|
2013-08-09 04:27:19 +00:00
|
|
|
if (!destInfo) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let key in srcInfo) {
|
2013-11-21 14:09:14 +00:00
|
|
|
if (key === "rilMessageType") {
|
2013-08-09 04:27:19 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (srcInfo[key] !== destInfo[key]) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
},
|
|
|
|
|
2014-01-08 06:10:58 +00: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 08:44:20 +00:00
|
|
|
if (DEBUG) this.debug("Unknown network type: " + type);
|
2014-01-08 06:10:58 +00:00
|
|
|
supportedNetworkTypes =
|
|
|
|
RIL.GECKO_SUPPORTED_NETWORK_TYPES_DEFAULT.split(",");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (DEBUG) this.debug("Supported Network Types: " + supportedNetworkTypes);
|
|
|
|
return supportedNetworkTypes;
|
|
|
|
},
|
|
|
|
|
2012-04-19 21:33:25 +00:00
|
|
|
/**
|
|
|
|
* Process a message from the content process.
|
|
|
|
*/
|
2014-01-13 02:44:40 +00:00
|
|
|
receiveMessage: function(msg) {
|
2012-04-19 21:33:25 +00:00
|
|
|
switch (msg.name) {
|
2012-06-13 02:46:41 +00:00
|
|
|
case "RIL:GetRilContext":
|
2012-04-19 21:33:25 +00:00
|
|
|
// This message is sync.
|
2012-06-13 02:46:41 +00:00
|
|
|
return this.rilContext;
|
2014-01-08 10:54:34 +00:00
|
|
|
case "RIL:GetLastKnownNetwork":
|
|
|
|
// This message is sync.
|
|
|
|
return this._lastKnownNetwork;
|
|
|
|
case "RIL:GetLastKnownHomeNetwork":
|
|
|
|
// This message is sync.
|
|
|
|
return this._lastKnownHomeNetwork;
|
2012-06-01 21:10:39 +00:00
|
|
|
case "RIL:GetAvailableNetworks":
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "getAvailableNetworks");
|
2012-06-01 21:10:39 +00:00
|
|
|
break;
|
2012-06-19 22:52:06 +00:00
|
|
|
case "RIL:SelectNetwork":
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "selectNetwork");
|
2012-06-19 22:52:06 +00:00
|
|
|
break;
|
|
|
|
case "RIL:SelectNetworkAuto":
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "selectNetworkAuto");
|
2012-10-09 10:07:11 +00:00
|
|
|
break;
|
2013-12-11 03:15:03 +00: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 07:12:09 +00:00
|
|
|
case "RIL:GetCardLockState":
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "iccGetCardLockState",
|
|
|
|
"RIL:CardLockResult");
|
2012-04-12 04:01:49 +00:00
|
|
|
break;
|
|
|
|
case "RIL:UnlockCardLock":
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "iccUnlockCardLock",
|
|
|
|
"RIL:CardLockResult");
|
2012-04-12 04:01:49 +00:00
|
|
|
break;
|
|
|
|
case "RIL:SetCardLock":
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "iccSetCardLock",
|
|
|
|
"RIL:CardLockResult");
|
2012-04-12 04:01:49 +00: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 14:06:05 +00:00
|
|
|
case "RIL:GetCardLockRetryCount":
|
2013-08-13 12:14:13 +00: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 14:06:05 +00:00
|
|
|
break;
|
2012-10-05 14:08:55 +00:00
|
|
|
case "RIL:SendMMI":
|
2013-08-13 12:14:13 +00:00
|
|
|
this.sendMMI(msg.target, msg.json.data);
|
2012-06-09 21:07:18 +00:00
|
|
|
break;
|
2012-10-05 14:08:55 +00:00
|
|
|
case "RIL:CancelMMI":
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "cancelUSSD");
|
2012-06-09 21:07:18 +00:00
|
|
|
break;
|
2012-04-10 12:04:27 +00:00
|
|
|
case "RIL:SendStkResponse":
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.send("sendStkTerminalResponse", msg.json.data);
|
2012-04-10 12:04:27 +00:00
|
|
|
break;
|
|
|
|
case "RIL:SendStkMenuSelection":
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.send("sendStkMenuSelection", msg.json.data);
|
2012-04-10 12:04:27 +00:00
|
|
|
break;
|
2012-11-28 08:16:20 +00:00
|
|
|
case "RIL:SendStkTimerExpiration":
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.send("sendStkTimerExpiration", msg.json.data);
|
2012-11-28 08:16:20 +00:00
|
|
|
break;
|
2012-09-11 02:34:36 +00:00
|
|
|
case "RIL:SendStkEventDownload":
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.send("sendStkEventDownload", msg.json.data);
|
2012-09-11 02:34:36 +00:00
|
|
|
break;
|
2013-02-25 09:27:26 +00:00
|
|
|
case "RIL:IccOpenChannel":
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "iccOpenChannel");
|
2013-02-25 09:27:26 +00:00
|
|
|
break;
|
|
|
|
case "RIL:IccCloseChannel":
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "iccCloseChannel");
|
2013-02-25 09:27:26 +00:00
|
|
|
break;
|
|
|
|
case "RIL:IccExchangeAPDU":
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "iccExchangeAPDU");
|
2013-02-25 09:27:26 +00:00
|
|
|
break;
|
2013-03-06 02:51:40 +00:00
|
|
|
case "RIL:ReadIccContacts":
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "readICCContacts");
|
2013-03-06 02:51:40 +00:00
|
|
|
break;
|
2013-03-25 03:09:01 +00:00
|
|
|
case "RIL:UpdateIccContact":
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "updateICCContact");
|
2012-10-09 10:07:11 +00:00
|
|
|
break;
|
2014-01-27 18:22:00 +00:00
|
|
|
case "RIL:MatchMvno":
|
|
|
|
this.matchMvno(msg.target, msg.json.data);
|
|
|
|
break;
|
2013-10-30 04:04:21 +00:00
|
|
|
case "RIL:SetCallForwardingOptions":
|
|
|
|
this.setCallForwardingOptions(msg.target, msg.json.data);
|
2012-10-31 13:58:39 +00:00
|
|
|
break;
|
2013-10-30 04:04:21 +00:00
|
|
|
case "RIL:GetCallForwardingOptions":
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "queryCallForwardStatus");
|
2012-10-31 13:58:39 +00:00
|
|
|
break;
|
2013-10-30 04:04:21 +00:00
|
|
|
case "RIL:SetCallBarringOptions":
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "setCallBarring");
|
2013-05-21 05:13:37 +00:00
|
|
|
break;
|
2013-10-30 04:04:21 +00:00
|
|
|
case "RIL:GetCallBarringOptions":
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "queryCallBarringStatus");
|
2013-05-21 05:13:37 +00:00
|
|
|
break;
|
2013-08-27 01:59:17 +00:00
|
|
|
case "RIL:ChangeCallBarringPassword":
|
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "changeCallBarringPassword");
|
|
|
|
break;
|
2013-10-30 04:04:21 +00:00
|
|
|
case "RIL:SetCallWaitingOptions":
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "setCallWaiting");
|
2013-04-18 12:18:50 +00:00
|
|
|
break;
|
2013-10-30 04:04:21 +00:00
|
|
|
case "RIL:GetCallWaitingOptions":
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "queryCallWaiting");
|
2012-12-04 02:40:47 +00:00
|
|
|
break;
|
2013-07-17 21:18:29 +00:00
|
|
|
case "RIL:SetCallingLineIdRestriction":
|
2013-08-13 12:14:13 +00:00
|
|
|
this.setCallingLineIdRestriction(msg.target, msg.json.data);
|
2013-07-17 21:18:29 +00:00
|
|
|
break;
|
|
|
|
case "RIL:GetCallingLineIdRestriction":
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "getCLIR");
|
2013-07-17 21:18:29 +00:00
|
|
|
break;
|
2013-08-14 12:50:36 +00:00
|
|
|
case "RIL:ExitEmergencyCbMode":
|
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "exitEmergencyCbMode");
|
|
|
|
break;
|
2013-11-21 14:09:14 +00:00
|
|
|
case "RIL:SetRadioEnabled":
|
|
|
|
this.setRadioEnabled(msg.target, msg.json.data);
|
|
|
|
break;
|
2012-12-26 10:49:08 +00:00
|
|
|
case "RIL:GetVoicemailInfo":
|
|
|
|
// This message is sync.
|
|
|
|
return this.voicemailInfo;
|
2013-06-10 07:47:03 +00:00
|
|
|
case "RIL:SetRoamingPreference":
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "setRoamingPreference");
|
2013-06-10 07:47:03 +00:00
|
|
|
break;
|
|
|
|
case "RIL:GetRoamingPreference":
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "queryRoamingPreference");
|
2013-06-10 07:47:03 +00:00
|
|
|
break;
|
2013-08-14 08:22:38 +00:00
|
|
|
case "RIL:SetVoicePrivacyMode":
|
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "setVoicePrivacyMode");
|
|
|
|
break;
|
|
|
|
case "RIL:GetVoicePrivacyMode":
|
|
|
|
this.workerMessenger.sendWithIPCMessage(msg, "queryVoicePrivacyMode");
|
|
|
|
break;
|
2014-01-08 06:10:58 +00:00
|
|
|
case "RIL:GetSupportedNetworkTypes":
|
|
|
|
// This message is sync.
|
|
|
|
return this.supportedNetworkTypes;
|
2012-04-19 21:33:25 +00:00
|
|
|
}
|
2013-09-13 22:12:30 +00:00
|
|
|
return null;
|
2012-04-19 21:33:25 +00:00
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
handleUnsolicitedWorkerMessage: function(message) {
|
2012-08-06 21:28:03 +00:00
|
|
|
switch (message.rilMessageType) {
|
2012-11-28 01:28:43 +00:00
|
|
|
case "callRing":
|
2013-09-07 06:19:57 +00:00
|
|
|
gTelephonyProvider.notifyCallRing();
|
2012-11-28 01:28:43 +00:00
|
|
|
break;
|
2012-01-09 22:28:47 +00:00
|
|
|
case "callStateChange":
|
2013-10-31 12:05:52 +00:00
|
|
|
gTelephonyProvider.notifyCallStateChanged(this.clientId, message.call);
|
2012-01-09 22:28:47 +00:00
|
|
|
break;
|
|
|
|
case "callDisconnected":
|
2013-10-31 12:05:52 +00:00
|
|
|
gTelephonyProvider.notifyCallDisconnected(this.clientId, message.call);
|
2012-01-09 22:28:47 +00:00
|
|
|
break;
|
2013-07-06 10:40:58 +00:00
|
|
|
case "conferenceCallStateChanged":
|
2013-09-07 06:19:57 +00:00
|
|
|
gTelephonyProvider.notifyConferenceCallStateChanged(message.state);
|
2013-07-06 10:40:58 +00:00
|
|
|
break;
|
2013-07-30 09:24:43 +00:00
|
|
|
case "cdmaCallWaiting":
|
2013-10-31 12:05:52 +00:00
|
|
|
gTelephonyProvider.notifyCdmaCallWaiting(this.clientId, message.number);
|
2013-07-30 09:24:43 +00:00
|
|
|
break;
|
2012-05-15 04:13:06 +00:00
|
|
|
case "callError":
|
2013-10-31 12:05:52 +00:00
|
|
|
gTelephonyProvider.notifyCallError(this.clientId, message.callIndex,
|
|
|
|
message.errorMsg);
|
2012-05-15 04:13:06 +00:00
|
|
|
break;
|
2013-08-05 20:28:31 +00:00
|
|
|
case "suppSvcNotification":
|
2013-10-31 12:05:52 +00:00
|
|
|
gTelephonyProvider.notifySupplementaryService(this.clientId,
|
|
|
|
message.callIndex,
|
2013-09-07 06:19:57 +00:00
|
|
|
message.notification);
|
2013-08-05 20:28:31 +00:00
|
|
|
break;
|
2013-10-28 06:46:54 +00:00
|
|
|
case "conferenceError":
|
|
|
|
gTelephonyProvider.notifyConferenceError(message.errorName,
|
|
|
|
message.errorMsg);
|
|
|
|
break;
|
2013-08-14 12:50:36 +00:00
|
|
|
case "emergencyCbModeChange":
|
|
|
|
this.handleEmergencyCbModeChange(message);
|
|
|
|
break;
|
2012-06-19 22:52:06 +00:00
|
|
|
case "networkinfochanged":
|
|
|
|
this.updateNetworkInfo(message);
|
|
|
|
break;
|
|
|
|
case "networkselectionmodechange":
|
|
|
|
this.updateNetworkSelectionMode(message);
|
|
|
|
break;
|
2012-03-19 22:49:27 +00:00
|
|
|
case "voiceregistrationstatechange":
|
2012-04-19 21:33:25 +00:00
|
|
|
this.updateVoiceConnection(message);
|
2012-02-10 19:27:23 +00:00
|
|
|
break;
|
2012-03-19 22:49:27 +00:00
|
|
|
case "dataregistrationstatechange":
|
2012-04-19 21:33:25 +00:00
|
|
|
this.updateDataConnection(message);
|
2012-02-10 19:27:23 +00:00
|
|
|
break;
|
2012-06-01 21:09:59 +00:00
|
|
|
case "datacallerror":
|
2012-09-25 19:22:38 +00:00
|
|
|
this.handleDataCallError(message);
|
2012-06-01 21:09:59 +00:00
|
|
|
break;
|
2011-12-05 07:58:27 +00:00
|
|
|
case "signalstrengthchange":
|
2012-04-19 21:33:25 +00:00
|
|
|
this.handleSignalStrengthChange(message);
|
2011-12-05 07:58:27 +00:00
|
|
|
break;
|
|
|
|
case "operatorchange":
|
2012-04-19 21:33:25 +00:00
|
|
|
this.handleOperatorChange(message);
|
2011-12-05 07:58:27 +00:00
|
|
|
break;
|
2013-08-27 12:25:54 +00:00
|
|
|
case "otastatuschange":
|
|
|
|
this.handleOtaStatus(message);
|
|
|
|
break;
|
2011-12-07 06:57:19 +00:00
|
|
|
case "radiostatechange":
|
2012-05-24 05:12:07 +00:00
|
|
|
this.handleRadioStateChange(message);
|
2011-12-05 07:58:27 +00:00
|
|
|
break;
|
|
|
|
case "cardstatechange":
|
2012-06-13 02:46:41 +00:00
|
|
|
this.rilContext.cardState = message.cardState;
|
2013-05-22 09:32:18 +00:00
|
|
|
gMessageManager.sendIccMessage("RIL:CardStateChanged",
|
|
|
|
this.clientId, message);
|
2011-12-05 07:58:27 +00:00
|
|
|
break;
|
2011-12-24 05:02:52 +00:00
|
|
|
case "sms-received":
|
2013-09-07 11:09:54 +00:00
|
|
|
let ackOk = this.handleSmsReceived(message);
|
2013-12-04 10:52:31 +00:00
|
|
|
// Note: ACK has been done by modem for NEW_SMS_ON_SIM
|
|
|
|
if (ackOk && message.simStatus === undefined) {
|
2013-09-07 11:09:54 +00:00
|
|
|
this.workerMessenger.send("ackSMS", { result: RIL.PDU_FCS_OK });
|
|
|
|
}
|
|
|
|
return;
|
2013-10-28 06:06:48 +00:00
|
|
|
case "broadcastsms-received":
|
2012-12-04 02:40:47 +00:00
|
|
|
case "cellbroadcast-received":
|
|
|
|
message.timestamp = Date.now();
|
2013-07-02 09:36:40 +00:00
|
|
|
gMessageManager.sendCellBroadcastMessage("RIL:CellBroadcastReceived",
|
|
|
|
this.clientId, message);
|
2012-12-04 02:40:47 +00:00
|
|
|
break;
|
2012-01-18 01:34:09 +00:00
|
|
|
case "datacallstatechange":
|
2014-01-14 10:33:28 +00:00
|
|
|
message.ip = null;
|
|
|
|
message.netmask = null;
|
|
|
|
message.broadcast = null;
|
|
|
|
if (message.ipaddr) {
|
|
|
|
message.ip = message.ipaddr.split("/")[0];
|
|
|
|
let ip_value = netHelpers.stringToIP(message.ip);
|
|
|
|
let prefix_len = message.ipaddr.split("/")[1];
|
|
|
|
let mask_value = netHelpers.makeMask(prefix_len);
|
|
|
|
message.netmask = netHelpers.ipToString(mask_value);
|
|
|
|
message.broadcast = netHelpers.ipToString((ip_value & mask_value) + ~mask_value);
|
|
|
|
}
|
2012-07-19 23:56:57 +00:00
|
|
|
this.handleDataCallState(message);
|
2012-01-18 01:34:09 +00:00
|
|
|
break;
|
|
|
|
case "datacalllist":
|
|
|
|
this.handleDataCallList(message);
|
|
|
|
break;
|
2012-03-09 04:16:06 +00:00
|
|
|
case "nitzTime":
|
2012-09-28 06:02:57 +00:00
|
|
|
this.handleNitzTime(message);
|
2012-03-09 04:16:06 +00:00
|
|
|
break;
|
2012-04-18 10:07:29 +00:00
|
|
|
case "iccinfochange":
|
2013-03-25 03:09:01 +00:00
|
|
|
this.handleIccInfoChange(message);
|
2012-03-17 14:23:17 +00:00
|
|
|
break;
|
2013-01-11 09:20:12 +00:00
|
|
|
case "iccimsi":
|
|
|
|
this.rilContext.imsi = message.imsi;
|
|
|
|
break;
|
2012-07-21 00:19:38 +00:00
|
|
|
case "iccmbdn":
|
2013-03-25 03:09:01 +00:00
|
|
|
this.handleIccMbdn(message);
|
2012-07-21 00:19:38 +00:00
|
|
|
break;
|
2013-12-06 09:35:13 +00:00
|
|
|
case "iccmwis":
|
|
|
|
gMessageManager.sendVoicemailMessage("RIL:VoicemailNotification",
|
|
|
|
this.clientId, message.mwi);
|
|
|
|
break;
|
2012-10-05 14:08:55 +00:00
|
|
|
case "USSDReceived":
|
2013-07-02 09:36:58 +00:00
|
|
|
if (DEBUG) this.debug("USSDReceived " + JSON.stringify(message));
|
2012-06-09 21:07:18 +00:00
|
|
|
this.handleUSSDReceived(message);
|
|
|
|
break;
|
2012-04-10 12:04:27 +00:00
|
|
|
case "stkcommand":
|
|
|
|
this.handleStkProactiveCommand(message);
|
|
|
|
break;
|
|
|
|
case "stksessionend":
|
2013-07-02 09:36:40 +00:00
|
|
|
gMessageManager.sendIccMessage("RIL:StkSessionEnd", this.clientId, null);
|
2012-04-10 12:04:27 +00:00
|
|
|
break;
|
2013-08-14 12:50:36 +00:00
|
|
|
case "exitEmergencyCbMode":
|
|
|
|
this.handleExitEmergencyCbMode(message);
|
|
|
|
break;
|
2013-09-10 16:48:19 +00: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-09 22:28:47 +00:00
|
|
|
default:
|
2012-08-06 21:28:03 +00:00
|
|
|
throw new Error("Don't know about this message type: " +
|
|
|
|
message.rilMessageType);
|
2011-12-05 07:58:27 +00:00
|
|
|
}
|
2012-01-09 22:28:47 +00:00
|
|
|
},
|
|
|
|
|
2013-10-15 02:42:49 +00: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 02:44:40 +00:00
|
|
|
getPhoneNumber: function() {
|
2013-09-07 11:09:54 +00:00
|
|
|
let iccInfo = this.rilContext.iccInfo;
|
2013-10-15 02:42:49 +00: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 11:09:54 +00:00
|
|
|
|
|
|
|
// Workaround an xpconnect issue with undefined string objects.
|
|
|
|
// See bug 808220
|
|
|
|
if (number === undefined || number === "undefined") {
|
|
|
|
return null;
|
|
|
|
}
|
2013-11-02 10:17:25 +00:00
|
|
|
|
2013-09-07 11:09:54 +00:00
|
|
|
return number;
|
|
|
|
},
|
|
|
|
|
2013-11-02 10:17:25 +00:00
|
|
|
/**
|
|
|
|
* A utility function to get the ICC ID of the SIM card (if installed).
|
|
|
|
*/
|
2014-01-13 02:44:40 +00:00
|
|
|
getIccId: function() {
|
2013-11-02 10:17:25 +00:00
|
|
|
let iccInfo = this.rilContext.iccInfo;
|
|
|
|
|
|
|
|
if (!iccInfo || !(iccInfo instanceof GsmIccInfo)) {
|
|
|
|
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 18:22:00 +00: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 02:44:40 +00:00
|
|
|
updateNetworkInfo: function(message) {
|
2012-06-19 22:52:06 +00: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 04:27:19 +00:00
|
|
|
let signalMessage = message[RIL.NETWORK_INFO_SIGNAL];
|
2012-06-19 22:52:06 +00:00
|
|
|
|
|
|
|
// Batch the *InfoChanged messages together
|
|
|
|
if (voiceMessage) {
|
2013-08-08 09:29:42 +00:00
|
|
|
this.updateVoiceConnection(voiceMessage, true);
|
2012-06-19 22:52:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (dataMessage) {
|
2013-08-08 09:29:42 +00:00
|
|
|
this.updateDataConnection(dataMessage, true);
|
2012-06-19 22:52:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (operatorMessage) {
|
2013-08-08 09:29:42 +00:00
|
|
|
this.handleOperatorChange(operatorMessage, true);
|
2012-06-19 22:52:06 +00:00
|
|
|
}
|
|
|
|
|
2013-08-09 04:27:19 +00:00
|
|
|
if (signalMessage) {
|
|
|
|
this.handleSignalStrengthChange(signalMessage, true);
|
|
|
|
}
|
|
|
|
|
2013-01-28 03:41:34 +00:00
|
|
|
let voice = this.rilContext.voice;
|
|
|
|
let data = this.rilContext.data;
|
|
|
|
|
2012-09-03 21:50:55 +00:00
|
|
|
this.checkRoamingBetweenOperators(voice);
|
|
|
|
this.checkRoamingBetweenOperators(data);
|
|
|
|
|
2013-08-09 04:27:19 +00:00
|
|
|
if (voiceMessage || operatorMessage || signalMessage) {
|
2013-07-02 09:36:40 +00:00
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:VoiceInfoChanged",
|
|
|
|
this.clientId, voice);
|
2012-06-19 22:52:06 +00:00
|
|
|
}
|
2013-08-09 04:27:19 +00:00
|
|
|
if (dataMessage || operatorMessage || signalMessage) {
|
2013-07-02 09:36:40 +00:00
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged",
|
|
|
|
this.clientId, data);
|
2012-06-19 22:52:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (selectionMessage) {
|
|
|
|
this.updateNetworkSelectionMode(selectionMessage);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2012-09-03 21:50:55 +00: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 02:44:40 +00:00
|
|
|
checkRoamingBetweenOperators: function(registration) {
|
2013-01-10 16:18:54 +00:00
|
|
|
let iccInfo = this.rilContext.iccInfo;
|
2014-01-23 09:28:24 +00:00
|
|
|
let operator = registration.network;
|
|
|
|
let state = registration.state;
|
|
|
|
|
|
|
|
if (!iccInfo || !operator ||
|
|
|
|
state != RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED) {
|
2012-09-03 21:50:55 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-01-10 16:18:54 +00:00
|
|
|
let spn = iccInfo.spn && iccInfo.spn.toLowerCase();
|
2012-10-04 22:30:06 +00:00
|
|
|
let longName = operator.longName && operator.longName.toLowerCase();
|
|
|
|
let shortName = operator.shortName && operator.shortName.toLowerCase();
|
2012-09-03 21:50:55 +00:00
|
|
|
|
|
|
|
let equalsLongName = longName && (spn == longName);
|
|
|
|
let equalsShortName = shortName && (spn == shortName);
|
2013-01-10 16:18:54 +00:00
|
|
|
let equalsMcc = iccInfo.mcc == operator.mcc;
|
2012-09-03 21:50:55 +00:00
|
|
|
|
|
|
|
registration.roaming = registration.roaming &&
|
|
|
|
!(equalsMcc && (equalsLongName || equalsShortName));
|
|
|
|
},
|
|
|
|
|
2012-06-19 22:52:06 +00:00
|
|
|
/**
|
2013-08-08 09:29:42 +00:00
|
|
|
* Handle data connection changes.
|
2012-06-19 22:52:06 +00:00
|
|
|
*
|
2013-08-08 09:29:42 +00:00
|
|
|
* @param newInfo The new voice connection information.
|
|
|
|
* @param batch When batch is true, the RIL:VoiceInfoChanged message will
|
|
|
|
* not be sent.
|
2012-06-19 22:52:06 +00:00
|
|
|
*/
|
2014-01-13 02:44:40 +00:00
|
|
|
updateVoiceConnection: function(newInfo, batch) {
|
2012-06-13 02:46:41 +00:00
|
|
|
let voiceInfo = this.rilContext.voice;
|
2012-08-07 19:11:48 +00:00
|
|
|
voiceInfo.state = newInfo.state;
|
|
|
|
voiceInfo.connected = newInfo.connected;
|
|
|
|
voiceInfo.roaming = newInfo.roaming;
|
|
|
|
voiceInfo.emergencyCallsOnly = newInfo.emergencyCallsOnly;
|
2013-06-07 08:50:10 +00:00
|
|
|
voiceInfo.type = newInfo.type;
|
2012-08-07 19:11:48 +00:00
|
|
|
|
|
|
|
// Make sure we also reset the operator and signal strength information
|
|
|
|
// if we drop off the network.
|
2013-08-08 09:29:42 +00:00
|
|
|
if (newInfo.state !== RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED) {
|
2013-07-04 03:48:48 +00:00
|
|
|
voiceInfo.cell = null;
|
2012-06-12 21:05:50 +00:00
|
|
|
voiceInfo.network = null;
|
2012-04-19 21:33:25 +00:00
|
|
|
voiceInfo.signalStrength = null;
|
|
|
|
voiceInfo.relSignalStrength = null;
|
2012-08-16 01:36:56 +00:00
|
|
|
} else {
|
2013-07-04 03:48:48 +00:00
|
|
|
voiceInfo.cell = newInfo.cell;
|
2013-08-08 09:29:42 +00:00
|
|
|
voiceInfo.network = this.operatorInfo;
|
2012-08-16 01:36:56 +00:00
|
|
|
}
|
|
|
|
|
2013-08-08 09:29:42 +00:00
|
|
|
if (!batch) {
|
2013-07-02 09:36:40 +00:00
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:VoiceInfoChanged",
|
|
|
|
this.clientId, voiceInfo);
|
2012-06-19 22:52:06 +00:00
|
|
|
}
|
2012-04-19 21:33:25 +00:00
|
|
|
},
|
|
|
|
|
2013-08-08 09:29:42 +00: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 02:44:40 +00:00
|
|
|
updateDataConnection: function(newInfo, batch) {
|
2012-08-07 19:11:48 +00: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 04:44:22 +00:00
|
|
|
let apnSetting = this.apnSettings.byType.default;
|
|
|
|
dataInfo.connected = false;
|
|
|
|
if (apnSetting) {
|
|
|
|
dataInfo.connected = (this.getDataCallStateByType("default") ==
|
|
|
|
RIL.GECKO_NETWORK_STATE_CONNECTED);
|
|
|
|
}
|
2012-08-07 19:11:48 +00:00
|
|
|
|
|
|
|
// Make sure we also reset the operator and signal strength information
|
|
|
|
// if we drop off the network.
|
2013-08-08 09:29:42 +00:00
|
|
|
if (newInfo.state !== RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED) {
|
2013-07-04 03:48:48 +00:00
|
|
|
dataInfo.cell = null;
|
2012-08-07 19:11:48 +00:00
|
|
|
dataInfo.network = null;
|
|
|
|
dataInfo.signalStrength = null;
|
|
|
|
dataInfo.relSignalStrength = null;
|
2012-08-16 01:36:56 +00:00
|
|
|
} else {
|
2013-07-04 03:48:48 +00:00
|
|
|
dataInfo.cell = newInfo.cell;
|
2013-08-08 09:29:42 +00:00
|
|
|
dataInfo.network = this.operatorInfo;
|
2012-08-16 01:36:56 +00:00
|
|
|
}
|
|
|
|
|
2013-08-08 09:29:42 +00:00
|
|
|
if (!batch) {
|
2013-07-02 09:36:40 +00:00
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged",
|
|
|
|
this.clientId, dataInfo);
|
2012-06-22 00:22:47 +00:00
|
|
|
}
|
2012-08-30 19:41:46 +00:00
|
|
|
this.updateRILNetworkInterface();
|
2012-04-19 21:33:25 +00:00
|
|
|
},
|
|
|
|
|
2012-09-25 19:22:38 +00:00
|
|
|
/**
|
|
|
|
* Handle data errors
|
|
|
|
*/
|
2014-01-13 02:44:40 +00:00
|
|
|
handleDataCallError: function(message) {
|
2012-09-26 12:52:21 +00:00
|
|
|
// Notify data call error only for data APN
|
2013-07-12 04:44:22 +00:00
|
|
|
if (this.apnSettings.byType.default) {
|
|
|
|
let apnSetting = this.apnSettings.byType.default;
|
|
|
|
if (message.apn == apnSetting.apn &&
|
|
|
|
apnSetting.iface.inConnectedTypes("default")) {
|
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:DataError",
|
|
|
|
this.clientId, message);
|
|
|
|
}
|
2012-09-25 19:22:38 +00:00
|
|
|
}
|
|
|
|
|
2012-09-26 12:52:21 +00:00
|
|
|
this._deliverDataCallCallback("dataCallError", [message]);
|
2012-09-25 19:22:38 +00:00
|
|
|
},
|
|
|
|
|
2012-09-28 03:45:06 +00:00
|
|
|
_preferredNetworkType: null,
|
2014-01-13 02:44:40 +00:00
|
|
|
getPreferredNetworkType: function(target, message) {
|
2013-12-11 03:15:03 +00:00
|
|
|
this.workerMessenger.send("getPreferredNetworkType", message, (function(response) {
|
|
|
|
if (response.success) {
|
|
|
|
this._preferredNetworkType = response.networkType;
|
|
|
|
response.type = RIL.RIL_PREFERRED_NETWORK_TYPE_TO_GECKO[this._preferredNetworkType];
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("_preferredNetworkType is now " +
|
|
|
|
RIL.RIL_PREFERRED_NETWORK_TYPE_TO_GECKO[this._preferredNetworkType]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
target.sendAsyncMessage("RIL:GetPreferredNetworkType", {
|
|
|
|
clientId: this.clientId,
|
|
|
|
data: response
|
|
|
|
});
|
|
|
|
return false;
|
|
|
|
}).bind(this));
|
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
setPreferredNetworkType: function(target, message) {
|
2013-12-11 03:15:03 +00:00
|
|
|
if (DEBUG) this.debug("setPreferredNetworkType: " + JSON.stringify(message));
|
|
|
|
let networkType = RIL.RIL_PREFERRED_NETWORK_TYPE_TO_GECKO.indexOf(message.type);
|
|
|
|
if (networkType < 0) {
|
|
|
|
message.errorMsg = RIL.GECKO_ERROR_INVALID_PARAMETER;
|
|
|
|
target.sendAsyncMessage("RIL:SetPreferredNetworkType", {
|
|
|
|
clientId: this.clientId,
|
|
|
|
data: message
|
|
|
|
});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
message.networkType = networkType;
|
|
|
|
|
|
|
|
this.workerMessenger.send("setPreferredNetworkType", message, (function(response) {
|
|
|
|
if (response.success) {
|
|
|
|
this._preferredNetworkType = response.networkType;
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("_preferredNetworkType is now " +
|
|
|
|
RIL.RIL_PREFERRED_NETWORK_TYPE_TO_GECKO[this._preferredNetworkType]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
target.sendAsyncMessage("RIL:SetPreferredNetworkType", {
|
|
|
|
clientId: this.clientId,
|
|
|
|
data: response
|
|
|
|
});
|
|
|
|
return false;
|
|
|
|
}).bind(this));
|
|
|
|
},
|
|
|
|
|
|
|
|
// TODO: Bug 946589 - B2G RIL: follow-up to bug 944225 - remove
|
|
|
|
// 'ril.radio.preferredNetworkType' setting handler
|
2014-01-13 02:44:40 +00:00
|
|
|
setPreferredNetworkTypeBySetting: function(value) {
|
2012-09-28 03:45:06 +00:00
|
|
|
let networkType = RIL.RIL_PREFERRED_NETWORK_TYPE_TO_GECKO.indexOf(value);
|
|
|
|
if (networkType < 0) {
|
|
|
|
networkType = (this._preferredNetworkType != null)
|
|
|
|
? RIL.RIL_PREFERRED_NETWORK_TYPE_TO_GECKO[this._preferredNetworkType]
|
|
|
|
: RIL.GECKO_PREFERRED_NETWORK_TYPE_DEFAULT;
|
|
|
|
gSettingsService.createLock().set("ril.radio.preferredNetworkType",
|
|
|
|
networkType, null);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (networkType == this._preferredNetworkType) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.send("setPreferredNetworkType",
|
|
|
|
{ networkType: networkType },
|
|
|
|
(function(response) {
|
|
|
|
if ((this._preferredNetworkType != null) && !response.success) {
|
|
|
|
gSettingsService.createLock().set("ril.radio.preferredNetworkType",
|
|
|
|
this._preferredNetworkType,
|
|
|
|
null);
|
|
|
|
return false;
|
|
|
|
}
|
2012-09-28 03:45:06 +00:00
|
|
|
|
2013-08-13 12:14:13 +00:00
|
|
|
this._preferredNetworkType = response.networkType;
|
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("_preferredNetworkType is now " +
|
|
|
|
RIL.RIL_PREFERRED_NETWORK_TYPE_TO_GECKO[this._preferredNetworkType]);
|
|
|
|
}
|
2012-09-28 03:45:06 +00:00
|
|
|
|
2013-08-13 12:14:13 +00:00
|
|
|
return false;
|
|
|
|
}).bind(this));
|
2012-09-28 03:45:06 +00:00
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
setCellBroadcastSearchList: function(newSearchListStr) {
|
2012-12-04 02:41:39 +00:00
|
|
|
if (newSearchListStr == this._cellBroadcastSearchListStr) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.send("setCellBroadcastSearchList",
|
|
|
|
{ searchListStr: newSearchListStr },
|
|
|
|
(function callback(response) {
|
|
|
|
if (!response.success) {
|
|
|
|
let lock = gSettingsService.createLock();
|
2013-10-24 08:14:59 +00:00
|
|
|
lock.set(kSettingsCellBroadcastSearchList,
|
2013-08-13 12:14:13 +00:00
|
|
|
this._cellBroadcastSearchListStr, null);
|
|
|
|
} else {
|
|
|
|
this._cellBroadcastSearchListStr = response.searchListStr;
|
|
|
|
}
|
2012-12-04 02:41:39 +00:00
|
|
|
|
2013-08-13 12:14:13 +00:00
|
|
|
return false;
|
|
|
|
}).bind(this));
|
2012-12-04 02:41:39 +00:00
|
|
|
},
|
|
|
|
|
2013-08-09 04:27:19 +00: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 02:44:40 +00:00
|
|
|
handleSignalStrengthChange: function(message, batch) {
|
2012-08-07 19:11:48 +00:00
|
|
|
let voiceInfo = this.rilContext.voice;
|
2013-08-09 04:27:19 +00: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 19:11:48 +00:00
|
|
|
}
|
2012-04-19 21:33:25 +00:00
|
|
|
|
2012-08-07 19:11:48 +00:00
|
|
|
let dataInfo = this.rilContext.data;
|
2013-08-09 04:27:19 +00: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 19:11:48 +00:00
|
|
|
}
|
2012-04-19 21:33:25 +00:00
|
|
|
},
|
|
|
|
|
2013-08-08 09:29:42 +00: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 02:44:40 +00:00
|
|
|
handleOperatorChange: function(message, batch) {
|
2013-08-08 09:29:42 +00:00
|
|
|
let operatorInfo = this.operatorInfo;
|
2012-06-13 02:46:41 +00:00
|
|
|
let voice = this.rilContext.voice;
|
|
|
|
let data = this.rilContext.data;
|
2012-06-12 21:05:50 +00:00
|
|
|
|
2013-08-09 04:27:19 +00:00
|
|
|
if (this.isInfoChanged(message, operatorInfo)) {
|
2013-08-08 09:29:42 +00:00
|
|
|
this.updateInfo(message, operatorInfo);
|
|
|
|
|
2013-05-03 01:37:51 +00:00
|
|
|
// Update lastKnownNetwork
|
|
|
|
if (message.mcc && message.mnc) {
|
2014-01-08 10:54:34 +00:00
|
|
|
this._lastKnownNetwork = message.mcc + "-" + message.mnc;
|
2013-05-03 01:37:51 +00:00
|
|
|
}
|
|
|
|
|
2013-08-08 09:29:42 +00:00
|
|
|
// If the voice is unregistered, no need to send RIL:VoiceInfoChanged.
|
|
|
|
if (voice.network && !batch) {
|
2013-07-02 09:36:40 +00:00
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:VoiceInfoChanged",
|
|
|
|
this.clientId, voice);
|
2013-01-28 03:41:34 +00:00
|
|
|
}
|
2012-06-12 21:05:50 +00:00
|
|
|
|
2013-08-08 09:29:42 +00:00
|
|
|
// If the data is unregistered, no need to send RIL:DataInfoChanged.
|
|
|
|
if (data.network && !batch) {
|
2013-07-02 09:36:40 +00:00
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged",
|
|
|
|
this.clientId, data);
|
2013-01-28 03:41:34 +00:00
|
|
|
}
|
2012-04-19 21:33:25 +00:00
|
|
|
}
|
2012-03-12 23:46:08 +00:00
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
handleOtaStatus: function(message) {
|
2013-08-27 12:25:54 +00:00
|
|
|
if (message.status < 0 ||
|
|
|
|
RIL.CDMA_OTA_PROVISION_STATUS_TO_GECKO.length <= message.status) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let status = RIL.CDMA_OTA_PROVISION_STATUS_TO_GECKO[message.status];
|
|
|
|
|
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:OtaStatusChanged",
|
|
|
|
this.clientId, status);
|
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
_convertRadioState: function(state) {
|
2013-11-21 14:09:14 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
},
|
2012-09-28 02:53:29 +00:00
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
handleRadioStateChange: function(message) {
|
2012-05-24 05:12:07 +00:00
|
|
|
let newState = message.radioState;
|
2012-06-13 02:46:41 +00:00
|
|
|
if (this.rilContext.radioState == newState) {
|
2012-05-24 05:12:07 +00:00
|
|
|
return;
|
|
|
|
}
|
2012-06-13 02:46:41 +00:00
|
|
|
this.rilContext.radioState = newState;
|
2013-11-21 14:09:14 +00:00
|
|
|
this.handleDetailedRadioStateChanged(this._convertRadioState(newState));
|
2012-05-24 05:12:07 +00:00
|
|
|
|
2013-11-21 14:09:14 +00:00
|
|
|
//TODO Should we notify this change as a card state change?
|
2012-05-25 17:37:37 +00:00
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
handleDetailedRadioStateChanged: function(state) {
|
2013-11-21 14:09:14 +00:00
|
|
|
if (this.rilContext.detailedRadioState == state) {
|
2012-05-25 17:37:37 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-11-21 14:09:14 +00:00
|
|
|
this.rilContext.detailedRadioState = state;
|
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:RadioStateChanged",
|
|
|
|
this.clientId, state);
|
2013-08-29 13:58:41 +00:00
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
deactivateDataCalls: function() {
|
2013-08-29 13:58:41 +00:00
|
|
|
let dataDisconnecting = false;
|
2013-11-02 10:17:45 +00:00
|
|
|
for each (let apnSetting in this.apnSettings.byApn) {
|
2013-08-29 13:58:41 +00:00
|
|
|
for each (let type in apnSetting.types) {
|
|
|
|
if (this.getDataCallStateByType(type) ==
|
|
|
|
RIL.GECKO_NETWORK_STATE_CONNECTED) {
|
|
|
|
this.deactivateDataCallByType(type);
|
|
|
|
dataDisconnecting = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-11-21 14:09:14 +00: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-08-29 13:58:41 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2014-01-29 13:19:55 +00:00
|
|
|
updateApnSettings: function(allApnSettings) {
|
|
|
|
let simApnSettings = allApnSettings[this.clientId];
|
|
|
|
if (!simApnSettings) {
|
|
|
|
return;
|
|
|
|
}
|
2014-01-29 13:20:10 +00:00
|
|
|
if (this._pendingApnSettings) {
|
|
|
|
// Change of apn settings in process, just update to the newest.
|
|
|
|
this._pengingApnSettings = simApnSettings;
|
|
|
|
return;
|
|
|
|
}
|
2014-01-29 13:19:55 +00:00
|
|
|
|
2014-01-29 13:20:10 +00:00
|
|
|
let isDeactivatingDataCalls = false;
|
2014-01-29 13:19:55 +00:00
|
|
|
// Clear all existing connections based on APN types.
|
|
|
|
for each (let apnSetting in this.apnSettings.byApn) {
|
|
|
|
for each (let type in apnSetting.types) {
|
|
|
|
if (this.getDataCallStateByType(type) ==
|
|
|
|
RIL.GECKO_NETWORK_STATE_CONNECTED) {
|
|
|
|
this.deactivateDataCallByType(type);
|
2014-01-29 13:20:10 +00:00
|
|
|
isDeactivatingDataCalls = true;
|
2014-01-29 13:19:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-01-29 13:20:10 +00:00
|
|
|
if (isDeactivatingDataCalls) {
|
|
|
|
// Defer apn settings setup until all data calls are cleared.
|
|
|
|
this._pendingApnSettings = simApnSettings;
|
|
|
|
return;
|
|
|
|
}
|
2014-01-29 13:19:55 +00:00
|
|
|
this.setupApnSettings(simApnSettings);
|
|
|
|
},
|
|
|
|
|
2013-07-12 04:44:22 +00:00
|
|
|
/**
|
|
|
|
* This function will do the following steps:
|
2013-11-02 10:17:45 +00:00
|
|
|
* 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.
|
2013-07-12 04:44:22 +00:00
|
|
|
*/
|
2014-01-29 13:19:55 +00:00
|
|
|
setupApnSettings: function(simApnSettings) {
|
2013-11-02 10:17:45 +00:00
|
|
|
if (!simApnSettings) {
|
2013-08-22 10:06:36 +00:00
|
|
|
return;
|
|
|
|
}
|
2014-01-29 13:20:10 +00:00
|
|
|
if (DEBUG) this.debug("setupApnSettings: " + JSON.stringify(simApnSettings));
|
2013-07-12 04:44:22 +00:00
|
|
|
|
2014-01-29 13:19:55 +00:00
|
|
|
// Unregister anything from iface and delete it.
|
2013-11-02 10:17:45 +00:00
|
|
|
for each (let apnSetting in this.apnSettings.byApn) {
|
2013-08-22 10:06:36 +00:00
|
|
|
if (apnSetting.iface.name in gNetworkManager.networkInterfaces) {
|
|
|
|
gNetworkManager.unregisterNetworkInterface(apnSetting.iface);
|
|
|
|
}
|
|
|
|
this.unregisterDataCallCallback(apnSetting.iface);
|
|
|
|
delete apnSetting.iface;
|
|
|
|
}
|
2013-11-02 10:17:45 +00:00
|
|
|
this.apnSettings.byApn = {};
|
2013-08-22 10:06:36 +00:00
|
|
|
this.apnSettings.byType = {};
|
2013-07-12 04:44:22 +00:00
|
|
|
|
2013-11-02 10:17:45 +00:00
|
|
|
// Cache the APN settings by APNs and by types in the RIL.
|
|
|
|
for (let i = 0; simApnSettings[i]; i++) {
|
|
|
|
let inputApnSetting = simApnSettings[i];
|
2013-08-22 10:06:36 +00:00
|
|
|
if (!this.validateApnSetting(inputApnSetting)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2013-11-02 10:17:45 +00:00
|
|
|
// Combine APN, user name, and password as the key of |byApn| object to
|
|
|
|
// refer to the corresponding APN setting.
|
|
|
|
let apnKey = inputApnSetting.apn +
|
2013-11-21 14:09:14 +00:00
|
|
|
(inputApnSetting.user || "") +
|
|
|
|
(inputApnSetting.password || "");
|
2013-11-02 10:17:45 +00:00
|
|
|
|
|
|
|
if (!this.apnSettings.byApn[apnKey]) {
|
|
|
|
this.apnSettings.byApn[apnKey] = inputApnSetting;
|
2013-08-22 10:06:36 +00:00
|
|
|
} else {
|
2013-11-02 10:17:45 +00:00
|
|
|
this.apnSettings.byApn[apnKey].types =
|
|
|
|
this.apnSettings.byApn[apnKey].types.concat(inputApnSetting.types);
|
2013-08-22 10:06:36 +00:00
|
|
|
}
|
2013-11-02 10:17:45 +00:00
|
|
|
|
|
|
|
// Use APN type as the index of |byType| object to refer to the
|
|
|
|
// corresponding APN setting.
|
2013-08-22 10:06:36 +00:00
|
|
|
for each (let type in inputApnSetting.types) {
|
2013-11-02 10:17:45 +00:00
|
|
|
this.apnSettings.byType[type] = this.apnSettings.byApn[apnKey];
|
2013-07-12 04:44:22 +00:00
|
|
|
}
|
|
|
|
}
|
2013-11-02 10:17:45 +00:00
|
|
|
|
|
|
|
// Create RilNetworkInterface for each APN setting that just cached.
|
|
|
|
for each (let apnSetting in this.apnSettings.byApn) {
|
|
|
|
apnSetting.iface = new RILNetworkInterface(this, apnSetting);
|
|
|
|
}
|
2013-07-12 04:44:22 +00:00
|
|
|
},
|
|
|
|
|
2014-01-29 13:20:26 +00:00
|
|
|
allDataDisconnected: function() {
|
|
|
|
for each (let apnSetting in 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;
|
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
anyDataConnected: function() {
|
2013-12-20 20:56:35 +00:00
|
|
|
for each (let apnSetting in this.apnSettings.byApn) {
|
2014-01-29 13:20:26 +00:00
|
|
|
let iface = apnSetting.iface;
|
|
|
|
if (iface && iface.state == RIL.GECKO_NETWORK_STATE_CONNECTED) {
|
|
|
|
return true;
|
2013-12-20 20:56:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
},
|
|
|
|
|
2013-07-12 04:44:22 +00:00
|
|
|
/**
|
|
|
|
* Check if we get all necessary APN data.
|
|
|
|
*/
|
2014-01-13 02:44:40 +00:00
|
|
|
validateApnSetting: function(apnSetting) {
|
2013-07-12 04:44:22 +00:00
|
|
|
return (apnSetting &&
|
|
|
|
apnSetting.apn &&
|
|
|
|
apnSetting.types &&
|
|
|
|
apnSetting.types.length);
|
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
setDataRegistration: function(attach) {
|
2013-12-20 20:56:35 +00:00
|
|
|
this.workerMessenger.send("setDataRegistration", {attach: attach});
|
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
updateRILNetworkInterface: function() {
|
2013-07-12 04:44:22 +00:00
|
|
|
let apnSetting = this.apnSettings.byType.default;
|
|
|
|
if (!this.validateApnSetting(apnSetting)) {
|
2013-07-02 09:36:58 +00:00
|
|
|
if (DEBUG) {
|
2013-07-12 04:44:22 +00:00
|
|
|
this.debug("We haven't gotten completely the APN data.");
|
2013-07-02 09:36:58 +00:00
|
|
|
}
|
2012-08-01 14:54:04 +00:00
|
|
|
return;
|
2013-01-23 09:40:45 +00:00
|
|
|
}
|
2012-08-01 14:54:04 +00:00
|
|
|
|
2013-01-23 09:40:45 +00:00
|
|
|
// This check avoids data call connection if the radio is not ready
|
|
|
|
// yet after toggling off airplane mode.
|
2012-08-01 14:54:04 +00:00
|
|
|
if (this.rilContext.radioState != RIL.GECKO_RADIOSTATE_READY) {
|
2013-07-02 09:36:58 +00:00
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("RIL is not ready for data connection: radio's not ready");
|
|
|
|
}
|
2013-01-23 09:40:45 +00:00
|
|
|
return;
|
2012-08-01 14:54:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
2013-07-12 04:44:22 +00:00
|
|
|
if (this.dataCallSettings.oldEnabled == this.dataCallSettings.enabled) {
|
2013-07-02 09:36:58 +00:00
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("No changes for ril.data.enabled flag. Nothing to do.");
|
|
|
|
}
|
2012-08-01 14:54:04 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-06-28 01:46:00 +00:00
|
|
|
let defaultDataCallState = this.getDataCallStateByType("default");
|
|
|
|
if (defaultDataCallState == RIL.GECKO_NETWORK_STATE_CONNECTING ||
|
|
|
|
defaultDataCallState == RIL.GECKO_NETWORK_STATE_DISCONNECTING) {
|
2013-07-02 09:36:58 +00:00
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("Nothing to do during connecting/disconnecting in progress.");
|
|
|
|
}
|
2012-09-26 13:05:28 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-08-30 19:41:46 +00:00
|
|
|
let dataInfo = this.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) {
|
2013-07-02 09:36:58 +00:00
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("RIL is not ready for data connection: Phone's not " +
|
|
|
|
"registered or doesn't have data connection.");
|
|
|
|
}
|
2012-08-30 19:41:46 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-01-23 04:05:34 +00:00
|
|
|
let wifi_active = false;
|
|
|
|
if (gNetworkManager.active &&
|
|
|
|
gNetworkManager.active.type == Ci.nsINetworkInterface.NETWORK_TYPE_WIFI) {
|
|
|
|
wifi_active = true;
|
|
|
|
}
|
2013-01-08 16:21:14 +00:00
|
|
|
|
2013-06-28 01:46:00 +00:00
|
|
|
let defaultDataCallConnected = defaultDataCallState ==
|
|
|
|
RIL.GECKO_NETWORK_STATE_CONNECTED;
|
|
|
|
if (defaultDataCallConnected &&
|
2013-07-12 04:44:22 +00:00
|
|
|
(!this.dataCallSettings.enabled ||
|
|
|
|
(dataInfo.roaming && !this.dataCallSettings.roamingEnabled))) {
|
2013-07-02 09:36:58 +00:00
|
|
|
if (DEBUG) this.debug("Data call settings: disconnect data call.");
|
2013-06-28 01:46:00 +00:00
|
|
|
this.deactivateDataCallByType("default");
|
2013-01-08 16:21:14 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-07-12 04:44:22 +00:00
|
|
|
|
|
|
|
if (defaultDataCallConnected && wifi_active) {
|
|
|
|
if (DEBUG) this.debug("Disconnect data call when Wifi is connected.");
|
|
|
|
this.deactivateDataCallByType("default");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-06-28 01:46:00 +00:00
|
|
|
if (!this.dataCallSettings.enabled || defaultDataCallConnected) {
|
2013-07-02 09:36:58 +00:00
|
|
|
if (DEBUG) this.debug("Data call settings: nothing to do.");
|
2013-01-08 16:21:14 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-07-12 04:44:22 +00:00
|
|
|
if (dataInfo.roaming && !this.dataCallSettings.roamingEnabled) {
|
2013-07-02 09:36:58 +00:00
|
|
|
if (DEBUG) this.debug("We're roaming, but data roaming is disabled.");
|
2012-08-30 19:41:46 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-06-28 01:46:00 +00:00
|
|
|
if (wifi_active) {
|
2013-07-02 09:36:58 +00:00
|
|
|
if (DEBUG) this.debug("Don't connect data call when Wifi is connected.");
|
2013-01-23 04:05:34 +00:00
|
|
|
return;
|
|
|
|
}
|
2014-01-29 13:20:10 +00:00
|
|
|
if (this._pendingApnSettings) {
|
|
|
|
if (DEBUG) this.debug("We're changing apn settings, ignore any changes.");
|
|
|
|
return;
|
|
|
|
}
|
2013-11-26 18:58:28 +00:00
|
|
|
|
|
|
|
let detailedRadioState = this.rilContext.detailedRadioState;
|
|
|
|
if (gRadioEnabledController.isDeactivatingDataCalls() ||
|
|
|
|
detailedRadioState == RIL.GECKO_DETAILED_RADIOSTATE_ENABLING ||
|
|
|
|
detailedRadioState == RIL.GECKO_DETAILED_RADIOSTATE_DISABLING) {
|
2012-10-05 01:19:21 +00:00
|
|
|
// We're changing the radio power currently, ignore any changes.
|
|
|
|
return;
|
|
|
|
}
|
2012-08-30 19:41:46 +00:00
|
|
|
|
2013-07-02 09:36:58 +00:00
|
|
|
if (DEBUG) this.debug("Data call settings: connect data call.");
|
2013-06-28 01:46:00 +00:00
|
|
|
this.setupDataCallByType("default");
|
2012-08-01 14:54:04 +00:00
|
|
|
},
|
|
|
|
|
2012-06-19 22:52:06 +00:00
|
|
|
/**
|
|
|
|
* Update network selection mode
|
|
|
|
*/
|
2014-01-13 02:44:40 +00:00
|
|
|
updateNetworkSelectionMode: function(message) {
|
2013-07-02 09:36:58 +00:00
|
|
|
if (DEBUG) this.debug("updateNetworkSelectionMode: " + JSON.stringify(message));
|
2013-03-29 02:56:07 +00:00
|
|
|
this.rilContext.networkSelectionMode = message.mode;
|
2013-07-02 09:36:40 +00:00
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:NetworkSelectionModeChanged",
|
|
|
|
this.clientId, message);
|
2012-06-19 22:52:06 +00:00
|
|
|
},
|
|
|
|
|
2013-08-14 12:50:36 +00:00
|
|
|
/**
|
|
|
|
* Handle emergency callback mode change.
|
|
|
|
*/
|
2014-01-13 02:44:40 +00:00
|
|
|
handleEmergencyCbModeChange: function(message) {
|
2013-08-14 12:50:36 +00:00
|
|
|
if (DEBUG) this.debug("handleEmergencyCbModeChange: " + JSON.stringify(message));
|
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:EmergencyCbModeChanged",
|
|
|
|
this.clientId, message);
|
|
|
|
},
|
|
|
|
|
2013-09-07 11:09:54 +00:00
|
|
|
/**
|
|
|
|
* Handle WDP port push PDU. Constructor WDP bearer information and deliver
|
|
|
|
* to WapPushManager.
|
|
|
|
*
|
|
|
|
* @param message
|
|
|
|
* A SMS message.
|
|
|
|
*/
|
2014-01-13 02:44:40 +00:00
|
|
|
handleSmsWdpPortPush: function(message) {
|
2013-09-07 11:09:54 +00: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,
|
|
|
|
sourcePort: message.header.originatorPort,
|
|
|
|
destinationAddress: this.rilContext.iccInfo.msisdn,
|
|
|
|
destinationPort: message.header.destinationPort,
|
2013-11-02 10:17:35 +00:00
|
|
|
serviceId: this.clientId
|
2013-09-07 11:09:54 +00: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 02:44:40 +00:00
|
|
|
broadcastSmsSystemMessage: function(aName, aDomMessage) {
|
2013-09-07 11:09:54 +00: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, {
|
2013-11-01 12:00:55 +00: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 02:31:32 +00:00
|
|
|
sentTimestamp: aDomMessage.sentTimestamp,
|
2013-11-01 12:00:55 +00:00
|
|
|
deliveryTimestamp: aDomMessage.deliveryTimestamp,
|
|
|
|
read: aDomMessage.read
|
2013-09-07 11:09:54 +00:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2013-10-28 06:07:28 +00: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 13:51:47 +00:00
|
|
|
_smsHandledWakeLock: null,
|
|
|
|
_smsHandledWakeLockTimer: null,
|
2013-10-28 06:07:28 +00:00
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
_releaseSmsHandledWakeLock: function() {
|
2013-09-10 13:51:47 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2013-09-07 11:09:54 +00:00
|
|
|
portAddressedSmsApps: null,
|
2014-01-13 02:44:40 +00:00
|
|
|
handleSmsReceived: function(message) {
|
2013-09-07 11:09:54 +00:00
|
|
|
if (DEBUG) this.debug("handleSmsReceived: " + JSON.stringify(message));
|
|
|
|
|
2013-09-10 13:51:47 +00:00
|
|
|
// We need to acquire a CPU wake lock to avoid the system falling into
|
|
|
|
// the sleep mode when the RIL handles the received SMS.
|
|
|
|
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 06:07:28 +00:00
|
|
|
.initWithCallback(this._releaseSmsHandledWakeLock.bind(this),
|
2013-09-10 13:51:47 +00:00
|
|
|
SMS_HANDLED_WAKELOCK_TIMEOUT,
|
|
|
|
Ci.nsITimer.TYPE_ONE_SHOT);
|
|
|
|
|
2013-09-07 11:09:54 +00:00
|
|
|
// FIXME: Bug 737202 - Typed arrays become normal arrays when sent to/from workers
|
|
|
|
if (message.encoding == RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
|
|
|
|
message.fullData = new Uint8Array(message.fullData);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
if (message.header && message.header.destinationPort != null) {
|
|
|
|
let handler = this.portAddressedSmsApps[message.header.destinationPort];
|
|
|
|
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 02:42:49 +00:00
|
|
|
message.receiver = this.getPhoneNumber();
|
2013-09-07 11:09:54 +00:00
|
|
|
message.body = message.fullBody = message.fullBody || null;
|
|
|
|
message.timestamp = Date.now();
|
2013-11-02 10:17:25 +00:00
|
|
|
message.iccId = this.getIccId();
|
2013-09-07 11:09:54 +00:00
|
|
|
|
|
|
|
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 10:17:25 +00:00
|
|
|
message.iccId,
|
2013-09-07 11:09:54 +00:00
|
|
|
message.delivery,
|
|
|
|
message.deliveryStatus,
|
|
|
|
message.sender,
|
|
|
|
message.receiver,
|
|
|
|
message.body,
|
|
|
|
message.messageClass,
|
|
|
|
message.timestamp,
|
2013-09-23 02:31:32 +00:00
|
|
|
message.sentTimestamp,
|
2013-11-01 12:00:55 +00:00
|
|
|
0,
|
2013-09-07 11:09:54 +00:00
|
|
|
message.read);
|
|
|
|
|
|
|
|
Services.obs.notifyObservers(domMessage,
|
|
|
|
kSilentSmsReceivedObserverTopic,
|
|
|
|
null);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
let mwi = message.mwi;
|
|
|
|
if (mwi) {
|
|
|
|
mwi.returnNumber = message.sender;
|
|
|
|
mwi.returnMessage = message.fullBody;
|
|
|
|
gMessageManager.sendVoicemailMessage("RIL:VoicemailNotification",
|
|
|
|
this.clientId, mwi);
|
2013-12-06 03:18:17 +00:00
|
|
|
|
|
|
|
// Dicarded MWI comes without text body.
|
|
|
|
// Hence, we discard it here after notifying the MWI status.
|
|
|
|
if (mwi.discard) {
|
|
|
|
return true;
|
|
|
|
}
|
2013-09-07 11:09:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let notifyReceived = function notifyReceived(rv, domMessage) {
|
|
|
|
let success = Components.isSuccessCode(rv);
|
|
|
|
|
|
|
|
// Acknowledge the reception of the SMS.
|
2013-12-04 10:52:31 +00:00
|
|
|
// Note: Ack has been done by modem for NEW_SMS_ON_SIM
|
|
|
|
if (message.simStatus === undefined) {
|
|
|
|
this.workerMessenger.send("ackSMS", {
|
|
|
|
result: (success ? RIL.PDU_FCS_OK
|
|
|
|
: RIL.PDU_FCS_MEMORY_CAPACITY_EXCEEDED)
|
|
|
|
});
|
|
|
|
}
|
2013-09-07 11:09:54 +00: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 18:58:41 +00:00
|
|
|
this.debug("Could not store SMS, error code " + rv);
|
2013-09-07 11:09:54 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-11-01 09:55:54 +00:00
|
|
|
this.broadcastSmsSystemMessage(kSmsReceivedObserverTopic, domMessage);
|
2013-09-07 11:09:54 +00: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 18:58:41 +00:00
|
|
|
gMobileMessageDatabaseService.saveReceivedMessage(message,
|
|
|
|
notifyReceived);
|
2013-09-07 11:09:54 +00: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 10:17:25 +00:00
|
|
|
message.iccId,
|
2013-09-07 11:09:54 +00:00
|
|
|
message.delivery,
|
|
|
|
message.deliveryStatus,
|
|
|
|
message.sender,
|
|
|
|
message.receiver,
|
|
|
|
message.body,
|
|
|
|
message.messageClass,
|
|
|
|
message.timestamp,
|
2013-09-23 02:31:32 +00:00
|
|
|
message.sentTimestamp,
|
2013-11-01 12:00:55 +00:00
|
|
|
0,
|
2013-09-07 11:09:54 +00:00
|
|
|
message.read);
|
|
|
|
|
|
|
|
notifyReceived(Cr.NS_OK, domMessage);
|
|
|
|
}
|
|
|
|
|
|
|
|
// SMS ACK will be sent in notifyReceived. Return false here.
|
|
|
|
return false;
|
|
|
|
},
|
|
|
|
|
2012-01-18 01:34:09 +00:00
|
|
|
/**
|
|
|
|
* Handle data call state changes.
|
|
|
|
*/
|
2014-01-13 02:44:40 +00:00
|
|
|
handleDataCallState: function(datacall) {
|
2012-06-22 00:22:47 +00:00
|
|
|
let data = this.rilContext.data;
|
2013-07-12 04:44:22 +00:00
|
|
|
let apnSetting = this.apnSettings.byType.default;
|
|
|
|
let dataCallConnected =
|
|
|
|
(datacall.state == RIL.GECKO_NETWORK_STATE_CONNECTED);
|
|
|
|
if (apnSetting && datacall.ifname) {
|
|
|
|
if (dataCallConnected && datacall.apn == apnSetting.apn &&
|
|
|
|
apnSetting.iface.inConnectedTypes("default")) {
|
|
|
|
data.connected = dataCallConnected;
|
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged",
|
|
|
|
this.clientId, data);
|
|
|
|
data.apn = datacall.apn;
|
|
|
|
} else if (!dataCallConnected && datacall.apn == data.apn) {
|
|
|
|
data.connected = dataCallConnected;
|
|
|
|
delete data.apn;
|
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged",
|
|
|
|
this.clientId, data);
|
2013-06-28 01:46:00 +00:00
|
|
|
}
|
2012-06-22 00:22:47 +00:00
|
|
|
}
|
|
|
|
|
2012-01-18 01:34:09 +00:00
|
|
|
this._deliverDataCallCallback("dataCallStateChanged",
|
2012-06-22 05:53:12 +00:00
|
|
|
[datacall]);
|
2013-08-29 13:58:41 +00:00
|
|
|
|
|
|
|
// Process pending radio power off request after all data calls
|
|
|
|
// are disconnected.
|
|
|
|
if (datacall.state == RIL.GECKO_NETWORK_STATE_UNKNOWN &&
|
2014-01-29 13:20:26 +00:00
|
|
|
this.allDataDisconnected()) {
|
2014-01-29 13:20:10 +00:00
|
|
|
if (gRadioEnabledController.isDeactivatingDataCalls()) {
|
2013-11-21 14:09:14 +00:00
|
|
|
if (DEBUG) this.debug("All data connections are disconnected.");
|
|
|
|
gRadioEnabledController.finishDeactivatingDataCalls(this.clientId);
|
2013-08-29 13:58:41 +00:00
|
|
|
}
|
2014-01-29 13:20:10 +00:00
|
|
|
|
|
|
|
if (this._pendingApnSettings) {
|
|
|
|
if (DEBUG) this.debug("Setup pending apn settings.");
|
|
|
|
this.setupApnSettings(this._pendingApnSettings);
|
|
|
|
this._pendingApnSettings = null;
|
|
|
|
this.updateRILNetworkInterface();
|
|
|
|
}
|
2013-08-29 13:58:41 +00:00
|
|
|
}
|
2012-01-18 01:34:09 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle data call list.
|
|
|
|
*/
|
2014-01-13 02:44:40 +00:00
|
|
|
handleDataCallList: function(message) {
|
2012-01-18 01:34:09 +00:00
|
|
|
this._deliverDataCallCallback("receiveDataCallList",
|
2012-06-22 05:53:12 +00:00
|
|
|
[message.datacalls, message.datacalls.length]);
|
2012-01-18 01:34:09 +00:00
|
|
|
},
|
|
|
|
|
2013-01-25 10:06:24 +00:00
|
|
|
/**
|
2013-06-22 14:22:05 +00:00
|
|
|
* Set the setting value of "time.clock.automatic-update.available".
|
|
|
|
*/
|
2014-01-13 02:44:40 +00:00
|
|
|
setClockAutoUpdateAvailable: function(value) {
|
2013-10-24 08:14:59 +00:00
|
|
|
gSettingsService.createLock().set(kSettingsClockAutoUpdateAvailable, value, null,
|
2013-06-22 14:22:05 +00:00
|
|
|
"fromInternalSetting");
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the setting value of "time.timezone.automatic-update.available".
|
2013-01-25 10:06:24 +00:00
|
|
|
*/
|
2014-01-13 02:44:40 +00:00
|
|
|
setTimezoneAutoUpdateAvailable: function(value) {
|
2013-10-24 08:14:59 +00:00
|
|
|
gSettingsService.createLock().set(kSettingsTimezoneAutoUpdateAvailable, value, null,
|
2013-01-25 10:06:24 +00:00
|
|
|
"fromInternalSetting");
|
|
|
|
},
|
|
|
|
|
2012-09-28 06:02:57 +00:00
|
|
|
/**
|
2013-06-22 14:22:05 +00:00
|
|
|
* Set the system clock by NITZ.
|
2012-09-28 06:02:57 +00:00
|
|
|
*/
|
2014-01-13 02:44:40 +00:00
|
|
|
setClockByNitz: function(message) {
|
2012-09-28 06:02:57 +00: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 14:22:05 +00:00
|
|
|
},
|
2012-09-28 06:02:57 +00:00
|
|
|
|
2013-06-22 14:22:05 +00:00
|
|
|
/**
|
|
|
|
* Set the system time zone by NITZ.
|
|
|
|
*/
|
2014-01-13 02:44:40 +00:00
|
|
|
setTimezoneByNitz: function(message) {
|
2012-09-28 06:02:57 +00: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 08:43:53 +00:00
|
|
|
// Ex, time zone -480 is "UTC+08:00"; time zone 630 is "UTC-10:30".
|
2012-09-28 06:02:57 +00: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 08:43:53 +00:00
|
|
|
timeZoneStr += (message.networkTimeZoneInMinutes > 0 ? "-" : "+");
|
2012-09-28 06:02:57 +00: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 07:15:53 +00:00
|
|
|
/**
|
|
|
|
* Handle the NITZ message.
|
|
|
|
*/
|
2014-01-13 02:44:40 +00:00
|
|
|
handleNitzTime: function(message) {
|
2013-01-25 10:06:24 +00:00
|
|
|
// Got the NITZ info received from the ril_worker.
|
2013-06-22 14:22:05 +00:00
|
|
|
this.setClockAutoUpdateAvailable(true);
|
|
|
|
this.setTimezoneAutoUpdateAvailable(true);
|
2013-01-25 10:06:24 +00:00
|
|
|
|
2012-10-23 07:15:53 +00:00
|
|
|
// Cache the latest NITZ message whenever receiving it.
|
|
|
|
this._lastNitzMessage = message;
|
|
|
|
|
2013-06-22 14:22:05 +00: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 02:44:40 +00:00
|
|
|
setClockBySntp: function(offset) {
|
2013-06-22 14:22:05 +00:00
|
|
|
// Got the SNTP info.
|
|
|
|
this.setClockAutoUpdateAvailable(true);
|
|
|
|
if (!this._clockAutoUpdateEnabled) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (this._lastNitzMessage) {
|
2014-01-23 08:44:20 +00:00
|
|
|
if (DEBUG) debug("SNTP: NITZ available, discard SNTP");
|
2013-06-22 14:22:05 +00:00
|
|
|
return;
|
2012-10-23 07:15:53 +00:00
|
|
|
}
|
2013-06-22 14:22:05 +00:00
|
|
|
gTimeService.set(Date.now() + offset);
|
2012-10-23 07:15:53 +00:00
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
handleIccMbdn: function(message) {
|
2012-12-26 10:49:08 +00:00
|
|
|
let voicemailInfo = this.voicemailInfo;
|
2012-11-23 04:09:01 +00:00
|
|
|
|
2012-12-26 10:49:08 +00:00
|
|
|
voicemailInfo.number = message.number;
|
|
|
|
voicemailInfo.displayName = message.alphaId;
|
2012-11-23 04:09:01 +00:00
|
|
|
|
2013-07-02 09:36:40 +00:00
|
|
|
gMessageManager.sendVoicemailMessage("RIL:VoicemailInfoChanged",
|
|
|
|
this.clientId, voicemailInfo);
|
2012-11-23 04:09:01 +00:00
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
handleIccInfoChange: function(message) {
|
2013-10-15 02:42:49 +00:00
|
|
|
let oldSpn = this.rilContext.iccInfo ? this.rilContext.iccInfo.spn : null;
|
2013-01-10 16:18:54 +00:00
|
|
|
|
2013-10-15 02:42:49 +00: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-03 21:43:59 +00:00
|
|
|
}
|
2013-10-15 02:42:49 +00:00
|
|
|
|
2012-09-03 21:43:59 +00:00
|
|
|
// RIL:IccInfoChanged corresponds to a DOM event that gets fired only
|
2013-08-12 06:59:17 +00:00
|
|
|
// when iccInfo has changed.
|
2013-05-30 11:14:39 +00:00
|
|
|
gMessageManager.sendIccMessage("RIL:IccInfoChanged",
|
2013-08-12 06:59:17 +00:00
|
|
|
this.clientId,
|
|
|
|
message.iccType ? message : null);
|
2013-01-04 08:44:20 +00:00
|
|
|
|
2013-07-18 20:17:41 +00:00
|
|
|
// Update lastKnownSimMcc.
|
|
|
|
if (message.mcc) {
|
|
|
|
try {
|
|
|
|
Services.prefs.setCharPref("ril.lastKnownSimMcc",
|
|
|
|
message.mcc.toString());
|
|
|
|
} catch (e) {}
|
|
|
|
}
|
|
|
|
|
2013-05-03 01:37:51 +00:00
|
|
|
// Update lastKnownHomeNetwork.
|
|
|
|
if (message.mcc && message.mnc) {
|
2014-01-08 10:54:34 +00:00
|
|
|
this._lastKnownHomeNetwork = message.mcc + "-" + message.mnc;
|
2013-05-03 01:37:51 +00:00
|
|
|
}
|
|
|
|
|
2013-01-04 08:44:20 +00:00
|
|
|
// If spn becomes available, we should check roaming again.
|
2013-01-08 12:40:00 +00:00
|
|
|
if (!oldSpn && message.spn) {
|
2013-01-04 08:44:20 +00: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 09:36:40 +00:00
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:VoiceInfoChanged",
|
|
|
|
this.clientId, voice);
|
2013-01-04 08:44:20 +00:00
|
|
|
}
|
|
|
|
if (dataRoaming != data.roaming) {
|
2013-07-02 09:36:40 +00:00
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged",
|
|
|
|
this.clientId, data);
|
2013-01-04 08:44:20 +00:00
|
|
|
}
|
|
|
|
}
|
2012-09-03 21:43:59 +00:00
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
handleUSSDReceived: function(ussd) {
|
2013-07-02 09:36:58 +00:00
|
|
|
if (DEBUG) this.debug("handleUSSDReceived " + JSON.stringify(ussd));
|
2012-12-16 12:25:02 +00:00
|
|
|
gSystemMessenger.broadcastMessage("ussd-received", ussd);
|
2013-07-02 09:36:40 +00:00
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:USSDReceived",
|
|
|
|
this.clientId, ussd);
|
2012-06-09 21:07:18 +00:00
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
handleStkProactiveCommand: function(message) {
|
2013-07-02 09:36:58 +00:00
|
|
|
if (DEBUG) this.debug("handleStkProactiveCommand " + JSON.stringify(message));
|
2013-11-25 10:10:34 +00:00
|
|
|
let iccId = this.rilContext.iccInfo && this.rilContext.iccInfo.iccid;
|
|
|
|
if (iccId) {
|
|
|
|
gSystemMessenger.broadcastMessage("icc-stkcommand",
|
|
|
|
{iccId: iccId,
|
|
|
|
command: message});
|
|
|
|
}
|
2013-07-02 09:36:40 +00:00
|
|
|
gMessageManager.sendIccMessage("RIL:StkCommand", this.clientId, message);
|
2012-04-10 12:04:27 +00:00
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
handleExitEmergencyCbMode: function(message) {
|
2013-08-14 12:50:36 +00:00
|
|
|
if (DEBUG) this.debug("handleExitEmergencyCbMode: " + JSON.stringify(message));
|
|
|
|
gMessageManager.sendRequestResults("RIL:ExitEmergencyCbMode", message);
|
|
|
|
},
|
|
|
|
|
2012-04-19 21:33:25 +00:00
|
|
|
// nsIObserver
|
2012-03-12 23:45:57 +00:00
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
observe: function(subject, topic, data) {
|
2012-04-24 20:46:42 +00:00
|
|
|
switch (topic) {
|
|
|
|
case kMozSettingsChangedObserverTopic:
|
|
|
|
let setting = JSON.parse(data);
|
2013-01-25 10:06:24 +00:00
|
|
|
this.handleSettingsChange(setting.key, setting.value, setting.message);
|
2012-04-24 20:46:42 +00:00
|
|
|
break;
|
2013-10-24 08:14:59 +00:00
|
|
|
case NS_PREFBRANCH_PREFCHANGE_TOPIC_ID:
|
|
|
|
if (data === kPrefCellBroadcastDisabled) {
|
2013-06-07 07:32:24 +00:00
|
|
|
let value = false;
|
|
|
|
try {
|
2013-10-24 08:14:59 +00:00
|
|
|
value = Services.prefs.getBoolPref(kPrefCellBroadcastDisabled);
|
2013-06-07 07:32:24 +00:00
|
|
|
} catch(e) {}
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.send("setCellBroadcastDisabled",
|
|
|
|
{ disabled: value });
|
2013-06-07 07:32:24 +00:00
|
|
|
}
|
|
|
|
break;
|
2013-10-24 08:14:59 +00:00
|
|
|
case NS_XPCOM_SHUTDOWN_OBSERVER_ID:
|
2013-10-28 06:07:28 +00:00
|
|
|
// Release the CPU wake lock for handling the received SMS.
|
|
|
|
this._releaseSmsHandledWakeLock();
|
2013-09-10 13:51:47 +00:00
|
|
|
|
2012-09-26 12:52:21 +00:00
|
|
|
// Shutdown all RIL network interfaces
|
2013-11-02 10:17:45 +00:00
|
|
|
for each (let apnSetting in this.apnSettings.byApn) {
|
2013-07-12 04:44:22 +00:00
|
|
|
if (apnSetting.iface) {
|
|
|
|
apnSetting.iface.shutdown();
|
|
|
|
}
|
|
|
|
}
|
2013-10-24 08:14:59 +00:00
|
|
|
Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
|
2012-04-24 20:46:42 +00:00
|
|
|
Services.obs.removeObserver(this, kMozSettingsChangedObserverTopic);
|
2012-10-23 07:15:53 +00:00
|
|
|
Services.obs.removeObserver(this, kSysClockChangeObserverTopic);
|
2013-06-06 07:28:59 +00:00
|
|
|
Services.obs.removeObserver(this, kScreenStateChangedTopic);
|
2013-06-22 14:22:05 +00:00
|
|
|
Services.obs.removeObserver(this, kNetworkInterfaceStateChangedTopic);
|
2012-10-23 07:15:53 +00:00
|
|
|
break;
|
|
|
|
case kSysClockChangeObserverTopic:
|
2013-06-22 14:22:05 +00:00
|
|
|
let offset = parseInt(data, 10);
|
2012-10-23 07:15:53 +00:00
|
|
|
if (this._lastNitzMessage) {
|
2013-06-22 14:22:05 +00:00
|
|
|
this._lastNitzMessage.receiveTimeInMS += offset;
|
|
|
|
}
|
|
|
|
this._sntp.updateOffset(offset);
|
|
|
|
break;
|
|
|
|
case kNetworkInterfaceStateChangedTopic:
|
|
|
|
let network = subject.QueryInterface(Ci.nsINetworkInterface);
|
2013-10-29 08:13:06 +00: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 14:22:05 +00:00
|
|
|
}
|
2012-10-23 07:15:53 +00:00
|
|
|
}
|
2013-10-29 08:13:06 +00:00
|
|
|
|
|
|
|
// SNTP won't update unless the SNTP is already expired.
|
|
|
|
if (this._sntp.isExpired()) {
|
|
|
|
this._sntp.request();
|
|
|
|
}
|
2012-04-24 20:46:42 +00:00
|
|
|
break;
|
2013-06-06 07:28:59 +00:00
|
|
|
case kScreenStateChangedTopic:
|
2013-08-14 10:11:47 +00:00
|
|
|
this.workerMessenger.send("setScreenState", { on: (data === "on") });
|
2013-06-06 07:28:59 +00:00
|
|
|
break;
|
2012-04-19 21:33:25 +00:00
|
|
|
}
|
2012-03-12 23:45:57 +00:00
|
|
|
},
|
|
|
|
|
2014-01-08 06:10:58 +00:00
|
|
|
supportedNetworkTypes: null,
|
|
|
|
|
2013-07-12 04:44:22 +00:00
|
|
|
// Data calls setting.
|
2013-07-02 09:36:37 +00:00
|
|
|
dataCallSettings: null,
|
2013-07-12 04:44:22 +00:00
|
|
|
|
|
|
|
apnSettings: null,
|
2012-09-05 20:00:06 +00:00
|
|
|
|
2014-01-29 13:20:10 +00:00
|
|
|
// Apn settings to be setup after data call are cleared.
|
|
|
|
_pendingApnSettings: null,
|
|
|
|
|
2013-06-22 14:22:05 +00:00
|
|
|
// Flag to determine whether to update system clock automatically. It
|
2013-11-21 14:09:14 +00:00
|
|
|
// corresponds to the "time.clock.automatic-update.enabled" setting.
|
2013-06-22 14:22:05 +00:00
|
|
|
_clockAutoUpdateEnabled: null,
|
|
|
|
|
|
|
|
// Flag to determine whether to update system timezone automatically. It
|
2013-11-21 14:09:14 +00:00
|
|
|
// corresponds to the "time.clock.automatic-update.enabled" setting.
|
2013-06-22 14:22:05 +00:00
|
|
|
_timezoneAutoUpdateEnabled: null,
|
2012-09-28 13:08:04 +00:00
|
|
|
|
2012-10-23 07:15:53 +00: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 14:22:05 +00:00
|
|
|
// Object that handles SNTP.
|
|
|
|
_sntp: null,
|
|
|
|
|
2012-12-04 02:41:39 +00:00
|
|
|
// Cell Broadcast settings values.
|
|
|
|
_cellBroadcastSearchListStr: null,
|
|
|
|
|
2014-01-08 10:54:34 +00:00
|
|
|
// Operator's mcc-mnc.
|
|
|
|
_lastKnownNetwork: null,
|
|
|
|
|
|
|
|
// ICC's mcc-mnc.
|
|
|
|
_lastKnownHomeNetwork: null,
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
handleSettingsChange: function(aName, aResult, aMessage) {
|
2013-01-25 10:06:24 +00:00
|
|
|
// Don't allow any content processes to modify the setting
|
2013-06-22 14:22:05 +00:00
|
|
|
// "time.clock.automatic-update.available" except for the chrome process.
|
2013-10-24 08:14:59 +00:00
|
|
|
if (aName === kSettingsClockAutoUpdateAvailable &&
|
2013-06-22 14:22:05 +00:00
|
|
|
aMessage !== "fromInternalSetting") {
|
|
|
|
let isClockAutoUpdateAvailable = this._lastNitzMessage !== null ||
|
|
|
|
this._sntp.isAvailable();
|
|
|
|
if (aResult !== isClockAutoUpdateAvailable) {
|
2014-01-23 08:44:20 +00:00
|
|
|
if (DEBUG) {
|
|
|
|
debug("Content processes cannot modify 'time.clock.automatic-update.available'. Restore!");
|
|
|
|
}
|
2013-06-22 14:22:05 +00: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 08:14:59 +00:00
|
|
|
if (aName === kSettingsTimezoneAutoUpdateAvailable &&
|
2013-06-22 14:22:05 +00: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 09:36:58 +00:00
|
|
|
}
|
2013-01-25 10:06:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
this.handle(aName, aResult);
|
|
|
|
},
|
|
|
|
|
2012-09-28 06:02:57 +00:00
|
|
|
// nsISettingsServiceCallback
|
2014-01-13 02:44:40 +00:00
|
|
|
handle: function(aName, aResult) {
|
2012-08-01 14:54:04 +00:00
|
|
|
switch(aName) {
|
2013-12-11 03:15:03 +00:00
|
|
|
// TODO: Bug 946589 - B2G RIL: follow-up to bug 944225 - remove
|
|
|
|
// 'ril.radio.preferredNetworkType' setting handler
|
2012-09-28 03:45:06 +00:00
|
|
|
case "ril.radio.preferredNetworkType":
|
2013-07-02 09:36:58 +00:00
|
|
|
if (DEBUG) this.debug("'ril.radio.preferredNetworkType' is now " + aResult);
|
2013-12-11 03:15:03 +00:00
|
|
|
this.setPreferredNetworkTypeBySetting(aResult);
|
2012-09-28 03:45:06 +00:00
|
|
|
break;
|
2012-08-01 14:54:04 +00:00
|
|
|
case "ril.data.roaming_enabled":
|
2013-07-12 04:44:22 +00:00
|
|
|
if (DEBUG) this.debug("'ril.data.roaming_enabled' is now " + aResult);
|
|
|
|
this.dataCallSettings.roamingEnabled = aResult;
|
2012-08-01 14:54:04 +00:00
|
|
|
this.updateRILNetworkInterface();
|
|
|
|
break;
|
2013-07-12 04:44:22 +00:00
|
|
|
case "ril.data.apnSettings":
|
|
|
|
if (DEBUG) this.debug("'ril.data.apnSettings' is now " + JSON.stringify(aResult));
|
|
|
|
if (aResult) {
|
|
|
|
this.updateApnSettings(aResult);
|
|
|
|
this.updateRILNetworkInterface();
|
|
|
|
}
|
2012-09-26 12:57:37 +00:00
|
|
|
break;
|
2013-10-24 08:14:59 +00:00
|
|
|
case kSettingsClockAutoUpdateEnabled:
|
2013-06-22 14:22:05 +00: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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2013-10-24 08:14:59 +00:00
|
|
|
case kSettingsTimezoneAutoUpdateEnabled:
|
2013-06-22 14:22:05 +00:00
|
|
|
this._timezoneAutoUpdateEnabled = aResult;
|
2012-10-23 07:15:53 +00:00
|
|
|
|
2013-06-22 14:22:05 +00: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 07:15:53 +00:00
|
|
|
}
|
2012-09-28 06:02:57 +00:00
|
|
|
break;
|
2013-10-24 08:14:59 +00:00
|
|
|
case kSettingsCellBroadcastSearchList:
|
2013-07-02 09:36:58 +00:00
|
|
|
if (DEBUG) {
|
2013-10-24 08:14:59 +00:00
|
|
|
this.debug("'" + kSettingsCellBroadcastSearchList + "' is now " + aResult);
|
2013-07-02 09:36:58 +00:00
|
|
|
}
|
2012-12-04 02:41:39 +00:00
|
|
|
this.setCellBroadcastSearchList(aResult);
|
|
|
|
break;
|
2013-06-10 02:41:14 +00:00
|
|
|
}
|
2012-05-24 05:12:07 +00:00
|
|
|
},
|
2012-09-05 09:36:01 +00:00
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
handleError: function(aErrorMessage) {
|
2013-07-02 09:36:58 +00:00
|
|
|
if (DEBUG) this.debug("There was an error while reading RIL settings.");
|
2012-08-01 14:54:04 +00:00
|
|
|
|
2013-01-23 09:40:45 +00:00
|
|
|
// Clean data call setting.
|
2013-07-12 04:44:22 +00:00
|
|
|
this.dataCallSettings.oldEnabled = false;
|
2013-06-10 02:41:14 +00:00
|
|
|
this.dataCallSettings.enabled = false;
|
2013-07-12 04:44:22 +00:00
|
|
|
this.dataCallSettings.roamingEnabled = false;
|
|
|
|
this.apnSettings = {
|
|
|
|
byType: {},
|
2013-11-02 10:17:45 +00:00
|
|
|
byApn: {},
|
2013-07-12 04:44:22 +00:00
|
|
|
};
|
2012-05-24 05:12:07 +00:00
|
|
|
},
|
|
|
|
|
2013-07-02 09:36:37 +00:00
|
|
|
// nsIRadioInterface
|
2011-12-05 07:58:27 +00:00
|
|
|
|
2012-06-13 02:46:41 +00:00
|
|
|
rilContext: null,
|
2011-12-05 07:58:27 +00:00
|
|
|
|
2012-04-24 15:44:42 +00:00
|
|
|
// Handle phone functions of nsIRILContentHelper
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
_sendCfStateChanged: function(message) {
|
2013-08-13 12:14:13 +00:00
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:CfStateChanged",
|
|
|
|
this.clientId, message);
|
2012-06-01 21:10:39 +00:00
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
_updateCallingLineIdRestrictionPref: function(mode) {
|
2013-08-13 12:14:13 +00:00
|
|
|
try {
|
2013-10-24 08:14:59 +00:00
|
|
|
Services.prefs.setIntPref(kPrefClirModePreference, mode);
|
2013-08-13 12:14:13 +00:00
|
|
|
Services.prefs.savePrefFile(null);
|
|
|
|
if (DEBUG) {
|
2013-10-24 08:14:59 +00:00
|
|
|
this.debug(kPrefClirModePreference + " pref is now " + mode);
|
2013-08-13 12:14:13 +00:00
|
|
|
}
|
|
|
|
} catch (e) {}
|
2013-06-06 07:28:59 +00:00
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
sendMMI: function(target, message) {
|
2013-07-02 09:36:58 +00:00
|
|
|
if (DEBUG) this.debug("SendMMI " + JSON.stringify(message));
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.send("sendMMI", message, (function(response) {
|
|
|
|
if (response.isSetCallForward) {
|
|
|
|
this._sendCfStateChanged(response);
|
|
|
|
} else if (response.isSetCLIR && response.success) {
|
|
|
|
this._updateCallingLineIdRestrictionPref(response.clirMode);
|
|
|
|
}
|
2013-02-25 09:27:26 +00:00
|
|
|
|
2013-09-30 00:56:00 +00:00
|
|
|
target.sendAsyncMessage("RIL:SendMMI", {
|
|
|
|
clientId: this.clientId,
|
|
|
|
data: response
|
|
|
|
});
|
2013-08-13 12:14:13 +00:00
|
|
|
return false;
|
|
|
|
}).bind(this));
|
2013-02-25 09:27:26 +00:00
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
setCallForwardingOptions: function(target, message) {
|
2013-10-30 04:04:21 +00:00
|
|
|
if (DEBUG) this.debug("setCallForwardingOptions: " + JSON.stringify(message));
|
2012-10-31 13:58:39 +00:00
|
|
|
message.serviceClass = RIL.ICC_SERVICE_CLASS_VOICE;
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.send("setCallForward", message, (function(response) {
|
|
|
|
this._sendCfStateChanged(response);
|
2013-10-30 04:04:21 +00:00
|
|
|
target.sendAsyncMessage("RIL:SetCallForwardingOptions", {
|
2013-09-30 00:56:00 +00:00
|
|
|
clientId: this.clientId,
|
|
|
|
data: response
|
|
|
|
});
|
2013-08-13 12:14:13 +00:00
|
|
|
return false;
|
|
|
|
}).bind(this));
|
2013-04-18 12:18:50 +00:00
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:44 +00:00
|
|
|
setCallingLineIdRestriction: function(target, message) {
|
2013-07-17 21:18:29 +00:00
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("setCallingLineIdRestriction: " + JSON.stringify(message));
|
|
|
|
}
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.send("setCLIR", message, (function(response) {
|
|
|
|
if (response.success) {
|
|
|
|
this._updateCallingLineIdRestrictionPref(response.clirMode);
|
|
|
|
}
|
2013-09-30 00:56:00 +00:00
|
|
|
target.sendAsyncMessage("RIL:SetCallingLineIdRestriction", {
|
|
|
|
clientId: this.clientId,
|
|
|
|
data: response
|
|
|
|
});
|
2013-08-23 12:42:20 +00:00
|
|
|
return false;
|
2013-08-13 12:14:13 +00:00
|
|
|
}).bind(this));
|
2013-07-17 21:18:29 +00:00
|
|
|
},
|
|
|
|
|
2013-11-21 14:09:14 +00:00
|
|
|
isValidStateForSetRadioEnabled: function() {
|
2013-11-26 18:58:28 +00:00
|
|
|
let state = this.rilContext.detailedRadioState;
|
|
|
|
return state == RIL.GECKO_DETAILED_RADIOSTATE_ENABLED ||
|
|
|
|
state == RIL.GECKO_DETAILED_RADIOSTATE_DISABLED;
|
2013-11-21 14:09:14 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
isDummyForSetRadioEnabled: function(message) {
|
2013-11-26 18:58:28 +00: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 14:09:14 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
setRadioEnabledResponse: function(target, message, errorMsg) {
|
|
|
|
if (errorMsg) {
|
|
|
|
message.errorMsg = errorMsg;
|
|
|
|
}
|
|
|
|
|
|
|
|
target.sendAsyncMessage("RIL:SetRadioEnabled", {
|
|
|
|
clientId: this.clientId,
|
|
|
|
data: message
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
setRadioEnabled: function(target, message) {
|
2013-11-21 14:09:14 +00: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 15:39:26 +00: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 14:09:14 +00:00
|
|
|
this.setRadioEnabledResponse(target, response);
|
|
|
|
return false;
|
|
|
|
}).bind(this);
|
|
|
|
|
|
|
|
this.setRadioEnabledInternal(message, callback);
|
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
setRadioEnabledInternal: function(message, callback) {
|
2013-11-21 14:09:14 +00: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 11:09:54 +00: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 02:44:40 +00:00
|
|
|
_countGsm7BitSeptets: function(message, langTable, langShiftTable, strict7BitEncoding) {
|
2013-09-07 11:09:54 +00: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 14:09:14 +00:00
|
|
|
c = "*";
|
2013-09-07 11:09:54 +00: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 02:44:40 +00:00
|
|
|
_calculateUserDataLength7Bit: function(message, strict7BitEncoding) {
|
2013-09-07 11:09:54 +00: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 02:44:40 +00:00
|
|
|
_calculateUserDataLengthUCS2: function(message) {
|
2013-09-07 11:09:54 +00: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 02:44:40 +00:00
|
|
|
_calculateUserDataLength: function(message, strict7BitEncoding) {
|
2013-09-07 11:09:54 +00: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 02:44:40 +00:00
|
|
|
_fragmentText7Bit: function(text, langTable, langShiftTable, segmentSeptets, strict7BitEncoding) {
|
2013-09-07 11:09:54 +00:00
|
|
|
let ret = [];
|
|
|
|
let body = "", len = 0;
|
2014-01-18 14:13:35 +00: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 11:09:54 +00: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 14:09:14 +00:00
|
|
|
c = "*";
|
2013-09-07 11:09:54 +00: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 02:44:40 +00:00
|
|
|
_fragmentTextUCS2: function(text, segmentChars) {
|
2013-09-07 11:09:54 +00:00
|
|
|
let ret = [];
|
2014-01-18 14:13:35 +00: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 11:09:54 +00: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 02:44:40 +00:00
|
|
|
_fragmentText: function(text, options, strict7BitEncoding) {
|
2013-09-07 11:09:54 +00: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 02:44:40 +00:00
|
|
|
getSegmentInfoForText: function(text, request) {
|
2013-09-07 11:09:54 +00: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 02:44:40 +00:00
|
|
|
getSmscAddress: function(request) {
|
2013-09-16 02:12:40 +00: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 02:44:40 +00:00
|
|
|
sendSMS: function(number, message, silent, request) {
|
2013-09-07 11:09:54 +00: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) {
|
|
|
|
// TODO bug 832140 handle !Components.isSuccessCode(rv)
|
|
|
|
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 14:09:14 +00:00
|
|
|
} else if (this.rilContext.detailedRadioState ==
|
|
|
|
RIL.GECKO_DETAILED_RADIOSTATE_DISABLED) {
|
2013-09-07 11:09:54 +00: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) {
|
|
|
|
request.notifySendMessageFailed(errorCode);
|
|
|
|
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)
|
|
|
|
request.notifySendMessageFailed(errorCode);
|
|
|
|
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 13:48:07 +00:00
|
|
|
case RIL.ERROR_FDN_CHECK_FAILURE:
|
|
|
|
error = Ci.nsIMobileMessageCallback.FDN_CHECK_ERROR;
|
|
|
|
break;
|
2013-09-07 11:09:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (context.silent) {
|
|
|
|
context.request.notifySendMessageFailed(error);
|
|
|
|
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)
|
|
|
|
context.request.notifySendMessageFailed(error);
|
|
|
|
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 14:45:57 +00:00
|
|
|
(function notifyResult(rv, domMessage) {
|
2013-09-07 11:09:54 +00:00
|
|
|
// TODO bug 832140 handle !Components.isSuccessCode(rv)
|
2013-11-01 09:55:54 +00:00
|
|
|
|
|
|
|
let topic = (response.deliveryStatus ==
|
|
|
|
RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS)
|
2013-09-07 11:09:54 +00:00
|
|
|
? kSmsDeliverySuccessObserverTopic
|
|
|
|
: kSmsDeliveryErrorObserverTopic;
|
2013-11-01 09:55:54 +00:00
|
|
|
|
2013-11-21 14:09:14 +00:00
|
|
|
// Broadcasting a "sms-delivery-success" system message to open apps.
|
2013-11-01 09:55:54 +00:00
|
|
|
if (topic == kSmsDeliverySuccessObserverTopic) {
|
|
|
|
this.broadcastSmsSystemMessage(topic, domMessage);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Notifying observers the delivery status is updated.
|
2013-09-07 11:09:54 +00:00
|
|
|
Services.obs.notifyObservers(domMessage, topic, null);
|
2013-11-01 14:45:57 +00:00
|
|
|
}).bind(this));
|
2013-09-07 11:09:54 +00:00
|
|
|
|
|
|
|
// Send transaction has ended completely.
|
|
|
|
return false;
|
|
|
|
} // End of message delivery.
|
|
|
|
|
|
|
|
// Message sent.
|
|
|
|
if (context.silent) {
|
2013-11-01 12:00:55 +00: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 11:09:54 +00:00
|
|
|
let sms = context.sms;
|
|
|
|
context.request.notifyMessageSent(
|
|
|
|
gMobileMessageService.createSmsMessage(sms.id,
|
|
|
|
sms.threadId,
|
2013-11-02 10:17:25 +00:00
|
|
|
sms.iccId,
|
2013-09-07 11:09:54 +00:00
|
|
|
DOM_MOBILE_MESSAGE_DELIVERY_SENT,
|
|
|
|
sms.deliveryStatus,
|
|
|
|
sms.sender,
|
|
|
|
sms.receiver,
|
|
|
|
sms.body,
|
|
|
|
sms.messageClass,
|
|
|
|
sms.timestamp,
|
2013-09-23 02:31:32 +00:00
|
|
|
Date.now(),
|
2013-11-01 12:00:55 +00:00
|
|
|
0,
|
2013-09-07 11:09:54 +00: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 09:55:54 +00:00
|
|
|
this.broadcastSmsSystemMessage(kSmsSentObserverTopic, domMessage);
|
2013-09-07 11:09:54 +00: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 02:42:49 +00:00
|
|
|
sender: this.getPhoneNumber(),
|
2013-09-07 11:09:54 +00:00
|
|
|
receiver: number,
|
|
|
|
body: message,
|
|
|
|
deliveryStatusRequested: options.requestStatusReport,
|
2013-11-02 10:17:25 +00:00
|
|
|
timestamp: Date.now(),
|
|
|
|
iccId: this.getIccId()
|
2013-09-07 11:09:54 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
if (silent) {
|
|
|
|
let delivery = DOM_MOBILE_MESSAGE_DELIVERY_SENDING;
|
2013-09-23 02:31:32 +00:00
|
|
|
let deliveryStatus = RIL.GECKO_SMS_DELIVERY_STATUS_PENDING;
|
2013-09-07 11:09:54 +00:00
|
|
|
let domMessage =
|
|
|
|
gMobileMessageService.createSmsMessage(-1, // id
|
|
|
|
0, // threadId
|
2013-11-02 10:17:25 +00:00
|
|
|
sendingMessage.iccId,
|
2013-09-07 11:09:54 +00:00
|
|
|
delivery,
|
|
|
|
deliveryStatus,
|
|
|
|
sendingMessage.sender,
|
|
|
|
sendingMessage.receiver,
|
|
|
|
sendingMessage.body,
|
|
|
|
"normal", // message class
|
|
|
|
sendingMessage.timestamp,
|
2013-11-01 12:00:55 +00:00
|
|
|
0,
|
2013-09-23 02:31:32 +00:00
|
|
|
0,
|
2013-09-07 11:09:54 +00:00
|
|
|
false);
|
|
|
|
notifyResult(Cr.NS_OK, domMessage);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-11-21 14:09:14 +00:00
|
|
|
let id = gMobileMessageDatabaseService.saveSendingMessage(
|
|
|
|
sendingMessage, notifyResult);
|
2013-09-07 11:09:54 +00:00
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
registerDataCallCallback: function(callback) {
|
2012-01-18 01:34:09 +00:00
|
|
|
if (this._datacall_callbacks) {
|
|
|
|
if (this._datacall_callbacks.indexOf(callback) != -1) {
|
|
|
|
throw new Error("Already registered this callback!");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
this._datacall_callbacks = [];
|
|
|
|
}
|
|
|
|
this._datacall_callbacks.push(callback);
|
2013-07-02 09:36:58 +00:00
|
|
|
if (DEBUG) this.debug("Registering callback: " + callback);
|
2012-01-18 01:34:09 +00:00
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
unregisterDataCallCallback: function(callback) {
|
2012-01-18 01:34:09 +00:00
|
|
|
if (!this._datacall_callbacks) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let index = this._datacall_callbacks.indexOf(callback);
|
|
|
|
if (index != -1) {
|
|
|
|
this._datacall_callbacks.splice(index, 1);
|
2013-07-02 09:36:58 +00:00
|
|
|
if (DEBUG) this.debug("Unregistering callback: " + callback);
|
2012-01-18 01:34:09 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
_deliverDataCallCallback: function(name, args) {
|
2012-01-18 01:34:09 +00:00
|
|
|
// 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.
|
|
|
|
if (!this._datacall_callbacks) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let callbacks = this._datacall_callbacks.slice();
|
2013-06-10 02:41:14 +00:00
|
|
|
for (let callback of callbacks) {
|
2012-01-18 01:34:09 +00:00
|
|
|
if (this._datacall_callbacks.indexOf(callback) == -1) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
let handler = callback[name];
|
|
|
|
if (typeof handler != "function") {
|
|
|
|
throw new Error("No handler for " + name);
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
handler.apply(callback, args);
|
|
|
|
} catch (e) {
|
2013-07-02 09:36:58 +00:00
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("callback handler for " + name + " threw an exception: " + e);
|
|
|
|
}
|
2012-01-18 01:34:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
setupDataCallByType: function(apntype) {
|
2014-01-23 08:44:49 +00:00
|
|
|
if (DEBUG) this.debug("setupDataCallByType: " + apntype);
|
2013-07-12 04:44:22 +00:00
|
|
|
let apnSetting = this.apnSettings.byType[apntype];
|
|
|
|
if (!apnSetting) {
|
2014-01-23 08:44:49 +00:00
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("No apn setting for type: " + apntype);
|
|
|
|
}
|
2013-07-12 04:44:22 +00:00
|
|
|
return;
|
2012-09-26 12:57:37 +00:00
|
|
|
}
|
|
|
|
|
2013-07-12 04:44:22 +00:00
|
|
|
let dataInfo = this.rilContext.data;
|
|
|
|
if (dataInfo.state != RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED ||
|
|
|
|
dataInfo.type == RIL.GECKO_MOBILE_CONNECTION_STATE_UNKNOWN) {
|
|
|
|
return;
|
|
|
|
}
|
2013-06-28 01:46:00 +00:00
|
|
|
|
2013-07-12 04:44:22 +00:00
|
|
|
apnSetting.iface.connect(apntype);
|
2013-06-28 01:46:00 +00:00
|
|
|
// 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
|
2013-07-12 04:44:22 +00:00
|
|
|
// and network manager for current data call type.
|
|
|
|
if (apnSetting.iface.connected) {
|
2013-06-28 01:46:00 +00:00
|
|
|
if (apntype == "default" && !dataInfo.connected) {
|
|
|
|
dataInfo.connected = true;
|
2013-07-02 09:36:40 +00:00
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged",
|
|
|
|
this.clientId, dataInfo);
|
2013-06-28 01:46:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Update the interface status via-registration if the interface has
|
|
|
|
// already been registered in the network manager.
|
2013-07-12 04:44:22 +00:00
|
|
|
if (apnSetting.iface.name in gNetworkManager.networkInterfaces) {
|
|
|
|
gNetworkManager.unregisterNetworkInterface(apnSetting.iface);
|
2013-06-28 01:46:00 +00:00
|
|
|
}
|
2013-07-12 04:44:22 +00:00
|
|
|
gNetworkManager.registerNetworkInterface(apnSetting.iface);
|
2013-06-28 01:46:00 +00:00
|
|
|
|
2013-07-12 04:44:22 +00:00
|
|
|
Services.obs.notifyObservers(apnSetting.iface,
|
2013-06-28 01:46:00 +00:00
|
|
|
kNetworkInterfaceStateChangedTopic,
|
|
|
|
null);
|
|
|
|
}
|
|
|
|
},
|
2013-01-23 04:05:34 +00:00
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
deactivateDataCallByType: function(apntype) {
|
2014-01-23 08:44:49 +00:00
|
|
|
if (DEBUG) this.debug("deactivateDataCallByType: " + apntype);
|
2013-07-12 04:44:22 +00:00
|
|
|
let apnSetting = this.apnSettings.byType[apntype];
|
|
|
|
if (!apnSetting) {
|
2014-01-23 08:44:49 +00:00
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("No apn setting for type: " + apntype);
|
|
|
|
}
|
2012-09-26 12:57:37 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-06-28 01:46:00 +00:00
|
|
|
|
2013-07-12 04:44:22 +00:00
|
|
|
apnSetting.iface.disconnect(apntype);
|
2013-06-28 01:46:00 +00:00
|
|
|
// 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
|
2013-07-12 04:44:22 +00:00
|
|
|
// and network manager for current data call type.
|
|
|
|
if (apnSetting.iface.connectedTypes.length && apnSetting.iface.connected) {
|
2013-06-28 01:46:00 +00:00
|
|
|
let dataInfo = this.rilContext.data;
|
|
|
|
if (apntype == "default" && dataInfo.connected) {
|
|
|
|
dataInfo.connected = false;
|
2013-07-02 09:36:40 +00:00
|
|
|
gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged",
|
|
|
|
this.clientId, dataInfo);
|
2013-06-28 01:46:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Update the interface status via-registration if the interface has
|
|
|
|
// already been registered in the network manager.
|
2013-07-12 04:44:22 +00:00
|
|
|
if (apnSetting.iface.name in gNetworkManager.networkInterfaces) {
|
|
|
|
gNetworkManager.unregisterNetworkInterface(apnSetting.iface);
|
2013-01-23 04:05:34 +00:00
|
|
|
}
|
2013-07-12 04:44:22 +00:00
|
|
|
gNetworkManager.registerNetworkInterface(apnSetting.iface);
|
2013-06-28 01:46:00 +00:00
|
|
|
|
2013-07-12 04:44:22 +00:00
|
|
|
Services.obs.notifyObservers(apnSetting.iface,
|
2013-06-28 01:46:00 +00:00
|
|
|
kNetworkInterfaceStateChangedTopic,
|
|
|
|
null);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
getDataCallStateByType: function(apntype) {
|
2013-07-12 04:44:22 +00:00
|
|
|
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;
|
2012-09-26 12:57:37 +00:00
|
|
|
}
|
2013-07-12 04:44:22 +00:00
|
|
|
return apnSetting.iface.state;
|
2012-09-26 12:57:37 +00:00
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
setupDataCall: function(radioTech, apn, user, passwd, chappap, pdptype) {
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.send("setupDataCall", { radioTech: radioTech,
|
|
|
|
apn: apn,
|
|
|
|
user: user,
|
|
|
|
passwd: passwd,
|
|
|
|
chappap: chappap,
|
|
|
|
pdptype: pdptype });
|
2012-01-18 01:34:09 +00:00
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
deactivateDataCall: function(cid, reason) {
|
2013-08-13 12:14:13 +00:00
|
|
|
this.workerMessenger.send("deactivateDataCall", { cid: cid,
|
|
|
|
reason: reason });
|
2012-12-28 03:11:36 +00:00
|
|
|
},
|
2013-09-07 06:19:57 +00:00
|
|
|
|
2014-01-13 02:44:44 +00:00
|
|
|
sendWorkerMessage: function(rilMessageType, message, callback) {
|
2014-01-13 02:44:33 +00:00
|
|
|
this.workerMessenger.send(rilMessageType, message, function(response) {
|
2013-09-07 06:19:57 +00:00
|
|
|
return callback.handleResponse(response);
|
|
|
|
});
|
|
|
|
}
|
2012-04-12 04:01:49 +00:00
|
|
|
};
|
2012-03-12 23:46:08 +00:00
|
|
|
|
2013-07-12 04:44:22 +00:00
|
|
|
function RILNetworkInterface(radioInterface, apnSetting) {
|
2013-07-02 09:36:37 +00:00
|
|
|
this.radioInterface = radioInterface;
|
2013-07-12 04:44:22 +00:00
|
|
|
this.apnSetting = apnSetting;
|
2013-08-20 11:31:10 +00:00
|
|
|
|
|
|
|
this.connectedTypes = [];
|
2012-09-26 12:52:21 +00:00
|
|
|
}
|
2012-03-12 23:46:08 +00:00
|
|
|
|
2012-09-26 12:52:21 +00:00
|
|
|
RILNetworkInterface.prototype = {
|
|
|
|
classID: RILNETWORKINTERFACE_CID,
|
|
|
|
classInfo: XPCOMUtils.generateCI({classID: RILNETWORKINTERFACE_CID,
|
|
|
|
classDescription: "RILNetworkInterface",
|
|
|
|
interfaces: [Ci.nsINetworkInterface,
|
2013-10-22 10:43:03 +00:00
|
|
|
Ci.nsIRilNetworkInterface,
|
2013-02-06 05:12:25 +00:00
|
|
|
Ci.nsIRILDataCallback]}),
|
2012-04-19 21:33:25 +00:00
|
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInterface,
|
2013-10-22 10:43:03 +00:00
|
|
|
Ci.nsIRilNetworkInterface,
|
2012-04-19 21:33:25 +00:00
|
|
|
Ci.nsIRILDataCallback]),
|
2012-03-12 23:46:08 +00:00
|
|
|
|
2012-04-19 21:33:25 +00:00
|
|
|
// nsINetworkInterface
|
2012-03-12 23:46:08 +00:00
|
|
|
|
2012-04-19 21:33:25 +00: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-12 23:46:08 +00:00
|
|
|
|
2012-08-30 16:57:33 +00: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,
|
2013-06-28 01:46:00 +00: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-19 21:33:25 +00:00
|
|
|
|
2012-06-01 21:09:59 +00: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 10:17:58 +00:00
|
|
|
/**
|
|
|
|
* nsINetworkInterface Implementation
|
|
|
|
*/
|
|
|
|
|
|
|
|
state: Ci.nsINetworkInterface.NETWORK_STATE_UNKNOWN,
|
|
|
|
|
2013-06-28 01:46:00 +00: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;
|
|
|
|
}
|
|
|
|
return this.NETWORK_TYPE_MOBILE_OTHERS;
|
|
|
|
},
|
2012-04-19 21:33:25 +00:00
|
|
|
|
|
|
|
name: null,
|
|
|
|
|
2012-08-14 01:54:42 +00:00
|
|
|
ip: null,
|
|
|
|
|
|
|
|
netmask: null,
|
|
|
|
|
|
|
|
broadcast: null,
|
|
|
|
|
|
|
|
dns1: null,
|
|
|
|
|
|
|
|
dns2: null,
|
|
|
|
|
2013-07-12 04:44:22 +00:00
|
|
|
get httpProxyHost() {
|
2013-11-21 14:09:14 +00:00
|
|
|
return this.apnSetting.proxy || "";
|
2013-07-12 04:44:22 +00:00
|
|
|
},
|
2012-08-01 14:55:43 +00:00
|
|
|
|
2013-07-12 04:44:22 +00:00
|
|
|
get httpProxyPort() {
|
2013-11-21 14:09:14 +00:00
|
|
|
return this.apnSetting.port || "";
|
2013-07-12 04:44:22 +00:00
|
|
|
},
|
2012-08-01 14:55:43 +00:00
|
|
|
|
2013-11-02 10:17:58 +00:00
|
|
|
/**
|
|
|
|
* nsIRilNetworkInterface Implementation
|
|
|
|
*/
|
|
|
|
|
2013-10-22 10:43:03 +00:00
|
|
|
get serviceId() {
|
|
|
|
return this.radioInterface.clientId;
|
|
|
|
},
|
|
|
|
|
|
|
|
get iccId() {
|
|
|
|
let iccInfo = this.radioInterface.rilContext.iccInfo;
|
|
|
|
return iccInfo && iccInfo.iccid;
|
|
|
|
},
|
|
|
|
|
2013-11-02 10:17:58 +00: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-01-13 02:44:40 +00:00
|
|
|
debug: function(s) {
|
2013-07-10 16:19:00 +00:00
|
|
|
dump("-*- RILNetworkInterface[" + this.radioInterface.clientId + ":" +
|
2013-07-02 09:36:58 +00:00
|
|
|
this.type + "]: " + s + "\n");
|
|
|
|
},
|
|
|
|
|
2012-03-12 23:46:08 +00:00
|
|
|
// nsIRILDataCallback
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
dataCallError: function(message) {
|
2013-07-12 04:44:22 +00:00
|
|
|
if (message.apn != this.apnSetting.apn) {
|
2012-09-26 12:52:21 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-07-02 09:36:58 +00:00
|
|
|
if (DEBUG) this.debug("Data call error on APN: " + message.apn);
|
2012-09-26 12:52:21 +00:00
|
|
|
this.reset();
|
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
dataCallStateChanged: function(datacall) {
|
2012-12-14 03:13:31 +00: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 04:44:22 +00:00
|
|
|
if (!this.cid && datacall.apn != this.apnSetting.apn) {
|
2012-09-26 12:52:21 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-07-02 09:36:58 +00:00
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("Data call ID: " + datacall.cid + ", interface name: " +
|
|
|
|
datacall.ifname + ", APN name: " + datacall.apn);
|
|
|
|
}
|
2012-03-12 23:46:08 +00:00
|
|
|
if (this.connecting &&
|
2012-06-22 05:53:12 +00:00
|
|
|
(datacall.state == RIL.GECKO_NETWORK_STATE_CONNECTING ||
|
|
|
|
datacall.state == RIL.GECKO_NETWORK_STATE_CONNECTED)) {
|
2012-03-12 23:46:08 +00:00
|
|
|
this.connecting = false;
|
2012-06-22 05:53:12 +00:00
|
|
|
this.cid = datacall.cid;
|
|
|
|
this.name = datacall.ifname;
|
2012-08-14 01:54:42 +00:00
|
|
|
this.ip = datacall.ip;
|
|
|
|
this.netmask = datacall.netmask;
|
|
|
|
this.broadcast = datacall.broadcast;
|
|
|
|
this.gateway = datacall.gw;
|
2012-08-26 02:29:07 +00:00
|
|
|
if (datacall.dns) {
|
|
|
|
this.dns1 = datacall.dns[0];
|
|
|
|
this.dns2 = datacall.dns[1];
|
|
|
|
}
|
2012-04-19 21:33:25 +00:00
|
|
|
if (!this.registeredAsNetworkInterface) {
|
2012-09-26 12:52:21 +00:00
|
|
|
gNetworkManager.registerNetworkInterface(this);
|
2012-04-19 21:33:25 +00:00
|
|
|
this.registeredAsNetworkInterface = true;
|
|
|
|
}
|
2012-03-12 23:46:08 +00:00
|
|
|
}
|
2012-12-14 03:13:31 +00: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-12 23:46:08 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-09-18 10:07:14 +00:00
|
|
|
|
2012-06-22 05:53:12 +00:00
|
|
|
if (this.state == datacall.state) {
|
2013-11-21 14:09:14 +00:00
|
|
|
if (datacall.state != RIL.GECKO_NETWORK_STATE_CONNECTED) {
|
2013-09-18 10:07:14 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
// State remains connected, check for minor changes.
|
|
|
|
let changed = false;
|
|
|
|
if (this.gateway != datacall.gw) {
|
|
|
|
this.gateway = datacall.gw;
|
|
|
|
changed = true;
|
|
|
|
}
|
|
|
|
if (datacall.dns &&
|
|
|
|
(this.dns1 != datacall.dns[0] ||
|
|
|
|
this.dns2 != datacall.dns[1])) {
|
|
|
|
this.dns1 = datacall.dns[0];
|
|
|
|
this.dns2 = datacall.dns[1];
|
|
|
|
changed = true;
|
|
|
|
}
|
|
|
|
if (changed) {
|
|
|
|
if (DEBUG) this.debug("Notify for data call minor changes.");
|
|
|
|
Services.obs.notifyObservers(this,
|
|
|
|
kNetworkInterfaceStateChangedTopic,
|
|
|
|
null);
|
|
|
|
}
|
2012-03-12 23:46:08 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-06-22 05:53:12 +00:00
|
|
|
this.state = datacall.state;
|
2012-09-26 12:52:21 +00:00
|
|
|
|
2013-11-22 15:16:31 +00:00
|
|
|
Services.obs.notifyObservers(this,
|
|
|
|
kNetworkInterfaceStateChangedTopic,
|
|
|
|
null);
|
|
|
|
|
2014-01-23 09:05:04 +00:00
|
|
|
if ((this.state == RIL.GECKO_NETWORK_STATE_UNKNOWN ||
|
|
|
|
this.state == RIL.GECKO_NETWORK_STATE_DISCONNECTED) &&
|
2013-07-12 04:44:22 +00:00
|
|
|
this.registeredAsNetworkInterface) {
|
2012-09-26 12:52:21 +00:00
|
|
|
gNetworkManager.unregisterNetworkInterface(this);
|
|
|
|
this.registeredAsNetworkInterface = false;
|
2012-12-14 03:13:31 +00:00
|
|
|
this.cid = null;
|
2013-06-28 01:46:00 +00:00
|
|
|
this.connectedTypes = [];
|
2012-09-26 12:52:21 +00:00
|
|
|
}
|
2014-01-23 09:05:04 +00: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.
|
|
|
|
if (this.radioInterface.apnSettings.byType.default &&
|
|
|
|
(this.radioInterface.apnSettings.byType.default.apn ==
|
|
|
|
this.apnSetting.apn)) {
|
|
|
|
this.radioInterface.updateRILNetworkInterface();
|
|
|
|
}
|
2012-03-12 23:46:08 +00:00
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
receiveDataCallList: function(dataCalls, length) {
|
2012-03-12 23:46:08 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
// Helpers
|
|
|
|
|
2012-04-19 21:33:25 +00:00
|
|
|
cid: null,
|
|
|
|
registeredAsDataCallCallback: false,
|
|
|
|
registeredAsNetworkInterface: false,
|
|
|
|
connecting: false,
|
2013-08-20 11:31:10 +00:00
|
|
|
apnSetting: null,
|
2012-04-19 21:33:25 +00:00
|
|
|
|
2012-06-01 21:09:59 +00:00
|
|
|
// APN failed connections. Retry counter
|
|
|
|
apnRetryCounter: 0,
|
|
|
|
|
2013-08-20 11:31:10 +00:00
|
|
|
connectedTypes: null,
|
2013-06-28 01:46:00 +00:00
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
inConnectedTypes: function(type) {
|
2013-06-28 01:46:00 +00:00
|
|
|
return this.connectedTypes.indexOf(type) != -1;
|
|
|
|
},
|
|
|
|
|
2012-04-24 20:46:42 +00:00
|
|
|
get connected() {
|
|
|
|
return this.state == RIL.GECKO_NETWORK_STATE_CONNECTED;
|
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
connect: function(apntype) {
|
2013-06-28 01:46:00 +00:00
|
|
|
if (apntype && !this.inConnectedTypes(apntype)) {
|
|
|
|
this.connectedTypes.push(apntype);
|
|
|
|
}
|
|
|
|
|
2012-08-28 14:37:43 +00:00
|
|
|
if (this.connecting || this.connected) {
|
2012-03-12 23:46:08 +00:00
|
|
|
return;
|
|
|
|
}
|
2012-08-01 14:54:04 +00:00
|
|
|
|
2013-06-28 01:46:00 +00: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-12 23:46:08 +00:00
|
|
|
if (!this.registeredAsDataCallCallback) {
|
2013-07-02 09:36:37 +00:00
|
|
|
this.radioInterface.registerDataCallCallback(this);
|
2012-03-12 23:46:08 +00:00
|
|
|
this.registeredAsDataCallCallback = true;
|
|
|
|
}
|
|
|
|
|
2013-07-12 04:44:22 +00:00
|
|
|
if (!this.apnSetting.apn) {
|
2013-07-02 09:36:58 +00:00
|
|
|
if (DEBUG) this.debug("APN name is empty, nothing to do.");
|
2012-09-26 12:57:37 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-07-02 09:36:58 +00:00
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("Going to set up data connection with APN " +
|
2013-07-12 04:44:22 +00:00
|
|
|
this.apnSetting.apn);
|
2013-07-02 09:36:58 +00:00
|
|
|
}
|
2013-07-02 09:36:37 +00:00
|
|
|
let radioTechType = this.radioInterface.rilContext.data.type;
|
2013-01-24 02:07:17 +00:00
|
|
|
let radioTechnology = RIL.GECKO_RADIO_TECH.indexOf(radioTechType);
|
2013-07-12 04:44:22 +00:00
|
|
|
let authType = RIL.RIL_DATACALL_AUTH_TO_GECKO.indexOf(this.apnSetting.authtype);
|
2013-05-06 08:58:56 +00: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 09:36:58 +00:00
|
|
|
if (DEBUG) {
|
2013-07-12 04:44:22 +00:00
|
|
|
this.debug("Invalid authType " + this.apnSetting.authtype);
|
2013-07-02 09:36:58 +00:00
|
|
|
}
|
2013-05-06 08:58:56 +00:00
|
|
|
authType = RIL.RIL_DATACALL_AUTH_TO_GECKO.indexOf(RIL.GECKO_DATACALL_AUTH_DEFAULT);
|
|
|
|
}
|
2013-07-02 09:36:37 +00:00
|
|
|
this.radioInterface.setupDataCall(radioTechnology,
|
2013-07-12 04:44:22 +00:00
|
|
|
this.apnSetting.apn,
|
|
|
|
this.apnSetting.user,
|
|
|
|
this.apnSetting.password,
|
|
|
|
authType,
|
|
|
|
"IP");
|
2012-03-12 23:46:08 +00:00
|
|
|
this.connecting = true;
|
|
|
|
},
|
|
|
|
|
2014-01-13 02:44:40 +00:00
|
|
|
reset: function() {
|
2012-06-01 21:09:59 +00: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 01:46:00 +00:00
|
|
|
this.connectedTypes = [];
|
2013-07-02 09:36:58 +00:00
|
|
|
if (DEBUG) this.debug("Too many APN Connection retries - STOP retrying");
|
2012-06-01 21:09:59 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
apnRetryTimer = this.NETWORK_APNRETRY_FACTOR *
|
|
|
|
(this.apnRetryCounter * this.apnRetryCounter) +
|
|
|
|
this.NETWORK_APNRETRY_ORIGIN;
|
|
|
|
this.apnRetryCounter++;
|
2013-07-02 09:36:58 +00:00
|
|
|
if (DEBUG) {
|
|
|
|
this.debug("Data call - APN Connection Retry Timer (secs-counter): " +
|
|
|
|
apnRetryTimer + "-" + this.apnRetryCounter);
|
|
|
|
}
|
2012-06-01 21:09:59 +00: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 02:44:40 +00:00
|
|
|
disconnect: function(apntype) {
|
2013-06-28 01:46:00 +00:00
|
|
|
let index = this.connectedTypes.indexOf(apntype);
|
|
|
|
if (index != -1) {
|
|
|
|
this.connectedTypes.splice(index, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.connectedTypes.length) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-04-24 20:46:42 +00:00
|
|
|
if (this.state == RIL.GECKO_NETWORK_STATE_DISCONNECTING ||
|
2013-07-12 04:44:22 +00:00
|
|
|
this.state == RIL.GECKO_NETWORK_STATE_DISCONNECTED ||
|
|
|
|
this.state == RIL.GECKO_NETWORK_STATE_UNKNOWN) {
|
2012-04-24 20:46:42 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
let reason = RIL.DATACALL_DEACTIVATE_NO_REASON;
|
2013-07-02 09:36:58 +00:00
|
|
|
if (DEBUG) this.debug("Going to disconnet data connection " + this.cid);
|
2013-07-02 09:36:37 +00:00
|
|
|
this.radioInterface.deactivateDataCall(this.cid, reason);
|
2012-03-12 23:46:08 +00:00
|
|
|
},
|
|
|
|
|
2012-06-01 21:09:59 +00:00
|
|
|
// Entry method for timer events. Used to reconnect to a failed APN
|
|
|
|
notify: function(timer) {
|
2012-09-26 12:52:21 +00:00
|
|
|
this.connect();
|
2012-06-01 21:09:59 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
shutdown: function() {
|
|
|
|
this.timer = null;
|
|
|
|
}
|
|
|
|
|
2012-03-12 23:46:08 +00:00
|
|
|
};
|
|
|
|
|
2012-10-31 16:13:28 +00:00
|
|
|
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([RadioInterfaceLayer]);
|