JacksOnF1re
JacksOnF1re

Reputation: 3512

Android LocationServices.checkLocationSettings false negative result

Affected devices so far:

Use: In order to request location updates, I check that the location settings are adequate beforehand. If not, I show a small text, that the services must be enabled for my feature. If the user clicks on it, the system dialog to enable the location service will be prompted.

How I run the check: I run the check through LocationSettingsRequest and LocationServices and handle the ResolvableApiException. If the Service is disabled by the user, then on all my devices this will show the System Dialog, asking the user to enable the service (and enables it, if okay is clicked).

What happens instead on Redmi: But for whatever reason, on Xiamoi Redmi Note 7, the checkLocationSettings will always return with an ResolvableApiException, even if the service is already enabled. The Dialog won't appear and directly return a positive result (sure, because the service is enabled). Hence, the user is stuck and clicks forever on "enable".

Does somebody has any information why the LocationSettingsRequest is not working properly on those devices and knows how to fix it?

Example Code snippet

void enableLocationSettings(onLocationServiceRequiredCallback: ICallback) {
   LocationRequest locationRequest = LocationRequest.create()
         .setInterval(LOCATION_UPDATE_INTERVAL)
         .setExpirationDuration(LOCATION_UPDATE_EXPIRATION_DURATION)
         .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

    LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
            .addLocationRequest(locationRequest);

    LocationServices
            .getSettingsClient(this)
            .checkLocationSettings(builder.build())
            .addOnSuccessListener(this, (LocationSettingsResponse response) -> {
                // update location as usual
            })
            .addOnFailureListener(this, error -> {
                if (error instanceOf ApiException) {
                    int statusCode = error.statusCode;
                    if(statusCode == LocationSettingsStatusCodes.RESOLUTION_REQUIRED) {
                        if(error instanceOf ResolvableApiException) {
                            PendingIntent resolution = error.resolution 
             // This will trigger the system dialog, see below
                            onLocationServiceRequiredCallback(resolution);
                        }
                    }
                }
                // error callback
            });  

 

Unfortunately the code for the callback will now be kotlin. Sorry for that. I can only post "example code snippets", since this is work related.

It uses ActivityResultContracts.StartIntentSenderForResult to start the system dialog.

resolution is the PendingIntent from above.

The contract:

private val locationServiceContract = registerForActivityResult(
    ActivityResultContracts.StartIntentSenderForResult()
) { activityResult ->
    lifecycleScope.launchWhenResumed {
        val result = if (activityResult.resultCode == Activity.RESULT_OK) {
            // This will retrigger the location fetch (looping)
            enableLocationSettings(...) 
        } else {
            // Do nothing
        }
    }
}

After the callback from above is called, this will get executed:

        locationServiceContract.launch(
            IntentSenderRequest.Builder(
                resolution
            ).build()
        )

Dump of LocationSettingsStates, aquired using the deprecated LocationSettings API (which is using GoogleApiClient):

isGpsPresent: true, 
isGpsUsable: false, 
isLocationPresent: true, 
isLocationUsable: true, 
isNetworkLocationPresent: true, 
isNetworkLocationUsable: true 

Upvotes: 3

Views: 1124

Answers (2)

AgentP
AgentP

Reputation: 7230

After doing a good amount of research I got a solution for this ...

The problem is basically, if the LocationSettingsStatusCodes.RESOLUTION_REQUIRED == true then the next consecutive call you make will always result in the same output

i.e if you are calling this function recursively you will get RESOLUTION_REQUIRED always so what you can do is modify your contract to something like this

private val locationServiceContract = registerForActivityResult(
    ActivityResultContracts.StartIntentSenderForResult()
) { activityResult ->
    lifecycleScope.launchWhenResumed {
        val result = if (activityResult.resultCode == Activity.RESULT_OK) {
            // Dont call this as it will retrigger the location fetch (looping)
           // enableLocationSettings(...) 
               requestForLocationUpdates() // create this method see method body below
              
        } else {
            // Do nothing
        }
    }
}

requestForLocationUpdates()

 private fun requestForLocationUpdates() {

          locationCallback = object : LocationCallback() {
               override fun onLocationResult(locationResult: LocationResult) {
                    if (locationResult.locations.size > 0) {
                          // update location as usual using locationResult.locations[0] or other item
                         fusedLocationClient.removeLocationUpdates(locationCallback)
                    }
               }
          }

          fusedLocationClient.requestLocationUpdates(
               locationRequest,
               locationCallback,
               Looper.getMainLooper()
          )
     }

Upvotes: 0

quealegriamasalegre
quealegriamasalegre

Reputation: 3258

Hi I use different code in order to check if GPS is enabled on a device. maybe its worth for you to try it out and see if it resolves your issue.

 private boolean isLocationEnabled(Context context) {
        LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
        return LocationManagerCompat.isLocationEnabled(locationManager);
    }

I then send the user to settings through a dialog using

Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
context.startActivity(intent);

I bet you are doing the same. After sending the user to enable GPS you can just run the method a second time on resume

let me know if this helps

Upvotes: 1

Related Questions