Bug 787421 - Wifi implementation. r=mrbkap
authorVincent Chang <vchang@mozilla.com>
Thu, 13 Sep 2012 15:19:47 +0800
changeset 108079 598c1564bf418fb461a8a66523eda2bb905c876c
parent 108078 baf1182b6924c30251c909316712e3707402af97
child 108080 3b1d2d4be3377d40ad9fa1c98f2d413fd0c2cd77
push id82
push usershu@rfrn.org
push dateFri, 05 Oct 2012 13:20:22 +0000
reviewersmrbkap
bugs787421
milestone18.0a1
Bug 787421 - Wifi implementation. r=mrbkap
dom/wifi/WifiWorker.js
--- a/dom/wifi/WifiWorker.js
+++ b/dom/wifi/WifiWorker.js
@@ -1002,38 +1002,48 @@ var WifiManager = (function() {
     }
   }
 
   // Get wifi interface and load wifi driver when enable Ap mode.
   manager.setWifiApEnabled = function(enabled, callback) {
     if (enabled) {
       getProperty("wifi.interface", "tiwlan0", function (ifname) {
         if (!ifname) {
-          callback(-1, null);
+          callback(enabled);
           return;
         }
         manager.ifname = ifname;
         loadDriver(function (status) {
           if (status < 0) {
-            callback(status, null);
+            callback(enabled);
             return;
           }
           WifiNetworkInterface.name = manager.ifname;
           manager.state = "WIFITETHERING";
-          callback(0, WifiNetworkInterface);
+          // Turning on wifi tethering.
+          gNetworkManager.setWifiTethering(enabled, WifiNetworkInterface, function(result) {
+            // Pop out current request.
+            callback(enabled);
+            // Should we fire a dom event if we fail to set wifi tethering  ?
+            debug("Enable Wifi tethering result: " + (result ? result : "successfully"));
+          });
         });
       });
     } else {
       manager.state = "UNINITIALIZED";
-      unloadDriver(function(status) {
-        if (status < 0) {
-          callback(status, null);
-          return;
-        }
-        callback(0, null);
+      gNetworkManager.setWifiTethering(enabled, WifiNetworkInterface, function(result) {
+        // Should we fire a dom event if we fail to set wifi tethering  ?
+        debug("Disable Wifi tethering result: " + (result ? result : "successfully"));
+        // Unload wifi driver even if we fail to control wifi tethering.
+        unloadDriver(function(status) {
+          if (status < 0) {
+            debug("Fail to unload wifi driver");
+          }
+          callback(enabled);
+        });
       });
     }
   }
 
   manager.disconnect = disconnectCommand;
   manager.reconnect = reconnectCommand;
   manager.reassociate = reassociateCommand;
 
@@ -2078,17 +2088,17 @@ WifiWorker.prototype = {
     }
 
     // If there were requests queued after this one, run them.
     if (this._stateRequests.length > 0) {
       let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
       let self = this;
       timer.initWithCallback(function(timer) {
         if ("callback" in self._stateRequests[0]) {
-          self._stateRequests[0].callback.call(self);
+          self._stateRequests[0].callback.call(self, self._stateRequests[0].enabled);
         } else {
           WifiManager.setWifiEnabled(self._stateRequests[0].enabled,
                                      self._setWifiEnabledCallback.bind(this));
         }
         timer = null;
       }, 1000, Ci.nsITimer.TYPE_ONE_SHOT);
     }
   },
@@ -2118,17 +2128,17 @@ WifiWorker.prototype = {
     //   - If we get multiple requests to turn on and off wifi before the
     //     current request has finished, then we need to queue up the requests
     //     and handle each on/off request in turn.
     //   - Because we can't pass a callback to WifiManager.start, we need to
     //     have a way to communicate with our onsupplicantconnection callback.
     this._stateRequests.push(msg);
     if (this._stateRequests.length === 1) {
       if ("callback" in this._stateRequests[0]) {
-        this._stateRequests[0].callback.call(this);
+        this._stateRequests[0].callback.call(this, msg.enabled);
       } else {
         WifiManager.setWifiEnabled(msg.enabled, this._setWifiEnabledCallback.bind(this));
       }
     }
   },
 
   setWifiEnabledInternal: function(enabled, callback) {
     this.setWifiEnabled({enabled: enabled, callback: callback});
@@ -2296,54 +2306,72 @@ WifiWorker.prototype = {
   // that RadioManager never actually tries to get the worker from us.
   get worker() { throw "Not implemented"; },
 
   shutdown: function() {
     debug("shutting down ...");
     this.setWifiEnabled({enabled: false});
   },
 
-  setWifiTethering: function(enabled, callback) {
-    debug("Requesting Wifi Tethering from NetworkManager " + enabled);
-    // Wifi is disabled switch to Ap mode immediately.
-    if (!WifiManager.enabled) {
-      this.setWifiApEnabled(enabled, callback.wifiTetheringEnabledChange);
+  nextRequest: function nextRequest(state) {
+    if (this._stateRequests.length <= 0 ||
+        !("callback" in this._stateRequests[0])) {
+      return;
+    }
+
+    do {
+      this._stateRequests.shift();
+    } while (this._stateRequests.length &&
+             this._stateRequests[0].enabled === state);
+
+    // Serve the pending requests.
+    if (this._stateRequests.length > 0) {
+      if ("callback" in this._stateRequests[0]) {
+        this._stateRequests[0].callback.call(this,
+                                             this._stateRequests[0].enabled);
+      } else {
+        WifiManager.setWifiEnabled(this._stateRequests[0].enabled,
+                                   this._setWifiEnabledCallback.bind(this));
+      }
+    }
+  },
+
+  handleWifiEnabled: function(enabled) {
+    if (WifiManager.enabled === enabled) {
       return;
     }
-    // Wifi is enabled, disabled it before switch to Ap mode.
+    // Disable wifi tethering before enabling wifi.
+    if (gNetworkManager.wifiTetheringEnabled) {
+      this.setWifiEnabledInternal(false, function(data) {
+        this.setWifiApEnabled(data, this.nextRequest.bind(this));
+      }.bind(this));
+    }
+    this.setWifiEnabled({enabled: enabled});
+  },
+
+  handleWifiTetheringEnabled: function(enabled) {
+    if (gNetworkManager.wifiTetheringEnabled === enabled) {
+      return;
+    }
+
+    // Wifi is disabled
+    if (!WifiManager.enabled) {
+      this.setWifiEnabledInternal(enabled, function(data) {
+        this.setWifiApEnabled(data, this.nextRequest.bind(this));
+      }.bind(this));
+      return;
+    }
+
+    // Wifi is enabled, turn off it before switching to Ap mode.
     if (enabled) {
-      // Disabled the wifi before switch to AP mode.
-      this.setWifiEnabledInternal(false, (function () {
-        WifiManager.setWifiEnabled(false, (function (status) {
-          if (status === 0) {
-            this.setWifiApEnabled(true, (function (status, network) {
-              callback.wifiTetheringEnabledChange(status, network);
-              // We have finished everything we would like to do for tethering.
-              // Pop out this request.
-              if (this._stateRequests.length > 0 &&
-                  ("callback" in this._stateRequests[0])) {
-                // Pop out the request.
-                this._stateRequests.shift();
-                // Serve the pending requests.
-                if (this._stateRequests.length > 0) {
-                  WifiManager.setWifiEnabled(this._stateRequests[0].enabled,
-                                             this._setWifiEnabledCallback.bind(this));
-                }
-              }
-            }).bind(this));
-          } else {
-            if (callback) {
-              callback.wifiTetheringEnabledChange(status, null);
-            }
-          }
-        }).bind(this));
+      // Turn off wifi first.
+      this.setWifiEnabled({enabled: false});
+      this.setWifiEnabledInternal(enabled, (function (data) {
+        this.setWifiApEnabled(data, this.nextRequest.bind(this));
       }).bind(this));
-    } else {
-      // This should not be happened. Return error to NetworkManager.
-      callback.wifiTetheringEnabledChange(1, null);
     }
   },
 
   _updateWifiSetting: function(enabled) {
     // This is used to update the setting value, whenever the
     // WifiManager.enabled is re-assigned based on supplicant
     // connection/lost/failed.
     //
@@ -2355,26 +2383,39 @@ WifiWorker.prototype = {
   },
 
   // nsIObserver implementation
   observe: function observe(subject, topic, data) {
     // Note that this function gets called for any and all settings changes,
     // so we need to carefully check if we have the one we're interested in.
     // The string we're interested in will be a JSON string that looks like:
     // {"key":"wifi.enabled","value":"true"}.
-    if (topic !== kMozSettingsChangedObserverTopic)
+    if (topic !== kMozSettingsChangedObserverTopic) {
       return;
+    }
+
     let setting = JSON.parse(data);
-    if (setting.key !== "wifi.enabled")
+    if (setting.key !== "wifi.enabled" &&
+        setting.key !== "tethering.wifi.enabled") {
       return;
+    }
     // To avoid WifiWorker setting the wifi again, don't need to deal with
     // the "mozsettings-changed" event fired from internal setting.
-    if (setting.message && setting.message === "fromInternalSetting")
+    if (setting.message && setting.message === "fromInternalSetting") {
       return;
-    this.setWifiEnabled({enabled: setting.value});
+    }
+
+    switch (setting.key) {
+      case "wifi.enabled":
+        this.handleWifiEnabled(setting.value)
+        break;
+      case "tethering.wifi.enabled":
+        this.handleWifiTetheringEnabled(setting.value)
+        break;
+    }
   }
 };
 
 const NSGetFactory = XPCOMUtils.generateNSGetFactory([WifiWorker]);
 
 let debug;
 if (DEBUG) {
   debug = function (s) {