summaryrefslogtreecommitdiff
path: root/platform/android/MapboxGLAndroidSDK/src/main/java/com
diff options
context:
space:
mode:
Diffstat (limited to 'platform/android/MapboxGLAndroidSDK/src/main/java/com')
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java81
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java28
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java11
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/log/Logger.java117
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java13
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java14
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/http/HttpRequestImpl.java12
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java257
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java75
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java1
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java12
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MapFragmentUtils.java2
13 files changed, 558 insertions, 69 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java
index c4cc6d0196..5ff4104ea8 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java
@@ -4,13 +4,13 @@ import android.graphics.Point;
import android.graphics.PointF;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
-
import android.support.annotation.Nullable;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.Projection;
import com.mapbox.mapboxsdk.maps.UiSettings;
+import junit.framework.Assert;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -45,9 +45,11 @@ public final class CameraUpdateFactory {
/**
* Returns a CameraUpdate that transforms the camera such that the specified
- * latitude/longitude bounds are centered on screen at the greatest possible zoom level.
+ * latitude/longitude bounds are centered on screen at the greatest possible zoom level while maintaining
+ * current camera position bearing and tilt values.
+ * <p>
* You can specify padding, in order to inset the bounding box from the map view's edges.
- * The returned CameraUpdate has a bearing of 0 and a tilt of 0.
+ * </p>
*
* @param bounds Bounds to match Camera position with
* @param padding Padding added to the bounds
@@ -59,9 +61,29 @@ public final class CameraUpdateFactory {
/**
* Returns a CameraUpdate that transforms the camera such that the specified
- * latitude/longitude bounds are centered on screen at the greatest possible zoom level.
+ * latitude/longitude bounds are centered on screen at the greatest possible zoom level while using
+ * provided bearing and tilt values.
+ * <p>
+ * You can specify padding, in order to inset the bounding box from the map view's edges.
+ * </p>
+ *
+ * @param bounds Bounds to match Camera position with
+ * @param bearing Bearing to take in account when generating the bounds
+ * @param tilt Tilt to take in account when generating the bounds
+ * @param padding Padding added to the bounds
+ * @return CameraUpdate Final Camera Position
+ */
+ public static CameraUpdate newLatLngBounds(@NonNull LatLngBounds bounds, double bearing, double tilt, int padding) {
+ return newLatLngBounds(bounds, bearing, tilt, padding, padding, padding, padding);
+ }
+
+ /**
+ * Returns a CameraUpdate that transforms the camera such that the specified
+ * latitude/longitude bounds are centered on screen at the greatest possible zoom level while maintaining
+ * current camera position bearing and tilt values.
+ * <p>
* You can specify padding, in order to inset the bounding box from the map view's edges.
- * The returned CameraUpdate has a bearing of 0 and a tilt of 0.
+ * </p>
*
* @param bounds Bounds to base the Camera position out of
* @param paddingLeft Padding left of the bounds
@@ -72,7 +94,29 @@ public final class CameraUpdateFactory {
*/
public static CameraUpdate newLatLngBounds(@NonNull LatLngBounds bounds, int paddingLeft, int paddingTop,
int paddingRight, int paddingBottom) {
- return new CameraBoundsUpdate(bounds, paddingLeft, paddingTop, paddingRight, paddingBottom);
+ return new CameraBoundsUpdate(bounds, null, null, paddingLeft, paddingTop, paddingRight, paddingBottom);
+ }
+
+ /**
+ * Returns a CameraUpdate that transforms the camera such that the specified
+ * latitude/longitude bounds are centered on screen at the greatest possible zoom level while using
+ * provided bearing and tilt values.
+ * <p>
+ * You can specify padding, in order to inset the bounding box from the map view's edges.
+ * </p>
+ *
+ * @param bounds Bounds to base the Camera position out of
+ * @param bearing Bearing to take in account when generating the bounds
+ * @param tilt Tilt to take in account when generating the bounds
+ * @param paddingLeft Padding left of the bounds
+ * @param paddingTop Padding top of the bounds
+ * @param paddingRight Padding right of the bounds
+ * @param paddingBottom Padding bottom of the bounds
+ * @return CameraUpdate Final Camera Position
+ */
+ public static CameraUpdate newLatLngBounds(@NonNull LatLngBounds bounds, double bearing, double tilt,
+ int paddingLeft, int paddingTop, int paddingRight, int paddingBottom) {
+ return new CameraBoundsUpdate(bounds, bearing, tilt, paddingLeft, paddingTop, paddingRight, paddingBottom);
}
/**
@@ -253,16 +297,21 @@ public final class CameraUpdateFactory {
static final class CameraBoundsUpdate implements CameraUpdate {
- private LatLngBounds bounds;
- private int[] padding;
+ private final LatLngBounds bounds;
+ private final int[] padding;
+ private final Double bearing;
+ private final Double tilt;
- CameraBoundsUpdate(LatLngBounds bounds, int[] padding) {
+ CameraBoundsUpdate(LatLngBounds bounds, Double bearing, Double tilt, int[] padding) {
this.bounds = bounds;
this.padding = padding;
+ this.bearing = bearing;
+ this.tilt = tilt;
}
- CameraBoundsUpdate(LatLngBounds bounds, int paddingLeft, int paddingTop, int paddingRight, int paddingBottom) {
- this(bounds, new int[] {paddingLeft, paddingTop, paddingRight, paddingBottom});
+ CameraBoundsUpdate(LatLngBounds bounds, Double bearing, Double tilt, int paddingLeft,
+ int paddingTop, int paddingRight, int paddingBottom) {
+ this(bounds, bearing, tilt, new int[] {paddingLeft, paddingTop, paddingRight, paddingBottom});
}
public LatLngBounds getBounds() {
@@ -275,7 +324,15 @@ public final class CameraUpdateFactory {
@Override
public CameraPosition getCameraPosition(@NonNull MapboxMap mapboxMap) {
- return mapboxMap.getCameraForLatLngBounds(bounds, padding);
+ if (bearing == null && tilt == null) {
+ // use current camera position tilt and bearing
+ return mapboxMap.getCameraForLatLngBounds(bounds, padding);
+ } else {
+ // use provided tilt and bearing
+ Assert.assertNotNull(bearing);
+ Assert.assertNotNull(tilt);
+ return mapboxMap.getCameraForLatLngBounds(bounds, padding, bearing, tilt);
+ }
}
@Override
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java
index 50bbb7acfc..6337287770 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java
@@ -347,6 +347,34 @@ final class LocationAnimatorCoordinator {
createNewFloatAnimator(ANIMATOR_CAMERA_COMPASS_BEARING, previousCameraBearing, normalizedCameraBearing);
}
+ void resetAllLayerAnimations() {
+ MapboxLatLngAnimator latLngAnimator = (MapboxLatLngAnimator) animatorArray.get(ANIMATOR_LAYER_LATLNG);
+ MapboxFloatAnimator gpsBearingAnimator = (MapboxFloatAnimator) animatorArray.get(ANIMATOR_LAYER_GPS_BEARING);
+ MapboxFloatAnimator compassBearingAnimator =
+ (MapboxFloatAnimator) animatorArray.get(ANIMATOR_LAYER_COMPASS_BEARING);
+
+ if (latLngAnimator != null && gpsBearingAnimator != null) {
+ LatLng currentLatLng = (LatLng) latLngAnimator.getAnimatedValue();
+ LatLng currentLatLngTarget = latLngAnimator.getTarget();
+ createNewLatLngAnimator(ANIMATOR_LAYER_LATLNG, currentLatLng, currentLatLngTarget);
+
+ float currentGpsBearing = (float) gpsBearingAnimator.getAnimatedValue();
+ float currentGpsBearingTarget = gpsBearingAnimator.getTarget();
+ createNewFloatAnimator(ANIMATOR_LAYER_GPS_BEARING, currentGpsBearing, currentGpsBearingTarget);
+
+ playAnimators(getAnimationDuration(), ANIMATOR_LAYER_LATLNG, ANIMATOR_LAYER_GPS_BEARING);
+ }
+
+ if (compassBearingAnimator != null) {
+ float currentLayerBearing = getPreviousLayerCompassBearing();
+ float currentLayerBearingTarget = compassBearingAnimator.getTarget();
+ createNewFloatAnimator(ANIMATOR_LAYER_COMPASS_BEARING, currentLayerBearing, currentLayerBearingTarget);
+ playAnimators(
+ compassAnimationEnabled ? COMPASS_UPDATE_RATE_MS : 0,
+ ANIMATOR_LAYER_COMPASS_BEARING);
+ }
+ }
+
void cancelZoomAnimation() {
cancelAnimator(ANIMATOR_ZOOM);
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java
index 5d8847eab4..5b2dcd8554 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java
@@ -1393,6 +1393,9 @@ public final class LocationComponent {
animationsValueChangeListeners.addAll(locationLayerController.getAnimationListeners());
animationsValueChangeListeners.addAll(locationCameraController.getAnimationListeners());
locationAnimatorCoordinator.updateAnimatorListenerHolders(animationsValueChangeListeners);
+ locationAnimatorCoordinator.resetAllCameraAnimations(mapboxMap.getCameraPosition(),
+ locationCameraController.getCameraMode() == CameraMode.TRACKING_GPS_NORTH);
+ locationAnimatorCoordinator.resetAllLayerAnimations();
}
@NonNull
@@ -1517,7 +1520,8 @@ public final class LocationComponent {
}
@NonNull
- private OnCameraTrackingChangedListener cameraTrackingChangedListener = new OnCameraTrackingChangedListener() {
+ @VisibleForTesting
+ OnCameraTrackingChangedListener cameraTrackingChangedListener = new OnCameraTrackingChangedListener() {
@Override
public void onCameraTrackingDismissed() {
for (OnCameraTrackingChangedListener listener : onCameraTrackingChangedListeners) {
@@ -1530,8 +1534,6 @@ public final class LocationComponent {
locationAnimatorCoordinator.cancelZoomAnimation();
locationAnimatorCoordinator.cancelTiltAnimation();
updateAnimatorListenerHolders();
- locationAnimatorCoordinator.resetAllCameraAnimations(mapboxMap.getCameraPosition(),
- locationCameraController.getCameraMode() == CameraMode.TRACKING_GPS_NORTH);
for (OnCameraTrackingChangedListener listener : onCameraTrackingChangedListeners) {
listener.onCameraTrackingChanged(currentMode);
}
@@ -1539,7 +1541,8 @@ public final class LocationComponent {
};
@NonNull
- private OnRenderModeChangedListener renderModeChangedListener = new OnRenderModeChangedListener() {
+ @VisibleForTesting
+ OnRenderModeChangedListener renderModeChangedListener = new OnRenderModeChangedListener() {
@Override
public void onRenderModeChanged(int currentMode) {
updateAnimatorListenerHolders();
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/log/Logger.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/log/Logger.java
index 4a262a8529..b6c4bc8722 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/log/Logger.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/log/Logger.java
@@ -1,8 +1,13 @@
package com.mapbox.mapboxsdk.log;
+import android.support.annotation.IntDef;
import android.support.annotation.Keep;
import android.util.Log;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+
/**
* Logger for the Mapbox Maps SDK for Android
* <p>
@@ -68,6 +73,22 @@ public final class Logger {
private static volatile LoggerDefinition logger = DEFAULT;
+ @LogLevel
+ private static int logLevel;
+
+ /**
+ * Set the verbosity of the Logger.
+ * <p>
+ * This configuration can be used to have more granular control over which logs are emitted by the
+ * Mapbox Maps SDK for Android.
+ * </p>
+ *
+ * @param logLevel the verbosity level
+ */
+ public static void setVerbosity(@LogLevel int logLevel) {
+ Logger.logLevel = logLevel;
+ }
+
/**
* Replace the current used logger definition.
*
@@ -85,7 +106,9 @@ public final class Logger {
* @param msg The message you would like logged.
*/
public static void v(String tag, String msg) {
- logger.v(tag, msg);
+ if (logLevel <= VERBOSE) {
+ logger.v(tag, msg);
+ }
}
/**
@@ -97,7 +120,9 @@ public final class Logger {
* @param tr An exception to log
*/
public static void v(String tag, String msg, Throwable tr) {
- logger.v(tag, msg, tr);
+ if (logLevel <= VERBOSE) {
+ logger.v(tag, msg, tr);
+ }
}
/**
@@ -108,7 +133,9 @@ public final class Logger {
* @param msg The message you would like logged.
*/
public static void d(String tag, String msg) {
- logger.d(tag, msg);
+ if (logLevel <= DEBUG) {
+ logger.d(tag, msg);
+ }
}
/**
@@ -120,7 +147,9 @@ public final class Logger {
* @param tr An exception to log
*/
public static void d(String tag, String msg, Throwable tr) {
- logger.d(tag, msg, tr);
+ if (logLevel <= DEBUG) {
+ logger.d(tag, msg, tr);
+ }
}
/**
@@ -131,7 +160,9 @@ public final class Logger {
* @param msg The message you would like logged.
*/
public static void i(String tag, String msg) {
- logger.i(tag, msg);
+ if (logLevel <= INFO) {
+ logger.i(tag, msg);
+ }
}
/**
@@ -143,7 +174,9 @@ public final class Logger {
* @param tr An exception to log
*/
public static void i(String tag, String msg, Throwable tr) {
- logger.i(tag, msg, tr);
+ if (logLevel <= INFO) {
+ logger.i(tag, msg, tr);
+ }
}
/**
@@ -154,7 +187,9 @@ public final class Logger {
* @param msg The message you would like logged.
*/
public static void w(String tag, String msg) {
- logger.w(tag, msg);
+ if (logLevel <= WARN) {
+ logger.w(tag, msg);
+ }
}
/**
@@ -166,7 +201,9 @@ public final class Logger {
* @param tr An exception to log
*/
public static void w(String tag, String msg, Throwable tr) {
- logger.w(tag, msg, tr);
+ if (logLevel <= WARN) {
+ logger.w(tag, msg, tr);
+ }
}
/**
@@ -177,7 +214,9 @@ public final class Logger {
* @param msg The message you would like logged.
*/
public static void e(String tag, String msg) {
- logger.e(tag, msg);
+ if (logLevel <= ERROR) {
+ logger.e(tag, msg);
+ }
}
/**
@@ -189,7 +228,9 @@ public final class Logger {
* @param tr An exception to log
*/
public static void e(String tag, String msg, Throwable tr) {
- logger.e(tag, msg, tr);
+ if (logLevel <= ERROR) {
+ logger.e(tag, msg, tr);
+ }
}
/**
@@ -221,4 +262,60 @@ public final class Logger {
throw new UnsupportedOperationException();
}
}
+
+ /**
+ * Priority constant for the println method; use Logger.v
+ * <p>
+ * This log level will print all logs.
+ * </p>
+ */
+ public static final int VERBOSE = Log.VERBOSE;
+
+ /**
+ * Priority constant for the println method; use Logger.d.
+ * <p>
+ * This log level will print all logs except verbose.
+ * </p>
+ */
+ public static final int DEBUG = Log.DEBUG;
+
+ /**
+ * Priority constant for the println method; use Logger.i.
+ * <p>
+ * This log level will print all logs except verbose and debug.
+ * </p>
+ */
+ public static final int INFO = Log.INFO;
+
+ /**
+ * Priority constant for the println method; use Logger.w.
+ * <p>
+ * This log level will print only warn and error logs.
+ * </p>
+ */
+ public static final int WARN = Log.WARN;
+
+ /**
+ * Priority constant for the println method; use Logger.e.
+ * <p>
+ * This log level will print only error logs.
+ * </p>
+ */
+ public static final int ERROR = Log.ERROR;
+
+ /**
+ * Priority constant for the println method.
+ * <p>
+ * This log level won't print any logs.
+ * </p>
+ */
+ public static final int NONE = 99;
+
+ /**
+ * Log level indicates which logs are allowed to be emitted by the Mapbox Maps SDK for Android.
+ */
+ @IntDef( {VERBOSE, DEBUG, INFO, WARN, ERROR, NONE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface LogLevel {
+ }
} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java
index 17d3ab0aa2..3f24ebe2ac 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java
@@ -344,8 +344,10 @@ final class MapGestureDetector {
}
if (motionEvent.getActionMasked() == MotionEvent.ACTION_UP) {
- // re-enabled the move detector
- gesturesManager.getMoveGestureDetector().setEnabled(true);
+ if (executeDoubleTap) {
+ // re-enable the move detector only if we did not start the quickzoom, otherwise, re-enable in the #onScaleEnd
+ gesturesManager.getMoveGestureDetector().setEnabled(true);
+ }
if (!uiSettings.isZoomGesturesEnabled() || !uiSettings.isDoubleTapGesturesEnabled() || !executeDoubleTap) {
return false;
@@ -512,6 +514,13 @@ final class MapGestureDetector {
@Override
public void onScaleEnd(@NonNull StandardScaleGestureDetector detector, float velocityX, float velocityY) {
+ if (quickZoom) {
+ // re-enabled the move detector only if the quickzoom happened
+ // we need to split the responsibility of re-enabling the move detector,
+ // because the double tap event (where the detector is disabled) can be canceled without warning (see #14598)
+ gesturesManager.getMoveGestureDetector().setEnabled(true);
+ }
+
if (uiSettings.isIncreaseRotateThresholdWhenScaling()) {
// resetting default angle threshold
gesturesManager.getRotateGestureDetector().setAngleThreshold(
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 81cd1830e6..1367de8729 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
@@ -91,7 +91,7 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback {
@UiThread
public MapView(@NonNull Context context) {
super(context);
- initialize(context, MapboxMapOptions.createFromAttributes(context, null));
+ initialize(context, MapboxMapOptions.createFromAttributes(context));
}
@UiThread
@@ -109,7 +109,7 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback {
@UiThread
public MapView(@NonNull Context context, @Nullable MapboxMapOptions options) {
super(context);
- initialize(context, options == null ? MapboxMapOptions.createFromAttributes(context, null) : options);
+ initialize(context, options == null ? MapboxMapOptions.createFromAttributes(context) : options);
}
@CallSuper
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java
index cc2124c6c7..09bb5012d1 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java
@@ -14,6 +14,7 @@ import android.support.v4.content.res.ResourcesCompat;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.Gravity;
+
import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
@@ -136,7 +137,18 @@ public class MapboxMapOptions implements Parcelable {
}
/**
- * Creates a MapboxMapsOptions from the attribute set.s
+ * Creates a default MapboxMapsOptions from a given context.
+ *
+ * @param context Context related to a map view.
+ * @return the MapboxMapOptions created from attributes
+ */
+ @NonNull
+ public static MapboxMapOptions createFromAttributes(@NonNull Context context) {
+ return createFromAttributes(context, null);
+ }
+
+ /**
+ * Creates a MapboxMapsOptions from the attribute set.
*
* @param context Context related to a map view.
* @param attrs Attributeset containing configuration
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/http/HttpRequestImpl.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/http/HttpRequestImpl.java
index 14b76e4fb7..24cb353d24 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/http/HttpRequestImpl.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/http/HttpRequestImpl.java
@@ -182,9 +182,15 @@ public class HttpRequestImpl implements HttpRequest {
@NonNull
private static Dispatcher getDispatcher() {
Dispatcher dispatcher = new Dispatcher();
- // Matches core limit set on
- // https://github.com/mapbox/mapbox-gl-native/blob/master/platform/android/src/http_file_source.cpp#L192
- dispatcher.setMaxRequestsPerHost(20);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ // Matches core limit set on
+ // https://github.com/mapbox/mapbox-gl-native/blob/master/platform/android/src/http_file_source.cpp#L192
+ dispatcher.setMaxRequestsPerHost(20);
+ } else {
+ // Limiting concurrent request on Android 4.4, to limit impact of SSL handshake platform library crash
+ // https://github.com/mapbox/mapbox-gl-native/issues/14910
+ dispatcher.setMaxRequestsPerHost(10);
+ }
return dispatcher;
}
} \ No newline at end of file
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
index 535107c529..5bd0dd4bf6 100644
--- 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
@@ -4,11 +4,10 @@ import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
-import android.support.annotation.AnyThread;
import android.support.annotation.Keep;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
-
import com.mapbox.mapboxsdk.LibraryLoader;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.R;
@@ -54,7 +53,7 @@ public class OfflineManager {
private final FileSource fileSource;
// Makes sure callbacks come back to the main thread
- private Handler handler;
+ private final Handler handler = new Handler(Looper.getMainLooper());
// This object is implemented as a singleton
@SuppressLint("StaticFieldLeak")
@@ -157,15 +156,6 @@ public class OfflineManager {
return instance;
}
- @AnyThread
- private Handler getHandler() {
- if (handler == null) {
- handler = new Handler(Looper.getMainLooper());
- }
-
- return handler;
- }
-
/**
* Retrieve all regions in the offline database.
* <p>
@@ -181,7 +171,7 @@ public class OfflineManager {
@Override
public void onList(final OfflineRegion[] offlineRegions) {
- getHandler().post(new Runnable() {
+ handler.post(new Runnable() {
@Override
public void run() {
fileSource.deactivate();
@@ -192,7 +182,7 @@ public class OfflineManager {
@Override
public void onError(final String error) {
- getHandler().post(new Runnable() {
+ handler.post(new Runnable() {
@Override
public void run() {
fileSource.deactivate();
@@ -234,7 +224,7 @@ public class OfflineManager {
public void run() {
String errorMessage = null;
if (src.canWrite()) {
- getHandler().post(new Runnable() {
+ handler.post(new Runnable() {
@Override
public void run() {
// path writable, merge and update schema in place if necessary
@@ -246,7 +236,7 @@ public class OfflineManager {
final File dst = new File(FileSource.getInternalCachePath(context), src.getName());
try {
copyTempDatabaseFile(src, dst);
- getHandler().post(new Runnable() {
+ handler.post(new Runnable() {
@Override
public void run() {
// merge and update schema using the copy
@@ -264,7 +254,7 @@ public class OfflineManager {
if (errorMessage != null) {
final String finalErrorMessage = errorMessage;
- getHandler().post(new Runnable() {
+ handler.post(new Runnable() {
@Override
public void run() {
callback.onError(finalErrorMessage);
@@ -275,6 +265,219 @@ public class OfflineManager {
}).start();
}
+ /**
+ * Delete existing database and re-initialize.
+ * <p>
+ * When the operation is complete or encounters an error, the given callback will be
+ * executed on the database thread; it is the responsibility of the SDK bindings
+ * to re-execute a user-provided callback on the main thread.
+ * </p>
+ *
+ * @param callback the callback to be invoked when the database was reset or when the operation erred.
+ */
+ public void resetDatabase(@Nullable final FileSourceCallback callback) {
+ fileSource.activate();
+ nativeResetDatabase(new FileSourceCallback() {
+ @Override
+ public void onSuccess() {
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ fileSource.deactivate();
+ if (callback != null) {
+ callback.onSuccess();
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onError(@NonNull final String message) {
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ fileSource.deactivate();
+ if (callback != null) {
+ callback.onError(message);
+ }
+ }
+ });
+ }
+ });
+ }
+
+ /**
+ * Forces revalidation of the ambient cache.
+ * <p>
+ * Forces Mapbox GL Native to revalidate resources stored in the ambient
+ * cache with the tile server before using them, making sure they
+ * are the latest version. This is more efficient than cleaning the
+ * cache because if the resource is considered valid after the server
+ * lookup, it will not get downloaded again.
+ * <p>
+ * Resources overlapping with offline regions will not be affected
+ * by this call.
+ * </p>
+ *
+ * @param callback the callback to be invoked when the ambient cache was invalidated or when the operation erred.
+ */
+ public void invalidateAmbientCache(@Nullable final FileSourceCallback callback) {
+ fileSource.activate();
+ nativeInvalidateAmbientCache(new FileSourceCallback() {
+ @Override
+ public void onSuccess() {
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ fileSource.deactivate();
+ if (callback != null) {
+ callback.onSuccess();
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onError(@NonNull final String message) {
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ fileSource.deactivate();
+ if (callback != null) {
+ callback.onError(message);
+ }
+ }
+ });
+ }
+ });
+ }
+
+ /**
+ * Erase resources from the ambient cache, freeing storage space.
+ * <p>
+ * Erases the ambient cache, freeing resources. This operation can be
+ * potentially slow because it will trigger a VACUUM on SQLite,
+ * forcing the database to move pages on the filesystem.
+ * </p>
+ * <p>
+ * Resources overlapping with offline regions will not be affected
+ * by this call.
+ * </p>
+ *
+ * @param callback the callback to be invoked when the ambient cache was cleared or when the operation erred.
+ */
+ public void clearAmbientCache(@Nullable final FileSourceCallback callback) {
+ fileSource.activate();
+ nativeClearAmbientCache(new FileSourceCallback() {
+ @Override
+ public void onSuccess() {
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ fileSource.deactivate();
+ if (callback != null) {
+ callback.onSuccess();
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onError(@NonNull final String message) {
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ fileSource.deactivate();
+ if (callback != null) {
+ callback.onError(message);
+ }
+ }
+ });
+ }
+ });
+ }
+
+ /**
+ * Sets the maximum size in bytes for the ambient cache.
+ * <p>
+ * This call is potentially expensive because it will try
+ * to trim the data in case the database is larger than the
+ * size defined. The size of offline regions are not affected
+ * by this settings, but the ambient cache will always try
+ * to not exceed the maximum size defined, taking into account
+ * the current size for the offline regions.
+ * </p>
+ * <p>
+ * Note that if you use the SDK's offline functionality, your ability to set the ambient cache size will be limited.
+ * Space that offline regions take up detract from the space available for ambient caching, and the ambient cache
+ * size does not block offline downloads. For example: if the maximum cache size is set to 50 MB and 40 MB are
+ * already used by offline regions, the ambient cache size will effectively be 10 MB.
+ * </p>
+ * <p>
+ * Setting the size to 0 will disable the cache if there is no
+ * offline region on the database.
+ * </p>
+ * <[
+ * <p>
+ * This method should always be called at the start of an app, before setting the style and loading a map.
+ * Otherwise, the map will instantiate with the default cache size of 50 MB.
+ * </p>
+ *
+ * @param size the maximum size of the ambient cache
+ * @param callback the callback to be invoked when the the maximum size has been set or when the operation erred.
+ */
+ public void setMaximumAmbientCacheSize(long size, @Nullable final FileSourceCallback callback) {
+ fileSource.activate();
+ nativeSetMaximumAmbientCacheSize(size, new FileSourceCallback() {
+ @Override
+ public void onSuccess() {
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ fileSource.deactivate();
+ if (callback != null) {
+ callback.onSuccess();
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onError(@NonNull final String message) {
+ fileSource.activate();
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ fileSource.deactivate();
+ if (callback != null) {
+ callback.onError(message);
+ }
+ }
+ });
+ }
+ });
+ }
+
+ /**
+ * This callback receives an asynchronous response indicating if an operation has succeeded or failed.
+ */
+ @Keep
+ public interface FileSourceCallback {
+
+ /**
+ * Receives the success of an operation
+ */
+ void onSuccess();
+
+ /**
+ * Receives an error message if an operation was not successful
+ *
+ * @param message the error message
+ */
+ void onError(@NonNull String message);
+
+ }
+
private static void copyTempDatabaseFile(@NonNull File sourceFile, File destFile) throws IOException {
if (!destFile.exists() && !destFile.createNewFile()) {
throw new IOException("Unable to copy database file for merge.");
@@ -308,7 +511,7 @@ public class OfflineManager {
if (isTemporaryFile) {
file.delete();
}
- getHandler().post(new Runnable() {
+ handler.post(new Runnable() {
@Override
public void run() {
fileSource.deactivate();
@@ -322,7 +525,7 @@ public class OfflineManager {
if (isTemporaryFile) {
file.delete();
}
- getHandler().post(new Runnable() {
+ handler.post(new Runnable() {
@Override
public void run() {
fileSource.deactivate();
@@ -365,7 +568,7 @@ public class OfflineManager {
@Override
public void onCreate(final OfflineRegion offlineRegion) {
- getHandler().post(new Runnable() {
+ handler.post(new Runnable() {
@Override
public void run() {
ConnectivityReceiver.instance(context).deactivate();
@@ -377,7 +580,7 @@ public class OfflineManager {
@Override
public void onError(final String error) {
- getHandler().post(new Runnable() {
+ handler.post(new Runnable() {
@Override
public void run() {
ConnectivityReceiver.instance(context).deactivate();
@@ -431,6 +634,18 @@ public class OfflineManager {
@Keep
private native void mergeOfflineRegions(FileSource fileSource, String path, MergeOfflineRegionsCallback callback);
+ @Keep
+ private native void nativeResetDatabase(@Nullable FileSourceCallback callback);
+
+ @Keep
+ private native void nativeInvalidateAmbientCache(@Nullable FileSourceCallback callback);
+
+ @Keep
+ private native void nativeClearAmbientCache(@Nullable FileSourceCallback callback);
+
+ @Keep
+ private native void nativeSetMaximumAmbientCacheSize(long size, @Nullable FileSourceCallback callback);
+
/**
* Insert the provided resource into the ambient cache
* This method mimics the caching that would take place if the equivalent
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
index 863219854b..2217850a2e 100644
--- 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
@@ -7,7 +7,6 @@ import android.support.annotation.IntDef;
import android.support.annotation.Keep;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-
import com.mapbox.mapboxsdk.LibraryLoader;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.net.ConnectivityReceiver;
@@ -148,6 +147,25 @@ public class OfflineRegion {
}
/**
+ * This callback receives an asynchronous response containing a notification when
+ * an offline region has been invalidated, or a {@link String} error message otherwise.
+ */
+ @Keep
+ public interface OfflineRegionInvalidateCallback {
+ /**
+ * Receives the invalidate notification
+ */
+ void onInvalidate();
+
+ /**
+ * Receives the error message
+ *
+ * @param error the error message
+ */
+ void onError(String error);
+ }
+
+ /**
* This callback receives an asynchronous response containing the newly update
* OfflineMetadata in the database, or an error message otherwise.
*/
@@ -337,14 +355,14 @@ public class OfflineRegion {
* @param callback the callback to invoked.
*/
public void getStatus(@NonNull final OfflineRegionStatusCallback callback) {
- FileSource.getInstance(Mapbox.getApplicationContext()).activate();
+ fileSource.activate();
getOfflineRegionStatus(new OfflineRegionStatusCallback() {
@Override
public void onStatus(final OfflineRegionStatus status) {
handler.post(new Runnable() {
@Override
public void run() {
- FileSource.getInstance(Mapbox.getApplicationContext()).deactivate();
+ fileSource.deactivate();
callback.onStatus(status);
}
});
@@ -355,7 +373,7 @@ public class OfflineRegion {
handler.post(new Runnable() {
@Override
public void run() {
- FileSource.getInstance(Mapbox.getApplicationContext()).deactivate();
+ fileSource.deactivate();
callback.onError(error);
}
});
@@ -383,14 +401,14 @@ public class OfflineRegion {
public void delete(@NonNull final OfflineRegionDeleteCallback callback) {
if (!isDeleted) {
isDeleted = true;
- FileSource.getInstance(Mapbox.getApplicationContext()).activate();
+ fileSource.activate();
deleteOfflineRegion(new OfflineRegionDeleteCallback() {
@Override
public void onDelete() {
handler.post(new Runnable() {
@Override
public void run() {
- FileSource.getInstance(Mapbox.getApplicationContext()).deactivate();
+ fileSource.deactivate();
callback.onDelete();
OfflineRegion.this.finalize();
}
@@ -403,7 +421,7 @@ public class OfflineRegion {
@Override
public void run() {
isDeleted = false;
- FileSource.getInstance(Mapbox.getApplicationContext()).deactivate();
+ fileSource.deactivate();
callback.onError(error);
}
});
@@ -413,6 +431,46 @@ public class OfflineRegion {
}
/**
+ * Invalidate all the tiles from an offline region forcing Mapbox GL to revalidate
+ * the tiles with the server before using. This is more efficient than deleting the
+ * offline region and downloading it again because if the data on the cache matches
+ * the server, no new data gets transmitted.
+ *
+ * @param callback the callback to be invoked
+ */
+ public void invalidate(@Nullable final OfflineRegionInvalidateCallback callback) {
+ fileSource.activate();
+ invalidateOfflineRegion(new OfflineRegionInvalidateCallback() {
+
+ @Override
+ public void onInvalidate() {
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ fileSource.deactivate();
+ if (callback != null) {
+ callback.onInvalidate();
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onError(@NonNull final String message) {
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ fileSource.deactivate();
+ if (callback != null) {
+ callback.onError(message);
+ }
+ }
+ });
+ }
+ });
+ }
+
+ /**
* Update an offline region metadata from the database.
* <p>
* When the operation is complete or encounters an error, the given callback will be
@@ -469,4 +527,7 @@ public class OfflineRegion {
@Keep
private native void updateOfflineRegionMetadata(byte[] metadata, OfflineRegionUpdateMetadataCallback callback);
+ @Keep
+ private native void invalidateOfflineRegion(OfflineRegionInvalidateCallback callback);
+
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java
index b3b7b61831..cdf197411a 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java
@@ -11,7 +11,6 @@ import android.support.annotation.Keep;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
-
import com.mapbox.mapboxsdk.MapStrictMode;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java
index ab3d68547e..8d741d1bdc 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java
@@ -124,14 +124,16 @@ public class ColorUtils {
*/
@ColorInt
public static int rgbaToColor(@NonNull String value) {
- Pattern c = Pattern.compile("rgba?\\s*\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,?\\s*(\\d+\\.?\\d*)?\\s*\\)");
+ // we need to accept and floor float values as well, as those can come from core
+ Pattern c = Pattern.compile("rgba?\\s*\\(\\s*(\\d+\\.?\\d*)\\s*,\\s*(\\d+\\.?\\d*)\\s*,\\s*(\\d+\\.?\\d*)\\s*,"
+ + "?\\s*(\\d+\\.?\\d*)?\\s*\\)");
Matcher m = c.matcher(value);
if (m.matches() && m.groupCount() == 3) {
- return Color.rgb(Integer.parseInt(m.group(1)), Integer.parseInt(m.group(2)),
- Integer.parseInt(m.group(3)));
+ return Color.rgb((int) Float.parseFloat(m.group(1)), (int) Float.parseFloat(m.group(2)),
+ (int) Float.parseFloat(m.group(3)));
} else if (m.matches() && m.groupCount() == 4) {
- return Color.argb((int) (Float.parseFloat(m.group(4)) * 255), Integer.parseInt(m.group(1)),
- Integer.parseInt(m.group(2)), Integer.parseInt(m.group(3)));
+ return Color.argb((int) (Float.parseFloat(m.group(4)) * 255), (int) Float.parseFloat(m.group(1)),
+ (int) Float.parseFloat(m.group(2)), (int) Float.parseFloat(m.group(3)));
} else {
throw new ConversionException("Not a valid rgb/rgba value");
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MapFragmentUtils.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MapFragmentUtils.java
index f3c8fd32cf..884e0a42be 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MapFragmentUtils.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MapFragmentUtils.java
@@ -44,7 +44,7 @@ public class MapFragmentUtils {
options = args.getParcelable(MapboxConstants.FRAG_ARG_MAPBOXMAPOPTIONS);
} else {
// load default options
- options = MapboxMapOptions.createFromAttributes(context, null);
+ options = MapboxMapOptions.createFromAttributes(context);
}
return options;
}