private void updateLocalVersions() {
    if (NavigineApp.Navigation == null) return;

    for (int i = 0; i < mInfoList.size(); ++i) {
      LocationInfo info = mInfoList.get(i);
      String versionStr = LocationLoader.getLocalVersion(NavigineApp.AppContext, info.title);
      if (versionStr != null) {
        // Log.d(TAG, info.title + ": " + versionStr);
        info.localModified = versionStr.endsWith("+");
        if (info.localModified) versionStr = versionStr.substring(0, versionStr.length() - 1);
        try {
          info.localVersion = Integer.parseInt(versionStr);
        } catch (Throwable e) {
        }
      } else {
        info.localVersion = -1;

        String mapFile = NavigineApp.Settings.getString("map_file", "");
        if (mapFile.equals(info.archiveFile)) {
          NavigineApp.Navigation.loadArchive(null);
          SharedPreferences.Editor editor = NavigineApp.Settings.edit();
          editor.putString("map_file", "");
          editor.commit();
        }
      }
    }
    mAdapter.updateList();
  }
  private void updateLoader() {
    if (NavigineApp.Navigation == null) return;

    // Log.d(TAG, String.format(Locale.ENGLISH, "Update loader: %d", mLoader));

    long timeNow = DateTimeUtils.currentTimeMillis();
    if (mLoader < 0) return;

    int status = LocationLoader.checkLocationLoader(mLoader);
    if (status < 100) {
      if ((Math.abs(timeNow - mLoaderTime) > LOADER_TIMEOUT / 3 && status == 0)
          || (Math.abs(timeNow - mLoaderTime) > LOADER_TIMEOUT)) {
        mListView.setVisibility(View.GONE);
        mStatusLabel.setVisibility(View.VISIBLE);
        mStatusLabel.setText("Loading timeout!\nPlease, check your internet connection!");
        Log.d(TAG, String.format(Locale.ENGLISH, "Load stopped on timeout!"));
        LocationLoader.stopLocationLoader(mLoader);
        mLoader = -1;
      } else {
        mListView.setVisibility(View.GONE);
        mStatusLabel.setVisibility(View.VISIBLE);
        mStatusLabel.setText(String.format(Locale.ENGLISH, "Loading content (%d%%)", status));
      }
    } else {
      Log.d(TAG, String.format(Locale.ENGLISH, "Load finished with result: %d", status));
      LocationLoader.stopLocationLoader(mLoader);
      mLoader = -1;

      if (status == 100) {
        parseMapsXml();
        if (mInfoList.isEmpty()) {
          mListView.setVisibility(View.GONE);
          mStatusLabel.setVisibility(View.VISIBLE);
          mStatusLabel.setText("No locations available");
        } else {
          mListView.setVisibility(View.VISIBLE);
          mStatusLabel.setVisibility(View.GONE);
        }
      } else {
        mListView.setVisibility(View.GONE);
        mStatusLabel.setVisibility(View.VISIBLE);
        mStatusLabel.setText("Error loading!\nPlease, check your ID!");
      }
    }
  }
  private void startUpload(int index) {
    if (NavigineApp.Navigation == null) return;

    String userHash = NavigineApp.Settings.getString("user_hash", "");
    if (userHash.length() == 0) return;

    LocationInfo info = mInfoList.get(index);
    String location = new String(info.title);
    Log.d(TAG, String.format(Locale.ENGLISH, "Start upload: %s", location));

    synchronized (mLoaderMap) {
      if (!mLoaderMap.containsKey(location)) {
        LoaderState loader = new LoaderState();
        loader.location = location;
        loader.type = UPLOAD;
        loader.id = LocationLoader.startLocationUploader(location, info.archiveFile, true);
        mLoaderMap.put(location, loader);
      }
    }
    mAdapter.updateList();
  }
  private void selectItem(int index) {
    _info = mInfoList.get(index);
    if (!(new File(_info.archiveFile)).exists()) {
      String text =
          String.format(
              Locale.ENGLISH,
              "Location '%s' cannot be selected!\n" + "Please, download location first!",
              _info.title);
      Toast.makeText(mContext, text, Toast.LENGTH_LONG).show();
      return;
    }

    AlertDialog.Builder alertBuilder = new AlertDialog.Builder(mContext);
    alertBuilder.setTitle(String.format(Locale.ENGLISH, "Location '%s'", _info.title));

    alertBuilder.setNegativeButton(
        "Delete location",
        new DialogInterface.OnClickListener() {
          @Override
          public void onClick(DialogInterface dlg, int id) {
            deleteLocation(_info);
          }
        });
    alertBuilder.setPositiveButton(
        "Select location",
        new DialogInterface.OnClickListener() {
          @Override
          public void onClick(DialogInterface dlg, int id) {
            selectLocation(_info);
          }
        });

    AlertDialog dialog = alertBuilder.create();
    dialog.setCanceledOnTouchOutside(false);
    dialog.show();
  }