8

Just received a Galaxy S7 (Edge) running Marshmallow (6.0.1) and find that it has an issue with my app that uses android.permission.ACCESS_COARSE_LOCATION and targets Sdk Version 22 (Lollipop). When I call locationManager.getLastKnownLocation() it always returns NULL. Here's what I'm running:

public Location getLastKnownLocationObject(Context context) {

    LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);

    try {
        if (locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
            Location location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
            // Location is always null on S7 (only)
            Log.i(TAG, ">>> getLastKnownLocationObject() getLastKnownLocation: " + location);
            return location;
        }

    } catch (Exception e) {
        Log.e(TAG, ">>> getLastKnownLocationObject() exception", e);
    }
    return null;

}

This same code works fine on every other device I've tried: Galaxy S5 (5.0.1), Nexus 7 (5.0.1), Nexus 9 (6.0.1), and Samsung Tab3 (4.4.2)

Note that if I change the manifest to use ACCESS_FINE_LOCATION, the above code works fine on every device. Unfortunately, management won't allow me to change permissions at this time.

In a few answers I've seen here on SO, it's suggested to call the following prior to doing the getLastKnownLocation(), but that didn't have any effect.

locationManager.requestLocationUpdates(
                        LocationManager.NETWORK_PROVIDER, 0, 0, new LocationListener() {
                            @Override
                            public void onStatusChanged(String provider, int status, Bundle extras) {
                            }

                            @Override
                            public void onProviderEnabled(String provider) {
                            }

                            @Override
                            public void onProviderDisabled(String provider) {
                            }

                            @Override
                            public void onLocationChanged(final Location location) {
                                // NEVER CALLED on Samsung S7 for LocationManager.NETWORK_PROVIDER
                            }
                        });

So at the moment, I feel this is an issue exclusive to the new Samsung Galaxy S7.

GaryAmundson
  • 199
  • 9
  • Did you tried requesting permissions programmatically since Marshmallow introduced Runtime permission model ? – Shadab Ansari Mar 15 '16 at 18:10
  • My apps target is 22 (Lollipop). minSdkVersion 19 targetSdkVersion 22 – GaryAmundson Mar 15 '16 at 18:20
  • You have to specifically request for permissions on Android Marshmallow and above. Check this post of mine - http://stackoverflow.com/questions/35856432/asking-for-permissions-while-using-locationmanager/35857017#35857017 – Shadab Ansari Mar 15 '16 at 18:26
  • Thanks Shadab... your post shows GPS_PROVIDER, which if I change my manifest permission to ACCESS_FINE_LOCATION, works fine with my code and without requesting permissions (I'm targeting Lollipop). – GaryAmundson Mar 15 '16 at 18:30
  • 2
    Please try Fused Location Provider api instead, available with Google Play Service Framework. That may help. – Shadab Ansari Mar 15 '16 at 18:41
  • Thanks again Shadab... I compiled the Google sample BasicLocationSample that uses the FuseLocationApi: github.com/googlesamples/android-play-location and it DOES work with the "coarse" permission to properly return last location! So that is a possible solution. We're not a fan of bringing in more of the Google Play Services than necessary as we're always battling dex count, we already use "ads"... just need to add "location"... :) compile 'com.google.android.gms:play-services-location:8.4.0' – GaryAmundson Mar 15 '16 at 21:47
  • Cool. Good to hear that :) – Shadab Ansari Mar 15 '16 at 21:49
  • So adding just the location service from Play Services (compile 'com.google.android.gms:play-services-location:8.4.0') added over 4600 methods to the .apk. That's a pretty big hit to take just to support a Samsung S7 :) – GaryAmundson Mar 15 '16 at 22:18

2 Answers2

3

From my experience with Samsung devices. If you reboot the phone and you DON'T enable GPS you will not get a location. If you enable GPS as some point - maybe by running Google Maps, then you will get a location. Samsung does not return a location for GPS, Network or Passive providers unless it has gotten a location during the devices power on cycle.

None of the calls I have made in code ever get it to kick in and activate and get a location. They work fine on other devices. Samsung does not seem to cache this information for very long either.

Kevin
  • 1,405
  • 15
  • 16
2

Well, you are calling isProviderEnabled() so at least that is covered and using the network location should be enabled. However the exact wording of the documentation is:

"If the user has enabled this provider in the Settings menu, true is returned otherwise false is returned"

So it's just about the provider being "enabled" as in not being turned off by the user.

Does the problematic phone (the S7) have a SIM card inside? It's possible that on that specific device the network based positioning requires a SIM card or internet connection.

Referring to the the documentation you could check what these return:

locationManager.getProvider(LocationManager.NETWORK_PROVIDER).requiresCell();
locationManager.getProvider(LocationManager.NETWORK_PROVIDER).requiresNetwork();

And of course just calling getLastKnownLocation() will return null if the location is unknown. And it's unknown if no application (yours or some other) has specifically requested the device to determine its location. So the suggestion to call requestLocationUpdates() is the correct advice. But it may take a while to determine the location so calling getLastKnownLocation() right after probably still returns null.

And even if it returns something, it might be very old data that's not even valid anymore. So why not just subscribe to receive location updates? That's the way it's intended. You are using network based positioning so it won't (at all/significantly) affect power consumption and the updates won't come too often if you specify time interval and distance limits that suit your needs.

Markus Kauppinen
  • 3,025
  • 4
  • 20
  • 30
  • Thanks for your help... there are now 2 different Galaxy S7's that I've been able to test on, both are fully functional cell phones with Internet access (and are on two different carriers, not that that means anything). I have no issue obtaining GPS coordinates with other apps. And do note that if I change permissions to ACCESS_FINE_LOCATION there isn't any issue. I did try the .requiresCell() and .requiresNetwork() and interestingly they both return True on the S7, but both calls return false on all the other devices I test on. – GaryAmundson Mar 16 '16 at 18:06
  • (and I don't need to subscribe to updates as I just need a rough location for a weather app) – GaryAmundson Mar 16 '16 at 18:07
  • You can of course call `removeUpdates()` once you have received the fresh and up-to-date location in the `onLocationChanged()` callback and you won't then receive further updates. That would be the solution for cases when `getLastKnownLocation()` returns null. – Markus Kauppinen Mar 18 '16 at 08:08
  • Actually our code does as you suggest and does request location updates if last known location would ever happen to be null (which we have never actually seen until the S7). The problem I'm seeing with this is that onLocationChanged() is never fired on the **S7** when requesting location from NETWORK_PROVIDER. `locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, mLocationListener);` This is with the manifest permission for ACCESS_COARSE_LOCATION. If I do change it to ACCESS_FINE_LOCATION, that code works as expected. – GaryAmundson Mar 18 '16 at 23:12