Bug 817985 - Mobile data connection is not disconnected when we are connected to Wifi network. r=vicamo, a=tef+
authorShian-Yow Wu <swu@mozilla.com>
Wed, 23 Jan 2013 12:05:34 +0800
changeset 118291 2e4b271c2ef1bb3b426d3b95bd2e74c78fd1e3fc
parent 118290 291138b021aacc000b8c311b963716752feeff25
child 118292 eb62fc2992252aa7ccf0bf132c7db371e32a6c31
push id331
push userryanvm@gmail.com
push dateThu, 24 Jan 2013 00:20:48 +0000
reviewersvicamo, tef
bugs817985
milestone18.0
Bug 817985 - Mobile data connection is not disconnected when we are connected to Wifi network. r=vicamo, a=tef+
dom/system/gonk/NetworkManager.js
dom/system/gonk/RadioInterfaceLayer.js
dom/system/gonk/nsIRadioInterfaceLayer.idl
--- a/dom/system/gonk/NetworkManager.js
+++ b/dom/system/gonk/NetworkManager.js
@@ -206,30 +206,38 @@ NetworkManager.prototype = {
                 network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS ||
                 network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_SUPL) {
               this.addHostRoute(network);
             }
             // Remove pre-created default route and let setAndConfigureActive()
             // to set default route only on preferred network
             this.removeDefaultRoute(network.name);
             this.setAndConfigureActive();
+            // Update data connection when Wifi connected/disconnected
+            if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_WIFI) {
+              this.mRIL.updateRILNetworkInterface();
+            }
             // Turn on wifi tethering when the callback is set.
             if (this.waitForConnectionReadyCallback) {
               this.waitForConnectionReadyCallback.call(this);
               this.waitForConnectionReadyCallback = null;
             }
             break;
           case Ci.nsINetworkInterface.NETWORK_STATE_DISCONNECTED:
             // Remove host route for data calls
             if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE ||
                 network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS ||
                 network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_SUPL) {
               this.removeHostRoute(network);
             }
             this.setAndConfigureActive();
+            // Update data connection when Wifi connected/disconnected
+            if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_WIFI) {
+              this.mRIL.updateRILNetworkInterface();
+            }
             break;
         }
         break;
       case TOPIC_MOZSETTINGS_CHANGED:
         let setting = JSON.parse(data);
         this.handle(setting.key, setting.value);
         break;
       case TOPIC_PREF_CHANGED:
@@ -822,16 +830,22 @@ NetworkManager.prototype = {
     // Disable tethering settings when fail to enable it.
     if (isError(code)) {
       this.tetheringSettings[SETTINGS_USB_ENABLED] = false;
       settingsLock.set("tethering.usb.enabled", false, null);
     }
   }
 };
 
+XPCOMUtils.defineLazyGetter(NetworkManager.prototype, "mRIL", function () {
+    return Cc["@mozilla.org/telephony/system-worker-manager;1"]
+              .getService(Ci.nsIInterfaceRequestor)
+              .getInterface(Ci.nsIRadioInterfaceLayer);
+});
+
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkManager]);
 
 
 let debug;
 if (DEBUG) {
   debug = function (s) {
     dump("-*- NetworkManager: " + s + "\n");
   };
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -1131,32 +1131,42 @@ RadioInterfaceLayer.prototype = {
       dataInfo.state == RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED;
     let haveDataConnection =
       dataInfo.type != RIL.GECKO_MOBILE_CONNECTION_STATE_UNKNOWN;
     if (!isRegistered || !haveDataConnection) {
       debug("RIL is not ready for data connection: Phone's not registered " +
             "or doesn't have data connection.");
       return;
     }
+    let wifi_active = false;
+    if (gNetworkManager.active &&
+        gNetworkManager.active.type == Ci.nsINetworkInterface.NETWORK_TYPE_WIFI) {
+      wifi_active = true;
+    }
 
     if (this.dataNetworkInterface.connected &&
         (!this.dataCallSettings["enabled"] ||
-         (dataInfo.roaming && !this.dataCallSettings["roaming_enabled"]))) {
+         (dataInfo.roaming && !this.dataCallSettings["roaming_enabled"]) ||
+         (wifi_active && this.shareDefaultAPNCounter == 0))) {
       debug("Data call settings: disconnect data call.");
       this.dataNetworkInterface.disconnect();
       return;
     }
     if (!this.dataCallSettings["enabled"] || this.dataNetworkInterface.connected) {
       debug("Data call settings: nothing to do.");
       return;
     }
     if (dataInfo.roaming && !this.dataCallSettings["roaming_enabled"]) {
       debug("We're roaming, but data roaming is disabled.");
       return;
     }
+    if (wifi_active && this.shareDefaultAPNCounter == 0) {
+      debug("Don't connect data call when Wifi is connected.");
+      return;
+    }
     if (this._changingRadioPower) {
       // We're changing the radio power currently, ignore any changes.
       return;
     }
 
     debug("Data call settings: connect data call.");
     this.dataNetworkInterface.connect(this.dataCallSettings);
   },
@@ -2470,19 +2480,26 @@ RadioInterfaceLayer.prototype = {
       case "mms":
         return (this.dataCallSettingsMMS["apn"] == this.dataCallSettings["apn"]);
       case "supl":
         return (this.dataCallSettingsSUPL["apn"] == this.dataCallSettings["apn"]);
       return false;
     }
   },
 
+  /**
+   * Number of activated secondary APN data call that shares with default APN.
+   */
+  shareDefaultAPNCounter: 0,
+
   setupDataCallByType: function setupDataCallByType(apntype) {
     if (apntype != "default" && this.usingDefaultAPN(apntype)) {
-      debug("Secondary APN type " + apntype + " goes through default APN, nothing to do.");
+      debug("Setup secondary APN type " + apntype + " which goes through default APN.");
+      this.shareDefaultAPNCounter++;
+      this.updateRILNetworkInterface();
       return;
     }
     switch (apntype) {
       case "default":
         this.dataNetworkInterface.connect(this.dataCallSettings);
         break;
       case "mms":
         this.mmsNetworkInterface.connect(this.dataCallSettingsMMS);
@@ -2493,17 +2510,21 @@ RadioInterfaceLayer.prototype = {
       default:
         debug("Unsupported APN type " + apntype);
         break;
     }
   },
 
   deactivateDataCallByType: function deactivateDataCallByType(apntype) {
     if (apntype != "default" && this.usingDefaultAPN(apntype)) {
-      debug("Secondary APN type " + apntype + " goes through default APN, nothing to do.");
+      debug("Deactivate secondary APN type " + apntype + " which goes through default APN.");
+      if (this.shareDefaultAPNCounter > 0) {
+        this.shareDefaultAPNCounter--;
+        this.updateRILNetworkInterface();
+      }
       return;
     }
     switch (apntype) {
       case "default":
         this.dataNetworkInterface.disconnect();
         break;
       case "mms":
         this.mmsNetworkInterface.disconnect();
--- a/dom/system/gonk/nsIRadioInterfaceLayer.idl
+++ b/dom/system/gonk/nsIRadioInterfaceLayer.idl
@@ -286,17 +286,17 @@ interface nsIRilContext : nsISupports
 
   readonly attribute nsIICCRecords icc;
 
   readonly attribute nsIDOMMozMobileConnectionInfo voice;
 
   readonly attribute nsIDOMMozMobileConnectionInfo data;
 };
 
-[scriptable, uuid(8526675d-2be7-4289-9d97-71e30c712010)]
+[scriptable, uuid(a585a7f4-6a64-4d6b-a3fb-bcd90624dcd4)]
 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;
@@ -330,16 +330,18 @@ interface nsIRadioInterfaceLayer : nsISu
                      in DOMString pdptype);
   void deactivateDataCall(in DOMString cid,
                           in DOMString reason);
   void getDataCallList();
 
   void registerDataCallCallback(in nsIRILDataCallback callback);
   void unregisterDataCallCallback(in nsIRILDataCallback callback);
 
+  void updateRILNetworkInterface();
+
   /**
    * SMS-related functionality.
    */
   nsIDOMMozSmsSegmentInfo getSegmentInfoForText(in DOMString text);
 
   void sendSMS(in DOMString number,
                in DOMString message,
                in nsISmsRequest request);