Merge pull request #9966 from osmandapp/import_fixes

Proper content-handling on import
This commit is contained in:
max-klaus 2020-10-09 17:35:00 +03:00 committed by GitHub
commit f39e7dd753
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 1811 additions and 1419 deletions

View file

@ -15,6 +15,7 @@ public class IndexConstants {
public static final String POI_INDEX_EXT = ".poi.odb"; //$NON-NLS-1$
public static final String ZIP_EXT = ".zip"; //$NON-NLS-1$
public static final String BINARY_MAP_INDEX_EXT = ".obf"; //$NON-NLS-1$
public static final String BINARY_MAP_INDEX_EXT_ZIP = ".obf.zip"; //$NON-NLS-1$

View file

@ -49,6 +49,11 @@ public class Algorithms {
private static char[] CHARS_TO_NORMALIZE_KEY = new char[''];
private static char[] CHARS_TO_NORMALIZE_VALUE = new char['\''];
public static final int ZIP_FILE_SIGNATURE = 0x504b0304;
public static final int XML_FILE_SIGNATURE = 0x3c3f786d;
public static final int OBF_FILE_SIGNATURE = 0x08029001;
public static final int SQLITE_FILE_SIGNATURE = 0x53514C69;
public static String normalizeSearchText(String s) {
boolean norm = false;
for (int i = 0; i < s.length() && !norm; i++) {
@ -293,7 +298,7 @@ public class Algorithms {
FileInputStream in = new FileInputStream(file);
int test = readInt(in);
in.close();
return test == 0x504b0304;
return test == ZIP_FILE_SIGNATURE;
}
/**
@ -322,7 +327,7 @@ public class Algorithms {
return false;
}
private static int readInt(InputStream in) throws IOException {
public static int readInt(InputStream in) throws IOException {
int ch1 = in.read();
int ch2 = in.read();
int ch3 = in.read();

View file

@ -101,7 +101,7 @@ import net.osmand.plus.firstusage.FirstUsageWelcomeFragment;
import net.osmand.plus.firstusage.FirstUsageWizardFragment;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.helpers.DiscountHelper;
import net.osmand.plus.helpers.ImportHelper;
import net.osmand.plus.importfiles.ImportHelper;
import net.osmand.plus.helpers.IntentHelper;
import net.osmand.plus.helpers.LockHelper;
import net.osmand.plus.helpers.LockHelper.LockUIAdapter;

View file

@ -13,7 +13,7 @@ import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.DividerHalfItem;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.ShortDescriptionItem;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem;
import net.osmand.plus.helpers.ImportHelper;
import net.osmand.plus.importfiles.ImportHelper;
public class ImportGpxBottomSheetDialogFragment extends MenuBottomSheetDialogFragment {

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,45 @@
package net.osmand.plus.importfiles;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentActivity;
import net.osmand.AndroidUtils;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import java.lang.ref.WeakReference;
abstract class BaseImportAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {
protected OsmandApplication app;
protected WeakReference<FragmentActivity> activityRef;
protected ProgressDialog progress;
public BaseImportAsyncTask(@NonNull FragmentActivity activity) {
app = (OsmandApplication) activity.getApplicationContext();
activityRef = new WeakReference<>(activity);
}
@Override
protected void onPreExecute() {
showProgress();
}
protected void showProgress() {
FragmentActivity activity = activityRef.get();
if (AndroidUtils.isActivityNotDestroyed(activity)) {
String title = app.getString(R.string.loading_smth, "");
progress = ProgressDialog.show(activity, title, app.getString(R.string.loading_data));
}
}
protected void hideProgress() {
FragmentActivity activity = activityRef.get();
if (progress != null && AndroidUtils.isActivityNotDestroyed(activity)) {
progress.dismiss();
}
}
}

View file

@ -0,0 +1,58 @@
package net.osmand.plus.importfiles;
import android.content.Intent;
import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentActivity;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.data.FavouritePoint;
import net.osmand.plus.FavouritesDbHelper;
import net.osmand.plus.R;
import java.util.List;
import static net.osmand.plus.importfiles.ImportHelper.asFavourites;
import static net.osmand.plus.myplaces.FavoritesActivity.FAV_TAB;
import static net.osmand.plus.myplaces.FavoritesActivity.TAB_ID;
class FavoritesImportTask extends BaseImportAsyncTask<Void, Void, GPXFile> {
private GPXFile gpxFile;
private String fileName;
private boolean forceImportFavourites;
public FavoritesImportTask(@NonNull FragmentActivity activity, @NonNull GPXFile gpxFile,
@NonNull String fileName, boolean forceImportFavourites) {
super(activity);
this.gpxFile = gpxFile;
this.fileName = fileName;
this.forceImportFavourites = forceImportFavourites;
}
@Override
protected GPXFile doInBackground(Void... nothing) {
List<FavouritePoint> favourites = asFavourites(app, gpxFile.getPoints(), fileName, forceImportFavourites);
FavouritesDbHelper favoritesHelper = app.getFavorites();
for (FavouritePoint favourite : favourites) {
favoritesHelper.deleteFavourite(favourite, false);
favoritesHelper.addFavourite(favourite, false);
}
favoritesHelper.sortAll();
favoritesHelper.saveCurrentPointsIntoFile();
return null;
}
@Override
protected void onPostExecute(GPXFile result) {
hideProgress();
FragmentActivity activity = activityRef.get();
if (activity != null) {
app.showToastMessage(R.string.fav_imported_sucessfully);
Intent newIntent = new Intent(activity, app.getAppCustomization().getFavoritesActivity());
newIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
newIntent.putExtra(TAB_ID, FAV_TAB);
activity.startActivity(newIntent);
}
}
}

View file

@ -0,0 +1,59 @@
package net.osmand.plus.importfiles;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentActivity;
import net.osmand.GPXUtilities;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.util.Algorithms;
import java.io.FileNotFoundException;
import java.io.InputStream;
class GpxImportTask extends BaseImportAsyncTask<Void, Void, GPXFile> {
private ImportHelper importHelper;
private Uri gpxFile;
private String fileName;
private boolean save;
private boolean useImportDir;
private boolean showInDetailsActivity;
public GpxImportTask(@NonNull ImportHelper importHelper, @NonNull FragmentActivity activity,
@NonNull Uri gpxFile, @NonNull String fileName, boolean save, boolean useImportDir,
boolean showInDetailsActivity) {
super(activity);
this.importHelper = importHelper;
this.gpxFile = gpxFile;
this.fileName = fileName;
this.save = save;
this.useImportDir = useImportDir;
this.showInDetailsActivity = showInDetailsActivity;
}
@Override
protected GPXFile doInBackground(Void... nothing) {
InputStream is = null;
try {
is = app.getContentResolver().openInputStream(gpxFile);
if (is != null) {
return GPXUtilities.loadGPXFile(is);
}
} catch (FileNotFoundException e) {
//
} catch (SecurityException e) {
ImportHelper.log.error(e.getMessage(), e);
} finally {
Algorithms.closeStream(is);
}
return null;
}
@Override
protected void onPostExecute(GPXFile result) {
hideProgress();
importHelper.handleResult(result, fileName, save, useImportDir, false, showInDetailsActivity);
}
}

View file

@ -0,0 +1,83 @@
package net.osmand.plus.importfiles;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentActivity;
import net.osmand.GPXUtilities;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.util.Algorithms;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import static net.osmand.plus.importfiles.KmlImportTask.loadGpxFromKml;
class GpxOrFavouritesImportTask extends BaseImportAsyncTask<Void, Void, GPXFile> {
private ImportHelper importHelper;
private Uri fileUri;
private String fileName;
private boolean save;
private boolean useImportDir;
private boolean forceImportFavourites;
private boolean forceImportGpx;
public GpxOrFavouritesImportTask(@NonNull ImportHelper importHelper, @NonNull FragmentActivity activity,
@NonNull Uri fileUri, String fileName, boolean save, boolean useImportDir,
boolean forceImportFavourites, boolean forceImportGpx) {
super(activity);
this.importHelper = importHelper;
this.fileUri = fileUri;
this.fileName = fileName;
this.save = save;
this.useImportDir = useImportDir;
this.forceImportFavourites = forceImportFavourites;
this.forceImportGpx = forceImportGpx;
}
@Override
protected GPXFile doInBackground(Void... nothing) {
InputStream is = null;
ZipInputStream zis = null;
try {
is = app.getContentResolver().openInputStream(fileUri);
if (is != null) {
if (fileName != null && fileName.endsWith(ImportHelper.KML_SUFFIX)) {
return loadGpxFromKml(is);
} else if (fileName != null && fileName.endsWith(ImportHelper.KMZ_SUFFIX)) {
try {
zis = new ZipInputStream(is);
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
if (entry.getName().endsWith(ImportHelper.KML_SUFFIX)) {
return loadGpxFromKml(zis);
}
}
} catch (Exception e) {
return null;
}
} else {
return GPXUtilities.loadGPXFile(is);
}
}
} catch (FileNotFoundException e) {
//
} catch (SecurityException e) {
ImportHelper.log.error(e.getMessage(), e);
} finally {
Algorithms.closeStream(is);
Algorithms.closeStream(zis);
}
return null;
}
@Override
protected void onPostExecute(GPXFile result) {
hideProgress();
importHelper.importGpxOrFavourites(result, fileName, save, useImportDir, forceImportFavourites, forceImportGpx);
}
}

View file

@ -0,0 +1,675 @@
package net.osmand.plus.importfiles;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.provider.OpenableColumns;
import android.provider.Settings;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import net.osmand.CallbackWithObject;
import net.osmand.GPXUtilities;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.GPXUtilities.WptPt;
import net.osmand.PlatformUtil;
import net.osmand.data.FavouritePoint;
import net.osmand.data.FavouritePoint.BackgroundType;
import net.osmand.plus.AppInitializer;
import net.osmand.plus.GPXDatabase.GpxDataItem;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.activities.ActivityResultListener;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.activities.TrackActivity;
import net.osmand.plus.dialogs.ImportGpxBottomSheetDialogFragment;
import net.osmand.plus.measurementtool.MeasurementToolFragment;
import net.osmand.plus.settings.backend.SettingsHelper;
import net.osmand.plus.settings.backend.SettingsHelper.SettingsItem;
import net.osmand.plus.views.OsmandMapTileView;
import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import static android.app.Activity.RESULT_OK;
import static net.osmand.IndexConstants.BINARY_MAP_INDEX_EXT;
import static net.osmand.IndexConstants.GPX_FILE_EXT;
import static net.osmand.IndexConstants.GPX_IMPORT_DIR;
import static net.osmand.IndexConstants.GPX_INDEX_DIR;
import static net.osmand.IndexConstants.OSMAND_SETTINGS_FILE_EXT;
import static net.osmand.IndexConstants.RENDERER_INDEX_EXT;
import static net.osmand.IndexConstants.ROUTING_FILE_EXT;
import static net.osmand.IndexConstants.SQLITE_CHART_FILE_EXT;
import static net.osmand.IndexConstants.SQLITE_EXT;
import static net.osmand.IndexConstants.WPT_CHART_FILE_EXT;
import static net.osmand.data.FavouritePoint.DEFAULT_BACKGROUND_TYPE;
import static net.osmand.plus.myplaces.FavoritesActivity.GPX_TAB;
import static net.osmand.plus.myplaces.FavoritesActivity.TAB_ID;
/**
* @author Koen Rabaey
*/
public class ImportHelper {
public static final Log log = PlatformUtil.getLog(ImportHelper.class);
public static final String KML_SUFFIX = ".kml";
public static final String KMZ_SUFFIX = ".kmz";
public static final int IMPORT_FILE_REQUEST = 1006;
private final OsmandApplication app;
private final OsmandMapTileView mapView;
private final AppCompatActivity activity;
private OnGpxImportCompleteListener gpxImportCompleteListener;
public enum ImportType {
SETTINGS(OSMAND_SETTINGS_FILE_EXT),
ROUTING(ROUTING_FILE_EXT),
RENDERING(RENDERER_INDEX_EXT),
GPX(GPX_FILE_EXT),
KML(KML_SUFFIX),
KMZ(KMZ_SUFFIX);
ImportType(String extension) {
this.extension = extension;
}
private String extension;
public String getExtension() {
return extension;
}
}
public interface OnGpxImportCompleteListener {
void onImportComplete(boolean success);
void onSaveComplete(boolean success, GPXFile result);
}
public ImportHelper(final AppCompatActivity 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, Bundle extras, final boolean useImportDir) {
String name = getNameFromContentUri(app, contentUri);
handleFileImport(contentUri, name, extras, useImportDir);
}
public void importFavoritesFromGpx(final GPXFile gpxFile, final String fileName) {
importFavoritesImpl(gpxFile, fileName, false);
}
public void handleGpxImport(GPXFile result, String name, boolean save, boolean useImportDir) {
handleResult(result, name, save, useImportDir, false);
}
public boolean handleGpxImport(final Uri contentUri, final boolean useImportDir) {
return handleGpxImport(contentUri, useImportDir, true);
}
public boolean handleGpxImport(final Uri contentUri, final boolean useImportDir, boolean showInDetailsActivity) {
String name = getNameFromContentUri(app, contentUri);
boolean isOsmandSubdir = Algorithms.isSubDirectory(app.getAppPath(GPX_INDEX_DIR), new File(contentUri.getPath()));
if (!isOsmandSubdir && name != null) {
String nameLC = name.toLowerCase();
if (nameLC.endsWith(GPX_FILE_EXT)) {
name = name.substring(0, name.length() - GPX_FILE_EXT.length()) + GPX_FILE_EXT;
handleGpxImport(contentUri, name, true, useImportDir, showInDetailsActivity);
return true;
} else if (nameLC.endsWith(KML_SUFFIX)) {
name = name.substring(0, name.length() - KML_SUFFIX.length()) + KML_SUFFIX;
handleKmlImport(contentUri, name, true, useImportDir);
return true;
} else if (nameLC.endsWith(KMZ_SUFFIX)) {
name = name.substring(0, name.length() - KMZ_SUFFIX.length()) + KMZ_SUFFIX;
handleKmzImport(contentUri, name, true, useImportDir);
return true;
}
}
return false;
}
public void handleGpxOrFavouritesImport(@NonNull Uri uri) {
String scheme = uri.getScheme();
boolean isFileIntent = "file".equals(scheme);
boolean isContentIntent = "content".equals(scheme);
boolean isOsmandSubdir = Algorithms.isSubDirectory(app.getAppPath(GPX_INDEX_DIR), new File(uri.getPath()));
final boolean saveFile = !isFileIntent || !isOsmandSubdir;
String fileName = "";
if (isFileIntent) {
fileName = new File(uri.getPath()).getName();
} else if (isContentIntent) {
fileName = getNameFromContentUri(app, uri);
}
handleGpxOrFavouritesImport(uri, fileName, saveFile, false, true, false);
}
public void handleFileImport(Uri intentUri, String fileName, Bundle extras, boolean useImportDir) {
boolean isFileIntent = "file".equals(intentUri.getScheme());
boolean isOsmandSubdir = Algorithms.isSubDirectory(app.getAppPath(GPX_INDEX_DIR), new File(intentUri.getPath()));
boolean saveFile = !isFileIntent || !isOsmandSubdir;
if (fileName == null) {
handleUriImport(intentUri, saveFile, useImportDir);
} else if (fileName.endsWith(KML_SUFFIX)) {
handleKmlImport(intentUri, fileName, saveFile, useImportDir);
} else if (fileName.endsWith(KMZ_SUFFIX)) {
handleKmzImport(intentUri, fileName, saveFile, useImportDir);
} else if (fileName.endsWith(BINARY_MAP_INDEX_EXT)) {
handleObfImport(intentUri, fileName);
} else if (fileName.endsWith(SQLITE_EXT)) {
handleSqliteTileImport(intentUri, fileName);
} else if (fileName.endsWith(OSMAND_SETTINGS_FILE_EXT)) {
handleOsmAndSettingsImport(intentUri, fileName, extras, null);
} else if (fileName.endsWith(ROUTING_FILE_EXT)) {
handleXmlFileImport(intentUri, fileName, null);
} else if (fileName.endsWith(WPT_CHART_FILE_EXT)) {
handleGpxOrFavouritesImport(intentUri, fileName.replace(WPT_CHART_FILE_EXT, GPX_FILE_EXT), saveFile, useImportDir, false, true);
} else if (fileName.endsWith(SQLITE_CHART_FILE_EXT)) {
handleSqliteTileImport(intentUri, fileName.replace(SQLITE_CHART_FILE_EXT, SQLITE_EXT));
} else {
handleGpxOrFavouritesImport(intentUri, fileName, saveFile, useImportDir, false, false);
}
}
public static String getNameFromContentUri(OsmandApplication app, Uri contentUri) {
try {
String name;
Cursor returnCursor = app.getContentResolver().query(contentUri, new String[] {OpenableColumns.DISPLAY_NAME}, 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;
} catch (RuntimeException e) {
log.error(e.getMessage(), e);
return null;
}
}
private void handleGpxImport(Uri gpxFile, String fileName, boolean save, boolean useImportDir, boolean showInDetailsActivity) {
executeImportTask(new GpxImportTask(this, activity, gpxFile, fileName, save, useImportDir, showInDetailsActivity));
}
protected void handleGpxOrFavouritesImport(Uri fileUri, String fileName, boolean save, boolean useImportDir,
boolean forceImportFavourites, boolean forceImportGpx) {
executeImportTask(new GpxOrFavouritesImportTask(this, activity, fileUri, fileName, save, useImportDir, forceImportFavourites, forceImportGpx));
}
private void importFavoritesImpl(GPXFile gpxFile, String fileName, boolean forceImportFavourites) {
executeImportTask(new FavoritesImportTask(activity, gpxFile, fileName, forceImportFavourites));
}
protected void handleKmzImport(Uri kmzFile, String name, boolean save, boolean useImportDir) {
executeImportTask(new KmzImportTask(this, activity, kmzFile, name, save, useImportDir));
}
private void handleKmlImport(Uri kmlFile, String name, boolean save, boolean useImportDir) {
executeImportTask(new KmlImportTask(this, activity, kmlFile, name, save, useImportDir));
}
protected void handleObfImport(Uri obfFile, String name) {
executeImportTask(new ObfImportTask(activity, obfFile, name));
}
protected void handleSqliteTileImport(Uri uri, String name) {
executeImportTask(new SqliteTileImportTask(activity, uri, name));
}
private void handleOsmAndSettingsImport(Uri intentUri, String fileName, Bundle extras, CallbackWithObject<List<SettingsItem>> callback) {
if (extras != null && extras.containsKey(SettingsHelper.SETTINGS_VERSION_KEY) && extras.containsKey(SettingsHelper.SETTINGS_LATEST_CHANGES_KEY)) {
int version = extras.getInt(SettingsHelper.SETTINGS_VERSION_KEY, -1);
String latestChanges = extras.getString(SettingsHelper.SETTINGS_LATEST_CHANGES_KEY);
handleOsmAndSettingsImport(intentUri, fileName, latestChanges, version, callback);
} else {
handleOsmAndSettingsImport(intentUri, fileName, null, -1, callback);
}
}
protected void handleOsmAndSettingsImport(Uri uri, String name, String latestChanges, int version,
CallbackWithObject<List<SettingsItem>> callback) {
executeImportTask(new SettingsImportTask(activity, uri, name, latestChanges, version, callback));
}
protected void handleXmlFileImport(Uri intentUri, String fileName, CallbackWithObject routingCallback) {
executeImportTask(new XmlImportTask(activity, intentUri, fileName, routingCallback));
}
private void handleUriImport(Uri uri, boolean save, boolean useImportDir) {
executeImportTask(new UriImportTask(this, activity, uri, save, useImportDir));
}
protected void handleZipImport(Uri uri, boolean save, boolean useImportDir) {
executeImportTask(new ZipImportTask(this, activity, uri, save, useImportDir));
}
@Nullable
public static String copyFile(OsmandApplication app, @NonNull File dest, @NonNull Uri uri, boolean overwrite) {
if (dest.exists() && !overwrite) {
return app.getString(R.string.file_with_name_already_exists);
}
String error = null;
InputStream in = null;
OutputStream out = null;
try {
in = app.getContentResolver().openInputStream(uri);
if (in != null) {
out = new FileOutputStream(dest);
Algorithms.streamCopy(in, out);
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
error = e.getMessage();
} catch (IOException e) {
e.printStackTrace();
error = e.getMessage();
} catch (SecurityException e) {
e.printStackTrace();
error = e.getMessage();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return error;
}
public void chooseFileToImport(final ImportType importType, final CallbackWithObject callback) {
final MapActivity mapActivity = getMapActivity();
if (mapActivity == null) {
return;
}
final OsmandApplication app = mapActivity.getMyApplication();
Intent intent = ImportHelper.getImportTrackIntent();
ActivityResultListener listener = new ActivityResultListener(IMPORT_FILE_REQUEST, new ActivityResultListener.OnActivityResultListener() {
@Override
public void onResult(int resultCode, Intent resultData) {
MapActivity mapActivity = getMapActivity();
if (resultCode == RESULT_OK) {
Uri data = resultData.getData();
if (mapActivity == null || data == null) {
return;
}
String scheme = data.getScheme();
String fileName = "";
if ("file".equals(scheme)) {
final String path = data.getPath();
if (path != null) {
fileName = new File(path).getName();
}
} else if ("content".equals(scheme)) {
fileName = getNameFromContentUri(app, data);
}
if (fileName.endsWith(importType.getExtension())) {
if (importType.equals(ImportType.SETTINGS)) {
handleOsmAndSettingsImport(data, fileName, resultData.getExtras(), callback);
} else if (importType.equals(ImportType.ROUTING)) {
handleXmlFileImport(data, fileName, callback);
}
} else {
app.showToastMessage(app.getString(R.string.not_support_file_type_with_ext,
importType.getExtension().replaceAll("\\.", "").toUpperCase()));
}
}
}
});
mapActivity.registerActivityResultListener(listener);
mapActivity.startActivityForResult(intent, IMPORT_FILE_REQUEST);
}
public static Intent getImportTrackIntent() {
Intent intent = new Intent();
String action;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
action = Intent.ACTION_OPEN_DOCUMENT;
} else {
action = Intent.ACTION_GET_CONTENT;
}
intent.setAction(action);
intent.setType("*/*");
return intent;
}
protected void handleResult(GPXFile result, String name, boolean save,
boolean useImportDir, boolean forceImportFavourites) {
handleResult(result, name, save, useImportDir, forceImportFavourites, true);
}
protected void handleResult(final GPXFile result, final String name, final boolean save,
final boolean useImportDir, boolean forceImportFavourites, boolean showInDetailsActivity) {
if (result != null) {
if (result.error != null) {
Toast.makeText(activity, result.error.getMessage(), Toast.LENGTH_LONG).show();
if (gpxImportCompleteListener != null) {
gpxImportCompleteListener.onImportComplete(false);
}
} else {
if (save) {
executeImportTask(new SaveAsyncTask(result, name, useImportDir, showInDetailsActivity));
} else {
showGpxInDetailsActivity(result);
}
if (gpxImportCompleteListener != null) {
gpxImportCompleteListener.onImportComplete(true);
}
}
} else {
new AlertDialog.Builder(activity)
.setTitle(R.string.shared_string_import2osmand)
.setMessage(R.string.import_gpx_failed_descr)
.setNeutralButton(R.string.shared_string_permissions, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri uri = Uri.fromParts("package", app.getPackageName(), null);
intent.setData(uri);
app.startActivity(intent);
if (gpxImportCompleteListener != null) {
gpxImportCompleteListener.onImportComplete(false);
}
}
})
.setNegativeButton(R.string.shared_string_cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (gpxImportCompleteListener != null) {
gpxImportCompleteListener.onImportComplete(false);
}
}
})
.show();
}
if (forceImportFavourites) {
final Intent newIntent = new Intent(activity, app.getAppCustomization().getFavoritesActivity());
newIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
newIntent.putExtra(TAB_ID, GPX_TAB);
activity.startActivity(newIntent);
}
}
private String saveImport(final 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(GPX_IMPORT_DIR);
} else {
importDir = app.getAppPath(GPX_INDEX_DIR);
}
//noinspection ResultOfMethodCallIgnored
importDir.mkdirs();
if (importDir.exists() && importDir.isDirectory() && importDir.canWrite()) {
final WptPt pt = gpxFile.findPointToShow();
final File toWrite = getFileToSave(fileName, importDir, pt);
boolean destinationExists = toWrite.exists();
Exception e = GPXUtilities.writeGpxFile(toWrite, gpxFile);
if (e == null) {
gpxFile.path = toWrite.getAbsolutePath();
File file = new File(gpxFile.path);
if (!destinationExists) {
GpxDataItem item = new GpxDataItem(file, gpxFile);
app.getGpxDbHelper().add(item);
} else {
GpxDataItem item = app.getGpxDbHelper().getItem(file);
if (item != null) {
app.getGpxDbHelper().clearAnalysis(item);
}
}
warning = null;
} else {
warning = app.getString(R.string.error_reading_gpx);
}
} else {
warning = app.getString(R.string.sd_dir_not_accessible);
}
}
return warning;
}
private File getFileToSave(final String fileName, final File importDir, final 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_FILE_EXT); //$NON-NLS-1$
}
if (fileName.endsWith(KML_SUFFIX)) {
builder.replace(builder.length() - KML_SUFFIX.length(), builder.length(), GPX_FILE_EXT);
} else if (fileName.endsWith(KMZ_SUFFIX)) {
builder.replace(builder.length() - KMZ_SUFFIX.length(), builder.length(), GPX_FILE_EXT);
} else if (!fileName.endsWith(GPX_FILE_EXT)) {
builder.append(GPX_FILE_EXT);
}
return new File(importDir, builder.toString());
}
private class SaveAsyncTask extends AsyncTask<Void, Void, String> {
private final GPXFile result;
private final String name;
private final boolean useImportDir;
private boolean showInDetailsActivity;
private SaveAsyncTask(GPXFile result, final String name, boolean useImportDir, boolean showInDetailsActivity) {
this.result = result;
this.name = name;
this.useImportDir = useImportDir;
this.showInDetailsActivity = showInDetailsActivity;
}
@Override
protected String doInBackground(Void... nothing) {
return saveImport(result, name, useImportDir);
}
@Override
protected void onPostExecute(final String warning) {
boolean success = Algorithms.isEmpty(warning);
if (gpxImportCompleteListener != null) {
gpxImportCompleteListener.onSaveComplete(success, result);
}
if (success) {
if (showInDetailsActivity) {
showGpxInDetailsActivity(result);
} else {
showPlanRouteFragment();
}
} else {
Toast.makeText(activity, warning, Toast.LENGTH_LONG).show();
}
}
private void showPlanRouteFragment() {
MeasurementToolFragment.showInstance(activity.getSupportFragmentManager(), result);
}
}
private MapActivity getMapActivity() {
if (activity instanceof MapActivity) {
return (MapActivity) activity;
} else {
return null;
}
}
private void showGpxInDetailsActivity(final GPXFile gpxFile) {
if (gpxFile.path != null) {
Intent newIntent = new Intent(activity, app.getAppCustomization().getTrackActivity());
newIntent.putExtra(TrackActivity.TRACK_FILE_NAME, gpxFile.path);
newIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
activity.startActivity(newIntent);
}
}
private void showGpxOnMap(final GPXFile result) {
if (mapView != null && getMapActivity() != null) {
app.getSelectedGpxHelper().setGpxFileToDisplay(result);
final 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);
}
}
}
protected void importGpxOrFavourites(final GPXFile gpxFile, final String fileName, final boolean save,
final boolean useImportDir, final boolean forceImportFavourites,
final boolean forceImportGpx) {
if (gpxFile == null || gpxFile.isPointsEmpty()) {
if (forceImportFavourites) {
final DialogInterface.OnClickListener importAsTrackListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
handleResult(gpxFile, fileName, save, useImportDir, true);
break;
case DialogInterface.BUTTON_NEGATIVE:
dialog.dismiss();
break;
}
}
};
new AlertDialog.Builder(activity)
.setTitle(R.string.import_track)
.setMessage(activity.getString(R.string.import_track_desc, fileName))
.setPositiveButton(R.string.shared_string_import, importAsTrackListener)
.setNegativeButton(R.string.shared_string_cancel, importAsTrackListener)
.show();
} else {
handleResult(gpxFile, fileName, save, useImportDir, false);
}
return;
}
if (forceImportFavourites) {
importFavoritesImpl(gpxFile, fileName, true);
} else if (fileName != null) {
if (forceImportGpx) {
handleResult(gpxFile, fileName, save, useImportDir, false);
} else {
ImportGpxBottomSheetDialogFragment fragment = new ImportGpxBottomSheetDialogFragment();
fragment.setUsedOnMap(true);
fragment.setImportHelper(this);
fragment.setGpxFile(gpxFile);
fragment.setFileName(fileName);
fragment.setSave(save);
fragment.setUseImportDir(useImportDir);
activity.getSupportFragmentManager().beginTransaction()
.add(fragment, ImportGpxBottomSheetDialogFragment.TAG)
.commitAllowingStateLoss();
}
}
}
protected static List<FavouritePoint> asFavourites(OsmandApplication app, List<WptPt> wptPts, String fileName, boolean forceImportFavourites) {
final List<FavouritePoint> favourites = new ArrayList<>();
for (WptPt p : wptPts) {
if (p.name != null) {
final String fpCat;
if (p.category == null) {
if (forceImportFavourites) {
fpCat = fileName;
} else {
fpCat = "";
}
} else {
fpCat = p.category;
}
final FavouritePoint fp = new FavouritePoint(p.lat, p.lon, p.name, fpCat);
if (p.desc != null) {
fp.setDescription(p.desc);
}
fp.setAddress(p.getExtensionsToRead().get("address"));
fp.setColor(p.getColor(0));
fp.setIconIdFromName(app, p.getIconName());
fp.setBackgroundType(BackgroundType.getByTypeName(p.getBackgroundType(), DEFAULT_BACKGROUND_TYPE));
favourites.add(fp);
}
}
return favourites;
}
@SuppressWarnings("unchecked")
private <P> void executeImportTask(final AsyncTask<P, ?, ?> importTask, final P... requests) {
if (app.isApplicationInitializing()) {
app.getAppInitializer().addListener(new AppInitializer.AppInitializeListener() {
@Override
public void onProgress(AppInitializer init, AppInitializer.InitEvents event) {
}
@Override
public void onFinish(AppInitializer init) {
importTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, requests);
}
});
} else {
importTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, requests);
}
}
}

View file

@ -0,0 +1,71 @@
package net.osmand.plus.importfiles;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentActivity;
import net.osmand.GPXUtilities;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.plus.helpers.Kml2Gpx;
import net.osmand.util.Algorithms;
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
class KmlImportTask extends BaseImportAsyncTask<Void, Void, GPXFile> {
private ImportHelper importHelper;
private Uri uri;
private String name;
private boolean save;
private boolean useImportDir;
public KmlImportTask(@NonNull ImportHelper importHelper, @NonNull FragmentActivity activity,
@NonNull Uri uri, String name, boolean save, boolean useImportDir) {
super(activity);
this.importHelper = importHelper;
this.uri = uri;
this.name = name;
this.save = save;
this.useImportDir = useImportDir;
}
@Override
protected GPXFile doInBackground(Void... nothing) {
InputStream is = null;
try {
is = app.getContentResolver().openInputStream(uri);
if (is != null) {
return loadGpxFromKml(is);
}
} catch (FileNotFoundException e) {
//
} catch (SecurityException e) {
ImportHelper.log.error(e.getMessage(), e);
} finally {
Algorithms.closeStream(is);
}
return null;
}
@Override
protected void onPostExecute(GPXFile result) {
hideProgress();
importHelper.handleResult(result, name, save, useImportDir, false);
}
protected static GPXFile loadGpxFromKml(@NonNull InputStream is) {
String result = Kml2Gpx.toGpx(is);
if (result != null) {
try {
return GPXUtilities.loadGPXFile(new ByteArrayInputStream(result.getBytes("UTF-8")));
} catch (UnsupportedEncodingException e) {
return null;
}
}
return null;
}
}

View file

@ -0,0 +1,66 @@
package net.osmand.plus.importfiles;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentActivity;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.util.Algorithms;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import static net.osmand.plus.importfiles.ImportHelper.KML_SUFFIX;
import static net.osmand.plus.importfiles.KmlImportTask.loadGpxFromKml;
class KmzImportTask extends BaseImportAsyncTask<Void, Void, GPXFile> {
private ImportHelper importHelper;
private Uri uri;
private String name;
private boolean save;
private boolean useImportDir;
public KmzImportTask(@NonNull ImportHelper importHelper, @NonNull FragmentActivity activity,
@NonNull Uri uri, @NonNull String name, boolean save, boolean useImportDir) {
super(activity);
this.importHelper = importHelper;
this.uri = uri;
this.name = name;
this.save = save;
this.useImportDir = useImportDir;
}
@Override
protected GPXFile doInBackground(Void... voids) {
InputStream is = null;
ZipInputStream zis = null;
try {
is = app.getContentResolver().openInputStream(uri);
if (is != null) {
zis = new ZipInputStream(is);
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
if (entry.getName().endsWith(KML_SUFFIX)) {
return loadGpxFromKml(is);
}
}
}
} catch (Exception e) {
ImportHelper.log.error(e.getMessage(), e);
} finally {
Algorithms.closeStream(is);
Algorithms.closeStream(zis);
}
return null;
}
@Override
protected void onPostExecute(GPXFile result) {
hideProgress();
importHelper.handleResult(result, name, save, useImportDir, false);
}
}

View file

@ -0,0 +1,52 @@
package net.osmand.plus.importfiles;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentActivity;
import net.osmand.IProgress;
import net.osmand.IndexConstants;
import net.osmand.plus.R;
import java.io.File;
import java.util.ArrayList;
class ObfImportTask extends BaseImportAsyncTask<Void, Void, String> {
private Uri uri;
private String name;
public ObfImportTask(@NonNull FragmentActivity activity, @NonNull Uri uri, @NonNull String name) {
super(activity);
this.uri = uri;
this.name = name;
}
@Override
protected String doInBackground(Void... voids) {
String error = ImportHelper.copyFile(app, getObfDestFile(name), uri, false);
if (error == null) {
app.getResourceManager().reloadIndexes(IProgress.EMPTY_PROGRESS, new ArrayList<String>());
app.getDownloadThread().updateLoadedFiles();
return app.getString(R.string.map_imported_successfully);
}
return app.getString(R.string.map_import_error) + ": " + error;
}
@Override
protected void onPostExecute(String message) {
hideProgress();
app.showShortToastMessage(message);
}
@NonNull
private File getObfDestFile(@NonNull String name) {
if (name.endsWith(IndexConstants.BINARY_ROAD_MAP_INDEX_EXT)) {
return app.getAppPath(IndexConstants.ROADS_INDEX_DIR + name);
} else if (name.endsWith(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT)) {
return app.getAppPath(IndexConstants.WIKI_INDEX_DIR + name);
}
return app.getAppPath(name);
}
}

View file

@ -0,0 +1,155 @@
package net.osmand.plus.importfiles;
import android.app.ProgressDialog;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import net.osmand.AndroidUtils;
import net.osmand.CallbackWithObject;
import net.osmand.FileUtils;
import net.osmand.IndexConstants;
import net.osmand.plus.CustomOsmandPlugin;
import net.osmand.plus.R;
import net.osmand.plus.settings.backend.SettingsHelper.CheckDuplicatesListener;
import net.osmand.plus.settings.backend.SettingsHelper.PluginSettingsItem;
import net.osmand.plus.settings.backend.SettingsHelper.ProfileSettingsItem;
import net.osmand.plus.settings.backend.SettingsHelper.SettingsCollectListener;
import net.osmand.plus.settings.backend.SettingsHelper.SettingsImportListener;
import net.osmand.plus.settings.backend.SettingsHelper.SettingsItem;
import net.osmand.plus.settings.fragments.ImportSettingsFragment;
import net.osmand.util.Algorithms;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import static net.osmand.plus.AppInitializer.loadRoutingFiles;
class SettingsImportTask extends BaseImportAsyncTask<Void, Void, String> {
private Uri uri;
private String name;
private String latestChanges;
private int version;
private CallbackWithObject<List<SettingsItem>> callback;
public SettingsImportTask(@NonNull FragmentActivity activity, @NonNull Uri uri,
@NonNull String name, String latestChanges, int version,
CallbackWithObject<List<SettingsItem>> callback) {
super(activity);
this.uri = uri;
this.name = name;
this.latestChanges = latestChanges;
this.version = version;
this.callback = callback;
}
@Override
protected String doInBackground(Void... voids) {
File tempDir = FileUtils.getTempDir(app);
File dest = new File(tempDir, name);
return ImportHelper.copyFile(app, dest, uri, true);
}
@Override
protected void onPostExecute(String error) {
File tempDir = FileUtils.getTempDir(app);
final File file = new File(tempDir, name);
if (error == null && file.exists()) {
app.getSettingsHelper().collectSettings(file, latestChanges, version, new SettingsCollectListener() {
@Override
public void onSettingsCollectFinished(boolean succeed, boolean empty, @NonNull List<SettingsItem> items) {
hideProgress();
if (succeed) {
List<SettingsItem> pluginIndependentItems = new ArrayList<>();
List<PluginSettingsItem> pluginSettingsItems = new ArrayList<>();
for (SettingsItem item : items) {
if (item instanceof PluginSettingsItem) {
pluginSettingsItems.add((PluginSettingsItem) item);
} else if (Algorithms.isEmpty(item.getPluginId())) {
pluginIndependentItems.add(item);
}
}
for (PluginSettingsItem pluginItem : pluginSettingsItems) {
handlePluginImport(pluginItem, file);
}
if (!pluginIndependentItems.isEmpty()) {
FragmentActivity activity = activityRef.get();
if (activity != null) {
FragmentManager fragmentManager = activity.getSupportFragmentManager();
ImportSettingsFragment.showInstance(fragmentManager, pluginIndependentItems, file);
}
}
} else if (empty) {
app.showShortToastMessage(app.getString(R.string.file_import_error, name, app.getString(R.string.shared_string_unexpected_error)));
}
}
});
} else {
hideProgress();
app.showShortToastMessage(app.getString(R.string.file_import_error, name, error));
}
}
private void handlePluginImport(final PluginSettingsItem pluginItem, final File file) {
FragmentActivity activity = activityRef.get();
final ProgressDialog progress;
if (AndroidUtils.isActivityNotDestroyed(activity)) {
progress = new ProgressDialog(activity);
progress.setTitle(app.getString(R.string.loading_smth, ""));
progress.setMessage(app.getString(R.string.importing_from, pluginItem.getPublicName(app)));
progress.setIndeterminate(true);
progress.setCancelable(false);
progress.show();
} else {
progress = null;
}
final SettingsImportListener importListener = new SettingsImportListener() {
@Override
public void onSettingsImportFinished(boolean succeed, @NonNull List<SettingsItem> items) {
FragmentActivity activity = activityRef.get();
if (progress != null && AndroidUtils.isActivityNotDestroyed(activity)) {
progress.dismiss();
}
CustomOsmandPlugin plugin = pluginItem.getPlugin();
plugin.loadResources();
for (SettingsItem item : items) {
if (item instanceof ProfileSettingsItem) {
((ProfileSettingsItem) item).applyAdditionalPrefs();
}
}
if (!Algorithms.isEmpty(plugin.getDownloadMaps())) {
app.getDownloadThread().runReloadIndexFilesSilent();
}
if (!Algorithms.isEmpty(plugin.getRendererNames())) {
app.getRendererRegistry().updateExternalRenderers();
}
if (!Algorithms.isEmpty(plugin.getRouterNames())) {
loadRoutingFiles(app, null);
}
if (activity != null) {
plugin.onInstall(app, activity);
}
String pluginId = pluginItem.getPluginId();
File pluginDir = new File(app.getAppPath(null), IndexConstants.PLUGINS_DIR + pluginId);
app.getSettingsHelper().exportSettings(pluginDir, "items", null, items, false);
}
};
List<SettingsItem> pluginItems = new ArrayList<>(pluginItem.getPluginDependentItems());
pluginItems.add(0, pluginItem);
app.getSettingsHelper().checkDuplicates(file, pluginItems, pluginItems, new CheckDuplicatesListener() {
@Override
public void onDuplicatesChecked(@NonNull List<Object> duplicates, List<SettingsItem> items) {
for (SettingsItem item : items) {
item.setShouldReplace(true);
}
app.getSettingsHelper().importSettings(file, items, "", 1, importListener);
}
});
}
}

View file

@ -0,0 +1,50 @@
package net.osmand.plus.importfiles;
import android.net.Uri;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentActivity;
import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.rastermaps.OsmandRasterMapsPlugin;
import static net.osmand.IndexConstants.TILES_INDEX_DIR;
class SqliteTileImportTask extends BaseImportAsyncTask<Void, Void, String> {
private Uri uri;
private String name;
public SqliteTileImportTask(@NonNull FragmentActivity activity, @NonNull Uri uri, @NonNull String name) {
super(activity);
this.uri = uri;
this.name = name;
}
@Override
protected String doInBackground(Void... voids) {
return ImportHelper.copyFile(app, app.getAppPath(TILES_INDEX_DIR + name), uri, false);
}
@Override
protected void onPostExecute(String error) {
hideProgress();
if (error == null) {
FragmentActivity activity = activityRef.get();
OsmandRasterMapsPlugin plugin = OsmandPlugin.getPlugin(OsmandRasterMapsPlugin.class);
if (plugin != null && !plugin.isActive() && !plugin.needsInstallation()) {
OsmandPlugin.enablePlugin(activity, app, plugin, true);
}
if (activity instanceof MapActivity) {
MapActivity mapActivity = (MapActivity) activity;
mapActivity.getMapLayers().selectMapLayer(mapActivity.getMapView(), null, null);
}
Toast.makeText(app, app.getString(R.string.map_imported_successfully), Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(app, app.getString(R.string.map_import_error) + ": " + error, Toast.LENGTH_SHORT).show();
}
}
}

View file

@ -0,0 +1,135 @@
package net.osmand.plus.importfiles;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentActivity;
import net.osmand.AndroidUtils;
import net.osmand.FileUtils;
import net.osmand.plus.R;
import net.osmand.plus.importfiles.ImportHelper.ImportType;
import net.osmand.util.Algorithms;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import static net.osmand.FileUtils.createUniqueFileName;
import static net.osmand.IndexConstants.BINARY_MAP_INDEX_EXT;
import static net.osmand.IndexConstants.MAPS_PATH;
import static net.osmand.IndexConstants.RENDERER_INDEX_EXT;
import static net.osmand.IndexConstants.ROUTING_FILE_EXT;
import static net.osmand.IndexConstants.SQLITE_EXT;
import static net.osmand.IndexConstants.TEMP_DIR;
import static net.osmand.IndexConstants.TILES_INDEX_DIR;
import static net.osmand.IndexConstants.ZIP_EXT;
import static net.osmand.util.Algorithms.OBF_FILE_SIGNATURE;
import static net.osmand.util.Algorithms.SQLITE_FILE_SIGNATURE;
import static net.osmand.util.Algorithms.XML_FILE_SIGNATURE;
import static net.osmand.util.Algorithms.ZIP_FILE_SIGNATURE;
class UriImportTask extends BaseImportAsyncTask<Void, Void, String> {
private ImportHelper importHelper;
private Uri uri;
private String tempFileName;
private int fileSignature;
private boolean save;
private boolean useImportDir;
public UriImportTask(@NonNull ImportHelper importHelper, @NonNull FragmentActivity activity,
@NonNull Uri uri, boolean save, boolean useImportDir) {
super(activity);
this.importHelper = importHelper;
this.uri = uri;
this.save = save;
this.useImportDir = useImportDir;
}
@Override
protected String doInBackground(Void... nothing) {
String error = null;
InputStream is = null;
OutputStream out = null;
try {
is = app.getContentResolver().openInputStream(uri);
if (is != null) {
fileSignature = Algorithms.readInt(is);
if (isSupportedFileSignature()) {
File tempDir = FileUtils.getTempDir(app);
tempFileName = getTempFileName();
File dest = new File(tempDir, tempFileName);
out = new FileOutputStream(dest);
Algorithms.writeInt(out, Integer.reverseBytes(fileSignature));
Algorithms.streamCopy(is, out);
}
}
} catch (FileNotFoundException e) {
ImportHelper.log.error(e);
error = e.getMessage();
} catch (SecurityException e) {
ImportHelper.log.error(e);
error = e.getMessage();
} catch (IOException e) {
ImportHelper.log.error(e);
error = e.getMessage();
} finally {
Algorithms.closeStream(is);
Algorithms.closeStream(out);
}
return error;
}
private boolean isSupportedFileSignature() {
return fileSignature == XML_FILE_SIGNATURE || fileSignature == OBF_FILE_SIGNATURE
|| fileSignature == ZIP_FILE_SIGNATURE || fileSignature == SQLITE_FILE_SIGNATURE;
}
@Override
protected void onPostExecute(String error) {
hideProgress();
File file = app.getAppPath(TEMP_DIR + tempFileName);
if (error == null && file.exists()) {
Uri tempUri = AndroidUtils.getUriForFile(app, file);
if (XML_FILE_SIGNATURE == fileSignature) {
ImportType importType = XmlImportTask.checkImportType(app, tempUri);
if (importType == ImportType.RENDERING || importType == ImportType.ROUTING) {
String name = importType == ImportType.RENDERING ? "renderer" + RENDERER_INDEX_EXT : "router" + ROUTING_FILE_EXT;
importHelper.handleXmlFileImport(tempUri, name, null);
} else if (importType == ImportType.GPX || importType == ImportType.KML) {
importHelper.handleGpxOrFavouritesImport(tempUri, tempFileName, save, useImportDir, false, false);
}
} else if (OBF_FILE_SIGNATURE == fileSignature) {
String name = createUniqueFileName(app, "map", MAPS_PATH, BINARY_MAP_INDEX_EXT);
importHelper.handleObfImport(tempUri, name + BINARY_MAP_INDEX_EXT);
} else if (ZIP_FILE_SIGNATURE == fileSignature) {
importHelper.handleZipImport(tempUri, save, useImportDir);
} else if (SQLITE_FILE_SIGNATURE == fileSignature) {
String name = createUniqueFileName(app, "online_map", TILES_INDEX_DIR, SQLITE_EXT);
importHelper.handleSqliteTileImport(tempUri, name + SQLITE_EXT);
}
} else {
app.showShortToastMessage(app.getString(R.string.file_import_error, tempFileName, error));
}
}
private String getTempFileName() {
if (XML_FILE_SIGNATURE == fileSignature) {
return createUniqueFileName(app, "xml_file", TEMP_DIR, ROUTING_FILE_EXT) + ROUTING_FILE_EXT;
} else if (OBF_FILE_SIGNATURE == fileSignature) {
return createUniqueFileName(app, "map", TEMP_DIR, BINARY_MAP_INDEX_EXT) + BINARY_MAP_INDEX_EXT;
} else if (ZIP_FILE_SIGNATURE == fileSignature) {
return createUniqueFileName(app, "zip_file", TEMP_DIR, ZIP_EXT) + ZIP_EXT;
} else if (SQLITE_FILE_SIGNATURE == fileSignature) {
return createUniqueFileName(app, "online_map", TEMP_DIR, SQLITE_EXT) + SQLITE_EXT;
}
return "";
}
}

View file

@ -0,0 +1,156 @@
package net.osmand.plus.importfiles;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity;
import net.osmand.AndroidUtils;
import net.osmand.CallbackWithObject;
import net.osmand.IndexConstants;
import net.osmand.PlatformUtil;
import net.osmand.plus.AppInitializer.LoadRoutingFilesCallback;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.importfiles.ImportHelper.ImportType;
import net.osmand.router.RoutingConfiguration.Builder;
import net.osmand.util.Algorithms;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import static net.osmand.IndexConstants.RENDERER_INDEX_EXT;
import static net.osmand.plus.AppInitializer.loadRoutingFiles;
class XmlImportTask extends BaseImportAsyncTask<Void, Void, String> {
private Uri uri;
private String destFileName;
private ImportType importType;
private CallbackWithObject routingCallback;
public XmlImportTask(@NonNull FragmentActivity activity, @NonNull Uri uri,
@NonNull String fileName, @Nullable CallbackWithObject routingCallback) {
super(activity);
this.uri = uri;
this.destFileName = fileName;
this.routingCallback = routingCallback;
}
@Override
protected String doInBackground(Void... voids) {
importType = checkImportType(app, uri);
if (importType != null) {
File dest = getDestinationFile();
if (dest != null) {
return ImportHelper.copyFile(app, dest, uri, true);
}
}
return app.getString(R.string.file_import_error, destFileName, app.getString(R.string.unsupported_type_error));
}
@Override
protected void onPostExecute(String error) {
File destDir = getDestinationDir();
File file = new File(destDir, destFileName);
if (error == null && file.exists()) {
if (importType == ImportType.RENDERING) {
app.getRendererRegistry().updateExternalRenderers();
app.showShortToastMessage(app.getString(R.string.file_imported_successfully, destFileName));
hideProgress();
} else if (importType == ImportType.ROUTING) {
loadRoutingFiles(app, new LoadRoutingFilesCallback() {
@Override
public void onRoutingFilesLoaded() {
hideProgress();
Builder builder = app.getCustomRoutingConfig(destFileName);
if (builder != null) {
if (routingCallback != null) {
routingCallback.processResult(builder);
}
app.showShortToastMessage(app.getString(R.string.file_imported_successfully, destFileName));
} else {
app.showToastMessage(app.getString(R.string.file_does_not_contain_routing_rules, destFileName));
}
}
});
}
} else {
hideProgress();
app.showShortToastMessage(app.getString(R.string.file_import_error, destFileName, error));
}
}
private File getDestinationDir() {
if (importType == ImportType.ROUTING) {
return app.getAppPath(IndexConstants.ROUTING_PROFILES_DIR);
} else if (importType == ImportType.RENDERING) {
return app.getAppPath(IndexConstants.RENDERERS_DIR);
}
return null;
}
private File getDestinationFile() {
File destDir = getDestinationDir();
if (destDir != null) {
if (!destDir.exists()) {
destDir.mkdirs();
}
if (importType == ImportType.RENDERING && !destFileName.endsWith(RENDERER_INDEX_EXT)) {
String fileName = Algorithms.getFileNameWithoutExtension(destFileName);
destFileName = fileName + RENDERER_INDEX_EXT;
}
File destFile = new File(destDir, destFileName);
while (destFile.exists()) {
destFileName = AndroidUtils.createNewFileName(destFileName);
destFile = new File(destDir, destFileName);
}
return destFile;
}
return null;
}
protected static ImportType checkImportType(OsmandApplication app, Uri uri) {
ImportType importType = null;
InputStream is = null;
try {
is = app.getContentResolver().openInputStream(uri);
if (is != null) {
XmlPullParser parser = PlatformUtil.newXMLPullParser();
parser.setInput(is, "UTF-8");
int tok;
while ((tok = parser.next()) != XmlPullParser.END_DOCUMENT) {
if (tok == XmlPullParser.START_TAG) {
String name = parser.getName();
if ("osmand_routing_config".equals(name)) {
importType = ImportType.ROUTING;
} else if ("renderingStyle".equals(name)) {
importType = ImportType.RENDERING;
} else if ("gpx".equals(name)) {
importType = ImportType.GPX;
} else if ("kml".equals(name)) {
importType = ImportType.KML;
}
break;
}
}
Algorithms.closeStream(is);
}
} catch (FileNotFoundException | XmlPullParserException e) {
ImportHelper.log.error(e);
} catch (IOException e) {
ImportHelper.log.error(e);
} catch (SecurityException e) {
ImportHelper.log.error(e.getMessage(), e);
} finally {
Algorithms.closeStream(is);
}
return importType;
}
}

View file

@ -0,0 +1,90 @@
package net.osmand.plus.importfiles;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentActivity;
import net.osmand.plus.importfiles.ImportHelper.ImportType;
import net.osmand.util.Algorithms;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import static net.osmand.FileUtils.createUniqueFileName;
import static net.osmand.IndexConstants.GPX_FILE_EXT;
import static net.osmand.IndexConstants.GPX_IMPORT_DIR;
import static net.osmand.IndexConstants.GPX_INDEX_DIR;
import static net.osmand.IndexConstants.OSMAND_SETTINGS_FILE_EXT;
import static net.osmand.IndexConstants.TEMP_DIR;
import static net.osmand.plus.importfiles.ImportHelper.KML_SUFFIX;
public class ZipImportTask extends BaseImportAsyncTask<Void, Void, ImportType> {
private ImportHelper importHelper;
private Uri uri;
private boolean save;
private boolean useImportDir;
public ZipImportTask(@NonNull ImportHelper importHelper, @NonNull FragmentActivity activity,
@NonNull Uri uri, boolean save, boolean useImportDir) {
super(activity);
this.importHelper = importHelper;
this.uri = uri;
this.save = save;
this.useImportDir = useImportDir;
}
@Override
protected ImportType doInBackground(Void... voids) {
ImportType importType = null;
InputStream is = null;
ZipInputStream zis = null;
try {
is = app.getContentResolver().openInputStream(uri);
if (is != null) {
zis = new ZipInputStream(is);
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
String fileName = checkEntryName(entry.getName());
if (fileName.endsWith(KML_SUFFIX)) {
importType = ImportType.KMZ;
break;
} else if (fileName.equals("items.json")) {
importType = ImportType.SETTINGS;
break;
}
}
}
} catch (Exception e) {
ImportHelper.log.error(e.getMessage(), e);
} finally {
Algorithms.closeStream(is);
Algorithms.closeStream(zis);
}
return importType;
}
private String checkEntryName(String entryName) {
String fileExt = OSMAND_SETTINGS_FILE_EXT + "/";
int index = entryName.indexOf(fileExt);
if (index != -1) {
entryName = entryName.substring(index + fileExt.length());
}
return entryName;
}
@Override
protected void onPostExecute(ImportType importType) {
hideProgress();
if (importType == ImportType.KMZ) {
String dir = useImportDir ? GPX_IMPORT_DIR : GPX_INDEX_DIR;
String name = createUniqueFileName(app, "track", dir, GPX_FILE_EXT);
importHelper.handleKmzImport(uri, name + GPX_FILE_EXT, save, useImportDir);
} else if (importType == ImportType.SETTINGS) {
String name = createUniqueFileName(app, "settings", TEMP_DIR, OSMAND_SETTINGS_FILE_EXT);
importHelper.handleOsmAndSettingsImport(uri, name + OSMAND_SETTINGS_FILE_EXT, null, -1, null);
}
}
}

View file

@ -28,8 +28,8 @@ import net.osmand.plus.base.bottomsheetmenu.simpleitems.DividerItem;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem;
import net.osmand.plus.helpers.GpxTrackAdapter;
import net.osmand.plus.helpers.GpxUiHelper.GPXInfo;
import net.osmand.plus.helpers.ImportHelper;
import net.osmand.plus.helpers.ImportHelper.OnGpxImportCompleteListener;
import net.osmand.plus.importfiles.ImportHelper;
import net.osmand.plus.importfiles.ImportHelper.OnGpxImportCompleteListener;
import org.apache.commons.logging.Log;

View file

@ -30,8 +30,8 @@ import net.osmand.plus.R;
import net.osmand.plus.activities.FavoritesTreeFragment;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.activities.TabActivity;
import net.osmand.plus.helpers.ImportHelper;
import net.osmand.plus.helpers.ImportHelper.OnGpxImportCompleteListener;
import net.osmand.plus.importfiles.ImportHelper;
import net.osmand.plus.importfiles.ImportHelper.OnGpxImportCompleteListener;
import net.osmand.plus.settings.backend.OsmAndAppCustomization;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.views.controls.PagerSlidingTabStrip;

View file

@ -40,7 +40,7 @@ import org.apache.commons.logging.Log;
import java.util.ArrayList;
import java.util.List;
import static net.osmand.plus.helpers.ImportHelper.ImportType.ROUTING;
import static net.osmand.plus.importfiles.ImportHelper.ImportType.ROUTING;
public class SelectProfileBottomSheetDialogFragment extends BasePreferenceBottomSheet {

View file

@ -40,8 +40,8 @@ import net.osmand.plus.base.ContextMenuScrollFragment;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.helpers.GpxUiHelper;
import net.osmand.plus.helpers.GpxUiHelper.GPXInfo;
import net.osmand.plus.helpers.ImportHelper;
import net.osmand.plus.helpers.ImportHelper.OnGpxImportCompleteListener;
import net.osmand.plus.importfiles.ImportHelper;
import net.osmand.plus.importfiles.ImportHelper.OnGpxImportCompleteListener;
import net.osmand.plus.measurementtool.GpxData;
import net.osmand.plus.measurementtool.GpxData.ActionType;
import net.osmand.plus.measurementtool.MeasurementEditingContext;

View file

@ -31,7 +31,7 @@ import net.osmand.plus.activities.PluginsActivity;
import net.osmand.plus.activities.SettingsActivity;
import net.osmand.plus.activities.TrackActivity;
import net.osmand.plus.download.DownloadActivity;
import net.osmand.plus.helpers.ImportHelper;
import net.osmand.plus.importfiles.ImportHelper;
import net.osmand.plus.helpers.WaypointHelper;
import net.osmand.plus.myplaces.FavoritesActivity;
import net.osmand.plus.routing.RouteCalculationResult;

View file

@ -2637,6 +2637,89 @@ public class SettingsHelper {
}
}
public static Map<ExportSettingsType, List<?>> getSettingsToOperate(List<SettingsItem> settingsItems, boolean importComplete) {
Map<ExportSettingsType, List<?>> settingsToOperate = new HashMap<>();
List<ApplicationModeBean> profiles = new ArrayList<>();
List<QuickAction> quickActions = new ArrayList<>();
List<PoiUIFilter> poiUIFilters = new ArrayList<>();
List<ITileSource> tileSourceTemplates = new ArrayList<>();
List<File> routingFilesList = new ArrayList<>();
List<File> renderFilesList = new ArrayList<>();
List<AvoidRoadInfo> avoidRoads = new ArrayList<>();
for (SettingsItem item : settingsItems) {
switch (item.getType()) {
case PROFILE:
profiles.add(((ProfileSettingsItem) item).getModeBean());
break;
case FILE:
FileSettingsItem fileItem = (FileSettingsItem) item;
if (fileItem.getSubtype() == FileSettingsItem.FileSubtype.RENDERING_STYLE) {
renderFilesList.add(fileItem.getFile());
} else if (fileItem.getSubtype() == FileSettingsItem.FileSubtype.ROUTING_CONFIG) {
routingFilesList.add(fileItem.getFile());
}
break;
case QUICK_ACTIONS:
QuickActionsSettingsItem quickActionsItem = (QuickActionsSettingsItem) item;
if (importComplete) {
quickActions.addAll(quickActionsItem.getAppliedItems());
} else {
quickActions.addAll(quickActionsItem.getItems());
}
break;
case POI_UI_FILTERS:
PoiUiFiltersSettingsItem poiUiFilterItem = (PoiUiFiltersSettingsItem) item;
if (importComplete) {
poiUIFilters.addAll(poiUiFilterItem.getAppliedItems());
} else {
poiUIFilters.addAll(poiUiFilterItem.getItems());
}
break;
case MAP_SOURCES:
MapSourcesSettingsItem mapSourcesItem = (MapSourcesSettingsItem) item;
if (importComplete) {
tileSourceTemplates.addAll(mapSourcesItem.getAppliedItems());
} else {
tileSourceTemplates.addAll(mapSourcesItem.getItems());
}
break;
case AVOID_ROADS:
AvoidRoadsSettingsItem avoidRoadsItem = (AvoidRoadsSettingsItem) item;
if (importComplete) {
avoidRoads.addAll(avoidRoadsItem.getAppliedItems());
} else {
avoidRoads.addAll(avoidRoadsItem.getItems());
}
break;
default:
break;
}
}
if (!profiles.isEmpty()) {
settingsToOperate.put(ExportSettingsType.PROFILE, profiles);
}
if (!quickActions.isEmpty()) {
settingsToOperate.put(ExportSettingsType.QUICK_ACTIONS, quickActions);
}
if (!poiUIFilters.isEmpty()) {
settingsToOperate.put(ExportSettingsType.POI_TYPES, poiUIFilters);
}
if (!tileSourceTemplates.isEmpty()) {
settingsToOperate.put(ExportSettingsType.MAP_SOURCES, tileSourceTemplates);
}
if (!renderFilesList.isEmpty()) {
settingsToOperate.put(ExportSettingsType.CUSTOM_RENDER_STYLE, renderFilesList);
}
if (!routingFilesList.isEmpty()) {
settingsToOperate.put(ExportSettingsType.CUSTOM_ROUTING, routingFilesList);
}
if (!avoidRoads.isEmpty()) {
settingsToOperate.put(ExportSettingsType.AVOID_ROADS, avoidRoads);
}
return settingsToOperate;
}
@SuppressLint("StaticFieldLeak")
public class ImportAsyncTask extends AsyncTask<Void, Void, List<SettingsItem>> {

View file

@ -22,9 +22,6 @@ import androidx.recyclerview.widget.RecyclerView;
import net.osmand.AndroidUtils;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.helpers.ImportHelper;
import net.osmand.plus.settings.backend.ExportSettingsType;
import net.osmand.plus.settings.backend.SettingsHelper.SettingsItem;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.base.BaseOsmAndFragment;
@ -33,6 +30,9 @@ import net.osmand.plus.dialogs.SelectMapStyleBottomSheetDialogFragment;
import net.osmand.plus.quickaction.QuickActionListFragment;
import net.osmand.plus.routepreparationmenu.AvoidRoadsBottomSheetDialogFragment;
import net.osmand.plus.search.QuickSearchDialogFragment;
import net.osmand.plus.settings.backend.ExportSettingsType;
import net.osmand.plus.settings.backend.SettingsHelper;
import net.osmand.plus.settings.backend.SettingsHelper.SettingsItem;
import java.util.List;
@ -118,7 +118,7 @@ public class ImportCompleteFragment extends BaseOsmAndFragment {
if (settingsItems != null) {
ImportedSettingsItemsAdapter adapter = new ImportedSettingsItemsAdapter(
app,
ImportHelper.getSettingsToOperate(settingsItems, true),
SettingsHelper.getSettingsToOperate(settingsItems, true),
nightMode,
new ImportedSettingsItemsAdapter.OnItemClickListener() {
@Override

View file

@ -34,8 +34,14 @@ import net.osmand.plus.AppInitializer;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.SQLiteTileSource;
import net.osmand.plus.settings.backend.ExportSettingsType;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.base.BaseOsmAndFragment;
import net.osmand.plus.helpers.AvoidSpecificRoads.AvoidRoadInfo;
import net.osmand.plus.poi.PoiUIFilter;
import net.osmand.plus.quickaction.QuickAction;
import net.osmand.plus.settings.backend.ApplicationMode.ApplicationModeBean;
import net.osmand.plus.settings.backend.ExportSettingsType;
import net.osmand.plus.settings.backend.SettingsHelper;
import net.osmand.plus.settings.backend.SettingsHelper.AvoidRoadsSettingsItem;
import net.osmand.plus.settings.backend.SettingsHelper.FileSettingsItem;
@ -47,12 +53,6 @@ import net.osmand.plus.settings.backend.SettingsHelper.ProfileSettingsItem;
import net.osmand.plus.settings.backend.SettingsHelper.QuickActionsSettingsItem;
import net.osmand.plus.settings.backend.SettingsHelper.SettingsItem;
import net.osmand.plus.settings.backend.SettingsHelper.SettingsItemType;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.base.BaseOsmAndFragment;
import net.osmand.plus.helpers.AvoidSpecificRoads.AvoidRoadInfo;
import net.osmand.plus.poi.PoiUIFilter;
import net.osmand.plus.quickaction.QuickAction;
import net.osmand.plus.widgets.TextViewEx;
import net.osmand.util.Algorithms;
@ -64,7 +64,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static net.osmand.plus.helpers.ImportHelper.getSettingsToOperate;
public class ImportSettingsFragment extends BaseOsmAndFragment
implements View.OnClickListener {
@ -183,7 +182,7 @@ public class ImportSettingsFragment extends BaseOsmAndFragment
adapter = new ExportImportSettingsAdapter(app, nightMode, true);
Map<ExportSettingsType, List<?>> itemsMap = new HashMap<>();
if (settingsItems != null) {
itemsMap = getSettingsToOperate(settingsItems, false);
itemsMap = SettingsHelper.getSettingsToOperate(settingsItems, false);
adapter.updateSettingsList(itemsMap);
}
expandableList.setAdapter(adapter);

View file

@ -32,7 +32,7 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import static net.osmand.plus.helpers.ImportHelper.ImportType.SETTINGS;
import static net.osmand.plus.importfiles.ImportHelper.ImportType.SETTINGS;
import static net.osmand.plus.profiles.SelectProfileBottomSheetDialogFragment.DIALOG_TYPE;
import static net.osmand.plus.profiles.SelectProfileBottomSheetDialogFragment.IS_PROFILE_IMPORTED_ARG;
import static net.osmand.plus.profiles.SelectProfileBottomSheetDialogFragment.PROFILE_KEY_ARG;