2011年1月3日 星期一

[Android] 如何藉由Cell ID 和 Location Area Code 取得經緯度座標 (How to get Cell ID and Location Area Code by Geolocation API)



在之前的文章 [Android] 如何使用Google Map 2.0 & 3.0 中有提到 , 當取得Cell Id 和LAC 之後可以透過 http://www.google.com/glm/mmap 這個API取得經緯度 , 不過在網路上關於這個API的Reference真的很少 , 根據目前我所蒐集的資料 , 只知道可以丟入Cell Id 和LAC 作為實際能影響經緯度的輸入參數 , 而網路上另外還有一個類似的API : Geolocation API , 這網頁有介紹API的Network Protocal , 描述了參數輸入的格式和回報輸出的經緯度格式 , 並針對每個參數做敘述 , 值得一提的是並不是每個參數都是必要輸入的。


另外可以看到如果使用字串來編排作為參數的輸入格式會相當的麻煩 , 在這篇文章會使用java 的 JSON物件來作為參數的輸入格式 , 而其中主要會影響輸出經緯度的輸入的參數為 cell_towers 和 wifi_towers , 有趣的是參數的內容都可以為多個 , 這樣可以增加輸出經緯度的準確度 , 這也是為什麼這個API是網路上比較多人使用的原因。


最後我們會使用TabWidget分頁來呈現要送出的參數和回應的資料 , 以下是程式碼的部分


import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import android.app.TabActivity;
import android.content.res.Configuration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.telephony.TelephonyManager;
import android.telephony.gsm.GsmCellLocation;
import android.util.Log;
import android.widget.TabHost;
import android.widget.TextView;


public class LocationTest extends TabActivity
{
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        mTabHost = getTabHost();
        //我們的TabWidgetListViewTest 是繼承 TabActivity的
        //所以這邊是透過他的method getTabHost()
        //來取得我們在main.xml中宣告的TabHost
         
        mTabHost.addTab(mTabHost.newTabSpec("tab_test1")
          //將Tab加入我們要的資料
          .setIndicator("Send JSON Object")
          //在Tab上標示名稱和加上Icon
          .setContent(R.id.LinearLayoutJSON));
                //Tab內容為main.xml檔案中宣告的ListView , 而ListView的內容我們先前已經處理好了
         
        mTabHost.addTab(mTabHost.newTabSpec("tab_test2").setIndicator("Response").setContent(R.id.LinearLayoutRES));
                 
        mTabHost.setCurrentTab(0);
        //預設該顯示哪個Tab的資料
        
        InitialUI(); //初始化元件
        getInfo();   //取得mmc mnc的資訊    
        getLocation();
    }    
 
    int CellID , LAC , mcc , mnc;    
    double lat, lng;
    
    TelephonyManager TManager;   
    WifiManager WManager;
    GsmCellLocation GCLocation;
 TextView TextViewJSON , TextViewRES;
    
    private void getInfo()
 {
       Configuration CF = (Configuration) getResources().getConfiguration(); 
     if(CF != null)
     {
     mcc = CF.mcc;
       mnc = CF.mnc; 
     }
 }
    
    private void InitialUI()
    { 
      TextViewJSON = (TextView) findViewById(R.id.TextViewJSON);
      TextViewRES = (TextView) findViewById(R.id.TextViewRES);
      
   TManager = (TelephonyManager) this.getSystemService(this.TELEPHONY_SERVICE); 
   WManager = (WifiManager) this.getSystemService(this.WIFI_SERVICE);
    }
        
    private void getCellIdLAC()
    {  
   if(TManager.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM)
        { 
        GCLocation = (GsmCellLocation) TManager.getCellLocation();
        //String imei = TManager.getDeviceId();
        if (GCLocation != null)
           {          
         CellID = GCLocation.getCid();
                  LAC = GCLocation.getLac();
              }
           else TextViewRES.append("無法獲得 GsmCellLocation 物件");
        }
        else TextViewRES.append("這不是GSM手機"); 
   }
    
    private void getLocation()
    {
  // TODO Auto-generated method stub
     
       JSONObject Locationdata = null;
     
       try
       {
      JSONObject JSONholder = new JSONObject();
      
      JSONholder.put("version", "1.1.0");
      JSONholder.put("host", "Android");
      JSONholder.put("request_address", true); //需要回報地址
      JSONholder.put("home_mobile_country_code", mcc);
      JSONholder.put("home_mobile_network_code", mnc);
      JSONholder.put("radio_type", "gsm"); //string (gsm|cdma|wcdma)     
      JSONholder.put("address_language", "zh_TW"); //地址語言 
           
           JSONArray cellTowerArray = new JSONArray(); 
           //為了可以儲存多筆Cell Tower的資料
           getCellIdLAC(); //取得Cell ID 和 LAC的資料     
         
           JSONObject cellTowerData = new JSONObject();
           cellTowerData.put("cell_id", Integer.toString(CellID)); 
      cellTowerData.put("location_area_code", LAC); 
      cellTowerArray.put(cellTowerData); // 目前只放入一筆資料 
      JSONholder.put("cell_towers", cellTowerArray);      
     
      
      JSONArray wifiTowerArray = new JSONArray();       
           JSONObject wifiTowerData = new JSONObject();
               
           WifiInfo WI = WManager.getConnectionInfo(); //取得現在連線的AP資訊               
           wifiTowerData.put("mac_address", WI.getMacAddress());
            wifiTowerData.put("ssid", WI.getSSID());
            wifiTowerArray.put(wifiTowerData);
           
         JSONholder.put("wifi_towers", wifiTowerArray);
        
      TextViewJSON.setText(JSONholder.toString());
      //顯示參數的輸出格式
      
         String urlString = "http://www.google.com/loc/json";          
         DefaultHttpClient client = new DefaultHttpClient();
         HttpPost post = new HttpPost(urlString); //使用post協定           
         StringEntity se = new StringEntity(JSONholder.toString());
         post.setEntity(se);
         HttpResponse resp = client.execute(post);
         HttpEntity entity = resp.getEntity(); //取得API傳回的資料          
           
         String result = EntityUtils.toString(entity); //轉成字串格式
         
         JSONObject RESdata = new JSONObject(result);
         //以下為解析回報得資料
         Locationdata = (JSONObject) RESdata.get("location");
         lat = (Double) Locationdata.get("latitude");
           lng = (Double) Locationdata.get("longitude");          
           
           JSONObject Addressdata = (JSONObject) Locationdata.get("address");
           StringBuffer sb = new StringBuffer();
           sb.append(Addressdata.get("country")+" ");
           sb.append(Addressdata.get("postal_code")+" ");
           sb.append(Addressdata.get("region")+" ");
           sb.append(Addressdata.get("city")+" ");
           sb.append(Addressdata.get("street")+" ");          
           
           TextViewRES.setText(lng+","+lat+" "+sb.toString());
           TextViewRES.append("\n\n"+Locationdata.toString());
         
         }catch(Exception E)
         {
          E.printStackTrace();
          Log.v("Locaiton result", "SomethingWrong"); 
          TextViewRES.setText("SomethingWrong ");
          TextViewRES.append(lng+","+lat+" "+Locationdata.toString());
         }  
 }
 TabHost mTabHost;
}


再來是Layout檔


    
        
         
        
        
                
        
        
        
                
         
            
        
        
               
        
        
        
                
                  
        
                  
      

最後是AndroidManifest
    
        
            
                
                
            
        
    
    
 
 
 
  

最後就可以獲得經緯度和地址的資訊了 , 實作結果如下



這邊呈現出準備要送出的JSON物件裡的內容




這邊為回應的資料結果




相關文章:
[Android Tips] 如何使用Google Map 2.0 & 3.0

[Android Tips] 如何取得手機的Cell ID 和 Location Area Code


參考資料:
http://developer.clear.com/wiki/12/JSON_REST

1 則留言:

  1. 您好,我把我的基地台資訊丟到The Google Maps Geolocation API這邊來試著找反查經緯度,都找不到,改輸入您的就可以....請問有什麼特別需要注意的地方嗎??

    回覆刪除

Google Analytics