GPS を利用して端末の位置情報を得るところまで実装できましたが、更に GPS エンジンの動作情報を取得することもできます。具体的には、GPS 測位に利用した GPS 衛星の位置や GPS 信号の受信状況を取得できるので、例えば GPS Status & Toolbox や GPS Essentials のように、GPS 衛星の位置をレーダーっぽく表示するようなことができるようになります。
位置情報を求めるシーンで、これら個々の GPS 衛星の情報まで必要とするケースはまず無いと思いますが、自分の書いたコードで、上空 20,000km を飛行する個々の GPS 衛星を追跡できていると思うとちょっとワクワクしますね。
基本的な処理の流れは次の通りです。
LocationManager を取得するLocationManager に LocationListener を登録するLocationManager に GpsStatus.Listener を登録するGpsStatus.Listener のメンバ関数 onGpsStatusChanged がコールバックされるLocationManager から LocationListener と GpsStatus.Listener を外す
必要なリスナを生成して LocationManager に登録する手順は、GPS で位置情報を得る場合と同じです。しかし注意すべき点として、GpsStatus.Listener だけでなく、位置情報を必要としていない場合であっても LocationListener も忘れずに登録しないと、更新通知がされません*1。
package com.example.helloworld;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.content.Context;
import android.location.LocationManager;
import android.location.LocationListener;
import android.location.Location;
import android.location.GpsStatus;
import android.location.GpsSatellite;
import android.widget.TextView;
// http://developer.android.com/reference/android/app/Activity.html
public class MainActivity extends ActionBarActivity
{
private LocationManager mLocationManager = null;
private LocationListener mLocationListener = null;
private GpsStatus.Listener mGpsStatusListener = null;
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLocationManager = (LocationManager) getSystemService( Context.LOCATION_SERVICE );
final boolean gpsEnabled = mLocationManager.isProviderEnabled( LocationManager.GPS_PROVIDER );
if (!gpsEnabled) {
// ToDo: GPS 有効にしてくれー
}
mLocationListener = new LocationListener()
{
public void onLocationChanged(Location location) {}
public void onStatusChanged(String provider, int status, Bundle extras) {}
public void onProviderEnabled(String provider) {}
public void onProviderDisabled(String provider) {}
};
mGpsStatusListener = new GpsStatus.Listener()
{
public void onGpsStatusChanged( int event ) {
// http://developer.android.com/reference/android/location/GpsSatellite.html
Iterable<GpsSatellite> satellites = mLocationManager.getGpsStatus(null).getSatellites();
int sat_used = 0;
int sat_total = 0; // GpsStaus.getMaxSatellites() の返り値が謎
String str = "PRN : Azimuth : Elevation : S/N\n";
for( GpsSatellite sat : satellites ) {
if( sat.usedInFix()) {
str += "*"; sat_total++; sat_used++;
} else {
str += " "; sat_total++;
}
str += String.format( "%2d", (int) sat.getPrn()) + " : ";
str += String.format( "%7d", (int) sat.getAzimuth()) + " : ";
str += String.format( "%9d", (int) sat.getElevation()) + " : ";
str += String.format( "%4.1f", sat.getSnr()) + "\n";
}
str += String.format( "\nsatellites %d/%d\n" , sat_used, sat_total );
TextView t = (TextView) findViewById( R.id.textView1 );
t.setText( str );
}
};
}
protected void onStart() { // ⇔ onStop
super.onStart();
mLocationManager.addGpsStatusListener( mGpsStatusListener );
mLocationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
1000 * 1/*mSec*/, 1/*meter*/,
mLocationListener );
}
protected void onStop() { // ⇔ onStart
super.onStop();
mLocationManager.removeGpsStatusListener( mGpsStatusListener );
mLocationManager.removeUpdates( mLocationListener );
}
}
基本的な部分は、GPS で位置情報のみを取得する場合と同じです。
LocationListener のインスタンスを生成しています(概要の手順 3)。ただし、今回のサンプルでは位置情報を利用しないので、実装すべきメンバ関数は何の動作もしませんが、動作に必須のためインスタンスを省略できません。GpsStatus.Listener のインスタンスを生成しています(概要の手順 4)。ここでは匿名クラスとしてリスナを生成していますが、お行儀よく GpsStatus.Listener を implements したサブクラスを定義すべきです。ここでリスナを生成していますが、まだ LocationManager に登録されていないので、位置情報は取得しません。GpsStatus オブジェクトから GpsSatellite オブジェクトを取得できるので、確認のために内容を整形して、アクティビティに配置した TextView に出力しています。GpsStatus.Listener だけでなく、LocationListener と一緒に登録しないと更新通知されません。GpsStatus.Listener だけでなく、LocationListener も忘れずに一緒に止めます。ついでに開発中に出会った単語などのメモ。
GpsSatellite.usedInFix()LocationListener からは位置情報を同時に取得できますが、このサンプルでは本題ではないので、取得した情報はそのまま捨てています。