Finished backup test activity
This commit is contained in:
parent
295c6c4df4
commit
1629183994
19 changed files with 1736 additions and 495 deletions
|
@ -42,6 +42,7 @@
|
|||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/main_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
|
@ -121,6 +122,13 @@
|
|||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="@dimen/default_list_text_size" />
|
||||
|
||||
<include
|
||||
android:id="@+id/btn_refresh"
|
||||
layout="@layout/bottom_sheet_dialog_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dialog_button_height"
|
||||
android:layout_marginTop="@dimen/content_padding_half" />
|
||||
|
||||
<include
|
||||
android:id="@+id/btn_backup"
|
||||
layout="@layout/bottom_sheet_dialog_button"
|
||||
|
|
|
@ -3,10 +3,10 @@ package net.osmand;
|
|||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import net.osmand.osm.io.NetworkUtils;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
|
@ -38,6 +38,7 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
public class AndroidNetworkUtils {
|
||||
|
@ -56,6 +57,15 @@ public class AndroidNetworkUtils {
|
|||
void onFilesUploadDone(@NonNull Map<File, String> errors);
|
||||
}
|
||||
|
||||
public interface OnFilesDownloadCallback {
|
||||
@Nullable
|
||||
Map<String, String> getAdditionalParams(@NonNull File file);
|
||||
void onFileDownloadProgress(@NonNull File file, int percent);
|
||||
@WorkerThread
|
||||
void onFileDownloadedAsync(@NonNull File file);
|
||||
void onFilesDownloadDone(@NonNull Map<File, String> errors);
|
||||
}
|
||||
|
||||
public static class RequestResponse {
|
||||
private Request request;
|
||||
private String response;
|
||||
|
@ -74,35 +84,46 @@ public class AndroidNetworkUtils {
|
|||
}
|
||||
}
|
||||
|
||||
public interface OnRequestsResultListener {
|
||||
void onResult(@NonNull List<RequestResponse> results);
|
||||
public interface OnSendRequestsListener {
|
||||
void onRequestSent(@NonNull RequestResponse response);
|
||||
void onRequestsSent(@NonNull List<RequestResponse> results);
|
||||
}
|
||||
|
||||
public static void sendRequestsAsync(final OsmandApplication ctx,
|
||||
final List<Request> requests,
|
||||
final OnRequestsResultListener listener) {
|
||||
public static void sendRequestsAsync(@Nullable final OsmandApplication ctx,
|
||||
@NonNull final List<Request> requests,
|
||||
@Nullable final OnSendRequestsListener listener) {
|
||||
|
||||
new AsyncTask<Void, Void, List<RequestResponse>>() {
|
||||
new AsyncTask<Void, RequestResponse, List<RequestResponse>>() {
|
||||
|
||||
@Override
|
||||
protected List<RequestResponse> doInBackground(Void... params) {
|
||||
List<RequestResponse> responses = new ArrayList<>();
|
||||
for (Request request : requests) {
|
||||
RequestResponse requestResponse;
|
||||
try {
|
||||
String response = sendRequest(ctx, request.getUrl(), request.getParameters(),
|
||||
request.getUserOperation(), request.isToastAllowed(), request.isPost());
|
||||
responses.add(new RequestResponse(request, response));
|
||||
requestResponse = new RequestResponse(request, response);
|
||||
} catch (Exception e) {
|
||||
responses.add(new RequestResponse(request, null));
|
||||
requestResponse = new RequestResponse(request, null);
|
||||
}
|
||||
responses.add(requestResponse);
|
||||
publishProgress(requestResponse);
|
||||
}
|
||||
return responses;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(RequestResponse... values) {
|
||||
if (listener != null) {
|
||||
listener.onRequestSent(values[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(@NonNull List<RequestResponse> results) {
|
||||
if (listener != null) {
|
||||
listener.onResult(results);
|
||||
listener.onRequestsSent(results);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,7 +167,7 @@ public class AndroidNetworkUtils {
|
|||
|
||||
@Override
|
||||
protected String doInBackground(Void... params) {
|
||||
return downloadFile(url, fileToSave);
|
||||
return downloadFile(url, fileToSave, false, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -158,8 +179,80 @@ public class AndroidNetworkUtils {
|
|||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
|
||||
}
|
||||
|
||||
public static String sendRequest(OsmandApplication ctx, String url, Map<String, String> parameters,
|
||||
String userOperation, boolean toastAllowed, boolean post) {
|
||||
public static void downloadFilesAsync(final @NonNull String url,
|
||||
final @NonNull List<File> files,
|
||||
final @NonNull Map<String, String> parameters,
|
||||
final @Nullable OnFilesDownloadCallback callback) {
|
||||
|
||||
new AsyncTask<Void, Object, Map<File, String>>() {
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
protected Map<File, String> doInBackground(Void... v) {
|
||||
Map<File, String> errors = new HashMap<>();
|
||||
for (final File file : files) {
|
||||
final int[] progressValue = {0};
|
||||
publishProgress(file, 0);
|
||||
IProgress progress = null;
|
||||
if (callback != null) {
|
||||
progress = new NetworkProgress() {
|
||||
@Override
|
||||
public void progress(int deltaWork) {
|
||||
progressValue[0] += deltaWork;
|
||||
publishProgress(file, progressValue[0]);
|
||||
}
|
||||
};
|
||||
}
|
||||
try {
|
||||
Map<String, String> params = new HashMap<>(parameters);
|
||||
if (callback != null) {
|
||||
Map<String, String> additionalParams = callback.getAdditionalParams(file);
|
||||
if (additionalParams != null) {
|
||||
params.putAll(additionalParams);
|
||||
}
|
||||
}
|
||||
boolean firstPrm = !url.contains("?");
|
||||
StringBuilder sb = new StringBuilder(url);
|
||||
for (Entry<String, String> entry : params.entrySet()) {
|
||||
sb.append(firstPrm ? "?" : "&").append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue(), "UTF-8"));
|
||||
firstPrm = false;
|
||||
}
|
||||
String res = downloadFile(sb.toString(), file, true, progress);
|
||||
if (res != null) {
|
||||
errors.put(file, res);
|
||||
} else {
|
||||
if (callback != null) {
|
||||
callback.onFileDownloadedAsync(file);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
errors.put(file, e.getMessage());
|
||||
}
|
||||
publishProgress(file, Integer.MAX_VALUE);
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(Object... objects) {
|
||||
if (callback != null) {
|
||||
callback.onFileDownloadProgress((File) objects[0], (Integer) objects[1]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(@NonNull Map<File, String> errors) {
|
||||
if (callback != null) {
|
||||
callback.onFilesDownloadDone(errors);
|
||||
}
|
||||
}
|
||||
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
|
||||
}
|
||||
|
||||
public static String sendRequest(@Nullable OsmandApplication ctx, @NonNull String url,
|
||||
@Nullable Map<String, String> parameters,
|
||||
@Nullable String userOperation, boolean toastAllowed, boolean post) {
|
||||
HttpURLConnection connection = null;
|
||||
try {
|
||||
|
||||
|
@ -177,7 +270,7 @@ public class AndroidNetworkUtils {
|
|||
String paramsSeparator = url.indexOf('?') == -1 ? "?" : "&";
|
||||
connection = NetworkUtils.getHttpURLConnection(params == null || post ? url : url + paramsSeparator + params);
|
||||
connection.setRequestProperty("Accept-Charset", "UTF-8");
|
||||
connection.setRequestProperty("User-Agent", Version.getFullVersion(ctx));
|
||||
connection.setRequestProperty("User-Agent", ctx != null ? Version.getFullVersion(ctx) : "OsmAnd");
|
||||
connection.setConnectTimeout(15000);
|
||||
if (params != null && post) {
|
||||
connection.setDoInput(true);
|
||||
|
@ -200,9 +293,10 @@ public class AndroidNetworkUtils {
|
|||
}
|
||||
|
||||
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
|
||||
if (toastAllowed) {
|
||||
String msg = userOperation
|
||||
+ " " + ctx.getString(R.string.failed_op) + ": " + connection.getResponseMessage();
|
||||
if (toastAllowed && ctx != null) {
|
||||
String msg = (!Algorithms.isEmpty(userOperation) ? userOperation + " " : "")
|
||||
+ ctx.getString(R.string.failed_op) + ": "
|
||||
+ connection.getResponseMessage();
|
||||
showToast(ctx, msg);
|
||||
}
|
||||
} else {
|
||||
|
@ -233,17 +327,17 @@ public class AndroidNetworkUtils {
|
|||
|
||||
} catch (NullPointerException e) {
|
||||
// that's tricky case why NPE is thrown to fix that problem httpClient could be used
|
||||
if (toastAllowed) {
|
||||
if (toastAllowed && ctx != null) {
|
||||
String msg = ctx.getString(R.string.auth_failed);
|
||||
showToast(ctx, msg);
|
||||
}
|
||||
} catch (MalformedURLException e) {
|
||||
if (toastAllowed) {
|
||||
if (toastAllowed && ctx != null) {
|
||||
showToast(ctx, MessageFormat.format(ctx.getResources().getString(R.string.shared_string_action_template)
|
||||
+ ": " + ctx.getResources().getString(R.string.shared_string_unexpected_error), userOperation));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (toastAllowed) {
|
||||
if (toastAllowed && ctx != null) {
|
||||
showToast(ctx, MessageFormat.format(ctx.getResources().getString(R.string.shared_string_action_template)
|
||||
+ ": " + ctx.getResources().getString(R.string.shared_string_io_error), userOperation));
|
||||
}
|
||||
|
@ -277,18 +371,23 @@ public class AndroidNetworkUtils {
|
|||
return res;
|
||||
}
|
||||
|
||||
public static String downloadFile(@NonNull String url, @NonNull File fileToSave) {
|
||||
public static String downloadFile(@NonNull String url, @NonNull File fileToSave, boolean gzip, @Nullable IProgress progress) {
|
||||
String error = null;
|
||||
try {
|
||||
URLConnection connection = NetworkUtils.getHttpURLConnection(url);
|
||||
connection.setConnectTimeout(CONNECTION_TIMEOUT);
|
||||
connection.setReadTimeout(CONNECTION_TIMEOUT);
|
||||
BufferedInputStream inputStream = new BufferedInputStream(connection.getInputStream(), 8 * 1024);
|
||||
if (gzip) {
|
||||
connection.setRequestProperty("Accept-Encoding", "deflate, gzip");
|
||||
}
|
||||
InputStream inputStream = gzip
|
||||
? new GZIPInputStream(connection.getInputStream())
|
||||
: new BufferedInputStream(connection.getInputStream(), 8 * 1024);
|
||||
fileToSave.getParentFile().mkdirs();
|
||||
OutputStream stream = null;
|
||||
try {
|
||||
stream = new FileOutputStream(fileToSave);
|
||||
Algorithms.streamCopy(inputStream, stream);
|
||||
Algorithms.streamCopy(inputStream, stream, progress, 1024);
|
||||
stream.flush();
|
||||
} finally {
|
||||
Algorithms.closeStream(inputStream);
|
||||
|
@ -307,12 +406,17 @@ public class AndroidNetworkUtils {
|
|||
private static final String BOUNDARY = "CowMooCowMooCowCowCow";
|
||||
|
||||
public static String uploadFile(@NonNull String urlText, @NonNull File file, boolean gzip,
|
||||
@NonNull Map<String, String> additionalParams, @Nullable Map<String, String> headers) throws IOException {
|
||||
return uploadFile(urlText, new FileInputStream(file), file.getName(), gzip, additionalParams, headers);
|
||||
@NonNull Map<String, String> additionalParams,
|
||||
@Nullable Map<String, String> headers,
|
||||
@Nullable IProgress progress) throws IOException {
|
||||
return uploadFile(urlText, new FileInputStream(file), file.getName(), gzip, additionalParams, headers, progress);
|
||||
}
|
||||
|
||||
public static String uploadFile(@NonNull String urlText, @NonNull InputStream inputStream, @NonNull String fileName, boolean gzip,
|
||||
Map<String, String> additionalParams, @Nullable Map<String, String> headers) {
|
||||
public static String uploadFile(@NonNull String urlText, @NonNull InputStream inputStream,
|
||||
@NonNull String fileName, boolean gzip,
|
||||
@NonNull Map<String, String> additionalParams,
|
||||
@Nullable Map<String, String> headers,
|
||||
@Nullable IProgress progress) {
|
||||
URL url;
|
||||
try {
|
||||
boolean firstPrm = !urlText.contains("?");
|
||||
|
@ -350,11 +454,11 @@ public class AndroidNetworkUtils {
|
|||
ous.flush();
|
||||
if (gzip) {
|
||||
GZIPOutputStream gous = new GZIPOutputStream(ous, 1024);
|
||||
Algorithms.streamCopy(bis, gous);
|
||||
Algorithms.streamCopy(bis, gous, progress, 1024);
|
||||
gous.flush();
|
||||
gous.finish();
|
||||
} else {
|
||||
Algorithms.streamCopy(bis, ous);
|
||||
Algorithms.streamCopy(bis, ous, progress, 1024);
|
||||
}
|
||||
|
||||
ous.write(("\r\n--" + BOUNDARY + "--\r\n").getBytes());
|
||||
|
@ -406,8 +510,19 @@ public class AndroidNetworkUtils {
|
|||
@NonNull
|
||||
protected Map<File, String> doInBackground(Void... v) {
|
||||
Map<File, String> errors = new HashMap<>();
|
||||
for (File file : files) {
|
||||
for (final File file : files) {
|
||||
final int[] progressValue = {0};
|
||||
publishProgress(file, 0);
|
||||
IProgress progress = null;
|
||||
if (callback != null) {
|
||||
progress = new NetworkProgress() {
|
||||
@Override
|
||||
public void progress(int deltaWork) {
|
||||
progressValue[0] += deltaWork;
|
||||
publishProgress(file, progressValue[0]);
|
||||
}
|
||||
};
|
||||
}
|
||||
try {
|
||||
Map<String, String> params = new HashMap<>(parameters);
|
||||
if (callback != null) {
|
||||
|
@ -416,14 +531,14 @@ public class AndroidNetworkUtils {
|
|||
params.putAll(additionalParams);
|
||||
}
|
||||
}
|
||||
String res = uploadFile(url, file, gzip, params, headers);
|
||||
String res = uploadFile(url, file, gzip, params, headers, progress);
|
||||
if (res != null) {
|
||||
errors.put(file, res);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
errors.put(file, e.getMessage());
|
||||
}
|
||||
publishProgress(file, 100);
|
||||
publishProgress(file, Integer.MAX_VALUE);
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
@ -484,4 +599,39 @@ public class AndroidNetworkUtils {
|
|||
return post;
|
||||
}
|
||||
}
|
||||
|
||||
private abstract static class NetworkProgress implements IProgress {
|
||||
@Override
|
||||
public void startTask(String taskName, int work) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startWork(int work) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract void progress(int deltaWork);
|
||||
|
||||
@Override
|
||||
public void remaining(int remainingWork) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishTask() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIndeterminate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInterrupted() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGeneralProgress(String genProgress) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -184,7 +184,8 @@ public class AnalyticsHelper extends SQLiteOpenHelper {
|
|||
|
||||
String jsonStr = json.toString();
|
||||
InputStream inputStream = new ByteArrayInputStream(jsonStr.getBytes());
|
||||
String res = AndroidNetworkUtils.uploadFile(ANALYTICS_UPLOAD_URL, inputStream, ANALYTICS_FILE_NAME, true, additionalData, null);
|
||||
String res = AndroidNetworkUtils.uploadFile(ANALYTICS_UPLOAD_URL, inputStream,
|
||||
ANALYTICS_FILE_NAME, true, additionalData, null, null);
|
||||
if (res != null) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import net.osmand.osm.MapPoiTypes;
|
|||
import net.osmand.plus.activities.LocalIndexHelper;
|
||||
import net.osmand.plus.activities.LocalIndexInfo;
|
||||
import net.osmand.plus.activities.SavingTrackHelper;
|
||||
import net.osmand.plus.backup.BackupHelper;
|
||||
import net.osmand.plus.base.MapViewTrackingUtilities;
|
||||
import net.osmand.plus.download.DownloadActivity;
|
||||
import net.osmand.plus.download.ui.AbstractLoadLocalIndexTask;
|
||||
|
@ -473,6 +474,7 @@ public class AppInitializer implements IProgress {
|
|||
app.oprAuthHelper = startupInit(new OprAuthHelper(app), OprAuthHelper.class);
|
||||
app.onlineRoutingHelper = startupInit(new OnlineRoutingHelper(app), OnlineRoutingHelper.class);
|
||||
app.itineraryHelper = startupInit(new ItineraryHelper(app), ItineraryHelper.class);
|
||||
app.backupHelper = startupInit(new BackupHelper(app), BackupHelper.class);
|
||||
|
||||
initOpeningHoursParser();
|
||||
}
|
||||
|
|
|
@ -146,6 +146,14 @@ public class FavouritesDbHelper {
|
|||
}
|
||||
}
|
||||
|
||||
public long getLastUploadedTime() {
|
||||
return context.getSettings().FAVORITES_LAST_UPLOADED_TIME.get();
|
||||
}
|
||||
|
||||
public void setLastUploadedTime(long time) {
|
||||
context.getSettings().FAVORITES_LAST_UPLOADED_TIME.set(time);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Drawable getColoredIconForGroup(String groupName) {
|
||||
String groupIdName = FavoriteGroup.convertDisplayNameToGroupIdName(context, groupName);
|
||||
|
|
|
@ -18,7 +18,7 @@ import androidx.annotation.Nullable;
|
|||
|
||||
public class GPXDatabase {
|
||||
|
||||
private static final int DB_VERSION = 11;
|
||||
private static final int DB_VERSION = 12;
|
||||
private static final String DB_NAME = "gpx_database";
|
||||
|
||||
private static final String GPX_TABLE_NAME = "gpxTable";
|
||||
|
@ -48,6 +48,7 @@ public class GPXDatabase {
|
|||
|
||||
private static final String GPX_COL_COLOR = "color";
|
||||
private static final String GPX_COL_FILE_LAST_MODIFIED_TIME = "fileLastModifiedTime";
|
||||
private static final String GPX_COL_FILE_LAST_UPLOADED_TIME = "fileLastUploadedTime";
|
||||
|
||||
private static final String GPX_COL_SPLIT_TYPE = "splitType";
|
||||
private static final String GPX_COL_SPLIT_INTERVAL = "splitInterval";
|
||||
|
@ -98,6 +99,7 @@ public class GPXDatabase {
|
|||
GPX_COL_WPT_POINTS + " int, " +
|
||||
GPX_COL_COLOR + " TEXT, " +
|
||||
GPX_COL_FILE_LAST_MODIFIED_TIME + " long, " +
|
||||
GPX_COL_FILE_LAST_UPLOADED_TIME + " long, " +
|
||||
GPX_COL_SPLIT_TYPE + " int, " +
|
||||
GPX_COL_SPLIT_INTERVAL + " double, " +
|
||||
GPX_COL_API_IMPORTED + " int, " + // 1 = true, 0 = false
|
||||
|
@ -133,6 +135,7 @@ public class GPXDatabase {
|
|||
GPX_COL_WPT_POINTS + ", " +
|
||||
GPX_COL_COLOR + ", " +
|
||||
GPX_COL_FILE_LAST_MODIFIED_TIME + ", " +
|
||||
GPX_COL_FILE_LAST_UPLOADED_TIME + ", " +
|
||||
GPX_COL_SPLIT_TYPE + ", " +
|
||||
GPX_COL_SPLIT_INTERVAL + ", " +
|
||||
GPX_COL_API_IMPORTED + ", " +
|
||||
|
@ -184,6 +187,7 @@ public class GPXDatabase {
|
|||
private int splitType;
|
||||
private double splitInterval;
|
||||
private long fileLastModifiedTime;
|
||||
private long fileLastUploadedTime;
|
||||
private boolean apiImported;
|
||||
private boolean showAsMarkers;
|
||||
private boolean joinSegments;
|
||||
|
@ -200,6 +204,11 @@ public class GPXDatabase {
|
|||
this.color = color;
|
||||
}
|
||||
|
||||
public GpxDataItem(File file, long fileLastUploadedTime) {
|
||||
this.file = file;
|
||||
this.fileLastUploadedTime = fileLastUploadedTime;
|
||||
}
|
||||
|
||||
public GpxDataItem(File file, @NonNull GPXFile gpxFile) {
|
||||
this.file = file;
|
||||
readGpxParams(gpxFile);
|
||||
|
@ -263,6 +272,10 @@ public class GPXDatabase {
|
|||
return fileLastModifiedTime;
|
||||
}
|
||||
|
||||
public long getFileLastUploadedTime() {
|
||||
return fileLastUploadedTime;
|
||||
}
|
||||
|
||||
public int getSplitType() {
|
||||
return splitType;
|
||||
}
|
||||
|
@ -441,10 +454,13 @@ public class GPXDatabase {
|
|||
db.execSQL("UPDATE " + GPX_TABLE_NAME + " SET " + GPX_COL_SHOW_START_FINISH + " = ? " +
|
||||
"WHERE " + GPX_COL_SHOW_START_FINISH + " IS NULL", new Object[]{1});
|
||||
}
|
||||
if (oldVersion < 12) {
|
||||
db.execSQL("ALTER TABLE " + GPX_TABLE_NAME + " ADD " + GPX_COL_FILE_LAST_UPLOADED_TIME + " long");
|
||||
}
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS " + GPX_INDEX_NAME_DIR + " ON " + GPX_TABLE_NAME + " (" + GPX_COL_NAME + ", " + GPX_COL_DIR + ");");
|
||||
}
|
||||
|
||||
private boolean updateLastModifiedTime(GpxDataItem item) {
|
||||
private boolean updateLastModifiedTime(@NonNull GpxDataItem item) {
|
||||
SQLiteConnection db = openConnection(false);
|
||||
if (db != null) {
|
||||
try {
|
||||
|
@ -464,6 +480,25 @@ public class GPXDatabase {
|
|||
return false;
|
||||
}
|
||||
|
||||
public boolean updateLastUploadedTime(@NonNull GpxDataItem item, long fileLastUploadedTime) {
|
||||
SQLiteConnection db = openConnection(false);
|
||||
if (db != null) {
|
||||
try {
|
||||
String fileName = getFileName(item.file);
|
||||
String fileDir = getFileDir(item.file);
|
||||
db.execSQL("UPDATE " + GPX_TABLE_NAME + " SET " +
|
||||
GPX_COL_FILE_LAST_UPLOADED_TIME + " = ? " +
|
||||
" WHERE " + GPX_COL_NAME + " = ? AND " + GPX_COL_DIR + " = ?",
|
||||
new Object[] { fileLastUploadedTime, fileName, fileDir });
|
||||
item.fileLastUploadedTime = fileLastUploadedTime;
|
||||
} finally {
|
||||
db.close();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean rename(@Nullable GpxDataItem item, File currentFile, File newFile) {
|
||||
SQLiteConnection db = openConnection(false);
|
||||
if (db != null){
|
||||
|
@ -721,11 +756,11 @@ public class GPXDatabase {
|
|||
String gradientScaleType = item.gradientScaleType != null ? item.gradientScaleType.getTypeName() : null;
|
||||
if (a != null) {
|
||||
db.execSQL(
|
||||
"INSERT INTO " + GPX_TABLE_NAME + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
"INSERT INTO " + GPX_TABLE_NAME + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
new Object[] {fileName, fileDir, a.totalDistance, a.totalTracks, a.startTime, a.endTime,
|
||||
a.timeSpan, a.timeMoving, a.totalDistanceMoving, a.diffElevationUp, a.diffElevationDown,
|
||||
a.avgElevation, a.minElevation, a.maxElevation, a.maxSpeed, a.avgSpeed, a.points, a.wptPoints,
|
||||
color, item.file.lastModified(), item.splitType, item.splitInterval, item.apiImported ? 1 : 0,
|
||||
color, item.file.lastModified(), item.fileLastUploadedTime, item.splitType, item.splitInterval, item.apiImported ? 1 : 0,
|
||||
Algorithms.encodeStringSet(item.analysis.wptCategoryNames), item.showAsMarkers ? 1 : 0,
|
||||
item.joinSegments ? 1 : 0, item.showArrows ? 1 : 0, item.showStartFinish ? 1 : 0, item.width,
|
||||
item.gradientSpeedPalette, item.gradientAltitudePalette, item.gradientSlopePalette, gradientScaleType});
|
||||
|
@ -735,6 +770,7 @@ public class GPXDatabase {
|
|||
GPX_COL_DIR + ", " +
|
||||
GPX_COL_COLOR + ", " +
|
||||
GPX_COL_FILE_LAST_MODIFIED_TIME + ", " +
|
||||
GPX_COL_FILE_LAST_UPLOADED_TIME + ", " +
|
||||
GPX_COL_SPLIT_TYPE + ", " +
|
||||
GPX_COL_SPLIT_INTERVAL + ", " +
|
||||
GPX_COL_API_IMPORTED + ", " +
|
||||
|
@ -747,8 +783,8 @@ public class GPXDatabase {
|
|||
GPX_COL_GRADIENT_ALTITUDE_COLOR + ", " +
|
||||
GPX_COL_GRADIENT_SLOPE_COLOR + ", " +
|
||||
GPX_COL_GRADIENT_SCALE_TYPE +
|
||||
") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
new Object[] {fileName, fileDir, color, 0, item.splitType, item.splitInterval,
|
||||
") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
new Object[] {fileName, fileDir, color, 0, item.fileLastUploadedTime, item.splitType, item.splitInterval,
|
||||
item.apiImported ? 1 : 0, item.showAsMarkers ? 1 : 0, item.joinSegments ? 1 : 0,
|
||||
item.showArrows ? 1 : 0, item.showStartFinish ? 1 : 0, item.width,
|
||||
Algorithms.gradientPaletteToString(item.gradientSpeedPalette),
|
||||
|
@ -828,19 +864,20 @@ public class GPXDatabase {
|
|||
int wptPoints = (int)query.getInt(17);
|
||||
String color = query.getString(18);
|
||||
long fileLastModifiedTime = query.getLong(19);
|
||||
int splitType = (int)query.getInt(20);
|
||||
double splitInterval = query.getDouble(21);
|
||||
boolean apiImported = query.getInt(22) == 1;
|
||||
String wptCategoryNames = query.getString(23);
|
||||
boolean showAsMarkers = query.getInt(24) == 1;
|
||||
boolean joinSegments = query.getInt(25) == 1;
|
||||
boolean showArrows = query.getInt(26) == 1;
|
||||
boolean showStartFinish = query.getInt(27) == 1;
|
||||
String width = query.getString(28);
|
||||
String gradientSpeedPalette = query.getString(29);
|
||||
String gradientAltitudePalette = query.getString(30);
|
||||
String gradientSlopePalette = query.getString(31);
|
||||
String gradientScaleType = query.getString(32);
|
||||
long fileLastUploadedTime = query.getLong(20);
|
||||
int splitType = (int)query.getInt(21);
|
||||
double splitInterval = query.getDouble(22);
|
||||
boolean apiImported = query.getInt(23) == 1;
|
||||
String wptCategoryNames = query.getString(24);
|
||||
boolean showAsMarkers = query.getInt(25) == 1;
|
||||
boolean joinSegments = query.getInt(26) == 1;
|
||||
boolean showArrows = query.getInt(27) == 1;
|
||||
boolean showStartFinish = query.getInt(28) == 1;
|
||||
String width = query.getString(29);
|
||||
String gradientSpeedPalette = query.getString(30);
|
||||
String gradientAltitudePalette = query.getString(31);
|
||||
String gradientSlopePalette = query.getString(32);
|
||||
String gradientScaleType = query.getString(33);
|
||||
|
||||
GPXTrackAnalysis a = new GPXTrackAnalysis();
|
||||
a.totalDistance = totalDistance;
|
||||
|
@ -873,6 +910,7 @@ public class GPXDatabase {
|
|||
GpxDataItem item = new GpxDataItem(new File(dir, fileName), a);
|
||||
item.color = parseColor(color);
|
||||
item.fileLastModifiedTime = fileLastModifiedTime;
|
||||
item.fileLastUploadedTime = fileLastUploadedTime;
|
||||
item.splitType = splitType;
|
||||
item.splitInterval = splitInterval;
|
||||
item.apiImported = apiImported;
|
||||
|
|
|
@ -78,6 +78,12 @@ public class GpxDbHelper {
|
|||
return res;
|
||||
}
|
||||
|
||||
public boolean updateLastUploadedTime(GpxDataItem item, long fileLastUploadedTime) {
|
||||
boolean res = db.updateLastUploadedTime(item, fileLastUploadedTime);
|
||||
putToCache(item);
|
||||
return res;
|
||||
}
|
||||
|
||||
public boolean updateGradientScalePalette(@NonNull GpxDataItem item, @NonNull GradientScaleType gradientScaleType, int[] palette) {
|
||||
boolean res = db.updateGradientScaleColor(item, gradientScaleType, palette);
|
||||
putToCache(item);
|
||||
|
|
|
@ -52,6 +52,7 @@ import net.osmand.plus.activities.SavingTrackHelper;
|
|||
import net.osmand.plus.activities.actions.OsmAndDialogs;
|
||||
import net.osmand.plus.api.SQLiteAPI;
|
||||
import net.osmand.plus.api.SQLiteAPIImpl;
|
||||
import net.osmand.plus.backup.BackupHelper;
|
||||
import net.osmand.plus.base.MapViewTrackingUtilities;
|
||||
import net.osmand.plus.download.DownloadIndexesThread;
|
||||
import net.osmand.plus.download.DownloadService;
|
||||
|
@ -169,6 +170,7 @@ public class OsmandApplication extends MultiDexApplication {
|
|||
MeasurementEditingContext measurementEditingContext;
|
||||
OnlineRoutingHelper onlineRoutingHelper;
|
||||
ItineraryHelper itineraryHelper;
|
||||
BackupHelper backupHelper;
|
||||
|
||||
private Map<String, Builder> customRoutingConfigs = new ConcurrentHashMap<>();
|
||||
private File externalStorageDirectory;
|
||||
|
@ -474,6 +476,10 @@ public class OsmandApplication extends MultiDexApplication {
|
|||
return itineraryHelper;
|
||||
}
|
||||
|
||||
public BackupHelper getBackupHelper() {
|
||||
return backupHelper;
|
||||
}
|
||||
|
||||
public TransportRoutingHelper getTransportRoutingHelper() {
|
||||
return transportRoutingHelper;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import android.app.ProgressDialog;
|
|||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnCancelListener;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.widget.ProgressBar;
|
||||
|
@ -204,7 +205,8 @@ public class ProgressImplementation implements IProgress {
|
|||
work = -1;
|
||||
progress = 0;
|
||||
if (taskName != null) {
|
||||
message = context.getResources().getString(R.string.finished_task) +" : "+ taskName; //$NON-NLS-1$
|
||||
Resources resources = context.getResources();
|
||||
message = resources.getString(R.string.ltr_or_rtl_combine_via_colon, resources.getString(R.string.finished_task), taskName);
|
||||
mViewUpdateHandler.sendEmptyMessage(HANDLER_START_TASK);
|
||||
}
|
||||
}
|
||||
|
|
581
OsmAnd/src/net/osmand/plus/backup/BackupHelper.java
Normal file
581
OsmAnd/src/net/osmand/plus/backup/BackupHelper.java
Normal file
|
@ -0,0 +1,581 @@
|
|||
package net.osmand.plus.backup;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.AsyncTask;
|
||||
import android.provider.Settings;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import net.osmand.AndroidNetworkUtils;
|
||||
import net.osmand.AndroidNetworkUtils.OnFilesDownloadCallback;
|
||||
import net.osmand.AndroidNetworkUtils.OnFilesUploadCallback;
|
||||
import net.osmand.AndroidNetworkUtils.OnRequestResultListener;
|
||||
import net.osmand.AndroidNetworkUtils.OnSendRequestsListener;
|
||||
import net.osmand.AndroidNetworkUtils.Request;
|
||||
import net.osmand.AndroidNetworkUtils.RequestResponse;
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.IndexConstants;
|
||||
import net.osmand.plus.FavouritesDbHelper;
|
||||
import net.osmand.plus.GPXDatabase.GpxDataItem;
|
||||
import net.osmand.plus.GpxDbHelper;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.inapp.InAppPurchaseHelper;
|
||||
import net.osmand.plus.inapp.InAppPurchases.InAppSubscription;
|
||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class BackupHelper {
|
||||
|
||||
private final OsmandApplication app;
|
||||
private final OsmandSettings settings;
|
||||
private final FavouritesDbHelper favouritesHelper;
|
||||
private final GpxDbHelper gpxHelper;
|
||||
|
||||
private static final String SERVER_URL = "https://osmand.net";
|
||||
|
||||
private static final String USER_REGISTER_URL = SERVER_URL + "/userdata/user-register";
|
||||
private static final String DEVICE_REGISTER_URL = SERVER_URL + "/userdata/device-register";
|
||||
private static final String UPLOAD_FILE_URL = SERVER_URL + "/userdata/upload-file";
|
||||
private static final String LIST_FILES_URL = SERVER_URL + "/userdata/list-files";
|
||||
private static final String DOWNLOAD_FILE_URL = SERVER_URL + "/userdata/download-file";
|
||||
private static final String DELETE_FILE_URL = SERVER_URL + "/userdata/delete-file";
|
||||
|
||||
public final static int STATUS_SUCCESS = 0;
|
||||
public final static int STATUS_PARSE_JSON_ERROR = 1;
|
||||
public final static int STATUS_EMPTY_RESPONSE_ERROR = 2;
|
||||
public final static int STATUS_SERVER_ERROR = 3;
|
||||
|
||||
public interface OnResultListener {
|
||||
void onResult(int status, @Nullable String message, @Nullable JSONObject json);
|
||||
}
|
||||
|
||||
public interface OnRegisterUserListener {
|
||||
void onRegisterUser(int status, @Nullable String message);
|
||||
}
|
||||
|
||||
public interface OnRegisterDeviceListener {
|
||||
void onRegisterDevice(int status, @Nullable String message);
|
||||
}
|
||||
|
||||
public interface OnDownloadFileListListener {
|
||||
void onDownloadFileList(int status, @Nullable String message, @NonNull List<UserFile> userFiles);
|
||||
}
|
||||
|
||||
public interface OnCollectLocalFilesListener {
|
||||
void onFileCollected(@NonNull GpxFileInfo fileInfo);
|
||||
|
||||
void onFilesCollected(@NonNull List<GpxFileInfo> fileInfos);
|
||||
}
|
||||
|
||||
public interface OnGenerateBackupInfoListener {
|
||||
void onBackupInfoGenerated(@Nullable BackupInfo backupInfo, @Nullable String error);
|
||||
}
|
||||
|
||||
public interface OnUploadFilesListener {
|
||||
void onFileUploadProgress(@NonNull File file, int progress);
|
||||
|
||||
void onFilesUploadDone(@NonNull Map<File, String> errors);
|
||||
}
|
||||
|
||||
public interface OnDeleteFilesListener {
|
||||
void onFileDeleteProgress(@NonNull UserFile file);
|
||||
|
||||
void onFilesDeleteDone(@NonNull Map<UserFile, String> errors);
|
||||
}
|
||||
|
||||
public interface OnDownloadFileListener {
|
||||
void onFileDownloadProgress(@NonNull UserFile userFile, int progress);
|
||||
@WorkerThread
|
||||
void onFileDownloadedAsync(@NonNull File file);
|
||||
void onFilesDownloadDone(@NonNull Map<File, String> errors);
|
||||
}
|
||||
|
||||
public static class BackupInfo {
|
||||
public List<UserFile> filesToDownload = new ArrayList<>();
|
||||
public List<GpxFileInfo> filesToUpload = new ArrayList<>();
|
||||
public List<UserFile> filesToDelete = new ArrayList<>();
|
||||
public List<Pair<GpxFileInfo, UserFile>> filesToMerge = new ArrayList<>();
|
||||
}
|
||||
|
||||
public BackupHelper(@NonNull OsmandApplication app) {
|
||||
this.app = app;
|
||||
this.settings = app.getSettings();
|
||||
this.favouritesHelper = app.getFavorites();
|
||||
this.gpxHelper = app.getGpxDbHelper();
|
||||
}
|
||||
|
||||
@SuppressLint("HardwareIds")
|
||||
private String getAndroidId() {
|
||||
try {
|
||||
return Settings.Secure.getString(app.getContentResolver(), Settings.Secure.ANDROID_ID);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isTokenValid(@NonNull String token) {
|
||||
return token.matches("[0-9]+");
|
||||
}
|
||||
|
||||
public boolean hasOsmLiveUpdates() {
|
||||
return InAppPurchaseHelper.isSubscribedToLiveUpdates(app);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getOrderId() {
|
||||
InAppPurchaseHelper purchaseHelper = app.getInAppPurchaseHelper();
|
||||
InAppSubscription purchasedSubscription = purchaseHelper.getAnyPurchasedSubscription();
|
||||
return purchasedSubscription != null ? purchasedSubscription.getOrderId() : null;
|
||||
}
|
||||
|
||||
public String getDeviceId() {
|
||||
return settings.BACKUP_DEVICE_ID.get();
|
||||
}
|
||||
|
||||
public String getAccessToken() {
|
||||
return settings.BACKUP_ACCESS_TOKEN.get();
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return settings.BACKUP_USER_EMAIL.get();
|
||||
}
|
||||
|
||||
public boolean isRegistered() {
|
||||
return !Algorithms.isEmpty(getDeviceId()) && !Algorithms.isEmpty(getAccessToken());
|
||||
}
|
||||
|
||||
private void checkRegistered() throws UserNotRegisteredException {
|
||||
if (Algorithms.isEmpty(getDeviceId()) || Algorithms.isEmpty(getAccessToken())) {
|
||||
throw new UserNotRegisteredException();
|
||||
}
|
||||
}
|
||||
|
||||
public void registerUser(@NonNull String email, @Nullable final OnRegisterUserListener listener) {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("email", email);
|
||||
params.put("orderid", getOrderId());
|
||||
params.put("deviceid", app.getUserAndroidId());
|
||||
AndroidNetworkUtils.sendRequestAsync(app, USER_REGISTER_URL, params, "Register user", true, true, new OnRequestResultListener() {
|
||||
@Override
|
||||
public void onResult(String resultJson) {
|
||||
int status;
|
||||
String message;
|
||||
if (!Algorithms.isEmpty(resultJson)) {
|
||||
try {
|
||||
JSONObject result = new JSONObject(resultJson);
|
||||
String statusStr = result.getString("status");
|
||||
if (statusStr.equals("ok")) {
|
||||
message = "You have been registered successfully. Please check for email with activation code.";
|
||||
status = STATUS_SUCCESS;
|
||||
} else {
|
||||
message = "User registration error: " + statusStr;
|
||||
status = STATUS_SERVER_ERROR;
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
message = "User registration error: json parsing";
|
||||
status = STATUS_PARSE_JSON_ERROR;
|
||||
}
|
||||
} else {
|
||||
message = "User registration error: empty response";
|
||||
status = STATUS_EMPTY_RESPONSE_ERROR;
|
||||
}
|
||||
if (listener != null) {
|
||||
listener.onRegisterUser(status, message);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void registerDevice(String token, @Nullable final OnRegisterDeviceListener listener) {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("email", getEmail());
|
||||
String orderId = getOrderId();
|
||||
if (orderId != null) {
|
||||
params.put("orderid", orderId);
|
||||
}
|
||||
String androidId = getAndroidId();
|
||||
if (!Algorithms.isEmpty(androidId)) {
|
||||
params.put("deviceid", androidId);
|
||||
}
|
||||
params.put("token", token);
|
||||
AndroidNetworkUtils.sendRequestAsync(app, DEVICE_REGISTER_URL, params, "Register device", true, true, new OnRequestResultListener() {
|
||||
@Override
|
||||
public void onResult(String resultJson) {
|
||||
int status;
|
||||
String message;
|
||||
if (!Algorithms.isEmpty(resultJson)) {
|
||||
try {
|
||||
JSONObject result = new JSONObject(resultJson);
|
||||
settings.BACKUP_DEVICE_ID.set(result.getString("id"));
|
||||
settings.BACKUP_USER_ID.set(result.getString("userid"));
|
||||
settings.BACKUP_NATIVE_DEVICE_ID.set(result.getString("deviceid"));
|
||||
settings.BACKUP_ACCESS_TOKEN.set(result.getString("accesstoken"));
|
||||
settings.BACKUP_ACCESS_TOKEN_UPDATE_TIME.set(result.getString("udpatetime"));
|
||||
status = STATUS_SUCCESS;
|
||||
message = "Device have been registered successfully";
|
||||
} catch (JSONException e) {
|
||||
message = "Device registration error: json parsing";
|
||||
status = STATUS_PARSE_JSON_ERROR;
|
||||
}
|
||||
} else {
|
||||
message = "Device registration error: empty response";
|
||||
status = STATUS_EMPTY_RESPONSE_ERROR;
|
||||
}
|
||||
if (listener != null) {
|
||||
listener.onRegisterDevice(status, message);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void uploadFiles(@NonNull List<GpxFileInfo> gpxFiles, @Nullable final OnUploadFilesListener listener) throws UserNotRegisteredException {
|
||||
checkRegistered();
|
||||
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("deviceid", getDeviceId());
|
||||
params.put("accessToken", getAccessToken());
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("Accept-Encoding", "deflate, gzip");
|
||||
|
||||
final Map<File, GpxFileInfo> gpxInfos = new HashMap<>();
|
||||
for (GpxFileInfo gpxFile : gpxFiles) {
|
||||
gpxInfos.put(gpxFile.file, gpxFile);
|
||||
}
|
||||
final File favoritesFile = favouritesHelper.getExternalFile();
|
||||
AndroidNetworkUtils.uploadFilesAsync(UPLOAD_FILE_URL, new ArrayList<>(gpxInfos.keySet()), true, params, headers, new OnFilesUploadCallback() {
|
||||
@Nullable
|
||||
@Override
|
||||
public Map<String, String> getAdditionalParams(@NonNull File file) {
|
||||
Map<String, String> additionaParams = new HashMap<>();
|
||||
GpxFileInfo gpxFileInfo = gpxInfos.get(file);
|
||||
if (gpxFileInfo != null) {
|
||||
additionaParams.put("name", gpxFileInfo.getFileName(true));
|
||||
additionaParams.put("type", Algorithms.getFileExtension(file));
|
||||
gpxFileInfo.uploadTime = System.currentTimeMillis();
|
||||
if (file.equals(favoritesFile)) {
|
||||
favouritesHelper.setLastUploadedTime(gpxFileInfo.uploadTime);
|
||||
} else {
|
||||
GpxDataItem gpxItem = gpxHelper.getItem(file);
|
||||
if (gpxItem != null) {
|
||||
gpxHelper.updateLastUploadedTime(gpxItem, gpxFileInfo.uploadTime);
|
||||
}
|
||||
}
|
||||
additionaParams.put("clienttime", String.valueOf(gpxFileInfo.uploadTime));
|
||||
}
|
||||
return additionaParams;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFileUploadProgress(@NonNull File file, int progress) {
|
||||
if (listener != null) {
|
||||
listener.onFileUploadProgress(file, progress);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFilesUploadDone(@NonNull Map<File, String> errors) {
|
||||
if (errors.isEmpty()) {
|
||||
settings.BACKUP_LAST_UPLOADED_TIME.set(System.currentTimeMillis() + 1);
|
||||
}
|
||||
if (listener != null) {
|
||||
listener.onFilesUploadDone(errors);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void deleteFiles(@NonNull List<UserFile> userFiles, @Nullable final OnDeleteFilesListener listener) throws UserNotRegisteredException {
|
||||
checkRegistered();
|
||||
|
||||
Map<String, String> commonParameters = new HashMap<>();
|
||||
commonParameters.put("deviceid", getDeviceId());
|
||||
commonParameters.put("accessToken", getAccessToken());
|
||||
|
||||
final List<Request> requests = new ArrayList<>();
|
||||
final Map<Request, UserFile> filesMap = new HashMap<>();
|
||||
for (UserFile userFile : userFiles) {
|
||||
Map<String, String> parameters = new HashMap<>(commonParameters);
|
||||
parameters.put("name", userFile.getName());
|
||||
parameters.put("type", userFile.getType());
|
||||
Request r = new Request(DELETE_FILE_URL, parameters, null, false, true);
|
||||
requests.add(r);
|
||||
filesMap.put(r, userFile);
|
||||
}
|
||||
AndroidNetworkUtils.sendRequestsAsync(null, requests, new OnSendRequestsListener() {
|
||||
@Override
|
||||
public void onRequestSent(@NonNull RequestResponse response) {
|
||||
if (listener != null) {
|
||||
UserFile userFile = filesMap.get(response.getRequest());
|
||||
if (userFile != null) {
|
||||
listener.onFileDeleteProgress(userFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestsSent(@NonNull List<RequestResponse> results) {
|
||||
if (listener != null) {
|
||||
Map<UserFile, String> errors = new HashMap<>();
|
||||
for (RequestResponse response : results) {
|
||||
UserFile userFile = filesMap.get(response.getRequest());
|
||||
if (userFile != null) {
|
||||
String responseStr = response.getResponse();
|
||||
boolean success;
|
||||
try {
|
||||
JSONObject json = new JSONObject(responseStr);
|
||||
String status = json.getString("status");
|
||||
success = status.equalsIgnoreCase("ok");
|
||||
} catch (JSONException e) {
|
||||
success = false;
|
||||
}
|
||||
if (!success) {
|
||||
errors.put(userFile, responseStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
listener.onFilesDeleteDone(errors);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void downloadFileList(@Nullable final OnDownloadFileListListener listener) throws UserNotRegisteredException {
|
||||
checkRegistered();
|
||||
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("deviceid", getDeviceId());
|
||||
params.put("accessToken", getAccessToken());
|
||||
AndroidNetworkUtils.sendRequestAsync(app, LIST_FILES_URL, params, "Download file list", true, false, new OnRequestResultListener() {
|
||||
@Override
|
||||
public void onResult(String resultJson) {
|
||||
int status;
|
||||
String message;
|
||||
List<UserFile> userFiles = new ArrayList<>();
|
||||
if (!Algorithms.isEmpty(resultJson)) {
|
||||
try {
|
||||
JSONObject result = new JSONObject(resultJson);
|
||||
String totalZipSize = result.getString("totalZipSize");
|
||||
String totalFiles = result.getString("totalFiles");
|
||||
String totalFileVersions = result.getString("totalFileVersions");
|
||||
JSONArray files = result.getJSONArray("uniqueFiles");
|
||||
for (int i = 0; i < files.length(); i++) {
|
||||
userFiles.add(new UserFile(files.getJSONObject(i)));
|
||||
}
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
message = "Total files: " + totalFiles + "\n" +
|
||||
"Total zip size: " + AndroidUtils.formatSize(app, Long.parseLong(totalZipSize)) + "\n" +
|
||||
"Total file versions: " + totalFileVersions;
|
||||
} catch (JSONException | ParseException e) {
|
||||
status = STATUS_PARSE_JSON_ERROR;
|
||||
message = "Download file list error: json parsing";
|
||||
}
|
||||
} else {
|
||||
status = STATUS_EMPTY_RESPONSE_ERROR;
|
||||
message = "Download file list error: empty response";
|
||||
}
|
||||
if (listener != null) {
|
||||
listener.onDownloadFileList(status, message, userFiles);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void downloadFiles(@NonNull final Map<File, UserFile> filesMap, @Nullable final OnDownloadFileListener listener) throws UserNotRegisteredException {
|
||||
checkRegistered();
|
||||
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("deviceid", getDeviceId());
|
||||
params.put("accessToken", getAccessToken());
|
||||
AndroidNetworkUtils.downloadFilesAsync(DOWNLOAD_FILE_URL,
|
||||
new ArrayList<>(filesMap.keySet()), params, new OnFilesDownloadCallback() {
|
||||
@Nullable
|
||||
@Override
|
||||
public Map<String, String> getAdditionalParams(@NonNull File file) {
|
||||
UserFile userFile = filesMap.get(file);
|
||||
Map<String, String> additionaParams = new HashMap<>();
|
||||
additionaParams.put("name", userFile.getName());
|
||||
additionaParams.put("type", userFile.getType());
|
||||
return additionaParams;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFileDownloadProgress(@NonNull File file, int percent) {
|
||||
if (listener != null) {
|
||||
listener.onFileDownloadProgress(filesMap.get(file), percent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFileDownloadedAsync(@NonNull File file) {
|
||||
if (listener != null) {
|
||||
listener.onFileDownloadedAsync(file);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFilesDownloadDone(@NonNull Map<File, String> errors) {
|
||||
if (listener != null) {
|
||||
listener.onFilesDownloadDone(errors);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
public void collectLocalFiles(@Nullable final OnCollectLocalFilesListener listener) {
|
||||
AsyncTask<Void, GpxFileInfo, List<GpxFileInfo>> task = new AsyncTask<Void, GpxFileInfo, List<GpxFileInfo>>() {
|
||||
|
||||
private final OnCollectLocalFilesListener internalListener = new OnCollectLocalFilesListener() {
|
||||
@Override
|
||||
public void onFileCollected(@NonNull GpxFileInfo fileInfo) {
|
||||
publishProgress(fileInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFilesCollected(@NonNull List<GpxFileInfo> fileInfos) {
|
||||
}
|
||||
};
|
||||
|
||||
private void loadGPXData(@NonNull File mapPath, @NonNull List<GpxFileInfo> result,
|
||||
@Nullable OnCollectLocalFilesListener listener) {
|
||||
if (mapPath.canRead()) {
|
||||
loadGPXFolder(mapPath, result, "", listener);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadGPXFolder(@NonNull File mapPath, @NonNull List<GpxFileInfo> result,
|
||||
@NonNull String gpxSubfolder, @Nullable OnCollectLocalFilesListener listener) {
|
||||
File[] listFiles = mapPath.listFiles();
|
||||
if (listFiles != null) {
|
||||
for (File gpxFile : listFiles) {
|
||||
if (gpxFile.isDirectory()) {
|
||||
String sub = gpxSubfolder.length() == 0 ? gpxFile.getName() : gpxSubfolder + "/"
|
||||
+ gpxFile.getName();
|
||||
loadGPXFolder(gpxFile, result, sub, listener);
|
||||
} else if (gpxFile.isFile() && gpxFile.getName().toLowerCase().endsWith(IndexConstants.GPX_FILE_EXT)) {
|
||||
GpxFileInfo info = new GpxFileInfo();
|
||||
info.subfolder = gpxSubfolder;
|
||||
info.file = gpxFile;
|
||||
GpxDataItem gpxItem = gpxHelper.getItem(gpxFile);
|
||||
if (gpxItem != null) {
|
||||
info.uploadTime = gpxItem.getFileLastUploadedTime();
|
||||
}
|
||||
result.add(info);
|
||||
if (listener != null) {
|
||||
listener.onFileCollected(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<GpxFileInfo> doInBackground(Void... voids) {
|
||||
List<GpxFileInfo> result = new ArrayList<>();
|
||||
|
||||
GpxFileInfo favInfo = new GpxFileInfo();
|
||||
favInfo.subfolder = "";
|
||||
favInfo.file = favouritesHelper.getExternalFile();
|
||||
favInfo.uploadTime = favouritesHelper.getLastUploadedTime();
|
||||
result.add(favInfo);
|
||||
if (listener != null) {
|
||||
listener.onFileCollected(favInfo);
|
||||
}
|
||||
|
||||
loadGPXData(app.getAppPath(IndexConstants.GPX_INDEX_DIR), result, internalListener);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(GpxFileInfo... fileInfos) {
|
||||
if (listener != null) {
|
||||
listener.onFileCollected(fileInfos[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(List<GpxFileInfo> fileInfos) {
|
||||
if (listener != null) {
|
||||
listener.onFilesCollected(fileInfos);
|
||||
}
|
||||
}
|
||||
};
|
||||
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
public void generateBackupInfo(@NonNull final List<GpxFileInfo> localFiles, @NonNull final List<UserFile> remoteFiles,
|
||||
@Nullable final OnGenerateBackupInfoListener listener) {
|
||||
|
||||
final long backupLastUploadedTime = settings.BACKUP_LAST_UPLOADED_TIME.get();
|
||||
|
||||
AsyncTask<Void, Void, BackupInfo> task = new AsyncTask<Void, Void, BackupInfo>() {
|
||||
@Override
|
||||
protected BackupInfo doInBackground(Void... voids) {
|
||||
BackupInfo info = new BackupInfo();
|
||||
for (UserFile remoteFile : remoteFiles) {
|
||||
boolean hasLocalFile = false;
|
||||
for (GpxFileInfo localFile : localFiles) {
|
||||
if (remoteFile.getName().equals(localFile.getFileName(true))) {
|
||||
hasLocalFile = true;
|
||||
long remoteUploadTime = remoteFile.getClienttimems();
|
||||
long localUploadTime = localFile.uploadTime;
|
||||
long localModifiedTime = localFile.file.lastModified();
|
||||
if (remoteUploadTime == localUploadTime) {
|
||||
if (localUploadTime < localModifiedTime) {
|
||||
info.filesToUpload.add(localFile);
|
||||
}
|
||||
} else {
|
||||
info.filesToMerge.add(new Pair<>(localFile, remoteFile));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasLocalFile) {
|
||||
if (backupLastUploadedTime > 0 && backupLastUploadedTime >= remoteFile.getClienttimems()) {
|
||||
info.filesToDelete.add(remoteFile);
|
||||
} else {
|
||||
info.filesToDownload.add(remoteFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (GpxFileInfo localFile : localFiles) {
|
||||
boolean hasRemoteFile = false;
|
||||
for (UserFile remoteFile : remoteFiles) {
|
||||
if (localFile.getFileName(true).equals(remoteFile.getName())) {
|
||||
hasRemoteFile = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasRemoteFile) {
|
||||
info.filesToUpload.add(localFile);
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(BackupInfo backupInfo) {
|
||||
if (listener != null) {
|
||||
listener.onBackupInfoGenerated(backupInfo, null);
|
||||
}
|
||||
}
|
||||
};
|
||||
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
}
|
335
OsmAnd/src/net/osmand/plus/backup/BackupTask.java
Normal file
335
OsmAnd/src/net/osmand/plus/backup/BackupTask.java
Normal file
|
@ -0,0 +1,335 @@
|
|||
package net.osmand.plus.backup;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.GPXUtilities;
|
||||
import net.osmand.GPXUtilities.GPXFile;
|
||||
import net.osmand.plus.GPXDatabase.GpxDataItem;
|
||||
import net.osmand.plus.GpxDbHelper;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.ProgressImplementation;
|
||||
import net.osmand.plus.backup.BackupHelper.BackupInfo;
|
||||
import net.osmand.plus.backup.BackupHelper.OnDeleteFilesListener;
|
||||
import net.osmand.plus.backup.BackupHelper.OnDownloadFileListener;
|
||||
import net.osmand.plus.backup.BackupHelper.OnUploadFilesListener;
|
||||
import net.osmand.plus.importfiles.FavoritesImportTask;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
|
||||
import static net.osmand.IndexConstants.GPX_INDEX_DIR;
|
||||
import static net.osmand.IndexConstants.TEMP_DIR;
|
||||
|
||||
public class BackupTask {
|
||||
|
||||
private final OsmandApplication app;
|
||||
private final BackupHelper backupHelper;
|
||||
|
||||
private final OnBackupListener listener;
|
||||
private final WeakReference<Context> contextRef;
|
||||
private ProgressImplementation progress;
|
||||
|
||||
private final BackupInfo backupInfo;
|
||||
private Map<File, String> uploadErrors;
|
||||
private Map<File, String> downloadErrors;
|
||||
private Map<UserFile, String> deleteErrors;
|
||||
private String error;
|
||||
|
||||
private final TaskType[] backupTasks = {TaskType.UPLOAD_FILES, TaskType.DELETE_FILES};
|
||||
private final TaskType[] restoreTasks = {TaskType.DOWNLOAD_FILES};
|
||||
|
||||
private Stack<TaskType> runningTasks = new Stack<>();
|
||||
|
||||
private enum TaskType {
|
||||
UPLOAD_FILES,
|
||||
DOWNLOAD_FILES,
|
||||
DELETE_FILES
|
||||
}
|
||||
|
||||
public interface OnBackupListener {
|
||||
void onBackupDone(@Nullable Map<File, String> uploadErrors,
|
||||
@Nullable Map<File, String> downloadErrors,
|
||||
@Nullable Map<UserFile, String> deleteErrors, @Nullable String error);
|
||||
}
|
||||
|
||||
public BackupTask(@NonNull BackupInfo backupInfo, @NonNull Context context, @Nullable OnBackupListener listener) {
|
||||
this.contextRef = new WeakReference<>(context);
|
||||
this.app = (OsmandApplication) context.getApplicationContext();
|
||||
this.backupHelper = app.getBackupHelper();
|
||||
this.backupInfo = backupInfo;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public BackupInfo getBackupInfo() {
|
||||
return backupInfo;
|
||||
}
|
||||
|
||||
public Map<File, String> getUploadErrors() {
|
||||
return uploadErrors;
|
||||
}
|
||||
|
||||
public Map<File, String> getDownloadErrors() {
|
||||
return downloadErrors;
|
||||
}
|
||||
|
||||
public Map<UserFile, String> getDeleteErrors() {
|
||||
return deleteErrors;
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public boolean runBackup() {
|
||||
if (!runningTasks.empty()) {
|
||||
return false;
|
||||
}
|
||||
initBackupTasks();
|
||||
return runTasks();
|
||||
}
|
||||
|
||||
public boolean runRestore() {
|
||||
if (!runningTasks.empty()) {
|
||||
return false;
|
||||
}
|
||||
initRestoreTasks();
|
||||
return runTasks();
|
||||
}
|
||||
|
||||
private void initBackupTasks() {
|
||||
initData();
|
||||
Stack<TaskType> tasks = new Stack<>();
|
||||
for (int i = backupTasks.length - 1; i >= 0; i--) {
|
||||
tasks.push(backupTasks[i]);
|
||||
}
|
||||
this.runningTasks = tasks;
|
||||
onTasksInit();
|
||||
}
|
||||
|
||||
private void initRestoreTasks() {
|
||||
initData();
|
||||
Stack<TaskType> tasks = new Stack<>();
|
||||
for (int i = restoreTasks.length - 1; i >= 0; i--) {
|
||||
tasks.push(restoreTasks[i]);
|
||||
}
|
||||
this.runningTasks = tasks;
|
||||
onTasksInit();
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
uploadErrors = null;
|
||||
downloadErrors = null;
|
||||
deleteErrors = null;
|
||||
error = null;
|
||||
}
|
||||
|
||||
private boolean runTasks() {
|
||||
if (runningTasks.empty()) {
|
||||
return false;
|
||||
} else {
|
||||
TaskType taskType = runningTasks.pop();
|
||||
runTask(taskType);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private void runTask(@NonNull TaskType taskType) {
|
||||
switch (taskType) {
|
||||
case UPLOAD_FILES:
|
||||
doUploadFiles();
|
||||
break;
|
||||
case DOWNLOAD_FILES:
|
||||
doDownloadFiles();
|
||||
break;
|
||||
case DELETE_FILES:
|
||||
doDeleteFiles();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void onTaskFinished(@NonNull TaskType taskType) {
|
||||
if (!runTasks()) {
|
||||
onTasksDone();
|
||||
}
|
||||
}
|
||||
|
||||
private void doUploadFiles() {
|
||||
if (Algorithms.isEmpty(backupInfo.filesToUpload)) {
|
||||
onTaskFinished(TaskType.UPLOAD_FILES);
|
||||
return;
|
||||
}
|
||||
onTaskProgressUpdate("Upload files...");
|
||||
try {
|
||||
backupHelper.uploadFiles(backupInfo.filesToUpload, new OnUploadFilesListener() {
|
||||
@Override
|
||||
public void onFileUploadProgress(@NonNull File file, int progress) {
|
||||
if (progress == 0) {
|
||||
onTaskProgressUpdate(file.getName(), (int) (file.length() / 1024));
|
||||
} else {
|
||||
onTaskProgressUpdate(progress);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFilesUploadDone(@NonNull Map<File, String> errors) {
|
||||
uploadErrors = errors;
|
||||
onTaskFinished(TaskType.UPLOAD_FILES);
|
||||
}
|
||||
});
|
||||
} catch (UserNotRegisteredException e) {
|
||||
onError("User is not registered");
|
||||
}
|
||||
}
|
||||
|
||||
private void doDownloadFiles() {
|
||||
if (Algorithms.isEmpty(backupInfo.filesToDownload)) {
|
||||
onTaskFinished(TaskType.DOWNLOAD_FILES);
|
||||
return;
|
||||
}
|
||||
onTaskProgressUpdate("Download files...");
|
||||
File favoritesFile = app.getFavorites().getExternalFile();
|
||||
String favoritesFileName = favoritesFile.getName();
|
||||
File tempFavoritesFile = null;
|
||||
final Map<File, UserFile> filesMap = new HashMap<>();
|
||||
for (UserFile userFile : backupInfo.filesToDownload) {
|
||||
File file;
|
||||
String fileName = userFile.getName();
|
||||
if (favoritesFileName.equals(fileName)) {
|
||||
file = new File(app.getAppPath(TEMP_DIR), fileName);
|
||||
tempFavoritesFile = file;
|
||||
} else {
|
||||
file = new File(app.getAppPath(GPX_INDEX_DIR), fileName);
|
||||
}
|
||||
filesMap.put(file, userFile);
|
||||
}
|
||||
final File finalTempFavoritesFile = tempFavoritesFile;
|
||||
try {
|
||||
backupHelper.downloadFiles(filesMap, new OnDownloadFileListener() {
|
||||
@Override
|
||||
public void onFileDownloadProgress(@NonNull UserFile userFile, int progress) {
|
||||
if (progress == 0) {
|
||||
onTaskProgressUpdate(new File(userFile.getName()).getName(), userFile.getFilesize() / 1024);
|
||||
} else {
|
||||
onTaskProgressUpdate(progress);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFileDownloadedAsync(@NonNull File file) {
|
||||
UserFile userFile = filesMap.get(file);
|
||||
long userFileTime = userFile.getClienttimems();
|
||||
if (file.equals(finalTempFavoritesFile)) {
|
||||
GPXFile gpxFile = GPXUtilities.loadGPXFile(finalTempFavoritesFile);
|
||||
FavoritesImportTask.mergeFavorites(app, gpxFile, "", false);
|
||||
finalTempFavoritesFile.delete();
|
||||
app.getFavorites().getExternalFile().setLastModified(userFileTime);
|
||||
} else {
|
||||
file.setLastModified(userFileTime);
|
||||
GpxDataItem item = new GpxDataItem(file, userFileTime);
|
||||
app.getGpxDbHelper().add(item);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFilesDownloadDone(@NonNull Map<File, String> errors) {
|
||||
downloadErrors = errors;
|
||||
onTaskFinished(TaskType.DOWNLOAD_FILES);
|
||||
}
|
||||
});
|
||||
} catch (UserNotRegisteredException e) {
|
||||
onError("User is not registered");
|
||||
}
|
||||
}
|
||||
|
||||
private void doDeleteFiles() {
|
||||
if (Algorithms.isEmpty(backupInfo.filesToDelete)) {
|
||||
onTaskFinished(TaskType.DELETE_FILES);
|
||||
return;
|
||||
}
|
||||
onTaskProgressUpdate("Delete files...");
|
||||
try {
|
||||
backupHelper.deleteFiles(backupInfo.filesToDelete, new OnDeleteFilesListener() {
|
||||
@Override
|
||||
public void onFileDeleteProgress(@NonNull UserFile userFile) {
|
||||
onTaskProgressUpdate(userFile.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFilesDeleteDone(@NonNull Map<UserFile, String> errors) {
|
||||
deleteErrors = errors;
|
||||
onTaskFinished(TaskType.DELETE_FILES);
|
||||
}
|
||||
});
|
||||
} catch (UserNotRegisteredException e) {
|
||||
onError("User is not registered");
|
||||
}
|
||||
}
|
||||
|
||||
private void onTasksInit() {
|
||||
Context ctx = contextRef.get();
|
||||
if (ctx instanceof Activity && AndroidUtils.isActivityNotDestroyed((Activity) ctx) && progress != null) {
|
||||
progress = ProgressImplementation.createProgressDialog(ctx,
|
||||
"Backup data", "Initializing...", ProgressDialog.STYLE_HORIZONTAL);
|
||||
}
|
||||
}
|
||||
|
||||
private void onTaskProgressUpdate(Object... objects) {
|
||||
Context ctx = contextRef.get();
|
||||
if (ctx instanceof Activity && AndroidUtils.isActivityNotDestroyed((Activity) ctx) && progress != null) {
|
||||
if (objects != null) {
|
||||
if (objects.length == 1) {
|
||||
if (objects[0] instanceof String) {
|
||||
progress.startTask((String) objects[0], -1);
|
||||
} else if (objects[0] instanceof Integer) {
|
||||
int progressValue = (Integer) objects[0];
|
||||
if (progressValue < Integer.MAX_VALUE) {
|
||||
progress.progress(progressValue);
|
||||
} else {
|
||||
progress.finishTask();
|
||||
}
|
||||
}
|
||||
} else if (objects.length == 2) {
|
||||
progress.startTask((String) objects[0], (Integer) objects[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void onError(@NonNull String message) {
|
||||
this.error = message;
|
||||
runningTasks.clear();
|
||||
onTasksDone();
|
||||
}
|
||||
|
||||
private void onTasksDone() {
|
||||
if (listener != null) {
|
||||
listener.onBackupDone(uploadErrors, downloadErrors, deleteErrors, error);
|
||||
}
|
||||
Context ctx = contextRef.get();
|
||||
if (ctx instanceof Activity && AndroidUtils.isActivityNotDestroyed((Activity) ctx) && progress != null) {
|
||||
progress.finishTask();
|
||||
app.runInUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (progress.getDialog().isShowing()) {
|
||||
progress.getDialog().dismiss();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
//ignored
|
||||
}
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
}
|
65
OsmAnd/src/net/osmand/plus/backup/GpxFileInfo.java
Normal file
65
OsmAnd/src/net/osmand/plus/backup/GpxFileInfo.java
Normal file
|
@ -0,0 +1,65 @@
|
|||
package net.osmand.plus.backup;
|
||||
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class GpxFileInfo {
|
||||
public File file;
|
||||
public String subfolder;
|
||||
public long uploadTime = 0;
|
||||
|
||||
private String name = null;
|
||||
private int sz = -1;
|
||||
private String fileName = null;
|
||||
|
||||
public String getName() {
|
||||
if (name == null) {
|
||||
name = formatName(file.getName());
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
private String formatName(String name) {
|
||||
int ext = name.lastIndexOf('.');
|
||||
if (ext != -1) {
|
||||
name = name.substring(0, ext);
|
||||
}
|
||||
return name.replace('_', ' ');
|
||||
}
|
||||
|
||||
// Usage: AndroidUtils.formatSize(v.getContext(), getSize() * 1024l);
|
||||
public int getSize() {
|
||||
if (sz == -1) {
|
||||
if (file == null) {
|
||||
return -1;
|
||||
}
|
||||
sz = (int) ((file.length() + 512) >> 10);
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
|
||||
public long getFileDate() {
|
||||
if (file == null) {
|
||||
return 0;
|
||||
}
|
||||
return file.lastModified();
|
||||
}
|
||||
|
||||
public String getFileName(boolean includeSubfolder) {
|
||||
String result;
|
||||
if (fileName != null) {
|
||||
result = fileName;
|
||||
} else {
|
||||
if (file == null) {
|
||||
result = "";
|
||||
} else {
|
||||
result = fileName = file.getName();
|
||||
}
|
||||
}
|
||||
if (includeSubfolder && !Algorithms.isEmpty(subfolder)) {
|
||||
result = subfolder + "/" + result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
211
OsmAnd/src/net/osmand/plus/backup/PrepareBackupTask.java
Normal file
211
OsmAnd/src/net/osmand/plus/backup/PrepareBackupTask.java
Normal file
|
@ -0,0 +1,211 @@
|
|||
package net.osmand.plus.backup;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.ProgressImplementation;
|
||||
import net.osmand.plus.backup.BackupHelper.BackupInfo;
|
||||
import net.osmand.plus.backup.BackupHelper.OnCollectLocalFilesListener;
|
||||
import net.osmand.plus.backup.BackupHelper.OnDownloadFileListListener;
|
||||
import net.osmand.plus.backup.BackupHelper.OnGenerateBackupInfoListener;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
public class PrepareBackupTask {
|
||||
|
||||
private final OsmandApplication app;
|
||||
private final BackupHelper backupHelper;
|
||||
|
||||
private final OnPrepareBackupListener listener;
|
||||
private final WeakReference<Context> contextRef;
|
||||
private ProgressImplementation progress;
|
||||
|
||||
private BackupInfo result;
|
||||
private List<UserFile> userFiles;
|
||||
private List<GpxFileInfo> fileInfos;
|
||||
private String error;
|
||||
|
||||
private Stack<TaskType> runningTasks = new Stack<>();
|
||||
|
||||
private enum TaskType {
|
||||
COLLECT_LOCAL_FILES,
|
||||
COLLECT_REMOTE_FILES,
|
||||
GENERATE_BACKUP_INFO
|
||||
}
|
||||
|
||||
public interface OnPrepareBackupListener {
|
||||
void onBackupPrepared(@Nullable BackupInfo backupInfo, @Nullable String error);
|
||||
}
|
||||
|
||||
public PrepareBackupTask(@NonNull Context context, @Nullable OnPrepareBackupListener listener) {
|
||||
this.contextRef = new WeakReference<>(context);
|
||||
this.app = (OsmandApplication) context.getApplicationContext();
|
||||
this.backupHelper = app.getBackupHelper();
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public BackupInfo getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public boolean prepare() {
|
||||
if (!runningTasks.empty()) {
|
||||
return false;
|
||||
}
|
||||
initTasks();
|
||||
return runTasks();
|
||||
}
|
||||
|
||||
private void initTasks() {
|
||||
result = null;
|
||||
userFiles = null;
|
||||
fileInfos = null;
|
||||
error = null;
|
||||
Stack<TaskType> tasks = new Stack<>();
|
||||
TaskType[] types = TaskType.values();
|
||||
for (int i = types.length - 1; i >= 0; i--) {
|
||||
tasks.push(types[i]);
|
||||
}
|
||||
this.runningTasks = tasks;
|
||||
onTasksInit();
|
||||
}
|
||||
|
||||
private boolean runTasks() {
|
||||
if (runningTasks.empty()) {
|
||||
return false;
|
||||
} else {
|
||||
TaskType taskType = runningTasks.pop();
|
||||
runTask(taskType);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private void runTask(@NonNull TaskType taskType) {
|
||||
switch (taskType) {
|
||||
case COLLECT_LOCAL_FILES:
|
||||
doCollectLocalFiles();
|
||||
break;
|
||||
case COLLECT_REMOTE_FILES:
|
||||
doCollectRemoteFiles();
|
||||
break;
|
||||
case GENERATE_BACKUP_INFO:
|
||||
doGenerateBackupInfo();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void onTaskFinished(@NonNull TaskType taskType) {
|
||||
if (!runTasks()) {
|
||||
onTasksDone();
|
||||
}
|
||||
}
|
||||
|
||||
private void doCollectLocalFiles() {
|
||||
onTaskProgressUpdate("Collecting local info...");
|
||||
backupHelper.collectLocalFiles(new OnCollectLocalFilesListener() {
|
||||
@Override
|
||||
public void onFileCollected(@NonNull GpxFileInfo fileInfo) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFilesCollected(@NonNull List<GpxFileInfo> fileInfos) {
|
||||
PrepareBackupTask.this.fileInfos = fileInfos;
|
||||
onTaskFinished(TaskType.COLLECT_LOCAL_FILES);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void doCollectRemoteFiles() {
|
||||
onTaskProgressUpdate("Downloading remote info...");
|
||||
try {
|
||||
backupHelper.downloadFileList(new OnDownloadFileListListener() {
|
||||
@Override
|
||||
public void onDownloadFileList(int status, @Nullable String message, @NonNull List<UserFile> userFiles) {
|
||||
if (status == BackupHelper.STATUS_SUCCESS) {
|
||||
PrepareBackupTask.this.userFiles = userFiles;
|
||||
} else {
|
||||
onError(!Algorithms.isEmpty(message) ? message : "Download file list error: " + status);
|
||||
}
|
||||
onTaskFinished(TaskType.COLLECT_REMOTE_FILES);
|
||||
}
|
||||
});
|
||||
} catch (UserNotRegisteredException e) {
|
||||
onError("User is not registered");
|
||||
}
|
||||
}
|
||||
|
||||
private void doGenerateBackupInfo() {
|
||||
if (fileInfos == null || userFiles == null) {
|
||||
onTaskFinished(TaskType.GENERATE_BACKUP_INFO);
|
||||
return;
|
||||
}
|
||||
onTaskProgressUpdate("Generating backup info...");
|
||||
backupHelper.generateBackupInfo(fileInfos, userFiles, new OnGenerateBackupInfoListener() {
|
||||
@Override
|
||||
public void onBackupInfoGenerated(@Nullable BackupInfo backupInfo, @Nullable String error) {
|
||||
if (Algorithms.isEmpty(error)) {
|
||||
PrepareBackupTask.this.result = backupInfo;
|
||||
} else {
|
||||
onError(error);
|
||||
}
|
||||
onTaskFinished(TaskType.GENERATE_BACKUP_INFO);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void onTasksInit() {
|
||||
Context ctx = contextRef.get();
|
||||
if (ctx instanceof Activity && AndroidUtils.isActivityNotDestroyed((Activity) ctx)) {
|
||||
progress = ProgressImplementation.createProgressDialog(ctx,
|
||||
"Prepare backup", "Initializing...", ProgressDialog.STYLE_HORIZONTAL);
|
||||
}
|
||||
}
|
||||
|
||||
private void onTaskProgressUpdate(String message) {
|
||||
Context ctx = contextRef.get();
|
||||
if (ctx instanceof Activity && AndroidUtils.isActivityNotDestroyed((Activity) ctx) && progress != null) {
|
||||
progress.startTask(message, -1);
|
||||
}
|
||||
}
|
||||
|
||||
private void onError(@NonNull String message) {
|
||||
this.error = message;
|
||||
runningTasks.clear();
|
||||
onTasksDone();
|
||||
}
|
||||
|
||||
private void onTasksDone() {
|
||||
if (listener != null) {
|
||||
listener.onBackupPrepared(result, error);
|
||||
}
|
||||
Context ctx = contextRef.get();
|
||||
if (ctx instanceof Activity && AndroidUtils.isActivityNotDestroyed((Activity) ctx) && progress != null) {
|
||||
progress.finishTask();
|
||||
app.runInUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (progress.getDialog().isShowing()) {
|
||||
progress.getDialog().dismiss();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
//ignored
|
||||
}
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
}
|
102
OsmAnd/src/net/osmand/plus/backup/UserFile.java
Normal file
102
OsmAnd/src/net/osmand/plus/backup/UserFile.java
Normal file
|
@ -0,0 +1,102 @@
|
|||
package net.osmand.plus.backup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
public class UserFile {
|
||||
|
||||
private int userid;
|
||||
private long id;
|
||||
private int deviceid;
|
||||
private int filesize;
|
||||
private String type;
|
||||
private String name;
|
||||
private Date updatetime;
|
||||
private long updatetimems;
|
||||
private Date clienttime;
|
||||
private long clienttimems;
|
||||
private int zipSize;
|
||||
|
||||
public UserFile(@NonNull JSONObject json) throws JSONException, ParseException {
|
||||
if (json.has("userid")) {
|
||||
userid = json.getInt("userid");
|
||||
}
|
||||
if (json.has("id")) {
|
||||
id = json.getLong("id");
|
||||
}
|
||||
if (json.has("deviceid")) {
|
||||
deviceid = json.getInt("deviceid");
|
||||
}
|
||||
if (json.has("filesize")) {
|
||||
filesize = json.getInt("filesize");
|
||||
}
|
||||
if (json.has("type")) {
|
||||
type = json.getString("type");
|
||||
}
|
||||
if (json.has("name")) {
|
||||
name = json.getString("name");
|
||||
}
|
||||
if (json.has("updatetimems")) {
|
||||
updatetimems = json.getLong("updatetimems");
|
||||
updatetime = new Date(updatetimems);
|
||||
}
|
||||
if (json.has("clienttimems")) {
|
||||
clienttimems = json.getLong("clienttimems");
|
||||
clienttime = new Date(clienttimems);
|
||||
}
|
||||
if (json.has("zipSize")) {
|
||||
zipSize = json.getInt("zipSize");
|
||||
}
|
||||
}
|
||||
|
||||
public int getUserid() {
|
||||
return userid;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getDeviceid() {
|
||||
return deviceid;
|
||||
}
|
||||
|
||||
public int getFilesize() {
|
||||
return filesize;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Date getUpdatetime() {
|
||||
return updatetime;
|
||||
}
|
||||
|
||||
public long getUpdatetimems() {
|
||||
return updatetimems;
|
||||
}
|
||||
|
||||
public Date getClienttime() {
|
||||
return clienttime;
|
||||
}
|
||||
|
||||
public long getClienttimems() {
|
||||
return clienttimems;
|
||||
}
|
||||
|
||||
public int getZipSize() {
|
||||
return zipSize;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package net.osmand.plus.backup;
|
||||
|
||||
public class UserNotRegisteredException extends Exception {
|
||||
private static final long serialVersionUID = -8005954380280822845L;
|
||||
|
||||
public UserNotRegisteredException() {
|
||||
super("User is not resistered");
|
||||
}
|
||||
}
|
|
@ -1,72 +1,64 @@
|
|||
package net.osmand.plus.development;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Patterns;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
|
||||
import net.osmand.AndroidNetworkUtils;
|
||||
import net.osmand.AndroidNetworkUtils.OnFilesUploadCallback;
|
||||
import net.osmand.AndroidNetworkUtils.OnRequestResultListener;
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.IndexConstants;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.ProgressImplementation;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.UiUtilities;
|
||||
import net.osmand.plus.UiUtilities.DialogButtonType;
|
||||
import net.osmand.plus.activities.OsmandActionBarActivity;
|
||||
import net.osmand.plus.backup.BackupHelper;
|
||||
import net.osmand.plus.backup.BackupHelper.BackupInfo;
|
||||
import net.osmand.plus.backup.BackupHelper.OnRegisterUserListener;
|
||||
import net.osmand.plus.backup.BackupTask;
|
||||
import net.osmand.plus.backup.BackupTask.OnBackupListener;
|
||||
import net.osmand.plus.backup.PrepareBackupTask;
|
||||
import net.osmand.plus.backup.PrepareBackupTask.OnPrepareBackupListener;
|
||||
import net.osmand.plus.backup.UserFile;
|
||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
import net.osmand.plus.widgets.OsmandTextFieldBoxes;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
public class TestBackupActivity extends OsmandActionBarActivity {
|
||||
|
||||
// TODO pass actual sub order id!
|
||||
private static final String TEST_ORDER_ID = "";
|
||||
|
||||
private OsmandApplication app;
|
||||
private OsmandSettings settings;
|
||||
private BackupHelper backupHelper;
|
||||
|
||||
private ProgressBar progressBar;
|
||||
private View buttonRegister;
|
||||
private View buttonVerify;
|
||||
private View buttonRefresh;
|
||||
private View buttonBackup;
|
||||
private View buttonRestore;
|
||||
private EditText emailEditText;
|
||||
private OsmandTextFieldBoxes tokenEdit;
|
||||
private EditText tokenEditText;
|
||||
private TextView infoView;
|
||||
|
||||
public interface OnResultListener {
|
||||
void onResult(boolean success, @Nullable String result);
|
||||
}
|
||||
private BackupInfo backupInfo;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
app = getMyApplication();
|
||||
settings = app.getSettings();
|
||||
backupHelper = app.getBackupHelper();
|
||||
final WeakReference<TestBackupActivity> activityRef = new WeakReference<>(this);
|
||||
|
||||
boolean nightMode = !app.getSettings().isLightContent();
|
||||
|
@ -90,15 +82,23 @@ public class TestBackupActivity extends OsmandActionBarActivity {
|
|||
}
|
||||
});
|
||||
|
||||
if (!backupHelper.hasOsmLiveUpdates()) {
|
||||
findViewById(R.id.main_view).setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
|
||||
buttonRegister = findViewById(R.id.btn_register);
|
||||
UiUtilities.setupDialogButton(nightMode, buttonRegister, DialogButtonType.PRIMARY, "Register");
|
||||
buttonVerify = findViewById(R.id.btn_verify);
|
||||
UiUtilities.setupDialogButton(nightMode, buttonVerify, DialogButtonType.PRIMARY, "Verify");
|
||||
buttonRefresh = findViewById(R.id.btn_refresh);
|
||||
UiUtilities.setupDialogButton(nightMode, buttonRefresh, DialogButtonType.PRIMARY, "Refresh");
|
||||
buttonBackup = findViewById(R.id.btn_backup);
|
||||
UiUtilities.setupDialogButton(nightMode, buttonBackup, DialogButtonType.PRIMARY, "Backup");
|
||||
buttonRestore = findViewById(R.id.btn_restore);
|
||||
UiUtilities.setupDialogButton(nightMode, buttonRestore, DialogButtonType.PRIMARY, "Restore");
|
||||
|
||||
tokenEdit = findViewById(R.id.edit_token_label);
|
||||
tokenEditText = findViewById(R.id.edit_token);
|
||||
infoView = findViewById(R.id.text_info);
|
||||
progressBar = findViewById(R.id.progress_bar);
|
||||
|
@ -109,22 +109,31 @@ public class TestBackupActivity extends OsmandActionBarActivity {
|
|||
if (!Algorithms.isEmpty(email)) {
|
||||
emailEditText.setText(email);
|
||||
}
|
||||
if (backupHelper.isRegistered()) {
|
||||
tokenEdit.setVisibility(View.GONE);
|
||||
buttonVerify.setVisibility(View.GONE);
|
||||
} else {
|
||||
tokenEdit.setVisibility(View.VISIBLE);
|
||||
buttonVerify.setVisibility(View.VISIBLE);
|
||||
}
|
||||
buttonRegister.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
String email = emailEditText.getText().toString();
|
||||
if (isEmailValid(email)) {
|
||||
if (AndroidUtils.isValidEmail(email)) {
|
||||
buttonRegister.setEnabled(false);
|
||||
settings.BACKUP_USER_EMAIL.set(email);
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
registerUser(email, new OnResultListener() {
|
||||
backupHelper.registerUser(email, new OnRegisterUserListener() {
|
||||
@Override
|
||||
public void onResult(boolean success, @Nullable String result) {
|
||||
public void onRegisterUser(int status, @Nullable String message) {
|
||||
TestBackupActivity a = activityRef.get();
|
||||
if (AndroidUtils.isActivityNotDestroyed(a)) {
|
||||
a.progressBar.setVisibility(View.GONE);
|
||||
a.buttonRegister.setEnabled(!success);
|
||||
a.buttonVerify.setEnabled(success);
|
||||
a.buttonRegister.setEnabled(status != BackupHelper.STATUS_SUCCESS);
|
||||
a.tokenEdit.setVisibility(View.VISIBLE);
|
||||
a.buttonVerify.setVisibility(View.VISIBLE);
|
||||
a.buttonVerify.setEnabled(status == BackupHelper.STATUS_SUCCESS);
|
||||
a.tokenEditText.requestFocus();
|
||||
}
|
||||
}
|
||||
|
@ -139,17 +148,22 @@ public class TestBackupActivity extends OsmandActionBarActivity {
|
|||
@Override
|
||||
public void onClick(View v) {
|
||||
String token = tokenEditText.getText().toString();
|
||||
if (isTokenValid(token)) {
|
||||
if (BackupHelper.isTokenValid(token)) {
|
||||
buttonVerify.setEnabled(false);
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
registerDevice(token, new OnResultListener() {
|
||||
backupHelper.registerDevice(token, new BackupHelper.OnRegisterDeviceListener() {
|
||||
|
||||
@Override
|
||||
public void onResult(boolean success, @Nullable String result) {
|
||||
public void onRegisterDevice(int status, @Nullable String message) {
|
||||
TestBackupActivity a = activityRef.get();
|
||||
if (AndroidUtils.isActivityNotDestroyed(a)) {
|
||||
a.progressBar.setVisibility(View.GONE);
|
||||
a.buttonVerify.setEnabled(!success);
|
||||
a.loadBackupInfo();
|
||||
a.buttonVerify.setEnabled(status != BackupHelper.STATUS_SUCCESS);
|
||||
if (status == BackupHelper.STATUS_SUCCESS) {
|
||||
tokenEdit.setVisibility(View.GONE);
|
||||
buttonVerify.setVisibility(View.GONE);
|
||||
}
|
||||
a.prepareBackup();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -160,262 +174,120 @@ public class TestBackupActivity extends OsmandActionBarActivity {
|
|||
}
|
||||
}
|
||||
});
|
||||
buttonRefresh.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
prepareBackup();
|
||||
}
|
||||
});
|
||||
buttonBackup.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
uploadFiles();
|
||||
if (backupInfo != null) {
|
||||
BackupTask task = new BackupTask(backupInfo, TestBackupActivity.this, new OnBackupListener() {
|
||||
@Override
|
||||
public void onBackupDone(@Nullable Map<File, String> uploadErrors, @Nullable Map<File, String> downloadErrors,
|
||||
@Nullable Map<UserFile, String> deleteErrors, @Nullable String error) {
|
||||
TestBackupActivity a = activityRef.get();
|
||||
if (AndroidUtils.isActivityNotDestroyed(a)) {
|
||||
String description;
|
||||
if (error != null) {
|
||||
description = error;
|
||||
} else if (uploadErrors == null && downloadErrors == null) {
|
||||
description = "No data";
|
||||
} else {
|
||||
description = getBackupDescription(uploadErrors, downloadErrors, deleteErrors, error);
|
||||
}
|
||||
a.infoView.setText(description);
|
||||
a.infoView.requestFocus();
|
||||
a.prepareBackup();
|
||||
}
|
||||
}
|
||||
});
|
||||
task.runBackup();
|
||||
}
|
||||
}
|
||||
});
|
||||
buttonRestore.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
}
|
||||
});
|
||||
|
||||
loadBackupInfo();
|
||||
}
|
||||
|
||||
private void loadBackupInfo() {
|
||||
if (!Algorithms.isEmpty(getDeviceId()) && !Algorithms.isEmpty(getAccessToken())) {
|
||||
final WeakReference<TestBackupActivity> activityRef = new WeakReference<>(this);
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
loadBackupInfo(new OnResultListener() {
|
||||
@Override
|
||||
public void onResult(boolean success, @Nullable String result) {
|
||||
TestBackupActivity a = activityRef.get();
|
||||
if (AndroidUtils.isActivityNotDestroyed(a)) {
|
||||
a.progressBar.setVisibility(View.GONE);
|
||||
a.infoView.setText(result);
|
||||
a.infoView.requestFocus();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isEmailValid(CharSequence target) {
|
||||
return (!TextUtils.isEmpty(target) && Patterns.EMAIL_ADDRESS.matcher(target).matches());
|
||||
}
|
||||
|
||||
private String getOrderId() {
|
||||
return TEST_ORDER_ID;
|
||||
}
|
||||
|
||||
private String getDeviceId() {
|
||||
return settings.BACKUP_DEVICE_ID.get();
|
||||
}
|
||||
|
||||
private String getAccessToken() {
|
||||
return settings.BACKUP_ACCESS_TOKEN.get();
|
||||
}
|
||||
|
||||
private void registerUser(@NonNull String email, @Nullable final OnResultListener listener) {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("email", email);
|
||||
params.put("orderid", getOrderId());
|
||||
params.put("deviceid", app.getUserAndroidId());
|
||||
AndroidNetworkUtils.sendRequestAsync(app, "https://osmand.net/userdata/user-register", params, "Register user", true, true, new OnRequestResultListener() {
|
||||
@Override
|
||||
public void onResult(String resultJson) {
|
||||
boolean success = false;
|
||||
if (!Algorithms.isEmpty(resultJson)) {
|
||||
try {
|
||||
// {"status":"ok"}
|
||||
JSONObject result = new JSONObject(resultJson);
|
||||
String status = result.getString("status");
|
||||
success = status.equals("ok");
|
||||
app.showToastMessage(success
|
||||
? "You have been registered successfully. Please check for email with activation code."
|
||||
: "User registration error: " + status);
|
||||
} catch (JSONException e) {
|
||||
app.showToastMessage("User registration error: json parsing");
|
||||
}
|
||||
} else {
|
||||
app.showToastMessage("User registration error: empty response");
|
||||
}
|
||||
if (listener != null) {
|
||||
listener.onResult(success, resultJson);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void registerDevice(String token, @Nullable final OnResultListener listener) {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("email", settings.BACKUP_USER_EMAIL.get());
|
||||
params.put("orderid", getOrderId());
|
||||
params.put("deviceid", app.getUserAndroidId());
|
||||
params.put("token", token);
|
||||
AndroidNetworkUtils.sendRequestAsync(app, "https://osmand.net/userdata/device-register", params, "Register device", true, true, new OnRequestResultListener() {
|
||||
@Override
|
||||
public void onResult(String resultJson) {
|
||||
boolean success = false;
|
||||
if (!Algorithms.isEmpty(resultJson)) {
|
||||
try {
|
||||
/*
|
||||
{
|
||||
"id": 1034,
|
||||
"userid": 1033,
|
||||
"deviceid": "2fa8080d2985a777",
|
||||
"orderid": "460000687003939",
|
||||
"accesstoken": "4bc0a61f-397a-4c3e-9ffc-db382ec00372",
|
||||
"udpatetime": "Apr 11, 2021, 11:32:20 AM"
|
||||
}
|
||||
*/
|
||||
JSONObject result = new JSONObject(resultJson);
|
||||
settings.BACKUP_DEVICE_ID.set(result.getString("id"));
|
||||
settings.BACKUP_USER_ID.set(result.getString("userid"));
|
||||
settings.BACKUP_NATIVE_DEVICE_ID.set(result.getString("deviceid"));
|
||||
settings.BACKUP_ACCESS_TOKEN.set(result.getString("accesstoken"));
|
||||
settings.BACKUP_ACCESS_TOKEN_UPDATE_TIME.set(result.getString("udpatetime"));
|
||||
success = true;
|
||||
app.showToastMessage("Device have been registered successfully");
|
||||
} catch (JSONException e) {
|
||||
app.showToastMessage("Device registration error: json parsing");
|
||||
}
|
||||
} else {
|
||||
app.showToastMessage("Device registration error: empty response");
|
||||
}
|
||||
if (listener != null) {
|
||||
listener.onResult(success, resultJson);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void uploadFiles() {
|
||||
LoadGpxTask loadGpxTask = new LoadGpxTask(this, new LoadGpxTask.OnLoadGpxListener() {
|
||||
@Override
|
||||
public void onLoadGpxDone(@NonNull List<GpxInfo> result) {
|
||||
uploadFiles(result);
|
||||
}
|
||||
});
|
||||
loadGpxTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, this);
|
||||
}
|
||||
|
||||
private void uploadFiles(List<GpxInfo> gpxFiles) {
|
||||
//{"status":"ok"}
|
||||
final WeakReference<TestBackupActivity> activityRef = new WeakReference<>(this);
|
||||
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("deviceid", getDeviceId());
|
||||
params.put("accessToken", getAccessToken());
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("Accept-Encoding", "deflate, gzip");
|
||||
|
||||
final Map<File, GpxInfo> gpxInfos = new HashMap<>();
|
||||
for (GpxInfo gpxFile : gpxFiles) {
|
||||
gpxInfos.put(gpxFile.file, gpxFile);
|
||||
}
|
||||
final List<File> files = new ArrayList<>(gpxInfos.keySet());
|
||||
File favoritesFile = app.getFavorites().getExternalFile();
|
||||
files.add(favoritesFile);
|
||||
|
||||
final ProgressImplementation progress = ProgressImplementation.createProgressDialog(this,
|
||||
"Create backup", "Uploading " + files.size() + " file(s) to server", ProgressDialog.STYLE_HORIZONTAL);
|
||||
|
||||
AndroidNetworkUtils.uploadFilesAsync("https://osmand.net/userdata/upload-file", files, true, params, headers, new OnFilesUploadCallback() {
|
||||
@Nullable
|
||||
@Override
|
||||
public Map<String, String> getAdditionalParams(@NonNull File file) {
|
||||
GpxInfo gpxInfo = gpxInfos.get(file);
|
||||
Map<String, String> additionaParams = new HashMap<>();
|
||||
additionaParams.put("name", gpxInfo == null ? file.getName() : gpxInfo.getFileName(true));
|
||||
additionaParams.put("type", Algorithms.getFileExtension(file));
|
||||
return additionaParams;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFileUploadProgress(@NonNull File file, int percent) {
|
||||
Activity a = activityRef.get();
|
||||
if (AndroidUtils.isActivityNotDestroyed(a)) {
|
||||
if (percent < 100) {
|
||||
progress.startTask(file.getName(), percent);
|
||||
} else {
|
||||
progress.finishTask();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFilesUploadDone(@NonNull Map<File, String> errors) {
|
||||
Activity a = activityRef.get();
|
||||
if (AndroidUtils.isActivityNotDestroyed(a)) {
|
||||
app.runInUIThread(new Runnable() {
|
||||
if (backupInfo != null) {
|
||||
BackupTask task = new BackupTask(backupInfo, TestBackupActivity.this, new OnBackupListener() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (progress.getDialog().isShowing()) {
|
||||
progress.getDialog().dismiss();
|
||||
public void onBackupDone(@Nullable Map<File, String> uploadErrors, @Nullable Map<File, String> downloadErrors,
|
||||
@Nullable Map<UserFile, String> deleteErrors, @Nullable String error) {
|
||||
TestBackupActivity a = activityRef.get();
|
||||
if (AndroidUtils.isActivityNotDestroyed(a)) {
|
||||
String description;
|
||||
if (error != null) {
|
||||
description = error;
|
||||
} else if (uploadErrors == null && downloadErrors == null) {
|
||||
description = "No data";
|
||||
} else {
|
||||
description = getBackupDescription(uploadErrors, downloadErrors, deleteErrors, error);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
//ignored
|
||||
a.infoView.setText(description);
|
||||
a.infoView.requestFocus();
|
||||
a.prepareBackup();
|
||||
}
|
||||
}
|
||||
}, 300);
|
||||
app.showToastMessage("Uploaded " + (files.size() - errors.size() + " files" +
|
||||
(errors.size() > 0 ? ". Errors: " + errors.size() : "")));
|
||||
loadBackupInfo();
|
||||
});
|
||||
task.runRestore();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
prepareBackup();
|
||||
}
|
||||
|
||||
private void loadBackupInfo(@Nullable final OnResultListener listener) {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("deviceid", getDeviceId());
|
||||
params.put("accessToken", getAccessToken());
|
||||
AndroidNetworkUtils.sendRequestAsync(app, "https://osmand.net/userdata/list-files", params, "Get backup info", true, false, new OnRequestResultListener() {
|
||||
private String getBackupDescription(@Nullable Map<File, String> uploadErrors, @Nullable Map<File, String> downloadErrors, @Nullable Map<UserFile, String> deleteErrors, @Nullable String error) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (!Algorithms.isEmpty(uploadErrors)) {
|
||||
sb.append("--- Upload errors ---").append("\n");
|
||||
for (Entry<File, String> uploadEntry : uploadErrors.entrySet()) {
|
||||
sb.append(uploadEntry.getKey().getName()).append(": ").append(uploadEntry.getValue()).append("\n");
|
||||
}
|
||||
}
|
||||
if (!Algorithms.isEmpty(downloadErrors)) {
|
||||
sb.append("--- Download errors ---").append("\n");
|
||||
for (Entry<File, String> downloadEntry : downloadErrors.entrySet()) {
|
||||
sb.append(downloadEntry.getKey().getName()).append(": ").append(downloadEntry.getValue()).append("\n");
|
||||
}
|
||||
}
|
||||
if (!Algorithms.isEmpty(deleteErrors)) {
|
||||
sb.append("--- Delete errors ---").append("\n");
|
||||
for (Entry<UserFile, String> deleteEntry : deleteErrors.entrySet()) {
|
||||
sb.append(deleteEntry.getKey().getName()).append(": ").append(deleteEntry.getValue()).append("\n");
|
||||
}
|
||||
}
|
||||
return sb.length() == 0 ? "OK" : sb.toString();
|
||||
}
|
||||
|
||||
private void prepareBackup() {
|
||||
final WeakReference<TestBackupActivity> activityRef = new WeakReference<>(this);
|
||||
PrepareBackupTask prepareBackupTask = new PrepareBackupTask(this, new OnPrepareBackupListener() {
|
||||
@Override
|
||||
public void onResult(String resultJson) {
|
||||
boolean success = false;
|
||||
StringBuilder resultString = new StringBuilder();
|
||||
if (!Algorithms.isEmpty(resultJson)) {
|
||||
try {
|
||||
/*
|
||||
{
|
||||
"totalZipSize": 21792,
|
||||
"totalFileSize": 185920,
|
||||
"totalFiles": 1,
|
||||
"totalFileVersions": 2,
|
||||
"uniqueFiles": [
|
||||
{
|
||||
"userid": 1033,
|
||||
"id": 7,
|
||||
"deviceid": 1034,
|
||||
"filesize": 92960,
|
||||
"type": "gpx",
|
||||
"name": "test/Day 2.gpx",
|
||||
"updatetime": "Apr 11, 2021, 1:49:01 PM",
|
||||
"updatetimems": 1618141741822,
|
||||
"zipSize": 10896
|
||||
}
|
||||
],
|
||||
"deviceid": 1034
|
||||
}
|
||||
*/
|
||||
JSONObject result = new JSONObject(resultJson);
|
||||
String totalZipSize = result.getString("totalZipSize");
|
||||
String totalFiles = result.getString("totalFiles");
|
||||
String totalFileVersions = result.getString("totalFileVersions");
|
||||
JSONArray files = result.getJSONArray("uniqueFiles");
|
||||
resultString.append("Total files: ").append(totalFiles).append("\n");
|
||||
resultString.append("Total zip size: ").append(AndroidUtils.formatSize(app, Long.parseLong(totalZipSize))).append("\n");
|
||||
resultString.append("Total file versions: ").append(totalFileVersions);
|
||||
|
||||
success = true;
|
||||
} catch (JSONException e) {
|
||||
public void onBackupPrepared(@Nullable BackupInfo backupInfo, @Nullable String error) {
|
||||
TestBackupActivity.this.backupInfo = backupInfo;
|
||||
TestBackupActivity a = activityRef.get();
|
||||
if (AndroidUtils.isActivityNotDestroyed(a)) {
|
||||
String description;
|
||||
if (error != null) {
|
||||
description = error;
|
||||
} else if (backupInfo == null) {
|
||||
description = "No data";
|
||||
} else {
|
||||
description = "Files to upload: " + backupInfo.filesToUpload.size()
|
||||
+ "\nFiles to download: " + backupInfo.filesToDownload.size()
|
||||
+ "\nFiles to delete: " + backupInfo.filesToDelete.size()
|
||||
+ "\nConflicts: " + backupInfo.filesToMerge.size();
|
||||
}
|
||||
}
|
||||
if (listener != null) {
|
||||
listener.onResult(success, resultString.toString());
|
||||
a.infoView.setText(description);
|
||||
a.infoView.requestFocus();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isTokenValid(String token) {
|
||||
return token.matches("[0-9]+");
|
||||
prepareBackupTask.prepare();
|
||||
}
|
||||
|
||||
private int resolveResourceId(final Activity activity, final int attr) {
|
||||
|
@ -423,173 +295,4 @@ public class TestBackupActivity extends OsmandActionBarActivity {
|
|||
activity.getTheme().resolveAttribute(attr, typedvalueattr, true);
|
||||
return typedvalueattr.resourceId;
|
||||
}
|
||||
|
||||
private static class LoadGpxTask extends AsyncTask<Activity, GpxInfo, List<GpxInfo>> {
|
||||
|
||||
private final OsmandApplication app;
|
||||
private final OnLoadGpxListener listener;
|
||||
private final WeakReference<Activity> activityRef;
|
||||
private List<GpxInfo> result;
|
||||
private ProgressImplementation progress;
|
||||
|
||||
interface OnLoadGpxListener {
|
||||
void onLoadGpxDone(@NonNull List<GpxInfo> result);
|
||||
}
|
||||
|
||||
LoadGpxTask(@NonNull Activity activity, @Nullable OnLoadGpxListener listener) {
|
||||
this.activityRef = new WeakReference<>(activity);
|
||||
this.app = (OsmandApplication) activity.getApplication();
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public List<GpxInfo> getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected List<GpxInfo> doInBackground(Activity... params) {
|
||||
List<GpxInfo> result = new ArrayList<>();
|
||||
loadGPXData(app.getAppPath(IndexConstants.GPX_INDEX_DIR), result, this);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void loadFile(GpxInfo... loaded) {
|
||||
publishProgress(loaded);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
Activity a = activityRef.get();
|
||||
if (AndroidUtils.isActivityNotDestroyed(a)) {
|
||||
progress = ProgressImplementation.createProgressDialog(a,
|
||||
"Create backup", "Collecting gpx files...", ProgressDialog.STYLE_HORIZONTAL);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(GpxInfo... values) {
|
||||
Activity a = activityRef.get();
|
||||
if (AndroidUtils.isActivityNotDestroyed(a)) {
|
||||
progress.startTask(values[0].getFileName(true), -1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(@NonNull List<GpxInfo> result) {
|
||||
this.result = result;
|
||||
if (listener != null) {
|
||||
listener.onLoadGpxDone(result);
|
||||
}
|
||||
Activity a = activityRef.get();
|
||||
if (AndroidUtils.isActivityNotDestroyed(a)) {
|
||||
progress.finishTask();
|
||||
app.runInUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (progress.getDialog().isShowing()) {
|
||||
progress.getDialog().dismiss();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
//ignored
|
||||
}
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadGPXData(File mapPath, List<GpxInfo> result, LoadGpxTask loadTask) {
|
||||
if (mapPath.canRead()) {
|
||||
List<GpxInfo> progress = new ArrayList<>();
|
||||
loadGPXFolder(mapPath, result, loadTask, progress, "");
|
||||
if (!progress.isEmpty()) {
|
||||
loadTask.loadFile(progress.toArray(new GpxInfo[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadGPXFolder(File mapPath, List<GpxInfo> result, LoadGpxTask loadTask, List<GpxInfo> progress,
|
||||
String gpxSubfolder) {
|
||||
File[] listFiles = mapPath.listFiles();
|
||||
if (listFiles != null) {
|
||||
for (File gpxFile : listFiles) {
|
||||
if (gpxFile.isDirectory()) {
|
||||
String sub = gpxSubfolder.length() == 0 ? gpxFile.getName() : gpxSubfolder + "/"
|
||||
+ gpxFile.getName();
|
||||
loadGPXFolder(gpxFile, result, loadTask, progress, sub);
|
||||
} else if (gpxFile.isFile() && gpxFile.getName().toLowerCase().endsWith(IndexConstants.GPX_FILE_EXT)) {
|
||||
GpxInfo info = new GpxInfo();
|
||||
info.subfolder = gpxSubfolder;
|
||||
info.file = gpxFile;
|
||||
result.add(info);
|
||||
progress.add(info);
|
||||
if (progress.size() > 7) {
|
||||
loadTask.loadFile(progress.toArray(new GpxInfo[0]));
|
||||
progress.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class GpxInfo {
|
||||
public File file;
|
||||
public String subfolder;
|
||||
|
||||
private String name = null;
|
||||
private int sz = -1;
|
||||
private String fileName = null;
|
||||
|
||||
public String getName() {
|
||||
if (name == null) {
|
||||
name = formatName(file.getName());
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
private String formatName(String name) {
|
||||
int ext = name.lastIndexOf('.');
|
||||
if (ext != -1) {
|
||||
name = name.substring(0, ext);
|
||||
}
|
||||
return name.replace('_', ' ');
|
||||
}
|
||||
|
||||
// Usage: AndroidUtils.formatSize(v.getContext(), getSize() * 1024l);
|
||||
public int getSize() {
|
||||
if (sz == -1) {
|
||||
if (file == null) {
|
||||
return -1;
|
||||
}
|
||||
sz = (int) ((file.length() + 512) >> 10);
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
|
||||
public long getFileDate() {
|
||||
if (file == null) {
|
||||
return 0;
|
||||
}
|
||||
return file.lastModified();
|
||||
}
|
||||
|
||||
public String getFileName(boolean includeSubfolder) {
|
||||
String result;
|
||||
if (fileName != null) {
|
||||
result = fileName;
|
||||
} else {
|
||||
if (file == null) {
|
||||
result = "";
|
||||
} else {
|
||||
result = fileName = file.getName();
|
||||
}
|
||||
}
|
||||
if (includeSubfolder && !Algorithms.isEmpty(subfolder)) {
|
||||
result = subfolder + "/" + result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import androidx.fragment.app.FragmentActivity;
|
|||
import net.osmand.GPXUtilities.GPXFile;
|
||||
import net.osmand.data.FavouritePoint;
|
||||
import net.osmand.plus.FavouritesDbHelper;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.base.BaseLoadAsyncTask;
|
||||
|
||||
|
@ -17,7 +18,7 @@ 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 BaseLoadAsyncTask<Void, Void, GPXFile> {
|
||||
public class FavoritesImportTask extends BaseLoadAsyncTask<Void, Void, GPXFile> {
|
||||
|
||||
private GPXFile gpxFile;
|
||||
private String fileName;
|
||||
|
@ -33,6 +34,12 @@ class FavoritesImportTask extends BaseLoadAsyncTask<Void, Void, GPXFile> {
|
|||
|
||||
@Override
|
||||
protected GPXFile doInBackground(Void... nothing) {
|
||||
mergeFavorites(app, gpxFile, fileName, forceImportFavourites);
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void mergeFavorites(@NonNull OsmandApplication app, @NonNull GPXFile gpxFile,
|
||||
@NonNull String fileName, boolean forceImportFavourites) {
|
||||
List<FavouritePoint> favourites = asFavourites(app, gpxFile.getPoints(), fileName, forceImportFavourites);
|
||||
FavouritesDbHelper favoritesHelper = app.getFavorites();
|
||||
checkDuplicateNames(favourites);
|
||||
|
@ -42,10 +49,9 @@ class FavoritesImportTask extends BaseLoadAsyncTask<Void, Void, GPXFile> {
|
|||
}
|
||||
favoritesHelper.sortAll();
|
||||
favoritesHelper.saveCurrentPointsIntoFile();
|
||||
return null;
|
||||
}
|
||||
|
||||
public void checkDuplicateNames(List<FavouritePoint> favourites) {
|
||||
public static void checkDuplicateNames(List<FavouritePoint> favourites) {
|
||||
for (FavouritePoint fp : favourites) {
|
||||
int number = 1;
|
||||
String index;
|
||||
|
|
|
@ -10,7 +10,7 @@ import android.util.Log;
|
|||
|
||||
import net.osmand.AndroidNetworkUtils;
|
||||
import net.osmand.AndroidNetworkUtils.OnRequestResultListener;
|
||||
import net.osmand.AndroidNetworkUtils.OnRequestsResultListener;
|
||||
import net.osmand.AndroidNetworkUtils.OnSendRequestsListener;
|
||||
import net.osmand.AndroidNetworkUtils.RequestResponse;
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
|
@ -608,9 +608,14 @@ public abstract class InAppPurchaseHelper {
|
|||
addUserInfo(parameters);
|
||||
requests.add(new AndroidNetworkUtils.Request(url, parameters, userOperation, true, true));
|
||||
}
|
||||
AndroidNetworkUtils.sendRequestsAsync(ctx, requests, new OnRequestsResultListener() {
|
||||
AndroidNetworkUtils.sendRequestsAsync(ctx, requests, new OnSendRequestsListener() {
|
||||
|
||||
@Override
|
||||
public void onResult(@NonNull List<RequestResponse> results) {
|
||||
public void onRequestSent(@NonNull RequestResponse response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestsSent(@NonNull List<RequestResponse> results) {
|
||||
for (RequestResponse rr : results) {
|
||||
String sku = rr.getRequest().getParameters().get("sku");
|
||||
PurchaseInfo info = getPurchaseInfo(sku);
|
||||
|
|
|
@ -1172,6 +1172,9 @@ public class OsmandSettings {
|
|||
public final OsmandPreference<String> BACKUP_ACCESS_TOKEN = new StringPreference(this, "backup_access_token", "").makeGlobal();
|
||||
public final OsmandPreference<String> BACKUP_ACCESS_TOKEN_UPDATE_TIME = new StringPreference(this, "backup_access_token_update_time", "").makeGlobal();
|
||||
|
||||
public final OsmandPreference<Long> FAVORITES_LAST_UPLOADED_TIME = new LongPreference(this, "favorites_last_uploaded_time", 0L).makeGlobal();
|
||||
public final OsmandPreference<Long> BACKUP_LAST_UPLOADED_TIME = new LongPreference(this, "backup_last_uploaded_time", 0L).makeGlobal();
|
||||
|
||||
// this value string is synchronized with settings_pref.xml preference name
|
||||
public final OsmandPreference<String> USER_OSM_BUG_NAME =
|
||||
new StringPreference(this, "user_osm_bug_name", "NoName/OsmAnd").makeGlobal().makeShared();
|
||||
|
|
Loading…
Reference in a new issue