diff --git a/src/android/Mapbox.java b/src/android/Mapbox.java index 990a29f..99cbb8d 100644 --- a/src/android/Mapbox.java +++ b/src/android/Mapbox.java @@ -50,6 +50,7 @@ public class Mapbox extends CordovaPlugin { private static final String ACTION_CREATE_OFFLINE_REGION = "createOfflineRegion"; private static final String ACTION_DOWNLOAD_OFFLINE_REGION = "downloadOfflineRegion"; private static final String ACTION_PAUSE_OFFLINE_REGION = "pauseOfflineRegion"; + private static final String ACTION_OFFLINE_REGION_STATUS = "offlineRegionStatus"; private static final String ACTION_ADD_MARKERS = "addMarkers"; private static final String ACTION_ADD_MARKER_CALLBACK = "addMarkerCallback"; private static final String ACTION_ADD_POLYGON = "addPolygon"; @@ -225,6 +226,23 @@ else if (ACTION_PAUSE_OFFLINE_REGION.equals(action)) { callbackContext.success(); } + else if (ACTION_OFFLINE_REGION_STATUS.equals(action)) { + final int offlineRegionId = args.getInt(0); + final OfflineRegion region = this.mapboxManager.getOfflineRegion(offlineRegionId); + + region.getStatus(new MapboxManager.OfflineRegionStatusCallback() { + @Override + public void onStatus(JSONObject status) { + callbackContext.success(status); + } + + @Override + public void onError(String error) { + callbackContext.error(error); + } + }); + } + else if (ACTION_GET_TILT.equals(action)) { // if (mapView != null) { // cordova.getActivity().runOnUiThread(new Runnable() { @@ -333,69 +351,65 @@ public void run() { } private void createMap(final JSONObject options, final CallbackContext callback) { - if (accessToken == null) { - callback.error(MAPBOX_ACCESSTOKEN_RESOURCE_KEY + " not set in strings.xml"); - return; - } - - cordova.getActivity().runOnUiThread(new Runnable() { + cordova.getActivity().runOnUiThread(new Runnable() { @Override public void run() { - MapView mapView = createMapView(accessToken, options); - Map.create(mapView, options, new Map.MapCreatedCallback() { - @Override - public void onCreate(final Map map) { - JSONObject resp = new JSONObject(); - try { - resp.put("id", map.getId()); - callback.success(resp); - return; - } catch (JSONException e) { - String error = "Failed to create map: " + e.getMessage(); - Log.e(LOG_TAG, error); - callback.error(error); - return; + try { + MapView mapView = createMapView(accessToken, options); + Map.create(mapView, options, new Map.MapCreatedCallback() { + @Override + public void onCreate(final Map map) { + JSONObject resp = new JSONObject(); + try { + resp.put("id", map.getId()); + callback.success(resp); + return; + } catch (JSONException e) { + String error = "Failed to create map: " + e.getMessage(); + Log.e(LOG_TAG, error); + callback.error(error); + return; + } } - } - @Override - public void onError(String error) { - String message = "Failed to create map: " + error; - Log.e(LOG_TAG, message); - callback.error(message); - } - }); + @Override + public void onError(String error) { + String message = "Failed to create map: " + error; + Log.e(LOG_TAG, message); + callback.error(message); + } + }); + } catch (JSONException e) { + callback.error(e.getMessage()); + } } }); } - private MapView createMapView(String accessToken, JSONObject options) { + private MapView createMapView(String accessToken, JSONObject options) throws JSONException { MapView mapView = new MapView(this.webView.getContext()); mapView.setAccessToken(accessToken); - try { - final JSONObject margins = options.isNull("margins") ? null : options.getJSONObject("margins"); - final int left = (int) (retinaFactor * (margins == null || margins.isNull("left") ? 0 : margins.getInt("left"))); - final int right = (int) (retinaFactor * (margins == null || margins.isNull("right") ? 0 : margins.getInt("right"))); - final int top = (int) (retinaFactor * (margins == null || margins.isNull("top") ? 0 : margins.getInt("top"))); - final int bottom = (int) (retinaFactor * (margins == null || margins.isNull("bottom") ? 0 : margins.getInt("bottom"))); - - // need to do this to register a receiver which onPause later needs - mapView.onResume(); - mapView.onCreate(null); - - // position the mapView overlay - int webViewWidth = webView.getView().getWidth(); - int webViewHeight = webView.getView().getHeight(); - final FrameLayout layout = (FrameLayout) webView.getView().getParent(); - FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(webViewWidth - left - right, webViewHeight - top - bottom); - params.setMargins(left, top, right, bottom); - mapView.setLayoutParams(params); - - layout.addView(mapView); - } catch (JSONException e) { - e.printStackTrace(); - } + final JSONObject margins = options.isNull("margins") ? null : options.getJSONObject("margins"); + final int left = (int) (retinaFactor * (margins == null || margins.isNull("left") ? 0 : margins.getInt("left"))); + final int right = (int) (retinaFactor * (margins == null || margins.isNull("right") ? 0 : margins.getInt("right"))); + final int top = (int) (retinaFactor * (margins == null || margins.isNull("top") ? 0 : margins.getInt("top"))); + final int bottom = (int) (retinaFactor * (margins == null || margins.isNull("bottom") ? 0 : margins.getInt("bottom"))); + + // need to do this to register a receiver which onPause later needs + mapView.onResume(); + mapView.onCreate(null); + + // position the mapView overlay + int webViewWidth = webView.getView().getWidth(); + int webViewHeight = webView.getView().getHeight(); + final FrameLayout layout = (FrameLayout) webView.getView().getParent(); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(webViewWidth - left - right, webViewHeight - top - bottom); + params.setMargins(left, top, right, bottom); + mapView.setLayoutParams(params); + + layout.addView(mapView); + return mapView; } @@ -427,7 +441,7 @@ public void createOfflineRegion(final JSONObject options, final CallbackContext public void run() { OfflineManager offlineManager = OfflineManager.getInstance(webView.getContext()); offlineManager.setAccessToken(accessToken); - mapboxManager.createOfflineRegion(options, callback, new MapboxManager.OfflineRegionStatusCallback() { + mapboxManager.createOfflineRegion(options, callback, new MapboxManager.OfflineRegionProgressCallback() { @Override public void onProgress(JSONObject progress) { PluginResult result = new PluginResult(PluginResult.Status.OK, progress); diff --git a/src/android/MapboxManager.java b/src/android/MapboxManager.java index 8e99a58..0190ee4 100644 --- a/src/android/MapboxManager.java +++ b/src/android/MapboxManager.java @@ -19,23 +19,21 @@ class MapboxManager { // JSON encoding/decoding public static final String JSON_CHARSET = "UTF-8"; - public static final String JSON_FIELD_REGION_NAME = "FIELD_REGION_NAME"; - - private String mapboxAccessToken; + public static final String JSON_FIELD_ID = "id"; + public static final String JSON_FIELD_REGION_NAME = "name"; private Float density; - private CordovaWebView cordovaWebView; - private OfflineManager offlineManager; - private HashMap regions = new HashMap(); - - private HashMap mapboxRegions = new HashMap(); - - private int ids = 0; + private HashMap regions = new HashMap(); public interface OfflineRegionStatusCallback { + void onStatus(JSONObject status); + void onError(String error); + } + + public interface OfflineRegionProgressCallback { void onComplete(JSONObject progress); void onProgress(JSONObject progress); void onError(String error); @@ -47,10 +45,9 @@ public interface LoadOfflineRegionsCallback { } public MapboxManager(String accessToken, Float screenDensity, CordovaWebView webView) { - this.mapboxAccessToken = accessToken; this.density = screenDensity; - this.cordovaWebView = webView; this.offlineManager = OfflineManager.getInstance(webView.getContext()); + this.offlineManager.setAccessToken(accessToken); } public void loadOfflineRegions(final LoadOfflineRegionsCallback callback) { @@ -58,29 +55,35 @@ public void loadOfflineRegions(final LoadOfflineRegionsCallback callback) { @Override public void onList(com.mapbox.mapboxsdk.offline.OfflineRegion[] offlineRegions) { try { - JSONArray regions = new JSONArray(); + JSONArray responses = new JSONArray(); JSONObject response; + OfflineRegion region; for (com.mapbox.mapboxsdk.offline.OfflineRegion offlineRegion : offlineRegions) { - OfflineRegion region = createOfflineRegion(offlineRegion); - response = new JSONObject(); - response.put("id", region.getId()); - regions.put(response); + if (regions.containsKey(offlineRegion.getID())) { + region = regions.get(offlineRegion.getID()); + } else { + region = createOfflineRegion(offlineRegion); + } + response = region.getMetadata(); + response.put(JSON_FIELD_ID, region.getId()); + responses.put(response); } - callback.onList(regions); + callback.onList(responses); } catch (JSONException e) { - String error = "Error loading OfflineRegions: " + e.getMessage(); - callback.onError(error); + this.onError(e.getMessage()); + } catch (UnsupportedEncodingException e) { + this.onError(e.getMessage()); } } @Override public void onError(String error) { - + callback.onError(error); } }); } - public void createOfflineRegion(final JSONObject options, final CallbackContext callback, final OfflineRegionStatusCallback offlineRegionStatusCallback) { + public void createOfflineRegion(final JSONObject options, final CallbackContext callback, final OfflineRegionProgressCallback offlineRegionStatusCallback) { try { final String regionName = options.getString("name"); @@ -95,11 +98,13 @@ public void onCreate(com.mapbox.mapboxsdk.offline.OfflineRegion offlineRegion) { try { OfflineRegion region = createOfflineRegion(offlineRegion); region.setObserver(offlineRegionStatusCallback); - JSONObject resp = new JSONObject(); - resp.put("id", region.getId()); - callback.success(resp); + JSONObject response = region.getMetadata(); + response.put(JSON_FIELD_ID, region.getId()); + callback.success(response); } catch (JSONException e) { this.onError(e.getMessage()); + } catch (UnsupportedEncodingException e) { + this.onError(e.getMessage()); } } @@ -116,21 +121,17 @@ public void onError(String error) { } } - private OfflineRegion createOfflineRegion(com.mapbox.mapboxsdk.offline.OfflineRegion offlineRegion) throws JSONException { - int id = this.ids++; - OfflineRegion region = new OfflineRegion(id, offlineRegion); - byte[] encodedMetadata = offlineRegion.getMetadata(); - JSONObject metadata = new JSONObject(encodedMetadata.toString()); - region.setRegionName(metadata.getString(JSON_FIELD_REGION_NAME)); - regions.put(id, region); + private OfflineRegion createOfflineRegion(com.mapbox.mapboxsdk.offline.OfflineRegion offlineRegion) throws JSONException, UnsupportedEncodingException { + OfflineRegion region = new OfflineRegion(offlineRegion); + regions.put(offlineRegion.getID(), region); return region; } - public OfflineRegion getOfflineRegion(int id) { + public OfflineRegion getOfflineRegion(long id) { return regions.get(id); } - public void removeOfflineRegion(int id) { + public void removeOfflineRegion(long id) { regions.remove(id); } diff --git a/src/android/OfflineRegion.java b/src/android/OfflineRegion.java index 41f5a23..464a36b 100644 --- a/src/android/OfflineRegion.java +++ b/src/android/OfflineRegion.java @@ -1,42 +1,51 @@ package com.telerik.plugins.mapbox; -import com.mapbox.mapboxsdk.geometry.LatLng; -import com.mapbox.mapboxsdk.geometry.LatLngBounds; -import com.mapbox.mapboxsdk.offline.OfflineManager; -import com.mapbox.mapboxsdk.offline.OfflineRegionDefinition; import com.mapbox.mapboxsdk.offline.OfflineRegionError; import com.mapbox.mapboxsdk.offline.OfflineRegionStatus; import org.json.JSONException; import org.json.JSONObject; -public class OfflineRegion { - protected interface OfflineRegionCreateCallback { - void onCreate(OfflineRegion region); - void onError(String error); - } +import java.io.UnsupportedEncodingException; - private int id; - - private long mapboxOfflineRegionId; +public class OfflineRegion { - private OfflineRegionCreateCallback createCallback; + public static final String JSON_CHARSET = "UTF-8"; - private String regionName; + private JSONObject metadata; private com.mapbox.mapboxsdk.offline.OfflineRegion region; - protected OfflineRegion(int id, com.mapbox.mapboxsdk.offline.OfflineRegion region) { - this.id = id; + protected OfflineRegion(com.mapbox.mapboxsdk.offline.OfflineRegion region) throws JSONException, UnsupportedEncodingException { this.region = region; + byte[] encodedMetadata = region.getMetadata(); + this.metadata = new JSONObject(new String(encodedMetadata, JSON_CHARSET)); } - public int getId() { - return this.id; + public Long getId() { + return this.region.getID(); } - public void setRegionName(String regionName) { - this.regionName = regionName; + public JSONObject getMetadata() { + return this.metadata; + } + + public void getStatus(final MapboxManager.OfflineRegionStatusCallback statusCallback) { + this.region.getStatus(new com.mapbox.mapboxsdk.offline.OfflineRegion.OfflineRegionStatusCallback() { + @Override + public void onStatus(OfflineRegionStatus status) { + try { + statusCallback.onStatus(statusToJSON(status)); + } catch (JSONException e) { + this.onError(e.getMessage()); + } + } + + @Override + public void onError(String error) { + statusCallback.onError(error); + } + }); } public void download() { @@ -47,51 +56,54 @@ public void pause() { this.region.setDownloadState(com.mapbox.mapboxsdk.offline.OfflineRegion.STATE_INACTIVE); } - public void setObserver(MapboxManager.OfflineRegionStatusCallback statusCallback) { + public void setObserver(MapboxManager.OfflineRegionProgressCallback statusCallback) { this.region.setObserver(new OfflineRegionObserver(statusCallback)); } + private JSONObject statusToJSON(OfflineRegionStatus status) throws JSONException { + long completedCount = status.getCompletedResourceCount(); + long requiredCount = status.getRequiredResourceCount(); + double percentage = requiredCount >= 0 ? (100.0 * completedCount / requiredCount) : 0.0; + JSONObject jsonStatus = new JSONObject() + .put("completedCount", completedCount) + .put("completedSize", status.getCompletedResourceSize()) + .put("requiredCount", requiredCount) + .put("percentage", percentage); + + return jsonStatus; + } + private class OfflineRegionObserver implements com.mapbox.mapboxsdk.offline.OfflineRegion.OfflineRegionObserver { - MapboxManager.OfflineRegionStatusCallback statusCallback; + private MapboxManager.OfflineRegionProgressCallback progressCallback; - OfflineRegionObserver(MapboxManager.OfflineRegionStatusCallback callback) { - this.statusCallback = callback; + OfflineRegionObserver(MapboxManager.OfflineRegionProgressCallback callback) { + this.progressCallback = callback; } @Override public void onStatusChanged(OfflineRegionStatus status) { - long completedCount = status.getCompletedResourceCount(); - long requiredCount = status.getRequiredResourceCount(); - double percentage = requiredCount >= 0 ? (100.0 * completedCount / requiredCount) : 0.0; - JSONObject progress = new JSONObject(); - try { - progress.put("completedCount", completedCount); - progress.put("completedSize", status.getCompletedResourceSize()); - progress.put("requiredCount", requiredCount); - progress.put("percentage", percentage); + JSONObject progress = statusToJSON(status); + if (!status.isComplete()) { + progressCallback.onProgress(progress); + } else { + progressCallback.onComplete(progress); + } } catch (JSONException e) { - statusCallback.onError(e.getMessage()); - return; - } - - if (status.isComplete()) { - statusCallback.onComplete(progress); - } else { - statusCallback.onProgress(progress); + progressCallback.onError(e.getMessage()); } } @Override public void onError(OfflineRegionError error) { String message = "OfflineRegionError: [" + error.getReason() + "] " + error.getMessage(); - statusCallback.onError(message); + progressCallback.onError(message); pause(); } @Override public void mapboxTileCountLimitExceeded(long limit) { - statusCallback.onError("Tile limit exceeded (limit: " + limit + ")"); + progressCallback.onError("Tile limit exceeded (limit: " + limit + ")"); } } } diff --git a/src/android/mapbox.gradle b/src/android/mapbox.gradle index a7910cd..57aca98 100644 --- a/src/android/mapbox.gradle +++ b/src/android/mapbox.gradle @@ -2,12 +2,11 @@ ext.cdvMinSdkVersion = 15 repositories { mavenCentral() - maven { url "http://oss.sonatype.org/content/repositories/snapshots/" } } dependencies { compile 'com.android.support:appcompat-v7:23.0.1' - compile ('com.mapbox.mapboxsdk:mapbox-android-sdk:4.0.0-SNAPSHOT@aar'){ + compile ('com.mapbox.mapboxsdk:mapbox-android-sdk:4.0.0-beta.2@aar'){ transitive=true } } diff --git a/www/Mapbox.js b/www/Mapbox.js index 72b376c..fecf072 100644 --- a/www/Mapbox.js +++ b/www/Mapbox.js @@ -1,23 +1,9 @@ var exec = require("cordova/exec"), MapInstance = require("./map-instance"), - OfflineRegion = require("./offline-region"), - offlineRegions = []; - - -function listOfflineRegions(successCallback, errorCallback) { - exec( - function (regions) { - console.log("Offline regions: ", regions); - }, - function (error) { - console.error("Error getting offline regions: ", error); - }, - "Mapbox", - "listOfflineRegions" - ); -} + offline = require("./offline-region"); module.exports = { Map: MapInstance, - OfflineRegion: OfflineRegion + createOfflineRegion: offline.createOfflineRegion, + listOfflineRegions: offline.listOfflineRegions }; diff --git a/www/offline-region.js b/www/offline-region.js index 4a92259..b6601d1 100644 --- a/www/offline-region.js +++ b/www/offline-region.js @@ -2,16 +2,20 @@ var cordova = require("cordova"), exec = require("cordova/exec"), EventsMixin = require("./events-mixin"); -function OfflineRegion(options) { - var onLoad = _onLoad.bind(this), - onProgress = _onProgress.bind(this), +var OFFLINE_REGIONS = {}; + +function OfflineRegion() { + var onProgress = _onProgress.bind(this), onComplete = _onComplete.bind(this), - onError = _onError.bind(this), - onProgressId = this._registerCallback('onProgress', onProgress), - onCompleteId = this._registerCallback('onComplete', onComplete, onError); + onError = _onError.bind(this); + + this._onProgressId = this._registerCallback('onProgress', onProgress); + this._onCompleteId = this._registerCallback('onComplete', onComplete, onError); this._error = this._error.bind(this); - this._downloaded = false; + this._create = this._create.bind(this); + this._instance = this._instance.bind(this); + this._downloading = false; this.initEvents("Mapbox.MapInstance"); @@ -20,22 +24,12 @@ function OfflineRegion(options) { this.createStickyChannel("complete"); this.createStickyChannel("error"); - exec(onLoad, this._error, "Mapbox", "createOfflineRegion", [options, onProgressId, onCompleteId]); - - function _onLoad(resp) { - this._id = resp.id; - this.loaded = true; - - this.fire("load", {map: this}); - } - function _onProgress(progress) { this.fire("progress", progress); } function _onComplete(resp) { this._downloading = false; - this._downloaded = true; this.fire("complete", resp); } @@ -50,10 +44,22 @@ function OfflineRegion(options) { EventsMixin(OfflineRegion.prototype); +OfflineRegion.prototype._create = function (options) { + var args = [options, this._onProgressId, this._onCompleteId]; + exec(this._instance, this._error, "Mapbox", "createOfflineRegion", args); +}; + +OfflineRegion.prototype._instance = function (response) { + this._id = response.id; + this._name = response.name; + this.loaded = true; + this.fire("load", {offlineRegion: this}); + OFFLINE_REGIONS[this._id] = this; +}; + OfflineRegion.prototype._error = function (err) { var error = new Error("OfflineRegion error (ID: " + this._id + "): " + err); this._downloading = false; - this._downloaded = false; console.warn("throwing OfflineRegionError: ", error); throw error; }; @@ -96,16 +102,61 @@ OfflineRegion.prototype.pause = function () { } }; +OfflineRegion.prototype.getStatus = function (callback) { + this._execAfterLoad(onSuccess, onError, "offlineRegionStatus"); + function onSuccess(status) { + callback(null, status); + } + function onError(error) { + callback(error); + } +}; + Object.defineProperty(OfflineRegion.prototype, "downloading", { get: function () { return this._downloading; } }); -Object.defineProperty(OfflineRegion.prototype, "downloaded", { +Object.defineProperty(OfflineRegion.prototype, "name", { get: function () { - return this._downloaded; + return this._name; } }); -module.exports = OfflineRegion; +module.exports = { + createOfflineRegion: function (options) { + var region = new OfflineRegion(); + region._create(options); + return region; + }, + + listOfflineRegions: function (callback) { + exec( + function (responses) { + console.log("Offline regions: ", responses); + var regions = responses.map(function (response) { + var region = OFFLINE_REGIONS[response.id]; + if (!region) { + region = new OfflineRegion(); + region._instance(response); + } + return region; + }), + byName = regions.reduce(function (regionsByName, region) { + regionsByName[region.name] = region; + return regionsByName; + }, {}); + callback(null, byName); + }, + function (errorMessage) { + var error = "Error getting offline regions: " + errorMessage; + console.error(error); + callback(error); + }, + "Mapbox", + "listOfflineRegions", + [] + ); + } +};