views:

4391

answers:

18
+3  Q: 

Android GPS status

Hi,

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.

So 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)

thx!

+1  A: 

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.

Erich Douglass
A status listener combined with `GPS_EVENT_FIRST_FIX` sounds like a closer fit.
Christopher
A: 

I tried it now with this GPSStatusListener: This thing returns GPS_EVENT_STARTED even if no fix is available.. Seems that it just indicates if the gps receiver is enabled or not or something like this..

nr1
@Christopher: I tried it: the GPS_EVENT_FIRST_FIX can be used to check when the first fix is available. Unfortunately there is no event that indicated that no gps signal is there anymore..
nr1
+3  A: 

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.

Christopher
the problem with counting the available satellites is, that even if you have 5 satellites in view, this doesn't mean that there a fix is always possible. (You mentioned it correct by writing "If it's more, then you _should_ have a fix")
nr1
Indeed. Though I don't know any more about what info is required to constitute a fix, or how/whether this can be retrieved from a `GpsSatellite` object.
Christopher
Another thought.. you don't mention this in your question, but have you tried just using `LocationManager.requestLocationUpdates` with the time and distance settings set to 0? That should send you GPS fixes as soon as they happen. If you're not receiving anything, then you most likely don't have a fix. You could combine this with the status listener above if you like.
Christopher
A: 

I am new to GPS and pardon me if u think the questions i ask are too noob.

1) what is fix? 2) how can i detect if the gps connection is up and working as i want to prompt error when the gps connection is not detected?

Thanks.

That's what this question is asking. Please use the "add comment" button to add comments instead of pressing "add answer".
Christopher
A: 
  1. http://en.wikipedia.org/wiki/Fix_%28position%29
  2. That's the thing we're also trying to discover ;)
nr1
A: 

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.

nr1
A: 

hmm still no solution yet..

nr1
You haven't said which of the solutions posted here you have tried and what isn't working and why. Also, you should post comments using the "add comment" button at the top of your question instead of posting new "answers".
Christopher
A: 

Hi,

Did you look at the api demos @ android.com? Might be able to get what you want there. Think you need to use requestLocationUpdates() to get a fix. I've tried it myself but somehow the GPS is not updating the location at all. I did get some response when I used the network provider instead of a GPS provider. Maybe you would have better luck. :)

pohtzeyun
A: 

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 )

Mark Borgerding
A: 

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.

CvR
Unfortunately, it often does not work. onLocationChanged() gets called once a second, but onStatusChanged doesn't get called at all. Sometimes I wish I could just query the current status instead of waiting for a notification that might not come for a long time, or ever.
Edward Falk
Unfortunately, it often does not work. onLocationChanged() gets called once a second, but onStatusChanged doesn't get called at all. Sometimes I wish I could just query the current status instead of waiting for a notification that might not come for a long time, or ever.
Edward Falk
Right. I've learned a few things myself after that previous reply, and one is that not all Android platforms are made alike. I definitely see calls to onStatusChanged on both my HTC Hero and my Archos 5, but I'm not surprised that doesn't work everywhere.How about plan B: you use the GPSStatusListener that is shown in another answer, and simply see if any of the satellites returns true for usedInFix(). In my experience that comes closest to the behavior of the standard GPS icon. (Have you tried to find the source that implements that standard icon, BTW?)
CvR
A: 

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)

cV2
A: 

Yes, cV2, so many posts, because no one has posted a working answer yet, including you. The "first fix" will tell you when a fix has been acquired, but there is still no (easy) code for detecting when the fix has been -lost-.

Pete
+2  A: 

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.

Justin Breitfeller
+3  A: 

First of all, I'm a developer of SpeedView, a GPS speedometer for Android, so you can trust me when I say that we tried every possible solution to this problem, all with the same negative result. Let's start by reiterating what doesn't work:

  1. onStatusChanged() doesn't get called on Eclair and Froyo. It does get called on 1.6 though.
  2. Simply counting all available satellites is, of course, useless.
  3. Checking if any of the satellites returns true for usedInFix() isn't very helpful also. The system apparently loses the fix but still continue to report that there are several sats that are used in it.

So, the only working solution we have, and the one we actually use in our application, is the following. 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() you should 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 milliseconds value of course, but I would suggest to set it around 3-5 seconds.

This actually works and though I haven't seen the source code that implements the standard GPS icon, this comes close to replicating its behavior. It could even outdo it lol. Hope this helps someone.

Stephen Daye
A: 

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 :)

chich
A: 

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.

Sebastian Mauthofer
A: 

Sorry, I am not allowed to comment and vote, so I write this as an answer:

I had met the same problem. I have implemented Stephen Daye's solution in my navigation application and it works perfect (as a workaround can be). Thanks, Stephen!

Andrey Novikov