[WIP] test backups

This commit is contained in:
max-klaus 2021-04-11 22:09:24 +03:00
parent 236f4c05b6
commit f73fd42931
9 changed files with 649 additions and 7 deletions

View file

@ -1026,6 +1026,7 @@
</activity>
<activity android:name="net.osmand.plus.development.TestVoiceActivity" />
<activity android:name="net.osmand.plus.development.TestBackupActivity" />
<activity android:name="net.osmand.plus.development.LogcatActivity" />
<activity android:name="net.osmand.plus.download.DownloadActivity" android:label="" />

View file

@ -0,0 +1,151 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/activity_background_basic"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/toolbar_theme">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right"
android:paddingStart="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding"
android:paddingEnd="@dimen/content_padding"
android:paddingRight="@dimen/content_padding">
<ProgressBar
android:id="@+id/progress_bar"
android:layout_width="@dimen/card_button_progress_size"
android:layout_height="@dimen/card_button_progress_size"
android:visibility="gone" />
</LinearLayout>
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/content_padding"
android:orientation="vertical"
android:paddingBottom="@dimen/content_padding">
<net.osmand.plus.widgets.OsmandTextFieldBoxes
android:id="@+id/edit_email_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="true"
android:focusableInTouchMode="true"
android:paddingBottom="@dimen/content_padding_small"
app:errorColor="@color/color_invalid"
app:hasClearButton="true"
app:labelText="Email"
app:primaryColor="@color/active_color_primary_dark"
app:secondaryColor="?android:textColorSecondary">
<studio.carbonylgroup.textfieldboxes.ExtendedEditText
android:id="@+id/edit_email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="actionNext"
android:inputType="textEmailAddress"
android:maxLines="1"
tools:text="test@test.com" />
</net.osmand.plus.widgets.OsmandTextFieldBoxes>
<include
android:id="@+id/btn_register"
layout="@layout/bottom_sheet_dialog_button"
android:layout_width="match_parent"
android:layout_height="@dimen/dialog_button_height" />
<net.osmand.plus.widgets.OsmandTextFieldBoxes
android:id="@+id/edit_token_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="true"
android:focusableInTouchMode="true"
android:paddingTop="@dimen/content_padding_small"
android:paddingBottom="@dimen/content_padding_small"
app:errorColor="@color/color_invalid"
app:hasClearButton="true"
app:labelText="Token"
app:primaryColor="@color/active_color_primary_dark"
app:secondaryColor="?android:textColorSecondary">
<studio.carbonylgroup.textfieldboxes.ExtendedEditText
android:id="@+id/edit_token"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="actionNext"
android:inputType="numberDecimal"
android:maxLines="1"
tools:text="123456" />
</net.osmand.plus.widgets.OsmandTextFieldBoxes>
<include
android:id="@+id/btn_verify"
layout="@layout/bottom_sheet_dialog_button"
android:layout_width="match_parent"
android:layout_height="@dimen/dialog_button_height" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/content_padding"
android:text="Actions"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size" />
<include
android:id="@+id/btn_backup"
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_restore"
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" />
<TextView
android:id="@+id/text_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/content_padding"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size"
tools:text="Last backup time: 2021-04-01 10:10:00\nModified files: 3" />
</LinearLayout>
</ScrollView>
</LinearLayout>

View file

@ -70,6 +70,13 @@
android:summary="@string/play_commands_of_currently_selected_voice"
android:title="@string/test_voice_prompts" />
<Preference
android:key="test_backup"
android:layout="@layout/preference_with_descr"
android:persistent="false"
android:summary="Register and backup/restore tracks and favorites"
android:title="Test backup" />
<Preference
android:key="logcat_buffer"
android:layout="@layout/preference_with_descr"

View file

@ -3,6 +3,7 @@ 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;
@ -33,8 +34,10 @@ import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.zip.GZIPOutputStream;
public class AndroidNetworkUtils {
@ -46,6 +49,13 @@ public class AndroidNetworkUtils {
void onResult(String result);
}
public interface OnFilesUploadCallback {
@Nullable
Map<String, String> getAdditionalParams(@NonNull File file);
void onFileUploadProgress(@NonNull File file, int percent);
void onFilesUploadDone(@NonNull Map<File, String> errors);
}
public static class RequestResponse {
private Request request;
private String response;
@ -156,7 +166,7 @@ public class AndroidNetworkUtils {
String params = null;
if (parameters != null && parameters.size() > 0) {
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : parameters.entrySet()) {
for (Entry<String, String> entry : parameters.entrySet()) {
if (sb.length() > 0) {
sb.append("&");
}
@ -296,16 +306,18 @@ public class AndroidNetworkUtils {
private static final String BOUNDARY = "CowMooCowMooCowCowCow";
public static String uploadFile(String urlText, File file, boolean gzip, Map<String, String> additionalParams) throws IOException {
return uploadFile(urlText, new FileInputStream(file), file.getName(), gzip, additionalParams);
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);
}
public static String uploadFile(String urlText, InputStream inputStream, String fileName, boolean gzip, Map<String, String> additionalParams) {
public static String uploadFile(@NonNull String urlText, @NonNull InputStream inputStream, @NonNull String fileName, boolean gzip,
Map<String, String> additionalParams, @Nullable Map<String, String> headers) {
URL url;
try {
boolean firstPrm = !urlText.contains("?");
StringBuilder sb = new StringBuilder(urlText);
for (Map.Entry<String, String> entry : additionalParams.entrySet()) {
for (Entry<String, String> entry : additionalParams.entrySet()) {
sb.append(firstPrm ? "?" : "&").append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue(), "UTF-8"));
firstPrm = false;
}
@ -320,6 +332,11 @@ public class AndroidNetworkUtils {
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
conn.setRequestProperty("User-Agent", "OsmAnd");
if (headers != null) {
for (Entry<String, String> header : headers.entrySet()) {
conn.setRequestProperty(header.getKey(), header.getValue());
}
}
OutputStream ous = conn.getOutputStream();
ous.write(("--" + BOUNDARY + "\r\n").getBytes());
@ -376,6 +393,58 @@ public class AndroidNetworkUtils {
}
}
public static void uploadFilesAsync(final @NonNull String url,
final @NonNull List<File> files,
final boolean gzip,
final @NonNull Map<String, String> parameters,
final @Nullable Map<String, String> headers,
final OnFilesUploadCallback callback) {
new AsyncTask<Void, Object, Map<File, String>>() {
@Override
@NonNull
protected Map<File, String> doInBackground(Void... v) {
Map<File, String> errors = new HashMap<>();
for (File file : files) {
publishProgress(file, 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);
}
}
String res = uploadFile(url, file, gzip, params, headers);
if (res != null) {
errors.put(file, res);
}
} catch (Exception e) {
errors.put(file, e.getMessage());
}
publishProgress(file, 100);
}
return errors;
}
@Override
protected void onProgressUpdate(Object... objects) {
if (callback != null) {
callback.onFileUploadProgress((File) objects[0], (Integer) objects[1]);
}
}
@Override
protected void onPostExecute(@NonNull Map<File, String> errors) {
if (callback != null) {
callback.onFilesUploadDone(errors);
}
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
}
private static void showToast(OsmandApplication ctx, String message) {
ctx.showToastMessage(message);
}

View file

@ -184,7 +184,7 @@ 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);
String res = AndroidNetworkUtils.uploadFile(ANALYTICS_UPLOAD_URL, inputStream, ANALYTICS_FILE_NAME, true, additionalData, null);
if (res != null) {
return;
}

View file

@ -48,6 +48,7 @@ public class DevelopmentSettingsFragment extends BaseSettingsFragment {
setupSimulateInitialStartupPref();
setupShouldShowFreeVersionBannerPref();
setupTestVoiceCommandsPref();
setupTestBackupsPref();
setupLogcatBufferPref();
Preference info = findPreference("info");
@ -117,6 +118,12 @@ public class DevelopmentSettingsFragment extends BaseSettingsFragment {
testVoiceCommands.setIconSpaceReserved(false);
}
private void setupTestBackupsPref() {
Preference testBackups = findPreference("test_backup");
testBackups.setIntent(new Intent(getActivity(), TestBackupActivity.class));
testBackups.setIconSpaceReserved(false);
}
private void setupLogcatBufferPref() {
Preference logcatBuffer = findPreference("logcat_buffer");
logcatBuffer.setIntent(new Intent(getActivity(), LogcatActivity.class));

View file

@ -0,0 +1,400 @@
package net.osmand.plus.development;
import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.drawable.Drawable;
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.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.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.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class TestBackupActivity extends OsmandActionBarActivity {
private static final String TEST_ORDER_ID = "460000687003939";
private OsmandApplication app;
private OsmandSettings settings;
private ProgressBar progressBar;
private View buttonRegister;
private View buttonVerify;
private View buttonBackup;
private View buttonRestore;
private EditText emailEditText;
private EditText tokenEditText;
private TextView infoView;
public interface OnResultListener {
void onResult(boolean success, @Nullable String result);
}
@Override
public void onCreate(Bundle savedInstanceState) {
app = getMyApplication();
settings = app.getSettings();
final WeakReference<TestBackupActivity> activityRef = new WeakReference<>(this);
boolean nightMode = !app.getSettings().isLightContent();
int themeId = nightMode ? R.style.OsmandDarkTheme_NoActionbar : R.style.OsmandLightTheme_NoActionbar;
setTheme(themeId);
super.onCreate(savedInstanceState);
setContentView(R.layout.test_backup_layout);
Toolbar tb = findViewById(R.id.toolbar);
tb.setTitle("Backup test");
tb.setClickable(true);
Drawable icBack = ((OsmandApplication) getApplication()).getUIUtilities().getIcon(AndroidUtils.getNavigationIconResId(app));
tb.setNavigationIcon(icBack);
tb.setNavigationContentDescription(R.string.access_shared_string_navigate_up);
tb.setBackgroundColor(getResources().getColor(resolveResourceId(this, R.attr.pstsTabBackground)));
tb.setTitleTextColor(getResources().getColor(resolveResourceId(this, R.attr.pstsTextColor)));
tb.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
finish();
}
});
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");
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");
tokenEditText = findViewById(R.id.edit_token);
infoView = findViewById(R.id.text_info);
progressBar = findViewById(R.id.progress_bar);
buttonVerify.setEnabled(false);
emailEditText = findViewById(R.id.edit_email);
String email = settings.BACKUP_USER_EMAIL.get();
if (!Algorithms.isEmpty(email)) {
emailEditText.setText(email);
}
buttonRegister.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String email = emailEditText.getText().toString();
if (isEmailValid(email)) {
buttonRegister.setEnabled(false);
settings.BACKUP_USER_EMAIL.set(email);
progressBar.setVisibility(View.VISIBLE);
registerUser(email, 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.buttonRegister.setEnabled(!success);
a.buttonVerify.setEnabled(success);
a.tokenEditText.requestFocus();
}
}
});
} else {
emailEditText.requestFocus();
emailEditText.setError(getString(R.string.osm_live_enter_email));
}
}
});
buttonVerify.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String token = tokenEditText.getText().toString();
if (isTokenValid(token)) {
buttonVerify.setEnabled(false);
progressBar.setVisibility(View.VISIBLE);
registerDevice(token, 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.buttonVerify.setEnabled(!success);
a.loadBackupInfo();
}
}
});
} else {
tokenEditText.requestFocus();
tokenEditText.setError("Token is not valid");
buttonVerify.setEnabled(true);
}
}
});
buttonBackup.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
uploadFiles();
}
});
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() {
//{"status":"ok"}
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 List<File> files = new ArrayList<>();
final ProgressImplementation progress = ProgressImplementation.createProgressDialog(this,
"Uploading files to server", "Files count: " + files.size(), ProgressDialog.STYLE_HORIZONTAL);
File favoritesFile = app.getFavorites().getExternalFile();
files.add(favoritesFile);
AndroidNetworkUtils.uploadFilesAsync("https://osmand.net/userdata/upload-file", files, true, params, headers, new OnFilesUploadCallback() {
@Nullable
@Override
public Map<String, String> getAdditionalParams(@NonNull File file) {
Map<String, String> additionaParams = new HashMap<>();
additionaParams.put("name", file.getName());
additionaParams.put("type", Algorithms.getFileExtension(file));
return additionaParams;
}
@Override
public void onFileUploadProgress(@NonNull File file, int percent) {
if (percent < 100) {
progress.startTask(file.getName(), percent);
} else {
progress.finishTask();
}
}
@Override
public void onFilesUploadDone(@NonNull Map<File, String> errors) {
app.runInUIThread(new Runnable() {
@Override
public void run() {
try {
if (progress.getDialog().isShowing()) {
progress.getDialog().dismiss();
}
} catch (Exception e) {
//ignored
}
}
}, 300);
app.showToastMessage("Uploaded " + (files.size() - errors.size() + " files" +
(errors.size() > 0 ? ". Errors: " + errors.size() : "")));
loadBackupInfo();
}
});
}
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() {
@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) {
}
}
if (listener != null) {
listener.onResult(success, resultString.toString());
}
}
});
}
private boolean isTokenValid(String token) {
return token.matches("[0-9]+");
}
private int resolveResourceId(final Activity activity, final int attr) {
final TypedValue typedvalueattr = new TypedValue();
activity.getTheme().resolveAttribute(attr, typedvalueattr, true);
return typedvalueattr.resourceId;
}
}

View file

@ -1165,6 +1165,13 @@ public class OsmandSettings {
public final OsmandPreference<Integer> DISCOUNT_TOTAL_SHOW = new IntPreference(this, "discount_total_show", 0).makeGlobal();
public final OsmandPreference<Long> DISCOUNT_SHOW_DATETIME_MS = new LongPreference(this, "show_discount_datetime_ms", 0).makeGlobal();
public final OsmandPreference<String> BACKUP_USER_EMAIL = new StringPreference(this, "backup_user_email", "").makeGlobal();
public final OsmandPreference<String> BACKUP_USER_ID = new StringPreference(this, "backup_user_id", "").makeGlobal();
public final OsmandPreference<String> BACKUP_DEVICE_ID = new StringPreference(this, "backup_device_id", "").makeGlobal();
public final OsmandPreference<String> BACKUP_NATIVE_DEVICE_ID = new StringPreference(this, "backup_native_device_id", "").makeGlobal();
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();
// 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();

View file

@ -10,7 +10,7 @@ buildscript {
}
dependencies {
//classpath 'com.android.tools.build:gradle:2.+'
classpath 'com.android.tools.build:gradle:4.1.2'
classpath 'com.android.tools.build:gradle:4.1.3'
classpath 'com.google.gms:google-services:3.0.0'
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"