Android系列之Wifi定位
来源:互联网 发布:gn口数据 编辑:程序博客网 时间:2024/06/06 08:41
Broncho A1还不支持基站和WIFI定位,Android的老版本里是有NetworkLocationProvider的,它实现了基站和WIFI定位,但从 android 1.5之后就被移除了。本来想在broncho A1里自己实现NetworkLocationProvider的,但一直没有时间去研究。我知道 gears(http://code.google.com/p/gears/)是有提供类似的功能,昨天研究了一下Gears的代码,看能不能移植到 android中来
1.下载源代码
svn checkout [url]http://gears.googlecode.com/svn/trunk/ gears-read-only[/url]
定位相关的源代码在gears/geolocation目录中。
2.关注android平台中的基站位置变化
JAVA类AndroidRadioDataProvider是 PhoneStateListener的子类,用来监听Android电话的状态变化。当服务状态、信号强度和基站变化时,
就会用下面代码获取小区信息:
1 RadioData radioData =
new RadioData();
2 GsmCellLocation gsmCellLocation = (GsmCellLocation) cellLocation;
3
4
// Extract the cell id, LAC, and signal strength.
5
radioData.cellId = gsmCellLocation.getCid();
6 radioData.locationAreaCode = gsmCellLocation.getLac();
7 radioData.signalStrength = signalStrength;
8
9
// Extract the home MCC and home MNC.
10
String operator
= telephonyManager.getSimOperator();
11 radioData.setMobileCodes(operator, true);
12
13
if (serviceState !=
null) {
14
// Extract the carrier name.
15
radioData.carrierName = serviceState.getOperatorAlphaLong();
16
17
// Extract the MCC and MNC.
18
operator
= serviceState.getOperatorNumeric();
19 radioData.setMobileCodes(operator, false);
20 }
21
22
// Finally get the radio type.
23
int type = telephonyManager.getNetworkType();
24
if (type == TelephonyManager.NETWORK_TYPE_UMTS) {
25 radioData.radioType = RADIO_TYPE_WCDMA;
26 } else
if (type == TelephonyManager.NETWORK_TYPE_GPRS
27
|| type == TelephonyManager.NETWORK_TYPE_EDGE) {
28 radioData.radioType = RADIO_TYPE_GSM;
29 }
30
然后再调用用C代码实现的onUpdateAvailable函数。
2.Native函数onUpdateAvailable是在 radio_data_provider_android.cc里实现的。
声明Native函数
1 JNINativeMethod AndroidRadioDataProvider::native_methods_[] = {
2 {"onUpdateAvailable",
3
"(L" GEARS_JAVA_PACKAGE "/AndroidRadioDataProvider$RadioData;J)V",
4 reinterpret_cast<void*>(AndroidRadioDataProvider::OnUpdateAvailable)
5 },
6 };
7
JNI调用好像只能调用静态成员函数,把对象本身用一个参数传进来,然后再调用对象的成员函数。
代码void AndroidRadioDataProvider::OnUpdateAvailable(JNIEnv* env,
jclass cls,
jobject radio_data,
jlong self) {
assert(radio_data);
assert(self);
AndroidRadioDataProvider *self_ptr =
reinterpret_cast<AndroidRadioDataProvider*>(self);
RadioData new_radio_data;
if (InitFromJavaRadioData(env, radio_data, &new_radio_data)) {
self_ptr->NewRadioDataAvailable(&new_radio_data);
}
}
先判断基站信息有没有变化,如果有变化则通知相关的监听者。
1 void AndroidRadioDataProvider::NewRadioDataAvailable(
2 RadioData* new_radio_data) {
3
bool is_update_available =
false;
4 data_mutex_.Lock();
5
if (new_radio_data &&
!radio_data_.Matches(*new_radio_data)) {
6 radio_data_ =
*new_radio_data;
7 is_update_available =
true;
8 }
9
// Avoid holding the mutex locked while notifying observers.
10
data_mutex_.Unlock();
11
12
if (is_update_available) {
13 NotifyListeners();
14 }
15 }
接下来的过程,在基站定位和WIFI定位是一样的,后面我们再来介绍。下面我们先看 WIFI定位
3.关注android平台中的WIFI变化。
JAVA类AndroidWifiDataProvider扩展了 BroadcastReceiver类,它关注WIFI扫描结果:
1 IntentFilter filter =
new IntentFilter();
2 filter.addAction(mWifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
3 mContext.registerReceiver(this, filter, null, handler);
当收到WIFI扫描结果后,调用Native函数 onUpdateAvailable,并把WIFI的扫描结果传递过去。
1 public
void onReceive(Context context, Intent intent) {
2
if (intent.getAction().equals(
3 mWifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
4
if (Config.LOGV) {
5 Log.v(TAG, "Wifi scan resulst available");
6 }
7 onUpdateAvailable(mWifiManager.getScanResults(), mNativeObject);
8 }
9 }
Native函数onUpdateAvailable是在 wifi_data_provider_android.cc里实现的。
1 JNINativeMethod AndroidWifiDataProvider::native_methods_[] = {
2 {"onUpdateAvailable",
3
"(Ljava/util/List;J)V",
4 reinterpret_cast<void*>(AndroidWifiDataProvider::OnUpdateAvailable)
5 },
6 };
7
8
void AndroidWifiDataProvider::OnUpdateAvailable(JNIEnv*
/* env */,
9 jclass /* cls */,
10 jobject wifi_data,
11 jlong self) {
12 assert(self);
13 AndroidWifiDataProvider *self_ptr =
14 reinterpret_cast<AndroidWifiDataProvider*>(self);
15 WifiData new_wifi_data;
16
if (wifi_data) {
17 InitFromJava(wifi_data, &new_wifi_data);
18 }
19
// We notify regardless of whether new_wifi_data is empty
20
// or not. The arbitrator will decide what to do with an empty
21
// WifiData object.
22
self_ptr->NewWifiDataAvailable(&new_wifi_data);
23 }
24
25
void AndroidWifiDataProvider::NewWifiDataAvailable(WifiData* new_wifi_data) {
26 assert(supported_);
27 assert(new_wifi_data);
28
bool is_update_available =
false;
29 data_mutex_.Lock();
30 is_update_available = wifi_data_.DiffersSignificantly(*new_wifi_data);
31 wifi_data_ =
*new_wifi_data;
32
// Avoid holding the mutex locked while notifying observers.
33
data_mutex_.Unlock();
34
35
if (is_update_available) {
36 is_first_scan_complete_ =
true;
37 NotifyListeners();
38 }
39
40
#if USING_CCTESTS
41
// This is needed for running the WiFi test on the emulator.
42
// See wifi_data_provider_android.h for details.
43
if (!first_callback_made_ && wifi_data_.access_point_data.empty()) {
44 first_callback_made_ =
true;
45 NotifyListeners();
46 }
47
#endif
48 }
49
50 JNINativeMethod AndroidWifiDataProvider::native_methods_[] = {
51 {"onUpdateAvailable",
52
"(Ljava/util/List;J)V",
53 reinterpret_cast<void*>(AndroidWifiDataProvider::OnUpdateAvailable)
54 },
55 };
56
57
void AndroidWifiDataProvider::OnUpdateAvailable(JNIEnv*
/* env */,
58 jclass /* cls */,
59 jobject wifi_data,
60 jlong self) {
61 assert(self);
62 AndroidWifiDataProvider *self_ptr =
63 reinterpret_cast<AndroidWifiDataProvider*>(self);
64 WifiData new_wifi_data;
65
if (wifi_data) {
66 InitFromJava(wifi_data, &new_wifi_data);
67 }
68
// We notify regardless of whether new_wifi_data is empty
69
// or not. The arbitrator will decide what to do with an empty
70
// WifiData object.
71
self_ptr->NewWifiDataAvailable(&new_wifi_data);
72 }
73
74
void AndroidWifiDataProvider::NewWifiDataAvailable(WifiData* new_wifi_data) {
75 assert(supported_);
76 assert(new_wifi_data);
77
bool is_update_available =
false;
78 data_mutex_.Lock();
79 is_update_available = wifi_data_.DiffersSignificantly(*new_wifi_data);
80 wifi_data_ =
*new_wifi_data;
81
// Avoid holding the mutex locked while notifying observers.
82
data_mutex_.Unlock();
83
84
if (is_update_available) {
85 is_first_scan_complete_ =
true;
86 NotifyListeners();
87 }
88
89
#if USING_CCTESTS
90
// This is needed for running the WiFi test on the emulator.
91
// See wifi_data_provider_android.h for details.
92
if (!first_callback_made_ && wifi_data_.access_point_data.empty()) {
93 first_callback_made_ =
true;
94 NotifyListeners();
95 }
96
#endif
97 }
98
从以上代码可以看出,WIFI定位和基站定位的逻辑差不多,只是前者获取的WIFI的扫描结果,而后者获取的基站信息。
后面代码的基本上就统一起来了,接下来我们继续看。
5.把变化(WIFI/基站)通知给相应的监听者。
1 AndroidWifiDataProvider和AndroidRadioDataProvider都是继承了DeviceDataProviderImplBase,DeviceDataProviderImplBase的主要功能就是管理所有Listeners。
2
3
static DeviceDataProvider *Register(ListenerInterface *listener) {
4 MutexLock mutex(&instance_mutex_);
5
if (!instance_) {
6 instance_ =
new DeviceDataProvider();
7 }
8 assert(instance_);
9 instance_->Ref();
10 instance_->AddListener(listener);
11
return instance_;
12 }
13
14
static
bool Unregister(ListenerInterface *listener) {
15 MutexLock mutex(&instance_mutex_);
16
if (!instance_->RemoveListener(listener)) {
17
return
false;
18 }
19
if (instance_->Unref()) {
20 delete instance_;
21 instance_ = NULL;
22 }
23
return
true;
24 }
25
6.谁在监听变化(WIFI/基站)
NetworkLocationProvider在监听变化(WIFI/基站):
1 radio_data_provider_ = RadioDataProvider::Register(this);
2 wifi_data_provider_ = WifiDataProvider::Register(this);
当有变化时,会调用函数DeviceDataUpdateAvailable:
代码// DeviceDataProviderInterface::ListenerInterface implementation.
void NetworkLocationProvider::DeviceDataUpdateAvailable(
RadioDataProvider *provider) {
MutexLock lock(&data_mutex_);
assert(provider == radio_data_provider_);
is_radio_data_complete_ = radio_data_provider_->GetData(&radio_data_);
DeviceDataUpdateAvailableImpl();
}
void NetworkLocationProvider::DeviceDataUpdateAvailable(
WifiDataProvider *provider) {
assert(provider == wifi_data_provider_);
MutexLock lock(&data_mutex_);
is_wifi_data_complete_ = wifi_data_provider_->GetData(&wifi_data_);
DeviceDataUpdateAvailableImpl();
}
无论是WIFI还是基站变化,最后都会调用 DeviceDataUpdateAvailableImpl:
1 void NetworkLocationProvider::DeviceDataUpdateAvailableImpl() {
2 timestamp_ = GetCurrentTimeMillis();
3
4
// Signal to the worker thread that new data is available.
5
is_new_data_available_ =
true;
6 thread_notification_event_.Signal();
7 }
这里面只是发了一个signal,通知另外一个线程去处理。
7.谁在等待thread_notification_event_
线程函数NetworkLocationProvider::Run在一个循环中等待 thread_notification_event,当有变化(WIFI/基站)时,就准备请求服务器查询位置。
先等待:
1 if (remaining_time >
0) {
2 thread_notification_event_.WaitWithTimeout(
3 static_cast<int>(remaining_time));
4 } else {
5 thread_notification_event_.Wait();
6 }
准备请求:
1 if (make_request) {
2 MakeRequest();
3 remaining_time =
1;
4 }
再来看MakeRequest的实现:
先从cache中查找位置:
1
const Position *cached_position =
2 position_cache_->FindPosition(radio_data_, wifi_data_);
3 data_mutex_.Unlock();
4
if (cached_position) {
5 assert(cached_position->IsGoodFix());
6
// Record the position and update its timestamp.
7
position_mutex_.Lock();
8 position_ =
*cached_position;
9 position_.timestamp = timestamp_;
10 position_mutex_.Unlock();
11
12
// Let listeners know that we now have a position available.
13
UpdateListeners();
14
return
true;
15 }
如果找不到,再做实际的请求
1
return request_->MakeRequest(access_token,
2 radio_data_,
3 wifi_data_,
4 request_address_,
5 address_language_,
6 kBadLatLng, // We don't have a position to pass
7
kBadLatLng, // to the server.
8
timestamp_);
7.客户端协议包装
前面的request_是NetworkLocationRequest实例,先看 MakeRequest的实现:
先对参数进行打包:
1
if (!FormRequestBody(host_name_, access_token, radio_data, wifi_data,
2 request_address, address_language, latitude, longitude,
3 is_reverse_geocode_, &post_body_)) {
4
return
false;
5 }
通知负责收发的线程
1 thread_event_.Signal();
8.负责收发的线程
1 void NetworkLocationRequest::Run() {
2
while (true) {
3 thread_event_.Wait();
4
if (is_shutting_down_) {
5
break;
6 }
7 MakeRequestImpl();
8 }
9 }
10
11
void NetworkLocationRequest::MakeRequestImpl() {
12 WebCacheDB::PayloadInfo payload;
把打包好的数据通过HTTP请求,发送给服务器
1 scoped_refptr<BlobInterface> payload_data;
2
bool result = HttpPost(url_.c_str(),
3
false, // Not capturing, so follow redirects
4
NULL, // reason_header_value
5
HttpConstants::kMimeApplicationJson, // Content-Type
6
NULL, // mod_since_date
7
NULL, // required_cookie
8
true, // disable_browser_cookies
9
post_body_.get(),
10
&payload,
11
&payload_data,
12 NULL, // was_redirected
13
NULL, // full_redirect_url
14
NULL); // error_message
15
16 MutexLock lock(&is_processing_response_mutex_);
17
// is_aborted_ may be true even if HttpPost succeeded.
18
if (is_aborted_) {
19 LOG(("NetworkLocationRequest::Run() : HttpPost request was cancelled./n"));
20
return;
21 }
22
if (listener_) {
23 Position position;
24 std::string response_body;
25
if (result) {
26
// If HttpPost succeeded, payload_data is guaranteed to be non-NULL.
27
assert(payload_data.get());
28
if (!payload_data->Length() ||
29
!BlobToString(payload_data.get(), &response_body)) {
30 LOG(("NetworkLocationRequest::Run() : Failed to get response body./n"));
31 }
32 }
解析出位置信息
1 std::string16 access_token;
2 GetLocationFromResponse(result, payload.status_code, response_body,
3 timestamp_, url_, is_reverse_geocode_,
4
&position, &access_token);
通知位置信息的监听者
1
bool server_error =
2
!result || (payload.status_code >=
500
&& payload.status_code <
600);
3 listener_->LocationResponseAvailable(position, server_error, access_token);
4 }
5 }
有人会问,请求是发哪个服务器的?当然是google了,缺省的URL是:
1 static
const char16 *kDefaultLocationProviderUrl =
2 STRING16(L"https://www.google.com/loc/json");
回过头来,我们再总结一下:
1.WIFI和基站定位过程如下:
2.NetworkLocationProvider和 NetworkLocationRequest各有一个线程来异步处理请求。
3.这里的NetworkLocationProvider与android中的 NetworkLocationProvider并不是同一个东西,这里是给gears用的,要在android的google map中使用,还得包装成android中的NetworkLocationProvider的接口。
4.WIFI和基站定位与平台无关,只要你能拿到WIFI扫描结果或基站信息,而且能访问google的定位服务器,不管你是Android平台,Windows Mobile平台还是传统的feature phone,你都可以实现WIFI和基站定位。
1.下载源代码
svn checkout [url]http://gears.googlecode.com/svn/trunk/ gears-read-only[/url]
定位相关的源代码在gears/geolocation目录中。
2.关注android平台中的基站位置变化
JAVA类AndroidRadioDataProvider是 PhoneStateListener的子类,用来监听Android电话的状态变化。当服务状态、信号强度和基站变化时,
就会用下面代码获取小区信息:
1 RadioData radioData =
new RadioData();
2 GsmCellLocation gsmCellLocation = (GsmCellLocation) cellLocation;
3
4
// Extract the cell id, LAC, and signal strength.
5
radioData.cellId = gsmCellLocation.getCid();
6 radioData.locationAreaCode = gsmCellLocation.getLac();
7 radioData.signalStrength = signalStrength;
8
9
// Extract the home MCC and home MNC.
10
String operator
= telephonyManager.getSimOperator();
11 radioData.setMobileCodes(operator, true);
12
13
if (serviceState !=
null) {
14
// Extract the carrier name.
15
radioData.carrierName = serviceState.getOperatorAlphaLong();
16
17
// Extract the MCC and MNC.
18
operator
= serviceState.getOperatorNumeric();
19 radioData.setMobileCodes(operator, false);
20 }
21
22
// Finally get the radio type.
23
int type = telephonyManager.getNetworkType();
24
if (type == TelephonyManager.NETWORK_TYPE_UMTS) {
25 radioData.radioType = RADIO_TYPE_WCDMA;
26 } else
if (type == TelephonyManager.NETWORK_TYPE_GPRS
27
|| type == TelephonyManager.NETWORK_TYPE_EDGE) {
28 radioData.radioType = RADIO_TYPE_GSM;
29 }
30
然后再调用用C代码实现的onUpdateAvailable函数。
2.Native函数onUpdateAvailable是在 radio_data_provider_android.cc里实现的。
声明Native函数
1 JNINativeMethod AndroidRadioDataProvider::native_methods_[] = {
2 {"onUpdateAvailable",
3
"(L" GEARS_JAVA_PACKAGE "/AndroidRadioDataProvider$RadioData;J)V",
4 reinterpret_cast<void*>(AndroidRadioDataProvider::OnUpdateAvailable)
5 },
6 };
7
JNI调用好像只能调用静态成员函数,把对象本身用一个参数传进来,然后再调用对象的成员函数。
代码void AndroidRadioDataProvider::OnUpdateAvailable(JNIEnv* env,
jclass cls,
jobject radio_data,
jlong self) {
assert(radio_data);
assert(self);
AndroidRadioDataProvider *self_ptr =
reinterpret_cast<AndroidRadioDataProvider*>(self);
RadioData new_radio_data;
if (InitFromJavaRadioData(env, radio_data, &new_radio_data)) {
self_ptr->NewRadioDataAvailable(&new_radio_data);
}
}
先判断基站信息有没有变化,如果有变化则通知相关的监听者。
1 void AndroidRadioDataProvider::NewRadioDataAvailable(
2 RadioData* new_radio_data) {
3
bool is_update_available =
false;
4 data_mutex_.Lock();
5
if (new_radio_data &&
!radio_data_.Matches(*new_radio_data)) {
6 radio_data_ =
*new_radio_data;
7 is_update_available =
true;
8 }
9
// Avoid holding the mutex locked while notifying observers.
10
data_mutex_.Unlock();
11
12
if (is_update_available) {
13 NotifyListeners();
14 }
15 }
接下来的过程,在基站定位和WIFI定位是一样的,后面我们再来介绍。下面我们先看 WIFI定位
3.关注android平台中的WIFI变化。
JAVA类AndroidWifiDataProvider扩展了 BroadcastReceiver类,它关注WIFI扫描结果:
1 IntentFilter filter =
new IntentFilter();
2 filter.addAction(mWifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
3 mContext.registerReceiver(this, filter, null, handler);
当收到WIFI扫描结果后,调用Native函数 onUpdateAvailable,并把WIFI的扫描结果传递过去。
1 public
void onReceive(Context context, Intent intent) {
2
if (intent.getAction().equals(
3 mWifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
4
if (Config.LOGV) {
5 Log.v(TAG, "Wifi scan resulst available");
6 }
7 onUpdateAvailable(mWifiManager.getScanResults(), mNativeObject);
8 }
9 }
Native函数onUpdateAvailable是在 wifi_data_provider_android.cc里实现的。
1 JNINativeMethod AndroidWifiDataProvider::native_methods_[] = {
2 {"onUpdateAvailable",
3
"(Ljava/util/List;J)V",
4 reinterpret_cast<void*>(AndroidWifiDataProvider::OnUpdateAvailable)
5 },
6 };
7
8
void AndroidWifiDataProvider::OnUpdateAvailable(JNIEnv*
/* env */,
9 jclass /* cls */,
10 jobject wifi_data,
11 jlong self) {
12 assert(self);
13 AndroidWifiDataProvider *self_ptr =
14 reinterpret_cast<AndroidWifiDataProvider*>(self);
15 WifiData new_wifi_data;
16
if (wifi_data) {
17 InitFromJava(wifi_data, &new_wifi_data);
18 }
19
// We notify regardless of whether new_wifi_data is empty
20
// or not. The arbitrator will decide what to do with an empty
21
// WifiData object.
22
self_ptr->NewWifiDataAvailable(&new_wifi_data);
23 }
24
25
void AndroidWifiDataProvider::NewWifiDataAvailable(WifiData* new_wifi_data) {
26 assert(supported_);
27 assert(new_wifi_data);
28
bool is_update_available =
false;
29 data_mutex_.Lock();
30 is_update_available = wifi_data_.DiffersSignificantly(*new_wifi_data);
31 wifi_data_ =
*new_wifi_data;
32
// Avoid holding the mutex locked while notifying observers.
33
data_mutex_.Unlock();
34
35
if (is_update_available) {
36 is_first_scan_complete_ =
true;
37 NotifyListeners();
38 }
39
40
#if USING_CCTESTS
41
// This is needed for running the WiFi test on the emulator.
42
// See wifi_data_provider_android.h for details.
43
if (!first_callback_made_ && wifi_data_.access_point_data.empty()) {
44 first_callback_made_ =
true;
45 NotifyListeners();
46 }
47
#endif
48 }
49
50 JNINativeMethod AndroidWifiDataProvider::native_methods_[] = {
51 {"onUpdateAvailable",
52
"(Ljava/util/List;J)V",
53 reinterpret_cast<void*>(AndroidWifiDataProvider::OnUpdateAvailable)
54 },
55 };
56
57
void AndroidWifiDataProvider::OnUpdateAvailable(JNIEnv*
/* env */,
58 jclass /* cls */,
59 jobject wifi_data,
60 jlong self) {
61 assert(self);
62 AndroidWifiDataProvider *self_ptr =
63 reinterpret_cast<AndroidWifiDataProvider*>(self);
64 WifiData new_wifi_data;
65
if (wifi_data) {
66 InitFromJava(wifi_data, &new_wifi_data);
67 }
68
// We notify regardless of whether new_wifi_data is empty
69
// or not. The arbitrator will decide what to do with an empty
70
// WifiData object.
71
self_ptr->NewWifiDataAvailable(&new_wifi_data);
72 }
73
74
void AndroidWifiDataProvider::NewWifiDataAvailable(WifiData* new_wifi_data) {
75 assert(supported_);
76 assert(new_wifi_data);
77
bool is_update_available =
false;
78 data_mutex_.Lock();
79 is_update_available = wifi_data_.DiffersSignificantly(*new_wifi_data);
80 wifi_data_ =
*new_wifi_data;
81
// Avoid holding the mutex locked while notifying observers.
82
data_mutex_.Unlock();
83
84
if (is_update_available) {
85 is_first_scan_complete_ =
true;
86 NotifyListeners();
87 }
88
89
#if USING_CCTESTS
90
// This is needed for running the WiFi test on the emulator.
91
// See wifi_data_provider_android.h for details.
92
if (!first_callback_made_ && wifi_data_.access_point_data.empty()) {
93 first_callback_made_ =
true;
94 NotifyListeners();
95 }
96
#endif
97 }
98
从以上代码可以看出,WIFI定位和基站定位的逻辑差不多,只是前者获取的WIFI的扫描结果,而后者获取的基站信息。
后面代码的基本上就统一起来了,接下来我们继续看。
5.把变化(WIFI/基站)通知给相应的监听者。
1 AndroidWifiDataProvider和AndroidRadioDataProvider都是继承了DeviceDataProviderImplBase,DeviceDataProviderImplBase的主要功能就是管理所有Listeners。
2
3
static DeviceDataProvider *Register(ListenerInterface *listener) {
4 MutexLock mutex(&instance_mutex_);
5
if (!instance_) {
6 instance_ =
new DeviceDataProvider();
7 }
8 assert(instance_);
9 instance_->Ref();
10 instance_->AddListener(listener);
11
return instance_;
12 }
13
14
static
bool Unregister(ListenerInterface *listener) {
15 MutexLock mutex(&instance_mutex_);
16
if (!instance_->RemoveListener(listener)) {
17
return
false;
18 }
19
if (instance_->Unref()) {
20 delete instance_;
21 instance_ = NULL;
22 }
23
return
true;
24 }
25
6.谁在监听变化(WIFI/基站)
NetworkLocationProvider在监听变化(WIFI/基站):
1 radio_data_provider_ = RadioDataProvider::Register(this);
2 wifi_data_provider_ = WifiDataProvider::Register(this);
当有变化时,会调用函数DeviceDataUpdateAvailable:
代码// DeviceDataProviderInterface::ListenerInterface implementation.
void NetworkLocationProvider::DeviceDataUpdateAvailable(
RadioDataProvider *provider) {
MutexLock lock(&data_mutex_);
assert(provider == radio_data_provider_);
is_radio_data_complete_ = radio_data_provider_->GetData(&radio_data_);
DeviceDataUpdateAvailableImpl();
}
void NetworkLocationProvider::DeviceDataUpdateAvailable(
WifiDataProvider *provider) {
assert(provider == wifi_data_provider_);
MutexLock lock(&data_mutex_);
is_wifi_data_complete_ = wifi_data_provider_->GetData(&wifi_data_);
DeviceDataUpdateAvailableImpl();
}
无论是WIFI还是基站变化,最后都会调用 DeviceDataUpdateAvailableImpl:
1 void NetworkLocationProvider::DeviceDataUpdateAvailableImpl() {
2 timestamp_ = GetCurrentTimeMillis();
3
4
// Signal to the worker thread that new data is available.
5
is_new_data_available_ =
true;
6 thread_notification_event_.Signal();
7 }
这里面只是发了一个signal,通知另外一个线程去处理。
7.谁在等待thread_notification_event_
线程函数NetworkLocationProvider::Run在一个循环中等待 thread_notification_event,当有变化(WIFI/基站)时,就准备请求服务器查询位置。
先等待:
1 if (remaining_time >
0) {
2 thread_notification_event_.WaitWithTimeout(
3 static_cast<int>(remaining_time));
4 } else {
5 thread_notification_event_.Wait();
6 }
准备请求:
1 if (make_request) {
2 MakeRequest();
3 remaining_time =
1;
4 }
再来看MakeRequest的实现:
先从cache中查找位置:
1
const Position *cached_position =
2 position_cache_->FindPosition(radio_data_, wifi_data_);
3 data_mutex_.Unlock();
4
if (cached_position) {
5 assert(cached_position->IsGoodFix());
6
// Record the position and update its timestamp.
7
position_mutex_.Lock();
8 position_ =
*cached_position;
9 position_.timestamp = timestamp_;
10 position_mutex_.Unlock();
11
12
// Let listeners know that we now have a position available.
13
UpdateListeners();
14
return
true;
15 }
如果找不到,再做实际的请求
1
return request_->MakeRequest(access_token,
2 radio_data_,
3 wifi_data_,
4 request_address_,
5 address_language_,
6 kBadLatLng, // We don't have a position to pass
7
kBadLatLng, // to the server.
8
timestamp_);
7.客户端协议包装
前面的request_是NetworkLocationRequest实例,先看 MakeRequest的实现:
先对参数进行打包:
1
if (!FormRequestBody(host_name_, access_token, radio_data, wifi_data,
2 request_address, address_language, latitude, longitude,
3 is_reverse_geocode_, &post_body_)) {
4
return
false;
5 }
通知负责收发的线程
1 thread_event_.Signal();
8.负责收发的线程
1 void NetworkLocationRequest::Run() {
2
while (true) {
3 thread_event_.Wait();
4
if (is_shutting_down_) {
5
break;
6 }
7 MakeRequestImpl();
8 }
9 }
10
11
void NetworkLocationRequest::MakeRequestImpl() {
12 WebCacheDB::PayloadInfo payload;
把打包好的数据通过HTTP请求,发送给服务器
1 scoped_refptr<BlobInterface> payload_data;
2
bool result = HttpPost(url_.c_str(),
3
false, // Not capturing, so follow redirects
4
NULL, // reason_header_value
5
HttpConstants::kMimeApplicationJson, // Content-Type
6
NULL, // mod_since_date
7
NULL, // required_cookie
8
true, // disable_browser_cookies
9
post_body_.get(),
10
&payload,
11
&payload_data,
12 NULL, // was_redirected
13
NULL, // full_redirect_url
14
NULL); // error_message
15
16 MutexLock lock(&is_processing_response_mutex_);
17
// is_aborted_ may be true even if HttpPost succeeded.
18
if (is_aborted_) {
19 LOG(("NetworkLocationRequest::Run() : HttpPost request was cancelled./n"));
20
return;
21 }
22
if (listener_) {
23 Position position;
24 std::string response_body;
25
if (result) {
26
// If HttpPost succeeded, payload_data is guaranteed to be non-NULL.
27
assert(payload_data.get());
28
if (!payload_data->Length() ||
29
!BlobToString(payload_data.get(), &response_body)) {
30 LOG(("NetworkLocationRequest::Run() : Failed to get response body./n"));
31 }
32 }
解析出位置信息
1 std::string16 access_token;
2 GetLocationFromResponse(result, payload.status_code, response_body,
3 timestamp_, url_, is_reverse_geocode_,
4
&position, &access_token);
通知位置信息的监听者
1
bool server_error =
2
!result || (payload.status_code >=
500
&& payload.status_code <
600);
3 listener_->LocationResponseAvailable(position, server_error, access_token);
4 }
5 }
有人会问,请求是发哪个服务器的?当然是google了,缺省的URL是:
1 static
const char16 *kDefaultLocationProviderUrl =
2 STRING16(L"https://www.google.com/loc/json");
回过头来,我们再总结一下:
1.WIFI和基站定位过程如下:
2.NetworkLocationProvider和 NetworkLocationRequest各有一个线程来异步处理请求。
3.这里的NetworkLocationProvider与android中的 NetworkLocationProvider并不是同一个东西,这里是给gears用的,要在android的google map中使用,还得包装成android中的NetworkLocationProvider的接口。
4.WIFI和基站定位与平台无关,只要你能拿到WIFI扫描结果或基站信息,而且能访问google的定位服务器,不管你是Android平台,Windows Mobile平台还是传统的feature phone,你都可以实现WIFI和基站定位。
- Android系列之Wifi定位
- Android系列之Wifi定位
- Android系列之Wifi定位
- Android系列之Wifi定位
- android 基站定位 wifi定位
- android WIFI定位
- android 的wifi定位
- android 的wifi定位
- android 的wifi定位
- android 的wifi定位
- android中 WIFI定位
- android wifi 问题定位
- 凯立德超快定位,Android平板变导航之Wifi篇
- android WIFI定位和基站定位实现
- android WIFI定位和基站定位实现
- android 使用基站 wifi定位
- android gps wifi 基站定位
- android基站和wifi定位
- windows和linux批处理互相调用的方法
- rsync 配置详解
- 向数据库添加连续日期(年和日期分开)
- 开发证书与发布证书申请和安装步骤
- 第一篇博客
- Android系列之Wifi定位
- 从网络上下载图片的纠结
- WinCE下的触摸屏校准
- windows自动登录设置
- Http之Get/Post请求区别
- 如何用SQL语句把同一列的数据按某个group by语句组合成一行数据
- 管理新理念:顾客不再是上帝
- 交通灯控制器program
- 10月Web服务器调查