From bb5d895edcf4c85facbd20362165f70804cf3e99 Mon Sep 17 00:00:00 2001 From: Antonio Zugaldia Date: Thu, 18 Feb 2016 17:06:52 -0500 Subject: [PATCH] [android] #3891 - bring callbacks into java via interfaces --- .../mapboxsdk/offline/OfflineManager.java | 8 +- .../mapboxsdk/testapp/OfflineActivity.java | 11 +++ platform/android/src/jni.cpp | 92 ++++++++++++++++++- platform/android/src/jni.hpp | 4 + 4 files changed, 112 insertions(+), 3 deletions(-) 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 2364d4a120c..64ed75150ea 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 @@ -1,7 +1,6 @@ package com.mapbox.mapboxsdk.offline; import android.content.Context; -import android.util.Log; import java.util.List; @@ -24,6 +23,7 @@ public class OfflineManager { public interface ListOfflineRegionsCallback { void onList(List offlineRegions); + void onError(String error); } public interface CreateOfflineRegionCallback { @@ -61,7 +61,9 @@ public String getAccessToken() { * of the SDK bindings to re-execute a user-provided callback on the main thread. */ public void listOfflineRegions(ListOfflineRegionsCallback callback) { - + if (callback != null) { + listOfflineRegions(mDefaultFileSourcePtr, callback); + } } /** @@ -89,4 +91,6 @@ public void createOfflineRegion( private native long createDefaultFileSource(String cachePath, String assetRoot); private native void setAccessToken(long defaultFileSourcePtr, String accessToken); private native String getAccessToken(long defaultFileSourcePtr); + private native void listOfflineRegions(long defaultFileSourcePtr, ListOfflineRegionsCallback callback); + } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/OfflineActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/OfflineActivity.java index 9e30ecfe21f..09fb5fc9ee6 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/OfflineActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/OfflineActivity.java @@ -39,12 +39,18 @@ public class OfflineActivity extends AppCompatActivity private final static String LOG_TAG = "OfflineActivity"; + /* + * UI elements + */ private MapView mMapView; private MapboxMap mMapboxMap; private ProgressBar mProgressBar; private Button downloadRegion; private Button listRegions; + /* + * Offline objects + */ private OfflineManager mOfflineManager; private OfflineRegion mOfflineRegion; @@ -210,6 +216,11 @@ public void onList(List offlineRegions) { listRegionsDialog.setArguments(args); listRegionsDialog.show(getSupportFragmentManager(), "list"); } + + @Override + public void onError(String error) { + Log.e(LOG_TAG, "Error: " + error); + } }); } diff --git a/platform/android/src/jni.cpp b/platform/android/src/jni.cpp index 3171c516dde..4bcea03e118 100755 --- a/platform/android/src/jni.cpp +++ b/platform/android/src/jni.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #pragma clang diagnostic ignored "-Wunused-parameter" @@ -118,6 +119,8 @@ jfieldID customLayerDeinitializeFunctionId = nullptr; // Offline declarations start jclass customOfflineManagerClass = nullptr; +jclass listOfflineRegionsCallbackClass = nullptr; +jmethodID onErrorMethodId = nullptr; // Offline declarations end @@ -1639,6 +1642,7 @@ jlong JNICALL createDefaultFileSource(JNIEnv *env, jobject obj, jstring cachePat void JNICALL setAccessToken(JNIEnv *env, jobject obj, jlong defaultFileSourcePtr, jstring accessToken_) { mbgl::Log::Debug(mbgl::Event::JNI, "setAccessToken"); + assert(defaultFileSourcePtr != 0); std::string accessToken = std_string_from_jstring(env, accessToken_); mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast(defaultFileSourcePtr); defaultFileSource->setAccessToken(accessToken); @@ -1646,11 +1650,36 @@ void JNICALL setAccessToken(JNIEnv *env, jobject obj, jlong defaultFileSourcePtr jstring JNICALL getAccessToken(JNIEnv *env, jobject obj, jlong defaultFileSourcePtr) { mbgl::Log::Debug(mbgl::Event::JNI, "getAccessToken"); + assert(defaultFileSourcePtr != 0); mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast(defaultFileSourcePtr); std::string accessToken = defaultFileSource->getAccessToken(); return std_string_to_jstring(env, accessToken); } +void JNICALL listOfflineRegions(JNIEnv *env, jobject obj, jlong defaultFileSourcePtr, jobject callback) { + mbgl::Log::Debug(mbgl::Event::JNI, "listOfflineRegions"); + + // Checks + assert(defaultFileSourcePtr != 0); + if (callback == nullptr) { + mbgl::Log::Error(mbgl::Event::JNI, "Callback has to be set."); + return; + } + + // Launch callback lambda + mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast(defaultFileSourcePtr); + defaultFileSource->listOfflineRegions([&env, &callback](std::exception_ptr error, mbgl::optional> regions) { + if (error) { + std::string message = mbgl::util::toString(error); + env->CallVoidMethod(callback, onErrorMethodId, std_string_to_jstring(env, message)); + } else if (regions) { + for(std::vector::size_type i = 0; i != regions->size(); i++) { + /* Handle regions */ + } + } + }); +} + // Offline calls end } @@ -2043,6 +2072,16 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { env->ExceptionDescribe(); } + listOfflineRegionsCallbackClass = env->FindClass("com/mapbox/mapboxsdk/offline/OfflineManager$ListOfflineRegionsCallback"); + if (listOfflineRegionsCallbackClass == nullptr) { + env->ExceptionDescribe(); + } + + onErrorMethodId = env->GetMethodID(listOfflineRegionsCallbackClass, "onError", "(Ljava/lang/String;)V"); + if (onErrorMethodId == nullptr) { + env->ExceptionDescribe(); + } + // Offline definitions end const std::vector methods = { @@ -2186,7 +2225,8 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { const std::vector offlineMethods = { {"createDefaultFileSource", "(Ljava/lang/String;Ljava/lang/String;)J", reinterpret_cast(&createDefaultFileSource)}, {"setAccessToken", "(JLjava/lang/String;)V", reinterpret_cast(&setAccessToken)}, - {"getAccessToken", "(J)Ljava/lang/String;", reinterpret_cast(&getAccessToken)} + {"getAccessToken", "(J)Ljava/lang/String;", reinterpret_cast(&getAccessToken)}, + {"listOfflineRegions", "(JLcom/mapbox/mapboxsdk/offline/OfflineManager$ListOfflineRegionsCallback;)V", reinterpret_cast(&listOfflineRegions)} }; if (env->RegisterNatives(customOfflineManagerClass, offlineMethods.data(), offlineMethods.size()) < 0) { @@ -2370,6 +2410,48 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { env->DeleteGlobalRef(httpContextClass); } + // Offline global definitions begin + + customOfflineManagerClass = reinterpret_cast(env->NewGlobalRef(customOfflineManagerClass)); + if (customOfflineManagerClass == nullptr) { + env->ExceptionDescribe(); + env->DeleteGlobalRef(latLngClass); + env->DeleteGlobalRef(latLngBoundsClass); + env->DeleteGlobalRef(iconClass); + env->DeleteGlobalRef(markerClass); + env->DeleteGlobalRef(polylineClass); + env->DeleteGlobalRef(polygonClass); + env->DeleteGlobalRef(runtimeExceptionClass); + env->DeleteGlobalRef(nullPointerExceptionClass); + env->DeleteGlobalRef(arrayListClass); + env->DeleteGlobalRef(projectedMetersClass); + env->DeleteGlobalRef(pointFClass); + env->DeleteGlobalRef(rectFClass); + env->DeleteGlobalRef(httpContextClass); + env->DeleteGlobalRef(httpRequestClass); + } + + listOfflineRegionsCallbackClass = reinterpret_cast(env->NewGlobalRef(listOfflineRegionsCallbackClass)); + if (listOfflineRegionsCallbackClass == nullptr) { + env->ExceptionDescribe(); + env->DeleteGlobalRef(latLngClass); + env->DeleteGlobalRef(latLngBoundsClass); + env->DeleteGlobalRef(iconClass); + env->DeleteGlobalRef(markerClass); + env->DeleteGlobalRef(polylineClass); + env->DeleteGlobalRef(polygonClass); + env->DeleteGlobalRef(runtimeExceptionClass); + env->DeleteGlobalRef(nullPointerExceptionClass); + env->DeleteGlobalRef(arrayListClass); + env->DeleteGlobalRef(projectedMetersClass); + env->DeleteGlobalRef(pointFClass); + env->DeleteGlobalRef(rectFClass); + env->DeleteGlobalRef(httpContextClass); + env->DeleteGlobalRef(customOfflineManagerClass); + } + + // Offline global definitions end + char release[PROP_VALUE_MAX] = ""; __system_property_get("ro.build.version.release", release); androidRelease = std::string(release); @@ -2472,6 +2554,14 @@ extern "C" JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) { httpRequestStartId = nullptr; httpRequestCancelId = nullptr; + // Offline delete begins + + env->DeleteGlobalRef(customOfflineManagerClass); + env->DeleteGlobalRef(listOfflineRegionsCallbackClass); + onErrorMethodId = nullptr; + + // Offline delete ends + theJVM = nullptr; } } diff --git a/platform/android/src/jni.hpp b/platform/android/src/jni.hpp index ae0624c4b32..a95ebff9148 100644 --- a/platform/android/src/jni.hpp +++ b/platform/android/src/jni.hpp @@ -103,6 +103,10 @@ extern jclass httpRequestClass; extern jmethodID httpRequestStartId; extern jmethodID httpRequestCancelId; +extern jclass customOfflineManagerClass; +extern jclass listOfflineRegionsCallbackClass; +extern jmethodID onErrorMethodId; + 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);