[android][sdk] Fix MapManager

Signed-off-by: Andrei Shkrob <github@shkrob.dev>
This commit is contained in:
Andrei Shkrob
2025-08-15 17:57:42 +02:00
committed by Konstantin Pastbin
parent 431e305a48
commit d4863643f7
12 changed files with 259 additions and 201 deletions

View File

@@ -27,6 +27,7 @@ import androidx.annotation.StringRes;
import androidx.annotation.StyleRes;
import androidx.core.view.ViewCompat;
import app.organicmaps.base.BaseMwmFragmentActivity;
import app.organicmaps.downloader.MapManagerHelper;
import app.organicmaps.intent.Factory;
import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.downloader.CountryItem;
@@ -155,7 +156,9 @@ public class DownloadResourcesLegacyActivity extends BaseMwmFragmentActivity
showMap();
return;
case CountryItem.STATUS_FAILED: MapManager.showError(DownloadResourcesLegacyActivity.this, item, null); return;
case CountryItem.STATUS_FAILED:
MapManagerHelper.showError(DownloadResourcesLegacyActivity.this, item, null);
return;
}
}
}
@@ -373,7 +376,7 @@ public class DownloadResourcesLegacyActivity extends BaseMwmFragmentActivity
mProgress.setProgressCompat((int) (item.totalSize/100), true);
mCountryDownloadListenerSlot = MapManager.nativeSubscribe(mCountryDownloadListener);
MapManager.startDownload(mCurrentCountry);
MapManagerHelper.startDownload(mCurrentCountry);
setAction(PROCEED_TO_MAP);
}
else

View File

@@ -12,6 +12,7 @@ import androidx.lifecycle.LifecycleOwner;
import app.organicmaps.R;
import app.organicmaps.car.screens.ErrorScreen;
import app.organicmaps.car.screens.base.BaseScreen;
import app.organicmaps.downloader.MapManagerHelper;
import app.organicmaps.sdk.downloader.CountryItem;
import app.organicmaps.sdk.downloader.MapManager;
import app.organicmaps.sdk.util.StringUtils;
@@ -169,7 +170,7 @@ class DownloaderScreen extends BaseScreen
mIsDownloadFailed = true;
final ErrorScreen.Builder builder = new ErrorScreen.Builder(getCarContext())
.setTitle(R.string.country_status_download_failed)
.setErrorMessage(MapManager.getErrorCodeStrRes(data.errorCode))
.setErrorMessage(MapManagerHelper.getErrorCodeStrRes(data.errorCode))
.setPositiveButton(R.string.downloader_retry, null);
if (!mIsCancelActionDisabled)
builder.setNegativeButton(R.string.cancel, this::finish);

View File

@@ -29,7 +29,7 @@ class BottomPanel
@Override
public void onClick(View v)
{
MapManager.warn3gAndDownload(mFragment.requireActivity(), mFragment.getCurrentRoot(), null);
MapManagerHelper.warn3gAndDownload(mFragment.requireActivity(), mFragment.getCurrentRoot(), null);
}
};
@@ -38,7 +38,10 @@ class BottomPanel
public void onClick(View v)
{
final String country = mFragment.getCurrentRoot();
MapManager.warnOn3gUpdate(mFragment.requireActivity(), country, () -> MapManager.startUpdate(country));
MapManagerHelper.warnOn3gUpdate(mFragment.requireActivity(), country, () -> {
DownloaderService.startForegroundService();
MapManagerHelper.startUpdate(country);
});
}
};
@@ -55,7 +58,7 @@ class BottomPanel
@Override
public void onClick(View v)
{
MapManager.warn3gAndRetry(mFragment.requireActivity(), mFragment.getCurrentRoot(), null);
MapManagerHelper.warn3gAndRetry(mFragment.requireActivity(), mFragment.getCurrentRoot(), null);
}
};

View File

@@ -198,7 +198,8 @@ public class CountrySuggestFragment extends BaseMwmFragment implements View.OnCl
final int id = v.getId();
if (id == R.id.btn__download_map)
{
MapManager.warn3gAndDownload(requireActivity(), mCurrentCountry.id, () -> mDownloadingCountry = mCurrentCountry);
MapManagerHelper.warn3gAndDownload(requireActivity(), mCurrentCountry.id,
() -> mDownloadingCountry = mCurrentCountry);
}
else if (id == R.id.btn__select_map)
{

View File

@@ -93,7 +93,7 @@ class DownloaderAdapter extends RecyclerView.Adapter<DownloaderAdapter.ViewHolde
private void onDownloadActionSelected(final CountryItem item, DownloaderAdapter adapter)
{
MapManager.warn3gAndDownload(adapter.mActivity, item.id, null);
MapManagerHelper.warn3gAndDownload(adapter.mActivity, item.id, null);
}
private void onUpdateActionSelected(final CountryItem item, DownloaderAdapter adapter)
@@ -101,7 +101,7 @@ class DownloaderAdapter extends RecyclerView.Adapter<DownloaderAdapter.ViewHolde
item.update();
if (item.status != CountryItem.STATUS_UPDATABLE)
return;
MapManager.warnOn3gUpdate(adapter.mActivity, item.id, () -> MapManager.startUpdate(item.id));
MapManagerHelper.warnOn3gUpdate(adapter.mActivity, item.id, () -> MapManagerHelper.startUpdate(item.id));
}
private void onExploreActionSelected(CountryItem item, DownloaderAdapter adapter)
@@ -206,7 +206,7 @@ class DownloaderAdapter extends RecyclerView.Adapter<DownloaderAdapter.ViewHolde
{
if (item.isLeafNode && item.newStatus == CountryItem.STATUS_FAILED)
{
MapManager.showError(mActivity, item, null);
MapManagerHelper.showError(mActivity, item, null);
break;
}
}
@@ -382,9 +382,12 @@ class DownloaderAdapter extends RecyclerView.Adapter<DownloaderAdapter.ViewHolde
else
processLongClick();
}
case CountryItem.STATUS_FAILED -> MapManager.warn3gAndRetry(mActivity, mItem.id, null);
case CountryItem.STATUS_FAILED ->
{
MapManagerHelper.warn3gAndRetry(mActivity, mItem.id, null);
}
case CountryItem.STATUS_UPDATABLE ->
MapManager.warnOn3gUpdate(mActivity, mItem.id, () -> MapManager.startUpdate(mItem.id));
MapManagerHelper.warnOn3gUpdate(mActivity, mItem.id, () -> MapManagerHelper.startUpdate(mItem.id));
default -> throw new IllegalArgumentException("Inappropriate item status: " + mItem.status);
}
}

View File

@@ -0,0 +1,223 @@
package app.organicmaps.downloader;
import android.app.Activity;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.appcompat.app.AlertDialog;
import androidx.core.util.Consumer;
import app.organicmaps.R;
import app.organicmaps.sdk.downloader.CountryItem;
import app.organicmaps.sdk.downloader.ExpandRetryConfirmationListener;
import app.organicmaps.sdk.downloader.MapManager;
import app.organicmaps.sdk.util.ConnectionState;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.lang.ref.WeakReference;
public class MapManagerHelper
{
private static WeakReference<AlertDialog> sCurrentErrorDialog;
@StringRes
public static int getErrorCodeStrRes(final int errorCode)
{
return switch (errorCode)
{
case CountryItem.ERROR_NO_INTERNET -> R.string.common_check_internet_connection_dialog;
case CountryItem.ERROR_OOM -> R.string.downloader_no_space_title;
default -> throw new IllegalArgumentException("Given error can not be displayed: " + errorCode);
};
}
public static void showError(final Activity activity, final MapManager.StorageCallbackData errorData,
@Nullable final Consumer<Boolean> dialogClickListener)
{
if (!MapManager.nativeIsAutoretryFailed())
return;
showErrorDialog(activity, errorData, dialogClickListener);
}
public static void showErrorDialog(final Activity activity, final MapManager.StorageCallbackData errorData,
@Nullable final Consumer<Boolean> dialogClickListener)
{
if (sCurrentErrorDialog != null)
{
AlertDialog dlg = sCurrentErrorDialog.get();
if (dlg != null && dlg.isShowing())
return;
}
final AlertDialog dlg = new MaterialAlertDialogBuilder(activity, R.style.MwmTheme_AlertDialog)
.setTitle(R.string.country_status_download_failed)
.setMessage(getErrorCodeStrRes(errorData.errorCode))
.setNegativeButton(R.string.cancel,
(dialog, which) -> {
sCurrentErrorDialog = null;
if (dialogClickListener != null)
dialogClickListener.accept(false);
})
.setPositiveButton(R.string.downloader_retry,
(dialog, which) -> {
ExpandRetryConfirmationListener listener =
new ExpandRetryConfirmationListener(dialogClickListener);
warn3gAndRetry(activity, errorData.countryId, listener);
})
.create();
dlg.setCanceledOnTouchOutside(false);
dlg.show();
sCurrentErrorDialog = new WeakReference<>(dlg);
}
private static void notifyNoSpaceInternal(Activity activity)
{
new MaterialAlertDialogBuilder(activity, R.style.MwmTheme_AlertDialog)
.setTitle(R.string.downloader_no_space_title)
.setMessage(R.string.downloader_no_space_message)
.setPositiveButton(android.R.string.ok, null)
.show();
}
/**
* @return true if there is no space to update the given {@code root}, so the alert dialog will be shown.
*/
private static boolean notifyNoSpaceToUpdate(Activity activity, String root)
{
if (MapManager.nativeHasSpaceToUpdate(root))
return false;
notifyNoSpaceInternal(activity);
return true;
}
/**
* @return true if there is no space to download the given {@code root}, so the alert dialog will be shown.
*/
private static boolean notifyNoSpace(Activity activity, String root)
{
if (MapManager.nativeHasSpaceToDownloadCountry(root))
return false;
notifyNoSpaceInternal(activity);
return true;
}
/**
* @return true if there is no space to download {@code size} bytes, so the alert dialog will be shown.
*/
private static boolean notifyNoSpace(Activity activity, long size)
{
if (MapManager.nativeHasSpaceToDownloadAmount(size))
return false;
notifyNoSpaceInternal(activity);
return true;
}
private static boolean warnOn3gInternal(Activity activity, @NonNull final Runnable onAcceptListener)
{
if (MapManager.nativeIsDownloadOn3gEnabled() || !ConnectionState.INSTANCE.isMobileConnected())
{
onAcceptListener.run();
return false;
}
new MaterialAlertDialogBuilder(activity, R.style.MwmTheme_AlertDialog)
.setTitle(R.string.download_over_mobile_header)
.setMessage(R.string.download_over_mobile_message)
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.ok,
(dlg, which) -> {
MapManager.nativeEnableDownloadOn3g();
onAcceptListener.run();
})
.show();
return true;
}
public static boolean warnOn3gUpdate(Activity activity, @Nullable String countryId,
@NonNull final Runnable onAcceptListener)
{
// noinspection SimplifiableIfStatement
if (TextUtils.isEmpty(countryId) || !notifyNoSpaceToUpdate(activity, countryId))
return warnOn3gInternal(activity, onAcceptListener);
return true;
}
public static boolean warnOn3g(Activity activity, @Nullable String countryId,
@NonNull final Runnable onAcceptListener)
{
// noinspection SimplifiableIfStatement
if (TextUtils.isEmpty(countryId) || !notifyNoSpace(activity, countryId))
return warnOn3gInternal(activity, onAcceptListener);
return true;
}
public static boolean warnOn3g(Activity activity, long size, @NonNull Runnable onAcceptListener)
{
return !notifyNoSpace(activity, size) && warnOn3gInternal(activity, onAcceptListener);
}
public static boolean warn3gAndDownload(Activity activity, final String countryId,
@Nullable final Runnable onAcceptListener)
{
return warnOn3g(activity, countryId, () -> {
if (onAcceptListener != null)
onAcceptListener.run();
startDownload(countryId);
});
}
public static boolean warn3gAndRetry(Activity activity, final String countryId,
@Nullable final Runnable onAcceptListener)
{
return warnOn3g(activity, countryId, () -> {
if (onAcceptListener != null)
onAcceptListener.run();
retryDownload(countryId);
});
}
/**
* Enqueues failed items under given {@code root} node in downloader.
*/
public static void retryDownload(@NonNull String countryId)
{
DownloaderService.startForegroundService();
MapManager.retryDownload(countryId);
}
/**
* Enqueues given {@code root} node with its children in downloader.
*/
public static void startUpdate(@NonNull String root)
{
DownloaderService.startForegroundService();
MapManager.startUpdate(root);
}
/**
* Enqueues the given list of nodes and its children in downloader.
*/
public static void startDownload(String... countries)
{
DownloaderService.startForegroundService();
for (var countryId : countries)
{
MapManager.startDownload(countryId);
}
}
/**
* Enqueues given {@code root} node and its children in downloader.
*/
public static void startDownload(@NonNull String countryId)
{
DownloaderService.startForegroundService();
MapManager.startDownload(countryId);
}
}

View File

@@ -52,7 +52,7 @@ public class OnmapDownloader implements MwmActivity.LeftAnimationTrackListener
continue;
if (item.newStatus == CountryItem.STATUS_FAILED)
MapManager.showError(mActivity, item, null);
MapManagerHelper.showError(mActivity, item, null);
if (mCurrentCountry.id.equals(item.countryId))
{
@@ -163,7 +163,7 @@ public class OnmapDownloader implements MwmActivity.LeftAnimationTrackListener
if (TextUtils.equals(mCurrentCountry.id, country)
&& MapManager.nativeHasSpaceToDownloadCountry(country))
{
MapManager.startDownload(mCurrentCountry.id);
MapManagerHelper.startDownload(mCurrentCountry.id);
}
}
}
@@ -199,18 +199,18 @@ public class OnmapDownloader implements MwmActivity.LeftAnimationTrackListener
setAutodownloadLocked(true);
});
mButton.setOnClickListener(
v -> MapManager.warnOn3g(mActivity, mCurrentCountry == null ? null : mCurrentCountry.id, () -> {
v -> MapManagerHelper.warnOn3g(mActivity, mCurrentCountry == null ? null : mCurrentCountry.id, () -> {
if (mCurrentCountry == null)
return;
boolean retry = (mCurrentCountry.status == CountryItem.STATUS_FAILED);
if (retry)
{
MapManager.retryDownload(mCurrentCountry.id);
MapManagerHelper.retryDownload(mCurrentCountry.id);
}
else
{
MapManager.startDownload(mCurrentCountry.id);
MapManagerHelper.startDownload(mCurrentCountry.id);
mActivity.requestPostNotificationsPermission();
}
}));

View File

@@ -14,6 +14,7 @@ import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentFactory;
import androidx.fragment.app.FragmentManager;
import app.organicmaps.R;
import app.organicmaps.downloader.MapManagerHelper;
import app.organicmaps.sdk.downloader.CountryItem;
import app.organicmaps.sdk.downloader.MapManager;
import app.organicmaps.util.UiUtils;
@@ -108,7 +109,7 @@ public class RoutingErrorDialogFragment extends BaseRoutingErrorDialogFragment
}
}
MapManager.warnOn3g(requireActivity(), size, () -> {
MapManagerHelper.warnOn3g(requireActivity(), size, () -> {
final FragmentManager manager = requireActivity().getSupportFragmentManager();
RoutingMapsDownloadFragment downloader =
RoutingMapsDownloadFragment.create(manager.getFragmentFactory(), getAppContextOrThrow(), mMapsArray);

View File

@@ -9,6 +9,7 @@ import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentFactory;
import app.organicmaps.R;
import app.organicmaps.downloader.MapManagerHelper;
import app.organicmaps.sdk.downloader.CountryItem;
import app.organicmaps.sdk.downloader.MapManager;
import app.organicmaps.sdk.routing.RoutingController;
@@ -40,7 +41,7 @@ public class RoutingMapsDownloadFragment extends BaseRoutingErrorDialogFragment
mMapsArray[i] = item.id;
}
MapManager.startDownload(mMapsArray);
MapManagerHelper.startDownload(mMapsArray);
}
private View setupFrame(View frame)

View File

@@ -37,6 +37,7 @@ import app.organicmaps.R;
import app.organicmaps.bookmarks.BookmarksSharingHelper;
import app.organicmaps.bookmarks.ChooseBookmarkCategoryFragment;
import app.organicmaps.downloader.DownloaderStatusIcon;
import app.organicmaps.downloader.MapManagerHelper;
import app.organicmaps.editor.OhState;
import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.bookmarks.data.Bookmark;
@@ -974,7 +975,7 @@ public class PlacePageView extends Fragment
mStorageCallbackSlot = MapManager.nativeSubscribe(mStorageCallback);
mDownloaderIcon
.setOnIconClickListener((v) -> MapManager.warn3gAndDownload(requireActivity(), mCurrentCountry.id, null))
.setOnIconClickListener((v) -> MapManagerHelper.warn3gAndDownload(requireActivity(), mCurrentCountry.id, null))
.setOnCancelClickListener((v) -> MapManager.nativeCancel(mCurrentCountry.id));
mDownloaderIcon.show(true);
UiUtils.show(mDownloaderInfo);

View File

@@ -3,12 +3,12 @@ package app.organicmaps.sdk.downloader;
import androidx.annotation.Nullable;
import androidx.core.util.Consumer;
class ExpandRetryConfirmationListener implements Runnable
public class ExpandRetryConfirmationListener implements Runnable
{
@Nullable
private final Consumer<Boolean> mDialogClickListener;
ExpandRetryConfirmationListener(@Nullable Consumer<Boolean> dialogClickListener)
public ExpandRetryConfirmationListener(@Nullable Consumer<Boolean> dialogClickListener)
{
mDialogClickListener = dialogClickListener;
}

View File

@@ -1,19 +1,9 @@
package app.organicmaps.sdk.downloader;
import android.app.Activity;
import android.text.TextUtils;
import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.annotation.UiThread;
import androidx.appcompat.app.AlertDialog;
import androidx.core.util.Consumer;
import app.organicmaps.R;
import app.organicmaps.downloader.DownloaderService;
import app.organicmaps.sdk.util.ConnectionState;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.lang.ref.WeakReference;
import java.util.List;
@UiThread
@@ -56,179 +46,13 @@ public final class MapManager
void onCurrentCountryChanged(String countryId);
}
private static WeakReference<AlertDialog> sCurrentErrorDialog;
private MapManager() {}
@StringRes
public static int getErrorCodeStrRes(final int errorCode)
{
return switch (errorCode)
{
case CountryItem.ERROR_NO_INTERNET -> R.string.common_check_internet_connection_dialog;
case CountryItem.ERROR_OOM -> R.string.downloader_no_space_title;
default -> throw new IllegalArgumentException("Given error can not be displayed: " + errorCode);
};
}
public static void showError(final Activity activity, final StorageCallbackData errorData,
@Nullable final Consumer<Boolean> dialogClickListener)
{
if (!nativeIsAutoretryFailed())
return;
showErrorDialog(activity, errorData, dialogClickListener);
}
public static void showErrorDialog(final Activity activity, final StorageCallbackData errorData,
@Nullable final Consumer<Boolean> dialogClickListener)
{
if (sCurrentErrorDialog != null)
{
AlertDialog dlg = sCurrentErrorDialog.get();
if (dlg != null && dlg.isShowing())
return;
}
final AlertDialog dlg = new MaterialAlertDialogBuilder(activity, R.style.MwmTheme_AlertDialog)
.setTitle(R.string.country_status_download_failed)
.setMessage(getErrorCodeStrRes(errorData.errorCode))
.setNegativeButton(R.string.cancel,
(dialog, which) -> {
sCurrentErrorDialog = null;
if (dialogClickListener != null)
dialogClickListener.accept(false);
})
.setPositiveButton(R.string.downloader_retry,
(dialog, which) -> {
ExpandRetryConfirmationListener listener =
new ExpandRetryConfirmationListener(dialogClickListener);
warn3gAndRetry(activity, errorData.countryId, listener);
})
.create();
dlg.setCanceledOnTouchOutside(false);
dlg.show();
sCurrentErrorDialog = new WeakReference<>(dlg);
}
private static void notifyNoSpaceInternal(Activity activity)
{
new MaterialAlertDialogBuilder(activity, R.style.MwmTheme_AlertDialog)
.setTitle(R.string.downloader_no_space_title)
.setMessage(R.string.downloader_no_space_message)
.setPositiveButton(android.R.string.ok, null)
.show();
}
/**
* @return true if there is no space to update the given {@code root}, so the alert dialog will be shown.
*/
private static boolean notifyNoSpaceToUpdate(Activity activity, String root)
{
if (nativeHasSpaceToUpdate(root))
return false;
notifyNoSpaceInternal(activity);
return true;
}
/**
* @return true if there is no space to download the given {@code root}, so the alert dialog will be shown.
*/
private static boolean notifyNoSpace(Activity activity, String root)
{
if (nativeHasSpaceToDownloadCountry(root))
return false;
notifyNoSpaceInternal(activity);
return true;
}
/**
* @return true if there is no space to download {@code size} bytes, so the alert dialog will be shown.
*/
private static boolean notifyNoSpace(Activity activity, long size)
{
if (nativeHasSpaceToDownloadAmount(size))
return false;
notifyNoSpaceInternal(activity);
return true;
}
private static boolean warnOn3gInternal(Activity activity, @NonNull final Runnable onAcceptListener)
{
if (nativeIsDownloadOn3gEnabled() || !ConnectionState.INSTANCE.isMobileConnected())
{
onAcceptListener.run();
return false;
}
new MaterialAlertDialogBuilder(activity, R.style.MwmTheme_AlertDialog)
.setTitle(R.string.download_over_mobile_header)
.setMessage(R.string.download_over_mobile_message)
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.ok,
(dlg, which) -> {
nativeEnableDownloadOn3g();
onAcceptListener.run();
})
.show();
return true;
}
public static boolean warnOn3gUpdate(Activity activity, @Nullable String countryId,
@NonNull final Runnable onAcceptListener)
{
// noinspection SimplifiableIfStatement
if (TextUtils.isEmpty(countryId) || !notifyNoSpaceToUpdate(activity, countryId))
return warnOn3gInternal(activity, onAcceptListener);
return true;
}
public static boolean warnOn3g(Activity activity, @Nullable String countryId,
@NonNull final Runnable onAcceptListener)
{
// noinspection SimplifiableIfStatement
if (TextUtils.isEmpty(countryId) || !notifyNoSpace(activity, countryId))
return warnOn3gInternal(activity, onAcceptListener);
return true;
}
public static boolean warnOn3g(Activity activity, long size, @NonNull Runnable onAcceptListener)
{
return !notifyNoSpace(activity, size) && warnOn3gInternal(activity, onAcceptListener);
}
public static boolean warn3gAndDownload(Activity activity, final String countryId,
@Nullable final Runnable onAcceptListener)
{
return warnOn3g(activity, countryId, () -> {
if (onAcceptListener != null)
onAcceptListener.run();
startDownload(countryId);
});
}
public static boolean warn3gAndRetry(Activity activity, final String countryId,
@Nullable final Runnable onAcceptListener)
{
return warnOn3g(activity, countryId, () -> {
if (onAcceptListener != null)
onAcceptListener.run();
retryDownload(countryId);
});
}
/**
* Enqueues failed items under given {@code root} node in downloader.
*/
public static void retryDownload(@NonNull String countryId)
{
DownloaderService.startForegroundService();
nativeRetry(countryId);
}
@@ -237,7 +61,6 @@ public final class MapManager
*/
public static void startUpdate(@NonNull String root)
{
DownloaderService.startForegroundService();
nativeUpdate(root);
}
@@ -246,7 +69,6 @@ public final class MapManager
*/
public static void startDownload(String... countries)
{
DownloaderService.startForegroundService();
for (var countryId : countries)
{
nativeDownload(countryId);
@@ -258,7 +80,6 @@ public final class MapManager
*/
public static void startDownload(@NonNull String countryId)
{
DownloaderService.startForegroundService();
nativeDownload(countryId);
}