Use OkHTTP to implement HTTPContext on Android.

Closes #823
This commit is contained in:
Leith Bade
2015-07-31 13:00:52 +10:00
parent dc11b8132b
commit 0cbe7e07f5
12 changed files with 734 additions and 252 deletions

View File

@@ -28,6 +28,8 @@
namespace mbgl {
namespace android {
JavaVM* theJVM;
std::string cachePath;
std::string dataPath;
std::string apkPath;
@@ -90,7 +92,15 @@ jmethodID pointFConstructorId = nullptr;
jfieldID pointFXId = nullptr;
jfieldID pointFYId = nullptr;
bool throw_error(JNIEnv *env, const char *msg) {
jclass httpContextClass = nullptr;
jmethodID httpContextGetInstanceId = nullptr;
jmethodID httpContextCreateRequestId = nullptr;
jclass httpRequestClass = nullptr;
jmethodID httpRequestStartId = nullptr;
jmethodID httpRequestCancelId = nullptr;
bool throw_jni_error(JNIEnv *env, const char *msg) {
if (env->ThrowNew(runtimeExceptionClass, msg) < 0) {
env->ExceptionDescribe();
return false;
@@ -99,6 +109,41 @@ bool throw_error(JNIEnv *env, const char *msg) {
return true;
}
bool attach_jni_thread(JavaVM* vm, JNIEnv** env, std::string threadName) {
JavaVMAttachArgs args = {JNI_VERSION_1_2, threadName.c_str(), NULL};
jint ret;
*env = nullptr;
bool detach = false;
ret = vm->GetEnv(reinterpret_cast<void **>(env), JNI_VERSION_1_6);
if (ret != JNI_OK) {
if (ret != JNI_EDETACHED) {
mbgl::Log::Error(mbgl::Event::JNI, "GetEnv() failed with %i", ret);
throw new std::runtime_error("GetEnv() failed");
} else {
ret = vm->AttachCurrentThread(env, &args);
if (ret != JNI_OK) {
mbgl::Log::Error(mbgl::Event::JNI, "AttachCurrentThread() failed with %i", ret);
throw new std::runtime_error("AttachCurrentThread() failed");
}
detach = true;
}
}
return detach;
}
void detach_jni_thread(JavaVM* vm, JNIEnv** env, bool detach) {
if (detach) {
jint ret;
if ((ret = vm->DetachCurrentThread()) != JNI_OK) {
mbgl::Log::Error(mbgl::Event::JNI, "DetachCurrentThread() failed with %i", ret);
throw new std::runtime_error("DetachCurrentThread() failed");
}
}
*env = nullptr;
}
std::string std_string_from_jstring(JNIEnv *env, jstring jstr) {
std::string str;
@@ -342,7 +387,7 @@ void JNICALL nativeInitializeDisplay(JNIEnv *env, jobject obj, jlong nativeMapVi
{
nativeMapView->initializeDisplay();
} catch(const std::exception& e) {
throw_error(env, "Unable to initialize GL display.");
throw_jni_error(env, "Unable to initialize GL display.");
}
}
@@ -361,7 +406,7 @@ void JNICALL nativeInitializeContext(JNIEnv *env, jobject obj, jlong nativeMapVi
try {
nativeMapView->initializeContext();
} catch(const std::exception& e) {
throw_error(env, "Unable to initialize GL context.");
throw_jni_error(env, "Unable to initialize GL context.");
}
}
@@ -380,7 +425,7 @@ void JNICALL nativeCreateSurface(JNIEnv *env, jobject obj, jlong nativeMapViewPt
try {
nativeMapView->createSurface(ANativeWindow_fromSurface(env, surface));
} catch(const std::exception& e) {
throw_error(env, "Unable to create GL surface.");
throw_jni_error(env, "Unable to create GL surface.");
}
}
@@ -1131,6 +1176,8 @@ extern "C" {
extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
mbgl::Log::Debug(mbgl::Event::JNI, "JNI_OnLoad");
theJVM = vm;
JNIEnv *env = nullptr;
jint ret = vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6);
if (ret != JNI_OK) {
@@ -1426,6 +1473,36 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
return JNI_ERR;
}
httpContextClass = env->FindClass("com/mapbox/mapboxgl/http/HTTPContext");
if (httpContextClass == nullptr) {
env->ExceptionDescribe();
}
httpContextGetInstanceId = env->GetStaticMethodID(httpContextClass, "getInstance", "()Lcom/mapbox/mapboxgl/http/HTTPContext;");
if (httpContextGetInstanceId == nullptr) {
env->ExceptionDescribe();
}
httpContextCreateRequestId = env->GetMethodID(httpContextClass, "createRequest", "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lcom/mapbox/mapboxgl/http/HTTPContext$HTTPRequest;");
if (httpContextCreateRequestId == nullptr) {
env->ExceptionDescribe();
}
httpRequestClass = env->FindClass("com/mapbox/mapboxgl/http/HTTPContext$HTTPRequest");
if (httpRequestClass == nullptr) {
env->ExceptionDescribe();
}
httpRequestStartId = env->GetMethodID(httpRequestClass, "start", "()V");
if (httpRequestStartId == nullptr) {
env->ExceptionDescribe();
}
httpRequestCancelId = env->GetMethodID(httpRequestClass, "cancel", "()V");
if (httpRequestCancelId == nullptr) {
env->ExceptionDescribe();
}
const std::vector<JNINativeMethod> methods = {
{"nativeCreate", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;FIJ)J",
reinterpret_cast<void *>(&nativeCreate)},
@@ -1524,10 +1601,16 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
//{"nativeGetWorldBoundsMeters", "(J)V", reinterpret_cast<void *>(&nativeGetWorldBoundsMeters)},
//{"nativeGetWorldBoundsLatLng", "(J)V", reinterpret_cast<void *>(&nativeGetWorldBoundsLatLng)},
{"nativeGetMetersPerPixelAtLatitude", "(JDD)D", reinterpret_cast<void *>(&nativeGetMetersPerPixelAtLatitude)},
{"nativeProjectedMetersForLatLng", "(JLcom/mapbox/mapboxgl/geometry/LatLng;)Lcom/mapbox/mapboxgl/geometry/ProjectedMeters;", reinterpret_cast<void *>(&nativeProjectedMetersForLatLng)},
{"nativeLatLngForProjectedMeters", "(JLcom/mapbox/mapboxgl/geometry/ProjectedMeters;)Lcom/mapbox/mapboxgl/geometry/LatLng;", reinterpret_cast<void *>(&nativeLatLngForProjectedMeters)},
{"nativePixelForLatLng", "(JLcom/mapbox/mapboxgl/geometry/LatLng;)Landroid/graphics/PointF;", reinterpret_cast<void *>(&nativePixelForLatLng)},
{"nativeLatLngForPixel", "(JLandroid/graphics/PointF;)Lcom/mapbox/mapboxgl/geometry/LatLng;", reinterpret_cast<void *>(&nativeLatLngForPixel)},
{"nativeProjectedMetersForLatLng",
"(JLcom/mapbox/mapboxgl/geometry/LatLng;)Lcom/mapbox/mapboxgl/geometry/ProjectedMeters;",
reinterpret_cast<void *>(&nativeProjectedMetersForLatLng)},
{"nativeLatLngForProjectedMeters",
"(JLcom/mapbox/mapboxgl/geometry/ProjectedMeters;)Lcom/mapbox/mapboxgl/geometry/LatLng;",
reinterpret_cast<void *>(&nativeLatLngForProjectedMeters)},
{"nativePixelForLatLng", "(JLcom/mapbox/mapboxgl/geometry/LatLng;)Landroid/graphics/PointF;",
reinterpret_cast<void *>(&nativePixelForLatLng)},
{"nativeLatLngForPixel", "(JLandroid/graphics/PointF;)Lcom/mapbox/mapboxgl/geometry/LatLng;",
reinterpret_cast<void *>(&nativeLatLngForPixel)},
};
if (env->RegisterNatives(nativeMapViewClass, methods.data(), methods.size()) < 0) {
@@ -1641,6 +1724,37 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
return JNI_ERR;
}
httpContextClass = reinterpret_cast<jclass>(env->NewGlobalRef(httpContextClass));
if (httpContextClass == nullptr) {
env->ExceptionDescribe();
env->DeleteGlobalRef(latLngClass);
env->DeleteGlobalRef(markerClass);
env->DeleteGlobalRef(latLngZoomClass);
env->DeleteGlobalRef(polylineClass);
env->DeleteGlobalRef(polygonClass);
env->DeleteGlobalRef(runtimeExceptionClass);
env->DeleteGlobalRef(nullPointerExceptionClass);
env->DeleteGlobalRef(arrayListClass);
env->DeleteGlobalRef(projectedMetersClass);
env->DeleteGlobalRef(pointFClass);
}
httpRequestClass = reinterpret_cast<jclass>(env->NewGlobalRef(httpRequestClass));
if (httpRequestClass == nullptr) {
env->ExceptionDescribe();
env->DeleteGlobalRef(latLngClass);
env->DeleteGlobalRef(markerClass);
env->DeleteGlobalRef(latLngZoomClass);
env->DeleteGlobalRef(polylineClass);
env->DeleteGlobalRef(polygonClass);
env->DeleteGlobalRef(runtimeExceptionClass);
env->DeleteGlobalRef(nullPointerExceptionClass);
env->DeleteGlobalRef(arrayListClass);
env->DeleteGlobalRef(projectedMetersClass);
env->DeleteGlobalRef(pointFClass);
env->DeleteGlobalRef(httpContextClass);
}
char release[PROP_VALUE_MAX] = "";
__system_property_get("ro.build.version.release", release);
androidRelease = std::string(release);
@@ -1651,6 +1765,8 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
extern "C" JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) {
mbgl::Log::Debug(mbgl::Event::JNI, "JNI_OnUnload");
theJVM = vm;
JNIEnv *env = nullptr;
jint ret = vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6);
if (ret != JNI_OK) {
@@ -1725,5 +1841,15 @@ extern "C" JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) {
pointFConstructorId = nullptr;
pointFXId = nullptr;
pointFYId = nullptr;
env->DeleteGlobalRef(httpContextClass);
httpContextGetInstanceId = nullptr;
httpContextCreateRequestId = nullptr;
env->DeleteGlobalRef(httpRequestClass);
httpRequestStartId = nullptr;
httpRequestCancelId = nullptr;
theJVM = nullptr;
}
}

View File

@@ -148,38 +148,15 @@ void NativeMapView::invalidate() {
assert(vm != nullptr);
assert(obj != nullptr);
JavaVMAttachArgs args = {JNI_VERSION_1_2, "NativeMapView::invalidate()", NULL};
jint ret;
JNIEnv *env = nullptr;
bool detach = false;
ret = vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6);
if (ret != JNI_OK) {
if (ret != JNI_EDETACHED) {
mbgl::Log::Error(mbgl::Event::JNI, "GetEnv() failed with %i", ret);
throw new std::runtime_error("GetEnv() failed");
} else {
ret = vm->AttachCurrentThread(&env, &args);
if (ret != JNI_OK) {
mbgl::Log::Error(mbgl::Event::JNI, "AttachCurrentThread() failed with %i", ret);
throw new std::runtime_error("AttachCurrentThread() failed");
}
detach = true;
}
}
bool detach = attach_jni_thread(vm, &env, "NativeMapView::invalidate()");
env->CallVoidMethod(obj, onInvalidateId);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
}
if (detach) {
if ((ret = vm->DetachCurrentThread()) != JNI_OK) {
mbgl::Log::Error(mbgl::Event::JNI, "DetachCurrentThread() failed with %i", ret);
throw new std::runtime_error("DetachCurrentThread() failed");
}
}
env = nullptr;
detach_jni_thread(vm, &env, detach);
}
void NativeMapView::swap() {
@@ -662,38 +639,15 @@ void NativeMapView::notifyMapChange(mbgl::MapChange) {
assert(vm != nullptr);
assert(obj != nullptr);
JavaVMAttachArgs args = {JNI_VERSION_1_2, "NativeMapView::notifyMapChange()", NULL};
jint ret;
JNIEnv *env = nullptr;
bool detach = false;
ret = vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6);
if (ret != JNI_OK) {
if (ret != JNI_EDETACHED) {
mbgl::Log::Error(mbgl::Event::JNI, "GetEnv() failed with %i", ret);
throw new std::runtime_error("GetEnv() failed");
} else {
ret = vm->AttachCurrentThread(&env, &args);
if (ret != JNI_OK) {
mbgl::Log::Error(mbgl::Event::JNI, "AttachCurrentThread() failed with %i", ret);
throw new std::runtime_error("AttachCurrentThread() failed");
}
detach = true;
}
}
bool detach = attach_jni_thread(vm, &env, "NativeMapView::notifyMapChange()");
env->CallVoidMethod(obj, onMapChangedId);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
}
if (detach) {
if ((ret = vm->DetachCurrentThread()) != JNI_OK) {
mbgl::Log::Error(mbgl::Event::JNI, "DetachCurrentThread() failed with %i", ret);
throw new std::runtime_error("DetachCurrentThread() failed");
}
}
env = nullptr;
detach_jni_thread(vm, &env, detach);
}
void NativeMapView::enableFps(bool enable) {
@@ -727,38 +681,15 @@ void NativeMapView::updateFps() {
assert(vm != nullptr);
assert(obj != nullptr);
JavaVMAttachArgs args = {JNI_VERSION_1_2, "NativeMapView::updateFps()", NULL};
jint ret;
JNIEnv *env = nullptr;
bool detach = false;
ret = vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6);
if (ret != JNI_OK) {
if (ret != JNI_EDETACHED) {
mbgl::Log::Error(mbgl::Event::JNI, "GetEnv() failed with %i", ret);
throw new std::runtime_error("GetEnv() failed");
} else {
ret = vm->AttachCurrentThread(&env, &args);
if (ret != JNI_OK) {
mbgl::Log::Error(mbgl::Event::JNI, "AttachCurrentThread() failed with %i", ret);
throw new std::runtime_error("AttachCurrentThread() failed");
}
detach = true;
}
}
bool detach = attach_jni_thread(vm, &env, "NativeMapView::updateFps()");
env->CallVoidMethod(obj, onFpsChangedId, fps);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
}
if (detach) {
if ((ret = vm->DetachCurrentThread()) != JNI_OK) {
mbgl::Log::Error(mbgl::Event::JNI, "DetachCurrentThread() failed with %i", ret);
throw new std::runtime_error("DetachCurrentThread() failed");
}
}
env = nullptr;
detach_jni_thread(vm, &env, detach);
}
void NativeMapView::onInvalidate() {