Bug 734300 - B2G RIL: Network registration state improvements. r=qDot
--- 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 = false; // set to true to see debug messages
+const DEBUG = true; // 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;
@@ -136,21 +136,25 @@ DataCallInfo.protoptype = {
};
function RadioInterfaceLayer() {
this.worker = new ChromeWorker("resource://gre/modules/ril_worker.js");
this.worker.onerror = this.onerror.bind(this);
this.worker.onmessage = this.onmessage.bind(this);
debug("Starting Worker\n");
- this.currentState = {
+ this.radioState = {
+ radioState: null,
+ cardState: null,
+ connected: null,
+ roaming: null,
signalStrength: null,
+ bars: null,
operator: null,
- radioState: null,
- cardState: null
+ type: null,
};
}
RadioInterfaceLayer.prototype = {
classID: RADIOINTERFACELAYER_CID,
classInfo: XPCOMUtils.generateCI({classID: RADIOINTERFACELAYER_CID,
classDescription: "RadioInterfaceLayer",
interfaces: [Ci.nsIWorkerHolder,
@@ -164,17 +168,17 @@ RadioInterfaceLayer.prototype = {
event.lineno + ": " + event.message + "\n");
event.preventDefault();
},
/**
* Process the incoming message from the RIL worker:
* (1) Update the current state. This way any component that hasn't
* been listening for callbacks can easily catch up by looking at
- * this.currentState.
+ * this.radioState.
* (2) Update state in related systems such as the audio.
* (3) Multiplex the message to telephone callbacks.
*/
onmessage: function onmessage(event) {
let message = event.data;
debug("Received message: " + JSON.stringify(message));
switch (message.type) {
case "callStateChange":
@@ -185,32 +189,68 @@ 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":
- this.currentState.registrationState = message.registrationState;
+ //TODO for simplicity's sake, for now we only look at
+ // gprsregistrationstatechange.
break;
case "gprsregistrationstatechange":
- this.currentState.gprsRegistrationState = message.gprsRegistrationState;
+ let state = message.gprsRegistrationState;
+ 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) ||
+ (state.regState == RIL.NETWORK_CREG_STATE_REGISTERED_ROAMING);
+ this.radioState.roaming =
+ this.radioState.connected &&
+ (state.regState == RIL.NETWORK_CREG_STATE_REGISTERED_ROAMING);
+ this.radioState.type = RIL.GECKO_RADIO_TECH[state.radioTech] || null;
+ this.notifyRadioStateChanged();
break;
case "signalstrengthchange":
- this.currentState.signalStrength = message.signalStrength;
+ //TODO GSM only?
+ let signalStrength = message.signalStrength.gsmSignalStrength;
+ if (signalStrength == 99) {
+ signalStrength = null;
+ }
+ this.radioState.signalStrength = signalStrength;
+ if (message.signalStrength.bars) {
+ this.radioState.bars = message.signalStrength.bars;
+ } else if (signalStrength != null) {
+ //TODO pretty sure that the bars aren't linear, but meh...
+ // Convert signal strength (0...31) to bars (0...4).
+ this.radioState.bars = Math.round(signalStrength / 7.75);
+ } else {
+ this.radioState.bars = null;
+ }
+ this.notifyRadioStateChanged();
break;
case "operatorchange":
- this.currentState.operator = message.operator;
+ this.radioState.operator = message.operator.alphaLong;
+ this.notifyRadioStateChanged();
break;
case "radiostatechange":
- this.currentState.radioState = message.radioState;
+ this.radioState.radioState = message.radioState;
+ this.notifyRadioStateChanged();
break;
case "cardstatechange":
- this.currentState.cardState = message.cardState;
+ this.radioState.cardState = message.cardState;
+ if (!message.cardState || message.cardState == "absent") {
+ this.resetRadioState();
+ }
+ this.notifyRadioStateChanged();
break;
case "sms-received":
this.handleSmsReceived(message);
return;
case "sms-sent":
this.handleSmsSent(message);
return;
case "datacallstatechange":
@@ -371,23 +411,37 @@ RadioInterfaceLayer.prototype = {
datacalls.push(new DataCallInfo(datacall.state,
datacall.cid,
datacall.apn));
}
this._deliverDataCallCallback("receiveDataCallList",
[datacalls, datacalls.length]);
},
+ resetRadioState: function resetRadioState() {
+ this.radioState.connected = null;
+ this.radioState.roaming = null;
+ this.radioState.signalStrength = null;
+ this.radioState.bars = null;
+ this.radioState.operator = null;
+ this.radioState.type = null;
+ },
+
+ notifyRadioStateChanged: function notifyRadioStateChanged() {
+ debug("Radio state changed: " + JSON.stringify(this.radioState));
+ Services.obs.notifyObservers(null, "ril-radiostate-changed", null);
+ },
+
// nsIRadioWorker
worker: null,
// nsIRadioInterfaceLayer
- currentState: null,
+ radioState: null,
dial: function dial(number) {
debug("Dialing " + number);
this.worker.postMessage({type: "dial", number: number});
},
hangUp: function hangUp(callIndex) {
debug("Hanging up call no. " + callIndex);
--- a/dom/system/b2g/nsIRadioInterfaceLayer.idl
+++ b/dom/system/b2g/nsIRadioInterfaceLayer.idl
@@ -111,17 +111,17 @@ interface nsIRILDataCallback : nsISuppor
* Array of nsIRILDataCallInfo objects.
* @param length
* Lenght of the aforementioned array.
*/
void receiveDataCallList([array,size_is(length)] in nsIRILDataCallInfo dataCalls,
in unsigned long length);
};
-[scriptable, uuid(aeb7ffe7-7d3a-4b7d-9b59-b6d3ae1c72ed)]
+[scriptable, uuid(78fc7ef6-0941-4fc8-89ff-de9398ef478a)]
interface nsIRadioInterfaceLayer : nsISupports
{
const unsigned short CALL_STATE_UNKNOWN = 0;
const unsigned short CALL_STATE_DIALING = 1;
const unsigned short CALL_STATE_RINGING = 2;
const unsigned short CALL_STATE_BUSY = 3;
const unsigned short CALL_STATE_CONNECTING = 4;
const unsigned short CALL_STATE_CONNECTED = 5;
@@ -134,17 +134,17 @@ interface nsIRadioInterfaceLayer : nsISu
// Keep consistent with GECKO_DATACALL_STATE_* values in ril_consts.js
const unsigned short DATACALL_STATE_UNKNOWN = 0;
const unsigned short DATACALL_STATE_CONNECTING = 1;
const unsigned short DATACALL_STATE_CONNECTED = 2;
const unsigned short DATACALL_STATE_DISCONNECTING = 3;
const unsigned short DATACALL_STATE_DISCONNECTED = 4;
- readonly attribute jsval currentState;
+ readonly attribute jsval radioState;
void registerCallback(in nsIRILTelephonyCallback callback);
void unregisterCallback(in nsIRILTelephonyCallback callback);
/**
* Will continue calling callback.enumerateCallState until the callback
* returns false.
*/
--- a/dom/system/b2g/ril_consts.js
+++ b/dom/system/b2g/ril_consts.js
@@ -1117,19 +1117,34 @@ const GECKO_NETWORK_STATE_SUSPENDED = 2;
const GECKO_NETWORK_STATE_DISCONNECTING = 3;
const GECKO_NETWORK_STATE_DISCONNECTED = 4;
// Other Gecko-specific constants
const GECKO_RADIOSTATE_UNAVAILABLE = "unavailable";
const GECKO_RADIOSTATE_OFF = "off";
const GECKO_RADIOSTATE_READY = "ready";
-const GECKO_CARDSTATE_UNAVAILABLE = "unavailable";
+const GECKO_CARDSTATE_UNAVAILABLE = null;
const GECKO_CARDSTATE_ABSENT = "absent";
const GECKO_CARDSTATE_PIN_REQUIRED = "pin_required";
const GECKO_CARDSTATE_PUK_REQUIRED = "puk_required";
const GECKO_CARDSTATE_NETWORK_LOCKED = "network_locked";
-const GECKO_CARDSTATE_NOT_READY = "not_ready";
+const GECKO_CARDSTATE_NOT_READY = null;
const GECKO_CARDSTATE_READY = "ready";
+const GECKO_RADIO_TECH = [
+ null,
+ "gprs",
+ "edge",
+ "umts",
+ "is95a",
+ "is95b",
+ "1xrtt",
+ "evdo0",
+ "evdoa",
+ "hsdpa",
+ "hsupa",
+ "hspa",
+ "evdob",
+];
// Allow this file to be imported via Components.utils.import().
const EXPORTED_SYMBOLS = Object.keys(this);
--- a/dom/system/b2g/ril_worker.js
+++ b/dom/system/b2g/ril_worker.js
@@ -1108,21 +1108,26 @@ RIL[REQUEST_HANGUP_FOREGROUND_RESUME_BAC
RIL[REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE] = null;
RIL[REQUEST_SWITCH_HOLDING_AND_ACTIVE] = null;
RIL[REQUEST_CONFERENCE] = null;
RIL[REQUEST_UDUB] = function REQUEST_UDUB(length) {
Phone.onRejectCall();
};
RIL[REQUEST_LAST_CALL_FAIL_CAUSE] = null;
RIL[REQUEST_SIGNAL_STRENGTH] = function REQUEST_SIGNAL_STRENGTH() {
+ let signalStrength = Buf.readUint32();
+ // The SGS2 seems to compute the number of bars for us and expose those
+ // instead of the actual signal strength.
+ let bars = signalStrength >> 8;
+ signalStrength = signalStrength & 0xff;
let strength = {
// Valid values are (0-31, 99) as defined in TS 27.007 8.5.
- // For some reason we're getting int32s like [99, 4, 0, 0] and [99, 3, 0, 0]
- // here, so let's strip of anything beyond the first byte.
- gsmSignalStrength: Buf.readUint32() & 0xff,
+ gsmSignalStrength: signalStrength,
+ // Non-standard extension by the SGS2.
+ bars: bars,
// GSM bit error rate (0-7, 99) as defined in TS 27.007 8.5.
gsmBitErrorRate: Buf.readUint32(),
// The CDMA RSSI value.
cdmaDBM: Buf.readUint32(),
// The CDMA EC/IO.
cdmaECIO: Buf.readUint32(),
// The EVDO RSSI value.
evdoDBM: Buf.readUint32(),
@@ -1645,16 +1650,17 @@ let Phone = {
if (DEBUG) {
debug("iccStatus: " + JSON.stringify(iccStatus));
}
this.iccStatus = iccStatus;
if ((!iccStatus) || (iccStatus.cardState == CARD_STATE_ABSENT)) {
if (DEBUG) debug("ICC absent");
if (this.cardState == GECKO_CARDSTATE_ABSENT) {
+ this.operator = null;
return;
}
this.cardState = GECKO_CARDSTATE_ABSENT;
this.sendDOMMessage({type: "cardstatechange",
cardState: this.cardState});
return;
}
@@ -1682,16 +1688,17 @@ let Phone = {
if (!app) {
if (DEBUG) {
debug("Subscription application is not present in iccStatus.");
}
if (this.cardState == GECKO_CARDSTATE_ABSENT) {
return;
}
this.cardState = GECKO_CARDSTATE_ABSENT;
+ this.operator = null;
this.sendDOMMessage({type: "cardstatechange",
cardState: this.cardState});
return;
}
let newCardState;
switch (app.app_state) {
case CARD_APP_STATE_PIN: