# 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
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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 {
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,7 +21,6 @@
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
@@ -91,22 +90,24 @@
|
||||
android:label="@string/activity_dynamic_marker" />
|
||||
<activity
|
||||
android:name=".MapPaddingActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:label="@string/activity_map_padding" />
|
||||
android:label="@string/activity_map_padding"
|
||||
android:screenOrientation="portrait" />
|
||||
<activity
|
||||
android:name=".OfflineActivity"
|
||||
android:label="@string/activity_offline" />
|
||||
|
||||
<meta-data
|
||||
android:name="com.mapbox.AccessToken"
|
||||
android:value="" />
|
||||
|
||||
<meta-data
|
||||
android:name="com.mapbox.TestEventsServer"
|
||||
android:value="https://cloudfront-staging.tilestream.net" />
|
||||
|
||||
<meta-data
|
||||
android:name="com.mapbox.TestEventsAccessToken"
|
||||
android:value="sk.eyJ1IjoiYmxlZWdlIiwiYSI6InNpcml1c2x5In0.KyT-boMyC_xZYTYojTc8zg" />
|
||||
|
||||
<service android:name="com.mapbox.mapboxsdk.telemetry.TelemetryService" />
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
||||
@@ -472,6 +472,10 @@ public class MainActivity extends AppCompatActivity {
|
||||
startActivity(new Intent(getApplicationContext(),MapPaddingActivity.class));
|
||||
return true;
|
||||
|
||||
case R.id.action_offline:
|
||||
startActivity(new Intent(getApplicationContext(), OfflineActivity.class));
|
||||
return true;
|
||||
|
||||
default:
|
||||
return changeMapStyle(menuItem.getItemId());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,364 @@
|
||||
package com.mapbox.mapboxsdk.testapp;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.util.Log;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.mapbox.mapboxsdk.camera.CameraPosition;
|
||||
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
|
||||
import com.mapbox.mapboxsdk.constants.Style;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
|
||||
import com.mapbox.mapboxsdk.maps.MapView;
|
||||
import com.mapbox.mapboxsdk.maps.MapboxMap;
|
||||
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
|
||||
import com.mapbox.mapboxsdk.offline.OfflineManager;
|
||||
import com.mapbox.mapboxsdk.offline.OfflineRegion;
|
||||
import com.mapbox.mapboxsdk.offline.OfflineTilePyramidRegionDefinition;
|
||||
import com.mapbox.mapboxsdk.offline.OfflineRegionError;
|
||||
import com.mapbox.mapboxsdk.offline.OfflineRegionMetadata;
|
||||
import com.mapbox.mapboxsdk.offline.OfflineRegionStatus;
|
||||
import com.mapbox.mapboxsdk.testapp.offline.DownloadRegionDialog;
|
||||
import com.mapbox.mapboxsdk.testapp.offline.ListRegionsDialog;
|
||||
import com.mapbox.mapboxsdk.utils.ApiAccess;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class OfflineActivity extends AppCompatActivity
|
||||
implements DownloadRegionDialog.DownloadRegionDialogListener {
|
||||
|
||||
private final static String LOG_TAG = "OfflineActivity";
|
||||
|
||||
private final static String KEY_REGION_NAME = "KEY_REGION_NAME";
|
||||
|
||||
/*
|
||||
* UI elements
|
||||
*/
|
||||
private MapView mMapView;
|
||||
private MapboxMap mMapboxMap;
|
||||
private ProgressBar mProgressBar;
|
||||
private Button downloadRegion;
|
||||
private Button listRegions;
|
||||
|
||||
private boolean isEndNotified;
|
||||
|
||||
/*
|
||||
* Offline objects
|
||||
*/
|
||||
private OfflineManager mOfflineManager;
|
||||
private OfflineRegion mOfflineRegion;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_offline);
|
||||
|
||||
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if (actionBar != null) {
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
actionBar.setDisplayShowHomeEnabled(true);
|
||||
}
|
||||
|
||||
// Set up map
|
||||
mMapView = (MapView) findViewById(R.id.mapView);
|
||||
mMapView.setAccessToken(ApiAccess.getToken(this));
|
||||
mMapView.onCreate(savedInstanceState);
|
||||
mMapView.getMapAsync(new OnMapReadyCallback() {
|
||||
@Override
|
||||
public void onMapReady(@NonNull MapboxMap mapboxMap) {
|
||||
Log.d(LOG_TAG, "Map is ready");
|
||||
mMapboxMap = mapboxMap;
|
||||
|
||||
// Set style
|
||||
mapboxMap.setStyle(Style.MAPBOX_STREETS);
|
||||
|
||||
// Set initial position to UNHQ in NYC
|
||||
mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(
|
||||
new CameraPosition.Builder()
|
||||
.target(new LatLng(40.749851, -73.967966))
|
||||
.zoom(14)
|
||||
.bearing(0)
|
||||
.tilt(0)
|
||||
.build()));
|
||||
}
|
||||
});
|
||||
|
||||
// The progress bar
|
||||
mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
|
||||
|
||||
// Set up button listeners
|
||||
downloadRegion = (Button) findViewById(R.id.button_download_region);
|
||||
downloadRegion.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
handleDownloadRegion();
|
||||
}
|
||||
});
|
||||
|
||||
listRegions = (Button) findViewById(R.id.button_list_regions);
|
||||
listRegions.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
handleListRegions();
|
||||
}
|
||||
});
|
||||
|
||||
// Set up the OfflineManager
|
||||
mOfflineManager = OfflineManager.getInstance(this);
|
||||
mOfflineManager.setAccessToken(ApiAccess.getToken(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
mMapView.onStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
mMapView.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
mMapView.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
mMapView.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
mMapView.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
mMapView.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLowMemory() {
|
||||
super.onLowMemory();
|
||||
mMapView.onLowMemory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
onBackPressed();
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Buttons logic
|
||||
*/
|
||||
|
||||
private void handleDownloadRegion() {
|
||||
Log.d(LOG_TAG, "handleDownloadRegion");
|
||||
|
||||
// Show dialog
|
||||
DownloadRegionDialog downloadRegionDialog = new DownloadRegionDialog();
|
||||
downloadRegionDialog.show(getSupportFragmentManager(), "download");
|
||||
}
|
||||
|
||||
private void handleListRegions() {
|
||||
Log.d(LOG_TAG, "handleListRegions");
|
||||
|
||||
// Query the DB asynchronously
|
||||
mOfflineManager.listOfflineRegions(new OfflineManager.ListOfflineRegionsCallback() {
|
||||
@Override
|
||||
public void onList(OfflineRegion[] offlineRegions) {
|
||||
// Check result
|
||||
if (offlineRegions == null || offlineRegions.length == 0) {
|
||||
Log.d(LOG_TAG, "You have no regions yet.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get regions info
|
||||
ArrayList<String> offlineRegionsNames = new ArrayList<>();
|
||||
for (OfflineRegion offlineRegion : offlineRegions) {
|
||||
offlineRegionsNames.add(getRegionName(offlineRegion));
|
||||
}
|
||||
|
||||
// Create args
|
||||
Bundle args = new Bundle();
|
||||
args.putStringArrayList(ListRegionsDialog.ITEMS, offlineRegionsNames);
|
||||
|
||||
// Show dialog
|
||||
ListRegionsDialog listRegionsDialog = new ListRegionsDialog();
|
||||
listRegionsDialog.setArguments(args);
|
||||
listRegionsDialog.show(getSupportFragmentManager(), "list");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String error) {
|
||||
Log.e(LOG_TAG, "Error: " + error);
|
||||
}
|
||||
|
||||
private String getRegionName(OfflineRegion offlineRegion) {
|
||||
String regionName = "Region " + offlineRegion.getID();
|
||||
|
||||
try {
|
||||
byte[] metadata = offlineRegion.getMetadata().getMetadata();
|
||||
HashMap<String, String> data = (HashMap<String, String>) OfflineRegionMetadata.deserialize(metadata);
|
||||
regionName = data.get(KEY_REGION_NAME);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Failed to decode metadata: " + e.getMessage());
|
||||
}
|
||||
|
||||
return regionName;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Dialogs
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void onDownloadRegionDialogPositiveClick(final String regionName) {
|
||||
Log.d(LOG_TAG, "Download started: " + regionName);
|
||||
|
||||
// Start progress bar
|
||||
startProgress();
|
||||
|
||||
// Definition
|
||||
String styleURL = mMapboxMap.getStyleUrl();
|
||||
LatLngBounds bounds = mMapboxMap.getProjection().getVisibleRegion().latLngBounds;
|
||||
double minZoom = 14; // Switch to dynamic once map refactor is complete
|
||||
double maxZoom = 16; // Switch to dynamic once map refactor is complete
|
||||
float pixelRatio = this.getResources().getDisplayMetrics().density;
|
||||
OfflineTilePyramidRegionDefinition definition = new OfflineTilePyramidRegionDefinition(
|
||||
styleURL, bounds, minZoom, maxZoom, pixelRatio);
|
||||
|
||||
// Sample way of encoding metadata
|
||||
OfflineRegionMetadata metadata = null;
|
||||
try {
|
||||
HashMap<String, String> data = new HashMap<>();
|
||||
data.put(KEY_REGION_NAME, regionName);
|
||||
byte[] dataEncoded = OfflineRegionMetadata.serialize(data);
|
||||
metadata = new OfflineRegionMetadata(dataEncoded);
|
||||
} catch (IOException e) {
|
||||
Log.e(LOG_TAG, "Metadata encoding failed: " + e.getMessage());
|
||||
}
|
||||
|
||||
// Create region
|
||||
mOfflineManager.createOfflineRegion(definition, metadata, new OfflineManager.CreateOfflineRegionCallback() {
|
||||
@Override
|
||||
public void onCreate(OfflineRegion offlineRegion) {
|
||||
Log.d(LOG_TAG, "Offline region created: " + regionName);
|
||||
mOfflineRegion = offlineRegion;
|
||||
launchDownload();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String error) {
|
||||
Log.e(LOG_TAG, "Error: " + error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void launchDownload() {
|
||||
// Set an observer
|
||||
mOfflineRegion.setObserver(new OfflineRegion.OfflineRegionObserver() {
|
||||
@Override
|
||||
public void onStatusChanged(OfflineRegionStatus status) {
|
||||
// Compute a percentage
|
||||
double percentage = status.getRequiredResourceCount() >= 0 ?
|
||||
(100.0 * status.getCompletedResourceCount() / status.getRequiredResourceCount()) :
|
||||
0.0;
|
||||
|
||||
if (status.isComplete() || percentage >= 98.0 /* Known issue */) {
|
||||
// Download complete
|
||||
endProgress("Region downloaded successfully.");
|
||||
return;
|
||||
} else if (status.isRequiredResourceCountPrecise()) {
|
||||
// Switch to determinate state
|
||||
setPercentage((int) Math.round(percentage));
|
||||
}
|
||||
|
||||
// Debug
|
||||
Log.d(LOG_TAG, String.format("%s/%s resources; %s bytes downloaded.",
|
||||
String.valueOf(status.getCompletedResourceCount()),
|
||||
String.valueOf(status.getRequiredResourceCount()),
|
||||
String.valueOf(status.getCompletedResourceSize())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(OfflineRegionError error) {
|
||||
Log.e(LOG_TAG, "onError reason: " + error.getReason());
|
||||
Log.e(LOG_TAG, "onError message: " + error.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mapboxTileCountLimitExceeded(long limit) {
|
||||
Log.e(LOG_TAG, "Mapbox tile count limit exceeded: " + limit);
|
||||
}
|
||||
});
|
||||
|
||||
// Change the region state
|
||||
mOfflineRegion.setDownloadState(OfflineRegion.STATE_ACTIVE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Progress bar
|
||||
*/
|
||||
|
||||
private void startProgress() {
|
||||
// Disable buttons
|
||||
downloadRegion.setEnabled(false);
|
||||
listRegions.setEnabled(false);
|
||||
|
||||
// Start and show the progress bar
|
||||
isEndNotified = false;
|
||||
mProgressBar.setIndeterminate(true);
|
||||
mProgressBar.setVisibility(View.VISIBLE);
|
||||
}
|
||||
private void setPercentage(final int percentage) {
|
||||
mProgressBar.setIndeterminate(false);
|
||||
mProgressBar.setProgress(percentage);
|
||||
}
|
||||
|
||||
private void endProgress(final String message) {
|
||||
// Don't notify more than once
|
||||
if (isEndNotified) return;
|
||||
|
||||
// Enable buttons
|
||||
downloadRegion.setEnabled(true);
|
||||
listRegions.setEnabled(true);
|
||||
|
||||
// Stop and hide the progress bar
|
||||
isEndNotified = true;
|
||||
mProgressBar.setIndeterminate(false);
|
||||
mProgressBar.setVisibility(View.GONE);
|
||||
|
||||
// Show a toast
|
||||
Toast.makeText(OfflineActivity.this, message, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.mapbox.mapboxsdk.testapp.offline;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.util.Log;
|
||||
import android.widget.EditText;
|
||||
|
||||
import com.mapbox.mapboxsdk.testapp.R;
|
||||
|
||||
/**
|
||||
* Created by antonio on 2/17/16.
|
||||
*/
|
||||
public class DownloadRegionDialog extends DialogFragment {
|
||||
|
||||
private final static String LOG_TAG = "DownloadRegionDialog";
|
||||
|
||||
public interface DownloadRegionDialogListener {
|
||||
void onDownloadRegionDialogPositiveClick(String regionName);
|
||||
}
|
||||
|
||||
DownloadRegionDialogListener mListener;
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
mListener = (DownloadRegionDialogListener) activity;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
|
||||
// Let the user choose a name for the region
|
||||
final EditText regionNameEdit = new EditText(getActivity());
|
||||
|
||||
builder.setTitle("Choose a name for the region")
|
||||
.setIcon(R.drawable.ic_airplanemode_active_black_24dp)
|
||||
.setView(regionNameEdit)
|
||||
.setPositiveButton("Start", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
String regionName = regionNameEdit.getText().toString();
|
||||
mListener.onDownloadRegionDialogPositiveClick(regionName);
|
||||
}
|
||||
}).setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
Log.d(LOG_TAG, "Download cancelled.");
|
||||
}
|
||||
});
|
||||
|
||||
return builder.create();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.mapbox.mapboxsdk.testapp.offline;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.util.Log;
|
||||
|
||||
import com.mapbox.mapboxsdk.testapp.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Created by antonio on 2/17/16.
|
||||
*/
|
||||
public class ListRegionsDialog extends DialogFragment {
|
||||
|
||||
private final static String LOG_TAG = "ListRegionsDialog";
|
||||
|
||||
public final static String ITEMS = "ITEMS";
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
|
||||
// Read args
|
||||
Bundle args = getArguments();
|
||||
ArrayList<String> offlineRegionsNames = (args == null ? null : args.getStringArrayList(ITEMS));
|
||||
CharSequence[] items = offlineRegionsNames.toArray(new CharSequence[offlineRegionsNames.size()]);
|
||||
|
||||
builder.setTitle("List of offline regions")
|
||||
.setIcon(R.drawable.ic_airplanemode_active_black_24dp)
|
||||
.setItems(items, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
Log.d(LOG_TAG, "Selected item: " + which);
|
||||
}
|
||||
})
|
||||
.setPositiveButton("Accept", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
Log.d(LOG_TAG, "Dialog dismissed");
|
||||
}
|
||||
});
|
||||
|
||||
return builder.create();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M10.18,9"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M21,16v-2l-8,-5V3.5c0,-0.83 -0.67,-1.5 -1.5,-1.5S10,2.67 10,3.5V9l-8,5v2l8,-2.5V19l-2,1.5V22l3.5,-1 3.5,1v-1.5L13,19v-5.5l8,2.5z"/>
|
||||
</vector>
|
||||
@@ -1,9 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<android.support.v7.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<android.support.v7.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="@color/primary"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress_bar"
|
||||
android:visibility="gone"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="25dp"
|
||||
android:layout_below="@+id/toolbar"
|
||||
style="@android:style/Widget.Material.ProgressBar.Horizontal" />
|
||||
|
||||
<com.mapbox.mapboxsdk.maps.MapView
|
||||
android:id="@+id/mapView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@+id/progress_bar" />
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp"
|
||||
android:text="@string/button_download_region"
|
||||
android:id="@+id/button_download_region"
|
||||
android:layout_margin="@dimen/fab_margin"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:background="@color/white"/>
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp"
|
||||
android:text="@string/button_list_regions"
|
||||
android:id="@+id/button_list_regions"
|
||||
android:layout_alignBottom="@+id/button_download_region"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginRight="@dimen/fab_margin"
|
||||
android:background="@color/white"/>
|
||||
|
||||
</RelativeLayout>
|
||||
@@ -72,6 +72,12 @@
|
||||
android:title="@string/navdrawer_menu_title_individual_tests">
|
||||
<menu>
|
||||
|
||||
<item
|
||||
android:id="@+id/action_offline"
|
||||
android:checkable="false"
|
||||
android:icon="@drawable/ic_airplanemode_active_black_24dp"
|
||||
android:title="@string/action_offline" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_mapboxmap"
|
||||
android:checkable="false"
|
||||
|
||||
@@ -6,5 +6,4 @@
|
||||
<dimen name="map_padding_left">96dp</dimen>
|
||||
<dimen name="map_padding_bottom">256dp</dimen>
|
||||
<dimen name="map_padding_right">32dp</dimen>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
<string name="activity_scroll_by">Scroll By Activity</string>
|
||||
<string name="activity_dynamic_marker">Dynamic Marker Activity</string>
|
||||
<string name="activity_map_padding">Map Padding Activity</string>
|
||||
<string name="activity_offline">Offline Map Activity</string>
|
||||
|
||||
<string name="navdrawer_menu_title_mainactivity_controls">Main Activity Controls</string>
|
||||
<string name="navdrawer_menu_title_mainactivity_styles">Main Activity Styles</string>
|
||||
@@ -56,6 +57,7 @@
|
||||
<string name="action_double_mapview">Double MapView</string>
|
||||
<string name="action_dynamic_marker">Dynamic Marker</string>
|
||||
<string name="action_map_padding">Map Padding</string>
|
||||
<string name="action_offline">Offline Map</string>
|
||||
|
||||
<string name="button_camera_move">Move</string>
|
||||
<string name="button_camera_ease">Ease</string>
|
||||
@@ -98,5 +100,7 @@
|
||||
|
||||
<string name="scrollby_x_value">X: %1$d</string>
|
||||
<string name="scrollby_y_value">Y: %1$d</string>
|
||||
<string name="button_download_region">Download region</string>
|
||||
<string name="button_list_regions">List regions</string>
|
||||
|
||||
</resources>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -103,6 +103,66 @@ extern jclass httpRequestClass;
|
||||
extern jmethodID httpRequestStartId;
|
||||
extern jmethodID httpRequestCancelId;
|
||||
|
||||
// Offline declarations start
|
||||
|
||||
extern jclass offlineManagerClass;
|
||||
extern jfieldID offlineManagerClassPtrId;
|
||||
|
||||
extern jclass listOfflineRegionsCallbackClass;
|
||||
extern jmethodID listOnListMethodId;
|
||||
extern jmethodID listOnErrorMethodId;
|
||||
|
||||
extern jclass offlineRegionClass;
|
||||
extern jfieldID offlineRegionOfflineManagerId;
|
||||
extern jfieldID offlineRegionIdId;
|
||||
extern jfieldID offlineRegionDefinitionId;
|
||||
extern jfieldID offlineRegionMetadataId;
|
||||
extern jfieldID offlineRegionPtrId;
|
||||
|
||||
extern jclass offlineRegionDefinitionClass;
|
||||
extern jmethodID offlineRegionDefinitionConstructorId;
|
||||
extern jfieldID offlineRegionDefinitionStyleURLId;
|
||||
extern jfieldID offlineRegionDefinitionBoundsId;
|
||||
extern jfieldID offlineRegionDefinitionMinZoomId;
|
||||
extern jfieldID offlineRegionDefinitionMaxZoomId;
|
||||
extern jfieldID offlineRegionDefinitionPixelRatioId;
|
||||
|
||||
extern jclass offlineRegionMetadataClass;
|
||||
extern jmethodID offlineRegionMetadataConstructorId;
|
||||
extern jfieldID offlineRegionMetadataMetadataId;
|
||||
|
||||
extern jclass createOfflineRegionCallbackClass;
|
||||
extern jmethodID createOnCreateMethodId;
|
||||
extern jmethodID createOnErrorMethodId;
|
||||
|
||||
extern jclass offlineRegionObserverClass;
|
||||
extern jmethodID offlineRegionObserveronStatusChangedId;
|
||||
extern jmethodID offlineRegionObserveronErrorId;
|
||||
extern jmethodID offlineRegionObserveronLimitId;
|
||||
|
||||
extern jclass offlineRegionStatusClass;
|
||||
extern jmethodID offlineRegionStatusConstructorId;
|
||||
extern jfieldID offlineRegionStatusDownloadStateId;
|
||||
extern jfieldID offlineRegionStatusCompletedResourceCountId;
|
||||
extern jfieldID offlineRegionStatusCompletedResourceSizeId;
|
||||
extern jfieldID offlineRegionStatusRequiredResourceCountId;
|
||||
extern jfieldID offlineRegionStatusRequiredResourceCountIsIndeterminateId;
|
||||
|
||||
extern jclass offlineRegionErrorClass;
|
||||
extern jmethodID offlineRegionErrorConstructorId;
|
||||
extern jfieldID offlineRegionErrorReasonId;
|
||||
extern jfieldID offlineRegionErrorMessageId;
|
||||
|
||||
extern jclass offlineRegionStatusCallbackClass;
|
||||
extern jmethodID offlineRegionStatusOnStatusId;
|
||||
extern jmethodID offlineRegionStatusOnErrorId;
|
||||
|
||||
extern jclass offlineRegionDeleteCallbackClass;
|
||||
extern jmethodID offlineRegionDeleteOnDeleteId;
|
||||
extern jmethodID offlineRegionDeleteOnErrorId;
|
||||
|
||||
// Offline declarations end
|
||||
|
||||
extern bool throw_jni_error(JNIEnv *env, const char *msg);
|
||||
extern bool attach_jni_thread(JavaVM* vm, JNIEnv** env, std::string threadName);
|
||||
extern void detach_jni_thread(JavaVM* vm, JNIEnv** env, bool detach);
|
||||
|
||||
Reference in New Issue
Block a user