Bug 734299 - Part 3: Set up a datacall when registering with the network. r=qDot DONTBUILD because NPOTB
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -439,8 +439,17 @@ pref("b2g.keys.menu.enabled", true);
pref("b2g.keys.search.enabled", false);
// Screen timeout in minutes
pref("power.screen.timeout", 60);
pref("full-screen-api.enabled", true);
pref("media.volume.steps", 10);
+
+// Data connection settings. These will eventually live in the
+// navigator.settings API, or even in a database where we can look
+// it up automatically (bug 729440), but for this will have to do.
+pref("ril.data.enabled", false);
+pref("ril.data.roaming.enabled", false);
+pref("ril.data.apn", "");
+pref("ril.data.user", "");
+pref("ril.data.passwd", "");
--- a/dom/system/b2g/RadioInterfaceLayer.js
+++ b/dom/system/b2g/RadioInterfaceLayer.js
@@ -42,17 +42,17 @@
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
var RIL = {};
Cu.import("resource://gre/modules/ril_consts.js", RIL);
-const DEBUG = true; // set to true to see debug messages
+const DEBUG = false; // set to true to see debug messages
const RADIOINTERFACELAYER_CID =
Components.ID("{2d831c8d-6017-435b-a80c-e5d422810cea}");
const DATACALLINFO_CID =
Components.ID("{ef474cd9-94f7-4c05-a31b-29b9de8a10d2}");
const nsIAudioManager = Ci.nsIAudioManager;
const nsIRadioInterfaceLayer = Ci.nsIRadioInterfaceLayer;
@@ -189,21 +189,25 @@ RadioInterfaceLayer.prototype = {
// This one will handle its own notifications.
this.handleCallDisconnected(message.call);
break;
case "enumerateCalls":
// This one will handle its own notifications.
this.handleEnumerateCalls(message.calls);
break;
case "registrationstatechange":
- //TODO for simplicity's sake, for now we only look at
- // gprsregistrationstatechange.
+ this.updateDataConnection(message.registrationState);
break;
case "gprsregistrationstatechange":
let state = message.gprsRegistrationState;
+ this.updateDataConnection(state);
+
+ //TODO for simplicity's sake, for now we only look at
+ // gprsRegistrationState for the radio registration state.
+
if (!state || state.regState == RIL.NETWORK_CREG_STATE_UNKNOWN) {
this.resetRadioState();
this.notifyRadioStateChanged();
return;
}
this.radioState.connected =
(state.regState == RIL.NETWORK_CREG_STATE_REGISTERED_HOME) ||
@@ -274,16 +278,51 @@ RadioInterfaceLayer.prototype = {
+ " timestamp=" + message.localTimeStampInMS);
}
break;
default:
throw new Error("Don't know about this message type: " + message.type);
}
},
+ _isDataEnabled: function _isDataEnabled() {
+ try {
+ return Services.prefs.getBoolPref("ril.data.enabled");
+ } catch(ex) {
+ return false;
+ }
+ },
+
+ _isDataRoamingEnabled: function _isDataRoamingEnabled() {
+ try {
+ return Services.prefs.getBoolPref("ril.data.roaming.enabled");
+ } catch(ex) {
+ return false;
+ }
+ },
+
+ updateDataConnection: function updateDataConnection(state) {
+ if (!this._isDataEnabled()) {
+ return;
+ }
+
+ let isRegistered =
+ state.regState == RIL.NETWORK_CREG_STATE_REGISTERED_HOME ||
+ (this._isDataRoamingEnabled() &&
+ state.regState == RIL.NETWORK_CREG_STATE_REGISTERED_ROAMING);
+ let haveDataConnection =
+ state.radioTech != RIL.NETWORK_CREG_TECH_UNKNOWN;
+
+ if (isRegistered && haveDataConnection) {
+ debug("Radio is ready for data connection.");
+ // RILNetworkInterface will ignore this if it's already connected.
+ RILNetworkInterface.connect();
+ }
+ },
+
/**
* Track the active call and update the audio system as its state changes.
*
* XXX Needs some more work to support hold/resume.
*/
_activeCall: null,
updateCallAudioState: function updateCallAudioState() {
if (!this._activeCall) {
@@ -637,16 +676,118 @@ RadioInterfaceLayer.prototype = {
},
getDataCallList: function getDataCallList() {
this.worker.postMessage({type: "getDataCallList"});
},
};
+
+let RILNetworkInterface = {
+
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIRILDataCallback]),
+
+ state: RIL.GECKO_NETWORK_STATE_UNKNOWN,
+ name: null,
+
+ worker: null,
+ cid: null,
+ registeredAsDataCallCallback: false,
+ connecting: false,
+
+ initWorker: function initWorker() {
+ debug("Starting net_worker.");
+ this.worker = new ChromeWorker("resource://gre/modules/net_worker.js");
+ this.worker.onerror = function onerror(event) {
+ debug("Received error from worker: " + event.filename +
+ ":" + event.lineno + ": " + event.message + "\n");
+ // Prevent the event from bubbling any further.
+ event.preventDefault();
+ };
+ },
+
+ // nsIRILDataCallback
+
+ dataCallStateChanged: function dataCallStateChanged(cid, interfaceName, callState) {
+ if (this.connecting &&
+ callState == RIL.GECKO_NETWORK_STATE_CONNECTING) {
+ this.connecting = false;
+ this.cid = cid;
+ this.name = interfaceName;
+ debug("Data call ID: " + cid + ", interface name: " + interfaceName);
+ }
+ if (this.cid != cid) {
+ return;
+ }
+ if (this.state == callState) {
+ return;
+ }
+
+ this.state = callState;
+
+ if (callState == RIL.GECKO_NETWORK_STATE_CONNECTED) {
+ debug("Data call is connected, going to configure networking bits.");
+ this.worker.postMessage({cmd: "setDefaultRouteAndDNS",
+ ifname: this.name});
+ }
+ },
+
+ receiveDataCallList: function receiveDataCallList(dataCalls, length) {
+ },
+
+ // Helpers
+
+ get mRIL() {
+ delete this.mRIL;
+ return this.mRIL = Cc["@mozilla.org/telephony/system-worker-manager;1"]
+ .getService(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIRadioInterfaceLayer);
+ },
+
+ connect: function connect() {
+ if (this.connecting ||
+ this.state == RIL.GECKO_NETWORK_STATE_CONNECTED ||
+ this.state == RIL.GECKO_NETWORK_STATE_SUSPENDED ||
+ this.state == RIL.GECKO_NETWORK_STATE_DISCONNECTING) {
+ return;
+ }
+ if (!this.registeredAsDataCallCallback) {
+ this.mRIL.registerDataCallCallback(this);
+ this.registeredAsDataCallCallback = true;
+ }
+
+ if (!this.worker) {
+ this.initWorker();
+ }
+
+ let apn, user, passwd;
+ // Eventually these values would be retrieved from the user's preferences
+ // via the settings API. For now we just use Gecko's preferences.
+ try {
+ apn = Services.prefs.getCharPref("ril.data.apn");
+ user = Services.prefs.getCharPref("ril.data.user");
+ passwd = Services.prefs.getCharPref("ril.data.passwd");
+ } catch (ex) {
+ debug("No APN settings found, not going to set up data connection.");
+ return;
+ }
+ debug("Going to set up data connection with APN " + apn);
+ this.mRIL.setupDataCall(RIL.DATACALL_RADIOTECHNOLOGY_GSM,
+ apn, user, passwd,
+ RIL.DATACALL_AUTH_PAP_OR_CHAP, "IP");
+ this.connecting = true;
+ },
+
+ disconnect: function disconnect() {
+ this.mRIL.deactivateDataCall(this.cid);
+ },
+
+};
+
const NSGetFactory = XPCOMUtils.generateNSGetFactory([RadioInterfaceLayer]);
let debug;
if (DEBUG) {
debug = function (s) {
dump("-*- RadioInterfaceLayer: " + s + "\n");
};
} else {