原理
通过手机读取附近的手机信号基站id,然后查询google公开的基站数据库获取经纬度。
实现
通过TelephonyManager 获取lac:mcc:mnc:cell-id(请参考sdk doc文档中TelephonyManager api介绍),发送到http://www.google.com/loc/json 查询。
如果不知道lac, mcc, mnc, cell-id, 请Google。
google location api 详细地址http://code.google.com/p/gears/wiki/GeolocationAPI
代码是以前写的简单的例子(其中函数getNeighboringCellInfo()在android1.5之下是有问题的,返回为空,后者返回无效数据)
package com.test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.util.List;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.telephony.CellLocation;
import android.telephony.NeighboringCellInfo;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.telephony.gsm.GsmCellLocation;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class LocationMe extends Activity implements OnClickListener {
/** Called when the activity is first created. */
TelephonyManager manager;
TextView tv,loc;
int mcc, mnc, lac[] , ci[];
String mac;
EditText mcc_text, mnc_text, lac_text, ci_text, mac_text;
Button find,showinmap,update;
int count ;
ProgressDialog mProgressDialog;
PhoneStateListener listener;
Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
if(msg.what==100){
mProgressDialog.dismiss();
lac_text.setText(lac[0]+","+lac[1]);//+","+lac[2]);
ci_text.setText(ci[0]+","+ci[1]);//+","+ci[2]);
}
if(msg.what==101){
tv.setText(result_location);
loc.setText( la + "-" + lo);
showinmap.setEnabled(true);
mProgressDialog.dismiss();
}
if(msg.what==102){
mProgressDialog.dismiss();
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tv = (TextView) findViewById(R.id.tv);
loc = (TextView) findViewById(R.id.location);
mcc_text = (EditText) findViewById(R.id.mcc);
mnc_text = (EditText) findViewById(R.id.mnc);
lac_text = (EditText) findViewById(R.id.lac);
ci_text = (EditText) findViewById(R.id.ci);
mac_text= (EditText) findViewById(R.id.mac);
find = (Button) findViewById(R.id.find_btn);
showinmap = (Button) findViewById(R.id.show_in_map);
manager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
update= (Button) findViewById(R.id.update);
find.setOnClickListener(this);
update.setOnClickListener(this);
showinmap.setOnClickListener(this);
ci = new int[10];
lac = new int[10];
mProgressDialog =new ProgressDialog(this);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
mProgressDialog.setCancelable(false);
listener = new CellStateListener ();
}
void update(){
count =0;
// CellLocation location = manager.getCellLocation();
Log.e("Location","NetworkCountryIso"+manager.getNetworkCountryIso());//cn
mcc = Integer.valueOf(manager.getNetworkOperator().substring(0,3));
mcc_text.setText(String.valueOf(mcc));
mnc = Integer.valueOf(manager.getNetworkOperator().substring(3,5));;
mnc_text.setText(String.valueOf(mnc));
// manager.listen(listener, PhoneStateListener.LISTEN_CELL_LOCATION);
manager.listen(listener, 0);
GsmCellLocation sm = ((GsmCellLocation)manager.getCellLocation());
Log.e("Location", "cid"+sm.getCid()+" lac"+sm.getLac());
lac[0]=sm.getLac();
// mProgressDialog.setMessage("Updating...(0/3)");
// mProgressDialog.show();
List<NeighboringCellInfo> list = manager.getNeighboringCellInfo();
count = list.size();
Log.e("Location","neighbors "+count);
NeighboringCellInfo info;
loc.setText("");
ci_text.setText("");
for(int i =0; i<count;i++){
info = list.get(i);
Log.e("Location", info.getCid()+"-"+info.getRssi()+" "+info.toString());
lac=lac[0];
ci=info.getCid()-415500000;
ci_text.setText(ci_text.getText().toString()+","+ci);
loc.setText(loc.getText()+" "+info.getCid());
}
}
void findme() {
mProgressDialog.setMessage("Finding...");
mProgressDialog.show();
Thread thread = new Thread(){
public void run(){
try {
DefaultHttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost("http://www.google.com/loc/json");//http://www.google.com/glm/mmap");//
JSONObject holder = new JSONObject();
holder.put("version", "1.1.0");
// holder.put("host", "maps.google.com");
// holder.put("home_mobile_country_code", mcc);
// holder.put("home_mobile_network_code", mnc);
// holder.put("radio_type", "gsm");
// holder.put("carrier", "Vodafone");
holder.put("request_address", true);
holder.put("address_language", "en-us");
JSONObject data ;// = new JSONObject();
// data.put("latitude", 31.244506);
// data.put("longitude", 121.591095);
// holder.put("location",data);
JSONArray array = new JSONArray();
for(int i =0;i<(count<2 count:2);i++){
data = new JSONObject();
data.put("cell_id", ci); // 9457, 8321,8243
data.put("location_area_code", lac);// 28602
data.put("mobile_country_code", mcc);// 208
data.put("mobile_network_code", mnc);// 0
data.put("age", 0);
// data.put("signal_strength", -60);
// data.put("timing_advance", 5555);
array.put(data);
}
holder.put("cell_towers", array);
////////////////////////WIFI//////////////////////////////////////
// WifiManager wm = (WifiManager)getSystemService(Context.WIFI_SERVICE);
// WifiInfo info = wm.getConnectionInfo();
// String mac = info.getMacAddress();
// Log.e("LocationMe","mac:"+mac);
// data = new JSONObject();
// data.put("mac_address", mac);
// data.put("signal_strength", 8);
// data.put("age", 0);
// array = new JSONArray();
// array.put(data);
//holder.put("wifi_towers ", array);
////////////////////////////////////
StringEntity se = new StringEntity(holder.toString());
Log.e("Location send",holder.toString());
post.setEntity(se);
HttpResponse resp = client.execute(post);
HttpEntity entity = resp.getEntity();
BufferedReader br = new BufferedReader(new InputStreamReader(entity
.getContent()));
StringBuffer sb = new StringBuffer();
String result = br.readLine();
while (result != null) {
Log.e("Locaiton reseive", result);
sb.append(result);
result = br.readLine();
}
result_location = sb.toString();
data = new JSONObject(sb.toString());
data = (JSONObject) data.get("location");
la = (Double) data.get("latitude");
lo = (Double) data.get("longitude");
mHandler.sendEmptyMessage(101);
} catch (ClientProtocolException e) {
e.printStackTrace();
mHandler.sendEmptyMessage(102);
} catch (IOException e) {
e.printStackTrace();
mHandler.sendEmptyMessage(102);
} catch (JSONException e) {
e.printStackTrace();
// loc.setText("");
// showinmap.setEnabled(false);
mHandler.sendEmptyMessage(102);
}
}
};
thread.start();
}
String result_location;
double la,lo;
@Override
public void onClick(View arg0) {
switch(arg0.getId()){
case R.id.find_btn:{
findme();
break;
}
case R.id.show_in_map:{
Uri mapUri = Uri.parse("geo:"+la+","+lo+" z=12&cbp=1");
startActivity(new Intent(Intent.ACTION_VIEW, mapUri));
break;
}
case R.id.update:{
update();
break;
}
}
}
class CellStateListener extends PhoneStateListener{
public void onCellLocationChanged(CellLocation location){
GsmCellLocation gsmL = (GsmCellLocation) location;
if(count <2){
ci[count] = gsmL.getCid();
lac[count] = gsmL.getLac();
count++;
mProgressDialog.setMessage("Updating...("+count+"/3)");
gsmL.requestLocationUpdate();
if(count ==2){
manager.listen(this, 0);
mHandler.sendEmptyMessage(100);
}
}
}
}
}
/*
Gears Request
{
"version": "1.1.0",
"host": "maps.google.com",
"access_token": "2:k7j3G6LaL6u_lafw:4iXOeOpTh1glSXe",
"home_mobile_country_code": 310,
"home_mobile_network_code": 410,
"radio_type": "gsm",
"carrier": "Vodafone",
"request_address": true,
"address_language": "en_GB",
"location": {
"latitude": 51.0,
"longitude": -0.1
},
"cell_towers": [
{
"cell_id": 42,
"location_area_code": 415,
"mobile_country_code": 310,
"mobile_network_code": 410,
"age": 0,
"signal_strength": -60,
"timing_advance": 5555
},
{
"cell_id": 88,
"location_area_code": 415,
"mobile_country_code": 310,
"mobile_network_code": 580,
"age": 0,
"signal_strength": -70,
"timing_advance": 7777
}
],
"wifi_towers": [
{
"mac_address": "01-23-45-67-89-ab",
"signal_strength": 8,
"age": 0
},
{
"mac_address": "01-23-45-67-89-ac",
"signal_strength": 4,
"age": 0
}
]
}
* responce
{
"location": {
"latitude": 51.0,
"longitude": -0.1,
"altitude": 30.1,
"accuracy": 1200.4,
"altitude_accuracy": 10.6,
"address": {
"street_number": "100",
"street": "Amphibian Walkway",
"postal_code": "94043",
"city": "Mountain View",
"county": "Mountain View County",
"region": "California",
"country": "United States of America",
"country_code": "US"
}
},
"access_token": "2:k7j3G6LaL6u_lafw:4iXOeOpTh1glSXe"
}
08-03 16:48:08.393: ERROR/Location(2350): NetworkCountryIsocn
08-03 16:48:08.423: ERROR/Location(2350): cid9457 lac6340
08-03 16:48:08.443: ERROR/Location(2350): neighbors 5
08-03 16:48:08.453: ERROR/Location(2350): 415506483-9 [18c42033 at 9]
08-03 16:48:08.463: ERROR/Location(2350): 415506691-9 [18c42103 at 9]
08-03 16:48:08.463: ERROR/Location(2350): 415506529-7 [18c42061 at 7]
08-03 16:48:08.473: ERROR/Location(2350): 415531363-11 [18c48163 at 11]
08-03 16:48:08.483: ERROR/Location(2350): 415506531-6 [18c42063 at 6]
*
*/
http://hi.baidu.com/adnroidorg/blog/item/96c65dd750a12c16a08bb7eb.html