diff --git a/OsmAnd-java/src/main/java/net/osmand/map/WorldRegion.java b/OsmAnd-java/src/main/java/net/osmand/map/WorldRegion.java index e3b2aa2a69..d54e4eb92c 100644 --- a/OsmAnd-java/src/main/java/net/osmand/map/WorldRegion.java +++ b/OsmAnd-java/src/main/java/net/osmand/map/WorldRegion.java @@ -5,8 +5,11 @@ import net.osmand.data.QuadRect; import net.osmand.util.Algorithms; import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; +import java.util.Set; public class WorldRegion implements Serializable { @@ -212,4 +215,22 @@ public class WorldRegion implements Serializable { } return false; } + + public static List removeDuplicates(List regions) { + List copy = new ArrayList<>(regions); + Set duplicates = new HashSet<>(); + for (int i = 0; i < copy.size() - 1; i++) { + WorldRegion r1 = copy.get(i); + for (int j = i + 1; j < copy.size(); j++) { + WorldRegion r2 = copy.get(j); + if (r1.containsRegion(r2)) { + duplicates.add(r2); + } else if (r2.containsRegion(r1)) { + duplicates.add(r1); + } + } + } + copy.removeAll(duplicates); + return copy; + } } \ No newline at end of file diff --git a/OsmAnd-java/src/main/java/net/osmand/search/core/SearchResult.java b/OsmAnd-java/src/main/java/net/osmand/search/core/SearchResult.java index 79d11a3fe0..60269fe5d4 100644 --- a/OsmAnd-java/src/main/java/net/osmand/search/core/SearchResult.java +++ b/OsmAnd-java/src/main/java/net/osmand/search/core/SearchResult.java @@ -55,7 +55,9 @@ public class SearchResult { public double getSumPhraseMatchWeight() { // if result is a complete match in the search we prioritize it higher - boolean match = requiredSearchPhrase.countWords(localeName) <= getSelfWordCount(); + int localWordsMatched = alternateName != null ? + requiredSearchPhrase.countWords(alternateName) : requiredSearchPhrase.countWords(localeName) ; + boolean match = localWordsMatched <= getSelfWordCount(); double res = ObjectType.getTypeWeight(match ? objectType : null); if (parentSearchResult != null) { res = res + parentSearchResult.getSumPhraseMatchWeight() / MAX_TYPE_WEIGHT; diff --git a/OsmAnd-java/src/test/java/net/osmand/search/SearchUICoreTest.java b/OsmAnd-java/src/test/java/net/osmand/search/SearchUICoreTest.java index f3ed25ca0b..07e7339401 100644 --- a/OsmAnd-java/src/test/java/net/osmand/search/SearchUICoreTest.java +++ b/OsmAnd-java/src/test/java/net/osmand/search/SearchUICoreTest.java @@ -80,9 +80,9 @@ public class SearchUICoreTest { if (files != null) { for (File file : files) { String fileName = file.getName(); - if(fileName.endsWith(".json")) { + if (fileName.endsWith(".json")) { String name = fileName.substring(0, fileName.length() - ".json".length()); - arrayList.add(new Object[] {name, file}); + arrayList.add(new Object[] { name, file }); } } } @@ -191,10 +191,10 @@ public class SearchUICoreTest { if (!Algorithms.stringsEqual(expected, present)) { System.out.println(String.format("Phrase: %s", phrase)); System.out.println(String.format("Mismatch for '%s' != '%s'. Result: ", expected, present)); + } for (SearchResult r : searchResults) { System.out.println(String.format("\t\"%s\",", formatResult(false, r, phrase))); } - } Assert.assertEquals(expected, present); } } diff --git a/OsmAnd/res/layout/settings_group_title.xml b/OsmAnd/res/layout/settings_group_title.xml index 7d4fb811cd..6c2c220b4e 100644 --- a/OsmAnd/res/layout/settings_group_title.xml +++ b/OsmAnd/res/layout/settings_group_title.xml @@ -31,7 +31,7 @@ tools:text="Some title" /> + + + + + + + android:paddingBottom="@dimen/content_padding_small"> - + - - - - - - - - - - - - - - - - - - - + diff --git a/OsmAnd/res/layout/troubleshooting_card.xml b/OsmAnd/res/layout/troubleshooting_card.xml index e7de139dc1..3ce447d5d0 100644 --- a/OsmAnd/res/layout/troubleshooting_card.xml +++ b/OsmAnd/res/layout/troubleshooting_card.xml @@ -32,7 +32,6 @@ android:id="@+id/troubleshooting_icon" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="center_vertical" android:layout_marginEnd="@dimen/map_widget_height" android:layout_marginRight="@dimen/map_widget_height" android:paddingBottom="@dimen/dialog_content_bottom_margin" diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index 9959488bd2..3897ad1806 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -16,6 +16,10 @@ User points Announce when exceeded Exit number + Please select the needed format. You will need to re-download the file to change the format. + OsmAnd provides contour lines data in meters and feet. You will need to re-download the file to change the format. + Contour lines unit format + feet Update all maps added to %1$s? • OsmAnd Live updates moved to \"Downloads > Updates\"\n\n diff --git a/OsmAnd/src/net/osmand/plus/UiUtilities.java b/OsmAnd/src/net/osmand/plus/UiUtilities.java index a7c0223c22..cba86b7f8b 100644 --- a/OsmAnd/src/net/osmand/plus/UiUtilities.java +++ b/OsmAnd/src/net/osmand/plus/UiUtilities.java @@ -442,15 +442,14 @@ public class UiUtilities { } catch (Throwable e) { } } - public static void rotateImageByLayoutDirection(ImageView image, int layoutDirection) { + public static void rotateImageByLayoutDirection(ImageView image) { if (image == null) { return; } - int rotation = layoutDirection == ViewCompat.LAYOUT_DIRECTION_RTL ? 180 : 0; + int rotation = AndroidUtils.getLayoutDirection(image.getContext()) == ViewCompat.LAYOUT_DIRECTION_RTL ? 180 : 0; image.setRotationY(rotation); } - public static void updateCustomRadioButtons(Context app, View buttonsView, boolean nightMode, CustomRadioButtonType buttonType) { int activeColor = ContextCompat.getColor(app, nightMode diff --git a/OsmAnd/src/net/osmand/plus/activities/LocalIndexHelper.java b/OsmAnd/src/net/osmand/plus/activities/LocalIndexHelper.java index c1de43084e..51d6125ed7 100644 --- a/OsmAnd/src/net/osmand/plus/activities/LocalIndexHelper.java +++ b/OsmAnd/src/net/osmand/plus/activities/LocalIndexHelper.java @@ -13,6 +13,7 @@ import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.SQLiteTileSource; import net.osmand.plus.Version; +import net.osmand.plus.download.SrtmDownloadItem; import net.osmand.plus.download.ui.AbstractLoadLocalIndexTask; import net.osmand.plus.voice.JSMediaCommandPlayerImpl; import net.osmand.plus.voice.JSTTSCommandPlayerImpl; @@ -143,8 +144,6 @@ public class LocalIndexHelper { return null; } - - public List getLocalIndexInfos(String downloadName) { List list = new ArrayList<>(); LocalIndexInfo info = getLocalIndexInfo(LocalIndexType.MAP_DATA, downloadName, false, false); @@ -313,7 +312,7 @@ public class LocalIndexHelper { } } } - + private void loadTravelData(File mapPath, List result, AbstractLoadLocalIndexTask loadTask) { if (mapPath.canRead()) { for (File mapFile : listFilesSorted(mapPath)) { @@ -333,14 +332,15 @@ public class LocalIndexHelper { if (mapPath.canRead()) { for (File mapFile : listFilesSorted(mapPath)) { if (mapFile.isFile() && mapFile.getName().endsWith(IndexConstants.BINARY_MAP_INDEX_EXT)) { + String fileName = mapFile.getName(); LocalIndexType lt = LocalIndexType.MAP_DATA; - if (mapFile.getName().endsWith(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)) { + if (SrtmDownloadItem.isSrtmFile(fileName)) { lt = LocalIndexType.SRTM_DATA; - } else if (mapFile.getName().endsWith(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT)) { + } else if (fileName.endsWith(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT)) { lt = LocalIndexType.WIKI_DATA; } LocalIndexInfo info = new LocalIndexInfo(lt, mapFile, backup, app); - if (loadedMaps.containsKey(mapFile.getName()) && !backup) { + if (loadedMaps.containsKey(fileName) && !backup) { info.setLoaded(true); } updateDescription(info); @@ -403,7 +403,7 @@ public class LocalIndexHelper { if (fileName.endsWith(IndexConstants.SQLITE_EXT)) { return fileName.substring(0, fileName.length() - IndexConstants.SQLITE_EXT.length()); } - if (localIndexInfo.getType() == TRAVEL_DATA && + if (localIndexInfo.getType() == TRAVEL_DATA && fileName.endsWith(IndexConstants.BINARY_WIKIVOYAGE_MAP_INDEX_EXT)) { return fileName.substring(0, fileName.length() - IndexConstants.BINARY_WIKIVOYAGE_MAP_INDEX_EXT.length()); } @@ -430,5 +430,4 @@ public class LocalIndexHelper { return fileName; } } - } diff --git a/OsmAnd/src/net/osmand/plus/activities/MapActivityKeyListener.java b/OsmAnd/src/net/osmand/plus/activities/MapActivityKeyListener.java index 33ce52296b..4b99e84350 100644 --- a/OsmAnd/src/net/osmand/plus/activities/MapActivityKeyListener.java +++ b/OsmAnd/src/net/osmand/plus/activities/MapActivityKeyListener.java @@ -94,6 +94,12 @@ public class MapActivityKeyListener implements KeyEvent.Callback { mapActivity.getMapViewTrackingUtilities().backToLocationImpl(); } else if (keyCode == KeyEvent.KEYCODE_D) { mapActivity.getMapViewTrackingUtilities().switchRotateMapMode(); + } else if (keyCode == KeyEvent.KEYCODE_MINUS) { + mapActivity.changeZoom(-1); + return true; + } else if (keyCode == KeyEvent.KEYCODE_PLUS || keyCode == KeyEvent.KEYCODE_EQUALS) { + mapActivity.changeZoom(1); + return true; } else if (mapScrollHelper.isAvailableKeyCode(keyCode)) { return mapScrollHelper.onKeyUp(keyCode, event); } else if (settings.EXTERNAL_INPUT_DEVICE.get() == PARROT_EXTERNAL_DEVICE) { @@ -121,13 +127,7 @@ public class MapActivityKeyListener implements KeyEvent.Callback { return true; } } else if (settings.EXTERNAL_INPUT_DEVICE.get() == GENERIC_EXTERNAL_DEVICE) { - if (keyCode == KeyEvent.KEYCODE_MINUS) { - mapActivity.changeZoom(-1); - return true; - } else if (keyCode == KeyEvent.KEYCODE_PLUS || keyCode == KeyEvent.KEYCODE_EQUALS) { - mapActivity.changeZoom(1); - return true; - } + // currently doesn't process specific commands } else if (OsmandPlugin.onMapActivityKeyUp(mapActivity, keyCode)) { return true; } diff --git a/OsmAnd/src/net/osmand/plus/activities/PluginInfoFragment.java b/OsmAnd/src/net/osmand/plus/activities/PluginInfoFragment.java index ced666e32b..5d32ee228d 100644 --- a/OsmAnd/src/net/osmand/plus/activities/PluginInfoFragment.java +++ b/OsmAnd/src/net/osmand/plus/activities/PluginInfoFragment.java @@ -109,7 +109,7 @@ public class PluginInfoFragment extends BaseOsmAndFragment implements PluginStat } } }); - UiUtilities.rotateImageByLayoutDirection(closeButton, AndroidUtils.getLayoutDirection(app)); + UiUtilities.rotateImageByLayoutDirection(closeButton); Drawable pluginImage = plugin.getAssetResourceImage(); if (pluginImage != null) { diff --git a/OsmAnd/src/net/osmand/plus/activities/PluginsFragment.java b/OsmAnd/src/net/osmand/plus/activities/PluginsFragment.java index 04666e9607..54439daefa 100644 --- a/OsmAnd/src/net/osmand/plus/activities/PluginsFragment.java +++ b/OsmAnd/src/net/osmand/plus/activities/PluginsFragment.java @@ -101,7 +101,7 @@ public class PluginsFragment extends BaseOsmAndFragment implements PluginStateLi } } }); - UiUtilities.rotateImageByLayoutDirection(closeButton, AndroidUtils.getLayoutDirection(app)); + UiUtilities.rotateImageByLayoutDirection(closeButton); adapter = new PluginsListAdapter(requireContext()); diff --git a/OsmAnd/src/net/osmand/plus/base/ModeSelectionBottomSheet.java b/OsmAnd/src/net/osmand/plus/base/ModeSelectionBottomSheet.java new file mode 100644 index 0000000000..f8355c8805 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/base/ModeSelectionBottomSheet.java @@ -0,0 +1,80 @@ +package net.osmand.plus.base; + +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.content.ContextCompat; +import androidx.fragment.app.FragmentManager; + +import net.osmand.AndroidUtils; +import net.osmand.plus.R; +import net.osmand.plus.widgets.MultiStateToggleButton.RadioItem; + +import java.util.Collections; +import java.util.List; + +public class ModeSelectionBottomSheet extends SelectionBottomSheet { + + public static final String TAG = ModeSelectionBottomSheet.class.getSimpleName(); + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + showElements(primaryDescription, toggleContainer); + hideElements(checkBox, checkBoxTitle, titleDescription, + secondaryDescription, selectedSize, selectAllButton); + } + + @Override + protected void updateItemView(SelectableItem item, View view) { + ImageView ivIcon = view.findViewById(R.id.icon); + TextView tvTitle = view.findViewById(R.id.title); + TextView tvDescr = view.findViewById(R.id.description); + + Drawable icon = uiUtilities.getIcon(item.getIconId(), activeColorRes); + ivIcon.setImageDrawable(icon); + tvTitle.setText(item.getTitle()); + tvDescr.setText(item.getDescription()); + tvDescr.setTextColor(ContextCompat.getColor(app, AndroidUtils.getSecondaryTextColorId(nightMode))); + } + + @Override + protected int getItemLayoutId() { + return R.layout.bottom_sheet_item_with_descr_56dp; + } + + public void setItem(SelectableItem item) { + setItems(Collections.singletonList(item)); + } + + @NonNull + @Override + public List getSelectedItems() { + return allItems; + } + + @Override + protected boolean shouldShowDivider() { + return false; + } + + public static ModeSelectionBottomSheet showInstance(@NonNull AppCompatActivity activity, + @NonNull SelectableItem previewItem, + @NonNull List radioItems, + boolean usedOnMap) { + ModeSelectionBottomSheet fragment = new ModeSelectionBottomSheet(); + fragment.setUsedOnMap(usedOnMap); + fragment.setModes(radioItems); + fragment.setItems(Collections.singletonList(previewItem)); + FragmentManager fm = activity.getSupportFragmentManager(); + fragment.show(fm, TAG); + return fragment; + } + +} diff --git a/OsmAnd/src/net/osmand/plus/base/MultipleSelectionBottomSheet.java b/OsmAnd/src/net/osmand/plus/base/MultipleSelectionBottomSheet.java new file mode 100644 index 0000000000..fc7d75416a --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/base/MultipleSelectionBottomSheet.java @@ -0,0 +1,180 @@ +package net.osmand.plus.base; + +import android.content.res.ColorStateList; +import android.os.Bundle; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.CheckBox; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.content.ContextCompat; +import androidx.core.widget.CompoundButtonCompat; +import androidx.fragment.app.FragmentManager; + +import net.osmand.AndroidUtils; +import net.osmand.plus.R; +import net.osmand.plus.helpers.AndroidUiHelper; +import net.osmand.util.Algorithms; + +import java.util.ArrayList; +import java.util.List; + +import static net.osmand.view.ThreeStateCheckbox.State.CHECKED; +import static net.osmand.view.ThreeStateCheckbox.State.MISC; +import static net.osmand.view.ThreeStateCheckbox.State.UNCHECKED; + +public class MultipleSelectionBottomSheet extends SelectionBottomSheet { + + public static final String TAG = MultipleSelectionBottomSheet.class.getSimpleName(); + + private final List selectedItems = new ArrayList<>(); + private SelectionUpdateListener selectionUpdateListener; + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + selectAllButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + checkBox.performClick(); + boolean checked = checkBox.getState() == CHECKED; + if (checked) { + selectedItems.addAll(allItems); + } else { + selectedItems.clear(); + } + onSelectedItemsChanged(); + updateItemsSelection(checked); + } + }); + } + + @Override + protected boolean shouldShowDivider() { + return true; + } + + @Override + protected void updateItemView(final SelectableItem item, View view) { + boolean checked = selectedItems.contains(item); + ImageView imageView = view.findViewById(R.id.icon); + TextView title = view.findViewById(R.id.title); + TextView description = view.findViewById(R.id.description); + final CheckBox checkBox = view.findViewById(R.id.compound_button); + AndroidUiHelper.setVisibility(View.VISIBLE, imageView, title, description, checkBox); + + checkBox.setChecked(checked); + CompoundButtonCompat.setButtonTintList(checkBox, AndroidUtils.createCheckedColorStateList(app, secondaryColorRes, activeColorRes)); + + view.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + boolean checked = !checkBox.isChecked(); + checkBox.setChecked(checked); + if (checked) { + selectedItems.add(item); + } else { + selectedItems.remove(item); + } + onSelectedItemsChanged(); + } + }); + title.setText(item.getTitle()); + description.setText(item.getDescription()); + imageView.setImageDrawable(uiUtilities.getIcon(item.getIconId(), activeColorRes)); + } + + @Override + protected int getItemLayoutId() { + return R.layout.bottom_sheet_item_with_descr_and_checkbox_56dp; + } + + @Override + protected void notifyUiInitialized() { + onSelectedItemsChanged(); + super.notifyUiInitialized(); + } + + private void onSelectedItemsChanged() { + updateSelectAllButton(); + updateSelectedSizeView(); + updateApplyButtonEnable(); + if (selectionUpdateListener != null) { + selectionUpdateListener.onSelectionUpdate(); + } + } + + private void updateSelectAllButton() { + String checkBoxTitle; + if (Algorithms.isEmpty(selectedItems)) { + checkBox.setState(UNCHECKED); + checkBoxTitle = getString(R.string.shared_string_select_all); + } else { + checkBox.setState(selectedItems.containsAll(allItems) ? CHECKED : MISC); + checkBoxTitle = getString(R.string.shared_string_deselect_all); + } + int checkBoxColor = checkBox.getState() == UNCHECKED ? secondaryColorRes : activeColorRes; + CompoundButtonCompat.setButtonTintList(checkBox, ColorStateList.valueOf(ContextCompat.getColor(app, checkBoxColor))); + this.checkBoxTitle.setText(checkBoxTitle); + } + + private void updateSelectedSizeView() { + String selected = String.valueOf(selectedItems.size()); + String all = String.valueOf(allItems.size()); + selectedSize.setText(getString(R.string.ltr_or_rtl_combine_via_slash, selected, all)); + } + + private void updateApplyButtonEnable() { + boolean noEmptySelection = !Algorithms.isEmpty(selectedItems); + rightButton.setEnabled(noEmptySelection); + } + + private void updateItemsSelection(boolean checked) { + for (SelectableItem item : allItems) { + View v = listViews.get(item); + CheckBox checkBox = v != null ? (CheckBox) v.findViewById(R.id.compound_button) : null; + if (checkBox != null) { + checkBox.setChecked(checked); + } + } + } + + protected void setSelectedItems(List selected) { + selectedItems.clear(); + if (!Algorithms.isEmpty(selected)) { + selectedItems.addAll(selected); + } + } + + @NonNull + @Override + public List getSelectedItems() { + return selectedItems; + } + + public void setSelectionUpdateListener(SelectionUpdateListener selectionUpdateListener) { + this.selectionUpdateListener = selectionUpdateListener; + } + + public static MultipleSelectionBottomSheet showInstance(@NonNull AppCompatActivity activity, + @NonNull List items, + @Nullable List selected, + boolean usedOnMap) { + MultipleSelectionBottomSheet fragment = new MultipleSelectionBottomSheet(); + fragment.setUsedOnMap(usedOnMap); + fragment.setItems(items); + fragment.setSelectedItems(selected); + FragmentManager fm = activity.getSupportFragmentManager(); + fragment.show(fm, TAG); + return fragment; + } + + public interface SelectionUpdateListener { + void onSelectionUpdate(); + } + +} \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/base/MultipleSelectionWithModeBottomSheet.java b/OsmAnd/src/net/osmand/plus/base/MultipleSelectionWithModeBottomSheet.java new file mode 100644 index 0000000000..261e8dfdea --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/base/MultipleSelectionWithModeBottomSheet.java @@ -0,0 +1,41 @@ +package net.osmand.plus.base; + +import android.os.Bundle; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.fragment.app.FragmentManager; + +import net.osmand.plus.widgets.MultiStateToggleButton.RadioItem; + +import java.util.List; + +public class MultipleSelectionWithModeBottomSheet extends MultipleSelectionBottomSheet { + + public static final String TAG = MultipleSelectionWithModeBottomSheet.class.getSimpleName(); + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + showElements(secondaryDescription, toggleContainer, checkBox, + checkBoxTitle, titleDescription, selectedSize, selectAllButton); + } + + public static MultipleSelectionWithModeBottomSheet showInstance(@NonNull AppCompatActivity activity, + @NonNull List items, + @Nullable List selected, + @NonNull List modes, + boolean usedOnMap) { + MultipleSelectionWithModeBottomSheet fragment = new MultipleSelectionWithModeBottomSheet(); + fragment.setUsedOnMap(usedOnMap); + fragment.setItems(items); + fragment.setSelectedItems(selected); + fragment.setModes(modes); + FragmentManager fm = activity.getSupportFragmentManager(); + fragment.show(fm, TAG); + return fragment; + } + +} diff --git a/OsmAnd/src/net/osmand/plus/base/SelectMultipleItemsBottomSheet.java b/OsmAnd/src/net/osmand/plus/base/SelectMultipleItemsBottomSheet.java deleted file mode 100644 index 60b507c972..0000000000 --- a/OsmAnd/src/net/osmand/plus/base/SelectMultipleItemsBottomSheet.java +++ /dev/null @@ -1,301 +0,0 @@ -package net.osmand.plus.base; - -import android.content.res.ColorStateList; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.appcompat.app.AppCompatActivity; -import androidx.core.content.ContextCompat; -import androidx.core.widget.CompoundButtonCompat; -import androidx.fragment.app.FragmentManager; - -import net.osmand.AndroidUtils; -import net.osmand.plus.OsmandApplication; -import net.osmand.plus.R; -import net.osmand.plus.UiUtilities; -import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem; -import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithCompoundButton; -import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithCompoundButton.Builder; -import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem; -import net.osmand.plus.base.bottomsheetmenu.simpleitems.SimpleDividerItem; -import net.osmand.util.Algorithms; -import net.osmand.view.ThreeStateCheckbox; - -import java.util.ArrayList; -import java.util.List; - -import static net.osmand.view.ThreeStateCheckbox.State.CHECKED; -import static net.osmand.view.ThreeStateCheckbox.State.MISC; -import static net.osmand.view.ThreeStateCheckbox.State.UNCHECKED; - -public class SelectMultipleItemsBottomSheet extends MenuBottomSheetDialogFragment { - - private OsmandApplication app; - private UiUtilities uiUtilities; - - private TextView title; - private TextView description; - private TextView applyButtonTitle; - private TextView checkBoxTitle; - private TextView selectedSize; - private ThreeStateCheckbox checkBox; - - private int activeColorRes; - private int secondaryColorRes; - - private final List allItems = new ArrayList<>(); - private final List selectedItems = new ArrayList<>(); - private SelectionUpdateListener selectionUpdateListener; - private OnApplySelectionListener onApplySelectionListener; - - public static final String TAG = SelectMultipleItemsBottomSheet.class.getSimpleName(); - - @Nullable - @Override - public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) { - View mainView = super.onCreateView(inflater, parent, savedInstanceState); - onSelectedItemsChanged(); - return mainView; - } - - @Override - public void createMenuItems(Bundle savedInstanceState) { - app = requiredMyApplication(); - uiUtilities = app.getUIUtilities(); - activeColorRes = nightMode ? R.color.icon_color_active_dark : R.color.icon_color_active_light; - secondaryColorRes = nightMode ? R.color.icon_color_secondary_dark : R.color.icon_color_secondary_light; - - items.add(createTitleItem()); - items.add(new SimpleDividerItem(app)); - createListItems(); - } - - private BaseBottomSheetItem createTitleItem() { - LayoutInflater themedInflater = UiUtilities.getInflater(requireContext(), nightMode); - View view = themedInflater.inflate(R.layout.settings_group_title, null); - - checkBox = view.findViewById(R.id.check_box); - checkBoxTitle = view.findViewById(R.id.check_box_title); - description = view.findViewById(R.id.description); - selectedSize = view.findViewById(R.id.selected_size); - title = view.findViewById(R.id.title); - View selectAllButton = view.findViewById(R.id.select_all_button); - selectAllButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - checkBox.performClick(); - boolean checked = checkBox.getState() == CHECKED; - if (checked) { - selectedItems.addAll(allItems); - } else { - selectedItems.clear(); - } - onSelectedItemsChanged(); - updateItems(checked); - } - }); - return new SimpleBottomSheetItem.Builder().setCustomView(view).create(); - } - - private void createListItems() { - for (final SelectableItem item : allItems) { - boolean checked = selectedItems.contains(item); - final BottomSheetItemWithCompoundButton[] uiItem = new BottomSheetItemWithCompoundButton[1]; - final Builder builder = (BottomSheetItemWithCompoundButton.Builder) new Builder(); - builder.setChecked(checked) - .setButtonTintList(AndroidUtils.createCheckedColorStateList(app, secondaryColorRes, activeColorRes)) - .setLayoutId(R.layout.bottom_sheet_item_with_descr_and_checkbox_56dp) - .setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - boolean checked = !uiItem[0].isChecked(); - uiItem[0].setChecked(checked); - SelectableItem tag = (SelectableItem) uiItem[0].getTag(); - if (checked) { - selectedItems.add(tag); - } else { - selectedItems.remove(tag); - } - onSelectedItemsChanged(); - } - }) - .setTag(item); - setupListItem(builder, item); - uiItem[0] = builder.create(); - items.add(uiItem[0]); - } - } - - @Override - protected void setupRightButton() { - super.setupRightButton(); - applyButtonTitle = rightButton.findViewById(R.id.button_text); - } - - @Override - protected void onRightBottomButtonClick() { - if (onApplySelectionListener != null) { - onApplySelectionListener.onSelectionApplied(selectedItems); - } - dismiss(); - } - - private void onSelectedItemsChanged() { - updateSelectAllButton(); - updateSelectedSizeView(); - updateApplyButtonEnable(); - if (selectionUpdateListener != null) { - selectionUpdateListener.onSelectionUpdate(); - } - } - - @Override - protected int getRightBottomButtonTextId() { - return R.string.shared_string_apply; - } - - @Override - protected boolean useVerticalButtons() { - return true; - } - - private void setupListItem(Builder builder, SelectableItem item) { - builder.setTitle(item.title); - builder.setDescription(item.description); - builder.setIcon(uiUtilities.getIcon(item.iconId, activeColorRes)); - } - - private void updateSelectAllButton() { - String checkBoxTitle; - if (Algorithms.isEmpty(selectedItems)) { - checkBox.setState(UNCHECKED); - checkBoxTitle = getString(R.string.shared_string_select_all); - } else { - checkBox.setState(selectedItems.containsAll(allItems) ? CHECKED : MISC); - checkBoxTitle = getString(R.string.shared_string_deselect_all); - } - int checkBoxColor = checkBox.getState() == UNCHECKED ? secondaryColorRes : activeColorRes; - CompoundButtonCompat.setButtonTintList(checkBox, ColorStateList.valueOf(ContextCompat.getColor(app, checkBoxColor))); - this.checkBoxTitle.setText(checkBoxTitle); - } - - private void updateSelectedSizeView() { - String selected = String.valueOf(selectedItems.size()); - String all = String.valueOf(allItems.size()); - selectedSize.setText(getString(R.string.ltr_or_rtl_combine_via_slash, selected, all)); - } - - private void updateApplyButtonEnable() { - if (Algorithms.isEmpty(selectedItems)) { - rightButton.setEnabled(false); - } else { - rightButton.setEnabled(true); - } - } - - private void updateItems(boolean checked) { - for (BaseBottomSheetItem item : items) { - if (item instanceof BottomSheetItemWithCompoundButton) { - ((BottomSheetItemWithCompoundButton) item).setChecked(checked); - } - } - } - - public void setTitle(@NonNull String title) { - this.title.setText(title); - } - - public void setDescription(@NonNull String description) { - this.description.setText(description); - } - - public void setConfirmButtonTitle(@NonNull String confirmButtonTitle) { - applyButtonTitle.setText(confirmButtonTitle); - } - - private void setItems(List allItems) { - if (!Algorithms.isEmpty(allItems)) { - this.allItems.addAll(allItems); - } - } - - private void setSelectedItems(List selected) { - if (!Algorithms.isEmpty(selected)) { - this.selectedItems.addAll(selected); - } - } - - public List getSelectedItems() { - return selectedItems; - } - - @Override - public void onPause() { - super.onPause(); - if (requireActivity().isChangingConfigurations()) { - dismiss(); - } - } - - public static SelectMultipleItemsBottomSheet showInstance(@NonNull AppCompatActivity activity, - @NonNull List items, - @Nullable List selected, - boolean usedOnMap) { - SelectMultipleItemsBottomSheet fragment = new SelectMultipleItemsBottomSheet(); - fragment.setUsedOnMap(usedOnMap); - fragment.setItems(items); - fragment.setSelectedItems(selected); - FragmentManager fm = activity.getSupportFragmentManager(); - fragment.show(fm, TAG); - return fragment; - } - - public void setSelectionUpdateListener(SelectionUpdateListener selectionUpdateListener) { - this.selectionUpdateListener = selectionUpdateListener; - } - - public void setOnApplySelectionListener(OnApplySelectionListener onApplySelectionListener) { - this.onApplySelectionListener = onApplySelectionListener; - } - - public interface SelectionUpdateListener { - void onSelectionUpdate(); - } - - public interface OnApplySelectionListener { - void onSelectionApplied(List selectedItems); - } - - public static class SelectableItem { - private String title; - private String description; - private int iconId; - private Object object; - - public void setTitle(String title) { - this.title = title; - } - - public void setDescription(String description) { - this.description = description; - } - - public void setIconId(int iconId) { - this.iconId = iconId; - } - - public void setObject(Object object) { - this.object = object; - } - - public Object getObject() { - return object; - } - } - -} diff --git a/OsmAnd/src/net/osmand/plus/base/SelectionBottomSheet.java b/OsmAnd/src/net/osmand/plus/base/SelectionBottomSheet.java new file mode 100644 index 0000000000..18c91f8cf5 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/base/SelectionBottomSheet.java @@ -0,0 +1,289 @@ +package net.osmand.plus.base; + +import android.content.Context; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import android.widget.LinearLayout.LayoutParams; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.R; +import net.osmand.plus.UiUtilities; +import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem; +import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem; +import net.osmand.plus.base.bottomsheetmenu.simpleitems.SimpleDividerItem; +import net.osmand.plus.helpers.AndroidUiHelper; +import net.osmand.plus.widgets.MultiStateToggleButton; +import net.osmand.plus.widgets.MultiStateToggleButton.RadioItem; +import net.osmand.util.Algorithms; +import net.osmand.view.ThreeStateCheckbox; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public abstract class SelectionBottomSheet extends MenuBottomSheetDialogFragment { + + protected OsmandApplication app; + protected LayoutInflater inflater; + protected UiUtilities uiUtilities; + + protected TextView title; + protected TextView titleDescription; + protected TextView primaryDescription; + protected TextView secondaryDescription; + protected TextView selectedSize; + protected LinearLayout toggleContainer; + protected MultiStateToggleButton radioGroup; + protected View selectAllButton; + protected TextView checkBoxTitle; + protected ThreeStateCheckbox checkBox; + protected LinearLayout listContainer; + protected TextView applyButtonTitle; + + protected int activeColorRes; + protected int secondaryColorRes; + + private OnUiInitializedAdapter onUiInitializedAdapter; + private OnApplySelectionListener onApplySelectionListener; + + protected List allItems = new ArrayList<>(); + protected Map listViews = new HashMap<>(); + private List modes; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) { + View mainView = super.onCreateView(inflater, parent, savedInstanceState); + createSelectionListIfPossible(); + notifyUiInitialized(); + return mainView; + } + + @Override + public void createMenuItems(Bundle savedInstanceState) { + app = requiredMyApplication(); + uiUtilities = app.getUIUtilities(); + inflater = UiUtilities.getInflater(requireContext(), nightMode); + activeColorRes = nightMode ? R.color.icon_color_active_dark : R.color.icon_color_active_light; + secondaryColorRes = nightMode ? R.color.icon_color_secondary_dark : R.color.icon_color_secondary_light; + + items.add(createHeaderView()); + if (shouldShowDivider()) { + items.add(new SimpleDividerItem(app)); + } + items.add(createSelectionView()); + } + + private BaseBottomSheetItem createHeaderView() { + View view = inflater.inflate(R.layout.settings_group_title, null); + + title = view.findViewById(R.id.title); + titleDescription = view.findViewById(R.id.title_description); + primaryDescription = view.findViewById(R.id.primary_description); + secondaryDescription = view.findViewById(R.id.secondary_description); + selectedSize = view.findViewById(R.id.selected_size); + toggleContainer = view.findViewById(R.id.custom_radio_buttons); + radioGroup = new MultiStateToggleButton(app, toggleContainer, nightMode); + selectAllButton = view.findViewById(R.id.select_all_button); + checkBoxTitle = view.findViewById(R.id.check_box_title); + checkBox = view.findViewById(R.id.check_box); + + if (modes != null) { + radioGroup.setItems(modes); + } + + return new SimpleBottomSheetItem.Builder().setCustomView(view).create(); + } + + private BaseBottomSheetItem createSelectionView() { + Context themedCtx = UiUtilities.getThemedContext(requireContext(), nightMode); + listContainer = new LinearLayout(themedCtx); + listContainer.setLayoutParams(new LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT)); + listContainer.setOrientation(LinearLayout.VERTICAL); + return new SimpleBottomSheetItem.Builder().setCustomView(listContainer).create(); + } + + public void setTitle(@NonNull String title) { + this.title.setText(title); + } + + public void setTitleDescription(@NonNull String description) { + titleDescription.setText(description); + } + + public void setPrimaryDescription(@NonNull String description) { + primaryDescription.setText(description); + } + + public void setSecondaryDescription(@NonNull String description) { + secondaryDescription.setText(description); + } + + public void setApplyButtonTitle(@NonNull String title) { + applyButtonTitle.setText(title); + } + + public void setModes(@NonNull List modes) { + this.modes = modes; + if (radioGroup != null) { + radioGroup.setItems(modes); + } + } + + public void setSelectedMode(@NonNull RadioItem mode) { + radioGroup.setSelectedItem(mode); + } + + public void setItems(List allItems) { + this.allItems.clear(); + if (!Algorithms.isEmpty(allItems)) { + this.allItems.addAll(allItems); + createSelectionListIfPossible(); + } + } + + public void setOnUiInitializedAdapter(OnUiInitializedAdapter onUiInitializedAdapter) { + this.onUiInitializedAdapter = onUiInitializedAdapter; + } + + public void setOnApplySelectionListener(OnApplySelectionListener onApplySelectionListener) { + this.onApplySelectionListener = onApplySelectionListener; + } + + private void createSelectionListIfPossible() { + if (listContainer != null && allItems != null) { + recreateList(); + } + } + + private void recreateList() { + listViews.clear(); + listContainer.removeAllViews(); + for (SelectableItem item : allItems) { + setupItemView(item, inflater.inflate(getItemLayoutId(), null)); + } + } + + private void setupItemView(SelectableItem item, View view) { + updateItemView(item, view); + listViews.put(item, view); + listContainer.addView(view); + } + + public List getAllItems() { + return allItems; + } + + @NonNull + public abstract List getSelectedItems(); + + protected abstract void updateItemView(SelectableItem item, View view); + + protected abstract int getItemLayoutId(); + + protected abstract boolean shouldShowDivider(); + + protected void notifyUiInitialized() { + if (onUiInitializedAdapter != null) { + onUiInitializedAdapter.onUiInitialized(); + } + } + + protected void showElements(View... views) { + AndroidUiHelper.setVisibility(View.VISIBLE, views); + } + + protected void hideElements(View... views) { + AndroidUiHelper.setVisibility(View.GONE, views); + } + + @Override + protected void setupRightButton() { + super.setupRightButton(); + applyButtonTitle = rightButton.findViewById(R.id.button_text); + } + + @Override + protected void onRightBottomButtonClick() { + if (onApplySelectionListener != null) { + onApplySelectionListener.onSelectionApplied(getSelectedItems()); + } + dismiss(); + } + + @Override + protected int getRightBottomButtonTextId() { + return R.string.shared_string_apply; + } + + @Override + protected boolean useVerticalButtons() { + return true; + } + + @Override + public void onPause() { + super.onPause(); + if (requireActivity().isChangingConfigurations()) { + dismiss(); + } + } + + public interface OnUiInitializedAdapter { + void onUiInitialized(); + } + + public interface OnApplySelectionListener { + void onSelectionApplied(List selectedItems); + } + + public static class SelectableItem { + private String title; + private String description; + private int iconId; + private Object object; + + public String getTitle() { + return title; + } + + public String getDescription() { + return description; + } + + public int getIconId() { + return iconId; + } + + public Object getObject() { + return object; + } + + public void setTitle(String title) { + this.title = title; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setIconId(int iconId) { + this.iconId = iconId; + } + + public void setObject(Object object) { + this.object = object; + } + } + +} diff --git a/OsmAnd/src/net/osmand/plus/base/bottomsheetmenu/BaseBottomSheetItem.java b/OsmAnd/src/net/osmand/plus/base/bottomsheetmenu/BaseBottomSheetItem.java index 1914756d21..f77fc8503f 100644 --- a/OsmAnd/src/net/osmand/plus/base/bottomsheetmenu/BaseBottomSheetItem.java +++ b/OsmAnd/src/net/osmand/plus/base/bottomsheetmenu/BaseBottomSheetItem.java @@ -32,6 +32,10 @@ public class BaseBottomSheetItem { return tag; } + public void setTag(Object tag) { + this.tag = tag; + } + public BaseBottomSheetItem(View view, @LayoutRes int layoutId, Object tag, diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadActivityType.java b/OsmAnd/src/net/osmand/plus/download/DownloadActivityType.java index 071a856454..c5c4dab186 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadActivityType.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadActivityType.java @@ -10,6 +10,7 @@ import net.osmand.map.OsmandRegions; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.Version; +import net.osmand.plus.activities.LocalIndexInfo; import net.osmand.plus.helpers.FileNameTranslationHelper; import net.osmand.util.Algorithms; @@ -27,11 +28,12 @@ import java.util.Locale; import java.util.Map; import static net.osmand.IndexConstants.BINARY_MAP_INDEX_EXT; +import static net.osmand.plus.activities.LocalIndexHelper.LocalIndexType.SRTM_DATA; public class DownloadActivityType { private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd.MM.yyyy", Locale.US); private static Map byTag = new HashMap<>(); - + public static final DownloadActivityType NORMAL_FILE = new DownloadActivityType(R.string.download_regular_maps, "map", 10); public static final DownloadActivityType VOICE_FILE = @@ -83,7 +85,7 @@ public class DownloadActivityType { iconResource = R.drawable.ic_map; } - public int getStringResource(){ + public int getStringResource() { return stringResource; } @@ -101,7 +103,7 @@ public class DownloadActivityType { public static boolean isCountedInDownloads(IndexItem es) { DownloadActivityType tp = es.getType(); - if(tp == NORMAL_FILE || tp == ROADS_FILE){ + if (tp == NORMAL_FILE || tp == ROADS_FILE) { if (!es.extra) { return true; } @@ -120,17 +122,17 @@ public class DownloadActivityType { public static Collection values() { return byTag.values(); } - + protected static String addVersionToExt(String ext, int version) { return "_" + version + ext; } - + public boolean isAccepted(String fileName) { - if(NORMAL_FILE == this) { - return fileName.endsWith(addVersionToExt(IndexConstants.BINARY_MAP_INDEX_EXT_ZIP, IndexConstants.BINARY_MAP_VERSION)) + if (NORMAL_FILE == this) { + return fileName.endsWith(addVersionToExt(IndexConstants.BINARY_MAP_INDEX_EXT_ZIP, IndexConstants.BINARY_MAP_VERSION)) || fileName.endsWith(IndexConstants.EXTRA_ZIP_EXT) || fileName.endsWith(IndexConstants.SQLITE_EXT); - } else if(ROADS_FILE == this) { + } else if (ROADS_FILE == this) { return fileName.endsWith(addVersionToExt(IndexConstants.BINARY_ROAD_MAP_INDEX_EXT_ZIP, IndexConstants.BINARY_MAP_VERSION)); } else if (VOICE_FILE == this) { return fileName.endsWith(addVersionToExt(IndexConstants.VOICE_INDEX_EXT_ZIP, IndexConstants.VOICE_VERSION)); @@ -145,8 +147,9 @@ public class DownloadActivityType { return fileName.endsWith(addVersionToExt(IndexConstants.BINARY_TRAVEL_GUIDE_MAP_INDEX_EXT_ZIP, IndexConstants.BINARY_MAP_VERSION)); } else if (SRTM_COUNTRY_FILE == this) { - return fileName.endsWith(addVersionToExt(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT_ZIP, - IndexConstants.BINARY_MAP_VERSION)); + boolean srtm = fileName.endsWith(addVersionToExt(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT_ZIP, IndexConstants.BINARY_MAP_VERSION)); + boolean srtmf = fileName.endsWith(addVersionToExt(IndexConstants.BINARY_SRTM_FEET_MAP_INDEX_EXT_ZIP, IndexConstants.BINARY_MAP_VERSION)); + return srtm || srtmf; } else if (HILLSHADE_FILE == this) { return fileName.endsWith(IndexConstants.SQLITE_EXT); } else if (SLOPE_FILE == this) { @@ -160,7 +163,7 @@ public class DownloadActivityType { } return false; } - + public File getDownloadFolder(OsmandApplication ctx, IndexItem indexItem) { if (NORMAL_FILE == this) { if (indexItem.fileName.endsWith(IndexConstants.SQLITE_EXT)) { @@ -196,17 +199,17 @@ public class DownloadActivityType { } public boolean isZipStream(OsmandApplication ctx, IndexItem indexItem) { - return HILLSHADE_FILE != this && SLOPE_FILE != this && SQLITE_FILE != this && WIKIVOYAGE_FILE != this && GPX_FILE != this; + return HILLSHADE_FILE != this && SLOPE_FILE != this && SQLITE_FILE != this && WIKIVOYAGE_FILE != this && GPX_FILE != this; } public boolean isZipFolder(OsmandApplication ctx, IndexItem indexItem) { return this == VOICE_FILE; } - + public boolean preventMediaIndexing(OsmandApplication ctx, IndexItem indexItem) { return this == VOICE_FILE && indexItem.fileName.endsWith(IndexConstants.VOICE_INDEX_EXT_ZIP); } - + public String getUnzipExtension(OsmandApplication ctx, IndexItem indexItem) { if (NORMAL_FILE == this) { if (indexItem.fileName.endsWith(IndexConstants.BINARY_MAP_INDEX_EXT_ZIP)) { @@ -217,7 +220,7 @@ public class DownloadActivityType { return IndexConstants.EXTRA_EXT; } else if (indexItem.fileName.endsWith(IndexConstants.SQLITE_EXT)) { return IndexConstants.SQLITE_EXT; - } else if (indexItem.fileName.endsWith(IndexConstants.ANYVOICE_INDEX_EXT_ZIP)){ + } else if (indexItem.fileName.endsWith(IndexConstants.ANYVOICE_INDEX_EXT_ZIP)) { return ""; } } else if (ROADS_FILE == this) { @@ -227,7 +230,7 @@ public class DownloadActivityType { } else if (FONT_FILE == this) { return IndexConstants.FONT_INDEX_EXT; } else if (SRTM_COUNTRY_FILE == this) { - return IndexConstants.BINARY_SRTM_MAP_INDEX_EXT; + return SrtmDownloadItem.getExtension(indexItem); } else if (WIKIPEDIA_FILE == this) { return IndexConstants.BINARY_WIKI_MAP_INDEX_EXT; } else if (WIKIVOYAGE_FILE == this) { @@ -249,9 +252,9 @@ public class DownloadActivityType { } throw new UnsupportedOperationException(); } - + public String getUrlSuffix(OsmandApplication ctx) { - if (this== ROADS_FILE) { + if (this == ROADS_FILE) { return "&road=yes"; } else if (this == LIVE_UPDATES_FILE) { return "&aosmc=yes"; @@ -280,7 +283,7 @@ public class DownloadActivityType { public String getBaseUrl(OsmandApplication ctx, String fileName) { String url = "https://" + IndexConstants.INDEX_DOWNLOAD_DOMAIN + "/download?event=2&" + Version.getVersionAsURLParam(ctx) + "&file=" + encode(fileName); - if(this == LIVE_UPDATES_FILE && fileName.length() > 16) { + if (this == LIVE_UPDATES_FILE && fileName.length() > 16) { // DATE_AND_EXT_STR_LEN = "_18_06_02.obf.gz".length() String region = fileName.substring(0, fileName.length() - 16).toLowerCase(); url += "®ion=" + encode(region); @@ -343,7 +346,7 @@ public class DownloadActivityType { } return ""; } - + public String getVisibleName(DownloadItem downloadItem, Context ctx, OsmandRegions osmandRegions, boolean includingParent) { if (this == VOICE_FILE) { String fileName = downloadItem.getFileName(); @@ -361,6 +364,9 @@ public class DownloadActivityType { if (basename.endsWith(FileNameTranslationHelper.WIKI_NAME)) { return FileNameTranslationHelper.getWikiName(ctx, basename); } + if (basename.endsWith(FileNameTranslationHelper.WIKIVOYAGE_NAME)) { + return FileNameTranslationHelper.getWikivoyageName(ctx, basename); + } // if (this == HILLSHADE_FILE){ // return FileNameTranslationHelper.getHillShadeName(ctx, osmandRegions, bn); // } @@ -383,7 +389,7 @@ public class DownloadActivityType { return osmandRegions.getLocaleName(basename, includingParent); } - + public String getTargetFileName(IndexItem item) { String fileName = item.fileName; // if(fileName.endsWith(IndexConstants.VOICE_INDEX_EXT_ZIP) || @@ -423,7 +429,7 @@ public class DownloadActivityType { } String baseNameWithoutVersion = fileName.substring(0, l); if (this == SRTM_COUNTRY_FILE) { - return baseNameWithoutVersion + IndexConstants.BINARY_SRTM_MAP_INDEX_EXT; + return baseNameWithoutVersion + SrtmDownloadItem.getExtension(item); } if (this == WIKIPEDIA_FILE) { return baseNameWithoutVersion + IndexConstants.BINARY_WIKI_MAP_INDEX_EXT; @@ -487,7 +493,7 @@ public class DownloadActivityType { return fileName.substring(0, l); } if (this == LIVE_UPDATES_FILE) { - if(fileName.indexOf('.') > 0){ + if (fileName.indexOf('.') > 0) { return fileName.substring(0, fileName.indexOf('.')); } return fileName; @@ -495,10 +501,10 @@ public class DownloadActivityType { int ls = fileName.lastIndexOf('_'); if (ls >= 0) { return fileName.substring(0, ls); - } else if(fileName.indexOf('.') > 0){ + } else if (fileName.indexOf('.') > 0) { return fileName.substring(0, fileName.indexOf('.')); } return fileName; } -} \ No newline at end of file +} diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadIndexesThread.java b/OsmAnd/src/net/osmand/plus/download/DownloadIndexesThread.java index 8b16e48d84..568dcc9ed6 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadIndexesThread.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadIndexesThread.java @@ -240,9 +240,12 @@ public class DownloadIndexesThread { } public void cancelDownload(DownloadItem item) { - if (item instanceof MultipleIndexItem) { - MultipleIndexItem multipleIndexItem = (MultipleIndexItem) item; - cancelDownload(multipleIndexItem.getAllIndexes()); + if (item instanceof MultipleDownloadItem) { + MultipleDownloadItem multipleDownloadItem = (MultipleDownloadItem) item; + cancelDownload(multipleDownloadItem.getAllIndexes()); + } else if (item instanceof SrtmDownloadItem) { + IndexItem indexItem = ((SrtmDownloadItem) item).getIndexItem(); + cancelDownload(indexItem); } else if (item instanceof IndexItem) { IndexItem indexItem = (IndexItem) item; cancelDownload(indexItem); diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadItem.java b/OsmAnd/src/net/osmand/plus/download/DownloadItem.java index 366f3554a7..6b758f8af8 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadItem.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadItem.java @@ -3,12 +3,14 @@ package net.osmand.plus.download; import android.content.Context; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import net.osmand.map.OsmandRegions; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import java.io.File; +import java.text.DateFormat; import java.util.List; import java.util.Locale; @@ -55,6 +57,12 @@ public abstract class DownloadItem { return type.getBasename(this); } + @NonNull + public abstract List getDownloadedFiles(@NonNull OsmandApplication app); + + @Nullable + public abstract String getAdditionalDescription(Context ctx); + protected abstract double getSizeToDownloadInMb(); public abstract double getArchiveSizeMB(); @@ -69,8 +77,7 @@ public abstract class DownloadItem { public abstract String getFileName(); - @NonNull - public abstract List getDownloadedFiles(@NonNull OsmandApplication app); + public abstract String getDate(@NonNull DateFormat dateFormat, boolean remote); @NonNull public static String getFormattedMb(@NonNull Context ctx, double sizeInMb) { diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadOsmandIndexesHelper.java b/OsmAnd/src/net/osmand/plus/download/DownloadOsmandIndexesHelper.java index d77245cecb..a67de8b8d7 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadOsmandIndexesHelper.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadOsmandIndexesHelper.java @@ -1,5 +1,26 @@ package net.osmand.plus.download; +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.res.AssetManager; +import android.provider.Settings.Secure; + +import net.osmand.AndroidUtils; +import net.osmand.IndexConstants; +import net.osmand.PlatformUtil; +import net.osmand.osm.io.NetworkUtils; +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.settings.backend.OsmandSettings; +import net.osmand.util.Algorithms; + +import org.apache.commons.logging.Log; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlPullParserFactory; + import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -11,29 +32,9 @@ import java.util.Comparator; import java.util.List; import java.util.zip.GZIPInputStream; -import net.osmand.AndroidUtils; -import net.osmand.IndexConstants; -import net.osmand.PlatformUtil; -import net.osmand.osm.io.NetworkUtils; -import net.osmand.plus.OsmandApplication; -import net.osmand.plus.settings.backend.OsmandSettings; - -import org.apache.commons.logging.Log; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlPullParserFactory; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.res.AssetManager; -import android.provider.Settings.Secure; - public class DownloadOsmandIndexesHelper { private final static Log log = PlatformUtil.getLog(DownloadOsmandIndexesHelper.class); - + public static class IndexFileList implements Serializable { private static final long serialVersionUID = 1L; @@ -41,29 +42,29 @@ public class DownloadOsmandIndexesHelper { IndexItem basemap; ArrayList indexFiles = new ArrayList(); private String mapversion; - - private Comparator comparator = new Comparator(){ + + private Comparator comparator = new Comparator() { @Override public int compare(IndexItem o1, IndexItem o2) { String object1 = o1.getFileName(); String object2 = o2.getFileName(); - if(object1.endsWith(IndexConstants.ANYVOICE_INDEX_EXT_ZIP)){ - if(object2.endsWith(IndexConstants.ANYVOICE_INDEX_EXT_ZIP)){ + if (object1.endsWith(IndexConstants.ANYVOICE_INDEX_EXT_ZIP)) { + if (object2.endsWith(IndexConstants.ANYVOICE_INDEX_EXT_ZIP)) { return object1.compareTo(object2); } else { return -1; } - } else if(object2.endsWith(IndexConstants.ANYVOICE_INDEX_EXT_ZIP)){ + } else if (object2.endsWith(IndexConstants.ANYVOICE_INDEX_EXT_ZIP)) { return 1; } return object1.compareTo(object2); } }; - + public void setDownloadedFromInternet(boolean downloadedFromInternet) { this.downloadedFromInternet = downloadedFromInternet; } - + public boolean isDownloadedFromInternet() { return downloadedFromInternet; } @@ -75,12 +76,12 @@ public class DownloadOsmandIndexesHelper { @SuppressLint("DefaultLocale") public void add(IndexItem indexItem) { indexFiles.add(indexItem); - if(indexItem.getFileName().toLowerCase().startsWith("world_basemap")) { + if (indexItem.getFileName().toLowerCase().startsWith("world_basemap")) { basemap = indexItem; } } - - public void sort(){ + + public void sort() { Collections.sort(indexFiles, comparator); } @@ -91,7 +92,7 @@ public class DownloadOsmandIndexesHelper { public List getIndexFiles() { return indexFiles; } - + public IndexItem getBasemap() { return basemap; } @@ -106,7 +107,7 @@ public class DownloadOsmandIndexesHelper { return false; } - } + } public static IndexFileList getIndexesList(OsmandApplication app) { PackageManager pm = app.getPackageManager(); @@ -141,16 +142,16 @@ public class DownloadOsmandIndexesHelper { } private static void listVoiceAssets(IndexFileList result, AssetManager amanager, PackageManager pm, - OsmandSettings settings) { + OsmandSettings settings) { try { - File voicePath = settings.getContext().getAppPath(IndexConstants.VOICE_INDEX_DIR); + File voicePath = settings.getContext().getAppPath(IndexConstants.VOICE_INDEX_DIR); // list = amanager.list("voice"); String date = ""; long dateModified = System.currentTimeMillis(); try { OsmandApplication app = settings.getContext(); ApplicationInfo appInfo = pm.getApplicationInfo(app.getPackageName(), 0); - dateModified = new File(appInfo.sourceDir).lastModified(); + dateModified = new File(appInfo.sourceDir).lastModified(); date = AndroidUtils.formatDate((Context) settings.getContext(), dateModified); } catch (NameNotFoundException e) { log.error(e); @@ -177,17 +178,17 @@ public class DownloadOsmandIndexesHelper { log.error("Error while loading tts files from assets", e); //$NON-NLS-1$ } } - - private static IndexFileList downloadIndexesListFromInternet(OsmandApplication ctx){ + + private static IndexFileList downloadIndexesListFromInternet(OsmandApplication ctx) { try { IndexFileList result = new IndexFileList(); log.debug("Start loading list of index files"); //$NON-NLS-1$ try { String strUrl = ctx.getAppCustomization().getIndexesUrl(); long nd = ctx.getAppInitializer().getFirstInstalledDays(); - if(nd > 0) { - strUrl += "&nd=" + nd; + if (nd > 0) { + strUrl += "&nd=" + nd; } strUrl += "&ns=" + ctx.getAppInitializer().getNumberOfStarts(); try { @@ -202,12 +203,12 @@ public class DownloadOsmandIndexesHelper { GZIPInputStream gzin = new GZIPInputStream(in); parser.setInput(gzin, "UTF-8"); //$NON-NLS-1$ int next; - while((next = parser.next()) != XmlPullParser.END_DOCUMENT) { + while ((next = parser.next()) != XmlPullParser.END_DOCUMENT) { if (next == XmlPullParser.START_TAG) { DownloadActivityType tp = DownloadActivityType.getIndexType(parser.getAttributeValue(null, "type")); if (tp != null) { IndexItem it = tp.parseIndexItem(ctx, parser); - if(it != null) { + if (it != null) { result.add(it); } } else if ("osmand_regions".equals(parser.getName())) { @@ -226,7 +227,7 @@ public class DownloadOsmandIndexesHelper { log.error("Error while loading indexes from repository", e); //$NON-NLS-1$ return null; } - + if (result.isAcceptable()) { return result; } else { @@ -239,19 +240,19 @@ public class DownloadOsmandIndexesHelper { } public static class AssetIndexItem extends IndexItem { - + private final String assetName; private final String destFile; private final long dateModified; public AssetIndexItem(String fileName, String description, String date, - long dateModified, String size, long sizeL, String assetName, String destFile, DownloadActivityType type) { + long dateModified, String size, long sizeL, String assetName, String destFile, DownloadActivityType type) { super(fileName, description, dateModified, size, sizeL, sizeL, type); this.dateModified = dateModified; this.assetName = assetName; this.destFile = destFile; } - + public long getDateModified() { return dateModified; } @@ -261,7 +262,7 @@ public class DownloadOsmandIndexesHelper { return new DownloadEntry(assetName, destFile, dateModified); } - public String getDestFile(){ + public String getDestFile() { return destFile; } } diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadResources.java b/OsmAnd/src/net/osmand/plus/download/DownloadResources.java index 40f4a7488a..e2320b16a8 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadResources.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadResources.java @@ -25,12 +25,11 @@ import java.io.InputStream; import java.text.DateFormat; import java.text.ParseException; import java.util.ArrayList; -import java.util.HashSet; +import java.util.Collections; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Set; import static net.osmand.plus.download.DownloadResourceGroup.DownloadResourceGroupType.REGION_MAPS; @@ -117,6 +116,16 @@ public class DownloadResources extends DownloadResourceGroup { return res; } + @NonNull + public List getDownloadItems(WorldRegion region) { + DownloadResourceGroup group = getRegionMapsGroup(region); + if (group != null) { + return group.getIndividualDownloadItems(); + } + return Collections.emptyList(); + } + + @NonNull public List getIndexItems(WorldRegion region) { if (groupByRegion != null) { List res = groupByRegion.get(region); @@ -124,7 +133,7 @@ public class DownloadResources extends DownloadResourceGroup { return res; } } - return new LinkedList<>(); + return Collections.emptyList(); } public void updateLoadedFiles() { @@ -471,30 +480,60 @@ public class DownloadResources extends DownloadResourceGroup { addGroup(otherGroup); createHillshadeSRTMGroups(); - collectMultipleIndexesItems(); + replaceIndividualSrtmWithGroups(region); + createMultipleDownloadItems(region); trimEmptyGroups(); updateLoadedFiles(); return true; } - private void collectMultipleIndexesItems() { - collectMultipleIndexesItems(region); + private void replaceIndividualSrtmWithGroups(@NonNull WorldRegion region) { + DownloadResourceGroup group = getRegionMapsGroup(region); + if (group != null) { + boolean useMetersByDefault = SrtmDownloadItem.shouldUseMetersByDefault(app); + boolean listModified = false; + DownloadActivityType srtmType = DownloadActivityType.SRTM_COUNTRY_FILE; + List individualItems = group.getIndividualDownloadItems(); + if (isListContainsType(individualItems, srtmType)) { + List srtmIndexes = new ArrayList<>(); + for (DownloadItem item : individualItems) { + if (item.getType() == srtmType && item instanceof IndexItem) { + srtmIndexes.add((IndexItem) item); + } + } + if (srtmIndexes.size() > 1) { + individualItems.removeAll(srtmIndexes); + group.addItem(new SrtmDownloadItem(srtmIndexes, useMetersByDefault)); + } + listModified = true; + } + if (listModified) { + sortDownloadItems(individualItems); + } + } + + List subRegions = region.getSubregions(); + if (!Algorithms.isEmpty(subRegions)) { + for (WorldRegion subRegion : subRegions) { + replaceIndividualSrtmWithGroups(subRegion); + } + } } - private void collectMultipleIndexesItems(@NonNull WorldRegion region) { + private void createMultipleDownloadItems(@NonNull WorldRegion region) { List subRegions = region.getSubregions(); if (Algorithms.isEmpty(subRegions)) return; DownloadResourceGroup group = getRegionMapsGroup(region); if (group != null) { boolean listModified = false; - List indexesList = group.getIndividualResources(); - List regionsToCollect = removeDuplicateRegions(subRegions); + List downloadItems = group.getIndividualDownloadItems(); + List uniqueSubRegions = WorldRegion.removeDuplicates(subRegions); for (DownloadActivityType type : DownloadActivityType.values()) { - if (!doesListContainIndexWithType(indexesList, type)) { - List indexesFromSubRegions = collectIndexesOfType(regionsToCollect, type); - if (indexesFromSubRegions != null) { - group.addItem(new MultipleIndexItem(region, indexesFromSubRegions, type)); + if (!isListContainsType(downloadItems, type)) { + List itemsFromSubRegions = collectItemsOfType(uniqueSubRegions, type); + if (itemsFromSubRegions != null) { + group.addItem(new MultipleDownloadItem(region, itemsFromSubRegions, type)); listModified = true; } } @@ -504,7 +543,7 @@ public class DownloadResources extends DownloadResourceGroup { } } for (WorldRegion subRegion : subRegions) { - collectMultipleIndexesItems(subRegion); + createMultipleDownloadItems(subRegion); } } @@ -517,43 +556,21 @@ public class DownloadResources extends DownloadResourceGroup { } @Nullable - private List collectIndexesOfType(@NonNull List regions, - @NonNull DownloadActivityType type) { - List collectedIndexes = new ArrayList<>(); + private List collectItemsOfType(@NonNull List regions, + @NonNull DownloadActivityType type) { + List collectedItems = new ArrayList<>(); for (WorldRegion region : regions) { - List regionIndexes = getIndexItems(region); boolean found = false; - if (regionIndexes != null) { - for (IndexItem index : regionIndexes) { - if (index.getType() == type) { - found = true; - collectedIndexes.add(index); - break; - } + for (DownloadItem item : getDownloadItems(region)) { + if (item.getType() == type) { + found = true; + collectedItems.add(item); + break; } } if (!found) return null; } - return collectedIndexes; - } - - private List removeDuplicateRegions(List regions) { - Set duplicates = new HashSet<>(); - for (int i = 0; i < regions.size() - 1; i++) { - WorldRegion r1 = regions.get(i); - for (int j = i + 1; j < regions.size(); j++) { - WorldRegion r2 = regions.get(j); - if (r1.containsRegion(r2)) { - duplicates.add(r2); - } else if (r2.containsRegion(r1)) { - duplicates.add(r1); - } - } - } - for (WorldRegion region : duplicates) { - regions.remove(region); - } - return regions; + return collectedItems; } private void buildRegionsGroups(WorldRegion region, DownloadResourceGroup group) { @@ -680,11 +697,11 @@ public class DownloadResources extends DownloadResourceGroup { && isIndexItemDownloaded(downloadThread, type, downloadRegion.getSuperregion(), res); } - private boolean doesListContainIndexWithType(List indexItems, - DownloadActivityType type) { - if (indexItems != null) { - for (IndexItem indexItem : indexItems) { - if (indexItem.getType() == type) { + private boolean isListContainsType(List items, + DownloadActivityType type) { + if (items != null) { + for (DownloadItem item : items) { + if (item.getType() == type) { return true; } } diff --git a/OsmAnd/src/net/osmand/plus/download/IndexItem.java b/OsmAnd/src/net/osmand/plus/download/IndexItem.java index da0103fdb0..82da2619a3 100644 --- a/OsmAnd/src/net/osmand/plus/download/IndexItem.java +++ b/OsmAnd/src/net/osmand/plus/download/IndexItem.java @@ -1,6 +1,9 @@ package net.osmand.plus.download; +import android.content.Context; + import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import net.osmand.IndexConstants; import net.osmand.PlatformUtil; @@ -19,6 +22,7 @@ import java.util.Date; import java.util.List; public class IndexItem extends DownloadItem implements Comparable { + private static final Log log = PlatformUtil.getLog(IndexItem.class); String description; @@ -225,6 +229,12 @@ public class IndexItem extends DownloadItem implements Comparable { public String getDate(java.text.DateFormat format) { return format.format(new Date(timestamp)); } + + @Nullable + @Override + public String getAdditionalDescription(Context ctx) { + return null; + } public static class DownloadEntry { public long dateModified; @@ -254,5 +264,4 @@ public class IndexItem extends DownloadItem implements Comparable { } } - } diff --git a/OsmAnd/src/net/osmand/plus/download/MultipleIndexItem.java b/OsmAnd/src/net/osmand/plus/download/MultipleDownloadItem.java similarity index 56% rename from OsmAnd/src/net/osmand/plus/download/MultipleIndexItem.java rename to OsmAnd/src/net/osmand/plus/download/MultipleDownloadItem.java index 5f5ff9c297..d30c9fc83b 100644 --- a/OsmAnd/src/net/osmand/plus/download/MultipleIndexItem.java +++ b/OsmAnd/src/net/osmand/plus/download/MultipleDownloadItem.java @@ -1,32 +1,47 @@ package net.osmand.plus.download; +import android.content.Context; + import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import net.osmand.map.WorldRegion; import net.osmand.plus.OsmandApplication; import java.io.File; +import java.text.DateFormat; import java.util.ArrayList; import java.util.List; -public class MultipleIndexItem extends DownloadItem { +public class MultipleDownloadItem extends DownloadItem { - private final List items; + private final List items; - public MultipleIndexItem(@NonNull WorldRegion region, - @NonNull List items, - @NonNull DownloadActivityType type) { + public MultipleDownloadItem(@NonNull WorldRegion region, + @NonNull List items, + @NonNull DownloadActivityType type) { super(type); this.items = items; } public List getAllIndexes() { + List indexes = new ArrayList<>(); + for (DownloadItem item : items) { + IndexItem index = getIndexItem(item); + if (index != null) { + indexes.add(index); + } + } + return indexes; + } + + public List getAllItems() { return items; } @Override public boolean isOutdated() { - for (IndexItem item : items) { + for (DownloadItem item : items) { if (item.isOutdated()) { return true; } @@ -36,7 +51,7 @@ public class MultipleIndexItem extends DownloadItem { @Override public boolean isDownloaded() { - for (IndexItem item : items) { + for (DownloadItem item : items) { if (item.isDownloaded()) { return true; } @@ -46,8 +61,8 @@ public class MultipleIndexItem extends DownloadItem { @Override public boolean isDownloading(@NonNull DownloadIndexesThread thread) { - for (IndexItem item : items) { - if (thread.isDownloading(item)) { + for (DownloadItem item : items) { + if (item.isDownloading(thread)) { return true; } } @@ -78,31 +93,31 @@ public class MultipleIndexItem extends DownloadItem { @Override public List getDownloadedFiles(@NonNull OsmandApplication app) { List result = new ArrayList<>(); - for (IndexItem item : items) { + for (DownloadItem item : items) { result.addAll(item.getDownloadedFiles(app)); } return result; } - public List getIndexesToDownload() { - List indexesToDownload = new ArrayList<>(); - for (IndexItem item : items) { + public List getItemsToDownload() { + List itemsToDownload = new ArrayList<>(); + for (DownloadItem item : getAllItems()) { if (item.hasActualDataToDownload()) { - indexesToDownload.add(item); + itemsToDownload.add(item); } } - return indexesToDownload; + return itemsToDownload; } @Override public boolean hasActualDataToDownload() { - return getIndexesToDownload().size() > 0; + return getItemsToDownload().size() > 0; } @Override public double getSizeToDownloadInMb() { double totalSizeMb = 0.0d; - for (IndexItem item : items) { + for (DownloadItem item : items) { if (item.hasActualDataToDownload()) { totalSizeMb += item.getSizeToDownloadInMb(); } @@ -113,10 +128,33 @@ public class MultipleIndexItem extends DownloadItem { @Override public double getArchiveSizeMB() { double result = 0.0d; - for (IndexItem item : items) { + for (DownloadItem item : items) { result += item.getArchiveSizeMB(); } return result; } + @Nullable + public static IndexItem getIndexItem(@NonNull DownloadItem obj) { + if (obj instanceof IndexItem) { + return (IndexItem) obj; + } else if (obj instanceof SrtmDownloadItem) { + return ((SrtmDownloadItem) obj).getIndexItem(); + } + return null; + } + + @Nullable + @Override + public String getAdditionalDescription(Context ctx) { + for (DownloadItem item : items) { + return item.getAdditionalDescription(ctx); + } + return null; + } + + @Override + public String getDate(@NonNull DateFormat dateFormat, boolean remote) { + return ""; + } } diff --git a/OsmAnd/src/net/osmand/plus/download/MultipleIndexesUiHelper.java b/OsmAnd/src/net/osmand/plus/download/MultipleIndexesUiHelper.java deleted file mode 100644 index f84da0a74a..0000000000 --- a/OsmAnd/src/net/osmand/plus/download/MultipleIndexesUiHelper.java +++ /dev/null @@ -1,113 +0,0 @@ -package net.osmand.plus.download; - -import androidx.annotation.NonNull; -import androidx.appcompat.app.AppCompatActivity; - -import net.osmand.map.OsmandRegions; -import net.osmand.plus.OsmandApplication; -import net.osmand.plus.R; -import net.osmand.plus.base.SelectMultipleItemsBottomSheet; -import net.osmand.plus.base.SelectMultipleItemsBottomSheet.OnApplySelectionListener; -import net.osmand.plus.base.SelectMultipleItemsBottomSheet.SelectableItem; -import net.osmand.plus.base.SelectMultipleItemsBottomSheet.SelectionUpdateListener; - -import java.text.DateFormat; -import java.util.ArrayList; -import java.util.List; - -public class MultipleIndexesUiHelper { - - public static void showDialog(@NonNull MultipleIndexItem multipleIndexItem, - @NonNull AppCompatActivity activity, - @NonNull final OsmandApplication app, - @NonNull DateFormat dateFormat, - boolean showRemoteDate, - @NonNull final SelectItemsToDownloadListener listener) { - List indexesToDownload = getIndexesToDownload(multipleIndexItem); - List allItems = new ArrayList<>(); - List selectedItems = new ArrayList<>(); - OsmandRegions osmandRegions = app.getRegions(); - for (IndexItem indexItem : multipleIndexItem.getAllIndexes()) { - SelectableItem selectableItem = new SelectableItem(); - selectableItem.setTitle(indexItem.getVisibleName(app, osmandRegions, false)); - - String size = indexItem.getSizeDescription(app); - String date = indexItem.getDate(dateFormat, showRemoteDate); - String description = app.getString(R.string.ltr_or_rtl_combine_via_bold_point, size, date); - selectableItem.setDescription(description); - - selectableItem.setIconId(indexItem.getType().getIconResource()); - selectableItem.setObject(indexItem); - allItems.add(selectableItem); - - if (indexesToDownload.contains(indexItem)) { - selectedItems.add(selectableItem); - } - } - - final SelectMultipleItemsBottomSheet dialog = - SelectMultipleItemsBottomSheet.showInstance(activity, allItems, selectedItems, true); - - dialog.setSelectionUpdateListener(new SelectionUpdateListener() { - @Override - public void onSelectionUpdate() { - dialog.setTitle(app.getString(R.string.welmode_download_maps)); - String total = app.getString(R.string.shared_string_total); - double sizeToDownload = getDownloadSizeInMb(dialog.getSelectedItems()); - String size = DownloadItem.getFormattedMb(app, sizeToDownload); - String description = - app.getString(R.string.ltr_or_rtl_combine_via_colon, total, size); - dialog.setDescription(description); - String btnTitle = app.getString(R.string.shared_string_download); - if (sizeToDownload > 0) { - btnTitle = app.getString(R.string.ltr_or_rtl_combine_via_dash, btnTitle, size); - } - dialog.setConfirmButtonTitle(btnTitle); - } - }); - - dialog.setOnApplySelectionListener(new OnApplySelectionListener() { - @Override - public void onSelectionApplied(List selectedItems) { - List indexItems = new ArrayList<>(); - for (SelectableItem item : selectedItems) { - Object obj = item.getObject(); - if (obj instanceof IndexItem) { - indexItems.add((IndexItem) obj); - } - } - listener.onItemsToDownloadSelected(indexItems); - } - }); - } - - private static List getIndexesToDownload(MultipleIndexItem multipleIndexItem) { - if (multipleIndexItem.hasActualDataToDownload()) { - // download left regions - return multipleIndexItem.getIndexesToDownload(); - } else { - // download all regions again - return multipleIndexItem.getAllIndexes(); - } - } - - private static double getDownloadSizeInMb(@NonNull List selectableItems) { - List indexItems = new ArrayList<>(); - for (SelectableItem i : selectableItems) { - Object obj = i.getObject(); - if (obj instanceof IndexItem) { - indexItems.add((IndexItem) obj); - } - } - double totalSizeMb = 0.0d; - for (IndexItem item : indexItems) { - totalSizeMb += item.getSizeToDownloadInMb(); - } - return totalSizeMb; - } - - public interface SelectItemsToDownloadListener { - void onItemsToDownloadSelected(List items); - } - -} diff --git a/OsmAnd/src/net/osmand/plus/download/SelectIndexesUiHelper.java b/OsmAnd/src/net/osmand/plus/download/SelectIndexesUiHelper.java new file mode 100644 index 0000000000..f7835ce348 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/download/SelectIndexesUiHelper.java @@ -0,0 +1,280 @@ +package net.osmand.plus.download; + +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; + +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.R; +import net.osmand.plus.base.MultipleSelectionBottomSheet; +import net.osmand.plus.base.MultipleSelectionBottomSheet.SelectionUpdateListener; +import net.osmand.plus.base.ModeSelectionBottomSheet; +import net.osmand.plus.base.MultipleSelectionWithModeBottomSheet; +import net.osmand.plus.base.SelectionBottomSheet; +import net.osmand.plus.base.SelectionBottomSheet.OnApplySelectionListener; +import net.osmand.plus.base.SelectionBottomSheet.OnUiInitializedAdapter; +import net.osmand.plus.base.SelectionBottomSheet.SelectableItem; +import net.osmand.plus.widgets.MultiStateToggleButton.OnRadioItemClickListener; +import net.osmand.plus.widgets.MultiStateToggleButton.RadioItem; +import net.osmand.util.Algorithms; + +import java.text.DateFormat; +import java.util.ArrayList; +import java.util.List; + +import static net.osmand.plus.download.MultipleDownloadItem.getIndexItem; + +public class SelectIndexesUiHelper { + + private final OsmandApplication app; + private final AppCompatActivity activity; + + private final ItemsToDownloadSelectedListener listener; + private final DateFormat dateFormat; + private final boolean showRemoteDate; + private final DownloadItem downloadItem; + + private SelectionBottomSheet dialog; + + private SelectIndexesUiHelper(@NonNull DownloadItem downloadItem, + @NonNull AppCompatActivity activity, + @NonNull DateFormat dateFormat, + boolean showRemoteDate, + @NonNull ItemsToDownloadSelectedListener listener) { + this.app = (OsmandApplication) activity.getApplicationContext(); + this.activity = activity; + this.downloadItem = downloadItem; + this.dateFormat = dateFormat; + this.showRemoteDate = showRemoteDate; + this.listener = listener; + } + + public static void showDialog(@NonNull DownloadItem i, + @NonNull AppCompatActivity a, + @NonNull DateFormat df, + boolean showRemoteDate, + @NonNull ItemsToDownloadSelectedListener l) { + + new SelectIndexesUiHelper(i, a, df, showRemoteDate, l).showDialogInternal(); + } + + private void showDialogInternal() { + if (downloadItem.getType() == DownloadActivityType.SRTM_COUNTRY_FILE) { + if (downloadItem instanceof MultipleDownloadItem) { + showSrtmMultipleSelectionDialog(); + } else { + showSrtmModeSelectionDialog(); + } + } else if (downloadItem instanceof MultipleDownloadItem) { + showMultipleSelectionDialog(); + } + } + + private void showMultipleSelectionDialog() { + List allItems = new ArrayList<>(); + List selectedItems = new ArrayList<>(); + prepareItems(allItems, selectedItems); + + MultipleSelectionBottomSheet msDialog = MultipleSelectionBottomSheet.showInstance( + activity, allItems, selectedItems, true); + this.dialog = msDialog; + + msDialog.setOnUiInitializedAdapter(new OnUiInitializedAdapter() { + @Override + public void onUiInitialized() { + dialog.setTitle(app.getString(R.string.welmode_download_maps)); + } + }); + + msDialog.setSelectionUpdateListener(new SelectionUpdateListener() { + @Override + public void onSelectionUpdate() { + updateSize(); + } + }); + + msDialog.setOnApplySelectionListener(getOnApplySelectionListener(listener)); + } + + private void showSrtmMultipleSelectionDialog() { + List allItems = new ArrayList<>(); + List selectedItems = new ArrayList<>(); + prepareItems(allItems, selectedItems); + + SrtmDownloadItem srtmItem = (SrtmDownloadItem) ((MultipleDownloadItem)downloadItem).getAllItems().get(0); + final int selectedModeOrder = srtmItem.isUseMetric() ? 0 : 1; + final List radioItems = createSrtmRadioItems(); + + MultipleSelectionBottomSheet msDialog = MultipleSelectionWithModeBottomSheet.showInstance( + activity, allItems, selectedItems, radioItems, true); + this.dialog = msDialog; + + msDialog.setOnUiInitializedAdapter(new OnUiInitializedAdapter() { + @Override + public void onUiInitialized() { + dialog.setTitle(app.getString(R.string.welmode_download_maps)); + dialog.setSelectedMode(radioItems.get(selectedModeOrder)); + dialog.setSecondaryDescription(app.getString(R.string.srtm_download_list_help_message)); + } + }); + + msDialog.setSelectionUpdateListener(new SelectionUpdateListener() { + @Override + public void onSelectionUpdate() { + updateSize(); + } + }); + + msDialog.setOnApplySelectionListener(getOnApplySelectionListener(listener)); + } + + private void showSrtmModeSelectionDialog() { + SrtmDownloadItem srtmItem = (SrtmDownloadItem) downloadItem; + final int selectedModeOrder = srtmItem.isUseMetric() ? 0 : 1; + + final List radioItems = createSrtmRadioItems(); + SelectableItem preview = createSelectableItem(srtmItem); + + dialog = ModeSelectionBottomSheet.showInstance(activity, preview, radioItems, true); + + dialog.setOnUiInitializedAdapter(new OnUiInitializedAdapter() { + @Override + public void onUiInitialized() { + ModeSelectionBottomSheet dialog = (ModeSelectionBottomSheet) SelectIndexesUiHelper.this.dialog; + dialog.setTitle(app.getString(R.string.srtm_unit_format)); + dialog.setPrimaryDescription(app.getString(R.string.srtm_download_single_help_message)); + updateSize(); + dialog.setSelectedMode(radioItems.get(selectedModeOrder)); + } + }); + + dialog.setOnApplySelectionListener(getOnApplySelectionListener(listener)); + } + + private void prepareItems(List allItems, + List selectedItems) { + final MultipleDownloadItem multipleDownloadItem = (MultipleDownloadItem) downloadItem; + final List itemsToDownload = getItemsToDownload(multipleDownloadItem); + for (DownloadItem downloadItem : multipleDownloadItem.getAllItems()) { + SelectableItem selectableItem = createSelectableItem(downloadItem); + allItems.add(selectableItem); + + if (itemsToDownload.contains(downloadItem)) { + selectedItems.add(selectableItem); + } + } + } + + private List createSrtmRadioItems() { + List radioItems = new ArrayList<>(); + radioItems.add(createSrtmRadioBtn(R.string.shared_string_meters, true)); + radioItems.add(createSrtmRadioBtn(R.string.shared_string_feet, false)); + return radioItems; + } + + private RadioItem createSrtmRadioBtn(int titleId, + final boolean useMeters) { + String title = Algorithms.capitalizeFirstLetter(app.getString(titleId)); + RadioItem radioItem = new RadioItem(title); + radioItem.setOnClickListener(new OnRadioItemClickListener() { + @Override + public boolean onRadioItemClick(RadioItem radioItem, View view) { + updateDialogListItems(useMeters); + updateSize(); + return true; + } + }); + return radioItem; + } + + private void updateDialogListItems(boolean useMeters) { + List items = new ArrayList<>(dialog.getAllItems()); + for (SelectableItem item : items) { + DownloadItem downloadItem = (DownloadItem) item.getObject(); + if (downloadItem instanceof SrtmDownloadItem) { + ((SrtmDownloadItem) downloadItem).setUseMetric(useMeters); + updateSelectableItem(item, downloadItem); + } + } + dialog.setItems(items); + } + + private SelectableItem createSelectableItem(DownloadItem item) { + SelectableItem selectableItem = new SelectableItem(); + updateSelectableItem(selectableItem, item); + return selectableItem; + } + + private void updateSelectableItem(SelectableItem selectableItem, + DownloadItem downloadItem) { + selectableItem.setTitle(downloadItem.getVisibleName(app, app.getRegions(), false)); + + String size = downloadItem.getSizeDescription(app); + String addDescr = downloadItem.getAdditionalDescription(app); + if (addDescr != null) { + size += " " + addDescr; + } + String date = downloadItem.getDate(dateFormat, showRemoteDate); + String description = app.getString(R.string.ltr_or_rtl_combine_via_bold_point, size, date); + selectableItem.setDescription(description); + + selectableItem.setIconId(downloadItem.getType().getIconResource()); + selectableItem.setObject(downloadItem); + } + + private OnApplySelectionListener getOnApplySelectionListener(final ItemsToDownloadSelectedListener listener) { + return new OnApplySelectionListener() { + @Override + public void onSelectionApplied(List selectedItems) { + List indexes = new ArrayList<>(); + for (SelectableItem item : selectedItems) { + IndexItem index = getIndexItem((DownloadItem) item.getObject()); + if (index != null) { + indexes.add(index); + } + } + listener.onItemsToDownloadSelected(indexes); + } + }; + } + + private void updateSize() { + double sizeToDownload = getDownloadSizeInMb(dialog.getSelectedItems()); + String size = DownloadItem.getFormattedMb(app, sizeToDownload); + String total = app.getString(R.string.shared_string_total); + String description = app.getString(R.string.ltr_or_rtl_combine_via_colon, total, size); + dialog.setTitleDescription(description); + String btnTitle = app.getString(R.string.shared_string_download); + if (sizeToDownload > 0) { + btnTitle = app.getString(R.string.ltr_or_rtl_combine_via_dash, btnTitle, size); + } + dialog.setApplyButtonTitle(btnTitle); + } + + private double getDownloadSizeInMb(@NonNull List selectableItems) { + double totalSizeMb = 0.0d; + for (SelectableItem i : selectableItems) { + Object obj = i.getObject(); + if (obj instanceof DownloadItem) { + totalSizeMb += ((DownloadItem) obj).getSizeToDownloadInMb(); + } + } + return totalSizeMb; + } + + private static List getItemsToDownload(MultipleDownloadItem md) { + if (md.hasActualDataToDownload()) { + // download left regions + return md.getItemsToDownload(); + } else { + // download all regions again + return md.getAllItems(); + } + } + + public interface ItemsToDownloadSelectedListener { + void onItemsToDownloadSelected(List items); + } + +} diff --git a/OsmAnd/src/net/osmand/plus/download/SrtmDownloadItem.java b/OsmAnd/src/net/osmand/plus/download/SrtmDownloadItem.java new file mode 100644 index 0000000000..8567f97409 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/download/SrtmDownloadItem.java @@ -0,0 +1,191 @@ +package net.osmand.plus.download; + +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import net.osmand.IndexConstants; +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.R; +import net.osmand.plus.activities.LocalIndexInfo; +import net.osmand.plus.helpers.enums.MetricsConstants; +import net.osmand.util.Algorithms; + +import java.io.File; +import java.text.DateFormat; +import java.util.ArrayList; +import java.util.List; + +import static net.osmand.IndexConstants.BINARY_SRTM_MAP_INDEX_EXT; +import static net.osmand.IndexConstants.BINARY_SRTM_MAP_INDEX_EXT_ZIP; +import static net.osmand.plus.activities.LocalIndexHelper.LocalIndexType.SRTM_DATA; +import static net.osmand.plus.download.DownloadActivityType.SRTM_COUNTRY_FILE; + +public class SrtmDownloadItem extends DownloadItem { + + private final List indexes; + private boolean useMetric; + + public SrtmDownloadItem(List indexes, boolean useMetric) { + super(SRTM_COUNTRY_FILE); + this.indexes = indexes; + this.useMetric = useMetric; + } + + public void setUseMetric(boolean useMetric) { + this.useMetric = useMetric; + } + + public boolean isUseMetric() { + for (IndexItem index : indexes) { + if (index.isDownloaded()) { + return isMetricItem(index); + } + } + return useMetric; + } + + @NonNull + public IndexItem getIndexItem() { + for (IndexItem index : indexes) { + if (index.isDownloaded()) { + return index; + } + } + for (IndexItem index : indexes) { + if (useMetric && isMetricItem(index) || !useMetric && !isMetricItem(index)) { + return index; + } + } + return indexes.get(0); + } + + @Override + protected double getSizeToDownloadInMb() { + return getIndexItem().getSizeToDownloadInMb(); + } + + @Override + public double getArchiveSizeMB() { + return getIndexItem().getArchiveSizeMB(); + } + + @Override + public boolean isOutdated() { + for (DownloadItem item : indexes) { + if (item.isOutdated()) { + return true; + } + } + return false; + } + + @Override + public boolean isDownloaded() { + for (DownloadItem item : indexes) { + if (item.isDownloaded()) { + return true; + } + } + return false; + } + + @Override + public boolean hasActualDataToDownload() { + for (IndexItem item : indexes) { + if (!item.hasActualDataToDownload()) { + return false; + } + } + return true; + } + + @Override + public boolean isDownloading(@NonNull DownloadIndexesThread thread) { + for (IndexItem item : indexes) { + if (thread.isDownloading(item)) { + return true; + } + } + return false; + } + + @Override + public String getFileName() { + return getIndexItem().getFileName(); + } + + @NonNull + @Override + public List getDownloadedFiles(@NonNull OsmandApplication app) { + List result = new ArrayList<>(); + for (IndexItem index : indexes) { + result.addAll(index.getDownloadedFiles(app)); + } + return result; + } + + public String getDate(@NonNull DateFormat dateFormat, boolean remote) { + return getIndexItem().getDate(dateFormat, remote); + } + + @Override + public @Nullable String getAdditionalDescription(Context ctx) { + return getAbbreviationInScopes(ctx, this); + } + + public static boolean shouldUseMetersByDefault(@NonNull OsmandApplication app) { + MetricsConstants metricSystem = app.getSettings().METRIC_SYSTEM.get(); + return metricSystem != MetricsConstants.MILES_AND_FEET; + } + + @NonNull + public static String getAbbreviationInScopes(Context ctx, Object obj) { + String abbreviation = ctx.getString(isMetricItem(obj) ? R.string.m : R.string.foot); + return "(" + abbreviation + ")"; + } + + public static boolean containsSrtmExtension(@NonNull String fileName) { + return fileName.contains(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT) + || fileName.contains(IndexConstants.BINARY_SRTM_FEET_MAP_INDEX_EXT); + } + + public static boolean isSrtmFile(@NonNull String fileName) { + return fileName.endsWith(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT) + || fileName.endsWith(IndexConstants.BINARY_SRTM_FEET_MAP_INDEX_EXT); + } + + @NonNull + public static String getExtension(IndexItem indexItem) { + return isMetricItem(indexItem) ? + IndexConstants.BINARY_SRTM_MAP_INDEX_EXT : + IndexConstants.BINARY_SRTM_FEET_MAP_INDEX_EXT; + } + + public static boolean isSRTMItem(Object item) { + if (item instanceof DownloadItem) { + return ((DownloadItem) item).getType() == SRTM_COUNTRY_FILE; + } else if (item instanceof LocalIndexInfo) { + return ((LocalIndexInfo) item).getType() == SRTM_DATA; + } + return false; + } + + private static boolean isMetricItem(Object item) { + if (item instanceof IndexItem) { + return ((IndexItem) item).getFileName().endsWith(BINARY_SRTM_MAP_INDEX_EXT_ZIP); + } else if (item instanceof LocalIndexInfo) { + return ((LocalIndexInfo) item).getFileName().endsWith(BINARY_SRTM_MAP_INDEX_EXT); + } else if (item instanceof SrtmDownloadItem) { + return isMetricItem(((SrtmDownloadItem) item).getIndexItem()); + } else if (item instanceof MultipleDownloadItem) { + List items = ((MultipleDownloadItem) item).getAllItems(); + if (!Algorithms.isEmpty(items)) { + return isMetricItem(items.get(0)); + } + } + return false; + } + +} diff --git a/OsmAnd/src/net/osmand/plus/download/ui/ActiveDownloadsDialogFragment.java b/OsmAnd/src/net/osmand/plus/download/ui/ActiveDownloadsDialogFragment.java index 1b8667685c..31a0205f0e 100644 --- a/OsmAnd/src/net/osmand/plus/download/ui/ActiveDownloadsDialogFragment.java +++ b/OsmAnd/src/net/osmand/plus/download/ui/ActiveDownloadsDialogFragment.java @@ -87,7 +87,7 @@ public class ActiveDownloadsDialogFragment extends DialogFragment implements Dow } ItemViewHolder viewHolder = (ItemViewHolder) convertView.getTag(); IndexItem item = getItem(position); - viewHolder.bindIndexItem(item); + viewHolder.bindDownloadItem(item); return convertView; } diff --git a/OsmAnd/src/net/osmand/plus/download/ui/DownloadResourceGroupAdapter.java b/OsmAnd/src/net/osmand/plus/download/ui/DownloadResourceGroupAdapter.java index d2e281bbfc..168888434d 100644 --- a/OsmAnd/src/net/osmand/plus/download/ui/DownloadResourceGroupAdapter.java +++ b/OsmAnd/src/net/osmand/plus/download/ui/DownloadResourceGroupAdapter.java @@ -78,7 +78,7 @@ public class DownloadResourceGroupAdapter extends OsmandBaseExpandableListAdapte } else { viewHolder.setShowTypeInDesc(true); } - viewHolder.bindIndexItem(item); + viewHolder.bindDownloadItem(item); } else { DownloadResourceGroup group = (DownloadResourceGroup) child; DownloadGroupViewHolder viewHolder; diff --git a/OsmAnd/src/net/osmand/plus/download/ui/ItemViewHolder.java b/OsmAnd/src/net/osmand/plus/download/ui/ItemViewHolder.java index a24e2c5b2a..135db84bc9 100644 --- a/OsmAnd/src/net/osmand/plus/download/ui/ItemViewHolder.java +++ b/OsmAnd/src/net/osmand/plus/download/ui/ItemViewHolder.java @@ -41,9 +41,9 @@ import net.osmand.plus.download.DownloadActivityType; import net.osmand.plus.download.DownloadResourceGroup; import net.osmand.plus.download.DownloadResources; import net.osmand.plus.download.IndexItem; -import net.osmand.plus.download.MultipleIndexesUiHelper; -import net.osmand.plus.download.MultipleIndexesUiHelper.SelectItemsToDownloadListener; -import net.osmand.plus.download.MultipleIndexItem; +import net.osmand.plus.download.SelectIndexesUiHelper; +import net.osmand.plus.download.SelectIndexesUiHelper.ItemsToDownloadSelectedListener; +import net.osmand.plus.download.MultipleDownloadItem; import net.osmand.plus.download.ui.LocalIndexesFragment.LocalIndexOperationTask; import net.osmand.plus.helpers.FileNameTranslationHelper; import net.osmand.plus.inapp.InAppPurchaseHelper; @@ -146,11 +146,11 @@ public class ItemViewHolder { depthContoursPurchased = InAppPurchaseHelper.isDepthContoursPurchased(context.getMyApplication()); } - public void bindIndexItem(final DownloadItem downloadItem) { - bindIndexItem(downloadItem, null); + public void bindDownloadItem(final DownloadItem downloadItem) { + bindDownloadItem(downloadItem, null); } - public void bindIndexItem(final DownloadItem downloadItem, final String cityName) { + public void bindDownloadItem(final DownloadItem downloadItem, final String cityName) { initAppStatusVariables(); boolean isDownloading = downloadItem.isDownloading(context.getDownloadThread()); int progress = -1; @@ -160,20 +160,20 @@ public class ItemViewHolder { boolean disabled = checkDisabledAndClickAction(downloadItem); /// name and left item String name; - if(showTypeInName) { + if (showTypeInName) { name = downloadItem.getType().getString(context); } else { name = downloadItem.getVisibleName(context, context.getMyApplication().getRegions(), showParentRegionName); } String text = (!Algorithms.isEmpty(cityName) && !cityName.equals(name) ? cityName + "\n" : "") + name; nameTextView.setText(text); - if(!disabled) { + if (!disabled) { nameTextView.setTextColor(textColorPrimary); } else { nameTextView.setTextColor(textColorSecondary); } int color = textColorSecondary; - if(downloadItem.isDownloaded() && !isDownloading) { + if (downloadItem.isDownloaded() && !isDownloading) { int colorId = downloadItem.isOutdated() ? R.color.color_distance : R.color.color_ok; color = context.getResources().getColor(colorId); } @@ -203,12 +203,12 @@ public class ItemViewHolder { } else { descrTextView.setText(downloadItem.getType().getString(context)); } - } else if (downloadItem instanceof MultipleIndexItem) { - MultipleIndexItem item = (MultipleIndexItem) downloadItem; + } else if (downloadItem instanceof MultipleDownloadItem) { + MultipleDownloadItem item = (MultipleDownloadItem) downloadItem; String allRegionsHeader = context.getString(R.string.shared_strings_all_regions); String regionsHeader = context.getString(R.string.regions); - String allRegionsCount = String.valueOf(item.getAllIndexes().size()); - String leftToDownloadCount = String.valueOf(item.getIndexesToDownload().size()); + String allRegionsCount = String.valueOf(item.getAllItems().size()); + String leftToDownloadCount = String.valueOf(item.getItemsToDownload().size()); String header; String count; if (item.hasActualDataToDownload()) { @@ -226,8 +226,11 @@ public class ItemViewHolder { header = allRegionsHeader; count = allRegionsCount; } - String fullDescription = - context.getString(R.string.ltr_or_rtl_combine_via_colon, header, count); + String fullDescription = context.getString(R.string.ltr_or_rtl_combine_via_colon, header, count); + String addDescr = item.getAdditionalDescription(context); + if (addDescr != null) { + fullDescription += " " + addDescr; + } if (item.hasActualDataToDownload()) { fullDescription = context.getString( R.string.ltr_or_rtl_combine_via_bold_point, fullDescription, @@ -235,11 +238,14 @@ public class ItemViewHolder { } descrTextView.setText(fullDescription); } else { - IndexItem item = (IndexItem) downloadItem; String pattern = context.getString(R.string.ltr_or_rtl_combine_via_bold_point); - String type = item.getType().getString(context); - String size = item.getSizeDescription(context); - String date = item.getDate(dateFormat, showRemoteDate); + String type = downloadItem.getType().getString(context); + String size = downloadItem.getSizeDescription(context); + String addDescr = downloadItem.getAdditionalDescription(context); + if (addDescr != null) { + size += " " + addDescr; + } + String date = downloadItem.getDate(dateFormat, showRemoteDate); String fullDescription = String.format(pattern, size, date); if (showTypeInDesc) { fullDescription = String.format(pattern, type, fullDescription); @@ -254,14 +260,14 @@ public class ItemViewHolder { if (showProgressInDesc) { double mb = downloadItem.getArchiveSizeMB(); - String v ; + String v; if (progress != -1) { v = context.getString(R.string.value_downloaded_of_max, mb * progress / 100, mb); } else { v = context.getString(R.string.file_size_in_mb, mb); } String fullDescription = v; - if(showTypeInDesc && downloadItem.getType() == DownloadActivityType.ROADS_FILE) { + if (showTypeInDesc && downloadItem.getType() == DownloadActivityType.ROADS_FILE) { fullDescription = context.getString(R.string.ltr_or_rtl_combine_via_bold_point, downloadItem.getType().getString(context), fullDescription); } @@ -274,9 +280,9 @@ public class ItemViewHolder { } } - public void bindIndexItem(final CityItem cityItem) { + public void bindDownloadItem(final CityItem cityItem) { if (cityItem.getIndexItem() != null) { - bindIndexItem(cityItem.getIndexItem(), cityItem.getName()); + bindDownloadItem(cityItem.getIndexItem(), cityItem.getName()); } else { nameTextView.setText(cityItem.getName()); nameTextView.setTextColor(textColorPrimary); @@ -302,7 +308,7 @@ public class ItemViewHolder { if (isDownloading) { rightImageButton.setImageDrawable(getContentIcon(context, R.drawable.ic_action_remove_dark)); rightImageButton.setContentDescription(context.getString(R.string.shared_string_cancel)); - } else if(!item.hasActualDataToDownload()) { + } else if (!item.hasActualDataToDownload()) { rightImageButton.setImageDrawable(getContentIcon(context, R.drawable.ic_overflow_menu_white)); rightImageButton.setContentDescription(context.getString(R.string.shared_string_more)); } else { @@ -316,9 +322,9 @@ public class ItemViewHolder { } private int getDownloadActionIconId(@NonNull DownloadItem item) { - return item instanceof MultipleIndexItem ? + return item instanceof MultipleDownloadItem ? R.drawable.ic_action_multi_download : - R.drawable.ic_action_import; + R.drawable.ic_action_gsave_dark; } @SuppressLint("DefaultLocale") @@ -389,13 +395,13 @@ public class ItemViewHolder { return new View.OnClickListener() { @Override public void onClick(View v) { - if(isDownloading) { - if(silentCancelDownload) { + if (isDownloading) { + if (silentCancelDownload) { context.getDownloadThread().cancelDownload(item); } else { context.makeSureUserCancelDownload(item); } - } else if(!item.hasActualDataToDownload()){ + } else if (!item.hasActualDataToDownload()) { showContextMenu(v, item, item.getRelatedGroup()); } else { download(item, item.getRelatedGroup()); @@ -406,8 +412,8 @@ public class ItemViewHolder { } protected void showContextMenu(View v, - final DownloadItem downloadItem, - final DownloadResourceGroup parentOptional) { + final DownloadItem downloadItem, + final DownloadResourceGroup parentOptional) { OsmandApplication app = context.getMyApplication(); PopupMenu optionsMenu = new PopupMenu(context, v); MenuItem item; @@ -455,10 +461,11 @@ public class ItemViewHolder { } } } - if(!handled) { + if (!handled) { startDownload(item); } } + private void confirmDownload(final DownloadItem item) { AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle(R.string.are_you_sure); @@ -476,18 +483,17 @@ public class ItemViewHolder { } private void startDownload(DownloadItem item) { - if (item instanceof MultipleIndexItem) { - selectIndexesToDownload((MultipleIndexItem) item); - } else if (item instanceof IndexItem) { + if (item instanceof IndexItem) { IndexItem indexItem = (IndexItem) item; context.startDownload(indexItem); + } else { + selectIndexesToDownload(item); } } - private void selectIndexesToDownload(MultipleIndexItem item) { - OsmandApplication app = context.getMyApplication(); - MultipleIndexesUiHelper.showDialog(item, context, app, dateFormat, showRemoteDate, - new SelectItemsToDownloadListener() { + private void selectIndexesToDownload(DownloadItem item) { + SelectIndexesUiHelper.showDialog(item, context, dateFormat, showRemoteDate, + new ItemsToDownloadSelectedListener() { @Override public void onItemsToDownloadSelected(List indexes) { IndexItem[] indexesArray = new IndexItem[indexes.size()]; @@ -498,7 +504,7 @@ public class ItemViewHolder { } private void confirmRemove(@NonNull final DownloadItem downloadItem, - @NonNull final List downloadedFiles) { + @NonNull final List downloadedFiles) { OsmandApplication app = context.getMyApplication(); AlertDialog.Builder confirm = new AlertDialog.Builder(context); @@ -526,7 +532,7 @@ public class ItemViewHolder { } private void remove(@NonNull LocalIndexType type, - @NonNull List filesToDelete) { + @NonNull List filesToDelete) { OsmandApplication app = context.getMyApplication(); LocalIndexOperationTask removeTask = new LocalIndexOperationTask( context, diff --git a/OsmAnd/src/net/osmand/plus/download/ui/LocalIndexesFragment.java b/OsmAnd/src/net/osmand/plus/download/ui/LocalIndexesFragment.java index 3b259ab241..2c691a78de 100644 --- a/OsmAnd/src/net/osmand/plus/download/ui/LocalIndexesFragment.java +++ b/OsmAnd/src/net/osmand/plus/download/ui/LocalIndexesFragment.java @@ -55,6 +55,7 @@ import net.osmand.plus.dialogs.DirectionsDialogs; import net.osmand.plus.download.DownloadActivity; import net.osmand.plus.download.DownloadIndexesThread.DownloadEvents; import net.osmand.plus.download.IndexItem; +import net.osmand.plus.download.SrtmDownloadItem; import net.osmand.plus.helpers.FileNameTranslationHelper; import net.osmand.plus.inapp.InAppPurchaseHelper; import net.osmand.plus.mapsource.EditMapSourceDialogFragment.OnMapSourceUpdateListener; @@ -74,6 +75,7 @@ import java.util.List; import java.util.Map; import java.util.Set; + public class LocalIndexesFragment extends OsmandExpandableListFragment implements DownloadEvents, OnMapSourceUpdateListener, RenameCallback { private LoadLocalIndexTask asyncLoader; @@ -351,10 +353,10 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement getMyApplication().getResourceManager().closeFile(info.getFileName()); File tShm = new File(f.getParentFile(), f.getName() + "-shm"); File tWal = new File(f.getParentFile(), f.getName() + "-wal"); - if(tShm.exists()) { + if (tShm.exists()) { Algorithms.removeAllFiles(tShm); } - if(tWal.exists()) { + if (tWal.exists()) { Algorithms.removeAllFiles(tWal); } } @@ -370,8 +372,8 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement getMyApplication().getResourceManager().closeFile(info.getFileName()); } } else if (operation == CLEAR_TILES_OPERATION) { - ITileSource src = (ITileSource) info.getAttachedObject(); - if(src != null) { + ITileSource src = (ITileSource) info.getAttachedObject(); + if (src != null) { src.deleteTiles(info.getPathToData()); } } @@ -419,10 +421,10 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement @Override protected void onPostExecute(String result) { a.setProgressBarIndeterminateVisibility(false); - if(result != null && result.length() > 0) { + if (result != null && result.length() > 0) { Toast.makeText(a, result, Toast.LENGTH_LONG).show(); } - + if (operation == RESTORE_OPERATION || operation == BACKUP_OPERATION || operation == CLEAR_TILES_OPERATION) { a.reloadLocalIndexes(); } else { @@ -507,7 +509,7 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement ItemClickListener listener = new ContextMenuAdapter.ItemClickListener() { @Override public boolean onContextMenuClick(ArrayAdapter adapter, - int itemId, int pos, boolean isChecked, int[] viewCoordinates) { + int itemId, int pos, boolean isChecked, int[] viewCoordinates) { localOptionsMenu(itemId); return true; } @@ -608,7 +610,7 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement } private void openSelectionMode(final int actionResId, final int actionIconId, - final DialogInterface.OnClickListener listener) { + final DialogInterface.OnClickListener listener) { final int colorResId = getMyApplication().getSettings().isLightContent() ? R.color.active_buttons_and_links_text_light : R.color.active_buttons_and_links_text_dark; String value = getString(actionResId); if (value.endsWith("...")) { @@ -709,7 +711,7 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement } public void openSelectionMode(int stringRes, int darkIcon, DialogInterface.OnClickListener listener, - EnumSet filter) { + EnumSet filter) { if (filter != null) { listAdapter.filterCategories(filter); } @@ -860,7 +862,7 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement @Override public View getChildView(final int groupPosition, final int childPosition, - boolean isLastChild, View convertView, ViewGroup parent) { + boolean isLastChild, View convertView, ViewGroup parent) { LocalIndexInfoViewHolder viewHolder; if (convertView == null) { LayoutInflater inflater = LayoutInflater.from(ctx); @@ -878,8 +880,8 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement private String getNameToDisplay(LocalIndexInfo child) { return child.getType() == LocalIndexType.VOICE_DATA ? FileNameTranslationHelper.getVoiceName(ctx, child.getFileName()) : FileNameTranslationHelper.getFileName(ctx, - ctx.getMyApplication().getResourceManager().getOsmandRegions(), - child.getFileName()); + ctx.getMyApplication().getResourceManager().getOsmandRegions(), + child.getFileName()); } @Override @@ -963,7 +965,7 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement return ctx.getString(R.string.download_roads_only_item); } else if (child.isBackupedData() && child.getFileName().endsWith(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT)) { return ctx.getString(R.string.download_wikipedia_maps); - } else if (child.isBackupedData() && child.getFileName().endsWith(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)) { + } else if (child.isBackupedData() && (SrtmDownloadItem.isSrtmFile(child.getFileName()))) { return ctx.getString(R.string.download_srtm_maps); } return ""; @@ -1029,6 +1031,10 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement builder.append(AndroidUtils.formatSize(ctx, child.getSize() * 1024l)); } + if (SrtmDownloadItem.isSRTMItem(child)) { + builder.append(" ").append(SrtmDownloadItem.getAbbreviationInScopes(ctx, child)); + } + if (!Algorithms.isEmpty(child.getDescription())) { if (builder.length() > 0) { builder.append(" • "); @@ -1150,5 +1156,4 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement private DownloadActivity getDownloadActivity() { return (DownloadActivity) getActivity(); } - } diff --git a/OsmAnd/src/net/osmand/plus/download/ui/SearchDialogFragment.java b/OsmAnd/src/net/osmand/plus/download/ui/SearchDialogFragment.java index ac9a87b32e..e6e3508ade 100644 --- a/OsmAnd/src/net/osmand/plus/download/ui/SearchDialogFragment.java +++ b/OsmAnd/src/net/osmand/plus/download/ui/SearchDialogFragment.java @@ -382,10 +382,10 @@ public class SearchDialogFragment extends DialogFragment implements DownloadEven if (obj instanceof IndexItem) { IndexItem item = (IndexItem) obj; viewHolder.setShowTypeInDesc(true); - viewHolder.bindIndexItem(item); + viewHolder.bindDownloadItem(item); } else { CityItem item = (CityItem) obj; - viewHolder.bindIndexItem(item); + viewHolder.bindDownloadItem(item); if (item.getIndexItem() == null) { new IndexItemResolverTask(viewHolder, item).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } @@ -461,7 +461,7 @@ public class SearchDialogFragment extends DialogFragment implements DownloadEven if (viewHolder != null) { if (indexItem != null) { cityItem.setIndexItem(indexItem); - viewHolder.bindIndexItem(indexItem, cityItem.getName()); + viewHolder.bindDownloadItem(indexItem, cityItem.getName()); } } } diff --git a/OsmAnd/src/net/osmand/plus/download/ui/UpdatesIndexFragment.java b/OsmAnd/src/net/osmand/plus/download/ui/UpdatesIndexFragment.java index ae0ab9b560..2cf1555428 100644 --- a/OsmAnd/src/net/osmand/plus/download/ui/UpdatesIndexFragment.java +++ b/OsmAnd/src/net/osmand/plus/download/ui/UpdatesIndexFragment.java @@ -410,7 +410,7 @@ public class UpdatesIndexFragment extends OsmAndListFragment implements Download holder.setShowRemoteDate(true); holder.setShowTypeInDesc(true); holder.setShowParentRegionName(true); - holder.bindIndexItem(getItem(position)); + holder.bindDownloadItem(getItem(position)); } return view; } diff --git a/OsmAnd/src/net/osmand/plus/helpers/FileNameTranslationHelper.java b/OsmAnd/src/net/osmand/plus/helpers/FileNameTranslationHelper.java index e366d1e8bb..203088d44e 100644 --- a/OsmAnd/src/net/osmand/plus/helpers/FileNameTranslationHelper.java +++ b/OsmAnd/src/net/osmand/plus/helpers/FileNameTranslationHelper.java @@ -1,9 +1,11 @@ package net.osmand.plus.helpers; import android.content.Context; + import net.osmand.IndexConstants; import net.osmand.PlatformUtil; import net.osmand.map.OsmandRegions; +import net.osmand.map.WorldRegion; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.download.DownloadResources; @@ -19,6 +21,7 @@ import java.lang.reflect.Field; public class FileNameTranslationHelper { private static final Log LOG = PlatformUtil.getLog(FileNameTranslationHelper.class); public static final String WIKI_NAME = "_wiki"; + public static final String WIKIVOYAGE_NAME = "_wikivoyage"; public static final String HILL_SHADE = "Hillshade"; public static final String SLOPE = "Slope"; public static final String SEA_DEPTH = "Depth_"; @@ -31,6 +34,8 @@ public class FileNameTranslationHelper { String basename = getBasename(fileName); if (basename.endsWith(WIKI_NAME)) { //wiki files return getWikiName(ctx, basename); + } else if (basename.endsWith(WIKIVOYAGE_NAME)) { + return getWikivoyageName(ctx, basename); } else if (fileName.endsWith("tts")) { //tts files return getVoiceName(ctx, fileName); } else if (fileName.endsWith(IndexConstants.FONT_INDEX_EXT)) { //otf files @@ -75,10 +80,10 @@ public class FileNameTranslationHelper { return ctx.getString(R.string.ltr_or_rtl_combine_via_space, locName, "(" + terrain + ")"); } - public static String getWikiName(Context ctx, String basename){ + public static String getWikiName(Context ctx, String basename) { String cutted = basename.substring(0, basename.indexOf("_wiki")); String wikiName = getStandardLangName(ctx, cutted); - if (wikiName == null){ + if (wikiName == null) { wikiName = cutted; } String wikiWord = ctx.getString(R.string.amenity_type_osmwiki); @@ -87,7 +92,18 @@ public class FileNameTranslationHelper { //removing word in "()" from recourse file return wikiName + " " + wikiWord.substring(0, index).trim(); } - return wikiName + " " + ctx.getString(R.string.amenity_type_osmwiki); + return wikiName + " " + ctx.getString(R.string.amenity_type_osmwiki); + } + + public static String getWikivoyageName(Context ctx, String basename) { + String formattedName = basename.substring(0, basename.indexOf(WIKIVOYAGE_NAME)).replaceAll("-", "").replaceAll("all", ""); + String wikiVoyageName = getSuggestedWikivoyageMaps(ctx, formattedName); + if (wikiVoyageName == null) { + wikiVoyageName = formattedName; + } + String wikiVoyageWord = ctx.getString(R.string.shared_string_wikivoyage); + + return ctx.getString(R.string.ltr_or_rtl_combine_via_space, wikiVoyageName, wikiVoyageWord); } public static String getVoiceName(Context ctx, String fileName) { @@ -196,8 +212,8 @@ public class FileNameTranslationHelper { return ctx.getString(R.string.lang_pl); } else if (filename.equalsIgnoreCase("Portuguese")) { return ctx.getString(R.string.lang_pt); - //} else if (filename.equalsIgnoreCase("Portuguese")) { - // return ctx.getString(R.string.lang_pt_br); + //} else if (filename.equalsIgnoreCase("Portuguese")) { + // return ctx.getString(R.string.lang_pt_br); } else if (filename.equalsIgnoreCase("Romanian")) { return ctx.getString(R.string.lang_ro); } else if (filename.equalsIgnoreCase("Russian")) { @@ -227,11 +243,11 @@ public class FileNameTranslationHelper { return ctx.getString(R.string.index_item_world_altitude_correction); } else if (basename.equals("world_basemap")) { return ctx.getString(R.string.index_item_world_basemap); - } else if (basename.equals("world_basemap_detailed")){ + } else if (basename.equals("world_basemap_detailed")) { return ctx.getString(R.string.index_item_world_basemap_detailed); } else if (basename.equals("world_bitcoin_payments")) { return ctx.getString(R.string.index_item_world_bitcoin_payments); - } else if (basename.equals(DownloadResources.WORLD_SEAMARKS_KEY) || + } else if (basename.equals(DownloadResources.WORLD_SEAMARKS_KEY) || basename.equals(DownloadResources.WORLD_SEAMARKS_OLD_KEY)) { return ctx.getString(R.string.index_item_world_seamarks); } else if (basename.equals("world_wikivoyage")) { @@ -245,4 +261,27 @@ public class FileNameTranslationHelper { } return null; } + + private static String getSuggestedWikivoyageMaps(Context ctx, String filename) { + if (WorldRegion.AFRICA_REGION_ID.equalsIgnoreCase(filename)) { + return ctx.getString(R.string.index_name_africa); + } else if (WorldRegion.AUSTRALIA_AND_OCEANIA_REGION_ID.replaceAll("-", "").equalsIgnoreCase(filename)) { + return ctx.getString(R.string.index_name_oceania); + } else if (WorldRegion.ASIA_REGION_ID.equalsIgnoreCase(filename)) { + return ctx.getString(R.string.index_name_asia); + } else if (WorldRegion.CENTRAL_AMERICA_REGION_ID.equalsIgnoreCase(filename)) { + return ctx.getString(R.string.index_name_central_america); + } else if (WorldRegion.EUROPE_REGION_ID.equalsIgnoreCase(filename)) { + return ctx.getString(R.string.index_name_europe); + } else if (WorldRegion.RUSSIA_REGION_ID.equalsIgnoreCase(filename)) { + return ctx.getString(R.string.index_name_russia); + } else if (WorldRegion.NORTH_AMERICA_REGION_ID.equalsIgnoreCase(filename)) { + return ctx.getString(R.string.index_name_north_america); + } else if (WorldRegion.SOUTH_AMERICA_REGION_ID.equalsIgnoreCase(filename)) { + return ctx.getString(R.string.index_name_south_america); + } else if (WorldRegion.ANTARCTICA_REGION_ID.equalsIgnoreCase(filename)) { + return ctx.getString(R.string.index_name_antarctica); + } + return null; + } } diff --git a/OsmAnd/src/net/osmand/plus/resources/IncrementalChangesManager.java b/OsmAnd/src/net/osmand/plus/resources/IncrementalChangesManager.java index 2f5ba258f0..565d300e47 100644 --- a/OsmAnd/src/net/osmand/plus/resources/IncrementalChangesManager.java +++ b/OsmAnd/src/net/osmand/plus/resources/IncrementalChangesManager.java @@ -1,12 +1,11 @@ package net.osmand.plus.resources; -import android.view.LayoutInflater; - import net.osmand.IndexConstants; import net.osmand.PlatformUtil; import net.osmand.binary.BinaryMapIndexReader; import net.osmand.osm.io.NetworkUtils; import net.osmand.plus.R; +import net.osmand.plus.download.SrtmDownloadItem; import net.osmand.util.Algorithms; import org.apache.commons.logging.Log; @@ -33,12 +32,11 @@ public class IncrementalChangesManager { private static final org.apache.commons.logging.Log log = PlatformUtil.getLog(IncrementalChangesManager.class); private ResourceManager resourceManager; private final Map regions = new ConcurrentHashMap(); - - + public IncrementalChangesManager(ResourceManager resourceManager) { this.resourceManager = resourceManager; } - + public List collectChangesFiles(File dir, String ext, List files) { if (dir.exists() && dir.canRead()) { File[] lf = dir.listFiles(); @@ -47,8 +45,8 @@ public class IncrementalChangesManager { } Set existingFiles = new HashSet(); for (File f : files) { - if(!f.getName().endsWith(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT) && - !f.getName().endsWith(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)) { + if (!f.getName().endsWith(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT) && + !SrtmDownloadItem.isSrtmFile(f.getName())) { existingFiles.add(Algorithms.getFileNameWithoutExtension(f)); } } @@ -71,7 +69,7 @@ public class IncrementalChangesManager { public synchronized void indexMainMap(File f, long dateCreated) { String nm = Algorithms.getFileNameWithoutExtension(f).toLowerCase(); RegionUpdateFiles regionUpdateFiles = regions.get(nm); - if(regionUpdateFiles == null) { + if (regionUpdateFiles == null) { regionUpdateFiles = new RegionUpdateFiles(nm); regions.put(nm, regionUpdateFiles); } @@ -98,7 +96,7 @@ public class IncrementalChangesManager { RegionUpdate monthRu = regionUpdateFiles.monthUpdates.get(month); while (it.hasNext()) { RegionUpdate ru = it.next(); - if(ru == null) { + if (ru == null) { continue; } if (ru.obfCreated <= dateCreated || @@ -114,58 +112,58 @@ public class IncrementalChangesManager { } } } - + public synchronized boolean index(File f, long dateCreated, BinaryMapIndexReader mapReader) { String index = Algorithms.getFileNameWithoutExtension(f).toLowerCase(); - if(index.length() <= 9 || index.charAt(index.length() - 9) != '_'){ + if (index.length() <= 9 || index.charAt(index.length() - 9) != '_') { return false; } String nm = index.substring(0, index.length() - 9); String date = index.substring(index.length() - 9 + 1); RegionUpdateFiles regionUpdateFiles = regions.get(nm); - if(regionUpdateFiles == null) { + if (regionUpdateFiles == null) { regionUpdateFiles = new RegionUpdateFiles(nm); regions.put(nm, regionUpdateFiles); } return regionUpdateFiles.addUpdate(date, f, dateCreated); } - + protected static String formatSize(long vl) { return (vl * 1000 / (1 << 20l)) / 1000.0f + ""; } - + public static long calculateSize(List list) { long l = 0; - for(IncrementalUpdate iu : list) { + for (IncrementalUpdate iu : list) { l += iu.containerSize; } return l; - } - + } + protected class RegionUpdate { protected File file; protected String date; - protected long obfCreated; + protected long obfCreated; } - + protected class RegionUpdateFiles { protected String nm; protected File mainFile; protected long mainFileInit; TreeMap> dayUpdates = new TreeMap>(); TreeMap monthUpdates = new TreeMap(); - + public RegionUpdateFiles(String nm) { this.nm = nm; } - + public boolean addUpdate(String date, File file, long dateCreated) { String monthYear = date.substring(0, 5); RegionUpdate ru = new RegionUpdate(); ru.date = date; ru.file = file; ru.obfCreated = dateCreated; - if(date.endsWith("00")) { + if (date.endsWith("00")) { monthUpdates.put(monthYear, ru); } else { List list = dayUpdates.get(monthYear); @@ -179,22 +177,21 @@ public class IncrementalChangesManager { } } - + public class IncrementalUpdateList { - public TreeMap updateByMonth = + public TreeMap updateByMonth = new TreeMap(); public String errorMessage; public RegionUpdateFiles updateFiles; - - + public boolean isPreferrableLimitForDayUpdates(String monthYearPart, List dayUpdates) { List lst = updateFiles.dayUpdates.get(monthYearPart); - if(lst == null || lst.size() < 10) { + if (lst == null || lst.size() < 10) { return true; } return false; } - + public List getItemsForUpdate() { Iterator it = updateByMonth.values().iterator(); List ll = new ArrayList(); @@ -208,7 +205,7 @@ public class IncrementalChangesManager { } else { // it causes problem when person doesn't restart application for 10 days so updates stop working // && isPreferrableLimitForDayUpdates(n.monthYearPart, n.getDayUpdates()) - if (n.isDayUpdateApplicable() ) { + if (n.isDayUpdateApplicable()) { ll.addAll(n.getDayUpdates()); } else if (n.isMonthUpdateApplicable()) { ll.addAll(n.getMonthUpdate()); @@ -234,51 +231,51 @@ public class IncrementalChangesManager { } } } - + protected static class IncrementalUpdateGroupByMonth { - public final String monthYearPart ; + public final String monthYearPart; public List dayUpdates = new ArrayList(); public IncrementalUpdate monthUpdate; - + public long calculateSizeMonthUpdates() { return calculateSize(getMonthUpdate()); } - + public long calculateSizeDayUpdates() { return calculateSize(getDayUpdates()); } - + public boolean isMonthUpdateApplicable() { return monthUpdate != null; } - + public boolean isDayUpdateApplicable() { boolean inLimits = dayUpdates.size() > 0 && dayUpdates.size() < 4; - if(!inLimits) { + if (!inLimits) { return false; } return true; } - + public List getMonthUpdate() { List ll = new ArrayList(); - if(monthUpdate == null) { + if (monthUpdate == null) { return ll; } ll.add(monthUpdate); - for(IncrementalUpdate iu : dayUpdates) { - if(iu.timestamp > monthUpdate.timestamp) { + for (IncrementalUpdate iu : dayUpdates) { + if (iu.timestamp > monthUpdate.timestamp) { ll.add(iu); } } return ll; } - + public List getDayUpdates() { return dayUpdates; } - - public IncrementalUpdateGroupByMonth(String monthYearPart ) { + + public IncrementalUpdateGroupByMonth(String monthYearPart) { this.monthYearPart = monthYearPart; } } @@ -300,7 +297,7 @@ public class IncrementalChangesManager { return "Update " + fileName + " " + sizeText + " MB " + date + ", timestamp: " + timestamp; } } - + private List getIncrementalUpdates(String file, long timestamp) throws IOException, XmlPullParserException { String url = URL + "?aosmc=true×tamp=" + timestamp + "&file=" + URLEncoder.encode(file); @@ -314,7 +311,7 @@ public class IncrementalChangesManager { int elements = 0; while (parser.next() != XmlPullParser.END_DOCUMENT) { if (parser.getEventType() == XmlPullParser.START_TAG) { - elements ++; + elements++; if (parser.getName().equals("update")) { IncrementalUpdate dt = new IncrementalUpdate(); dt.date = parser.getAttributeValue("", "updateDate"); @@ -332,21 +329,19 @@ public class IncrementalChangesManager { conn.disconnect(); return lst; } - - public IncrementalUpdateList getUpdatesByMonth(String fileName) { IncrementalUpdateList iul = new IncrementalUpdateList(); RegionUpdateFiles ruf = regions.get(fileName.toLowerCase()); iul.updateFiles = ruf; - if(ruf == null) { + if (ruf == null) { iul.errorMessage = resourceManager.getContext().getString(R.string.no_updates_available); return iul; } long timestamp = getTimestamp(ruf); try { List lst = getIncrementalUpdates(fileName, timestamp); - for(IncrementalUpdate iu : lst) { + for (IncrementalUpdate iu : lst) { iul.addUpdate(iu); } } catch (Exception e) { @@ -357,9 +352,9 @@ public class IncrementalChangesManager { return iul; } - public long getUpdatesSize(String fileName){ + public long getUpdatesSize(String fileName) { RegionUpdateFiles ruf = regions.get(fileName.toLowerCase()); - if(ruf == null) { + if (ruf == null) { return 0; } long size = 0; @@ -374,9 +369,9 @@ public class IncrementalChangesManager { return size; } - public void deleteUpdates(String fileName){ + public void deleteUpdates(String fileName) { RegionUpdateFiles ruf = regions.get(fileName.toLowerCase()); - if(ruf == null) { + if (ruf == null) { return; } for (List regionUpdates : ruf.dayUpdates.values()) { @@ -399,7 +394,7 @@ public class IncrementalChangesManager { public long getTimestamp(String fileName) { RegionUpdateFiles ruf = regions.get(fileName.toLowerCase()); - if(ruf == null) { + if (ruf == null) { return System.currentTimeMillis(); } return getTimestamp(ruf); @@ -407,7 +402,7 @@ public class IncrementalChangesManager { public long getMapTimestamp(String fileName) { RegionUpdateFiles ruf = regions.get(fileName.toLowerCase()); - if(ruf == null) { + if (ruf == null) { return System.currentTimeMillis(); } return ruf.mainFileInit; diff --git a/OsmAnd/src/net/osmand/plus/resources/ResourceManager.java b/OsmAnd/src/net/osmand/plus/resources/ResourceManager.java index e48e37878a..7263eab1d8 100644 --- a/OsmAnd/src/net/osmand/plus/resources/ResourceManager.java +++ b/OsmAnd/src/net/osmand/plus/resources/ResourceManager.java @@ -41,6 +41,7 @@ import net.osmand.plus.R; import net.osmand.plus.Version; import net.osmand.plus.download.DownloadOsmandIndexesHelper; import net.osmand.plus.download.DownloadOsmandIndexesHelper.AssetEntry; +import net.osmand.plus.download.SrtmDownloadItem; import net.osmand.plus.inapp.InAppPurchaseHelper; import net.osmand.plus.render.MapRenderRepositories; import net.osmand.plus.render.NativeOsmandLibrary; @@ -78,11 +79,11 @@ import java.util.concurrent.ConcurrentHashMap; import static net.osmand.IndexConstants.VOICE_INDEX_DIR; /** - * Resource manager is responsible to work with all resources + * Resource manager is responsible to work with all resources * that could consume memory (especially with file resources). * Such as indexes, tiles. * Also it is responsible to create cache for that resources if they - * can't be loaded fully into memory & clear them on request. + * can't be loaded fully into memory & clear them on request. */ public class ResourceManager { @@ -91,10 +92,10 @@ public class ResourceManager { public static final String DEFAULT_WIKIVOYAGE_TRAVEL_OBF = "Default_wikivoyage.travel.obf"; private static final Log log = PlatformUtil.getLog(ResourceManager.class); - + protected static ResourceManager manager = null; - protected File dirWithTiles ; + protected File dirWithTiles; private List tilesCacheList = new ArrayList<>(); private BitmapTilesCache bitmapTilesCache; @@ -115,21 +116,22 @@ public class ResourceManager { STREET_LOOKUP, TRANSPORT, ADDRESS, - QUICK_SEARCH, + QUICK_SEARCH, ROUTING, TRANSPORT_ROUTING } - + public static class BinaryMapReaderResource { private BinaryMapIndexReader initialReader; private File filename; private List readers = new ArrayList<>(BinaryMapReaderResourceType.values().length); private boolean useForRouting; private boolean useForPublicTransport; + public BinaryMapReaderResource(File f, BinaryMapIndexReader initialReader) { this.filename = f; this.initialReader = initialReader; - while(readers.size() < BinaryMapReaderResourceType.values().length) { + while (readers.size() < BinaryMapReaderResourceType.values().length) { readers.add(null); } } @@ -173,7 +175,7 @@ public class ResourceManager { } initialReader = null; } - + public boolean isClosed() { return initialReader == null; } @@ -189,7 +191,7 @@ public class ResourceManager { public void setUseForRouting(boolean useForRouting) { this.useForRouting = useForRouting; } - + public boolean isUseForRouting() { return useForRouting; } @@ -202,34 +204,32 @@ public class ResourceManager { this.useForPublicTransport = useForPublicTransport; } } - + protected final Map fileReaders = new ConcurrentHashMap(); - - + private final Map addressMap = new ConcurrentHashMap(); - protected final Map amenityRepositories = new ConcurrentHashMap(); -// protected final Map routingMapFiles = new ConcurrentHashMap(); + protected final Map amenityRepositories = new ConcurrentHashMap(); + // protected final Map routingMapFiles = new ConcurrentHashMap(); protected final Map transportRepositories = new ConcurrentHashMap(); protected final Map travelRepositories = new ConcurrentHashMap(); protected final Map indexFileNames = new ConcurrentHashMap(); protected final Map basemapFileNames = new ConcurrentHashMap(); - - + protected final IncrementalChangesManager changesManager = new IncrementalChangesManager(this); - + protected final MapRenderRepositories renderer; protected final MapTileDownloader tileDownloader; - + public final AsyncLoadingThread asyncLoadingThread = new AsyncLoadingThread(this); - + private HandlerThread renderingBufferImageThread; - + protected boolean internetIsNotAccessible = false; private boolean depthContours; - + public ResourceManager(OsmandApplication context) { - + this.context = context; this.renderer = new MapRenderRepositories(context); @@ -271,7 +271,7 @@ public class ResourceManager { public MapTileDownloader getMapTileDownloader() { return tileDownloader; } - + public HandlerThread getRenderingBufferImageThread() { return renderingBufferImageThread; } @@ -293,17 +293,17 @@ public class ResourceManager { // ".nomedia" indicates there are no pictures and no music to list in this dir for the Gallery app try { context.getAppPath(".nomedia").createNewFile(); //$NON-NLS-1$ - } catch( Exception e ) { + } catch (Exception e) { } for (TilesCache tilesCache : tilesCacheList) { tilesCache.setDirWithTiles(dirWithTiles); } } - + public java.text.DateFormat getDateFormat() { return DateFormat.getDateFormat(context); } - + public OsmandApplication getContext() { return context; } @@ -323,7 +323,7 @@ public class ResourceManager { return null; } - public synchronized void tileDownloaded(DownloadRequest request){ + public synchronized void tileDownloaded(DownloadRequest request) { if (request instanceof TileLoadDownloadRequest) { TileLoadDownloadRequest req = ((TileLoadDownloadRequest) request); TilesCache cache = getTilesCache(req.tileSource); @@ -332,13 +332,13 @@ public class ResourceManager { } } } - + public synchronized boolean tileExistOnFileSystem(String file, ITileSource map, int x, int y, int zoom) { TilesCache cache = getTilesCache(map); return cache != null && cache.tileExistOnFileSystem(file, map, x, y, zoom); } - - public void clearTileForMap(String file, ITileSource map, int x, int y, int zoom){ + + public void clearTileForMap(String file, ITileSource map, int x, int y, int zoom) { TilesCache cache = getTilesCache(map); if (cache != null) { cache.getTileForMap(file, map, x, y, zoom, true, false, true, true); @@ -376,7 +376,7 @@ public class ResourceManager { ////////////////////////////////////////////// Working with indexes //////////////////////////////////////////////// - public List reloadIndexesOnStart(AppInitializer progress, List warnings){ + public List reloadIndexesOnStart(AppInitializer progress, List warnings) { close(); // check we have some assets to copy to sdcard warnings.addAll(checkAssets(progress, false)); @@ -429,7 +429,7 @@ public class ResourceManager { return warnings; } - public List indexFontFiles(IProgress progress){ + public List indexFontFiles(IProgress progress) { File file = context.getAppPath(IndexConstants.FONT_INDEX_DIR); file.mkdirs(); List warnings = new ArrayList(); @@ -473,10 +473,10 @@ public class ResourceManager { log.error("Error while loading tts files from assets", e); } } - + public List checkAssets(IProgress progress, boolean forceUpdate) { String fv = Version.getFullVersion(context); - if(context.getAppInitializer().isAppVersionChanged()) { + if (context.getAppInitializer().isAppVersionChanged()) { copyMissingJSAssets(); } if (!fv.equalsIgnoreCase(context.getSettings().PREVIOUS_INSTALLED_VERSION.get()) || forceUpdate) { @@ -509,7 +509,7 @@ public class ResourceManager { } return Collections.emptyList(); } - + private void copyRegionsBoundaries() { try { File file = context.getAppPath("regions.ocbf"); @@ -522,7 +522,7 @@ public class ResourceManager { log.error(e.getMessage(), e); } } - + private void copyPoiTypes() { try { File file = context.getAppPath(IndexConstants.SETTINGS_DIR + "poi_types.xml"); @@ -540,6 +540,7 @@ public class ResourceManager { private final static String ASSET_COPY_MODE__overwriteOnlyIfExists = "overwriteOnlyIfExists"; private final static String ASSET_COPY_MODE__alwaysOverwriteOrCopy = "alwaysOverwriteOrCopy"; private final static String ASSET_COPY_MODE__copyOnlyIfDoesNotExist = "copyOnlyIfDoesNotExist"; + private void unpackBundledAssets(AssetManager assetManager, File appDataDir, IProgress progress, boolean isFirstInstall) throws IOException, XmlPullParserException { List assetEntries = DownloadOsmandIndexesHelper.getBundledAssets(assetManager); for (AssetEntry asset : assetEntries) { @@ -581,7 +582,7 @@ public class ResourceManager { } public static void copyAssets(AssetManager assetManager, String assetName, File file) throws IOException { - if(file.exists()){ + if (file.exists()) { Algorithms.removeAllFiles(file); } file.getParentFile().mkdirs(); @@ -593,9 +594,9 @@ public class ResourceManager { } private List collectFiles(File dir, String ext, List files) { - if(dir.exists() && dir.canRead()) { + if (dir.exists() && dir.canRead()) { File[] lf = dir.listFiles(); - if(lf == null || lf.length == 0) { + if (lf == null || lf.length == 0) { return files; } for (File f : lf) { @@ -606,12 +607,10 @@ public class ResourceManager { } return files; } - - - + private void renameRoadsFiles(ArrayList files, File roadsPath) { Iterator it = files.iterator(); - while(it.hasNext()) { + while (it.hasNext()) { File f = it.next(); if (f.getName().endsWith("-roads" + IndexConstants.BINARY_MAP_INDEX_EXT)) { f.renameTo(new File(roadsPath, f.getName().replace("-roads" + IndexConstants.BINARY_MAP_INDEX_EXT, @@ -632,7 +631,7 @@ public class ResourceManager { File appPath = context.getAppPath(null); File roadsPath = context.getAppPath(IndexConstants.ROADS_INDEX_DIR); roadsPath.mkdirs(); - + collectFiles(appPath, IndexConstants.BINARY_MAP_INDEX_EXT, files); renameRoadsFiles(files, roadsPath); collectFiles(roadsPath, IndexConstants.BINARY_MAP_INDEX_EXT, files); @@ -645,7 +644,7 @@ public class ResourceManager { if (OsmandPlugin.getEnabledPlugin(SRTMPlugin.class) != null || InAppPurchaseHelper.isContourLinesPurchased(context)) { collectFiles(context.getAppPath(IndexConstants.SRTM_INDEX_DIR), IndexConstants.BINARY_MAP_INDEX_EXT, files); } - + changesManager.collectChangesFiles(context.getAppPath(IndexConstants.LIVE_INDEX_DIR), IndexConstants.BINARY_MAP_INDEX_EXT, files); Collections.sort(files, Algorithms.getFileVersionComparator()); @@ -703,7 +702,7 @@ public class ResourceManager { log.error(String.format("File %s could not be read", f.getName()), e); } boolean wikiMap = (f.getName().contains("_wiki") || f.getName().contains(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT)); - boolean srtmMap = f.getName().contains(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT); + boolean srtmMap = SrtmDownloadItem.containsSrtmExtension(f.getName()); if (mapReader == null || (!Version.isPaidVersion(context) && wikiMap && !f.getName().equals(DEFAULT_WIKIVOYAGE_TRAVEL_OBF))) { warnings.add(MessageFormat.format(context.getString(R.string.version_index_is_not_supported), f.getName())); //$NON-NLS-1$ } else { @@ -714,9 +713,9 @@ public class ResourceManager { if (dateCreated == 0) { dateCreated = f.lastModified(); } - if(f.getParentFile().getName().equals(liveDir.getName())) { + if (f.getParentFile().getName().equals(liveDir.getName())) { boolean toUse = changesManager.index(f, dateCreated, mapReader); - if(!toUse) { + if (!toUse) { try { mapReader.close(); } catch (IOException e) { @@ -724,7 +723,7 @@ public class ResourceManager { } continue; } - } else if(!wikiMap && !srtmMap) { + } else if (!wikiMap && !srtmMap) { changesManager.indexMainMap(f, dateCreated); } indexFileNames.put(f.getName(), dateFormat.format(dateCreated)); //$NON-NLS-1$ @@ -733,7 +732,7 @@ public class ResourceManager { } renderer.initializeNewResource(progress, f, mapReader); BinaryMapReaderResource resource = new BinaryMapReaderResource(f, mapReader); - if (collectTravelFiles(resource)){ + if (collectTravelFiles(resource)) { //travel files are indexed continue; } @@ -746,7 +745,7 @@ public class ResourceManager { transportRepositories.put(f.getName(), resource); } // disable osmc for routing temporarily due to some bugs - if (mapReader.containsRouteData() && (!f.getParentFile().equals(liveDir) || + if (mapReader.containsRouteData() && (!f.getParentFile().equals(liveDir) || context.getSettings().USE_OSM_LIVE_FOR_ROUTING.get())) { resource.setUseForRouting(true); } @@ -789,7 +788,7 @@ public class ResourceManager { } } Iterator>> it = toAddPoiTypes.entrySet().iterator(); - while(it.hasNext()) { + while (it.hasNext()) { Entry> next = it.next(); PoiCategory category = next.getKey(); category.addExtraPoiTypes(next.getValue()); @@ -839,7 +838,7 @@ public class ResourceManager { } private boolean collectTravelFiles(BinaryMapReaderResource resource) { - if (resource.getFileName().contains(IndexConstants.BINARY_TRAVEL_GUIDE_MAP_INDEX_EXT)){ + if (resource.getFileName().contains(IndexConstants.BINARY_TRAVEL_GUIDE_MAP_INDEX_EXT)) { travelRepositories.put(resource.getFileName(), resource); return true; } @@ -855,7 +854,7 @@ public class ResourceManager { } } } - + ////////////////////////////////////////////// Working with amenities //////////////////////////////////////////////// public List getAmenityRepositories() { @@ -872,7 +871,7 @@ public class ResourceManager { } public List searchAmenities(SearchPoiTypeFilter filter, - double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, final ResultMatcher matcher) { + double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, final ResultMatcher matcher) { final List amenities = new ArrayList(); searchAmenitiesInProgress = true; try { @@ -901,8 +900,8 @@ public class ResourceManager { return amenities; } - public List searchAmenitiesOnThePath(List locations, double radius, SearchPoiTypeFilter filter, - ResultMatcher matcher) { + public List searchAmenitiesOnThePath(List locations, double radius, SearchPoiTypeFilter filter, + ResultMatcher matcher) { searchAmenitiesInProgress = true; final List amenities = new ArrayList(); try { @@ -921,9 +920,9 @@ public class ResourceManager { if (!filter.isEmpty()) { for (AmenityIndexRepository index : getAmenityRepositories()) { if (index.checkContainsInt( - MapUtils.get31TileNumberY(topLatitude), - MapUtils.get31TileNumberX(leftLongitude), - MapUtils.get31TileNumberY(bottomLatitude), + MapUtils.get31TileNumberY(topLatitude), + MapUtils.get31TileNumberX(leftLongitude), + MapUtils.get31TileNumberY(bottomLatitude), MapUtils.get31TileNumberX(rightLongitude))) { repos.add(index); } @@ -931,7 +930,7 @@ public class ResourceManager { if (!repos.isEmpty()) { for (AmenityIndexRepository r : repos) { List res = r.searchAmenitiesOnThePath(locations, radius, filter, matcher); - if(res != null) { + if (res != null) { amenities.addAll(res); } } @@ -943,12 +942,11 @@ public class ResourceManager { } return amenities; } - - - public boolean containsAmenityRepositoryToSearch(boolean searchByName){ + + public boolean containsAmenityRepositoryToSearch(boolean searchByName) { for (AmenityIndexRepository index : getAmenityRepositories()) { - if(searchByName){ - if(index instanceof AmenityIndexRepositoryBinary){ + if (searchByName) { + if (index instanceof AmenityIndexRepositoryBinary) { return true; } } else { @@ -957,10 +955,10 @@ public class ResourceManager { } return false; } - + public List searchAmenitiesByName(String searchQuery, - double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, - double lat, double lon, ResultMatcher matcher) { + double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, + double lat, double lon, ResultMatcher matcher) { List amenities = new ArrayList(); List list = new ArrayList(); int left = MapUtils.get31TileNumberX(leftLongitude); @@ -973,16 +971,16 @@ public class ResourceManager { } if (index instanceof AmenityIndexRepositoryBinary) { if (index.checkContainsInt(top, left, bottom, right)) { - if(index.checkContains(lat, lon)){ + if (index.checkContains(lat, lon)) { list.add(0, (AmenityIndexRepositoryBinary) index); } else { list.add((AmenityIndexRepositoryBinary) index); } - + } } } - + // Not using boundares results in very slow initial search if user has many maps installed // int left = 0; // int top = 0; @@ -1000,7 +998,7 @@ public class ResourceManager { return amenities; } - + public Map> searchAmenityCategoriesByName(String searchQuery, double lat, double lon) { Map> map = new LinkedHashMap>(); for (AmenityIndexRepository index : getAmenityRepositories()) { @@ -1016,17 +1014,17 @@ public class ResourceManager { public AmenityIndexRepositoryBinary getAmenityRepositoryByFileName(String filename) { return (AmenityIndexRepositoryBinary) amenityRepositories.get(filename); } - + ////////////////////////////////////////////// Working with address /////////////////////////////////////////// - - public RegionAddressRepository getRegionRepository(String name){ + + public RegionAddressRepository getRegionRepository(String name) { return addressMap.get(name); } - - public Collection getAddressRepositories(){ + + public Collection getAddressRepositories() { return addressMap.values(); } - + public Collection getFileReaders() { List fileNames = new ArrayList<>(fileReaders.keySet()); Collections.sort(fileNames, Algorithms.getStringVersionComparator()); @@ -1039,8 +1037,7 @@ public class ResourceManager { } return res; } - - + ////////////////////////////////////////////// Working with transport //////////////////////////////////////////////// private List getTransportRepositories(double topLat, double leftLon, double bottomLat, double rightLon) { @@ -1059,7 +1056,7 @@ public class ResourceManager { public List searchTransportSync(double topLat, double leftLon, double bottomLat, double rightLon, - ResultMatcher matcher) throws IOException { + ResultMatcher matcher) throws IOException { TransportStopsRouteReader readers = new TransportStopsRouteReader(getTransportRepositories(topLat, leftLon, bottomLat, rightLon)); List stops = new ArrayList<>(); @@ -1076,7 +1073,7 @@ public class ResourceManager { public List getRoutesForStop(TransportStop stop) { List rts = stop.getRoutes(); - if(rts != null) { + if (rts != null) { return rts; } return Collections.emptyList(); @@ -1086,26 +1083,26 @@ public class ResourceManager { public boolean updateRenderedMapNeeded(RotatedTileBox rotatedTileBox, DrawSettings drawSettings) { return renderer.updateMapIsNeeded(rotatedTileBox, drawSettings); } - - public void updateRendererMap(RotatedTileBox rotatedTileBox, OnMapLoadedListener mapLoadedListener){ + + public void updateRendererMap(RotatedTileBox rotatedTileBox, OnMapLoadedListener mapLoadedListener) { renderer.interruptLoadingMap(); asyncLoadingThread.requestToLoadMap(new MapLoadRequest(rotatedTileBox, mapLoadedListener)); } - - public void interruptRendering(){ + + public void interruptRendering() { renderer.interruptLoadingMap(); } - + public boolean isSearchAmenitiesInProgress() { return searchAmenitiesInProgress; } - + public MapRenderRepositories getRenderer() { return renderer; } - + ////////////////////////////////////////////// Closing methods //////////////////////////////////////////////// - + public void closeFile(String fileName) { amenityRepositories.remove(fileName); addressMap.remove(fileName); @@ -1114,12 +1111,12 @@ public class ResourceManager { travelRepositories.remove(fileName); renderer.closeConnection(fileName); BinaryMapReaderResource resource = fileReaders.remove(fileName); - if(resource != null) { + if (resource != null) { resource.close(); } - } + } - public synchronized void close(){ + public synchronized void close() { for (TilesCache tc : tilesCacheList) { tc.close(); } @@ -1130,7 +1127,7 @@ public class ResourceManager { travelRepositories.clear(); addressMap.clear(); amenityRepositories.clear(); - for(BinaryMapReaderResource res : fileReaders.values()) { + for (BinaryMapReaderResource res : fileReaders.values()) { res.close(); } fileReaders.clear(); @@ -1154,7 +1151,7 @@ public class ResourceManager { Collection fileReaders = getFileReaders(); List readers = new ArrayList<>(fileReaders.size()); for (BinaryMapReaderResource r : fileReaders) { - if (r.isUseForPublicTransport()) { + if (r.isUseForPublicTransport()) { BinaryMapIndexReader reader = r.getReader(BinaryMapReaderResourceType.TRANSPORT_ROUTING); if (reader != null) { readers.add(reader); @@ -1182,9 +1179,8 @@ public class ResourceManager { public Map getIndexFileNames() { return new LinkedHashMap(indexFileNames); } - - - public boolean containsBasemap(){ + + public boolean containsBasemap() { return !basemapFileNames.isEmpty(); } @@ -1218,13 +1214,13 @@ public class ResourceManager { } return map; } - + public synchronized void reloadTilesFromFS() { for (TilesCache tc : tilesCacheList) { tc.tilesOnFS.clear(); } } - + /// On low memory method /// public void onLowMemory() { log.info("On low memory"); @@ -1233,10 +1229,10 @@ public class ResourceManager { r.clearCache(); } renderer.clearCache(); - + System.gc(); } - + public GeoidAltitudeCorrection getGeoidAltitudeCorrection() { return geoidAltitudeCorrection; } @@ -1251,7 +1247,7 @@ public class ResourceManager { tc.clearTiles(); } } - + public IncrementalChangesManager getChangesManager() { return changesManager; } diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/FileSettingsItem.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/FileSettingsItem.java index 88c72beddc..53b6ec0500 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/FileSettingsItem.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/FileSettingsItem.java @@ -7,6 +7,7 @@ import androidx.annotation.Nullable; import net.osmand.IndexConstants; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; +import net.osmand.plus.download.SrtmDownloadItem; import net.osmand.util.Algorithms; import org.json.JSONException; @@ -92,7 +93,7 @@ public class FileSettingsItem extends StreamSettingsItem { case OTHER: break; case SRTM_MAP: - if (name.endsWith(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)) { + if (SrtmDownloadItem.isSrtmFile(name)) { return subtype; } break; @@ -257,6 +258,8 @@ public class FileSettingsItem extends StreamSettingsItem { prefix = oldPath.substring(0, oldPath.lastIndexOf(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT)); } else if (oldPath.endsWith(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)) { prefix = oldPath.substring(0, oldPath.lastIndexOf(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)); + } else if (oldPath.endsWith(IndexConstants.BINARY_SRTM_FEET_MAP_INDEX_EXT)) { + prefix = oldPath.substring(0, oldPath.lastIndexOf(IndexConstants.BINARY_SRTM_FEET_MAP_INDEX_EXT)); } else if (oldPath.endsWith(IndexConstants.BINARY_ROAD_MAP_INDEX_EXT)) { prefix = oldPath.substring(0, oldPath.lastIndexOf(IndexConstants.BINARY_ROAD_MAP_INDEX_EXT)); } else { diff --git a/OsmAnd/src/net/osmand/plus/settings/datastorage/DataStorageHelper.java b/OsmAnd/src/net/osmand/plus/settings/datastorage/DataStorageHelper.java index 67fd73897e..763f8ff996 100644 --- a/OsmAnd/src/net/osmand/plus/settings/datastorage/DataStorageHelper.java +++ b/OsmAnd/src/net/osmand/plus/settings/datastorage/DataStorageHelper.java @@ -200,7 +200,7 @@ public class DataStorageHelper { terrainMemory = MemoryItem.builder() .setKey(TERRAIN_MEMORY) - .setExtensions(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT) + .setExtensions(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT, IndexConstants.BINARY_SRTM_FEET_MAP_INDEX_EXT) .setDirectories( createDirectory(SRTM_INDEX_DIR, true, EXTENSIONS, true), createDirectory(TILES_INDEX_DIR, false, PREFIX, false)) @@ -323,7 +323,7 @@ public class DataStorageHelper { public interface UpdateMemoryInfoUIAdapter { void onMemoryInfoUpdate(); - + void onFinishUpdating(String tag); } diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/BaseSettingsFragment.java b/OsmAnd/src/net/osmand/plus/settings/fragments/BaseSettingsFragment.java index 05c4c7e323..73c62eacfe 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/BaseSettingsFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/BaseSettingsFragment.java @@ -492,8 +492,7 @@ public abstract class BaseSettingsFragment extends PreferenceFragmentCompat impl } }); if (closeButton instanceof ImageView) { - UiUtilities.rotateImageByLayoutDirection( - (ImageView) closeButton, AndroidUtils.getLayoutDirection(app)); + UiUtilities.rotateImageByLayoutDirection((ImageView) closeButton); } } diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/ExportItemsBottomSheet.java b/OsmAnd/src/net/osmand/plus/settings/fragments/ExportItemsBottomSheet.java index dfe3771416..5e4b4f0449 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/ExportItemsBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/ExportItemsBottomSheet.java @@ -36,6 +36,7 @@ import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithCompoundButton.Bu import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription; import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem; import net.osmand.plus.base.bottomsheetmenu.simpleitems.SimpleDividerItem; +import net.osmand.plus.download.SrtmDownloadItem; import net.osmand.plus.helpers.AvoidSpecificRoads.AvoidRoadInfo; import net.osmand.plus.helpers.FileNameTranslationHelper; import net.osmand.plus.helpers.GpxUiHelper; @@ -530,7 +531,7 @@ public class ExportItemsBottomSheet extends MenuBottomSheetDialogFragment { return getString(R.string.download_roads_only_item); } else if (file.getName().endsWith(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT)) { return getString(R.string.download_wikipedia_maps); - } else if (file.getName().endsWith(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)) { + } else if (SrtmDownloadItem.isSrtmFile(file.getName())) { return getString(R.string.download_srtm_maps); } else if (file.getName().endsWith(IndexConstants.BINARY_MAP_INDEX_EXT)) { return getString(R.string.download_regular_maps); diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/PurchasesFragment.java b/OsmAnd/src/net/osmand/plus/settings/fragments/PurchasesFragment.java index 461f51e14d..9c60348d65 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/PurchasesFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/PurchasesFragment.java @@ -10,6 +10,11 @@ import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; + import com.google.android.material.appbar.AppBarLayout; import net.osmand.AndroidUtils; @@ -30,11 +35,6 @@ import net.osmand.util.Algorithms; import org.apache.commons.logging.Log; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.fragment.app.FragmentActivity; -import androidx.fragment.app.FragmentManager; - public class PurchasesFragment extends BaseOsmAndFragment implements InAppPurchaseListener, OnFragmentInteractionListener { private static final Log log = PlatformUtil.getLog(PurchasesFragment.class); @@ -152,6 +152,7 @@ public class PurchasesFragment extends BaseOsmAndFragment implements InAppPurcha } }); ImageButton backButton = toolbar.findViewById(R.id.close_button); + UiUtilities.rotateImageByLayoutDirection(backButton); backButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -197,9 +198,7 @@ public class PurchasesFragment extends BaseOsmAndFragment implements InAppPurcha @Override public void onSearchResult(CountrySelectionFragment.CountryItem name) { - if (subscriptionsCard != null) { - subscriptionsCard.onSupportRegionSelected(name); - } + } @Override diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/SubscriptionsCard.java b/OsmAnd/src/net/osmand/plus/settings/fragments/SubscriptionsCard.java index 6b7ba26980..0957969ccd 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/SubscriptionsCard.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/SubscriptionsCard.java @@ -5,30 +5,26 @@ import android.net.Uri; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; -import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; import net.osmand.AndroidUtils; import net.osmand.plus.R; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.helpers.AndroidUiHelper; import net.osmand.plus.inapp.InAppPurchaseHelper; -import net.osmand.plus.liveupdates.CountrySelectionFragment; import net.osmand.plus.liveupdates.LiveUpdatesFragment; import net.osmand.plus.liveupdates.OsmLiveActivity; import net.osmand.plus.routepreparationmenu.cards.BaseCard; -import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.util.Algorithms; -import androidx.annotation.NonNull; -import androidx.fragment.app.Fragment; - public class SubscriptionsCard extends BaseCard { private static final String PLAY_STORE_SUBSCRIPTION_URL = "https://play.google.com/store/account/subscriptions"; private static final String PLAY_STORE_SUBSCRIPTION_DEEPLINK_URL = "https://play.google.com/store/account/subscriptions?sku=%s&package=%s"; private Fragment target; - private CountrySelectionFragment countrySelectionFragment = new CountrySelectionFragment(); private SubscriptionsListCard subscriptionsListCard; private InAppPurchaseHelper purchaseHelper; @@ -54,7 +50,6 @@ public class SubscriptionsCard extends BaseCard { } updateSubscriptionsListCard(); - setupSupportRegion(); LinearLayout reportContainer = view.findViewById(R.id.report_container); reportContainer.setOnClickListener(new View.OnClickListener() { @@ -99,26 +94,6 @@ public class SubscriptionsCard extends BaseCard { } } - private void setupSupportRegion() { - String region = LiveUpdatesFragment.getSupportRegionName(app, purchaseHelper); - String header = LiveUpdatesFragment.getSupportRegionHeader(app, region); - TextView supportRegionHeader = view.findViewById(R.id.support_region_header); - TextView supportRegion = view.findViewById(R.id.support_region); - supportRegionHeader.setText(header); - supportRegion.setText(region); - - View supportRegionContainer = view.findViewById(R.id.support_region_container); - supportRegionContainer.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - CountrySelectionFragment countryCountrySelectionFragment = countrySelectionFragment; - countryCountrySelectionFragment.show(target.getChildFragmentManager(), CountrySelectionFragment.TAG); - } - }); - - countrySelectionFragment.initCountries(app); - } - private String getSubscriptionUrl() { InAppPurchaseHelper purchaseHelper = app.getInAppPurchaseHelper(); if (purchaseHelper != null && purchaseHelper.getFullVersion() != null) { @@ -129,17 +104,4 @@ public class SubscriptionsCard extends BaseCard { return PLAY_STORE_SUBSCRIPTION_URL; } } - - public void onSupportRegionSelected(CountrySelectionFragment.CountryItem selectedCountryItem) { - String countryName = selectedCountryItem != null ? selectedCountryItem.getLocalName() : ""; - String countryDownloadName = selectedCountryItem != null ? - selectedCountryItem.getDownloadName() : OsmandSettings.BILLING_USER_DONATION_WORLD_PARAMETER; - - TextView supportRegionHeader = view.findViewById(R.id.support_region_header); - TextView supportRegion = view.findViewById(R.id.support_region); - supportRegionHeader.setText(LiveUpdatesFragment.getSupportRegionHeader(app, countryName)); - supportRegion.setText(countryName); - app.getSettings().BILLING_USER_COUNTRY.set(countryName); - app.getSettings().BILLING_USER_COUNTRY_DOWNLOAD_NAME.set(countryDownloadName); - } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/TroubleshootingOrPurchasingCard.java b/OsmAnd/src/net/osmand/plus/settings/fragments/TroubleshootingOrPurchasingCard.java index f0ed9d8968..6758292334 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/TroubleshootingOrPurchasingCard.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/TroubleshootingOrPurchasingCard.java @@ -7,20 +7,22 @@ import android.text.Spannable; import android.text.SpannableString; import android.text.style.StyleSpan; import android.view.View; +import android.widget.ImageView; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.cardview.widget.CardView; +import androidx.core.content.ContextCompat; + import net.osmand.AndroidUtils; import net.osmand.plus.R; +import net.osmand.plus.UiUtilities; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.chooseplan.ChoosePlanDialogFragment; import net.osmand.plus.inapp.InAppPurchaseHelper; import net.osmand.plus.routepreparationmenu.cards.BaseCard; import net.osmand.plus.wikipedia.WikipediaDialogFragment; -import androidx.annotation.NonNull; -import androidx.cardview.widget.CardView; -import androidx.core.content.ContextCompat; - public class TroubleshootingOrPurchasingCard extends BaseCard { private static final String OSMAND_NEW_DEVICE_URL = "https://docs.osmand.net/en/main@latest/osmand/purchases#new-device--new-account"; @@ -74,6 +76,9 @@ public class TroubleshootingOrPurchasingCard extends BaseCard { } else { AndroidUtils.setBackground(mapActivity, getItButton, nightMode, R.drawable.btn_unstroked_light, R.drawable.btn_unstroked_dark); } + + ImageView getItArrow = view.findViewById(R.id.additional_button_icon); + UiUtilities.rotateImageByLayoutDirection(getItArrow); } } diff --git a/OsmAnd/src/net/osmand/plus/widgets/multistatetoggle/MultiStateToggleButton.java b/OsmAnd/src/net/osmand/plus/widgets/multistatetoggle/MultiStateToggleButton.java index 2207933acc..f3d2e5aafb 100644 --- a/OsmAnd/src/net/osmand/plus/widgets/multistatetoggle/MultiStateToggleButton.java +++ b/OsmAnd/src/net/osmand/plus/widgets/multistatetoggle/MultiStateToggleButton.java @@ -20,6 +20,8 @@ import net.osmand.plus.widgets.multistatetoggle.RadioItem.OnRadioItemClickListen import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; +import java.util.Collection; import java.util.List; public abstract class MultiStateToggleButton<_Radio extends RadioItem> { @@ -45,6 +47,13 @@ public abstract class MultiStateToggleButton<_Radio extends RadioItem> { this.nightMode = nightMode; } + public void setItems(Collection<_Radio> radioItems) { + if (radioItems == null || radioItems.size() < 2) return; + items.clear(); + items.addAll(radioItems); + initView(); + } + @SafeVarargs public final void setItems(@NonNull _Radio firstBtn, @NonNull _Radio secondBtn,