package com.openxc.sources; import android.content.Context; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; import android.os.Looper; import android.util.Log; import com.google.common.base.MoreObjects; import com.openxc.measurements.Latitude; import com.openxc.measurements.Longitude; import com.openxc.messages.SimpleVehicleMessage; /** * Generate location measurements based on native GPS updates. * * This source listens for GPS location updates from the built-in Android location * framework and passes them to the OpenXC vehicle measurement framework as if * they originated from the vehicle. This source is useful to seamlessly use * location in an application regardless of it the vehicle has built-in GPS. * * The ACCESS_FINE_LOCATION permission is required to use this source. */ public class NativeLocationSource extends ContextualVehicleDataSource implements LocationListener, Runnable { private final static String TAG = "NativeLocationSource"; private final static int NATIVE_GPS_UPDATE_INTERVAL = 5000; private LocationManager mLocationManager; private Looper mLooper; public NativeLocationSource(SourceCallback callback, Context context) { super(callback, context); mLocationManager = (LocationManager) getContext().getSystemService( Context.LOCATION_SERVICE); } public NativeLocationSource(Context context) { this(null, context); } @Override public void run() { Looper.prepare(); // try to grab a rough location from the network provider before // registering for GPS, which may take a while to initialize Location lastKnownLocation = mLocationManager .getLastKnownLocation( LocationManager.NETWORK_PROVIDER); if(lastKnownLocation != null) { onLocationChanged(lastKnownLocation); } try { mLocationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, NATIVE_GPS_UPDATE_INTERVAL, 0, this); Log.d(TAG, "Requested GPS updates"); } catch(IllegalArgumentException e) { Log.w(TAG, "GPS location provider is unavailable"); } mLooper = Looper.myLooper(); Looper.loop(); } @Override public void stop() { super.stop(); onPipelineDeactivated(); } @Override public void onLocationChanged(final Location location) { handleMessage(new SimpleVehicleMessage(Latitude.ID, location.getLatitude())); handleMessage(new SimpleVehicleMessage(Longitude.ID, location.getLongitude())); } @Override public void onStatusChanged(String provider, int status, Bundle extras) {} @Override public void onProviderEnabled(String provider) { } @Override public void onProviderDisabled(String provider) { } @Override public boolean isConnected() { // Always return false so we don't keep the pipeline awake if no actual // vehicle interface is connected. return false; } @Override public void onPipelineActivated() { new Thread(this).start(); } @Override public void onPipelineDeactivated() { Log.i(TAG, "Disabled native GPS passthrough"); if(mLooper != null) { mLooper.quit(); } mLocationManager.removeUpdates(this); } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("updateInterval", NATIVE_GPS_UPDATE_INTERVAL) .toString(); } }