summaryrefslogtreecommitdiff
path: root/platform/android/MapboxGLAndroidSDK
diff options
context:
space:
mode:
authorAntonio Zugaldia <antonio@mapbox.com>2016-02-17 10:55:12 -0500
committerAntonio Zugaldia <antonio@mapbox.com>2016-02-26 09:13:17 -0500
commit01e55f183e4468d040e7b144536ca592c9b64cb5 (patch)
treef448bd208c3b43650ae5aa3918090f298d708fbf /platform/android/MapboxGLAndroidSDK
parentf683b10e106e7376322b9c67c2baf57f5022cec2 (diff)
downloadqtlocation-mapboxgl-01e55f183e4468d040e7b144536ca592c9b64cb5.tar.gz
# This is a combination of 8 commits.
# The first commit's message is: # This is a combination of 2 commits. # The first commit's message is: # This is a combination of 3 commits. # The first commit's message is: # This is a combination of 2 commits. # The first commit's message is: # This is a combination of 21 commits. # The first commit's message is: [android] - Implements Android bindings for offline API Fixes #3891 # The 2nd commit message will be skipped: # [android] #3891 - rename OFFLINE_MAX_CACHE_SIZE to DEFAULT_MAX_CACHE_SIZE and adjust value # The 3rd commit message will be skipped: # [android] #3891 - makes de documentation more relevant to the current android implementation # The 4th commit message will be skipped: # [android] #3891 - rename isRequiredResourceCountIsIndeterminate() to isRequiredResourceCountPrecise() # The 5th commit message will be skipped: # [android] #3891 - rename complete() to isComplete() # The 6th commit message will be skipped: # [android] #3891 - rename OfflineRegionDefinition to OfflineTilePyramidRegionDefinition and make OfflineRegionDefinition an interface. Docs for corresponding classes updated. # The 7th commit message will be skipped: # [android] #3891 - make reason a more idiomatic ErrorReason Android IntDef and remove unnecessary constructor # The 8th commit message will be skipped: # [android] #3891 - reuse the calling object instead of creating a new manager # The 9th commit message will be skipped: # [android] #3891 - location, location, location # The 10th commit message will be skipped: # [android] #3891 - simpler list regions iteration # The 11th commit message will be skipped: # [android] #3891 - proper indeterminate -> precise transition # The 12th commit message will be skipped: # [android] #3891 - improve description for DEFAULT_MAX_CACHE_SIZE # The 13th commit message will be skipped: # [android] #3891 - delete global refs for obj and listCallback # The 14th commit message will be skipped: # [android] #3891 - simplify metadata conversion and fix metadata object # The 15th commit message will be skipped: # [android] - Implements Android bindings for offline API # Fixes #3891 # The 16th commit message will be skipped: # [android] #3891 - avoid exposing the int reason value in the public API # The 17th commit message will be skipped: # [android] #3891 - delete global refs for remaining callbacks and observer # The 18th commit message will be skipped: # [android] #3891 - remove unused offlineManagerClassConstructorId together with unnecessary private java constructor # The 19th commit message will be skipped: # [android] #3891 - remove non-relevant line # The 20th commit message will be skipped: # [android] #3891 - handle requiredResourceCountIsIndeterminate -> requiredResourceCountIsPrecise rename # The 21st commit message will be skipped: # [android] #3891 - revert map changes to allow rebase # The 2nd commit message will be skipped: # [android] #3891 - avoid exposing the int reason value in the public API # The 2nd commit message will be skipped: # [android] #3891 - rename complete() to isComplete() # The 3rd commit message will be skipped: # [android] #3891 - rename OfflineRegionDefinition to OfflineTilePyramidRegionDefinition and make OfflineRegionDefinition an interface. Docs for corresponding classes updated. # The 2nd commit message will be skipped: # [android] #3891 - location, location, location # The 2nd commit message will be skipped: # [android] #3891 - improve description for DEFAULT_MAX_CACHE_SIZE # The 3rd commit message will be skipped: # [android] #3891 - delete global refs for obj and listCallback # The 4th commit message will be skipped: # [android] #3891 - simplify metadata conversion and fix metadata object # The 5th commit message will be skipped: # [android] #3891 - delete global refs for remaining callbacks and observer # The 6th commit message will be skipped: # [android] #3891 - remove unused offlineManagerClassConstructorId together with unnecessary private java constructor # The 7th commit message will be skipped: # [android] #3891 - remove non-relevant line # The 8th commit message will be skipped: # [android] #3891 - handle requiredResourceCountIsIndeterminate -> requiredResourceCountIsPrecise rename
Diffstat (limited to 'platform/android/MapboxGLAndroidSDK')
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java33
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java1
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java184
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java278
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionDefinition.java9
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionError.java53
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionMetadata.java63
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionStatus.java84
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition.java65
9 files changed, 766 insertions, 4 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
index 0c2690aec1..6b213bb655 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
@@ -620,11 +620,26 @@ public class MapView extends FrameLayout {
// Zoom
//
- double getZoom() {
+ /**
+ * Returns the current zoom level of the map view.
+ *
+ * @return The current zoom.
+ */
+ @UiThread
+ @FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM)
+ public double getZoom() {
return mNativeMapView.getZoom();
}
- void setMinZoom(@FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM) double minZoom) {
+ /**
+ * <p>
+ * Sets the minimum zoom level the map can be displayed at.
+ * </p>
+ *
+ * @param minZoom The new minimum zoom level.
+ */
+ @UiThread
+ public void setMinZoom(@FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM) double minZoom) {
mNativeMapView.setMinZoom(minZoom);
}
@@ -640,7 +655,19 @@ public class MapView extends FrameLayout {
return mNativeMapView.getMaxZoom();
}
- void setZoomControlsEnabled(boolean enabled) {
+ /**
+ * <p>
+ * Sets whether the zoom controls are enabled.
+ * If enabled, the zoom controls are a pair of buttons
+ * (one for zooming in, one for zooming out) that appear on the screen.
+ * When pressed, they cause the camera to zoom in (or out) by one zoom level.
+ * If disabled, the zoom controls are not shown.
+ * </p>
+ * By default the zoom controls are enabled if the device is only single touch capable;
+ *
+ * @param enabled If true, the zoom controls are enabled.
+ */
+ public void setZoomControlsEnabled(boolean enabled) {
mZoomButtonsController.setVisible(enabled);
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java
index 6c9806f79b..9530096131 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java
@@ -1,7 +1,6 @@
package com.mapbox.mapboxsdk.maps;
import android.content.Context;
-
import android.location.Location;
import android.os.Bundle;
import android.os.SystemClock;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java
new file mode 100644
index 0000000000..b56ecfc057
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java
@@ -0,0 +1,184 @@
+package com.mapbox.mapboxsdk.offline;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.annotation.NonNull;
+
+import java.io.File;
+
+/**
+ * The offline manager is the main entry point for offline-related functionality.
+ * It'll help you list and create offline regions.
+ */
+public class OfflineManager {
+
+ // Default database name
+ private final static String OFFLINE_DATABASE_NAME = "mbgl-offline.db";
+
+ /*
+ * The maximumCacheSize parameter is a limit applied to non-offline resources only,
+ * i.e. resources added to the database for the "ambient use" caching functionality.
+ * There is no size limit for offline resources.
+ */
+ private final static long DEFAULT_MAX_CACHE_SIZE = 50 * 1024 * 1024;
+
+ // Holds the pointer to JNI DefaultFileSource
+ private long mDefaultFileSourcePtr = 0;
+
+ // Makes sure callbacks come back to the main thread
+ private Handler handler;
+
+ // This object is implemented as a singleton
+ private static OfflineManager instance;
+
+ /*
+ * Callbacks
+ */
+
+ public interface ListOfflineRegionsCallback {
+ void onList(OfflineRegion[] offlineRegions);
+ void onError(String error);
+ }
+
+ public interface CreateOfflineRegionCallback {
+ void onCreate(OfflineRegion offlineRegion);
+ void onError(String error);
+ }
+
+ /*
+ * Constructors
+ */
+
+ private OfflineManager(Context context) {
+ // Get a pointer to the DefaultFileSource instance
+ String assetRoot = context.getFilesDir().getAbsolutePath();
+ String cachePath = assetRoot + File.separator + OFFLINE_DATABASE_NAME;
+ mDefaultFileSourcePtr = createDefaultFileSource(cachePath, assetRoot, DEFAULT_MAX_CACHE_SIZE);
+ }
+
+ public static synchronized OfflineManager getInstance(Context context) {
+ if (instance == null) {
+ instance = new OfflineManager(context);
+ }
+
+ return instance;
+ }
+
+ /*
+ * Access token getter/setter
+ */
+ public void setAccessToken(String accessToken) {
+ setAccessToken(mDefaultFileSourcePtr, accessToken);
+ }
+
+ public String getAccessToken() {
+ return getAccessToken(mDefaultFileSourcePtr);
+ }
+
+ private Handler getHandler() {
+ if (handler == null) {
+ handler = new Handler(Looper.getMainLooper());
+ }
+
+ return handler;
+ }
+
+ /**
+ * Retrieve all regions in the offline database.
+ *
+ * The query will be executed asynchronously and the results passed to the given
+ * callback on the main thread.
+ */
+ public void listOfflineRegions(@NonNull final ListOfflineRegionsCallback callback) {
+ listOfflineRegions(mDefaultFileSourcePtr, new ListOfflineRegionsCallback() {
+ @Override
+ public void onList(final OfflineRegion[] offlineRegions) {
+ getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ callback.onList(offlineRegions);
+ }
+ });
+ }
+
+ @Override
+ public void onError(final String error) {
+ getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ callback.onError(error);
+ }
+ });
+ }
+ });
+ }
+
+ /**
+ * Create an offline region in the database.
+ *
+ * When the initial database queries have completed, the provided callback will be
+ * executed on the main thread.
+ *
+ * Note that the resulting region will be in an inactive download state; to begin
+ * downloading resources, call `OfflineRegion.setDownloadState(DownloadState.STATE_ACTIVE)`,
+ * optionally registering an `OfflineRegionObserver` beforehand.
+ */
+ public void createOfflineRegion(
+ @NonNull OfflineRegionDefinition definition,
+ @NonNull OfflineRegionMetadata metadata,
+ @NonNull final CreateOfflineRegionCallback callback) {
+
+ createOfflineRegion(mDefaultFileSourcePtr, definition, metadata, new CreateOfflineRegionCallback() {
+ @Override
+ public void onCreate(final OfflineRegion offlineRegion) {
+ getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ callback.onCreate(offlineRegion);
+ }
+ });
+ }
+
+ @Override
+ public void onError(final String error) {
+ getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ callback.onError(error);
+ }
+ });
+ }
+ });
+ }
+
+ /*
+ * Changing or bypassing this limit without permission from Mapbox is prohibited
+ * by the Mapbox Terms of Service.
+ */
+ public void setOfflineMapboxTileCountLimit(long limit) {
+ setOfflineMapboxTileCountLimit(mDefaultFileSourcePtr, limit);
+ }
+
+
+ /*
+ * Native methods
+ */
+
+ private native long createDefaultFileSource(
+ String cachePath, String assetRoot, long maximumCacheSize);
+
+ private native void setAccessToken(long defaultFileSourcePtr, String accessToken);
+ private native String getAccessToken(long defaultFileSourcePtr);
+
+ private native void listOfflineRegions(
+ long defaultFileSourcePtr, ListOfflineRegionsCallback callback);
+
+ private native void createOfflineRegion(
+ long defaultFileSourcePtr, OfflineRegionDefinition definition,
+ OfflineRegionMetadata metadata, CreateOfflineRegionCallback callback);
+
+ private native void setOfflineMapboxTileCountLimit(
+ long defaultFileSourcePtr, long limit);
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java
new file mode 100644
index 0000000000..9e518f1e6a
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java
@@ -0,0 +1,278 @@
+package com.mapbox.mapboxsdk.offline;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * To use offline maps on mobile, you will first have to create an offline region.
+ * Use OfflineManager.createOfflineRegion() to create a new offline region.
+ */
+public class OfflineRegion {
+
+ private final static String LOG_TAG = "OfflineRegion";
+
+ // Parent OfflineManager
+ private OfflineManager offlineManager;
+
+ // Members
+ private long mId = 0;
+ private OfflineRegionDefinition mDefinition = null;
+ private OfflineRegionMetadata mMetadata = null;
+
+ // Holds the pointer to JNI OfflineRegion
+ private long mOfflineRegionPtr = 0;
+
+ // Makes sure callbacks come back to the main thread
+ private Handler handler;
+
+ /**
+ * A region can have a single observer, which gets notified whenever a change
+ * to the region's status occurs.
+ */
+ public interface OfflineRegionObserver {
+ /**
+ * Implement this method to be notified of a change in the status of an
+ * offline region. Status changes include any change in state of the members
+ * of OfflineRegionStatus.
+ *
+ * This method will be executed on the main thread.
+ */
+ void onStatusChanged(OfflineRegionStatus status);
+
+ /**
+ * Implement this method to be notified of errors encountered while downloading
+ * regional resources. Such errors may be recoverable; for example the implementation
+ * will attempt to re-request failed resources based on an exponential backoff
+ * algorithm, or when it detects that network access has been restored.
+ *
+ * This method will be executed on the main thread.
+ */
+ void onError(OfflineRegionError error);
+
+ /*
+ * Implement this method to be notified when the limit on the number of Mapbox
+ * tiles stored for offline regions has been reached.
+ *
+ * Once the limit has been reached, the SDK will not download further offline
+ * tiles from Mapbox APIs until existing tiles have been removed. Contact your
+ * Mapbox sales representative to raise the limit.
+ *
+ * This limit does not apply to non-Mapbox tile sources.
+ *
+ * This method will be executed on the main thread.
+ */
+ void mapboxTileCountLimitExceeded(long limit);
+ }
+
+ /*
+ * Callbacks
+ */
+
+ public interface OfflineRegionStatusCallback {
+ void onStatus(OfflineRegionStatus status);
+ void onError(String error);
+ }
+
+ public interface OfflineRegionDeleteCallback {
+ void onDelete();
+ void onError(String error);
+ }
+
+ /**
+ * A region is either inactive (not downloading, but previously-downloaded
+ * resources are available for use), or active (resources are being downloaded
+ * or will be downloaded, if necessary, when network access is available).
+ *
+ * This state is independent of whether or not the complete set of resources
+ * is currently available for offline use. To check if that is the case, use
+ * `OfflineRegionStatus.isComplete()`.
+ */
+
+ @IntDef({STATE_INACTIVE, STATE_ACTIVE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DownloadState {}
+
+ public static final int STATE_INACTIVE = 0;
+ public static final int STATE_ACTIVE = 1;
+
+ /*
+ * Constructor
+ */
+
+ private OfflineRegion() {
+ // For JNI use only, to create a new offline region, use
+ // OfflineManager.createOfflineRegion() instead.
+ }
+
+ /*
+ * Getters
+ */
+
+ public long getID() {
+ return mId;
+ }
+
+ public OfflineRegionDefinition getDefinition() {
+ return mDefinition;
+ }
+
+ public OfflineRegionMetadata getMetadata() {
+ return mMetadata;
+ }
+
+ private Handler getHandler() {
+ if (handler == null) {
+ handler = new Handler(Looper.getMainLooper());
+ }
+
+ return handler;
+ }
+
+ /**
+ * Register an observer to be notified when the state of the region changes.
+ */
+ public void setObserver(@NonNull final OfflineRegionObserver observer) {
+ setOfflineRegionObserver(this, new OfflineRegionObserver() {
+ @Override
+ public void onStatusChanged(final OfflineRegionStatus status) {
+ getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ observer.onStatusChanged(status);
+ }
+ });
+ }
+
+ @Override
+ public void onError(final OfflineRegionError error) {
+ getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ observer.onError(error);
+ }
+ });
+ }
+
+ @Override
+ public void mapboxTileCountLimitExceeded(final long limit) {
+ getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ observer.mapboxTileCountLimitExceeded(limit);
+ }
+ });
+ }
+ });
+ }
+
+ /**
+ * Pause or resume downloading of regional resources.
+ */
+ public void setDownloadState(@DownloadState int state) {
+ setOfflineRegionDownloadState(this, state);
+ }
+
+ /**
+ * Retrieve the current status of the region. The query will be executed
+ * asynchronously and the results passed to the given callback which will be
+ * executed on the main thread.
+ */
+ public void getStatus(@NonNull final OfflineRegionStatusCallback callback) {
+ getOfflineRegionStatus(this, new OfflineRegionStatusCallback() {
+ @Override
+ public void onStatus(final OfflineRegionStatus status) {
+ getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ callback.onStatus(status);
+ }
+ });
+ }
+
+ @Override
+ public void onError(final String error) {
+ getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ callback.onError(error);
+ }
+ });
+ }
+ });
+ }
+
+ /**
+ * Remove an offline region from the database and perform any resources evictions
+ * necessary as a result.
+ *
+ * Eviction works by removing the least-recently requested resources not also required
+ * by other regions, until the database shrinks below a certain size.
+ *
+ * When the operation is complete or encounters an error, the given callback will be
+ * executed on the main thread.
+ */
+ public void delete(@NonNull final OfflineRegionDeleteCallback callback) {
+ deleteOfflineRegion(this, new OfflineRegionDeleteCallback() {
+ @Override
+ public void onDelete() {
+ getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ callback.onDelete();
+ OfflineRegion.this.finalize();
+ }
+ });
+ }
+
+ @Override
+ public void onError(final String error) {
+ getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ callback.onError(error);
+ }
+ });
+ }
+ });
+ }
+
+ @Override
+ protected void finalize() {
+ try {
+ super.finalize();
+ destroyOfflineRegion(mOfflineRegionPtr);
+ mOfflineRegionPtr = 0;
+ } catch (Throwable throwable) {
+ Log.e(LOG_TAG, "Failed to finalize OfflineRegion: " + throwable.getMessage());
+ }
+ }
+
+ /*
+ * Native methods
+ */
+
+ private native void destroyOfflineRegion(long offlineRegionPtr);
+
+ private native void setOfflineRegionObserver(
+ OfflineRegion offlineRegion,
+ OfflineRegionObserver observerCallback);
+
+ private native void setOfflineRegionDownloadState(
+ OfflineRegion offlineRegion,
+ @DownloadState int offlineRegionDownloadState);
+
+ private native void getOfflineRegionStatus(
+ OfflineRegion offlineRegion,
+ OfflineRegionStatusCallback statusCallback);
+
+ private native void deleteOfflineRegion(
+ OfflineRegion offlineRegion,
+ OfflineRegionDeleteCallback deleteCallback);
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionDefinition.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionDefinition.java
new file mode 100644
index 0000000000..0e7fb38e1c
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionDefinition.java
@@ -0,0 +1,9 @@
+package com.mapbox.mapboxsdk.offline;
+
+/**
+ * This is the interface that all Offline Region definitions have to implement.
+ *
+ * For the present, a tile pyramid is the only type of offline region.
+ */
+public interface OfflineRegionDefinition {
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionError.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionError.java
new file mode 100644
index 0000000000..e7a57379c5
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionError.java
@@ -0,0 +1,53 @@
+package com.mapbox.mapboxsdk.offline;
+
+import android.support.annotation.StringDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * An Offline Region error
+ */
+public class OfflineRegionError {
+
+ /**
+ * Error code, as a string, self-explanatory.
+ */
+ @StringDef({REASON_SUCCESS, REASON_NOT_FOUND, REASON_SERVER, REASON_CONNECTION, REASON_OTHER})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ErrorReason {}
+
+ public static final String REASON_SUCCESS = "REASON_SUCCESS";
+ public static final String REASON_NOT_FOUND = "REASON_NOT_FOUND";
+ public static final String REASON_SERVER = "REASON_SERVER";
+ public static final String REASON_CONNECTION = "REASON_CONNECTION";
+ public static final String REASON_OTHER = "REASON_OTHER";
+
+ private @ErrorReason String reason;
+
+ /**
+ /* An error message from the request handler, e.g. a server message or a system message
+ /* informing the user about the reason for the failure.
+ */
+ private String message;
+
+ /*
+ * Constructors
+ */
+
+ private OfflineRegionError() {
+ // For JNI use only
+ }
+
+ /*
+ * Getters
+ */
+
+ public @ErrorReason String getReason() {
+ return reason;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionMetadata.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionMetadata.java
new file mode 100644
index 0000000000..bbea4580f8
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionMetadata.java
@@ -0,0 +1,63 @@
+package com.mapbox.mapboxsdk.offline;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+/**
+ * Arbitrary binary region metadata. The contents are opaque to the SDK implementation;
+ * it just stores and retrieves a byte[].
+ */
+public class OfflineRegionMetadata {
+
+ private byte[] metadata;
+
+ /*
+ * Constructor
+ */
+
+ public OfflineRegionMetadata(byte[] metadata) {
+ this.metadata = metadata;
+ }
+
+ /*
+ * Getters and setters
+ */
+
+ public byte[] getMetadata() {
+ return metadata;
+ }
+
+ public void setMetadata(byte[] metadata) {
+ this.metadata = metadata;
+ }
+
+ /*
+ * Overrides
+ */
+
+ @Override
+ public String toString() {
+ return "OfflineRegionMetadata{metadata=" + metadata + "}";
+ }
+
+ /*
+ * byte[] utils
+ */
+
+ public static byte[] serialize(Object obj) throws IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ObjectOutputStream os = new ObjectOutputStream(out);
+ os.writeObject(obj);
+ return out.toByteArray();
+ }
+
+ public static Object deserialize(byte[] data) throws IOException, ClassNotFoundException {
+ ByteArrayInputStream in = new ByteArrayInputStream(data);
+ ObjectInputStream is = new ObjectInputStream(in);
+ return is.readObject();
+ }
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionStatus.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionStatus.java
new file mode 100644
index 0000000000..e65a20f18e
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionStatus.java
@@ -0,0 +1,84 @@
+package com.mapbox.mapboxsdk.offline;
+
+/**
+ * A region's status includes its active/inactive state as well as counts
+ * of the number of resources that have completed downloading, their total
+ * size in bytes, and the total number of resources that are required.
+ *
+ * Note that the total required size in bytes is not currently available. A
+ * future API release may provide an estimate of this number.
+ */
+public class OfflineRegionStatus {
+
+ @OfflineRegion.DownloadState private int downloadState = OfflineRegion.STATE_INACTIVE;
+
+ /**
+ * The number of resources that have been fully downloaded and are ready for
+ * offline access.
+ */
+ private long completedResourceCount = 0;
+
+ /**
+ * The cumulative size, in bytes, of all resources that have been fully downloaded.
+ */
+ private long completedResourceSize = 0;
+
+ /**
+ * The number of resources that are known to be required for this region. See the
+ * documentation for `requiredResourceCountIsPrecise` for an important caveat
+ * about this number.
+ */
+ private long requiredResourceCount = 0;
+
+ /**
+ * This property is true when the value of requiredResourceCount is a precise
+ * count of the number of required resources, and false when it is merely a lower
+ * bound.
+ *
+ * Specifically, it is false during early phases of an offline download. Once
+ * style and tile sources have been downloaded, it is possible to calculate the
+ * precise number of required resources, at which point it is set to true.
+ */
+ private boolean requiredResourceCountIsPrecise = true;
+
+ /*
+ * Use setObserver(OfflineRegionObserver observer) to obtain a OfflineRegionStatus object.
+ */
+
+ private OfflineRegionStatus() {
+ // For JNI use only
+ }
+
+ /*
+ * Is the region complete?
+ */
+
+ public boolean isComplete() {
+ return (completedResourceCount == requiredResourceCount);
+ }
+
+ /*
+ * Getters
+ */
+
+ public @OfflineRegion.DownloadState int getDownloadState() {
+ return downloadState;
+ }
+
+ public long getCompletedResourceCount() {
+ return completedResourceCount;
+ }
+
+ public long getCompletedResourceSize() {
+ return completedResourceSize;
+ }
+
+ public long getRequiredResourceCount() {
+ return requiredResourceCount;
+ }
+
+ public boolean isRequiredResourceCountPrecise() {
+ return requiredResourceCountIsPrecise;
+ }
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition.java
new file mode 100644
index 0000000000..5a0be6b33f
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition.java
@@ -0,0 +1,65 @@
+package com.mapbox.mapboxsdk.offline;
+
+import com.mapbox.mapboxsdk.geometry.LatLngBounds;
+
+/**
+ * An offline region defined by a style URL, geographic bounding box, zoom range, and
+ * device pixel ratio.
+ *
+ * Both minZoom and maxZoom must be ≥ 0, and maxZoom must be ≥ minZoom.
+ *
+ * maxZoom may be ∞, in which case for each tile source, the region will include
+ * tiles from minZoom up to the maximum zoom level provided by that source.
+ *
+ * pixelRatio must be ≥ 0 and should typically be 1.0 or 2.0.
+ */
+public class OfflineTilePyramidRegionDefinition implements OfflineRegionDefinition {
+
+ private String styleURL;
+ private LatLngBounds bounds;
+ private double minZoom;
+ private double maxZoom;
+ private float pixelRatio;
+
+ /*
+ * Constructors
+ */
+
+ private OfflineTilePyramidRegionDefinition() {
+ // For JNI use only
+ }
+
+ public OfflineTilePyramidRegionDefinition(
+ String styleURL, LatLngBounds bounds, double minZoom, double maxZoom, float pixelRatio) {
+ this.styleURL = styleURL;
+ this.bounds = bounds;
+ this.minZoom = minZoom;
+ this.maxZoom = maxZoom;
+ this.pixelRatio = pixelRatio;
+ }
+
+ /*
+ * Getters
+ */
+
+ public String getStyleURL() {
+ return styleURL;
+ }
+
+ public LatLngBounds getBounds() {
+ return bounds;
+ }
+
+ public double getMinZoom() {
+ return minZoom;
+ }
+
+ public double getMaxZoom() {
+ return maxZoom;
+ }
+
+ public float getPixelRatio() {
+ return pixelRatio;
+ }
+
+}