经过几天的调研以及测试,终于解决了联通2G、移动2G、电信3G的基站定位代码。团队里面只有这些机器的制式了。下面就由我来做一个详细的讲解吧。
1 相关技术内容
Google Android Api里面的TelephonyManager的管理。
联通、移动、电信不同制式在获取基站位置的代码区别。
通过基站的基本信息,通过Google Gears获取对应的GPS经纬度。
通过Google Map API根据GPS经纬度获取当前位置。
2 目前存在的几个问题
由于得到的GPS经纬度在Google Map上面显示需要偏移,这块暂时没有进行处理。
没有使用PhoneStateListener来对状态实时进行更新。
没有使用线程异步获取数据
没有使用服务的方式来实时获取数据
所以如果是商业使用的话,还需进一步修改。
3 当然本部分代码已经移植到我们的家庭卫士的项目中了,2提到的问题全部解决了。
下面我针对第一部分的四大内容进行代码注解。
1 Google Android Api里面的TelephonyManager的管理。
1
|
通过这个方式就可以得到TelephonyManager接口。
这个接口的源代码可以通过设置在项目里面查看,这里不具体附上了。
得到TelephonyManager后,由于针对不同的运营商,代码有所不同,所以需要判断getNetworkType()
在源代码里面有如下的类型定义
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/** Network type is unknown */
public static final intNETWORK_TYPE_UNKNOWN = 0 ; /** Current network is GPRS */ public static final intNETWORK_TYPE_GPRS = 1 ; /** Current network is EDGE */ public static final intNETWORK_TYPE_EDGE = 2 ; /** Current network is UMTS */ public static final intNETWORK_TYPE_UMTS = 3 ; /** Current network is CDMA: Either IS95A or IS95B*/ public static final intNETWORK_TYPE_CDMA = 4 ; /** Current network is EVDO revision 0*/ public static final intNETWORK_TYPE_EVDO_0 = 5 ; /** Current network is EVDO revision A*/ public static final intNETWORK_TYPE_EVDO_A = 6 ; /** Current network is 1xRTT*/ public static final intNETWORK_TYPE_1xRTT = 7 ; /** Current network is HSDPA */ public static final intNETWORK_TYPE_HSDPA = 8 ; /** Current network is HSUPA */ public static final intNETWORK_TYPE_HSUPA = 9 ; /** Current network is HSPA */ public static final intNETWORK_TYPE_HSPA = 10 ; |
2 联通、移动、电信不同制式在获取基站位置的代码区别。
这部分是我实际测试出来的,经过无数次的拆机,放卡,才实现了不同制式的完美实现。
代码如下:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
TelephonyManager tm
=
(TelephonyManager
)getSystemService
(
Context.
TELEPHONY_SERVICE
)
;
inttype =tm. getNetworkType ( ) ; //中国电信为CTC //NETWORK_TYPE_EVDO_A是中国电信3G的getNetworkType //NETWORK_TYPE_CDMA电信2G是CDMA if (type ==TelephonyManager. NETWORK_TYPE_EVDO_A ||type ==TelephonyManager. NETWORK_TYPE_CDMA ||type ==TelephonyManager. NETWORK_TYPE_1xRTT ) { } //移动2G卡 + CMCC + 2 //type = NETWORK_TYPE_EDGE else if (type ==TelephonyManager. NETWORK_TYPE_EDGE ) { } //联通的2G经过测试 China Unicom 1 NETWORK_TYPE_GPRS else if (type ==TelephonyManager. NETWORK_TYPE_GPRS ) { } else { tv. setText ( "Current Not Support This Type." ) ; } |
3 通过基站的基本信息,通过Google Gears获取对应的GPS经纬度。
这部分前面的两篇文章都有提到,代码参考了网友们的代码,感谢感谢。
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 |
privateLocation callGear
(
ArrayListcellID
)
{
if (cellID == null ) return null ; DefaultHttpClient client = newDefaultHttpClient ( ) ; HttpPost post = newHttpPost ( "http://www.google.com/loc/json" ) ; JSONObject holder = newJSONObject ( ) ; try { holder. put ( "version", "1.1.0" ) ; holder. put ( "host", "maps.google.com" ) ; holder. put ( "home_mobile_country_code", cellID. get ( 0 ). mobileCountryCode ) ; holder. put ( "home_mobile_network_code", cellID. get ( 0 ). mobileNetworkCode ) ; holder. put ( "radio_type", cellID. get ( 0 ). radioType ) ; holder. put ( "request_address", true ) ; if ( "460". equals (cellID. get ( 0 ). mobileCountryCode ) ) holder. put ( "address_language", "zh_CN" ) ; else holder. put ( "address_language", "en_US" ) ; JSONObject data,current_data ; JSONArray array = newJSONArray ( ) ; current_data = newJSONObject ( ) ; current_data. put ( "cell_id", cellID. get ( 0 ). cellId ) ; current_data. put ( "location_area_code", cellID. get ( 0 ). locationAreaCode ) ; current_data. put ( "mobile_country_code", cellID. get ( 0 ). mobileCountryCode ) ; current_data. put ( "mobile_network_code", cellID. get ( 0 ). mobileNetworkCode ) ; current_data. put ( "age", 0 ) ; array. put (current_data ) ; if (cellID. size ( ) > ; 2 ) { for ( inti = 1 ;i < ;cellID. size ( ) ;i ++ ) { data = newJSONObject ( ) ; data. put ( "cell_id", cellID. get (i ). cellId ) ; data. put ( "location_area_code", cellID. get (i ). locationAreaCode ) ; data. put ( "mobile_country_code", cellID. get (i ). mobileCountryCode ) ; data. put ( "mobile_network_code", cellID. get (i ). mobileNetworkCode ) ; data. put ( "age", 0 ) ; array. put (data ) ; } } holder. put ( "cell_towers", array ) ; StringEntity se = newStringEntity (holder. toString ( ) ) ; Log. e ( "Location send", holder. toString ( ) ) ; post. setEntity (se ) ; HttpResponse resp =client. execute (post ) ; HttpEntity entity =resp. getEntity ( ) ; BufferedReaderbr = new BufferedReader ( new InputStreamReader (entity. getContent ( ) ) ) ; StringBuffersb = new StringBuffer ( ) ; Stringresult =br. readLine ( ) ; while (result != null ) { Log. e ( "Locaiton receive", result ) ; sb. append (result ) ; result =br. readLine ( ) ; } if (sb. length ( ) return null ; data = newJSONObject (sb. toString ( ) ) ; data = (JSONObject )data. get ( "location" ) ; Location loc = newLocation (LocationManager. NETWORK_PROVIDER ) ; loc. setLatitude ( ( Double )data. get ( "latitude" ) ) ; loc. setLongitude ( ( Double )data. get ( "longitude" ) ) ; loc. setAccuracy ( Float. parseFloat (data. get ( "accuracy" ). toString ( ) ) ) ; loc. setTime (GetUTCTime ( ) ) ; returnloc ; } catch (JSONException e ) { return null ; } catch ( UnsupportedEncodingExceptione ) { e. printStackTrace ( ) ; } catch (ClientProtocolException e ) { e. printStackTrace ( ) ; } catch ( IOExceptione ) { e. printStackTrace ( ) ; } return null ; } |
4 通过Google Map API根据GPS经纬度获取当前位置。
本部分代码参考了简单基站定位程序,感谢雷一兄这么好的文章。同时雷一兄的排版真的非常好看,清晰明了。
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 |
private
StringgetLocation
(Location itude
)
throws
Exception
{
StringresultString = "" ; /** 这里采用get方法,直接将参数加到URL上 */ StringurlString = String. format ( "http://maps.google.cn/maps/geo?key=abcdefg&q=%s,%s", itude. getLatitude ( ), itude. getLongitude ( ) ) ; Log. i ( "URL", urlString ) ; /** 新建HttpClient */ HttpClient client = newDefaultHttpClient ( ) ; /** 采用GET方法 */ HttpGet get = newHttpGet (urlString ) ; try { /** 发起GET请求并获得返回数据 */ HttpResponse response =client. execute (get ) ; HttpEntity entity =response. getEntity ( ) ; BufferedReaderbuffReader = new BufferedReader ( new InputStreamReader (entity. getContent ( ) ) ) ; StringBufferstrBuff = new StringBuffer ( ) ; Stringresult = null ; while ( (result =buffReader. readLine ( ) ) != null ) { strBuff. append (result ) ; } resultString =strBuff. toString ( ) ; /** 解析JSON数据,获得物理地址 */ if (resultString != null & ;& ;resultString. length ( ) > ; 0 ) { JSONObject jsonobject = newJSONObject (resultString ) ; JSONArray jsonArray = newJSONArray (jsonobject. get ( "Placemark" ). toString ( ) ) ; resultString = "" ; for ( inti = 0 ;i < ;jsonArray. length ( ) ;i ++ ) { resultString =jsonArray. getJSONObject (i ). getString ( "address" ) ; } } } catch ( Exceptione ) { throw new Exception ( "获取物理位置出现错误:" +e. getMessage ( ) ) ; } finally { get. abort ( ) ; client = null ; } returnresultString ; } |
5 最关键的出来了,附上代码吧。
AndroidPosition
补充一下:
在AndroidMenifest.xml里面需要加上
android.permission.INTERNET、android.permission.ACCESS_COARSE_LOCATION、android.permission.READ_PHONE_STATE权限,否则会出错。
放在Application包前面。
7 另外在提交数据到Google Gears的时候,格式如下
发送到Google的数据格式:
02-24 18:08:20.550: E/Location send(12892): {"address_language":"zh_CN","host":"maps.google.com","radio_type":"cdma","home_mobile_country_code":"460","home_mobile_network_code":"13965","cell_towers":[{"mobile_network_code":"13965","location_area_code":11,"cell_id":1985,"age":0,"mobile_country_code":"460"}],"request_address":true,"version":"1.1.0"}
接收到Google的数据格式:
02-24 18:08:22.975: E/Locaiton receive(12892): {"location":{"latitude":43.8595097,"longitude":125.3355736,"address":{"country":"中国","country_code":"CN","region":"吉林省","city":"长春市","street":"文昌路","street_number":""},"accuracy":1815.0},"access_token":"2:_Kpk9mOFMgyWgLai:8iWlDpBYZsp4_VxO"}
-End-