@Override
    void updateLatLng(@NonNull Location location) {
      if (latLng == null) {
        // first location fix
        latLng = new LatLng(location);
        locationUpdateTimestamp = SystemClock.elapsedRealtime();
      }

      // updateLatLng timestamp
      long previousUpdateTimeStamp = locationUpdateTimestamp;
      locationUpdateTimestamp = SystemClock.elapsedRealtime();

      // calculate animation duration
      long locationUpdateDuration;
      if (previousUpdateTimeStamp == 0) {
        locationUpdateDuration = 0;
      } else {
        // TODO remove 10 * hack to multiply duration to workaround easing interpolation
        // (easeCamera)
        locationUpdateDuration = 10 * (locationUpdateTimestamp - previousUpdateTimeStamp);
      }

      // calculate interpolated location
      previousLocation = latLng;
      latLng = new LatLng(location);
      interpolatedLocation =
          new LatLng(
              (latLng.getLatitude() + previousLocation.getLatitude()) / 2,
              (latLng.getLongitude() + previousLocation.getLongitude()) / 2);

      // build new camera
      CameraPosition.Builder builder = new CameraPosition.Builder().target(interpolatedLocation);

      // add direction
      if (myBearingTrackingMode == MyBearingTracking.GPS) {
        if (location.hasBearing()) {
          builder.bearing(location.getBearing());
          gpsDirection = 0;
        }
      } else if (myBearingTrackingMode == MyBearingTracking.COMPASS) {
        if (!compassListener.isPaused()) {
          builder.bearing(compassListener.getCurrentDegree());
          compassDirection = 0;
        }
      }

      updateAccuracy(location);

      // animate to new camera
      mapboxMap.easeCamera(
          CameraUpdateFactory.newCameraPosition(builder.build()),
          (int) locationUpdateDuration,
          null);
    }