Merge pull request #8918 from osmandapp/create_custom_poi

custom poi types cache db
This commit is contained in:
vshcherb 2020-05-18 15:23:05 +02:00 committed by GitHub
commit 392d69dd66
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 251 additions and 64 deletions

View file

@ -1424,7 +1424,7 @@ public class BinaryMapIndexReader {
return addressIndexes;
}
protected List<PoiRegion> getPoiIndexes() {
public List<PoiRegion> getPoiIndexes() {
return poiIndexes;
}

View file

@ -229,17 +229,7 @@ public class BinaryMapPoiReaderAdapter {
region.subcategories.add(new ArrayList<String>());
break;
case OsmandOdb.OsmAndCategoryTable.SUBCATEGORIES_FIELD_NUMBER:
String subCat = codedIS.readString().intern();
PoiCategory lastCat = poiTypes.getPoiCategoryByName(region.categories.get(region.categories.size() - 1));
PoiType poiType = new PoiType(MapPoiTypes.getDefault(), lastCat, null, subCat);
List<String> filters = new ArrayList<>();
for (PoiType poi : lastCat.getPoiTypes()) {
filters.add(poi.getKeyName());
}
if (!filters.contains(subCat)) {
lastCat.getPoiTypes().add(poiType);
}
region.subcategories.get(region.subcategories.size() - 1).add(subCat);
region.subcategories.get(region.subcategories.size() - 1).add(codedIS.readString().intern());
break;
default:
skipUnknownField(t);

View file

@ -918,11 +918,4 @@ public class MapPoiTypes {
return pat.isText();
}
}
}

View file

@ -69,5 +69,5 @@ public class PoiFilter extends AbstractPoiType {
public List<PoiType> getPoiTypes() {
return poiTypes;
}
}

View file

@ -23,7 +23,6 @@ import net.osmand.IProgress;
import net.osmand.IndexConstants;
import net.osmand.PlatformUtil;
import net.osmand.aidl.OsmandAidlApi;
import net.osmand.binary.BinaryMapIndexReader;
import net.osmand.map.OsmandRegions;
import net.osmand.map.OsmandRegions.RegionTranslation;
import net.osmand.map.WorldRegion;
@ -406,17 +405,6 @@ public class AppInitializer implements IProgress {
});
}
private void readPoiTypesFromMap() {
final BinaryMapIndexReader[] currentFile = app.resourceManager.getPoiSearchFiles();
for (BinaryMapIndexReader r : currentFile) {
try {
r.initCategories();
} catch (IOException e) {
LOG.error("Error while read poi types from map " + e);
}
}
}
public void onCreateApplication() {
// always update application mode to default
OsmandSettings osmandSettings = app.getSettings();
@ -667,7 +655,6 @@ public class AppInitializer implements IProgress {
initPoiTypes();
notifyEvent(InitEvents.POI_TYPES_INITIALIZED);
app.resourceManager.reloadIndexesOnStart(this, warnings);
readPoiTypesFromMap();
// native depends on renderers
initNativeCore();

View file

@ -333,7 +333,6 @@ public class OsmandApplication extends MultiDexApplication {
return poiFilters;
}
public GpxSelectionHelper getSelectedGpxHelper() {
return selectedGpxHelper;
}

View file

@ -3,7 +3,10 @@ package net.osmand.plus.poi;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.util.Pair;
import net.osmand.PlatformUtil;
import net.osmand.osm.AbstractPoiType;
import net.osmand.osm.MapPoiTypes;
import net.osmand.osm.PoiCategory;
@ -12,12 +15,18 @@ import net.osmand.plus.ApplicationMode;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.api.SQLiteAPI;
import net.osmand.plus.api.SQLiteAPI.SQLiteConnection;
import net.osmand.plus.api.SQLiteAPI.SQLiteCursor;
import net.osmand.plus.api.SQLiteAPI.SQLiteStatement;
import net.osmand.plus.wikipedia.WikipediaPoiMenu;
import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@ -36,6 +45,7 @@ import static net.osmand.osm.MapPoiTypes.WIKI_PLACE;
public class PoiFiltersHelper {
private static final Log LOG = PlatformUtil.getLog(PoiFiltersHelper.class);
private final OsmandApplication application;
private NominatimPoiFilter nominatimPOIFilter;
@ -625,6 +635,33 @@ public class PoiFiltersHelper {
}
}
@Nullable
public Pair<Long, Map<String, List<String>>> getCacheByResourceName(String fileName) {
Pair<Long, Map<String, List<String>>> cache = null;
PoiFilterDbHelper helper = openDbHelper();
if (helper != null) {
cache = helper.getCacheByResourceName(helper.getReadableDatabase(), fileName);
helper.close();
}
return cache;
}
public void updateCacheForResource(String fileName, long lastModified, Map<String, List<String>> categories) {
PoiFilterDbHelper helper = openDbHelper();
if (helper != null) {
helper.updateCacheForResource(helper.getReadableDatabase(), fileName, lastModified, categories);
helper.close();
}
}
public void insertCacheForResource(String fileName, long lastModified, Map<String, List<String>> categories) {
PoiFilterDbHelper helper = openDbHelper();
if (helper != null) {
helper.insertCacheForResource(helper.getReadableDatabase(), fileName, lastModified, categories);
helper.close();
}
}
private void saveSelectedPoiFilters() {
Set<String> filters = new HashSet<>();
for (Set<PoiUIFilter> template : selectedPoiFilters.values()) {
@ -641,7 +678,7 @@ public class PoiFiltersHelper {
private static final int FALSE_INT = 0;
public static final String DATABASE_NAME = "poi_filters";
private static final int DATABASE_VERSION = 6;
private static final int DATABASE_VERSION = 7;
private static final String FILTER_NAME = "poi_filters";
private static final String FILTER_COL_NAME = "name";
@ -669,6 +706,20 @@ public class PoiFiltersHelper {
CATEGORIES_COL_CATEGORY + ", " +
CATEGORIES_COL_SUBCATEGORY + ");";
private static final String POI_TYPES_CACHE_NAME = "poi_types_cache";
private static final String MAP_FILE_NAME = "map_name";
private static final String MAP_FILE_DATE = "map_date";
private static final String CACHED_POI_CATEGORIES = "cached_categories";
private static final String POI_CACHE_TABLE_CREATE = "CREATE TABLE " +
POI_TYPES_CACHE_NAME + " (" +
MAP_FILE_NAME + ", " +
MAP_FILE_DATE + ", " +
CACHED_POI_CATEGORIES + ");";
private static final String CATEGORY_KEY = "category";
private static final String SUB_CATEGORIES_KEY = "sub_categories";
private OsmandApplication context;
private SQLiteConnection conn;
private MapPoiTypes mapPoiTypes;
@ -714,6 +765,7 @@ public class PoiFiltersHelper {
public void onCreate(SQLiteConnection conn) {
conn.execSQL(FILTER_TABLE_CREATE);
conn.execSQL(CATEGORIES_TABLE_CREATE);
conn.execSQL(POI_CACHE_TABLE_CREATE);
}
@ -725,6 +777,9 @@ public class PoiFiltersHelper {
conn.execSQL("ALTER TABLE " + FILTER_NAME + " ADD " + FILTER_COL_HISTORY + " int DEFAULT " + FALSE_INT);
conn.execSQL("ALTER TABLE " + FILTER_NAME + " ADD " + FILTER_COL_DELETED + " int DEFAULT " + FALSE_INT);
}
if (oldVersion < 7) {
conn.execSQL(POI_CACHE_TABLE_CREATE);
}
}
private void deleteOldFilters(SQLiteConnection conn) {
@ -887,5 +942,89 @@ public class PoiFiltersHelper {
db.execSQL("DELETE FROM " + FILTER_NAME + " WHERE " + FILTER_COL_ID + " = ?", new Object[]{key});
db.execSQL("DELETE FROM " + CATEGORIES_NAME + " WHERE " + CATEGORIES_FILTER_ID + " = ?", new Object[]{key});
}
@Nullable
protected Pair<Long, Map<String, List<String>>> getCacheByResourceName(SQLiteConnection db, String fileName) {
Pair<Long, Map<String, List<String>>> cache = null;
if (db != null) {
SQLiteAPI.SQLiteCursor query = db.rawQuery("SELECT " +
MAP_FILE_DATE + ", " +
CACHED_POI_CATEGORIES +
" FROM " +
POI_TYPES_CACHE_NAME +
" WHERE " + MAP_FILE_NAME + " = ?", new String[]{fileName});
if (query != null && query.moveToFirst()) {
long lastModified = query.getLong(0);
Map<String, List<String>> categories = getCategories(query.getString(1));
cache = new Pair<>(lastModified, categories);
}
if (query != null) {
query.close();
}
db.close();
}
return cache;
}
private Map<String, List<String>> getCategories(String json) {
Map<String, List<String>> categories = new HashMap<>();
try {
JSONArray jsonArray = new JSONArray(json);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
String category = jsonObject.optString(CATEGORY_KEY);
List<String> subCategories = getSubCategories(jsonObject.optString(SUB_CATEGORIES_KEY));
categories.put(category, subCategories);
}
} catch (JSONException e) {
LOG.error("Error parsing categories: " + e);
}
return categories;
}
protected void updateCacheForResource(SQLiteConnection db, String fileName, long lastModified, Map<String, List<String>> categories) {
try {
db.execSQL("UPDATE " + POI_TYPES_CACHE_NAME + " SET " +
MAP_FILE_DATE + " = ?, " +
CACHED_POI_CATEGORIES + " = ? " +
"WHERE " + MAP_FILE_NAME + " = ?",
new Object[]{lastModified, getCategoriesJson(categories), fileName});
} catch (JSONException e) {
LOG.error("Error converting category to json: " + e);
}
}
protected void insertCacheForResource(SQLiteConnection db, String fileName, long lastModified, Map<String, List<String>> categories) {
try {
db.execSQL("INSERT INTO " + POI_TYPES_CACHE_NAME + " VALUES(?,?,?)",
new Object[]{fileName, lastModified, getCategoriesJson(categories)});
} catch (JSONException e) {
LOG.error("Error converting category to json: " + e);
}
}
private String getCategoriesJson(Map<String, List<String>> categories) throws JSONException {
JSONArray json = new JSONArray();
for (Map.Entry<String, List<String>> entry : categories.entrySet()) {
JSONObject jsonObject = new JSONObject();
JSONArray subCategories = new JSONArray();
for (String subCategory : entry.getValue()) {
subCategories.put(subCategory);
}
jsonObject.put(CATEGORY_KEY, entry.getKey());
jsonObject.put(SUB_CATEGORIES_KEY, subCategories);
json.put(jsonObject);
}
return json.toString();
}
private List<String> getSubCategories(@NonNull String json) throws JSONException {
List<String> subCategories = new ArrayList<>();
JSONArray jsonArray = new JSONArray(json);
for (int i = 0; i < jsonArray.length(); i++) {
subCategories.add(jsonArray.optString(i));
}
return subCategories;
}
}
}

View file

@ -1,6 +1,7 @@
package net.osmand.plus.resources;
import androidx.annotation.Nullable;
import androidx.core.util.Pair;
import net.osmand.Location;
import net.osmand.PlatformUtil;
@ -9,8 +10,12 @@ import net.osmand.binary.BinaryMapIndexReader;
import net.osmand.binary.BinaryMapIndexReader.MapIndex;
import net.osmand.binary.BinaryMapIndexReader.SearchPoiTypeFilter;
import net.osmand.binary.BinaryMapIndexReader.SearchRequest;
import net.osmand.binary.BinaryMapPoiReaderAdapter;
import net.osmand.data.Amenity;
import net.osmand.osm.MapPoiTypes;
import net.osmand.osm.PoiCategory;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.poi.PoiFiltersHelper;
import net.osmand.plus.resources.ResourceManager.BinaryMapReaderResource;
import net.osmand.plus.resources.ResourceManager.BinaryMapReaderResourceType;
import net.osmand.util.MapUtils;
@ -18,6 +23,7 @@ import net.osmand.util.MapUtils;
import org.apache.commons.logging.Log;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@ -27,9 +33,73 @@ public class AmenityIndexRepositoryBinary implements AmenityIndexRepository {
private final static Log log = PlatformUtil.getLog(AmenityIndexRepositoryBinary.class);
private BinaryMapReaderResource resource;
private MapPoiTypes poiTypes;
private Map<String, List<String>> deltaPoiCategories = new HashMap<>();
public AmenityIndexRepositoryBinary(BinaryMapReaderResource resource) {
public AmenityIndexRepositoryBinary(BinaryMapReaderResource resource, OsmandApplication app) {
this.resource = resource;
poiTypes = app.getPoiTypes();
checkCachedCategories(app.getPoiFilters());
}
public Map<String, List<String>> getDeltaPoiCategories() {
return deltaPoiCategories;
}
private void checkCachedCategories(PoiFiltersHelper poiFiltersHelper) {
String fileName = resource.getFileName();
long lastModified = resource.getFileLastModified();
Pair<Long, Map<String, List<String>>> cache = poiFiltersHelper.getCacheByResourceName(fileName);
if (cache == null || cache.first != null && cache.first != lastModified) {
deltaPoiCategories = new HashMap<>();
try {
BinaryMapIndexReader reader = getOpenFile();
if (reader != null) {
reader.initCategories();
List<BinaryMapPoiReaderAdapter.PoiRegion> regions = reader.getPoiIndexes();
for (BinaryMapPoiReaderAdapter.PoiRegion region : regions) {
calculateDeltaSubcategories(region);
}
if (cache == null) {
poiFiltersHelper.insertCacheForResource(fileName, lastModified, deltaPoiCategories);
} else {
poiFiltersHelper.updateCacheForResource(fileName, lastModified, deltaPoiCategories);
}
}
} catch (IOException e) {
log.error("Error initializing categories ", e);
}
} else if (cache.second != null) {
deltaPoiCategories = cache.second;
}
}
private void calculateDeltaSubcategories(BinaryMapPoiReaderAdapter.PoiRegion region) {
List<String> categories = region.getCategories();
List<List<String>> subCategories = region.getSubcategories();
for (int i = 0; i < categories.size(); i++) {
String categoryName = categories.get(i);
PoiCategory poiCategory = poiTypes.getPoiCategoryByName(categoryName);
List<String> deltaSubCategories = null;
for (List<String> subList : subCategories) {
for (String subCategory : subList) {
if (poiCategory.getPoiTypeByKeyName(subCategory) != null) {
if (deltaSubCategories == null) {
deltaSubCategories = new ArrayList<>();
}
deltaSubCategories.add(subCategory);
}
}
}
if (deltaSubCategories != null) {
if(deltaPoiCategories.containsKey(categoryName)) {
deltaPoiCategories.get(categoryName).addAll(deltaSubCategories);
} else {
deltaPoiCategories.put(categoryName, deltaSubCategories);
}
}
}
}
@Nullable
@ -54,8 +124,8 @@ public class AmenityIndexRepositoryBinary implements AmenityIndexRepository {
BinaryMapIndexReader reader = getOpenFile();
return reader != null && reader.containsPoiData(left31, top31, right31, bottom31);
}
public synchronized Map<PoiCategory, List<String>> searchAmenityCategoriesByName(String query, Map<PoiCategory, List<String>> map) {
try {
BinaryMapIndexReader reader = getOpenFile();
@ -65,12 +135,12 @@ public class AmenityIndexRepositoryBinary implements AmenityIndexRepository {
}
return map;
}
public synchronized List<Amenity> searchAmenitiesByName(int x, int y, int l, int t, int r, int b, String query, ResultMatcher<Amenity> resulMatcher) {
long now = System.currentTimeMillis();
List<Amenity> amenities = Collections.emptyList();
SearchRequest<Amenity> req = BinaryMapIndexReader.buildSearchPoiRequest(x, y, query, l, r, t, b,resulMatcher);
SearchRequest<Amenity> req = BinaryMapIndexReader.buildSearchPoiRequest(x, y, query, l, r, t, b, resulMatcher);
try {
BinaryMapIndexReader index = getOpenFile();
if (index != null) {
@ -90,10 +160,10 @@ public class AmenityIndexRepositoryBinary implements AmenityIndexRepository {
}
return amenities;
}
@Override
public synchronized List<Amenity> searchAmenities(int stop, int sleft, int sbottom, int sright, int zoom,
final SearchPoiTypeFilter filter, ResultMatcher<Amenity> matcher) {
public synchronized List<Amenity> searchAmenities(int stop, int sleft, int sbottom, int sright, int zoom,
final SearchPoiTypeFilter filter, ResultMatcher<Amenity> matcher) {
long now = System.currentTimeMillis();
SearchRequest<Amenity> req = BinaryMapIndexReader.buildSearchPoiRequest(sleft, sright, stop, sbottom, zoom,
filter, matcher);
@ -118,7 +188,7 @@ public class AmenityIndexRepositoryBinary implements AmenityIndexRepository {
long now = System.currentTimeMillis();
List<Amenity> result = null;
SearchRequest<Amenity> req = BinaryMapIndexReader.buildSearchPoiRequest(locations, radius,
filter, matcher );
filter, matcher);
try {
BinaryMapIndexReader reader = getOpenFile();
if (reader != null) {
@ -129,10 +199,10 @@ public class AmenityIndexRepositoryBinary implements AmenityIndexRepository {
return result;
}
if (log.isDebugEnabled() && result != null) {
log.debug(String.format("Search done in %s ms found %s.", (System.currentTimeMillis() - now), result.size())); //$NON-NLS-1$
log.debug(String.format("Search done in %s ms found %s.", (System.currentTimeMillis() - now), result.size())); //$NON-NLS-1$
}
return result;
}
}

View file

@ -32,6 +32,7 @@ import net.osmand.map.MapTileDownloader.DownloadRequest;
import net.osmand.map.OsmandRegions;
import net.osmand.osm.MapPoiTypes;
import net.osmand.osm.PoiCategory;
import net.osmand.osm.PoiType;
import net.osmand.plus.AppInitializer;
import net.osmand.plus.AppInitializer.InitEvents;
import net.osmand.plus.OsmandApplication;
@ -152,6 +153,10 @@ public class ResourceManager {
return filename.getName();
}
public long getFileLastModified() {
return filename.lastModified();
}
// should not use methods to read from file!
@Nullable
public BinaryMapIndexReader getShallowReader() {
@ -735,7 +740,7 @@ public class ResourceManager {
resource.setUseForPublicTransport(true);
}
if (mapReader.containsPoiData()) {
amenityRepositories.put(f.getName(), new AmenityIndexRepositoryBinary(resource));
amenityRepositories.put(f.getName(), new AmenityIndexRepositoryBinary(resource, context));
}
}
} catch (SQLiteException e) {
@ -746,6 +751,17 @@ public class ResourceManager {
warnings.add(MessageFormat.format(context.getString(R.string.version_index_is_big_for_memory), f.getName()));
}
}
for (AmenityIndexRepository repo : amenityRepositories.values()) {
Map<String, List<String>> categories = ((AmenityIndexRepositoryBinary) repo).getDeltaPoiCategories();
if (!categories.isEmpty()) {
for (Map.Entry<String, List<String>> entry : categories.entrySet()) {
PoiCategory poiCategory = context.getPoiTypes().getPoiCategoryByName(entry.getKey(), true);
for (String s : entry.getValue()) {
poiCategory.addPoiType(new PoiType(MapPoiTypes.getDefault(), poiCategory, null, s));
}
}
}
}
log.debug("All map files initialized " + (System.currentTimeMillis() - val) + " ms");
if (files.size() > 0 && (!indCache.exists() || indCache.canWrite())) {
try {
@ -1122,21 +1138,6 @@ public class ResourceManager {
return readers.toArray(new BinaryMapIndexReader[readers.size()]);
}
public BinaryMapIndexReader[] getPoiSearchFiles() {
Collection<BinaryMapReaderResource> fileReaders = getFileReaders();
List<BinaryMapIndexReader> readers = new ArrayList<>(fileReaders.size());
for (BinaryMapReaderResource r : fileReaders) {
BinaryMapIndexReader shallowReader = r.getShallowReader();
if (shallowReader != null && shallowReader.containsPoiData()) {
BinaryMapIndexReader reader = r.getReader(BinaryMapReaderResourceType.POI);
if (reader != null) {
readers.add(reader);
}
}
}
return readers.toArray(new BinaryMapIndexReader[readers.size()]);
}
public Map<String, String> getIndexFileNames() {
return new LinkedHashMap<String, String>(indexFileNames);
}

View file

@ -43,6 +43,8 @@ import net.osmand.plus.render.RenderingIcons;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
@ -90,6 +92,12 @@ public class QuickSearchCustomPoiFragment extends DialogFragment {
this.nightMode = app.getSettings().OSMAND_THEME.get() == OsmandSettings.OSMAND_DARK_THEME;
setStyle(STYLE_NO_FRAME, nightMode ? R.style.OsmandDarkTheme : R.style.OsmandLightTheme);
poiCategoryList = app.getPoiTypes().getCategories(false);
Collections.sort(poiCategoryList, new Comparator<PoiCategory>() {
@Override
public int compare(PoiCategory poiCategory, PoiCategory t1) {
return poiCategory.getTranslation().compareTo(t1.getTranslation());
}
});
}
@Override