Exemple #1
0
  private static JSONObject request(
      final OCApiConnector connector, final OkapiService service, final Parameters params) {
    if (connector == null) {
      return null;
    }

    final String host = connector.getHost();
    if (StringUtils.isBlank(host)) {
      return null;
    }

    params.add("langpref", getPreferredLanguage());

    if (connector.getSupportedAuthLevel() == OAuthLevel.Level3) {
      OAuth.signOAuth(
          host,
          service.methodName,
          "GET",
          false,
          params,
          Settings.getOCDETokenPublic(),
          Settings.getOCDETokenSecret(),
          connector.getCK(),
          connector.getCS());
    } else {
      connector.addAuthentication(params);
    }

    final String uri = "http://" + host + service.methodName;
    return Network.requestJSON(uri, params);
  }
Exemple #2
0
    @Override
    public void run() {
      if (app == null) {
        return;
      }
      if (cleanupRunning) {
        return;
      }

      boolean more = false;
      if (version != Settings.getVersion()) {
        Log.i(
            "Initializing hard cleanup - version changed from "
                + Settings.getVersion()
                + " to "
                + version
                + ".");

        more = true;
      }

      cleanupRunning = true;
      DataStore.clean(more);
      cleanupRunning = false;

      if (version > 0) {
        Settings.setVersion(version);
      }
    }
Exemple #3
0
  @Override
  public void onCreate() {
    try {
      final ViewConfiguration config = ViewConfiguration.get(this);
      final Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
      menuKeyField.setAccessible(true);
      menuKeyField.setBoolean(config, false);
    } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException ignored) {
    }

    // Set language to English if the user decided so.
    initApplicationLocale(Settings.useEnglish());

    // ensure initialization of lists
    DataStore.getLists();

    // Check if Google Play services is available
    if (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this)
        == ConnectionResult.SUCCESS) {
      isGooglePlayServicesAvailable = true;
    }
    Log.i(
        "Google Play services are " + (isGooglePlayServicesAvailable ? "" : "not ") + "available");
    final Sensors sensors = Sensors.getInstance();
    sensors.setupGeoDataObservables(Settings.useGooglePlayServices(), Settings.useLowPowerMode());
    sensors.setupDirectionObservable(Settings.useLowPowerMode());

    // Attempt to acquire an initial location before any real activity happens.
    sensors
        .geoDataObservable(true)
        .subscribeOn(RxUtils.looperCallbacksScheduler)
        .first()
        .subscribe();
  }
Exemple #4
0
 private void updateTweetBox(final LogType type) {
   if (type == LogType.FOUND_IT && Settings.isUseTwitter() && Settings.isTwitterLoginValid()) {
     tweetCheck.setVisibility(View.VISIBLE);
   } else {
     tweetCheck.setVisibility(View.GONE);
   }
 }
 @NonNull
 private static App getDefaultNavigationApplication(final int defaultNavigation) {
   if (defaultNavigation == 2) {
     return getNavigationAppForId(Settings.getDefaultNavigationTool2());
   }
   return getNavigationAppForId(Settings.getDefaultNavigationTool());
 }
  public static void testDownloadStaticMaps() {
    final double lat = 52.354176d;
    final double lon = 9.745685d;
    String geocode = "GCTEST1";

    boolean backupStore = Settings.isStoreOfflineMaps();
    boolean backupStoreWP = Settings.isStoreOfflineWpMaps();
    TestSettings.setStoreOfflineMaps(true);
    TestSettings.setStoreOfflineWpMaps(true);
    try {
      Geopoint gp = new Geopoint(lat + 0.25d, lon + 0.25d);
      Geocache cache = new Geocache();
      cache.setGeocode(geocode);
      cache.setCoords(gp);
      cache.setCacheId(String.valueOf(1));

      Waypoint theFinal = new Waypoint("Final", WaypointType.FINAL, false);
      Geopoint finalGp = new Geopoint(lat + 0.25d + 1, lon + 0.25d + 1);
      theFinal.setCoords(finalGp);
      theFinal.setId(1);
      cache.addOrChangeWaypoint(theFinal, false);

      Waypoint trailhead = new Waypoint("Trail head", WaypointType.TRAILHEAD, false);
      Geopoint trailheadGp = new Geopoint(lat + 0.25d + 2, lon + 0.25d + 2);
      trailhead.setCoords(trailheadGp);
      trailhead.setId(2);
      cache.addOrChangeWaypoint(trailhead, false);

      // make sure we don't have stale downloads
      deleteCacheDirectory(geocode);
      assertThat(StaticMapsProvider.hasStaticMap(cache)).isFalse();
      assertThat(StaticMapsProvider.hasStaticMapForWaypoint(geocode, theFinal)).isFalse();
      assertThat(StaticMapsProvider.hasStaticMapForWaypoint(geocode, trailhead)).isFalse();

      // download
      StaticMapsProvider.downloadMaps(cache).await();

      try {
        Thread.sleep(10000);
      } catch (InterruptedException e) {
        fail();
      }

      // check download
      assertThat(StaticMapsProvider.hasStaticMap(cache)).isTrue();
      assertThat(StaticMapsProvider.hasStaticMapForWaypoint(geocode, theFinal)).isTrue();
      assertThat(StaticMapsProvider.hasStaticMapForWaypoint(geocode, trailhead)).isTrue();

      // waypoint static maps hashcode dependent
      trailhead.setCoords(new Geopoint(lat + 0.24d + 2, lon + 0.25d + 2));
      assertThat(StaticMapsProvider.hasStaticMapForWaypoint(geocode, trailhead)).isFalse();
    } finally {
      TestSettings.setStoreOfflineWpMaps(backupStoreWP);
      TestSettings.setStoreOfflineMaps(backupStore);
      deleteCacheDirectory(geocode);
    }
  }
Exemple #7
0
 private void checkShowChangelog() {
   final long lastChecksum = Settings.getLastChangelogChecksum();
   final long checksum =
       TextUtils.checksum(
           getString(R.string.changelog_master) + getString(R.string.changelog_release));
   Settings.setLastChangelogChecksum(checksum);
   // don't show change log after new install...
   if (lastChecksum > 0 && lastChecksum != checksum) {
     AboutActivity.showChangeLog(this);
   }
 }
Exemple #8
0
 private static void addFilterParams(
     final Map<String, String> valueMap, final OCApiConnector connector) {
   if (!Settings.isExcludeDisabledCaches()) {
     valueMap.put("status", "Available|Temporarily unavailable");
   }
   if (Settings.isExcludeMyCaches() && connector.getSupportedAuthLevel() == OAuthLevel.Level3) {
     valueMap.put("exclude_my_own", "true");
     valueMap.put("found_status", "notfound_only");
   }
   if (Settings.getCacheType() != CacheType.ALL) {
     valueMap.put("type", getFilterFromType(Settings.getCacheType()));
   }
 }
Exemple #9
0
 private void loadLogFromDatabase() {
   final LogEntry log = DataStore.loadLogOffline(geocode);
   if (log != null) {
     typeSelected = log.getType();
     date.setTime(new Date(log.date));
     text = log.log;
   } else if (StringUtils.isNotBlank(Settings.getSignature())
       && Settings.isAutoInsertSignature()
       && StringUtils.isBlank(currentLogText())) {
     insertIntoLog(
         LogTemplateProvider.applyTemplates(Settings.getSignature(), new LogContext(cache, null)),
         false);
   }
 }
 @Override
 protected void setTokens(String tokenPublic, String tokenSecret, boolean enable) {
   Settings.setTokens(
       authParams.getTokenPublicPrefKey(),
       tokenPublic,
       authParams.getTokenSecretPrefKey(),
       tokenSecret);
   if (tokenPublic != null) {
     Settings.setTokens(
         authParams.getTempTokenPublicPrefKey(),
         null,
         authParams.getTempTokenSecretPrefKey(),
         null);
   }
 }
Exemple #11
0
  /**
   * Get user ratings from gcvote.com
   *
   * @param guids
   * @param geocodes
   * @return
   */
  @NonNull
  private static Map<String, GCVoteRating> getRating(
      final List<String> guids, final List<String> geocodes) {
    if (guids == null && geocodes == null) {
      return Collections.emptyMap();
    }

    final Parameters params = new Parameters("version", "cgeo");
    final ImmutablePair<String, String> login = Settings.getGCvoteLogin();
    if (login != null) {
      params.put("userName", login.left, "password", login.right);
    }

    // use guid or gccode for lookup
    final boolean requestByGuids = CollectionUtils.isNotEmpty(guids);
    if (requestByGuids) {
      params.put("cacheIds", StringUtils.join(guids, ','));
    } else {
      params.put("waypoints", StringUtils.join(geocodes, ','));
    }
    final InputStream response =
        Network.getResponseStream(Network.getRequest("http://gcvote.com/getVotes.php", params));
    if (response == null) {
      return Collections.emptyMap();
    }
    try {
      return getRatingsFromXMLResponse(response, requestByGuids);
    } finally {
      IOUtils.closeQuietly(response);
    }
  }
Exemple #12
0
  public static void loadRatings(final @NonNull ArrayList<Geocache> caches) {
    if (!Settings.isRatingWanted()) {
      return;
    }

    final ArrayList<String> geocodes = getVotableGeocodes(caches);
    if (geocodes.isEmpty()) {
      return;
    }

    try {
      final Map<String, GCVoteRating> ratings = GCVote.getRating(null, geocodes);

      // save found cache coordinates
      for (Geocache cache : caches) {
        if (ratings.containsKey(cache.getGeocode())) {
          GCVoteRating rating = ratings.get(cache.getGeocode());

          cache.setRating(rating.getRating());
          cache.setVotes(rating.getVotes());
          cache.setMyVote(rating.getMyVote());
        }
      }
    } catch (Exception e) {
      Log.e("GCvote.loadRatings", e);
    }
  }
Exemple #13
0
  /**
   * Transmit user vote to gcvote.com
   *
   * @param cache
   * @param vote
   * @return {@code true} if the rating was submitted successfully
   */
  public static boolean setRating(final Geocache cache, final float vote) {
    if (!isVotingPossible(cache)) {
      return false;
    }
    if (!isValidRating(vote)) {
      return false;
    }

    final ImmutablePair<String, String> login = Settings.getGCvoteLogin();
    if (login == null) {
      return false;
    }

    final Parameters params =
        new Parameters(
            "userName",
            login.left,
            "password",
            login.right,
            "cacheId",
            cache.getGuid(),
            "voteUser",
            String.format("%.1f", vote).replace(',', '.'),
            "version",
            "cgeo");

    final String result =
        Network.getResponseData(Network.getRequest("http://gcvote.com/setVote.php", params));

    return result != null && result.trim().equalsIgnoreCase("ok");
  }
Exemple #14
0
 public static int getDialogTheme() {
   // Light theme dialogs don't work on Android Api < 11
   if (Settings.isLightSkin() && VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
     return R.style.popup_light;
   }
   return R.style.popup_dark;
 }
Exemple #15
0
  private static List<Geocache> requestCaches(
      final OCApiConnector connector,
      final Parameters params,
      final Map<String, String> valueMap,
      final boolean my) {
    // if a global type filter is set, and OKAPI does not know that type, then return an empty list
    // instead of all caches
    if (Settings.getCacheType() != CacheType.ALL && StringUtils.isBlank(getFilterFromType())) {
      return Collections.emptyList();
    }

    addFilterParams(valueMap, connector, my);
    try {
      params.add("search_params", JsonUtils.writer.writeValueAsString(valueMap));
    } catch (final JsonProcessingException e) {
      Log.e("requestCaches", e);
      return Collections.emptyList();
    }
    addRetrieveParams(params, connector);

    final ObjectNode data =
        request(connector, OkapiService.SERVICE_SEARCH_AND_RETRIEVE, params).data;

    if (data == null) {
      return Collections.emptyList();
    }

    return parseCaches(data);
  }
Exemple #16
0
 private void initializeTrackablesAction() {
   if (Settings.isTrackableAutoVisit()) {
     for (final TrackableLog trackable : trackables) {
       trackable.action = LogTypeTrackable.VISITED;
     }
   }
 }
 /*
  * (non-Javadoc)
  *
  * @see cgeo.geocaching.test.mock.MockedCache#isOwn()
  */
 @Override
 public boolean isOwner() {
   if ("Tom03".equals(Settings.getUserName())) {
     return true;
   }
   return super.isOwner();
 }
  @Override
  public OAuthLevel getSupportedAuthLevel() {

    if (Settings.hasOCAuthorization(tokenPublicPrefKeyId, tokenSecretPrefKeyId)) {
      return OAuthLevel.Level3;
    }
    return OAuthLevel.Level1;
  }
 @Override
 protected void setTempTokens(String tokenPublic, String tokenSecret) {
   Settings.setTokens(
       authParams.getTempTokenPublicPrefKey(),
       tokenPublic,
       authParams.getTempTokenSecretPrefKey(),
       tokenSecret);
 }
  /**
   * Specialized way to handle selection of navigation tool.<br>
   * A dialog is created for tool selection and the selected tool is started afterwards.
   *
   * @param cache may be <code>null</code>
   * @param waypoint may be <code>null</code>
   * @param destination may be <code>null</code>
   * @param showInternalMap should be <code>false</code> only when called from within the internal
   *     map
   * @param showDefaultNavigation should be <code>false</code> by default
   * @see #showNavigationMenu(Activity, cgeo.geocaching.Geocache, cgeo.geocaching.Waypoint,
   *     Geopoint)
   */
  public static void showNavigationMenu(
      final Activity activity,
      final Geocache cache,
      final Waypoint waypoint,
      final Geopoint destination,
      final boolean showInternalMap,
      final boolean showDefaultNavigation) {
    final List<NavigationAppsEnum> items = new ArrayList<>();
    final int defaultNavigationTool = Settings.getDefaultNavigationTool();
    for (final NavigationAppsEnum navApp : getActiveNavigationApps()) {
      if ((showInternalMap || !(navApp.app instanceof InternalMap))
          && (showDefaultNavigation || defaultNavigationTool != navApp.id)) {
        boolean add = false;
        if (cache != null
            && navApp.app instanceof CacheNavigationApp
            && navApp.app.isEnabled(cache)) {
          add = true;
        }
        if (waypoint != null
            && navApp.app instanceof WaypointNavigationApp
            && ((WaypointNavigationApp) navApp.app).isEnabled(waypoint)) {
          add = true;
        }
        if (destination != null && navApp.app instanceof GeopointNavigationApp) {
          add = true;
        }
        if (add) {
          items.add(navApp);
        }
      }
    }

    if (items.size() == 1) {
      invokeNavigation(activity, cache, waypoint, destination, items.get(0).app);
      return;
    }

    /*
     * Using an ArrayAdapter with list of NavigationAppsEnum items avoids
     * handling between mapping list positions allows us to do dynamic filtering of the list based on use case.
     */
    final ArrayAdapter<NavigationAppsEnum> adapter =
        new ArrayAdapter<>(activity, android.R.layout.select_dialog_item, items);

    final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
    builder.setTitle(R.string.cache_menu_navigate);
    builder.setAdapter(
        adapter,
        new DialogInterface.OnClickListener() {
          @Override
          public void onClick(final DialogInterface dialog, final int item) {
            final NavigationAppsEnum selectedItem = adapter.getItem(item);
            invokeNavigation(activity, cache, waypoint, destination, selectedItem.app);
          }
        });
    final AlertDialog alert = builder.create();
    alert.show();
  }
        @Override
        protected Void doInBackground(final Void... params) {
          final Waypoint waypoint = new Waypoint(name, type, own);
          waypoint.setGeocode(geocode);
          waypoint.setPrefix(prefix);
          waypoint.setLookup(lookup);
          waypoint.setCoords(coordsToSave);
          waypoint.setNote(noteText);
          waypoint.setVisited(visited);
          waypoint.setId(waypointId);

          final Geocache cache = DataStore.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS);
          if (cache == null) {
            finishHandler.sendEmptyMessage(SAVE_ERROR);
            return null;
          }
          final Waypoint oldWaypoint = cache.getWaypointById(waypointId);
          if (cache.addOrChangeWaypoint(waypoint, true)) {
            DataStore.saveCache(cache, EnumSet.of(SaveFlag.DB));
            if (!StaticMapsProvider.hasAllStaticMapsForWaypoint(geocode, waypoint)) {
              StaticMapsProvider.removeWpStaticMaps(oldWaypoint, geocode);
              if (Settings.isStoreOfflineWpMaps()) {
                StaticMapsProvider.storeWaypointStaticMap(cache, waypoint).subscribe();
              }
            }
            if (modifyLocal.isChecked() || modifyBoth.isChecked()) {
              if (!cache.hasUserModifiedCoords()) {
                final Waypoint origWaypoint =
                    new Waypoint(
                        CgeoApplication.getInstance()
                            .getString(R.string.cache_coordinates_original),
                        WaypointType.ORIGINAL,
                        false);
                origWaypoint.setCoords(cache.getCoords());
                cache.addOrChangeWaypoint(origWaypoint, false);
                cache.setUserModifiedCoords(true);
              }
              cache.setCoords(waypoint.getCoords());
              DataStore.saveChangedCache(cache);
            }
            if (modifyBoth.isChecked() && waypoint.getCoords() != null) {
              finishHandler.sendEmptyMessage(UPLOAD_START);

              if (cache.supportsOwnCoordinates()) {
                final boolean result = uploadModifiedCoords(cache, waypoint.getCoords());
                finishHandler.sendEmptyMessage(result ? SUCCESS : UPLOAD_ERROR);
              } else {
                showToast(getString(R.string.waypoint_coordinates_couldnt_be_modified_on_website));
                finishHandler.sendEmptyMessage(UPLOAD_NOT_POSSIBLE);
              }
            } else {
              finishHandler.sendEmptyMessage(SUCCESS);
            }
          } else {
            finishHandler.sendEmptyMessage(SAVE_ERROR);
          }
          return null;
        }
 /** @return all navigation apps, which are installed and activated in the settings */
 static List<NavigationAppsEnum> getActiveNavigationApps() {
   final List<NavigationAppsEnum> activeApps = new ArrayList<>();
   for (final NavigationAppsEnum appEnum : getInstalledNavigationApps()) {
     if (Settings.isUseNavigationApp(appEnum)) {
       activeApps.add(appEnum);
     }
   }
   return activeApps;
 }
Exemple #23
0
 public static void onCreate(final Activity abstractActivity, final boolean keepScreenOn) {
   final Window window = abstractActivity.getWindow();
   if (keepScreenOn) {
     window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
   }
   if (Settings.useHardwareAcceleration()) {
     enableHardwareAcceleration(window);
   }
 }
  public DirectionDrawer(final Geopoint coords) {
    this.destinationCoords = coords;
    this.mapItemFactory = Settings.getMapProvider().getMapItemFactory();

    final DisplayMetrics metrics = new DisplayMetrics();
    final WindowManager windowManager =
        (WindowManager) CgeoApplication.getInstance().getSystemService(Context.WINDOW_SERVICE);
    windowManager.getDefaultDisplay().getMetrics(metrics);

    width = 4f * metrics.density;
  }
  private void download() {
    try {
      showProgress();

      final SearchResult searchResult =
          DataStore.loadCachedInViewport(getViewport(), Settings.getCacheType());

      if (Settings.isGCConnectorActive() && tokens == null) {
        tokens = GCLogin.getInstance().getMapTokens();
        if (StringUtils.isEmpty(tokens.getUserSession())
            || StringUtils.isEmpty(tokens.getSessionToken())) {
          tokens = null;
          // TODO: show missing map token toast
          //                    if (!noMapTokenShowed) {
          //                        ActivityMixin.showToast(activity,
          // res.getString(R.string.map_token_err));
          //                        noMapTokenShowed = true;
          //                    }
        }
      }
      searchResult.addSearchResult(
          ConnectorFactory.searchByViewport(getViewport().resize(1.2), tokens));

      final Set<Geocache> result =
          searchResult.getCachesFromSearchResult(LoadFlags.LOAD_CACHE_OR_DB);
      AbstractCachesOverlay.filter(result);
      // update the caches
      // first remove filtered out
      final Set<String> filteredCodes = searchResult.getFilteredGeocodes();
      Log.d("Filtering out " + filteredCodes.size() + " caches: " + filteredCodes.toString());
      DataStore.removeCaches(filteredCodes, EnumSet.of(RemoveFlag.CACHE));

      Log.d(String.format(Locale.ENGLISH, "Live caches found: %d", result.size()));

      // render
      fill(result);

    } finally {
      hideProgress();
    }
  }
Exemple #26
0
  private void saveLog(final boolean force) {
    final String log = currentLogText();

    // Do not erase the saved log if the user has removed all the characters
    // without using "Clear". This may be a manipulation mistake, and erasing
    // again will be easy using "Clear" while retyping the text may not be.
    if (force || (StringUtils.isNotEmpty(log) && !StringUtils.equals(log, text))) {
      cache.logOffline(this, log, date, typeSelected);
      Settings.setLastCacheLog(log);
    }
    text = log;
  }
Exemple #27
0
  protected void selectGlobalTypeFilter() {
    final List<CacheType> cacheTypes = new ArrayList<CacheType>();

    // first add the most used types
    cacheTypes.add(CacheType.ALL);
    cacheTypes.add(CacheType.TRADITIONAL);
    cacheTypes.add(CacheType.MULTI);
    cacheTypes.add(CacheType.MYSTERY);

    // then add all other cache types sorted alphabetically
    final List<CacheType> sorted = new ArrayList<CacheType>();
    sorted.addAll(Arrays.asList(CacheType.values()));
    sorted.removeAll(cacheTypes);

    Collections.sort(
        sorted,
        new Comparator<CacheType>() {

          @Override
          public int compare(final CacheType left, final CacheType right) {
            return left.getL10n().compareToIgnoreCase(right.getL10n());
          }
        });

    cacheTypes.addAll(sorted);

    int checkedItem = cacheTypes.indexOf(Settings.getCacheType());
    if (checkedItem < 0) {
      checkedItem = 0;
    }

    final String[] items = new String[cacheTypes.size()];
    for (int i = 0; i < cacheTypes.size(); i++) {
      items[i] = cacheTypes.get(i).getL10n();
    }

    final Builder builder = new AlertDialog.Builder(this);
    builder.setTitle(R.string.menu_filter);
    builder.setSingleChoiceItems(
        items,
        checkedItem,
        new DialogInterface.OnClickListener() {

          @Override
          public void onClick(final DialogInterface dialog, final int position) {
            final CacheType cacheType = cacheTypes.get(position);
            Settings.setCacheType(cacheType);
            setFilterTitle();
            dialog.dismiss();
          }
        });
    builder.create().show();
  }
Exemple #28
0
  /**
   * Searches the view port on the live map with Strategy.AUTO
   *
   * @param viewport Area to search
   * @param tokens Live map tokens
   */
  @NonNull
  public static SearchResult searchByViewport(final Viewport viewport, final MapTokens tokens) {
    final int speed =
        (int) Sensors.getInstance().currentGeo().getSpeed() * 60 * 60 / 1000; // in km/h
    LivemapStrategy strategy = Settings.getLiveMapStrategy();
    if (strategy == LivemapStrategy.AUTO) {
      strategy = speed >= 30 ? LivemapStrategy.FAST : LivemapStrategy.DETAILED;
    }

    final SearchResult result = searchByViewport(viewport, tokens, strategy);

    if (Settings.isDebug()) {
      final StringBuilder text =
          new StringBuilder(Formatter.SEPARATOR)
              .append(strategy.getL10n())
              .append(Formatter.SEPARATOR)
              .append(Units.getSpeed(speed));
      result.setUrl(result.getUrl() + text);
    }

    return result;
  }
  public static void addMapviewMenuItems(final Menu menu) {
    final SubMenu parentMenu = menu.findItem(R.id.menu_select_mapview).getSubMenu();

    final int currentSource = Settings.getMapSource().getNumericalId();
    for (int i = 0; i < mapSources.size(); i++) {
      final MapSource mapSource = mapSources.get(i);
      final int id = mapSource.getNumericalId();
      parentMenu
          .add(R.id.menu_group_map_sources, id, i, mapSource.getName())
          .setCheckable(true)
          .setChecked(id == currentSource);
    }
    parentMenu.setGroupCheckable(R.id.menu_group_map_sources, true, true);
  }
Exemple #30
0
 private static void assertDistance(final String expected, final float distance) {
   final String actual = Units.getDistanceFromKilometers(distance);
   if (!StringUtils.equals(expected, actual.replace(',', '.'))) { // make 1.2 the same as 1,2
     fail(
         "getHumanDistance("
             + distance
             + ") [metric: "
             + (!Settings.useImperialUnits() ? "yes" : "no")
             + "] fails to match "
             + expected
             + ": "
             + actual);
   }
 }