androidgoogle-mapsandroid-volleygoogle-places

Getting com.android.volley.TimeoutError when trying to access PlacesClient.findCurrentPlace()


I need to access PlacesClient.findCurrentPlace() each time I get a location update through FusedLocationProviderClient.requestLocationUpdates(). I decided to do this by enqueing a OneTimeWorkRequest in the BroadcastReceiver that is called by the PendingIntent passed to FusedLocationProviderClient.requestLocationUpdates():

public class LocationReceiver extends BroadcastReceiver {    
    @Override
    public void onReceive(Context context, Intent intent) {
        WorkRequest locationRequest = new OneTimeWorkRequest.Builder(HeartBeatWorker.class)
                .build();
        WorkManager.getInstance(context).enqueue(locationRequest);
    }
}

However, sometimes, the Worker's doWork gets the com.android.volley.TimeoutError from the Task<FindCurrentPlaceResponse> returned by the Places SDK call:

@Override
public Result doWork() {            
    // Initialize the SDK
    Places.initialize(getApplicationContext(), "<my API key>");

    // Create a new Places client instance
    PlacesClient placesClient = Places.createClient(getApplicationContext());

    // Use fields to define the data types to return.
    List<Place.Field> placeFields = new ArrayList<>();
    placeFields.add(Place.Field.NAME);
    placeFields.add(Place.Field.TYPES);

    // Use the builder to create a FindCurrentPlaceRequest.
    FindCurrentPlaceRequest request = FindCurrentPlaceRequest.newInstance(placeFields);

    if (ContextCompat.checkSelfPermission(getApplicationContext(),
        Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {

        // Call Places SDK to get current PlaceLikelihoods
        Task<FindCurrentPlaceResponse> placeResponse =
                              placesClient.findCurrentPlace(request);

        placeResponse.addOnCompleteListener(new OnCompleteListener<FindCurrentPlaceResponse>() {
            @Override
            public void onComplete(@NonNull Task<FindCurrentPlaceResponse> task) {
                if (task.isSuccessful()) {
                    ...
                } else {
                    // sometimes I fall here, with status code 15.
                    // Looking into it, the error turns out to be:
                    // com.android.volley.TimeoutError
                    Exception exception = task.getException();
                    if (exception instanceof ApiException) {
                        ApiException apiException = (ApiException) exception;
                        Log.d(MainActivity.LOG_TAG, "HeartBeatWorker: Place not found: " + apiException.getStatusCode());
                    }
                }
            }
        });
    } else {
        Log.d(MainActivity.LOG_TAG, "HeartBeatWorker: No ACCESS_FINE_LOCATION permission: HeartBeatWorker returning");
    }
    return Result.success();
}

I'm aware that Android enacts relevant power management restrictions that could cause the network (presumably needed by the Places SDK call) to be unavailable. However I get the error even when the app is not in Doze mode and it is still in App Standby Bucket = 10 (i.e. Active) and should not have any network restrictions. What could be the cause of the error, then?


Solution

  • I found the answer here:

    A short time after the screen turns off while the device is on battery, Doze restricts network access and defers jobs and syncs.

    I overlooked this, as it is not explicitly mentioned on the main Doze guide in the documentation, which still insists that the device should also be stationary to enter Doze:

    If a user leaves a device unplugged and stationary for a period of time, with the screen off, the device enters Doze mode.