Files
comaps/android/app/src/main/java/app/organicmaps/DownloadResourcesLegacyActivity.java
Andrei Shkrob 428ff30af7 [android] Proper usage of dark theme
Signed-off-by: Andrei Shkrob <github@shkrob.dev>
2025-10-11 14:07:21 +02:00

441 lines
14 KiB
Java

package app.organicmaps;
import static app.organicmaps.sdk.DownloadResourcesLegacyActivity.ERR_DISK_ERROR;
import static app.organicmaps.sdk.DownloadResourcesLegacyActivity.ERR_DOWNLOAD_ERROR;
import static app.organicmaps.sdk.DownloadResourcesLegacyActivity.ERR_DOWNLOAD_SUCCESS;
import static app.organicmaps.sdk.DownloadResourcesLegacyActivity.ERR_NOT_ENOUGH_FREE_SPACE;
import static app.organicmaps.sdk.DownloadResourcesLegacyActivity.ERR_NO_MORE_FILES;
import static app.organicmaps.sdk.DownloadResourcesLegacyActivity.ERR_STORAGE_DISCONNECTED;
import static app.organicmaps.sdk.DownloadResourcesLegacyActivity.nativeCancelCurrentFile;
import static app.organicmaps.sdk.DownloadResourcesLegacyActivity.nativeGetBytesToDownload;
import static app.organicmaps.sdk.DownloadResourcesLegacyActivity.nativeStartNextFileDownload;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.ComponentName;
import android.content.Intent;
import android.location.Location;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.CallSuper;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
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;
import app.organicmaps.sdk.downloader.MapManager;
import app.organicmaps.sdk.location.LocationListener;
import app.organicmaps.sdk.util.Config;
import app.organicmaps.sdk.util.ConnectionState;
import app.organicmaps.sdk.util.StringUtils;
import app.organicmaps.util.UiUtils;
import app.organicmaps.util.Utils;
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.textview.MaterialTextView;
import java.util.List;
import java.util.Objects;
@SuppressLint("StringFormatMatches")
public class DownloadResourcesLegacyActivity extends BaseMwmFragmentActivity
{
private static final String TAG = DownloadResourcesLegacyActivity.class.getSimpleName();
private MaterialTextView mTvMessage;
private LinearProgressIndicator mProgress;
private MaterialButton mBtnDownload;
private MaterialCheckBox mChbDownloadCountry;
private String mCurrentCountry;
@Nullable
private Dialog mAlertDialog;
@NonNull
private ActivityResultLauncher<Intent> mApiRequest;
private boolean mAreResourcesDownloaded;
private static final int DOWNLOAD = 0;
private static final int PAUSE = 1;
private static final int RESUME = 2;
private static final int TRY_AGAIN = 3;
private static final int PROCEED_TO_MAP = 4;
private static final int BTN_COUNT = 5;
private View.OnClickListener[] mBtnListeners;
private String[] mBtnNames;
private int mCountryDownloadListenerSlot;
private final LocationListener mLocationListener = new LocationListener() {
@Override
public void onLocationUpdated(@NonNull Location location)
{
if (mCurrentCountry != null)
return;
final double lat = location.getLatitude();
final double lon = location.getLongitude();
mCurrentCountry = MapManager.nativeFindCountry(lat, lon);
if (TextUtils.isEmpty(mCurrentCountry))
{
mCurrentCountry = null;
return;
}
CountryItem item = CountryItem.fill(mCurrentCountry);
String fileSizeString = StringUtils.getFileSizeString(getApplicationContext(), item.totalSize);
if (item.status != CountryItem.STATUS_DONE)
{
UiUtils.show(mChbDownloadCountry);
String checkBoxText;
if (item.status == CountryItem.STATUS_UPDATABLE)
checkBoxText = String.format(getString(R.string.update_country_ask), item.name, fileSizeString);
else
checkBoxText = String.format(getString(R.string.download_country_ask), item.name, fileSizeString);
mChbDownloadCountry.setText(checkBoxText);
}
MwmApplication.from(DownloadResourcesLegacyActivity.this).getLocationHelper().removeListener(this);
}
};
private final app.organicmaps.sdk.DownloadResourcesLegacyActivity.Listener mResourcesDownloadListener =
new app.organicmaps.sdk.DownloadResourcesLegacyActivity.Listener() {
@Override
public void onProgress(final int bytesDownloaded)
{
if (!isFinishing())
mProgress.setProgressCompat(bytesDownloaded, true);
}
@Override
public void onFinish(final int errorCode)
{
if (isFinishing())
return;
if (errorCode == ERR_DOWNLOAD_SUCCESS)
{
final int res = nativeStartNextFileDownload(mResourcesDownloadListener);
if (res == ERR_NO_MORE_FILES)
finishFilesDownload(res);
}
else
finishFilesDownload(errorCode);
}
};
private final MapManager.StorageCallback mCountryDownloadListener = new MapManager.StorageCallback() {
@Override
public void onStatusChanged(List<MapManager.StorageCallbackData> data)
{
for (MapManager.StorageCallbackData item : data)
{
if (!item.isLeafNode)
continue;
switch (item.newStatus)
{
case CountryItem.STATUS_DONE:
mAreResourcesDownloaded = true;
showMap();
return;
case CountryItem.STATUS_FAILED:
MapManagerHelper.showError(DownloadResourcesLegacyActivity.this, item, null);
return;
}
}
}
@Override
public void onProgress(String countryId, long localSize, long remoteSize)
{
mProgress.setProgressCompat((int) localSize, true);
}
};
@CallSuper
@Override
protected void onSafeCreate(@Nullable Bundle savedInstanceState)
{
super.onSafeCreate(savedInstanceState);
UiUtils.setLightStatusBar(this, true);
setContentView(R.layout.activity_download_resources);
final View view = getWindow().getDecorView().findViewById(android.R.id.content);
ViewCompat.setOnApplyWindowInsetsListener(view, PaddingInsetsListener.allSides());
initViewsAndListeners();
mApiRequest = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
setResult(result.getResultCode(), result.getData());
finish();
});
if (prepareFilesDownload(false))
{
Utils.keepScreenOn(true, getWindow());
setAction(DOWNLOAD);
return;
}
showMap();
}
@CallSuper
@Override
protected void onSafeDestroy()
{
super.onSafeDestroy();
mApiRequest.unregister();
mApiRequest = null;
Utils.keepScreenOn(Config.isKeepScreenOnEnabled(), getWindow());
if (mCountryDownloadListenerSlot != 0)
{
MapManager.nativeUnsubscribe(mCountryDownloadListenerSlot);
mCountryDownloadListenerSlot = 0;
}
}
@CallSuper
@Override
protected void onResume()
{
super.onResume();
if (!isFinishing())
MwmApplication.from(this).getLocationHelper().addListener(mLocationListener);
}
@Override
protected void onPause()
{
super.onPause();
MwmApplication.from(this).getLocationHelper().removeListener(mLocationListener);
if (mAlertDialog != null && mAlertDialog.isShowing())
mAlertDialog.dismiss();
mAlertDialog = null;
}
private void setDownloadMessage(int bytesToDownload)
{
mTvMessage.setText(getString(R.string.download_resources, StringUtils.getFileSizeString(this, bytesToDownload)));
}
private boolean prepareFilesDownload(boolean showMap)
{
final int bytes = nativeGetBytesToDownload();
if (bytes == 0)
{
mAreResourcesDownloaded = true;
if (showMap)
showMap();
return false;
}
if (bytes > 0)
{
setDownloadMessage(bytes);
mProgress.setMax(bytes);
// Start progress at 1% according to M3 guidelines
mProgress.setProgressCompat(bytes/100, true);
}
else
finishFilesDownload(bytes);
return true;
}
private void initViewsAndListeners()
{
mTvMessage = findViewById(R.id.download_message);
mProgress = findViewById(R.id.progressbar);
mBtnDownload = findViewById(R.id.btn_download_resources);
mChbDownloadCountry = findViewById(R.id.chb_download_country);
mBtnListeners = new View.OnClickListener[BTN_COUNT];
mBtnNames = new String[BTN_COUNT];
mBtnListeners[DOWNLOAD] = v -> onDownloadClicked();
mBtnNames[DOWNLOAD] = getString(R.string.download);
mBtnListeners[PAUSE] = v -> onPauseClicked();
mBtnNames[PAUSE] = getString(R.string.pause);
mBtnListeners[RESUME] = v -> onResumeClicked();
mBtnNames[RESUME] = getString(R.string.continue_button);
mBtnListeners[TRY_AGAIN] = v -> onTryAgainClicked();
mBtnNames[TRY_AGAIN] = getString(R.string.try_again);
mBtnListeners[PROCEED_TO_MAP] = v -> onProceedToMapClicked();
mBtnNames[PROCEED_TO_MAP] = getString(R.string.download_resources_continue);
}
private void setAction(int action)
{
mBtnDownload.setOnClickListener(mBtnListeners[action]);
mBtnDownload.setText(mBtnNames[action]);
}
private void doDownload()
{
if (nativeStartNextFileDownload(mResourcesDownloadListener) == ERR_NO_MORE_FILES)
finishFilesDownload(ERR_NO_MORE_FILES);
}
private void onDownloadClicked()
{
setAction(PAUSE);
doDownload();
}
private void onPauseClicked()
{
setAction(RESUME);
nativeCancelCurrentFile();
}
private void onResumeClicked()
{
setAction(PAUSE);
doDownload();
}
private void onTryAgainClicked()
{
if (prepareFilesDownload(true))
{
setAction(PAUSE);
doDownload();
}
}
private void onProceedToMapClicked()
{
mAreResourcesDownloaded = true;
showMap();
}
public void showMap()
{
if (!mAreResourcesDownloaded)
return;
// Re-use original intent to retain all flags and payload.
// https://github.com/organicmaps/organicmaps/issues/6944
final Intent intent = Objects.requireNonNull(getIntent());
intent.setComponent(new ComponentName(this, MwmActivity.class));
// Disable animation because MwmActivity should appear exactly over this one
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_CLEAR_TOP);
// See {@link SplashActivity.processNavigation()}
if (Factory.isStartedForApiResult(intent))
{
// Wait for the result from MwmActivity for API callers.
mApiRequest.launch(intent);
return;
}
startActivity(intent);
finish();
}
private void finishFilesDownload(int result)
{
if (result == ERR_NO_MORE_FILES)
{
// World and WorldCoasts has been downloaded, we should register maps again to correctly add them to the model.
Framework.nativeReloadWorldMaps();
if (mCurrentCountry != null && mChbDownloadCountry.isChecked())
{
UiUtils.hide(mChbDownloadCountry);
CountryItem item = CountryItem.fill(mCurrentCountry);
String fileSizeString = StringUtils.getFileSizeString(this, item.totalSize);
mTvMessage.setText(getString(R.string.downloading_country_can_proceed, item.name, fileSizeString));
mProgress.setMax((int) item.totalSize);
// Start progress at 1% according to M3 guidelines
mProgress.setProgressCompat((int) (item.totalSize/100), true);
mCountryDownloadListenerSlot = MapManager.nativeSubscribe(mCountryDownloadListener);
MapManagerHelper.startDownload(mCurrentCountry);
setAction(PROCEED_TO_MAP);
}
else
{
mAreResourcesDownloaded = true;
showMap();
}
}
else
{
showErrorDialog(result);
}
}
private void showErrorDialog(int result)
{
if (mAlertDialog != null && mAlertDialog.isShowing())
return;
@StringRes
final int titleId;
@StringRes
final int messageId = switch (result)
{
case ERR_NOT_ENOUGH_FREE_SPACE ->
{
titleId = R.string.routing_not_enough_space;
yield R.string.not_enough_free_space_on_sdcard;
}
case ERR_STORAGE_DISCONNECTED ->
{
titleId = R.string.disconnect_usb_cable_title;
yield R.string.disconnect_usb_cable;
}
case ERR_DOWNLOAD_ERROR ->
{
titleId = R.string.connection_failure;
yield(ConnectionState.INSTANCE.isConnected() ? R.string.download_has_failed
: R.string.common_check_internet_connection_dialog);
}
case ERR_DISK_ERROR ->
{
titleId = R.string.disk_error_title;
yield R.string.disk_error;
}
default -> throw new AssertionError("Unexpected result code = " + result);
};
mAlertDialog = new MaterialAlertDialogBuilder(this, R.style.MwmTheme_AlertDialog)
.setTitle(titleId)
.setMessage(messageId)
.setCancelable(true)
.setOnCancelListener((dialog) -> setAction(PAUSE))
.setPositiveButton(R.string.try_again,
(dialog, which) -> {
setAction(TRY_AGAIN);
onTryAgainClicked();
})
.setOnDismissListener(dialog -> mAlertDialog = null)
.show();
}
}