Search code examples
javaandroidgpssatellite

Android emulate GPS satellites (not only location)


I'm looking for a way to simulate satellite presence in Android Emulator. I'm able to submit lon/lat pair through telnet as "geo fix" and that works fine in google maps or similar apps, or replay .kml files through Extended controls. The problem is that other applications (for example, GPS test by chartcross) are still complaining that GPS signal is lost or no satellites found.

Also tried sending nmea sentence but probably there's some mistake in format cause it didn't change the location even in google maps:

geo nmea $GPGGA,090000.00,4452.85370156,N,06330.55438023,W,1,05,2.87,160.00,M,-21.3213,M,,*61

Solution

  • After a lot of digging in the end I switched to native Android's API for setting Lat/Long through Mock Locations

    NMEA works on layer below system calls and it's generally invisible to the applications To summarize, this is an approximate flow of GPS data in Android:

    GPS Device => GPS driver = (NMEA coordinates) => Android GPS engine = (Lat/Long coordinates) => Android service layer <=> Various API calls from applications

    Thus in order to mock locations it wasn't needed to go that deep. 99% of apps rely on Service layer's data and so you can easily obfuscate System's GPS_PROVIDER:

    import android.content.Context;
    import android.location.*;
    import android.os.SystemClock;
    import android.util.Log;
    
    
    /**
     * Created by the.Legend on 17/07/2016.
     */
    public class FakeGPS {
    
        private LocationManager locationManager;
        public static final String GPS_MOCK_PROVIDER = "gps";
    
        public FakeGPS(){    
            locationManager = (LocationManager) Environment.mainContext.getSystemService(Context.LOCATION_SERVICE);
    
            if(!locationManager.isProviderEnabled(GPS_MOCK_PROVIDER)) {
    
                locationManager.addTestProvider(GPS_MOCK_PROVIDER, false, false,
                        false, false, true, false, false, 0, 5);
                locationManager.setTestProviderEnabled(GPS_MOCK_PROVIDER, true);
    
                locationManager.setTestProviderStatus(GPS_MOCK_PROVIDER, LocationProvider.AVAILABLE, null, System.currentTimeMillis());
            }    
        }    
    
        public void applyCoordinates(   Double longitude,  Double latitude){
    
            if(locationManager.isProviderEnabled(GPS_MOCK_PROVIDER)) {  
                Double altitude= 0.0;
                Float accuracy=3.0f;
                long timestamp=System.currentTimeMillis();    
    
                try {    
                    Location location = new Location(LocationManager.GPS_PROVIDER);
                    location.setLatitude(latitude);
                    location.setLongitude(longitude);
                    location.setAltitude(altitude);
                    location.setAccuracy(accuracy);
                    location.setTime(timestamp);
                    location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());                    locationManager.setTestProviderLocation(GPS_MOCK_PROVIDER, location);    
                }
                catch (Exception e) {
                    e.printStackTrace();
                }
            }    
        }
    }