30

this is how I register my app to receive location updates:

mLocationRequest = LocationRequest.create();
mLocationRequest.setInterval(Consts.ONE_MINUTE * 10);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
mLocationRequest.setFastestInterval(Consts.ONE_MINUTE);

Builder builder = new GoogleApiClient.Builder(context);
builder.addApi(ActivityRecognition.API);

mGoogleApiClient = builder.addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .build();

mGoogleApiClient.connect();

....
....

@Override
public void onConnected(Bundle connectionHint) {
   LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, locationUpdatespendingInent);
}

my pending intent been invoked in background almost in the exact requested intervals...

so far so good.

the problem: When WIFI is disabled/ not connected to any network, or when there is no 3G/4G network data enabled - the fused location provider not providing new location updates!!

my Location access settings are turned on, and GPS satellites and WI-FI & mobile network location is checked.

the even bigger problem: sometimes in that case, I do receive location updates callbacks via the pending intent, but with the last location it knew (even if it was an hour ago, and I'm long long gone away miles from that place)

according to the documentation of PRIORITY_BALANCED_POWER_ACCURACY :

Used with setPriority(int) to request "block" level accuracy. Block level accuracy is considered to be about 100 meter accuracy. Using a coarse accuracy such as this often consumes less power.

I'm expecting that the fused location provider will open the GPS when it have no other choice, or at least won't provide a new location updates if he don't have any.

another unpredictable and disturbing issue:

I changed PRIORITY_BALANCED_POWER_ACCURACY to PRIORITY_HIGH_ACCURACY in order to see how it behaves (for 24 hours). all the intervals stayed the same (10 minutes interval between updates). accurate location indeed received even in phones with no network/sim card, but - the battery drained out fast! when I looked on the battery history, I was surprised to see that GPS radio was on full transmission mode all the time!!!! and I saw also in my log that loction was received every minute, even that I requested location each ten minutes (I don't have any other installed apps that opens GPS to receive locations..)

I noticed this behavior on several devices (such as Moto X 2013, HTC One X, Nexus 5) , all with latest Google Play Services (version 6.1.11) , and android KITKAT 4.4.4

my application depends a lot on the user current location, and periodically receives location updates in the specified interval as long as the user logged in, so I don't want to use the PRIORITY_HIGH_ACCURACY mode, to prevent battery drain..

my questions:

  • is the fused location provider suppose to use GPS at all if it set to receive updates with PRIORITY_BALANCED_POWER_ACCURACY and don't have any WI-FI or cell towers info ?

  • if it does, then what am I doing wrong?

  • why I'm getting this misleading location updates that are not correct? (as I explained in the the "even bigger problem" section..

  • why GPS radio is opened all the time instead of been opened for the 10 minutes interval when I used the PRIORITY_HIGH_ACCURACY parameter? (I don't have other installed apps that triggers location updates faster..)

Tal Kanel
  • 10,475
  • 10
  • 60
  • 98

4 Answers4

20

For the questions specified,

1. is the fused location provider suppose to use GPS at all if it set to receive updates with PRIORITY_BALANCED_POWER_ACCURACY and don't have any WI-FI or cell towers info ? &
2. if it does, then what am I doing wrong?

Apparently no explicitly unique source is specified anywhere within documentation. With either PRIORITY options, even through code, the "source" of obtained location is "fused".
[location.getProvider() returns :"fused"]
I have seen GPS being used only when the LocationRequest has PRIORITY_HIGH_ACCURACY. So it does not use GPS under other conditions.

4. why GPS radio is opened all the time instead of been opened for the 10 minutes interval when I used the PRIORITY_HIGH_ACCURACY parameter? (I don't have other installed apps that triggers location updates faster..)

The fastest interval has been set for 1 minute. From what i understood, the setFastestInterval is given precedence over setInterval when the value for fastest interval is shorter in duration than the value of setInterval.
In your case, 1 minute against 10.
About not having other installed apps that triggers location updates, its just given as an example and not specified that only that case explicitly.

This controls the fastest rate at which your application will receive location updates, which might be faster than setInterval(long) in some situations (for example, if other applications are triggering location updates).

So, what happens is with PRIORITY_HIGH_ACCURACY, it requests location on the fastest interval set - 1min, by using GPS(kind of exclusively).

3. why I'm getting this misleading location updates that are not correct? (as I explained in the the "even bigger problem" section..

Need to check the code for pendingIntent mechanism also. Though there could be a few things to take note of:
You can add a location.getTime() to ensure and verify the time of obtained location. Very likely it is not being updated, if there is no wifi-cell towers in range and PRIORITY_BALANCED_POWER_ACCURACY is used.
A block level accuracy of location on the first place, which is being used when "lastKnown" is called wouldn't help.

The battery consumption was because of the combination of GPS and 1 min updates. Try setting the fastest interval as 5 or 10 mins, if that is suitable for your implementation but PRIORITY_BALANCED_POWER may not help if you need absolutely accurate location. I normally add a check for the location obtained in onLocationChanged and depending on that, switch the priority in LocationRequest. It helps in, surely, obtaining a location generally, unless i am inside a building with no line-of-sight for GPS and Wifi-Network are off.

Pararth
  • 8,114
  • 4
  • 34
  • 51
  • thank. I'll check how things behaves when I change the fastestInterval, and all the other points you mentioned. if it really works like that - I'll be happy to come back the reward your answer – Tal Kanel Oct 08 '14 at 07:17
  • sure, no problem, also try high accuracy with no line-of-sight in an independent location only app, it probably won't return any updated accurate location..just to ensure the behaviour – Pararth Oct 08 '14 at 07:19
  • thanks so for the help, location changing the fastest interval indeed affects the pending intent callbacks, but - still I see that the GPS radio is 100% of the time is opend (based on the battery data on settings). any idea? – Tal Kanel Oct 08 '14 at 07:52
  • 1
    this could help, its [one of the better answers for why GPS uses so much battery](http://www.quora.com/Why-does-GPS-use-so-much-more-battery-than-any-other-antenna-or-sensor-in-a-smartphone), still need to check in specific mobile app contexts, i'd try asking the user to enable/disable it depending on when he/she required an accurate location, that way wouldn't make it mandatory, won't work in your case i guess (considering a consistent requirement) – Pararth Oct 08 '14 at 09:25
  • Your answer was the only one answer which provided me insights I did not knew of... Thanks! – Tal Kanel Oct 13 '14 at 17:56
  • 1
    Those explanations are very helpful for a new dev like me. I found that new Fused location interface very good compared to Location Manager / GPS provider / Network provider etc... But I had the same issues and questions in my application Thanks a lot. – Mario Apr 28 '15 at 13:29
  • @Mario : Assuming you are talking about the new Fused Location interface [-Google Play services 6.5 LocationClient missing-](http://stackoverflow.com/questions/27372638/android-play-services-6-5-locationclient-is-missing), you are using play services anyway then this would also help -better user experience; [Enabling GPS without user being redirected to LocationSettings](http://stackoverflow.com/questions/28759454/enabling-location-with-mode-high-accuracy-or-battery-saving-without-user-needing/29002760#29002760) – Pararth Apr 28 '15 at 14:31
  • Hi @user2450263 . Please check my [problem](http://stackoverflow.com/questions/30451503/change-fuse-location-setting-while-service-is-running/3/0458731#30458731). I want switch my priorities. How can I achieve that – Kunu May 26 '15 at 13:23
  • 1
    either question was removed, or link issue...page not found – Pararth May 26 '15 at 13:29
  • @user2450263 check [this](http://stackoverflow.com/questions/30451503/change-fuse-location-setting-while-service-is-running) – Kunu May 27 '15 at 06:02
  • @Kunu you need to google and attempt more than what you have, don't just post the requirement :) – Pararth May 27 '15 at 11:54
  • @user2450263 I am doing that. Because google is only source for that. But I was just wondering if you have done it or not because in your answer you said `switch the priority in LocationRequest` in `onLocationChanged`. By the way thanks :) – Kunu May 27 '15 at 12:01
  • hey , i m having prob when device is using cellular data and this location setting builder requests to TURN ON WIFI .this is irrelevant .So how to disable wifi request from Pending intent to pop up. i need location only – Hemant Shori Aug 03 '15 at 09:41
  • i think that is needed, and in a way is relevant because under PRIORITY_BALANCED_POWER_ACCURACY, the location provided by GooglePlayServices is not under "device only" or gps only mode, it is through an algorithm which considers matching up a table of wifi spots available in range. I don't remember the exact words for what i had read, but have tried to give you the gist of it. So the requests to Turn on Wifi may be internally managed by the o.s. as i have seen them myself under some conditions where location needs to be obtained in a few apps – Pararth Aug 03 '15 at 13:10
4

I would suggest you to use AlarmManager and FusedLocationProvider together in such a way that your AlarmManager fire alarm on every 10minute with a view to start location updates.

Once you get updated location, disconnect the location client. You don't need to keep it running for all the time by setting interval time in LocationRequest, Instead you can invoke the process on each time interval by using AlarmManager.

In such kind of mechanism, you will have following benefits which will resolve your problems:

  • GPS radio will stay open only for few seconds while retrieving location because you are going to disconnect after getting first location update. Thus GPS radio will not stay open all the time so the battery will be saved.
  • You will be able to get new location on each 10minutes without messing around with old location or something.

I hope it will be helpful.

Mehul Joisar
  • 15,348
  • 6
  • 48
  • 57
  • actually I thought to do something like that. it might work, but - it's a work-around which I prefer to avoid. – Tal Kanel Oct 12 '14 at 05:02
  • 1
    @TalKanel: AFAIK, it's not work around.it's an alternative approach. you may continue with your current approach when you develop some app specially for navigation maps etc which will be on screen all the time when user use that. if it is not navigation kind of app then AlarmManager is the way to go. – Mehul Joisar Oct 13 '14 at 04:56
  • Connecting every ten minutes to google play services (IPC) to register and request one time location smells like a bad approach. Don't you think so? I might be wrong.. Please inlight me – Tal Kanel Oct 13 '14 at 05:24
  • @TalKanel: You should perform a test run. I guess my approach will be more user friendly and will not drain battery that much as it won't keep GPS radio on 24x7. You will be able to see huge performance difference for sure. Apart from that, If possible, I would insist you to give the user some option to change the frequency of location retrieval. – Mehul Joisar Oct 13 '14 at 05:51
  • I would avoid using this approach to avoid the overhead of `AlarmManager`. Wouldn't it be a separate component addition when we already can set intervals for obtaining the location ? Further, if we do not obtain location(which can happen with moments without line-of-sight for GPS) in that 1 call during 10minutes, there will be a recursive call for location anyway. Can switch between `BALANCED_POWER` and `HIGH_ACCURACY` otherwise, GPS battery consumption may always stay, not sure if the on/off request response would really be effective/optimal when the app runs for longer durations – Pararth Oct 13 '14 at 07:45
  • 1
    @TalKanel, in mehul joisar`s approach, because of using alarm manager, battery consumption increases but it is more reliable, cause if we want to have periodic location updates in the background we may use services but this services may be stopped by android so the only possible option would be to use alarm manger to call one time services periodically. – Mr.Q Jun 10 '16 at 06:30
  • @TalKanel I have done the same, Also you do not need to register to google play services every time , you just have to make one time initialization and registration and make a check if google api is connected and not null before proceeding , other wise first register then proceed. For Marshmallow and above i have used Job Scheduler to awake back end service for getting fused location other wise simple Alarm manager for below versions. – Jamil Jul 10 '17 at 07:11
3

Cell towers cover a several mile area so they aren't the best for getting a location from. Look at the location accuracy when you are working with locations.

@Override
public void onLocationChanged(Location location) {
    //it happens
    if (location == null) {
        return;
    }
    // all locations should have an accuracy
    if (!location.hasAccuracy()) {
        return;
    }
    // if its not accurate enough don't use it
    // this value is in meters
    if (location.getAccuracy() > 200) {
        return;
    }
}

You could put a broadcastreceiver on the network status and when there is no connection you could restart your location provider with priority_high_accuracy which will use the GPS only when the user has the GPS enabled otherwise it falls back on the wifi and cell towers.

<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>

/** Checks whether the device currently has a network connection */

private boolean isDeviceOnline() {
    ConnectivityManager connMgr = (ConnectivityManager) activity
            .getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
    if (networkInfo != null && networkInfo.isConnected()) {
        return true;
    }
    return false;
}
danny117
  • 5,581
  • 1
  • 26
  • 35
0

For updating of the GPS coordinates you can use GPS and WI-FI providers also. For updating of the position use as well minimum distance parameter. I will provide you with small GPS service example.

Answers :

1) PRIORITY_BALANCED_POWER_ACCURACY do not use GPS.

2) Use GPS and WI-FI to detect location.

3) PRIORITY_BALANCED_POWER_ACCURACY probably because of no WI-FI in area.

Code example :

public class GPSservice extends Service implements LocationListener {


    private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 2;

    private static final long MIN_TIME_BW_UPDATES = 1000 * 1;

    double latitude, longitude;

    boolean isGPSEnabled = false;

    boolean isNetworkEnabled = false;

    boolean canGetLocation = false;

    Location location;

    protected LocationManager locationManager;

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }


    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        getLocation();

        return super.onStartCommand(intent, flags, startId);
    }


    @Override
    public void onLocationChanged(Location location) {
        new LocationReceiver(location, getApplicationContext());
    }


    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {

    }

    @Override
    public void onProviderEnabled(String provider) {

    }

    @Override
    public void onProviderDisabled(String provider) {

    }

    public Location getLocation() {
        try {
            locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);

            // getting GPS status
            isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);

            isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

            if (!isGPSEnabled && !isNetworkEnabled) {
                Log.d("Network", "NO network");
            } else {
                this.canGetLocation = true;
                if (isNetworkEnabled) {
                    locationManager.requestLocationUpdates(
                            LocationManager.NETWORK_PROVIDER,
                            MIN_TIME_BW_UPDATES,
                            MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
                    Log.d("Network", "Network");
                    if (locationManager != null) {
                        location = locationManager
                                .getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
                        if (location != null) {
                            latitude = location.getLatitude();
                            longitude = location.getLongitude();
                        }
                    }
                }
                if (isGPSEnabled) {
                    if (location == null) {
                        locationManager.requestLocationUpdates(
                                LocationManager.GPS_PROVIDER,
                                MIN_TIME_BW_UPDATES,
                                MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
                        Log.d("GPS Enabled", "GPS Enabled");
                        if (locationManager != null) {
                            location = locationManager
                                    .getLastKnownLocation(LocationManager.GPS_PROVIDER);
                            if (location != null) {
                                latitude = location.getLatitude();
                                longitude = location.getLongitude();
                            }
                        }
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return location;
    }
}
Community
  • 1
  • 1
Oleg Gordiichuk
  • 15,240
  • 7
  • 60
  • 100
  • "PRIORITY_BALANCED_POWER_ACCURACY do not use GPS" - I don't see in the post you provided any evidence that it's the case. the person there wrote that he only thinks that this is what it means. also, I know I can use explicitly the LocationManager, but I want to use the reccomended location services API's – Tal Kanel Oct 05 '14 at 08:22
  • Make small research by you own, just try to use wifi and gps and see results. – Oleg Gordiichuk Oct 05 '14 at 08:23