package net.osmand.plus.helpers;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.ParcelFileDescriptor;
import android.provider.OpenableColumns;
import android.support.v7.app.AlertDialog;
import android.widget.Toast;
import net.osmand.IndexConstants;
import net.osmand.data.FavouritePoint;
import net.osmand.plus.FavouritesDbHelper;
import net.osmand.plus.GPXUtilities;
import net.osmand.plus.GPXUtilities.GPXFile;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.views.OsmandMapTileView;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
/**
* @author Koen Rabaey
*/
public class GpxImportHelper {
public static final String KML_SUFFIX = ".kml";
public static final String GPX_SUFFIX = ".gpx";
private final Activity activity;
private final OsmandApplication app;
private final OsmandMapTileView mapView;
private OnGpxImportCompleteListener gpxImportCompleteListener;
public interface OnGpxImportCompleteListener {
void onComplete(boolean success);
}
public GpxImportHelper(final Activity activity, final OsmandApplication app, final OsmandMapTileView mapView) {
this.activity = activity;
this.app = app;
this.mapView = mapView;
}
public void setGpxImportCompleteListener(OnGpxImportCompleteListener gpxImportCompleteListener) {
this.gpxImportCompleteListener = gpxImportCompleteListener;
}
public void handleContentImport(final Uri contentUri, final boolean useImportDir) {
final String name = getNameFromContentUri(contentUri);
handleFileImport(contentUri, name, useImportDir);
}
public boolean handleGpxImport(final Uri contentUri, final boolean useImportDir) {
final String name = getNameFromContentUri(contentUri);
final boolean isOsmandSubdir = isSubDirectory(app.getAppPath(IndexConstants.GPX_INDEX_DIR), new File(contentUri.getPath()));
if (!isOsmandSubdir && name != null && name.endsWith(GPX_SUFFIX)) {
handleGpxImport(contentUri, name, true, useImportDir);
return true;
}
return false;
}
public void handleFileImport(final Uri intentUri, final String fileName, final boolean useImportDir) {
final boolean isFileIntent = "file".equals(intentUri.getScheme());
final boolean isOsmandSubdir = isSubDirectory(app.getAppPath(IndexConstants.GPX_INDEX_DIR), new File(intentUri.getPath()));
final boolean saveFile = !isFileIntent || !isOsmandSubdir;
if (fileName != null && fileName.endsWith(KML_SUFFIX)) {
handleKmlImport(intentUri, fileName, saveFile, useImportDir);
} else {
handleFavouritesImport(intentUri, fileName, saveFile, useImportDir);
}
}
private String getNameFromContentUri(Uri contentUri) {
final String name;
final Cursor returnCursor = app.getContentResolver().query(contentUri, null, null, null, null);
if (returnCursor != null && returnCursor.moveToFirst()) {
int columnIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
if (columnIndex != -1) {
name = returnCursor.getString(columnIndex);
} else {
name = contentUri.getLastPathSegment();
}
} else {
name = null;
}
if (returnCursor != null && !returnCursor.isClosed()) {
returnCursor.close();
}
return name;
}
private void handleGpxImport(final Uri gpxFile, final String fileName, final boolean save, final boolean useImportDir) {
new AsyncTask<Void, Void, GPXUtilities.GPXFile>() {
ProgressDialog progress = null;
@Override
protected void onPreExecute() {
progress = ProgressDialog.show(activity, app.getString(R.string.loading_smth, ""), app.getString(R.string.loading_data));
}
@Override
protected GPXUtilities.GPXFile doInBackground(Void... nothing) {
InputStream is = null;
try {
final ParcelFileDescriptor pFD = app.getContentResolver().openFileDescriptor(gpxFile, "r");
if (pFD != null) {
is = new FileInputStream(pFD.getFileDescriptor());
return GPXUtilities.loadGPXFile(app, is);
}
} catch (FileNotFoundException e) {
//
} finally {
if (is != null) try {
is.close();
} catch (IOException ignore) {
}
}
return null;
}
@Override
protected void onPostExecute(GPXUtilities.GPXFile result) {
progress.dismiss();
handleResult(result, fileName, save, useImportDir);
}
}.execute();
}
private void handleFavouritesImport(final Uri gpxFile, final String fileName, final boolean save, final boolean useImportDir) {
new AsyncTask<Void, Void, GPXUtilities.GPXFile>() {
ProgressDialog progress = null;
@Override
protected void onPreExecute() {
progress = ProgressDialog.show(activity, app.getString(R.string.loading_smth, ""), app.getString(R.string.loading_data));
}
@Override
protected GPXUtilities.GPXFile doInBackground(Void... nothing) {
InputStream is = null;
try {
final ParcelFileDescriptor pFD = app.getContentResolver().openFileDescriptor(gpxFile, "r");
if (pFD != null) {
is = new FileInputStream(pFD.getFileDescriptor());
return GPXUtilities.loadGPXFile(app, is);
}
} catch (FileNotFoundException e) {
//
} finally {
if (is != null) try {
is.close();
} catch (IOException ignore) {
}
}
return null;
}
@Override
protected void onPostExecute(final GPXUtilities.GPXFile result) {
progress.dismiss();
importFavourites(result, fileName, save, useImportDir);
}
}.execute();
}
private void importFavoritesImpl(final GPXFile gpxFile) {
new AsyncTask<Void, Void, GPXUtilities.GPXFile>() {
ProgressDialog progress = null;
@Override
protected void onPreExecute() {
progress = ProgressDialog.show(activity, app.getString(R.string.loading_smth, ""), app.getString(R.string.loading_data));
}
@Override
protected GPXUtilities.GPXFile doInBackground(Void... nothing) {
final List<FavouritePoint> favourites = asFavourites(gpxFile.points);
final FavouritesDbHelper favoritesHelper = app.getFavorites();
for (final FavouritePoint favourite : favourites) {
favoritesHelper.deleteFavourite(favourite, false);
favoritesHelper.addFavourite(favourite, false);
}
favoritesHelper.sortAll();
favoritesHelper.saveCurrentPointsIntoFile();
return null;
}
@Override
protected void onPostExecute(GPXUtilities.GPXFile result) {
progress.dismiss();
Toast.makeText(activity, R.string.fav_imported_sucessfully, Toast.LENGTH_LONG).show();
final Intent newIntent = new Intent(activity, app.getAppCustomization().getFavoritesActivity());
activity.startActivity(newIntent);
}
}.execute();
}
private void handleKmlImport(final Uri kmlFile, final String name, final boolean save, final boolean useImportDir) {
new AsyncTask<Void, Void, GPXUtilities.GPXFile>() {
ProgressDialog progress = null;
@Override
protected void onPreExecute() {
progress = ProgressDialog.show(activity, app.getString(R.string.loading_smth, ""), app.getString(R.string.loading_data));
}
@Override
protected GPXUtilities.GPXFile doInBackground(Void... nothing) {
InputStream is = null;
try {
final ParcelFileDescriptor pFD = app.getContentResolver().openFileDescriptor(kmlFile, "r");
if (pFD != null) {
is = new FileInputStream(pFD.getFileDescriptor());
final String result = Kml2Gpx.toGpx(is);
if (result != null) {
try {
return GPXUtilities.loadGPXFile(app, new ByteArrayInputStream(result.getBytes("UTF-8")));
} catch (UnsupportedEncodingException e) {
return null;
}
}
}
} catch (FileNotFoundException e) {
//
} finally {
if (is != null) try {
is.close();
} catch (IOException ignore) {
}
}
return null;
}
@Override
protected void onPostExecute(GPXUtilities.GPXFile result) {
progress.dismiss();
handleResult(result, name, save, useImportDir);
}
}.execute();
}
private void handleResult(final GPXUtilities.GPXFile result, final String name, final boolean save, final boolean useImportDir) {
if (result != null) {
if (result.warning != null) {
Toast.makeText(activity, result.warning, Toast.LENGTH_LONG).show();
if (gpxImportCompleteListener != null) {
gpxImportCompleteListener.onComplete(false);
}
} else {
if (save) {
new SaveAsyncTask(result, name, useImportDir).execute();
} else {
showGpxOnMap(result);
}
if (gpxImportCompleteListener != null) {
gpxImportCompleteListener.onComplete(true);
}
}
} else {
Toast.makeText(activity, R.string.error_reading_gpx, Toast.LENGTH_LONG).show();
if (gpxImportCompleteListener != null) {
gpxImportCompleteListener.onComplete(false);
}
}
}
private String saveImport(final GPXUtilities.GPXFile gpxFile, final String fileName, final boolean useImportDir) {
final String warning;
if (gpxFile.isEmpty() || fileName == null) {
warning = app.getString(R.string.error_reading_gpx);
} else {
final File importDir;
if (useImportDir) {
importDir = app.getAppPath(IndexConstants.GPX_IMPORT_DIR);
} else {
importDir = app.getAppPath(IndexConstants.GPX_INDEX_DIR);
}
//noinspection ResultOfMethodCallIgnored
importDir.mkdirs();
if (importDir.exists() && importDir.isDirectory() && importDir.canWrite()) {
final GPXUtilities.WptPt pt = gpxFile.findPointToShow();
final File toWrite = getFileToSave(fileName, importDir, pt);
warning = GPXUtilities.writeGpxFile(toWrite, gpxFile, app);
if (warning == null) {
gpxFile.path = toWrite.getAbsolutePath();
}
} else {
warning = app.getString(R.string.sd_dir_not_accessible);
}
}
return warning;
}
private File getFileToSave(final String fileName, final File importDir, final GPXUtilities.WptPt pt) {
final StringBuilder builder = new StringBuilder(fileName);
if ("".equals(fileName)) {
builder.append("import_").append(new SimpleDateFormat("HH-mm_EEE", Locale.US).format(new Date(pt.time))).append(GPX_SUFFIX); //$NON-NLS-1$
}
if (fileName.endsWith(KML_SUFFIX)) {
builder.replace(builder.length() - KML_SUFFIX.length(), builder.length(), GPX_SUFFIX);
} else if (!fileName.endsWith(GPX_SUFFIX)) {
builder.append(GPX_SUFFIX);
}
return new File(importDir, builder.toString());
}
private class SaveAsyncTask extends AsyncTask<Void, Void, String> {
private final GPXUtilities.GPXFile result;
private final String name;
private final boolean useImportDir;
private SaveAsyncTask(GPXUtilities.GPXFile result, final String name, boolean useImportDir) {
this.result = result;
this.name = name;
this.useImportDir = useImportDir;
}
@Override
protected String doInBackground(Void... nothing) {
return saveImport(result, name, useImportDir);
}
@Override
protected void onPostExecute(final String warning) {
final String msg = warning == null ? MessageFormat.format(app.getString(R.string.gpx_saved_sucessfully), result.path) : warning;
Toast.makeText(activity, msg, Toast.LENGTH_LONG).show();
showGpxOnMap(result);
}
}
private MapActivity getMapActivity() {
if (activity instanceof MapActivity) {
return (MapActivity) activity;
} else {
return null;
}
}
private void showGpxOnMap(final GPXUtilities.GPXFile result) {
if (mapView != null && getMapActivity() != null) {
app.getSelectedGpxHelper().setGpxFileToDisplay(result);
final GPXUtilities.WptPt moveTo = result.findPointToShow();
if (moveTo != null) {
mapView.getAnimatedDraggingThread().startMoving(moveTo.lat, moveTo.lon, mapView.getZoom(), true);
}
mapView.refreshMap();
if (getMapActivity().getDashboard().isVisible()) {
getMapActivity().getDashboard().refreshContent(true);
}
}
}
private void importFavourites(final GPXUtilities.GPXFile gpxFile, final String fileName, final boolean save, final boolean useImportDir) {
if(gpxFile == null || gpxFile.points == null || gpxFile.points.size() == 0) {
handleResult(gpxFile, fileName, save, useImportDir);
return;
}
final DialogInterface.OnClickListener importFavouritesListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
importFavoritesImpl(gpxFile);
break;
case DialogInterface.BUTTON_NEGATIVE:
handleResult(gpxFile, fileName, save, useImportDir);
break;
}
}
};
new AlertDialog.Builder(activity)
.setTitle(R.string.shared_string_import2osmand)
.setMessage(R.string.import_file_favourites)
.setPositiveButton(R.string.shared_string_import, importFavouritesListener)
.setNegativeButton(R.string.shared_string_save, importFavouritesListener)
.show();
}
private List<FavouritePoint> asFavourites(final List<GPXUtilities.WptPt> wptPts) {
final List<FavouritePoint> favourites = new ArrayList<>();
for (GPXUtilities.WptPt p : wptPts) {
if (p.name != null) {
final String fpCat = (p.category != null) ? p.category : "";
final FavouritePoint fp = new FavouritePoint(p.lat, p.lon, p.name, fpCat);
if (p.desc != null) {
fp.setDescription(p.desc);
}
favourites.add(fp);
}
}
return favourites;
}
/**
* Checks, whether the child directory is a subdirectory of the parent
* directory.
*
* @param parent the parent directory.
* @param child the suspected child directory.
* @return true if the child is a subdirectory of the parent directory.
*/
public boolean isSubDirectory(File parent, File child) {
try {
parent = parent.getCanonicalFile();
child = child.getCanonicalFile();
File dir = child;
while (dir != null) {
if (parent.equals(dir)) {
return true;
}
dir = dir.getParentFile();
}
} catch (IOException e) {
return false;
}
return false;
}
}