Bug 734300 - B2G RIL: Network registration state improvements. r=qDot
authorPhilipp von Weitershausen <philipp@weitershausen.de>
Mon, 12 Mar 2012 16:45:57 -0700
changeset 88809 b0cd3ea2398cac032087494a38d6900118bfc697
parent 88808 170757be69f3d5d24c5cd2ee8fa1a083f5efd5a4
child 88810 94c48b2660cb061f2b24fcd72461e44191f0df7e
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersqDot
bugs734300
milestone13.0a1
Bug 734300 - B2G RIL: Network registration state improvements. r=qDot
dom/system/b2g/RadioInterfaceLayer.js
dom/system/b2g/nsIRadioInterfaceLayer.idl
dom/system/b2g/ril_consts.js
dom/system/b2g/ril_worker.js
--- 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: