Android基站定位源代碼
經過幾天的調研以及測試,終於解決了聯通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的管理。
TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
這個接口的源代碼可以通過設置在項目裏面查看,這裏不具體附上了。
得到TelephonyManager後,由於針對不同的運營商,代碼有所不同,所以需要判斷getNetworkType()
在源代碼裏面有如下的類型定義
/** Network type is unknown */ public static final int NETWORK_TYPE_UNKNOWN = 0; /** Current network is GPRS */ public static final int NETWORK_TYPE_GPRS = 1; /** Current network is EDGE */ public static final int NETWORK_TYPE_EDGE = 2; /** Current network is UMTS */ public static final int NETWORK_TYPE_UMTS = 3; /** Current network is CDMA: Either IS95A or IS95B*/ public static final int NETWORK_TYPE_CDMA = 4; /** Current network is EVDO revision 0*/ public static final int NETWORK_TYPE_EVDO_0 = 5; /** Current network is EVDO revision A*/ public static final int NETWORK_TYPE_EVDO_A = 6; /** Current network is 1xRTT*/ public static final int NETWORK_TYPE_1xRTT = 7; /** Current network is HSDPA */ public static final int NETWORK_TYPE_HSDPA = 8; /** Current network is HSUPA */ public static final int NETWORK_TYPE_HSUPA = 9; /** Current network is HSPA */ public static final int NETWORK_TYPE_HSPA = 10;
2 聯通、移動、電信不同制式在獲取基站位置的代碼區別。
這部分是我實際測試出來的,經過無數次的拆機,放卡,才實現了不同制式的完美實現。
代碼如下:
TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); int type = 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經緯度。
這部分前面的兩篇文章都有提到,代碼參考了網友們的代碼,感謝感謝。
private Location callGear(ArrayList cellID) { if (cellID == null) return null; DefaultHttpClient client = new DefaultHttpClient(); HttpPost post = new HttpPost( "http://www.google.com/loc/json"); JSONObject holder = new JSONObject(); 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 = new JSONArray(); current_data = new JSONObject(); 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 (int i = 1; i < cellID.size(); i++) { data = new JSONObject(); 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 = 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 receive", result); sb.append(result); result = br.readLine(); } if(sb.length() return null; data = new JSONObject(sb.toString()); data = (JSONObject) data.get("location"); Location loc = new Location(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()); return loc; } catch (JSONException e) { return null; } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; }
4 通過Google Map API根據GPS經緯度獲取當前位置。
本部分代碼參考了 簡單基站定位程序 ,感謝雷一兄這麼好的文章。同時雷一兄的排版真的非常好看,清晰明瞭。
private String getLocation(Location itude) throws Exception { String resultString = ""; /** 這裏採用get方法,直接將參數加到URL上 */ String urlString = String.format("http://maps.google.cn/maps/geo?key=abcdefg&q=%s,%s", itude.getLatitude(), itude.getLongitude()); Log.i("URL", urlString); /** 新建HttpClient */ HttpClient client = new DefaultHttpClient(); /** 採用GET方法 */ HttpGet get = new HttpGet(urlString); try { /** 發起GET請求並獲得返回數據 */ HttpResponse response = client.execute(get); HttpEntity entity = response.getEntity(); BufferedReader buffReader = new BufferedReader(new InputStreamReader(entity.getContent())); StringBuffer strBuff = new StringBuffer(); String result = null; while ((result = buffReader.readLine()) != null) { strBuff.append(result); } resultString = strBuff.toString(); /** 解析JSON數據,獲得物理地址 */ if (resultString != null && resultString.length() > 0) { JSONObject jsonobject = new JSONObject(resultString); JSONArray jsonArray = new JSONArray(jsonobject.get("Placemark").toString()); resultString = ""; for (int i = 0; i < jsonArray.length(); i++) { resultString = jsonArray.getJSONObject(i).getString("address"); } } } catch (Exception e) { throw new Exception("獲取物理位置出現錯誤:" + e.getMessage()); } finally { get.abort(); client = null; } return resultString; }
5 最關鍵的出來了,附上代碼吧。
AndroidPosition
補充一下:
在AndroidMenifest.xml裏面需要加上
android.permission.INTERNET、android.permission.ACCESS_COARSE_LOCATION、android.permission.READ_PHONE_STATE權限,否則會出錯。
放在Application包前面。
6 圖片看一下效果吧。
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-