From 4daa02987b77c32265ad0aa8819419d4e21e66c0 Mon Sep 17 00:00:00 2001 From: Leith Bade Date: Mon, 16 Feb 2015 12:20:07 -0800 Subject: [PATCH 01/15] Tidy up JNI LatLng refs --- android/cpp/jni.cpp | 152 +++++++++--------- .../com/mapbox/mapboxgl/lib/LatLngZoom.java | 37 ++--- .../mapbox/mapboxgl/lib/NativeMapView.java | 22 +-- .../mapboxgl/lib/constants/MathConstants.java | 6 +- .../mapbox/mapboxgl/lib/geometry/LatLng.java | 45 +++--- include/mbgl/android/jni.hpp | 20 +-- 6 files changed, 142 insertions(+), 140 deletions(-) diff --git a/android/cpp/jni.cpp b/android/cpp/jni.cpp index b1bfefe2803..b583b835614 100644 --- a/android/cpp/jni.cpp +++ b/android/cpp/jni.cpp @@ -33,16 +33,16 @@ std::string androidRelease; jmethodID onMapChangedId = nullptr; jmethodID onFpsChangedId = nullptr; -jclass lonLatClass = nullptr; -jmethodID lonLatConstructorId = nullptr; -jfieldID lonLatLonId = nullptr; -jfieldID lonLatLatId = nullptr; +jclass latLngClass = nullptr; +jmethodID latLngConstructorId = nullptr; +jfieldID latLngLatitudeId = nullptr; +jfieldID latLngLongitudeId = nullptr; -jclass lonLatZoomClass = nullptr; -jmethodID lonLatZoomConstructorId = nullptr; -jfieldID lonLatZoomLonId = nullptr; -jfieldID lonLatZoomLatId = nullptr; -jfieldID lonLatZoomZoomId = nullptr; +jclass latLngZoomClass = nullptr; +jmethodID latLngZoomConstructorId = nullptr; +jfieldID latLngZoomLatitudeId = nullptr; +jfieldID latLngZoomLongitudeId = nullptr; +jfieldID latLngZoomZoomId = nullptr; jclass runtimeExceptionClass = nullptr; jclass nullPointerExceptionClass = nullptr; @@ -449,34 +449,34 @@ void JNICALL nativeMoveBy(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jdou nativeMapView->getMap().moveBy(dx, dy, std::chrono::milliseconds(duration)); } -void JNICALL nativeSetLonLat(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jobject lonLat, +void JNICALL nativeSetLatLng(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jobject latLng, jlong duration) { - mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetLonLat"); + mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetLatLng"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - double lon = env->GetDoubleField(lonLat, lonLatLonId); + double latitude = env->GetDoubleField(latLng, latLngLatitudeId); if (env->ExceptionCheck()) { env->ExceptionDescribe(); return; } - double lat = env->GetDoubleField(lonLat, lonLatLatId); + double longitude = env->GetDoubleField(latLng, latLngLongitudeId); if (env->ExceptionCheck()) { env->ExceptionDescribe(); return; } - nativeMapView->getMap().setLatLng(mbgl::LatLng(lat, lon), std::chrono::milliseconds(duration)); + nativeMapView->getMap().setLatLng(mbgl::LatLng(latitude, longitude), std::chrono::milliseconds(duration)); } -jobject JNICALL nativeGetLonLat(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { - mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetLonLat"); +jobject JNICALL nativeGetLatLng(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetLatLng"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); mbgl::LatLng latLng = nativeMapView->getMap().getLatLng(); - jobject ret = env->NewObject(lonLatClass, lonLatConstructorId, latLng.longitude, latLng.latitude); + jobject ret = env->NewObject(latLngClass, latLngConstructorId, latLng.latitude, latLng.longitude); if (ret == nullptr) { env->ExceptionDescribe(); return nullptr; @@ -544,41 +544,41 @@ jdouble JNICALL nativeGetZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) return nativeMapView->getMap().getZoom(); } -void JNICALL nativeSetLonLatZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, - jobject lonLatZoom, jlong duration) { - mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetLonLatZoom"); +void JNICALL nativeSetLatLngZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, + jobject latLngZoom, jlong duration) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetLatLngZoom"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - double lon = env->GetDoubleField(lonLatZoom, lonLatZoomLonId); + double latitude = env->GetDoubleField(latLngZoom, latLngZoomLatitudeId); if (env->ExceptionCheck()) { env->ExceptionDescribe(); return; } - double lat = env->GetDoubleField(lonLatZoom, lonLatZoomLatId); + double longitude = env->GetDoubleField(latLngZoom, latLngZoomLongitudeId); if (env->ExceptionCheck()) { env->ExceptionDescribe(); return; } - double zoom = env->GetDoubleField(lonLatZoom, lonLatZoomZoomId); + double zoom = env->GetDoubleField(latLngZoom, latLngZoomZoomId); if (env->ExceptionCheck()) { env->ExceptionDescribe(); return; } - nativeMapView->getMap().setLatLngZoom(mbgl::LatLng(lat, lon), zoom, std::chrono::milliseconds(duration)); + nativeMapView->getMap().setLatLngZoom(mbgl::LatLng(latitude, longitude), zoom, std::chrono::milliseconds(duration)); } -jobject JNICALL nativeGetLonLatZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { - mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetLonLatZoom"); +jobject JNICALL nativeGetLatLngZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetLatLngZoom"); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); mbgl::LatLng latLng = nativeMapView->getMap().getLatLng(); double zoom = nativeMapView->getMap().getZoom(); - jobject ret = env->NewObject(lonLatZoomClass, lonLatZoomConstructorId, latLng.longitude, latLng.latitude, zoom); + jobject ret = env->NewObject(latLngZoomClass, latLngZoomConstructorId, latLng.longitude, latLng.latitude, zoom); if (ret == nullptr) { env->ExceptionDescribe(); return nullptr; @@ -721,56 +721,56 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { return JNI_ERR; } - lonLatClass = env->FindClass("com/mapbox/mapboxgl/lib/geometry/LatLng"); - if (lonLatClass == nullptr) { + latLngClass = env->FindClass("com/mapbox/mapboxgl/lib/geometry/LatLng"); + if (latLngClass == nullptr) { env->ExceptionDescribe(); return JNI_ERR; } - lonLatConstructorId = env->GetMethodID(lonLatClass, "", "(DD)V"); - if (lonLatConstructorId == nullptr) { + latLngConstructorId = env->GetMethodID(latLngClass, "", "(DD)V"); + if (latLngConstructorId == nullptr) { env->ExceptionDescribe(); return JNI_ERR; } - lonLatLonId = env->GetFieldID(lonLatClass, "longitude", "D"); - if (lonLatLonId == nullptr) { + latLngLatitudeId = env->GetFieldID(latLngClass, "latitude", "D"); + if (latLngLatitudeId == nullptr) { env->ExceptionDescribe(); return JNI_ERR; } - lonLatLatId = env->GetFieldID(lonLatClass, "latitude", "D"); - if (lonLatLatId == nullptr) { + latLngLongitudeId = env->GetFieldID(latLngClass, "longitude", "D"); + if (latLngLongitudeId == nullptr) { env->ExceptionDescribe(); return JNI_ERR; } - lonLatZoomClass = env->FindClass("com/mapbox/mapboxgl/lib/LatLngZoom"); - if (lonLatClass == nullptr) { + latLngZoomClass = env->FindClass("com/mapbox/mapboxgl/lib/LatLngZoom"); + if (latLngZoomClass == nullptr) { env->ExceptionDescribe(); return JNI_ERR; } - lonLatZoomConstructorId = env->GetMethodID(lonLatZoomClass, "", "(DDD)V"); - if (lonLatZoomConstructorId == nullptr) { + latLngZoomConstructorId = env->GetMethodID(latLngZoomClass, "", "(DDD)V"); + if (latLngZoomConstructorId == nullptr) { env->ExceptionDescribe(); return JNI_ERR; } - lonLatZoomLonId = env->GetFieldID(lonLatZoomClass, "longitude", "D"); - if (lonLatZoomLonId == nullptr) { + latLngZoomLatitudeId = env->GetFieldID(latLngZoomClass, "latitude", "D"); + if (latLngZoomLatitudeId == nullptr) { env->ExceptionDescribe(); return JNI_ERR; } - lonLatZoomLatId = env->GetFieldID(lonLatZoomClass, "latitude", "D"); - if (lonLatZoomLatId == nullptr) { + latLngZoomLongitudeId = env->GetFieldID(latLngZoomClass, "longitude", "D"); + if (latLngZoomLongitudeId == nullptr) { env->ExceptionDescribe(); return JNI_ERR; } - lonLatZoomZoomId = env->GetFieldID(lonLatZoomClass, "zoom", "D"); - if (lonLatZoomZoomId == nullptr) { + latLngZoomZoomId = env->GetFieldID(latLngZoomClass, "zoom", "D"); + if (latLngZoomZoomId == nullptr) { env->ExceptionDescribe(); return JNI_ERR; } @@ -891,10 +891,10 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { reinterpret_cast(&nativeGetAccessToken)}, {"nativeCancelTransitions", "(J)V", reinterpret_cast(&nativeCancelTransitions)}, {"nativeMoveBy", "(JDDJ)V", reinterpret_cast(&nativeMoveBy)}, - {"nativeSetLonLat", "(JLcom/mapbox/mapboxgl/lib/geometry/LatLng;J)V", - reinterpret_cast(&nativeSetLonLat)}, - {"nativeGetLonLat", "(J)Lcom/mapbox/mapboxgl/lib/geometry/LatLng;", - reinterpret_cast(&nativeGetLonLat)}, + {"nativeSetLatLng", "(JLcom/mapbox/mapboxgl/lib/geometry/LatLng;J)V", + reinterpret_cast(&nativeSetLatLng)}, + {"nativeGetLatLng", "(J)Lcom/mapbox/mapboxgl/lib/geometry/LatLng;", + reinterpret_cast(&nativeGetLatLng)}, {"nativeStartPanning", "(J)V", reinterpret_cast(&nativeStartPanning)}, {"nativeStopPanning", "(J)V", reinterpret_cast(&nativeStopPanning)}, {"nativeResetPosition", "(J)V", reinterpret_cast(&nativeResetPosition)}, @@ -903,10 +903,10 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { {"nativeGetScale", "(J)D", reinterpret_cast(&nativeGetScale)}, {"nativeSetZoom", "(JDJ)V", reinterpret_cast(&nativeSetZoom)}, {"nativeGetZoom", "(J)D", reinterpret_cast(&nativeGetZoom)}, - {"nativeSetLonLatZoom", "(JLcom/mapbox/mapboxgl/lib/LatLngZoom;J)V", - reinterpret_cast(&nativeSetLonLatZoom)}, - {"nativeGetLonLatZoom", "(J)Lcom/mapbox/mapboxgl/lib/LatLngZoom;", - reinterpret_cast(&nativeGetLonLatZoom)}, + {"nativeSetLatLngZoom", "(JLcom/mapbox/mapboxgl/lib/LatLngZoom;J)V", + reinterpret_cast(&nativeSetLatLngZoom)}, + {"nativeGetLatLngZoom", "(J)Lcom/mapbox/mapboxgl/lib/LatLngZoom;", + reinterpret_cast(&nativeGetLatLngZoom)}, {"nativeResetZoom", "(J)V", reinterpret_cast(&nativeResetZoom)}, {"nativeStartPanning", "(J)V", reinterpret_cast(&nativeStartScaling)}, {"nativeStopPanning", "(J)V", reinterpret_cast(&nativeStopScaling)}, @@ -935,24 +935,24 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { return JNI_ERR; } - lonLatClass = reinterpret_cast(env->NewGlobalRef(lonLatClass)); - if (lonLatClass == nullptr) { + latLngClass = reinterpret_cast(env->NewGlobalRef(latLngClass)); + if (latLngClass == nullptr) { env->ExceptionDescribe(); return JNI_ERR; } - lonLatZoomClass = reinterpret_cast(env->NewGlobalRef(lonLatZoomClass)); - if (lonLatZoomClass == nullptr) { + latLngZoomClass = reinterpret_cast(env->NewGlobalRef(latLngZoomClass)); + if (latLngZoomClass == nullptr) { env->ExceptionDescribe(); - env->DeleteGlobalRef(lonLatClass); + env->DeleteGlobalRef(latLngClass); return JNI_ERR; } runtimeExceptionClass = reinterpret_cast(env->NewGlobalRef(runtimeExceptionClass)); if (runtimeExceptionClass == nullptr) { env->ExceptionDescribe(); - env->DeleteGlobalRef(lonLatClass); - env->DeleteGlobalRef(lonLatZoomClass); + env->DeleteGlobalRef(latLngClass); + env->DeleteGlobalRef(latLngZoomClass); return JNI_ERR; } @@ -960,8 +960,8 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { reinterpret_cast(env->NewGlobalRef(nullPointerExceptionClass)); if (nullPointerExceptionClass == nullptr) { env->ExceptionDescribe(); - env->DeleteGlobalRef(lonLatClass); - env->DeleteGlobalRef(lonLatZoomClass); + env->DeleteGlobalRef(latLngClass); + env->DeleteGlobalRef(latLngZoomClass); env->DeleteGlobalRef(runtimeExceptionClass); return JNI_ERR; } @@ -969,8 +969,8 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { arrayListClass = reinterpret_cast(env->NewGlobalRef(arrayListClass)); if (arrayListClass == nullptr) { env->ExceptionDescribe(); - env->DeleteGlobalRef(lonLatClass); - env->DeleteGlobalRef(lonLatZoomClass); + env->DeleteGlobalRef(latLngClass); + env->DeleteGlobalRef(latLngZoomClass); env->DeleteGlobalRef(runtimeExceptionClass); env->DeleteGlobalRef(nullPointerExceptionClass); return JNI_ERR; @@ -993,18 +993,18 @@ extern "C" JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) { throw new std::runtime_error("GetEnv() failed"); } - env->DeleteGlobalRef(lonLatClass); - lonLatClass = nullptr; - lonLatConstructorId = nullptr; - lonLatLonId = nullptr; - lonLatLatId = nullptr; - - env->DeleteGlobalRef(lonLatZoomClass); - lonLatZoomClass = nullptr; - lonLatZoomConstructorId = nullptr; - lonLatZoomLonId = nullptr; - lonLatZoomLatId = nullptr; - lonLatZoomZoomId = nullptr; + env->DeleteGlobalRef(latLngClass); + latLngClass = nullptr; + latLngConstructorId = nullptr; + latLngLongitudeId = nullptr; + latLngLatitudeId = nullptr; + + env->DeleteGlobalRef(latLngZoomClass); + latLngZoomClass = nullptr; + latLngZoomConstructorId = nullptr; + latLngZoomLongitudeId = nullptr; + latLngZoomLatitudeId = nullptr; + latLngZoomZoomId = nullptr; onMapChangedId = nullptr; onFpsChangedId = nullptr; diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/LatLngZoom.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/LatLngZoom.java index 5cbb48d366c..c6e80b0c13f 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/LatLngZoom.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/LatLngZoom.java @@ -42,33 +42,30 @@ public void setZoom(double zoom) { } @Override - public int hashCode() { - final int prime = 31; - int result = 1; - long temp; - temp = super.hashCode(); - result = prime * result + (int) (temp ^ (temp >>> 32)); - return result; + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + + LatLngZoom that = (LatLngZoom) o; + + if (Double.compare(that.zoom, zoom) != 0) return false; + + return true; } @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - LatLngZoom other = (LatLngZoom) obj; - return super.equals(obj) && Double.doubleToLongBits(zoom) == Double.doubleToLongBits(other.zoom); + public int hashCode() { + int result = super.hashCode(); + long temp; + temp = Double.doubleToLongBits(zoom); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + return result; } @Override public String toString() { - return "LatLngZoom [lat=" + super.getLatitude() + ", lon=" + super.getLongitude() + ", zoom=" + zoom + "]"; + return "LatLngZoom [latitude=" + super.getLatitude() + ", longitude=" + super.getLongitude() + ", altitude=" + super.getAltitude() + ", zoom=" + zoom + "]"; } @Override diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/NativeMapView.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/NativeMapView.java index 17a95fa3247..c1c5dcf10a7 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/NativeMapView.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/NativeMapView.java @@ -248,11 +248,11 @@ public void setLatLng(LatLng latLng) { } public void setLatLng(LatLng latLng, long duration) { - nativeSetLonLat(mNativeMapViewPtr, latLng, duration); + nativeSetLatLng(mNativeMapViewPtr, latLng, duration); } public LatLng getLatLng() { - return nativeGetLonLat(mNativeMapViewPtr); + return nativeGetLatLng(mNativeMapViewPtr); } public void startPanning() { @@ -307,16 +307,16 @@ public double getZoom() { return nativeGetZoom(mNativeMapViewPtr); } - public void setLatLngZoom(LatLngZoom lonLatZoom) { - setLatLngZoom(lonLatZoom, 0); + public void setLatLngZoom(LatLngZoom latLngZoom) { + setLatLngZoom(latLngZoom, 0); } - public void setLatLngZoom(LatLngZoom lonLatZoom, long duration) { - nativeSetLonLatZoom(mNativeMapViewPtr, lonLatZoom, duration); + public void setLatLngZoom(LatLngZoom latLngZoom, long duration) { + nativeSetLatLngZoom(mNativeMapViewPtr, latLngZoom, duration); } public LatLngZoom getLatLngZoom() { - return nativeGetLonLatZoom(mNativeMapViewPtr); + return nativeGetLatLngZoom(mNativeMapViewPtr); } public void resetZoom() { @@ -490,10 +490,10 @@ private native void nativeSetStyleJson(long nativeMapViewPtr, private native void nativeMoveBy(long nativeMapViewPtr, double dx, double dy, long duration); - private native void nativeSetLonLat(long nativeMapViewPtr, LatLng latLng, + private native void nativeSetLatLng(long nativeMapViewPtr, LatLng latLng, long duration); - private native LatLng nativeGetLonLat(long nativeMapViewPtr); + private native LatLng nativeGetLatLng(long nativeMapViewPtr); private native void nativeStartPanning(long nativeMapViewPtr); @@ -514,10 +514,10 @@ private native void nativeSetZoom(long nativeMapViewPtr, double zoom, private native double nativeGetZoom(long nativeMapViewPtr); - private native void nativeSetLonLatZoom(long nativeMapViewPtr, + private native void nativeSetLatLngZoom(long nativeMapViewPtr, LatLngZoom lonLatZoom, long duration); - private native LatLngZoom nativeGetLonLatZoom(long nativeMapViewPtr); + private native LatLngZoom nativeGetLatLngZoom(long nativeMapViewPtr); private native void nativeResetZoom(long nativeMapViewPtr); diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/constants/MathConstants.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/constants/MathConstants.java index 3e4a3dea550..f6a692d4431 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/constants/MathConstants.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/constants/MathConstants.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxgl.lib.constants; public interface MathConstants { - public static final float DEG2RAD = (float) (Math.PI / 180.0); - public static final float RAD2DEG = (float) (180.0 / Math.PI); + public static final double DEG2RAD = (Math.PI / 180.0); + public static final double RAD2DEG = (180.0 / Math.PI); - public static final float PI = (float) Math.PI; + public static final double PI = Math.PI; } diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/LatLng.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/LatLng.java index 89c51f2da39..eddd99a9400 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/LatLng.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/LatLng.java @@ -19,9 +19,9 @@ public LatLng[] newArray(int size) { } }; - private double longitude; private double latitude; - private double altitude = 0f; + private double longitude; + private double altitude = 0.0; /** * Construct a new latitude, longitude point given float arguments @@ -85,30 +85,35 @@ public double getAltitude() { } @Override - public boolean equals(final Object obj) { - if (obj == null) { - return false; - } - if (obj == this) { - return true; - } - if (!obj.getClass().equals(this.getClass())) { - return false; - } - final LatLng rhs = (LatLng) obj; - return rhs.latitude == this.latitude - && rhs.longitude == this.longitude - && rhs.altitude == this.altitude; + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + LatLng latLng = (LatLng) o; + + if (Double.compare(latLng.altitude, altitude) != 0) return false; + if (Double.compare(latLng.latitude, latitude) != 0) return false; + if (Double.compare(latLng.longitude, longitude) != 0) return false; + + return true; } @Override public int hashCode() { - return (int) (37.0 * (17.0 * latitude * 1E6d + longitude * 1E6d) + altitude); + int result; + long temp; + temp = Double.doubleToLongBits(latitude); + result = (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(longitude); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(altitude); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + return result; } @Override public String toString() { - return "LatLng [longitude=" + longitude + ", latitude=" + latitude + "]"; + return "LatLng [longitude=" + longitude + ", latitude=" + latitude + ", altitude=" + altitude + "]"; } @Override @@ -128,7 +133,7 @@ public void writeToParcel(Parcel out, int flags) { * @param other Other LatLng to compare to * @return distance in meters */ - public int distanceTo(final LatLng other) { + public double distanceTo(final LatLng other) { final double a1 = DEG2RAD * this.latitude; final double a2 = DEG2RAD * this.longitude; @@ -143,6 +148,6 @@ public int distanceTo(final LatLng other) { final double t3 = Math.sin(a1) * Math.sin(b1); final double tt = Math.acos(t1 + t2 + t3); - return (int) (RADIUS_EARTH_METERS * tt); + return RADIUS_EARTH_METERS * tt; } } diff --git a/include/mbgl/android/jni.hpp b/include/mbgl/android/jni.hpp index 698c0247313..aa2f1ab2fcf 100644 --- a/include/mbgl/android/jni.hpp +++ b/include/mbgl/android/jni.hpp @@ -19,16 +19,16 @@ extern std::string androidRelease; extern jmethodID onMapChangedId; extern jmethodID onFpsChangedId; -extern jclass lonLatClass; -extern jmethodID lonLatConstructorId; -extern jfieldID lonLatLonId; -extern jfieldID lonLatLatId; - -extern jclass lonLatZoomClass; -extern jmethodID lonLatZoomConstructorId; -extern jfieldID lonLatZoomLonId; -extern jfieldID lonLatZoomLatId; -extern jfieldID lonLatZoomZoomId; +extern jclass latLngClass; +extern jmethodID latLngConstructorId; +extern jfieldID latLngLatitudeId; +extern jfieldID latLngLongitudeId; + +extern jclass latLngZoomClass; +extern jmethodID latLngZoomConstructorId; +extern jfieldID latLngZoomLatitudeId; +extern jfieldID latLngZoomLongitudeId; +extern jfieldID latLngZoomZoomId; extern jclass runtimeExceptionClass; extern jclass nullPointerExceptionClass; From 5c79baedf933e7a3d90cbad541deee294f5ed6ed Mon Sep 17 00:00:00 2001 From: Leith Bade Date: Mon, 16 Feb 2015 15:25:31 -0800 Subject: [PATCH 02/15] Add projection functions to Java --- android/cpp/jni.cpp | 244 +++++++++++++++++- .../java/com/mapbox/mapboxgl/lib/MapView.java | 17 +- .../mapbox/mapboxgl/lib/NativeMapView.java | 41 +++ .../mapboxgl/lib/constants/GeoConstants.java | 2 +- .../mapboxgl/lib/constants/MathConstants.java | 2 +- .../mapboxgl/lib/geometry/BoundingBox.java | 3 +- .../lib/geometry/CoordinateRegion.java | 6 +- .../mapboxgl/lib/geometry/CoordinateSpan.java | 8 +- .../lib/geometry/IProjectedMeters.java | 7 + .../mapbox/mapboxgl/lib/geometry/LatLng.java | 49 ++-- .../lib/{ => geometry}/LatLngZoom.java | 27 +- .../lib/geometry/ProjectedMeters.java | 95 +++++++ .../com/mapbox/mapboxgl/app/MainActivity.java | 6 +- include/mbgl/android/jni.hpp | 10 + 14 files changed, 452 insertions(+), 65 deletions(-) create mode 100644 android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/IProjectedMeters.java rename android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/{ => geometry}/LatLngZoom.java (74%) create mode 100644 android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/ProjectedMeters.java diff --git a/android/cpp/jni.cpp b/android/cpp/jni.cpp index b583b835614..eca13c764fc 100644 --- a/android/cpp/jni.cpp +++ b/android/cpp/jni.cpp @@ -53,6 +53,16 @@ jclass arrayListClass = nullptr; jmethodID arrayListConstructorId = nullptr; jmethodID arrayListAddId = nullptr; +jclass projectedMetersClass = nullptr; +jmethodID projectedMetersConstructorId = nullptr; +jfieldID projectedMetersNorthingId = nullptr; +jfieldID projectedMetersEastingId = nullptr; + +jclass pointFClass = nullptr; +jmethodID pointFConstructorId = nullptr; +jfieldID pointFXId = nullptr; +jfieldID pointFYId = nullptr; + bool throw_error(JNIEnv *env, const char *msg) { if (env->ThrowNew(runtimeExceptionClass, msg) < 0) { env->ExceptionDescribe(); @@ -455,13 +465,13 @@ void JNICALL nativeSetLatLng(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, j assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - double latitude = env->GetDoubleField(latLng, latLngLatitudeId); + jdouble latitude = env->GetDoubleField(latLng, latLngLatitudeId); if (env->ExceptionCheck()) { env->ExceptionDescribe(); return; } - double longitude = env->GetDoubleField(latLng, latLngLongitudeId); + jdouble longitude = env->GetDoubleField(latLng, latLngLongitudeId); if (env->ExceptionCheck()) { env->ExceptionDescribe(); return; @@ -550,19 +560,19 @@ void JNICALL nativeSetLatLngZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPt assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - double latitude = env->GetDoubleField(latLngZoom, latLngZoomLatitudeId); + jdouble latitude = env->GetDoubleField(latLngZoom, latLngZoomLatitudeId); if (env->ExceptionCheck()) { env->ExceptionDescribe(); return; } - double longitude = env->GetDoubleField(latLngZoom, latLngZoomLongitudeId); + jdouble longitude = env->GetDoubleField(latLngZoom, latLngZoomLongitudeId); if (env->ExceptionCheck()) { env->ExceptionDescribe(); return; } - double zoom = env->GetDoubleField(latLngZoom, latLngZoomZoomId); + jdouble zoom = env->GetDoubleField(latLngZoom, latLngZoomZoomId); if (env->ExceptionCheck()) { env->ExceptionDescribe(); return; @@ -576,7 +586,7 @@ jobject JNICALL nativeGetLatLngZoom(JNIEnv *env, jobject obj, jlong nativeMapVie assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); mbgl::LatLng latLng = nativeMapView->getMap().getLatLng(); - double zoom = nativeMapView->getMap().getZoom(); + jdouble zoom = nativeMapView->getMap().getZoom(); jobject ret = env->NewObject(latLngZoomClass, latLngZoomConstructorId, latLng.longitude, latLng.latitude, zoom); if (ret == nullptr) { @@ -705,6 +715,125 @@ nativeSetReachability(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jboolean mbgl::NetworkStatus::Reachable(); } } + +jdouble JNICALL nativeGetMetersPerPixelAtLatitude(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jdouble lat, jdouble zoom) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetMetersPerPixelAtLatitude"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + return nativeMapView->getMap().getMetersPerPixelAtLatitude(lat, zoom); +} + +jobject JNICALL nativeProjectedMetersForLatLng(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jobject latLng) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeProjectedMetersForLatLng"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + + jdouble latitude = env->GetDoubleField(latLng, latLngLatitudeId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return nullptr; + } + + jdouble longitude = env->GetDoubleField(latLng, latLngLongitudeId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return nullptr; + } + + mbgl::ProjectedMeters projectedMeters = nativeMapView->getMap().projectedMetersForLatLng(mbgl::LatLng(latitude, longitude)); + + jobject ret = env->NewObject(projectedMetersClass, projectedMetersConstructorId, projectedMeters.northing, projectedMeters.easting); + if (ret == nullptr) { + env->ExceptionDescribe(); + return nullptr; + } + + return ret; +} + +jobject JNICALL nativeLatLngForProjectedMeters(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jobject projectedMeters) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeLatLngForProjectedMeters"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + + jdouble northing = env->GetDoubleField(projectedMeters, projectedMetersNorthingId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return nullptr; + } + + jdouble easting = env->GetDoubleField(projectedMeters, projectedMetersEastingId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return nullptr; + } + + mbgl::LatLng latLng = nativeMapView->getMap().latLngForProjectedMeters(mbgl::ProjectedMeters(northing, easting)); + + jobject ret = env->NewObject(latLngClass, latLngConstructorId, latLng.latitude, latLng.longitude); + if (ret == nullptr) { + env->ExceptionDescribe(); + return nullptr; + } + + return ret; +} + +jobject JNICALL nativePixelForLatLng(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jobject latLng) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativePixelForLatLng"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + + jdouble latitude = env->GetDoubleField(latLng, latLngLatitudeId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return nullptr; + } + + jdouble longitude = env->GetDoubleField(latLng, latLngLongitudeId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return nullptr; + } + + mbgl::vec2 pixel = nativeMapView->getMap().pixelForLatLng(mbgl::LatLng(latitude, longitude)); + + jobject ret = env->NewObject(pointFClass, pointFConstructorId, static_cast(pixel.x), static_cast(pixel.y)); + if (ret == nullptr) { + env->ExceptionDescribe(); + return nullptr; + } + + return ret; +} + +jobject JNICALL nativeLatLngForPixel(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jobject pixel) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeLatLngForPixel"); + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); + + jfloat x = env->GetDoubleField(pixel, pointFXId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return nullptr; + } + + jfloat y = env->GetDoubleField(pixel, pointFYId); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + return nullptr; + } + + mbgl::LatLng latLng = nativeMapView->getMap().latLngForPixel(mbgl::vec2(x, y)); + + jobject ret = env->NewObject(latLngClass, latLngConstructorId, latLng.latitude, latLng.longitude); + if (ret == nullptr) { + env->ExceptionDescribe(); + return nullptr; + } + + return ret; +} } extern "C" { @@ -745,7 +874,7 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { return JNI_ERR; } - latLngZoomClass = env->FindClass("com/mapbox/mapboxgl/lib/LatLngZoom"); + latLngZoomClass = env->FindClass("com/mapbox/mapboxgl/lib/geometry/LatLngZoom"); if (latLngZoomClass == nullptr) { env->ExceptionDescribe(); return JNI_ERR; @@ -835,9 +964,57 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { return JNI_ERR; } + projectedMetersClass = env->FindClass("com/mapbox/mapboxgl/lib/geometry/ProjectedMeters"); + if (projectedMetersClass == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + projectedMetersConstructorId = env->GetMethodID(projectedMetersClass, "", "(DD)V"); + if (projectedMetersConstructorId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + projectedMetersNorthingId = env->GetFieldID(projectedMetersClass, "northing", "D"); + if (projectedMetersNorthingId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + projectedMetersEastingId = env->GetFieldID(projectedMetersClass, "easting", "D"); + if (projectedMetersEastingId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + pointFClass = env->FindClass("android/graphics/PointF"); + if (pointFClass == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + pointFConstructorId = env->GetMethodID(pointFClass, "", "(FF)V"); + if (pointFConstructorId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + pointFXId = env->GetFieldID(pointFClass, "x", "F"); + if (pointFXId == nullptr) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + pointFYId = env->GetFieldID(pointFClass, "y", "F"); + if (pointFYId == 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 methods = {{ // Can remove the extra brace in C++14 + std::array methods = {{ // Can remove the extra brace in C++14 {"nativeCreate", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)J", reinterpret_cast(&nativeCreate)}, {"nativeDestroy", "(J)V", reinterpret_cast(&nativeDestroy)}, @@ -903,9 +1080,9 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { {"nativeGetScale", "(J)D", reinterpret_cast(&nativeGetScale)}, {"nativeSetZoom", "(JDJ)V", reinterpret_cast(&nativeSetZoom)}, {"nativeGetZoom", "(J)D", reinterpret_cast(&nativeGetZoom)}, - {"nativeSetLatLngZoom", "(JLcom/mapbox/mapboxgl/lib/LatLngZoom;J)V", + {"nativeSetLatLngZoom", "(JLcom/mapbox/mapboxgl/lib/geometry/LatLngZoom;J)V", reinterpret_cast(&nativeSetLatLngZoom)}, - {"nativeGetLatLngZoom", "(J)Lcom/mapbox/mapboxgl/lib/LatLngZoom;", + {"nativeGetLatLngZoom", "(J)Lcom/mapbox/mapboxgl/lib/geometry/LatLngZoom;", reinterpret_cast(&nativeGetLatLngZoom)}, {"nativeResetZoom", "(J)V", reinterpret_cast(&nativeResetZoom)}, {"nativeStartPanning", "(J)V", reinterpret_cast(&nativeStartScaling)}, @@ -928,7 +1105,15 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { {"nativeSetDebug", "(JZ)V", reinterpret_cast(&nativeSetDebug)}, {"nativeToggleDebug", "(J)V", reinterpret_cast(&nativeToggleDebug)}, {"nativeGetDebug", "(J)Z", reinterpret_cast(&nativeGetDebug)}, - {"nativeSetReachability", "(JZ)V", reinterpret_cast(&nativeSetReachability)}}}; + {"nativeSetReachability", "(JZ)V", reinterpret_cast(&nativeSetReachability)}, + //{"nativeGetWorldBoundsMeters", "(J)V", reinterpret_cast(&nativeGetWorldBoundsMeters)}, + //{"nativeGetWorldBoundsLatLng", "(J)V", reinterpret_cast(&nativeGetWorldBoundsLatLng)}, + {"nativeGetMetersPerPixelAtLatitude", "(JDD)D", reinterpret_cast(&nativeGetMetersPerPixelAtLatitude)}, + {"nativeProjectedMetersForLatLng", "(JLcom/mapbox/mapboxgl/lib/geometry/LatLng;)Lcom/mapbox/mapboxgl/lib/geometry/ProjectedMeters;", reinterpret_cast(&nativeProjectedMetersForLatLng)}, + {"nativeLatLngForProjectedMeters", "(JLcom/mapbox/mapboxgl/lib/geometry/ProjectedMeters;)Lcom/mapbox/mapboxgl/lib/geometry/LatLng;", reinterpret_cast(&nativeLatLngForProjectedMeters)}, + {"nativePixelForLatLng", "(JLcom/mapbox/mapboxgl/lib/geometry/LatLng;)Landroid/graphics/PointF;", reinterpret_cast(&nativePixelForLatLng)}, + {"nativeLatLngForPixel", "(JLandroid/graphics/PointF;)Lcom/mapbox/mapboxgl/lib/geometry/LatLng;", reinterpret_cast(&nativeLatLngForPixel)}, + }}; if (env->RegisterNatives(nativeMapViewClass, methods.data(), methods.size()) < 0) { env->ExceptionDescribe(); @@ -976,6 +1161,31 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { return JNI_ERR; } + projectedMetersClass = reinterpret_cast(env->NewGlobalRef(projectedMetersClass)); + if (projectedMetersClass == nullptr) { + env->ExceptionDescribe(); + env->DeleteGlobalRef(latLngClass); + env->DeleteGlobalRef(latLngZoomClass); + env->DeleteGlobalRef(runtimeExceptionClass); + env->DeleteGlobalRef(nullPointerExceptionClass); + env->DeleteGlobalRef(arrayListClass); + return JNI_ERR; + } + + + pointFClass = reinterpret_cast(env->NewGlobalRef(pointFClass)); + if (pointFClass == nullptr) { + env->ExceptionDescribe(); + env->DeleteGlobalRef(latLngClass); + env->DeleteGlobalRef(latLngZoomClass); + env->DeleteGlobalRef(runtimeExceptionClass); + env->DeleteGlobalRef(nullPointerExceptionClass); + env->DeleteGlobalRef(arrayListClass); + env->DeleteGlobalRef(projectedMetersClass); + return JNI_ERR; + } + + char release[PROP_VALUE_MAX] = ""; __system_property_get("ro.build.version.release", release); androidRelease = std::string(release); @@ -1021,5 +1231,17 @@ extern "C" JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) { arrayListClass = nullptr; arrayListConstructorId = nullptr; arrayListAddId = nullptr; + + env->DeleteGlobalRef(projectedMetersClass); + projectedMetersClass = nullptr; + projectedMetersConstructorId = nullptr; + projectedMetersNorthingId = nullptr; + projectedMetersEastingId = nullptr; + + env->DeleteGlobalRef(pointFClass); + pointFClass = nullptr; + pointFConstructorId = nullptr; + pointFXId = nullptr; + pointFYId = nullptr; } } diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/MapView.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/MapView.java index d157cc07f87..b9545dc33ed 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/MapView.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/MapView.java @@ -30,6 +30,7 @@ import com.almeros.android.multitouch.gesturedetectors.RotateGestureDetector; import com.almeros.android.multitouch.gesturedetectors.TwoFingerGestureDetector; import com.mapbox.mapboxgl.lib.geometry.LatLng; +import com.mapbox.mapboxgl.lib.geometry.LatLngZoom; import org.apache.commons.validator.routines.UrlValidator; @@ -135,7 +136,6 @@ private void initialize(Context context, AttributeSet attrs) { // Check if we are in Eclipse UI editor if (isInEditMode()) { - // TODO editor does not load properly because we don't implement this return; } @@ -386,7 +386,7 @@ public void removeAllClasses() { public void removeAllClasses(long transitionDuration) { mNativeMapView.setDefaultTransitionDuration(transitionDuration); - ArrayList classes = new ArrayList(0); + ArrayList classes = new ArrayList<>(0); setClasses(classes); } @@ -436,7 +436,7 @@ public void onSaveInstanceState(Bundle outState) { outState.putBoolean(STATE_DEBUG_ACTIVE, isDebugActive()); outState.putString(STATE_STYLE_URL, mStyleUrl); outState.putString(STATE_ACCESS_TOKEN, getAccessToken()); - outState.putStringArrayList(STATE_CLASSES, new ArrayList(getClasses())); + outState.putStringArrayList(STATE_CLASSES, new ArrayList<>(getClasses())); outState.putLong(STATE_DEFAULT_TRANSITION_DURATION, mNativeMapView.getDefaultTransitionDuration()); } @@ -531,8 +531,6 @@ public void surfaceRedrawNeeded(SurfaceHolder holder) { } } - // TODO examine how GLSurvaceView hadles attach/detach from window - // Called when view is no longer connected @Override protected void onDetachedFromWindow() { @@ -560,10 +558,6 @@ protected void onVisibilityChanged(@NonNull View changedView, int visibility) { // Draw events // - // TODO: onDraw for UI editor mockup? - // By default it just shows a gray screen with "MapView" - // Not too important but perhaps we could put a static demo map image there - // // Input events // @@ -782,7 +776,7 @@ public boolean onScale(ScaleGestureDetector detector) { return false; } - // TODO complex decision between roate or scale or both (see Google + // TODO complex decision between rotate or scale or both (see Google // Maps app) // Cancel any animation @@ -1011,7 +1005,6 @@ public boolean onKeyUp(int keyCode, KeyEvent event) { // Called for trackball events, all motions are relative in device specific // units - // TODO: test trackball click and long click @Override public boolean onTrackballEvent(MotionEvent event) { // Choose the action @@ -1105,8 +1098,6 @@ public void run() { @Override @TargetApi(12) public boolean onGenericMotionEvent(MotionEvent event) { // Mouse events - // TODO: SOURCE_TOUCH_NAVIGATION? - // TODO: source device resolution? //if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { // this is not available before API 18 if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) == InputDevice.SOURCE_CLASS_POINTER) { // Choose the action diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/NativeMapView.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/NativeMapView.java index c1c5dcf10a7..3059c0bfa47 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/NativeMapView.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/NativeMapView.java @@ -1,8 +1,11 @@ package com.mapbox.mapboxgl.lib; +import android.graphics.PointF; import android.view.Surface; import com.mapbox.mapboxgl.lib.geometry.LatLng; +import com.mapbox.mapboxgl.lib.geometry.LatLngZoom; +import com.mapbox.mapboxgl.lib.geometry.ProjectedMeters; import java.util.List; @@ -392,6 +395,30 @@ public void setReachability(boolean status) { nativeSetReachability(mNativeMapViewPtr, status); } + //public void getWorldBoundsMeters(); + + //public void getWorldBoundsLatLng(); + + public double getMetersPerPixelAtLatitude(double lat, double zoom) { + return nativeGetMetersPerPixelAtLatitude(mNativeMapViewPtr, lat, zoom); + } + + public ProjectedMeters projectedMetersForLatLng(LatLng latLng) { + return nativeProjectedMetersForLatLng(mNativeMapViewPtr, latLng); + } + + public LatLng latLngForProjectedMeters(ProjectedMeters projectedMeters) { + return nativeLatLngForProjectedMeters(mNativeMapViewPtr, projectedMeters); + } + + public PointF pixelForLatLng(LatLng latLng) { + return nativePixelForLatLng(mNativeMapViewPtr, latLng); + } + + public LatLng latLngForPixel(PointF pixel) { + return nativeLatLngForPixel(mNativeMapViewPtr, pixel); + } + // // Callbacks // @@ -553,4 +580,18 @@ private native void nativeSetBearing(long nativeMapViewPtr, double degrees, private native boolean nativeGetDebug(long nativeMapViewPtr); private native void nativeSetReachability(long nativeMapViewPtr, boolean status); + + //private native void nativeGetWorldBoundsMeters(long nativeMapViewPtr); + + //private native void nativeGetWorldBoundsLatLng(long nativeMapViewPtr); + + private native double nativeGetMetersPerPixelAtLatitude(long nativeMapViewPtr, double lat, double zoom); + + private native ProjectedMeters nativeProjectedMetersForLatLng(long nativeMapViewPtr, LatLng latLng); + + private native LatLng nativeLatLngForProjectedMeters(long nativeMapViewPtr, ProjectedMeters projectedMeters); + + private native PointF nativePixelForLatLng(long nativeMapViewPtr, LatLng latLng); + + private native LatLng nativeLatLngForPixel(long nativeMapViewPtr, PointF pixel); } diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/constants/GeoConstants.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/constants/GeoConstants.java index d7f674d7b19..fff665b5a1e 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/constants/GeoConstants.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/constants/GeoConstants.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxgl.lib.constants; -public interface GeoConstants { +public class GeoConstants { // http://en.wikipedia.org/wiki/Earth_radius#Equatorial_radius public static final int RADIUS_EARTH_METERS = 6378137; public static final double MIN_LATITUDE = -85.05112878; diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/constants/MathConstants.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/constants/MathConstants.java index f6a692d4431..cd11523605a 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/constants/MathConstants.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/constants/MathConstants.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxgl.lib.constants; -public interface MathConstants { +public class MathConstants { public static final double DEG2RAD = (Math.PI / 180.0); public static final double RAD2DEG = (180.0 / Math.PI); diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/BoundingBox.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/BoundingBox.java index 3a8141e3c33..ba60701b82d 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/BoundingBox.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/BoundingBox.java @@ -2,6 +2,7 @@ import android.os.Parcel; import android.os.Parcelable; + import java.io.Serializable; import java.util.List; @@ -10,8 +11,6 @@ */ public final class BoundingBox implements Parcelable, Serializable { - static final long serialVersionUID = 2L; - private final double mLatNorth; private final double mLatSouth; private final double mLonEast; diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/CoordinateRegion.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/CoordinateRegion.java index 1d2409b464e..b5c5f66ba88 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/CoordinateRegion.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/CoordinateRegion.java @@ -7,7 +7,7 @@ public class CoordinateRegion { private LatLng center; private CoordinateSpan span; - public CoordinateRegion(LatLng center, CoordinateSpan span) { + public CoordinateRegion(final LatLng center, final CoordinateSpan span) { this.center = center; this.span = span; } @@ -16,7 +16,7 @@ public LatLng getCenter() { return center; } - public void setCenter(LatLng center) { + public void setCenter(final LatLng center) { this.center = center; } @@ -24,7 +24,7 @@ public CoordinateSpan getSpan() { return span; } - public void setSpan(CoordinateSpan span) { + public void setSpan(final CoordinateSpan span) { this.span = span; } } diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/CoordinateSpan.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/CoordinateSpan.java index 4fa239f664d..b79fb7c42d0 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/CoordinateSpan.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/CoordinateSpan.java @@ -3,12 +3,12 @@ /** * Implementation of iOS MKCoordinateSpan */ -public final class CoordinateSpan { +public class CoordinateSpan { private double latitudeSpan; private double longitudeSpan; - public CoordinateSpan(double latitudeSpan, double longitudeSpan) { + public CoordinateSpan(final double latitudeSpan, final double longitudeSpan) { this.latitudeSpan = latitudeSpan; this.longitudeSpan = longitudeSpan; } @@ -17,7 +17,7 @@ public double getLatitudeSpan() { return latitudeSpan; } - public void setLatitudeSpan(double latitudeSpan) { + public void setLatitudeSpan(final double latitudeSpan) { this.latitudeSpan = latitudeSpan; } @@ -25,7 +25,7 @@ public double getLongitudeSpan() { return longitudeSpan; } - public void setLongitudeSpan(double longitudeSpan) { + public void setLongitudeSpan(final double longitudeSpan) { this.longitudeSpan = longitudeSpan; } } diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/IProjectedMeters.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/IProjectedMeters.java new file mode 100644 index 00000000000..398f368b3f3 --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/IProjectedMeters.java @@ -0,0 +1,7 @@ +package com.mapbox.mapboxgl.lib.geometry; + +public interface IProjectedMeters { + double getNorthing(); + + double getEasting(); +} diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/LatLng.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/LatLng.java index eddd99a9400..de97b575154 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/LatLng.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/LatLng.java @@ -3,11 +3,13 @@ import android.location.Location; import android.os.Parcel; import android.os.Parcelable; + import com.mapbox.mapboxgl.lib.constants.GeoConstants; import com.mapbox.mapboxgl.lib.constants.MathConstants; + import java.io.Serializable; -public class LatLng implements ILatLng, GeoConstants, MathConstants, Parcelable, Serializable { +public class LatLng implements ILatLng, Parcelable, Serializable { public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public LatLng createFromParcel(Parcel in) { @@ -26,7 +28,7 @@ public LatLng[] newArray(int size) { /** * Construct a new latitude, longitude point given float arguments * @param latitude Latitude in degrees - * @param longitude Longitude in degress + * @param longitude Longitude in degrees */ public LatLng(double latitude, double longitude) { this.latitude = latitude; @@ -39,7 +41,7 @@ public LatLng(double latitude, double longitude) { * @param longitude Longitude in degress * @param altitude Altitude in meters */ - public LatLng(final double latitude, final double longitude, final double altitude) { + public LatLng(double latitude, double longitude, double altitude) { this.latitude = latitude; this.longitude = longitude; this.altitude = altitude; @@ -49,7 +51,7 @@ public LatLng(final double latitude, final double longitude, final double altitu * Transform a Location into a LatLng point * @param location Android Location */ - public LatLng(final Location location) { + public LatLng(Location location) { this(location.getLatitude(), location.getLongitude(), location.getAltitude()); } @@ -57,15 +59,15 @@ public LatLng(final Location location) { * Clone an existing latitude longitude point * @param aLatLng LatLng */ - public LatLng(final LatLng aLatLng) { + public LatLng(LatLng aLatLng) { this.latitude = aLatLng.latitude; this.longitude = aLatLng.longitude; this.altitude = aLatLng.altitude; } protected LatLng(Parcel in) { - longitude = in.readDouble(); latitude = in.readDouble(); + longitude = in.readDouble(); altitude = in.readDouble(); } @@ -86,14 +88,25 @@ public double getAltitude() { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } LatLng latLng = (LatLng) o; - if (Double.compare(latLng.altitude, altitude) != 0) return false; - if (Double.compare(latLng.latitude, latitude) != 0) return false; - if (Double.compare(latLng.longitude, longitude) != 0) return false; + if (Double.compare(latLng.altitude, altitude) != 0) { + return false; + } + + if (Double.compare(latLng.latitude, latitude) != 0) { + return false; + } + if (Double.compare(latLng.longitude, longitude) != 0) { + return false; + } return true; } @@ -123,8 +136,8 @@ public int describeContents() { @Override public void writeToParcel(Parcel out, int flags) { - out.writeDouble(longitude); out.writeDouble(latitude); + out.writeDouble(longitude); out.writeDouble(altitude); } @@ -133,12 +146,12 @@ public void writeToParcel(Parcel out, int flags) { * @param other Other LatLng to compare to * @return distance in meters */ - public double distanceTo(final LatLng other) { + public double distanceTo(LatLng other) { - final double a1 = DEG2RAD * this.latitude; - final double a2 = DEG2RAD * this.longitude; - final double b1 = DEG2RAD * other.getLatitude(); - final double b2 = DEG2RAD * other.getLongitude(); + final double a1 = MathConstants.DEG2RAD * this.latitude; + final double a2 = MathConstants.DEG2RAD * this.longitude; + final double b1 = MathConstants.DEG2RAD * other.getLatitude(); + final double b2 = MathConstants.DEG2RAD * other.getLongitude(); final double cosa1 = Math.cos(a1); final double cosb1 = Math.cos(b1); @@ -148,6 +161,6 @@ public double distanceTo(final LatLng other) { final double t3 = Math.sin(a1) * Math.sin(b1); final double tt = Math.acos(t1 + t2 + t3); - return RADIUS_EARTH_METERS * tt; + return GeoConstants.RADIUS_EARTH_METERS * tt; } } diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/LatLngZoom.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/LatLngZoom.java similarity index 74% rename from android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/LatLngZoom.java rename to android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/LatLngZoom.java index c6e80b0c13f..bd8a214e2b5 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/LatLngZoom.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/LatLngZoom.java @@ -1,10 +1,11 @@ -package com.mapbox.mapboxgl.lib; +package com.mapbox.mapboxgl.lib.geometry; import android.os.Parcel; import android.os.Parcelable; -import com.mapbox.mapboxgl.lib.geometry.LatLng; -public class LatLngZoom extends LatLng implements Parcelable { +import java.io.Serializable; + +public class LatLngZoom extends LatLng implements Parcelable, Serializable { public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public LatLngZoom createFromParcel(Parcel in) { @@ -18,8 +19,8 @@ public LatLngZoom[] newArray(int size) { private double zoom; - public LatLngZoom(double lat, double lon, double zoom) { - super(lat, lon); + public LatLngZoom(double latitude, double longitude, double zoom) { + super(latitude, longitude); this.zoom = zoom; } @@ -43,13 +44,21 @@ public void setZoom(double zoom) { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + if (!super.equals(o)) { + return false; + } LatLngZoom that = (LatLngZoom) o; - if (Double.compare(that.zoom, zoom) != 0) return false; + if (Double.compare(that.zoom, zoom) != 0) { + return false; + } return true; } diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/ProjectedMeters.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/ProjectedMeters.java new file mode 100644 index 00000000000..9bab088d128 --- /dev/null +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/ProjectedMeters.java @@ -0,0 +1,95 @@ +package com.mapbox.mapboxgl.lib.geometry; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.io.Serializable; + +public class ProjectedMeters implements IProjectedMeters, Parcelable, Serializable { + + public static final Creator CREATOR = new Creator() { + public ProjectedMeters createFromParcel(Parcel in) { + return new ProjectedMeters(in); + } + + public ProjectedMeters[] newArray(int size) { + return new ProjectedMeters[size]; + } + }; + + private double northing; + private double easting; + + public ProjectedMeters(double northing, double easting) { + this.northing = northing; + this.easting = easting; + } + + public ProjectedMeters(ProjectedMeters aProjectedMeters) { + this.northing = aProjectedMeters.northing; + this.easting = aProjectedMeters.easting; + } + + protected ProjectedMeters(Parcel in) { + northing = in.readDouble(); + easting = in.readDouble(); + } + + @Override + public double getNorthing() { + return northing; + } + + @Override + public double getEasting() { + return easting; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + ProjectedMeters projectedMeters = (ProjectedMeters) o; + + if (Double.compare(projectedMeters.easting, easting) != 0) { + return false; + } + if (Double.compare(projectedMeters.northing, northing) != 0) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result; + long temp; + temp = Double.doubleToLongBits(easting); + result = (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(northing); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + return result; + } + + @Override + public String toString() { + return "ProjectedMeters [northing=" + northing + ", easting=" + easting + "]"; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeDouble(northing); + out.writeDouble(easting); + } +} diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/app/MainActivity.java b/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/app/MainActivity.java index 831dd99ae22..bb8a6bacc6f 100644 --- a/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/app/MainActivity.java +++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/app/MainActivity.java @@ -15,7 +15,7 @@ import android.widget.Spinner; import android.widget.TextView; -import com.mapbox.mapboxgl.lib.LatLngZoom; +import com.mapbox.mapboxgl.lib.geometry.LatLngZoom; import com.mapbox.mapboxgl.lib.MapView; import com.mapzen.android.lost.LocationClient; import com.mapzen.android.lost.LocationListener; @@ -283,7 +283,7 @@ private class OutdoorClassSpinnerListener implements AdapterView.OnItemSelectedL @Override public void onItemSelected(AdapterView parent, View view, int position, long id) { - ArrayList classes = new ArrayList(1); + ArrayList classes = new ArrayList<>(1); switch(position) { // Day @@ -315,7 +315,7 @@ private class SatelliteClassSpinnerListener implements AdapterView.OnItemSelecte @Override public void onItemSelected(AdapterView parent, View view, int position, long id) { - ArrayList classes = new ArrayList(2); + ArrayList classes = new ArrayList<>(2); switch(position) { // Labels + Contours diff --git a/include/mbgl/android/jni.hpp b/include/mbgl/android/jni.hpp index aa2f1ab2fcf..721104897d9 100644 --- a/include/mbgl/android/jni.hpp +++ b/include/mbgl/android/jni.hpp @@ -39,6 +39,16 @@ extern jclass arrayListClass; extern jmethodID arrayListConstructorId; extern jmethodID arrayListAddId; +extern jclass projectedMetersClass; +extern jmethodID projectedMetersConstructorId; +extern jfieldID projectedMetersNorthingId; +extern jfieldID projectedMetersEastingId; + +extern jclass pointFClass; +extern jmethodID pointFConstructorId; +extern jfieldID pointFXId; +extern jfieldID pointFYId; + } } From 921309730b4e6cfbafb70d850b85f3010b5b265c Mon Sep 17 00:00:00 2001 From: Leith Bade Date: Mon, 16 Feb 2015 16:46:15 -0800 Subject: [PATCH 03/15] Rename packages. Add GPS arrow. --- .../src/main/AndroidManifest.xml | 2 +- .../{lib => }/constants/GeoConstants.java | 2 +- .../{lib => }/constants/MathConstants.java | 2 +- .../{lib => }/geometry/BoundingBox.java | 2 +- .../{lib => }/geometry/CoordinateRegion.java | 2 +- .../{lib => }/geometry/CoordinateSpan.java | 2 +- .../mapboxgl/{lib => }/geometry/ILatLng.java | 2 +- .../{lib => }/geometry/IProjectedMeters.java | 2 +- .../mapboxgl/{lib => }/geometry/LatLng.java | 6 +++--- .../mapboxgl/{lib => }/geometry/LatLngZoom.java | 2 +- .../{lib => }/geometry/ProjectedMeters.java | 2 +- .../mapbox/mapboxgl/{lib => views}/MapView.java | 10 +++++----- .../mapboxgl/{lib => views}/NativeMapView.java | 8 ++++---- .../java/MapboxGLAndroidSDKTestApp/build.gradle | 2 +- .../src/main/AndroidManifest.xml | 4 ++-- .../mapboxgl/{app => testapp}/MainActivity.java | 10 +++++----- .../mapboxgl/{app => testapp}/MapFragment.java | 4 ++-- .../main/res/drawable-hdpi/direction_arrow.png | Bin 0 -> 8095 bytes .../main/res/drawable-hdpi/location_marker.png | Bin 0 -> 4788 bytes .../main/res/drawable-ldpi/direction_arrow.png | Bin 0 -> 5291 bytes .../main/res/drawable-ldpi/location_marker.png | Bin 0 -> 4046 bytes .../main/res/drawable-mdpi/direction_arrow.png | Bin 0 -> 6191 bytes .../main/res/drawable-mdpi/location_marker.png | Bin 0 -> 4379 bytes .../main/res/drawable-xhdpi/direction_arrow.png | Bin 0 -> 10477 bytes .../main/res/drawable-xhdpi/location_marker.png | Bin 0 -> 5720 bytes .../res/drawable-xxhdpi/direction_arrow.png | Bin 0 -> 14812 bytes .../res/drawable-xxhdpi/location_marker.png | Bin 0 -> 7175 bytes .../res/drawable-xxxhdpi/direction_arrow.png | Bin 0 -> 20792 bytes .../res/drawable-xxxhdpi/location_marker.png | Bin 0 -> 8809 bytes .../src/main/res/layout/activity_main.xml | 2 +- .../src/main/res/layout/fragment_main.xml | 2 +- 31 files changed, 34 insertions(+), 34 deletions(-) rename android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/{lib => }/constants/GeoConstants.java (89%) rename android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/{lib => }/constants/MathConstants.java (82%) rename android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/{lib => }/geometry/BoundingBox.java (99%) rename android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/{lib => }/geometry/CoordinateRegion.java (93%) rename android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/{lib => }/geometry/CoordinateSpan.java (94%) rename android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/{lib => }/geometry/ILatLng.java (78%) rename android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/{lib => }/geometry/IProjectedMeters.java (68%) rename android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/{lib => }/geometry/LatLng.java (96%) rename android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/{lib => }/geometry/LatLngZoom.java (98%) rename android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/{lib => }/geometry/ProjectedMeters.java (98%) rename android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/{lib => views}/MapView.java (99%) rename android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/{lib => views}/NativeMapView.java (98%) rename android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/{app => testapp}/MainActivity.java (98%) rename android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/{app => testapp}/MapFragment.java (97%) create mode 100644 android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/direction_arrow.png create mode 100644 android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/location_marker.png create mode 100644 android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-ldpi/direction_arrow.png create mode 100644 android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-ldpi/location_marker.png create mode 100644 android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/direction_arrow.png create mode 100644 android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/location_marker.png create mode 100644 android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/direction_arrow.png create mode 100644 android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/location_marker.png create mode 100644 android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/direction_arrow.png create mode 100644 android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/location_marker.png create mode 100644 android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/direction_arrow.png create mode 100644 android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/location_marker.png diff --git a/android/java/MapboxGLAndroidSDK/src/main/AndroidManifest.xml b/android/java/MapboxGLAndroidSDK/src/main/AndroidManifest.xml index 7c7dac9a011..dea0f1e7632 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/AndroidManifest.xml +++ b/android/java/MapboxGLAndroidSDK/src/main/AndroidManifest.xml @@ -1,5 +1,5 @@ + package="com.mapbox.mapboxgl.views"> diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/constants/GeoConstants.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/constants/GeoConstants.java similarity index 89% rename from android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/constants/GeoConstants.java rename to android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/constants/GeoConstants.java index fff665b5a1e..4c899d2d8b5 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/constants/GeoConstants.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/constants/GeoConstants.java @@ -1,4 +1,4 @@ -package com.mapbox.mapboxgl.lib.constants; +package com.mapbox.mapboxgl.constants; public class GeoConstants { // http://en.wikipedia.org/wiki/Earth_radius#Equatorial_radius diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/constants/MathConstants.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/constants/MathConstants.java similarity index 82% rename from android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/constants/MathConstants.java rename to android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/constants/MathConstants.java index cd11523605a..71e235c9183 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/constants/MathConstants.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/constants/MathConstants.java @@ -1,4 +1,4 @@ -package com.mapbox.mapboxgl.lib.constants; +package com.mapbox.mapboxgl.constants; public class MathConstants { public static final double DEG2RAD = (Math.PI / 180.0); diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/BoundingBox.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/BoundingBox.java similarity index 99% rename from android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/BoundingBox.java rename to android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/BoundingBox.java index ba60701b82d..cb0409d3e9a 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/BoundingBox.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/BoundingBox.java @@ -1,4 +1,4 @@ -package com.mapbox.mapboxgl.lib.geometry; +package com.mapbox.mapboxgl.geometry; import android.os.Parcel; import android.os.Parcelable; diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/CoordinateRegion.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/CoordinateRegion.java similarity index 93% rename from android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/CoordinateRegion.java rename to android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/CoordinateRegion.java index b5c5f66ba88..c7f63e7902e 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/CoordinateRegion.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/CoordinateRegion.java @@ -1,4 +1,4 @@ -package com.mapbox.mapboxgl.lib.geometry; +package com.mapbox.mapboxgl.geometry; /** * Implementation of iOS MKCoordinateRegion diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/CoordinateSpan.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/CoordinateSpan.java similarity index 94% rename from android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/CoordinateSpan.java rename to android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/CoordinateSpan.java index b79fb7c42d0..b673f83f724 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/CoordinateSpan.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/CoordinateSpan.java @@ -1,4 +1,4 @@ -package com.mapbox.mapboxgl.lib.geometry; +package com.mapbox.mapboxgl.geometry; /** * Implementation of iOS MKCoordinateSpan diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/ILatLng.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/ILatLng.java similarity index 78% rename from android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/ILatLng.java rename to android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/ILatLng.java index c22a8ae3969..620676d83be 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/ILatLng.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/ILatLng.java @@ -1,4 +1,4 @@ -package com.mapbox.mapboxgl.lib.geometry; +package com.mapbox.mapboxgl.geometry; /** * A Latitude, Longitude point. diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/IProjectedMeters.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/IProjectedMeters.java similarity index 68% rename from android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/IProjectedMeters.java rename to android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/IProjectedMeters.java index 398f368b3f3..99f4fdec3ba 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/IProjectedMeters.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/IProjectedMeters.java @@ -1,4 +1,4 @@ -package com.mapbox.mapboxgl.lib.geometry; +package com.mapbox.mapboxgl.geometry; public interface IProjectedMeters { double getNorthing(); diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/LatLng.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/LatLng.java similarity index 96% rename from android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/LatLng.java rename to android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/LatLng.java index de97b575154..9b0991b0820 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/LatLng.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/LatLng.java @@ -1,11 +1,11 @@ -package com.mapbox.mapboxgl.lib.geometry; +package com.mapbox.mapboxgl.geometry; import android.location.Location; import android.os.Parcel; import android.os.Parcelable; -import com.mapbox.mapboxgl.lib.constants.GeoConstants; -import com.mapbox.mapboxgl.lib.constants.MathConstants; +import com.mapbox.mapboxgl.constants.GeoConstants; +import com.mapbox.mapboxgl.constants.MathConstants; import java.io.Serializable; diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/LatLngZoom.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/LatLngZoom.java similarity index 98% rename from android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/LatLngZoom.java rename to android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/LatLngZoom.java index bd8a214e2b5..f1d2862b24a 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/LatLngZoom.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/LatLngZoom.java @@ -1,4 +1,4 @@ -package com.mapbox.mapboxgl.lib.geometry; +package com.mapbox.mapboxgl.geometry; import android.os.Parcel; import android.os.Parcelable; diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/ProjectedMeters.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/ProjectedMeters.java similarity index 98% rename from android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/ProjectedMeters.java rename to android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/ProjectedMeters.java index 9bab088d128..d28d8688761 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/geometry/ProjectedMeters.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/geometry/ProjectedMeters.java @@ -1,4 +1,4 @@ -package com.mapbox.mapboxgl.lib.geometry; +package com.mapbox.mapboxgl.geometry; import android.os.Parcel; import android.os.Parcelable; diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/MapView.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/MapView.java similarity index 99% rename from android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/MapView.java rename to android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/MapView.java index b9545dc33ed..2fc3022236a 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/MapView.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/MapView.java @@ -1,4 +1,4 @@ -package com.mapbox.mapboxgl.lib; +package com.mapbox.mapboxgl.views; import android.annotation.TargetApi; import android.content.BroadcastReceiver; @@ -29,8 +29,8 @@ import com.almeros.android.multitouch.gesturedetectors.RotateGestureDetector; import com.almeros.android.multitouch.gesturedetectors.TwoFingerGestureDetector; -import com.mapbox.mapboxgl.lib.geometry.LatLng; -import com.mapbox.mapboxgl.lib.geometry.LatLngZoom; +import com.mapbox.mapboxgl.geometry.LatLng; +import com.mapbox.mapboxgl.geometry.LatLngZoom; import org.apache.commons.validator.routines.UrlValidator; @@ -777,7 +777,7 @@ public boolean onScale(ScaleGestureDetector detector) { } // TODO complex decision between rotate or scale or both (see Google - // Maps app) + // Maps testapp) // Cancel any animation mNativeMapView.cancelTransitions(); @@ -842,7 +842,7 @@ public boolean onRotate(RotateGestureDetector detector) { } // TODO complex decision between rotate or scale or both (see Google - // Maps app). It seems if you start one or the other it takes more + // Maps testapp). It seems if you start one or the other it takes more // to start the other too. Haven't figured out what it uses to // decide when to transition to both at the same time. diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/NativeMapView.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/NativeMapView.java similarity index 98% rename from android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/NativeMapView.java rename to android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/NativeMapView.java index 3059c0bfa47..96321d84321 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/lib/NativeMapView.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/NativeMapView.java @@ -1,11 +1,11 @@ -package com.mapbox.mapboxgl.lib; +package com.mapbox.mapboxgl.views; import android.graphics.PointF; import android.view.Surface; -import com.mapbox.mapboxgl.lib.geometry.LatLng; -import com.mapbox.mapboxgl.lib.geometry.LatLngZoom; -import com.mapbox.mapboxgl.lib.geometry.ProjectedMeters; +import com.mapbox.mapboxgl.geometry.LatLng; +import com.mapbox.mapboxgl.geometry.LatLngZoom; +import com.mapbox.mapboxgl.geometry.ProjectedMeters; import java.util.List; diff --git a/android/java/MapboxGLAndroidSDKTestApp/build.gradle b/android/java/MapboxGLAndroidSDKTestApp/build.gradle index 46c3a8d6321..2006dc1ff38 100644 --- a/android/java/MapboxGLAndroidSDKTestApp/build.gradle +++ b/android/java/MapboxGLAndroidSDKTestApp/build.gradle @@ -38,7 +38,7 @@ android { } defaultConfig { - applicationId "com.mapbox.mapboxgl.app" + applicationId "com.mapbox.mapboxgl.testapp" minSdkVersion 14 targetSdkVersion 21 versionCode 4 diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/android/java/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml index deee959d770..92c69783ab1 100644 --- a/android/java/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml +++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ + package="com.mapbox.mapboxgl.testapp"> @@ -12,7 +12,7 @@ android:theme="@style/AppTheme" android:supportsRtl="true"> diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/app/MainActivity.java b/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java similarity index 98% rename from android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/app/MainActivity.java rename to android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java index bb8a6bacc6f..5e33665197a 100644 --- a/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/app/MainActivity.java +++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java @@ -1,4 +1,4 @@ -package com.mapbox.mapboxgl.app; +package com.mapbox.mapboxgl.testapp; import android.location.Location; import android.os.Bundle; @@ -15,8 +15,8 @@ import android.widget.Spinner; import android.widget.TextView; -import com.mapbox.mapboxgl.lib.geometry.LatLngZoom; -import com.mapbox.mapboxgl.lib.MapView; +import com.mapbox.mapboxgl.geometry.LatLngZoom; +import com.mapbox.mapboxgl.views.MapView; import com.mapzen.android.lost.LocationClient; import com.mapzen.android.lost.LocationListener; import com.mapzen.android.lost.LocationRequest; @@ -125,7 +125,7 @@ public void onDisconnected() { }); } - // Called when our app goes into the background + // Called when our testapp goes into the background @Override public void onPause() { super.onPause(); @@ -137,7 +137,7 @@ public void onPause() { } } - // Called when our app comes into the foreground + // Called when our testapp comes into the foreground @Override public void onResume() { super.onResume(); diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/app/MapFragment.java b/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MapFragment.java similarity index 97% rename from android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/app/MapFragment.java rename to android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MapFragment.java index 0249dab293b..b78926b9e19 100644 --- a/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/app/MapFragment.java +++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MapFragment.java @@ -1,4 +1,4 @@ -package com.mapbox.mapboxgl.app; +package com.mapbox.mapboxgl.testapp; import android.os.Bundle; import android.support.v4.app.Fragment; @@ -7,7 +7,7 @@ import android.view.View; import android.view.ViewGroup; -import com.mapbox.mapboxgl.lib.MapView; +import com.mapbox.mapboxgl.views.MapView; import java.io.BufferedReader; import java.io.IOException; diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/direction_arrow.png b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/direction_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..379ac4fb160d57de4730851eb7c66e87d80be927 GIT binary patch literal 8095 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 F_+JE*DlY&4 literal 0 HcmV?d00001 diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/location_marker.png b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/location_marker.png new file mode 100644 index 0000000000000000000000000000000000000000..f3a57845b740230b0011f4ace9e13748b132533f GIT binary patch literal 4788 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 literal 0 HcmV?d00001 diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-ldpi/direction_arrow.png b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-ldpi/direction_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..292d2c5dfad4533cdfb10697c9907c1e007359e8 GIT binary patch literal 5291 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 O0cxu1sMIJ~NBj>qMZBv3 literal 0 HcmV?d00001 diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-ldpi/location_marker.png b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-ldpi/location_marker.png new file mode 100644 index 0000000000000000000000000000000000000000..94a78378178fb95943d0408fcf4028c1b686b1a5 GIT binary patch literal 4046 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 q_@w&&7d=iuZ literal 0 HcmV?d00001 diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/direction_arrow.png b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/direction_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..5227caf44b2970340259fcf840a8a8d7dba28611 GIT binary patch literal 10477 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 a^A0095FSw&TQ~pbxUM9pCR-(K67oL;griyj literal 0 HcmV?d00001 diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/direction_arrow.png b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/direction_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..760edd43904fe74725ee4e0e1ce236578d6b9bf9 GIT binary patch literal 14812 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 Xa$)_SQwe^=zCm8EJVOhW$$gwmIe literal 0 HcmV?d00001 diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/direction_arrow.png b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/direction_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..8e3c598195eda3ab970f0968c632124d450c8a33 GIT binary patch literal 20792 zcmZs?1z4Lw(=Lo_aCd2OcXyZK?(XjHgyOEn-Ju1FySqav?(XgfButPNuF$G zW_M=x+1;7B6RD&ig@k~Q00stzBqJ@Z0{UF~_kx1~z1QseF@k|1h**n>DanY5kt(@3 zT3FkegMmpS<)nG4sjgs0Om}j1&Y+W%QrzMDz?07LNn=4NN6G{#K>))jJ;b3UG0|u= z%+z|or6R~pB`^^~Lrj+8Z%~zndX>c`_Sa)<;V)}AZa1>thqX6X4x5)(EHC|++rX6G zLZJHGw7`Sd3$!pVPJ8vxF~$cTA#hQ_k+r~kwk<56q@Khf7T!7qGBeAihZ-I(7=z5( zSLwTzC|#F60~5))#J<9SAxJE8@&{1j>_eoeHVopienO4irP8nhSy-_P;0vqCcL(b1 z9?A~r+D9|eDfbHSwWshp*mGmrl{T^{wu@q*3iL84wk(VMV9h(#WU|2aAF1c(pR(n_ zm@zXACk`nK>>^nuF!3%TZy>g z8&sc7Sm;vvziof_lApe71jI4p1l2jFNq|#m+hIY!U~kz6*@_ zysBSQo=xY9#N=vk+MQK1bz*}(eAW3u)X@KmX*qhPfP%i z)2GeeA5lMddw8rTNBils^LlWu!;jRJk5b^nBCXoP`Gd6*7|jsE0vERfaXG1A@d9#e zF|FJU!TiH{lv-q9M;ryf#J)g&brAA_@ITc>WkDF}>aeOwtaFWL_4zn_AwkrOa@dv^ zAy++k0K}WQP!!VR6>Wyu^+KR0z`Erlum>|TL(m%`5eBh2L2i(Og#}5YLZ(47N<&x+ zL;VsF`~#YTEPuc~LT#MD7J_|dpcFzlonZ8!G<%So5CK6_!U(`#IcD&UU~9OLD^#pP zk;(+@Vw6nLB~$_(IBzi#C2mZ}L9xgL)Fk2O8Om~8+R(}ZF(rY!FK+m4aQdMy`LHvj z>@e@({$Xet5c9@Jf53hRt<>`o!b$awZ;5+hWy9k1tZvJ;U<)EQ_u*_4T!GPt8}=o` z36H=*⪻*5nPLlCTM*HMctgM^7FFwVfm9>Uv=(2m(Q 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

t`>@zvisl+!ig0WQu0m^^=2 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 literal 0 HcmV?d00001 diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/location_marker.png b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/location_marker.png new file mode 100644 index 0000000000000000000000000000000000000000..2318f1b7cc098173eda4e2ddde96711e4fec8b49 GIT binary patch literal 8809 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 literal 0 HcmV?d00001 diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_main.xml b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_main.xml index 5376ee2d24d..49eb6fdeab6 100644 --- a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_main.xml +++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_main.xml @@ -29,7 +29,7 @@ android:orientation="vertical"> - From 0bb1ef8c1508f64f3f7b25302c1df4396b7a42bc Mon Sep 17 00:00:00 2001 From: Leith Bade Date: Mon, 16 Feb 2015 18:40:36 -0800 Subject: [PATCH 04/15] Add GPS marker on map --- .../com/mapbox/mapboxgl/views/MapView.java | 16 +-- .../MapboxGLAndroidSDKTestApp/build.gradle | 2 +- .../mapbox/mapboxgl/testapp/MainActivity.java | 101 ++++++++++++------ .../src/main/res/layout/activity_main.xml | 13 +-- 4 files changed, 89 insertions(+), 43 deletions(-) diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/MapView.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/MapView.java index 2fc3022236a..3f4fb9e54b9 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/MapView.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/MapView.java @@ -351,10 +351,6 @@ public String getAccessToken() { return mNativeMapView.getAccessToken(); } - // - // Style methods - // - public List getClasses() { return mNativeMapView.getClasses(); } @@ -390,6 +386,14 @@ public void removeAllClasses(long transitionDuration) { setClasses(classes); } + public LatLng fromScreenLocation(PointF point) { + return mNativeMapView.latLngForPixel(point); + } + + public PointF toScreenLocation(LatLng location) { + return mNativeMapView.pixelForLatLng(location); + } + // // Lifecycle events // @@ -777,7 +781,7 @@ public boolean onScale(ScaleGestureDetector detector) { } // TODO complex decision between rotate or scale or both (see Google - // Maps testapp) + // Maps app) // Cancel any animation mNativeMapView.cancelTransitions(); @@ -842,7 +846,7 @@ public boolean onRotate(RotateGestureDetector detector) { } // TODO complex decision between rotate or scale or both (see Google - // Maps testapp). It seems if you start one or the other it takes more + // Maps app). It seems if you start one or the other it takes more // to start the other too. Haven't figured out what it uses to // decide when to transition to both at the same time. diff --git a/android/java/MapboxGLAndroidSDKTestApp/build.gradle b/android/java/MapboxGLAndroidSDKTestApp/build.gradle index 2006dc1ff38..a785c3b3035 100644 --- a/android/java/MapboxGLAndroidSDKTestApp/build.gradle +++ b/android/java/MapboxGLAndroidSDKTestApp/build.gradle @@ -77,7 +77,7 @@ dependencies { compile 'com.android.support:support-annotations:21.0.0' compile 'com.android.support:support-v4:21.0.3' compile 'com.android.support:appcompat-v7:21.0.3' - compile 'com.mapzen.android:lost:0.2' + compile 'com.mapzen.android:lost:1.0.0' } checkstyle { diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java b/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java index 5e33665197a..c3eca2fbdeb 100644 --- a/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java +++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java @@ -1,5 +1,6 @@ package com.mapbox.mapboxgl.testapp; +import android.graphics.PointF; import android.location.Location; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; @@ -11,15 +12,18 @@ import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; +import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.Spinner; import android.widget.TextView; +import com.mapbox.mapboxgl.geometry.LatLng; import com.mapbox.mapboxgl.geometry.LatLngZoom; import com.mapbox.mapboxgl.views.MapView; -import com.mapzen.android.lost.LocationClient; -import com.mapzen.android.lost.LocationListener; -import com.mapzen.android.lost.LocationRequest; +import com.mapzen.android.lost.api.LocationListener; +import com.mapzen.android.lost.api.LocationRequest; +import com.mapzen.android.lost.api.LocationServices; +import com.mapzen.android.lost.api.LostApiClient; import java.util.ArrayList; @@ -45,11 +49,18 @@ public class MainActivity extends ActionBarActivity { // The compass private ImageView mCompassView; + // The FrameLayout + private FrameLayout mMapFrameLayout; + // Used for GPS private boolean mIsGpsOn = false; - private LocationClient mLocationClient; + private LostApiClient mLocationClient; private LocationListener mLocationListener; private LocationRequest mLocationRequest; + private ImageView mGpsMarker; + private Location mGpsMarkerLocation; + private boolean mLockGpsCenter = true; + private boolean mLockGpsZoom = true; // Used for the class spinner Spinner mClassSpinner; @@ -78,6 +89,13 @@ protected void onCreate(Bundle savedInstanceState) { mCompassView = (ImageView) findViewById(R.id.view_compass); mCompassView.setOnClickListener(new CompassOnClickListener()); + mGpsMarker = new ImageView(getApplicationContext()); + mGpsMarker.setVisibility(View.INVISIBLE); + mGpsMarker.setImageResource(R.drawable.location_marker); + + mMapFrameLayout = (FrameLayout) findViewById(R.id.layout_map); + mMapFrameLayout.addView(mGpsMarker); + // Add a toolbar as the action bar Toolbar mainToolbar = (Toolbar) findViewById(R.id.toolbar_main); setSupportActionBar(mainToolbar); @@ -98,34 +116,25 @@ protected void onCreate(Bundle savedInstanceState) { R.array.satellite_class_list, android.R.layout.simple_spinner_dropdown_item); // Prepare for GPS + mLocationClient = new LostApiClient.Builder(this).build(); + mLocationRequest = LocationRequest.create(); mLocationRequest.setInterval(0); mLocationRequest.setSmallestDisplacement(0); - mLocationClient = new LocationClient(getApplicationContext(), new LocationClient.ConnectionCallbacks() { - @Override - public void onConnected(Bundle connectionHint) { - updateLocation(mLocationClient.getLastLocation()); - - mLocationListener = new LocationListener() { - @Override - public void onLocationChanged(Location location) { - //Toast.makeText(getApplicationContext(), "Location: " + location.toString(), Toast.LENGTH_SHORT).show(); - updateLocation(location); - } - }; - - mLocationClient.requestLocationUpdates(mLocationRequest, mLocationListener); - } + updateLocation(LocationServices.FusedLocationApi.getLastLocation()); + mLocationListener = new LocationListener() { @Override - public void onDisconnected() { - mLocationListener = null; + public void onLocationChanged(Location location) { + updateLocation(location); } - }); + }; + + LocationServices.FusedLocationApi.requestLocationUpdates(mLocationRequest, mLocationListener); } - // Called when our testapp goes into the background + // Called when our app goes into the background @Override public void onPause() { super.onPause(); @@ -137,7 +146,7 @@ public void onPause() { } } - // Called when our testapp comes into the foreground + // Called when our app comes into the foreground @Override public void onResume() { super.onResume(); @@ -172,11 +181,15 @@ public boolean onOptionsItemSelected(MenuItem item) { mIsGpsOn = false; item.setIcon(R.drawable.ic_action_location_searching); mLocationClient.disconnect(); + mGpsMarker.setVisibility(View.INVISIBLE); + mGpsMarkerLocation = null; } else { mIsGpsOn = true; item.setIcon(R.drawable.ic_action_location_found); mLocationClient.connect(); + mGpsMarker.setVisibility(View.VISIBLE); + mGpsMarkerLocation = null; } return true; @@ -201,9 +214,19 @@ public boolean onOptionsItemSelected(MenuItem item) { // Handles location updates from GPS private void updateLocation(Location location) { if (location != null) { - LatLngZoom coordinate = new LatLngZoom(location.getLatitude(), location.getLongitude(), 16); - mMapFragment.getMap().setCenterCoordinate(coordinate, true); + mGpsMarkerLocation = location; + LatLng coordinate = new LatLng(mGpsMarkerLocation); + LatLngZoom zoomedCoordinate = new LatLngZoom(coordinate, 16); + if (mLockGpsCenter) { + if (mLockGpsZoom) { + mMapFragment.getMap().setCenterCoordinate(zoomedCoordinate, true); + } else { + mMapFragment.getMap().setCenterCoordinate(coordinate, true); + } + } } + + updateMap(); } // This class handles style change events @@ -349,7 +372,7 @@ public void onNothingSelected(AdapterView parent) { } // Called when FPS changes - public class MyOnFpsChangedListener implements MapView.OnFpsChangedListener { + private class MyOnFpsChangedListener implements MapView.OnFpsChangedListener { @Override public void onFpsChanged(double fps) { @@ -357,17 +380,35 @@ public void onFpsChanged(double fps) { } } + private void updateMap() { + mCompassView.setRotation((float) mMapFragment.getMap().getDirection()); + + if (mGpsMarkerLocation != null) { + LatLng coordinate = new LatLng(mGpsMarkerLocation); + PointF screenLocation = mMapFragment.getMap().toScreenLocation(coordinate); + mGpsMarker.setPadding((int) screenLocation.x, (int) screenLocation.y, 0, 0); + + if (mGpsMarkerLocation.hasBearing()) { + mGpsMarker.setImageResource(R.drawable.direction_arrow); + mCompassView.setRotation(mGpsMarkerLocation.getBearing()); + } else { + mGpsMarker.setImageResource(R.drawable.location_marker); + mGpsMarker.setRotation(0.0f); + } + } + } + // Called when map state changes - public class MyOnMapChangedListener implements MapView.OnMapChangedListener { + private class MyOnMapChangedListener implements MapView.OnMapChangedListener { @Override public void onMapChanged() { - mCompassView.setRotation((float) mMapFragment.getMap().getDirection()); + updateMap(); } } // Called when someone presses the compass - public class CompassOnClickListener implements View.OnClickListener { + private class CompassOnClickListener implements View.OnClickListener { @Override public void onClick(View view) { diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_main.xml b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_main.xml index 49eb6fdeab6..7d646222b25 100644 --- a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_main.xml +++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_main.xml @@ -24,6 +24,7 @@ @@ -46,12 +47,12 @@ android:src="@drawable/compass"/> + android:id="@+id/view_fps" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceLarge" + android:text="@string/label_fps" + android:padding="10dp" /> From d661fc9eb2ebe970f0512d85d3654d8fda4ef5bc Mon Sep 17 00:00:00 2001 From: Leith Bade Date: Mon, 16 Feb 2015 20:07:57 -0800 Subject: [PATCH 05/15] Fixup LatLng class ref --- android/cpp/jni.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/android/cpp/jni.cpp b/android/cpp/jni.cpp index eca13c764fc..37c790a4261 100644 --- a/android/cpp/jni.cpp +++ b/android/cpp/jni.cpp @@ -850,7 +850,7 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { return JNI_ERR; } - latLngClass = env->FindClass("com/mapbox/mapboxgl/lib/geometry/LatLng"); + latLngClass = env->FindClass("com/mapbox/mapboxgl/geometry/LatLng"); if (latLngClass == nullptr) { env->ExceptionDescribe(); return JNI_ERR; @@ -874,7 +874,7 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { return JNI_ERR; } - latLngZoomClass = env->FindClass("com/mapbox/mapboxgl/lib/geometry/LatLngZoom"); + latLngZoomClass = env->FindClass("com/mapbox/mapboxgl/geometry/LatLngZoom"); if (latLngZoomClass == nullptr) { env->ExceptionDescribe(); return JNI_ERR; @@ -904,7 +904,7 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { return JNI_ERR; } - jclass nativeMapViewClass = env->FindClass("com/mapbox/mapboxgl/lib/NativeMapView"); + jclass nativeMapViewClass = env->FindClass("com/mapbox/mapboxgl/views/NativeMapView"); if (nativeMapViewClass == nullptr) { env->ExceptionDescribe(); return JNI_ERR; @@ -964,7 +964,7 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { return JNI_ERR; } - projectedMetersClass = env->FindClass("com/mapbox/mapboxgl/lib/geometry/ProjectedMeters"); + projectedMetersClass = env->FindClass("com/mapbox/mapboxgl/geometry/ProjectedMeters"); if (projectedMetersClass == nullptr) { env->ExceptionDescribe(); return JNI_ERR; @@ -1068,9 +1068,9 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { reinterpret_cast(&nativeGetAccessToken)}, {"nativeCancelTransitions", "(J)V", reinterpret_cast(&nativeCancelTransitions)}, {"nativeMoveBy", "(JDDJ)V", reinterpret_cast(&nativeMoveBy)}, - {"nativeSetLatLng", "(JLcom/mapbox/mapboxgl/lib/geometry/LatLng;J)V", + {"nativeSetLatLng", "(JLcom/mapbox/mapboxgl/geometry/LatLng;J)V", reinterpret_cast(&nativeSetLatLng)}, - {"nativeGetLatLng", "(J)Lcom/mapbox/mapboxgl/lib/geometry/LatLng;", + {"nativeGetLatLng", "(J)Lcom/mapbox/mapboxgl/geometry/LatLng;", reinterpret_cast(&nativeGetLatLng)}, {"nativeStartPanning", "(J)V", reinterpret_cast(&nativeStartPanning)}, {"nativeStopPanning", "(J)V", reinterpret_cast(&nativeStopPanning)}, @@ -1080,9 +1080,9 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { {"nativeGetScale", "(J)D", reinterpret_cast(&nativeGetScale)}, {"nativeSetZoom", "(JDJ)V", reinterpret_cast(&nativeSetZoom)}, {"nativeGetZoom", "(J)D", reinterpret_cast(&nativeGetZoom)}, - {"nativeSetLatLngZoom", "(JLcom/mapbox/mapboxgl/lib/geometry/LatLngZoom;J)V", + {"nativeSetLatLngZoom", "(JLcom/mapbox/mapboxgl/geometry/LatLngZoom;J)V", reinterpret_cast(&nativeSetLatLngZoom)}, - {"nativeGetLatLngZoom", "(J)Lcom/mapbox/mapboxgl/lib/geometry/LatLngZoom;", + {"nativeGetLatLngZoom", "(J)Lcom/mapbox/mapboxgl/geometry/LatLngZoom;", reinterpret_cast(&nativeGetLatLngZoom)}, {"nativeResetZoom", "(J)V", reinterpret_cast(&nativeResetZoom)}, {"nativeStartPanning", "(J)V", reinterpret_cast(&nativeStartScaling)}, @@ -1109,10 +1109,10 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { //{"nativeGetWorldBoundsMeters", "(J)V", reinterpret_cast(&nativeGetWorldBoundsMeters)}, //{"nativeGetWorldBoundsLatLng", "(J)V", reinterpret_cast(&nativeGetWorldBoundsLatLng)}, {"nativeGetMetersPerPixelAtLatitude", "(JDD)D", reinterpret_cast(&nativeGetMetersPerPixelAtLatitude)}, - {"nativeProjectedMetersForLatLng", "(JLcom/mapbox/mapboxgl/lib/geometry/LatLng;)Lcom/mapbox/mapboxgl/lib/geometry/ProjectedMeters;", reinterpret_cast(&nativeProjectedMetersForLatLng)}, - {"nativeLatLngForProjectedMeters", "(JLcom/mapbox/mapboxgl/lib/geometry/ProjectedMeters;)Lcom/mapbox/mapboxgl/lib/geometry/LatLng;", reinterpret_cast(&nativeLatLngForProjectedMeters)}, - {"nativePixelForLatLng", "(JLcom/mapbox/mapboxgl/lib/geometry/LatLng;)Landroid/graphics/PointF;", reinterpret_cast(&nativePixelForLatLng)}, - {"nativeLatLngForPixel", "(JLandroid/graphics/PointF;)Lcom/mapbox/mapboxgl/lib/geometry/LatLng;", reinterpret_cast(&nativeLatLngForPixel)}, + {"nativeProjectedMetersForLatLng", "(JLcom/mapbox/mapboxgl/geometry/LatLng;)Lcom/mapbox/mapboxgl/geometry/ProjectedMeters;", reinterpret_cast(&nativeProjectedMetersForLatLng)}, + {"nativeLatLngForProjectedMeters", "(JLcom/mapbox/mapboxgl/geometry/ProjectedMeters;)Lcom/mapbox/mapboxgl/geometry/LatLng;", reinterpret_cast(&nativeLatLngForProjectedMeters)}, + {"nativePixelForLatLng", "(JLcom/mapbox/mapboxgl/geometry/LatLng;)Landroid/graphics/PointF;", reinterpret_cast(&nativePixelForLatLng)}, + {"nativeLatLngForPixel", "(JLandroid/graphics/PointF;)Lcom/mapbox/mapboxgl/geometry/LatLng;", reinterpret_cast(&nativeLatLngForPixel)}, }}; if (env->RegisterNatives(nativeMapViewClass, methods.data(), methods.size()) < 0) { From bbd19e04fbf6b663c3088c74110630c4159d0b73 Mon Sep 17 00:00:00 2001 From: Leith Bade Date: Mon, 16 Feb 2015 20:15:02 -0800 Subject: [PATCH 06/15] Fix LOST loading --- .../java/com/mapbox/mapboxgl/testapp/MainActivity.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java b/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java index c3eca2fbdeb..18113ace488 100644 --- a/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java +++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java @@ -122,16 +122,12 @@ protected void onCreate(Bundle savedInstanceState) { mLocationRequest.setInterval(0); mLocationRequest.setSmallestDisplacement(0); - updateLocation(LocationServices.FusedLocationApi.getLastLocation()); - mLocationListener = new LocationListener() { @Override public void onLocationChanged(Location location) { updateLocation(location); } }; - - LocationServices.FusedLocationApi.requestLocationUpdates(mLocationRequest, mLocationListener); } // Called when our app goes into the background @@ -142,6 +138,7 @@ public void onPause() { // Cancel GPS if (mIsGpsOn) { + LocationServices.FusedLocationApi.removeLocationUpdates(mLocationListener); mLocationClient.disconnect(); } } @@ -156,6 +153,10 @@ public void onResume() { // Cancel any outstanding GPS if (mIsGpsOn) { mLocationClient.connect(); + + updateLocation(LocationServices.FusedLocationApi.getLastLocation()); + + LocationServices.FusedLocationApi.requestLocationUpdates(mLocationRequest, mLocationListener); } } From 1e1102898513f70275fbeeb1d6d57ad82fd11b16 Mon Sep 17 00:00:00 2001 From: Leith Bade Date: Mon, 16 Feb 2015 20:19:54 -0800 Subject: [PATCH 07/15] Fix min SDK version --- android/java/MapboxGLAndroidSDKTestApp/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/java/MapboxGLAndroidSDKTestApp/build.gradle b/android/java/MapboxGLAndroidSDKTestApp/build.gradle index a785c3b3035..6e17bc43c60 100644 --- a/android/java/MapboxGLAndroidSDKTestApp/build.gradle +++ b/android/java/MapboxGLAndroidSDKTestApp/build.gradle @@ -39,7 +39,7 @@ android { defaultConfig { applicationId "com.mapbox.mapboxgl.testapp" - minSdkVersion 14 + minSdkVersion 8 targetSdkVersion 21 versionCode 4 versionName "0.1.3" From f84c0381c720c43bab7c6f817bb662be5769540a Mon Sep 17 00:00:00 2001 From: Leith Bade Date: Wed, 18 Feb 2015 17:21:41 -0800 Subject: [PATCH 08/15] Fix GPS marker positioning. Disable map centre locking to GPS --- .../mapbox/mapboxgl/testapp/MainActivity.java | 70 +++++++++++++------ android/java/build.gradle | 1 - 2 files changed, 48 insertions(+), 23 deletions(-) diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java b/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java index 18113ace488..891535b2b41 100644 --- a/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java +++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java @@ -18,7 +18,7 @@ import android.widget.TextView; import com.mapbox.mapboxgl.geometry.LatLng; -import com.mapbox.mapboxgl.geometry.LatLngZoom; +//import com.mapbox.mapboxgl.geometry.LatLngZoom; import com.mapbox.mapboxgl.views.MapView; import com.mapzen.android.lost.api.LocationListener; import com.mapzen.android.lost.api.LocationRequest; @@ -59,8 +59,9 @@ public class MainActivity extends ActionBarActivity { private LocationRequest mLocationRequest; private ImageView mGpsMarker; private Location mGpsMarkerLocation; - private boolean mLockGpsCenter = true; - private boolean mLockGpsZoom = true; + //private boolean mLockGpsCenter = true; + //private boolean mLockGpsZoom = true; + private float mDensity; // Used for the class spinner Spinner mClassSpinner; @@ -77,6 +78,8 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.v(TAG, "onCreate"); + mDensity = getResources().getDisplayMetrics().density; + // Load the layout setContentView(R.layout.activity_main); mMapFragment = (MapFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_map); @@ -92,10 +95,11 @@ protected void onCreate(Bundle savedInstanceState) { mGpsMarker = new ImageView(getApplicationContext()); mGpsMarker.setVisibility(View.INVISIBLE); mGpsMarker.setImageResource(R.drawable.location_marker); + mGpsMarker.setLayoutParams(new FrameLayout.LayoutParams((int) (27.0f * mDensity), (int) (27.0f * mDensity))); + mGpsMarker.requestLayout(); mMapFrameLayout = (FrameLayout) findViewById(R.id.layout_map); mMapFrameLayout.addView(mGpsMarker); - // Add a toolbar as the action bar Toolbar mainToolbar = (Toolbar) findViewById(R.id.toolbar_main); setSupportActionBar(mainToolbar); @@ -118,9 +122,10 @@ protected void onCreate(Bundle savedInstanceState) { // Prepare for GPS mLocationClient = new LostApiClient.Builder(this).build(); - mLocationRequest = LocationRequest.create(); - mLocationRequest.setInterval(0); - mLocationRequest.setSmallestDisplacement(0); + mLocationRequest = LocationRequest.create() + .setInterval(1000) + .setSmallestDisplacement(1) + .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); mLocationListener = new LocationListener() { @Override @@ -138,8 +143,7 @@ public void onPause() { // Cancel GPS if (mIsGpsOn) { - LocationServices.FusedLocationApi.removeLocationUpdates(mLocationListener); - mLocationClient.disconnect(); + stopGps(); } } @@ -152,11 +156,7 @@ public void onResume() { // Restart GPS // Cancel any outstanding GPS if (mIsGpsOn) { - mLocationClient.connect(); - - updateLocation(LocationServices.FusedLocationApi.getLastLocation()); - - LocationServices.FusedLocationApi.requestLocationUpdates(mLocationRequest, mLocationListener); + startGps(); } } @@ -179,19 +179,20 @@ public boolean onOptionsItemSelected(MenuItem item) { case R.id.action_gps: // Toggle GPS position updates if (mIsGpsOn) { + // Turn off mIsGpsOn = false; item.setIcon(R.drawable.ic_action_location_searching); - mLocationClient.disconnect(); - mGpsMarker.setVisibility(View.INVISIBLE); + stopGps(); mGpsMarkerLocation = null; } else { + // Turn on mIsGpsOn = true; item.setIcon(R.drawable.ic_action_location_found); - mLocationClient.connect(); - mGpsMarker.setVisibility(View.VISIBLE); mGpsMarkerLocation = null; + startGps(); } + updateMap(); return true; case R.id.action_debug: @@ -212,11 +213,24 @@ public boolean onOptionsItemSelected(MenuItem item) { } } + // Turns the GPS location updates on + private void startGps() { + mLocationClient.connect(); + updateLocation(LocationServices.FusedLocationApi.getLastLocation()); + LocationServices.FusedLocationApi.requestLocationUpdates(mLocationRequest, mLocationListener); + } + + // Turns the GPS location updates off + private void stopGps() { + LocationServices.FusedLocationApi.removeLocationUpdates(mLocationListener); + mLocationClient.disconnect(); + } + // Handles location updates from GPS private void updateLocation(Location location) { if (location != null) { mGpsMarkerLocation = location; - LatLng coordinate = new LatLng(mGpsMarkerLocation); + /*LatLng coordinate = new LatLng(mGpsMarkerLocation); LatLngZoom zoomedCoordinate = new LatLngZoom(coordinate, 16); if (mLockGpsCenter) { if (mLockGpsZoom) { @@ -224,7 +238,7 @@ private void updateLocation(Location location) { } else { mMapFragment.getMap().setCenterCoordinate(coordinate, true); } - } + }*/ } updateMap(); @@ -385,17 +399,29 @@ private void updateMap() { mCompassView.setRotation((float) mMapFragment.getMap().getDirection()); if (mGpsMarkerLocation != null) { + mGpsMarker.setVisibility(View.VISIBLE); LatLng coordinate = new LatLng(mGpsMarkerLocation); PointF screenLocation = mMapFragment.getMap().toScreenLocation(coordinate); - mGpsMarker.setPadding((int) screenLocation.x, (int) screenLocation.y, 0, 0); if (mGpsMarkerLocation.hasBearing()) { mGpsMarker.setImageResource(R.drawable.direction_arrow); - mCompassView.setRotation(mGpsMarkerLocation.getBearing()); + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams((int) (54.0f * mDensity), (int) (54.0f * mDensity)); + lp.leftMargin = (int) ((screenLocation.x - 54.0f / 2.0f) * mDensity); + lp.topMargin = mMapFrameLayout.getHeight() - (int) ((screenLocation.y + 54.0f / 2.0f) * mDensity); + mGpsMarker.setLayoutParams(lp); + mGpsMarker.setRotation(mGpsMarkerLocation.getBearing()); + mGpsMarker.requestLayout(); } else { mGpsMarker.setImageResource(R.drawable.location_marker); + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams((int) (27.0f * mDensity), (int) (27.0f * mDensity)); + lp.leftMargin = (int) ((screenLocation.x - 27.0f / 2.0f) * mDensity); + lp.topMargin = mMapFrameLayout.getHeight() - (int) ((screenLocation.y + 27.0f / 2.0f) * mDensity); + mGpsMarker.setLayoutParams(lp); mGpsMarker.setRotation(0.0f); + mGpsMarker.requestLayout(); } + } else { + mGpsMarker.setVisibility(View.INVISIBLE); } } diff --git a/android/java/build.gradle b/android/java/build.gradle index e51332720c4..9090070982c 100644 --- a/android/java/build.gradle +++ b/android/java/build.gradle @@ -2,4 +2,3 @@ task wrapper(type: Wrapper) { gradleVersion = '2.2.1' } - From fd45302b80f7304d655117bf83a74cd6dca32768 Mon Sep 17 00:00:00 2001 From: Leith Bade Date: Thu, 19 Feb 2015 15:55:07 -0800 Subject: [PATCH 09/15] Add compass support --- .../mapbox/mapboxgl/testapp/MainActivity.java | 129 +++++++++++++----- styles | 2 +- 2 files changed, 99 insertions(+), 32 deletions(-) diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java b/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java index 891535b2b41..ee018085943 100644 --- a/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java +++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java @@ -1,6 +1,12 @@ package com.mapbox.mapboxgl.testapp; +import android.content.Context; import android.graphics.PointF; +import android.hardware.GeomagneticField; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; import android.location.Location; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; @@ -40,33 +46,38 @@ public class MainActivity extends ActionBarActivity { // Instance members // - // Holds the MapFragment + // Used for the UI private MapFragment mMapFragment; - - // The FPS label private TextView mFpsTextView; - - // The compass private ImageView mCompassView; - - // The FrameLayout private FrameLayout mMapFrameLayout; + private float mDensity; + Spinner mClassSpinner; + ArrayAdapter mOutdoorsClassAdapter; + ArrayAdapter mSatelliteClassAdapter; // Used for GPS private boolean mIsGpsOn = false; private LostApiClient mLocationClient; - private LocationListener mLocationListener; + private GpsListener mGpsListener; private LocationRequest mLocationRequest; private ImageView mGpsMarker; - private Location mGpsMarkerLocation; + private Location mGpsLocation; //private boolean mLockGpsCenter = true; //private boolean mLockGpsZoom = true; - private float mDensity; - // Used for the class spinner - Spinner mClassSpinner; - ArrayAdapter mOutdoorsClassAdapter; - ArrayAdapter mSatelliteClassAdapter; + // Used for compass + private SensorManager mSensorManager; + private Sensor mSensorAccelerometer; + private Sensor mSensorMagneticField; + private CompassListener mCompassListener; + private float[] mValuesAccelerometer = new float[3]; + private float[] mValuesMagneticField = new float[3]; + private float[] mMatrixR = new float[9]; + private float[] mMatrixI = new float[9]; + private float[] mMatrixValues = new float[3]; + private float mCompassBearing; + private boolean mCompassValid = false; // // Lifecycle events @@ -121,18 +132,16 @@ protected void onCreate(Bundle savedInstanceState) { // Prepare for GPS mLocationClient = new LostApiClient.Builder(this).build(); - mLocationRequest = LocationRequest.create() .setInterval(1000) .setSmallestDisplacement(1) .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); + mGpsListener = new GpsListener(); - mLocationListener = new LocationListener() { - @Override - public void onLocationChanged(Location location) { - updateLocation(location); - } - }; + mSensorManager = (SensorManager) getApplicationContext().getSystemService(Context.SENSOR_SERVICE); + mSensorAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); + mSensorMagneticField = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); + mCompassListener = new CompassListener(); } // Called when our app goes into the background @@ -178,18 +187,19 @@ public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_gps: // Toggle GPS position updates + // TODO: how to persist this if (mIsGpsOn) { // Turn off mIsGpsOn = false; item.setIcon(R.drawable.ic_action_location_searching); stopGps(); - mGpsMarkerLocation = null; + mGpsLocation = null; } else { // Turn on mIsGpsOn = true; item.setIcon(R.drawable.ic_action_location_found); - mGpsMarkerLocation = null; + mGpsLocation = null; startGps(); } updateMap(); @@ -217,20 +227,76 @@ public boolean onOptionsItemSelected(MenuItem item) { private void startGps() { mLocationClient.connect(); updateLocation(LocationServices.FusedLocationApi.getLastLocation()); - LocationServices.FusedLocationApi.requestLocationUpdates(mLocationRequest, mLocationListener); + LocationServices.FusedLocationApi.requestLocationUpdates(mLocationRequest, new GpsListener()); + mSensorManager.registerListener(mCompassListener, mSensorAccelerometer, SensorManager.SENSOR_DELAY_UI); + mSensorManager.registerListener(mCompassListener, mSensorMagneticField, SensorManager.SENSOR_DELAY_UI); } // Turns the GPS location updates off private void stopGps() { - LocationServices.FusedLocationApi.removeLocationUpdates(mLocationListener); + LocationServices.FusedLocationApi.removeLocationUpdates(mGpsListener); mLocationClient.disconnect(); + mSensorManager.unregisterListener(mCompassListener, mSensorAccelerometer); + mSensorManager.unregisterListener(mCompassListener, mSensorMagneticField); + } + + // This class forwards location updates to updateLocation() + private class GpsListener implements LocationListener { + + @Override + public void onLocationChanged(Location location) { + updateLocation(location); + } + } + + // This class handles sensor updates to calculate compass bearing + private class CompassListener implements SensorEventListener { + + @Override + public void onSensorChanged(SensorEvent event) { + switch (event.sensor.getType()) { + case Sensor.TYPE_ACCELEROMETER: + System.arraycopy(event.values, 0, mValuesAccelerometer, 0, 3); + break; + case Sensor.TYPE_MAGNETIC_FIELD: + System.arraycopy(event.values, 0, mValuesMagneticField, 0, 3); + break; + } + + boolean valid = SensorManager.getRotationMatrix(mMatrixR, mMatrixI, + mValuesAccelerometer, + mValuesMagneticField); + + if (valid) { + SensorManager.getOrientation(mMatrixR, mMatrixValues); + //mAzimuthRadians.putValue(mMatrixValues[0]); + //mAzimuth = Math.toDegrees(mAzimuthRadians.getAverage()); + + if (mGpsLocation != null) { + GeomagneticField geomagneticField = new GeomagneticField( + (float) mGpsLocation.getLatitude(), + (float) mGpsLocation.getLongitude(), + (float) mGpsLocation.getAltitude(), + System.currentTimeMillis()); + mCompassBearing = (float) Math.toDegrees(mMatrixValues[0]) + geomagneticField.getDeclination(); + mCompassValid = true; + } + } + + updateMap(); + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + // TODO: ignore unreliable stuff + } } // Handles location updates from GPS private void updateLocation(Location location) { if (location != null) { - mGpsMarkerLocation = location; - /*LatLng coordinate = new LatLng(mGpsMarkerLocation); + mGpsLocation = location; + /*LatLng coordinate = new LatLng(mGpsLocation); LatLngZoom zoomedCoordinate = new LatLngZoom(coordinate, 16); if (mLockGpsCenter) { if (mLockGpsZoom) { @@ -398,18 +464,19 @@ public void onFpsChanged(double fps) { private void updateMap() { mCompassView.setRotation((float) mMapFragment.getMap().getDirection()); - if (mGpsMarkerLocation != null) { + if (mGpsLocation != null) { mGpsMarker.setVisibility(View.VISIBLE); - LatLng coordinate = new LatLng(mGpsMarkerLocation); + LatLng coordinate = new LatLng(mGpsLocation); PointF screenLocation = mMapFragment.getMap().toScreenLocation(coordinate); - if (mGpsMarkerLocation.hasBearing()) { + if (mGpsLocation.hasBearing() || mCompassValid) { mGpsMarker.setImageResource(R.drawable.direction_arrow); FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams((int) (54.0f * mDensity), (int) (54.0f * mDensity)); lp.leftMargin = (int) ((screenLocation.x - 54.0f / 2.0f) * mDensity); lp.topMargin = mMapFrameLayout.getHeight() - (int) ((screenLocation.y + 54.0f / 2.0f) * mDensity); mGpsMarker.setLayoutParams(lp); - mGpsMarker.setRotation(mGpsMarkerLocation.getBearing()); + float bearing = mGpsLocation.hasBearing() ? mGpsLocation.getBearing() : mCompassBearing; + mGpsMarker.setRotation(bearing); mGpsMarker.requestLayout(); } else { mGpsMarker.setImageResource(R.drawable.location_marker); diff --git a/styles b/styles index c1303933798..25b1b7dff37 160000 --- a/styles +++ b/styles @@ -1 +1 @@ -Subproject commit c1303933798e1bb48649d8a64b71038b4d3ed0a4 +Subproject commit 25b1b7dff37a18151e3286144bc8013b432a8860 From 8cffa9d078a9685782d49ce5c3edeb6606201d01 Mon Sep 17 00:00:00 2001 From: Leith Bade Date: Mon, 23 Feb 2015 12:05:18 -0800 Subject: [PATCH 10/15] Save GPS on/off state --- .../mapbox/mapboxgl/testapp/MainActivity.java | 47 +++++++++++++++---- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java b/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java index ee018085943..7c0032bfa61 100644 --- a/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java +++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java @@ -42,6 +42,9 @@ public class MainActivity extends ActionBarActivity { // Tag used for logging private static final String TAG = "MainActivity"; + // Used for saving instance state + private static final String STATE_IS_GPS_ON = "isGpsOn"; + // // Instance members // @@ -52,9 +55,9 @@ public class MainActivity extends ActionBarActivity { private ImageView mCompassView; private FrameLayout mMapFrameLayout; private float mDensity; - Spinner mClassSpinner; - ArrayAdapter mOutdoorsClassAdapter; - ArrayAdapter mSatelliteClassAdapter; + private Spinner mClassSpinner; + private ArrayAdapter mOutdoorsClassAdapter; + private ArrayAdapter mSatelliteClassAdapter; // Used for GPS private boolean mIsGpsOn = false; @@ -63,6 +66,7 @@ public class MainActivity extends ActionBarActivity { private LocationRequest mLocationRequest; private ImageView mGpsMarker; private Location mGpsLocation; + private MenuItem mGpsMenuItem; //private boolean mLockGpsCenter = true; //private boolean mLockGpsZoom = true; @@ -89,6 +93,10 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.v(TAG, "onCreate"); + if (savedInstanceState != null) { + mIsGpsOn = savedInstanceState.getBoolean(STATE_IS_GPS_ON, false); + } + mDensity = getResources().getDisplayMetrics().density; // Load the layout @@ -169,6 +177,16 @@ public void onResume() { } } + // Called when we need to save instance state + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + Log.v(TAG, "onSaveInstanceState"); + + outState.putBoolean(STATE_IS_GPS_ON, mIsGpsOn); + } + + // // Other events // @@ -178,6 +196,12 @@ public void onResume() { public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu_main, menu); + mGpsMenuItem = menu.findItem(R.id.action_gps); + if (mIsGpsOn) { + mGpsMenuItem.setIcon(R.drawable.ic_action_location_found); + } else { + mGpsMenuItem.setIcon(R.drawable.ic_action_location_searching); + } return super.onCreateOptionsMenu(menu); } @@ -190,17 +214,12 @@ public boolean onOptionsItemSelected(MenuItem item) { // TODO: how to persist this if (mIsGpsOn) { // Turn off - mIsGpsOn = false; - item.setIcon(R.drawable.ic_action_location_searching); stopGps(); - mGpsLocation = null; - + mIsGpsOn = false; } else { // Turn on - mIsGpsOn = true; - item.setIcon(R.drawable.ic_action_location_found); - mGpsLocation = null; startGps(); + mIsGpsOn = true; } updateMap(); return true; @@ -225,6 +244,10 @@ public boolean onOptionsItemSelected(MenuItem item) { // Turns the GPS location updates on private void startGps() { + if (mGpsMenuItem != null) { + mGpsMenuItem.setIcon(R.drawable.ic_action_location_found); + } + mGpsLocation = null; mLocationClient.connect(); updateLocation(LocationServices.FusedLocationApi.getLastLocation()); LocationServices.FusedLocationApi.requestLocationUpdates(mLocationRequest, new GpsListener()); @@ -234,10 +257,14 @@ private void startGps() { // Turns the GPS location updates off private void stopGps() { + if (mGpsMenuItem != null) { + mGpsMenuItem.setIcon(R.drawable.ic_action_location_searching); + } LocationServices.FusedLocationApi.removeLocationUpdates(mGpsListener); mLocationClient.disconnect(); mSensorManager.unregisterListener(mCompassListener, mSensorAccelerometer); mSensorManager.unregisterListener(mCompassListener, mSensorMagneticField); + mGpsLocation = null; } // This class forwards location updates to updateLocation() From cd7dceeaaaa4e6d647b7a35ab649285f05753c22 Mon Sep 17 00:00:00 2001 From: Leith Bade Date: Tue, 24 Feb 2015 16:30:03 -0800 Subject: [PATCH 11/15] Work on javadoc warnings --- android/java/MapboxGLAndroidSDK/build.gradle | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/android/java/MapboxGLAndroidSDK/build.gradle b/android/java/MapboxGLAndroidSDK/build.gradle index 950ce19a0c6..37282659f29 100644 --- a/android/java/MapboxGLAndroidSDK/build.gradle +++ b/android/java/MapboxGLAndroidSDK/build.gradle @@ -82,8 +82,7 @@ android.libraryVariants.all { variant -> failOnError = false destinationDir = new File(destinationDir, variant.baseName) source = files(variant.javaCompile.source) - ext.androidJar = "${android.sdkDirectory}/platforms/${android.compileSdkVersion}/android.jar" - classpath = files(variant.javaCompile.classpath.files) + files(ext.androidJar) + classpath = files(variant.javaCompile.classpath.files) + files(android.bootClasspath) options.links("http://docs.oracle.com/javase/7/docs/api/") options.links("http://d.android.com/reference/") exclude '**/R.html', '**/R.*.html' @@ -235,7 +234,7 @@ afterEvaluate { project -> task androidJavadocs(type: Javadoc) { failOnError false source = android.sourceSets.main.java.sourceFiles - classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) + classpath = files(android.bootClasspath) } task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) { From 195fad1b673bad2efbeb212cff1d82cca5313dd1 Mon Sep 17 00:00:00 2001 From: Leith Bade Date: Wed, 25 Feb 2015 15:51:23 -0800 Subject: [PATCH 12/15] Replace constant --- .../src/main/java/com/mapbox/mapboxgl/views/MapView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/MapView.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/MapView.java index dca9bff10d0..f865f9144a8 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/MapView.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/MapView.java @@ -569,7 +569,7 @@ private void zoom(boolean zoomIn, float x, float y) { @Override @TargetApi(14) public boolean onTouchEvent(@NonNull MotionEvent event) { // Check and ignore non touch or left clicks - if ((android.os.Build.VERSION.SDK_INT >= 14) && (event.getButtonState() != 0) && (event.getButtonState() != MotionEvent.BUTTON_PRIMARY)) { + if ((android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) && (event.getButtonState() != 0) && (event.getButtonState() != MotionEvent.BUTTON_PRIMARY)) { return false; } From d0109fb834f15127fc12c95c17e5dd089eb90d0c Mon Sep 17 00:00:00 2001 From: Leith Bade Date: Thu, 26 Feb 2015 10:21:49 -0800 Subject: [PATCH 13/15] Ignore lint error from OkHTTP Fixes #921 --- android/java/MapboxGLAndroidSDK/lint.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/android/java/MapboxGLAndroidSDK/lint.xml b/android/java/MapboxGLAndroidSDK/lint.xml index 309f4e478b1..3a244199a77 100644 --- a/android/java/MapboxGLAndroidSDK/lint.xml +++ b/android/java/MapboxGLAndroidSDK/lint.xml @@ -1,3 +1,7 @@ + + + + From a5430e8730897924ab484b406a70eaf7bc89bd2f Mon Sep 17 00:00:00 2001 From: Leith Bade Date: Thu, 26 Feb 2015 11:16:14 -0800 Subject: [PATCH 14/15] Replace setRotation with Matrix --- .../mapbox/mapboxgl/testapp/MainActivity.java | 17 ++++++++++++++--- .../src/main/res/layout/activity_main.xml | 4 ++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java b/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java index 49707604143..bd7100d98d8 100644 --- a/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java +++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java @@ -1,6 +1,7 @@ package com.mapbox.mapboxgl.testapp; import android.content.Context; +import android.graphics.Matrix; import android.graphics.PointF; import android.hardware.GeomagneticField; import android.hardware.Sensor; @@ -462,8 +463,18 @@ public void onFpsChanged(double fps) { } } + // Rotates an ImageView - does not work if the ImageView has padding, use margins + private void rotateImageView(ImageView imageView, float angle) { + Matrix matrix = new Matrix(); + matrix.setScale((float) imageView.getWidth() / (float) imageView.getDrawable().getIntrinsicWidth(), (float) imageView.getHeight() / (float) imageView.getDrawable().getIntrinsicHeight()); + matrix.postRotate(angle, (float) imageView.getWidth() / 2.0f, (float) imageView.getHeight() / 2.0f); + imageView.setImageMatrix(matrix); + imageView.setScaleType(ImageView.ScaleType.MATRIX); + } + + // Updates the UI to match the current map's position private void updateMap() { - mCompassView.setRotation((float) mMapFragment.getMap().getDirection()); + rotateImageView(mCompassView, (float) mMapFragment.getMap().getDirection()); if (mGpsLocation != null) { mGpsMarker.setVisibility(View.VISIBLE); @@ -477,7 +488,7 @@ private void updateMap() { lp.topMargin = mMapFrameLayout.getHeight() - (int) ((screenLocation.y + 54.0f / 2.0f) * mDensity); mGpsMarker.setLayoutParams(lp); float bearing = mGpsLocation.hasBearing() ? mGpsLocation.getBearing() : mCompassBearing; - mGpsMarker.setRotation(bearing); + rotateImageView(mGpsMarker, bearing); mGpsMarker.requestLayout(); } else { mGpsMarker.setImageResource(R.drawable.location_marker); @@ -485,7 +496,7 @@ private void updateMap() { lp.leftMargin = (int) ((screenLocation.x - 27.0f / 2.0f) * mDensity); lp.topMargin = mMapFrameLayout.getHeight() - (int) ((screenLocation.y + 27.0f / 2.0f) * mDensity); mGpsMarker.setLayoutParams(lp); - mGpsMarker.setRotation(0.0f); + rotateImageView(mGpsMarker, 0.0f); mGpsMarker.requestLayout(); } } else { diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_main.xml b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_main.xml index 7d646222b25..6a9bf8266a7 100644 --- a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_main.xml +++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_main.xml @@ -42,7 +42,7 @@ android:layout_width="48dp" android:layout_height="48dp" android:layout_gravity="end|top" - android:padding="10dp" + android:layout_margin="10dp" android:contentDescription="@string/compass_desc" android:src="@drawable/compass"/> @@ -52,7 +52,7 @@ android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceLarge" android:text="@string/label_fps" - android:padding="10dp" /> + android:layout_margin="10dp" /> From aa32b41b59a88fa41cec4cd7f4db775af9bec5e5 Mon Sep 17 00:00:00 2001 From: Leith Bade Date: Thu, 26 Feb 2015 11:32:35 -0800 Subject: [PATCH 15/15] Fix all lint errors --- android/java/MapboxGLAndroidSDK/build.gradle | 2 +- android/java/MapboxGLAndroidSDKTestApp/build.gradle | 6 +++--- .../MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml | 3 ++- .../src/main/res/layout/fragment_main.xml | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/android/java/MapboxGLAndroidSDK/build.gradle b/android/java/MapboxGLAndroidSDK/build.gradle index 40287c95365..192bc2bd7a3 100644 --- a/android/java/MapboxGLAndroidSDK/build.gradle +++ b/android/java/MapboxGLAndroidSDK/build.gradle @@ -55,7 +55,7 @@ android { lintOptions { checkAllWarnings true warningsAsErrors true - disable 'IconMissingDensityFolder' + disable 'InvalidPackage' } buildTypes { diff --git a/android/java/MapboxGLAndroidSDKTestApp/build.gradle b/android/java/MapboxGLAndroidSDKTestApp/build.gradle index 08b78df6b6d..1aac4988701 100644 --- a/android/java/MapboxGLAndroidSDKTestApp/build.gradle +++ b/android/java/MapboxGLAndroidSDKTestApp/build.gradle @@ -57,9 +57,9 @@ android { lintOptions { checkAllWarnings true - disable 'UnusedAttribute' - abortOnError false - //disable 'IconDensities' + warningsAsErrors true + disable 'IconDensities' + disable 'InvalidPackage' } buildTypes { diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/android/java/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml index 92c69783ab1..901a63f5720 100644 --- a/android/java/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml +++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml @@ -1,5 +1,5 @@ - @@ -10,6 +10,7 @@ android:icon="@drawable/icon_burned" android:label="@string/app_name" android:theme="@style/AppTheme" + tools:ignore="UnusedAttribute" android:supportsRtl="true"> -