1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
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__
|