summaryrefslogtreecommitdiff
path: root/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java
diff options
context:
space:
mode:
Diffstat (limited to 'android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java')
-rw-r--r--android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java299
1 files changed, 102 insertions, 197 deletions
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 dd757082c4..b4e4e7b77e 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
@@ -1,6 +1,5 @@
package com.mapbox.mapboxsdk.views;
-import android.animation.Animator;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.Dialog;
@@ -13,7 +12,7 @@ import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
-import android.graphics.Matrix;
+import android.graphics.Canvas;
import android.graphics.PointF;
import android.graphics.RectF;
import android.graphics.SurfaceTexture;
@@ -48,7 +47,6 @@ import android.view.TextureView;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
-import android.view.ViewPropertyAnimator;
import android.widget.ArrayAdapter;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -73,10 +71,6 @@ import com.mapbox.mapboxsdk.geometry.BoundingBox;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngZoom;
import com.mapbox.mapboxsdk.utils.ApiAccess;
-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.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -170,7 +164,7 @@ public final class MapView extends FrameLayout {
private NativeMapView mNativeMapView;
// Used to track rendering
- private Boolean mDirty = false;
+ private TextureView mTextureView;
// Used to handle DPI scaling
private float mScreenDensity = 1.0f;
@@ -194,14 +188,7 @@ public final class MapView extends FrameLayout {
private Context mContext;
// Used for user location
- private LostApiClient mLocationClient;
- private LocationRequest mLocationRequest;
- private ImageView mGpsMarker;
- private float mGpsMarkerOffset;
- private Location mGpsLocation;
- private MyLocationListener mLocationListener;
- private ViewPropertyAnimator mGpsMarkerAnimatorX;
- private ViewPropertyAnimator mGpsMarkerAnimatorY;
+ private UserLocationView mUserLocationView;
// Used for the compass
private CompassView mCompassView;
@@ -222,7 +209,7 @@ public final class MapView extends FrameLayout {
private ImageView mAttributionsView;
// Used to manage MapChange event listeners
- private ArrayList<OnMapChangedListener> mOnMapChangedListener;
+ private ArrayList<OnMapChangedListener> mOnMapChangedListener = new ArrayList<>();
// Used to manage map click event listeners
private OnMapClickListener mOnMapClickListener;
@@ -247,7 +234,6 @@ public final class MapView extends FrameLayout {
private boolean mScrollEnabled = true;
private boolean mRotateEnabled = true;
private String mStyleUrl;
- private boolean mIsMyLocationEnabled = false;
//
// Inner classes
@@ -479,10 +465,26 @@ public final class MapView extends FrameLayout {
* @return View to be shown as a {@code InfoWindow}. If null is returned the default
* {@code InfoWindow} will be shown.
*/
- @NonNull
+ @Nullable
View getInfoWindow(@NonNull Marker marker);
}
+ /**
+ * Interface definition for a callback to be invoked when the the My Location dot
+ * (which signifies the user's location) changes location.
+ *
+ * @see MapView#setOnMyLocationChangeListener(OnMyLocationChangeListener)
+ */
+ public interface OnMyLocationChangeListener {
+ /**
+ * Called when the location of the My Location dot has changed
+ * (be it latitude/longitude, bearing or accuracy).
+ *
+ * @param location The current location of the My Location dot The type of map change event.
+ */
+ void onMyLocationChange(@Nullable Location location);
+ }
+
//
// Constructors
//
@@ -563,9 +565,12 @@ public final class MapView extends FrameLayout {
// Save the context
mContext = context;
+ setWillNotDraw(false);
+
// Create the TextureView
- TextureView textureView = new TextureView(mContext);
- addView(textureView);
+ mTextureView = new TextureView(mContext);
+ addView(mTextureView);
+ mTextureView.setSurfaceTextureListener(new SurfaceTextureListener());
// Check if we are in Android Studio UI editor to avoid error in layout preview
if (isInEditMode()) {
@@ -600,9 +605,6 @@ public final class MapView extends FrameLayout {
setFocusableInTouchMode(true);
requestFocus();
- // Register the TextureView callbacks
- textureView.setSurfaceTextureListener(new SurfaceTextureListener());
-
// Touch gesture detectors
mGestureDetector = new GestureDetectorCompat(context, new GestureListener());
mGestureDetector.setIsLongpressEnabled(true);
@@ -628,26 +630,12 @@ public final class MapView extends FrameLayout {
onConnectivityChanged(isConnected);
}
- // Setup location services
- mLocationClient = new LostApiClient.Builder(getContext()).build();
- mLocationRequest = LocationRequest.create()
- .setFastestInterval(1250l)
- .setSmallestDisplacement(2.0f)
- .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
-
// Setup user location UI
- mGpsMarker = new ImageView(getContext());
- mGpsMarker.setImageResource(R.drawable.location_marker);
- mGpsMarker.setVisibility(View.INVISIBLE);
- float iconSize = 27.0f * mScreenDensity;
- mGpsMarkerOffset = iconSize/2;
- FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams((int) iconSize, (int) iconSize);
- mGpsMarker.setLayoutParams(lp);
- addView(mGpsMarker);
+ mUserLocationView = new UserLocationView(this, getContext());
+ addView(mUserLocationView);
// Setup compass
mCompassView = new CompassView(mContext);
- mCompassView.setVisibility(View.INVISIBLE);
mCompassView.setOnClickListener(new CompassView.CompassClickListener(this));
addView(mCompassView);
@@ -655,7 +643,7 @@ public final class MapView extends FrameLayout {
mLogoView = new ImageView(mContext);
mLogoView.setImageDrawable(ContextCompat.getDrawable(mContext, R.drawable.ic_logo_mapbox));
mLogoView.setContentDescription(getResources().getString(R.string.mapboxIconContentDescription));
- LayoutParams logoParams = new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams logoParams = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
mLogoView.setLayoutParams(logoParams);
addView(mLogoView);
@@ -675,10 +663,6 @@ public final class MapView extends FrameLayout {
addView(mAttributionsView);
mAttributionsView.setOnClickListener(new AttributionOnClickListener(this));
- // Setup Support For Listener Tracking
- // MapView's internal listener is setup in onCreate()
- mOnMapChangedListener = new ArrayList<>();
-
// Load the attributes
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MapView, 0, 0);
try {
@@ -887,6 +871,9 @@ public final class MapView extends FrameLayout {
public void onDestroy() {
mNativeMapView.terminateContext();
mNativeMapView.terminateDisplay();
+ mNativeMapView.destroySurface();
+ mNativeMapView.destroy();
+ mNativeMapView = null;
}
/**
@@ -901,6 +888,7 @@ public final class MapView extends FrameLayout {
*/
@UiThread
public void onStop() {
+ mUserLocationView.cancelAnimations();
}
/**
@@ -912,10 +900,7 @@ public final class MapView extends FrameLayout {
getContext().unregisterReceiver(mConnectivityReceiver);
mConnectivityReceiver = null;
- if (mIsMyLocationEnabled) {
- toggleGps(false);
- }
-
+ mUserLocationView.pause();
mNativeMapView.pause();
}
@@ -928,11 +913,9 @@ public final class MapView extends FrameLayout {
mConnectivityReceiver = new ConnectivityReceiver();
mContext.registerReceiver(mConnectivityReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
- if (mIsMyLocationEnabled) {
- toggleGps(true);
- }
-
+ mUserLocationView.resume();
mNativeMapView.resume();
+ mNativeMapView.update();
}
/**
@@ -1360,7 +1343,6 @@ public final class MapView extends FrameLayout {
* @param style The bundled style. Accepts one of the values from {@link Style}.
*/
@UiThread
- @NonNull
public void setStyle(@Style.StyleUrl String style) {
setStyleUrl(style);
}
@@ -1694,8 +1676,10 @@ public final class MapView extends FrameLayout {
throw new NullPointerException("markerOptionsList is null");
}
- List<Marker> markers = new ArrayList<>(markerOptionsList.size());
- for (MarkerOptions markerOptions : markerOptionsList) {
+ int count = markerOptionsList.size();
+ List<Marker> markers = new ArrayList<>(count);
+ for (int i = 0; i < count; i++) {
+ MarkerOptions markerOptions = markerOptionsList.get(i);
Marker marker = prepareMarker(markerOptions);
markers.add(marker);
}
@@ -1703,7 +1687,6 @@ public final class MapView extends FrameLayout {
long[] ids = mNativeMapView.addMarkers(markers);
Marker m;
- int count = markers.size();
for (int i = 0; i < count; i++) {
m = markers.get(i);
m.setId(ids[i]);
@@ -1749,8 +1732,10 @@ public final class MapView extends FrameLayout {
}
// TODO make faster in JNI
- List<Polyline> polylines = new ArrayList<>(polylineOptionsList.size());
- for (PolylineOptions polylineOptions : polylineOptionsList) {
+ int count = polylineOptionsList.size();
+ List<Polyline> polylines = new ArrayList<>(count);
+ for (int i = 0; i < count; i++) {
+ PolylineOptions polylineOptions = polylineOptionsList.get(i);
polylines.add(addPolyline(polylineOptions));
}
@@ -1842,7 +1827,9 @@ public final class MapView extends FrameLayout {
}
// TODO make faster in JNI
- for (Annotation annotation : annotationList) {
+ int count = annotationList.size();
+ for (int i = 0; i < count; i++) {
+ Annotation annotation = annotationList.get(i);
removeAnnotation(annotation);
}
}
@@ -1887,8 +1874,8 @@ public final class MapView extends FrameLayout {
long[] ids = mNativeMapView.getAnnotationsInBounds(bbox);
List<Long> idsList = new ArrayList<>(ids.length);
- for (long id : ids) {
- idsList.add(id);
+ for (int i = 0; i < ids.length; i++) {
+ idsList.add(ids[i]);
}
List<Marker> annotations = new ArrayList<>(ids.length);
@@ -1924,7 +1911,7 @@ public final class MapView extends FrameLayout {
*/
@UiThread
public double getMetersPerPixelAtLatitude(@FloatRange(from = -180, to = 180) double latitude) {
- return mNativeMapView.getMetersPerPixelAtLatitude(latitude, getZoomLevel());
+ return mNativeMapView.getMetersPerPixelAtLatitude(latitude, getZoomLevel()) / mScreenDensity;
}
private void selectMarker(Marker marker) {
@@ -1977,7 +1964,9 @@ public final class MapView extends FrameLayout {
}
private void adjustTopOffsetPixels() {
- for (Annotation annotation : mAnnotations) {
+ int count = mAnnotations.size();
+ for (int i = 0; i < count; i++) {
+ Annotation annotation = mAnnotations.get(i);
if (annotation instanceof Marker) {
Marker marker = (Marker) annotation;
marker.setTopOffsetPixels(
@@ -2012,29 +2001,16 @@ public final class MapView extends FrameLayout {
// Called when the map needs to be rerendered
// Called via JNI from NativeMapView
- synchronized protected void onInvalidate() {
- if (!mDirty) {
- mDirty = true;
- postRender();
- }
+ protected void onInvalidate() {
+ postInvalidate();
}
- private void postRender() {
- Runnable mRunnable = new Runnable() {
- @Override
- public void run() {
- updateCompass();
- updateGpsMarker();
- mNativeMapView.renderSync();
- mDirty = false;
- }
- };
-
- if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
- postOnAnimation(mRunnable);
- } else {
- postDelayed(mRunnable, 1000 / 60);
+ @Override
+ public void onDraw(Canvas canvas) {
+ if (!mNativeMapView.isPaused()) {
+ mNativeMapView.renderSync();
}
+ super.onDraw(canvas);
}
@Override
@@ -2059,7 +2035,9 @@ public final class MapView extends FrameLayout {
// Must do all EGL/GL ES destruction here
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
- mNativeMapView.destroySurface();
+ if (mNativeMapView != null) {
+ mNativeMapView.destroySurface();
+ }
return true;
}
@@ -2070,13 +2048,20 @@ public final class MapView extends FrameLayout {
mNativeMapView.resizeFramebuffer(width, height);
}
- // Not used
+ // Called when the SurfaceTexure frame is drawn to screen
+ // Must sync with UI here
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
- // Do nothing
+ mCompassView.update(getDirection());
+ mUserLocationView.update();
}
}
+ // Used by UserLocationView
+ void update() {
+ mNativeMapView.update();
+ }
+
//
// View events
//
@@ -2111,7 +2096,7 @@ public final class MapView extends FrameLayout {
// Called when user touches the screen, all positions are absolute
@Override
- public boolean onTouchEvent(MotionEvent event) {
+ public boolean onTouchEvent(@NonNull MotionEvent event) {
// Check and ignore non touch or left clicks
if ((event.getButtonState() != 0) && (event.getButtonState() != MotionEvent.BUTTON_PRIMARY)) {
@@ -2260,7 +2245,9 @@ public final class MapView extends FrameLayout {
if (newSelectedMarkerId >= 0) {
- for (Annotation annotation : mAnnotations) {
+ int count = mAnnotations.size();
+ for (int i = 0; i < count; i++) {
+ Annotation annotation = mAnnotations.get(i);
if (annotation instanceof Marker) {
if (annotation.getId() == newSelectedMarkerId) {
if (mSelectedMarker == null || annotation.getId() != mSelectedMarker.getId()) {
@@ -2512,7 +2499,7 @@ public final class MapView extends FrameLayout {
// Called when the user presses a key, also called for repeating keys held
// down
@Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
+ public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
// If the user has held the scroll key down for a while then accelerate
// the scroll speed
double scrollDist = event.getRepeatCount() >= 5 ? 50.0 : 10.0;
@@ -2761,7 +2748,7 @@ public final class MapView extends FrameLayout {
// Called when the mouse pointer enters or exits the view
// or when it fades in or out due to movement
@Override
- public boolean onHoverEvent(MotionEvent event) {
+ public boolean onHoverEvent(@NonNull MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_HOVER_ENTER:
case MotionEvent.ACTION_HOVER_MOVE:
@@ -2840,18 +2827,12 @@ public final class MapView extends FrameLayout {
// Called when the map view transformation has changed
// Called via JNI from NativeMapView
// Forward to any listeners
- protected void onMapChanged(int rawChange) {
- final int mapChange = rawChange;
+ protected void onMapChanged(int mapChange) {
if (mOnMapChangedListener != null) {
- post(new Runnable() {
- @Override
- public void run() {
- for (OnMapChangedListener listener : mOnMapChangedListener) {
- //noinspection ResourceType
- listener.onMapChanged(mapChange);
- }
- }
- });
+ int count = mOnMapChangedListener.size();
+ for (int i = 0; i < count; i++) {
+ mOnMapChangedListener.get(i).onMapChanged(mapChange);
+ }
}
}
@@ -2883,14 +2864,14 @@ public final class MapView extends FrameLayout {
// Called via JNI from NativeMapView
// Forward to any listener
protected void onFpsChanged(final double fps) {
- if (mOnFpsChangedListener != null) {
- post(new Runnable() {
- @Override
- public void run() {
+ post(new Runnable() {
+ @Override
+ public void run() {
+ if (mOnFpsChangedListener != null) {
mOnFpsChangedListener.onFpsChanged(fps);
}
- });
- }
+ }
+ });
}
/**
@@ -2959,13 +2940,13 @@ public final class MapView extends FrameLayout {
*/
@UiThread
public boolean isMyLocationEnabled() {
- return mIsMyLocationEnabled;
+ return mUserLocationView.isEnabled();
}
/**
* Enables or disables the my-location layer.
* While enabled, the my-location layer continuously draws an indication of a user's current
- * location.
+ * location and bearing.
* <p/>
* In order to use the my-location-layer feature you need to request permission for either
* {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
@@ -2975,8 +2956,7 @@ public final class MapView extends FrameLayout {
*/
@UiThread
public void setMyLocationEnabled(boolean enabled) {
- mIsMyLocationEnabled = enabled;
- toggleGps(enabled);
+ mUserLocationView.setEnabled(enabled);
}
/**
@@ -2987,74 +2967,19 @@ public final class MapView extends FrameLayout {
@UiThread
@Nullable
public Location getMyLocation() {
- return mGpsLocation;
+ return mUserLocationView.getLocation();
}
/**
- * Enabled / Disable GPS location updates along with updating the UI
+ * Sets a callback that's invoked when the the My Location dot
+ * (which signifies the user's location) changes location.
*
- * @param enableGps true if GPS is to be enabled, false if GPS is to be disabled
+ * @param listener The callback that's invoked when the user clicks on a marker.
+ * To unset the callback, use null.
*/
- private void toggleGps(boolean enableGps) {
- if (enableGps) {
- if (!mLocationClient.isConnected()) {
- mGpsLocation = null;
- mLocationClient.connect();
- updateLocation(LocationServices.FusedLocationApi.getLastLocation());
- mLocationListener = new MyLocationListener();
- LocationServices.FusedLocationApi.requestLocationUpdates(mLocationRequest, mLocationListener);
- }
- } else {
- if (mLocationClient.isConnected()) {
- LocationServices.FusedLocationApi.removeLocationUpdates(mLocationListener);
- mLocationListener = null;
- mLocationClient.disconnect();
- mGpsLocation = null;
- }
- }
-
- onInvalidate();
- }
-
- private class MyLocationListener implements LocationListener {
- @Override
- public void onLocationChanged(Location location) {
- updateLocation(location);
- }
- }
-
- // Handles location updates from GPS
- private void updateLocation(Location location) {
- if (location != null) {
- mGpsLocation = location;
- updateGpsMarker();
- }
- }
-
- private void updateGpsMarker() {
- if (mIsMyLocationEnabled && mGpsLocation != null) {
- mGpsMarker.setVisibility(View.VISIBLE);
- LatLng coordinate = new LatLng(mGpsLocation);
- PointF screenLocation = toScreenLocation(coordinate);
- if (!mDirty) {
- // Map is idle, animate change of location
- mGpsMarkerAnimatorX = mGpsMarker.animate().x(screenLocation.x - mGpsMarkerOffset);
- mGpsMarkerAnimatorY = mGpsMarker.animate().y(screenLocation.y - mGpsMarkerOffset);
- } else {
- // Map is not idle, set value, don't animate
- if (mGpsMarkerAnimatorX != null) {
- mGpsMarkerAnimatorX.cancel();
- mGpsMarkerAnimatorY.cancel();
- }
- // Reposition correctly
- mGpsMarker.setX(screenLocation.x - mGpsMarkerOffset);
- mGpsMarker.setY(screenLocation.y - mGpsMarkerOffset);
- }
- } else {
- if (mGpsMarker != null) {
- mGpsMarker.setVisibility(View.INVISIBLE);
- }
- }
+ @UiThread
+ public void setOnMyLocationChangeListener(@Nullable OnMyLocationChangeListener listener) {
+ mUserLocationView.setOnMyLocationChangeListener(listener);
}
//
@@ -3084,7 +3009,6 @@ public final class MapView extends FrameLayout {
@UiThread
public void setCompassEnabled(boolean compassEnabled) {
mCompassView.setEnabled(compassEnabled);
- onInvalidate();
}
/**
@@ -3096,8 +3020,8 @@ public final class MapView extends FrameLayout {
* @param gravity One of the values from {@link Gravity}.
* @see Gravity
*/
- @UiThread
- public void setCompassGravity(int gravity) {
+ @UiThread
+ public void setCompassGravity(int gravity) {
setWidgetGravity(mCompassView, gravity);
}
@@ -3115,25 +3039,6 @@ public final class MapView extends FrameLayout {
setWidgetMargins(mCompassView, left, top, right, bottom);
}
- // 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 updateCompass() {
- if (isCompassEnabled()) {
- mCompassView.setVisibility(VISIBLE);
- rotateImageView(mCompassView, (float) getDirection());
- } else {
- mCompassView.setVisibility(INVISIBLE);
- }
- }
-
//
// Logo
//