summaryrefslogtreecommitdiffstats
path: root/chrome/browser/geolocation/device_data_provider.h
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/geolocation/device_data_provider.h')
-rw-r--r--chrome/browser/geolocation/device_data_provider.h391
1 files changed, 391 insertions, 0 deletions
diff --git a/chrome/browser/geolocation/device_data_provider.h b/chrome/browser/geolocation/device_data_provider.h
new file mode 100644
index 0000000..6d5740e
--- /dev/null
+++ b/chrome/browser/geolocation/device_data_provider.h
@@ -0,0 +1,391 @@
+// Copyright 2008, Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// 2. 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.
+// 3. Neither the name of Google Inc. 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 AUTHOR ``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 AUTHOR 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.
+//
+// A device data provider provides data from the device that is used by a
+// NetworkLocationProvider to obtain a position fix. This data may be either
+// cell radio data or wifi data. For a given type of data, we use a singleton
+// instance of the device data provider, which is used by multiple
+// NetworkLocationProvider objects.
+//
+// This file providers DeviceDataProvider, which provides static methods to
+// access the singleton instance. The singleton instance uses a private
+// implementation to abstract across platforms and also to allow mock providers
+// to be used for testing.
+//
+// This file also provides DeviceDataProviderImplBase, a base class which
+// provides commom functionality for the private implementations.
+//
+// This file also declares the data structures used to represent cell radio data
+// and wifi data.
+
+#ifndef GEARS_GEOLOCATION_DEVICE_DATA_PROVIDER_H__
+#define GEARS_GEOLOCATION_DEVICE_DATA_PROVIDER_H__
+
+#include <algorithm>
+#include <set>
+#include <vector>
+#include "gears/base/common/basictypes.h" // For int64
+#include "gears/base/common/common.h"
+#include "gears/base/common/mutex.h"
+#include "gears/base/common/scoped_refptr.h" // For RefCount
+#include "gears/base/common/string16.h"
+#include "third_party/scoped_ptr/scoped_ptr.h"
+
+// The following data structures are used to store cell radio data and wifi
+// data. See the Geolocation API design document at
+// http://code.google.com/p/google-gears/wiki/LocationAPI for a more complete
+// description.
+//
+// For all integer fields, we use kint32min to represent unknown values.
+
+// Cell radio data relating to a single cell tower.
+struct CellData {
+ CellData()
+ : cell_id(kint32min),
+ location_area_code(kint32min),
+ mobile_network_code(kint32min),
+ mobile_country_code(kint32min),
+ age(kint32min),
+ radio_signal_strength(kint32min),
+ timing_advance(kint32min) {}
+ bool Matches(const CellData &other) const {
+ // Ignore age and radio_signal_strength when matching.
+ return cell_id == other.cell_id &&
+ location_area_code == other.location_area_code &&
+ mobile_network_code == other.mobile_network_code &&
+ mobile_country_code == other.mobile_country_code &&
+ timing_advance == other.timing_advance;
+ }
+
+ int cell_id; // Unique identifier of the cell
+ int location_area_code; // For current location area
+ int mobile_network_code; // For current cell
+ int mobile_country_code; // For current cell
+ int age; // Milliseconds since this cell was primary
+ int radio_signal_strength; // Measured in dBm.
+ int timing_advance; // Timing advance representing the distance from
+ // the cell tower. Each unit is roughly 550
+ // meters.
+};
+
+static bool CellDataMatches(const CellData &data1, const CellData &data2) {
+ return data1.Matches(data2);
+}
+
+enum RadioType {
+ RADIO_TYPE_UNKNOWN,
+ RADIO_TYPE_GSM,
+ RADIO_TYPE_CDMA,
+ RADIO_TYPE_WCDMA,
+};
+
+// All data for the cell radio.
+struct RadioData {
+ RadioData()
+ : home_mobile_network_code(kint32min),
+ home_mobile_country_code(kint32min),
+ radio_type(RADIO_TYPE_UNKNOWN) {}
+ bool Matches(const RadioData &other) const {
+ if (cell_data.size() != other.cell_data.size()) {
+ return false;
+ }
+ if (!std::equal(cell_data.begin(), cell_data.end(), other.cell_data.begin(),
+ CellDataMatches)) {
+ return false;
+ }
+ return device_id == other.device_id &&
+ home_mobile_network_code == other.home_mobile_network_code &&
+ home_mobile_country_code == other.home_mobile_country_code &&
+ radio_type == other.radio_type &&
+ carrier == other.carrier;
+ }
+ // Determines whether a new set of radio data differs significantly from this.
+ bool DiffersSignificantly(const RadioData &other) const {
+ // This is required by MockDeviceDataProviderImpl.
+ // TODO(steveblock): Implement properly.
+ return !Matches(other);
+ }
+
+ std::string16 device_id;
+ std::vector<CellData> cell_data;
+ int home_mobile_network_code; // For the device's home network.
+ int home_mobile_country_code; // For the device's home network.
+ RadioType radio_type; // Mobile radio type.
+ std::string16 carrier; // Carrier name.
+};
+
+// Wifi data relating to a single access point.
+struct AccessPointData {
+ AccessPointData()
+ : radio_signal_strength(kint32min),
+ age(kint32min),
+ channel(kint32min),
+ signal_to_noise(kint32min) {}
+
+ std::string16 mac_address;
+ int radio_signal_strength; // Measured in dBm
+ int age; // Milliseconds since this access point was detected
+ int channel;
+ int signal_to_noise; // Ratio in dB
+ std::string16 ssid; // Network identifier
+};
+
+// This is to allow AccessPointData to be used in std::set. We order
+// lexicographically by MAC address.
+struct AccessPointDataLess : public std::less<AccessPointData> {
+ bool operator()(const AccessPointData &data1,
+ const AccessPointData &data2) const {
+ return data1.mac_address < data2.mac_address;
+ }
+};
+
+// All data for wifi.
+struct WifiData {
+ // Determines whether a new set of WiFi data differs significantly from this.
+ bool DiffersSignificantly(const WifiData &other) const {
+ // At least 5 or 50% of access points added or removed is significant.
+ static const size_t kMinChangedAccessPoints = 5;
+
+ // Compute size of interesction of old and new sets.
+ size_t num_common = 0;
+ for (AccessPointDataSet::const_iterator iter = access_point_data.begin();
+ iter != access_point_data.end();
+ iter++) {
+ if (other.access_point_data.find(*iter) !=
+ other.access_point_data.end()) {
+ ++num_common;
+ }
+ }
+ assert(num_common <= access_point_data.size());
+ assert(num_common <= other.access_point_data.size());
+
+ // Test how many have changed.
+ size_t added_or_removed = std::max(
+ other.access_point_data.size() - num_common,
+ access_point_data.size() - num_common);
+ return added_or_removed >=
+ std::min(kMinChangedAccessPoints, access_point_data.size() / 2);
+ }
+
+ // Store access points as a set, sorted by MAC address. This allows quick
+ // comparison of sets for detecting changes and for caching.
+ typedef std::set<AccessPointData, AccessPointDataLess> AccessPointDataSet;
+ AccessPointDataSet access_point_data;
+};
+
+template<typename DataType>
+class DeviceDataProvider;
+
+// DeviceDataProvider uses containment to hide platform-specific implementation
+// details from common code. This class provides common functionality for these
+// contained implementation classes.
+template<typename DataType>
+class DeviceDataProviderImplBase {
+ public:
+ DeviceDataProviderImplBase() : container_(NULL) {}
+ virtual ~DeviceDataProviderImplBase() {}
+
+ virtual bool GetData(DataType *data) = 0;
+
+ // Sets the container of this class, which is of type DeviceDataProvider.
+ // This is required to pass as a parameter when making the callback to
+ // listeners.
+ void SetContainer(DeviceDataProvider<DataType> *container) {
+ container_ = container;
+ }
+
+ typedef typename DeviceDataProvider<DataType>::ListenerInterface
+ ListenerInterface;
+ void AddListener(ListenerInterface *listener) {
+ MutexLock mutex(&listeners_mutex_);
+ listeners_.insert(listener);
+ }
+ bool RemoveListener(ListenerInterface *listener) {
+ MutexLock mutex(&listeners_mutex_);
+ typename ListenersSet::iterator iter = find(listeners_.begin(),
+ listeners_.end(),
+ listener);
+ if (iter == listeners_.end()) {
+ return false;
+ }
+ listeners_.erase(iter);
+ return true;
+ }
+
+ protected:
+ // Calls DeviceDataUpdateAvailable() on all registered listeners.
+ typedef std::set<ListenerInterface*> ListenersSet;
+ void NotifyListeners() {
+ MutexLock lock(&listeners_mutex_);
+ for (typename ListenersSet::const_iterator iter = listeners_.begin();
+ iter != listeners_.end();
+ ++iter) {
+ (*iter)->DeviceDataUpdateAvailable(container_);
+ }
+ }
+
+ private:
+ DeviceDataProvider<DataType> *container_;
+
+ // The listeners to this class and their mutex.
+ ListenersSet listeners_;
+ Mutex listeners_mutex_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(DeviceDataProviderImplBase);
+};
+
+typedef DeviceDataProviderImplBase<RadioData> RadioDataProviderImplBase;
+typedef DeviceDataProviderImplBase<WifiData> WifiDataProviderImplBase;
+
+// A device data provider
+//
+// We use a singleton instance of this class which is shared by multiple network
+// location providers. These location providers access the instance through the
+// Register and Unregister methods.
+template<typename DataType>
+class DeviceDataProvider {
+ public:
+ // Interface to be implemented by listeners to a device data provider.
+ class ListenerInterface {
+ public:
+ virtual void DeviceDataUpdateAvailable(
+ DeviceDataProvider<DataType> *provider) = 0;
+ virtual ~ListenerInterface() {}
+ };
+
+ // Sets the factory function which will be used by Register to create the
+ // implementation used by the singleton instance. This factory approach is
+ // used to abastract accross both platform-specific implementation and to
+ // inject mock implementations for testing.
+ typedef DeviceDataProviderImplBase<DataType> *(*ImplFactoryFunction)(void);
+ static void SetFactory(ImplFactoryFunction factory_function_in) {
+ factory_function_ = factory_function_in;
+ }
+
+ static void ResetFactory() {
+ factory_function_ = DefaultFactoryFunction;
+ }
+
+ // Adds a listener, which will be called back with DeviceDataUpdateAvailable
+ // whenever new data is available. Returns the singleton instance.
+ static DeviceDataProvider *Register(ListenerInterface *listener) {
+ // We protect against Register and Unregister being called asynchronously
+ // from different threads. This is the case when a device data provider is
+ // used by a NetworkLocationProvider object. Register is always called from
+ // the JavaScript thread. Unregister is called when NetworkLocationProvider
+ // objects are destructed, which happens asynchronously once the
+ // NetworkLocationProvider HTTP request has completed.
+ MutexLock mutex(&instance_mutex_);
+ if (!instance_) {
+ instance_ = new DeviceDataProvider();
+ }
+ assert(instance_);
+ instance_->Ref();
+ instance_->AddListener(listener);
+ return instance_;
+ }
+
+ // Removes a listener. If this is the last listener, deletes the singleton
+ // instance. Return value indicates success.
+ static bool Unregister(ListenerInterface *listener) {
+ MutexLock mutex(&instance_mutex_);
+ if (!instance_->RemoveListener(listener)) {
+ return false;
+ }
+ if (instance_->Unref()) {
+ delete instance_;
+ instance_ = NULL;
+ }
+ return true;
+ }
+
+ // Provides whatever data the provider has, which may be nothing. Return
+ // value indicates whether this is all the data the provider could ever
+ // obtain.
+ bool GetData(DataType *data) {
+ return impl_->GetData(data);
+ }
+
+ private:
+ // Private constructor and destructor, callers access singleton through
+ // Register and Unregister.
+ DeviceDataProvider() {
+ assert(factory_function_);
+ impl_.reset((*factory_function_)());
+ impl_->SetContainer(this);
+ }
+ virtual ~DeviceDataProvider() {}
+
+ void Ref() {
+ count_.Ref();
+ }
+ // Returns true when the ref count transitions from 1 to 0.
+ bool Unref() {
+ return count_.Unref();
+ }
+
+ void AddListener(ListenerInterface *listener) {
+ impl_->AddListener(listener);
+ }
+
+ bool RemoveListener(ListenerInterface *listener) {
+ return impl_->RemoveListener(listener);
+ }
+
+ static DeviceDataProviderImplBase<DataType> *DefaultFactoryFunction();
+
+ // The singleton instance of this class and its mutex.
+ static DeviceDataProvider *instance_;
+ static Mutex instance_mutex_;
+
+ // The factory function used to create the singleton instance.
+ static ImplFactoryFunction factory_function_;
+
+ // The internal implementation.
+ scoped_ptr<DeviceDataProviderImplBase<DataType> > impl_;
+
+ RefCount count_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(DeviceDataProvider);
+};
+
+// static
+template<typename DataType>
+Mutex DeviceDataProvider<DataType>::instance_mutex_;
+
+// static
+template<typename DataType>
+DeviceDataProvider<DataType> *DeviceDataProvider<DataType>::instance_ =
+ NULL;
+
+// static
+template<typename DataType>
+typename DeviceDataProvider<DataType>::ImplFactoryFunction
+ DeviceDataProvider<DataType>::factory_function_ = DefaultFactoryFunction;
+
+typedef DeviceDataProvider<RadioData> RadioDataProvider;
+typedef DeviceDataProvider<WifiData> WifiDataProvider;
+
+#endif // GEARS_GEOLOCATION_DEVICE_DATA_PROVIDER_H__