mirror of
https://codeberg.org/comaps/comaps
synced 2025-12-19 13:03:36 +00:00
[android] Add validation for custom map download URL
- Add validation for custom map download URL. - Re-enable advanced server button after failed or paused downloads. Signed-off-by: NoelClick <dev@noel.click>
This commit is contained in:
committed by
Konstantin Pastbin
parent
c75d1fc79d
commit
a1a13caa4e
@@ -13,6 +13,7 @@ import static app.organicmaps.sdk.DownloadResourcesLegacyActivity.nativeStartNex
|
|||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
@@ -20,13 +21,25 @@ import android.os.Bundle;
|
|||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.widget.Button;
|
||||||
|
|
||||||
import androidx.activity.result.ActivityResultLauncher;
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
import androidx.activity.result.contract.ActivityResultContracts;
|
import androidx.activity.result.contract.ActivityResultContracts;
|
||||||
import androidx.annotation.CallSuper;
|
import androidx.annotation.CallSuper;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes;
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.core.view.ViewCompat;
|
import androidx.core.view.ViewCompat;
|
||||||
|
|
||||||
|
import com.google.android.material.button.MaterialButton;
|
||||||
|
import com.google.android.material.checkbox.MaterialCheckBox;
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
|
import com.google.android.material.progressindicator.LinearProgressIndicator;
|
||||||
|
import com.google.android.material.textfield.TextInputEditText;
|
||||||
|
import com.google.android.material.textfield.TextInputLayout;
|
||||||
|
import com.google.android.material.textview.MaterialTextView;
|
||||||
|
|
||||||
import app.organicmaps.base.BaseMwmFragmentActivity;
|
import app.organicmaps.base.BaseMwmFragmentActivity;
|
||||||
import app.organicmaps.downloader.MapManagerHelper;
|
import app.organicmaps.downloader.MapManagerHelper;
|
||||||
import app.organicmaps.intent.Factory;
|
import app.organicmaps.intent.Factory;
|
||||||
@@ -40,12 +53,7 @@ import app.organicmaps.sdk.util.StringUtils;
|
|||||||
import app.organicmaps.util.UiUtils;
|
import app.organicmaps.util.UiUtils;
|
||||||
import app.organicmaps.util.Utils;
|
import app.organicmaps.util.Utils;
|
||||||
import app.organicmaps.util.WindowInsetUtils.PaddingInsetsListener;
|
import app.organicmaps.util.WindowInsetUtils.PaddingInsetsListener;
|
||||||
import com.google.android.material.button.MaterialButton;
|
|
||||||
import com.google.android.material.checkbox.MaterialCheckBox;
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
|
||||||
import com.google.android.material.progressindicator.LinearProgressIndicator;
|
|
||||||
import com.google.android.material.textfield.TextInputEditText;
|
|
||||||
import com.google.android.material.textview.MaterialTextView;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@@ -274,6 +282,7 @@ public class DownloadResourcesLegacyActivity extends BaseMwmFragmentActivity
|
|||||||
mBtnAdvanced = findViewById(R.id.btn_advanced);
|
mBtnAdvanced = findViewById(R.id.btn_advanced);
|
||||||
|
|
||||||
mBtnAdvanced.setOnClickListener(v -> openCustomServerDialog());
|
mBtnAdvanced.setOnClickListener(v -> openCustomServerDialog());
|
||||||
|
mBtnAdvanced.setEnabled(true);
|
||||||
|
|
||||||
mBtnListeners = new View.OnClickListener[BTN_COUNT];
|
mBtnListeners = new View.OnClickListener[BTN_COUNT];
|
||||||
mBtnNames = new String[BTN_COUNT];
|
mBtnNames = new String[BTN_COUNT];
|
||||||
@@ -300,7 +309,7 @@ public class DownloadResourcesLegacyActivity extends BaseMwmFragmentActivity
|
|||||||
mBtnDownload.setText(mBtnNames[action]);
|
mBtnDownload.setText(mBtnNames[action]);
|
||||||
|
|
||||||
// Allow changing server only when idle or after an error.
|
// Allow changing server only when idle or after an error.
|
||||||
boolean advancedEnabled = (action == DOWNLOAD || action == TRY_AGAIN);
|
boolean advancedEnabled = (action == DOWNLOAD || action == TRY_AGAIN || action == RESUME);
|
||||||
mBtnAdvanced.setEnabled(advancedEnabled);
|
mBtnAdvanced.setEnabled(advancedEnabled);
|
||||||
mBtnAdvanced.setAlpha(advancedEnabled ? 1f : 0.5f);
|
mBtnAdvanced.setAlpha(advancedEnabled ? 1f : 0.5f);
|
||||||
}
|
}
|
||||||
@@ -371,6 +380,9 @@ public class DownloadResourcesLegacyActivity extends BaseMwmFragmentActivity
|
|||||||
|
|
||||||
private void finishFilesDownload(int result)
|
private void finishFilesDownload(int result)
|
||||||
{
|
{
|
||||||
|
mBtnAdvanced.setEnabled(true);
|
||||||
|
mBtnAdvanced.setAlpha(1f);
|
||||||
|
|
||||||
if (result == ERR_NO_MORE_FILES)
|
if (result == ERR_NO_MORE_FILES)
|
||||||
{
|
{
|
||||||
// World and WorldCoasts has been downloaded, we should register maps again to correctly add them to the model.
|
// World and WorldCoasts has been downloaded, we should register maps again to correctly add them to the model.
|
||||||
@@ -405,34 +417,51 @@ public class DownloadResourcesLegacyActivity extends BaseMwmFragmentActivity
|
|||||||
private void openCustomServerDialog()
|
private void openCustomServerDialog()
|
||||||
{
|
{
|
||||||
View dialogView = getLayoutInflater().inflate(R.layout.dialog_custom_map_server, null);
|
View dialogView = getLayoutInflater().inflate(R.layout.dialog_custom_map_server, null);
|
||||||
|
TextInputLayout til = dialogView.findViewById(R.id.til_custom_map_server);
|
||||||
TextInputEditText edit = dialogView.findViewById(R.id.edit_custom_map_server);
|
TextInputEditText edit = dialogView.findViewById(R.id.edit_custom_map_server);
|
||||||
|
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
String current = prefs.getString(getString(R.string.pref_custom_map_download_url), "");
|
String current = prefs.getString(getString(R.string.pref_custom_map_download_url), "");
|
||||||
edit.setText(current);
|
edit.setText(current);
|
||||||
|
|
||||||
new MaterialAlertDialogBuilder(this, R.style.MwmTheme_AlertDialog)
|
MaterialAlertDialogBuilder builder =
|
||||||
|
new MaterialAlertDialogBuilder(this, R.style.MwmTheme_AlertDialog)
|
||||||
.setTitle(R.string.download_resources_custom_url_title)
|
.setTitle(R.string.download_resources_custom_url_title)
|
||||||
.setMessage(R.string.download_resources_custom_url_message)
|
.setMessage(R.string.download_resources_custom_url_message)
|
||||||
.setView(dialogView)
|
.setView(dialogView)
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
.setPositiveButton(R.string.save, (dialog, which) -> {
|
.setPositiveButton(R.string.save, null);
|
||||||
String url = "";
|
|
||||||
if (edit.getText() != null)
|
|
||||||
url = edit.getText().toString().trim();
|
|
||||||
|
|
||||||
// Persist for future runs + Settings screen
|
AlertDialog dialog = builder.create();
|
||||||
prefs.edit()
|
dialog.setOnShowListener(d -> {
|
||||||
.putString(getString(R.string.pref_custom_map_download_url), url)
|
Button ok = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
|
||||||
.apply();
|
ok.setOnClickListener(v -> {
|
||||||
|
String url = edit.getText() != null ? edit.getText().toString().trim() : "";
|
||||||
|
|
||||||
// Apply to native + reset meta configs
|
if (!url.isEmpty()
|
||||||
Framework.applyCustomMapDownloadUrl(this, url);
|
&& !url.startsWith("http://")
|
||||||
|
&& !url.startsWith("https://")) {
|
||||||
|
til.setError(getString(R.string.download_resources_custom_url_error_scheme));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Recompute total bytes (it can change with another server)
|
til.setError(null);
|
||||||
prepareFilesDownload(false);
|
|
||||||
})
|
prefs.edit()
|
||||||
.show();
|
.putString(getString(R.string.pref_custom_map_download_url), url)
|
||||||
|
.apply();
|
||||||
|
|
||||||
|
// Apply to native + reset meta configs
|
||||||
|
Framework.applyCustomMapDownloadUrl(this, url);
|
||||||
|
|
||||||
|
// Recompute total bytes (it can change with another server)
|
||||||
|
prepareFilesDownload(false);
|
||||||
|
|
||||||
|
dialog.dismiss();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
dialog.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showErrorDialog(int result)
|
private void showErrorDialog(int result)
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import android.annotation.SuppressLint;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.preference.EditTextPreference;
|
import androidx.preference.EditTextPreference;
|
||||||
@@ -13,6 +15,9 @@ import androidx.preference.ListPreference;
|
|||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
import androidx.preference.PreferenceCategory;
|
import androidx.preference.PreferenceCategory;
|
||||||
import androidx.preference.TwoStatePreference;
|
import androidx.preference.TwoStatePreference;
|
||||||
|
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
|
|
||||||
import app.organicmaps.MwmApplication;
|
import app.organicmaps.MwmApplication;
|
||||||
import app.organicmaps.R;
|
import app.organicmaps.R;
|
||||||
import app.organicmaps.downloader.OnmapDownloader;
|
import app.organicmaps.downloader.OnmapDownloader;
|
||||||
@@ -36,7 +41,7 @@ import app.organicmaps.sdk.util.SharedPropertiesUtils;
|
|||||||
import app.organicmaps.sdk.util.log.LogsManager;
|
import app.organicmaps.sdk.util.log.LogsManager;
|
||||||
import app.organicmaps.util.ThemeSwitcher;
|
import app.organicmaps.util.ThemeSwitcher;
|
||||||
import app.organicmaps.util.Utils;
|
import app.organicmaps.util.Utils;
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -542,6 +547,16 @@ public class SettingsPrefsFragment extends BaseXmlSettingsFragment implements La
|
|||||||
EditTextPreference customUrlPref = getPreference(getString(R.string.pref_custom_map_download_url));
|
EditTextPreference customUrlPref = getPreference(getString(R.string.pref_custom_map_download_url));
|
||||||
customUrlPref.setOnPreferenceChangeListener((preference, newValue) -> {
|
customUrlPref.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||||
String url = newValue != null ? ((String) newValue).trim() : "";
|
String url = newValue != null ? ((String) newValue).trim() : "";
|
||||||
|
|
||||||
|
if (!url.isEmpty()
|
||||||
|
&& !url.startsWith("http://")
|
||||||
|
&& !url.startsWith("https://")) {
|
||||||
|
Toast.makeText(requireContext(),
|
||||||
|
R.string.download_resources_custom_url_error_scheme,
|
||||||
|
Toast.LENGTH_SHORT).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Framework.applyCustomMapDownloadUrl(requireContext(), url);
|
Framework.applyCustomMapDownloadUrl(requireContext(), url);
|
||||||
return true; // save the value
|
return true; // save the value
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/til_custom_map_server"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="@string/download_resources_custom_url_title"
|
android:hint="@string/download_resources_custom_url_title"
|
||||||
|
|||||||
@@ -974,4 +974,5 @@
|
|||||||
<string name="download_resources_custom_url_title">Custom Map Server</string>
|
<string name="download_resources_custom_url_title">Custom Map Server</string>
|
||||||
<string name="download_resources_custom_url_message">Override the default map download server used for map downloads. Leave empty to use CoMaps default server.</string>
|
<string name="download_resources_custom_url_message">Override the default map download server used for map downloads. Leave empty to use CoMaps default server.</string>
|
||||||
<string name="download_resources_custom_url_hint">https://maps.comaps.app/</string>
|
<string name="download_resources_custom_url_hint">https://maps.comaps.app/</string>
|
||||||
|
<string name="download_resources_custom_url_error_scheme">Please enter a full URL starting with http:// or https:// and ending with /.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -2,10 +2,12 @@ package app.organicmaps.sdk;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
|
||||||
import androidx.annotation.Keep;
|
import androidx.annotation.Keep;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.Size;
|
import androidx.annotation.Size;
|
||||||
|
|
||||||
import app.organicmaps.sdk.api.ParsedRoutingData;
|
import app.organicmaps.sdk.api.ParsedRoutingData;
|
||||||
import app.organicmaps.sdk.api.ParsedSearchRequest;
|
import app.organicmaps.sdk.api.ParsedSearchRequest;
|
||||||
import app.organicmaps.sdk.api.RequestType;
|
import app.organicmaps.sdk.api.RequestType;
|
||||||
@@ -24,6 +26,7 @@ import app.organicmaps.sdk.routing.RoutingRecommendationListener;
|
|||||||
import app.organicmaps.sdk.routing.TransitRouteInfo;
|
import app.organicmaps.sdk.routing.TransitRouteInfo;
|
||||||
import app.organicmaps.sdk.settings.SpeedCameraMode;
|
import app.organicmaps.sdk.settings.SpeedCameraMode;
|
||||||
import app.organicmaps.sdk.util.Constants;
|
import app.organicmaps.sdk.util.Constants;
|
||||||
|
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@@ -353,8 +356,13 @@ public class Framework
|
|||||||
|
|
||||||
public static void applyCustomMapDownloadUrl(@NonNull Context context, @Nullable String url)
|
public static void applyCustomMapDownloadUrl(@NonNull Context context, @Nullable String url)
|
||||||
{
|
{
|
||||||
String trimmed = url != null ? url.trim() : "";
|
String normalizedUrl = url != null ? url.trim() : "";
|
||||||
nativeSetCustomMapDownloadUrl(trimmed);
|
|
||||||
|
// Normalize
|
||||||
|
if (!normalizedUrl.isEmpty() && !normalizedUrl.endsWith("/"))
|
||||||
|
normalizedUrl = normalizedUrl + "/";
|
||||||
|
|
||||||
|
nativeSetCustomMapDownloadUrl(normalizedUrl);
|
||||||
// Reset the legacy downloader too (world/coasts).
|
// Reset the legacy downloader too (world/coasts).
|
||||||
app.organicmaps.sdk.DownloadResourcesLegacyActivity.nativeResetMetaConfig();
|
app.organicmaps.sdk.DownloadResourcesLegacyActivity.nativeResetMetaConfig();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user