Skip to content
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

Update OfflineRegion/OfflineRegionDefinition interfaces, synchronize with iOS and Android #545

Merged
merged 12 commits into from
Feb 28, 2021
Merged
Original file line number Diff line number Diff line change
@@ -5,7 +5,6 @@

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.mapbox.mapboxgl.models.OfflineRegionData;
import android.content.Context;

import androidx.annotation.NonNull;
@@ -74,21 +73,23 @@ public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
break;

case "downloadOfflineRegion":
// Get download region arguments from caller
OfflineRegionData regionData = new Gson().fromJson(methodCall.argument("region").toString(), OfflineRegionData.class);
// Prepare channel
// Get args from caller
Map<String, Object> definitionMap = (Map<String, Object>) methodCall.argument("definition");
Map<String, Object> metadataMap = (Map<String, Object>) methodCall.argument("metadata");
String channelName = methodCall.argument("channelName");

// Prepare args
OfflineChannelHandlerImpl channelHandler = new OfflineChannelHandlerImpl(messenger, channelName);

// Start downloading
OfflineManagerUtils.downloadRegion(result, context, regionData, channelHandler);
OfflineManagerUtils.downloadRegion(result, context, definitionMap, metadataMap, channelHandler);
break;
case "getListOfRegions":
OfflineManagerUtils.regionsList(result, context);
break;
case "updateOfflineRegionMetadata":
// Get download region arguments from caller
Map<String, Object> metadata = (Map<String, Object>) methodCall.<Map>argument("metadata");
Map<String, Object> metadata = (Map<String, Object>) methodCall.argument("metadata");
OfflineManagerUtils.updateRegionMetadata(result, context, methodCall.<Number>argument("id").longValue(), metadata);
break;
case "deleteOfflineRegion":
105 changes: 84 additions & 21 deletions android/src/main/java/com/mapbox/mapboxgl/OfflineManagerUtils.java
Original file line number Diff line number Diff line change
@@ -4,14 +4,16 @@
import android.util.Log;

import com.google.gson.Gson;
import com.mapbox.mapboxgl.models.OfflineRegionData;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import com.mapbox.mapboxsdk.offline.OfflineManager;
import com.mapbox.mapboxsdk.offline.OfflineRegion;
import com.mapbox.mapboxsdk.offline.OfflineRegionDefinition;
import com.mapbox.mapboxsdk.offline.OfflineTilePyramidRegionDefinition;
import com.mapbox.mapboxsdk.offline.OfflineRegionError;
import com.mapbox.mapboxsdk.offline.OfflineRegionStatus;

import java.util.Arrays;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -27,9 +29,9 @@ static void mergeRegions(MethodChannel.Result result, Context context, String pa
OfflineManager.getInstance(context).mergeOfflineRegions(path, new OfflineManager.MergeOfflineRegionsCallback() {
public void onMerge(OfflineRegion[] offlineRegions) {
if (result == null) return;
List<OfflineRegionData> regionsArgs = new ArrayList<>();
List<Map<String, Object>> regionsArgs = new ArrayList<>();
for (OfflineRegion offlineRegion : offlineRegions) {
regionsArgs.add(OfflineRegionData.fromOfflineRegion(offlineRegion));
regionsArgs.add(offlineRegionToMap(offlineRegion));
}
String json = new Gson().toJson(regionsArgs);
result.success(json);
@@ -50,24 +52,25 @@ static void setOfflineTileCountLimit(MethodChannel.Result result, Context contex
static void downloadRegion(
MethodChannel.Result result,
Context context,
OfflineRegionData offlineRegionData,
Map<String, Object> definitionMap,
Map<String, Object> metadataMap,
OfflineChannelHandlerImpl channelHandler
) {
// Define the offline region
float pixelDensity = context.getResources().getDisplayMetrics().density;
OfflineRegionDefinition definition = offlineRegionData.generateRegionDefinition(pixelDensity);
//Prepare metadata
byte[] metadata = offlineRegionData.prepareMetadata();
//Tracker of result
OfflineRegionDefinition definition = mapToRegionDefinition(definitionMap, pixelDensity);
String metadata = "{}";
if (metadataMap != null) {
metadata = new Gson().toJson(metadataMap);
}
AtomicBoolean isComplete = new AtomicBoolean(false);
//Download region
OfflineManager.getInstance(context).createOfflineRegion(definition, metadata, new OfflineManager.CreateOfflineRegionCallback() {
OfflineManager.getInstance(context).createOfflineRegion(definition, metadata.getBytes(), new OfflineManager.CreateOfflineRegionCallback() {
private OfflineRegion _offlineRegion;

@Override
public void onCreate(OfflineRegion offlineRegion) {
OfflineRegionData data = OfflineRegionData.fromOfflineRegion(offlineRegion);
result.success(new Gson().toJson(data));
Map<String, Object> regionData = offlineRegionToMap(offlineRegion);
result.success(new Gson().toJson(regionData));

_offlineRegion = offlineRegion;
//Start downloading region
@@ -112,7 +115,7 @@ public void mapboxTileCountLimitExceeded(long limit) {
isComplete.set(true);
channelHandler.onError("mapboxTileCountLimitExceeded", "Mapbox tile count limit exceeded: " + limit, null);
//Mapbox even after crash and not downloading fully region still keeps part of it in database, so we have to remove it
deleteRegion(null, context, offlineRegionData.getId());
deleteRegion(null, context, _offlineRegion.getID());
}
};
_offlineRegion.setObserver(observer);
@@ -137,9 +140,9 @@ static void regionsList(MethodChannel.Result result, Context context) {
OfflineManager.getInstance(context).listOfflineRegions(new OfflineManager.ListOfflineRegionsCallback() {
@Override
public void onList(OfflineRegion[] offlineRegions) {
List<OfflineRegionData> regionsArgs = new ArrayList<>();
List<Map<String, Object>> regionsArgs = new ArrayList<>();
for (OfflineRegion offlineRegion : offlineRegions) {
regionsArgs.add(OfflineRegionData.fromOfflineRegion(offlineRegion));
regionsArgs.add(offlineRegionToMap(offlineRegion));
}
result.success(new Gson().toJson(regionsArgs));
}
@@ -151,20 +154,23 @@ public void onError(String error) {
});
}

static void updateRegionMetadata(MethodChannel.Result result, Context context, long id, Map<String, Object> metadata) {
static void updateRegionMetadata(MethodChannel.Result result, Context context, long id, Map<String, Object> metadataMap) {
OfflineManager.getInstance(context).listOfflineRegions(new OfflineManager.ListOfflineRegionsCallback() {
@Override
public void onList(OfflineRegion[] offlineRegions) {
for (OfflineRegion offlineRegion : offlineRegions) {
if (offlineRegion.getID() != id) continue;

final OfflineRegionData regionData = OfflineRegionData.fromOfflineRegion(offlineRegion);
regionData.setMetadata(metadata);

offlineRegion.updateMetadata(regionData.prepareMetadata(), new OfflineRegion.OfflineRegionUpdateMetadataCallback() {
String metadata = "{}";
if (metadataMap != null) {
metadata = new Gson().toJson(metadataMap);
}
offlineRegion.updateMetadata(metadata.getBytes(), new OfflineRegion.OfflineRegionUpdateMetadataCallback() {
@Override
public void onUpdate(byte[] metadataBytes) {
regionData.setMetadataBytes(metadataBytes);
Map<String, Object> regionData = offlineRegionToMap(offlineRegion);
regionData.put("metadata", metadataBytesToMap(metadataBytes));

if (result == null) return;
result.success(new Gson().toJson(regionData));
}
@@ -228,4 +234,61 @@ private static double calculateDownloadingProgress(long requiredResourceCount, l
? (100.0 * completedResourceCount / requiredResourceCount) :
0.0;
}

private static OfflineRegionDefinition mapToRegionDefinition(Map<String, Object> map, float pixelDensity) {
for (Map.Entry<String, Object> entry : map.entrySet()) {
Log.d(TAG, entry.getKey());
Log.d(TAG, entry.getValue().toString());
}
// Create a bounding box for the offline region
return new OfflineTilePyramidRegionDefinition(
(String) map.get("mapStyleUrl"),
listToBounds((List<List<Double>>) map.get("bounds")),
((Number) map.get("minZoom")).doubleValue(),
((Number) map.get("maxZoom")).doubleValue(),
pixelDensity,
(Boolean) map.get("includeIdeographs")
);
}

private static LatLngBounds listToBounds(List<List<Double>> bounds) {
return new LatLngBounds.Builder()
.include(new LatLng(bounds.get(1).get(0), bounds.get(1).get(1))) //Northeast
.include(new LatLng(bounds.get(0).get(0), bounds.get(0).get(1))) //Southwest
.build();
}

private static Map<String, Object> offlineRegionToMap(OfflineRegion region) {
Map<String, Object> result = new HashMap();
result.put("id", region.getID());
result.put("definition", offlineRegionDefinitionToMap(region.getDefinition()));
result.put("metadata", metadataBytesToMap(region.getMetadata()));
return result;
}

private static Map<String, Object> offlineRegionDefinitionToMap(OfflineRegionDefinition definition) {
Map<String, Object> result = new HashMap();
result.put("mapStyleUrl", definition.getStyleURL());
result.put("bounds", boundsToList(definition.getBounds()));
result.put("minZoom", definition.getMinZoom());
result.put("maxZoom", definition.getMaxZoom());
result.put("includeIdeographs", definition.getIncludeIdeographs());
return result;
}

private static List<List<Double>> boundsToList(LatLngBounds bounds) {
List<List<Double>> boundsList = new ArrayList<>();
List<Double> northeast = Arrays.asList(bounds.getLatNorth(), bounds.getLonEast());
List<Double> southwest = Arrays.asList(bounds.getLatSouth(), bounds.getLonWest());
boundsList.add(southwest);
boundsList.add(northeast);
return boundsList;
}

private static Map<String, Object> metadataBytesToMap(byte[] metadataBytes) {
if (metadataBytes != null) {
return new Gson().fromJson(new String(metadataBytes), HashMap.class);
}
return new HashMap();
}
}

This file was deleted.

12 changes: 6 additions & 6 deletions example/lib/offline_region_map.dart
Original file line number Diff line number Diff line change
@@ -22,22 +22,22 @@ class _OfflineRegionMapState extends State<OfflineRegionMap> {
body: MapboxMap(
initialCameraPosition: CameraPosition(
target: _center,
zoom: widget.item.offlineRegion.minZoom,
zoom: widget.item.offlineRegionDefinition.minZoom,
),
minMaxZoomPreference: MinMaxZoomPreference(
widget.item.offlineRegion.minZoom,
widget.item.offlineRegion.maxZoom,
widget.item.offlineRegionDefinition.minZoom,
widget.item.offlineRegionDefinition.maxZoom,
),
styleString: widget.item.offlineRegion.mapStyleUrl,
styleString: widget.item.offlineRegionDefinition.mapStyleUrl,
cameraTargetBounds: CameraTargetBounds(
widget.item.offlineRegion.bounds,
widget.item.offlineRegionDefinition.bounds,
),
),
);
}

LatLng get _center {
final bounds = widget.item.offlineRegion.bounds;
final bounds = widget.item.offlineRegionDefinition.bounds;
final lat = (bounds.southwest.latitude + bounds.northeast.latitude) / 2;
final lng = (bounds.southwest.longitude + bounds.northeast.longitude) / 2;
return LatLng(lat, lng);
Loading