Merge pull request #542 from ljbade/android-mason

Android mason: Get android building
This commit is contained in:
Leith Bade
2014-11-07 17:57:31 +11:00
56 changed files with 5336 additions and 11 deletions

2
.mason

Submodule .mason updated: 4c53b0a3a6...a3ebabd0c6

View File

@@ -23,12 +23,16 @@ env:
- secure: "Cbvap9ubVKgjPe3hUhI6JGeDZzBXHpOG9RaYKh+SdoIPhKnlJiNOYm1egomi+e4uqJInlFKuVHTw7Ng9Cun6Zm0jIxpkSchv1GpsR7hmB3UGnGed19Dw8121FwuUaktN+4YnbVlsyd+u8EHD3+h58t4eELrLrZolM4rS7DL6caA="
- secure: "RiBIBfVhhaMjU5ksuwJO3shdvG9FpinBjdSv4co9jg9171SR8edNriedHjVKSIeBhSGNmZmX+twS3dJS/By6tl/LKh9sTynA+ZAYYljkE7jn881B/gMrlYvdAA6og5KvkhV1/0iJWlhuZrMTkhpDR200iLgg3EWBhWjltzmDW/I="
- LD_LIBRARY_PATH: '/usr/local/lib'
- TERM=dumb
before_install:
- source ./scripts/local_mason.sh
- source ./scripts/travis_helper.sh
- source ./scripts/flags.sh
- export ANDROID_NDK_PATH="$(pwd)/android-ndk-r10c"
- export NDK_HOME="$(pwd)/android-ndk-r10c"
- export JAVA_HOME="$(pwd)/jdk1.7.0_71"
- export ANDROID_HOME="$(pwd)/android-sdk-linux"
- ./scripts/travis_before_install.sh
- if [[ ${TRAVIS_OS_NAME} == "linux" ]]; then export LD_LIBRARY_PATH=`mason prefix mesa 10.3.1`/lib; fi
- if [[ ${TRAVIS_OS_NAME} == "linux" ]]; then glxinfo; fi

View File

@@ -74,6 +74,7 @@ android:
export CXX="`MASON_DIR=./.mason MASON_PLATFORM=android ./.mason/mason env CXX`" && \
export CC="`MASON_DIR=./.mason MASON_PLATFORM=android ./.mason/mason env CC`" && \
export LD="`MASON_DIR=./.mason MASON_PLATFORM=android ./.mason/mason env LD`" && \
export LINK="`MASON_DIR=./.mason MASON_PLATFORM=android ./.mason/mason env CXX`" && \
export AR="`MASON_DIR=./.mason MASON_PLATFORM=android ./.mason/mason env AR`" && \
export RANLIB="`MASON_DIR=./.mason MASON_PLATFORM=android ./.mason/mason env RANLIB`" && \
export LDFLAGS="`MASON_DIR=./.mason MASON_PLATFORM=android ./.mason/mason env LDFLAGS` ${LDFLAGS}" && \
@@ -81,8 +82,12 @@ android:
export CPPFLAGS="`MASON_DIR=./.mason MASON_PLATFORM=android ./.mason/mason env CPPFLAGS` ${CPPFLAGS}" && \
export PATH="`MASON_DIR=./.mason MASON_PLATFORM=android ./.mason/mason env PATH`:${PATH}" && \
MASON_PLATFORM=android ./configure config-android.gypi && \
deps/run_gyp mapboxgl.gyp -Iconfig-android.gypi -Dplatform=android --depth=. --generator-output=./build/android -f make-android && \
$(MAKE) -C ./build/android BUILDTYPE=$(BUILDTYPE) V=$(V) mbgl-core
deps/run_gyp android/mapboxgl-app.gyp -Iconfig-android.gypi -Dplatform=android --depth=. --generator-output=./build/android -f make-android && \
$(MAKE) -C build/android BUILDTYPE=$(BUILDTYPE) V=$(V) androidapp && \
mkdir -p android/java/lib/src/main/jniLibs/armeabi-v7a && \
cp build/android/out/$(BUILDTYPE)/lib.target/libmapbox-gl.so android/java/lib/src/main/jniLibs/armeabi-v7a/libmapbox-gl.so && \
cd android/java && \
./gradlew build
##### Test cases ###############################################################
@@ -147,6 +152,8 @@ clean: clear_xcode_cache
-rm -rf ./build/
-rm -rf ./macosx/build/
-rm -rf ./config.gypi ./config-ios.gypi ./config-android.gypi
-rm -rf ./android/java/build ./android/java/app/build ./android/java/lib/build
-rm -rf ./android/java/lib/src/main/jniLibs
distclean: clean
-rm -rf ./mason_packages

812
android/cpp/JNI.cpp Normal file
View File

@@ -0,0 +1,812 @@
#include <cstdint>
#include <cinttypes>
#include <string>
#include <locale>
#include <codecvt>
#include <array>
#include <vector>
#include <jni.h>
#include <android/native_window_jni.h>
#include "log.h"
#include "NativeMapView.hpp"
#pragma clang diagnostic ignored "-Wunused-parameter"
namespace mbgl {
namespace android {
jmethodID on_map_changed_id = nullptr;
jclass lon_lat_class = nullptr;
jmethodID lon_lat_constructor_id = nullptr;
jfieldID lon_lat_lon_id = nullptr;
jfieldID lon_lat_lat_id = nullptr;
jclass lon_lat_zoom_class = nullptr;
jmethodID lon_lat_zoom_constructor_id = nullptr;
jfieldID lon_lat_zoom_lon_id = nullptr;
jfieldID lon_lat_zoom_lat_id = nullptr;
jfieldID lon_lat_zoom_zoom_id = nullptr;
jclass runtime_exception_class = nullptr;
jmethodID set_to_array_id = nullptr;
jclass tree_set_class = nullptr;
jmethodID tree_set_constructor_id = nullptr;
jmethodID tree_set_add_id = nullptr;
bool throw_error(JNIEnv* env, const char* msg) {
if (env->ThrowNew(runtime_exception_class, msg) < 0) {
env->ExceptionDescribe();
return false;
}
return true;
}
std::string std_string_from_jstring(JNIEnv* env, jstring jstr) {
std::string str;
jsize len = env->GetStringLength(jstr);
if (len < 0) {
env->ExceptionDescribe();
return str;
}
const jchar* chars = env->GetStringChars(jstr, nullptr);
if (chars == nullptr) {
env->ExceptionDescribe();
return str;
}
std::u16string ustr(reinterpret_cast<const char16_t*>(chars), len);
env->ReleaseStringChars(jstr, chars);
chars = nullptr;
str = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t>().to_bytes(ustr);
return str;
}
jstring std_string_to_jstring(JNIEnv* env, std::string str) {
std::u16string ustr = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t>().from_bytes(str);
jstring jstr = env->NewString(reinterpret_cast<const jchar*>(ustr.c_str()), ustr.size());
if (jstr == nullptr) {
env->ExceptionDescribe();
return nullptr;
}
return jstr;
}
// TODO: change from Java TreeSet to ArrayList
std::vector<std::string> std_vector_string_from_jobject(JNIEnv* env, jobject jset) {
std::vector<std::string> vector;
jobjectArray array = reinterpret_cast<jobjectArray>(env->CallObjectMethod(jset, set_to_array_id));
if (env->ExceptionCheck() || (array == nullptr)) {
env->ExceptionDescribe();
return vector;
}
jsize len = env->GetArrayLength(array);
if (len < 0) {
env->ExceptionDescribe();
return vector;
}
for (jsize i = 0; i < len; i++) {
jstring jstr = reinterpret_cast<jstring>(env->GetObjectArrayElement(array, i));
if (jstr == nullptr) {
env->ExceptionDescribe();
return vector;
}
vector.push_back(std_string_from_jstring(env, jstr));
}
return vector;
}
// TODO: change from Java TreeSet to ArrayList
jobject std_vector_string_to_jobject(JNIEnv* env, std::vector<std::string> vector) {
jobject jset = env->NewObject(tree_set_class, tree_set_constructor_id);
if (jset == nullptr) {
env->ExceptionDescribe();
return nullptr;
}
for (std::string str : vector) {
env->CallBooleanMethod(jset, tree_set_add_id, std_string_to_jstring(env, str));
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
return nullptr;
}
}
return jset;
}
} // namespace android
} // namespace mbgl
namespace {
using namespace mbgl::android;
// TODO: wrap C++ exceptions?
// TODO: wrap other sorts of exceptions? eg coffee catch
jlong JNICALL nativeCreate(JNIEnv* env, jobject obj, jstring default_style_json) {
VERBOSE("nativeCreate");
NativeMapView* native_map_view = new NativeMapView(env, obj, std_string_from_jstring(env, default_style_json));
if (native_map_view == nullptr) {
throw_error(env, "Unable to create NativeMapView.");
return 0;
}
jlong map_view_ptr = reinterpret_cast<jlong>(native_map_view);
return map_view_ptr;
}
void JNICALL nativeDestroy(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeDestroy");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
delete native_map_view;
native_map_view = nullptr;
}
void JNICALL nativeInitializeDisplay(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeInitializeDisplay");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
if (!native_map_view->initializeDisplay()) {
throw_error(env, "Unable to initialize GL display.");
}
}
void JNICALL nativeTerminateDisplay(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeTerminateDisplay");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->terminateDisplay();
}
void JNICALL nativeInitializeContext(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeInitializeContext");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
if (!native_map_view->initializeContext()) {
throw_error(env, "Unable to initialize GL context.");
}
}
void JNICALL nativeTerminateContext(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeTerminateContext");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->terminateContext();
}
void JNICALL nativeCreateSurface(JNIEnv* env, jobject obj, jlong native_map_view_ptr, jobject surface) {
VERBOSE("nativeCreateSurface");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
if (!native_map_view->createSurface(ANativeWindow_fromSurface(env, surface))) {
throw_error(env, "Unable to create GL surface.");
}
}
void JNICALL nativeDestroySurface(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeDestroySurface");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->destroySurface();
}
void JNICALL nativeStart(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeStart");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->start();
}
void JNICALL nativeStop(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeStop");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->stop();
}
void JNICALL nativeRerender(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeRerender");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->getMap()->rerender();
}
void JNICALL nativeUpdate(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeUpdate");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->getMap()->update();
}
void JNICALL nativeCleanup(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeCleanup");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->getMap()->cleanup();
}
void JNICALL nativeResize(JNIEnv* env, jobject obj, jlong native_map_view_ptr, jint width, jint height, jfloat ratio) {
VERBOSE("nativeResize");
ASSERT(native_map_view_ptr != 0);
ASSERT(width >= 0);
ASSERT(height >= 0);
ASSERT(width <= UINT16_MAX);
ASSERT(height <= UINT16_MAX);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->getMap()->resize(width, height, ratio);
}
void JNICALL nativeResize(JNIEnv* env, jobject obj, jlong native_map_view_ptr, jint width, jint height, jfloat ratio, jint fb_width, jint fb_height) {
VERBOSE("nativeResize");
ASSERT(native_map_view_ptr != 0);
ASSERT(width >= 0);
ASSERT(height >= 0);
ASSERT(width <= UINT16_MAX);
ASSERT(height <= UINT16_MAX);
ASSERT(fb_width >= 0);
ASSERT(fb_height >= 0);
ASSERT(fb_width <= UINT16_MAX);
ASSERT(fb_height <= UINT16_MAX);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->getMap()->resize(width, height, ratio, fb_width, fb_height);
}
void JNICALL nativeSetAppliedClasses(JNIEnv* env, jobject obj, jlong native_map_view_ptr, jobject applied_classes) {
VERBOSE("nativeSetAppliedClasses");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->getMap()->setAppliedClasses(std_vector_string_from_jobject(env, applied_classes));
}
jobject JNICALL nativeGetAppliedClasses(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeGetAppliedClasses");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
return std_vector_string_to_jobject(env, native_map_view->getMap()->getAppliedClasses());
}
void JNICALL nativeSetDefaultTransitionDuration(JNIEnv* env, jobject obj, jlong native_map_view_ptr, jlong duration_milliseconds) {
VERBOSE("nativeSetDefaultTransitionDuration");
ASSERT(native_map_view_ptr != 0);
ASSERT(duration_milliseconds >= 0);
//ASSERT(duration_milliseconds <= UINT64_MAX);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->getMap()->setDefaultTransitionDuration(duration_milliseconds);
}
void JNICALL nativeSetStyleJSON(JNIEnv* env, jobject obj, jlong native_map_view_ptr, jstring new_style_json) {
VERBOSE("nativeSetStyleJSON");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->getMap()->setStyleJSON(std_string_from_jstring(env, new_style_json));
}
jstring JNICALL nativeGetStyleJSON(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeGetStyleJSON");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
return std_string_to_jstring(env, native_map_view->getMap()->getStyleJSON());
}
void JNICALL nativeCancelTransitions(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeCancelTransitions");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->getMap()->cancelTransitions();
}
void JNICALL nativeMoveBy(JNIEnv* env, jobject obj, jlong native_map_view_ptr, jdouble dx, jdouble dy, jdouble duration) {
VERBOSE("nativeMoveBy");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->getMap()->moveBy(dx, dy, duration);
}
void JNICALL nativeSetLonLat(JNIEnv* env, jobject obj, jlong native_map_view_ptr, jobject lon_lat, jdouble duration) {
VERBOSE("nativeSetLonLat");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
double lon = env->GetDoubleField(lon_lat, lon_lat_lon_id);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
return;
}
double lat = env->GetDoubleField(lon_lat, lon_lat_lat_id);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
return;
}
// TODO remove when fixed
DEBUG("lon lat %f %f", lon, lat);
native_map_view->getMap()->setLonLat(lon, lat, duration);
}
jobject JNICALL nativeGetLonLat(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeGetLonLat");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
double lon, lat;
native_map_view->getMap()->getLonLat(lon, lat);
jobject ret = env->NewObject(lon_lat_class, lon_lat_constructor_id, lon, lat);
if (ret == nullptr) {
env->ExceptionDescribe();
return nullptr;
}
return ret;
}
void JNICALL nativeStartPanning(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeStartPanning");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->getMap()->startPanning();
}
void JNICALL nativeStopPanning(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeStopPanning");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->getMap()->stopPanning();
}
void JNICALL nativeResetPosition(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeResetPosition");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->getMap()->resetPosition();
}
void JNICALL nativeScaleBy(JNIEnv* env, jobject obj, jlong native_map_view_ptr, jdouble ds, jdouble cx, jdouble cy, jdouble duration) {
VERBOSE("nativeScaleBy");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->getMap()->scaleBy(ds, cx, cy, duration);
}
void JNICALL nativeSetScale(JNIEnv* env, jobject obj, jlong native_map_view_ptr, jdouble scale, jdouble cx, jdouble cy, jdouble duration) {
VERBOSE("nativeSetScale");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->getMap()->setScale(scale, cx, cy, duration);
}
jdouble JNICALL nativeGetScale(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeGetScale");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
return native_map_view->getMap()->getScale();
}
void JNICALL nativeSetZoom(JNIEnv* env, jobject obj, jlong native_map_view_ptr, jdouble zoom, jdouble duration) {
VERBOSE("nativeSetZoom");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->getMap()->setZoom(zoom, duration);
}
jdouble JNICALL nativeGetZoom(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeGetZoom");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
return native_map_view->getMap()->getZoom();
}
void JNICALL nativeSetLonLatZoom(JNIEnv* env, jobject obj, jlong native_map_view_ptr, jobject lon_lat_zoom, jdouble duration) {
VERBOSE("nativeSetLonLatZoom");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
double lon = env->GetDoubleField(lon_lat_zoom, lon_lat_zoom_lon_id);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
return;
}
double lat = env->GetDoubleField(lon_lat_zoom, lon_lat_zoom_lat_id);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
return;
}
double zoom = env->GetDoubleField(lon_lat_zoom, lon_lat_zoom_zoom_id);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
return;
}
native_map_view->getMap()->setLonLatZoom(lon, lat, zoom, duration);
}
jobject JNICALL nativeGetLonLatZoom(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeGetLonLatZoom");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
double lon, lat, zoom;
native_map_view->getMap()->getLonLatZoom(lon, lat, zoom);
jobject ret = env->NewObject(lon_lat_zoom_class, lon_lat_zoom_constructor_id, lon, lat, zoom);
if (ret == nullptr) {
env->ExceptionDescribe();
return nullptr;
}
return ret;
}
void JNICALL nativeResetZoom(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeResetZoom");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->getMap()->resetZoom();
}
void JNICALL nativeStartScaling(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeStartScaling");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->getMap()->startScaling();
}
void JNICALL nativeStopScaling(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeStopScaling");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->getMap()->stopScaling();
}
jdouble JNICALL nativeGetMinZoom(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeGetMinZoom");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
return native_map_view->getMap()->getMinZoom();
}
jdouble JNICALL nativeGetMaxZoom(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeGetMaxZoom");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
return native_map_view->getMap()->getMaxZoom();
}
void JNICALL nativeRotateBy(JNIEnv* env, jobject obj, jlong native_map_view_ptr, jdouble sx, jdouble sy, jdouble ex, jdouble ey, jdouble duration) {
VERBOSE("nativeRotateBy");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->getMap()->rotateBy(sx, sy, ex, ey, duration);
}
void JNICALL nativeSetBearing(JNIEnv* env, jobject obj, jlong native_map_view_ptr, jdouble degrees, jdouble duration) {
VERBOSE("nativeSetBearing");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->getMap()->setBearing(degrees, duration);
}
void JNICALL nativeSetBearing(JNIEnv* env, jobject obj, jlong native_map_view_ptr, jdouble degrees, jdouble cx, jdouble cy) {
VERBOSE("nativeSetBearing");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->getMap()->setBearing(degrees, cx, cy);
}
jdouble JNICALL nativeGetBearing(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeGetBearing");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
return native_map_view->getMap()->getBearing();
}
void JNICALL nativeResetNorth(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeResetNorth");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->getMap()->resetNorth();
}
void JNICALL nativeStartRotating(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeStartRotating");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->getMap()->startRotating();
}
void JNICALL nativeStopRotating(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeStopRotating");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->getMap()->stopRotating();
}
jboolean JNICALL nativeCanRotate(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeCanRotate");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
return native_map_view->getMap()->canRotate();
}
void JNICALL nativeSetDebug(JNIEnv* env, jobject obj, jlong native_map_view_ptr, jboolean debug) {
VERBOSE("nativeSetDebug");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->getMap()->setDebug(debug);
}
void JNICALL nativeToggleDebug(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeToggleDebug");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
native_map_view->getMap()->toggleDebug();
}
jboolean JNICALL nativeGetDebug(JNIEnv* env, jobject obj, jlong native_map_view_ptr) {
VERBOSE("nativeGetDebug");
ASSERT(native_map_view_ptr != 0);
NativeMapView* native_map_view = reinterpret_cast<NativeMapView*>(native_map_view_ptr);
return native_map_view->getMap()->getDebug();
}
} // namespace
extern "C" {
extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
VERBOSE("JNI_OnLoad");
JNIEnv* env = nullptr;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
ERROR("GetEnv() failed");
return JNI_ERR;
}
lon_lat_class = env->FindClass("com/mapbox/mapboxgl/lib/LonLat");
if (lon_lat_class == nullptr) {
env->ExceptionDescribe();
return JNI_ERR;
}
lon_lat_constructor_id = env->GetMethodID(lon_lat_class, "<init>", "(DD)V");
if (lon_lat_constructor_id == nullptr) {
env->ExceptionDescribe();
return JNI_ERR;
}
lon_lat_lon_id = env->GetFieldID(lon_lat_class, "lon", "D");
if (lon_lat_lon_id == nullptr) {
env->ExceptionDescribe();
return JNI_ERR;
}
lon_lat_lat_id = env->GetFieldID(lon_lat_class, "lat", "D");
if (lon_lat_lat_id == nullptr) {
env->ExceptionDescribe();
return JNI_ERR;
}
lon_lat_zoom_class = env->FindClass("com/mapbox/mapboxgl/lib/LonLatZoom");
if (lon_lat_class == nullptr) {
env->ExceptionDescribe();
return JNI_ERR;
}
lon_lat_zoom_constructor_id = env->GetMethodID(lon_lat_zoom_class, "<init>", "(DDD)V");
if (lon_lat_zoom_constructor_id == nullptr) {
env->ExceptionDescribe();
return JNI_ERR;
}
lon_lat_zoom_lon_id = env->GetFieldID(lon_lat_zoom_class, "lon", "D");
if (lon_lat_zoom_lon_id == nullptr) {
env->ExceptionDescribe();
return JNI_ERR;
}
lon_lat_zoom_lat_id = env->GetFieldID(lon_lat_zoom_class, "lat", "D");
if (lon_lat_zoom_lat_id == nullptr) {
env->ExceptionDescribe();
return JNI_ERR;
}
lon_lat_zoom_zoom_id = env->GetFieldID(lon_lat_zoom_class, "zoom", "D");
if (lon_lat_zoom_zoom_id == nullptr) {
env->ExceptionDescribe();
return JNI_ERR;
}
jclass native_map_view_class = env->FindClass("com/mapbox/mapboxgl/lib/NativeMapView");
if (native_map_view_class == nullptr) {
env->ExceptionDescribe();
return JNI_ERR;
}
on_map_changed_id = env->GetMethodID(native_map_view_class, "onMapChanged", "()V");
if (on_map_changed_id == nullptr) {
env->ExceptionDescribe();
return JNI_ERR;
}
runtime_exception_class = env->FindClass("java/lang/RuntimeException");
if (runtime_exception_class == nullptr) {
env->ExceptionDescribe();
return JNI_ERR;
}
jclass set_class = env->FindClass("java/util/Set");
if (set_class == nullptr) {
env->ExceptionDescribe();
return JNI_ERR;
}
set_to_array_id = env->GetMethodID(set_class, "toArray", "()[Ljava/lang/Object;");
if (set_to_array_id == nullptr) {
env->ExceptionDescribe();
return JNI_ERR;
}
tree_set_class = env->FindClass("java/util/TreeSet");
if (tree_set_class == nullptr) {
env->ExceptionDescribe();
return JNI_ERR;
}
tree_set_constructor_id = env->GetMethodID(tree_set_class, "<init>", "()V");
if (tree_set_constructor_id == nullptr) {
env->ExceptionDescribe();
return JNI_ERR;
}
tree_set_add_id = env->GetMethodID(tree_set_class, "add", "(Ljava/lang/Object;)Z");
if (tree_set_add_id == nullptr) {
env->ExceptionDescribe();
return JNI_ERR;
}
// NOTE: if you get java.lang.UnsatisfiedLinkError you likely forgot to set the size of the array correctly (too large)
std::array<JNINativeMethod, 50> methods = {{ // Can remove the extra brace in C++14
{ "nativeCreate", "(Ljava/lang/String;)J", reinterpret_cast<void*>(&nativeCreate) },
{ "nativeDestroy", "(J)V", reinterpret_cast<void*>(&nativeDestroy) },
{ "nativeInitializeDisplay", "(J)V", reinterpret_cast<void*>(&nativeInitializeDisplay) },
{ "nativeTerminateDisplay", "(J)V", reinterpret_cast<void*>(&nativeTerminateDisplay) },
{ "nativeInitializeContext", "(J)V", reinterpret_cast<void*>(&nativeInitializeContext) },
{ "nativeTerminateContext", "(J)V", reinterpret_cast<void*>(&nativeTerminateContext) },
{ "nativeCreateSurface", "(JLandroid/view/Surface;)V", reinterpret_cast<void*>(&nativeCreateSurface) },
{ "nativeDestroySurface", "(J)V", reinterpret_cast<void*>(&nativeDestroySurface) },
{ "nativeStart", "(J)V", reinterpret_cast<void*>(&nativeStart) },
{ "nativeStop", "(J)V", reinterpret_cast<void*>(&nativeStop) },
{ "nativeRerender", "(J)V", reinterpret_cast<void*>(&nativeRerender) },
{ "nativeUpdate", "(J)V", reinterpret_cast<void*>(&nativeUpdate) },
{ "nativeCleanup", "(J)V", reinterpret_cast<void*>(&nativeCleanup) },
{ "nativeResize", "(JIIF)V", reinterpret_cast<void*>(static_cast<void JNICALL(*)(JNIEnv*,jobject,jlong,jint,jint,jfloat)>(&nativeResize)) },
{ "nativeResize", "(JIIFII)V", reinterpret_cast<void*>(static_cast<void JNICALL(*)(JNIEnv*,jobject,jlong,jint,jint,jfloat,jint,jint)>(&nativeResize)) },
{ "nativeSetAppliedClasses", "(JLjava/util/Set;)V", reinterpret_cast<void*>(&nativeSetAppliedClasses) },
{ "nativeGetAppliedClasses", "(J)Ljava/util/Set;", reinterpret_cast<void*>(&nativeGetAppliedClasses) },
{ "nativeSetDefaultTransitionDuration", "(JJ)V", reinterpret_cast<void*>(&nativeSetDefaultTransitionDuration) },
{ "nativeSetStyleJSON", "(JLjava/lang/String;)V", reinterpret_cast<void*>(&nativeSetStyleJSON) },
{ "nativeGetStyleJSON", "(J)Ljava/lang/String;", reinterpret_cast<void*>(&nativeGetStyleJSON) },
{ "nativeCancelTransitions", "(J)V", reinterpret_cast<void*>(&nativeCancelTransitions) },
{ "nativeMoveBy", "(JDDD)V", reinterpret_cast<void*>(&nativeMoveBy) },
{ "nativeSetLonLat", "(JLcom/mapbox/mapboxgl/lib/LonLat;D)V", reinterpret_cast<void*>(&nativeSetLonLat) },
{ "nativeGetLonLat", "(J)Lcom/mapbox/mapboxgl/lib/LonLat;", reinterpret_cast<void*>(&nativeGetLonLat) },
{ "nativeStartPanning", "(J)V", reinterpret_cast<void*>(&nativeStartPanning) },
{ "nativeStopPanning", "(J)V", reinterpret_cast<void*>(&nativeStopPanning) },
{ "nativeResetPosition", "(J)V", reinterpret_cast<void*>(&nativeResetPosition) },
{ "nativeScaleBy", "(JDDDD)V", reinterpret_cast<void*>(&nativeScaleBy) },
{ "nativeSetScale", "(JDDDD)V", reinterpret_cast<void*>(&nativeSetScale) },
{ "nativeGetScale", "(J)D", reinterpret_cast<void*>(&nativeGetScale) },
{ "nativeSetZoom", "(JDD)V", reinterpret_cast<void*>(&nativeSetZoom) },
{ "nativeGetZoom", "(J)D", reinterpret_cast<void*>(&nativeGetZoom) },
{ "nativeSetLonLatZoom", "(JLcom/mapbox/mapboxgl/lib/LonLatZoom;D)V", reinterpret_cast<void*>(&nativeSetLonLatZoom) },
{ "nativeGetLonLatZoom", "(J)Lcom/mapbox/mapboxgl/lib/LonLatZoom;", reinterpret_cast<void*>(&nativeGetLonLatZoom) },
{ "nativeResetZoom", "(J)V", reinterpret_cast<void*>(&nativeResetZoom) },
{ "nativeStartPanning", "(J)V", reinterpret_cast<void*>(&nativeStartScaling) },
{ "nativeStopPanning", "(J)V", reinterpret_cast<void*>(&nativeStopScaling) },
{ "nativeGetMinZoom", "(J)D", reinterpret_cast<void*>(&nativeGetMinZoom) },
{ "nativeGetMaxZoom", "(J)D", reinterpret_cast<void*>(&nativeGetMaxZoom) },
{ "nativeRotateBy", "(JDDDDD)V", reinterpret_cast<void*>(&nativeRotateBy) },
{ "nativeSetBearing", "(JDD)V", reinterpret_cast<void*>(static_cast<void JNICALL(*)(JNIEnv*,jobject,jlong,jdouble,jdouble)>(&nativeSetBearing)) },
{ "nativeSetBearing", "(JDDD)V", reinterpret_cast<void*>(static_cast<void JNICALL(*)(JNIEnv*,jobject,jlong,jdouble,jdouble,jdouble)>(&nativeSetBearing)) },
{ "nativeGetBearing", "(J)D", reinterpret_cast<void*>(&nativeGetBearing) },
{ "nativeResetNorth", "(J)V", reinterpret_cast<void*>(&nativeResetNorth) },
{ "nativeStartRotating", "(J)V", reinterpret_cast<void*>(&nativeStartRotating) },
{ "nativeStopRotating", "(J)V", reinterpret_cast<void*>(&nativeStopRotating) },
{ "nativeCanRotate", "(J)Z", reinterpret_cast<void*>(&nativeCanRotate) },
{ "nativeSetDebug", "(JZ)V", reinterpret_cast<void*>(&nativeSetDebug) },
{ "nativeToggleDebug", "(J)V", reinterpret_cast<void*>(&nativeToggleDebug) },
{ "nativeGetDebug", "(J)Z", reinterpret_cast<void*>(&nativeGetDebug) }
}};
if (env->RegisterNatives(native_map_view_class, methods.data(), methods.size()) < 0) {
env->ExceptionDescribe();
return JNI_ERR;
}
lon_lat_class = reinterpret_cast<jclass>(env->NewGlobalRef(lon_lat_class));
if (lon_lat_class == nullptr) {
env->ExceptionDescribe();
return JNI_ERR;
}
lon_lat_zoom_class = reinterpret_cast<jclass>(env->NewGlobalRef(lon_lat_zoom_class));
if (lon_lat_zoom_class == nullptr) {
env->ExceptionDescribe();
env->DeleteGlobalRef(lon_lat_class);
return JNI_ERR;
}
runtime_exception_class = reinterpret_cast<jclass>(env->NewGlobalRef(runtime_exception_class));
if (runtime_exception_class == nullptr) {
env->ExceptionDescribe();
env->DeleteGlobalRef(lon_lat_class);
env->DeleteGlobalRef(lon_lat_zoom_class);
return JNI_ERR;
}
tree_set_class = reinterpret_cast<jclass>(env->NewGlobalRef(tree_set_class));
if (tree_set_class == nullptr) {
env->ExceptionDescribe();
env->DeleteGlobalRef(lon_lat_class);
env->DeleteGlobalRef(lon_lat_zoom_class);
env->DeleteGlobalRef(runtime_exception_class);
return JNI_ERR;
}
return JNI_VERSION_1_6;
}
extern "C" JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) {
VERBOSE("JNI_OnUnload");
JNIEnv* env = nullptr;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
ERROR("GetEnv() failed");
return;
}
env->DeleteGlobalRef(lon_lat_class);
lon_lat_class = nullptr;
lon_lat_constructor_id = nullptr;
lon_lat_lon_id = nullptr;
lon_lat_lat_id = nullptr;
env->DeleteGlobalRef(lon_lat_zoom_class);
lon_lat_zoom_class = nullptr;
lon_lat_zoom_constructor_id = nullptr;
lon_lat_zoom_lon_id = nullptr;
lon_lat_zoom_lat_id = nullptr;
lon_lat_zoom_zoom_id = nullptr;
on_map_changed_id = nullptr;
env->DeleteGlobalRef(runtime_exception_class);
runtime_exception_class = nullptr;
set_to_array_id = nullptr;
env->DeleteGlobalRef(tree_set_class);
tree_set_class = nullptr;
tree_set_constructor_id = nullptr;
tree_set_add_id = nullptr;
}
} // extern "C"

View File

@@ -0,0 +1,559 @@
//#include <cstdio>
#include <memory>
#include <GLES2/gl2.h>
#include <mbgl/platform/platform.hpp>
#include "log.h"
#include "NativeMapView.hpp"
namespace mbgl {
namespace android {
void log_egl_string(EGLDisplay display, EGLint name, const char* label) {
const char* str = eglQueryString(display, name);
if (str == nullptr) {
ERROR("eglQueryString(%d) returned error %d", name, eglGetError());
} else {
INFO("EGL %s: %s", label, str);
}
}
void log_gl_string(GLenum name, const char* label) {
const GLubyte* str = glGetString(name);
if (str == nullptr) {
ERROR("glGetString(%d) returned error %d", name, glGetError());
} else {
INFO("GL %s: %s", label, str);
}
}
NativeMapView::NativeMapView(JNIEnv* env, jobject obj_,
std::string default_style_json_) :
default_style_json(default_style_json_) {
VERBOSE("NativeMapView::NativeMapView");
ASSERT(env != nullptr);
ASSERT(obj_ != nullptr);
if (env->GetJavaVM(&vm) < 0) {
env->ExceptionDescribe();
return;
}
obj = env->NewGlobalRef(obj_);
if (obj == nullptr) {
env->ExceptionDescribe();
return;
}
// TODO replace all printfs in map code with android logging
//freopen("/sdcard/stdout.txt", "w", stdout); // NOTE: can't use <cstdio> till NDK fix the stdout macro bug
//freopen("/sdcard/stderr.txt", "w", stderr);
view = new MBGLView(this);
map = new mbgl::Map(*view);
// FIXME need way to load this from Java
map->setAccessToken("pk.eyJ1IjoibGpiYWRlIiwiYSI6IlJSQ0FEZ2MifQ.7mE4aOegldh3595AG9dxpQ");
// FIXME this asserts because it creates FileSource of different thread from run thread
//map->setStyleJSON(default_style_json);
map->setStyleURL("https://raw.githubusercontent.com/mapbox/mapbox-gl-styles/mb-pages/styles/bright-v6.json");
}
NativeMapView::~NativeMapView() {
VERBOSE("NativeMapView::~NativeMapView");
terminateContext();
delete map;
map = nullptr;
delete view;
view = nullptr;
ASSERT(vm != nullptr);
ASSERT(obj != nullptr);
jint ret;
JNIEnv* env = nullptr;
if ((ret = vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6)) == JNI_OK) {
env->DeleteGlobalRef(obj);
} else {
ERROR("GetEnv() failed with %i", ret);
}
obj = nullptr;
vm = nullptr;
}
bool NativeMapView::initializeDisplay() {
VERBOSE("NativeMapView::initializeDisplay");
ASSERT(display == EGL_NO_DISPLAY);
ASSERT(config == nullptr);
ASSERT(format < 0);
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (display == EGL_NO_DISPLAY) {
ERROR("eglGetDisplay() returned error %d", eglGetError());
terminateDisplay();
return false;
}
EGLint major, minor;
if (!eglInitialize(display, &major, &minor)) {
ERROR("eglInitialize() returned error %d", eglGetError());
terminateDisplay();
return false;
}
if ((major <= 1) && (minor < 3)) {
ERROR("EGL version is too low, need 1.3, got %d.%d", major, minor);
terminateDisplay();
return false;
}
log_egl_string(display, EGL_VENDOR, "Vendor");
log_egl_string(display, EGL_VERSION, "Version");
log_egl_string(display, EGL_CLIENT_APIS, "Client APIs");
log_egl_string(display, EGL_EXTENSIONS, "Client Extensions");
// TODO should try 565, then 8888?
bool use565 = true;
const EGLint config_attribs[] = {
EGL_CONFIG_CAVEAT, EGL_NONE,
EGL_CONFORMANT, EGL_OPENGL_ES2_BIT,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER,
EGL_BUFFER_SIZE, use565 ? 16 : 32, // Ensure we get 32bit color buffer on Tegra, 24 bit will be sorted first without it (slow software mode)
EGL_RED_SIZE, use565 ? 5 : 8,
EGL_GREEN_SIZE, use565 ? 6 : 8,
EGL_BLUE_SIZE, use565 ? 5 : 8,
EGL_DEPTH_SIZE, 16,
EGL_STENCIL_SIZE, 8,
EGL_NONE
};
EGLint num_configs;
if (!eglChooseConfig(display, config_attribs, nullptr, 0, &num_configs)) {
ERROR("eglChooseConfig(NULL) returned error %d", eglGetError());
terminateDisplay();
return false;
}
if (num_configs < 1) {
ERROR("eglChooseConfig() returned no configs");
terminateDisplay();
return false;
}
// TODO make_unique missing in Android NDK?
// const std::unique_ptr<EGLConfig[]> configs = std::make_unique(new EGLConfig[num_configs]);
const std::unique_ptr<EGLConfig[]> configs(new EGLConfig[num_configs]);
if (!eglChooseConfig(display, config_attribs, configs.get(), num_configs,
&num_configs)) {
ERROR("eglChooseConfig() returned error %d", eglGetError());
terminateDisplay();
return false;
}
config = chooseConfig(configs.get(), num_configs, use565);
if (config == nullptr) {
ERROR("No config chosen");
terminateDisplay();
return false;
}
if (!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format)) {
ERROR("eglGetConfigAttrib() returned error %d", eglGetError());
terminateDisplay();
return false;
}
DEBUG("Chosen window format is %d", format);
return true;
}
void NativeMapView::terminateDisplay() {
VERBOSE("NativeMapView::terminateDisplay");
if (display != EGL_NO_DISPLAY) {
if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE,
EGL_NO_CONTEXT)) {
ERROR("eglMakeCurrent(EGL_NO_CONTEXT) returned error %d",
eglGetError());
}
if (!eglTerminate(display)) {
ERROR("eglTerminate() returned error %d", eglGetError());
}
}
display = EGL_NO_DISPLAY;
config = nullptr;
format = -1;
}
bool NativeMapView::initializeContext() {
VERBOSE("NativeMapView::initializeContext");
ASSERT(display != EGL_NO_DISPLAY);
ASSERT(context == EGL_NO_CONTEXT);
ASSERT(config != nullptr);
const EGLint context_attribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
context = eglCreateContext(display, config, EGL_NO_CONTEXT,
context_attribs);
if (context == EGL_NO_CONTEXT) {
ERROR("eglCreateContext() returned error %d", eglGetError());
terminateContext();
return false;
}
INFO("Context initialized");
return true;
}
void NativeMapView::terminateContext() {
VERBOSE("NativeMapView::terminateContext");
map->terminate();
// TODO: there is a bug when you double tap home to go app switcher, as map is black if you immediately switch to the map again
// TODO: this is in the onPause/onResume path
// TODO: the bug causes an GL_INVALID_VALUE with glDelteProgram (I think due to context being deleted first)
// TODO: we need to free resources before we terminate
// TODO: but cause terminate and stop is async they try to do stuff with no context and crash!
if (display != EGL_NO_DISPLAY) {
if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE,
EGL_NO_CONTEXT)) {
ERROR("eglMakeCurrent(EGL_NO_CONTEXT) returned error %d",
eglGetError());
}
if (context != EGL_NO_CONTEXT) {
if (!eglDestroyContext(display, context)) {
ERROR("eglDestroyContext() returned error %d", eglGetError());
}
}
}
context = EGL_NO_CONTEXT;
}
bool NativeMapView::createSurface(ANativeWindow* window_) {
VERBOSE("NativeMapView::createSurface");
ASSERT(window == nullptr);
ASSERT(window_ != nullptr);
window = window_;
ASSERT(display != EGL_NO_DISPLAY);
ASSERT(surface == EGL_NO_SURFACE);
ASSERT(config != nullptr);
ASSERT(format >= 0);
ANativeWindow_setBuffersGeometry(window, 0, 0, format);
const EGLint surface_attribs[] = {
EGL_NONE
};
surface = eglCreateWindowSurface(display, config, window, surface_attribs);
if (surface == EGL_NO_SURFACE) {
ERROR("eglCreateWindowSurface() returned error %d", eglGetError());
destroySurface();
return false;
}
start();
return true;
}
void NativeMapView::destroySurface() {
VERBOSE("NativeMapView::destroySurface");
if (surface != EGL_NO_SURFACE) {
if (!eglDestroySurface(display, surface)) {
ERROR("eglDestroySurface() returned error %d", eglGetError());
}
}
surface = EGL_NO_SURFACE;
if (window != nullptr) {
ANativeWindow_release(window);
window = nullptr;
}
}
EGLConfig NativeMapView::chooseConfig(const EGLConfig configs[],
EGLint num_configs, bool use565) const {
INFO("Found %d configs", num_configs);
int chosen_config = -1;
for (int i = 0; i < num_configs; i++) {
INFO("Config %d:", i);
EGLint bits, red, green, blue, alpha, alpha_mask, depth, stencil,
sample_buffers, samples;
if (!eglGetConfigAttrib(display, configs[i], EGL_BUFFER_SIZE, &bits)) {
ERROR("eglGetConfigAttrib(EGL_BUFFER_SIZE) returned error %d",
eglGetError());
return nullptr;
}
if (!eglGetConfigAttrib(display, configs[i], EGL_RED_SIZE, &red)) {
ERROR("eglGetConfigAttrib(EGL_RED_SIZE) returned error %d",
eglGetError());
return nullptr;
}
if (!eglGetConfigAttrib(display, configs[i], EGL_GREEN_SIZE, &green)) {
ERROR("eglGetConfigAttrib(EGL_GREEN_SIZE) returned error %d",
eglGetError());
return nullptr;
}
if (!eglGetConfigAttrib(display, configs[i], EGL_BLUE_SIZE, &blue)) {
ERROR("eglGetConfigAttrib(EGL_BLUE_SIZE) returned error %d",
eglGetError());
return nullptr;
}
if (!eglGetConfigAttrib(display, configs[i], EGL_ALPHA_SIZE, &alpha)) {
ERROR("eglGetConfigAttrib(EGL_ALPHA_SIZE) returned error %d",
eglGetError());
return nullptr;
}
if (!eglGetConfigAttrib(display, configs[i], EGL_ALPHA_MASK_SIZE,
&alpha_mask)) {
ERROR("eglGetConfigAttrib(EGL_ALPHA_MASK_SIZE) returned error %d",
eglGetError());
return nullptr;
}
if (!eglGetConfigAttrib(display, configs[i], EGL_DEPTH_SIZE, &depth)) {
ERROR("eglGetConfigAttrib(EGL_DEPTH_SIZE) returned error %d",
eglGetError());
return nullptr;
}
if (!eglGetConfigAttrib(display, configs[i], EGL_STENCIL_SIZE,
&stencil)) {
ERROR("eglGetConfigAttrib(EGL_STENCIL_SIZE) returned error %d",
eglGetError());
return nullptr;
}
if (!eglGetConfigAttrib(display, configs[i], EGL_SAMPLE_BUFFERS,
&sample_buffers)) {
ERROR("eglGetConfigAttrib(EGL_SAMPLE_BUFFERS) returned error %d",
eglGetError());
return nullptr;
}
if (!eglGetConfigAttrib(display, configs[i], EGL_SAMPLES, &samples)) {
ERROR("eglGetConfigAttrib(EGL_SAMPLES) returned error %d",
eglGetError());
return nullptr;
}
INFO("Color: %d", bits);
INFO("Red: %d", red);
INFO("Green: %d", green);
INFO("Blue: %d", blue);
INFO("Alpha: %d", alpha);
INFO("Alpha mask: %d", alpha_mask);
INFO("Depth: %d", depth);
INFO("Stencil: %d", stencil);
INFO("Sample buffers: %d", sample_buffers);
INFO("Samples: %d", samples);
bool config_ok = true;
config_ok &= bits == (use565 ? 16 : 32);
config_ok &= red == (use565 ? 5 : 8);
config_ok &= green == (use565 ? 6 : 8);
config_ok &= blue == (use565 ? 5 : 8);
//config_ok &= (alpha == 0) || (alpha == 8); // Can be either 0 for RGBX or 8 for RGBA but we don't care either way
config_ok &= alpha == 0; // TODO should prefer no alpha over alpha, and 565 over 8888?
//config_ok &= depth == 16;
//config_ok &= stencil == 8;
//config_ok &= sample_buffers == 0;
config_ok &= samples == 0;
if (config_ok) { // Choose the last matching config, that way we get RGBX if possible (since it is sorted highest to lowest bits)
chosen_config = i;
}
}
DEBUG("Chosen config is %d", chosen_config);
if (chosen_config >= 0) {
return configs[chosen_config];
} else {
return nullptr;
}
}
void NativeMapView::start() {
VERBOSE("NativeMapView::start");
if (display == EGL_NO_DISPLAY) {
initializeDisplay();
}
if (context == EGL_NO_CONTEXT) {
initializeContext();
}
if ((display != EGL_NO_DISPLAY) && (surface != EGL_NO_SURFACE)
&& (context != EGL_NO_CONTEXT)) {
if (!eglMakeCurrent(display, surface, surface, context)) {
ERROR("eglMakeCurrent() returned error %d", eglGetError());
}
log_gl_string(GL_VENDOR, "Vendor");
log_gl_string(GL_RENDERER, "Renderer");
log_gl_string(GL_VERSION, "Version");
log_gl_string(GL_SHADING_LANGUAGE_VERSION, "SL Version");
log_gl_string(GL_EXTENSIONS, "Extensions");
if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE,
EGL_NO_CONTEXT)) {
ERROR("eglMakeCurrent(EGL_NO_CONTEXT) returned error %d",
eglGetError());
}
map->start();
} else {
DEBUG("Not starting because we are not ready");
}
}
void NativeMapView::stop() {
VERBOSE("NativeMapView::stop");
if ((display != EGL_NO_DISPLAY) && (surface != EGL_NO_SURFACE)
&& (context != EGL_NO_CONTEXT)) {
map->stop();
}
}
void NativeMapView::notifyMapChange() {
DEBUG("NativeMapView::notify_map_change()");
ASSERT(vm != nullptr);
ASSERT(obj != nullptr);
JavaVMAttachArgs args = {
JNI_VERSION_1_2,
"NativeMapView::notify_map_change()",
NULL
};
jint ret;
JNIEnv* env = nullptr;
bool detach = false;
if ((ret = vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6)) != JNI_OK) {
if (ret != JNI_EDETACHED) {
ERROR("GetEnv() failed with %i", ret);
return;
} else {
if ((ret = vm->AttachCurrentThread(&env, &args)) != JNI_OK) {
ERROR("AttachCurrentThread() failed with %i", ret);
return;
}
detach = true;
}
}
env->CallVoidMethod(obj, on_map_changed_id);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
}
if (detach) {
if ((ret = vm->DetachCurrentThread()) != JNI_OK) {
ERROR("DetachCurrentThread() failed with %i", ret);
return;
}
}
env = nullptr;
}
void MBGLView::make_active() {
VERBOSE("MBGLView::make_active");
if ((nativeView->display != EGL_NO_DISPLAY)
&& (nativeView->surface != EGL_NO_SURFACE)
&& (nativeView->context != EGL_NO_CONTEXT)) {
if (!eglMakeCurrent(nativeView->display, nativeView->surface,
nativeView->surface, nativeView->context)) {
ERROR("eglMakeCurrent() returned error %d", eglGetError());
}
// TODO still can't fix the black screen problem :-(
EGLint width, height;
if (!(eglQuerySurface(nativeView->display, nativeView->surface, EGL_WIDTH, &width)
& eglQuerySurface(nativeView->display, nativeView->surface, EGL_HEIGHT, &height))) {
ERROR("eglQuerySurface() returned error %d", eglGetError());
}
map->resize(width, height);
} else {
DEBUG("Not activating as we are not ready");
}
}
void MBGLView::make_inactive() {
VERBOSE("MBGLView::make_inactive");
// FIXME: this gets called before swap? bug?
if (!eglMakeCurrent(nativeView->display, EGL_NO_SURFACE, EGL_NO_SURFACE,
EGL_NO_CONTEXT)) {
ERROR("eglMakeCurrent(EGL_NO_CONTEXT) returned error %d",
eglGetError());
}
}
void MBGLView::swap() {
VERBOSE("MBGLView::swap");
// FIXME bug workaround
make_active();
if (map->needsSwap() && (nativeView->display != EGL_NO_DISPLAY)
&& (nativeView->surface != EGL_NO_SURFACE)) {
if (!eglSwapBuffers(nativeView->display, nativeView->surface)) {
ERROR("eglSwapBuffers() returned error %d", eglGetError());
ERROR("%u", reinterpret_cast<unsigned int>(nativeView->surface)); // TODO remove
}
map->swapped();
} else {
DEBUG("Not swapping as we are not ready");
}
// FIXME bug workaround
make_inactive();
}
void MBGLView::notify() {
DEBUG("MBGLView::notify()");
// noop
}
void MBGLView::notify_map_change(mbgl::MapChange change, mbgl::timestamp delay) {
DEBUG("MBGLView::notify_map_change()");
nativeView->notifyMapChange();
// TODO: use new variables - do i need to?
(void)change;
(void)delay;
}
} // namespace android
} // namespace mbgl

View File

@@ -0,0 +1,111 @@
#ifndef MAP_VIEW_HPP
#define MAP_VIEW_HPP
#include <string>
#include <jni.h>
#include <android/native_window.h>
#include <EGL/egl.h>
#include <mbgl/mbgl.hpp>
namespace mbgl {
namespace android {
extern jmethodID on_map_changed_id;
extern jclass lon_lat_class;
extern jmethodID lon_lat_constructor_id;
extern jfieldID lon_lat_lon_id;
extern jfieldID lon_lat_lat_id;
extern jclass lon_lat_zoom_class;
extern jmethodID lon_lat_zoom_constructor_id;
extern jfieldID lon_lat_zoom_lon_id;
extern jfieldID lon_lat_zoom_lat_id;
extern jfieldID lon_lat_zoom_zoom_id;
extern jclass runtime_exception_class;
extern jmethodID set_to_array_id;
extern jclass tree_set_class;
extern jmethodID tree_set_constructor_id;
extern jmethodID tree_set_add_id;
class MBGLView;
class NativeMapView {
friend class MBGLView;
public:
NativeMapView(JNIEnv* env, jobject obj, std::string default_style_json);
~NativeMapView();
mbgl::Map* getMap() const {
return map;
}
bool initializeDisplay();
void terminateDisplay();
bool initializeContext();
void terminateContext();
bool createSurface(ANativeWindow* window);
void destroySurface();
void start();
void stop();
void notifyMapChange();
private:
EGLConfig chooseConfig(const EGLConfig configs[], EGLint num_configs,
bool use565) const;
private:
JavaVM* vm = nullptr;
jobject obj = nullptr;
ANativeWindow* window = nullptr;
mbgl::Map* map = nullptr;
MBGLView* view = nullptr;
EGLDisplay display = EGL_NO_DISPLAY;
EGLSurface surface = EGL_NO_SURFACE;
EGLContext context = EGL_NO_CONTEXT;
EGLConfig config = nullptr;
EGLint format = -1;
std::string default_style_json;
};
class MBGLView: public mbgl::View {
public:
MBGLView(NativeMapView* nativeView_) :
nativeView(nativeView_) {
}
virtual ~MBGLView() {
}
void make_active() override;
void make_inactive() override;
void swap() override;
void notify() override;
void notify_map_change(mbgl::MapChange change, mbgl::timestamp delay = 0) override;
private:
NativeMapView* nativeView = nullptr;
};
} // namespace android
} // namespace mbgl
#endif // MAP_VIEW_HPP

18
android/cpp/log.h Normal file
View File

@@ -0,0 +1,18 @@
#ifndef LOG_H
#define LOG_H
#include <android/log.h>
#define S(x) #x
#define S_(x) S(x)
#define S__LINE__ S_(__LINE__)
#define VERBOSE(fmt, args...) __android_log_print(ANDROID_LOG_VERBOSE, __FILE__ ":" S__LINE__, fmt, ##args)
#define DEBUG(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, __FILE__ ":" S__LINE__, fmt, ##args)
#define INFO(fmt, args...) __android_log_print(ANDROID_LOG_INFO, __FILE__ ":" S__LINE__, fmt, ##args)
#define WARN(fmt, args...) __android_log_print(ANDROID_LOG_WARN, __FILE__ ":" S__LINE__, fmt, ##args)
#define ERROR(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, __FILE__ ":" S__LINE__, fmt, ##args)
#define ASSERT(cond, ...) ((cond)?(void)0:__android_log_assert(#cond, __FILE__ ":" S__LINE__, NULL))
#define ASSERTMSG(cond, fmt, args...) ((cond)?(void)0:__android_log_assert(#cond, __FILE__ ":" S__LINE__, fmt, ##args))
#endif // LOG_H

14
android/java/.gitignore vendored Normal file
View File

@@ -0,0 +1,14 @@
# Gradle files
.gradle/
# IntelliJ files
.idea
*.iml
# Build files
build/
*/build/
*.so
# Local settings
local.properties

View File

@@ -0,0 +1,23 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 21
buildToolsVersion "21.1.0"
defaultConfig {
applicationId "com.mapbox.mapboxgl.app"
minSdkVersion 19
targetSdkVersion 21
}
buildTypes {
release {
runProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
}
dependencies {
compile project(':lib')
}

View File

@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<lint>
</lint>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mapbox.mapboxgl.app"
android:versionCode="1"
android:versionName="1.0" >
<uses-feature android:glEsVersion="0x00020000" />
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="false"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.mapbox.mapboxgl.app.MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|smallestScreenSize">
</activity>
<activity
android:name="com.mapbox.mapboxgl.app.FragmentActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|smallestScreenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,29 @@
package com.mapbox.mapboxgl.app;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
public class FragmentActivity extends Activity {
//
// Static members
//
// Tag used for logging
private static final String TAG = "FragmentActivity";
//
// Lifecycle events
//
// Called when activity is created
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v(TAG, "onCreate");
// Load the layout
setContentView(R.layout.activity_fragment);
}
}

View File

@@ -0,0 +1,98 @@
package com.mapbox.mapboxgl.app;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import com.mapbox.mapboxgl.lib.MapView;
public class MainActivity extends Activity {
//
// Static members
//
// Tag used for logging
private static final String TAG = "MainActivity";
// The map
private MapView mMapView;
//
// Lifecycle events
//
// Called when the activity is created
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v(TAG, "onCreate");
// Load the layout
setContentView(R.layout.activity_main);
mMapView = (MapView) findViewById(R.id.map);
// Need to pass on any saved state to the map
mMapView.onCreate(savedInstanceState);
}
// Called when the activity is destroyed
@Override
protected void onDestroy() {
super.onDestroy();
Log.v(TAG, "onDestroy");
// Need to pass on to view
mMapView.onDestroy();
}
// Called when the activity is visible
@Override
protected void onStart() {
super.onStart();
Log.v(TAG, "onStart");
// Need to pass on to view
mMapView.onStart();
}
// Called when the activity is invisible
@Override
protected void onStop() {
super.onStop();
Log.v(TAG, "onStop");
// Need to pass on to view
mMapView.onStop();
}
// Called when the activity is in the background
@Override
protected void onPause() {
super.onPause();
Log.v(TAG, "onPause");
// Need to pass on to view
mMapView.onPause();
}
// Called when the activity is no longer in the background
@Override
protected void onResume() {
super.onResume();
Log.v(TAG, "onResume");
// Need to pass on to view
mMapView.onResume();
}
// Called before activity is destroyed
@Override
protected void onSaveInstanceState(Bundle outState) {
Log.v(TAG, "onSaveInstanceState");
// Need to retrieve any saved state from the map
mMapView.onSaveInstanceState(outState);
super.onSaveInstanceState(outState);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -0,0 +1,11 @@
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context="${packageName}.${activityClass}" >
<fragment
android:layout_width="fill_parent"
android:layout_height="fill_parent"
class="com.mapbox.mapboxgl.lib.MapFragment"
android:id="@+id/map_fragment" />
</merge>

View File

@@ -0,0 +1,11 @@
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context="${packageName}.${activityClass}" >
<view
android:layout_width="fill_parent"
android:layout_height="fill_parent"
class="com.mapbox.mapboxgl.lib.MapView"
android:id="@+id/map" />
</merge>

View File

@@ -0,0 +1,11 @@
<resources>
<!--
Base application theme for API 11+. This theme completely replaces
AppBaseTheme from res/values/styles.xml on API 11+ devices.
-->
<style name="AppBaseTheme" parent="android:Theme.Holo.Light">
<!-- API 11 theme customizations can go here. -->
</style>
</resources>

View File

@@ -0,0 +1,12 @@
<resources>
<!--
Base application theme for API 14+. This theme completely replaces
AppBaseTheme from BOTH res/values/styles.xml and
res/values-v11/styles.xml on API 14+ devices.
-->
<style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
<!-- API 14 theme customizations can go here. -->
</style>
</resources>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Mapbox GL</string>
</resources>

View File

@@ -0,0 +1,20 @@
<resources>
<!--
Base application theme, dependent on API level. This theme is replaced
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
-->
<style name="AppBaseTheme" parent="android:Theme.Light">
<!--
Theme customizations available in newer API levels can go in
res/values-vXX/styles.xml, while customizations related to
backward-compatibility can go here.
-->
</style>
<!-- Application theme. -->
<style name="AppTheme" parent="AppBaseTheme">
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
</style>
</resources>

15
android/java/build.gradle Normal file
View File

@@ -0,0 +1,15 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.13.2'
}
}
allprojects {
repositories {
jcenter()
}
}

Binary file not shown.

View File

@@ -0,0 +1,6 @@
#Wed Apr 10 15:27:10 PDT 2013
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.1-all.zip

164
android/java/gradlew vendored Executable file
View File

@@ -0,0 +1,164 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

90
android/java/gradlew.bat vendored Normal file
View File

@@ -0,0 +1,90 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@@ -0,0 +1,31 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 21
buildToolsVersion "21.1.0"
defaultConfig {
applicationId "com.mapbox.mapboxgl.lib"
minSdkVersion 19
targetSdkVersion 21
ndk {
moduleName "NativeMapView"
}
}
buildTypes {
debug {
jniDebugBuild true
}
release {
runProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
}
dependencies {
compile "commons-io:commons-io:2.4"
}

View File

@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<lint>
</lint>

View File

@@ -0,0 +1,12 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mapbox.mapboxgl.lib"
android:versionCode="1"
android:versionName="1.0" >
<uses-feature android:glEsVersion="0x00020000" />
<!-- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> -->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View File

@@ -0,0 +1,160 @@
package com.almeros.android.multitouch.gesturedetectors;
import android.content.Context;
import android.view.MotionEvent;
/**
* @author Almer Thie (code.almeros.com) Copyright (c) 2013, Almer Thie
* (code.almeros.com)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
public abstract class BaseGestureDetector {
protected final Context mContext;
protected boolean mGestureInProgress;
protected MotionEvent mPrevEvent;
protected MotionEvent mCurrEvent;
protected float mCurrPressure;
protected float mPrevPressure;
protected long mTimeDelta;
/**
* This value is the threshold ratio between the previous combined pressure
* and the current combined pressure. When pressure decreases rapidly
* between events the position values can often be imprecise, as it usually
* indicates that the user is in the process of lifting a pointer off of the
* device. This value was tuned experimentally.
*/
protected static final float PRESSURE_THRESHOLD = 0.67f;
public BaseGestureDetector(Context context) {
mContext = context;
}
/**
* All gesture detectors need to be called through this method to be able to
* detect gestures. This method delegates work to handler methods
* (handleStartProgressEvent, handleInProgressEvent) implemented in
* extending classes.
*
* @param event
* @return
*/
public boolean onTouchEvent(MotionEvent event) {
final int actionCode = event.getAction() & MotionEvent.ACTION_MASK;
if (!mGestureInProgress) {
handleStartProgressEvent(actionCode, event);
} else {
handleInProgressEvent(actionCode, event);
}
return true;
}
/**
* Called when the current event occurred when NO gesture is in progress
* yet. The handling in this implementation may set the gesture in progress
* (via mGestureInProgress) or out of progress
*
* @param actionCode
* @param event
*/
protected abstract void handleStartProgressEvent(int actionCode,
MotionEvent event);
/**
* Called when the current event occurred when a gesture IS in progress. The
* handling in this implementation may set the gesture out of progress (via
* mGestureInProgress).
*
* @param action
* @param event
*/
protected abstract void handleInProgressEvent(int actionCode,
MotionEvent event);
protected void updateStateByEvent(MotionEvent curr) {
final MotionEvent prev = mPrevEvent;
// Reset mCurrEvent
if (mCurrEvent != null) {
mCurrEvent.recycle();
mCurrEvent = null;
}
mCurrEvent = MotionEvent.obtain(curr);
// Delta time
mTimeDelta = curr.getEventTime() - prev.getEventTime();
// Pressure
mCurrPressure = curr.getPressure(curr.getActionIndex());
mPrevPressure = prev.getPressure(prev.getActionIndex());
}
protected void resetState() {
if (mPrevEvent != null) {
mPrevEvent.recycle();
mPrevEvent = null;
}
if (mCurrEvent != null) {
mCurrEvent.recycle();
mCurrEvent = null;
}
mGestureInProgress = false;
}
/**
* Returns {@code true} if a gesture is currently in progress.
*
* @return {@code true} if a gesture is currently in progress, {@code false}
* otherwise.
*/
public boolean isInProgress() {
return mGestureInProgress;
}
/**
* Return the time difference in milliseconds between the previous accepted
* GestureDetector event and the current GestureDetector event.
*
* @return Time difference since the last move event in milliseconds.
*/
public long getTimeDelta() {
return mTimeDelta;
}
/**
* Return the event time of the current GestureDetector event being
* processed.
*
* @return Current GestureDetector event time in milliseconds.
*/
public long getEventTime() {
return mCurrEvent.getEventTime();
}
}

View File

@@ -0,0 +1,188 @@
package com.almeros.android.multitouch.gesturedetectors;
import android.content.Context;
import android.graphics.PointF;
import android.view.MotionEvent;
/**
* @author Almer Thie (code.almeros.com) Copyright (c) 2013, Almer Thie
* (code.almeros.com)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
public class MoveGestureDetector extends BaseGestureDetector {
/**
* Listener which must be implemented which is used by MoveGestureDetector
* to perform callbacks to any implementing class which is registered to a
* MoveGestureDetector via the constructor.
*
* @see MoveGestureDetector.SimpleOnMoveGestureListener
*/
public interface OnMoveGestureListener {
public boolean onMove(MoveGestureDetector detector);
public boolean onMoveBegin(MoveGestureDetector detector);
public void onMoveEnd(MoveGestureDetector detector);
}
/**
* Helper class which may be extended and where the methods may be
* implemented. This way it is not necessary to implement all methods of
* OnMoveGestureListener.
*/
public static class SimpleOnMoveGestureListener implements
OnMoveGestureListener {
public boolean onMove(MoveGestureDetector detector) {
return false;
}
public boolean onMoveBegin(MoveGestureDetector detector) {
return true;
}
public void onMoveEnd(MoveGestureDetector detector) {
// Do nothing, overridden implementation may be used
}
}
private static final PointF FOCUS_DELTA_ZERO = new PointF();
private final OnMoveGestureListener mListener;
private PointF mCurrFocusInternal;
private PointF mPrevFocusInternal;
private PointF mFocusExternal = new PointF();
private PointF mFocusDeltaExternal = new PointF();
public MoveGestureDetector(Context context, OnMoveGestureListener listener) {
super(context);
mListener = listener;
}
@Override
protected void handleStartProgressEvent(int actionCode, MotionEvent event) {
switch (actionCode) {
case MotionEvent.ACTION_DOWN:
resetState(); // In case we missed an UP/CANCEL event
mPrevEvent = MotionEvent.obtain(event);
mTimeDelta = 0;
updateStateByEvent(event);
break;
case MotionEvent.ACTION_MOVE:
mGestureInProgress = mListener.onMoveBegin(this);
break;
}
}
@Override
protected void handleInProgressEvent(int actionCode, MotionEvent event) {
switch (actionCode) {
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mListener.onMoveEnd(this);
resetState();
break;
case MotionEvent.ACTION_MOVE:
updateStateByEvent(event);
// Only accept the event if our relative pressure is within
// a certain limit. This can help filter shaky data as a
// finger is lifted.
if (mCurrPressure / mPrevPressure > PRESSURE_THRESHOLD) {
final boolean updatePrevious = mListener.onMove(this);
if (updatePrevious) {
mPrevEvent.recycle();
mPrevEvent = MotionEvent.obtain(event);
}
}
break;
}
}
protected void updateStateByEvent(MotionEvent curr) {
super.updateStateByEvent(curr);
final MotionEvent prev = mPrevEvent;
// Focus intenal
mCurrFocusInternal = determineFocalPoint(curr);
mPrevFocusInternal = determineFocalPoint(prev);
// Focus external
// - Prevent skipping of focus delta when a finger is added or removed
boolean mSkipNextMoveEvent = prev.getPointerCount() != curr
.getPointerCount();
mFocusDeltaExternal = mSkipNextMoveEvent ? FOCUS_DELTA_ZERO
: new PointF(mCurrFocusInternal.x - mPrevFocusInternal.x,
mCurrFocusInternal.y - mPrevFocusInternal.y);
// - Don't directly use mFocusInternal (or skipping will occur). Add
// unskipped delta values to mFocusExternal instead.
mFocusExternal.x += mFocusDeltaExternal.x;
mFocusExternal.y += mFocusDeltaExternal.y;
}
/**
* Determine (multi)finger focal point (a.k.a. center point between all
* fingers)
*
* @param MotionEvent
* e
* @return PointF focal point
*/
private PointF determineFocalPoint(MotionEvent e) {
// Number of fingers on screen
final int pCount = e.getPointerCount();
float x = 0.0f;
float y = 0.0f;
for (int i = 0; i < pCount; i++) {
x += e.getX(i);
y += e.getY(i);
}
return new PointF(x / pCount, y / pCount);
}
public float getFocusX() {
return mFocusExternal.x;
}
public float getFocusY() {
return mFocusExternal.y;
}
public PointF getFocusDelta() {
return mFocusDeltaExternal;
}
}

View File

@@ -0,0 +1,180 @@
package com.almeros.android.multitouch.gesturedetectors;
import android.content.Context;
import android.view.MotionEvent;
/**
* @author Almer Thie (code.almeros.com) Copyright (c) 2013, Almer Thie
* (code.almeros.com)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
public class RotateGestureDetector extends TwoFingerGestureDetector {
/**
* Listener which must be implemented which is used by RotateGestureDetector
* to perform callbacks to any implementing class which is registered to a
* RotateGestureDetector via the constructor.
*
* @see RotateGestureDetector.SimpleOnRotateGestureListener
*/
public interface OnRotateGestureListener {
public boolean onRotate(RotateGestureDetector detector);
public boolean onRotateBegin(RotateGestureDetector detector);
public void onRotateEnd(RotateGestureDetector detector);
}
/**
* Helper class which may be extended and where the methods may be
* implemented. This way it is not necessary to implement all methods of
* OnRotateGestureListener.
*/
public static class SimpleOnRotateGestureListener implements
OnRotateGestureListener {
public boolean onRotate(RotateGestureDetector detector) {
return false;
}
public boolean onRotateBegin(RotateGestureDetector detector) {
return true;
}
public void onRotateEnd(RotateGestureDetector detector) {
// Do nothing, overridden implementation may be used
}
}
private final OnRotateGestureListener mListener;
private boolean mSloppyGesture;
public RotateGestureDetector(Context context,
OnRotateGestureListener listener) {
super(context);
mListener = listener;
}
@Override
protected void handleStartProgressEvent(int actionCode, MotionEvent event) {
switch (actionCode) {
case MotionEvent.ACTION_POINTER_DOWN:
// At least the second finger is on screen now
resetState(); // In case we missed an UP/CANCEL event
mPrevEvent = MotionEvent.obtain(event);
mTimeDelta = 0;
updateStateByEvent(event);
// See if we have a sloppy gesture
mSloppyGesture = isSloppyGesture(event);
if (!mSloppyGesture) {
// No, start gesture now
mGestureInProgress = mListener.onRotateBegin(this);
}
break;
case MotionEvent.ACTION_MOVE:
if (!mSloppyGesture) {
break;
}
// See if we still have a sloppy gesture
mSloppyGesture = isSloppyGesture(event);
if (!mSloppyGesture) {
// No, start normal gesture now
mGestureInProgress = mListener.onRotateBegin(this);
}
break;
case MotionEvent.ACTION_POINTER_UP:
if (!mSloppyGesture) {
break;
}
break;
}
}
@Override
protected void handleInProgressEvent(int actionCode, MotionEvent event) {
switch (actionCode) {
case MotionEvent.ACTION_POINTER_UP:
// Gesture ended but
updateStateByEvent(event);
if (!mSloppyGesture) {
mListener.onRotateEnd(this);
}
resetState();
break;
case MotionEvent.ACTION_CANCEL:
if (!mSloppyGesture) {
mListener.onRotateEnd(this);
}
resetState();
break;
case MotionEvent.ACTION_MOVE:
updateStateByEvent(event);
// Only accept the event if our relative pressure is within
// a certain limit. This can help filter shaky data as a
// finger is lifted.
if (mCurrPressure / mPrevPressure > PRESSURE_THRESHOLD) {
final boolean updatePrevious = mListener.onRotate(this);
if (updatePrevious) {
mPrevEvent.recycle();
mPrevEvent = MotionEvent.obtain(event);
}
}
break;
}
}
@Override
protected void resetState() {
super.resetState();
mSloppyGesture = false;
}
/**
* Return the rotation difference from the previous rotate event to the
* current event.
*
* @return The current rotation //difference in degrees.
*/
public float getRotationDegreesDelta() {
double diffRadians = Math.atan2(mPrevFingerDiffY, mPrevFingerDiffX)
- Math.atan2(mCurrFingerDiffY, mCurrFingerDiffX);
return (float) (diffRadians * 180.0 / Math.PI);
}
}

View File

@@ -0,0 +1,213 @@
package com.almeros.android.multitouch.gesturedetectors;
import android.content.Context;
import android.view.MotionEvent;
/**
* @author Robert Nordan (robert.nordan@norkart.no)
*
* Copyright (c) 2013, Norkart AS
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
public class ShoveGestureDetector extends TwoFingerGestureDetector {
/**
* Listener which must be implemented which is used by ShoveGestureDetector
* to perform callbacks to any implementing class which is registered to a
* ShoveGestureDetector via the constructor.
*
* @see ShoveGestureDetector.SimpleOnShoveGestureListener
*/
public interface OnShoveGestureListener {
public boolean onShove(ShoveGestureDetector detector);
public boolean onShoveBegin(ShoveGestureDetector detector);
public void onShoveEnd(ShoveGestureDetector detector);
}
/**
* Helper class which may be extended and where the methods may be
* implemented. This way it is not necessary to implement all methods of
* OnShoveGestureListener.
*/
public static class SimpleOnShoveGestureListener implements
OnShoveGestureListener {
public boolean onShove(ShoveGestureDetector detector) {
return false;
}
public boolean onShoveBegin(ShoveGestureDetector detector) {
return true;
}
public void onShoveEnd(ShoveGestureDetector detector) {
// Do nothing, overridden implementation may be used
}
}
private float mPrevAverageY;
private float mCurrAverageY;
private final OnShoveGestureListener mListener;
private boolean mSloppyGesture;
public ShoveGestureDetector(Context context, OnShoveGestureListener listener) {
super(context);
mListener = listener;
}
@Override
protected void handleStartProgressEvent(int actionCode, MotionEvent event) {
switch (actionCode) {
case MotionEvent.ACTION_POINTER_DOWN:
// At least the second finger is on screen now
resetState(); // In case we missed an UP/CANCEL event
mPrevEvent = MotionEvent.obtain(event);
mTimeDelta = 0;
updateStateByEvent(event);
// See if we have a sloppy gesture
mSloppyGesture = isSloppyGesture(event);
if (!mSloppyGesture) {
// No, start gesture now
mGestureInProgress = mListener.onShoveBegin(this);
}
break;
case MotionEvent.ACTION_MOVE:
if (!mSloppyGesture) {
break;
}
// See if we still have a sloppy gesture
mSloppyGesture = isSloppyGesture(event);
if (!mSloppyGesture) {
// No, start normal gesture now
mGestureInProgress = mListener.onShoveBegin(this);
}
break;
case MotionEvent.ACTION_POINTER_UP:
if (!mSloppyGesture) {
break;
}
break;
}
}
@Override
protected void handleInProgressEvent(int actionCode, MotionEvent event) {
switch (actionCode) {
case MotionEvent.ACTION_POINTER_UP:
// Gesture ended but
updateStateByEvent(event);
if (!mSloppyGesture) {
mListener.onShoveEnd(this);
}
resetState();
break;
case MotionEvent.ACTION_CANCEL:
if (!mSloppyGesture) {
mListener.onShoveEnd(this);
}
resetState();
break;
case MotionEvent.ACTION_MOVE:
updateStateByEvent(event);
// Only accept the event if our relative pressure is within
// a certain limit. This can help filter shaky data as a
// finger is lifted. Also check that shove is meaningful.
if (mCurrPressure / mPrevPressure > PRESSURE_THRESHOLD
&& Math.abs(getShovePixelsDelta()) > 0.5f) {
final boolean updatePrevious = mListener.onShove(this);
if (updatePrevious) {
mPrevEvent.recycle();
mPrevEvent = MotionEvent.obtain(event);
}
}
break;
}
}
@Override
protected void resetState() {
super.resetState();
mSloppyGesture = false;
mPrevAverageY = 0.0f;
mCurrAverageY = 0.0f;
}
@Override
protected void updateStateByEvent(MotionEvent curr) {
super.updateStateByEvent(curr);
final MotionEvent prev = mPrevEvent;
float py0 = prev.getY(0);
float py1 = prev.getY(1);
mPrevAverageY = (py0 + py1) / 2.0f;
float cy0 = curr.getY(0);
float cy1 = curr.getY(1);
mCurrAverageY = (cy0 + cy1) / 2.0f;
}
@Override
protected boolean isSloppyGesture(MotionEvent event) {
boolean sloppy = super.isSloppyGesture(event);
if (sloppy)
return true;
// If it's not traditionally sloppy, we check if the angle between
// fingers
// is acceptable.
double angle = Math.abs(Math.atan2(mCurrFingerDiffY, mCurrFingerDiffX));
// about 20 degrees, left or right
return !((0.0f < angle && angle < 0.35f) || 2.79f < angle
&& angle < Math.PI);
}
/**
* Return the distance in pixels from the previous shove event to the
* current event.
*
* @return The current distance in pixels.
*/
public float getShovePixelsDelta() {
return mCurrAverageY - mPrevAverageY;
}
}

View File

@@ -0,0 +1,228 @@
package com.almeros.android.multitouch.gesturedetectors;
import android.content.Context;
import android.graphics.PointF;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
/**
* @author Almer Thie (code.almeros.com) Copyright (c) 2013, Almer Thie
* (code.almeros.com)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
public abstract class TwoFingerGestureDetector extends BaseGestureDetector {
private final float mEdgeSlop;
private float mRightSlopEdge;
private float mBottomSlopEdge;
protected float mPrevFingerDiffX;
protected float mPrevFingerDiffY;
protected float mCurrFingerDiffX;
protected float mCurrFingerDiffY;
private float mCurrLen;
private float mPrevLen;
private PointF mFocus;
public TwoFingerGestureDetector(Context context) {
super(context);
ViewConfiguration config = ViewConfiguration.get(context);
mEdgeSlop = config.getScaledEdgeSlop();
}
@Override
protected abstract void handleStartProgressEvent(int actionCode,
MotionEvent event);
@Override
protected abstract void handleInProgressEvent(int actionCode,
MotionEvent event);
protected void updateStateByEvent(MotionEvent curr) {
super.updateStateByEvent(curr);
final MotionEvent prev = mPrevEvent;
mCurrLen = -1;
mPrevLen = -1;
// Previous
final float px0 = prev.getX(0);
final float py0 = prev.getY(0);
final float px1 = prev.getX(1);
final float py1 = prev.getY(1);
final float pvx = px1 - px0;
final float pvy = py1 - py0;
mPrevFingerDiffX = pvx;
mPrevFingerDiffY = pvy;
// Current
final float cx0 = curr.getX(0);
final float cy0 = curr.getY(0);
final float cx1 = curr.getX(1);
final float cy1 = curr.getY(1);
final float cvx = cx1 - cx0;
final float cvy = cy1 - cy0;
mCurrFingerDiffX = cvx;
mCurrFingerDiffY = cvy;
mFocus = determineFocalPoint(curr);
}
/**
* Return the current distance between the two pointers forming the gesture
* in progress.
*
* @return Distance between pointers in pixels.
*/
public float getCurrentSpan() {
if (mCurrLen == -1) {
final float cvx = mCurrFingerDiffX;
final float cvy = mCurrFingerDiffY;
mCurrLen = (float) Math.sqrt(cvx * cvx + cvy * cvy);
}
return mCurrLen;
}
/**
* Return the previous distance between the two pointers forming the gesture
* in progress.
*
* @return Previous distance between pointers in pixels.
*/
public float getPreviousSpan() {
if (mPrevLen == -1) {
final float pvx = mPrevFingerDiffX;
final float pvy = mPrevFingerDiffY;
mPrevLen = (float) Math.sqrt(pvx * pvx + pvy * pvy);
}
return mPrevLen;
}
/**
* MotionEvent has no getRawX(int) method; simulate it pending future API
* approval.
*
* @param event
* @param pointerIndex
* @return
*/
protected static float getRawX(MotionEvent event, int pointerIndex) {
float offset = event.getX() - event.getRawX();
if (pointerIndex < event.getPointerCount()) {
return event.getX(pointerIndex) + offset;
}
return 0.0f;
}
/**
* MotionEvent has no getRawY(int) method; simulate it pending future API
* approval.
*
* @param event
* @param pointerIndex
* @return
*/
protected static float getRawY(MotionEvent event, int pointerIndex) {
float offset = event.getY() - event.getRawY();
if (pointerIndex < event.getPointerCount()) {
return event.getY(pointerIndex) + offset;
}
return 0.0f;
}
/**
* Check if we have a sloppy gesture. Sloppy gestures can happen if the edge
* of the user's hand is touching the screen, for example.
*
* @param event
* @return
*/
protected boolean isSloppyGesture(MotionEvent event) {
// As orientation can change, query the metrics in touch down
DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
mRightSlopEdge = metrics.widthPixels - mEdgeSlop;
mBottomSlopEdge = metrics.heightPixels - mEdgeSlop;
final float edgeSlop = mEdgeSlop;
final float rightSlop = mRightSlopEdge;
final float bottomSlop = mBottomSlopEdge;
final float x0 = event.getRawX();
final float y0 = event.getRawY();
final float x1 = getRawX(event, 1);
final float y1 = getRawY(event, 1);
boolean p0sloppy = x0 < edgeSlop || y0 < edgeSlop || x0 > rightSlop
|| y0 > bottomSlop;
boolean p1sloppy = x1 < edgeSlop || y1 < edgeSlop || x1 > rightSlop
|| y1 > bottomSlop;
if (p0sloppy && p1sloppy) {
return true;
} else if (p0sloppy) {
return true;
} else if (p1sloppy) {
return true;
}
return false;
}
/**
* Determine (multi)finger focal point (a.k.a. center point between all
* fingers)
*
* @param MotionEvent
* e
* @return PointF focal point
*/
public static PointF determineFocalPoint(MotionEvent e) {
// Number of fingers on screen
final int pCount = e.getPointerCount();
float x = 0.0f;
float y = 0.0f;
for (int i = 0; i < pCount; i++) {
x += e.getX(i);
y += e.getY(i);
}
return new PointF(x / pCount, y / pCount);
}
public float getFocusX() {
return mFocus.x;
}
public float getFocusY() {
return mFocus.y;
}
}

View File

@@ -0,0 +1,91 @@
package com.mapbox.mapboxgl.lib;
import android.os.Parcel;
import android.os.Parcelable;
public class LonLat implements Parcelable {
public static final Parcelable.Creator<LonLat> CREATOR = new Parcelable.Creator<LonLat>() {
public LonLat createFromParcel(Parcel in) {
return new LonLat(in);
}
public LonLat[] newArray(int size) {
return new LonLat[size];
}
};
private double lon;
private double lat;
public LonLat(double lon, double lat) {
this.lon = lon;
this.lat = lat;
}
private LonLat(Parcel in) {
lon = in.readDouble();
lat = in.readDouble();
}
public double getLon() {
return lon;
}
public void setLon(double lon) {
this.lon = lon;
}
public double getLat() {
return lat;
}
public void setLat(double lat) {
this.lat = lat;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
long temp;
temp = Double.doubleToLongBits(lat);
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(lon);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
LonLat other = (LonLat) obj;
if (Double.doubleToLongBits(lat) != Double.doubleToLongBits(other.lat))
return false;
if (Double.doubleToLongBits(lon) != Double.doubleToLongBits(other.lon))
return false;
return true;
}
@Override
public String toString() {
return "LonLat [lon=" + lon + ", lat=" + lat + "]";
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeDouble(lon);
out.writeDouble(lat);
}
}

View File

@@ -0,0 +1,124 @@
package com.mapbox.mapboxgl.lib;
import android.os.Parcel;
import android.os.Parcelable;
public class LonLatZoom implements Parcelable {
public static final Parcelable.Creator<LonLatZoom> CREATOR = new Parcelable.Creator<LonLatZoom>() {
public LonLatZoom createFromParcel(Parcel in) {
return new LonLatZoom(in);
}
public LonLatZoom[] newArray(int size) {
return new LonLatZoom[size];
}
};
private double lon;
private double lat;
private double zoom;
public LonLatZoom(double lon, double lat, double zoom) {
this.lon = lon;
this.lat = lat;
this.zoom = zoom;
}
public LonLatZoom(LonLat lonLat, double zoom) {
this.lon = lonLat.getLon();
this.lat = lonLat.getLat();
this.zoom = zoom;
}
private LonLatZoom(Parcel in) {
lon = in.readDouble();
lat = in.readDouble();
zoom = in.readDouble();
}
public double getLon() {
return lon;
}
public void setLon(double lon) {
this.lon = lon;
}
public double getLat() {
return lat;
}
public void setLat(double lat) {
this.lat = lat;
}
public double getZoom() {
return zoom;
}
public void setZoom(double zoom) {
this.zoom = zoom;
}
public LonLat getLonLat() {
return new LonLat(lon, lat);
}
public void setLonLat(LonLat lonLat) {
this.lon = lonLat.getLon();
this.lat = lonLat.getLat();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
long temp;
temp = Double.doubleToLongBits(lat);
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(lon);
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(zoom);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
LonLatZoom other = (LonLatZoom) obj;
if (Double.doubleToLongBits(lat) != Double.doubleToLongBits(other.lat))
return false;
if (Double.doubleToLongBits(lon) != Double.doubleToLongBits(other.lon))
return false;
if (Double.doubleToLongBits(zoom) != Double
.doubleToLongBits(other.zoom))
return false;
return true;
}
@Override
public String toString() {
return "LonLatZoom [lon=" + lon + ", lat=" + lat + ", zoom=" + zoom
+ "]";
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeDouble(lon);
out.writeDouble(lat);
out.writeDouble(zoom);
}
}

View File

@@ -0,0 +1,150 @@
package com.mapbox.mapboxgl.lib;
import android.app.Activity;
import android.app.Fragment;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class MapFragment extends Fragment {
//
// Static members
//
// Tag used for logging
private static final String TAG = "MapFragment";
// The map
private MapView mMapView;
// The style attrs to load into the map
AttributeSet mAttrs;
//
// Lifecycle events
//
// Called when the fragment is created
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
Log.v(TAG, "onCreateView");
// Create the map
mMapView = new MapView(getActivity());
// Load the attributes
TypedArray typedArray = getActivity().obtainStyledAttributes(mAttrs,
R.styleable.MapFragment, 0, 0);
try {
double centerLongitude = typedArray.getFloat(
R.styleable.MapFragment_centerLongitude, 0.0f);
double centerLatitude = typedArray.getFloat(
R.styleable.MapFragment_centerLatitude, 0.0f);
LonLat centerCoordinate = new LonLat(centerLongitude,
centerLatitude);
mMapView.setCenterCoordinate(centerCoordinate);
mMapView.setDirection(typedArray.getFloat(
R.styleable.MapFragment_direction, 0.0f));
mMapView.setZoomLevel(typedArray.getFloat(
R.styleable.MapFragment_zoomLevel, 0.0f));
mMapView.setZoomEnabled(typedArray.getBoolean(
R.styleable.MapFragment_zoomEnabled, true));
mMapView.setScrollEnabled(typedArray.getBoolean(
R.styleable.MapFragment_scrollEnabled, true));
mMapView.setRotateEnabled(typedArray.getBoolean(
R.styleable.MapFragment_rotateEnabled, true));
mMapView.setDebugActive(typedArray.getBoolean(
R.styleable.MapFragment_debugActive, false));
} finally {
typedArray.recycle();
}
// Need to pass on any saved state to the map
mMapView.onCreate(savedInstanceState);
// Return the map as the root view
return mMapView;
}
// Called when the fragment is destroyed
@Override
public void onDestroyView() {
super.onDestroyView();
Log.v(TAG, "onDestroyView");
// Need to pass on to view
mMapView.onDestroy();
mMapView = null;
}
// Called to load any fragment attributes set in the activity's layout
@Override
public void onInflate(Activity activity, AttributeSet attrs,
Bundle savedInstanceState) {
super.onInflate(activity, attrs, savedInstanceState);
Log.v(TAG, "onInflate");
// TODO seems this is called before onCreateView
// Kinda strange, is it supposed to be like this?
// Need to keep a copy of these and pass on to MapView later
mAttrs = attrs;
}
// Called when the fragment is visible
@Override
public void onStart() {
super.onStart();
Log.v(TAG, "onStart");
// Need to pass on to view
mMapView.onStart();
}
// Called when the fragment is invisible
@Override
public void onStop() {
super.onStop();
Log.v(TAG, "onStop");
// Need to pass on to view
mMapView.onStop();
}
// Called when the fragment is in the background
@Override
public void onPause() {
super.onPause();
Log.v(TAG, "onPause");
// Need to pass on to view
mMapView.onPause();
}
// Called when the fragment is no longer in the background
@Override
public void onResume() {
super.onResume();
Log.v(TAG, "onResume");
// Need to pass on to view
mMapView.onResume();
}
// Called before fragment is destroyed
@Override
public void onSaveInstanceState(Bundle outState) {
Log.v(TAG, "onSaveInstanceState");
// Need to retrieve any saved state from the map
mMapView.onSaveInstanceState(outState);
super.onSaveInstanceState(outState);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,476 @@
package com.mapbox.mapboxgl.lib;
import java.util.Set;
import android.util.Log;
import android.view.Surface;
// Class that wraps the native methods for convenience
class NativeMapView {
//
// Static members
//
// Tag used for logging
private static final String TAG = "NativeMapView";
//
// Instance members
//
// Holds the pointer to JNI NativeMapView
private long mNativeMapViewPtr = 0;
// Used for callbacks
private MapView mMapView;
//
// Static methods
//
static {
System.loadLibrary("mapbox-gl");
}
//
// Constructors
//
public NativeMapView(MapView mapView, String defaultStyleJSON) {
mMapView = mapView;
// Create the NativeMapView
mNativeMapViewPtr = nativeCreate(defaultStyleJSON);
}
//
// Methods
//
public void initializeDisplay() {
nativeInitializeDisplay(mNativeMapViewPtr);
}
public void terminateDisplay() {
nativeTerminateDisplay(mNativeMapViewPtr);
}
public void initializeContext() {
nativeInitializeContext(mNativeMapViewPtr);
}
public void terminateContext() {
nativeTerminateContext(mNativeMapViewPtr);
}
public void createSurface(Surface surface) {
nativeCreateSurface(mNativeMapViewPtr, surface);
}
public void destroySurface() {
nativeDestroySurface(mNativeMapViewPtr);
}
public void start() {
nativeStart(mNativeMapViewPtr);
}
public void stop() {
nativeStop(mNativeMapViewPtr);
}
public void rerender() {
nativeRerender(mNativeMapViewPtr);
}
public void update() {
nativeUpdate(mNativeMapViewPtr);
}
public void cleanup() {
nativeCleanup(mNativeMapViewPtr);
}
public void resize(int width, int height) {
resize(width, height, 1.0f);
}
public void resize(int width, int height, float ratio) {
if (width < 0) {
throw new IllegalArgumentException("width cannot be negative.");
}
if (height < 0) {
throw new IllegalArgumentException("height cannot be negative.");
}
if (width > 65535) {
throw new IllegalArgumentException(
"width cannot be greater than 65535.");
}
if (height > 65535) {
throw new IllegalArgumentException(
"height cannot be greater than 65535.");
}
nativeResize(mNativeMapViewPtr, width, height, ratio);
}
public void resize(int width, int height, float ratio, int fbWidth,
int fbHeight) {
if (width < 0) {
throw new IllegalArgumentException("width cannot be negative.");
}
if (height < 0) {
throw new IllegalArgumentException("height cannot be negative.");
}
if (fbWidth < 0) {
throw new IllegalArgumentException("fbWidth cannot be negative.");
}
if (fbHeight < 0) {
throw new IllegalArgumentException("fbHeight cannot be negative.");
}
if (fbWidth > 65535) {
throw new IllegalArgumentException(
"fbWidth cannot be greater than 65535.");
}
if (fbHeight > 65535) {
throw new IllegalArgumentException(
"fbHeight cannot be greater than 65535.");
}
nativeResize(mNativeMapViewPtr, width, height, ratio, fbWidth, fbHeight);
}
public void setAppliedClasses(Set<String> appliedClasses) {
nativeSetAppliedClasses(mNativeMapViewPtr, appliedClasses);
}
public Set<String> getAppliedClasses() {
return nativeGetAppliedClasses(mNativeMapViewPtr);
}
public void setDefaultTransitionDuration() {
setDefaultTransitionDuration(0);
}
public void setDefaultTransitionDuration(long durationMilliseconds) {
if (durationMilliseconds < 0) {
throw new IllegalArgumentException(
"durationMilliseconds cannot be negative.");
}
nativeSetDefaultTransitionDuration(mNativeMapViewPtr,
durationMilliseconds);
}
public void setStyleJSON(String newStyleJSON) {
nativeSetStyleJSON(mNativeMapViewPtr, newStyleJSON);
}
public String getStyleJSON() {
return nativeGetStyleJSON(mNativeMapViewPtr);
}
public void cancelTransitions() {
nativeCancelTransitions(mNativeMapViewPtr);
}
public void moveBy(double dx, double dy) {
moveBy(dx, dy, 0.0);
}
public void moveBy(double dx, double dy, double duration) {
nativeMoveBy(mNativeMapViewPtr, dx, dy, duration);
}
public void setLonLat(LonLat lonLat) {
setLonLat(lonLat, 0.0);
}
public void setLonLat(LonLat lonLat, double duration) {
nativeSetLonLat(mNativeMapViewPtr, lonLat, duration);
}
public LonLat getLonLat() {
return nativeGetLonLat(mNativeMapViewPtr);
}
public void startPanning() {
nativeStartPanning(mNativeMapViewPtr);
}
public void stopPanning() {
nativeStopPanning(mNativeMapViewPtr);
}
public void resetPosition() {
nativeResetPosition(mNativeMapViewPtr);
}
public void scaleBy(double ds) {
scaleBy(ds, -1.0, -1.0);
}
public void scaleBy(double ds, double cx, double cy) {
scaleBy(ds, cx, cy, 0.0);
}
public void scaleBy(double ds, double cx, double cy, double duration) {
nativeScaleBy(mNativeMapViewPtr, ds, cx, cy, duration);
}
public void setScale(double scale) {
setScale(scale, -1.0, -1.0);
}
public void setScale(double scale, double cx, double cy) {
setScale(scale, cx, cy, 0.0);
}
public void setScale(double scale, double cx, double cy, double duration) {
nativeSetScale(mNativeMapViewPtr, scale, cx, cy, duration);
}
public double getScale() {
return nativeGetScale(mNativeMapViewPtr);
}
public void setZoom(double zoom) {
setZoom(zoom, 0.0);
}
public void setZoom(double zoom, double duration) {
nativeSetZoom(mNativeMapViewPtr, zoom, duration);
}
public double getZoom() {
return nativeGetZoom(mNativeMapViewPtr);
}
public void setLonLatZoom(LonLatZoom lonLatZoom) {
setLonLatZoom(lonLatZoom, 0.0);
}
public void setLonLatZoom(LonLatZoom lonLatZoom, double duration) {
nativeSetLonLatZoom(mNativeMapViewPtr, lonLatZoom, duration);
}
public LonLatZoom getLonLatZoom() {
return nativeGetLonLatZoom(mNativeMapViewPtr);
}
public void resetZoom() {
nativeResetZoom(mNativeMapViewPtr);
}
public void startScaling() {
nativeStartScaling(mNativeMapViewPtr);
}
public void stopScaling() {
nativeStopScaling(mNativeMapViewPtr);
}
public double getMinZoom() {
return nativeGetMinZoom(mNativeMapViewPtr);
}
public double getMaxZoom() {
return nativeGetMaxZoom(mNativeMapViewPtr);
}
public void rotateBy(double sx, double sy, double ex, double ey) {
rotateBy(sx, sy, ex, ey, 0.0);
}
public void rotateBy(double sx, double sy, double ex, double ey,
double duration) {
nativeRotateBy(mNativeMapViewPtr, sx, sy, ex, ey, duration);
}
public void setBearing(double degrees) {
setBearing(degrees, 0.0);
}
public void setBearing(double degrees, double duration) {
nativeSetBearing(mNativeMapViewPtr, degrees, duration);
}
public void setBearing(double degrees, double cx, double cy) {
nativeSetBearing(mNativeMapViewPtr, degrees, cx, cy);
}
public double getBearing() {
return nativeGetBearing(mNativeMapViewPtr);
}
public void resetNorth() {
nativeResetNorth(mNativeMapViewPtr);
}
public void startRotating() {
nativeStartRotating(mNativeMapViewPtr);
}
public void stopRotating() {
nativeStopRotating(mNativeMapViewPtr);
}
public boolean canRotate() {
return nativeCanRotate(mNativeMapViewPtr);
}
public void setDebug(boolean debug) {
nativeSetDebug(mNativeMapViewPtr, debug);
}
public void toggleDebug() {
nativeToggleDebug(mNativeMapViewPtr);
}
public boolean getDebug() {
return nativeGetDebug(mNativeMapViewPtr);
}
//
// Callbacks
//
protected void onMapChanged() {
Log.v(TAG, "onMapChanged");
mMapView.onMapChanged();
}
//
// JNI methods
//
@Override
protected void finalize() throws Throwable {
nativeDestroy(mNativeMapViewPtr);
mNativeMapViewPtr = 0;
super.finalize();
}
private native long nativeCreate(String defaultStyleJSON);
private native void nativeDestroy(long nativeMapViewPtr);
private native void nativeInitializeDisplay(long nativeMapViewPtr);
private native void nativeTerminateDisplay(long nativeMapViewPtr);
private native void nativeInitializeContext(long nativeMapViewPtr);
private native void nativeTerminateContext(long nativeMapViewPtr);
private native void nativeCreateSurface(long nativeMapViewPtr,
Surface surface);
private native void nativeDestroySurface(long nativeMapViewPtr);
private native void nativeStart(long nativeMapViewPtr);
private native void nativeStop(long nativeMapViewPtr);
private native void nativeRerender(long nativeMapViewPtr);
private native void nativeUpdate(long nativeMapViewPtr);
private native void nativeCleanup(long nativeMapViewPtr);
private native void nativeResize(long nativeMapViewPtr, int width,
int height, float ratio);
private native void nativeResize(long nativeMapViewPtr, int width,
int height, float ratio, int fbWidth, int fbHeight);
private native void nativeSetAppliedClasses(long nativeMapViewPtr,
Set<String> appliedClasses);
private native Set<String> nativeGetAppliedClasses(long nativeMapViewPtr);
private native void nativeSetDefaultTransitionDuration(
long nativeMapViewPtr, long durationMilliseconds);
private native void nativeSetStyleJSON(long nativeMapViewPtr,
String newStyleJSON);
private native String nativeGetStyleJSON(long nativeMapViewPtr);
private native void nativeCancelTransitions(long nativeMapViewPtr);
private native void nativeMoveBy(long nativeMapViewPtr, double dx,
double dy, double duration);
private native void nativeSetLonLat(long nativeMapViewPtr, LonLat lonLat,
double duration);
private native LonLat nativeGetLonLat(long nativeMapViewPtr);
private native void nativeStartPanning(long nativeMapViewPtr);
private native void nativeStopPanning(long nativeMapViewPtr);
private native void nativeResetPosition(long nativeMapViewPtr);
private native void nativeScaleBy(long nativeMapViewPtr, double ds,
double cx, double cy, double duration);
private native void nativeSetScale(long nativeMapViewPtr, double scale,
double cx, double cy, double duration);
private native double nativeGetScale(long nativeMapViewPtr);
private native void nativeSetZoom(long nativeMapViewPtr, double zoom,
double duration);
private native double nativeGetZoom(long nativeMapViewPtr);
private native void nativeSetLonLatZoom(long nativeMapViewPtr,
LonLatZoom lonLatZoom, double duration);
private native LonLatZoom nativeGetLonLatZoom(long nativeMapViewPtr);
private native void nativeResetZoom(long nativeMapViewPtr);
private native void nativeStartScaling(long nativeMapViewPtr);
private native void nativeStopScaling(long nativeMapViewPtr);
private native double nativeGetMinZoom(long nativeMapViewPtr);
private native double nativeGetMaxZoom(long nativeMapViewPtr);
private native void nativeRotateBy(long nativeMapViewPtr, double sx,
double sy, double ex, double ey, double duration);
private native void nativeSetBearing(long nativeMapViewPtr, double degrees,
double duration);
private native void nativeSetBearing(long nativeMapViewPtr, double degrees,
double cx, double cy);
private native double nativeGetBearing(long nativeMapViewPtr);
private native void nativeResetNorth(long nativeMapViewPtr);
private native void nativeStartRotating(long nativeMapViewPtr);
private native void nativeStopRotating(long nativeMapViewPtr);
private native boolean nativeCanRotate(long nativeMapViewPtr);
private native void nativeSetDebug(long nativeMapViewPtr, boolean debug);
private native void nativeToggleDebug(long nativeMapViewPtr);
private native boolean nativeGetDebug(long nativeMapViewPtr);
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,32 @@
<resources>
<attr name="centerLongitude" format="float" />
<attr name="centerLatitude" format="float" />
<attr name="zoomLevel" format="float" />
<attr name="direction" format="float" />
<attr name="zoomEnabled" format="boolean" />
<attr name="scrollEnabled" format="boolean" />
<attr name="rotateEnabled" format="boolean" />
<attr name="debugActive" format="boolean" />
<declare-styleable name="MapView">
<attr name="centerLongitude" />
<attr name="centerLatitude" />
<attr name="zoomLevel" />
<attr name="direction" />
<attr name="zoomEnabled" />
<attr name="scrollEnabled" />
<attr name="rotateEnabled" />
<attr name="debugActive" />
</declare-styleable>
<declare-styleable name="MapFragment">
<attr name="centerLongitude" />
<attr name="centerLatitude" />
<attr name="zoomLevel" />
<attr name="direction" />
<attr name="zoomEnabled" />
<attr name="scrollEnabled" />
<attr name="rotateEnabled" />
<attr name="debugActive" />
</declare-styleable>
</resources>

View File

@@ -0,0 +1,3 @@
<resources>
</resources>

View File

@@ -0,0 +1,2 @@
include ':app'
include ':lib'

50
android/mapboxgl-app.gyp Normal file
View File

@@ -0,0 +1,50 @@
{
'includes': [
'../gyp/common.gypi',
],
'targets': [
{
'target_name': 'androidapp',
'product_name': 'mapbox-gl',
'type': 'shared_library',
'sources': [
'./cpp/NativeMapView.cpp',
'./cpp/JNI.cpp',
],
'cflags_cc': [
'-I<(boost_root)/include',
],
'libraries': [
'<@(openssl_static_libs)',
'<@(curl_static_libs)',
'<@(png_static_libs)',
'<@(sqlite3_static_libs)',
'<@(uv_static_libs)',
'<@(nu_static_libs)',
],
'variables': {
'ldflags': [
'-llog -landroid -lEGL -lGLESv2 -lstdc++ -latomic '
'<@(png_ldflags)',
'<@(sqlite3_ldflags)',
'<@(openssl_ldflags)',
'<@(curl_ldflags)',
'<@(zlib_ldflags)',
],
},
'conditions': [
['OS == "mac"', {
'xcode_settings': {
'OTHER_LDFLAGS': [ '<@(ldflags)' ],
}
}, {
'libraries': [ '<@(ldflags)' ],
}]
],
'dependencies': [
'../mapboxgl.gyp:mbgl-standalone',
'../mapboxgl.gyp:mbgl-android',
],
},
],
}

10
configure vendored
View File

@@ -26,6 +26,9 @@ case ${MASON_PLATFORM} in
;;
'android')
SQLITE_VERSION=3.8.6
LIBPNG_VERSION=1.6.13
OPENSSL_VERSION=1.0.1i
LIBCURL_VERSION=7.38.0
LIBUV_VERSION=0.11.29
ZLIB_VERSION=system
BOOST_VERSION=1.57.0
@@ -75,6 +78,13 @@ if [ ! -z ${BOOST_VERSION} ]; then
CONFIG+=" 'boost_root': '$(mason prefix boost ${BOOST_VERSION})',"$LN
fi
if [ ! -z ${OPENSSL_VERSION} ]; then
mason install openssl ${OPENSSL_VERSION}
CONFIG+=" 'openssl_static_libs': $(quote_flags $(mason static_libs openssl ${OPENSSL_VERSION})),"$LN
CONFIG+=" 'openssl_cflags': $(quote_flags $(mason cflags openssl ${OPENSSL_VERSION})),"$LN
CONFIG+=" 'openssl_ldflags': $(quote_flags $(mason ldflags openssl ${OPENSSL_VERSION})),"$LN
fi
if [ ! -z ${LIBCURL_VERSION} ]; then
mason install libcurl ${LIBCURL_VERSION}
CONFIG+=" 'curl_static_libs': $(quote_flags $(mason static_libs libcurl ${LIBCURL_VERSION})),"$LN

69
gyp/mbgl-android.gypi Normal file
View File

@@ -0,0 +1,69 @@
{
'targets': [
{ 'target_name': 'mbgl-android',
'product_name': 'mbgl-android',
'type': 'static_library',
'standalone_static_library': 1,
'hard_dependency': 1,
'variables': {
'cflags_cc': [
'<@(png_cflags)',
'<@(uv_cflags)',
'<@(curl_cflags)',
'<@(nu_cflags)',
'-I<(boost_root)/include',
],
'cflags': [
'<@(uv_cflags)',
'<@(nu_cflags)',
],
'ldflags': [
'<@(png_ldflags)',
'<@(uv_ldflags)',
'<@(curl_ldflags)',
'<@(nu_ldflags)',
],
},
'sources': [
'../platform/android/cache_database_data.cpp',
'../platform/android/log_android.cpp',
'../platform/default/string_stdlib.cpp',
'../platform/default/http_request_baton_curl.cpp',
'../platform/default/image.cpp',
],
'include_dirs': [
'../include',
],
'link_settings': {
'libraries': [
'<@(png_static_libs)',
],
},
'conditions': [
['OS == "mac"', {
'xcode_settings': {
'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags_cc)' ],
'OTHER_CFLAGS': [ '<@(cflags)' ],
}
}, {
'cflags_cc': [ '<@(cflags_cc)' ],
'cflags': [ '<@(cflags)' ],
}]
],
'direct_dependent_settings': {
'include_dirs': [
'../include',
],
'conditions': [
['OS == "mac"', {
'xcode_settings': {
'OTHER_LDFLAGS': [ '<@(ldflags)' ],
}
}, {
'ldflags': [ '<@(ldflags)' ],
}]
],
},
},
],
}

View File

@@ -12,5 +12,9 @@
'includes': ['mbgl-linux.gypi'],
'variables': { 'platform_library': 'mbgl-linux' },
}],
['platform == "android"', {
'includes': ['mbgl-android.gypi'],
'variables': { 'platform_library': 'mbgl-android' },
}],
],
}

View File

@@ -0,0 +1,13 @@
#include <mbgl/platform/platform.hpp>
namespace mbgl {
namespace platform {
// Returns the path to the default cache database on this system.
std::string defaultCacheDatabase() {
// TODO need to use get cache dir from java
return "/data/data/com.mapbox.mapboxgl.app/mbgl-cache.db";
}
}
}

View File

@@ -0,0 +1,32 @@
#include <mbgl/platform/default/log_stderr.hpp>
#include <iostream>
#include <cstdarg>
namespace mbgl {
// TODO use android logging
void StderrLogBackend::record(EventSeverity severity, Event event, const std::string &msg) {
std::cerr << "[" << severity << "] " << event << ": " << msg << std::endl;
}
void StderrLogBackend::record(EventSeverity severity, Event event, const char* format, ...) {
std::cerr << "[" << severity << "] " << event << ": ";
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
std::cerr << std::endl;
}
void StderrLogBackend::record(EventSeverity severity, Event event, int64_t code) {
std::cerr << "[" << severity << "] " << event << ": (" << code << ")" << std::endl;
}
void StderrLogBackend::record(EventSeverity severity, Event event, int64_t code, const std::string &msg) {
std::cerr << "[" << severity << "] " << event << ": (" << code << ") " << msg << std::endl;
}
}

View File

@@ -266,7 +266,11 @@ void on_timeout(uv_timer_t *) {
void start_timeout(CURLM *, long timeout_ms, void *) {
if (timeout_ms <= 0) {
#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
on_timeout(&timeout, 0);
#else
on_timeout(&timeout);
#endif
} else {
uv_timer_start(&timeout, on_timeout, timeout_ms, 0);
}

View File

@@ -4,8 +4,8 @@
set -o pipefail
if [[ "${MASON_PLATFORM}" == "android" ]]; then
echo "debug: unpacking"
#mapbox_time "unpacking NDK" \
echo "debug: installing 7z"
#mapbox_time "installing 7z" \
MASON_PLATFORM= ./.mason/mason install 7z 9.20
echo "debug: setting 7z path"
@@ -18,10 +18,31 @@ if [[ "${MASON_PLATFORM}" == "android" ]]; then
echo "debug: chmod NDK"
chmod a+x ./android-ndk-r10c-linux-x86_64.bin
echo "debug: upacking NDK"
echo "debug: unpacking NDK"
#mapbox_time "unpacking NDK" \
$SEVEN_ZIP_PATH x ./android-ndk-r10c-linux-x86_64.bin > .tmp-ndk-log
rm .tmp-ndk-log
echo "debug: fetching JDK"
#mapbox_time "fetching JDK" \
wget --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/7u71-b14/jdk-7u71-linux-x64.tar.gz
echo "debug: unpacking JDK"
#mapbox_time "unpacking JDK" \
tar -xzf ./jdk-7u71-linux-x64.tar.gz
echo "debug: fetching SDK"
#mapbox_time "fetching SDK" \
wget http://dl.google.com/android/android-sdk_r23.0.2-linux.tgz
echo "debug: unpacking SDK"
#mapbox_time "unpacking SDK" \
tar -xzf ./android-sdk_r23.0.2-linux.tgz
echo "debug: installing SDK"
#mapbox_time "installing SDK" \
sudo apt-get -y install lib32stdc++6 lib32z1
echo y | ./android-sdk-linux/tools/android update sdk -u -a -t tools,platform-tools,build-tools-21.1.0,android-19,android-21
fi
if [[ ${TRAVIS_OS_NAME} == "linux" ]]; then

View File

@@ -66,7 +66,7 @@ void Painter::setup() {
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
// Set clear values
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0f);
glClearStencil(0x0);
@@ -174,7 +174,7 @@ void Painter::clear() {
glStencilMask(0xFF);
depthMask(true);
glClearColor(0, 0, 0, 0);
glClearColor(1, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}

View File

@@ -10,7 +10,7 @@ void Painter::preparePrerender(RasterBucket &bucket) {
glDisable(GL_STENCIL_TEST);
// Render the actual tile.
#if GL_EXT_discard_framebuffer
#if GL_EXT_discard_framebuffer && !__ANDROID__
const GLenum discards[] = {GL_COLOR_ATTACHMENT0};
glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, discards);
#endif

View File

@@ -117,7 +117,7 @@ void PrerenderedTexture::blur(Painter& painter, uint16_t passes) {
for (int i = 0; i < passes; i++) {
// Render horizontal
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, secondary_texture, 0);
#if GL_EXT_discard_framebuffer
#if GL_EXT_discard_framebuffer && !__ANDROID__
const GLenum discards[] = { GL_COLOR_ATTACHMENT0 };
glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, discards);
#endif
@@ -132,7 +132,7 @@ void PrerenderedTexture::blur(Painter& painter, uint16_t passes) {
// Render vertical
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, original_texture, 0);
#if GL_EXT_discard_framebuffer
#if GL_EXT_discard_framebuffer && !__ANDROID__
glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, discards);
#endif
glClear(GL_COLOR_BUFFER_BIT);