summaryrefslogtreecommitdiff
path: root/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
diff options
context:
space:
mode:
Diffstat (limited to 'platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java')
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java3965
1 files changed, 920 insertions, 3045 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
index 32b327e8d0..5dee9bf43d 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
@@ -1,7 +1,5 @@
package com.mapbox.mapboxsdk.maps;
-import android.Manifest;
-import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Dialog;
import android.app.Fragment;
@@ -10,90 +8,53 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.PointF;
-import android.graphics.RectF;
import android.graphics.SurfaceTexture;
-import android.location.Location;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.CallSuper;
-import android.support.annotation.FloatRange;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
-import android.support.v4.content.ContextCompat;
-import android.support.v4.view.GestureDetectorCompat;
-import android.support.v4.view.ScaleGestureDetectorCompat;
import android.support.v7.app.AlertDialog;
import android.text.TextUtils;
import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.view.GestureDetector;
-import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
-import android.view.ScaleGestureDetector;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.TextureView;
import android.view.View;
-import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.FrameLayout;
import android.widget.ImageView;
-import android.widget.ZoomButtonsController;
-import com.almeros.android.multitouch.gesturedetectors.RotateGestureDetector;
-import com.almeros.android.multitouch.gesturedetectors.ShoveGestureDetector;
-import com.almeros.android.multitouch.gesturedetectors.TwoFingerGestureDetector;
-import com.mapbox.mapboxsdk.MapboxAccountManager;
+import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.R;
-import com.mapbox.mapboxsdk.annotations.Annotation;
-import com.mapbox.mapboxsdk.annotations.Icon;
-import com.mapbox.mapboxsdk.annotations.IconFactory;
-import com.mapbox.mapboxsdk.annotations.InfoWindow;
-import com.mapbox.mapboxsdk.annotations.Marker;
-import com.mapbox.mapboxsdk.annotations.MarkerView;
-import com.mapbox.mapboxsdk.annotations.Polygon;
-import com.mapbox.mapboxsdk.annotations.Polyline;
+import com.mapbox.mapboxsdk.annotations.MarkerViewManager;
import com.mapbox.mapboxsdk.camera.CameraPosition;
-import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
-import com.mapbox.mapboxsdk.constants.MyBearingTracking;
-import com.mapbox.mapboxsdk.constants.MyLocationTracking;
import com.mapbox.mapboxsdk.constants.Style;
-import com.mapbox.mapboxsdk.exceptions.IconBitmapChangedException;
-import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.location.LocationListener;
-import com.mapbox.mapboxsdk.location.LocationServices;
import com.mapbox.mapboxsdk.maps.widgets.CompassView;
import com.mapbox.mapboxsdk.maps.widgets.MyLocationView;
import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings;
import com.mapbox.mapboxsdk.telemetry.MapboxEvent;
import com.mapbox.mapboxsdk.telemetry.MapboxEventManager;
-import com.mapbox.mapboxsdk.utils.ColorUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.nio.ByteBuffer;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
/**
* <p>
@@ -111,3090 +72,1004 @@ import java.util.concurrent.CopyOnWriteArrayList;
*/
public class MapView extends FrameLayout {
- private MapboxMap mapboxMap;
- private boolean initialLoad;
- private boolean destroyed;
-
- private List<Icon> icons;
- private int averageIconHeight;
- private int averageIconWidth;
-
- private NativeMapView nativeMapView;
- private boolean hasSurface = false;
-
- private ViewGroup markerViewContainer;
- private CompassView compassView;
- private ImageView logoView;
- private ImageView attributionsView;
- private MyLocationView myLocationView;
- private LocationListener myLocationListener;
-
- private Projection projection;
-
- private CopyOnWriteArrayList<OnMapChangedListener> onMapChangedListener;
- private ZoomButtonsController zoomButtonsController;
- private ConnectivityReceiver connectivityReceiver;
- private float screenDensity = 1.0f;
-
- private TrackballLongPressTimeOut currentTrackballLongPressTimeOut;
- private GestureDetectorCompat gestureDetector;
- private ScaleGestureDetector scaleGestureDetector;
- private RotateGestureDetector rotateGestureDetector;
- private ShoveGestureDetector shoveGestureDetector;
- private boolean twoTap = false;
- private boolean zoomStarted = false;
- private boolean dragStarted = false;
- private boolean quickZoom = false;
- private boolean scrollInProgress = false;
-
- private int contentPaddingLeft;
- private int contentPaddingTop;
- private int contentPaddingRight;
- private int contentPaddingBottom;
-
- private PointF focalPoint;
-
- private String styleUrl = Style.MAPBOX_STREETS;
- private boolean styleWasSet = false;
-
- private List<OnMapReadyCallback> onMapReadyCallbackList;
- private SnapshotRequest snapshotRequest;
-
- @UiThread
- public MapView(@NonNull Context context) {
- super(context);
- initialize(context, MapboxMapOptions.createFromAttributes(context, null));
- }
-
- @UiThread
- public MapView(@NonNull Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- initialize(context, MapboxMapOptions.createFromAttributes(context, attrs));
- }
-
- @UiThread
- public MapView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- initialize(context, MapboxMapOptions.createFromAttributes(context, attrs));
- }
-
- @UiThread
- public MapView(@NonNull Context context, @Nullable MapboxMapOptions options) {
- super(context);
- initialize(context, options);
- }
-
- private void initialize(@NonNull Context context, @NonNull MapboxMapOptions options) {
- if (isInEditMode()) {
- // if we are in an editor mode we show an image of a map
- LayoutInflater.from(context).inflate(R.layout.mapview_preview, this);
- return;
- }
-
- initialLoad = true;
- onMapReadyCallbackList = new ArrayList<>();
- onMapChangedListener = new CopyOnWriteArrayList<>();
- mapboxMap = new MapboxMap(this);
- projection = mapboxMap.getProjection();
-
- icons = new ArrayList<>();
- View view = LayoutInflater.from(context).inflate(R.layout.mapview_internal, this);
- setWillNotDraw(false);
-
- if (options.getTextureMode()) {
- TextureView textureView = new TextureView(context);
- textureView.setSurfaceTextureListener(new SurfaceTextureListener());
- addView(textureView, 0);
- } else {
- SurfaceView surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
- surfaceView.getHolder().addCallback(new SurfaceCallback());
- surfaceView.setVisibility(View.VISIBLE);
- }
-
- nativeMapView = new NativeMapView(this);
-
- // load transparent icon for MarkerView to trace actual markers, see #6352
- loadIcon(IconFactory.recreate(IconFactory.ICON_MARKERVIEW_ID, IconFactory.ICON_MARKERVIEW_BITMAP));
-
- // Ensure this view is interactable
- setClickable(true);
- setLongClickable(true);
- setFocusable(true);
- setFocusableInTouchMode(true);
- requestFocus();
-
- // Touch gesture detectors
- gestureDetector = new GestureDetectorCompat(context, new GestureListener());
- gestureDetector.setIsLongpressEnabled(true);
- scaleGestureDetector = new ScaleGestureDetector(context, new ScaleGestureListener());
- ScaleGestureDetectorCompat.setQuickScaleEnabled(scaleGestureDetector, true);
- rotateGestureDetector = new RotateGestureDetector(context, new RotateGestureListener());
- shoveGestureDetector = new ShoveGestureDetector(context, new ShoveGestureListener());
-
- zoomButtonsController = new ZoomButtonsController(this);
- zoomButtonsController.setZoomSpeed(MapboxConstants.ANIMATION_DURATION);
- zoomButtonsController.setOnZoomListener(new OnZoomListener());
-
- // Connectivity
- onConnectivityChanged(isConnected());
-
- markerViewContainer = (ViewGroup) view.findViewById(R.id.markerViewContainer);
-
- myLocationView = (MyLocationView) view.findViewById(R.id.userLocationView);
- myLocationView.setMapboxMap(mapboxMap);
-
- compassView = (CompassView) view.findViewById(R.id.compassView);
- compassView.setMapboxMap(mapboxMap);
-
- logoView = (ImageView) view.findViewById(R.id.logoView);
-
- // Setup Attributions control
- attributionsView = (ImageView) view.findViewById(R.id.attributionView);
- attributionsView.setOnClickListener(new AttributionOnClickListener(this));
-
- screenDensity = context.getResources().getDisplayMetrics().density;
-
- setInitialState(options);
-
- // Shows the zoom controls
- if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH)) {
- mapboxMap.getUiSettings().setZoomControlsEnabled(true);
- }
- }
-
- private void setInitialState(MapboxMapOptions options) {
- mapboxMap.setDebugActive(options.getDebugActive());
-
- CameraPosition position = options.getCamera();
- if (position != null) {
- mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(position));
- myLocationView.setTilt(position.tilt);
- }
-
- // api base url
- String apiBaseUrl = options.getApiBaseUrl();
- if (!TextUtils.isEmpty(apiBaseUrl)) {
- setApiBaseUrl(apiBaseUrl);
- }
-
- // access token
- String accessToken = options.getAccessToken();
- if (!TextUtils.isEmpty(accessToken)) {
- mapboxMap.setAccessToken(accessToken);
- }
-
- // style url
- String style = options.getStyle();
- if (!TextUtils.isEmpty(style)) {
- styleUrl = style;
- }
-
- // MyLocationView
- MyLocationViewSettings myLocationViewSettings = mapboxMap.getMyLocationViewSettings();
- myLocationViewSettings.setForegroundDrawable(
- options.getMyLocationForegroundDrawable(), options.getMyLocationForegroundBearingDrawable());
- myLocationViewSettings.setForegroundTintColor(options.getMyLocationForegroundTintColor());
- myLocationViewSettings.setBackgroundDrawable(
- options.getMyLocationBackgroundDrawable(), options.getMyLocationBackgroundPadding());
- myLocationViewSettings.setBackgroundTintColor(options.getMyLocationBackgroundTintColor());
- myLocationViewSettings.setAccuracyAlpha(options.getMyLocationAccuracyAlpha());
- myLocationViewSettings.setAccuracyTintColor(options.getMyLocationAccuracyTintColor());
- mapboxMap.setMyLocationEnabled(options.getLocationEnabled());
-
- // Enable gestures
- UiSettings uiSettings = mapboxMap.getUiSettings();
- uiSettings.setZoomGesturesEnabled(options.getZoomGesturesEnabled());
- uiSettings.setZoomGestureChangeAllowed(options.getZoomGesturesEnabled());
- uiSettings.setScrollGesturesEnabled(options.getScrollGesturesEnabled());
- uiSettings.setScrollGestureChangeAllowed(options.getScrollGesturesEnabled());
- uiSettings.setRotateGesturesEnabled(options.getRotateGesturesEnabled());
- uiSettings.setRotateGestureChangeAllowed(options.getRotateGesturesEnabled());
- uiSettings.setTiltGesturesEnabled(options.getTiltGesturesEnabled());
- uiSettings.setTiltGestureChangeAllowed(options.getTiltGesturesEnabled());
-
- // Ui Controls
- uiSettings.setZoomControlsEnabled(options.getZoomControlsEnabled());
-
- // Zoom
- mapboxMap.setMaxZoom(options.getMaxZoom());
- mapboxMap.setMinZoom(options.getMinZoom());
-
- // Compass
- uiSettings.setCompassEnabled(options.getCompassEnabled());
- uiSettings.setCompassGravity(options.getCompassGravity());
- int[] compassMargins = options.getCompassMargins();
- if (compassMargins != null) {
- uiSettings.setCompassMargins(compassMargins[0], compassMargins[1], compassMargins[2], compassMargins[3]);
- } else {
- int tenDp = (int) getResources().getDimension(R.dimen.ten_dp);
- uiSettings.setCompassMargins(tenDp, tenDp, tenDp, tenDp);
- }
- uiSettings.setCompassFadeFacingNorth(options.getCompassFadeFacingNorth());
-
- // Logo
- uiSettings.setLogoEnabled(options.getLogoEnabled());
- uiSettings.setLogoGravity(options.getLogoGravity());
- int[] logoMargins = options.getLogoMargins();
- if (logoMargins != null) {
- uiSettings.setLogoMargins(logoMargins[0], logoMargins[1], logoMargins[2], logoMargins[3]);
- } else {
- int sixteenDp = (int) getResources().getDimension(R.dimen.sixteen_dp);
- uiSettings.setLogoMargins(sixteenDp, sixteenDp, sixteenDp, sixteenDp);
- }
-
- // Attribution
- uiSettings.setAttributionEnabled(options.getAttributionEnabled());
- uiSettings.setAttributionGravity(options.getAttributionGravity());
- int[] attributionMargins = options.getAttributionMargins();
- if (attributionMargins != null) {
- uiSettings.setAttributionMargins(attributionMargins[0], attributionMargins[1], attributionMargins[2], attributionMargins[3]);
- } else {
- Resources resources = getResources();
- int sevenDp = (int) resources.getDimension(R.dimen.seven_dp);
- int seventySixDp = (int) resources.getDimension(R.dimen.seventy_six_dp);
- uiSettings.setAttributionMargins(seventySixDp, sevenDp, sevenDp, sevenDp);
- }
-
- int attributionTintColor = options.getAttributionTintColor();
- uiSettings.setAttributionTintColor(attributionTintColor != -1
- ? attributionTintColor : ColorUtils.getPrimaryColor(getContext()));
- }
-
- //
- // Lifecycle events
- //
-
- /**
- * <p>
- * You must call this method from the parent's {@link android.app.Activity#onCreate(Bundle)} or
- * {@link android.app.Fragment#onCreate(Bundle)}.
- * </p>
- * You must set a valid access token with {@link MapView#setAccessToken(String)} before you this method
- * or an exception will be thrown.
- *
- * @param savedInstanceState Pass in the parent's savedInstanceState.
- * @see MapView#setAccessToken(String)
- */
- @UiThread
- public void onCreate(@Nullable Bundle savedInstanceState) {
- String accessToken = mapboxMap.getAccessToken();
- if (TextUtils.isEmpty(accessToken)) {
- accessToken = MapboxAccountManager.getInstance().getAccessToken();
- mapboxMap.setAccessToken(accessToken);
- } else {
- // user provided access token through xml attributes, need to start MapboxAccountManager
- MapboxAccountManager.start(getContext(), accessToken);
- }
-
- // Force a check for an access token
- MapboxAccountManager.validateAccessToken(accessToken);
-
- if (savedInstanceState != null && savedInstanceState.getBoolean(MapboxConstants.STATE_HAS_SAVED_STATE)) {
-
- // Get previous camera position
- CameraPosition cameraPosition = savedInstanceState.getParcelable(MapboxConstants.STATE_CAMERA_POSITION);
- if (cameraPosition != null) {
- mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder(cameraPosition).build()));
- }
-
- UiSettings uiSettings = mapboxMap.getUiSettings();
- uiSettings.setZoomGesturesEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_ZOOM_ENABLED));
- uiSettings.setZoomGestureChangeAllowed(savedInstanceState.getBoolean(MapboxConstants.STATE_ZOOM_ENABLED_CHANGE));
- uiSettings.setScrollGesturesEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_SCROLL_ENABLED));
- uiSettings.setScrollGestureChangeAllowed(savedInstanceState.getBoolean(MapboxConstants.STATE_SCROLL_ENABLED_CHANGE));
- uiSettings.setRotateGesturesEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_ROTATE_ENABLED));
- uiSettings.setRotateGestureChangeAllowed(savedInstanceState.getBoolean(MapboxConstants.STATE_ROTATE_ENABLED_CHANGE));
- uiSettings.setTiltGesturesEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_TILT_ENABLED));
- uiSettings.setTiltGestureChangeAllowed(savedInstanceState.getBoolean(MapboxConstants.STATE_TILT_ENABLED_CHANGE));
- uiSettings.setZoomControlsEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_ZOOM_CONTROLS_ENABLED));
-
- // Compass
- uiSettings.setCompassEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_COMPASS_ENABLED));
- uiSettings.setCompassGravity(savedInstanceState.getInt(MapboxConstants.STATE_COMPASS_GRAVITY));
- uiSettings.setCompassMargins(savedInstanceState.getInt(MapboxConstants.STATE_COMPASS_MARGIN_LEFT),
- savedInstanceState.getInt(MapboxConstants.STATE_COMPASS_MARGIN_TOP),
- savedInstanceState.getInt(MapboxConstants.STATE_COMPASS_MARGIN_RIGHT),
- savedInstanceState.getInt(MapboxConstants.STATE_COMPASS_MARGIN_BOTTOM));
- uiSettings.setCompassFadeFacingNorth(savedInstanceState.getBoolean(MapboxConstants.STATE_COMPASS_FADE_WHEN_FACING_NORTH));
-
- // Logo
- uiSettings.setLogoEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_LOGO_ENABLED));
- uiSettings.setLogoGravity(savedInstanceState.getInt(MapboxConstants.STATE_LOGO_GRAVITY));
- uiSettings.setLogoMargins(savedInstanceState.getInt(MapboxConstants.STATE_LOGO_MARGIN_LEFT)
- , savedInstanceState.getInt(MapboxConstants.STATE_LOGO_MARGIN_TOP)
- , savedInstanceState.getInt(MapboxConstants.STATE_LOGO_MARGIN_RIGHT)
- , savedInstanceState.getInt(MapboxConstants.STATE_LOGO_MARGIN_BOTTOM));
-
- // Attribution
- uiSettings.setAttributionEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_ATTRIBUTION_ENABLED));
- uiSettings.setAttributionGravity(savedInstanceState.getInt(MapboxConstants.STATE_ATTRIBUTION_GRAVITY));
- uiSettings.setAttributionMargins(savedInstanceState.getInt(MapboxConstants.STATE_ATTRIBUTION_MARGIN_LEFT)
- , savedInstanceState.getInt(MapboxConstants.STATE_ATTRIBUTION_MARGIN_TOP)
- , savedInstanceState.getInt(MapboxConstants.STATE_ATTRIBUTION_MARGIN_RIGHT)
- , savedInstanceState.getInt(MapboxConstants.STATE_ATTRIBUTION_MARGIN_BOTTOM));
-
- mapboxMap.setDebugActive(savedInstanceState.getBoolean(MapboxConstants.STATE_DEBUG_ACTIVE));
- styleUrl = savedInstanceState.getString(MapboxConstants.STATE_STYLE_URL);
-
- // User location
- try {
- mapboxMap.setMyLocationEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_MY_LOCATION_ENABLED));
- } catch (SecurityException ignore) {
- // User did not accept location permissions
- }
-
- TrackingSettings trackingSettings = mapboxMap.getTrackingSettings();
- //noinspection ResourceType
- trackingSettings.setMyLocationTrackingMode(
- savedInstanceState.getInt(MapboxConstants.STATE_MY_LOCATION_TRACKING_MODE, MyLocationTracking.TRACKING_NONE));
- //noinspection ResourceType
- trackingSettings.setMyBearingTrackingMode(
- savedInstanceState.getInt(MapboxConstants.STATE_MY_BEARING_TRACKING_MODE, MyBearingTracking.NONE));
- trackingSettings.setDismissLocationTrackingOnGesture(
- savedInstanceState.getBoolean(MapboxConstants.STATE_MY_LOCATION_TRACKING_DISMISS, true));
- trackingSettings.setDismissBearingTrackingOnGesture(
- savedInstanceState.getBoolean(MapboxConstants.STATE_MY_BEARING_TRACKING_DISMISS, true));
- } else if (savedInstanceState == null) {
- // Start Telemetry (authorization determined in initial MapboxEventManager constructor)
- Log.i(MapView.class.getCanonicalName(), "MapView start Telemetry...");
- MapboxEventManager eventManager = MapboxEventManager.getMapboxEventManager();
- eventManager.initialize(getContext(), getAccessToken());
- }
-
- // Initialize EGL
- nativeMapView.initializeDisplay();
- nativeMapView.initializeContext();
-
- // Add annotation deselection listener
- addOnMapChangedListener(new OnMapChangedListener() {
- @Override
- public void onMapChanged(@MapChange int change) {
- if (change == DID_FINISH_LOADING_STYLE && initialLoad) {
- initialLoad = false;
- reloadIcons();
- reloadMarkers();
- adjustTopOffsetPixels();
-
- // Notify listeners the map is ready
- if (onMapReadyCallbackList.size() > 0) {
- Iterator<OnMapReadyCallback> iterator = onMapReadyCallbackList.iterator();
- while (iterator.hasNext()) {
- OnMapReadyCallback callback = iterator.next();
- callback.onMapReady(mapboxMap);
- iterator.remove();
- }
- }
-
- // invalidate camera to update overlain views with correct tilt value
- invalidateCameraPosition();
-
- } else if (change == REGION_IS_CHANGING || change == REGION_DID_CHANGE || change == DID_FINISH_LOADING_MAP) {
- mapboxMap.getMarkerViewManager().scheduleViewMarkerInvalidation();
-
- compassView.update(getDirection());
- myLocationView.update();
- mapboxMap.getMarkerViewManager().update();
-
- for (InfoWindow infoWindow : mapboxMap.getInfoWindows()) {
- infoWindow.update();
- }
- }
-
- }
- });
-
- // Fire MapLoad
- if (savedInstanceState == null) {
- Hashtable<String, Object> evt = new Hashtable<>();
- evt.put(MapboxEvent.ATTRIBUTE_EVENT, MapboxEvent.TYPE_MAP_LOAD);
- evt.put(MapboxEvent.ATTRIBUTE_CREATED, MapboxEventManager.generateCreateDate());
- MapboxEventManager.getMapboxEventManager().pushEvent(evt);
- }
- }
-
- /**
- * You must call this method from the parent's {@link android.app.Activity#onSaveInstanceState(Bundle)}
- * or {@link android.app.Fragment#onSaveInstanceState(Bundle)}.
- *
- * @param outState Pass in the parent's outState.
- */
-
- @UiThread
- public void onSaveInstanceState(@NonNull Bundle outState) {
- outState.putBoolean(MapboxConstants.STATE_HAS_SAVED_STATE, true);
- outState.putParcelable(MapboxConstants.STATE_CAMERA_POSITION, mapboxMap.getCameraPosition());
- outState.putBoolean(MapboxConstants.STATE_DEBUG_ACTIVE, mapboxMap.isDebugActive());
- outState.putString(MapboxConstants.STATE_STYLE_URL, styleUrl);
- outState.putBoolean(MapboxConstants.STATE_MY_LOCATION_ENABLED, mapboxMap.isMyLocationEnabled());
-
- // TrackingSettings
- TrackingSettings trackingSettings = mapboxMap.getTrackingSettings();
- outState.putInt(MapboxConstants.STATE_MY_LOCATION_TRACKING_MODE, trackingSettings.getMyLocationTrackingMode());
- outState.putInt(MapboxConstants.STATE_MY_BEARING_TRACKING_MODE, trackingSettings.getMyBearingTrackingMode());
- outState.putBoolean(MapboxConstants.STATE_MY_LOCATION_TRACKING_DISMISS, trackingSettings.isDismissLocationTrackingOnGesture());
- outState.putBoolean(MapboxConstants.STATE_MY_BEARING_TRACKING_DISMISS, trackingSettings.isDismissBearingTrackingOnGesture());
-
- // UiSettings
- UiSettings uiSettings = mapboxMap.getUiSettings();
- outState.putBoolean(MapboxConstants.STATE_ZOOM_ENABLED, uiSettings.isZoomGesturesEnabled());
- outState.putBoolean(MapboxConstants.STATE_ZOOM_ENABLED_CHANGE, uiSettings.isZoomGestureChangeAllowed());
- outState.putBoolean(MapboxConstants.STATE_SCROLL_ENABLED, uiSettings.isScrollGesturesEnabled());
- outState.putBoolean(MapboxConstants.STATE_SCROLL_ENABLED_CHANGE, uiSettings.isScrollGestureChangeAllowed());
- outState.putBoolean(MapboxConstants.STATE_ROTATE_ENABLED, uiSettings.isRotateGesturesEnabled());
- outState.putBoolean(MapboxConstants.STATE_ROTATE_ENABLED_CHANGE, uiSettings.isRotateGestureChangeAllowed());
- outState.putBoolean(MapboxConstants.STATE_TILT_ENABLED, uiSettings.isTiltGesturesEnabled());
- outState.putBoolean(MapboxConstants.STATE_TILT_ENABLED_CHANGE, uiSettings.isTiltGestureChangeAllowed());
- outState.putBoolean(MapboxConstants.STATE_ZOOM_CONTROLS_ENABLED, uiSettings.isZoomControlsEnabled());
-
- // UiSettings - Compass
- outState.putBoolean(MapboxConstants.STATE_COMPASS_ENABLED, uiSettings.isCompassEnabled());
- outState.putInt(MapboxConstants.STATE_COMPASS_GRAVITY, uiSettings.getCompassGravity());
- outState.putInt(MapboxConstants.STATE_COMPASS_MARGIN_LEFT, uiSettings.getCompassMarginLeft());
- outState.putInt(MapboxConstants.STATE_COMPASS_MARGIN_TOP, uiSettings.getCompassMarginTop());
- outState.putInt(MapboxConstants.STATE_COMPASS_MARGIN_BOTTOM, uiSettings.getCompassMarginBottom());
- outState.putInt(MapboxConstants.STATE_COMPASS_MARGIN_RIGHT, uiSettings.getCompassMarginRight());
- outState.putBoolean(MapboxConstants.STATE_COMPASS_FADE_WHEN_FACING_NORTH, uiSettings.isCompassFadeWhenFacingNorth());
-
- // UiSettings - Logo
- outState.putInt(MapboxConstants.STATE_LOGO_GRAVITY, uiSettings.getLogoGravity());
- outState.putInt(MapboxConstants.STATE_LOGO_MARGIN_LEFT, uiSettings.getLogoMarginLeft());
- outState.putInt(MapboxConstants.STATE_LOGO_MARGIN_TOP, uiSettings.getLogoMarginTop());
- outState.putInt(MapboxConstants.STATE_LOGO_MARGIN_RIGHT, uiSettings.getLogoMarginRight());
- outState.putInt(MapboxConstants.STATE_LOGO_MARGIN_BOTTOM, uiSettings.getLogoMarginBottom());
- outState.putBoolean(MapboxConstants.STATE_LOGO_ENABLED, uiSettings.isLogoEnabled());
-
- // UiSettings - Attribution
- outState.putInt(MapboxConstants.STATE_ATTRIBUTION_GRAVITY, uiSettings.getAttributionGravity());
- outState.putInt(MapboxConstants.STATE_ATTRIBUTION_MARGIN_LEFT, uiSettings.getAttributionMarginLeft());
- outState.putInt(MapboxConstants.STATE_ATTRIBUTION_MARGIN_TOP, uiSettings.getAttributionMarginTop());
- outState.putInt(MapboxConstants.STATE_ATTRIBUTION_MARGIN_RIGHT, uiSettings.getAttributionMarginRight());
- outState.putInt(MapboxConstants.STATE_ATTRIBUTION_MARGIN_BOTTOM, uiSettings.getAttributionMarginBottom());
- outState.putBoolean(MapboxConstants.STATE_ATTRIBUTION_ENABLED, uiSettings.isAttributionEnabled());
- }
-
- /**
- * You must call this method from the parent's {@link Activity#onDestroy()} or {@link Fragment#onDestroy()}.
- */
- @UiThread
- public void onDestroy() {
- destroyed = true;
- nativeMapView.terminateContext();
- nativeMapView.terminateDisplay();
- nativeMapView.destroySurface();
- nativeMapView.destroy();
- nativeMapView = null;
- }
-
- /**
- * You must call this method from the parent's {@link Activity#onPause()} or {@link Fragment#onPause()}.
- */
- @UiThread
- public void onPause() {
- // Unregister for connectivity changes
- if (connectivityReceiver != null) {
- getContext().unregisterReceiver(connectivityReceiver);
- connectivityReceiver = null;
- }
-
- myLocationView.onPause();
- }
-
- /**
- * You must call this method from the parent's {@link Activity#onResume()} or {@link Fragment#onResume()}.
- */
- @UiThread
- public void onResume() {
- // Register for connectivity changes
- connectivityReceiver = new ConnectivityReceiver();
- getContext().registerReceiver(connectivityReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
-
- nativeMapView.update();
- myLocationView.onResume();
-
- // In case that no style was set or was loaded through MapboxMapOptions
- if (!styleWasSet) {
- setStyleUrl(styleUrl);
- }
- }
-
- void setFocalPoint(PointF focalPoint) {
- if (focalPoint == null) {
- // resetting focal point,
- UiSettings uiSettings = mapboxMap.getUiSettings();
- // need to validate if we need to reset focal point with user provided one
- if (uiSettings.getFocalPoint() != null) {
- focalPoint = uiSettings.getFocalPoint();
- }
- }
- this.focalPoint = focalPoint;
- }
-
- /**
- * You must call this method from the parent's {@link Activity#onLowMemory()} or {@link Fragment#onLowMemory()}.
- */
- @UiThread
- public void onLowMemory() {
- nativeMapView.onLowMemory();
- }
-
- // Called when debug mode is enabled to update a FPS counter
- // Called via JNI from NativeMapView
- // Forward to any listener
- protected void onFpsChanged(final double fps) {
- post(new Runnable() {
- @Override
- public void run() {
- MapboxMap.OnFpsChangedListener listener = mapboxMap.getOnFpsChangedListener();
- if (listener != null) {
- listener.onFpsChanged(fps);
- }
- }
- });
- }
-
- //
- // LatLng / CenterCoordinate
- //
-
- LatLng getLatLng() {
- return nativeMapView.getLatLng();
- }
-
- //
- // Pitch / Tilt
- //
-
- double getTilt() {
- return nativeMapView.getPitch();
- }
-
- void setTilt(Double pitch) {
- mapboxMap.getMarkerViewManager().setTilt(pitch.floatValue());
- myLocationView.setTilt(pitch);
- nativeMapView.setPitch(pitch, 0);
- }
-
-
- //
- // Direction
- //
-
- double getDirection() {
- if (destroyed) {
- return 0;
- }
-
- double direction = -nativeMapView.getBearing();
-
- while (direction > 360) {
- direction -= 360;
- }
- while (direction < 0) {
- direction += 360;
- }
-
- return direction;
- }
-
- void setDirection(@FloatRange(from = MapboxConstants.MINIMUM_DIRECTION, to = MapboxConstants.MAXIMUM_DIRECTION) double direction) {
- if (destroyed) {
- return;
- }
- setDirection(direction, false);
- }
-
- void setDirection(@FloatRange(from = MapboxConstants.MINIMUM_DIRECTION, to = MapboxConstants.MAXIMUM_DIRECTION) double direction, boolean animated) {
- if (destroyed) {
- return;
- }
- long duration = animated ? MapboxConstants.ANIMATION_DURATION : 0;
- nativeMapView.cancelTransitions();
- // Out of range directions are normalised in setBearing
- nativeMapView.setBearing(-direction, duration);
- }
-
- void resetNorth() {
- if (destroyed) {
- return;
- }
- myLocationView.setBearing(0);
- nativeMapView.cancelTransitions();
- nativeMapView.resetNorth();
- }
-
- //
- // Content padding
- //
-
- int getContentPaddingLeft() {
- return contentPaddingLeft;
- }
-
- int getContentPaddingTop() {
- return contentPaddingTop;
- }
-
- int getContentPaddingRight() {
- return contentPaddingRight;
- }
-
- int getContentPaddingBottom() {
- return contentPaddingBottom;
- }
-
- int getContentWidth() {
- return getWidth() - contentPaddingLeft - contentPaddingRight;
- }
-
- int getContentHeight() {
- return getHeight() - contentPaddingBottom - contentPaddingTop;
- }
-
- //
- // Zoom
- //
-
- double getZoom() {
- if (destroyed) {
- return 0;
- }
- return nativeMapView.getZoom();
- }
-
- void setMinZoom(@FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM) double minZoom) {
- if (destroyed) {
- return;
- }
- nativeMapView.setMinZoom(minZoom);
- }
-
- double getMinZoom() {
- if (destroyed) {
- return 0;
- }
- return nativeMapView.getMinZoom();
- }
-
- void setMaxZoom(@FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM) double maxZoom) {
- if (destroyed) {
- return;
- }
- nativeMapView.setMaxZoom(maxZoom);
- }
-
- double getMaxZoom() {
- if (destroyed) {
- return 0;
- }
- return nativeMapView.getMaxZoom();
- }
-
- // Zoom in or out
- private void zoom(boolean zoomIn) {
- zoom(zoomIn, -1.0f, -1.0f);
- }
-
- private void zoom(boolean zoomIn, float x, float y) {
- // Cancel any animation
- nativeMapView.cancelTransitions();
-
- if (zoomIn) {
- nativeMapView.scaleBy(2.0, x / screenDensity, y / screenDensity, MapboxConstants.ANIMATION_DURATION);
- } else {
- nativeMapView.scaleBy(0.5, x / screenDensity, y / screenDensity, MapboxConstants.ANIMATION_DURATION);
- }
-
- // work around to invalidate camera position
- postDelayed(new ZoomInvalidator(mapboxMap), MapboxConstants.ANIMATION_DURATION);
- }
-
- //
- // Debug
- //
-
- boolean isDebugActive() {
- if (destroyed) {
- return false;
- }
- return nativeMapView.getDebug();
- }
-
- void setDebugActive(boolean debugActive) {
- if (destroyed) {
- return;
- }
- nativeMapView.setDebug(debugActive);
- }
-
- void cycleDebugOptions() {
- if (destroyed) {
- return;
- }
- nativeMapView.cycleDebugOptions();
- }
-
- //
- // Styling
- //
-
- /**
- * <p>
- * Loads a new map style from the specified URL.
- * </p>
- * {@code url} can take the following forms:
- * <ul>
- * <li>{@code Style.*}: load one of the bundled styles in {@link Style}.</li>
- * <li>{@code mapbox://styles/<user>/<style>}:
- * retrieves the style from a <a href="https://www.mapbox.com/account/">Mapbox account.</a>
- * {@code user} is your username. {@code style} is the ID of your custom
- * style created in <a href="https://www.mapbox.com/studio">Mapbox Studio</a>.</li>
- * <li>{@code http://...} or {@code https://...}:
- * retrieves the style over the Internet from any web server.</li>
- * <li>{@code asset://...}:
- * reads the style from the APK {@code assets/} directory.
- * This is used to load a style bundled with your app.</li>
- * <li>{@code null}: loads the default {@link Style#MAPBOX_STREETS} style.</li>
- * </ul>
- * <p>
- * This method is asynchronous and will return immediately before the style finishes loading.
- * If you wish to wait for the map to finish loading listen for the {@link MapView#DID_FINISH_LOADING_MAP} event.
- * </p>
- * If the style fails to load or an invalid style URL is set, the map view will become blank.
- * An error message will be logged in the Android logcat and {@link MapView#DID_FAIL_LOADING_MAP} event will be sent.
- *
- * @param url The URL of the map style
- * @see Style
- */
- public void setStyleUrl(@NonNull String url) {
- if (destroyed) {
- return;
- }
-
- // stopgap for https://github.com/mapbox/mapbox-gl-native/issues/6242
- if (TextUtils.isEmpty(nativeMapView.getAccessToken())) {
- setAccessToken(MapboxAccountManager.getInstance().getAccessToken());
- }
-
- styleUrl = url;
- nativeMapView.setStyleUrl(url);
- styleWasSet = true;
- }
-
- /**
- * <p>
- * Loads a new map style from the specified bundled style.
- * </p>
- * <p>
- * This method is asynchronous and will return immediately before the style finishes loading.
- * If you wish to wait for the map to finish loading listen for the {@link MapView#DID_FINISH_LOADING_MAP} event.
- * </p>
- * If the style fails to load or an invalid style URL is set, the map view will become blank.
- * An error message will be logged in the Android logcat and {@link MapView#DID_FAIL_LOADING_MAP} event will be sent.
- *
- * @param style The bundled style. Accepts one of the values from {@link Style}.
- * @see Style
- */
- @UiThread
- public void setStyle(@Style.StyleUrl String style) {
- setStyleUrl(style);
- }
-
- /**
- * <p>
- * Returns the map style currently displayed in the map view.
- * </p>
- * If the default style is currently displayed, a URL will be returned instead of null.
- *
- * @return The URL of the map style.
- */
- @UiThread
- @NonNull
- public String getStyleUrl() {
- return styleUrl;
- }
-
- //
- // API Base URL
- //
-
- @UiThread
- void setApiBaseUrl(@NonNull String baseUrl) {
- nativeMapView.setApiBaseUrl(baseUrl);
- }
-
- //
- // Access token
- //
-
- /**
- * <p>
- * DEPRECATED @see MapboxAccountManager#start(String)
- * </p>
- * <p>
- * Sets the current Mapbox access token used to load map styles and tiles.
- * </p>
- * <p>
- * You must set a valid access token before you call {@link MapView#onCreate(Bundle)}
- * or an exception will be thrown.
- * </p>
- *
- * @param accessToken Your public Mapbox access token.
- * @see MapView#onCreate(Bundle)
- * @deprecated As of release 4.1.0, replaced by {@link com.mapbox.mapboxsdk.MapboxAccountManager#start(Context, String)}
- */
- @Deprecated
- @UiThread
- public void setAccessToken(@NonNull String accessToken) {
- if (destroyed) {
- return;
- }
- // validateAccessToken does the null check
- if (!TextUtils.isEmpty(accessToken)) {
- accessToken = accessToken.trim();
- }
- MapboxAccountManager.validateAccessToken(accessToken);
- nativeMapView.setAccessToken(accessToken);
- }
-
- /**
- * <p>
- * DEPRECATED @see MapboxAccountManager#getAccessToken()
- * </p>
- * <p>
- * Returns the current Mapbox access token used to load map styles and tiles.
- * </p>
- *
- * @return The current Mapbox access token.
- * @deprecated As of release 4.1.0, replaced by {@link MapboxAccountManager#getAccessToken()}
- */
- @Deprecated
- @UiThread
- @Nullable
- public String getAccessToken() {
- if (destroyed) {
- return "";
- }
- return nativeMapView.getAccessToken();
- }
-
- //
- // Projection
- //
-
- /*
- * Internal use only, use Projection#fromScreenLocation instead
- */
- LatLng fromNativeScreenLocation(@NonNull PointF point) {
- if (destroyed) {
- return new LatLng();
- }
- return nativeMapView.latLngForPixel(point);
- }
-
- /*
- * Internal use only, use Projection#toScreenLocation instead.
- */
- PointF toNativeScreenLocation(@NonNull LatLng location) {
- if (destroyed || location == null) {
- return new PointF();
- }
- return nativeMapView.pixelForLatLng(location);
- }
-
- //
- // Annotations
- //
-
- Icon loadIconForMarker(Marker marker) {
- Icon icon = marker.getIcon();
-
- // calculating average before adding
- int iconSize = icons.size() + 1;
-
- // TODO replace former if case with anchor implementation,
- // current workaround for having extra pixels is diving height by 2
- if (icon == null) {
- icon = IconFactory.getInstance(getContext()).defaultMarker();
- Bitmap bitmap = icon.getBitmap();
- averageIconHeight = averageIconHeight + (bitmap.getHeight() / 2 - averageIconHeight) / iconSize;
- averageIconWidth = averageIconWidth + (bitmap.getWidth() - averageIconWidth) / iconSize;
- marker.setIcon(icon);
- } else {
- Bitmap bitmap = icon.getBitmap();
- averageIconHeight = averageIconHeight + (bitmap.getHeight() - averageIconHeight) / iconSize;
- averageIconWidth = averageIconWidth + (bitmap.getWidth() - averageIconWidth) / iconSize;
- }
-
- if (!icons.contains(icon)) {
- icons.add(icon);
- loadIcon(icon);
- } else {
- Icon oldIcon = icons.get(icons.indexOf(icon));
- if (!oldIcon.getBitmap().sameAs(icon.getBitmap())) {
- throw new IconBitmapChangedException();
- }
- }
- return icon;
- }
-
- Icon loadIconForMarkerView(MarkerView marker) {
- Icon icon = marker.getIcon();
- int iconSize = icons.size() + 1;
- if (icon == null) {
- icon = IconFactory.getInstance(getContext()).defaultMarkerView();
- marker.setIcon(icon);
- }
- Bitmap bitmap = icon.getBitmap();
- averageIconHeight = averageIconHeight + (bitmap.getHeight() - averageIconHeight) / iconSize;
- averageIconWidth = averageIconWidth + (bitmap.getWidth() - averageIconWidth) / iconSize;
- if (!icons.contains(icon)) {
- icons.add(icon);
- } else {
- Icon oldIcon = icons.get(icons.indexOf(icon));
- if (!oldIcon.getBitmap().sameAs(icon.getBitmap())) {
- throw new IconBitmapChangedException();
- }
- }
- return icon;
- }
-
- void loadIcon(Icon icon) {
- if (destroyed) {
- return;
- }
- Bitmap bitmap = icon.getBitmap();
- String id = icon.getId();
- if (bitmap.getConfig() != Bitmap.Config.ARGB_8888) {
- bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, false);
- }
- ByteBuffer buffer = ByteBuffer.allocate(bitmap.getRowBytes() * bitmap.getHeight());
- bitmap.copyPixelsToBuffer(buffer);
-
- float density = bitmap.getDensity();
- if (density == Bitmap.DENSITY_NONE) {
- density = DisplayMetrics.DENSITY_DEFAULT;
- }
- float scale = density / DisplayMetrics.DENSITY_DEFAULT;
- nativeMapView.addAnnotationIcon(
- id,
- bitmap.getWidth(),
- bitmap.getHeight(),
- scale, buffer.array());
- }
-
- void reloadIcons() {
- int count = icons.size();
- for (int i = 0; i < count; i++) {
- Icon icon = icons.get(i);
- loadIcon(icon);
- }
- }
-
- void updateMarker(@NonNull Marker updatedMarker) {
- if (destroyed) {
- return;
- }
- if (updatedMarker == null) {
- Log.w(MapboxConstants.TAG, "marker was null, doing nothing");
- return;
- }
-
- if (updatedMarker.getId() == -1) {
- Log.w(MapboxConstants.TAG, "marker has an id of -1, possibly was not added yet, doing nothing");
- return;
- }
-
- if (!(updatedMarker instanceof MarkerView)) {
- ensureIconLoaded(updatedMarker);
- }
-
- nativeMapView.updateMarker(updatedMarker);
- }
-
-
- void updatePolygon(Polygon polygon) {
- if (destroyed) {
- return;
- }
-
- if (polygon == null) {
- Log.w(MapboxConstants.TAG, "polygon was null, doing nothing");
- return;
- }
-
- if (polygon.getId() == -1) {
- Log.w(MapboxConstants.TAG, "polygon has an id of -1, indicating the polygon was not added to the map yet.");
- return;
- }
-
- nativeMapView.updatePolygon(polygon);
- }
-
- void updatePolyline(Polyline polyline) {
- if (destroyed) {
- return;
- }
-
- if (polyline == null) {
- Log.w(MapboxConstants.TAG, "polygon was null, doing nothing");
- return;
- }
-
- if (polyline.getId() == -1) {
- Log.w(MapboxConstants.TAG, "polygon has an id of -1, indicating the polygon was not added to the map yet.");
- return;
- }
-
- nativeMapView.updatePolyline(polyline);
- }
-
- private void ensureIconLoaded(Marker marker) {
- Icon icon = marker.getIcon();
- if (icon == null) {
- icon = IconFactory.getInstance(getContext()).defaultMarker();
- marker.setIcon(icon);
- }
- if (!icons.contains(icon)) {
- icons.add(icon);
- loadIcon(icon);
- } else {
- Icon oldIcon = icons.get(icons.indexOf(icon));
- if (!oldIcon.getBitmap().sameAs(icon.getBitmap())) {
- throw new IconBitmapChangedException();
- }
- }
-
- // this seems to be a costly operation according to the profiler so I'm trying to save some calls
- Marker previousMarker = marker.getId() != -1 ? (Marker) mapboxMap.getAnnotation(marker.getId()) : null;
- if (previousMarker == null || previousMarker.getIcon() == null || previousMarker.getIcon() != marker.getIcon()) {
- marker.setTopOffsetPixels(getTopOffsetPixelsForIcon(icon));
- }
- }
-
- long addMarker(@NonNull Marker marker) {
- if (destroyed) {
- return 0L;
- }
- return nativeMapView.addMarker(marker);
- }
-
- long[] addMarkers(@NonNull List<Marker> markerList) {
- if (destroyed) {
- return new long[]{};
- }
- return nativeMapView.addMarkers(markerList);
- }
-
- long addPolyline(@NonNull Polyline polyline) {
- if (destroyed) {
- return 0L;
- }
- return nativeMapView.addPolyline(polyline);
- }
-
- long[] addPolylines(@NonNull List<Polyline> polylines) {
- if (destroyed) {
- return new long[]{};
- }
- return nativeMapView.addPolylines(polylines);
- }
-
- long addPolygon(@NonNull Polygon polygon) {
- if (destroyed) {
- return 0L;
- }
- return nativeMapView.addPolygon(polygon);
- }
-
- long[] addPolygons(@NonNull List<Polygon> polygons) {
- if (destroyed) {
- return new long[]{};
- }
- return nativeMapView.addPolygons(polygons);
- }
-
- void removeAnnotation(long id) {
- if (destroyed) {
- return;
- }
- nativeMapView.removeAnnotation(id);
- }
-
- void removeAnnotations(@NonNull long[] ids) {
- if (destroyed) {
- return;
- }
- nativeMapView.removeAnnotations(ids);
- }
-
- List<Marker> getMarkersInRect(@NonNull RectF rect) {
- if (destroyed || rect == null) {
- return new ArrayList<>();
- }
-
- long[] ids = nativeMapView.queryPointAnnotations(rect);
-
- List<Long> idsList = new ArrayList<>(ids.length);
- for (int i = 0; i < ids.length; i++) {
- idsList.add(ids[i]);
- }
-
- List<Marker> annotations = new ArrayList<>(ids.length);
- List<Annotation> annotationList = mapboxMap.getAnnotations();
- int count = annotationList.size();
- for (int i = 0; i < count; i++) {
- Annotation annotation = annotationList.get(i);
- if (annotation instanceof Marker && idsList.contains(annotation.getId())) {
- annotations.add((Marker) annotation);
- }
- }
-
- return new ArrayList<>(annotations);
- }
-
- public List<MarkerView> getMarkerViewsInRect(@NonNull RectF rect) {
- if (destroyed || rect == null) {
- return new ArrayList<>();
- }
-
- long[] ids = nativeMapView.queryPointAnnotations(rect);
-
- List<Long> idsList = new ArrayList<>(ids.length);
- for (int i = 0; i < ids.length; i++) {
- idsList.add(ids[i]);
- }
-
- List<MarkerView> annotations = new ArrayList<>(ids.length);
- List<Annotation> annotationList = mapboxMap.getAnnotations();
- int count = annotationList.size();
- for (int i = 0; i < count; i++) {
- Annotation annotation = annotationList.get(i);
- if (annotation instanceof MarkerView) {
- annotations.add((MarkerView) annotation);
- }
- }
-
- return new ArrayList<>(annotations);
- }
-
- /**
- * @return the ViewGroup containing the marker views
- */
- public ViewGroup getMarkerViewContainer() {
- return markerViewContainer;
- }
-
-
- int getTopOffsetPixelsForIcon(Icon icon) {
- if (destroyed) {
- return 0;
+ private NativeMapView nativeMapView;
+ private boolean destroyed;
+ private boolean hasSurface = false;
+
+ private MapboxMap mapboxMap;
+ private MapCallback mapCallback;
+ private boolean onStartCalled;
+ private boolean onStopCalled;
+
+ private MapGestureDetector mapGestureDetector;
+ private MapKeyListener mapKeyListener;
+ private MapZoomButtonController mapZoomButtonController;
+
+ private ConnectivityReceiver connectivityReceiver;
+ private SnapshotRequest snapshotRequest;
+
+ @UiThread
+ public MapView(@NonNull Context context) {
+ super(context);
+ initialise(context, MapboxMapOptions.createFromAttributes(context, null));
+ }
+
+ @UiThread
+ public MapView(@NonNull Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ initialise(context, MapboxMapOptions.createFromAttributes(context, attrs));
+ }
+
+ @UiThread
+ public MapView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ initialise(context, MapboxMapOptions.createFromAttributes(context, attrs));
+ }
+
+ @UiThread
+ public MapView(@NonNull Context context, @NonNull MapboxMapOptions options) {
+ super(context);
+ initialise(context, options);
+ }
+
+ private void initialise(@NonNull final Context context, @NonNull final MapboxMapOptions options) {
+ if (isInEditMode()) {
+ // in IDE, show preview map
+ LayoutInflater.from(context).inflate(R.layout.mapbox_mapview_preview, this);
+ return;
+ }
+
+ // inflate view
+ View view = LayoutInflater.from(context).inflate(R.layout.mapbox_mapview_internal, this);
+ CompassView compassView = (CompassView) view.findViewById(R.id.compassView);
+ MyLocationView myLocationView = (MyLocationView) view.findViewById(R.id.userLocationView);
+ ImageView attrView = (ImageView) view.findViewById(R.id.attributionView);
+ initalizeDrawingSurface(context, options);
+
+ // create native Map object
+ nativeMapView = new NativeMapView(this);
+
+ // callback for focal point invalidation
+ FocalPointInvalidator focalPoint = new FocalPointInvalidator();
+
+ // callback for registering touch listeners
+ RegisterTouchListener registerTouchListener = new RegisterTouchListener();
+
+ // setup components for MapboxMap creation
+ Projection proj = new Projection(nativeMapView);
+ UiSettings uiSettings = new UiSettings(proj, focalPoint, compassView, attrView, view.findViewById(R.id.logoView));
+ TrackingSettings trackingSettings = new TrackingSettings(myLocationView, uiSettings, focalPoint);
+ MyLocationViewSettings myLocationViewSettings = new MyLocationViewSettings(myLocationView, proj, focalPoint);
+ MarkerViewManager markerViewManager = new MarkerViewManager((ViewGroup) findViewById(R.id.markerViewContainer));
+ AnnotationManager annotations = new AnnotationManager(nativeMapView, this, markerViewManager);
+ Transform transform = new Transform(nativeMapView, annotations.getMarkerViewManager(), trackingSettings);
+ mapboxMap = new MapboxMap(nativeMapView, transform, uiSettings, trackingSettings, myLocationViewSettings, proj,
+ registerTouchListener, annotations);
+
+ // user input
+ mapGestureDetector = new MapGestureDetector(context, transform, proj, uiSettings, trackingSettings, annotations);
+ mapKeyListener = new MapKeyListener(transform, trackingSettings, uiSettings);
+ mapZoomButtonController = new MapZoomButtonController(this, uiSettings, transform);
+
+ // inject widgets with MapboxMap
+ compassView.setMapboxMap(mapboxMap);
+ myLocationView.setMapboxMap(mapboxMap);
+ attrView.setOnClickListener(new AttributionOnClickListener(context, transform));
+
+ // Ensure this view is interactable
+ setClickable(true);
+ setLongClickable(true);
+ setFocusable(true);
+ setFocusableInTouchMode(true);
+ requestDisallowInterceptTouchEvent(true);
+
+ // allow onDraw invocation
+ setWillNotDraw(false);
+
+ // notify Map object about current connectivity state
+ nativeMapView.setReachability(isConnected());
+
+ // initialise MapboxMap
+ mapboxMap.initialise(context, options);
+ }
+
+ private void initalizeDrawingSurface(Context context, MapboxMapOptions options) {
+ if (options.getTextureMode()) {
+ TextureView textureView = new TextureView(context);
+ textureView.setSurfaceTextureListener(new SurfaceTextureListener());
+ addView(textureView, 0);
+ } else {
+ SurfaceView surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
+ surfaceView.getHolder().addCallback(new SurfaceCallback());
+ surfaceView.setVisibility(View.VISIBLE);
+ }
+ }
+
+ //
+ // Lifecycle events
+ //
+
+ /**
+ * <p>
+ * You must call this method from the parent's {@link android.app.Activity#onCreate(Bundle)} or
+ * {@link android.app.Fragment#onCreate(Bundle)}.
+ * </p>
+ * You must set a valid access token with {@link Mapbox#getInstance(Context, String)}) before you call this method
+ * or an exception will be thrown.
+ *
+ * @param savedInstanceState Pass in the parent's savedInstanceState.
+ * @see Mapbox#getInstance(Context, String)
+ */
+ @UiThread
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ Mapbox.validateAccessToken();
+ nativeMapView.setAccessToken(Mapbox.getAccessToken());
+
+ if (savedInstanceState == null) {
+ MapboxEvent.trackMapLoadEvent();
+ } else if (savedInstanceState.getBoolean(MapboxConstants.STATE_HAS_SAVED_STATE)) {
+ mapboxMap.onRestoreInstanceState(savedInstanceState);
+ }
+
+ // Initialize EGL
+ nativeMapView.initializeDisplay();
+ nativeMapView.initializeContext();
+
+ addOnMapChangedListener(mapCallback = new MapCallback(mapboxMap));
+ }
+
+ /**
+ * You must call this method from the parent's {@link android.app.Activity#onSaveInstanceState(Bundle)}
+ * or {@link android.app.Fragment#onSaveInstanceState(Bundle)}.
+ *
+ * @param outState Pass in the parent's outState.
+ */
+
+ @UiThread
+ public void onSaveInstanceState(@NonNull Bundle outState) {
+ outState.putBoolean(MapboxConstants.STATE_HAS_SAVED_STATE, true);
+ mapboxMap.onSaveInstanceState(outState);
+ }
+
+ /**
+ * You must call this method from the parent's {@link Activity#onStart()} or {@link Fragment#onStart()}
+ */
+ @UiThread
+ public void onStart() {
+ onStartCalled = true;
+ mapboxMap.onStart();
+ registerConnectivityReceiver();
+ }
+
+ /**
+ * You must call this method from the parent's {@link Activity#onResume()} or {@link Fragment#onResume()}.
+ */
+ @UiThread
+ public void onResume() {
+ if (!onStartCalled) {
+ // TODO: 26/10/16, can be removed after 5.0.0 release
+ throw new IllegalStateException("MapView#onStart() was not called. "
+ + "You must call this method from the parent's {@link Activity#onStart()} or {@link Fragment#onStart()}.");
+ }
+ }
+
+ /**
+ * You must call this method from the parent's {@link Activity#onPause()} or {@link Fragment#onPause()}.
+ */
+ @UiThread
+ public void onPause() {
+ // replaced by onStop in v5.0.0, keep around for future development
+ }
+
+ /**
+ * You must call this method from the parent's {@link Activity#onStop()} or {@link Fragment#onStop()}.
+ */
+ @UiThread
+ public void onStop() {
+ onStopCalled = true;
+ mapboxMap.onStop();
+ unregisterConnectivityReceiver();
+ }
+
+ /**
+ * You must call this method from the parent's {@link Activity#onDestroy()} or {@link Fragment#onDestroy()}.
+ */
+ @UiThread
+ public void onDestroy() {
+ if (!onStopCalled) {
+ // TODO: 26/10/16, can be removed after 5.0.0 release
+ throw new IllegalStateException("MapView#onStop() was not called. "
+ + "You must call this method from the parent's {@link Activity#onStop()} or {@link Fragment#onStop()}.");
+ }
+
+ destroyed = true;
+ nativeMapView.terminateContext();
+ nativeMapView.terminateDisplay();
+ nativeMapView.destroySurface();
+ nativeMapView.destroy();
+ nativeMapView = null;
+ }
+
+ private void registerConnectivityReceiver() {
+ getContext().registerReceiver(connectivityReceiver = new ConnectivityReceiver(),
+ new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
+ }
+
+ private void unregisterConnectivityReceiver() {
+ if (connectivityReceiver != null) {
+ getContext().unregisterReceiver(connectivityReceiver);
+ connectivityReceiver = null;
+ }
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ mapZoomButtonController.setVisible(true);
+ }
+ return mapGestureDetector.onTouchEvent(event) || super.onTouchEvent(event);
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ return mapKeyListener.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event);
+ }
+
+ @Override
+ public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+ return mapKeyListener.onKeyLongPress(keyCode, event) || super.onKeyLongPress(keyCode, event);
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ return mapKeyListener.onKeyUp(keyCode, event) || super.onKeyUp(keyCode, event);
+ }
+
+ @Override
+ public boolean onTrackballEvent(MotionEvent event) {
+ return mapKeyListener.onTrackballEvent(event) || super.onTrackballEvent(event);
+ }
+
+ @Override
+ public boolean onGenericMotionEvent(MotionEvent event) {
+ return mapGestureDetector.onGenericMotionEvent(event) || super.onGenericMotionEvent(event);
+ }
+
+ @Override
+ public boolean onHoverEvent(MotionEvent event) {
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_HOVER_ENTER:
+ case MotionEvent.ACTION_HOVER_MOVE:
+ mapZoomButtonController.setVisible(true);
+ return true;
+
+ case MotionEvent.ACTION_HOVER_EXIT:
+ mapZoomButtonController.setVisible(false);
+ return true;
+
+ default:
+ // We are not interested in this event
+ return false;
+ }
+ }
+
+ /**
+ * You must call this method from the parent's {@link Activity#onLowMemory()} or {@link Fragment#onLowMemory()}.
+ */
+ @UiThread
+ public void onLowMemory() {
+ nativeMapView.onLowMemory();
+ }
+
+ // Called when debug mode is enabled to update a FPS counter
+ // Called via JNI from NativeMapView
+ // Forward to any listener
+ protected void onFpsChanged(final double fps) {
+ final MapboxMap.OnFpsChangedListener listener = mapboxMap.getOnFpsChangedListener();
+ if (listener != null) {
+ post(new Runnable() {
+ @Override
+ public void run() {
+ listener.onFpsChanged(fps);
}
-
- return (int) (nativeMapView.getTopOffsetPixelsForAnnotationSymbol(icon.getId())
- * screenDensity);
+ });
}
+ }
- void setContentPadding(int left, int top, int right, int bottom) {
- if (destroyed) {
- return;
- }
-
-// if (left == contentPaddingLeft && top == contentPaddingTop && right == contentPaddingRight && bottom == contentPaddingBottom) {
-// return;
-// }
-
- contentPaddingLeft = left;
- contentPaddingTop = top;
- contentPaddingRight = right;
- contentPaddingBottom = bottom;
-
- int[] userLocationViewPadding = mapboxMap.getMyLocationViewSettings().getPadding();
- left += userLocationViewPadding[0];
- top += userLocationViewPadding[1];
- right += userLocationViewPadding[2];
- bottom += userLocationViewPadding[3];
-
- nativeMapView.setContentPadding(top / screenDensity, left / screenDensity, bottom / screenDensity, right / screenDensity);
+ /**
+ * <p>
+ * Loads a new map style from the specified URL.
+ * </p>
+ * {@code url} can take the following forms:
+ * <ul>
+ * <li>{@code Style.*}: load one of the bundled styles in {@link Style}.</li>
+ * <li>{@code mapbox://styles/<user>/<style>}:
+ * retrieves the style from a <a href="https://www.mapbox.com/account/">Mapbox account.</a>
+ * {@code user} is your username. {@code style} is the ID of your custom
+ * style created in <a href="https://www.mapbox.com/studio">Mapbox Studio</a>.</li>
+ * <li>{@code http://...} or {@code https://...}:
+ * retrieves the style over the Internet from any web server.</li>
+ * <li>{@code asset://...}:
+ * reads the style from the APK {@code assets/} directory.
+ * This is used to load a style bundled with your app.</li>
+ * <li>{@code null}: loads the default {@link Style#MAPBOX_STREETS} style.</li>
+ * </ul>
+ * <p>
+ * This method is asynchronous and will return immediately before the style finishes loading.
+ * If you wish to wait for the map to finish loading listen for the {@link MapView#DID_FINISH_LOADING_MAP} event.
+ * </p>
+ * If the style fails to load or an invalid style URL is set, the map view will become blank.
+ * An error message will be logged in the Android logcat and {@link MapView#DID_FAIL_LOADING_MAP} event will be sent.
+ *
+ * @param url The URL of the map style
+ * @see Style
+ */
+ public void setStyleUrl(@NonNull String url) {
+ if (destroyed) {
+ return;
}
- public void invalidateContentPadding() {
- setContentPadding(contentPaddingLeft, contentPaddingTop, contentPaddingRight, contentPaddingBottom);
-
- if (!mapboxMap.getTrackingSettings().isLocationTrackingDisabled()) {
- setFocalPoint(new PointF(myLocationView.getCenterX(), myLocationView.getCenterY()));
- } else {
- setFocalPoint(null);
- }
+ // stopgap for https://github.com/mapbox/mapbox-gl-native/issues/6242
+ if (TextUtils.isEmpty(nativeMapView.getAccessToken())) {
+ Mapbox.validateAccessToken();
+ nativeMapView.setAccessToken(Mapbox.getAccessToken());
}
- double getMetersPerPixelAtLatitude(@FloatRange(from = -180, to = 180) double latitude) {
- if (destroyed) {
- return 0;
- }
+ nativeMapView.setStyleUrl(url);
+ }
- return nativeMapView.getMetersPerPixelAtLatitude(latitude, getZoom()) / screenDensity;
- }
+ //
+ // Rendering
+ //
- //
- // Mapbox Core GL Camera
- //
+ // Called when the map needs to be rerendered
+ // Called via JNI from NativeMapView
+ protected void onInvalidate() {
+ postInvalidate();
+ }
- void jumpTo(double bearing, LatLng center, double pitch, double zoom) {
- if (destroyed) {
- return;
- }
- nativeMapView.cancelTransitions();
- nativeMapView.jumpTo(bearing, center, pitch, zoom);
+ @Override
+ public void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ if (isInEditMode()) {
+ return;
}
- void easeTo(double bearing, LatLng center, long duration, double pitch, double zoom, boolean easingInterpolator, @Nullable final MapboxMap.CancelableCallback cancelableCallback) {
- if (destroyed) {
- return;
- }
- nativeMapView.cancelTransitions();
-
- // Register callbacks early enough
- if (cancelableCallback != null) {
- addOnMapChangedListener(new OnMapChangedListener() {
- @Override
- public void onMapChanged(@MapChange int change) {
- if (change == REGION_DID_CHANGE_ANIMATED) {
- cancelableCallback.onFinish();
-
- // Clean up after self
- removeOnMapChangedListener(this);
- }
- }
- });
- }
-
- nativeMapView.easeTo(bearing, center, duration, pitch, zoom, easingInterpolator);
+ if (destroyed) {
+ return;
}
- void flyTo(double bearing, LatLng center, long duration, double pitch, double zoom, @Nullable final MapboxMap.CancelableCallback cancelableCallback) {
- if (destroyed) {
- return;
- }
- nativeMapView.cancelTransitions();
-
- // Register callbacks early enough
- if (cancelableCallback != null) {
- addOnMapChangedListener(new OnMapChangedListener() {
- @Override
- public void onMapChanged(@MapChange int change) {
- if (change == REGION_DID_CHANGE_ANIMATED) {
- cancelableCallback.onFinish();
-
- // Clean up after self
- removeOnMapChangedListener(this);
- }
- }
- });
- }
-
- nativeMapView.flyTo(bearing, center, duration, pitch, zoom);
+ if (!hasSurface) {
+ return;
}
- private void adjustTopOffsetPixels() {
- List<Annotation> annotations = mapboxMap.getAnnotations();
- int count = annotations.size();
- for (int i = 0; i < count; i++) {
- Annotation annotation = annotations.get(i);
- if (annotation instanceof Marker) {
- Marker marker = (Marker) annotation;
- marker.setTopOffsetPixels(
- getTopOffsetPixelsForIcon(marker.getIcon()));
- }
- }
+ nativeMapView.render();
+ }
- for (Marker marker : mapboxMap.getSelectedMarkers()) {
- if (marker.isInfoWindowShown()) {
- marker.hideInfoWindow();
- marker.showInfoWindow(mapboxMap, this);
- }
- }
+ @Override
+ protected void onSizeChanged(int width, int height, int oldw, int oldh) {
+ if (destroyed) {
+ return;
}
- private void reloadMarkers() {
- if (destroyed) {
- return;
- }
- List<Annotation> annotations = mapboxMap.getAnnotations();
- int count = annotations.size();
- for (int i = 0; i < count; i++) {
- Annotation annotation = annotations.get(i);
- if (annotation instanceof Marker) {
- Marker marker = (Marker) annotation;
- nativeMapView.removeAnnotation(annotation.getId());
- long newId = nativeMapView.addMarker(marker);
- marker.setId(newId);
- }
- }
+ if (!isInEditMode()) {
+ nativeMapView.resizeView(width, height);
}
+ }
- //
- // Rendering
- //
+ private class SurfaceCallback implements SurfaceHolder.Callback {
- // Called when the map needs to be rerendered
- // Called via JNI from NativeMapView
- protected void onInvalidate() {
- postInvalidate();
- }
+ private Surface surface;
@Override
- public void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- if (isInEditMode()) {
- return;
- }
-
- if (destroyed) {
- return;
- }
-
- if (!hasSurface) {
- return;
- }
-
- nativeMapView.render();
+ public void surfaceCreated(SurfaceHolder holder) {
+ nativeMapView.createSurface(surface = holder.getSurface());
+ hasSurface = true;
}
@Override
- protected void onSizeChanged(int width, int height, int oldw, int oldh) {
- if (destroyed) {
- return;
- }
-
- if (!isInEditMode()) {
- nativeMapView.resizeView((int) (width / screenDensity), (int) (height / screenDensity));
- }
- }
-
- double getScale() {
- if (destroyed) {
- return 0;
- }
-
- return nativeMapView.getScale();
- }
-
- private class SurfaceCallback implements SurfaceHolder.Callback {
-
- private Surface surface;
-
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- nativeMapView.createSurface(surface = holder.getSurface());
- hasSurface = true;
- }
-
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
- if (destroyed) {
- return;
- }
- nativeMapView.resizeFramebuffer(width, height);
- }
-
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- hasSurface = false;
-
- if (nativeMapView != null) {
- nativeMapView.destroySurface();
- }
- surface.release();
- }
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ if (destroyed) {
+ return;
+ }
+ nativeMapView.resizeFramebuffer(width, height);
}
- // This class handles TextureView callbacks
- private class SurfaceTextureListener implements TextureView.SurfaceTextureListener {
-
- private Surface surface;
-
- // Called when the native surface texture has been created
- // Must do all EGL/GL ES initialization here
- @Override
- public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
- nativeMapView.createSurface(this.surface = new Surface(surface));
- nativeMapView.resizeFramebuffer(width, height);
- hasSurface = true;
- }
-
- // Called when the native surface texture has been destroyed
- // Must do all EGL/GL ES destruction here
- @Override
- public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
- hasSurface = false;
-
- if (nativeMapView != null) {
- nativeMapView.destroySurface();
- }
- this.surface.release();
- return true;
- }
-
- // Called when the format or size of the native surface texture has been changed
- // Must handle window resizing here.
- @Override
- public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
- if (destroyed) {
- return;
- }
-
- nativeMapView.resizeFramebuffer(width, height);
- }
-
- // Called when the SurfaceTexure frame is drawn to screen
- // Must sync with UI here
- @Override
- public void onSurfaceTextureUpdated(SurfaceTexture surface) {
- if (destroyed) {
- return;
- }
- compassView.update(getDirection());
- myLocationView.update();
- mapboxMap.getMarkerViewManager().update();
-
- for (InfoWindow infoWindow : mapboxMap.getInfoWindows()) {
- infoWindow.update();
- }
- }
- }
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ hasSurface = false;
- CameraPosition invalidateCameraPosition() {
- if (destroyed) {
- return new CameraPosition.Builder().build();
- }
- CameraPosition position = new CameraPosition.Builder(nativeMapView.getCameraValues()).build();
- myLocationView.setCameraPosition(position);
- mapboxMap.getMarkerViewManager().setTilt((float) position.tilt);
- return position;
+ if (nativeMapView != null) {
+ nativeMapView.destroySurface();
+ }
+ surface.release();
}
+ }
- double getBearing() {
- if (destroyed) {
- return 0;
- }
-
- double direction = -nativeMapView.getBearing();
-
- while (direction > 360) {
- direction -= 360;
- }
- while (direction < 0) {
- direction += 360;
- }
+ // This class handles TextureView callbacks
+ private class SurfaceTextureListener implements TextureView.SurfaceTextureListener {
- return direction;
- }
+ private Surface surface;
- void setBearing(float bearing) {
- if (destroyed) {
- return;
- }
- myLocationView.setBearing(bearing);
- nativeMapView.setBearing(bearing);
+ // Called when the native surface texture has been created
+ // Must do all EGL/GL ES initialization here
+ @Override
+ public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
+ nativeMapView.createSurface(this.surface = new Surface(surface));
+ nativeMapView.resizeFramebuffer(width, height);
+ hasSurface = true;
}
- void setBearing(float bearing, long duration) {
- if (destroyed) {
- return;
- }
- myLocationView.setBearing(bearing);
- nativeMapView.setBearing(bearing, duration);
- }
+ // Called when the native surface texture has been destroyed
+ // Must do all EGL/GL ES destruction here
+ @Override
+ public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
+ hasSurface = false;
- void setBearing(double bearing, float focalX, float focalY) {
- if (destroyed) {
- return;
- }
- myLocationView.setBearing(bearing);
- nativeMapView.setBearing(bearing, focalX, focalY);
+ if (nativeMapView != null) {
+ nativeMapView.destroySurface();
+ }
+ this.surface.release();
+ return true;
}
- //
- // View events
- //
-
- // Called when view is no longer connected
+ // Called when the format or size of the native surface texture has been changed
+ // Must handle window resizing here.
@Override
- @CallSuper
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- // Required by ZoomButtonController (from Android SDK documentation)
- if (mapboxMap.getUiSettings().isZoomControlsEnabled()) {
- zoomButtonsController.setVisible(false);
- }
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+ if (destroyed) {
+ return;
+ }
- // make sure we don't leak location listener
- if (myLocationListener != null) {
- // cleanup to prevent memory leak
- LocationServices services = LocationServices.getLocationServices(getContext());
- services.removeLocationListener(myLocationListener);
- myLocationListener = null;
- }
+ nativeMapView.resizeFramebuffer(width, height);
}
- // Called when view is hidden and shown
+ // Called when the SurfaceTexure frame is drawn to screen
+ // Must sync with UI here
@Override
- protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
- if (isInEditMode()) {
- return;
- }
+ public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+ if (destroyed) {
+ return;
+ }
+ mapboxMap.onUpdate();
+ }
+ }
+
+ //
+ // View events
+ //
+
+ // Called when view is no longer connected
+ @Override
+ @CallSuper
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mapZoomButtonController.setVisible(false);
+ }
+
+ // Called when view is hidden and shown
+ @Override
+ protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
+ if (isInEditMode()) {
+ return;
+ }
+ mapZoomButtonController.setVisible(visibility == View.VISIBLE);
+ }
+
+ //
+ // Connectivity events
+ //
+
+ // This class handles connectivity changes
+ private class ConnectivityReceiver extends BroadcastReceiver {
+
+ // Called when an action we are listening to in the manifest has been sent
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!destroyed && intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
+ nativeMapView.setReachability(!intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false));
+ }
+ }
+ }
+
+ // Called when MapView is being created
+ private boolean isConnected() {
+ ConnectivityManager connectivityManager = (ConnectivityManager)
+ getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+ NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
+ return (activeNetwork != null) && activeNetwork.isConnectedOrConnecting();
+ }
+
+ //
+ // Map events
+ //
+
+ /**
+ * <p>
+ * Add a callback that's invoked when the displayed map view changes.
+ * </p>
+ * To remove the callback, use {@link MapView#removeOnMapChangedListener(OnMapChangedListener)}.
+ *
+ * @param listener The callback that's invoked on every frame rendered to the map view.
+ * @see MapView#removeOnMapChangedListener(OnMapChangedListener)
+ */
+ public void addOnMapChangedListener(@Nullable OnMapChangedListener listener) {
+ if (listener != null) {
+ nativeMapView.addOnMapChangedListener(listener);
+ }
+ }
+
+ /**
+ * Remove a callback added with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}
+ *
+ * @param listener The previously added callback to remove.
+ * @see MapView#addOnMapChangedListener(OnMapChangedListener)
+ */
+ public void removeOnMapChangedListener(@Nullable OnMapChangedListener listener) {
+ if (listener != null) {
+ nativeMapView.removeOnMapChangedListener(listener);
+ }
+ }
+
+ // Called when the map view transformation has changed
+ // Called via JNI from NativeMapView
+ // Forward to any listeners
+ protected void onMapChanged(int mapChange) {
+ nativeMapView.onMapChangedEventDispatch(mapChange);
+ }
+
+
+ /**
+ * Sets a callback object which will be triggered when the {@link MapboxMap} instance is ready to be used.
+ *
+ * @param callback The callback object that will be triggered when the map is ready to be used.
+ */
+ @UiThread
+ public void getMapAsync(final OnMapReadyCallback callback) {
+ if (!mapCallback.isInitialLoad() && callback != null) {
+ callback.onMapReady(mapboxMap);
+ } else {
+ if (callback != null) {
+ mapCallback.addOnMapReadyCallback(callback);
+ }
+ }
+ }
+
+ MapboxMap getMapboxMap() {
+ return mapboxMap;
+ }
+
+ void setMapboxMap(MapboxMap mapboxMap) {
+ this.mapboxMap = mapboxMap;
+ }
+
+ //
+ // Snapshot API
+ //
+
+ @UiThread
+ void snapshot(@NonNull final MapboxMap.SnapshotReadyCallback callback, @Nullable final Bitmap bitmap) {
+ snapshotRequest = new SnapshotRequest(bitmap, callback);
+ nativeMapView.scheduleTakeSnapshot();
+ nativeMapView.render();
+ }
+
+ // Called when the snapshot method was executed
+ // Called via JNI from NativeMapView
+ // Forward to any listeners
+ protected void onSnapshotReady(byte[] bytes) {
+ if (snapshotRequest != null && bytes != null) {
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inBitmap = snapshotRequest.getBitmap(); // the old Bitmap to be reused
+ options.inMutable = true;
+ options.inSampleSize = 1;
+ Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
+
+ MapboxMap.SnapshotReadyCallback callback = snapshotRequest.getCallback();
+ if (callback != null) {
+ callback.onSnapshotReady(bitmap);
+ }
+ }
+ }
+
+ private class SnapshotRequest {
+ private Bitmap bitmap;
+ private MapboxMap.SnapshotReadyCallback callback;
+
+ SnapshotRequest(Bitmap bitmap, MapboxMap.SnapshotReadyCallback callback) {
+ this.bitmap = bitmap;
+ this.callback = callback;
+ }
+
+ public Bitmap getBitmap() {
+ return bitmap;
+ }
+
+ public MapboxMap.SnapshotReadyCallback getCallback() {
+ return callback;
+ }
+ }
+
+ private static class AttributionOnClickListener implements View.OnClickListener, DialogInterface.OnClickListener {
+
+ private static final int ATTRIBUTION_INDEX_IMPROVE_THIS_MAP = 2;
+ private static final int ATTRIBUTION_INDEX_TELEMETRY_SETTINGS = 3;
+ private Context context;
+ private Transform transform;
- // Required by ZoomButtonController (from Android SDK documentation)
- if (visibility == View.VISIBLE) {
- if (mapboxMap != null && mapboxMap.getUiSettings().isZoomControlsEnabled()) {
- zoomButtonsController.setVisible(true);
- }
- } else {
- if (mapboxMap != null && mapboxMap.getUiSettings().isZoomControlsEnabled()) {
- zoomButtonsController.setVisible(false);
- }
- }
+ public AttributionOnClickListener(Context context, Transform transform) {
+ this.context = context;
+ this.transform = transform;
+ }
+
+ // Called when someone presses the attribution icon
+ @Override
+ public void onClick(View view) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.mapbox_AlertDialogStyle);
+ builder.setTitle(R.string.mapbox_attributionsDialogTitle);
+ String[] items = context.getResources().getStringArray(R.array.mapbox_attribution_names);
+ builder.setAdapter(new ArrayAdapter<>(context, R.layout.mapbox_attribution_list_item, items), this);
+ builder.show();
}
- //
- // Touch events
- //
-
- /**
- * Helper method for tracking gesture events
- *
- * @param gestureId Type of Gesture See {@see MapboxEvent#GESTURE_SINGLETAP MapboxEvent#GESTURE_DOUBLETAP MapboxEvent#GESTURE_TWO_FINGER_SINGLETAP MapboxEvent#GESTURE_QUICK_ZOOM MapboxEvent#GESTURE_PAN_START MapboxEvent#GESTURE_PINCH_START MapboxEvent#GESTURE_ROTATION_START MapboxEvent#GESTURE_PITCH_START}
- * @param xCoordinate Original x screen coordinate at start of gesture
- * @param yCoordinate Original y screen cooridnate at start of gesture
- */
- private void trackGestureEvent(@NonNull String gestureId, @NonNull float xCoordinate, @NonNull float yCoordinate) {
- LatLng tapLatLng = projection.fromScreenLocation(new PointF(xCoordinate, yCoordinate));
-
- // NaN and Infinite checks to prevent JSON errors at send to server time
- if (Double.isNaN(tapLatLng.getLatitude()) || Double.isNaN(tapLatLng.getLongitude())) {
- Log.d(MapView.class.getSimpleName(), "trackGestureEvent() has a NaN lat or lon. Returning.");
- return;
- }
-
- if (Double.isInfinite(tapLatLng.getLatitude()) || Double.isInfinite(tapLatLng.getLongitude())) {
- Log.d(MapView.class.getSimpleName(), "trackGestureEvent() has an Infinite lat or lon. Returning.");
- return;
- }
-
- Hashtable<String, Object> evt = new Hashtable<>();
- evt.put(MapboxEvent.ATTRIBUTE_EVENT, MapboxEvent.TYPE_MAP_CLICK);
- evt.put(MapboxEvent.ATTRIBUTE_CREATED, MapboxEventManager.generateCreateDate());
- evt.put(MapboxEvent.KEY_GESTURE_ID, gestureId);
- evt.put(MapboxEvent.KEY_LATITUDE, tapLatLng.getLatitude());
- evt.put(MapboxEvent.KEY_LONGITUDE, tapLatLng.getLongitude());
- evt.put(MapboxEvent.KEY_ZOOM, mapboxMap.getCameraPosition().zoom);
-
- MapboxEventManager.getMapboxEventManager().pushEvent(evt);
- }
+ // Called when someone selects an attribution, 'Improve this map' adds location data to the url
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ final Context context = ((Dialog) dialog).getContext();
+ if (which == ATTRIBUTION_INDEX_TELEMETRY_SETTINGS) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.mapbox_AlertDialogStyle);
+ builder.setTitle(R.string.mapbox_attributionTelemetryTitle);
+ builder.setMessage(R.string.mapbox_attributionTelemetryMessage);
+ builder.setPositiveButton(R.string.mapbox_attributionTelemetryPositive, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ MapboxEventManager.getMapboxEventManager().setTelemetryEnabled(true);
+ dialog.cancel();
+ }
+ });
+ builder.setNeutralButton(R.string.mapbox_attributionTelemetryNeutral, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ String url = context.getResources().getStringArray(R.array.mapbox_attribution_links)[3];
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse(url));
+ context.startActivity(intent);
+ dialog.cancel();
+ }
+ });
+ builder.setNegativeButton(R.string.mapbox_attributionTelemetryNegative, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ MapboxEventManager.getMapboxEventManager().setTelemetryEnabled(false);
+ dialog.cancel();
+ }
+ });
+ builder.show();
+ return;
+ }
+ String url = context.getResources().getStringArray(R.array.mapbox_attribution_links)[which];
+ if (which == ATTRIBUTION_INDEX_IMPROVE_THIS_MAP) {
+ CameraPosition cameraPosition = transform.getCameraPosition();
+ if (cameraPosition != null) {
+ url = String.format(url, cameraPosition.target.getLongitude(),
+ cameraPosition.target.getLatitude(), (int) cameraPosition.zoom);
+ }
+ }
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse(url));
+ context.startActivity(intent);
+ }
+ }
+
+ /**
+ * Definition of a map change event.
+ *
+ * @see MapView.OnMapChangedListener#onMapChanged(int)
+ */
+ @IntDef( {REGION_WILL_CHANGE,
+ REGION_WILL_CHANGE_ANIMATED,
+ REGION_IS_CHANGING,
+ REGION_DID_CHANGE,
+ REGION_DID_CHANGE_ANIMATED,
+ WILL_START_LOADING_MAP,
+ DID_FINISH_LOADING_MAP,
+ DID_FAIL_LOADING_MAP,
+ WILL_START_RENDERING_FRAME,
+ DID_FINISH_RENDERING_FRAME,
+ DID_FINISH_RENDERING_FRAME_FULLY_RENDERED,
+ WILL_START_RENDERING_MAP,
+ DID_FINISH_RENDERING_MAP,
+ DID_FINISH_RENDERING_MAP_FULLY_RENDERED,
+ DID_FINISH_LOADING_STYLE,
+ SOURCE_DID_CHANGE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface MapChange {
+ }
+
+ /**
+ * This event is triggered whenever the currently displayed map region is about to changing
+ * without an animation.
+ * <p>
+ * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
+ * </p>
+ *
+ * @see MapChange
+ * @see MapView.OnMapChangedListener
+ */
+ public static final int REGION_WILL_CHANGE = 0;
+
+ /**
+ * This event is triggered whenever the currently displayed map region is about to changing
+ * with an animation.
+ * <p>
+ * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}
+ * </p>
+ *
+ * @see MapChange
+ * @see MapView.OnMapChangedListener
+ */
+ public static final int REGION_WILL_CHANGE_ANIMATED = 1;
+
+ /**
+ * This event is triggered whenever the currently displayed map region is changing.
+ * <p>
+ * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
+ * </p>
+ *
+ * @see MapChange
+ * @see MapView.OnMapChangedListener
+ */
+ public static final int REGION_IS_CHANGING = 2;
+
+ /**
+ * This event is triggered whenever the currently displayed map region finished changing
+ * without an animation.
+ * <p>
+ * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
+ * </p>
+ *
+ * @see MapChange
+ * @see MapView.OnMapChangedListener
+ */
+ public static final int REGION_DID_CHANGE = 3;
+
+ /**
+ * This event is triggered whenever the currently displayed map region finished changing
+ * with an animation.
+ * <p>
+ * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
+ * </p>
+ *
+ * @see MapChange
+ * @see MapView.OnMapChangedListener
+ */
+ public static final int REGION_DID_CHANGE_ANIMATED = 4;
+
+ /**
+ * This event is triggered when the map is about to start loading a new map style.
+ * <p>
+ * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
+ * </p>
+ *
+ * @see MapChange
+ * @see MapView.OnMapChangedListener
+ */
+ public static final int WILL_START_LOADING_MAP = 5;
+
+ /**
+ * This is triggered when the map has successfully loaded a new map style.
+ * <p>
+ * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
+ * </p>
+ *
+ * @see MapChange
+ * @see MapView.OnMapChangedListener
+ */
+ public static final int DID_FINISH_LOADING_MAP = 6;
+
+ /**
+ * This event is triggered when the map has failed to load a new map style.
+ * <p>
+ * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
+ * </p>
+ *
+ * @see MapChange
+ * @see MapView.OnMapChangedListener
+ */
+ public static final int DID_FAIL_LOADING_MAP = 7;
+
+ /**
+ * This event is triggered when the map will start rendering a frame.
+ * <p>
+ * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
+ * </p>
+ *
+ * @see MapChange
+ * @see MapView.OnMapChangedListener
+ */
+ public static final int WILL_START_RENDERING_FRAME = 8;
+
+ /**
+ * This event is triggered when the map finished rendering a frame.
+ * <p>
+ * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
+ * </p>
+ *
+ * @see MapChange
+ * @see MapView.OnMapChangedListener
+ */
+ public static final int DID_FINISH_RENDERING_FRAME = 9;
+
+ /**
+ * This event is triggered when the map finished rendeirng the frame fully.
+ * <p>
+ * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
+ * </p>
+ *
+ * @see MapChange
+ * @see MapView.OnMapChangedListener
+ */
+ public static final int DID_FINISH_RENDERING_FRAME_FULLY_RENDERED = 10;
+
+ /**
+ * This event is triggered when the map will start rendering the map.
+ * <p>
+ * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
+ * </p>
+ *
+ * @see MapChange
+ * @see MapView.OnMapChangedListener
+ */
+ public static final int WILL_START_RENDERING_MAP = 11;
+
+ /**
+ * This event is triggered when the map finished rendering the map.
+ * <p>
+ * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
+ * </p>
+ *
+ * @see MapChange
+ * @see MapView.OnMapChangedListener
+ */
+ public static final int DID_FINISH_RENDERING_MAP = 12;
+
+ /**
+ * This event is triggered when the map is fully rendered.
+ * <p>
+ * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
+ * </p>
+ *
+ * @see MapChange
+ * @see MapView.OnMapChangedListener
+ */
+ public static final int DID_FINISH_RENDERING_MAP_FULLY_RENDERED = 13;
+
+ /**
+ * This {@link MapChange} is triggered when a style has finished loading.
+ * <p>
+ * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
+ * </p>
+ *
+ * @see MapChange
+ * @see MapView.OnMapChangedListener
+ */
+ public static final int DID_FINISH_LOADING_STYLE = 14;
+
+ /**
+ * This {@link MapChange} is triggered when a source attribution changes.
+ * <p>
+ * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
+ * </p>
+ *
+ * @see MapChange
+ * @see MapView.OnMapChangedListener
+ */
+ public static final int SOURCE_DID_CHANGE = 15;
+
+ /**
+ * Interface definition for a callback to be invoked when the displayed map view changes.
+ * <p>
+ * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
+ * </p>
+ *
+ * @see MapView#addOnMapChangedListener(OnMapChangedListener)
+ * @see MapView.MapChange
+ */
+ public interface OnMapChangedListener {
/**
- * Helper method for tracking DragEnd gesture event
- * See {@see MapboxEvent#TYPE_MAP_DRAGEND}
+ * Called when the displayed map view changes.
*
- * @param xCoordinate Original x screen coordinate at end of drag
- * @param yCoordinate Orginal y screen coordinate at end of drag
+ * @param change Type of map change event, one of {@link #REGION_WILL_CHANGE},
+ * {@link #REGION_WILL_CHANGE_ANIMATED},
+ * {@link #REGION_IS_CHANGING},
+ * {@link #REGION_DID_CHANGE},
+ * {@link #REGION_DID_CHANGE_ANIMATED},
+ * {@link #WILL_START_LOADING_MAP},
+ * {@link #DID_FAIL_LOADING_MAP},
+ * {@link #DID_FINISH_LOADING_MAP},
+ * {@link #WILL_START_RENDERING_FRAME},
+ * {@link #DID_FINISH_RENDERING_FRAME},
+ * {@link #DID_FINISH_RENDERING_FRAME_FULLY_RENDERED},
+ * {@link #WILL_START_RENDERING_MAP},
+ * {@link #DID_FINISH_RENDERING_MAP},
+ * {@link #DID_FINISH_RENDERING_MAP_FULLY_RENDERED}.
*/
- private void trackGestureDragEndEvent(@NonNull float xCoordinate, @NonNull float yCoordinate) {
- LatLng tapLatLng = projection.fromScreenLocation(new PointF(xCoordinate, yCoordinate));
-
- // NaN and Infinite checks to prevent JSON errors at send to server time
- if (Double.isNaN(tapLatLng.getLatitude()) || Double.isNaN(tapLatLng.getLongitude())) {
- Log.d(MapView.class.getSimpleName(), "trackGestureDragEndEvent() has a NaN lat or lon. Returning.");
- return;
- }
-
- if (Double.isInfinite(tapLatLng.getLatitude()) || Double.isInfinite(tapLatLng.getLongitude())) {
- Log.d(MapView.class.getSimpleName(), "trackGestureDragEndEvent() has an Infinite lat or lon. Returning.");
- return;
- }
+ void onMapChanged(@MapChange int change);
+ }
- Hashtable<String, Object> evt = new Hashtable<>();
- evt.put(MapboxEvent.ATTRIBUTE_EVENT, MapboxEvent.TYPE_MAP_DRAGEND);
- evt.put(MapboxEvent.ATTRIBUTE_CREATED, MapboxEventManager.generateCreateDate());
- evt.put(MapboxEvent.KEY_LATITUDE, tapLatLng.getLatitude());
- evt.put(MapboxEvent.KEY_LONGITUDE, tapLatLng.getLongitude());
- evt.put(MapboxEvent.KEY_ZOOM, mapboxMap.getCameraPosition().zoom);
+ private class FocalPointInvalidator implements FocalPointChangeListener {
- MapboxEventManager.getMapboxEventManager().pushEvent(evt);
- }
-
- // Called when user touches the screen, all positions are absolute
@Override
- public boolean onTouchEvent(@NonNull MotionEvent event) {
- // Check and ignore non touch or left clicks
- if (destroyed) {
- return super.onTouchEvent(event);
- }
-
- if ((event.getButtonState() != 0) && (event.getButtonState() != MotionEvent.BUTTON_PRIMARY)) {
- return false;
- }
-
- // Check two finger gestures first
- rotateGestureDetector.onTouchEvent(event);
- scaleGestureDetector.onTouchEvent(event);
- shoveGestureDetector.onTouchEvent(event);
-
- // Handle two finger tap
- switch (event.getActionMasked()) {
- case MotionEvent.ACTION_DOWN:
- // First pointer down
- nativeMapView.setGestureInProgress(true);
- break;
-
- case MotionEvent.ACTION_POINTER_DOWN:
- // Second pointer down
- twoTap = event.getPointerCount() == 2
- && mapboxMap.getUiSettings().isZoomGesturesEnabled();
- if (twoTap) {
- // Confirmed 2nd Finger Down
- trackGestureEvent(MapboxEvent.GESTURE_TWO_FINGER_SINGLETAP, event.getX(), event.getY());
- }
- break;
-
- case MotionEvent.ACTION_POINTER_UP:
- // Second pointer up
- break;
-
- case MotionEvent.ACTION_UP:
- // First pointer up
- long tapInterval = event.getEventTime() - event.getDownTime();
- boolean isTap = tapInterval <= ViewConfiguration.getTapTimeout();
- boolean inProgress = rotateGestureDetector.isInProgress()
- || scaleGestureDetector.isInProgress()
- || shoveGestureDetector.isInProgress();
-
- if (twoTap && isTap && !inProgress) {
- if (focalPoint != null) {
- zoom(false, focalPoint.x, focalPoint.y);
- } else {
- PointF focalPoint = TwoFingerGestureDetector.determineFocalPoint(event);
- zoom(false, focalPoint.x, focalPoint.y);
- }
- twoTap = false;
- return true;
- }
-
- // Scroll / Pan Has Stopped
- if (scrollInProgress) {
- trackGestureDragEndEvent(event.getX(), event.getY());
- scrollInProgress = false;
- }
-
- twoTap = false;
- nativeMapView.setGestureInProgress(false);
- break;
-
- case MotionEvent.ACTION_CANCEL:
- twoTap = false;
- nativeMapView.setGestureInProgress(false);
- break;
- }
-
- boolean retVal = gestureDetector.onTouchEvent(event);
- return retVal || super.onTouchEvent(event);
- }
-
- // This class handles one finger gestures
- private class GestureListener extends GestureDetector.SimpleOnGestureListener {
-
- // Must always return true otherwise all events are ignored
- @Override
- @SuppressLint("ResourceType")
- public boolean onDown(MotionEvent event) {
- // Show the zoom controls
- if (mapboxMap.getUiSettings().isZoomControlsEnabled()) {
- zoomButtonsController.setVisible(true);
- }
- return true;
- }
-
- // Called for double taps
- @Override
- public boolean onDoubleTapEvent(MotionEvent e) {
- if (destroyed || !mapboxMap.getUiSettings().isZoomGesturesEnabled()) {
- return false;
- }
-
- switch (e.getAction()) {
- case MotionEvent.ACTION_DOWN:
- break;
- case MotionEvent.ACTION_MOVE:
- break;
- case MotionEvent.ACTION_UP:
- if (quickZoom) {
- // insert here?
- quickZoom = false;
- break;
- }
-
- // Single finger double tap
- if (focalPoint != null) {
- // User provided focal point
- zoom(true, focalPoint.x, focalPoint.y);
- } else {
- // Zoom in on gesture
- zoom(true, e.getX(), e.getY());
- }
- break;
- }
-
- trackGestureEvent(MapboxEvent.GESTURE_DOUBLETAP, e.getX(), e.getY());
-
- return true;
- }
-
- @Override
- public boolean onSingleTapUp(MotionEvent motionEvent) {
- if (destroyed) {
- return false;
- }
- // Cancel any animation
- nativeMapView.cancelTransitions();
- return true;
- }
-
- @Override
- public boolean onSingleTapConfirmed(MotionEvent motionEvent) {
- List<Marker> selectedMarkers = mapboxMap.getSelectedMarkers();
-
- PointF tapPoint = new PointF(motionEvent.getX(), motionEvent.getY());
- float toleranceSides = 4 * screenDensity;
- float toleranceTopBottom = 10 * screenDensity;
-
- RectF tapRect = new RectF((tapPoint.x - averageIconWidth / 2 - toleranceSides) / screenDensity,
- (tapPoint.y - averageIconHeight / 2 - toleranceTopBottom) / screenDensity,
- (tapPoint.x + averageIconWidth / 2 + toleranceSides) / screenDensity,
- (tapPoint.y + averageIconHeight / 2 + toleranceTopBottom) / screenDensity);
-
- List<Marker> nearbyMarkers = getMarkersInRect(tapRect);
- long newSelectedMarkerId = -1;
-
- if (nearbyMarkers != null && nearbyMarkers.size() > 0) {
- Collections.sort(nearbyMarkers);
- for (Marker nearbyMarker : nearbyMarkers) {
- boolean found = false;
- for (Marker selectedMarker : selectedMarkers) {
- if (selectedMarker.equals(nearbyMarker)) {
- found = true;
- }
- }
- if (!found) {
- newSelectedMarkerId = nearbyMarker.getId();
- break;
- }
- }
- }
-
- if (newSelectedMarkerId >= 0) {
- List<Annotation> annotations = mapboxMap.getAnnotations();
- int count = annotations.size();
- for (int i = 0; i < count; i++) {
- Annotation annotation = annotations.get(i);
- if (annotation instanceof Marker) {
- if (annotation.getId() == newSelectedMarkerId) {
- if (selectedMarkers.isEmpty() || !selectedMarkers.contains(annotation)) {
- if (!(annotation instanceof MarkerView)) {
- mapboxMap.selectMarker((Marker) annotation);
- } else {
- mapboxMap.getMarkerViewManager().onClickMarkerView((MarkerView) annotation);
- }
- }
- break;
- }
- }
- }
- } else {
- if (mapboxMap.getUiSettings().isDeselectMarkersOnTap()) {
- // deselect any selected marker
- mapboxMap.deselectMarkers();
- }
-
- // notify app of map click
- MapboxMap.OnMapClickListener listener = mapboxMap.getOnMapClickListener();
- if (listener != null) {
- LatLng point = projection.fromScreenLocation(tapPoint);
- listener.onMapClick(point);
- }
- }
-
- trackGestureEvent(MapboxEvent.GESTURE_SINGLETAP, motionEvent.getX(), motionEvent.getY());
- return true;
- }
-
- // Called for a long press
- @Override
- public void onLongPress(MotionEvent motionEvent) {
- MapboxMap.OnMapLongClickListener listener = mapboxMap.getOnMapLongClickListener();
- if (listener != null && !quickZoom) {
- LatLng point = projection.fromScreenLocation(new PointF(motionEvent.getX(), motionEvent.getY()));
- listener.onMapLongClick(point);
- }
- }
-
- // Called for flings
- @Override
- public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
- if (destroyed || !mapboxMap.getTrackingSettings().isScrollGestureCurrentlyEnabled()) {
- return false;
- }
-
- resetTrackingModesIfRequired(true, false);
-
- // Fling the map
- float ease = 0.25f;
-
- velocityX = velocityX * ease;
- velocityY = velocityY * ease;
-
- double speed = Math.sqrt(velocityX * velocityX + velocityY * velocityY);
- double deceleration = 2500;
- double duration = speed / (deceleration * ease);
-
- // Cancel any animation
- nativeMapView.cancelTransitions();
-
- nativeMapView.moveBy(velocityX * duration / 2.0 / screenDensity, velocityY * duration / 2.0 / screenDensity, (long) (duration * 1000.0f));
-
- MapboxMap.OnFlingListener listener = mapboxMap.getOnFlingListener();
- if (listener != null) {
- listener.onFling();
- }
-
- trackGestureEvent(MapboxEvent.GESTURE_PAN_START, e1.getX(), e1.getY());
- return true;
- }
-
- // Called for drags
- @Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
- if (!scrollInProgress) {
- scrollInProgress = true;
- }
- if (destroyed || !mapboxMap.getTrackingSettings().isScrollGestureCurrentlyEnabled()) {
- return false;
- }
-
- if (dragStarted) {
- return false;
- }
-
- requestDisallowInterceptTouchEvent(true);
-
- // reset tracking if needed
- resetTrackingModesIfRequired(true, false);
- // Cancel any animation
- nativeMapView.cancelTransitions();
-
- // Scroll the map
- nativeMapView.moveBy(-distanceX / screenDensity, -distanceY / screenDensity);
-
- MapboxMap.OnScrollListener listener = mapboxMap.getOnScrollListener();
- if (listener != null) {
- listener.onScroll();
- }
- return true;
- }
+ public void onFocalPointChanged(PointF pointF) {
+ mapGestureDetector.setFocalPoint(pointF);
}
+ }
- // This class handles two finger gestures and double-tap drag gestures
- private class ScaleGestureListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
-
- long beginTime = 0;
- float scaleFactor = 1.0f;
-
- // Called when two fingers first touch the screen
- @Override
- public boolean onScaleBegin(ScaleGestureDetector detector) {
- if (destroyed || !mapboxMap.getUiSettings().isZoomGesturesEnabled()) {
- return false;
- }
-
- beginTime = detector.getEventTime();
- trackGestureEvent(MapboxEvent.GESTURE_PINCH_START, detector.getFocusX(), detector.getFocusY());
- return true;
- }
-
- // Called when fingers leave screen
- @Override
- public void onScaleEnd(ScaleGestureDetector detector) {
- beginTime = 0;
- scaleFactor = 1.0f;
- zoomStarted = false;
- }
+ private class RegisterTouchListener implements MapboxMap.OnRegisterTouchListener {
- // Called each time a finger moves
- // Called for pinch zooms and quickzooms/quickscales
- @Override
- public boolean onScale(ScaleGestureDetector detector) {
- UiSettings uiSettings = mapboxMap.getUiSettings();
- if (destroyed || !uiSettings.isZoomGesturesEnabled()) {
- return super.onScale(detector);
- }
-
- // If scale is large enough ignore a tap
- scaleFactor *= detector.getScaleFactor();
- if ((scaleFactor > 1.05f) || (scaleFactor < 0.95f)) {
- zoomStarted = true;
- }
-
- // Ignore short touches in case it is a tap
- // Also ignore small scales
- long time = detector.getEventTime();
- long interval = time - beginTime;
- if (!zoomStarted && (interval <= ViewConfiguration.getTapTimeout())) {
- return false;
- }
-
- if (!zoomStarted) {
- return false;
- }
-
- if (dragStarted) {
- return false;
- }
-
- // Cancel any animation
- nativeMapView.cancelTransitions();
-
- // Gesture is a quickzoom if there aren't two fingers
- quickZoom = !twoTap;
-
- // make an assumption here; if the zoom center is specified by the gesture, it's NOT going
- // to be in the center of the map. Therefore the zoom will translate the map center, so tracking
- // should be disabled.
-
- resetTrackingModesIfRequired(!quickZoom, false);
- // Scale the map
- if (focalPoint != null) {
- // arround user provided focal point
- nativeMapView.scaleBy(detector.getScaleFactor(), focalPoint.x / screenDensity, focalPoint.y / screenDensity);
- } else if (quickZoom) {
- // around center map
- nativeMapView.scaleBy(detector.getScaleFactor(), (getWidth() / 2) / screenDensity, (getHeight() / 2) / screenDensity);
- } else {
- // around gesture
- nativeMapView.scaleBy(detector.getScaleFactor(), detector.getFocusX() / screenDensity, detector.getFocusY() / screenDensity);
- }
-
- return true;
- }
- }
-
- // This class handles two finger rotate gestures
- private class RotateGestureListener extends RotateGestureDetector.SimpleOnRotateGestureListener {
-
- long beginTime = 0;
- float totalAngle = 0.0f;
- boolean started = false;
-
- // Called when two fingers first touch the screen
- @Override
- public boolean onRotateBegin(RotateGestureDetector detector) {
- if (destroyed || !mapboxMap.getTrackingSettings().isRotateGestureCurrentlyEnabled()) {
- return false;
- }
-
- beginTime = detector.getEventTime();
- trackGestureEvent(MapboxEvent.GESTURE_ROTATION_START, detector.getFocusX(), detector.getFocusY());
- return true;
- }
-
- // Called when the fingers leave the screen
- @Override
- public void onRotateEnd(RotateGestureDetector detector) {
- beginTime = 0;
- totalAngle = 0.0f;
- started = false;
- }
-
- // Called each time one of the two fingers moves
- // Called for rotation
- @Override
- public boolean onRotate(RotateGestureDetector detector) {
- if (destroyed || !mapboxMap.getTrackingSettings().isRotateGestureCurrentlyEnabled() || dragStarted) {
- return false;
- }
-
- // If rotate is large enough ignore a tap
- // Also is zoom already started, don't rotate
- totalAngle += detector.getRotationDegreesDelta();
- if (!zoomStarted && ((totalAngle > 20.0f) || (totalAngle < -20.0f))) {
- started = true;
- }
-
- // Ignore short touches in case it is a tap
- // Also ignore small rotate
- long time = detector.getEventTime();
- long interval = time - beginTime;
- if (!started && (interval <= ViewConfiguration.getTapTimeout())) {
- return false;
- }
-
- if (!started) {
- return false;
- }
-
- // Cancel any animation
- nativeMapView.cancelTransitions();
-
- // rotation constitutes translation of anything except the center of
- // rotation, so cancel both location and bearing tracking if required
-
- resetTrackingModesIfRequired(true, true);
-
- // Get rotate value
- double bearing = nativeMapView.getBearing();
- bearing += detector.getRotationDegreesDelta();
-
- // Rotate the map
- if (focalPoint != null) {
- // User provided focal point
- setBearing(bearing, focalPoint.x / screenDensity, focalPoint.y / screenDensity);
- } else {
- // around gesture
- setBearing(bearing, detector.getFocusX() / screenDensity, detector.getFocusY() / screenDensity);
- }
- return true;
- }
- }
-
- // This class handles a vertical two-finger shove. (If you place two fingers on screen with
- // less than a 20 degree angle between them, this will detect movement on the Y-axis.)
- private class ShoveGestureListener implements ShoveGestureDetector.OnShoveGestureListener {
-
- long beginTime = 0;
- float totalDelta = 0.0f;
- boolean started = false;
-
- @Override
- public boolean onShoveBegin(ShoveGestureDetector detector) {
- if (!mapboxMap.getUiSettings().isTiltGesturesEnabled()) {
- return false;
- }
-
- beginTime = detector.getEventTime();
- trackGestureEvent(MapboxEvent.GESTURE_PITCH_START, detector.getFocusX(), detector.getFocusY());
- return true;
- }
-
- @Override
- public void onShoveEnd(ShoveGestureDetector detector) {
- beginTime = 0;
- totalDelta = 0.0f;
- started = false;
- dragStarted = false;
- }
-
- @Override
- public boolean onShove(ShoveGestureDetector detector) {
- if (destroyed || !mapboxMap.getUiSettings().isTiltGesturesEnabled()) {
- return false;
- }
-
- // If tilt is large enough ignore a tap
- // Also if zoom already started, don't tilt
- totalDelta += detector.getShovePixelsDelta();
- if (!zoomStarted && ((totalDelta > 10.0f) || (totalDelta < -10.0f))) {
- started = true;
- }
-
- // Ignore short touches in case it is a tap
- // Also ignore small tilt
- long time = detector.getEventTime();
- long interval = time - beginTime;
- if (!started && (interval <= ViewConfiguration.getTapTimeout())) {
- return false;
- }
-
- if (!started) {
- return false;
- }
-
- // Cancel any animation
- nativeMapView.cancelTransitions();
-
- // Get tilt value (scale and clamp)
- double pitch = getTilt();
- pitch -= 0.1 * detector.getShovePixelsDelta();
- pitch = Math.max(MapboxConstants.MINIMUM_TILT, Math.min(MapboxConstants.MAXIMUM_TILT, pitch));
-
- // Tilt the map
- mapboxMap.setTilt(pitch);
-
- dragStarted = true;
-
- return true;
- }
- }
-
- // This class handles input events from the zoom control buttons
- // Zoom controls allow single touch only devices to zoom in and out
- private class OnZoomListener implements ZoomButtonsController.OnZoomListener {
-
- // Not used
- @Override
- public void onVisibilityChanged(boolean visible) {
- // Ignore
- }
-
- // Called when user pushes a zoom button
- @Override
- public void onZoom(boolean zoomIn) {
- if (!mapboxMap.getUiSettings().isZoomGesturesEnabled()) {
- return;
- }
- zoom(zoomIn);
- }
- }
-
- //
- // Input events
- //
-
- // Called when the user presses a key, also called for repeating keys held
- // down
@Override
- public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
- if (destroyed) {
- return super.onKeyDown(keyCode, 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;
-
- // Check which key was pressed via hardware/real key code
- switch (keyCode) {
- // Tell the system to track these keys for long presses on
- // onKeyLongPress is fired
- case KeyEvent.KEYCODE_ENTER:
- case KeyEvent.KEYCODE_DPAD_CENTER:
- event.startTracking();
- return true;
-
- case KeyEvent.KEYCODE_DPAD_LEFT:
- if (!mapboxMap.getTrackingSettings().isScrollGestureCurrentlyEnabled()) {
- return false;
- }
-
- // Cancel any animation
- nativeMapView.cancelTransitions();
-
- // Move left
- nativeMapView.moveBy(scrollDist / screenDensity, 0.0 / screenDensity);
- return true;
-
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- if (!mapboxMap.getTrackingSettings().isScrollGestureCurrentlyEnabled()) {
- return false;
- }
-
- // Cancel any animation
- nativeMapView.cancelTransitions();
-
- // Move right
- nativeMapView.moveBy(-scrollDist / screenDensity, 0.0 / screenDensity);
- return true;
-
- case KeyEvent.KEYCODE_DPAD_UP:
- if (!mapboxMap.getTrackingSettings().isScrollGestureCurrentlyEnabled()) {
- return false;
- }
-
- // Cancel any animation
- nativeMapView.cancelTransitions();
-
- // Move up
- nativeMapView.moveBy(0.0 / screenDensity, scrollDist / screenDensity);
- return true;
-
- case KeyEvent.KEYCODE_DPAD_DOWN:
- if (!mapboxMap.getTrackingSettings().isScrollGestureCurrentlyEnabled()) {
- return false;
- }
-
- // Cancel any animation
- nativeMapView.cancelTransitions();
-
- // Move down
- nativeMapView.moveBy(0.0 / screenDensity, -scrollDist / screenDensity);
- return true;
-
- default:
- // We are not interested in this key
- return super.onKeyUp(keyCode, event);
- }
+ public void onRegisterMapClickListener(MapboxMap.OnMapClickListener listener) {
+ mapGestureDetector.setOnMapClickListener(listener);
}
- // Called when the user long presses a key that is being tracked
@Override
- public boolean onKeyLongPress(int keyCode, KeyEvent event) {
- // Check which key was pressed via hardware/real key code
- switch (keyCode) {
- // Tell the system to track these keys for long presses on
- // onKeyLongPress is fired
- case KeyEvent.KEYCODE_ENTER:
- case KeyEvent.KEYCODE_DPAD_CENTER:
- if (!mapboxMap.getUiSettings().isZoomGesturesEnabled()) {
- return false;
- }
-
- // Zoom out
- zoom(false);
- return true;
-
- default:
- // We are not interested in this key
- return super.onKeyUp(keyCode, event);
- }
+ public void onRegisterMapLongClickListener(MapboxMap.OnMapLongClickListener listener) {
+ mapGestureDetector.setOnMapLongClickListener(listener);
}
- // Called when the user releases a key
@Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- // Check if the key action was canceled (used for virtual keyboards)
- if (event.isCanceled()) {
- return super.onKeyUp(keyCode, event);
- }
-
- // Check which key was pressed via hardware/real key code
- // Note if keyboard does not have physical key (ie primary non-shifted
- // key) then it will not appear here
- // Must use the key character map as physical to character is not
- // fixed/guaranteed
- switch (keyCode) {
- case KeyEvent.KEYCODE_ENTER:
- case KeyEvent.KEYCODE_DPAD_CENTER:
- if (!mapboxMap.getUiSettings().isZoomGesturesEnabled()) {
- return false;
- }
-
- // Zoom in
- zoom(true);
- return true;
- }
-
- // We are not interested in this key
- return super.onKeyUp(keyCode, event);
+ public void onRegisterScrollListener(MapboxMap.OnScrollListener listener) {
+ mapGestureDetector.setOnScrollListener(listener);
}
- // Called for trackball events, all motions are relative in device specific
- // units
@Override
- public boolean onTrackballEvent(MotionEvent event) {
- if (destroyed) {
- return false;
- }
- // Choose the action
- switch (event.getActionMasked()) {
- // The trackball was rotated
- case MotionEvent.ACTION_MOVE:
- if (!mapboxMap.getTrackingSettings().isScrollGestureCurrentlyEnabled()) {
- return false;
- }
-
- // Cancel any animation
- nativeMapView.cancelTransitions();
-
- // Scroll the map
- nativeMapView.moveBy(-10.0 * event.getX() / screenDensity, -10.0 * event.getY() / screenDensity);
- return true;
-
- // Trackball was pushed in so start tracking and tell system we are
- // interested
- // We will then get the up action
- case MotionEvent.ACTION_DOWN:
- // Set up a delayed callback to check if trackball is still
- // After waiting the system long press time out
- if (currentTrackballLongPressTimeOut != null) {
- currentTrackballLongPressTimeOut.cancel();
- currentTrackballLongPressTimeOut = null;
- }
- currentTrackballLongPressTimeOut = new TrackballLongPressTimeOut();
- postDelayed(currentTrackballLongPressTimeOut,
- ViewConfiguration.getLongPressTimeout());
- return true;
-
- // Trackball was released
- case MotionEvent.ACTION_UP:
- if (!mapboxMap.getUiSettings().isZoomGesturesEnabled()) {
- return false;
- }
-
- // Only handle if we have not already long pressed
- if (currentTrackballLongPressTimeOut != null) {
- // Zoom in
- zoom(true);
- }
- return true;
-
- // Trackball was cancelled
- case MotionEvent.ACTION_CANCEL:
- if (currentTrackballLongPressTimeOut != null) {
- currentTrackballLongPressTimeOut.cancel();
- currentTrackballLongPressTimeOut = null;
- }
- return true;
-
- default:
- // We are not interested in this event
- return super.onTrackballEvent(event);
- }
+ public void onRegisterFlingListener(MapboxMap.OnFlingListener listener) {
+ mapGestureDetector.setOnFlingListener(listener);
}
+ }
- // This class implements the trackball long press time out callback
- private class TrackballLongPressTimeOut implements Runnable {
-
- // Track if we have been cancelled
- private boolean cancelled;
-
- public TrackballLongPressTimeOut() {
- cancelled = false;
- }
+ private static class MapCallback implements OnMapChangedListener {
- // Cancel the timeout
- public void cancel() {
- cancelled = true;
- }
+ private final MapboxMap mapboxMap;
+ private final List<OnMapReadyCallback> onMapReadyCallbackList = new ArrayList<>();
+ private boolean initialLoad = true;
- // Called when long press time out expires
- @Override
- public void run() {
- // Check if the trackball is still pressed
- if (!cancelled) {
- // Zoom out
- zoom(false);
-
- // Ensure the up action is not run
- currentTrackballLongPressTimeOut = null;
- }
- }
+ MapCallback(MapboxMap mapboxMap) {
+ this.mapboxMap = mapboxMap;
}
- // Called for events that don't fit the other handlers
- // such as mouse scroll events, mouse moves, joystick, trackpad
@Override
- public boolean onGenericMotionEvent(MotionEvent event) {
- if (destroyed) {
- return false;
- }
- // Mouse events
- //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
- switch (event.getActionMasked()) {
- // Mouse scrolls
- case MotionEvent.ACTION_SCROLL:
- if (!mapboxMap.getUiSettings().isZoomGesturesEnabled()) {
- return false;
- }
-
- // Cancel any animation
- nativeMapView.cancelTransitions();
-
- // Get the vertical scroll amount, one click = 1
- float scrollDist = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
-
- // Scale the map by the appropriate power of two factor
- nativeMapView.scaleBy(Math.pow(2.0, scrollDist), event.getX() / screenDensity, event.getY() / screenDensity);
-
- return true;
-
- default:
- // We are not interested in this event
- return super.onGenericMotionEvent(event);
- }
- }
-
- // We are not interested in this event
- return super.onGenericMotionEvent(event);
- }
-
- // Called when the mouse pointer enters or exits the view
- // or when it fades in or out due to movement
- @Override
- public boolean onHoverEvent(@NonNull MotionEvent event) {
- switch (event.getActionMasked()) {
- case MotionEvent.ACTION_HOVER_ENTER:
- case MotionEvent.ACTION_HOVER_MOVE:
- // Show the zoom controls
- if (mapboxMap.getUiSettings().isZoomControlsEnabled()) {
- zoomButtonsController.setVisible(true);
- }
- return true;
-
- case MotionEvent.ACTION_HOVER_EXIT:
- // Hide the zoom controls
- if (mapboxMap.getUiSettings().isZoomControlsEnabled()) {
- zoomButtonsController.setVisible(false);
- }
- return true;
-
- default:
- // We are not interested in this event
- return super.onHoverEvent(event);
- }
- }
-
- //
- // Connectivity events
- //
-
- // This class handles connectivity changes
- private class ConnectivityReceiver extends BroadcastReceiver {
-
- // Called when an action we are listening to in the manifest has been sent
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
- boolean noConnectivity = intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
- onConnectivityChanged(!noConnectivity);
- }
- }
- }
-
- // Called when MapView is being created
- private boolean isConnected() {
- Context appContext = getContext().getApplicationContext();
- ConnectivityManager connectivityManager = (ConnectivityManager) appContext.getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
- return (activeNetwork != null) && activeNetwork.isConnectedOrConnecting();
- }
-
- // Called when our Internet connectivity has changed
- private void onConnectivityChanged(boolean isConnected) {
- nativeMapView.setReachability(isConnected);
+ public void onMapChanged(@MapChange int change) {
+ if (change == DID_FINISH_LOADING_STYLE && initialLoad) {
+ initialLoad = false;
+ mapboxMap.onPreMapReady();
+ onMapReady();
+ mapboxMap.onPostMapReady();
+ } else if (change == REGION_IS_CHANGING || change == REGION_DID_CHANGE || change == DID_FINISH_LOADING_MAP) {
+ mapboxMap.onUpdate();
+ }
}
- //
- // Map events
- //
-
- /**
- * <p>
- * Add a callback that's invoked when the displayed map view changes.
- * </p>
- * To remove the callback, use {@link MapView#removeOnMapChangedListener(OnMapChangedListener)}.
- *
- * @param listener The callback that's invoked on every frame rendered to the map view.
- * @see MapView#removeOnMapChangedListener(OnMapChangedListener)
- */
- public void addOnMapChangedListener(@Nullable OnMapChangedListener listener) {
- if (listener != null) {
- onMapChangedListener.add(listener);
+ private void onMapReady() {
+ if (onMapReadyCallbackList.size() > 0) {
+ // Notify listeners, clear when done
+ Iterator<OnMapReadyCallback> iterator = onMapReadyCallbackList.iterator();
+ while (iterator.hasNext()) {
+ OnMapReadyCallback callback = iterator.next();
+ callback.onMapReady(mapboxMap);
+ iterator.remove();
}
+ }
}
- /**
- * Remove a callback added with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}
- *
- * @param listener The previously added callback to remove.
- * @see MapView#addOnMapChangedListener(OnMapChangedListener)
- */
- public void removeOnMapChangedListener(@Nullable OnMapChangedListener listener) {
- if (listener != null) {
- onMapChangedListener.remove(listener);
- }
+ public boolean isInitialLoad() {
+ return initialLoad;
}
- // Called when the map view transformation has changed
- // Called via JNI from NativeMapView
- // Forward to any listeners
- protected void onMapChanged(int mapChange) {
- if (onMapChangedListener != null) {
- OnMapChangedListener listener;
- final Iterator<OnMapChangedListener> iterator = onMapChangedListener.iterator();
- while (iterator.hasNext()) {
- listener = iterator.next();
- listener.onMapChanged(mapChange);
- }
- }
+ void addOnMapReadyCallback(OnMapReadyCallback callback) {
+ onMapReadyCallbackList.add(callback);
}
-
- //
- // User location
- //
-
- void setMyLocationEnabled(boolean enabled) {
- myLocationView.setEnabled(enabled);
- }
-
- Location getMyLocation() {
- return myLocationView.getLocation();
- }
-
- void setOnMyLocationChangeListener(@Nullable final MapboxMap.OnMyLocationChangeListener listener) {
- if (listener != null) {
- myLocationListener = new LocationListener() {
- @Override
- public void onLocationChanged(Location location) {
- if (listener != null) {
- listener.onMyLocationChange(location);
- }
- }
- };
- LocationServices.getLocationServices(getContext()).addLocationListener(myLocationListener);
- } else {
- LocationServices.getLocationServices(getContext()).removeLocationListener(myLocationListener);
- myLocationListener = null;
- }
- }
-
- void setMyLocationTrackingMode(@MyLocationTracking.Mode int myLocationTrackingMode) {
- if (myLocationTrackingMode != MyLocationTracking.TRACKING_NONE && !mapboxMap.isMyLocationEnabled()) {
- mapboxMap.setMyLocationEnabled(true);
- }
- myLocationView.setMyLocationTrackingMode(myLocationTrackingMode);
-
- if (myLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW) {
- setFocalPoint(new PointF(myLocationView.getCenterX(), myLocationView.getCenterY()));
- } else {
- setFocalPoint(null);
- }
-
- MapboxMap.OnMyLocationTrackingModeChangeListener listener = mapboxMap.getOnMyLocationTrackingModeChangeListener();
- if (listener != null) {
- listener.onMyLocationTrackingModeChange(myLocationTrackingMode);
- }
- }
-
- void setMyBearingTrackingMode(@MyBearingTracking.Mode int myBearingTrackingMode) {
- if (myBearingTrackingMode != MyBearingTracking.NONE && !mapboxMap.isMyLocationEnabled()) {
- mapboxMap.setMyLocationEnabled(true);
- }
- myLocationView.setMyBearingTrackingMode(myBearingTrackingMode);
- MapboxMap.OnMyBearingTrackingModeChangeListener listener = mapboxMap.getOnMyBearingTrackingModeChangeListener();
- if (listener != null) {
- listener.onMyBearingTrackingModeChange(myBearingTrackingMode);
- }
- }
-
- boolean isPermissionsAccepted() {
- return (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) ||
- ContextCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
- }
-
- /**
- * Reset the tracking modes as necessary. Location tracking is reset if the map center is changed,
- * bearing tracking if there is a rotation.
- *
- * @param translate
- * @param rotate
- */
- void resetTrackingModesIfRequired(boolean translate, boolean rotate) {
- TrackingSettings trackingSettings = mapboxMap.getTrackingSettings();
-
- // if tracking is on, and we should dismiss tracking with gestures, and this is a scroll action, turn tracking off
- if (translate && !trackingSettings.isLocationTrackingDisabled() && trackingSettings.isDismissLocationTrackingOnGesture()) {
- resetLocationTrackingMode();
- }
-
- // reset bearing tracking only on rotate
- if (rotate && !trackingSettings.isBearingTrackingDisabled() && trackingSettings.isDismissBearingTrackingOnGesture()) {
- resetBearingTrackingMode();
- }
- }
-
- void resetTrackingModesIfRequired(CameraPosition cameraPosition) {
- resetTrackingModesIfRequired(cameraPosition.target != null, cameraPosition.bearing != -1);
- }
-
- private void resetLocationTrackingMode() {
- try {
- TrackingSettings trackingSettings = mapboxMap.getTrackingSettings();
- trackingSettings.setMyLocationTrackingMode(MyLocationTracking.TRACKING_NONE);
- } catch (SecurityException ignore) {
- // User did not accept location permissions
- }
- }
-
- private void resetBearingTrackingMode() {
- try {
- TrackingSettings trackingSettings = mapboxMap.getTrackingSettings();
- trackingSettings.setMyBearingTrackingMode(MyBearingTracking.NONE);
- } catch (SecurityException ignore) {
- // User did not accept location permissions
- }
- }
-
- //
- // Compass
- //
-
- void setCompassEnabled(boolean compassEnabled) {
- compassView.setEnabled(compassEnabled);
- }
-
- void setCompassGravity(int gravity) {
- setWidgetGravity(compassView, gravity);
- }
-
- void setCompassMargins(int left, int top, int right, int bottom) {
- setWidgetMargins(compassView, left, top, right, bottom);
- }
-
- void setCompassFadeFacingNorth(boolean compassFadeFacingNorth) {
- compassView.fadeCompassViewFacingNorth(compassFadeFacingNorth);
- }
-
- //
- // Logo
- //
-
- void setLogoGravity(int gravity) {
- setWidgetGravity(logoView, gravity);
- }
-
- void setLogoMargins(int left, int top, int right, int bottom) {
- setWidgetMargins(logoView, left, top, right, bottom);
- }
-
- void setLogoEnabled(boolean visible) {
- logoView.setVisibility(visible ? View.VISIBLE : View.GONE);
- }
-
- //
- // Attribution
- //
-
- void setAttributionGravity(int gravity) {
- setWidgetGravity(attributionsView, gravity);
- }
-
- void setAttributionMargins(int left, int top, int right, int bottom) {
- setWidgetMargins(attributionsView, left, top, right, bottom);
- }
-
- void setAttributionEnabled(int visibility) {
- attributionsView.setVisibility(visibility);
- }
-
- void setAtttibutionTintColor(int tintColor) {
- ColorUtils.setTintList(attributionsView, tintColor);
- }
-
- int getAttributionTintColor() {
- return mapboxMap.getUiSettings().getAttributionTintColor();
- }
-
- /**
- * Sets a callback object which will be triggered when the {@link MapboxMap} instance is ready to be used.
- *
- * @param callback The callback object that will be triggered when the map is ready to be used.
- */
- @UiThread
- public void getMapAsync(final OnMapReadyCallback callback) {
- if (!initialLoad && callback != null) {
- callback.onMapReady(mapboxMap);
- } else {
- if (callback != null) {
- onMapReadyCallbackList.add(callback);
- }
- }
- }
-
- MapboxMap getMapboxMap() {
- return mapboxMap;
- }
-
- void setMapboxMap(MapboxMap mapboxMap) {
- this.mapboxMap = mapboxMap;
- }
-
- MyLocationView getUserLocationView() {
- return myLocationView;
- }
-
- NativeMapView getNativeMapView() {
- return nativeMapView;
- }
-
- //
- // Snapshot API
- //
-
- @UiThread
- void snapshot(@NonNull final MapboxMap.SnapshotReadyCallback callback, @Nullable final Bitmap bitmap) {
- snapshotRequest = new SnapshotRequest(bitmap, callback);
- nativeMapView.scheduleTakeSnapshot();
- nativeMapView.render();
- }
-
- // Called when the snapshot method was executed
- // Called via JNI from NativeMapView
- // Forward to any listeners
- protected void onSnapshotReady(byte[] bytes) {
- if (snapshotRequest != null && bytes != null) {
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inBitmap = snapshotRequest.getBitmap(); // the old Bitmap to be reused
- options.inMutable = true;
- options.inSampleSize = 1;
- Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
-
- MapboxMap.SnapshotReadyCallback callback = snapshotRequest.getCallback();
- if (callback != null) {
- callback.onSnapshotReady(bitmap);
- }
- }
- }
-
- private class SnapshotRequest {
- private Bitmap bitmap;
- private MapboxMap.SnapshotReadyCallback callback;
-
- public SnapshotRequest(Bitmap bitmap, MapboxMap.SnapshotReadyCallback callback) {
- this.bitmap = bitmap;
- this.callback = callback;
- }
-
- public Bitmap getBitmap() {
- return bitmap;
- }
-
- public MapboxMap.SnapshotReadyCallback getCallback() {
- return callback;
- }
- }
-
- //
- // View utility methods
- //
-
- private void setWidgetGravity(@NonNull final View view, int gravity) {
- LayoutParams layoutParams = (LayoutParams) view.getLayoutParams();
- layoutParams.gravity = gravity;
- view.setLayoutParams(layoutParams);
- }
-
- private void setWidgetMargins(@NonNull final View view, int left, int top, int right, int bottom) {
- LayoutParams layoutParams = (LayoutParams) view.getLayoutParams();
- left += contentPaddingLeft;
- top += contentPaddingTop;
- right += contentPaddingRight;
- bottom += contentPaddingBottom;
- layoutParams.setMargins(left, top, right, bottom);
- view.setLayoutParams(layoutParams);
- }
-
- private static class AttributionOnClickListener implements View.OnClickListener, DialogInterface.OnClickListener {
-
- private static final int ATTRIBUTION_INDEX_IMPROVE_THIS_MAP = 2;
- private static final int ATTRIBUTION_INDEX_TELEMETRY_SETTINGS = 3;
- private MapView mapView;
-
- public AttributionOnClickListener(MapView mapView) {
- super();
- this.mapView = mapView;
- }
-
- // Called when someone presses the attribution icon
- @Override
- public void onClick(View view) {
-
- AlertDialog.Builder builder = new AlertDialog.Builder(mapView.getContext(), R.style.TelemAlertDialogStyle);
- builder.setTitle(R.string.attributionsDialogTitle);
- String[] items = mapView.getContext().getResources().getStringArray(R.array.attribution_names);
- builder.setAdapter(new ArrayAdapter<>(mapView.getContext(), R.layout.attribution_list_item, items), this);
- AlertDialog attributionDialog = builder.show();
-
- // TODO Change listview text color to mapView.getAttributionTintColor()
- }
-
- // Called when someone selects an attribution, 'Improve this map' adds location data to the url
- @Override
- public void onClick(DialogInterface dialog, int which) {
- final Context context = ((Dialog) dialog).getContext();
- if (which == ATTRIBUTION_INDEX_TELEMETRY_SETTINGS) {
- AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.TelemAlertDialogStyle);
- builder.setTitle(R.string.attributionTelemetryTitle);
- builder.setMessage(R.string.attributionTelemetryMessage);
- builder.setPositiveButton(R.string.attributionTelemetryPositive, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- MapboxEventManager.getMapboxEventManager().setTelemetryEnabled(true);
- dialog.cancel();
- }
- });
- builder.setNeutralButton(R.string.attributionTelemetryNeutral, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- String url = context.getResources().getStringArray(R.array.attribution_links)[3];
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(Uri.parse(url));
- context.startActivity(intent);
- dialog.cancel();
- }
- });
- builder.setNegativeButton(R.string.attributionTelemetryNegative, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- MapboxEventManager.getMapboxEventManager().setTelemetryEnabled(false);
- dialog.cancel();
- }
- });
-
- AlertDialog telemDialog = builder.show();
- telemDialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(mapView.getAttributionTintColor());
- telemDialog.getButton(AlertDialog.BUTTON_NEGATIVE).setTextColor(mapView.getAttributionTintColor());
- telemDialog.getButton(AlertDialog.BUTTON_NEUTRAL).setTextColor(mapView.getAttributionTintColor());
- return;
- }
- String url = context.getResources().getStringArray(R.array.attribution_links)[which];
- if (which == ATTRIBUTION_INDEX_IMPROVE_THIS_MAP) {
- LatLng latLng = mapView.getMapboxMap().getCameraPosition().target;
- url = String.format(url, latLng.getLongitude(), latLng.getLatitude(), (int) mapView.getZoom());
- }
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(Uri.parse(url));
- context.startActivity(intent);
- }
- }
-
- private static class ZoomInvalidator implements Runnable {
-
- private MapboxMap mapboxMap;
-
- public ZoomInvalidator(MapboxMap mapboxMap) {
- this.mapboxMap = mapboxMap;
- }
-
- @Override
- public void run() {
- // invalidate camera position
- mapboxMap.getCameraPosition();
- }
- }
-
- /**
- * Definition of a map change event.
- *
- * @see MapView.OnMapChangedListener#onMapChanged(int)
- */
- @IntDef({REGION_WILL_CHANGE,
- REGION_WILL_CHANGE_ANIMATED,
- REGION_IS_CHANGING,
- REGION_DID_CHANGE,
- REGION_DID_CHANGE_ANIMATED,
- WILL_START_LOADING_MAP,
- DID_FINISH_LOADING_MAP,
- DID_FAIL_LOADING_MAP,
- WILL_START_RENDERING_FRAME,
- DID_FINISH_RENDERING_FRAME,
- DID_FINISH_RENDERING_FRAME_FULLY_RENDERED,
- WILL_START_RENDERING_MAP,
- DID_FINISH_RENDERING_MAP,
- DID_FINISH_RENDERING_MAP_FULLY_RENDERED,
- DID_FINISH_LOADING_STYLE
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface MapChange {
- }
-
- /**
- * This event is triggered whenever the currently displayed map region is about to changing
- * without an animation.
- * <p>
- * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
- * </p>
- *
- * @see MapChange
- * @see MapView.OnMapChangedListener
- */
- public static final int REGION_WILL_CHANGE = 0;
-
- /**
- * This event is triggered whenever the currently displayed map region is about to changing
- * with an animation.
- * <p
- * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}
- * </p>
- *
- * @see MapChange
- * @see MapView.OnMapChangedListener
- */
- public static final int REGION_WILL_CHANGE_ANIMATED = 1;
-
- /**
- * This event is triggered whenever the currently displayed map region is changing.
- * <p>
- * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
- * </p>
- *
- * @see MapChange
- * @see MapView.OnMapChangedListener
- */
- public static final int REGION_IS_CHANGING = 2;
-
- /**
- * This event is triggered whenever the currently displayed map region finished changing
- * without an animation.
- * <p>
- * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
- * </p>
- *
- * @see MapChange
- * @see MapView.OnMapChangedListener
- */
- public static final int REGION_DID_CHANGE = 3;
-
- /**
- * This event is triggered whenever the currently displayed map region finished changing
- * with an animation.
- * <p>
- * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
- * </p>
- *
- * @see MapChange
- * @see MapView.OnMapChangedListener
- */
- public static final int REGION_DID_CHANGE_ANIMATED = 4;
-
- /**
- * This event is triggered when the map is about to start loading a new map style.
- * <p>
- * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
- * </p>
- *
- * @see MapChange
- * @see MapView.OnMapChangedListener
- */
- public static final int WILL_START_LOADING_MAP = 5;
-
- /**
- * This is triggered when the map has successfully loaded a new map style.
- * <p>
- * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
- * </p>
- *
- * @see MapChange
- * @see MapView.OnMapChangedListener
- */
- public static final int DID_FINISH_LOADING_MAP = 6;
-
- /**
- * This event is triggered when the map has failed to load a new map style.
- * <p>
- * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
- * </p>
- *
- * @see MapChange
- * @see MapView.OnMapChangedListener
- */
- public static final int DID_FAIL_LOADING_MAP = 7;
-
- /**
- * This event is triggered when the map will start rendering a frame.
- * <p>
- * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
- * </p>
- *
- * @see MapChange
- * @see MapView.OnMapChangedListener
- */
- public static final int WILL_START_RENDERING_FRAME = 8;
-
- /**
- * This event is triggered when the map finished rendering a frame.
- * <p>
- * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
- * </p>
- *
- * @see MapChange
- * @see MapView.OnMapChangedListener
- */
- public static final int DID_FINISH_RENDERING_FRAME = 9;
-
- /**
- * This event is triggered when the map finished rendeirng the frame fully.
- * <p>
- * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
- * </p>
- *
- * @see MapChange
- * @see MapView.OnMapChangedListener
- */
- public static final int DID_FINISH_RENDERING_FRAME_FULLY_RENDERED = 10;
-
- /**
- * This event is triggered when the map will start rendering the map.
- * <p>
- * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
- * </p>
- *
- * @see MapChange
- * @see MapView.OnMapChangedListener
- */
- public static final int WILL_START_RENDERING_MAP = 11;
-
- /**
- * This event is triggered when the map finished rendering the map.
- * <p>
- * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
- * </p>
- *
- * @see MapChange
- * @see MapView.OnMapChangedListener
- */
- public static final int DID_FINISH_RENDERING_MAP = 12;
-
- /**
- * This event is triggered when the map is fully rendered.
- * <p>
- * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
- * </p>
- *
- * @see MapChange
- * @see MapView.OnMapChangedListener
- */
- public static final int DID_FINISH_RENDERING_MAP_FULLY_RENDERED = 13;
-
-
- /**
- * This {@link MapChange} is triggered when a style has finished loading.
- * <p>
- * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
- * </p>
- *
- * @see MapChange
- * @see MapView.OnMapChangedListener
- */
- public static final int DID_FINISH_LOADING_STYLE = 14;
-
- /**
- * Interface definition for a callback to be invoked when the displayed map view changes.
- * <p>
- * Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
- * </p>
- *
- * @see MapView#addOnMapChangedListener(OnMapChangedListener)
- * @see MapView.MapChange
- */
- public interface OnMapChangedListener {
- /**
- * Called when the displayed map view changes.
- *
- * @param change Type of map change event, one of {@link #REGION_WILL_CHANGE},
- * {@link #REGION_WILL_CHANGE_ANIMATED},
- * {@link #REGION_IS_CHANGING},
- * {@link #REGION_DID_CHANGE},
- * {@link #REGION_DID_CHANGE_ANIMATED},
- * {@link #WILL_START_LOADING_MAP},
- * {@link #DID_FAIL_LOADING_MAP},
- * {@link #DID_FINISH_LOADING_MAP},
- * {@link #WILL_START_RENDERING_FRAME},
- * {@link #DID_FINISH_RENDERING_FRAME},
- * {@link #DID_FINISH_RENDERING_FRAME_FULLY_RENDERED},
- * {@link #WILL_START_RENDERING_MAP},
- * {@link #DID_FINISH_RENDERING_MAP},
- * {@link #DID_FINISH_RENDERING_MAP_FULLY_RENDERED}.
- */
- void onMapChanged(@MapChange int change);
- }
-
+ }
}