How can I check the current status of the GPS receiver?

AndroidGps

Android Problem Overview


How can I check the current status of the GPS receiver? I already checked the LocationListener onStatusChanged method but somehow it seems that is not working, or just the wrong possibility.

Basically I just need to know if the GPS icon at the top of the screen is blinking (no actual fix) or solid (fix is available).

Android Solutions


Solution 1 - Android

As a developer of SpeedView: GPS speedometer for Android, I must have tried every possible solution to this problem, all with the same negative result. Let's reiterate what doesn't work:

  1. onStatusChanged() isn't getting called on Eclair and Froyo.
  2. Simply counting all available satellites is, of course, useless.
  3. Checking if any of the satellites return true for usedInFix() isn't very helpful also. The system clearly loses the fix but keeps reporting that there are still several sats that are used in it.

So here's the only working solution I found, and the one that I actually use in my app. Let's say we have this simple class that implements the GpsStatus.Listener:

private class MyGPSListener implements GpsStatus.Listener {
	public void onGpsStatusChanged(int event) {
		switch (event) {
			case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
				if (mLastLocation != null)
					isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < 3000;
				
				if (isGPSFix) { // A fix has been acquired.
					// Do something.
				} else { // The fix has been lost.
					// Do something.
				}
				
				break;
			case GpsStatus.GPS_EVENT_FIRST_FIX:
				// Do something.
				isGPSFix = true;
				
				break;
		}
	}
}

OK, now in onLocationChanged() we add the following:

@Override
public void onLocationChanged(Location location) {
	if (location == null) return;
	
	mLastLocationMillis = SystemClock.elapsedRealtime();
	
	// Do something.
			
	mLastLocation = location;
}

And that's it. Basically, this is the line that does it all:

isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < 3000;

You can tweak the millis value of course, but I'd suggest to set it around 3-5 seconds.

This actually works and although I haven't looked at the source code that draws the native GPS icon, this comes close to replicating its behaviour. Hope this helps someone.

Solution 2 - Android

The GPS icon seems to change its state according to received broadcast intents. You can change its state yourself with the following code samples:

Notify that the GPS has been enabled:

Intent intent = new Intent("android.location.GPS_ENABLED_CHANGE");
intent.putExtra("enabled", true);
sendBroadcast(intent);

Notify that the GPS is receiving fixes:

Intent intent = new Intent("android.location.GPS_FIX_CHANGE");
intent.putExtra("enabled", true);
sendBroadcast(intent);

Notify that the GPS is no longer receiving fixes:

Intent intent = new Intent("android.location.GPS_FIX_CHANGE");
intent.putExtra("enabled", false);
sendBroadcast(intent);

Notify that the GPS has been disabled:

Intent intent = new Intent("android.location.GPS_ENABLED_CHANGE");
intent.putExtra("enabled", false);
sendBroadcast(intent);

Example code to register receiver to the intents:

// MyReceiver must extend BroadcastReceiver
MyReceiver receiver = new MyReceiver();
IntentFilter filter = new IntentFilter("android.location.GPS_ENABLED_CHANGE");
filter.addAction("android.location.GPS_FIX_CHANGE");
registerReceiver(receiver, filter);

By receiving these broadcast intents you can notice the changes in GPS status. However, you will be notified only when the state changes. Thus it is not possible to determine the current state using these intents.

Solution 3 - Android

new member so unfortunately im unable to comment or vote up, however Stephen Daye's post above was the perfect solution to the exact same problem that i've been looking for help with.

a small alteration to the following line:

isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < 3000;

to:

isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < (GPS_UPDATE_INTERVAL * 2);

basically as im building a slow paced game and my update interval is already set to 5 seconds, once the gps signal is out for 10+ seconds, thats the right time to trigger off something.

cheers mate, spent about 10 hours trying to solve this solution before i found your post :)

Solution 4 - Android

Ok, so let's try a combination of all the answers and updates so far and do something like this:

The GPS listener could be something like this:

GpsStatus.Listener listener = new GpsStatus.Listener() {
    void onGpsStatusChanged(int event) {
        if (event == GPS_EVENT_SATELLITE_STATUS) {
            GpsStatus status = mLocManager.getGpsStatus(null);
            Iterable<GpsSatellite> sats = status.getSatellites();
            // Check number of satellites in list to determine fix state
        }
    }
}

The APIs are a bit unclear about when and what GPS and satellite information is given, but I think an idea would be to look at how many satellites are available. If it's below three, then you can't have a fix. If it's more, then you should have a fix.

Trial and error is probably the way to go to determine how often Android reports satellite info, and what info each GpsSatellite object contains.

Solution 5 - Android

After a few years of working with GPS on windows mobile, I realized that the concept of "losing" a GPS fix can be subjective. To simply listen to what the GPS tells you, adding a NMEAListener and parsing the sentence will tell you whether the fix was "valid" or not. See http://www.gpsinformation.org/dale/nmea.htm#GGA . Unfortunately with some GPSes this value will fluctuate back and forth even during the normal course of operation in a "good fix" area.

So, the other solution is to compare the UTC time of the GPS location against the phone's time (converted to UTC). If they are a certain time difference apart, you can assume you lost the GPS position.

Solution 6 - Android

get into similar problem while working on my MSc project, it seems that Daye's answer mistakenly reported "no fix" while the device stays in a static location. I've modified the solution just a little bit which seems to work fine for me in a static location. I don't how would it affect the battery as it is not my main concern, but here's how i did it by re-requesting location updates when a fix has timed out.

private class MyGPSListener implements GpsStatus.Listener {
    public void onGpsStatusChanged(int event) {
        switch (event) {
        case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
            if (Global.getInstance().currentGPSLocation != null)
            {
            	if((SystemClock.elapsedRealtime() - mLastLocationMillis) < 20000)
            	{
            		if (!hasGPSFix) 
            			Log.i("GPS","Fix Acquired");
            		hasGPSFix = true;
            	} 
            	else
            	{
            		if (hasGPSFix) 
            		{
            			Log.i("GPS","Fix Lost (expired)");
            			lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 2000, 10, locationListener);
            		}
            		hasGPSFix = false;
            	}
            }
            break;
        case GpsStatus.GPS_EVENT_FIRST_FIX:
        	Log.i("GPS", "First Fix/ Refix");
        	hasGPSFix = true;
            break;
        case GpsStatus.GPS_EVENT_STARTED:
        	Log.i("GPS", "Started!");
        	break;
        case GpsStatus.GPS_EVENT_STOPPED:
        	Log.i("GPS", "Stopped");
        	break;
        }
    }
}

Solution 7 - Android

Well, putting together every working approach will result in this (also dealing with deprecated GpsStatus.Listener):

private GnssStatus.Callback mGnssStatusCallback;
@Deprecated private GpsStatus.Listener mStatusListener;
private LocationManager mLocationManager;

@Override
public void onCreate() {
    mLocationManager = (LocationManager) getSystemService(LOCATION_SERVICE);

    mLocationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
    if (checkPermission()) {
       mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, GPS_UPDATE_INTERVAL, MIN_DISTANCE, this);
    }

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        mGnssStatusCallback = new GnssStatus.Callback() {
            @Override
            public void onSatelliteStatusChanged(GnssStatus status) {
                satelliteStatusChanged();
            }

            @Override
            public void onFirstFix(int ttffMillis) {
                gpsFixAcquired();

            }
        };
        mLocationManager.registerGnssStatusCallback(mGnssStatusCallback);
    } else {
        mStatusListener = new GpsStatus.Listener() {
            @Override
            public void onGpsStatusChanged(int event) {
                switch (event) {
                    case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
                        satelliteStatusChanged();
                        break;
                    case GpsStatus.GPS_EVENT_FIRST_FIX:
                        // Do something.
                        gpsFixAcquired();
                        break;
                }
            }
        };
        mLocationManager.addGpsStatusListener(mStatusListener);
    }
}

private void gpsFixAcquired() {
    // Do something.
    isGPSFix = true;
}

private void satelliteStatusChanged() {
    if (mLastLocation != null)
        isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < (GPS_UPDATE_INTERVAL * 2);

    if (isGPSFix) { // A fix has been acquired.
        // Do something.
    } else { // The fix has been lost.
        // Do something.
    }
}

@Override
public void onLocationChanged(Location location) {
    if (location == null) return;

    mLastLocationMillis = SystemClock.elapsedRealtime();

    mLastLocation = location;
}

@Override
public void onStatusChanged(String s, int i, Bundle bundle) {

}

@Override
public void onProviderEnabled(String s) {

}

@Override
public void onProviderDisabled(String s) {

}

Note: this answer is a combination of the answers above.

Solution 8 - Android

If you just need to know if there's a fix, then check for the last known location provided by the GPS receiver and check the .getTime() value to know how old is that. If it's recent enough (like... a few seconds) you have a fix.

   LocationManager lm = (LocationManager)context.getSystemService(LOCATION_SERVICE); 
   Location loc = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);

   // Get the time of the last fix
   long lastFixTimeMillis = loc.getTime(); 

... and finally compare that to current date time (In UTC!). If it's recent enough you have a fix.

I do that in my app and so far so good.

Solution 9 - Android

You could try using LocationManager.addGpsStatusListener to get updated when the GPS status changes. It looks like GPS_EVENT_STARTED and GPS_EVENT_STOPPED might be what you're looking for.

Solution 10 - Android

I may be wrong but it seems people seem to be going way off-topic for

> i just need to know if the gps icon at the top of the screen is blinking (no actual fix)

That is easily done with

LocationManager lm = (LocationManager) getSystemService(LOCATION_SERVICE);
boolean gps_on = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);

To see if you have a solid fix, things get a little trickier:

public class whatever extends Activity {
    LocationManager lm;
    Location loc;
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);        
        lm = (LocationManager) getSystemService(LOCATION_SERVICE);
        loc = null;
        request_updates();        
    }

    private void request_updates() {
        if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
            // GPS is enabled on device so lets add a loopback for this locationmanager
            lm.requestLocationUpdates(LocationManager.GPS_PROVIDER,0, 0, locationListener);
        }      
    }

    LocationListener locationListener = new LocationListener() {
	    public void onLocationChanged(Location location) {
            // Each time the location is changed we assign loc
		    loc = location;
        }

         // Need these even if they do nothing. Can't remember why.
         public void onProviderDisabled(String arg0) {}
         public void onProviderEnabled(String provider) {}
         public void onStatusChanged(String provider, int status, Bundle extras) {}
    };

Now whenever you want to see if you have fix?

if (loc != null){
    // Our location has changed at least once
    blah.....
}

If you want to be fancy you can always have a timeout using System.currentTimeMillis() and loc.getTime()

Works reliably, at least on an N1 since 2.1.

Solution 11 - Android

With LocationManager you can getLastKnownLocation() after you getBestProvider(). This gives you a Location object, which has the methods getAccuracy() in meters and getTime() in UTC milliseconds

Does this give you enough info?

Or perhaps you could iterate over the LocationProviders and find out if each one meetsCriteria( ACCURACY_COARSE )

Solution 12 - Android

so many posts...

GpsStatus.Listener gpsListener = new GpsStatus.Listener() {
	        		    public void onGpsStatusChanged(int event) {
	        		        if( event == GpsStatus.GPS_EVENT_FIRST_FIX){
	        		        	showMessageDialog("GPS fixed");
	        		        }
	        		    }
	        	 };

adding this code, with addGpsListener... showMessageDialog ... just shows a standard dialog window with the string

did the job perfectly for me :) thanks a lot :=) (sry for this post, not yet able to vote)

Solution 13 - Android

If you do not need an update on the very instant the fix is lost, you can modify the solution of Stephen Daye in that way, that you have a method that checks if the fix is still present.

So you can just check it whenever you need some GPS data and and you don't need that GpsStatus.Listener.

The "global" variables are:

private Location lastKnownLocation;
private long lastKnownLocationTimeMillis = 0;
private boolean isGpsFix = false;

This is the method that is called within "onLocationChanged()" to remember the update time and the current location. Beside that it updates "isGpsFix":

private void handlePositionResults(Location location) {
		if(location == null) return;
		
		lastKnownLocation = location;
		lastKnownLocationTimeMillis = SystemClock.elapsedRealtime();

		checkGpsFix(); // optional
	}

That method is called whenever I need to know if there is a GPS fix:

private boolean checkGpsFix(){
	
	if (SystemClock.elapsedRealtime() - lastKnownLocationTimeMillis < 3000) {
		isGpsFix = true;

	} else {
		isGpsFix = false;
		lastKnownLocation = null;
	}
	return isGpsFix;
}

In my implementation I first run checkGpsFix() and if the result is true I use the variable "lastKnownLocation" as my current position.

Solution 14 - Android

I know this is a little late. However why not use the NMEAListener if you want to know if you have a fix. From what I've read, the NMEAListener will give you the NMEA sentences and from there you pick the correct sentence.

The RMC sentence contains the fix status which is either A for OK or V for warning. The GGA sentence contains the Fix Quality (0 invalid, 1 GPS or 2 DGPS)

I can't offer you any java code as I'm only just starting out with Android, but I have done a GPS library in C# for Windows apps, which I'm looking to use with Xamarin. I only came across this thread because I was looking for provider information.

From what I've read so far about the Location object I'm not all that comfortable about methods like getAccuracy() and hasAccuracy(). I'm used to extracting from the NMEA sentences HDOP and VDOP values to determine how accurate my fixes are. Its quite common to have a fix, but have a lousy HDOP which means your horizontal accuracy is not very good at all. For example sitting at your desk debugging with an external Bluetooth GPS device hard up against a window, you are quite likely to get a fix, but very poor HDOP and VDOP. Place your GPS device in a flower pot outside or something similar or add an external aerial to the GPS and immediately you get good HDOP and VDOP values.

Solution 15 - Android

Maybe it's the best possiblity to create a TimerTask that sets the received Location to a certain value (null?) regularly. If a new value is received by the GPSListener it will update the location with the current data.

I think that would be a working solution.

Solution 16 - Android

You say that you already tried onStatusChanged(), but that does work for me.

Here's the method I use (I let the class itself handle the onStatusChanged):

private void startLocationTracking() {
    final int updateTime = 2000; // ms
    final int updateDistance = 10; // meter
    final Criteria criteria = new Criteria();
    criteria.setCostAllowed(false);
    criteria.setAccuracy(Criteria.ACCURACY_FINE);
    final String p = locationManager.getBestProvider(criteria, true);
    locationManager.requestLocationUpdates(p, updateTime, updateDistance,
            this);
}

And I handle the onStatusChanged as follows:

void onStatusChanged(final String provider, final int status,
        final Bundle extras) {
    switch (status) {
    case LocationProvider.OUT_OF_SERVICE:
        if (location == null || location.getProvider().equals(provider)) {
            statusString = "No Service";
            location = null;
        }
        break;
    case LocationProvider.TEMPORARILY_UNAVAILABLE:
        if (location == null || location.getProvider().equals(provider)) {
            statusString = "no fix";
        }
        break;
    case LocationProvider.AVAILABLE:
        statusString = "fix";
        break;
    }
}

Note that the onProvider{Dis,En}abled() methods are about enabling and disabling GPS tracking by the user; not what you're looking for.

Solution 17 - Android

Setting time interval to check for fix is not a good choice.. i noticed that onLocationChanged is not called if you are not moving.. what is understandable since location is not changing :)

Better way would be for example:

  • check interval to last location received (in gpsStatusChanged)
  • if that interval is more than 15s set variable: long_interval = true
  • remove the location listener and add it again, usually then you get updated position if location really is available, if not - you probably lost location
  • in onLocationChanged you just set long_interval to false..

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionnr1View Question on Stackoverflow
Solution 1 - AndroidsoundmavenView Answer on Stackoverflow
Solution 2 - AndroidsastView Answer on Stackoverflow
Solution 3 - AndroidchichView Answer on Stackoverflow
Solution 4 - AndroidChristopher OrrView Answer on Stackoverflow
Solution 5 - AndroidJustin BreitfellerView Answer on Stackoverflow
Solution 6 - AndroidJeffery LeeView Answer on Stackoverflow
Solution 7 - AndroidGregory SteinView Answer on Stackoverflow
Solution 8 - AndroidAdanView Answer on Stackoverflow
Solution 9 - AndroidErich DouglassView Answer on Stackoverflow
Solution 10 - AndroidregomodoView Answer on Stackoverflow
Solution 11 - AndroidMark BorgerdingView Answer on Stackoverflow
Solution 12 - AndroidcV2View Answer on Stackoverflow
Solution 13 - AndroidSebastian MauthoferView Answer on Stackoverflow
Solution 14 - Androiduser2153142View Answer on Stackoverflow
Solution 15 - Androidnr1View Answer on Stackoverflow
Solution 16 - AndroidCvRView Answer on Stackoverflow
Solution 17 - AndroidHardyView Answer on Stackoverflow