Bug 744709 - B2G RIL: control radio power via Settings API. r=philikon
authorJose Antonio Olivera Ortega <josea.olivera@gmail.com>
Wed, 23 May 2012 22:12:07 -0700
changeset 94798 a0bb98a2b52400b3e3532da66354c58e36b84420
parent 94797 f9485954f94ff384f35ba48c49fb1e60b9e71fb1
child 94799 d9064a680e21f650c728b116ca554ed34cc0b60d
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersphilikon
bugs744709
milestone15.0a1
Bug 744709 - B2G RIL: control radio power via Settings API. r=philikon
dom/system/gonk/RadioInterfaceLayer.js
dom/system/gonk/nsIRadioInterfaceLayer.idl
dom/system/gonk/ril_worker.js
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -60,16 +60,20 @@ XPCOMUtils.defineLazyServiceGetter(this,
 XPCOMUtils.defineLazyServiceGetter(this, "gSmsDatabaseService",
                                    "@mozilla.org/sms/rilsmsdatabaseservice;1",
                                    "nsISmsDatabaseService");
 
 XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
                                    "@mozilla.org/parentprocessmessagemanager;1",
                                    "nsIFrameMessageManager");
 
+XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService",
+                                   "@mozilla.org/settingsService;1",
+                                   "nsISettingsService");
+
 function convertRILCallState(state) {
   switch (state) {
     case RIL.CALL_STATE_ACTIVE:
       return nsIRadioInterfaceLayer.CALL_STATE_CONNECTED;
     case RIL.CALL_STATE_HOLDING:
       return nsIRadioInterfaceLayer.CALL_STATE_HELD;
     case RIL.CALL_STATE_DIALING:
       return nsIRadioInterfaceLayer.CALL_STATE_DIALING;
@@ -150,16 +154,21 @@ function RadioInterfaceLayer() {
     data:          {connected: false,
                      emergencyCallsOnly: false,
                      roaming: false,
                      operator: null,
                      type: null,
                      signalStrength: null,
                      relSignalStrength: null},
   };
+
+  // Read the 'ril.radio.disabled' setting in order to start with a known value at
+  // booting time.
+  gSettingsService.getLock().get("ril.radio.disabled", this);
+
   for each (let msgname in RIL_IPC_MSG_NAMES) {
     ppmm.addMessageListener(msgname, this);
   }
   Services.obs.addObserver(this, "xpcom-shutdown", false);
   Services.obs.addObserver(this, kMozSettingsChangedObserverTopic, false);
 
   this._sentSmsEnvelopes = {};
   this.portAddressedSmsApps = {};
@@ -169,17 +178,18 @@ RadioInterfaceLayer.prototype = {
   classID:   RADIOINTERFACELAYER_CID,
   classInfo: XPCOMUtils.generateCI({classID: RADIOINTERFACELAYER_CID,
                                     classDescription: "RadioInterfaceLayer",
                                     interfaces: [Ci.nsIWorkerHolder,
                                                  Ci.nsIRadioInterfaceLayer]}),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIWorkerHolder,
                                          Ci.nsIRadioInterfaceLayer,
-                                         Ci.nsIObserver]),
+                                         Ci.nsIObserver,
+                                         Ci.nsISettingsServiceCallback]),
 
   /**
    * Process a message from the content process.
    */
   receiveMessage: function receiveMessage(msg) {
     debug("Received '" + msg.name + "' message from content process");
     switch (msg.name) {
       case "RIL:GetRadioState":
@@ -276,17 +286,17 @@ RadioInterfaceLayer.prototype = {
         break;
       case "signalstrengthchange":
         this.handleSignalStrengthChange(message);
         break;
       case "operatorchange":
         this.handleOperatorChange(message);
         break;
       case "radiostatechange":
-        this.radioState.radioState = message.radioState;
+        this.handleRadioStateChange(message);
         break;
       case "cardstatechange":
         this.radioState.cardState = message.cardState;
         ppmm.sendAsyncMessage("RIL:CardStateChanged", message);
         break;
       case "sms-received":
         this.handleSmsReceived(message);
         return;
@@ -419,16 +429,34 @@ RadioInterfaceLayer.prototype = {
       ppmm.sendAsyncMessage("RIL:VoiceInfoChanged", this.radioState.voice);
     }
     if (operator != this.radioState.data.operator) {
       this.radioState.data.operator = operator;
       ppmm.sendAsyncMessage("RIL:DataInfoChanged", this.radioState.data);
     }
   },
 
+  handleRadioStateChange: function handleRadioStateChange(message) {
+    let newState = message.radioState;
+    if (this.radioState.radioState == newState) {
+      return;
+    }
+    this.radioState.radioState = newState;
+    //TODO Should we notify this change as a card state change?
+
+    if (this.radioState.radioState == RIL.GECKO_RADIOSTATE_OFF &&
+        this._radioEnabled) {
+      this.setRadioEnabled(true);
+    }
+    if (this.radioState.radioState == RIL.GECKO_RADIOSTATE_READY &&
+        !this._radioEnabled) {
+      this.setRadioEnabled(false);
+    }
+  },
+
   /**
    * Track the active call and update the audio system as its state changes.
    */
   _activeCall: null,
   updateCallAudioState: function updateCallAudioState() {
     if (!this._activeCall) {
       // Disable audio.
       gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_NORMAL;
@@ -632,31 +660,36 @@ RadioInterfaceLayer.prototype = {
     this._deliverDataCallCallback("receiveDataCallList",
                                   [datacalls, datacalls.length]);
   },
 
   /**
    * Handle setting changes.
    */
   handleMozSettingsChanged: function handleMozSettingsChanged(setting) {
-    // We only watch at "ril.data.enabled" flag changes for connecting or
-    // disconnecting the data call. If the value of "ril.data.enabled" is
-    // true and any of the remaining flags change the setting application
-    // should turn this flag to false and then to true in order to reload
-    // the new values and reconnect the data call.
-    if (setting.key != "ril.data.enabled") {
-      return;
-    }
-    if (!setting.value && RILNetworkInterface.connected) {
-      debug("Data call settings: disconnect data call.");
-      RILNetworkInterface.disconnect();
-    }
-    if (setting.value && !RILNetworkInterface.connected) {
-      debug("Data call settings connect data call.");
-      RILNetworkInterface.connect();
+    switch (setting.key) {
+      case "ril.radio.disabled":
+        this._radioEnabled = !setting.value;
+        this.setRadioEnabled(this._radioEnabled);
+        break;
+      case "ril.data.enabled":
+        // We only watch at "ril.data.enabled" flag changes for connecting or
+        // disconnecting the data call. If the value of "ril.data.enabled" is
+        // true and any of the remaining flags change the setting application
+        // should turn this flag to false and then to true in order to reload
+        // the new values and reconnect the data call.
+        if (!setting.value && RILNetworkInterface.connected) {
+          debug("Data call settings: disconnect data call.");
+          RILNetworkInterface.disconnect();
+        }
+        if (setting.value && !RILNetworkInterface.connected) {
+          debug("Data call settings connect data call.");
+          RILNetworkInterface.connect();
+        }
+        break;
     }
   },
 
   handleICCGetCardLock: function handleICCGetCardLock(message) {
     ppmm.sendAsyncMessage("RIL:GetCardLock:Return:OK", message);
   },
 
   handleICCSetCardLock: function handleICCSetCardLock(message) {
@@ -681,22 +714,43 @@ RadioInterfaceLayer.prototype = {
         }
         ppmm = null;
         Services.obs.removeObserver(this, "xpcom-shutdown");
         Services.obs.removeObserver(this, kMozSettingsChangedObserverTopic);
         break;
     }
   },
 
+  // nsISettingsServiceCallback
+
+  // Flag to determine the radio state to start with when we boot up. It
+  // corresponds to the 'ril.radio.disabled' setting from the UI.
+  _radioEnabled: null,
+
+  handle: function handle(aName, aResult) {
+    if (aName == "ril.radio.disabled") {
+      this._radioEnabled = !aResult;
+    }
+  },
+
+  handleError: function handleError(aErrorMessage) {
+    this._radioEnabled = true;
+  },
+
   // nsIRadioWorker
 
   worker: null,
 
   // nsIRadioInterfaceLayer
 
+  setRadioEnabled: function setRadioEnabled(value) {
+    debug("Setting radio power to " + value);
+    this.worker.postMessage({type: "setRadioPower", on: value});
+  },
+
   radioState: null,
 
   // Handle phone functions of nsIRILContentHelper
 
   enumerateCalls: function enumerateCalls() {
     debug("Requesting enumeration of calls for callback");
     this.worker.postMessage({type: "enumerateCalls"});
   },
--- a/dom/system/gonk/nsIRadioInterfaceLayer.idl
+++ b/dom/system/gonk/nsIRadioInterfaceLayer.idl
@@ -129,17 +129,17 @@ interface nsIRILContentHelper : nsIMobil
   void rejectCall(in unsigned long callIndex);
   void holdCall(in unsigned long callIndex);
   void resumeCall(in unsigned long callIndex);
 
   attribute bool microphoneMuted;
   attribute bool speakerEnabled;
 };
 
-[scriptable, uuid(d976f4c2-af5b-4fe1-97c2-c9c5d0d1af5c)]
+[scriptable, uuid(0ffa10cf-9629-42d6-bc48-6d8bea90d1a9)]
 interface nsIRadioInterfaceLayer : nsISupports
 {
   const unsigned short CALL_STATE_UNKNOWN = 0;
   const unsigned short CALL_STATE_DIALING = 1;
   const unsigned short CALL_STATE_ALERTING = 2;
   const unsigned short CALL_STATE_BUSY = 3;
   const unsigned short CALL_STATE_CONNECTING = 4;
   const unsigned short CALL_STATE_CONNECTED = 5;
@@ -152,16 +152,21 @@ 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;
 
+  /**
+   * Activates or deactivates radio power.
+   */
+  void setRadioEnabled(in bool value);
+
   readonly attribute jsval radioState;
 
   /**
    * PDP APIs
    */
   void setupDataCall(in long radioTech,
                      in DOMString apn,
                      in DOMString user,
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -1114,20 +1114,20 @@ let RIL = {
   },
 
   /**
    * Request the phone's radio power to be switched on or off.
    *
    * @param on
    *        Boolean indicating the desired power state.
    */
-  setRadioPower: function setRadioPower(on) {
+  setRadioPower: function setRadioPower(options) {
     Buf.newParcel(REQUEST_RADIO_POWER);
     Buf.writeUint32(1);
-    Buf.writeUint32(on ? 1 : 0);
+    Buf.writeUint32(options.on ? 1 : 0);
     Buf.sendParcel();
   },
 
   /**
    * Set screen state.
    *
    * @param on
    *        Boolean indicating whether the screen should be on or off.
@@ -2872,33 +2872,27 @@ RIL[UNSOLICITED_RESPONSE_RADIO_STATE_CHA
   }
   if (this.radioState == newState) {
     return;
   }
 
   // TODO hardcoded for now (see bug 726098)
   let cdma = false;
 
-  if (this.radioState == GECKO_RADIOSTATE_UNAVAILABLE &&
-      newState != GECKO_RADIOSTATE_UNAVAILABLE) {
+  if ((this.radioState == GECKO_RADIOSTATE_UNAVAILABLE ||
+       this.radioState == GECKO_RADIOSTATE_OFF) &&
+       newState == GECKO_RADIOSTATE_READY) {
     // The radio became available, let's get its info.
     if (cdma) {
       this.getDeviceIdentity();
     } else {
       this.getIMEI();
       this.getIMEISV();
     }
     this.getBasebandVersion();
-
-    //XXX TODO For now, just turn the radio on if it's off. for the real
-    // deal we probably want to do the opposite: start with a known state
-    // when we boot up and let the UI layer control the radio power.
-    if (newState == GECKO_RADIOSTATE_OFF) {
-      this.setRadioPower(true);
-    }
   }
 
   this.radioState = newState;
   this.sendDOMMessage({
     type: "radiostatechange",
     radioState: newState
   });