From bcfce808ca178c01eb417a6575035903d57265c1 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Fri, 28 Aug 2015 15:29:04 -0700 Subject: [PATCH] implement annotation marker tap recognition in Android --- android/cpp/jni.cpp | 104 ++++++++++++++++++ .../com/mapbox/mapboxgl/views/MapView.java | 36 ++++++ .../mapbox/mapboxgl/views/NativeMapView.java | 9 ++ include/mbgl/android/jni.hpp | 7 ++ 4 files changed, 156 insertions(+) diff --git a/android/cpp/jni.cpp b/android/cpp/jni.cpp index d1040d68e6c..e077e318a45 100644 --- a/android/cpp/jni.cpp +++ b/android/cpp/jni.cpp @@ -50,6 +50,13 @@ jfieldID latLngZoomLatitudeId = nullptr; jfieldID latLngZoomLongitudeId = nullptr; jfieldID latLngZoomZoomId = nullptr; +jclass bboxClass = nullptr; +jmethodID bboxConstructorId = nullptr; +jfieldID bboxLatNorthId = nullptr; +jfieldID bboxLatSouthId = nullptr; +jfieldID bboxLonEastId = nullptr; +jfieldID bboxLonWestId = nullptr; + jclass markerClass = nullptr; jmethodID markerConstructorId = nullptr; jfieldID markerPositionId = nullptr; @@ -970,6 +977,50 @@ void JNICALL nativeRemoveAnnotations(JNIEnv *env, jobject obj, jlong nativeMapVi nativeMapView->getMap().removeAnnotations(ids); } +jlongArray JNICALL nativeGetAnnotationsInBounds(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jobject bbox) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetAnnotationsInBounds"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + + if (env->ExceptionCheck() || (bbox == nullptr)) { + env->ExceptionDescribe(); + return nullptr; + } + + jdouble swLat = env->GetDoubleField(bbox, bboxLatSouthId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return nullptr; + } + + jdouble swLon = env->GetDoubleField(bbox, bboxLonWestId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return nullptr; + } + + jdouble neLat = env->GetDoubleField(bbox, bboxLatNorthId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return nullptr; + } + + jdouble neLon = env->GetDoubleField(bbox, bboxLonEastId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return nullptr; + } + + mbgl::LatLngBounds bounds; + bounds.sw = { swLat, swLon }; + bounds.ne = { neLat, neLon }; + + // assume only points for now + std::vector annotations = nativeMapView->getMap().getAnnotationsInBounds(bounds, mbgl::AnnotationType::Point); + + return std_vector_uint_to_jobject(env, annotations); +} + void JNICALL nativeSetSprite(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jstring symbol, jint width, jint height, jfloat scale, jbyteArray jpixels) { mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetSprite"); @@ -1246,6 +1297,42 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { return JNI_ERR; } + bboxClass = env->FindClass("com/mapbox/mapboxgl/geometry/BoundingBox"); + if (bboxClass == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + bboxConstructorId = env->GetMethodID(bboxClass, "", "(DDDD)V"); + if (bboxConstructorId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + bboxLatNorthId = env->GetFieldID(bboxClass, "mLatNorth", "D"); + if (bboxLatNorthId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + bboxLatSouthId = env->GetFieldID(bboxClass, "mLatSouth", "D"); + if (bboxLatSouthId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + bboxLonEastId = env->GetFieldID(bboxClass, "mLonEast", "D"); + if (bboxLonEastId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + bboxLonWestId = env->GetFieldID(bboxClass, "mLonWest", "D"); + if (bboxLonWestId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + markerClass = env->FindClass("com/mapbox/mapboxgl/annotations/Marker"); if (markerClass == nullptr) { env->ExceptionDescribe(); @@ -1596,6 +1683,8 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { reinterpret_cast(&nativeAddPolygons)}, {"nativeRemoveAnnotation", "(JJ)V", reinterpret_cast(&nativeRemoveAnnotation)}, {"nativeRemoveAnnotations", "(J[J)V", reinterpret_cast(&nativeRemoveAnnotations)}, + {"nativeGetAnnotationsInBounds", "(JLcom/mapbox/mapboxgl/geometry/BoundingBox;)[J", + reinterpret_cast(&nativeGetAnnotationsInBounds)}, {"nativeSetSprite", "(JLjava/lang/String;IIF[B)V", reinterpret_cast(&nativeSetSprite)}, {"nativeOnLowMemory", "(J)V", reinterpret_cast(&nativeOnLowMemory)}, {"nativeSetDebug", "(JZ)V", reinterpret_cast(&nativeSetDebug)}, @@ -1639,6 +1728,13 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { return JNI_ERR; } + bboxClass = reinterpret_cast(env->NewGlobalRef(bboxClass)); + if (bboxClass == nullptr) { + env->ExceptionDescribe(); + env->DeleteGlobalRef(bboxClass); + return JNI_ERR; + } + markerClass = reinterpret_cast(env->NewGlobalRef(markerClass)); if (markerClass == nullptr) { env->ExceptionDescribe(); @@ -1795,6 +1891,14 @@ extern "C" JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) { latLngZoomLatitudeId = nullptr; latLngZoomZoomId = nullptr; + env->DeleteGlobalRef(bboxClass); + bboxClass = nullptr; + bboxConstructorId = nullptr; + bboxLatNorthId = nullptr; + bboxLatSouthId = nullptr; + bboxLonEastId = nullptr; + bboxLonWestId = nullptr; + env->DeleteGlobalRef(markerClass); markerClass = nullptr; markerConstructorId = nullptr; diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/MapView.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/MapView.java index 219069fdab6..8dde403c7ce 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/MapView.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/MapView.java @@ -50,6 +50,7 @@ import com.mapbox.mapboxgl.annotations.PolygonOptions; import com.mapbox.mapboxgl.annotations.Polyline; import com.mapbox.mapboxgl.annotations.PolylineOptions; +import com.mapbox.mapboxgl.geometry.BoundingBox; import com.mapbox.mapboxgl.geometry.LatLng; import com.mapbox.mapboxgl.geometry.LatLngZoom; import com.mapzen.android.lost.api.LocationListener; @@ -428,6 +429,25 @@ public List getAnnotations() { return Collections.unmodifiableList(mAnnotations); } + public List getAnnotationsInBounds(BoundingBox bbox) { + List annotations = new ArrayList<>(); + long[] ids = mNativeMapView.getAnnotationsInBounds(bbox); + List idsList = new ArrayList<>(); + for(int i = 0; i < ids.length; i++) { + idsList.add(new Long(ids[i])); + } + for(int i = 0; i < mAnnotations.size(); i++) { + Annotation annotation = mAnnotations.get(i); + if (annotation instanceof Marker && idsList.contains(annotation.getId())) { + annotations.add(annotation); + } + } + for(int i = 0; i < annotations.size(); i++) { + Log.d(TAG, "tapped: " + Long.toString(annotations.get(i).getId())); + } + return annotations; + } + // // Property methods // @@ -919,6 +939,22 @@ public boolean onSingleTapUp(MotionEvent e) { // Cancel any animation mNativeMapView.cancelTransitions(); + // Select or deselect point annotations + PointF tapPoint = new PointF(e.getX(), e.getY()); + + float toleranceWidth = 60 * mScreenDensity; + float toleranceHeight = 80 * mScreenDensity; + + PointF tr = new PointF(tapPoint.x + toleranceWidth / 2, tapPoint.y + 2 * toleranceHeight / 3); + PointF bl = new PointF(tapPoint.x - toleranceWidth / 2, tapPoint.y - 1 * toleranceHeight / 3); + + LatLng sw = fromScreenLocation(bl); + LatLng ne = fromScreenLocation(tr); + + BoundingBox bbox = new BoundingBox(ne, sw); + + List annotations = getAnnotationsInBounds(bbox); + return true; } diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/NativeMapView.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/NativeMapView.java index 6257a23622e..56589f479b5 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/NativeMapView.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/NativeMapView.java @@ -3,13 +3,16 @@ import android.graphics.PointF; import android.view.Surface; +import com.mapbox.mapboxgl.annotations.Annotation; import com.mapbox.mapboxgl.annotations.Marker; import com.mapbox.mapboxgl.annotations.Polygon; import com.mapbox.mapboxgl.annotations.Polyline; +import com.mapbox.mapboxgl.geometry.BoundingBox; import com.mapbox.mapboxgl.geometry.LatLng; import com.mapbox.mapboxgl.geometry.LatLngZoom; import com.mapbox.mapboxgl.geometry.ProjectedMeters; +import java.util.ArrayList; import java.util.List; // Class that wraps the native methods for convenience @@ -353,6 +356,10 @@ public void removeAnnotations(long[] ids) { nativeRemoveAnnotations(mNativeMapViewPtr, ids); } + public long[] getAnnotationsInBounds(BoundingBox bbox) { + return nativeGetAnnotationsInBounds(mNativeMapViewPtr, bbox); + } + public void setSprite(String symbol, int width, int height, float scale, byte[] pixels) { nativeSetSprite(mNativeMapViewPtr, symbol, width, height, scale, pixels); } @@ -563,6 +570,8 @@ private native void nativeSetBearing(long nativeMapViewPtr, double degrees, private native void nativeRemoveAnnotations(long nativeMapViewPtr, long[] id); + private native long[] nativeGetAnnotationsInBounds(long mNativeMapViewPtr, BoundingBox bbox); + private native void nativeSetSprite(long nativeMapViewPtr, String symbol, int width, int height, float scale, byte[] pixels); diff --git a/include/mbgl/android/jni.hpp b/include/mbgl/android/jni.hpp index 62cb399d3fd..07c44fc7ada 100644 --- a/include/mbgl/android/jni.hpp +++ b/include/mbgl/android/jni.hpp @@ -43,6 +43,13 @@ extern jfieldID latLngZoomLatitudeId; extern jfieldID latLngZoomLongitudeId; extern jfieldID latLngZoomZoomId; +extern jclass bboxClass; +extern jmethodID bboxConstructorId; +extern jfieldID bboxLatNorthId; +extern jfieldID bboxLatSouthId; +extern jfieldID bboxLonEastId; +extern jfieldID bboxLonWestId; + extern jclass markerClass; extern jmethodID markerConstructorId; extern jfieldID markerPositionId;