GPS代碼學習---Framework代碼學習

Android基於位置的服務,不得不提到andriod.location包,它提供了很方便的API來實現基於位置的服務。和其他android系統服務一樣,我們不能直接實例化一個LocationManager,而是通過getSystemService(Context.LOCATION_SERVICE)獲取LocationManager實例。在獲得LocationManager實例後,我們可以做三件事情:

1、查詢上次已知所有用戶位置列表;

2、註冊或取消註冊用戶位置階段性從LocationProvider獲得的更新;

3、註冊或取消註冊一個指定的Intent,如果手機設備接近一個指定經緯度指定範圍(由半徑米指定)

相關組件。location相關的GoogleMap APIMapView,在聚焦MapView時,可捕獲按鍵,觸屏手勢去放大縮小地圖。

相關權限設置。

<manifest ... >
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    ...
</manifest>

ACCESS_COARSE_LOCATION只提供NETWORK_PROVIDER的權限,ACCESS_FINE_LOCATION則提供NETWORK_PROVIDERGPS_PROVIDER

調試。可通過EclipseDDMS調試,或者命令方式調試。打開DDMSEmulatorControls中有LocationControls部分,選擇設備後,可向設備發送經緯度信息。

Android.Location包的目錄結構分析

frameworks/base/location/java/android/location

-----Address.aidl提供一個parcelable

-----Address.java提供地址信息,包含featurename, postal code, country code

-----Country.aidl提供一個parcelable

-----Country.java提供ISO標準兩個字符國家碼(CN僅限於大陸,不含港澳臺)

-----ICountryDetector.aidl獲取國家碼接口類

-----CountryDetector.java獲取用戶所在地國家碼

-----ICountryListener.aidl檢測國家碼監聽

----CountryListener.java檢測國家碼監聽

-----Criteria.aidl提供一個parcelable

-----Criteria.java提供精確度信息

-----GeocoderParams.aidl提供一個parcelable

-----GeocoderParams.java獲取Geocoder參數

-----Geofence.aidl提供一個parcelable

-----Geofence.java對獲取的經緯度判斷保護

-----GpsSatellite.java描述GPS衛星狀態,主要在GpsStatus.java中使用

-----GpsStatus.java描述GPSengine的狀態,通過僞隨機碼初始化衛星得到mSatelliteList

-----IGeocodeProvider.aidl接口類提供兩個方法

-----IGpsStatusListener.aidlGPS的狀態監聽。

-----IGpsStatusProvider.aidl增加和移除GPS狀態監聽

-----ILocationListener.aidl定義接口,在LocationManagerListenerTransport實現

-----LocationListener.java定義接口

-----ILocationManager.aidl定義接口,在LocationManagerService中實現

-----INetInitiatedListener.aidl定義接口GpsLocationProvider中實現

(從多個aidl文件分析看,aidl並非僅在service類中使用,另一種使用方法(Binder)是:定義aidl文件後,在其他文件中只需newIXXX.Stub並實現aidl中定義的方法,然後該實例即可作爲其他類的成員,並最終調用方法)

-----Location.aidl提供一個parcelable

-----Location.javaLocation,實現Parcelable的類

-----LocationProvider.java提供諸如是否需要網絡,衛星等信息

-----LocationRequest.aidl提供一個parcelable

-----LocationRequest.java請求對應精度的位置更新服務

ACCURACY_FINE1MACCURACY_BLOCK100MACCURACY_CITY10KM

其中可設置位置更新請求間隔時間setInterval(),最快間隔時間setFastestInterval()等。

-----LocationManager.java其他類或接口大多和這個文件有關,下面篇幅重點介紹

frameworks/base/location/java/com/android/internal/location

-----GpsNetInitiatedHandler.javaGPS網絡初始化的處理類,彈提示框等,在GpsLocationProvider.java中用到。

擴展:frameworks/base/services/jni/下有個Onload.cppJNI_OnLoad註冊了一些系統服務如:

PowerManagerServiceSystemServerlocation_GpsLocationProvider等,其中location_GpsLocationProvider對應註冊JNI接口的文件是com_android_server_location_GpsLocationProvider.cpp

-----ILocationProvider.aidl

-----ProviderProperties.aidl

-----ProviderProperties.java

-----ProviderRequest.aidl

-----ProviderRequest.java

frameworks/base/location/lib/java/com/android/location/provider

-----GeocodeProvider.java

-----LocationProviderBase.java

-----LocationRequestUnbundled.java

-----ProviderPropertiesUnbundled.java

-----ProviderRequestUnbundled.java

frameworks/base/services/java/com/android/server/location

-----ComprehensiveCountryDetector.java

-----CountryDetectorBase.java

-----GeocoderProxy.java

-----GeofenceManager.java

-----GeofenceState.java

-----GpsLocationProvider.java

-----GpsXtraDownloader.java

-----LocationBasedCountryDetector.java

-----LocationBlacklist.java

-----LocationFudger.java

-----LocationProviderInterface.java

-----LocationProviderProxy.java

-----MockProvider.java

-----PassiveProvider.java


問題1CountryDetector類中的成員ICountryDetectormService調用detectCountry()接口時,怎麼和CountryDetectorService.java中的detectorCountry()聯繫在一起呢?

在系統啓動時,SystemServer起來時,在run()函數中會加載不少系統服務,代碼如:

try{
    Slog.i(TAG,"Country Detector");
    countryDetector= new CountryDetectorService(context);
    ServiceManager.addService(Context.COUNTRY_DETECTOR,countryDetector);
}catch (Throwable e) {
    reportWtf("startingCountry Detector", e);
}

而之後運行到ContextImpl.java中時,我們看到有個static代碼塊,代碼片段如下:

static{
    ......
    registerService(COUNTRY_DETECTOR,new StaticServiceFetcher() {
    publicObject createStaticService() {
        IBinderb = ServiceManager.getService(COUNTRY_DETECTOR);
        returnnew CountryDetector(ICountryDetector.Stub.asInterface(b));
    }});
    ......
}

從上面兩個代碼片段就可以看出,在SystemServer加載服務後,在ContextImpl中獲取到對應的Binder後,將CountryDetectorService作爲參數傳給CountryDetector的構造函數中。這樣,就完成了CountryDetectorService和成員變量mService的綁定。從而我們也看出,aidl實現Service的數據通信,並非一定要使用bindServiceServiceConnectionIXXX.aidl綁定在一起。


問題2IGeocodeProvider作爲aidl文件,如果將虛函數看作插槽。爲什麼GeocodeProvider不直接將接口實現?仍然作爲虛函數使用呢?

搜了一圈,終於在LocationManagerService中找到一個成員mGpsStatusProvider,有如下代碼:

@Override
public boolean addGpsStatusListener(IGpsStatusListener listener) {
    if(mGpsStatusProvider == null) {
        return false;
    }
    checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),LocationManager.GPS_PROVIDER);

    try{
        mGpsStatusProvider.addGpsStatusListener(listener);
    }catch (RemoteException e) {
        Slog.e(TAG,"mGpsStatusProvider.addGpsStatusListener failed", e);
        returnfalse;
    }
    return true;
}

該函數的調用流程實際上是從LocationManageraddGpsStatusListener調起的。爲什麼這麼說呢?和問題1流程相同,在LocationManager中有個變量ILocationManagermService,從問題1分析可得出結論,實際上mServiceLocationManagerService。那下面的這段代碼就好理解了:

public boolean addGpsStatusListener(GpsStatus.Listener listener) {
    boolean result;

    if(mGpsStatusListeners.get(listener) != null) {
        //listener is already registered
        return true;
    }
    try{
        GpsStatusListenerTransporttransport = new GpsStatusListenerTransport(listener);
        result = mService.addGpsStatusListener(transport);
        if(result) {
            mGpsStatusListeners.put(listener,transport);
        }
    }catch (RemoteException e) {
        Log.e(TAG,"RemoteException in registerGpsStatusListener: ", e);
        result = false;
    }

    return result;
}

Location相關內容主要包括GeocoderLocationManager

一、Geocoder

Geocoder可以在街道地址和經緯度地圖座標之間進行轉換。它提供了對兩種地理編碼功能的訪問:

ForwardGeocoding(前向地理編碼):查找某個地址的經緯度

ReverseGeocoding(反向地理編碼):查找一個給定的經緯度所對應的街道地址。

對應的API是:

List<Address>  getFromLocationName(String locationName, int maxResults)  

List<Address>  getFromLocation(double latitudedouble longitudeint maxResults); 


二、LocationManager相關的兩個知識點

providerLocationManager獲取位置信息的途徑,常用的有兩種:GPSNETWORKGPS定位更精確,缺點是隻能在戶外使用,耗電嚴重,並且返回用戶位置信息的速度遠不能滿足用戶需求。NETWORK通過基站和Wi-Fi信號來獲取位置信息,室內室外均可用,速度更快,耗電更少。爲了獲取用戶位置信息,我們可以使用其中一個,也可以同時使用兩個。

LocationListener:位置監聽器接口,定義了常見的provider狀態變化和位置的變化的方法,我們需要實現此接口,完成自己的處理邏輯,然後LocationManager註冊此監聽器,完成對各種狀態的監聽。

locationManager.java中,可以看到PROVIDER有幾種,就會對應有幾種類型的LocationListenerGPS_PROVIDER對應mGpsListener。例如:在MTK寫的一個apk rcse中,AndroidManifest.xml中有如下代碼:

<service
    android:name=".core.ims.service.presence.pidf.geoloc.GPSLocationService">
    <intent-filter>
        <actionandroid:name="com.orangelabs.rcs.GPS" />
    </intent-filter>
</service>
GPSLocationService繼承自Service,其中有個onBind()函數,註冊了對應GPS_PROVIDER的監聽:

mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,5000, 0, mGpsListener);
先來看下requestLocationUpdatesmLocationManagerLocationManager類型,在LocationManager.java中找到對應接口後,發現最終調用的是如下接口:

private void requestLocationUpdates(LocationRequest request, LocationListenerlistener,
        Looperlooper, PendingIntent intent) {

    String packageName = mContext.getPackageName();

    //wrap the listener class
    ListenerTransport transport = wrapListener(listener, looper);

    try{
        mService.requestLocationUpdates(request,transport, intent, packageName);
    }catch (RemoteException e) {
        Log.e(TAG, "RemoteException",e);
    }
}

首先,WrapListener將傳入的mGpsListener放入hashmapmListeners中。在try塊代碼中,mLocationManagerServiceLocationManagerService類型,最終調用到LocationManagerService.java中的requestLocationUpdates函數。


GoogleMaps V2簡單應用

GoogleMaps Android API V2改進:

1API作爲GooglePlay servicesSDK一部分
2
Maps裝入MapFragment類,該類繼承自androidFragment類,取代MapView
3
、允許擴展標準的Activity,而不再必須是V1中的MapActivity
4
、使用矢量貼圖,所以地圖顯示更快,佔用帶寬更少
5
、改良的緩存,用戶不會再看到有空白區域
6
、使用3D地圖,移動用戶的視角,可以看透視圖

開發局限性:

官網上說V1APIKey 2013318號開始停止申請了,而且V1Key不適用V2

運行侷限性:

設備安裝有GooglePlay service APK

版本限制:

android2.2或更高版本

1SDK配置

打開EclipseAndroidSDK Manager,安裝更新Extras下面的googleplay services,這點很關鍵,否則無法使用。按照google官網的步驟執行後出現程序異常,需要加載庫文件解決。

Eclipse裏面選擇:File>Import>Android>ExistingAndroid Code Into Workspace然後點擊Next.之後Browse...,找到路徑下的<android-sdk-folder>/extras/google/google_play_services/libproject/google-play-services_lib,然後選擇Finish

第二步是添加對這個庫的引用:在自己的項目上右鍵,選Properties,左邊選Android,然後在下面的Library裏面Add剛纔的google-play-services_lib

有傳言說V2不能在AVD上運行,可能Google還會對此問題進行更新。在Stackoverflow上已經有過討論,簡單的採用以下方法即可在emulator中跑起來。

AVD上安裝兩個包(GooglePlay StoreGooglePlayservices):vending.apkgms.apk,(給一個網盤鏈接:http://pan.baidu.com/share/link?shareid=190602&uk=2701745266

2、獲取AndroidMaps Api Key

想要獲取googlemap api服務,需要在應用中添加AndroidMaps ApiKey。先找到本地的debug.keystore文件。如果不知道路徑,可打開Eclipse,在Window\Preference\Android\Build中可以看到,一般路徑爲~/.android/debug.keystore。然後用keytool工具獲取唯一的指紋認證碼:

linux中命令如下:

keytool-list -v -keystore ~/.android/debug.keystore -alias androiddebugkey-storepass android -keypass android

window系統命令如下:

keytool-list -v -keystore "C:\Users\your_user_name\.android\debug.keystore"-alias androiddebugkey -storepass android -keypass android

以上命令其實並無太大差別,只是linuxwindow存儲debug.keystore的路徑不同。

生成的SHA-1指紋認證碼如下:

別名名稱:androiddebugkey

創建日期:2012-8-28

項類型:PrivateKeyEntry

認證鏈長度:1

認證[1]:

所有者:CN=AndroidDebug, O=Android, C=US

簽發人:CN=AndroidDebug, O=Android, C=US

序列號:503c9c42

有效期:Tue Aug 28 18:24:02 CST 2012 ThuAug 21 18:24:02 CST 2042

證書指紋:

MD5:3A:D9:CA:87:53:A7:38:1C:56:77:32:18:5B:D7:EB:72

SHA1:39:03:D5:1E:0F:F1:E0:AC:12:11:2F:D8:8D:88:0F:EF:58:07:EE:4A

簽名算法名稱:SHA1withRSA

版本:3

爲了獲取APIKey,需要用你的gmail帳號登錄,進入後點擊CreateProject按鈕,左邊導航欄點Services。在其中找到GoogleMaps Android Api v2,選擇打開on,在進入的頁面中接受協議內容並點Accept。然後再在導航欄中選擇ApiAccess,在頁面中找到CreateNew Android Key....然後在以下彈出框中輸入以上指紋及應用包名,中間以分號隔開,例如:39:03:D5:1E:0F:F1:E0:AC:12:11:2F:D8:8D:88:0F:EF:58:07:EE:4A;com.dewav.locationtest

生成40位字符的APIkey碼:

APIkey:

AIzaSyB3fUxGpH15Y_4y53VBHIps4IueTuTQJnY

androidManifest.xml<application>標籤中間填入apikey,例如:

<meta-data
    android:name="com.google.android.maps.v2.API_KEY"
    android:value="AIzaSyB3fUxGpH15Y_4y53VBHIps4IueTuTQJnY"/>

添加權限控制,例如:

<permission
    android:name="com.example.mapdemo.permission.MAPS_RECEIVE"
    android:protectionLevel="signature"/>
<uses-permission android:name="com.example.mapdemo.permission.MAPS_RECEIVE"/>

另外,添加其他權限:

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
<!-- The following two permissions are not required to use
    Google Maps Android API v2, but are recommended. -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

因爲googlemap v2 api要求使用OpenglES Version 2,所以,我們必須加入

<uses-feature
    android:glEsVersion="0x00020000"
    android:required="true"/>

3MapFragmentsampleCode

首先在佈局文件中加入MapFragment

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
          android:id="@+id/map"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:name="com.google.android.gms.maps.MapFragment"/>

mapActivity中,添加如下代碼:
public class MapActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_map);
    }
}

除了用Google Map Android Api V1Google Map Android Api V2外,還可用百度的SDK實現地圖app,詳細實例可參考百度SDK的介紹及sample code

參考資料:

GoogleMap Android APIV1https://developers.google.com/maps/documentation/android/v1/hello-mapview?hl=zh-CN

GoogleMap Android API V2

https://developers.google.com/maps/documentation/android/?hl=zh-CN

APIKEY request:https://code.google.com/apis/console/#project:470805776290:access


介紹百度地圖:http://blog.csdn.net/lyq8479/article/details/6384428

百度地圖SDKhttp://developer.baidu.com/map/sdk-android.htm


http://www.cnblogs.com/mengdd/archive/2013/01/01/2841390.html

http://wiki.eoe.cn/page/Using_the_Location_Manager

http://blog.csdn.net/liuhe688/article/details/6566505

http://www.cnblogs.com/feisky/archive/2010/01/20/1652230.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章