2012年1月5日木曜日

LARK買ってみました

さて、ちょっと調べものはひと休憩して、買い物記録。
Apple Storeの初売りを眺めようと見に行ったら、安くなってるのと別の品に目が止まりました。




どうみても濃いパッケージなんですが、この歯を出して笑っている男性の腕にまいているのが、今回の品です。こんな形をしていますが、目覚まし時計です。iPhoneとセットで使うようにできています。




小汚い部屋の片隅でとったのでよけいなものが移ってますが、テーブルの上に乗っているのが中身です。就寝までの時間、充電しておくDockとACアダプタ、腕にまくバンド、そしてセンサー付きの目覚ましです。
普通の目覚ましと違うのは、まずアラーム音はしないです。振動して起こすタイプですね。

パッケージの男性がどや顔なのは、傍らの女性を起こさずに目が覚めたからということなんでしょう。まぁ、僕には無縁の話ではあるのですが。
じゃ、なんでこんなのをかったのかというと、睡眠の履歴を見てみたかったからです。




年末の疲れがたっぷり残っていたので、いつもより睡眠時間が長めだったので、まだあまり参考になっていないのですが、眠りについた時間と、起床時間が記録されています。



ただそれだけなのか?というと、実は違っていて、眠っている間の寝返り等の動作から、眠りの深さと周期を計測してくれます。7日間分のデータで、眠りのパターンや改善点を示唆してくれるらしいです。

どこかのサイトでは、おきやすいところで起こしてくれるとかいう記述をみたのですが、どうも気のせいだった模様。今のところアラームの設定時間に起こされている気がします。

ちなみに、起きた時の気分や、その日の状態をメモできる機能もあり、どんな時のどういう眠りの傾向にあるのか記録して分析してみるにはよさそうです。

ちなみに、このデータ、Web上のサーバーにも転送しているらしく、メーカーページに自分のアカウントでログインすると、ブラウザでも状態が表示されます。プライバシーを気にする方には、ちょっと嫌な機能かもしれませんね。

まぁ、僕は、探されると住所も氏名も電話番号も、趣味や性癖までネットで把握されちゃうであろうくらいそのあたりがずぼらにできているので、そんなに気にしていませんけどね。

とりあえず、今年の目標は、最低4時間半睡眠は確保する事で、今のところ順調に進んでいるので、このまま、記録をとりつつ、眠りの質を改善してみたいなと思っています。

P.S.
一応アプリは日本語ですが、コーチの機能や、Webページの多くが英語です。
もう少しがんばって翻訳して欲しいなぁ。

2012年1月3日火曜日

位置情報取得について調べてみた(その3)

さて、ではGpsLocationProviderを中心に調べてみる事にしよう。
前回、GpsLocationProviderを呼び出すとnativeの初期化関数が呼び出されるという話をした。実際に何をやっているのかというと以下のようになっています。


static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
    int err;
    hw_module_t* module;

    method_reportLocation             = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V");
    method_reportStatus                   = env->GetMethodID(clazz, "reportStatus", "(I)V");
    method_reportSvStatus              = env->GetMethodID(clazz, "reportSvStatus", "()V");
    method_reportAGpsStatus         = env->GetMethodID(clazz, "reportAGpsStatus", "(III)V");
    method_reportNmea                    = env->GetMethodID(clazz, "reportNmea", "(J)V");
    method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V");
    method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
    method_reportNiNotification     = env->GetMethodID(clazz, "reportNiNotification",
                                                                "(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V");
    method_requestRefLocation      = env->GetMethodID(clazz,"requestRefLocation","(I)V");
    method_requestSetID                   = env->GetMethodID(clazz,"requestSetID","(I)V");
    method_requestUtcTime             = env->GetMethodID(clazz,"requestUtcTime","()V");

    err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
    if (err == 0) {
        hw_device_t* device;
        err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);
        if (err == 0) {
            gps_device_t* gps_device = (gps_device_t *)device;
            sGpsInterface = gps_device->get_gps_interface(gps_device);
        }
    }

    if (sGpsInterface) {
        sGpsXtraInterface      = (const GpsXtraInterface*)sGpsInterface->get_extension(GPS_XTRA_INTERFACE);
        sAGpsInterface           = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
        sGpsNiInterface         = (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
        sGpsDebugInterface = (const GpsDebugInterface*)sGpsInterface->get_extension(GPS_DEBUG_INTERFACE);
        sAGpsRilInterface     = (const AGpsRilInterface*)sGpsInterface->get_extension(AGPS_RIL_INTERFACE);
    }
}

やっている事は以下の事になります。
  1. Native層から呼び出すいくつかのJavaのMethod IDを入手し、globalに保存
  2. gpsのHAL実装ライブラリのloadとModuleのopen, Interfaceの入手
  3. 拡張Interface情報の取得
なお、上記で入手している以下の情報については、HAL層の実装(gps.xxxxx.so)で用意する必要があります。
  • hw_module_t
  • hw_device_t (gps_device_t)

これらの基本的なstructは、hardware/libhardware/include/hardware/hardware.h に定義されています。

最初の hw_module_t は、hw_get_module()関数で、以下のようにして取得されます。

    const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
    hmi = (struct hw_module_t *)dlsym(handle, sym);

この事から、HAL(gps.xxxx.so)内部では、HAL_MODULE_INFO_SYM_AS_STRの名前のhw_module_t構造体が実体定義されている必要があります。

なお、hardware.hの中の定義は以下の通りです。

#define HAL_MODUULE_INFO_SYM HMI
#define HAL_MODUULE_INFO_SYM_AS_STR HMI

typedef struct hw_module_t {
    uint32_t tag;
    uint16_t version_major;
    uint16_t version_minor;
    const char *id;
    const char *name;
    const char *author;
    struct hw_module_methods_t* methods;
    void* dso;
    uint32_t reserved[32-7];
} hw_module_t;

typedef struct hw_module_methods_t {
    int (*open)(const struct hw_module_t* module, const char* id,
            struct hw_device_t** device);
} hw_module_methods_t;


実際、gpsの実装例であるqcom用のコードでは以下のようになっています。
[hardware/qcom/gps/loc_api/libloc_api/gps.c]

static struct hw_module_methods_t gps_module_methods = {
    .open = open_gps
};

const struct hw_module_t HAL_MODULE_INFO_SYM = {
    .tag = HARDWARE_MODULE_TAG,
    .version_major = 1,
    .version_minor = 0,
    .id = GPS_HARDWARE_MODULE_ID,
    .name = "loc_api GPS Module",
    .author = "Qualcomm USA, Inc.",
    .methods = &gps_module_methods,
};

続いて、hw_device_tのポインタの取得になります。ただし、これには1点注意が必要で、構造体のキャストによるハックが含まれています。
hw_module_t.hw_module_methods_t.open() では、hw_device_t** にポインタが含まれて帰ります。ただし、この実体は、hw_device_t型構造体の実体ではありません。 gpsの場合、gps_device_t型の構造体のポインタとなります。

hw_device_t* でアクセスしている場合は、先頭のcommon領域にポインタがあう事になり、gps_device_t*でアクセスした場合は、get_gps_interfaceの関数ポインタまで含めたメモリ領域にアクセスできるようになります。

typedef struct hw_device_t {
    uint32_t tag;
    uint32_t version;
    struct hw_module_t* module;
    uint32_t reserved[12];
    int (*close)(struct hw_device_t* device);
} hw_device_t;

[hardware/libhardware/include/hardware/gps.h]
struct gps_device_t {
    struct hw_device_t common;
    const GpsInterface* (*get_gps_interface)(struct gps_device_t* dev);
};

[hardware/qcom/gps/loc_api/libloc_api/gps.c]
static int open_gps(const struct hw_module_t* module, char const* name, struct hw_device_t** device)
{
    struct gps_device_t *dev = malloc(sizeof(struct gps_device_t));
    memset(dev, 0, sizeof(*dev));

    dev->common.tag = HARDWARE_DEVICE_TAG;
    dev->common.version = 0;
    dev->common.module = (struct hw_module_t*)module;
    dev->get_gps_interface = gps__get_gps_interface;

    *device = (struct hw_device_t*)dev;
    return 0;
}

この辺りからは、HALの中でもGPS固有の処理となります。
const GpsInterface* (*get_gps_interface)(struct gps_device_t* dev) に設定されているgps__get_gps_interfaceで、GPSドライバのインターフェースを入手します。

typedef struct {
    size_t          size;
    int   (*init)( GpsCallbacks* callbacks );
    int   (*start)( void );
    int   (*stop)( void );
    void  (*cleanup)( void );
    int   (*inject_time)(GpsUtcTime time, int64_t timeReference,int uncertainty);
    int  (*inject_location)(double latitude, double longitude, float accuracy);
    void  (*delete_aiding_data)(GpsAidingData flags);
    int   (*set_position_mode)(GpsPositionMode mode, GpsPositionRecurrence recurrence,
            uint32_t min_interval, uint32_t preferred_accuracy, uint32_t preferred_time);
    const void* (*get_extension)(const char* name);
} GpsInterface;

つまり、HALのGPSドライバとしてはこのインターフェースを実装する事になります。
さらに、この最低限のAPIに加え、実装に応じて追加の機能を提供するための拡張用のAPIを取得するのが、get_extension関数ですね。


・GPS_XTRA_INTERFACE
typedef void (* gps_xtra_download_request)();

typedef struct {
    gps_xtra_download_request download_request_cb;
    gps_create_thread create_thread_cb;
} GpsXtraCallbacks;

typedef struct {
    size_t          size;
    int  (*init)( GpsXtraCallbacks* callbacks );
    int  (*inject_xtra_data)( char* data, int length );
} GpsXtraInterface;


・AGPS_INTERFACE
typedef struct {
    size_t          size;
    AGpsType        type;
    AGpsStatusValue status;
    uint32_t        ipaddr;
} AGpsStatus;

typedef void (* agps_status_callback)(AGpsStatus* status);

typedef struct {
    agps_status_callback status_cb;
    gps_create_thread create_thread_cb;
} AGpsCallbacks;

typedef struct {
    size_t          size;
    void  (*init)( AGpsCallbacks* callbacks );
    int  (*data_conn_open)( const char* apn );
    int  (*data_conn_closed)();
    int  (*data_conn_failed)();
    int  (*set_server)( AGpsType type, const char* hostname, int port );
} AGpsInterface;


・GPS_NI_INTERFACE
typedef struct {
    size_t          size;
    int             notification_id;
    GpsNiType       ni_type;
    GpsNiNotifyFlags notify_flags;
    int             timeout;
    GpsUserResponseType default_response;
    char            requestor_id[GPS_NI_SHORT_STRING_MAXLEN];
    char            text[GPS_NI_LONG_STRING_MAXLEN];
    GpsNiEncodingType requestor_id_encoding;
    GpsNiEncodingType text_encoding;
    char           extras[GPS_NI_LONG_STRING_MAXLEN];
} GpsNiNotification;

typedef void (*gps_ni_notify_callback)(GpsNiNotification *notification);

typedef struct
{
    gps_ni_notify_callback notify_cb;
    gps_create_thread create_thread_cb;
} GpsNiCallbacks;

typedef struct
{
    size_t          size;
   void (*init) (GpsNiCallbacks *callbacks);
   void (*respond) (int notif_id, GpsUserResponseType user_response);
} GpsNiInterface;

・GPS_DEBUG_INTERFACE
typedef struct {
    size_t          size;
    size_t (*get_internal_state)(char* buffer, size_t bufferSize);
} GpsDebugInterface;


・AGPS_RIL_INTERFACE
typedef struct {
    agps_ril_request_set_id request_setid;
    agps_ril_request_ref_loc request_refloc;
    gps_create_thread create_thread_cb;
} AGpsRilCallbacks;

typedef struct {
    size_t          size;
    void  (*init)( AGpsRilCallbacks* callbacks );
    void (*set_ref_location) (const AGpsRefLocation *agps_reflocation, size_t sz_struct);
    void (*set_set_id) (AGpsSetIDType type, const char* setid);
    void (*ni_message) (uint8_t *msg, size_t len);
    void (*update_network_state) (int connected, int type, int roaming, const char* extra_in
fo);
    void (*update_network_availability) (int avaiable, const char* apn);
} AGpsRilInterface;

拡張のAPIも含めると、HALでは結構な数のAPIを実装する必要がありそうですね。
ちなみに、先ほどみたqcomの実装だと3種類の拡張を用意しているようですね。

static const void* loc_eng_get_extension(const char* name)
{
    if (strcmp(name, GPS_XTRA_INTERFACE) == 0)
    {
        return &sLocEngXTRAInterface;
    }
    else if (strcmp(name, AGPS_INTERFACE) == 0)
    {
        return &sLocEngAGpsInterface;
    }
    else if (strcmp(name, GPS_NI_INTERFACE) == 0)
    {
        return &sLocEngNiInterface;
    }
    return NULL;
}

というわけで、GpsProviderLocationは、まず真っ先にHALのAPIを読み込んでいます。
その後、GpsLocationProvier.isSupported()が呼ばれているわけですが、これは、

public static boolean isSupported() {
    return native_is_supported();
}

static jboolean android_location_GpsLocationProvider_is_supported()
{
    return (sGpsInterface != NULL);
}

とあるように、HALから基本となるInterfaceが取得できているかのチェックとなります。
さて、実際のLocationProviderのInterfaceですが、以下のように定義されています。

public interface LocationProviderInterface {
    String getName();
    boolean requiresNetwork();
    boolean requiresSatellite();
    boolean requiresCell();
    boolean hasMonetaryCost();
    boolean supportsAltitude();
    boolean supportsSpeed();
    boolean supportsBearing();
    int getPowerRequirement();
    boolean meetsCriteria(Criteria criteria);
    int getAccuracy();
    boolean isEnabled();
    void enable();
    void disable();
    int getStatus(Bundle extras);
    long getStatusUpdateTime();
    void enableLocationTracking(boolean enable);
    /* returns false if single shot is not supported */
    boolean requestSingleShotFix();
    String getInternalState();
    void setMinTime(long minTime, WorkSource ws);
    void updateNetworkState(int state, NetworkInfo info);
    void updateLocation(Location location);
    boolean sendExtraCommand(String command, Bundle extras);
    void addListener(int uid);
    void removeListener(int uid);
}

ちなみに、GpsLocationProviderでは
    /**
     * Returns true if the provider requires access to a
     * data network (e.g., the Internet), false otherwise.
     */
    public boolean requiresNetwork() {
        return true;
    }

    /**
     * Returns true if the provider requires access to a
     * satellite-based positioning system (e.g., GPS), false
     * otherwise.
     */
    public boolean requiresSatellite() {
        return true;
    }

    /**
     * Returns true if the provider requires access to an appropriate
     * cellular network (e.g., to make use of cell tower IDs), false
     * otherwise.
     */
    public boolean requiresCell() {
        return false;
    }

が設定されています。A-GPSかどうかに関わらず、Network必要なのか。

クライアントの処理を見た時の、LocationManager.getBestProvider(criteria,truer); が実行されると条件にあうProviderを探しながら最適なProviderを返すわけですが、この処理が以下のようになっています。

    public String getBestProvider(Criteria criteria, boolean enabledOnly) {
        List<String> goodProviders = getProviders(criteria, enabledOnly);
        if (!goodProviders.isEmpty()) {
            return best(goodProviders).getName();
        }

        // Make a copy of the criteria that we can modify
        criteria = new Criteria(criteria);

        // Loosen power requirement
        int power = criteria.getPowerRequirement();
        while (goodProviders.isEmpty() && (power != Criteria.NO_REQUIREMENT)) {
            power = nextPower(power);
            criteria.setPowerRequirement(power);
            goodProviders = getProviders(criteria, enabledOnly);
        }
        if (!goodProviders.isEmpty()) {
            return best(goodProviders).getName();
        }

        // Loosen accuracy requirement
        int accuracy = criteria.getAccuracy();
        while (goodProviders.isEmpty() && (accuracy != Criteria.NO_REQUIREMENT)) {
            accuracy = nextAccuracy(accuracy);
            criteria.setAccuracy(accuracy);
            goodProviders = getProviders(criteria, enabledOnly);
        }
        if (!goodProviders.isEmpty()) {
            return best(goodProviders).getName();
        }

        // Remove bearing requirement
        criteria.setBearingRequired(false);
        goodProviders = getProviders(criteria, enabledOnly);
        if (!goodProviders.isEmpty()) {
            return best(goodProviders).getName();
        }

        // Remove speed requirement
        criteria.setSpeedRequired(false);
        goodProviders = getProviders(criteria, enabledOnly);
        if (!goodProviders.isEmpty()) {
            return best(goodProviders).getName();
        }

        // Remove altitude requirement
        criteria.setAltitudeRequired(false);
        goodProviders = getProviders(criteria, enabledOnly);
        if (!goodProviders.isEmpty()) {
            return best(goodProviders).getName();
        }

        return null;
    }

以下の順で条件を緩くしながら、合致するProviderを探して、条件が合致するProviderが見つかったら、その中から最適なものを返しています。
  1. ユーザー指定のCriteriaに合致するProviderを探す。
  2. Power条件を下げながらその他がCriteriaに合致するProviderを探す。
  3. 精密さの条件を下げながらその他のCriteriaに合致するProviderを探す。
  4. 方角に関する条件を削除してその他のCriteriaに合致するProviderを探す。
  5. 速度に関する条件を削除してその他のCriteriaに合致するProviderを探す。
  6. 高度に関する条件を削除してその他のCriteriaに合致するProviderを探す
この時の、条件合致は、getProviders()でProvider側で実装している
boolean meetsCriteria(Criteria criteria);
でチェックされていますね。ちなみに、GpsLocationProviderの条件はPowerしかみてません。

    public boolean meetsCriteria(Criteria criteria) {
        return (criteria.getPowerRequirement() != Criteria.POWER_LOW);
    }

とりあえず、ここまでで初期処理とProviderの選択のうっすらとしたイメージがつかめたので、次回は、ようやくLocationの取得を調べてみたいと思います。

2012年1月2日月曜日

位置情報取得について調べてみた(その2)

さて、昨日は位置情報の取得技術と、Androidのアプリからの利用方法について軽く調べてみました。というわけで、続きの調査メモです。

前回のエントリで見た位置情報関連クラスは以下の通りです。
  • Address
  • Criteria
  • Geocoder
  • GpsSatelite
  • GpsStatus
  • Location
  • LocationManager
  • LocationProvider
さて、この中で真っ先に取得するのは、LocationManager [ frameworks/base/location/java/android/location/LocationManager.java ]
でした。LocationManagerは、Binderを使ってSystem Location Service(LocationManagerService)へアクセスするためのクラスのようです。

実体は、ContextImplクラスのstaticブロックで生成・登録されています。
[src] frameworks/base/core/java/android/app/ContextImpl.java
        registerService(LOCATION_SERVICE, new StaticServiceFetcher() {
                public Object createStaticService() {
                    IBinder b = ServiceManager.getService(LOCATION_SERVICE);
                    return new LocationManager(ILocationManager.Stub.asInterface(b));
                }});

というわけで、ここでPF部として目を付けなくてはならないのは、LocationManagerServiceですね。で、このLocationManagerServiceが生成されているのは何処か?というと、いつか何処かでみた場所なんですね。この辺りはPF部でも発表してますし、さらっと呼び出しだけ見ておきましょう。

SystemServer::init2()
  ServerThread::start()
    ServerThread::run() [frameworks/base/services/java/com/android/server/SystemServer.java]
        location = new LocationManagerService(context);
        ServiceManager.addService(Context.LOCATION_SERVICE, location);
        final LocationManagerService locationF = location;
        locationF.systemReady(); [frameworks/base/services/java/com/android/server/LocationManagerService.java]
            Thread thread = new Thread(null, this, "LocationManagerService");
            thread.start();

注: 例によって上記はC++チックなメソッド名の表記をしているだけです。

init周りを追いかけた時にでてきたSystemServerのServerThread中で生成され、LocationManagerServiceスレッドがstartされています。

public void LocationManagerService::run()
{
    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
    Looper.prepare();
    mLocationHandler = new LocationWorkerHandler();
    initialize();
    Looper.loop();
}

Runされると、initialize処理を行った後、Looperでまわしています。このLocationManagerService::initialize()の中で、呼んでいるLocationManagerSerivce::loadProviders()でAndroid共通のProviderの生成と登録、Geocoderの生成が行われています。

LocationManagerService::loadProviders()
    LocationManagerService::loadProvidersLocked()
        LocationManagerService::_loadProvidersLocked()
        {
                if (GpsLocationProvider.isSupported()) {
                    GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
                    mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
                    mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
                    addProvider(gpsProvider);
                    mGpsLocationProvider = gpsProvider;
                }
                PassiveProvider passiveProvider = new PassiveProvider(this);
                addProvider(passiveProvider);
                mEnabledProviders.add(passiveProvider.getName());

                PackageManager pm = mContext.getPackageManager();
                if (mNetworkLocationProviderPackageName != null &&
                    pm.resolveService(new Intent(mNetworkLocationProviderPackageName), 0) != null) {
                    mNetworkLocationProvider =
                        new LocationProviderProxy(mContext, LocationManager.NETWORK_PROVIDER,
                                mNetworkLocationProviderPackageName, mLocationHandler);
                    addProvider(mNetworkLocationProvider);
                }

                if (mGeocodeProviderPackageName != null &&
                         pm.resolveService(new Intent(mGeocodeProviderPackageName), 0) != null) {
                    mGeocodeProvider = new GeocoderProxy(mContext, mGeocodeProviderPackageName);
                }
                updateProvidersLocked();
        }

生成/AddされているProviderは、3つ
  • public class GpsLocationProvider implements LocationProviderInterface
  • public class PassiveProvider implements LocationProviderInterface
  • public class LocationProviderProxy implements LocationProviderInterface
GeocodeProviderとしては
  • public class GeocoderProxy
が生成されています。

またこのうちPassiveProviderは、mNetworkLocationProviderPackageNameのパッケージがある場合に生成されています。これは、リソース中のcom.android.internal.R.string.config_networkLocationProvider の文字列になります。
また、GeocodeProxyについても、mGeocodeProviderPackageNameのパッケージがある場合にのみ生成されており、こちらは、com.android.internal.R.string.config_geocodeProvider の文字列になります。

4.0のソースコードに含まれるtunaのconfig設定 [
device/samsung/tuna/overlay/frameworks/base/core/res/res/values/config.xml]  ですと

<string name="config_networkLocationProvider">com.google.android.location.NetworkLocationProvider</string>
<string name="config_geocodeProvider">com.google.android.location.GeocodeProvider</string>

となっています。
ちなみに、GplLocationProvider classには

    static { class_init_native(); }

となっています。ですので、最初のif文の時にこの関数が呼び出されます。
こちらは、nativeコードで実装されており、実際には

android_location_GpsLocationProvider_class_init_native()

で、その中でhw_get_module("gps",....)が呼び出されます。この辺りはHALの実装の周りの部分でして、必要になるライブラリを探して行きます。4.0のコードでは以下の順にライブラリを探し見つかったものをdlopenを使ってZygoteとリンクします。


  1. /vendor/lib/hw/gps.<ro.hardware>.so
  2. /system/lib/hw/gps.<ro.hardware>.so
  3. /vendor/lib/hw/gps.<ro.product.board>.so
  4. /system/lib/hw/gps.<ro.product.board>.so
  5. /vendor/lib/hw/gps.<ro.board.platform>.so
  6. /system/lib/hw/gps.<ro.board.platform>.so
  7. /vendor/lib/hw/gps.<ro.arch>.so
  8. /system/lib/hw/gps.<ro.arch>.so
  9. /system/lib/hw/gps.default.so

以前は、libがついていた気がするんですけどね。最近はlibがつかないのかな。

ついでにいうと、implements LocationProviderInterfaceなclassは他にもあって
  • public class MockProvider implements LocationProviderInterface
というのがあります。こちらは、LocationManager::addTestProviderを行った時に内部でaddProviderされるProviderのようです。CTS等のテスト時に使われるようですね。


さて、とりあえずここまでで見た限りは、LocationManagerはLocation情報を管理しているわけではなく、LocationProviderの管理をしていると見るのが自然なようです。
というわけで、次回は、LocationProviderについて、Gpsを中心にもう少し調べてみたいなと思います。