android GSM+CDMA基站定位

在googleAPI里提供了基站信息的获取类TelephonyManager,通过其方法getCellLocation得到CellLocation即可获取到基站相关信息

但CellLocation是个抽象类,所以在具体使用时需要判断接入的网络制式来用其子类CdmaCellLocation或GsmCellLocation 来强转

CdmaCellLocation对应CDMA网,GsmCellLocation对应GSM网

三大网络运营商的网络制式对应如下:

移动2G 网 --> GSM

移动3G 网 --> TD-SCDMA

电信2G 网 --> CDMA

电信3G 网 --> CDMA2000

联通2G 网 --> GSM

联通3G 网 --> WCDMA

由此可见移动,联通2G 网都可使用GsmCellLocation

电信2G,3G网则使用CdmaCellLocation

那么移动3G和联通3G又当如何

其实经本人亲测,移动3G网也可使用GsmCellLocation,听说是TD-SCDMA衍生于GSM,具体原因咱也不用纠结了,反正能用就是了

而联通的WCDMA据说也可使用GsmCellLocation,那姑且就是这样吧,有条件的童鞋试一试吧。

对于网络制式的判断调用TelephonyManager.getNetworkType()可有多种情况,如下:

  • NETWORK_TYPE_UNKNOWN
  • NETWORK_TYPE_GPRS
  • NETWORK_TYPE_EDGE
  • NETWORK_TYPE_UMTS
  • NETWORK_TYPE_HSDPA
  • NETWORK_TYPE_HSUPA
  • NETWORK_TYPE_HSPA
  • NETWORK_TYPE_CDMA
  • NETWORK_TYPE_EVDO_0
  • NETWORK_TYPE_EVDO_A
  • NETWORK_TYPE_EVDO_B
  • NETWORK_TYPE_1xRTT
  • NETWORK_TYPE_IDEN
  • NETWORK_TYPE_LTE
  • NETWORK_TYPE_EHRPD

通过对网络类型判断后获取对应基站信息代码片段如下:

public static ArrayList getCellIDInfo(Context context) throws Exception{
		
		TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
		
		ArrayList CellID = new ArrayList();
		CellIDInfo currentCell = new CellIDInfo();

		int type = manager.getNetworkType();
		Log.d(TAG, "getCellIDInfo--> 		NetworkType = " + type);
		int phoneType = manager.getPhoneType();
		Log.d(TAG, "getCellIDInfo--> 		phoneType = " + phoneType);
		
		if (type == TelephonyManager.NETWORK_TYPE_GPRS				// GSM网
				|| type == TelephonyManager.NETWORK_TYPE_EDGE
				|| type == TelephonyManager.NETWORK_TYPE_HSDPA)
		{
			GsmCellLocation gsm = ((GsmCellLocation) manager.getCellLocation());
			if (gsm == null)
			{
				Log.e(TAG, "GsmCellLocation is null!!!");
				return null;
			}
				

			int lac = gsm.getLac();
			String mcc = manager.getNetworkOperator().substring(0, 3);
			String mnc = manager.getNetworkOperator().substring(3, 5);
			int cid = gsm.getCid();
			
			currentCell.cellId = gsm.getCid();
			currentCell.mobileCountryCode = mcc;
			currentCell.mobileNetworkCode = mnc;
			currentCell.locationAreaCode = lac;
			
			currentCell.radioType = "gsm";
			
			CellID.add(currentCell);
			
			// 获得邻近基站信息
			List list = manager.getNeighboringCellInfo();
			int size = list.size();
			for (int i = 0; i < size; i++) {

				CellIDInfo info = new CellIDInfo();
				info.cellId = list.get(i).getCid();
				info.mobileCountryCode = mcc;
				info.mobileNetworkCode = mnc;
				info.locationAreaCode = lac;
			
				CellID.add(info);
			}
			
		}else if (type == TelephonyManager.NETWORK_TYPE_CDMA		// 电信cdma网
				|| type == TelephonyManager.NETWORK_TYPE_1xRTT
				|| type == TelephonyManager.NETWORK_TYPE_EVDO_0
				|| type == TelephonyManager.NETWORK_TYPE_EVDO_A)
		{
			
			CdmaCellLocation cdma = (CdmaCellLocation) manager.getCellLocation();	
			if (cdma == null)
			{
				Log.e(TAG, "CdmaCellLocation is null!!!");
				return null;
			}
			
			int lac = cdma.getNetworkId();
			String mcc = manager.getNetworkOperator().substring(0, 3);
			String mnc = String.valueOf(cdma.getSystemId());
			int cid = cdma.getBaseStationId();
			
			currentCell.cellId = cid;
			currentCell.mobileCountryCode = mcc;
			currentCell.mobileNetworkCode = mnc;
			currentCell.locationAreaCode = lac;
	
			currentCell.radioType = "cdma";
			
			CellID.add(currentCell);
			
			// 获得邻近基站信息
			List list = manager.getNeighboringCellInfo();
			int size = list.size();
			for (int i = 0; i < size; i++) {

				CellIDInfo info = new CellIDInfo();
				info.cellId = list.get(i).getCid();
				info.mobileCountryCode = mcc;
				info.mobileNetworkCode = mnc;
				info.locationAreaCode = lac;
			
				CellID.add(info);
			}
		}
		
		return CellID;
			
	}


从GOOGLE的API文档里总共有14钟网络类型,这里只罗列了其中7种,其他的主要是本人也不太清楚其对应到的网络制式是怎样的

所以部分童鞋的SIM卡网络制式不在这7种之内,自己根据实际情况看看它是归类于GSM还是CDMA在添进去就可以了


网络上多数教程是讲GSM网获取基站的,而忽略了C网的基站
这里我们可以比较一下GSM 和 CDMA 在获取基站信息时的不同之处



GSM:

int lac = gsm.getLac();
String mcc = manager.getNetworkOperator().substring(0, 3);
String mnc = manager.getNetworkOperator().substring(3, 5);
int cid = gsm.getCid();



CDMA:

int lac = cdma.getNetworkId();
String mcc = manager.getNetworkOperator().substring(0, 3);
String mnc = String.valueOf(cdma.getSystemId());
int cid = cdma.getBaseStationId();



在获取区域码LAC时GSM使用的是GsmCellLocation.getLac(),CDMA则用CdmaCellLocation.getNetworkId()来代替

在获取基站ID时GSM使用的是GsmCellLocation.getCid(),CDMA则用CdmaCellLocation.getBaseStationId()来代替





前面获取到的都是单个基站的信息,后面再获取周围邻近基站信息以辅助通过基站定位的精准性

TelephonyManager.getNeighboringCellInfo(),将其也放入基站信息LIST表中





最后通过google提供的gear接口获取经纬度,代码如下:

public static Location callGear(List cellID) {
	        if (cellID == null || cellID.size() == 0) 
	                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);
	                    current_data.put("signal_strength", -60);
	                    current_data.put("timing_advance", 5555);
	                    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 reseive-->", result);
	                            sb.append(result);
	                            result = br.readLine();
	                    }
	                    
	                    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( System.currentTimeMillis());//AppUtil.getUTCTime());
	                    return loc;
	            } catch (JSONException e) {
	                    e.printStackTrace();
	                    return null;
	            } catch (UnsupportedEncodingException e) {
	                    e.printStackTrace();
	            } catch (ClientProtocolException e) {
	                    e.printStackTrace();
	            } catch (IOException e) {
	                    e.printStackTrace();
	            }

	            return null;
	    }


大家注意看这行holder.put("radio_type", cellID.get(0).radioType);

GSM就用"gsm",CDMA就用"cdma"

这个千万别搞混了,不然就获取不到信息了

值得一提的是C网获取基站再定位那偏差不是一般的大,是恨大,将近1千米了,大概是C网基站较少的缘故吧

最后通过经纬度获取地理位置信息,代码如下:

 public static  String getAddress(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();
	 
	            Log.e("resultAdress--->", resultString);
	            
	            /** 解析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;
	    }

在获取地理位置的这个location事实上应该传入纠偏后的location,本文暂不做此处理,所以得到的地理信息位置是偶偏差的,大家注意

最后附上截图:

工程下载链接:http://download.csdn.net/detail/geniuseoe2012/4340303

你可能感兴趣的:(android GSM+CDMA基站定位)