GPS代码学习---Framework代码学习

来源:互联网 发布:ma编程怎么转中文 编辑:程序博客网 时间:2024/06/05 18:21

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,有如下代码:

@Overridepublic 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

原创粉丝点击