New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Updated NGA GEOPackage core from 2.0.1 to 6.6.0 #1853
Conversation
Because GeoPackage now supports DocumentFile natively, we may be able to provide support for DocumentFile as an alternative to File (polymorphs methods to support both classes) so Geopackage files can be opened from the shared storage with respect to scoped storage introduction since Android 10+. Even, to make it more flexible, we can simply use the GeoPackage class instead of the File class. A Geopackage file can have multiple tiles tables storing different tile maps. With a single tile source approach, we can separately handle each tile table with a separate GeoPackageMapTileModuleProvider(). Map<String, MapTileModuleProviderBase> providers = new LinkedHashMap<>();
//tiles object stores info about each geopackage file data (database, tile table, current tile table active state)
//so, we can granularly control its data that we want to manipulate
//key is database:table string format
String key = String.join(":", tiles.getDatabase(), tiles.getName());
//handle one geopackage
GeoPackage geoPackage = geoPackageViewModel.getGeoPackage(tiles.getDatabase());
GeoPackageProvider geoPackageProvider = new GeoPackageProvider(geoPackage, activity);
if (tileOverlays.get(key) == null) {
TilesOverlay tilesOverlay = new TilesOverlay(geoPackageProvider, activity); //with default MapTileProviderBase
tilesOverlay.setLoadingBackgroundColor(Color.TRANSPARENT);
tilesOverlay.setLoadingLineColor(Color.TRANSPARENT);
tilesOverlay.setLoadingDrawable(null);
tileOverlays.put(key, tilesOverlay);
}
//...
if (!mapView.getOverlayManager().overlays().contains(tileOverlays.get(key))) {
mapView.getOverlayManager().add(tileOverlays.get(key));
mapView.setDrawingCacheBackgroundColor(Color.TRANSPARENT);
mapView.setBackgroundColor(Color.TRANSPARENT);
}
//this geopackage may have multiple tile tables
GeoPackageMapTileModuleProvider provider = geoPackageProvider.geoPackageMapTileModuleProvider();
providers.put(key, provider);
GeoPackageMapTileModuleProvider provider = (GeoPackageMapTileModuleProvider) providers.get(key);
List<GeopackageRasterTileSource> tileSources = provider
.getTileSources(tiles.getDatabase(), tiles.getName(), tiles.isActive());
tileSources.forEach((tileSource) -> {
if (tileSource != null) {
String tileSourceName = ((GeopackageRasterTileSource) tileSource).name();
//...
final MapTileFileStorageProviderBase cacheProvider =
MapTileProviderBasic.getMapTileFileStorageProviderBase(simpleRegisterReceiver, tileSource, tileWriter);
providers.put(String.join("-", key, "cacheProvider"), cacheProvider);
//...
mapView.setTileSource(tileSource);
mapView.zoomToBoundingBox(((GeopackageRasterTileSource) tileSource).getBounds(), true);
mapView.getController().setZoom(((GeopackageRasterTileSource) tileSource).getMinimumZoomLevel()*1.0);
}
});
String[] providerNames = new String[providers.size()];
int i = 0;
for (Map.Entry<String, MapTileModuleProviderBase> entry : providers.entrySet()) {
if (entry.getKey() != null && entry.getValue() != null) {
providerNames[i++] = String.format("%s (%s)", entry.getKey(), entry.getValue().getClass().getSimpleName());
}
}
MapTileProviderArray obj = new MapTileProviderArray(tileSource, new SimpleRegisterReceiver(activity), providerArray);
mapView.setTileProvider(obj); This improvement is to limit GeoPackageProvider() to a single GeoPackage file so that we may control its tile source(s) more precisely with the required tileprovider(s) to manage a separate tile cache. It will be very simple to control the tile source hide/unhide feature (which is currently missing). From public GeoPackageProvider(final IRegisterReceiver pRegisterReceiver,
final INetworkAvailablityCheck aNetworkAvailablityCheck, final ITileSource pTileSource,
final Context pContext, final IFilesystemCache cacheWriter, File[] databases) to public GeoPackageProvider(final IRegisterReceiver pRegisterReceiver,
final INetworkAvailablityCheck aNetworkAvailablityCheck, final ITileSource pTileSource,
final Context pContext, final IFilesystemCache cacheWriter, GeoPackage geoPackage) From public GeoPackageMapTileModuleProvider(File[] pFile,
final Context context, IFilesystemCache cache) to public GeoPackageMapTileModuleProvider(final Context context, IFilesystemCache cache, GeoPackage geoPackage) This is my version to idealize the above proposal. I've also hacked a way to control the range of zoom levels allowed on the tile source of each tile table based on the data from the GeoPackage file itself in the GeoPackageProvider
public class GeoPackageProvider extends MapTileProviderArray implements IMapTileProviderCallback {
protected GeoPackageMapTileModuleProvider packageMapTileModuleProvider;
protected IFilesystemCache tileWriter;
protected INetworkAvailablityCheck mNetworkAvailabilityCheck;
protected GeoPackage geoPackage;
private final double mInitialZoomLevel = 5;
private final int mLieFieLagInMillis = 1000;
public GeoPackageProvider(GeoPackage geoPackage, Context context) {
this(new SimpleRegisterReceiver(context), new NetworkAvailabliltyCheck(context),
TileSourceFactory.DEFAULT_TILE_SOURCE, context, null, geoPackage);
}
public GeoPackageProvider(final IRegisterReceiver pRegisterReceiver,
final INetworkAvailablityCheck aNetworkAvailablityCheck, final ITileSource pTileSource,
final Context pContext, final IFilesystemCache cacheWriter, GeoPackage geoPackage) {
super(pTileSource, pRegisterReceiver);
Log.i(IMapView.LOGTAG, "Geopackage support is BETA. Please report any issues");
Log.i(IMapView.LOGTAG, String.format("tilesUpdate.GeoPackageProvider()"));
this.geoPackage = geoPackage;
if (cacheWriter != null) {
tileWriter = cacheWriter;
} else {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD_MR1) {
tileWriter = new TileWriter();
} else {
tileWriter = new SqlTileWriter();
}
}
packageMapTileModuleProvider = new GeoPackageMapTileModuleProvider(pContext, tileWriter, geoPackage);
mTileProviderList.add(packageMapTileModuleProvider);
getTileCache().getProtectedTileContainers().add(this);
final String[] tileProviderList = mTileProviderList.stream().map(t -> t.getTileLoader().toString()).toArray(String[]::new);
Log.i(IMapView.LOGTAG, String.format("tilesUpdate.GeoPackageProvider(%s): tileProviders(%d) = %s", geoPackage.getName(), tileProviderList.length, Arrays.toString(tileProviderList)));
}
public GeoPackageMapTileModuleProvider geoPackageMapTileModuleProvider() {
return packageMapTileModuleProvider;
}
@Override
public IFilesystemCache getTileWriter() {
return tileWriter;
}
@Override
public void detach() {
//@TODO need to understand reason why detach() is called early during app creation
//https://github.com/osmdroid/osmdroid/issues/213
//close the writer
if (tileWriter != null)
tileWriter.onDetach();
tileWriter = null;
packageMapTileModuleProvider.detach();
super.detach();
}
@Override
public ITileSource getTileSource() {
return super.getTileSource();
}
@Override
public void setTileSource(final ITileSource aTileSource) {
super.setTileSource(aTileSource);
packageMapTileModuleProvider.setTileSource(aTileSource);
Log.i(IMapView.LOGTAG, String.format("tilesUpdate.GeoPackageProvider.setTileSource(%s) TILESOURCE UPDATED", aTileSource.name()));
}
} GeoPackageMapTileModuleProvider
public class GeoPackageMapTileModuleProvider extends MapTileModuleProviderBase {
public static final String GEO_PACKAGE_EXTENSION = ".gpkg";
private final TileSystem tileSystem = org.osmdroid.views.MapView.getTileSystem();
GeoPackage geoPackage;
protected GeopackageRasterTileSource currentTileSource;
public GeoPackageMapTileModuleProvider(final Context context, IFilesystemCache cache, GeoPackage geoPackage) {
super(Configuration.getInstance().getTileFileSystemThreads(), Configuration.getInstance().getTileFileSystemMaxQueueSize());
Log.i(IMapView.LOGTAG, "Geopackage support is BETA. Please report any issues");
this.geoPackage = geoPackage;
if (geoPackage != null) {
Log.i(IMapView.LOGTAG, String.format("GeoPackageMapTileModuleProvider(%s): current tilesource = %s", geoPackage.getName(), currentTileSource));
} else {
Log.i(IMapView.LOGTAG, String.format("GeoPackageMapTileModuleProvider(%s): current tilesource = %s", geoPackage, currentTileSource));
}
}
/**
* Restrict x to the range [low, high].
*/
static private int clamp(int x, int low, int high) {
return x < low ? low : (x > high ? high : x);
}
static private long clamp(long x, long low, long high) {
return x < low ? low : (x > high ? high : x);
}
static private double clamp(double x, double low, double high) {
return x < low ? low : (x > high ? high : x);
}
public Drawable getMapTile(final long pMapTileIndex) {
Drawable tile = null;
if (currentTileSource != null) {
String database = currentTileSource.getDatabase();
String table = currentTileSource.getTableDao();
boolean isActive = currentTileSource.isActive();
try {
TileDao tileDao = geoPackage.getTileDao(table);
TileRetriever retriever = null;
TileMatrixSet tileMatrixSet = tileDao.getTileMatrixSet();
mil.nga.geopackage.BoundingBox displayBoundingBox = tileMatrixSet.getBoundingBox();
Contents contents = tileMatrixSet.getContents();
mil.nga.geopackage.BoundingBox contentsBoundingBox = contents.getBoundingBox();
int zoom = (int) MapTileIndex.getZoom(pMapTileIndex); //clamp(MapTileIndex.getZoom(pMapTileIndex), 0, TileSystem.primaryKeyMaxZoomLevel);
final long MIN_ZOOM = tileDao.getTileMatrix(tileDao.getMinZoom()).getZoomLevel();
final long MAX_ZOOM = tileDao.getTileMatrix(tileDao.getMaxZoom()).getZoomLevel();
final long minZoomOffset = zoom - tileDao.getMinZoom();
final long maxZoomOffset = zoom - tileDao.getMaxZoom();
int newZoom = (int) (zoom);
String[] zoomList = tileDao.getZoomLevels().stream().map(k -> String.valueOf(k.longValue())).toArray(String[]::new);
int fullMapSizeInPixels = (int) (256 * Math.pow(2, zoom));
double zoomFactor = TileSystem.getFactor(zoom);
int x = (int) MapTileIndex.getX(pMapTileIndex); //clamp(MapTileIndex.getX(pMapTileIndex), 0, maxTileColumn);
int y = (int) MapTileIndex.getY(pMapTileIndex); //clamp(MapTileIndex.getY(pMapTileIndex), 0, maxTileRow);
long tileIndex = MapTileIndex.getTileIndex(zoom, x, y);
boolean hasTile = false;
long mapZoom = 0;
long matrixWidth = 0;
long matrixHeight = 0;
long tileWidth = 0;
long tileHeight = 0;
double pixel_x_size = 0;
double pixel_y_size = 0;
mil.nga.geopackage.BoundingBox boundingBox = tileDao.getBoundingBox(); //default
double minLonWgs84 = 0;
double maxLonWgs84 = 0;
double minLatWgs84 = 0;
double maxLatWgs84 = 0;
double minLonMerc = 0;
double maxLonMerc = 0;
double minLatMerc = 0;
double maxLatMerc = 0;
double minLon = 0;
double maxLon = 0;
double minLat = 0;
double maxLat = 0;
{
mil.nga.geopackage.BoundingBox boundingBox3 = tileDao.getBoundingBox();
double northOri = maxLatMerc = boundingBox3.getMaxLatitude(); //MaxY
double eastOri = maxLonMerc = boundingBox3.getMaxLongitude(); //MaxX
double southOri = minLatMerc = boundingBox3.getMinLatitude(); //MinY
double westOri = minLonMerc = boundingBox3.getMinLongitude(); //MinX
if (maxLatMerc > tileSystem.getMaxLatitude() || minLatMerc < tileSystem.getMinLatitude()) {
ProjectionTransform toWgs84 = tileDao.getProjection().getTransformation(ProjectionConstants.EPSG_WORLD_GEODETIC_SYSTEM);
mil.nga.geopackage.BoundingBox boundingBox2 = new mil.nga.geopackage.BoundingBox(westOri, southOri, eastOri, northOri);
boundingBox = boundingBox2.transform(toWgs84);
} else {
boundingBox = boundingBox3;
}
double north = Math.min(tileSystem.getMaxLatitude(), boundingBox.getMaxLatitude()); //MaxY
double east = boundingBox.getMaxLongitude(); //MaxX
double south = Math.max(tileSystem.getMinLatitude(), boundingBox.getMinLatitude()); //MinY
double west = boundingBox.getMinLongitude(); //MinX
BoundingBox bounds = new BoundingBox(north, east, south, west);
ProjectionTransform toWgs84 = tileDao.getProjection().getTransformation(ProjectionConstants.EPSG_WORLD_GEODETIC_SYSTEM);
mil.nga.geopackage.BoundingBox boundingBox2 = tileDao.getBoundingBox().transform(toWgs84);
if (boundingBox2 != null) {
minLon = boundingBox2.getMinLongitude();
maxLon = boundingBox2.getMaxLongitude();
minLat = boundingBox2.getMinLatitude();
maxLat = boundingBox2.getMaxLatitude();
}
}
final double minLonX = tileSystem.getLongitudeFromTileX(x, zoom); //minX
final double minLatY = tileSystem.getLatitudeFromTileY(y, zoom); //minY
final double maxLonX = tileSystem.getLongitudeFromTileX(x + 1, zoom); //maxX
final double maxLatY = tileSystem.getLatitudeFromTileY(y + 1, zoom); //maxY
final long pixelMinX = tileSystem.getMercatorXFromLongitude(minLonMerc, fullMapSizeInPixels, true);
final long pixelMinY = tileSystem.getMercatorYFromLatitude(minLatMerc, fullMapSizeInPixels, true);
final long pixelMaxX = tileSystem.getMercatorXFromLongitude(maxLonMerc, fullMapSizeInPixels, true);
final long pixelMaxY = tileSystem.getMercatorYFromLatitude(maxLatMerc, fullMapSizeInPixels, true);
final long tileMinX = tileSystem.getTileXFromLongitude(minLonMerc, zoom);
final long tileMinY = tileSystem.getTileYFromLatitude(minLatMerc, zoom);
final long tileMaxX = tileSystem.getTileXFromLongitude(maxLonMerc, zoom);
final long tileMaxY = tileSystem.getTileYFromLatitude(maxLatMerc, zoom);
int offsetX = (int) (x);
int offsetY = (int) (y);
TileMatrix tileMatrix = tileDao.getTileMatrix(newZoom);
if (tileMatrix != null) {
mapZoom = tileDao.getMapZoom(tileMatrix);
matrixWidth = tileMatrix.getMatrixWidth();
matrixHeight = tileMatrix.getMatrixHeight();
tileWidth = tileMatrix.getTileWidth();
tileHeight = tileMatrix.getTileHeight();
pixel_x_size = tileMatrix.getPixelXSize();
pixel_y_size = tileMatrix.getPixelYSize();
}
try {
retriever = new GeoPackageTileRetriever(tileDao);
} catch (Exception gpkgExp) {
Log.i(IMapView.LOGTAG, gpkgExp.getMessage());
}
if (retriever != null) {
hasTile = retriever.hasTile(offsetX, offsetY, newZoom);
if (hasTile) {
GeoPackageTile geoPackageTile = retriever.getTile(offsetX, offsetY, newZoom);
if (geoPackageTile != null && geoPackageTile.getData() != null) {
//don't show a tile if beyond the max zoom allowed by this raster and not active
if (zoom >= MIN_ZOOM && zoom <= MAX_ZOOM) {
Log.i(IMapView.LOGTAG, String.format("getMapTile(): Tile index %d (%s:%s:%s) => %d /%d/%d/%d => zoomFactor(%f) => mapZoom(%d) => lonWgs84(%f, %f) => latWgs84(%f, %f) => lonMerc(%f, %f) => latMerc(%f, %f) => tileX(%d, %d) => tileY(%d, %d) => tile /%d/%d/%d => tile_size(%d, %d) => pixel_size (%f, %f) => fullMapSizeInPixels(%d) => URL: %s = zoomList: %s",
tileIndex,
database, table, hasTile,
pMapTileIndex,
zoom, x, y,
zoomFactor,
mapZoom,
minLon, maxLon,
minLat, maxLat,
minLonMerc, maxLonMerc,
minLatMerc, maxLatMerc,
tileMinX, tileMaxX,
tileMinY, tileMaxY,
newZoom, offsetX, offsetY,
tileWidth, tileHeight,
pixel_x_size, pixel_y_size, fullMapSizeInPixels,
currentTileSource != null ? currentTileSource.getTileURLString(pMapTileIndex) : "null",
Arrays.toString(zoomList)));
tile = new BitmapDrawable(BitmapConverter.toBitmap(geoPackageTile.getData()));
}
}
}
}
}
catch (java.lang.IllegalStateException e) {
Log.w(IMapView.LOGTAG, "IllegalStateException downloading MapTile: " + MapTileIndex.toString(pMapTileIndex) + " : " + e);
}
}
return tile;
}
/**
* returns ALL available raster tile sources for the specified database.
* This will throw if the database doesn't exist or isn't registered
*
* @return
*/
public List<GeopackageRasterTileSource> getTileSources(String database, String tileTable, boolean isActive) {
List<GeopackageRasterTileSource> srcs = new ArrayList<>();
if (geoPackage != null)
{
{
TileDao tileDao = geoPackage.getTileDao(tileTable);
final long MIN_ZOOM = tileDao.getMapZoom(tileDao.getTileMatrix(tileDao.getMinZoom()));
final long MAX_ZOOM = tileDao.getMapZoom(tileDao.getTileMatrix(tileDao.getMaxZoom()));
{
mil.nga.geopackage.BoundingBox boundingBox3 = tileDao.getBoundingBox(/*MAX_ZOOM*/ tileDao.getMaxZoom());
double northOri = boundingBox3.getMaxLatitude(); //MaxY
double eastOri = boundingBox3.getMaxLongitude(); //MaxX
double southOri = boundingBox3.getMinLatitude(); //MinY
double westOri = boundingBox3.getMinLongitude(); //MinX
mil.nga.geopackage.BoundingBox boundingBox = null;
if (northOri > tileSystem.getMaxLatitude() || southOri < tileSystem.getMinLatitude()) {
ProjectionTransform transform = tileDao.getProjection().getTransformation(ProjectionConstants.EPSG_WORLD_GEODETIC_SYSTEM);
mil.nga.geopackage.BoundingBox boundingBox2 = new mil.nga.geopackage.BoundingBox(westOri, southOri, eastOri, northOri);
boundingBox = boundingBox2.transform(transform);
} else {
boundingBox = boundingBox3;
}
double north = Math.min(tileSystem.getMaxLatitude(), boundingBox.getMaxLatitude()); //MaxY
double east = boundingBox.getMaxLongitude(); //MaxX
double south = Math.max(tileSystem.getMinLatitude(), boundingBox.getMinLatitude()); //MinY
double west = boundingBox.getMinLongitude(); //MinX
org.osmdroid.util.BoundingBox bounds = new org.osmdroid.util.BoundingBox(north, east, south, west);
Log.i(IMapView.LOGTAG, String.format("GeoPackageMapTileModuleProvider.getTileSources(%s:%s) zoom(%d:%d), CRS (%s) => (%s), bounding box from (N=max_y=%f, E=max_x=%f, S=min_y=%f, W=min_x=%f) => bounding box to (N=max_y=%f, E=max_x=%f, S=min_y=%f, W=min_x=%f)",
database, tileTable,
(int) MIN_ZOOM, (int) MAX_ZOOM,
tileDao.getProjection().getCode(), String.valueOf(ProjectionConstants.EPSG_WORLD_GEODETIC_SYSTEM),
northOri, eastOri, southOri, westOri,
north, east, south, west));
//must project in WGS84
currentTileSource = new GeopackageRasterTileSource(database, tileTable, (int) MIN_ZOOM, (int) MAX_ZOOM, bounds, isActive);
srcs.add(currentTileSource);
}
Log.i(IMapView.LOGTAG, String.format("GeoPackageMapTileModuleProvider.getTileSources(%s:%s): size = %d, current tilesource = %s", database, tileTable, srcs.size(), currentTileSource));
}
}
return srcs;
}
//@Override
//public void detach() {
// //@TODO need to understand reason why detach() is called early during app creation
// super.detach();
// Log.i(IMapView.LOGTAG, String.format("GeoPackageMapTileModuleProvider.detach(%s): current tilesource = %s", geoPackage.getName(), currentTileSource));
//}
protected class TileLoader extends MapTileModuleProviderBase.TileLoader {
@Override
public Drawable loadTile(final long pMapTileIndex) {
try {
Drawable mapTile = getMapTile(pMapTileIndex);
return mapTile;
} catch (final Throwable e) {
Log.e(IMapView.LOGTAG, "Error loading tile", e);
} finally {
}
return null;
}
}
@Override
protected String getName() {
return "Geopackage";
}
@Override
protected String getThreadGroupName() {
return getName();
}
@Override
public GeoPackageMapTileModuleProvider.TileLoader getTileLoader() {
return new GeoPackageMapTileModuleProvider.TileLoader();
}
@Override
public boolean getUsesDataConnection() {
return false;
}
@Override
public int getMinimumZoomLevel() {
// hackish solution to make sure we can still zoom to the OsmDroid min level
// ignoring the tile source min zoom level; we check for this while retrieving
// the tile at the given tile index instead
//if (currentTileSource != null)
// return currentTileSource.getMinimumZoomLevel();
return 0;
}
@Override
public int getMaximumZoomLevel() {
// hackish solution to make sure we can still zoom to the OsmDroid max level
// ignoring the tile source max zoom level; we check for this while retrieving
// the tile at the given tile index instead
//if (currentTileSource != null)
// return currentTileSource.getMaximumZoomLevel();
return 29;
}
@Override
public void setTileSource(ITileSource tileSource) {
if (tileSource instanceof GeopackageRasterTileSource) {
if (currentTileSource != null && currentTileSource.isActive()) {
currentTileSource = (GeopackageRasterTileSource) tileSource;
}
}
}
} GeopackageRasterTileSource
public class GeopackageRasterTileSource extends XYTileSource {
private String database;
private String tableDao;
private BoundingBox bounds;
private boolean isActive;
public GeopackageRasterTileSource(String database, String table, int aZoomMinLevel, int aZoomMaxLevel, BoundingBox bbox, boolean isActive) {
super(database + ":" + table, aZoomMinLevel, aZoomMaxLevel, 256, "png", new String[]{""});
Log.i(IMapView.LOGTAG, "Geopackage support is BETA. Please report any issues");
this.database = database;
this.tableDao = table;
this.bounds = bbox;
this.isActive = isActive;
}
public BoundingBox getBounds() {
return bounds;
}
public void setBounds(BoundingBox bounds) {
this.bounds = bounds;
}
public String getDatabase() {
return database;
}
public void setDatabase(String database) {
this.database = database;
}
public String getTableDao() {
return tableDao;
}
public void setTableDao(String tableDao) {
this.tableDao = tableDao;
}
public boolean isActive() {
return isActive;
}
public void setActive(boolean active) {
isActive = active;
}
} Discussions on my approach can be found here: #1709 (comment) Next support should be able to tell whether a table in a GeoPackage file is a features-based (vector type), a tiles-based (raster type), or feature tiles. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me @PWRxPSYCHO!
@eclectice Are these changes something that will be added to OSMDroid in the next release? Or is this a suggestion for developers who wish to use this feature going forward? |
@monsieurtanuki The CI looks like it is failing for an API version. Should I address that? Or could that be a breaking change for the application as a whole? |
That does look like a breaking change. |
@PWRxPSYCHO I suggest it as a proposal to be implemented once your change has been successfully committed, as I was unable to push my change owing to an unknown OsmDroid build issue with Gradle-Fury last time. I'm also unfamiliar with the Git tool. On minimum SDK version, there is a note regarding Android platform support
https://developer.android.com/studio/releases/gradle-plugin#android-platform-support |
We don't need to go that high, do we? |
My current AGP 7.3.0 build (which I will update this info soon) generated this lint error demanding minSDKversion 24. https://issuetracker.google.com/issues/219091668?hl=id |
That would be problematic for my Lollipop smartphone (21). |
This is my current project build.gradle that is causing the lint error (I upgraded to Android Studio Dolphin 2021.3.1 last month); buildscript {
repositories {
mavenCentral()
google()
}
dependencies {
classpath "com.android.tools.build:gradle:7.3.0"
classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.19"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10"
classpath 'com.google.gradle:osdetector-gradle-plugin:1.7.1'
}
}
ext {
android_build_sdk_version = "33"
android_compile_sdk_version = "android-33"
if (USE_LOCAL_USB_LIB) {
android_build_min_sdk_version = "24"
} else {
android_build_min_sdk_version = "24"
}
android_build_target_sdk_version = "33"
android_build_tools_version = "30.0.3"
buildToolsVersion = "$android_build_tools_version"
compileSdkVersion = android_compile_sdk_version
minSdkVersion = android_build_min_sdk_version
targetSdkVersion = android_build_target_sdk_version
}
wrapper {
gradleVersion = "7.5.1"
//noinspection UnnecessaryQualifiedReference
distributionType = Wrapper.DistributionType.ALL
} |
Latest CI build issue is related to this: j256/ormlite-android#141 The compileSDK bump is no longer required |
It is just a variable but it is not applied in the |
This is how I solved dependency duplicates between libraries that use different versions, and how I implemented my local version of OsmDroid Geopackage API support without using the same class package names. For example, I created SafGeoPackageProvider as a replacement for OsmDroid GeoPackageProvider version so that I could use the most recent GeoPackage API version. dependencies {
api 'mil.nga.geopackage:geopackage-android:6.6.0'
implementation('org.osmdroid:osmdroid-geopackage:6.1.14') {
exclude group: 'org.osmdroid.gpkg'
exclude module: 'ormlite-core'
exclude group: 'com.j256.ormlite'
}
implementation('com.github.MKergall:osmbonuspack:6.9.0') {
exclude group: 'org.osmdroid.gpkg'
}
}
android {
packagingOptions {
excludes += "DebugProbesKt.bin"
excludes += "com/j256/ormlite/core/LICENSE.txt"
}
} |
Last issue seems to be on the DocumentFile There are 2 different versions being used. Android.x 1.0.1 & android support: 28.0.0 |
Hmm, compileSdkVersion is still required in the |
The original compileSdkVersion issue we ran into was resolved. I was using version 6.5.0 of Geopackage-Android which bumped the version up, but in 6.6.0 the version was bumped back down so that got rid of that issue. If you checkout the CI run here: https://github.com/ScriptTactics/osmdroid/actions/runs/3244600273/jobs/5320984386#step:5:327 You'll see that it's clashing with the document file issue. Android-Support brings in version 28.0.0 while the NGA-Geopackage-Android brings in Androidx which uses version 1.0.1. I am also running CI on my newest PR: #1856 -> This has all the changes in from this PR and the other PR(#1856). (Removing all android-support libraries and updating to Androidx) and there does not seem to be any issues about dependencies or duplicates |
Because of changes in the GeoPackage API since v2.0.1, this WIKI must be updated. |
merged, feel free to update the wiki |
#1707
#1684
#1706
Looking to update the NGA-Geopackage libraries within OSMDroid to the latest versions.