@Override
 public double calculateDistance(int txPower, double rssi) {
   if (mDistanceCalculator == null) {
     LogManager.w(TAG, "distance calculator has not been set");
     return -1.0;
   }
   return mDistanceCalculator.calculateDistance(txPower, rssi);
 }
  @TargetApi(Build.VERSION_CODES.HONEYCOMB)
  private void requestModelMapFromWeb() {

    if (mContext.checkCallingOrSelfPermission("android.permission.INTERNET")
        != PackageManager.PERMISSION_GRANTED) {
      LogManager.w(
          TAG,
          "App has no android.permission.INTERNET permission.  Cannot check for distance model updates");
      return;
    }

    new ModelSpecificDistanceUpdater(
            mContext,
            mRemoteUpdateUrlString,
            new ModelSpecificDistanceUpdater.CompletionHandler() {
              @Override
              public void onComplete(String body, Exception ex, int code) {
                if (ex != null) {
                  LogManager.w(
                      TAG,
                      "Cannot updated distance models from online database at %s",
                      ex,
                      mRemoteUpdateUrlString);
                } else if (code != 200) {
                  LogManager.w(
                      TAG,
                      "Cannot updated distance models from online database at %s "
                          + "due to HTTP status code %s",
                      mRemoteUpdateUrlString,
                      code);
                } else {
                  LogManager.d(TAG, "Successfully downloaded distance models from online database");
                  try {
                    buildModelMap(body);
                    if (saveJson(body)) {
                      loadModelMapFromFile();
                      mDistanceCalculator = findCalculatorForModel(mRequestedModel);
                      LogManager.i(
                          TAG,
                          "Successfully updated distance model with latest from online database");
                    }
                  } catch (JSONException e) {
                    LogManager.w(e, TAG, "Cannot parse json from downloaded distance model");
                  }
                }
              }
            })
        .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
  }
  private boolean saveJson(String jsonString) {

    FileOutputStream outputStream = null;

    try {
      outputStream = mContext.openFileOutput(CONFIG_FILE, Context.MODE_PRIVATE);
      outputStream.write(jsonString.getBytes());
      outputStream.close();
    } catch (Exception e) {
      LogManager.w(e, TAG, "Cannot write updated distance model to local storage");
      return false;
    } finally {
      try {
        if (outputStream != null) outputStream.close();
      } catch (Exception e) {
      }
    }
    LogManager.i(TAG, "Successfully saved new distance model file");
    return true;
  }
  private DistanceCalculator findCalculatorForModel(AndroidModel model) {
    LogManager.d(
        TAG,
        "Finding best distance calculator for %s, %s, %s, %s",
        model.getVersion(),
        model.getBuildNumber(),
        model.getModel(),
        model.getManufacturer());

    if (mModelMap == null) {
      LogManager.d(TAG, "Cannot get distance calculator because modelMap was never initialized");
      return null;
    }

    int highestScore = 0;
    AndroidModel bestMatchingModel = null;
    for (AndroidModel candidateModel : mModelMap.keySet()) {
      if (candidateModel.matchScore(model) > highestScore) {
        highestScore = candidateModel.matchScore(model);
        bestMatchingModel = candidateModel;
      }
    }
    if (bestMatchingModel != null) {
      LogManager.d(TAG, "found a match with score %s", highestScore);
      LogManager.d(
          TAG,
          "Finding best distance calculator for %s, %s, %s, %s",
          bestMatchingModel.getVersion(),
          bestMatchingModel.getBuildNumber(),
          bestMatchingModel.getModel(),
          bestMatchingModel.getManufacturer());
      mModel = bestMatchingModel;
    } else {
      mModel = mDefaultModel;
      LogManager.w(TAG, "Cannot find match for this device.  Using default");
    }
    return mModelMap.get(mModel);
  }