Backout 2ea2669b53c3, Bug 917642 - [Helix] Please update the helix blobs
[gecko.git] / dom / system / NetworkGeolocationProvider.js
blob38957d48f460fa171b9728f535528b86057267c8
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 // See https://developers.google.com/maps/documentation/business/geolocation/
7 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
8 Components.utils.import("resource://gre/modules/Services.jsm");
10 const Ci = Components.interfaces;
11 const Cc = Components.classes;
13 let gLoggingEnabled = false;
14 let gTestingEnabled = false;
15 let gUseScanning = true;
17 function LOG(aMsg) {
18   if (gLoggingEnabled)
19   {
20     aMsg = "*** WIFI GEO: " + aMsg + "\n";
21     Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService).logStringMessage(aMsg);
22     dump(aMsg);
23   }
26 function WifiGeoCoordsObject(lat, lon, acc, alt, altacc) {
27   this.latitude = lat;
28   this.longitude = lon;
29   this.accuracy = acc;
30   this.altitude = alt;
31   this.altitudeAccuracy = altacc;
34 WifiGeoCoordsObject.prototype = {
36   QueryInterface:  XPCOMUtils.generateQI([Ci.nsIDOMGeoPositionCoords]),
38   classInfo: XPCOMUtils.generateCI({interfaces: [Ci.nsIDOMGeoPositionCoords],
39                                     flags: Ci.nsIClassInfo.DOM_OBJECT,
40                                     classDescription: "wifi geo position coords object"}),
43 function WifiGeoPositionObject(lat, lng, acc) {
44   this.coords = new WifiGeoCoordsObject(lat, lng, acc, 0, 0);
45   this.address = null;
46   this.timestamp = Date.now();
49 WifiGeoPositionObject.prototype = {
51   QueryInterface:   XPCOMUtils.generateQI([Ci.nsIDOMGeoPosition]),
53   // Class Info is required to be able to pass objects back into the DOM.
54   classInfo: XPCOMUtils.generateCI({interfaces: [Ci.nsIDOMGeoPosition],
55                                     flags: Ci.nsIClassInfo.DOM_OBJECT,
56                                     classDescription: "wifi geo location position object"}),
59 function WifiGeoPositionProvider() {
60   try {
61     gLoggingEnabled = Services.prefs.getBoolPref("geo.wifi.logging.enabled");
62   } catch (e) {}
64   try {
65     gTestingEnabled = Services.prefs.getBoolPref("geo.wifi.testing");
66   } catch (e) {}
68   try {
69     gUseScanning = Services.prefs.getBoolPref("geo.wifi.scan");
70   } catch (e) {}
72   this.wifiService = null;
73   this.timer = null;
74   this.hasSeenWiFi = false;
75   this.started = false;
76   // this is only used when logging is enabled, to debug interactions with the
77   // geolocation service
78   this.highAccuracy = false;
81 WifiGeoPositionProvider.prototype = {
82   classID:          Components.ID("{77DA64D3-7458-4920-9491-86CC9914F904}"),
83   QueryInterface:   XPCOMUtils.generateQI([Ci.nsIGeolocationProvider,
84                                            Ci.nsIWifiListener,
85                                            Ci.nsITimerCallback]),
86   startup:  function() {
87     if (this.started)
88       return;
89     this.started = true;
90     this.hasSeenWiFi = false;
92     LOG("startup called.  testing mode is" + gTestingEnabled);
94     // if we don't see anything in 5 seconds, kick of one IP geo lookup.
95     // if we are testing, just hammer this callback so that we are more or less
96     // always sending data.  It doesn't matter if we have an access point or not.
97     this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
98     if (!gTestingEnabled)
99       this.timer.initWithCallback(this, 5000, this.timer.TYPE_ONE_SHOT);
100     else
101       this.timer.initWithCallback(this, 200, this.timer.TYPE_REPEATING_SLACK);
102   },
104   watch: function(c) {
105     LOG("watch called");
107     if (!this.wifiService && gUseScanning) {
108       this.wifiService = Cc["@mozilla.org/wifi/monitor;1"].getService(Components.interfaces.nsIWifiMonitor);
109       this.wifiService.startWatching(this);
110     }
111     if (this.hasSeenWiFi) {
112       this.hasSeenWiFi = false;
113       if (gUseScanning) {
114         this.wifiService.stopWatching(this);
115         this.wifiService.startWatching(this);
116       } else {
117         // For testing situations, ensure that we always trigger an update.
118         this.timer.initWithCallback(this, 5000, this.timer.TYPE_ONE_SHOT);
119       }
120     }
121   },
123   shutdown: function() { 
124     LOG("shutdown called");
125     if(this.wifiService) {
126       this.wifiService.stopWatching(this);
127       this.wifiService = null;
128     }
129     if (this.timer != null) {
130       this.timer.cancel();
131       this.timer = null;
132     }
134     this.started = false;
135   },
137   setHighAccuracy: function(enable) {
138     this.highAccuracy = enable;
139     LOG("setting highAccuracy to " + (this.highAccuracy?"TRUE":"FALSE"));
140   },
142   onChange: function(accessPoints) {
143     LOG("onChange called, highAccuracy = " + (this.highAccuracy?"TRUE":"FALSE"));
144     this.hasSeenWiFi = true;
146     let url = Services.urlFormatter.formatURLPref("geo.wifi.uri");
148     function isPublic(ap) {
149         let mask = "_nomap"
150         let result = ap.ssid.indexOf(mask, ap.ssid.length - mask.length) == -1;
151         if (result != -1) {
152             LOG("Filtering out " + ap.ssid);
153         }
154         return result;
155     };
157     function sort(a, b) {
158       return b.signal - a.signal;
159     };
161     function encode(ap) {
162       return { 'macAddress': ap.mac, 'signalStrength': ap.signal }; 
163     };
165     var data;
166     if (accessPoints) {
167         data = JSON.stringify({wifiAccessPoints: accessPoints.filter(isPublic).sort(sort).map(encode)})
168     }
170     LOG("************************************* Sending request:\n" + url + "\n");
172     // send our request to a wifi geolocation network provider:
173     let xhr = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
174                         .createInstance(Ci.nsIXMLHttpRequest);
176     // This is a background load
177   
178     xhr.open("POST", url, true);
179     xhr.setRequestHeader("Content-Type", "application/json; charset=UTF-8");
180     xhr.responseType = "json";
181     xhr.mozBackgroundRequest = true;
182     xhr.channel.loadFlags = Ci.nsIChannel.LOAD_ANONYMOUS;
183     xhr.onerror = function() {
184         LOG("onerror: " + xhr);
185     };
187     xhr.onload = function() {  
188         LOG("gls returned status: " + xhr.status + " --> " +  JSON.stringify(xhr.response));
189         if (xhr.channel instanceof Ci.nsIHttpChannel && xhr.status != 200) {
190             return;
191         }
193         if (!xhr.response || !xhr.response.location) {
194             return;
195         }
197         let newLocation = new WifiGeoPositionObject(xhr.response.location.lat,
198                                                     xhr.response.location.lng,
199                                                     xhr.response.accuracy);
200         
201         Cc["@mozilla.org/geolocation/service;1"].getService(Ci.nsIGeolocationUpdate)
202             .update(newLocation);
203     };
205     LOG("************************************* ------>>>> sending " + data);
206     xhr.send(data);
207   },
209   onError: function (code) {
210     LOG("wifi error: " + code);
211   },
213   notify: function (timer) {
214     if (gTestingEnabled || !gUseScanning) {
215       // if we are testing, timer is repeating
216       this.onChange(null);
217     }
218     else {
219       if (!this.hasSeenWiFi)
220         this.onChange(null);
221       this.timer = null;
222     }
223   },
226 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([WifiGeoPositionProvider]);