summaryrefslogtreecommitdiff
path: root/android
diff options
context:
space:
mode:
authorLeith Bade <leith@mapbox.com>2015-10-21 23:07:43 +1100
committerLeith Bade <leith@mapbox.com>2015-10-22 16:18:13 +1100
commit2daa5f14a8902ef0fe623558097f18644a2a8bf6 (patch)
tree6ba2908b03843219a742e30dc0db1074f876f847 /android
parente5289d685fde4255414e5bf784f8ffb24008f681 (diff)
downloadqtlocation-mapboxgl-2daa5f14a8902ef0fe623558097f18644a2a8bf6.tar.gz
[android] Fix bug in setSprite when calculating pixel data size
Change Marker sprite() to icon() and use Sprite class Load a Maki dog icon in test app Fixes #2506
Diffstat (limited to 'android')
-rw-r--r--android/cpp/jni.cpp99
-rw-r--r--android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java27
-rw-r--r--android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java10
-rw-r--r--android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Sprite.java40
-rw-r--r--android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/SpriteFactory.java109
-rw-r--r--android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/SpriteBitmapChangedException.java26
-rw-r--r--android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/TooManySpritesException.java20
-rw-r--r--android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java126
-rw-r--r--android/java/MapboxGLAndroidSDKTestApp/src/main/assets/dog-park-24.pngbin0 -> 831 bytes
-rw-r--r--android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MainActivity.java10
10 files changed, 350 insertions, 117 deletions
diff --git a/android/cpp/jni.cpp b/android/cpp/jni.cpp
index 7397c6f5df..bf16a3dbfb 100644
--- a/android/cpp/jni.cpp
+++ b/android/cpp/jni.cpp
@@ -57,13 +57,14 @@ jfieldID bboxLatSouthId = nullptr;
jfieldID bboxLonEastId = nullptr;
jfieldID bboxLonWestId = nullptr;
+jclass spriteClass = nullptr;
+jfieldID spriteIdId = nullptr;
+
jclass markerClass = nullptr;
-jmethodID markerConstructorId = nullptr;
jfieldID markerPositionId = nullptr;
-jfieldID markerSpriteId = nullptr;
+jfieldID markerIconId = nullptr;
jclass polylineClass = nullptr;
-jmethodID polylineConstructorId = nullptr;
jfieldID polylineAlphaId = nullptr;
jfieldID polylineVisibleId = nullptr;
jfieldID polylineColorId = nullptr;
@@ -71,7 +72,6 @@ jfieldID polylineWidthId = nullptr;
jfieldID polylinePointsId = nullptr;
jclass polygonClass = nullptr;
-jmethodID polygonConstructorId = nullptr;
jfieldID polygonAlphaId = nullptr;
jfieldID polygonVisibleId = nullptr;
jfieldID polygonFillColorId = nullptr;
@@ -809,8 +809,14 @@ jlong JNICALL nativeAddMarker(JNIEnv *env, jobject obj, jlong nativeMapViewPtr,
return -1;
}
- jstring jsprite = reinterpret_cast<jstring>(env->GetObjectField(marker, markerSpriteId));
- std::string sprite = std_string_from_jstring(env, jsprite);
+ jobject icon = env->GetObjectField(marker, markerIconId);
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ return -1;
+ }
+
+ jstring jid = reinterpret_cast<jstring>(env->GetObjectField(icon, spriteIdId));
+ std::string id = std_string_from_jstring(env, jid);
jdouble latitude = env->GetDoubleField(position, latLngLatitudeId);
if (env->ExceptionCheck()) {
@@ -825,7 +831,7 @@ jlong JNICALL nativeAddMarker(JNIEnv *env, jobject obj, jlong nativeMapViewPtr,
}
// Because Java only has int, not unsigned int, we need to bump the annotation id up to a long.
- return nativeMapView->getMap().addPointAnnotation(mbgl::PointAnnotation(mbgl::LatLng(latitude, longitude), sprite));
+ return nativeMapView->getMap().addPointAnnotation(mbgl::PointAnnotation(mbgl::LatLng(latitude, longitude), id));
}
jlongArray JNICALL nativeAddMarkers(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jobject jlist) {
@@ -867,8 +873,14 @@ jlongArray JNICALL nativeAddMarkers(JNIEnv *env, jobject obj, jlong nativeMapVie
return nullptr;
}
- jstring jsprite = reinterpret_cast<jstring>(env->GetObjectField(marker, markerSpriteId));
- std::string sprite = std_string_from_jstring(env, jsprite);
+ jobject icon = env->GetObjectField(marker, markerIconId);
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ return nullptr;
+ }
+
+ jstring jid = reinterpret_cast<jstring>(env->GetObjectField(icon, spriteIdId));
+ std::string id = std_string_from_jstring(env, jid);
jdouble latitude = env->GetDoubleField(position, latLngLatitudeId);
if (env->ExceptionCheck()) {
@@ -882,7 +894,7 @@ jlongArray JNICALL nativeAddMarkers(JNIEnv *env, jobject obj, jlong nativeMapVie
return nullptr;
}
- markers.emplace_back(mbgl::PointAnnotation(mbgl::LatLng(latitude, longitude), sprite));
+ markers.emplace_back(mbgl::PointAnnotation(mbgl::LatLng(latitude, longitude), id));
/* Do I need to delete other LocalRefs? */
env->DeleteLocalRef(marker);
@@ -1110,7 +1122,8 @@ void JNICALL nativeSetSprite(JNIEnv *env, jobject obj, jlong nativeMapViewPtr,
const std::string symbolName = std_string_from_jstring(env, symbol);
jbyte* pixelData = env->GetByteArrayElements(jpixels, nullptr);
- std::string pixels(reinterpret_cast<char*>(pixelData), width * height * 4);
+ jsize size = env->GetArrayLength(jpixels);
+ std::string pixels(reinterpret_cast<char*>(pixelData), size);
env->ReleaseByteArrayElements(jpixels, pixelData, JNI_ABORT);
auto spriteImage = std::make_shared<mbgl::SpriteImage>(
@@ -1421,38 +1434,38 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
return JNI_ERR;
}
- markerClass = env->FindClass("com/mapbox/mapboxsdk/annotations/Marker");
- if (markerClass == nullptr) {
+ spriteClass = env->FindClass("com/mapbox/mapboxsdk/annotations/Sprite");
+ if (spriteClass == nullptr) {
env->ExceptionDescribe();
return JNI_ERR;
}
- markerConstructorId = env->GetMethodID(markerClass, "<init>", "()V");
- if (markerConstructorId == nullptr) {
+ spriteIdId = env->GetFieldID(spriteClass, "mId", "Ljava/lang/String;");
+ if (spriteIdId == nullptr) {
env->ExceptionDescribe();
return JNI_ERR;
}
- markerPositionId = env->GetFieldID(markerClass, "position", "Lcom/mapbox/mapboxsdk/geometry/LatLng;");
- if (markerPositionId == nullptr) {
+ markerClass = env->FindClass("com/mapbox/mapboxsdk/annotations/Marker");
+ if (markerClass == nullptr) {
env->ExceptionDescribe();
return JNI_ERR;
}
- markerSpriteId = env->GetFieldID(markerClass, "sprite", "Ljava/lang/String;");
- if (markerSpriteId == nullptr) {
+ markerPositionId = env->GetFieldID(markerClass, "position", "Lcom/mapbox/mapboxsdk/geometry/LatLng;");
+ if (markerPositionId == nullptr) {
env->ExceptionDescribe();
return JNI_ERR;
}
- polylineClass = env->FindClass("com/mapbox/mapboxsdk/annotations/Polyline");
- if (polylineClass == nullptr) {
+ markerIconId = env->GetFieldID(markerClass, "icon", "Lcom/mapbox/mapboxsdk/annotations/Sprite;");
+ if (markerIconId == nullptr) {
env->ExceptionDescribe();
return JNI_ERR;
}
- polylineConstructorId = env->GetMethodID(polylineClass, "<init>", "()V");
- if (polylineConstructorId == nullptr) {
+ polylineClass = env->FindClass("com/mapbox/mapboxsdk/annotations/Polyline");
+ if (polylineClass == nullptr) {
env->ExceptionDescribe();
return JNI_ERR;
}
@@ -1493,12 +1506,6 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
return JNI_ERR;
}
- polygonConstructorId = env->GetMethodID(polygonClass, "<init>", "()V");
- if (polygonConstructorId == nullptr) {
- env->ExceptionDescribe();
- return JNI_ERR;
- }
-
polygonAlphaId = env->GetFieldID(polygonClass, "alpha", "F");
if (polygonAlphaId == nullptr) {
env->ExceptionDescribe();
@@ -1828,12 +1835,22 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
return JNI_ERR;
}
+ spriteClass = reinterpret_cast<jclass>(env->NewGlobalRef(spriteClass));
+ if (spriteClass == nullptr) {
+ env->ExceptionDescribe();
+ env->DeleteGlobalRef(latLngClass);
+ env->DeleteGlobalRef(latLngZoomClass);
+ env->DeleteGlobalRef(bboxClass);
+ return JNI_ERR;
+ }
+
markerClass = reinterpret_cast<jclass>(env->NewGlobalRef(markerClass));
if (markerClass == nullptr) {
env->ExceptionDescribe();
env->DeleteGlobalRef(latLngClass);
env->DeleteGlobalRef(latLngZoomClass);
env->DeleteGlobalRef(bboxClass);
+ env->DeleteGlobalRef(spriteClass);
return JNI_ERR;
}
@@ -1843,6 +1860,7 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
env->DeleteGlobalRef(latLngClass);
env->DeleteGlobalRef(latLngZoomClass);
env->DeleteGlobalRef(bboxClass);
+ env->DeleteGlobalRef(spriteClass);
env->DeleteGlobalRef(markerClass);
return JNI_ERR;
}
@@ -1853,6 +1871,7 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
env->DeleteGlobalRef(latLngClass);
env->DeleteGlobalRef(latLngZoomClass);
env->DeleteGlobalRef(bboxClass);
+ env->DeleteGlobalRef(spriteClass);
env->DeleteGlobalRef(markerClass);
env->DeleteGlobalRef(polylineClass);
return JNI_ERR;
@@ -1864,6 +1883,7 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
env->DeleteGlobalRef(latLngClass);
env->DeleteGlobalRef(latLngZoomClass);
env->DeleteGlobalRef(bboxClass);
+ env->DeleteGlobalRef(spriteClass);
env->DeleteGlobalRef(markerClass);
env->DeleteGlobalRef(polylineClass);
env->DeleteGlobalRef(polygonClass);
@@ -1877,6 +1897,7 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
env->DeleteGlobalRef(latLngClass);
env->DeleteGlobalRef(latLngZoomClass);
env->DeleteGlobalRef(bboxClass);
+ env->DeleteGlobalRef(spriteClass);
env->DeleteGlobalRef(markerClass);
env->DeleteGlobalRef(polylineClass);
env->DeleteGlobalRef(polygonClass);
@@ -1890,6 +1911,7 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
env->DeleteGlobalRef(latLngClass);
env->DeleteGlobalRef(latLngZoomClass);
env->DeleteGlobalRef(bboxClass);
+ env->DeleteGlobalRef(spriteClass);
env->DeleteGlobalRef(markerClass);
env->DeleteGlobalRef(polylineClass);
env->DeleteGlobalRef(polygonClass);
@@ -1904,6 +1926,7 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
env->DeleteGlobalRef(latLngClass);
env->DeleteGlobalRef(latLngZoomClass);
env->DeleteGlobalRef(bboxClass);
+ env->DeleteGlobalRef(spriteClass);
env->DeleteGlobalRef(markerClass);
env->DeleteGlobalRef(polylineClass);
env->DeleteGlobalRef(polygonClass);
@@ -1917,9 +1940,10 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
if (pointFClass == nullptr) {
env->ExceptionDescribe();
env->DeleteGlobalRef(latLngClass);
- env->DeleteGlobalRef(markerClass);
env->DeleteGlobalRef(latLngZoomClass);
env->DeleteGlobalRef(bboxClass);
+ env->DeleteGlobalRef(markerClass);
+ env->DeleteGlobalRef(spriteClass);
env->DeleteGlobalRef(polylineClass);
env->DeleteGlobalRef(polygonClass);
env->DeleteGlobalRef(runtimeExceptionClass);
@@ -1933,9 +1957,10 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
if (httpContextClass == nullptr) {
env->ExceptionDescribe();
env->DeleteGlobalRef(latLngClass);
- env->DeleteGlobalRef(markerClass);
env->DeleteGlobalRef(latLngZoomClass);
env->DeleteGlobalRef(bboxClass);
+ env->DeleteGlobalRef(spriteClass);
+ env->DeleteGlobalRef(markerClass);
env->DeleteGlobalRef(polylineClass);
env->DeleteGlobalRef(polygonClass);
env->DeleteGlobalRef(runtimeExceptionClass);
@@ -1949,9 +1974,10 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
if (httpRequestClass == nullptr) {
env->ExceptionDescribe();
env->DeleteGlobalRef(latLngClass);
- env->DeleteGlobalRef(markerClass);
env->DeleteGlobalRef(latLngZoomClass);
env->DeleteGlobalRef(bboxClass);
+ env->DeleteGlobalRef(spriteClass);
+ env->DeleteGlobalRef(markerClass);
env->DeleteGlobalRef(polylineClass);
env->DeleteGlobalRef(polygonClass);
env->DeleteGlobalRef(runtimeExceptionClass);
@@ -2002,15 +2028,17 @@ extern "C" JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) {
bboxLonEastId = nullptr;
bboxLonWestId = nullptr;
+ env->DeleteGlobalRef(spriteClass);
+ spriteClass = nullptr;
+ spriteIdId = nullptr;
+
env->DeleteGlobalRef(markerClass);
markerClass = nullptr;
- markerConstructorId = nullptr;
markerPositionId = nullptr;
- markerSpriteId = nullptr;
+ markerIconId = nullptr;
env->DeleteGlobalRef(polylineClass);
polylineClass = nullptr;
- polylineConstructorId = nullptr;
polylineAlphaId = nullptr;
polylineVisibleId = nullptr;
polylineColorId = nullptr;
@@ -2019,7 +2047,6 @@ extern "C" JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) {
env->DeleteGlobalRef(polygonClass);
polygonClass = nullptr;
- polygonConstructorId = nullptr;
polygonAlphaId = nullptr;
polygonVisibleId = nullptr;
polygonFillColorId = nullptr;
diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java
index 3567c1a8ef..eed66d2738 100644
--- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java
+++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java
@@ -2,7 +2,6 @@ package com.mapbox.mapboxsdk.annotations;
import android.graphics.Point;
import android.support.annotation.Nullable;
-import android.text.TextUtils;
import android.view.View;
import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.geometry.LatLng;
@@ -18,7 +17,7 @@ public final class Marker extends Annotation {
private LatLng position;
private float rotation;
private String snippet;
- private String sprite = "default_marker";
+ private Sprite icon;
private String title;
private InfoWindow infoWindow = null;
@@ -140,23 +139,14 @@ public final class Marker extends Annotation {
}
/**
- * You can specify the name of a sprite to get a marker other than the default marker.
- * This name can be found in the sprite json file:
- *
- * https://github.com/mapbox/mapbox-gl-styles/blob/mb-pages/sprites/mapbox-streets.json
- *
- * If null you will get the default marker.
- *
- * @param sprite The name of the sprite.
+ * Do not use this method. Used internally by the SDK.
*/
- void setSprite(@Nullable String sprite) {
- if (!TextUtils.isEmpty(sprite)) {
- this.sprite = sprite;
- }
+ public void setIcon(@Nullable Sprite icon) {
+ this.icon = icon;
}
- public String getSprite() {
- return sprite;
+ public Sprite getIcon() {
+ return icon;
}
void setTitle(String title) {
@@ -227,11 +217,6 @@ public final class Marker extends Annotation {
// TODO Method in Google Maps Android API
// public int hashCode()
- // TODO: Implement this method of Google Maps Android API
-// void setIcon(BitmapDescriptor icon) {
-//
-// }
-
/**
* Do not use this method. Used internally by the SDK.
*/
diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java
index 77a0172cb1..5fa6412c01 100644
--- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java
+++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java
@@ -71,8 +71,8 @@ public final class MarkerOptions {
return marker.getTitle();
}
- public String getSprite() {
- return marker.getSprite();
+ public Sprite getIcon() {
+ return marker.getIcon();
}
private MarkerOptions infoWindowAnchor(float u, float v) {
@@ -107,10 +107,8 @@ public final class MarkerOptions {
return this;
}
- public MarkerOptions sprite(@Nullable String sprite) {
- if (!TextUtils.isEmpty(sprite)) {
- marker.setSprite(sprite);
- }
+ public MarkerOptions icon(@Nullable Sprite icon) {
+ marker.setIcon(icon);
return this;
}
diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Sprite.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Sprite.java
new file mode 100644
index 0000000000..597c196d2a
--- /dev/null
+++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Sprite.java
@@ -0,0 +1,40 @@
+package com.mapbox.mapboxsdk.annotations;
+
+import android.graphics.Bitmap;
+
+public final class Sprite {
+ private Bitmap mBitmap;
+ private String mId;
+
+ Sprite(String id, Bitmap bitmap) {
+ mId = id;
+ mBitmap = bitmap;
+ }
+
+ public String getId() {
+ return mId;
+ }
+
+ public Bitmap getBitmap() {
+ return mBitmap;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Sprite sprite = (Sprite) o;
+
+ if (!mBitmap.equals(sprite.mBitmap)) return false;
+ return mId.equals(sprite.mId);
+
+ }
+
+ @Override
+ public int hashCode() {
+ int result = mBitmap.hashCode();
+ result = 31 * result + mId.hashCode();
+ return result;
+ }
+}
diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/SpriteFactory.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/SpriteFactory.java
new file mode 100644
index 0000000000..3178ef1553
--- /dev/null
+++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/SpriteFactory.java
@@ -0,0 +1,109 @@
+package com.mapbox.mapboxsdk.annotations;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.BitmapDrawable;
+import android.os.Build;
+import android.support.v4.content.ContextCompat;
+import android.util.DisplayMetrics;
+import android.view.WindowManager;
+
+import com.mapbox.mapboxsdk.R;
+import com.mapbox.mapboxsdk.exceptions.TooManySpritesException;
+import com.mapbox.mapboxsdk.views.MapView;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.ref.WeakReference;
+import java.util.Map;
+
+public final class SpriteFactory {
+
+ private static final String SPRITE_ID_PREFIX = "com.mapbox.sprites.sprite_";
+
+ private MapView mMapView;
+ private Sprite mDefaultMarker;
+ private BitmapFactory.Options mOptions;
+
+ private int mNextId = 0;
+
+ public SpriteFactory(MapView mapView) {
+ mMapView = mapView;
+ DisplayMetrics realMetrics = null;
+ DisplayMetrics metrics = new DisplayMetrics();
+ WindowManager wm = (WindowManager) mMapView.getContext().getSystemService(Context.WINDOW_SERVICE);
+
+ if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ realMetrics = new DisplayMetrics();
+ wm.getDefaultDisplay().getRealMetrics(realMetrics);
+ }
+ wm.getDefaultDisplay().getMetrics(metrics);
+
+ mOptions = new BitmapFactory.Options();
+ mOptions.inScaled = true;
+ mOptions.inDensity = DisplayMetrics.DENSITY_DEFAULT;
+ mOptions.inTargetDensity = metrics.densityDpi;
+ if (realMetrics != null) {
+ mOptions.inScreenDensity = realMetrics.densityDpi;
+ }
+
+ }
+
+ public Sprite fromBitmap(Bitmap bitmap) {
+ if (bitmap == null) {
+ return null;
+ }
+
+ if (mNextId < 0) {
+ throw new TooManySpritesException();
+ }
+ String id = SPRITE_ID_PREFIX + ++mNextId;
+
+ return new Sprite(id, bitmap);
+ }
+
+ public Sprite fromResource(int resourceId) {
+ Bitmap bitmap = BitmapFactory.decodeResource(mMapView.getResources(), resourceId);
+ return fromBitmap(bitmap);
+ }
+
+ public Sprite defaultMarker() {
+ if (mDefaultMarker == null) {
+ mDefaultMarker = fromResource(R.drawable.default_marker);
+ }
+ return mDefaultMarker;
+ }
+
+ private Sprite fromInputStream(InputStream is) {
+ Bitmap bitmap = BitmapFactory.decodeStream(is, null, mOptions);
+ return fromBitmap(bitmap);
+ }
+
+ public Sprite fromAsset(String assetName) {
+ InputStream is;
+ try {
+ is = mMapView.getContext().getAssets().open(assetName);
+ } catch (IOException e) {
+ return null;
+ }
+ return fromInputStream(is);
+ }
+
+ public Sprite fromPath(String absolutePath) {
+ Bitmap bitmap = BitmapFactory.decodeFile(absolutePath, mOptions);
+ return fromBitmap(bitmap);
+ }
+
+ public Sprite fromFile(String fileName) {
+ FileInputStream is = null;
+ try {
+ is = mMapView.getContext().openFileInput(fileName);
+ } catch (FileNotFoundException e) {
+ return null;
+ }
+ return fromInputStream(is);
+ }
+}
diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/SpriteBitmapChangedException.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/SpriteBitmapChangedException.java
new file mode 100644
index 0000000000..15c6d7eec6
--- /dev/null
+++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/SpriteBitmapChangedException.java
@@ -0,0 +1,26 @@
+package com.mapbox.mapboxsdk.exceptions;
+
+import android.graphics.Bitmap;
+
+import com.mapbox.mapboxsdk.annotations.Marker;
+import com.mapbox.mapboxsdk.annotations.Sprite;
+import com.mapbox.mapboxsdk.views.MapView;
+
+/**
+ * A {@code SpriteBitmapChangedException} is thrown by {@link MapView} when a {@link Marker} is added
+ * that has a {@link Sprite} with a {@link Bitmap} that has been modified.
+ * <p/>
+ * You cannot modify a {@code Sprite} after it has been added to the map in a {@code Marker}
+ *
+ * @see MapView
+ * @see Sprite
+ * @see Marker
+ */
+public class SpriteBitmapChangedException extends RuntimeException {
+
+ public SpriteBitmapChangedException() {
+ super("The added Marker has a Sprite with a Bitmap that has been modified. You cannot modufy" +
+ "a Sprite after it has been added in a Marker.");
+ }
+
+}
diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/TooManySpritesException.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/TooManySpritesException.java
new file mode 100644
index 0000000000..02a57ba225
--- /dev/null
+++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/TooManySpritesException.java
@@ -0,0 +1,20 @@
+package com.mapbox.mapboxsdk.exceptions;
+
+import com.mapbox.mapboxsdk.annotations.Sprite;
+import com.mapbox.mapboxsdk.annotations.SpriteFactory;
+
+/**
+ * A {@code TooManySpritesException} is thrown by {@link SpriteFactory} when it
+ * cannot create a {@link Sprite} because there are already too many.
+ * <p/>
+ * You should try to reuse Sprite objects whenever possible.
+ *
+ * @see SpriteFactory
+ */
+public class TooManySpritesException extends RuntimeException {
+
+ public TooManySpritesException() {
+ super("Cannot create a Sprite because there are already too many. Try reusing Sprites.");
+ }
+
+}
diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java
index 0b10993819..515f1a74d7 100644
--- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java
+++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java
@@ -17,6 +17,7 @@ import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.RectF;
import android.graphics.SurfaceTexture;
+import android.graphics.drawable.BitmapDrawable;
import android.location.Location;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
@@ -36,6 +37,7 @@ import android.support.v4.view.ScaleGestureDetectorCompat;
import android.support.v7.app.AlertDialog;
import android.text.TextUtils;
import android.util.AttributeSet;
+import android.util.DisplayMetrics;
import android.util.Log;
import android.view.GestureDetector;
import android.view.Gravity;
@@ -64,8 +66,11 @@ import com.mapbox.mapboxsdk.annotations.Polygon;
import com.mapbox.mapboxsdk.annotations.PolygonOptions;
import com.mapbox.mapboxsdk.annotations.Polyline;
import com.mapbox.mapboxsdk.annotations.PolylineOptions;
+import com.mapbox.mapboxsdk.annotations.Sprite;
+import com.mapbox.mapboxsdk.annotations.SpriteFactory;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.exceptions.InvalidAccessTokenException;
+import com.mapbox.mapboxsdk.exceptions.SpriteBitmapChangedException;
import com.mapbox.mapboxsdk.geometry.BoundingBox;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngZoom;
@@ -152,9 +157,6 @@ public final class MapView extends FrameLayout {
// Index into R.arrays.attribution_links
private static final int ATTRIBUTION_INDEX_IMPROVE_THIS_MAP = 2;
- // Used for loading default marker sprite
- private static final String DEFAULT_SPRITE = "com.mapbox.sprites.default";
-
/**
* The currently supported maximum zoom level.
*
@@ -174,7 +176,6 @@ public final class MapView extends FrameLayout {
// Used to handle DPI scaling
private float mScreenDensity = 1.0f;
- private float mScreenDensityDpi = 1.0f;
// Touch gesture detectors
private GestureDetectorCompat mGestureDetector;
@@ -213,6 +214,8 @@ public final class MapView extends FrameLayout {
private List<Marker> mMarkersNearLastTap = new ArrayList<>();
private Marker mSelectedMarker;
private InfoWindowAdapter mInfoWindowAdapter;
+ private SpriteFactory mSpriteFactory;
+ private ArrayList<Sprite> mSprites = new ArrayList<>();
// Used for the Mapbox Logo
private ImageView mLogoView;
@@ -573,7 +576,6 @@ public final class MapView extends FrameLayout {
// Get the screen's density
mScreenDensity = context.getResources().getDisplayMetrics().density;
- mScreenDensityDpi = context.getResources().getDisplayMetrics().densityDpi;
// Get the cache path
String cachePath = context.getCacheDir().getAbsolutePath();
@@ -818,6 +820,8 @@ public final class MapView extends FrameLayout {
}
if (change == DID_FINISH_LOADING_MAP) {
+ reloadSprites();
+ reloadMarkers();
adjustTopOffsetPixels();
}
}
@@ -1595,18 +1599,61 @@ public final class MapView extends FrameLayout {
// Annotations
//
- // Marking this function private until #2506 fixed
- private void setSprite(String symbol, Bitmap bitmap) {
+ public SpriteFactory getSpriteFactory() {
+ if (mSpriteFactory == null) {
+ mSpriteFactory = new SpriteFactory(this);
+ }
+ return mSpriteFactory;
+ }
+
+ private void loadSprite(Sprite sprite) {
+ Bitmap bitmap = sprite.getBitmap();
+ String id = sprite.getId();
if (bitmap.getConfig() != Bitmap.Config.ARGB_8888) {
bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, false);
}
ByteBuffer buffer = ByteBuffer.allocate(bitmap.getRowBytes() * bitmap.getHeight());
bitmap.copyPixelsToBuffer(buffer);
- //float scale = mScreenDensityDpi / bitmap.getDensity() * mScreenDensity;
- float scale = 1.0f;
+ float density = bitmap.getDensity();
+ if (density == Bitmap.DENSITY_NONE) {
+ density = DisplayMetrics.DENSITY_DEFAULT;
+ }
+ float scale = density / DisplayMetrics.DENSITY_DEFAULT;
+
+ mNativeMapView.setSprite(
+ id,
+ (int) (bitmap.getWidth() / scale),
+ (int) (bitmap.getHeight() / scale),
+ scale, buffer.array());
+ }
- mNativeMapView.setSprite(symbol, bitmap.getWidth(), bitmap.getHeight(), scale, buffer.array());
+ private void reloadSprites() {
+ int count = mSprites.size();
+ for (int i = 0; i < count; i++) {
+ Sprite sprite = mSprites.get(i);
+ loadSprite(sprite);
+ }
+ }
+
+ private Marker prepareMarker(MarkerOptions markerOptions) {
+ Marker marker = markerOptions.getMarker();
+ Sprite icon = marker.getIcon();
+ if (icon == null) {
+ icon = getSpriteFactory().defaultMarker();
+ marker.setIcon(icon);
+ }
+ if (!mSprites.contains(icon)) {
+ mSprites.add(icon);
+ loadSprite(icon);
+ } else {
+ Sprite oldSprite = mSprites.get(mSprites.indexOf(icon));
+ if (!oldSprite.getBitmap().sameAs(icon.getBitmap())) {
+ throw new SpriteBitmapChangedException();
+ }
+ }
+ marker.setTopOffsetPixels(getTopOffsetPixelsForSprite(icon));
+ return marker;
}
/**
@@ -1625,21 +1672,7 @@ public final class MapView extends FrameLayout {
throw new NullPointerException("markerOptions is null");
}
- Marker marker = markerOptions.getMarker();
-
- // Load the default marker sprite
- if (marker.getSprite() == null) {
- //BitmapDrawable bitmapDrawable = (BitmapDrawable) ContextCompat.getDrawable(mContext, R.drawable.default_marker);
- //Bitmap bitmap = bitmapDrawable.getBitmap();
- //setSprite(DEFAULT_SPRITE, bitmap);
-
- // Red default marker is currently broken
- //marker.setSprite("default_marker");
- //marker.setSprite(DEFAULT_SPRITE);
- }
-
- marker.setTopOffsetPixels(getTopOffsetPixelsForAnnotationSymbol(marker.getSprite()));
-
+ Marker marker = prepareMarker(markerOptions);
long id = mNativeMapView.addMarker(marker);
marker.setId(id); // the annotation needs to know its id
marker.setMapView(this); // the annotation needs to know which map view it is in
@@ -1665,21 +1698,7 @@ public final class MapView extends FrameLayout {
List<Marker> markers = new ArrayList<>(markerOptionsList.size());
for (MarkerOptions markerOptions : markerOptionsList) {
- Marker marker = markerOptions.getMarker();
-
- // Load the default marker sprite
- if (marker.getSprite() == null) {
- //BitmapDrawable bitmapDrawable = (BitmapDrawable) ContextCompat.getDrawable(mContext, R.drawable.default_marker);
- //Bitmap bitmap = bitmapDrawable.getBitmap();
- //setSprite(DEFAULT_SPRITE, bitmap);
-
- // Red default marker is currently broken
- //marker.setSprite("default_marker");
- //marker.setSprite(DEFAULT_SPRITE);
- }
-
- marker.setTopOffsetPixels(getTopOffsetPixelsForAnnotationSymbol(marker.getSprite()));
-
+ Marker marker = prepareMarker(markerOptions);
markers.add(marker);
}
@@ -1885,21 +1904,15 @@ public final class MapView extends FrameLayout {
return new ArrayList<>(annotations);
}
- /**
- * Get Top Offset for the annotation symbol.
- * Used by InfoWindow
- *
- * @param symbolName Annotation Symbol
- * @return Top Offset in pixels
- */
- private int getTopOffsetPixelsForAnnotationSymbol(String symbolName) {
+ private int getTopOffsetPixelsForSprite(Sprite sprite) {
// This method will dead lock if map paused. Causes a freeze if you add a marker in an
// activity's onCreate()
if (mNativeMapView.isPaused()) {
return 0;
}
- return (int) (mNativeMapView.getTopOffsetPixelsForAnnotationSymbol(symbolName) * mScreenDensity);
+ return (int) (mNativeMapView.getTopOffsetPixelsForAnnotationSymbol(sprite.getId())
+ * mScreenDensity);
}
/**
@@ -1970,7 +1983,7 @@ public final class MapView extends FrameLayout {
if (annotation instanceof Marker) {
Marker marker = (Marker) annotation;
marker.setTopOffsetPixels(
- getTopOffsetPixelsForAnnotationSymbol(marker.getSprite()));
+ getTopOffsetPixelsForSprite(marker.getIcon()));
}
}
@@ -1982,6 +1995,19 @@ public final class MapView extends FrameLayout {
}
}
+ private void reloadMarkers() {
+ int count = mAnnotations.size();
+ for (int i = 0; i < count; i++) {
+ Annotation annotation = mAnnotations.get(i);
+ if (annotation instanceof Marker) {
+ Marker marker = (Marker) annotation;
+ mNativeMapView.removeAnnotation(annotation.getId());
+ long newId = mNativeMapView.addMarker(marker);
+ marker.setId(newId);
+ }
+ }
+ }
+
//
// Rendering
//
diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/assets/dog-park-24.png b/android/java/MapboxGLAndroidSDKTestApp/src/main/assets/dog-park-24.png
new file mode 100644
index 0000000000..235f4b4d34
--- /dev/null
+++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/assets/dog-park-24.png
Binary files differ
diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MainActivity.java b/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MainActivity.java
index ab8deffd97..019d4c763d 100644
--- a/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MainActivity.java
+++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MainActivity.java
@@ -28,6 +28,7 @@ import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
import com.mapbox.mapboxsdk.annotations.PolygonOptions;
import com.mapbox.mapboxsdk.annotations.PolylineOptions;
+import com.mapbox.mapboxsdk.annotations.Sprite;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.utils.ApiAccess;
@@ -115,7 +116,7 @@ public class MainActivity extends AppCompatActivity {
.title("Dropped Pin")
.snippet(latLngFormatter.format(point.getLatitude()) + ", " +
latLngFormatter.format(point.getLongitude()))
- .sprite("default_marker"));
+ .icon(null));
}
});
@@ -400,7 +401,8 @@ public class MainActivity extends AppCompatActivity {
final MarkerOptions backLot = generateMarker("Back Lot", "The back lot behind my house", null, 38.649441, -121.369064);
markerOptionsList.add(backLot);
- final MarkerOptions cheeseRoom = generateMarker("Cheese Room", "The only air conditioned room on the property", "dog-park-15", 38.531577, -122.010646);
+ final Sprite dogIcon = mMapView.getSpriteFactory().fromAsset("dog-park-24.png");
+ final MarkerOptions cheeseRoom = generateMarker("Cheese Room", "The only air conditioned room on the property", dogIcon, 38.531577, -122.010646);
markerOptionsList.add(cheeseRoom);
List<Marker> markers = mMapView.addMarkers(markerOptionsList);
@@ -417,11 +419,11 @@ public class MainActivity extends AppCompatActivity {
});
}
- private MarkerOptions generateMarker(String title, String snippet, String sprite, double lat, double lng){
+ private MarkerOptions generateMarker(String title, String snippet, Sprite icon, double lat, double lng){
return new MarkerOptions()
.position(new LatLng(lat, lng))
.title(title)
- .sprite(sprite)
+ .icon(icon)
.snippet(snippet);
}