getCurrentPositionAsync wait forever

Hi, I’m having a problem trying to get GPS positions.
I’m using the following method, which causes to wait forever for the GPS fix.

Expo.Location.getCurrentPositionAsync({
  enableHighAccuracy: true
})

I’m testing on Android 6.0.1 and my device is a Samsung S5 without SIM, location services enabled, also I’m under roof.

I think the correct behavior should be to timeout if no GPS fix can be obtained after some amount of time.

I’m trying to implement a timeout myself, here’s the code:

import { Platform } from 'react-native';
import Expo from 'expo';
import Settings from '../config/settings'
import Sentry from 'sentry-expo';

export default {
  async get() {
    let location;
    if (Platform.OS === 'android' && !Expo.Constants.isDevice) {
      if (__DEV__) {
        console.log('[Location] No location when running on virtual device');
      }
    } else {
      const { status } = await Expo.Permissions.askAsync(Expo.Permissions.LOCATION);
      const { locationServicesEnabled } = await Expo.Location.getProviderStatusAsync();
      if (status === 'granted' && locationServicesEnabled) {
        // resolves or rejects as soon as one
        await Promise.race([
          Expo.Location.getCurrentPositionAsync({
            enableHighAccuracy: true
          }),
          new Promise((resolve, reject) => {
            setTimeout(reject, Settings.GPS_TIMEOUT);
          }),
        ]).then(result => {
          location = result;
          if (__DEV__) {
            console.log('[Location] Found', location);
          }
        })
        .catch(error => {
          if (__DEV__) {
            console.log('[Location] Timed out', Settings.GPS_TIMEOUT);
          }
          Sentry.captureMessage('Location timed out', {
            level: 'warning',
          });
        });
      } else {
        if (__DEV__) {
          console.log('[Location] Unavailable', status, locationServicesEnabled);
        }
        Sentry.captureMessage('Location unavailable', {
          level: 'warning',
          extra: {
            permission_status: status,
            location_services: locationServicesEnabled,
          }
        });
      }
    }
    return location;
  }
}

Does your current code work as intended?

Hi Edgar, the code is working as intended, but I think it would be nice that Expo.Location.getCurrentPositionAsync method could take a timeout parameter (or at least handle the case internally) to avoid to wait forever in case the GPS can’t provide a position.

@outatime – there is actually a timeout parameter that is only used on Android (on iOS) it’s ignored. This isn’t documented because of the platform difference. This could work for you?

1 Like

Hi @nikki, sorry for delay … it works for me but im leave the code as is for better handling in both os, thanks !!!

[ANDROID]

Hi guys, is there any way to stop getCurrentPositionAsync while in progress?
I am using the timeout solution (Promise.race) given by OP, but unfortunately if position can’t be obtained it will look for it forever. Navigating away does not help.
The location marker symbol in the status bar will appear and stay there indefinitely (or at least until a fix is obtained).
I also tried the timeout parameter in options but it’s still the same - looking for a fix even though it times out.

Thanks in advance!

@nikki please have a look at this. I hope you find it useful. It seems to me ‘timeout’ must be mentioned as a required parameter for getCurrentPostionAsync in docs
or
prepareLocationRequest in LocationHelpers.java should call setExpirationDuration(long) or setExpirationTime(long) as per google’s LocationRequest docs

com.google.android.gms.location.LocationRequest please find its documentation as i am limited to 2 links only on comments. i have copied just a paragraph for reference.
" When using this(setNumUpdates) option care must be taken to either explicitly remove the request when no longer needed or to set an expiration with (setExpirationDuration(long) or setExpirationTime(long). Otherwise in some cases if a location can’t be computed, this request could stay active indefinitely consuming power. "

LocationModule.java

 @ExpoMethod
  public void getCurrentPositionAsync(final Map<String, Object> options, final Promise promise) {
    // Read options
    final Long timeout = options.containsKey("timeout") ? ((Double) options.get("timeout")).longValue() : null;
    final LocationRequest locationRequest = LocationHelpers.prepareLocationRequest(options);
    ...
    ...
static void requestSingleLocation(final LocationModule locationModule, final LocationRequest locationRequest, final TimeoutObject timeoutObject, final Promise promise) {
    // we want just one update
    locationRequest.setNumUpdates(1);
   ....
   ....

LocationHelpers.java

 public static LocationRequest prepareLocationRequest(Map<String, Object> options) {
    LocationParams locationParams = LocationHelpers.mapOptionsToLocationParams(options);
    int accuracy = LocationHelpers.getAccuracyFromOptions(options);

    return new LocationRequest()
       .setFastestInterval(locationParams.getInterval())
       .setInterval(locationParams.getInterval())
       .setMaxWaitTime(locationParams.getInterval())
       .setSmallestDisplacement(locationParams.getDistance())
       .setPriority(mapAccuracyToPriority(accuracy));
 }