Android Network Locates: When Enabled is NOT Enabled

The Network Location Provider is a key part of an Android location-based solution because it is far more power efficient than GPS and works in places where GPS doesn’t (of course GPS works in places the Network Location Provider doesn’t so it’s often good to use both).

The Network Location Provider capitalizes on the Wi-Fi and cellular radios within your phone to estimate location. This, of course, means that the Network Location Provide only works when those radios are working … and this is where we can easily run into trouble.

Prior to using a location provider, it’s always a good idea to confirm that the user hasn’t disabled it. According the Android docs, the code in the following function checks that the Network Location Provider is enabled.

  // Check that Network Location Provider reports enabled
  boolen isNetLocEnabled(Context context) {
    LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
    return lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
  }

What that code actually checks is whether the user has the Location Service enabled … basically … is the following box checked in the device settings?

LocationSettings_251x397

But what that code does not check is whether the phone’s Wi-Fi radio is turned on or if the phone is in Airplane mode …. that’s these device settings …

WiFiSettings

AirplaneSettings

If the user disables Wi-Fi, the Network Location Provider can no longer use the Wi-Fi system and will be limited to cellular towers for locates. Using cellular towers generally provides very limited accuracy (in the area of 1 to 3 kilometers … not accurate enough for most systems).

If the user puts the phone in Airplane mode, neither Wi-Fi nor the cellular radio are available .. in this case, the Network Location Provider will simply never report any location values.

And here’s the problem – in both of these cases, LocationManager.isProviderEnabled will still report that the Network Location Provider is enabled. This is a false positive.

To safely use the Network Location Provider, we need to explicitly check the Wi-Fi and Airplane Mode, settings. The following code shows how we can check those.

  // Check Wi-Fi is on
  boolean confirmWiFiAvailable(Context context) {
    ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo wifiInfo = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
    return wifiInfo.isAvailable();
  }

  // Check Airplane Mode - we want airplane mode off
  boolean confirmAirplaneModeOff(Context context) {
    int airplaneSetting =
      Settings.System.getInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) ;
    return airplaneSetting == 0;
  }

Using the above 2 functions along with the isNetLocEnabled function from earlier in this post, we can now use the following function to determine if the Network Location Provider is really usable.

  bool isNetLocUsable(Context context) {
    return
      isNetLocEnabled(context) &&
      confirmAirplaneModeOff(context) &&
      confirmWiFiAvailable(context);
  }

With that, we can now be sure that the Network Location Provider is enabled and the underlying services it relies upon are also available.

For complete certainty, in addition to checking the Wi-Fi and Airplane Mode settings prior to using the Network Location Provider, we should also continuously monitor the Wi-Fi and Airplane Mode settings (notification mechanisms exist for each) the entire time we’re using the Network Location Provider. Doing so allows our application to respond accordingly should the user change either setting while we’re using the Network Location Provider.

This post is adapted from Jim’s Plurasight Course

AndroidLBS_436x155

For more information about Jim and his courses visit his Pluralsight Author Page

Advertisements

15 thoughts on “Android Network Locates: When Enabled is NOT Enabled

  1. Great post, some findings below:

    Need to add :
    import android.content.Context;
    import android.location.LocationManager;

    Typo in the code to check location provider :
    change boolen to boolean.

  2. What if the phone is searching for network constantly because no signal?, Ie, no mobile signal network available. the wifi is off and airplane mode disabled, and the method “isProviderEnabled(LocationManager.NETWORK_PROVIDER)” still tell that this network mobile provider is enabled. ¿what do you do? sorry by my bad english

  3. Hi Yeferson … no worries on your english … it looks good to me.

    In the scenario you describe, isProviderEnabled should still return true .. That method (isProviderEnabled) simply indicates whether the provider is on, not whether it’s reliable.

    What would probably happen is that you would get either very low-accuracy results or old results.

    In most cases where one is not able to get a phone signal it means that you are out in the middle of nowhere which is when a GPS provider is preferable.

    So if you find that the network provider is returning old results or results with poor accuracy you’ll want to start the GPS provider and start using it instead.

    Something you might want to consider is using the Google Play Services location system (something that Google released after I wrote the above post). It takes care of these kinds of scenarios in terms of switching between the network and gps providers, etc.

    The following link will take you to a page that walks through its usage…
    http://developer.android.com/training/location/retrieve-current.html

    I hope that helps,
    Jim

    • Thanks for the prompt reply. I read on the possibility of obtaining the location with google play services, but in my country, the most android devices use 2.2 version so that the minimum target, and the device I use for testing, does not allow me to use the services of google because it asked me upgrade the apk of google play, but still does not allow me to use google services play because is incompatble.

      however, your post help me to improve the app development

      best regards

  4. Pingback: Dealing with Spotty Network Coverage in Xamarin | hedgehogjim

    • If both GPS and network locates are disabled, you can’t get the location.

      Google’s desire is to provide the user with the ability to control whether apps can get the device location. When both of those options are disabled, the user is telling us that they don’t want our apps to get their location.

  5. i need to know how to restrict user can disable the location service.if the user disabled means how to send information to server.the particular user are turned off his gps.

    • There’s no way to actually prevent a user from disabling location services. Google’s attitude is that it’s the user’s phone and the user therefore has authority over the settings. 🙂

      In terms of being notified when the service is disabled …
      I have not had to do this myself but you should be able to achieve the desired result with the FusedLocationProviderAPI. Using that API you can register a PendingIntent (directed to a service, for example) that will fire when there’s a change in Location Availability. The corresponding Intent will contain an instance of the LocationAvailability class which you can then use to check whether location is currently available.

      If the location is not available, you can then check the current device settings to make a determination as to whether the lack of location availability is due to the current device settings. If it is due to the settings, you can then send a message to the server indicating the change.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s