Port the gears OSX wifi data provider into chrome
Pulls in the custom header file uesd to access these functions in gears

BUG=11246
TEST=unit_tests.exe --gtest_filer=Geoloc* 

Review URL: http://codereview.chromium.org/600146

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@40004 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/geolocation/empty_device_data_provider.cc b/chrome/browser/geolocation/empty_device_data_provider.cc
index 0a4df8b..4cb34f5 100644
--- a/chrome/browser/geolocation/empty_device_data_provider.cc
+++ b/chrome/browser/geolocation/empty_device_data_provider.cc
@@ -4,14 +4,15 @@
 
 #include "chrome/browser/geolocation/empty_device_data_provider.h"
 
+// No platform has (cellular) radio data provider yet.
 // static
 template<>
 RadioDataProviderImplBase* RadioDataProvider::DefaultFactoryFunction() {
   return new EmptyDeviceDataProvider<RadioData>();
 }
 
-// Windows has a real wifi data provider.
-#if !defined(OS_WIN)
+// Only define for platforms that lack a real wifi data provider.
+#if !defined(OS_WIN) && !defined(OS_MACOSX)
 // static
 template<>
 WifiDataProviderImplBase* WifiDataProvider::DefaultFactoryFunction() {
diff --git a/chrome/browser/geolocation/osx_wifi.h b/chrome/browser/geolocation/osx_wifi.h
new file mode 100644
index 0000000..d912034
--- /dev/null
+++ b/chrome/browser/geolocation/osx_wifi.h
@@ -0,0 +1,102 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// The remainder of this file is copied from the Google Gear project:
+// http://code.google.com/p/gears/source/browse/trunk/gears/geolocation/osx_wifi.h
+
+// The contents of this file are taken from Apple80211.h from the iStumbler
+// project (http://www.istumbler.net). This project is released under the BSD
+// license with the following restrictions.
+//
+// Copyright (c) 02006, Alf Watt ([email protected]). All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+// * Redistributions of source code must retain the above copyright
+//   notice, this list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright
+//   notice, this list of conditions and the following disclaimer in the
+//   documentation and/or other materials provided with the distribution.
+//
+// * Neither the name of iStumbler nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// This is the reverse engineered header for the Apple80211 private framework.
+// The framework can be found at
+// /System/Library/PrivateFrameworks/Apple80211.framework.
+
+#ifndef CHROME_BROWSER_GEOLOCATION_OSX_WIFI_H_
+#define CHROME_BROWSER_GEOLOCATION_OSX_WIFI_H_
+
+#include <CoreFoundation/CoreFoundation.h>
+
+extern "C" {
+
+typedef SInt32 WIErr;
+
+// A WirelessContext should be created using WirelessAttach
+// before any other Wireless functions are called. WirelessDetach
+// is used to dispose of a WirelessContext.
+struct WirelessContext;
+
+// WirelessAttach
+//
+// This should be called before all other wireless functions.
+typedef WIErr (*WirelessAttachFunction)(WirelessContext** outContext,
+                                        const UInt32);
+
+// WirelessDetach
+//
+// This should be called after all other wireless functions.
+typedef WIErr (*WirelessDetachFunction)(WirelessContext* inContext);
+
+typedef UInt16 WINetworkInfoFlags;
+
+struct WirelessNetworkInfo
+{
+  UInt16 channel;            // Channel for the network.
+  SInt16 noise;              // Noise for the network. 0 for Adhoc.
+  SInt16 signal;             // Signal strength of the network. 0 for Adhoc.
+  UInt8 macAddress[6];       // MAC address of the wireless access point.
+  UInt16 beaconInterval;     // Beacon interval in milliseconds
+  WINetworkInfoFlags flags;  // Flags for the network
+  UInt16 nameLen;
+  SInt8 name[32];
+};
+
+// WirelessScanSplit
+//
+// WirelessScanSplit scans for available wireless networks. It will allocate 2
+// CFArrays to store a list of managed and adhoc networks. The arrays hold
+// CFData objects which contain WirelessNetworkInfo structures.
+//
+// Note: An adhoc network created on the computer the scan is running on will
+// not be found. WirelessGetInfo can be used to find info about a local adhoc
+// network.
+//
+// If stripDups != 0 only one bases tation for each SSID will be returned.
+typedef WIErr (*WirelessScanSplitFunction)(WirelessContext* inContext,
+                                           CFArrayRef* apList,
+                                           CFArrayRef* adhocList,
+                                           const UInt32 stripDups);
+
+}  // extern "C"
+
+#endif  // CHROME_BROWSER_GEOLOCATION_OSX_WIFI_H_
diff --git a/chrome/browser/geolocation/wifi_data_provider_mac.cc b/chrome/browser/geolocation/wifi_data_provider_mac.cc
index 4fb9f175..e9c2b0f 100644
--- a/chrome/browser/geolocation/wifi_data_provider_mac.cc
+++ b/chrome/browser/geolocation/wifi_data_provider_mac.cc
@@ -7,97 +7,84 @@
 // osx_wifi_.h. This file is taken from the iStumbler project
 // (http://www.istumbler.net).
 
-// TODO(joth): port to chromium
-#if 0
-
-#include "gears/geolocation/wifi_data_provider_osx.h"
+#include "chrome/browser/geolocation/wifi_data_provider_mac.h"
 
 #include <dlfcn.h>
 #include <stdio.h>
-#include "gears/base/common/string_utils.h"
-#include "gears/geolocation/wifi_data_provider_common.h"
+#include "base/lock.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/geolocation/osx_wifi.h"
+#include "chrome/browser/geolocation/wifi_data_provider_common.h"
 
+namespace {
 // The time periods, in milliseconds, between successive polls of the wifi data.
-extern const int kDefaultPollingInterval = 120000;  // 2 mins
-extern const int kNoChangePollingInterval = 300000;  // 5 mins
-extern const int kTwoNoChangePollingInterval = 600000;  // 10 mins
+const int kDefaultPollingInterval = 120000;  // 2 mins
+const int kNoChangePollingInterval = 300000;  // 5 mins
+const int kTwoNoChangePollingInterval = 600000;  // 10 mins
 
-// static
-template<>
-WifiDataProviderImplBase *WifiDataProvider::DefaultFactoryFunction() {
-  return new OsxWifiDataProvider();
+class OsxWlanApi : public WifiDataProviderCommon::WlanApiInterface {
+ public:
+  OsxWlanApi();
+  virtual ~OsxWlanApi();
+
+  bool Init();
+
+  // WlanApiInterface
+  virtual bool GetAccessPointData(WifiData::AccessPointDataSet* data);
+
+ private:
+  // Handle, context and function pointers for Apple80211 library.
+  void* apple_80211_library_;
+  WirelessContext* wifi_context_;
+  WirelessAttachFunction WirelessAttach_function_;
+  WirelessScanSplitFunction WirelessScanSplit_function_;
+  WirelessDetachFunction WirelessDetach_function_;
+
+  WifiData wifi_data_;
+  Lock data_mutex_;
+};
+
+OsxWlanApi::OsxWlanApi()
+    : apple_80211_library_(NULL), wifi_context_(NULL),
+      WirelessAttach_function_(NULL), WirelessScanSplit_function_(NULL),
+      WirelessDetach_function_(NULL) {
 }
 
-
-OsxWifiDataProvider::OsxWifiDataProvider() : is_first_scan_complete_(false) {
-  Start();
+OsxWlanApi::~OsxWlanApi() {
+  if (WirelessDetach_function_)
+    (*WirelessDetach_function_)(wifi_context_);
+  dlclose(apple_80211_library_);
 }
 
-OsxWifiDataProvider::~OsxWifiDataProvider() {
-  stop_event_.Signal();
-  Join();
-}
-
-bool OsxWifiDataProvider::GetData(WifiData *data) {
-  DCHECK(data);
-  MutexLock lock(&data_mutex_);
-  *data = wifi_data_;
-  // If we've successfully completed a scan, indicate that we have all of the
-  // data we can get.
-  return is_first_scan_complete_;
-}
-
-// Thread implementation
-void OsxWifiDataProvider::Run() {
-  void *apple_80211_library = dlopen(
+bool OsxWlanApi::Init() {
+  apple_80211_library_ = dlopen(
       "/System/Library/PrivateFrameworks/Apple80211.framework/Apple80211",
       RTLD_LAZY);
-  if (!apple_80211_library) {
-    is_first_scan_complete_ = true;
-    return;
-  }
+  if (!apple_80211_library_)
+    return false;
 
   WirelessAttach_function_ = reinterpret_cast<WirelessAttachFunction>(
-      dlsym(apple_80211_library, "WirelessAttach"));
+      dlsym(apple_80211_library_, "WirelessAttach"));
   WirelessScanSplit_function_ = reinterpret_cast<WirelessScanSplitFunction>(
-      dlsym(apple_80211_library, "WirelessScanSplit"));
+      dlsym(apple_80211_library_, "WirelessScanSplit"));
   WirelessDetach_function_ = reinterpret_cast<WirelessDetachFunction>(
-      dlsym(apple_80211_library, "WirelessDetach"));
-  DCHECK(WirelessAttach_function_ &&
-         WirelessScanSplit_function_ &&
-         WirelessDetach_function_);
+      dlsym(apple_80211_library_, "WirelessDetach"));
+  DCHECK(WirelessAttach_function_);
+  DCHECK(WirelessScanSplit_function_);
+  DCHECK(WirelessDetach_function_);
 
-  if ((*WirelessAttach_function_)(&wifi_context_, 0) != noErr) {
-    is_first_scan_complete_ = true;
-    return;
+  if (!WirelessAttach_function_ || !WirelessScanSplit_function_ ||
+      !WirelessDetach_function_) {
+    return false;
   }
 
-  // Regularly get the access point data.
-  int polling_interval = kDefaultPollingInterval;
-  do {
-    WifiData new_data;
-    GetAccessPointData(&new_data.access_point_data);
-    bool update_available;
-    data_mutex_.Lock();
-    update_available = wifi_data_.DiffersSignificantly(new_data);
-    wifi_data_ = new_data;
-    data_mutex_.Unlock();
-    polling_interval =
-        UpdatePollingInterval(polling_interval, update_available);
-    if (update_available) {
-      is_first_scan_complete_ = true;
-      NotifyListeners();
-    }
-  } while (!stop_event_.WaitWithTimeout(polling_interval));
-
-  (*WirelessDetach_function_)(wifi_context_);
-
-  dlclose(apple_80211_library);
+  if ((*WirelessAttach_function_)(&wifi_context_, 0) != noErr)
+    return false;
+  return true;
 }
 
-void OsxWifiDataProvider::GetAccessPointData(
-    WifiData::AccessPointDataSet *access_points) {
-  DCHECK(access_points);
+bool OsxWlanApi::GetAccessPointData(WifiData::AccessPointDataSet* data) {
+  DCHECK(data);
   DCHECK(WirelessScanSplit_function_);
   CFArrayRef managed_access_points = NULL;
   CFArrayRef adhoc_access_points = NULL;
@@ -105,16 +92,15 @@
                                      &managed_access_points,
                                      &adhoc_access_points,
                                      0) != noErr) {
-    return;
+    return false;
   }
 
-  if (managed_access_points == NULL) {
-    return;
-  }
+  if (managed_access_points == NULL)
+    return false;
 
   int num_access_points = CFArrayGetCount(managed_access_points);
   for (int i = 0; i < num_access_points; ++i) {
-    const WirelessNetworkInfo *access_point_info =
+    const WirelessNetworkInfo* access_point_info =
         reinterpret_cast<const WirelessNetworkInfo*>(
         CFDataGetBytePtr(
         reinterpret_cast<const CFDataRef>(
@@ -132,15 +118,41 @@
     // WirelessNetworkInfo::noise appears to be noise floor in dBm.
     access_point_data.signal_to_noise = access_point_info->signal -
                                         access_point_info->noise;
-    string16 ssid;
-    if (UTF8ToString16(reinterpret_cast<const char*>(access_point_info->name),
-                       access_point_info->nameLen,
-                       &ssid)) {
-      access_point_data.ssid = ssid;
+    if (!UTF8ToUTF16(reinterpret_cast<const char*>(access_point_info->name),
+                     access_point_info->nameLen,
+                     &access_point_data.ssid)) {
+      access_point_data.ssid.clear();
     }
 
-    access_points->insert(access_point_data);
+    data->insert(access_point_data);
   }
+  return true;
+}
+}  // namespace
+
+// static
+template<>
+WifiDataProviderImplBase* WifiDataProvider::DefaultFactoryFunction() {
+  return new OsxWifiDataProvider();
 }
 
-#endif  // 0
+OsxWifiDataProvider::OsxWifiDataProvider() {
+}
+
+OsxWifiDataProvider::~OsxWifiDataProvider() {
+}
+
+OsxWifiDataProvider::WlanApiInterface* OsxWifiDataProvider::NewWlanApi() {
+  scoped_ptr<OsxWlanApi> wlan_api(new OsxWlanApi);
+  if (!wlan_api->Init()) {
+   DLOG(INFO) << "OsxWifiDataProvider : failed to initialize wlan api";
+   return NULL;
+  }
+  return wlan_api.release();
+}
+
+PollingPolicyInterface* OsxWifiDataProvider::NewPolicyPolicy() {
+  return new GenericPollingPolicy<kDefaultPollingInterval,
+                                  kNoChangePollingInterval,
+                                  kTwoNoChangePollingInterval>;
+}
diff --git a/chrome/browser/geolocation/wifi_data_provider_mac.h b/chrome/browser/geolocation/wifi_data_provider_mac.h
index 10b8aa9..3958502 100644
--- a/chrome/browser/geolocation/wifi_data_provider_mac.h
+++ b/chrome/browser/geolocation/wifi_data_provider_mac.h
@@ -5,51 +5,20 @@
 #ifndef CHROME_BROWSER_GEOLOCATION_WIFI_DATA_PROVIDER_MAC_H_
 #define CHROME_BROWSER_GEOLOCATION_WIFI_DATA_PROVIDER_MAC_H_
 
-// TODO(joth): port to chromium
-#if 0
+#include "chrome/browser/geolocation/wifi_data_provider_common.h"
 
-#include "gears/base/common/common.h"
-#include "gears/base/common/event.h"
-#include "gears/base/common/mutex.h"
-#include "gears/base/common/thread.h"
-#include "gears/geolocation/device_data_provider.h"
-#include "gears/geolocation/osx_wifi.h"
-
-class OsxWifiDataProvider
-    : public WifiDataProviderImplBase,
-      public Thread {
+class OsxWifiDataProvider : public WifiDataProviderCommon {
  public:
   OsxWifiDataProvider();
-  virtual ~OsxWifiDataProvider();
-
-  // WifiDataProviderImplBase implementation.
-  virtual bool GetData(WifiData *data);
 
  private:
-  // Thread implementation.
-  virtual void Run();
+  virtual ~OsxWifiDataProvider();
 
-  void GetAccessPointData(WifiData::AccessPointDataSet *access_points);
-
-  // Context and function pointers for Apple80211 library.
-  WirelessContextPtr wifi_context_;
-  WirelessAttachFunction WirelessAttach_function_;
-  WirelessScanSplitFunction WirelessScanSplit_function_;
-  WirelessDetachFunction WirelessDetach_function_;
-
-  WifiData wifi_data_;
-  Mutex data_mutex_;
-
-  // Event signalled to shut down the thread that polls for wifi data.
-  Event stop_event_;
-
-  // Whether we've successfully completed a scan for WiFi data (or the polling
-  // thread has terminated early).
-  bool is_first_scan_complete_;
+  // WifiDataProviderCommon
+  virtual WlanApiInterface* NewWlanApi();
+  virtual PollingPolicyInterface* NewPolicyPolicy();
 
   DISALLOW_COPY_AND_ASSIGN(OsxWifiDataProvider);
 };
 
-#endif  // 0
-
 #endif  // CHROME_BROWSER_GEOLOCATION_WIFI_DATA_PROVIDER_MAC_H_
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index cf0779c..82c90094 100755
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -977,6 +977,7 @@
         'browser/geolocation/network_location_provider.h',
         'browser/geolocation/network_location_request.cc',
         'browser/geolocation/network_location_request.h',
+        'browser/geolocation/osx_wifi.h',
         'browser/geolocation/wifi_data_provider_common.cc',
         'browser/geolocation/wifi_data_provider_common.h',
         'browser/geolocation/wifi_data_provider_common_win.cc',