summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManabu-GT <manabu1984+github@gmail.com>2015-10-05 02:57:26 +0900
committerManabu Shimobe <manabu1984+github@gmail.com>2015-10-22 19:58:52 +0900
commit84c8d1fd6ec55bf4cd43cba0ca8fc26d77061196 (patch)
treeb5cc788216cb89847dbd68e2d4730f2344373ff1
parent927b4c6dbe6c81aa4df0f662044ec3c9e55a8458 (diff)
downloadqtlocation-mapboxgl-84c8d1fd6ec55bf4cd43cba0ca8fc26d77061196.tar.gz
add setSetVisibleCoordinateBounds api as already in iOS
-rw-r--r--android/cpp/jni.cpp141
-rw-r--r--android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/CoordinateBounds.java31
-rw-r--r--android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java37
-rw-r--r--android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/NativeMapView.java27
-rw-r--r--android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MainActivity.java22
-rw-r--r--android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_action_crop.pngbin0 -> 602 bytes
-rw-r--r--android/java/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_drawer.xml12
-rw-r--r--android/java/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml1
-rw-r--r--include/mbgl/android/jni.hpp7
9 files changed, 257 insertions, 21 deletions
diff --git a/android/cpp/jni.cpp b/android/cpp/jni.cpp
index 94de069215..36c4fe1ddc 100644
--- a/android/cpp/jni.cpp
+++ b/android/cpp/jni.cpp
@@ -16,6 +16,7 @@
#include <mbgl/android/jni.hpp>
#include <mbgl/android/native_map_view.hpp>
#include <mbgl/map/map.hpp>
+#include <mbgl/map/camera.hpp>
#include <mbgl/annotation/point_annotation.hpp>
#include <mbgl/annotation/shape_annotation.hpp>
#include <mbgl/annotation/sprite_image.hpp>
@@ -95,6 +96,13 @@ jmethodID pointFConstructorId = nullptr;
jfieldID pointFXId = nullptr;
jfieldID pointFYId = nullptr;
+jclass rectFClass = nullptr;
+jmethodID rectFConstructorId = nullptr;
+jfieldID rectFLeftId = nullptr;
+jfieldID rectFTopId = nullptr;
+jfieldID rectFRightId = nullptr;
+jfieldID rectFBottomId = nullptr;
+
jclass httpContextClass = nullptr;
jmethodID httpContextGetInstanceId = nullptr;
jmethodID httpContextCreateRequestId = nullptr;
@@ -1124,6 +1132,72 @@ void JNICALL nativeSetSprite(JNIEnv *env, jobject obj, jlong nativeMapViewPtr,
nativeMapView->getMap().setSprite(symbolName, spriteImage);
}
+void JNICALL nativeSetVisibleCoordinateBounds(JNIEnv *env, jobject obj, jlong nativeMapViewPtr,
+ jobjectArray coordinates, jobject padding, jdouble direction, jlong duration) {
+ mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetVisibleCoordinateBounds");
+ assert(nativeMapViewPtr != 0);
+ NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
+
+ jfloat left = env->GetFloatField(padding, rectFLeftId);
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ return;
+ }
+
+ jfloat right = env->GetFloatField(padding, rectFRightId);
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ return;
+ }
+
+ jfloat top = env->GetFloatField(padding, rectFTopId);
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ return;
+ }
+
+ jfloat bottom = env->GetFloatField(padding, rectFBottomId);
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ return;
+ }
+
+ jsize count = env->GetArrayLength(coordinates);
+
+ mbgl::EdgeInsets mbglInsets = {top, left, bottom, right};
+ mbgl::AnnotationSegment segment;
+ segment.reserve(count);
+
+ for (int i = 0; i < count; i++) {
+ jobject latLng = reinterpret_cast<jobject>(env->GetObjectArrayElement(coordinates, i));
+ jdouble latitude = env->GetDoubleField(latLng, latLngLatitudeId);
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ return;
+ }
+ jdouble longitude = env->GetDoubleField(latLng, latLngLongitudeId);
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ return;
+ }
+ segment.push_back(mbgl::LatLng(latitude, longitude));
+ }
+
+ mbgl::CameraOptions options = nativeMapView->getMap().cameraForLatLngs(segment, mbglInsets);
+
+ if (direction >= 0) {
+ // convert from degrees to radians
+ options.angle = (-direction * M_PI) / 180;
+ }
+ if (duration > 0) {
+ options.duration = std::chrono::milliseconds(duration);
+ // equivalent to kCAMediaTimingFunctionDefault in iOS
+ options.easing = {0.25, 0.1, 0.25, 0.1};
+ }
+
+ nativeMapView->getMap().easeTo(options);
+}
+
void JNICALL nativeOnLowMemory(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeOnLowMemory");
assert(nativeMapViewPtr != 0);
@@ -1627,6 +1701,42 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
return JNI_ERR;
}
+ rectFClass = env->FindClass("android/graphics/RectF");
+ if (rectFClass == nullptr) {
+ env->ExceptionDescribe();
+ return JNI_ERR;
+ }
+
+ rectFConstructorId = env->GetMethodID(rectFClass, "<init>", "()V");
+ if (rectFConstructorId == nullptr) {
+ env->ExceptionDescribe();
+ return JNI_ERR;
+ }
+
+ rectFLeftId = env->GetFieldID(rectFClass, "left", "F");
+ if (rectFLeftId == nullptr) {
+ env->ExceptionDescribe();
+ return JNI_ERR;
+ }
+
+ rectFRightId = env->GetFieldID(rectFClass, "right", "F");
+ if (rectFRightId == nullptr) {
+ env->ExceptionDescribe();
+ return JNI_ERR;
+ }
+
+ rectFTopId = env->GetFieldID(rectFClass, "top", "F");
+ if (rectFTopId == nullptr) {
+ env->ExceptionDescribe();
+ return JNI_ERR;
+ }
+
+ rectFBottomId = env->GetFieldID(rectFClass, "bottom", "F");
+ if (rectFBottomId == nullptr) {
+ env->ExceptionDescribe();
+ return JNI_ERR;
+ }
+
httpContextClass = env->FindClass("com/mapbox/mapboxsdk/http/HTTPContext");
if (httpContextClass == nullptr) {
env->ExceptionDescribe();
@@ -1749,6 +1859,8 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
{"nativeGetAnnotationsInBounds", "(JLcom/mapbox/mapboxsdk/geometry/BoundingBox;)[J",
reinterpret_cast<void *>(&nativeGetAnnotationsInBounds)},
{"nativeSetSprite", "(JLjava/lang/String;IIF[B)V", reinterpret_cast<void *>(&nativeSetSprite)},
+ {"nativeSetVisibleCoordinateBounds", "(J[Lcom/mapbox/mapboxsdk/geometry/LatLng;Landroid/graphics/RectF;DJ)V",
+ reinterpret_cast<void *>(&nativeSetVisibleCoordinateBounds)},
{"nativeOnLowMemory", "(J)V", reinterpret_cast<void *>(&nativeOnLowMemory)},
{"nativeSetDebug", "(JZ)V", reinterpret_cast<void *>(&nativeSetDebug)},
{"nativeToggleDebug", "(J)V", reinterpret_cast<void *>(&nativeToggleDebug)},
@@ -1918,6 +2030,23 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
return JNI_ERR;
}
+ rectFClass = reinterpret_cast<jclass>(env->NewGlobalRef(rectFClass));
+ if (rectFClass == nullptr) {
+ env->ExceptionDescribe();
+ env->DeleteGlobalRef(latLngClass);
+ env->DeleteGlobalRef(markerClass);
+ env->DeleteGlobalRef(latLngZoomClass);
+ env->DeleteGlobalRef(bboxClass);
+ env->DeleteGlobalRef(polylineClass);
+ env->DeleteGlobalRef(polygonClass);
+ env->DeleteGlobalRef(runtimeExceptionClass);
+ env->DeleteGlobalRef(nullPointerExceptionClass);
+ env->DeleteGlobalRef(arrayListClass);
+ env->DeleteGlobalRef(projectedMetersClass);
+ env->DeleteGlobalRef(pointFClass);
+ return JNI_ERR;
+ }
+
httpContextClass = reinterpret_cast<jclass>(env->NewGlobalRef(httpContextClass));
if (httpContextClass == nullptr) {
env->ExceptionDescribe();
@@ -1933,6 +2062,7 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
env->DeleteGlobalRef(arrayListClass);
env->DeleteGlobalRef(projectedMetersClass);
env->DeleteGlobalRef(pointFClass);
+ env->DeleteGlobalRef(rectFClass);
}
httpRequestClass = reinterpret_cast<jclass>(env->NewGlobalRef(httpRequestClass));
@@ -1950,6 +2080,7 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
env->DeleteGlobalRef(arrayListClass);
env->DeleteGlobalRef(projectedMetersClass);
env->DeleteGlobalRef(pointFClass);
+ env->DeleteGlobalRef(rectFClass);
env->DeleteGlobalRef(httpContextClass);
}
@@ -2045,6 +2176,14 @@ extern "C" JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) {
pointFXId = nullptr;
pointFYId = nullptr;
+ env->DeleteGlobalRef(rectFClass);
+ rectFClass = nullptr;
+ rectFConstructorId = nullptr;
+ rectFLeftId = nullptr;
+ rectFTopId = nullptr;
+ rectFRightId = nullptr;
+ rectFBottomId = nullptr;
+
env->DeleteGlobalRef(httpContextClass);
httpContextGetInstanceId = nullptr;
httpContextCreateRequestId = nullptr;
@@ -2055,4 +2194,4 @@ extern "C" JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) {
theJVM = nullptr;
}
-}
+} \ No newline at end of file
diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/CoordinateBounds.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/CoordinateBounds.java
new file mode 100644
index 0000000000..0cf098e35f
--- /dev/null
+++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/CoordinateBounds.java
@@ -0,0 +1,31 @@
+package com.mapbox.mapboxsdk.geometry;
+
+/**
+ * Implementation of iOS MGLCoordinateBounds
+ */
+public class CoordinateBounds {
+
+ private LatLng sw;
+ private LatLng ne;
+
+ public CoordinateBounds(LatLng sw, LatLng ne) {
+ this.sw = sw;
+ this.ne = ne;
+ }
+
+ public LatLng getSw() {
+ return sw;
+ }
+
+ public void setSw(LatLng sw) {
+ this.sw = sw;
+ }
+
+ public LatLng getNe() {
+ return ne;
+ }
+
+ public void setNe(LatLng ne) {
+ this.ne = ne;
+ }
+} \ No newline at end of file
diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java
index 477235e48c..15cebd52c3 100644
--- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java
+++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java
@@ -68,6 +68,7 @@ import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.exceptions.InvalidAccessTokenException;
import com.mapbox.mapboxsdk.exceptions.SpriteBitmapChangedException;
import com.mapbox.mapboxsdk.geometry.BoundingBox;
+import com.mapbox.mapboxsdk.geometry.CoordinateBounds;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngZoom;
import com.mapbox.mapboxsdk.utils.ApiAccess;
@@ -1981,6 +1982,42 @@ public final class MapView extends FrameLayout {
}
}
}
+
+ //
+ // Camera
+ //
+ public void setVisibleCoordinateBounds(@NonNull CoordinateBounds bounds) {
+ setVisibleCoordinateBounds(bounds, false);
+ }
+
+ public void setVisibleCoordinateBounds(@NonNull CoordinateBounds bounds, boolean animated) {
+ setVisibleCoordinateBounds(bounds, new RectF(), animated);
+ }
+
+ public void setVisibleCoordinateBounds(@NonNull CoordinateBounds bounds, @NonNull RectF padding, boolean animated) {
+ LatLng[] coordinates = {
+ new LatLng(bounds.getNe().getLatitude(), bounds.getSw().getLongitude()),
+ bounds.getSw(),
+ new LatLng(bounds.getSw().getLatitude(), bounds.getNe().getLongitude()),
+ bounds.getNe()
+
+ };
+ setVisibleCoordinateBounds(coordinates, padding, animated);
+ }
+
+ public void setVisibleCoordinateBounds(@NonNull LatLng[] coordinates, @NonNull RectF padding, boolean animated) {
+ setVisibleCoordinateBounds(coordinates, padding, getDirection(), animated);
+ }
+
+ private void setVisibleCoordinateBounds(LatLng[] coordinates, RectF padding, double direction, boolean animated) {
+ setVisibleCoordinateBounds(coordinates, padding, direction, animated ? ANIMATION_DURATION : 0l);
+ }
+
+ private void setVisibleCoordinateBounds(LatLng[] coordinates, RectF padding, double direction, long duration) {
+ mNativeMapView.setVisibleCoordinateBounds(coordinates, new RectF(padding.left / mScreenDensity,
+ padding.top / mScreenDensity, padding.right / mScreenDensity, padding.bottom / mScreenDensity),
+ direction, duration);
+ }
/**
* Gets the currently selected marker.
diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/NativeMapView.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/NativeMapView.java
index 50b242a9f4..a4b9917006 100644
--- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/NativeMapView.java
+++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/NativeMapView.java
@@ -1,6 +1,7 @@
package com.mapbox.mapboxsdk.views;
import android.graphics.PointF;
+import android.graphics.RectF;
import android.view.Surface;
import com.mapbox.mapboxsdk.annotations.Marker;
@@ -384,6 +385,10 @@ final class NativeMapView {
nativeSetSprite(mNativeMapViewPtr, symbol, width, height, scale, pixels);
}
+ public void setVisibleCoordinateBounds(LatLng[] coordinates, RectF padding, double direction, long duration) {
+ nativeSetVisibleCoordinateBounds(mNativeMapViewPtr, coordinates, padding, direction, duration);
+ }
+
public void onLowMemory() {
nativeOnLowMemory(mNativeMapViewPtr);
}
@@ -477,7 +482,7 @@ final class NativeMapView {
private native void nativeTerminateContext(long nativeMapViewPtr);
private native void nativeCreateSurface(long nativeMapViewPtr,
- Surface surface);
+ Surface surface);
private native void nativeDestroySurface(long nativeMapViewPtr);
@@ -502,7 +507,7 @@ final class NativeMapView {
private native boolean nativeHasClass(long nativeMapViewPtr, String clazz);
private native void nativeSetClasses(long nativeMapViewPtr,
- List<String> classes);
+ List<String> classes);
private native List<String> nativeGetClasses(long nativeMapViewPtr);
@@ -514,7 +519,7 @@ final class NativeMapView {
private native void nativeSetStyleUrl(long nativeMapViewPtr, String url);
private native void nativeSetStyleJson(long nativeMapViewPtr,
- String newStyleJson, String base);
+ String newStyleJson, String base);
private native String nativeGetStyleJson(long nativeMapViewPtr);
@@ -527,7 +532,7 @@ final class NativeMapView {
private native void nativeSetGestureInProgress(long nativeMapViewPtr, boolean inProgress);
private native void nativeMoveBy(long nativeMapViewPtr, double dx,
- double dy, long duration);
+ double dy, long duration);
private native void nativeSetLatLng(long nativeMapViewPtr, LatLng latLng,
long duration);
@@ -537,10 +542,10 @@ final class NativeMapView {
private native void nativeResetPosition(long nativeMapViewPtr);
private native void nativeScaleBy(long nativeMapViewPtr, double ds,
- double cx, double cy, long duration);
+ double cx, double cy, long duration);
private native void nativeSetScale(long nativeMapViewPtr, double scale,
- double cx, double cy, long duration);
+ double cx, double cy, long duration);
private native double nativeGetScale(long nativeMapViewPtr);
@@ -550,7 +555,7 @@ final class NativeMapView {
private native double nativeGetZoom(long nativeMapViewPtr);
private native void nativeSetLatLngZoom(long nativeMapViewPtr,
- LatLngZoom lonLatZoom, long duration);
+ LatLngZoom lonLatZoom, long duration);
private native LatLngZoom nativeGetLatLngZoom(long nativeMapViewPtr);
@@ -561,13 +566,13 @@ final class NativeMapView {
private native double nativeGetMaxZoom(long nativeMapViewPtr);
private native void nativeRotateBy(long nativeMapViewPtr, double sx,
- double sy, double ex, double ey, long duration);
+ double sy, double ex, double ey, long duration);
private native void nativeSetBearing(long nativeMapViewPtr, double degrees,
- long duration);
+ long duration);
private native void nativeSetBearing(long nativeMapViewPtr, double degrees,
- double cx, double cy);
+ double cx, double cy);
private native double nativeGetBearing(long nativeMapViewPtr);
@@ -592,6 +597,8 @@ final class NativeMapView {
private native void nativeSetSprite(long nativeMapViewPtr, String symbol,
int width, int height, float scale, byte[] pixels);
+ private native void nativeSetVisibleCoordinateBounds(long mNativeMapViewPtr, LatLng[] coordinates, RectF padding, double direction, long duration);
+
private native void nativeOnLowMemory(long nativeMapViewPtr);
private native void nativeSetDebug(long nativeMapViewPtr, boolean debug);
diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MainActivity.java b/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MainActivity.java
index 999d38d1d9..8012c5201e 100644
--- a/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MainActivity.java
+++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MainActivity.java
@@ -4,6 +4,7 @@ import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Color;
+import android.graphics.RectF;
import android.location.Location;
import android.os.Bundle;
import android.support.annotation.NonNull;
@@ -21,10 +22,8 @@ import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.MenuItem;
-import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
-import android.widget.Toast;
import com.crashlytics.android.Crashlytics;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
@@ -32,6 +31,7 @@ import com.mapbox.mapboxsdk.annotations.PolygonOptions;
import com.mapbox.mapboxsdk.annotations.PolylineOptions;
import com.mapbox.mapboxsdk.annotations.Sprite;
import com.mapbox.mapboxsdk.constants.Style;
+import com.mapbox.mapboxsdk.geometry.CoordinateBounds;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.utils.ApiAccess;
import com.mapbox.mapboxsdk.views.MapView;
@@ -196,7 +196,6 @@ public class MainActivity extends AppCompatActivity {
mSelectedStyle = savedInstanceState.getInt(STATE_SELECTED_STYLE);
}
-
// Set default UI state
mNavigationView.getMenu().findItem(R.id.action_compass).setChecked(mMapView.isCompassEnabled());
mNavigationView.getMenu().findItem(R.id.action_debug).setChecked(mMapView.isDebugActive());
@@ -333,6 +332,13 @@ public class MainActivity extends AppCompatActivity {
startActivity(new Intent(getApplicationContext(), InfoWindowActivity.class));
return true;
+ case R.id.action_visible_bounds:
+ // Set visible bounds to Moscone Center West (37.783703, -122.403589) and Union Square (37.7874436,-122.4072359)
+ mMapView.setVisibleCoordinateBounds(
+ new CoordinateBounds(new LatLng(37.783703, -122.403589), new LatLng(37.7874436,-122.4072359)),
+ new RectF(100, 350, 100, 300), true);
+ return true;
+
default:
return changeMapStyle(menuItem.getItemId());
}
@@ -389,9 +395,13 @@ public class MainActivity extends AppCompatActivity {
*/
private void toggleGps(boolean enableGps) {
if (enableGps) {
- if ((ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) ||
- (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)) {
- ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_LOCATION);
+ if ((ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
+ != PackageManager.PERMISSION_GRANTED) ||
+ (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
+ != PackageManager.PERMISSION_GRANTED)) {
+ ActivityCompat.requestPermissions(this,
+ new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION},
+ PERMISSIONS_LOCATION);
} else {
enableGps();
}
diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_action_crop.png b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_action_crop.png
new file mode 100644
index 0000000000..e01ede5ddb
--- /dev/null
+++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_action_crop.png
Binary files differ
diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_drawer.xml b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_drawer.xml
index 40573d5d3b..1ec2cd2f5b 100644
--- a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_drawer.xml
+++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_drawer.xml
@@ -92,11 +92,15 @@
android:icon="@drawable/ic_filter_none_white_24dp"
android:title="@string/action_info_window_adapter" />
- <item
- android:id="@+id/action_press_for_marker"
+ <item android:id="@+id/action_press_for_marker"
+ android:checkable="false"
+ android:icon="@drawable/ic_pin_drop_white_24dp"
+ android:title="@string/action_press_for_marker"/>
+
+ <item android:id="@+id/action_visible_bounds"
android:checkable="false"
- android:icon="@drawable/ic_pin_drop_white_24dp"
- android:title="@string/action_press_for_marker"/>
+ android:icon="@drawable/ic_action_crop"
+ android:title="@string/action_visible_bounds"/>
</menu>
</item>
diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml
index b1b32e4385..3a691c108b 100644
--- a/android/java/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml
+++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml
@@ -23,6 +23,7 @@
<string name="action_map_fragment">MapFragment</string>
<string name="action_press_for_marker">Press For Marker</string>
<string name="action_info_window">InfoWindow</string>
+ <string name="action_visible_bounds">Set Visible Bounds</string>
<string name="label_fps">FPS:</string>
diff --git a/include/mbgl/android/jni.hpp b/include/mbgl/android/jni.hpp
index 89bda3c7ed..06b9d781c7 100644
--- a/include/mbgl/android/jni.hpp
+++ b/include/mbgl/android/jni.hpp
@@ -88,6 +88,13 @@ extern jmethodID pointFConstructorId;
extern jfieldID pointFXId;
extern jfieldID pointFYId;
+extern jclass rectFClass;
+extern jmethodID rectFConstructorId;
+extern jfieldID rectFLeftId;
+extern jfieldID rectFTopId;
+extern jfieldID rectFRightId;
+extern jfieldID rectFBottomId;
+
extern jclass httpContextClass;
extern jmethodID httpContextGetInstanceId;
extern jmethodID httpContextCreateRequestId;